mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-08 13:01:52 +00:00
2848555235
APPROX_VERTICES / APPROX_EDGES for CalculateBoundingBox's approximation shortcut and MIN_SHIFT_CENTER_LENGTH_SQ for SmTemporaryBrepTransform. The FFI module derives its record and output lengths from named layouts, passes the op and kind codes as #[repr(i32)] discriminants, routes both fixture-B-rep entry points through one validated call, and owns the sentinel box (SEED_BOX), which it now hands to the shim instead of both sides repeating it. The runner names its status, no-entity and object kind codes. Outputs are unchanged (report identical). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
536 lines
18 KiB
C++
536 lines
18 KiB
C++
// SPDX-License-Identifier: Apache-2.0
|
|
// difftest shim for unit `query.brep`: the SM_API surface evaluation entry points
|
|
// SmApiEvaluateSurfacePoint, SmApiEvaluateSurfaceNormal and SmApiEvaluateSurfaceDerivatives
|
|
// (source/SM_API/src/SmApiSurfaces.cpp), called through the public API; the decimation
|
|
// attribute constructors and MakeCopy overrides (source/SMLib/inc/SmPolyDecimate.h,
|
|
// source/SMLib/src/SmPolyDecimate.cpp), whose protected data is reached through derived
|
|
// "peek" classes; and SmBrep::CalculateBoundingBox, CalculateTightBoundingBox,
|
|
// LockBoundingBox, UnLockBoundingBox and Point3DClassify (source/SMLib/src/SmBrep.cpp) on a
|
|
// real SmBrep
|
|
// built with the shared topology fixture (sc_topology_fixture::apply: unit
|
|
// topology.edgeuse_p1's B-rep block and traversal order, which the Rust side imports from
|
|
// that unit's export).
|
|
//
|
|
// The surface reader is a copy of the surface.surface_cache_p3 shim's (another translation
|
|
// unit). Layouts are documented in crates/solidcore-ffi/src/units/query_brep.rs, which
|
|
// validates every input.
|
|
#include "sc_shim.h"
|
|
#include "support/topology_fixture.h"
|
|
|
|
#include "StdAfx.h"
|
|
#include <SmApiGeneral.h>
|
|
#include <SmApiSurfaces.h>
|
|
#include <SmBSplineSurface.h>
|
|
#include <SmBrep.h>
|
|
#include <SmCacheMgr.h>
|
|
#include <SmContext.h>
|
|
#include <SmCurveBoundedSurface.h>
|
|
#include <SmExtent3d.h>
|
|
#include <SmEdge.h>
|
|
#include <SmFace.h>
|
|
#include <SmPointClass.h>
|
|
#include <SmRegion.h>
|
|
#include <SmVertex.h>
|
|
#include <SmExtent2d.h>
|
|
#include <SmNurbsSrf.h>
|
|
#include <SmPlane.h>
|
|
#include <SmPolyDecimate.h>
|
|
#include <SmSurface.h>
|
|
#include <SmTArray.h>
|
|
#include <SmVector2d.h>
|
|
#include <SmVector3d.h>
|
|
#include <nurbs.h>
|
|
|
|
#include <limits>
|
|
#include <vector>
|
|
|
|
#include "sc_sm.h"
|
|
|
|
using sc::put_vec;
|
|
|
|
namespace sc_query_brep
|
|
{
|
|
enum
|
|
{
|
|
OP_POINT = 0,
|
|
OP_NORMAL = 1,
|
|
OP_DERIVATIVES = 2,
|
|
};
|
|
|
|
struct Rd
|
|
{
|
|
const double* in;
|
|
int64_t at;
|
|
double num() { return in[at++]; }
|
|
int64_t idx() { return (int64_t)in[at++]; }
|
|
bool flag() { return in[at++] != 0.0; }
|
|
SmVector3d vec()
|
|
{
|
|
double x = num();
|
|
double y = num();
|
|
double z = num();
|
|
return SmVector3d(x, y, z);
|
|
}
|
|
SmExtent2d domain()
|
|
{
|
|
double a = num();
|
|
double b = num();
|
|
double c = num();
|
|
double d = num();
|
|
return SmExtent2d(a, b, c, d);
|
|
}
|
|
};
|
|
|
|
gw_SURFACE* read_nurb(Rd& rd)
|
|
{
|
|
gw_INDEX n = (gw_INDEX)rd.idx();
|
|
gw_INDEX m = (gw_INDEX)rd.idx();
|
|
gw_DEGREE p = (gw_DEGREE)rd.idx();
|
|
gw_DEGREE q = (gw_DEGREE)rd.idx();
|
|
gw_INDEX r = (gw_INDEX)rd.idx();
|
|
gw_INDEX s = (gw_INDEX)rd.idx();
|
|
gw_SURFACE* sur = sm_AllocateNurbSurface(n, m, p, q, r, s);
|
|
for (gw_INDEX i = 0; i <= n; i++)
|
|
for (gw_INDEX j = 0; j <= m; j++)
|
|
{
|
|
sur->net->Pw[i][j].x = rd.num();
|
|
sur->net->Pw[i][j].y = rd.num();
|
|
sur->net->Pw[i][j].z = rd.num();
|
|
sur->net->Pw[i][j].w = rd.num();
|
|
}
|
|
for (gw_INDEX i = 0; i <= r; i++)
|
|
sur->knu->U[i] = rd.num();
|
|
for (gw_INDEX i = 0; i <= s; i++)
|
|
sur->knv->U[i] = rd.num();
|
|
return sur;
|
|
}
|
|
|
|
// `oob form nurb`.
|
|
SmBSplineSurface* read_bspline(Rd& rd, const SmContext& ctx)
|
|
{
|
|
bool oob = rd.flag();
|
|
SmBSplineSurfaceForm form = (SmBSplineSurfaceForm)rd.idx();
|
|
SmBSplineSurface* s = new (ctx) SmBSplineSurface(read_nurb(rd), FALSE, NULL);
|
|
s->GetOutOfBoundsEnabled() = oob ? TRUE : FALSE;
|
|
s->SetBSplineSurfaceForm(form);
|
|
return s;
|
|
}
|
|
|
|
// A surface `kind ...`: 0 B-spline `oob form nurb`; 1 bounded plane `o x y sx sy D`;
|
|
// 2 curve-bounded surface (implicit outer, no boundary curves) over a B-spline block.
|
|
SmSurface* read_surface(Rd& rd, const SmContext& ctx)
|
|
{
|
|
int64_t kind = rd.idx();
|
|
if (kind == 1)
|
|
{
|
|
SmPoint3d o = rd.vec();
|
|
SmVector3d x = rd.vec();
|
|
SmVector3d y = rd.vec();
|
|
double sx = rd.num();
|
|
double sy = rd.num();
|
|
SmExtent2d d = rd.domain();
|
|
return new (ctx) SmPlane(o, x, y, SmVector2d(sx, sy), d, &ctx);
|
|
}
|
|
SmBSplineSurface* b = read_bspline(rd, ctx);
|
|
if (kind == 0)
|
|
return b;
|
|
// the curve-bounded surface owns (deletes) its basis
|
|
SmTArray<SmCurve*> c3d(ctx), cuv(ctx);
|
|
return new (ctx) SmCurveBoundedSurface(*b, &c3d, &cuv, TRUE);
|
|
}
|
|
|
|
// Peek classes: the decimation attributes' data is protected (SmPolyDecimate is a friend).
|
|
struct DecimatePeek : SmDecimateVertexAttr
|
|
{
|
|
ULONG& sort() { return m_lSortIndex; }
|
|
SmPolyVertexClass& vclass() { return m_eVertClass; }
|
|
double& distance() { return m_dVertexDistance; }
|
|
double& error() { return m_dMaxFaceError; }
|
|
SmVector3d& normal() { return m_vAveragePlaneNormal; }
|
|
};
|
|
|
|
struct QuadricVertexPeek : SmQuadricVertexAttr
|
|
{
|
|
SmVector3d& q(int i) { return m_Q[i]; }
|
|
SmVector3d& b() { return m_b; }
|
|
double& c() { return m_c; }
|
|
};
|
|
|
|
struct QuadricEdgePeek : SmQuadricEdgeAttr
|
|
{
|
|
SmPoint3d& point() { return m_vNewPoint; }
|
|
double& error() { return m_dError; }
|
|
ULONG& sort() { return m_lSortIndex; }
|
|
};
|
|
|
|
enum
|
|
{
|
|
KIND_DECIMATE_VERTEX = 0,
|
|
KIND_QUADRIC_VERTEX = 1,
|
|
KIND_QUADRIC_EDGE = 2,
|
|
};
|
|
|
|
// An ULONG as its exact 32-bit halves `hi lo`.
|
|
void put_ulong(std::vector<double>& o, ULONG v)
|
|
{
|
|
o.push_back((double)(v >> 32));
|
|
o.push_back((double)(v & 0xffffffffUL));
|
|
}
|
|
|
|
ULONG read_ulong(Rd& rd)
|
|
{
|
|
ULONG hi = (ULONG)rd.num();
|
|
ULONG lo = (ULONG)rd.num();
|
|
return (hi << 32) | lo;
|
|
}
|
|
|
|
// The data of a decimation attribute of kind `kind`: `sort(hi lo) class distance error N`,
|
|
// `Q0 Q1 Q2 b c`, or `P error sort(hi lo)` (the quadric edge sort index only when
|
|
// `sort_set`: it is uninitialised until set; else NaN NaN).
|
|
void put_data(std::vector<double>& o, int64_t kind, SmAttribute* a, bool sort_set)
|
|
{
|
|
if (kind == KIND_DECIMATE_VERTEX)
|
|
{
|
|
DecimatePeek* d = static_cast<DecimatePeek*>(static_cast<SmDecimateVertexAttr*>(a));
|
|
put_ulong(o, d->sort());
|
|
o.push_back((double)d->vclass());
|
|
o.push_back(d->distance());
|
|
o.push_back(d->error());
|
|
put_vec(o, d->normal());
|
|
}
|
|
else if (kind == KIND_QUADRIC_VERTEX)
|
|
{
|
|
QuadricVertexPeek* d = static_cast<QuadricVertexPeek*>(static_cast<SmQuadricVertexAttr*>(a));
|
|
for (int i = 0; i < 3; i++)
|
|
put_vec(o, d->q(i));
|
|
put_vec(o, d->b());
|
|
o.push_back(d->c());
|
|
}
|
|
else
|
|
{
|
|
QuadricEdgePeek* d = static_cast<QuadricEdgePeek*>(static_cast<SmQuadricEdgeAttr*>(a));
|
|
put_vec(o, d->point());
|
|
o.push_back(d->error());
|
|
if (sort_set)
|
|
put_ulong(o, d->sort());
|
|
else
|
|
{
|
|
o.push_back(std::numeric_limits<double>::quiet_NaN());
|
|
o.push_back(std::numeric_limits<double>::quiet_NaN());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sets the data of a decimation attribute from the record (layout in the ffi module):
|
|
// `class distance error N`, `Q0 Q1 Q2 b c` or `P error`, then for the decimate vertex and
|
|
// quadric edge attributes `sort_set sort(hi lo)`.
|
|
void set_data(Rd& rd, int64_t kind, SmAttribute* a, bool& sort_set)
|
|
{
|
|
if (kind == KIND_DECIMATE_VERTEX)
|
|
{
|
|
DecimatePeek* d = static_cast<DecimatePeek*>(static_cast<SmDecimateVertexAttr*>(a));
|
|
d->vclass() = (SmPolyVertexClass)rd.idx();
|
|
d->distance() = rd.num();
|
|
d->error() = rd.num();
|
|
d->normal() = rd.vec();
|
|
sort_set = rd.flag();
|
|
ULONG sort = read_ulong(rd);
|
|
if (sort_set)
|
|
d->sort() = sort;
|
|
}
|
|
else if (kind == KIND_QUADRIC_VERTEX)
|
|
{
|
|
QuadricVertexPeek* d = static_cast<QuadricVertexPeek*>(static_cast<SmQuadricVertexAttr*>(a));
|
|
for (int i = 0; i < 3; i++)
|
|
d->q(i) = rd.vec();
|
|
d->b() = rd.vec();
|
|
d->c() = rd.num();
|
|
}
|
|
else
|
|
{
|
|
QuadricEdgePeek* d = static_cast<QuadricEdgePeek*>(static_cast<SmQuadricEdgeAttr*>(a));
|
|
d->point() = rd.vec();
|
|
d->error() = rd.num();
|
|
sort_set = rd.flag();
|
|
ULONG sort = read_ulong(rd);
|
|
if (sort_set)
|
|
d->sort() = sort;
|
|
}
|
|
}
|
|
|
|
void put_attribute(std::vector<double>& o, int64_t kind, SmAttribute* a, bool sort_set)
|
|
{
|
|
put_ulong(o, a->GetAttributeID());
|
|
o.push_back((double)a->GetBehavior());
|
|
o.push_back((double)a->GetType());
|
|
put_data(o, kind, a, sort_set);
|
|
}
|
|
|
|
} // namespace sc_query_brep
|
|
|
|
// `id(hi lo) has_behavior behavior set [data]` for an attribute of class `kind`:
|
|
// constructs the attribute (with the default behaviour unless `has_behavior`), sets its
|
|
// data when `set`, copies it with MakeCopy and returns `id(hi lo) behavior type data` of
|
|
// the original, then of the copy.
|
|
SC_EXPORT int32_t sc_query_brep_attribute(int32_t kind, const double* in, int64_t n_in, double* out,
|
|
int64_t cap, int64_t* out_len)
|
|
{
|
|
using namespace sc_query_brep;
|
|
if (!in || n_in < 5)
|
|
return SC_ERR_ARG;
|
|
SC_TRY
|
|
const SmContext& ctx = *SmApiGetOrCreateContext();
|
|
Rd rd{in, 0};
|
|
ULONG id = read_ulong(rd);
|
|
bool has_behavior = rd.flag();
|
|
SmAttributeBehaviorType behavior = (SmAttributeBehaviorType)rd.idx();
|
|
bool set = rd.flag();
|
|
|
|
SmAttribute* a;
|
|
if (kind == KIND_DECIMATE_VERTEX)
|
|
a = has_behavior ? new (ctx) SmDecimateVertexAttr(id, behavior) : new (ctx) SmDecimateVertexAttr(id);
|
|
else if (kind == KIND_QUADRIC_VERTEX)
|
|
a = has_behavior ? new (ctx) SmQuadricVertexAttr(id, behavior) : new (ctx) SmQuadricVertexAttr(id);
|
|
else if (kind == KIND_QUADRIC_EDGE)
|
|
a = has_behavior ? new (ctx) SmQuadricEdgeAttr(id, behavior) : new (ctx) SmQuadricEdgeAttr(id);
|
|
else
|
|
return SC_ERR_ARG;
|
|
|
|
// the decimate vertex constructor sets its sort index; the quadric edge's is unset
|
|
bool sort_set = kind == KIND_DECIMATE_VERTEX;
|
|
if (set)
|
|
set_data(rd, kind, a, sort_set);
|
|
if (rd.at != n_in)
|
|
{
|
|
delete a;
|
|
return SC_ERR_ARG;
|
|
}
|
|
|
|
SmAttribute* c = a->MakeCopy(ctx);
|
|
std::vector<double> o;
|
|
put_attribute(o, kind, a, sort_set);
|
|
// every MakeCopy sets or keeps a defined sort index
|
|
put_attribute(o, kind, c, true);
|
|
delete c;
|
|
delete a;
|
|
return sc_copy_out(o.data(), (int64_t)o.size(), out, cap, out_len);
|
|
SC_CATCH
|
|
}
|
|
|
|
// `has_surface [S] u v P Du Dv`: the op's status, then P, Du and Dv as the entry point
|
|
// leaves them (the given sentinels where it does not write them).
|
|
SC_EXPORT int32_t sc_query_brep_evaluate(int32_t op, const double* in, int64_t n_in, double* out,
|
|
int64_t cap, int64_t* out_len)
|
|
{
|
|
using namespace sc_query_brep;
|
|
if (op < OP_POINT || op > OP_DERIVATIVES || !in || n_in < 12)
|
|
return SC_ERR_ARG;
|
|
SC_TRY
|
|
const SmContext& ctx = *SmApiGetOrCreateContext();
|
|
Rd rd{in, 0};
|
|
SmSurface* s = rd.flag() ? read_surface(rd, ctx) : NULL;
|
|
double u = rd.num();
|
|
double v = rd.num();
|
|
SmVector2d uv(u, v);
|
|
SmVector3d p = rd.vec();
|
|
SmVector3d du = rd.vec();
|
|
SmVector3d dv = rd.vec();
|
|
if (rd.at != n_in)
|
|
{
|
|
delete s;
|
|
return SC_ERR_ARG;
|
|
}
|
|
|
|
SmApiStatus r;
|
|
if (op == OP_POINT)
|
|
r = SmApiEvaluateSurfacePoint(s, uv, p);
|
|
else if (op == OP_NORMAL)
|
|
r = SmApiEvaluateSurfaceNormal(s, uv, p);
|
|
else
|
|
r = SmApiEvaluateSurfaceDerivatives(s, uv, p, du, dv);
|
|
delete s;
|
|
|
|
std::vector<double> o;
|
|
o.push_back(r == SM_SUCCESS ? 0.0 : (double)r);
|
|
put_vec(o, p);
|
|
put_vec(o, du);
|
|
put_vec(o, dv);
|
|
return sc_copy_out(o.data(), (int64_t)o.size(), out, cap, out_len);
|
|
SC_CATCH
|
|
}
|
|
|
|
namespace sc_query_brep
|
|
{
|
|
enum
|
|
{
|
|
STEP_BOX = 0,
|
|
STEP_TIGHT = 1,
|
|
STEP_LOCK = 2,
|
|
STEP_UNLOCK = 3,
|
|
};
|
|
|
|
// Appends the status and `min max` of a box seeded with `seed` (`min max`).
|
|
template <typename F> void put_box(std::vector<double>& o, const double* seed, F call)
|
|
{
|
|
SmExtent3d box;
|
|
box.SetMinMax(SmPoint3d(seed[0], seed[1], seed[2]), SmPoint3d(seed[3], seed[4], seed[5]));
|
|
SmStatus s = call(box);
|
|
o.push_back(s == SM_SUCCESS ? 0.0 : (double)s);
|
|
SmPoint3d lo = box.GetMin(), hi = box.GetMax();
|
|
o.insert(o.end(), {lo.x, lo.y, lo.z, hi.x, hi.y, hi.z});
|
|
}
|
|
|
|
// Runs `seed n` then `n` steps `kind a b c defaults` on the B-rep (layouts in the ffi
|
|
// module).
|
|
int32_t run_steps(const double* args, int64_t n_args, SmBrep& brep, std::vector<double>& o)
|
|
{
|
|
const int64_t SEED_LEN = 6, STEP_LEN = 5;
|
|
if (n_args < SEED_LEN + 1)
|
|
return SC_ERR_ARG;
|
|
const double* seed = args;
|
|
int64_t n = (int64_t)args[SEED_LEN];
|
|
if (n < 0 || n_args != SEED_LEN + 1 + STEP_LEN * n)
|
|
return SC_ERR_ARG;
|
|
for (int64_t i = 0; i < n; i++)
|
|
{
|
|
const double* a = args + SEED_LEN + 1 + STEP_LEN * i;
|
|
int64_t kind = (int64_t)a[0];
|
|
SmBoolean x = a[1] != 0.0 ? TRUE : FALSE;
|
|
SmBoolean y = a[2] != 0.0 ? TRUE : FALSE;
|
|
SmBoolean z = a[3] != 0.0 ? TRUE : FALSE;
|
|
bool defaults = a[4] != 0.0;
|
|
if (kind == STEP_BOX)
|
|
put_box(o, seed, [&](SmExtent3d& b) {
|
|
return defaults ? brep.CalculateBoundingBox(b) : brep.CalculateBoundingBox(b, x, y, z);
|
|
});
|
|
else if (kind == STEP_TIGHT)
|
|
put_box(o, seed, [&](SmExtent3d& b) { return brep.CalculateTightBoundingBox(b); });
|
|
else if (kind == STEP_LOCK)
|
|
{
|
|
SmStatus s = defaults ? brep.LockBoundingBox() : brep.LockBoundingBox(x);
|
|
o.push_back(s == SM_SUCCESS ? 0.0 : (double)s);
|
|
}
|
|
else if (kind == STEP_UNLOCK)
|
|
{
|
|
brep.UnLockBoundingBox();
|
|
o.push_back(0.0);
|
|
}
|
|
else
|
|
return SC_ERR_ARG;
|
|
}
|
|
return 0;
|
|
}
|
|
} // namespace sc_query_brep
|
|
|
|
// Builds the B-rep of `path` / `block` and runs the box steps `args` on it; the output is
|
|
// each step's values in order.
|
|
SC_EXPORT int32_t sc_query_brep_box(const char* path, const double* block, int64_t n_block,
|
|
const double* args, int64_t n_args, double* out, int64_t cap,
|
|
int64_t* out_len)
|
|
{
|
|
if (path == nullptr || block == nullptr || n_block < 1 || args == nullptr || n_args < 1 ||
|
|
out_len == nullptr)
|
|
return SC_ERR_ARG;
|
|
SC_TRY
|
|
std::vector<double> o;
|
|
int32_t rc = sc_topology_fixture::apply(path, block, n_block, [&](const sc_topology_fixture::View& g) -> int32_t {
|
|
// the trimmed surface caches a file read leaves on face surfaces (the port has
|
|
// no object caches)
|
|
for (SmFace* f : g.faces)
|
|
{
|
|
SmSurface* srf = f->GetSurface();
|
|
if (srf == nullptr)
|
|
return SC_ERR_ARG; // SmFace::CalculateBoundingBox dereferences it unchecked
|
|
if (SmCacheMgr::GetObjectCache(SM_OC_TRIMSRF, srf) != nullptr)
|
|
SmCacheMgr::DeleteObjectsCache(SM_OC_TRIMSRF, srf);
|
|
}
|
|
return sc_query_brep::run_steps(args, n_args, g.brep, o);
|
|
});
|
|
if (rc != 0)
|
|
return rc;
|
|
return sc_copy_out(o.data(), (int64_t)o.size(), out, cap, out_len);
|
|
SC_CATCH
|
|
}
|
|
|
|
namespace sc_query_brep
|
|
{
|
|
template <typename T> int64_t index_of(const std::vector<T*>& v, const void* p)
|
|
{
|
|
for (size_t i = 0; i < v.size(); i++)
|
|
if ((const void*)v[i] == p)
|
|
return (int64_t)i;
|
|
return -1;
|
|
}
|
|
|
|
// `kind index` of a classification object: 1 face, 2 edge, 3 vertex, 4 region (traversal
|
|
// index), `0 -1` for none, `-3 -1` for anything else.
|
|
void put_object(std::vector<double>& o, const sc_topology_fixture::View& g, const SmObject* p)
|
|
{
|
|
int64_t kind = -3, index = -1;
|
|
if (p == nullptr)
|
|
kind = 0;
|
|
else if (p->IsKindOf(SmFace_TYPE))
|
|
kind = 1, index = index_of(g.faces, p);
|
|
else if (p->IsKindOf(SmEdge_TYPE))
|
|
kind = 2, index = index_of(g.edges, p);
|
|
else if (p->IsKindOf(SmVertex_TYPE))
|
|
kind = 3, index = index_of(g.vertices, p);
|
|
else if (p->IsKindOf(SmRegion_TYPE))
|
|
kind = 4, index = index_of(g.regions, p);
|
|
o.push_back((double)kind);
|
|
o.push_back((double)index);
|
|
}
|
|
|
|
// `class kind index gap src_tol presnap tparam u v param_set face_kind face_index`
|
|
void put_pc(std::vector<double>& o, const sc_topology_fixture::View& g, const SmPointClassification& pc)
|
|
{
|
|
o.push_back((double)pc.GetPointClass());
|
|
put_object(o, g, pc.GetObject());
|
|
o.push_back(pc.GetGap3d());
|
|
o.push_back((double)pc.GetTolerance());
|
|
o.push_back(pc.GetPreSnapParam());
|
|
o.push_back(pc.GetTParam());
|
|
SmPoint2d uv = pc.GetUVParam();
|
|
o.push_back(uv.x);
|
|
o.push_back(uv.y);
|
|
o.push_back(pc.AreParametersSet() ? 1.0 : 0.0);
|
|
put_object(o, g, pc.GetFace());
|
|
}
|
|
} // namespace sc_query_brep
|
|
|
|
// Builds the B-rep of `path` / `block` and classifies `x y z` with zone tolerance `tol`
|
|
// (`do_bnd`: bDoBoundaryIntersections) into a classification constructed with that
|
|
// tolerance; the output is the status and the classification (see put_pc).
|
|
SC_EXPORT int32_t sc_query_brep_classify(const char* path, const double* block, int64_t n_block,
|
|
const double* args, int64_t n_args, double* out,
|
|
int64_t cap, int64_t* out_len)
|
|
{
|
|
if (path == nullptr || block == nullptr || n_block < 1 || args == nullptr || n_args != 5 ||
|
|
out_len == nullptr)
|
|
return SC_ERR_ARG;
|
|
SC_TRY
|
|
std::vector<double> o;
|
|
int32_t rc = sc_topology_fixture::apply(path, block, n_block, [&](const sc_topology_fixture::View& g) -> int32_t {
|
|
for (SmFace* f : g.faces)
|
|
{
|
|
SmSurface* srf = f->GetSurface();
|
|
if (srf == nullptr)
|
|
return SC_ERR_ARG; // the face queries dereference it unchecked
|
|
if (SmCacheMgr::GetObjectCache(SM_OC_TRIMSRF, srf) != nullptr)
|
|
SmCacheMgr::DeleteObjectsCache(SM_OC_TRIMSRF, srf);
|
|
}
|
|
SmPoint3d p(args[0], args[1], args[2]);
|
|
SmZoneTol3d tol(args[3]);
|
|
SmBoolean do_bnd = args[4] != 0.0 ? TRUE : FALSE;
|
|
SmPointClassification pc(tol, g.brep.GetContext());
|
|
SmStatus s = g.brep.Point3DClassify(p, tol, do_bnd, pc);
|
|
o.push_back(s == SM_SUCCESS ? 0.0 : (double)s);
|
|
sc_query_brep::put_pc(o, g, pc);
|
|
return 0;
|
|
});
|
|
if (rc != 0)
|
|
return rc;
|
|
return sc_copy_out(o.data(), (int64_t)o.size(), out, cap, out_len);
|
|
SC_CATCH
|
|
}
|