44constexpr uint32_t kSidecarVersionMin = 1;
45constexpr uint32_t kSidecarVersionMax = 3;
48constexpr double kSidecarV1FallbackTolerance = 1.e-6;
50constexpr uint32_t kFlagInnerWall = 1u << 0;
53constexpr uint32_t kFlatCSGVersion = 1;
54constexpr uint64_t kFlatCSGHalfspaceBytes = 100;
55constexpr uint64_t kFlatCSGCellBytes = 64;
57enum SurfaceType : uint32_t {
65enum CurveType : uint32_t {
72bool parseBSplineEdge(
const std::vector<double>&
params, O2BVHSurfaceSolid::PlanarBoundaryCurve& curve)
77 const int degree =
static_cast<int>(std::lround(
params[0]));
78 const int nPoles =
static_cast<int>(std::lround(
params[1]));
79 if (degree < 1 || nPoles < degree + 1) {
82 const size_t nKnots =
static_cast<size_t>(nPoles) + degree + 1;
83 const size_t expected = 2 + 2 *
static_cast<size_t>(nPoles) +
static_cast<size_t>(nPoles) + nKnots;
87 std::vector<O2BVHSurfaceSolid::Point2D> poles(nPoles);
89 for (
int i = 0;
i < nPoles; ++
i) {
93 std::vector<double>
weights(nPoles);
94 for (
int i = 0;
i < nPoles; ++
i) {
97 std::vector<double> knots(nKnots);
98 for (
size_t i = 0;
i < nKnots; ++
i) {
118bool readValue(std::ifstream& in, T&
value)
120 in.read(
reinterpret_cast<char*
>(&
value),
sizeof(
value));
121 return static_cast<bool>(in);
126void writeValue(std::ofstream& out,
const T&
value)
128 out.write(
reinterpret_cast<const char*
>(&
value),
sizeof(
value));
132uint64_t bytesRemaining(std::ifstream& in, std::streamoff fileSize)
137 const std::streamoff here = in.tellg();
138 return here < 0 || here > fileSize ? 0 :
static_cast<uint64_t
>(fileSize - here);
141bool readDoubles(std::ifstream& in, std::vector<double>&
values, uint32_t
n, std::streamoff fileSize)
143 if (
static_cast<uint64_t
>(
n) *
sizeof(
double) > bytesRemaining(in, fileSize)) {
147 in.read(
reinterpret_cast<char*
>(
values.data()),
static_cast<std::streamsize
>(
n) *
sizeof(
double));
148 return static_cast<bool>(in);
158 O2BVHSurfaceSolid::PlanarBoundaryCurve& bspline)
160 if (edge.curveType == kLineSegment && edge.params.size() >= 4) {
161 start = {edge.params[0], edge.params[1]};
162 end = {edge.params[2], edge.params[3]};
165 if (edge.curveType == kCircularArc && edge.params.size() >= 5) {
166 const double cu = edge.params[0], cv = edge.params[1],
r = edge.params[2];
167 const double a0 = edge.params[3], a1 = edge.params[3] + edge.params[4];
168 start = {cu +
r * std::cos(a0), cv +
r * std::sin(a0)};
169 end = {cu +
r * std::cos(a1), cv +
r * std::sin(a1)};
172 if (edge.curveType == kBSpline2D) {
173 if (!parseBSplineEdge(edge.params, bspline)) {
178 std::vector<surface::Vec2> poles;
179 poles.reserve(bspline.poles.size());
180 for (
const auto& pole : bspline.poles) {
181 poles.push_back({pole[0], pole[1]});
183 const surface::Curve2D evaluated =
185 const surface::Vec2
first = evaluated.startPoint();
186 const surface::Vec2
last = evaluated.endPoint();
197 const double*
params =
nullptr;
199 static void evaluate(
const void* context,
const surface::Vec2& uv,
double& gUU,
double& gUV,
double& gVV)
201 const auto& record = *
static_cast<const RecordMetric*
>(context);
202 const double* p = record.params;
203 switch (record.surfaceType) {
212 const double slope = (p[10] - p[9]) / (p[12] - p[11]);
231 surface::ParametricMetric metric()
const {
return {&evaluate,
this}; }
236bool wireToCurves(
const std::string& file,
size_t surfaceIndex,
const SidecarWire& wire,
237 std::vector<O2BVHSurfaceSolid::PlanarBoundaryCurve>& curves,
bool& anyArc,
238 const surface::ParametricMetric& metric,
double joinTolerance,
const char* toleranceOrigin)
240 using Curve = O2BVHSurfaceSolid::PlanarBoundaryCurve;
242 curves.reserve(wire.edges.size());
244 const size_t nEdges = wire.edges.size();
245 std::vector<O2BVHSurfaceSolid::Point2D> starts(nEdges);
246 std::vector<O2BVHSurfaceSolid::Point2D> ends(nEdges);
247 std::vector<Curve> bsplines(nEdges);
248 for (
size_t e = 0; e < nEdges; ++e) {
249 if (!edgeEndpoints(wire.edges[e], starts[e], ends[e], bsplines[e])) {
250 ::Error(
"LoadSurfaceSolid",
"%s: surface %zu: unsupported or malformed wire edge %zu",
file.c_str(),
255 for (
size_t e = 0; e < nEdges; ++e) {
256 const auto& edge = wire.edges[e];
257 const auto&
end = ends[e];
258 const auto& nextStart = starts[(e + 1) % nEdges];
259 const double joinGapSq = metric.distanceSq({
end[0],
end[1]}, {nextStart[0], nextStart[1]});
260 if (joinGapSq > joinTolerance * joinTolerance) {
261 ::Error(
"LoadSurfaceSolid",
262 "%s: surface %zu: wire edge %zu end does not join the next edge start (gap %.3g cm, tolerance %.3g cm, "
264 file.c_str(), surfaceIndex, e, std::sqrt(joinGapSq), joinTolerance, toleranceOrigin);
267 if (edge.curveType == kCircularArc) {
269 curves.push_back(Curve::makeArc({edge.params[0], edge.params[1]}, edge.params[2], edge.params[3],
270 edge.params[3] + edge.params[4]));
271 }
else if (edge.curveType == kBSpline2D) {
273 curves.push_back(std::move(bsplines[e]));
275 curves.push_back(Curve::makeLine(starts[e],
end));
286constexpr TrimWording kPlaneWording{
"%s: plane surface %zu has more than one outer wire",
287 "%s: plane surface %zu has no outer wire"};
288constexpr TrimWording kQuadricWording{
"%s: quadric surface %zu has more than one outer trim wire",
289 "%s: quadric surface %zu trim block has no outer wire"};
292bool collectTrim(
const std::string& file,
size_t surfaceIndex,
const TrimWording& wording,
293 const std::vector<SidecarWire>& wires, std::vector<O2BVHSurfaceSolid::PlanarBoundaryCurve>& outer,
294 std::vector<std::vector<O2BVHSurfaceSolid::PlanarBoundaryCurve>>& inners,
bool& anyArc,
295 const surface::ParametricMetric& metric,
double joinTolerance,
const char* toleranceOrigin)
297 bool haveOuter =
false;
298 for (
const auto& wire : wires) {
299 std::vector<O2BVHSurfaceSolid::PlanarBoundaryCurve> curves;
300 if (!wireToCurves(file, surfaceIndex, wire, curves, anyArc, metric, joinTolerance, toleranceOrigin)) {
303 if (wire.role == 0) {
305 ::Error(
"LoadSurfaceSolid", wording.moreThanOneOuter,
file.c_str(), surfaceIndex);
308 outer = std::move(curves);
311 inners.push_back(std::move(curves));
315 ::Error(
"LoadSurfaceSolid", wording.noOuter,
file.c_str(), surfaceIndex);
322void reorderEdgeRefsToKernelOrder(
const std::vector<SidecarWire>& wires, std::vector<unsigned int>& edgeIds,
323 std::vector<unsigned char>& edgeFlags)
325 size_t totalEdges = 0;
326 for (
const auto& wire : wires) {
327 totalEdges += wire.edges.size();
329 if (wires.empty() || totalEdges != edgeIds.size()) {
333 std::vector<size_t> kernelOffset(wires.size(), 0);
335 for (
size_t w = 0;
w < wires.size(); ++
w) {
336 if (wires[
w].
role == 0) {
338 running = wires[
w].edges.size();
342 for (
size_t w = 0;
w < wires.size(); ++
w) {
343 if (wires[
w].
role != 0) {
344 kernelOffset[
w] = running;
345 running += wires[
w].edges.size();
349 std::vector<unsigned int> permutedIds(edgeIds.size());
350 std::vector<unsigned char> permutedFlags(edgeFlags.size());
351 size_t sidecarOffset = 0;
352 for (
size_t w = 0;
w < wires.size(); ++
w) {
353 for (
size_t e = 0; e < wires[
w].edges.size(); ++e) {
354 permutedIds[kernelOffset[
w] + e] = edgeIds[sidecarOffset + e];
355 permutedFlags[kernelOffset[
w] + e] = edgeFlags[sidecarOffset + e];
357 sidecarOffset += wires[
w].edges.size();
359 edgeIds.swap(permutedIds);
360 edgeFlags.swap(permutedFlags);
367 std::ifstream in(file, std::ios::binary);
369 ::Error(
"LoadSurfaceSolid",
"Cannot open surface sidecar file %s", file.c_str());
373 in.seekg(0, std::ios::end);
374 const std::streamoff fileSize = in.tellg();
375 in.seekg(0, std::ios::beg);
378 in.read(magic,
sizeof(magic));
379 if (!in || std::memcmp(magic,
"O2SS", 4) != 0) {
380 ::Error(
"LoadSurfaceSolid",
"%s is not a surface sidecar file (bad magic)", file.c_str());
384 uint32_t
version = 0, nSurfaces = 0, reserved = 0;
385 if (!readValue(in,
version) || !readValue(in, nSurfaces) || !readValue(in, reserved)) {
386 ::Error(
"LoadSurfaceSolid",
"%s: truncated header", file.c_str());
389 if (version < kSidecarVersionMin || version > kSidecarVersionMax) {
390 ::Error(
"LoadSurfaceSolid",
"%s: unsupported sidecar version %u (reader supports %u..%u)", file.c_str(),
version,
391 kSidecarVersionMin, kSidecarVersionMax);
395 uint32_t nModelEdges = 0;
397 double modelTolerance = 0.;
398 if (!readValue(in, modelTolerance)) {
399 ::Error(
"LoadSurfaceSolid",
"%s: truncated version-2 header (no model tolerance)", file.c_str());
403 if (
version >= 3 && !readValue(in, nModelEdges)) {
404 ::Error(
"LoadSurfaceSolid",
"%s: truncated version-3 header (no edge table size)", file.c_str());
408 ::Warning(
"LoadSurfaceSolid",
409 "%s is a version-1 sidecar and states no model tolerance; assuming %g cm (the extractor's precision). "
410 "Re-run the converter to record the model's own value.",
411 file.c_str(), kSidecarV1FallbackTolerance);
418 ?
"declared by the model"
419 :
"the extractor-precision fallback";
421 for (
size_t s = 0; s < nSurfaces; ++s) {
423 if (!readValue(in,
surfaceType) || !readValue(in,
flags) || !readValue(in, nParams)) {
424 ::Error(
"LoadSurfaceSolid",
"%s: truncated surface record %zu", file.c_str(), s);
427 std::vector<double> p;
428 if (!readDoubles(in, p, nParams, fileSize)) {
429 ::Error(
"LoadSurfaceSolid",
"%s: truncated parameters of surface %zu", file.c_str(), s);
435 if (!readValue(in, nWires)) {
436 ::Error(
"LoadSurfaceSolid",
"%s: truncated wire count of surface %zu", file.c_str(), s);
440 if (
static_cast<uint64_t
>(nWires) * 8u > bytesRemaining(in, fileSize)) {
441 ::Error(
"LoadSurfaceSolid",
"%s: surface %zu claims %u wires, more than the file holds", file.c_str(), s, nWires);
444 std::vector<SidecarWire> wires(nWires);
445 for (
auto& wire : wires) {
447 if (!readValue(in, wire.role) || !readValue(in, nEdges)) {
448 ::Error(
"LoadSurfaceSolid",
"%s: truncated wire header in surface %zu", file.c_str(), s);
451 if (
static_cast<uint64_t
>(nEdges) * 8u > bytesRemaining(in, fileSize)) {
452 ::Error(
"LoadSurfaceSolid",
"%s: surface %zu claims %u wire edges, more than the file holds", file.c_str(), s,
456 wire.edges.resize(nEdges);
457 for (
auto& edge : wire.edges) {
458 uint32_t nCurveParams = 0;
459 if (!readValue(in, edge.curveType) || !readValue(in, nCurveParams) ||
460 !readDoubles(in, edge.params, nCurveParams, fileSize)) {
461 ::Error(
"LoadSurfaceSolid",
"%s: truncated edge record in surface %zu", file.c_str(), s);
468 std::vector<unsigned int> edgeIds;
469 std::vector<unsigned char> edgeFlags;
471 uint32_t nEdgeRefs = 0;
472 if (!readValue(in, nEdgeRefs)) {
473 ::Error(
"LoadSurfaceSolid",
"%s: truncated edge identity count of surface %zu", file.c_str(), s);
476 if (
static_cast<uint64_t
>(nEdgeRefs) * 5u > bytesRemaining(in, fileSize)) {
477 ::Error(
"LoadSurfaceSolid",
"%s: surface %zu claims %u edge identities, more than the file holds",
478 file.c_str(), s, nEdgeRefs);
481 edgeIds.resize(nEdgeRefs);
482 edgeFlags.resize(nEdgeRefs);
483 for (uint32_t e = 0; e < nEdgeRefs; ++e) {
485 uint8_t edgeFlag = 0;
486 if (!readValue(in, edgeId) || !readValue(in, edgeFlag)) {
487 ::Error(
"LoadSurfaceSolid",
"%s: truncated edge identity %u of surface %zu", file.c_str(), e, s);
490 if (nModelEdges > 0 && edgeId >= nModelEdges) {
491 ::Error(
"LoadSurfaceSolid",
"%s: surface %zu edge identity %u is %u, outside the model's %u edge(s)",
492 file.c_str(), s, e, edgeId, nModelEdges);
496 edgeFlags[e] = edgeFlag;
500 const bool innerWall = (
flags & kFlagInnerWall) != 0;
501 const RecordMetric recordMetric{
surfaceType, p.data()};
505 const auto addQuadric = [&](
const char*
name, uint32_t expectedParams,
const auto& addUntrimmed,
506 const auto& addTrimmed) {
507 if (nParams != expectedParams) {
508 ::Error(
"LoadSurfaceSolid",
"%s: %s surface %zu has %u parameters, expected %u", file.c_str(),
name, s,
509 nParams, expectedParams);
513 added = addUntrimmed();
516 std::vector<O2BVHSurfaceSolid::PlanarBoundaryCurve> outer;
517 std::vector<std::vector<O2BVHSurfaceSolid::PlanarBoundaryCurve>> inners;
519 if (!collectTrim(file, s, kQuadricWording, wires, outer, inners, anyArc, recordMetric.metric(), joinTolerance,
523 added = addTrimmed(outer, inners);
530 ::Error(
"LoadSurfaceSolid",
"%s: plane surface %zu has %u parameters, expected 9", file.c_str(), s, nParams);
535 std::vector<O2BVHSurfaceSolid::PlanarBoundaryCurve> outer;
536 std::vector<std::vector<O2BVHSurfaceSolid::PlanarBoundaryCurve>> inners;
538 if (!collectTrim(file, s, kPlaneWording, wires, outer, inners, anyArc, recordMetric.metric(), joinTolerance,
545 const auto toPolygon = [](
const std::vector<O2BVHSurfaceSolid::PlanarBoundaryCurve>& curves) {
546 std::vector<O2BVHSurfaceSolid::Point2D> polygon;
547 polygon.reserve(curves.size());
548 for (
const auto&
c : curves) {
549 polygon.push_back(
c.lineStart);
553 std::vector<std::vector<O2BVHSurfaceSolid::Point2D>> innerPolys;
554 innerPolys.reserve(inners.size());
555 for (
const auto& inner : inners) {
556 innerPolys.push_back(toPolygon(inner));
558 added = solid.
AddPlanarSurface(point3(p, 0), point3(p, 3), point3(p, 6), toPolygon(outer), innerPolys);
566 return solid.
AddCylindricalSurface(point3(p, 0), point3(p, 3), point3(p, 6), p[9], p[10], p[11], p[12],
569 [&](
const auto& outer,
const auto& inners) {
570 return solid.
AddCylindricalSurface(point3(p, 0), point3(p, 3), point3(p, 6), p[9], p[10], p[11], p[12],
571 p[13], innerWall, outer, inners);
580 return solid.
AddConicalSurface(point3(p, 0), point3(p, 3), point3(p, 6), p[9], p[10], p[11], p[12],
581 p[13], p[14], innerWall);
583 [&](
const auto& outer,
const auto& inners) {
584 return solid.
AddConicalSurface(point3(p, 0), point3(p, 3), point3(p, 6), p[9], p[10], p[11], p[12],
585 p[13], p[14], innerWall, outer, inners);
594 return solid.
AddSphericalSurface(point3(p, 0), point3(p, 3), point3(p, 6), p[9], p[10], p[11], p[12],
597 [&](
const auto& outer,
const auto& inners) {
598 return solid.
AddSphericalSurface(point3(p, 0), point3(p, 3), point3(p, 6), p[9], p[10], p[11], p[12],
599 p[13], innerWall, outer, inners);
608 return solid.
AddToroidalSurface(point3(p, 0), point3(p, 3), point3(p, 6), p[9], p[10], p[11], p[12],
609 p[13], p[14], innerWall);
611 [&](
const auto& outer,
const auto& inners) {
612 return solid.
AddToroidalSurface(point3(p, 0), point3(p, 3), point3(p, 6), p[9], p[10], p[11], p[12],
613 p[13], p[14], innerWall, outer, inners);
619 ::Error(
"LoadSurfaceSolid",
"%s: surface %zu has unknown surface type %u", file.c_str(), s,
surfaceType);
624 ::Error(
"LoadSurfaceSolid",
"%s: surface %zu was rejected by O2BVHSurfaceSolid", file.c_str(), s);
627 if (!edgeIds.empty()) {
628 reorderEdgeRefsToKernelOrder(wires, edgeIds, edgeFlags);
638 std::ifstream in(file, std::ios::binary);
640 ::Error(
"LoadFacetSolid",
"Cannot open facet sidecar file %s", file.c_str());
644 in.seekg(0, std::ios::end);
645 const std::streamoff fileSize = in.tellg();
646 in.seekg(0, std::ios::beg);
648 uint32_t nTriangles = 0;
649 if (!readValue(in, nTriangles)) {
650 ::Error(
"LoadFacetSolid",
"%s: truncated header", file.c_str());
655 const uint64_t recordsBytes =
static_cast<uint64_t
>(nTriangles) * 9u *
sizeof(
float);
656 const uint64_t remaining = bytesRemaining(in, fileSize);
657 if (recordsBytes > remaining) {
658 ::Error(
"LoadFacetSolid",
"%s: truncated: %u facet record(s) need %llu byte(s), found %llu", file.c_str(),
659 nTriangles,
static_cast<unsigned long long>(recordsBytes),
static_cast<unsigned long long>(remaining));
662 std::vector<float>
records(9 *
static_cast<size_t>(nTriangles));
663 in.read(
reinterpret_cast<char*
>(
records.data()),
static_cast<std::streamsize
>(recordsBytes));
665 ::Error(
"LoadFacetSolid",
"%s: truncated facet records", file.c_str());
669 uint32_t nDegenerate = 0;
670 for (uint32_t
i = 0;
i < nTriangles; ++
i) {
671 const float*
v = &
records[9 *
static_cast<size_t>(
i)];
681 if (nDegenerate > 0) {
682 ::Warning(
"LoadFacetSolid",
"%s: skipped %u degenerate facet(s) of %u", file.c_str(), nDegenerate, nTriangles);
690 std::ifstream in(file, std::ios::binary);
692 ::Error(
"LoadFlatCSG",
"Cannot open flat-CSG sidecar file %s", file.c_str());
696 in.seekg(0, std::ios::end);
697 const std::streamoff fileSize = in.tellg();
698 in.seekg(0, std::ios::beg);
701 in.read(magic,
sizeof(magic));
702 if (!in || std::memcmp(magic,
"O2FLTCSG",
sizeof(magic)) != 0) {
703 ::Error(
"LoadFlatCSG",
"%s is not a flat-CSG sidecar file (bad magic)", file.c_str());
707 uint32_t
version = 0, nHalfspaces = 0, nCells = 0;
708 if (!readValue(in,
version) || !readValue(in, nHalfspaces) || !readValue(in, nCells)) {
709 ::Error(
"LoadFlatCSG",
"%s: truncated header", file.c_str());
712 if (
version != kFlatCSGVersion) {
713 ::Error(
"LoadFlatCSG",
"%s: unsupported sidecar version %u (reader supports %u)", file.c_str(),
version,
720 static_cast<uint64_t
>(nHalfspaces) * kFlatCSGHalfspaceBytes +
static_cast<uint64_t
>(nCells) * kFlatCSGCellBytes;
721 const uint64_t remaining = bytesRemaining(in, fileSize);
723 ::Error(
"LoadFlatCSG",
724 "%s: file length does not match its header (%u halfspace(s) + %u cell(s) implies %llu more byte(s), "
726 file.c_str(), nHalfspaces, nCells,
static_cast<unsigned long long>(
expected),
727 static_cast<unsigned long long>(remaining));
733 for (uint32_t
h = 0;
h < nHalfspaces; ++
h) {
736 if (!readValue(in,
kind) || !readValue(in, sign)) {
737 ::Error(
"LoadFlatCSG",
"%s: truncated halfspace record %u", file.c_str(),
h);
742 for (
int i = 0;
i < 11 && ok; ++
i) {
743 ok = readValue(in,
c[
i]);
746 ::Error(
"LoadFlatCSG",
"%s: truncated halfspace record %u", file.c_str(),
h);
749 bool finite = std::isfinite(sign);
751 finite = finite && std::isfinite(
value);
754 ::Error(
"LoadFlatCSG",
"%s: halfspace %u has a non-finite coefficient", file.c_str(),
h);
760 const double centre[3] = {
c[0],
c[1],
c[2]};
761 const double axis[3] = {
c[3],
c[4],
c[5]};
762 if (!(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2] > 0.)) {
763 ::Error(
"LoadFlatCSG",
"%s: torus halfspace %u has a zero axis", file.c_str(),
h);
766 solid.
AddTorus(sign, centre, axis,
c[6],
c[7]);
768 ::Error(
"LoadFlatCSG",
"%s: halfspace %u has unknown kind %d", file.c_str(),
h,
kind);
773 for (uint32_t cellIdx = 0; cellIdx < nCells; ++cellIdx) {
776 if (!readValue(in,
first) || !readValue(in,
count) || !readValue(in, volume)) {
777 ::Error(
"LoadFlatCSG",
"%s: truncated cell record %u", file.c_str(), cellIdx);
782 for (
int i = 0;
i < 3 && ok; ++
i) {
783 ok = readValue(in, lo[
i]);
785 for (
int i = 0;
i < 3 && ok; ++
i) {
786 ok = readValue(in, hi[
i]);
789 ::Error(
"LoadFlatCSG",
"%s: truncated cell record %u", file.c_str(), cellIdx);
793 ::Error(
"LoadFlatCSG",
"%s: cell %u has an invalid range (first=%d, count=%d) into %u halfspace(s)",
794 file.c_str(), cellIdx,
first,
count, nHalfspaces);
798 solid.
SetCellBBox(
static_cast<int>(cellIdx), lo, hi);
808 ::Error(
"WriteFlatCSG",
809 "%s: shape %s is not closed (CloseShape() was never called, or refused); refusing to "
810 "write a sidecar that may encode a degenerate cell box",
811 file.c_str(), solid.GetName());
815 std::ofstream out(file, std::ios::binary);
817 ::Error(
"WriteFlatCSG",
"Cannot open %s for writing", file.c_str());
821 out.write(
"O2FLTCSG", 8);
822 const uint32_t
version = kFlatCSGVersion;
823 const uint32_t nHalfspaces =
static_cast<uint32_t
>(solid.
GetNhalfspaces());
824 const uint32_t nCells =
static_cast<uint32_t
>(solid.
GetNcells());
826 writeValue(out, nHalfspaces);
827 writeValue(out, nCells);
830 for (uint32_t
h = 0;
h < nHalfspaces; ++
h) {
832 const int32_t
kind = halfspace.
kind;
833 writeValue(out,
kind);
834 writeValue(out, halfspace.
sign);
835 for (
double value : halfspace.
c) {
836 writeValue(out,
value);
839 for (uint32_t cellIdx = 0; cellIdx < nCells; ++cellIdx) {
843 writeValue(out,
first);
844 writeValue(out,
count);
845 writeValue(out, cell.
volume);
847 solid.
GetCellBBox(
static_cast<int>(cellIdx), lo, hi);
848 for (
double value : lo) {
849 writeValue(out,
value);
851 for (
double value : hi) {
852 writeValue(out,
value);
857 ::Error(
"WriteFlatCSG",
"%s: write failed", file.c_str());
std::vector< o2::soa::IndexRecord > records
Private analytic bounded surfaces, trim wires and closure checks behind O2BVHSurfaceSolid.
constexpr int p1()
constexpr to accelerate the coordinates changing
std::vector< SidecarEdge > edges
const char * moreThanOneOuter
Class for time synchronization of RawReader instances.
bool AddFacet(const Vertex_t &pt0, const Vertex_t &pt1, const Vertex_t &pt2)
Adding a triangular facet from vertex positions in absolute coordinates.
Tessellated::Vertex_t Vertex_t
bool AddCylindricalSurface(const Point3D ¢erPoint, const Point3D &axis, const Point3D &referenceAxisU, double radius, double heightMin, double heightMax, double phiStart=0., double phiSweep=6.283185307179586, bool innerWall=false)
Add a cylindrical wall of radius around axis over a height range and a phi sweep; innerWall points th...
double GetModelTolerance() const
std::array< double, 3 > Point3D
std::array< double, 2 > Point2D
bool AddCurvedPlanarSurface(const Point3D &origin, const Point3D &axisU, const Point3D &axisV, const std::vector< PlanarBoundaryCurve > &outerWire, const std::vector< std::vector< PlanarBoundaryCurve > > &innerWires={})
Add an exact planar surface bounded by line/arc wires; axisU and axisV are orthonormal and axisU x ax...
bool AddConicalSurface(const Point3D ¢erPoint, const Point3D &axis, const Point3D &referenceAxisU, double radiusAtMin, double radiusAtMax, double heightMin, double heightMax, double phiStart=0., double phiSweep=6.283185307179586, bool innerWall=false)
Add a conical wall whose radius runs linearly from radiusAtMin to radiusAtMax; one radius may be zero...
void SetModelTolerance(double toleranceCm)
bool SetSurfaceBoundaryEdges(int surfaceIndex, const std::vector< unsigned int > &edgeIds, const std::vector< unsigned char > &edgeFlags)
Attach surface surfaceIndex's edge identities in trim-curve order; false on a bad index or mismatched...
bool AddSphericalSurface(const Point3D ¢er, const Point3D &polarAxis, const Point3D &referenceAxisU, double radius, double thetaMin=0., double thetaMax=3.141592653589793, double phiStart=0., double phiSweep=6.283185307179586, bool innerWall=false)
Add a spherical surface of radius trimmed to a theta range and a phi sweep; the defaults give a full ...
bool AddToroidalSurface(const Point3D ¢erPoint, const Point3D &axis, const Point3D &referenceAxisU, double majorRadius, double minorRadius, double phiStart=0., double phiSweep=6.283185307179586, double tubeStart=0., double tubeSweep=6.283185307179586, bool innerWall=false)
Add a toroidal surface trimmed to a phiRing x phiTube rectangle; the defaults give a full torus,...
bool AddPlanarSurface(const Point3D &origin, const Point3D &axisU, const Point3D &axisV, const std::vector< Point2D > &outerWire, const std::vector< std::vector< Point2D > > &innerWires={})
int AddCell(int first, int count, double volume)
Append a cell over [first, first + count) of the halfspace array; returns its index.
int AddQuadric(double sign, const double coeff[10])
Append a quadric halfspace; returns its index. sign is +1 or -1, inside is sign*Q <= 0.
int GetNhalfspaces() const
const FlatCSGCell & GetCell(int index) const
int AddTorus(double sign, const double *centre, const double *axis, double major, double minor)
Append a torus halfspace, inside sign * (sqrt((rho - major)^2 + z^2) - minor) <= 0 about unit axis; r...
void GetCellBBox(int cell, double *lo, double *hi) const
const FlatCSGHalfspace & GetHalfspace(int index) const
void SetCellBBox(int cell, const double *lo, const double *hi)
GLsizei const GLuint const GLfloat * weights
GLuint const GLchar * name
GLsizei const GLfloat * value
GLenum const GLfloat * params
GLenum GLsizei GLsizei GLint * values
GLubyte GLubyte GLubyte GLubyte w
constexpr double wireJoinToleranceFor(double modelTolerance)
The wire-join band for a model with a declared tolerance: that tolerance when looser than kWireJoinTo...
void coneParametricMetric(double radiusAtHeight, double slope, double &gUU, double &gUV, double &gVV)
void planeParametricMetric(const Vec3 &axisU, const Vec3 &axisV, double &gUU, double &gUV, double &gVV)
constexpr double kWireJoinTolerance
Wire-closure tolerance, a 3D length in cm through the surface metric: the CAD extractor's endpoint pr...
void torusParametricMetric(double majorRadius, double minorRadius, double phiTube, double &gUU, double &gUV, double &gVV)
Torus, (u, v) = (phiRing[rad], phiTube[rad]). The ring scale runs from R - r to R + r.
void cylinderParametricMetric(double radius, double &gUU, double &gUV, double &gVV)
Cylinder, (u, v) = (phi[rad], h[cm]).
void sphereParametricMetric(double radius, double theta, double &gUU, double &gUV, double &gVV)
bool LoadFlatCSG(const std::string &file, O2FlatCSG &solid)
Load a flat-CSG sidecar (flatcsg_*.bin, version 1) into solid; call CloseShape() after....
bool LoadFacetSolid(const std::string &file, o2::base::O2Tessellated &solid)
bool WriteFlatCSG(const std::string &file, const O2FlatCSG &solid)
bool LoadSurfaceSolid(const std::string &file, O2BVHSurfaceSolid &solid)
int32_t const char * file
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
One DNF cell: [first, first + count) of the halfspace array, intersected; volume is its own volume.
static PlanarBoundaryCurve makeBSpline(int splineDegree, std::vector< Point2D > splinePoles, std::vector< double > splineWeights, std::vector< double > splineKnots)
static Curve2D makeBSpline(int splineDegree, std::vector< Vec2 > splinePoles, std::vector< double > splineWeights, std::vector< double > splineKnots)
std::map< std::string, ID > expected