// SPDX-License-Identifier: Apache-2.0 // difftest shim for unit `query.poly_properties`. // Builds an SmPolyBrep (one region, one shell, closed loops, radial rings set directly, as // query_poly.cpp does) and runs one of SmApiPolyBrepIsManifoldSolid, // SmApiPolyBrepComputeVolume, SmApiPolyBrepComputeMassProperties // (source/SM_API/src/SmApiPolygons.cpp), SmPolyBrep::ComputeProperties or // SmPolyFace::ComputeProperties of every face (source/SMLib/src/SmPoly.cpp). // // One entry point, sc_query_poly_properties_eval(in, n_in, out, cap, out_len). Block: // op which origin[3] density brep_tol // nv (x y z tol)[nv] // nf (ftol has_n n[3] nl (etol k v[k])[nl])[nf] // ng (k e[k])[ng] // Edges are numbered in creation order; every loop is closed (FinishPolyEdgeLoop). // crates/solidcore-ffi/src/units/query_poly_properties.rs validates every index. // Output: `status` then, on success, by op: // 0 IsManifoldSolid: flag // 1 ComputeVolume: volume // 2 ComputeMassProperties: area volume mass centroid[3] moments[3] products[3] // 3 SmPolyBrep::ComputeProperties(origin, which): area volume bary[3] m0[3] m1[3] // 4 per face (GetPolyFaces order): status, then on success the op-3 record #include "sc_shim.h" #include "StdAfx.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Set the radial rings and the vertex list directly (as query_poly.cpp): open the access // of this header only. #define protected public #define private public #include #undef private #undef protected #include #include #include namespace { struct Rd { const double* in; int64_t at; double num() { return in[at++]; } int64_t idx() { return (int64_t)in[at++]; } SmVector3d vec() { double x = num(); double y = num(); double z = num(); SmVector3d v; v.x = x; v.y = y; v.z = z; return v; } }; void put(std::vector& o, const SmVector3d& v) { o.push_back(v.x); o.push_back(v.y); o.push_back(v.z); } double st(long s) { return s == SM_SUCCESS ? 0.0 : (double)s; } void put_props(std::vector& o, double area, double volume, const SmVector3d& bary, const SmVector3d m[2]) { o.push_back(area); o.push_back(volume); put(o, bary); put(o, m[0]); put(o, m[1]); } } // namespace SC_EXPORT int32_t sc_query_poly_properties_eval(const double* input, int64_t n, double* out, int64_t cap, int64_t* out_len) { SC_TRY (void)n; SmContext ctx; Rd rd{input, 0}; int64_t op = rd.idx(); SmMassPropertiesType which = (SmMassPropertiesType)rd.idx(); SmPoint3d origin = rd.vec(); double density = rd.num(); double tol = rd.num(); SmPolyBrep* b = new (ctx) SmPolyBrep(tol); SmPolyRegion* region = new (b) SmPolyRegion(b); SmPolyShell* shell = new (b) SmPolyShell(region); std::vector vertices; int64_t nv = rd.idx(); for (int64_t i = 0; i < nv; ++i) { SmVector3d p = rd.vec(); double t = rd.num(); SmPolyVertex* v = new (b) SmPolyVertex(p, t); b->m_pPolyVertexListHead->PostInsert(v); vertices.push_back(v); } std::vector edges; int64_t nf = rd.idx(); for (int64_t i = 0; i < nf; ++i) { double ftol = rd.num(); bool has_n = rd.num() != 0.0; SmVector3d nrm = rd.vec(); SmPolyFace* f = new (b) SmPolyFace(ftol, NULL, NULL, shell, has_n ? &nrm : NULL); int64_t nl = rd.idx(); for (int64_t l = 0; l < nl; ++l) { double etol = rd.num(); int64_t k = rd.idx(); std::vector vs; for (int64_t j = 0; j < k; ++j) vs.push_back(vertices[rd.idx()]); SmPolyLoop* lp = NULL; f->StartPolyEdgeLoop(lp); for (int64_t j = 0; j < k; ++j) { SmPolyVertex* v0 = vs[j]; SmPolyVertex* v1 = vs[(j + 1) % k]; SmPolyEdge* e = NULL; lp->AddPolyEdge(etol, v0->GetPoint(), v1->GetPoint(), v0, NULL, b, e); edges.push_back(e); } lp->FinishPolyEdgeLoop(b); } } int64_t ng = rd.idx(); for (int64_t g = 0; g < ng; ++g) { int64_t k = rd.idx(); std::vector es; for (int64_t j = 0; j < k; ++j) es.push_back(edges[rd.idx()]); for (int64_t j = 0; j < k; ++j) { es[j]->m_pNextRadialE = es[(j + 1) % k]; es[j]->m_pLastRadialE = es[(j + k - 1) % k]; } } std::vector o; if (op == 0) { SmBoolean manifold = FALSE; long s = SmApiPolyBrepIsManifoldSolid(b, manifold); o.push_back(st(s)); if (s == SM_SUCCESS) o.push_back(manifold ? 1.0 : 0.0); } else if (op == 1) { double volume = 0.0; long s = SmApiPolyBrepComputeVolume(b, volume); o.push_back(st(s)); if (s == SM_SUCCESS) o.push_back(volume); } else if (op == 2) { double area = 0.0, volume = 0.0, mass = 0.0; SmPoint3d centroid; SmVector3d moments, products; long s = SmApiPolyBrepComputeMassProperties(b, density, origin, area, volume, mass, centroid, moments, products); o.push_back(st(s)); if (s == SM_SUCCESS) { o.push_back(area); o.push_back(volume); o.push_back(mass); put(o, centroid); put(o, moments); put(o, products); } } else if (op == 3) { double area = 0.0, volume = 0.0; SmPoint3d bary; SmVector3d m[2]; SmStatus s = b->ComputeProperties(origin, area, volume, bary, m, which); o.push_back(st(s)); if (s == SM_SUCCESS) put_props(o, area, volume, bary, m); } else { SmTArray faces; b->GetPolyFaces(faces); o.push_back(0.0); o.push_back((double)faces.GetSize()); for (ULONG i = 0; i < faces.GetSize(); ++i) { double area = 0.0, volume = 0.0; SmPoint3d bary; SmVector3d m[2]; SmStatus s = faces[i]->ComputeProperties(origin, area, volume, bary, m, which); o.push_back(st(s)); if (s == SM_SUCCESS) put_props(o, area, volume, bary, m); } } delete b; return sc_copy_out(o.data(), (int64_t)o.size(), out, cap, out_len); SC_CATCH }