// SPDX-License-Identifier: Apache-2.0 // difftest shim for unit `surface.surface_p6`: the SmSurface members owned by the unit // (source/SMLib/src/SmSurface.cpp, source/SMLib/inc/SmSurface.h), called through `SmSurface*` // on SmBSplineSurface, SmPlane, SmCurveBoundedSurface and SmSurfOfRevolution objects // (virtual dispatch as upstream): CalculateContinuities, CreateNaturalUVTrimCurves, // SmDerivSurfDefinition::GetSampleValues, LocalCurveIntersect, SimpleCoincidenceChecker, // ClassifyIntersectingRangeSolution, SmSSGlobalSolver::IdenticalSolutions and sm_SCLocalSolve. // // SmSSGlobalSolver and the static functions of SmSurface.cpp cannot be linked against, so the // code exercised here is a VERBATIM copy of upstream SmSurface.cpp (commit c9c5979) inside the // namespace sc_srf_p6 (line ranges noted at each block): sm_CCLocalSolve and // sm_PassSCConvergenceTest as called, and IdenticalSolutions on a class holding the members it // reads (m_pSurf1, m_pSurf2, m_d3dTolerance of its SmGlobalSolver base). sm_SCLocalSolve takes // what it reads from its nodes and patch instead of them (lines marked ADAPTED): the surface to // evaluate (sm_GetSurfaceToEvaluate), the patch surface (mBA_pSurface) and the node boxes; its // call of sm_SpLocalSolve uses the shared verbatim surface_p5 reference body, // with the same resolved surface as the Rust path. // // One entry point, sc_surface_surface_p6_eval(op, in, n_in, out, cap, out_len). Layouts are // documented in crates/solidcore-ffi/src/units/surface_surface_p6.rs, which validates every // input. #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 #include #include #include #include #include "sc_sm.h" using sc::put_vec; namespace sc_srf_p6 { // clang-format off #include "surface_sp_local_solve.hpp" // ---- verbatim: SmSurface.cpp lines 3826-3940: sm_CCLocalSolve static SmStatus sm_CCLocalSolve (const SmCurve & crCurve1, const SmExtent1d & crInterval1, SmContinuityType aeConts1[2], const SmCurve & crCurve2, const SmExtent1d & crInterval2, SmContinuityType aeConts2[2], SmSolverOperationType & eSolverOperation, double d3dTolerance, SmSolutionArray & rSolutions) { rSolutions.ReSet(); SM_ASSERT(eSolverOperation == SM_SO_MINIMIZE || eSolverOperation == SM_SO_MAXIMIZE); SmBoolean bFoundAnswer; SmSolution sSolution; sSolution.m_lNumVariables = 2; sSolution.m_eSolutionType = SM_ST_SINGLE_VALUE; // If we have a total discontinuity (i.e. end of curve) // then we always test. If we have a derivative // discontinuity then we just test the ones on the left // side - otherwise we would do each point two times. SmPoint3d sPnt; SmSolution sSol; if (aeConts1[0] <= SM_CT_C0) { SER(crCurve1.EvaluatePoint(crInterval1.GetMin(),sPnt)); SER(crCurve2.LocalPointSolve(crInterval2,eSolverOperation,sPnt, NULL,NULL,NULL,crInterval2.Evaluate(0.5),bFoundAnswer,sSol)); if (bFoundAnswer) { sSol.m_lNumVariables = 2; sSol.m_vStart[1] = sSol.m_vStart[0]; sSol.m_vStart[0] = crInterval1.GetMin(); rSolutions.Add(sSol); } } if (aeConts1[1] <= SM_CT_DISCONTINUOUS) { SER(crCurve1.EvaluatePoint(crInterval1.GetMax(),sPnt)); SER(crCurve2.LocalPointSolve(crInterval2,eSolverOperation,sPnt, NULL,NULL,NULL,crInterval2.Evaluate(0.5),bFoundAnswer,sSol)); if (bFoundAnswer) { sSol.m_lNumVariables = 2; sSol.m_vStart[1] = sSol.m_vStart[0]; sSol.m_vStart[0] = crInterval1.GetMax(); rSolutions.Add(sSol); } } if (aeConts2[0] <= SM_CT_C0) { SER(crCurve2.EvaluatePoint(crInterval2.GetMin(),sPnt)); SER(crCurve1.LocalPointSolve(crInterval1,eSolverOperation,sPnt, NULL,NULL,NULL,crInterval1.Evaluate(0.5),bFoundAnswer,sSol)); if (bFoundAnswer) { sSol.m_lNumVariables = 2; sSol.m_vStart[1] = crInterval2.GetMin(); rSolutions.Add(sSol); } } if (aeConts2[1] <= SM_CT_DISCONTINUOUS) { SER(crCurve2.EvaluatePoint(crInterval2.GetMax(),sPnt)); SER(crCurve1.LocalPointSolve(crInterval1,eSolverOperation,sPnt, NULL,NULL,NULL,crInterval1.Evaluate(0.5),bFoundAnswer,sSol)); if (bFoundAnswer) { sSol.m_lNumVariables = 2; sSol.m_vStart[1] = crInterval2.GetMax(); rSolutions.Add(sSol); } } double daGuess1[4], daGuess2[4]; ULONG lNumGuess = 0; if (lNumGuess == 0) { // Take midpoint of interval for guess. lNumGuess = 1; daGuess1[0] = crInterval1.Evaluate(0.5); daGuess2[0] = crInterval2.Evaluate(0.5); } SmSolverOperationType eLocalSolverOp = eSolverOperation; for (ULONG i=0; i SM_EFF_ZERO * dScale || smos_Fabs(sDV.Dot(sDiff)) > SM_EFF_ZERO * dScale || smos_Fabs(sPV[1].Dot(sDiff)) > SM_EFF_ZERO * dScale) { sDiff.Unitize(); if (sDU.LengthSquared() > SM_EFF_ZERO_SQ) { sDU.Unitize(); if (smos_Fabs(sDU.Dot(sDiff)) > SM_EFF_ZERO) { return FALSE; } } if (sDV.LengthSquared() > SM_EFF_ZERO_SQ) { sDV.Unitize(); if (smos_Fabs(sDV.Dot(sDiff)) > SM_EFF_ZERO) { return FALSE; } } if (sPV[1].LengthSquared() > SM_EFF_ZERO_SQ) { sPV[1].Unitize(); if (smos_Fabs(sPV[1].Dot(sDiff)) > SM_EFF_ZERO) { return FALSE; } } } return TRUE; } // end sm_PassSCConvergenceTest // ---- end verbatim // ---- verbatim (ADAPTED lines marked): SmSurface.cpp lines 4812-5129: sm_SCLocalSolve static SmStatus sm_SCLocalSolve (const SmSurface * pSrfEvalArg, // ADAPTED: in : sm_GetSurfaceToEvaluate(pSurfaceNode, ..) const SmSurface & sBSSArg, // ADAPTED: in : *pBezPatch->mBA_pSurface const SmExtent3d & crSurfaceNodeBox, // ADAPTED: in : pSurfaceNode->m_sBBox const SmExtent2d & crUVDomain, // in : SmContinuityType aeUConts[2], // in : SmContinuityType aeVConts[2], // in : const SmExtent3d * pCurveNodeBox, // ADAPTED: in : pCurveNode ? &pCurveNode->m_sBBox : NULL const SmCurve & crCurve, // in : const SmExtent1d & crInterval, // in : SmContinuityType aeTConts[2], // in : double d3dTolerance, // in : const SmVector3d * cpOptVectors, // in : SmSolverOperationType & eSolverOperation, // in : SmBoolean bSkipNormalize, // in : SmBoolean bProcessBoundaryCurves, // in : double & rdBestAnswerSoFarSq, // NotUsed: out: SmSolutionArray & rSolutions) // out: { SM_REF1(rdBestAnswerSoFarSq) ; // check input SM_ASSERT( eSolverOperation == SM_SO_MINIMIZE || eSolverOperation == SM_SO_MAXIMIZE || eSolverOperation == SM_SO_3D_SIGNED_DIRECTED_MINIMIZE || eSolverOperation == SM_SO_NORMALIZE); // locals //const SmSurface * pSurf = sm_GetOriginalSurface(*pSurfaceNode); //const SmContext * pContext = pSurf->GetContext(); const SmSurface &sBSS = sBSSArg ; // ADAPTED const SmSurface *pSrfEval = pSrfEvalArg; // ADAPTED // for two passes for (ULONG j=0; j<2; j++) { SmSolution aSols[10]; SmSolutionArray sSolutions(10,aSols); // Handle curve discontinuities only for min and max if ( eSolverOperation != SM_SO_MAXIMIZE && eSolverOperation != SM_SO_MINIMIZE) continue; if ( aeTConts[j] <= SM_CT_C0 ) { // following line prevents multiple solves for points inside curve. if ( j==1 && aeTConts[j] != SM_CT_DISCONTINUOUS ) continue; double dT = ( j == 0 ) ? crInterval.GetMin() : crInterval.GetMax(); SmPoint3d sPnt; SER( crCurve.EvaluatePoint( dT, sPnt )); // ADAPTED: node/patch resolution supplies pSrfEval, as above. SER( sm_SpLocalSolve( pSrfEval, crUVDomain, aeUConts, aeVConts, sPnt, d3dTolerance, eSolverOperation, TRUE, bProcessBoundaryCurves, sSolutions )); for ( ULONG k=0; kGetSize().Length(); // ADAPTED // See if we need to obtain better start/guess point // when one bounding box is much larger than the other if ( dSurfBoxSize > 3.0*dCurveBoxSize ) { // Drop point from center of curve to surface SmSolution sSolution; SmBoolean bFoundAnswer; SmPoint3d sCurvePnt, sSurfPnt; SER( crCurve.EvaluatePoint( crInterval.Evaluate(0.5), sCurvePnt )); SER( sBSS.LocalPointSolve( crUVDomain, SM_SO_MINIMIZE, sCurvePnt, sUVGuesses[0], bFoundAnswer, sSolution )); if ( bFoundAnswer ) { // Drop point back to curve & // replace sUVGuess[0], sTGuesses[0] with values sUVGuesses[0] = SmPoint2d( sSolution.m_vStart[0], sSolution.m_vStart[1] ); SER( sBSS.EvaluatePoint( sUVGuesses[0], sSurfPnt )); SER( crCurve.LocalPointSolve( crInterval, SM_SO_MINIMIZE, sSurfPnt, NULL, NULL, NULL, sTGuesses[0], bFoundAnswer, sSolution )); if ( bFoundAnswer ) { sTGuesses[0] = sSolution.m_vStart[0]; } } } if ( dCurveBoxSize > 3.0*dSurfBoxSize ) { // Drop point from center of surface to curve SmSolution sSolution; SmBoolean bFoundAnswer; SmPoint3d sCurvePnt, sSurfPnt; SER( sBSS.EvaluatePoint(crUVDomain.Evaluate(0.5,0.5),sSurfPnt)); SER( crCurve.LocalPointSolve( crInterval, SM_SO_MINIMIZE, sSurfPnt, NULL, NULL, NULL, sTGuesses[0], bFoundAnswer, sSolution )); if ( bFoundAnswer ) { // Drop point back to surface sTGuesses[0] = sSolution.m_vStart[0]; SER( crCurve.EvaluatePoint( sTGuesses[0], sCurvePnt )); SER( sBSS.LocalPointSolve( crUVDomain, SM_SO_MINIMIZE, sCurvePnt, sUVGuesses[0], bFoundAnswer, sSolution )); if ( bFoundAnswer ) { sUVGuesses[0] = SmPoint2d( sSolution.m_vStart[0], sSolution.m_vStart[1] ); } } } } for (ULONG i=0; iLocalCurveSolve( crUVDomain, crCurve, crInterval, eSolverOperation, d3dTolerance, NULL, cpOptVectors, sUVGuesses[i], sTGuesses[i], bFoundAnswer, sSolution )); if ( bFoundAnswer && eSolverOperation != SM_SO_3D_SIGNED_DIRECTED_MINIMIZE ) { SmPoint2d sUV( sSolution.m_vStart[1], sSolution.m_vStart[2] ); if ( !sm_PassSCConvergenceTest( *pSrfEval, sUV, crCurve, sSolution.m_vStart[0] )) { bFoundAnswer = FALSE; } } if ( bFoundAnswer ) { sSolution.m_lNumVariables = 3; rSolutions.Add(sSolution); } } // For each guess return SM_SUCCESS; } // end sm_SCLocalSolve // ---- end verbatim // ---- verbatim (class reduced to the members IdenticalSolutions reads): SmSurface.cpp lines // 20910-20938 (class SmSSGlobalSolver) and 21522-21657 (IdenticalSolutions) class SmSSGlobalSolver : public SmGlobalSolver { public: const SmSurface * m_pSurf1; // surface1 being solved for const SmSurface * m_pSurf2; // surface2 being solved for SmSSGlobalSolver(const SmSurface * pSurf1, const SmSurface * pSurf2, double d3dTolerance) // ADAPTED : SmGlobalSolver(), m_pSurf1(pSurf1), m_pSurf2(pSurf2) { m_d3dTolerance = d3dTolerance; } // return TRUE when two solutions are identical virtual SmSolutionPairType IdenticalSolutions(const SmSolution & crSol1, const SmSolution & crSol2, const SmSolution *&pPreferredSol) const; } ; // end class SmSSGlobalSolver SmSolutionPairType SmSSGlobalSolver::IdenticalSolutions // rtn: oneof SM_SP_IDENTICAL // SM_SP_DIFFCOUNTS // SM_SP_DIFFOBJECTS // SM_SP_DIFFPARAMETERS (const SmSolution & crSol1, // in : 1st target solution const SmSolution & crSol2, // in : 2nd target solution const SmSolution *&pPreferredSol) // out: When identical, set to the preferred solution or NULL for none. // NULL to ignore, default:[NULL] const { // init output pPreferredSol = NULL ; // If the parent thinks they're identical, then they are. SmSolutionPairType eSPType = SmGlobalSolver::IdenticalSolutions( crSol1, crSol2, pPreferredSol ) ; if(SM_SP_IDENTICAL == eSPType) { return SM_SP_IDENTICAL; } if(SM_SP_DIFFPARAMETERS == eSPType) { if( crSol1.m_eSolutionType == SM_ST_SINGLE_VALUE && crSol2.m_eSolutionType == SM_ST_SINGLE_VALUE) { // At a singularity, the same 3d point can have different uv values. SmPoint2d sUV1A( crSol1.m_vStart[1], crSol1.m_vStart[2] ); SmPoint2d sUV1B( crSol2.m_vStart[1], crSol2.m_vStart[2] ); SmPoint2d sUV2A( crSol1.m_vStart[3], crSol1.m_vStart[4] ); SmPoint2d sUV2B( crSol2.m_vStart[3], crSol2.m_vStart[4] ); // Check positions. SmPoint3d sPt1A, sPt1B, sPt2A, sPt2B; m_pSurf1->EvaluatePoint( sUV1A, sPt1A ); m_pSurf1->EvaluatePoint( sUV1B, sPt1B ); m_pSurf2->EvaluatePoint( sUV2A, sPt2A ); m_pSurf2->EvaluatePoint( sUV2B, sPt2B ); double dTol = m_d3dTolerance; // untested: see how it works in practice if( !sPt1A.CloserThan( dTol, sPt2A ) || !sPt1A.CloserThan( dTol, sPt2B ) || !sPt1B.CloserThan( dTol, sPt2A ) || !sPt1B.CloserThan( dTol, sPt2B ) ) { return SM_SP_DIFFPARAMETERS; } // 3d points are the same. Need to check seams and poles. // Check poles first, it's a cheaper check. // If either is nonsingular, they're distinct. // Surface1 - both solutions are on singularities SmSurfParamType eSingDir; SmBoolean bSurf1Singular = ( m_pSurf1->IsSingularity( sUV1A, eSingDir ) && m_pSurf1->IsSingularity( sUV1B, eSingDir )) ; // Surface2 - both solutions are on singularities SmBoolean bSurf2Singular = ( m_pSurf2->IsSingularity( sUV2A, eSingDir ) && m_pSurf2->IsSingularity( sUV2B, eSingDir )) ; // when neither Surf1 nor Surf2 solutions are on a singularity if( !bSurf1Singular && !bSurf2Singular) { return SM_SP_DIFFPARAMETERS; } SmBoolean bASol1OnSeam = m_pSurf1->IsOnSeam( sUV1A ) || m_pSurf2->IsOnSeam( sUV2A ) ; SmBoolean bASol2OnSeam = m_pSurf1->IsOnSeam( sUV1B ) || m_pSurf2->IsOnSeam( sUV2B ) ; if( bASol1OnSeam && !bASol2OnSeam) { pPreferredSol = &crSol1 ; return SM_SP_IDENTICAL ; } if(!bASol1OnSeam && bASol2OnSeam) { pPreferredSol = &crSol2 ; return SM_SP_IDENTICAL ; } if(!bASol1OnSeam && !bASol2OnSeam) { pPreferredSol = (crSol1.m_vStart.m_dSolutionValue < crSol2.m_vStart.m_dSolutionValue) ? &crSol1 : &crSol2 ; return SM_SP_IDENTICAL ; } } } // Identical positions, at a pole on a seam: // Call them distinct points. return eSPType; } // end SmSSGlobalSolver::IdenticalSolutions // ---- end verbatim // clang-format on } // namespace sc_srf_p6 namespace { enum : int32_t { OP_CONT = 0, OP_TRIM = 1, OP_SAMPLE = 2, OP_LCI = 3, OP_SCC = 4, OP_CLASSIFY = 5, OP_SSID = 6, OP_SCLS = 7, }; 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; } SmBoolean bflag() { return flag() ? TRUE : FALSE; } SmVector3d vec() { double x = num(); double y = num(); double z = num(); return SmVector3d(x, y, z); } SmPoint2d uv() { double u = num(); double v = num(); return SmPoint2d(u, v); } SmExtent1d ivl() { double a = num(); double b = num(); return SmExtent1d(a, b); } SmExtent2d dom() { double u0 = num(); double v0 = num(); double u1 = num(); double v1 = num(); return SmExtent2d(SmPoint2d(u0, v0), SmPoint2d(u1, v1)); } SmExtent3d box() { SmPoint3d a = vec(); SmPoint3d b = vec(); return SmExtent3d(a, b); } }; double st(SmStatus s) { return s == SM_SUCCESS ? 0.0 : (double)s; } double flg(SmBoolean b) { return b ? 1.0 : 0.0; } const SmContext& the_context() { static SmContext* p = new SmContext(); return *p; } SmBSplineCurve* read_bspline_curve(Rd& rd, const SmContext& ctx) { ULONG dim = (ULONG)rd.idx(); gw_INDEX n = (gw_INDEX)rd.idx(); gw_DEGREE p = (gw_DEGREE)rd.idx(); gw_INDEX m = (gw_INDEX)rd.idx(); gw_CURVE* cur = sm_AllocateNurbCurve(n, p, m); for (gw_INDEX i = 0; i <= n; i++) { cur->pol->Pw[i].x = rd.num(); cur->pol->Pw[i].y = rd.num(); cur->pol->Pw[i].z = rd.num(); cur->pol->Pw[i].w = rd.num(); } for (gw_INDEX i = 0; i <= m; i++) cur->knt->U[i] = rd.num(); return new (ctx) SmBSplineCurve(cur, dim, FALSE); } // `0 bspline` (SmBSplineCurve) or `1 A[3] B[3]` (SmLine::CreateLineSegment, 3D). SmCurve* read_curve(Rd& rd, const SmContext& ctx) { int64_t kind = rd.idx(); if (kind == 1) { SmPoint3d a = rd.vec(); SmPoint3d b = rd.vec(); SmLine* l = NULL; if (SmLine::CreateLineSegment(ctx, 3, a, b, l) != SM_SUCCESS) return NULL; return l; } return read_bspline_curve(rd, ctx); } SmSurface* read_surface(Rd& rd, const SmContext& ctx) { int64_t kind = rd.idx(); if (kind == 4) { SmSphere* sphere = NULL; SmStatus stt = SmSphere::CreateCanonical( ctx, SmAxis2Placement(SmPoint3d(0, 0, 0), SmVector3d(1, 0, 0), SmVector3d(0, 1, 0)), 2.0, sphere); if (stt != SM_SUCCESS || sphere == NULL) { if (sphere) delete sphere; return NULL; } return sphere; } if (kind == 3) { // an SmSurfOfRevolution::CreateCanonical of an SmLine generator SmPoint3d a = rd.vec(); SmPoint3d b = rd.vec(); SmPoint3d p = rd.vec(); SmVector3d ax = rd.vec(); bool swap = rd.flag(); SmLine* gen = new (ctx) SmLine(a, b, 3, &ctx); gen->GetOrCreateGwNurbPointer(); SmSurfOfRevolution* s = NULL; SmStatus stt = SmSurfOfRevolution::CreateCanonical(ctx, gen, p, ax, s, swap ? TRUE : FALSE); if (stt != SM_SUCCESS || s == NULL) { if (s) delete s; else delete gen; return NULL; } return s; } if (kind == 2) { // a curve-bounded surface without boundary curves over a basis surface block SmSurface* basis = read_surface(rd, ctx); bool implicit = rd.flag(); if (basis == NULL) return NULL; SmTArray c3d, cuv; return new (ctx) SmCurveBoundedSurface(*basis, &c3d, &cuv, implicit ? TRUE : FALSE); } if (kind == 1) { SmPoint3d o = rd.vec(); SmVector3d n = rd.vec(); return new (ctx) SmPlane(o, n, &ctx); } bool oob = rd.flag(); SmBSplineSurfaceForm form = (SmBSplineSurfaceForm)rd.idx(); 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(); SmBSplineSurface* b = new (ctx) SmBSplineSurface(sur, FALSE, NULL); b->GetOutOfBoundsEnabled() = oob ? TRUE : FALSE; b->SetBSplineSurfaceForm(form); return b; } // A curve as `ivl_min ivl_max P(0) P(1/4) P(1/2) P(3/4) P(1)` over its natural interval // (EvaluatePoint statuses: a failure writes NaN). void put_curve(std::vector& o, const SmCurve* c) { SmExtent1d ivl = c->GetNaturalInterval(); o.push_back(ivl.GetMin()); o.push_back(ivl.GetMax()); for (int i = 0; i <= 4; i++) { SmPoint3d p; if (c->EvaluatePoint(ivl.Evaluate(i / 4.0), p) == SM_SUCCESS) put_vec(o, p); else put_vec(o, SmVector3d(NAN, NAN, NAN)); } } SmContinuityType cont(Rd& rd) { return (SmContinuityType)rd.idx(); } // A solution `type nvars value end_value params[5] end_params[5]` with objects `objs`. SmSolution read_solution(Rd& rd, SmObject* o0, SmObject* o1) { SmSolution s; s.m_eSolutionType = (SmSolutionType)rd.idx(); s.m_lNumVariables = (ULONG)rd.idx(); s.m_lNumObjects = 2; s.m_apObjects[0] = o0; s.m_apObjects[1] = o1; s.m_vStart.m_dSolutionValue = rd.num(); s.m_vEnd.m_dSolutionValue = rd.num(); for (ULONG i = 0; i < 5; i++) s.m_vStart[i] = rd.num(); for (ULONG i = 0; i < 5; i++) s.m_vEnd[i] = rd.num(); return s; } void run(int32_t op, Rd& rd, std::vector& o) { const SmContext& ctx = the_context(); SmSurface* s = read_surface(rd, ctx); switch (op) { case OP_CONT: { SmSurfParamType param = (SmSurfParamType)rd.idx(); if (s == NULL) { o.push_back(-3.0); break; } SmContinuityType eMin = SM_CT_UNDEFINED; SmTArray conts; SmStatus r = s->CalculateContinuities(param, eMin, conts); o.push_back(st(r)); if (r == SM_SUCCESS) { o.push_back((double)eMin); o.push_back((double)conts.GetSize()); for (ULONG i = 0; i < conts.GetSize(); i++) o.push_back((double)conts[i]); } break; } case OP_TRIM: { SmExtent2d d = rd.dom(); SmSurfParamType side = (SmSurfParamType)rd.idx(); SmBoolean remove = rd.bflag(); if (s == NULL) { o.push_back(-3.0); break; } SmTArray c3d; SmTArray cuv; SmTArray orients; SmTArray gaps; SmStatus r = s->CreateNaturalUVTrimCurves(ctx, d, side, remove, c3d, cuv, orients, &gaps); o.push_back(st(r)); if (r == SM_SUCCESS) { o.push_back((double)c3d.GetSize()); for (ULONG i = 0; i < c3d.GetSize(); i++) { o.push_back((double)orients[i]); o.push_back(gaps[i]); put_curve(o, c3d[i]); put_curve(o, cuv[i]); } } for (ULONG i = 0; i < c3d.GetSize(); i++) delete c3d[i]; for (ULONG i = 0; i < cuv.GetSize(); i++) delete cuv[i]; break; } case OP_SAMPLE: { SmDerivSurfDefinition def; def.m_lNumSamples = (ULONG)rd.idx(); def.m_eTangencyType = (SmTangencyType)rd.idx(); def.m_dStartDerivDirAngleDeg = rd.num(); def.m_dEndDerivDirAngleDeg = rd.num(); def.m_dStartTanLength = rd.num(); def.m_dEndTanScale = rd.num(); def.m_dStartAngleDeg = rd.num(); def.m_dEndAngleDeg = rd.num(); bool has_ref = rd.flag(); SmCurve* ref = has_ref ? read_curve(rd, ctx) : NULL; SmCurve* bc = read_curve(rd, ctx); SmExtent1d ivl = rd.ivl(); SmBoolean right = rd.bflag(); SmBoolean start = rd.bflag(); bool want2 = rd.flag(); bool want3 = rd.flag(); if (s == NULL || bc == NULL || (has_ref && ref == NULL)) { o.push_back(-3.0); delete ref; delete bc; break; } def.m_pTangentReference = ref; SmTArray params; SmTArray pos, d1, d2, d3; SmStatus r = def.GetSampleValues(*s, *bc, ivl, right, start, params, pos, d1, want2 ? &d2 : NULL, want3 ? &d3 : NULL); def.m_pTangentReference = NULL; o.push_back(st(r)); if (r == SM_SUCCESS) { o.push_back((double)params.GetSize()); for (ULONG i = 0; i < params.GetSize(); i++) { o.push_back(params[i]); put_vec(o, pos[i]); put_vec(o, d1[i]); if (want2) put_vec(o, d2[i]); if (want3) put_vec(o, d3[i]); } } delete ref; delete bc; break; } case OP_LCI: { SmExtent2d d = rd.dom(); SmCurve* c = read_curve(rd, ctx); SmExtent1d ivl = rd.ivl(); double tol = rd.num(); SmPoint2d g = rd.uv(); double gt = rd.num(); if (s == NULL || c == NULL) { o.push_back(-3.0); delete c; break; } SmBoolean found = FALSE; SmPoint2d uv; double t = 0.0, dev = 0.0; SmStatus r = s->LocalCurveIntersect(d, *c, ivl, tol, g, gt, found, uv, t, dev); o.push_back(st(r)); if (r == SM_SUCCESS) { o.push_back(flg(found)); if (found) { o.push_back(uv.x); o.push_back(uv.y); o.push_back(t); o.push_back(dev); } } delete c; break; } case OP_SCC: { SmExtent2d d = rd.dom(); SmCurve* c = read_curve(rd, ctx); SmExtent1d ivl = rd.ivl(); double tol = rd.num(); SmBoolean partial = rd.bflag(); if (s == NULL || c == NULL) { o.push_back(-3.0); delete c; break; } SmBoolean found = FALSE; SmSolution sol; SmStatus r = s->SimpleCoincidenceChecker(d, *c, ivl, tol, found, sol, partial); o.push_back(st(r)); if (r == SM_SUCCESS) { o.push_back(flg(found)); if (found) { o.push_back((double)sol.m_eSolutionType); o.push_back(flg(sol.m_apObjects[0] == c)); o.push_back(flg(sol.m_apObjects[1] == s)); o.push_back(sol.m_vStart.m_dSolutionValue); for (ULONG i = 0; i < 3; i++) o.push_back(sol.m_vStart[i]); o.push_back(sol.m_vEnd.m_dSolutionValue); for (ULONG i = 0; i < 3; i++) o.push_back(sol.m_vEnd[i]); } } delete c; break; } case OP_CLASSIFY: { SmCurve* c = read_curve(rd, ctx); SmSolution sol = read_solution(rd, c, s); if (s == NULL || c == NULL) { o.push_back(-3.0); delete c; break; } SmBoolean degen = FALSE; SmSolutionEnd pt; pt.m_dSolutionValue = 12345.0; pt.m_adParameters[0] = 12345.0; pt.m_adParameters[1] = 12345.0; pt.m_adParameters[2] = 12345.0; SmStatus r = s->ClassifyIntersectingRangeSolution(*c, sol, 0.0, degen, pt); o.push_back(st(r)); if (r == SM_SUCCESS) { o.push_back(flg(degen)); o.push_back(pt.m_dSolutionValue); for (ULONG i = 0; i < 3; i++) o.push_back(pt.m_adParameters[i]); } delete c; break; } case OP_SSID: { SmSurface* s2 = read_surface(rd, ctx); double tol = rd.num(); SmSolution a = read_solution(rd, s, s2); SmSolution b = read_solution(rd, s, s2); if (s == NULL || s2 == NULL) { o.push_back(-3.0); delete s2; break; } sc_srf_p6::SmSSGlobalSolver solver(s, s2, tol); const SmSolution* pref = NULL; SmSolutionPairType t = solver.IdenticalSolutions(a, b, pref); o.push_back(0.0); o.push_back((double)t); o.push_back(pref == NULL ? 0.0 : pref == &a ? 1.0 : 2.0); delete s2; break; } case OP_SCLS: { SmExtent2d d = rd.dom(); SmContinuityType uc[2], vc[2], tc[2]; uc[0] = cont(rd); uc[1] = cont(rd); vc[0] = cont(rd); vc[1] = cont(rd); SmExtent3d sbox = rd.box(); bool has_cbox = rd.flag(); SmExtent3d cbox = rd.box(); SmCurve* c = read_curve(rd, ctx); SmExtent1d ivl = rd.ivl(); tc[0] = cont(rd); tc[1] = cont(rd); double tol = rd.num(); bool has_vec = rd.flag(); SmVector3d vec = rd.vec(); SmSolverOperationType sop = (SmSolverOperationType)rd.idx(); SmBoolean skip = rd.bflag(); SmBoolean process = rd.bflag(); if (s == NULL || c == NULL) { o.push_back(-3.0); delete c; break; } double best = 0.0; SmSolutionArray sols; SmStatus r = sc_srf_p6::sm_SCLocalSolve(s, *s, sbox, d, uc, vc, has_cbox ? &cbox : NULL, *c, ivl, tc, tol, has_vec ? &vec : NULL, sop, skip, process, best, sols); o.push_back(st(r)); if (r == SM_SUCCESS) { o.push_back((double)sols.GetSize()); for (ULONG i = 0; i < sols.GetSize(); i++) { o.push_back((double)sols[i].m_eSolutionType); o.push_back((double)sols[i].m_lNumVariables); o.push_back(sols[i].m_vStart.m_dSolutionValue); for (ULONG k = 0; k < 3; k++) o.push_back(sols[i].m_vStart[k]); } } delete c; break; } default: o.push_back((double)SC_ERR_ARG); break; } delete s; } } // namespace SC_EXPORT int32_t sc_surface_surface_p6_eval(int32_t op, const double* in, int64_t n_in, double* out, int64_t cap, int64_t* out_len) { if (in == NULL || n_in < 1 || out_len == NULL) return SC_ERR_ARG; SC_TRY Rd rd{in, 0}; std::vector o; run(op, rd, o); if (rd.at != n_in) { *out_len = 0; return SC_ERR_ARG; } return sc_copy_out(o.data(), (int64_t)o.size(), out, cap, out_len); SC_CATCH }