mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-08 21:11:56 +00:00
4dca7c953c
Checklist (AGENTS.md section 4.5): SmPlane::IsClosed is plane_p1's (ported), not a plane_p2 stub; CreateParallelProjectionCurves keeps its approximation and angle tolerances; no UNPORTED tag for the partial surface_cache_p1; the FFI accepts any finite IsClosed/IsPlanar tolerance; the shim builds curve-bounded surfaces; the generator adds 1e-4/1e4 scales and keeps the always-deferred global solves at unit scale (GlobalSurfaceSolve is fixture-only: intersecting surfaces take upstream minutes). difftest: 3658 cases, 3029 pass bit-identical, 0 fail, 629 deferred. Upstream issues UB-73, WR-48..50. Unit tests that asserted the old stubs now check the wired results. Reports of the touched units regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1037 lines
34 KiB
C++
1037 lines
34 KiB
C++
// SPDX-License-Identifier: Apache-2.0
|
|
// difftest shim for unit `surface.surface_p7`: the SmSurface members owned by the unit
|
|
// (source/SMLib/src/SmSurface.cpp, source/SMLib/inc/SmSurface.h), called through `SmSurface*`
|
|
// on SmBSplineSurface and SmPlane objects (virtual dispatch as upstream; `base` calls the
|
|
// SmSurface body explicitly), plus the co-ported Evaluate1stDerivatives,
|
|
// Evaluate2ndDerivatives and EvaluateDirectionalDerivs and the file-static helpers.
|
|
//
|
|
// Static functions of SmSurface.cpp cannot be linked against, so the helpers exercised here
|
|
// are VERBATIM copies of upstream SmSurface.cpp (commit c9c5979), inside the namespace
|
|
// sc_srf_p7 (line ranges noted at each block). sm_LoadGuesses takes its node's owner surface
|
|
// directly (two lines marked ADAPTED), as the port does: reaching it through a tree node
|
|
// needs a real SmSurfaceCache.
|
|
//
|
|
// One entry point, sc_surface_surface_p7_eval(op, in, n_in, out, cap, out_len). Layouts are
|
|
// documented in crates/solidcore-ffi/src/units/surface_surface_p7.rs, which validates every
|
|
// input. A surface block is `0 oob form n m p q r s cpts(x y z w) u v` (an
|
|
// SmBSplineSurface(gw_SURFACE*, FALSE, NULL)), `1 O[3] N[3]` (SmPlane(O, N)) or `2 basis implicit`
|
|
// (an SmCurveBoundedSurface without boundary curves over a basis block); a curve block
|
|
// is `dim n p m cpts(x y z w) knots` (SmBSplineCurve(gw_CURVE*, dim, FALSE)). `out` receives
|
|
// the op status (0 = SM_SUCCESS, else the SmStatus value) and the op's outputs.
|
|
#include "sc_shim.h"
|
|
|
|
#include "StdAfx.h"
|
|
#include <SmBSplineCurve.h>
|
|
#include <SmBSplineSurface.h>
|
|
#include <SmContext.h>
|
|
#include <SmCurve.h>
|
|
#include <SmCurveBoundedSurface.h>
|
|
#include <SmExtent1d.h>
|
|
#include <SmExtent2d.h>
|
|
#include <SmNurbsCrv.h>
|
|
#include <SmNurbsSrf.h>
|
|
#include <SmPlane.h>
|
|
#include <SmSolutionArray.h>
|
|
#include <SmSurface.h>
|
|
#include <SmSurfTypes.h>
|
|
#include <SmTArray.h>
|
|
#include <SmTree.h>
|
|
#include <SmVector2d.h>
|
|
#include <SmVector3d.h>
|
|
#include <nurbs.h>
|
|
|
|
#include <vector>
|
|
|
|
namespace sc_srf_p7
|
|
{
|
|
// clang-format off
|
|
// ---- verbatim (two ADAPTED lines): SmSurface.cpp lines 4117-4285: sm_LoadGuesses
|
|
static SmStatus sm_LoadGuesses
|
|
(const SmSurface * pSurfaceOwner, // ADAPTED: in : the node's owner surface (pSurfaceNode->GetOwnerObject())
|
|
SmBezierPatch * pBezPatch, // NotUsed: in : SurfaceNode Bezier patch
|
|
const SmExtent2d & crUVDomain, // in : Problem domain limits
|
|
const SmPoint3d & crTestPnt, // in : target solution start point
|
|
SmSolverOperationType eSolverOperation, // in : oneof SM_SO_MINIMIZE,
|
|
// SM_SO_MAXIMIZE,
|
|
// SM_SO_NORMALIZE,
|
|
// SM_SO_INTERSECT
|
|
SmPoint2d * sGuesses, // out: UVGuess Point or not used
|
|
ULONG & lNumGuesses) // out: set to 1 or 0
|
|
{
|
|
SM_REF1(pBezPatch) ;
|
|
// check state - restricted set of operations
|
|
SM_ASSERT( eSolverOperation == SM_SO_MINIMIZE
|
|
|| eSolverOperation == SM_SO_MAXIMIZE
|
|
|| eSolverOperation == SM_SO_NORMALIZE
|
|
|| eSolverOperation == SM_SO_INTERSECT) ;
|
|
|
|
// locals
|
|
ULONG ii, jj;
|
|
const SmSurface *pSurface = pSurfaceOwner ; // ADAPTED (was: (SmSurface *)pSurfaceNode->GetOwnerObject())
|
|
const SmBSplineSurface *pBSS = SM_CAST_PTR(SmBSplineSurface, pSurface) ;
|
|
SM_ASSERT(pSurface && pSurface->IsKindOf(SmSurface_TYPE)) ;
|
|
|
|
// select a grid sample size
|
|
constexpr ULONG lGridSize = 2;
|
|
|
|
// set gridSize = 1 for linear geometry
|
|
ULONG lGridSizeU = (pBSS && pBSS->GetNumberControlPoints( SM_SP_U ) == 2) ? 1 : lGridSize ;
|
|
ULONG lGridSizeV = (pBSS && pBSS->GetNumberControlPoints( SM_SP_V ) == 2) ? 1 : lGridSize ;
|
|
|
|
// get UV mid-point as 1st guess
|
|
SmPoint2d sClosePtUV = crUVDomain.Evaluate(.5, .5) ;
|
|
|
|
// Evaluate MidPoint
|
|
SmPoint2d sUV;
|
|
SmPoint3d sPt;
|
|
SmVector3d sSu, sSv, sSuv, sSuu, sSvv;
|
|
SmStatus sRtn = pSurface->Evaluate1stDerivatives(sClosePtUV, TRUE, TRUE, sPt, sSu, sSv) ;
|
|
if(sRtn != SM_SUCCESS)
|
|
{
|
|
pSurface->EvaluatePoint( sClosePtUV, sPt );
|
|
}
|
|
|
|
// get current distance and upcoming NewtonRaphson values
|
|
SmVector3d sSurfToPt = sPt - crTestPnt;
|
|
double dF = sSurfToPt.Dot(sSu);
|
|
double dG = sSurfToPt.Dot(sSv);
|
|
|
|
// save current values as initial best values
|
|
double dBestDist = sSurfToPt.Length();
|
|
double dBestFG = (sRtn == SM_SUCCESS) ? fabs(dF) + fabs(dG) : SM_BIG_DOUBLE ;
|
|
|
|
// check each sample point - and check 1st NewtonRaphson step
|
|
// towards the surface point where the SurfaceNormal intersects
|
|
// target point.
|
|
// First NewtonRaphson step: want (Su*Sv).(T-S) = 0, so
|
|
// find du, dv so
|
|
// 0 = Su . (T-S) = F(u+du,v+dv) ~= F + du*Fu + dv*Fv ==> [Fu Fv][du] = [-F]
|
|
// 0 = Sv . (T-S) = G(u+du,v+dv) ~= G + du*Gu + dv*Gv [Gu Gv][dv] = [-G]
|
|
// where S = S(u,v) a point on the surface,
|
|
// Su = 1st u derivative
|
|
// Sv = 1st v derivative
|
|
// T = Test point
|
|
//
|
|
// solve for du,dv yields [du] = [ Gv -Fv][-F]
|
|
// [dv] [-Gu Fu][-G]
|
|
// -------------------
|
|
// (Fu . Gv - Gu . Fv)
|
|
|
|
// Make a clamping domain that runs halfway between the outermost
|
|
// sample points and the real domain boundary.
|
|
SmExtent2d sUVExt(crUVDomain.Evaluate(0.5 / ((double)(2*lGridSizeU)),
|
|
0.5 / ((double)(2*lGridSizeV))),
|
|
crUVDomain.Evaluate(1.0 - 0.5 / ((double)(2*lGridSizeU)),
|
|
1.0 - 0.5 / ((double)(2*lGridSizeV)))) ;
|
|
|
|
// Sample every grid point - Take 1 NewtonRaphson Step from there and keep the best point
|
|
for(ii=0;ii<lGridSizeU;ii++)
|
|
{
|
|
// select evenly spaced interior domain points
|
|
// exs: GridSize 1: [1/2]
|
|
// GridSize 2: [1/4 3/4],
|
|
// GridSize 3: [1/6 3/6 5/6], etc.
|
|
double dPrmU = ((double)(2*ii+1)) / ((double)(2*lGridSizeU)) ;
|
|
|
|
for(jj=0;jj<lGridSizeV;jj++)
|
|
{
|
|
double dPrmV = ((double)(2*jj+1)) / ((double)(2*lGridSizeV)) ;
|
|
|
|
// skip grid points that don't evaluate to 2nd deriviatives
|
|
sUV = crUVDomain.Evaluate( dPrmU, dPrmV ) ;
|
|
sRtn = pSurface->Evaluate2ndDerivatives(sUV, TRUE, TRUE,
|
|
sPt, sSu, sSv,
|
|
sSuv, sSuu, sSvv) ; // nonZeroTangents
|
|
|
|
// get dist and NewtonRaphson function values from SamplePoint to TestPoint
|
|
sSurfToPt = sPt - crTestPnt;
|
|
dF = sSurfToPt.Dot(sSu);
|
|
dG = sSurfToPt.Dot(sSv);
|
|
double dThisDist = sSurfToPt.Length() ;
|
|
double dThisFG = (sRtn == SM_SUCCESS) ? fabs(dF) + fabs(dG) : SM_BIG_DOUBLE ;
|
|
|
|
// Save the best grid point for the current operation
|
|
if( (eSolverOperation == SM_SO_MINIMIZE && dThisDist < dBestDist)
|
|
|| (eSolverOperation == SM_SO_MAXIMIZE && dThisDist > dBestDist)
|
|
|| (eSolverOperation == SM_SO_NORMALIZE && sRtn == SM_SUCCESS && dThisFG < dBestFG )
|
|
|| (eSolverOperation == SM_SO_INTERSECT && dThisDist < dBestDist))
|
|
{
|
|
sClosePtUV = sUV ;
|
|
dBestDist = dThisDist ;
|
|
if(dThisFG < dBestFG) dBestFG = dThisFG ;
|
|
}
|
|
|
|
// skip sample points that failed to generate 2nd order derivative values
|
|
if(sRtn != SM_SUCCESS)
|
|
{ continue ; }
|
|
|
|
// Take 1 clamped Newton-Raphson step towards F=0 and G=0 and check if closer
|
|
double dFu = sSu.Dot(sSu) + sSurfToPt.Dot(sSuu);
|
|
double dFv = sSu.Dot(sSv) + sSurfToPt.Dot(sSuv);
|
|
double dGu = dFv;
|
|
double dGv = sSv.Dot(sSv) + sSurfToPt.Dot(sSvv);
|
|
|
|
double dDen = dFu*dGv - dFv*dGu;
|
|
if ( smos_Fabs( dDen ) < SM_EFF_ZERO_SQ )
|
|
{
|
|
continue; // just ignore if singular.
|
|
}
|
|
|
|
double dNumU = dG*dFv - dGv*dF;
|
|
double dNumV = dF*dGu - dG*dFu;
|
|
|
|
sUV.Set(sUV.x + dNumU/dDen, sUV.y + dNumV/dDen);
|
|
sUV = sUVExt.ClampPoint2d(sUV);
|
|
|
|
// evaluate and judge the New Point
|
|
sRtn = pSurface->Evaluate1stDerivatives(sUV, TRUE, TRUE, sPt, sSu, sSv) ;
|
|
if(sRtn != SM_SUCCESS)
|
|
{ pSurface->EvaluatePoint( sUV, sPt ); }
|
|
|
|
sSurfToPt = sPt - crTestPnt;
|
|
dF = sSurfToPt.Dot(sSu);
|
|
dG = sSurfToPt.Dot(sSv);
|
|
dThisDist = sSurfToPt.Length();
|
|
dThisFG = fabs(dF) + fabs(dG) ;
|
|
|
|
// Save the best NewtonRaphson point for the current operation
|
|
if( (eSolverOperation == SM_SO_MINIMIZE && dThisDist < dBestDist)
|
|
|| (eSolverOperation == SM_SO_MAXIMIZE && dThisDist > dBestDist)
|
|
|| (eSolverOperation == SM_SO_NORMALIZE && sRtn == SM_SUCCESS && dThisFG < dBestFG )
|
|
|| (eSolverOperation == SM_SO_INTERSECT && dThisDist < dBestDist))
|
|
{
|
|
sClosePtUV = sUV ;
|
|
dBestDist = dThisDist ;
|
|
if(dThisFG < dBestFG) dBestFG = dThisFG ;
|
|
}
|
|
} // end iter every jj grid index
|
|
} // end iter every ii grid index
|
|
|
|
// set output
|
|
sGuesses[0] = sClosePtUV;
|
|
lNumGuesses = 1;
|
|
|
|
// all done
|
|
return SM_SUCCESS;
|
|
|
|
} // end sm_LoadGuesses
|
|
|
|
// ---- verbatim: SmSurface.cpp lines 4750-4805: sm_PassSCConvergenceTest
|
|
static SmBoolean sm_PassSCConvergenceTest
|
|
(const SmSurface & crSurface, // in :
|
|
const SmPoint2d & crUV, // in :
|
|
const SmCurve & crCurve, // in :
|
|
double dParameter) // in :
|
|
{
|
|
// surface eval
|
|
SmPoint3d sPnt;
|
|
SmVector3d sDU, sDV;
|
|
crSurface.Evaluate1stDerivatives(crUV,TRUE,TRUE,sPnt,sDU,sDV); // nonZeroTangents
|
|
|
|
// curve eval
|
|
SmVector3d sPV[2]; // sPV[0] = crCurve 3dPoint for param = dParameter
|
|
// sPV[1] = crCurve 3dTangent for param = dParameter
|
|
crCurve.Evaluate(dParameter,1,TRUE,sPV, TRUE); // NonZeroTangents
|
|
|
|
// curve surface displacement
|
|
SmVector3d sDiff = sPnt - sPV[0];
|
|
double dScale = 1.0 + sPnt.GetMaxDimension();
|
|
|
|
// when surf and curve tangents are nonZero
|
|
// and displacement is nonZero
|
|
// and angle between any tangent and the displacement is not 90 degrees
|
|
if( smos_Fabs(sDU.Dot(sDiff)) > 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
|
|
|
|
// ---- verbatim: SmSurface.cpp lines 7837-7921: sm_CheckSeamDrop
|
|
static SmStatus sm_CheckSeamDrop(
|
|
SmSurface *pThisSurf,
|
|
SmPoint2d &sThisUV, // in/out: STEP parameter, possibly moved across seam
|
|
const SmExtent2d &sThisDomain,
|
|
const SmSurface *pOtherSurf,
|
|
const SmPoint2d &sOtherUV, // in: Nurbs parameter
|
|
const SmExtent2d &sOtherDomain,
|
|
SmLocationType eLocation) // where the dropped point is on pThisSurf.
|
|
{
|
|
|
|
if ( eLocation == SM_LT_POLE )
|
|
{ return SM_ERR; }
|
|
|
|
if ( eLocation != SM_LT_U_SEAM && eLocation != SM_LT_V_SEAM && eLocation != SM_LT_UV_SEAM )
|
|
{ return SM_SUCCESS; }
|
|
|
|
// pOther point is dropped onto a seam in pThis.
|
|
// sUVOther is a boundary point on pOther.
|
|
// pOther is evauated in Nurbs parameterization, pThis is STEP.
|
|
|
|
SmVector3d sPtDer[4];
|
|
pThisSurf->EvaluateSTEP( sThisUV, 1, 1, TRUE, TRUE, TRUE, sPtDer );
|
|
|
|
SmVector3d sPt, sThisDeriv, sOtherU, sOtherV, sOtherDeriv;
|
|
|
|
double dDotU, dDotV;
|
|
|
|
pOtherSurf->Evaluate1stDerivatives( sOtherUV, TRUE, TRUE, sPt, sOtherU, sOtherV );
|
|
|
|
// Unitize them, so that dot-product comparisons mean direction only.
|
|
if ( sOtherU.Unitize() != SM_SUCCESS )
|
|
{ return SM_ERR; }
|
|
if ( sOtherV.Unitize() != SM_SUCCESS )
|
|
{ return SM_ERR; }
|
|
|
|
// Flip directions of the derivatives if they are at the top of their domains,
|
|
// so that the derivatives point into the surface.
|
|
if ( sOtherUV.x > sOtherDomain.GetUInterval().GetMid() )
|
|
{ sOtherU = -sOtherU; }
|
|
if ( sOtherUV.y > sOtherDomain.GetVInterval().GetMid() )
|
|
{ sOtherV = -sOtherV; }
|
|
|
|
if ( eLocation == SM_LT_U_SEAM || eLocation == SM_LT_UV_SEAM )
|
|
{
|
|
// Closed in U: sUVThis.x is at low end of u-range but could be the high end.
|
|
// Get our u-deriv, and whichever deriv of pOtherSurf that lines up with it.
|
|
sThisDeriv = sPtDer[2];
|
|
|
|
dDotU = sThisDeriv.Dot( sOtherU );
|
|
dDotV = sThisDeriv.Dot( sOtherV );
|
|
|
|
if ( smos_Fabs( dDotU ) > smos_Fabs( dDotV ) )
|
|
{ sOtherDeriv = sOtherU; }
|
|
else
|
|
{ sOtherDeriv = sOtherV; }
|
|
|
|
if ( sThisDeriv.Dot( sOtherDeriv ) > 0.0 )
|
|
{ sThisUV.x = sThisDomain.GetMin().x; }
|
|
else
|
|
{ sThisUV.x = sThisDomain.GetMax().x; }
|
|
}
|
|
|
|
if ( eLocation == SM_LT_V_SEAM || eLocation == SM_LT_UV_SEAM )
|
|
{
|
|
// Closed in V: sUVThis.y is at low end of v-range but could be the high end.
|
|
// Get our v-deriv, and whichever deriv of pOtherSurf that lines up with it.
|
|
sThisDeriv = sPtDer[1];
|
|
|
|
dDotU = sThisDeriv.Dot( sOtherU );
|
|
dDotV = sThisDeriv.Dot( sOtherV );
|
|
|
|
if ( smos_Fabs( dDotU ) > smos_Fabs( dDotV ) )
|
|
{ sOtherDeriv = sOtherU; }
|
|
else
|
|
{ sOtherDeriv = sOtherV; }
|
|
|
|
if ( sThisDeriv.Dot( sOtherDeriv ) > 0.0 )
|
|
{ sThisUV.y = sThisDomain.GetMin().y; }
|
|
else
|
|
{ sThisUV.y = sThisDomain.GetMax().y; }
|
|
}
|
|
|
|
return SM_SUCCESS;
|
|
|
|
} // end sm_CheckSeamDrop
|
|
|
|
// ---- verbatim: SmSurface.cpp lines 10256-10359: sm_GoodDropResult
|
|
static SmBoolean sm_GoodDropResult(
|
|
const SmSurface * pSurface, // in
|
|
const SmExtent2d & crDomain, // in
|
|
const SmPoint3d & crPtToDrop, // in
|
|
const SmPoint2d & crGuessUV, // in
|
|
const SmSolution & crSol // in: result of drop using crGuessUV
|
|
)
|
|
{
|
|
// Check whether it's right on.
|
|
if ( crSol.m_vStart.m_dSolutionValue < SM_EFF_ZERO )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
SmPoint2d sResultUV( crSol.m_vStart[0], crSol.m_vStart[1] );
|
|
|
|
// If result is far from guess, it's suspicious.
|
|
constexpr double dMaxStep = 0.50; // 50% of domain: big steps do happen.
|
|
SmVector2d sUVStep( sResultUV - crGuessUV );
|
|
if ( smos_Fabs( sUVStep.x ) > dMaxStep * crDomain.XLength() ) {
|
|
return FALSE;
|
|
}
|
|
if ( smos_Fabs( sUVStep.y ) > dMaxStep * crDomain.YLength() ) {
|
|
return FALSE;
|
|
}
|
|
// end if check on big step size.
|
|
|
|
// Check whether it's a solution or not.
|
|
// Note, function values could be bad if it's legitimately off a boundary
|
|
// (assuming SM_SO_MINIMIZE); must check for that.
|
|
|
|
// Evaluate the error functions: how far from the surface normal.
|
|
// Note, this test is loose: if the local solver can get anywhere near,
|
|
// then it should be good.
|
|
SmPoint3d sSrfPoint;
|
|
SmVector3d Su, Sv;
|
|
pSurface->Evaluate1stDerivatives( sResultUV, TRUE, TRUE, sSrfPoint, Su, Sv );
|
|
Su.Unitize();
|
|
Sv.Unitize();
|
|
SmVector3d sGap( crPtToDrop - sSrfPoint );
|
|
double Fu = sGap.Dot( Su );
|
|
double Fv = sGap.Dot( Sv );
|
|
if ( smos_Fabs( Fu ) + smos_Fabs( Fv ) < 0.0001 ) {
|
|
return TRUE;
|
|
}
|
|
|
|
// Need to check legitimately off boundary.
|
|
// If it's off the lower end of a domain, and the solution is before the
|
|
// beginning, then the dot of Gap with the deriv will be negative, so a
|
|
// positive value indicates error; reverse for the top of a domain.
|
|
|
|
// Check u-param first.
|
|
if ( sResultUV.x < crDomain.GetMin().x + SM_EFF_ZERO )
|
|
{
|
|
if ( Fu > SM_EFF_ZERO ) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
else if ( sResultUV.x > crDomain.GetMax().x - SM_EFF_ZERO )
|
|
{
|
|
if ( Fu < -SM_EFF_ZERO ) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
else if ( smos_Fabs( Fu ) > 0.001 )
|
|
{
|
|
return FALSE; // interior, bad fcn value.
|
|
}
|
|
// end check u-param.
|
|
|
|
// Now check v-param.
|
|
if ( sResultUV.y < crDomain.GetMin().y + SM_EFF_ZERO )
|
|
{
|
|
if ( Fv > SM_EFF_ZERO ) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
else if ( sResultUV.y > crDomain.GetMax().y - SM_EFF_ZERO )
|
|
{
|
|
if ( Fv < -SM_EFF_ZERO ) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
else if ( smos_Fabs( Fv ) > 0.001 )
|
|
{
|
|
return FALSE; // interior, bad fcn value.
|
|
}
|
|
// end check v-param.
|
|
|
|
// One more: if the solution 3d point is farther than the guess.
|
|
// (Remember, this routine uses MINIMIZE.)
|
|
SmPoint3d sGuess3dPt;
|
|
pSurface->EvaluatePoint( crGuessUV, sGuess3dPt );
|
|
double dDsqGuess = crPtToDrop.DistanceBetweenSquared( sSrfPoint );
|
|
double dDsqResult = crPtToDrop.DistanceBetweenSquared( sGuess3dPt );
|
|
if ( dDsqResult > dDsqGuess )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// If we made it here, there's nothing to complain about.
|
|
return TRUE;
|
|
|
|
} // end helper function sm_GoodDropResult
|
|
|
|
// ---- verbatim: SmSurface.cpp lines 20854-20902: sm_PassSSConvergenceTest
|
|
static SmBoolean sm_PassSSConvergenceTest
|
|
(const SmSurface & crSurface,
|
|
const SmPoint2d & crUV,
|
|
const SmSurface & crSurface2,
|
|
const SmPoint2d & crUV2)
|
|
|
|
{
|
|
SmPoint3d sPnt;
|
|
SmVector3d sDU, sDV;
|
|
crSurface.Evaluate1stDerivatives(crUV,TRUE,TRUE,sPnt,sDU,sDV);
|
|
SmPoint3d sPnt2;
|
|
SmVector3d sDU2, sDV2;
|
|
crSurface2.Evaluate1stDerivatives(crUV2,TRUE,TRUE,sPnt2,sDU2,sDV2);
|
|
SmVector3d sDiff = sPnt - sPnt2;
|
|
if (smos_Fabs(sDU.Dot(sDiff)) > SM_EFF_ZERO ||
|
|
smos_Fabs(sDV.Dot(sDiff)) > SM_EFF_ZERO ||
|
|
smos_Fabs(sDU2.Dot(sDiff)) > SM_EFF_ZERO ||
|
|
smos_Fabs(sDV2.Dot(sDiff)) > SM_EFF_ZERO) {
|
|
if (sDiff.LengthSquared() > SM_EFF_ZERO_SQ) {
|
|
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 (sDU2.LengthSquared() > SM_EFF_ZERO_SQ) {
|
|
sDU2.Unitize();
|
|
if (smos_Fabs(sDU2.Dot(sDiff)) > SM_EFF_ZERO) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
if (sDV2.LengthSquared() > SM_EFF_ZERO_SQ) {
|
|
sDV2.Unitize();
|
|
if (smos_Fabs(sDV2.Dot(sDiff)) > SM_EFF_ZERO) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
|
|
} // end sm_PassSSConvergenceTest
|
|
|
|
// clang-format on
|
|
} // namespace sc_srf_p7
|
|
|
|
namespace
|
|
{
|
|
// Ops (keep in sync with crates/solidcore-ffi/src/units/surface_surface_p7.rs).
|
|
enum : int32_t
|
|
{
|
|
OP_EVAL1 = 0,
|
|
OP_EVAL2 = 1,
|
|
OP_DIRDERIV = 2,
|
|
OP_NORMAL = 3,
|
|
OP_IS_CLOSED = 4,
|
|
OP_IS_PLANAR = 5,
|
|
OP_APPROX_LEN = 6,
|
|
OP_HIGHER = 7,
|
|
OP_INWARD = 8,
|
|
OP_DROP_PTS = 9,
|
|
OP_DROP_VECS = 10,
|
|
OP_DEGEN = 11,
|
|
OP_FLAT = 12,
|
|
OP_BREP = 13,
|
|
OP_GPS0 = 14,
|
|
OP_GCS = 15,
|
|
OP_GSS = 16,
|
|
OP_LCS = 17,
|
|
OP_PROJ = 18,
|
|
OP_LOAD_GUESSES = 19,
|
|
OP_PASS_SC = 20,
|
|
OP_PASS_SS = 21,
|
|
OP_GOOD_DROP = 22,
|
|
OP_CHECK_SEAM = 23,
|
|
};
|
|
|
|
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);
|
|
}
|
|
SmExtent2d dom()
|
|
{
|
|
double u0 = num();
|
|
double v0 = num();
|
|
double u1 = num();
|
|
double v1 = num();
|
|
return SmExtent2d(SmPoint2d(u0, v0), SmPoint2d(u1, v1));
|
|
}
|
|
};
|
|
|
|
double st(SmStatus s) { return s == SM_SUCCESS ? 0.0 : (double)s; }
|
|
double flg(SmBoolean b) { return b ? 1.0 : 0.0; }
|
|
|
|
void put_vec(std::vector<double>& o, const SmVector3d& v)
|
|
{
|
|
o.push_back(v.x);
|
|
o.push_back(v.y);
|
|
o.push_back(v.z);
|
|
}
|
|
|
|
void put_uv(std::vector<double>& o, const SmVector2d& v)
|
|
{
|
|
o.push_back(v.x);
|
|
o.push_back(v.y);
|
|
}
|
|
|
|
const SmContext& the_context()
|
|
{
|
|
static SmContext* p = new SmContext();
|
|
return *p;
|
|
}
|
|
|
|
SmSurface* read_surface(Rd& rd, const SmContext& ctx)
|
|
{
|
|
int64_t kind = rd.idx();
|
|
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();
|
|
SmTArray<SmCurve*> 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;
|
|
}
|
|
|
|
SmBSplineCurve* read_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);
|
|
}
|
|
|
|
const double* opt_target(Rd& rd, double& store)
|
|
{
|
|
bool has = rd.flag();
|
|
store = rd.num();
|
|
return has ? &store : NULL;
|
|
}
|
|
|
|
std::vector<SmVector3d> read_vecs(Rd& rd)
|
|
{
|
|
int64_t n = rd.idx();
|
|
std::vector<SmVector3d> v;
|
|
for (int64_t i = 0; i < n; i++)
|
|
v.push_back(rd.vec());
|
|
return v;
|
|
}
|
|
|
|
void run(int32_t op, Rd& rd, std::vector<double>& o)
|
|
{
|
|
const SmContext& ctx = the_context();
|
|
SmSurface* s = read_surface(rd, ctx);
|
|
switch (op)
|
|
{
|
|
case OP_EVAL1:
|
|
{
|
|
SmPoint2d uv = rd.uv();
|
|
SmBoolean ul = rd.bflag(), vl = rd.bflag();
|
|
SmPoint3d p;
|
|
SmVector3d du, dv;
|
|
SmStatus r = s->Evaluate1stDerivatives(uv, ul, vl, p, du, dv);
|
|
o.push_back(st(r));
|
|
if (r == SM_SUCCESS)
|
|
{
|
|
put_vec(o, p);
|
|
put_vec(o, du);
|
|
put_vec(o, dv);
|
|
}
|
|
break;
|
|
}
|
|
case OP_EVAL2:
|
|
{
|
|
SmPoint2d uv = rd.uv();
|
|
SmBoolean ul = rd.bflag(), vl = rd.bflag();
|
|
SmPoint3d p;
|
|
SmVector3d du, dv, duv, duu, dvv;
|
|
SmStatus r = s->Evaluate2ndDerivatives(uv, ul, vl, p, du, dv, duv, duu, dvv);
|
|
o.push_back(st(r));
|
|
if (r == SM_SUCCESS)
|
|
for (const SmVector3d* v : {&p, &du, &dv, &duv, &duu, &dvv})
|
|
put_vec(o, *v);
|
|
break;
|
|
}
|
|
case OP_DIRDERIV:
|
|
{
|
|
SmPoint2d uv = rd.uv();
|
|
SmVector2d dir = rd.uv();
|
|
ULONG h = (ULONG)rd.idx();
|
|
SmBoolean ul = rd.bflag(), vl = rd.bflag();
|
|
SmVector3d d[4];
|
|
SmStatus r = s->EvaluateDirectionalDerivs(uv, dir, h, d, ul, vl);
|
|
o.push_back(st(r));
|
|
if (r == SM_SUCCESS)
|
|
for (ULONG i = 0; i <= h; i++)
|
|
put_vec(o, d[i]);
|
|
break;
|
|
}
|
|
case OP_NORMAL:
|
|
{
|
|
SmPoint2d uv = rd.uv();
|
|
SmBoolean ul = rd.bflag(), vl = rd.bflag();
|
|
bool base = rd.flag();
|
|
SmVector3d n(SM_UNDEF_DOUBLE, SM_UNDEF_DOUBLE, SM_UNDEF_DOUBLE);
|
|
SmStatus r = base ? s->SmSurface::EvaluateNormal(uv, ul, vl, n) : s->EvaluateNormal(uv, ul, vl, n);
|
|
o.push_back(st(r));
|
|
if (r == SM_SUCCESS)
|
|
put_vec(o, n);
|
|
break;
|
|
}
|
|
case OP_IS_CLOSED:
|
|
{
|
|
SmExtent2d d = rd.dom();
|
|
SmSurfParamType param = (SmSurfParamType)rd.idx();
|
|
bool has_tol = rd.flag();
|
|
double tol = rd.num();
|
|
bool want = rd.flag();
|
|
bool base = rd.flag();
|
|
SmContinuityType c = SM_CT_UNDEFINED;
|
|
SmBoolean r = base ? s->SmSurface::IsClosed(d, param, has_tol ? &tol : NULL, want ? &c : NULL)
|
|
: s->IsClosed(d, param, has_tol ? &tol : NULL, want ? &c : NULL);
|
|
o.push_back(0.0);
|
|
o.push_back(flg(r));
|
|
o.push_back(want ? (double)c : -1.0);
|
|
break;
|
|
}
|
|
case OP_IS_PLANAR:
|
|
{
|
|
double tol = rd.num();
|
|
bool base = rd.flag();
|
|
SmPoint3d p(SM_UNDEF_DOUBLE, SM_UNDEF_DOUBLE, SM_UNDEF_DOUBLE);
|
|
SmVector3d n(SM_UNDEF_DOUBLE, SM_UNDEF_DOUBLE, SM_UNDEF_DOUBLE);
|
|
double dev = SM_UNDEF_DOUBLE;
|
|
SmBoolean r = base ? s->SmSurface::IsPlanar(tol, &p, &n, &dev) : s->IsPlanar(tol, &p, &n, &dev);
|
|
o.push_back(0.0);
|
|
o.push_back(flg(r));
|
|
put_vec(o, p);
|
|
put_vec(o, n);
|
|
o.push_back(dev);
|
|
break;
|
|
}
|
|
case OP_APPROX_LEN:
|
|
{
|
|
SmExtent2d d = rd.dom();
|
|
SmVector2d r = s->ApproxDerivativeLengths(d);
|
|
o.push_back(0.0);
|
|
put_uv(o, r);
|
|
break;
|
|
}
|
|
case OP_HIGHER:
|
|
{
|
|
SmPoint2d uv = rd.uv();
|
|
SmVector2d g1 = rd.uv();
|
|
bool w3 = rd.flag(), w4 = rd.flag();
|
|
SmVector3d g2, g3, g4;
|
|
SmStatus r = s->ComputeHigherOrderDerivs(uv, g1, g2, w3 ? &g3 : NULL, w4 ? &g4 : NULL);
|
|
o.push_back(st(r));
|
|
if (r == SM_SUCCESS)
|
|
{
|
|
put_vec(o, g2);
|
|
if (w3)
|
|
put_vec(o, g3);
|
|
if (w4)
|
|
put_vec(o, g4);
|
|
}
|
|
break;
|
|
}
|
|
case OP_INWARD:
|
|
{
|
|
SmPoint2d uv = rd.uv();
|
|
SmVector3d v;
|
|
SmStatus r = s->ComputeInwardVector(uv, v);
|
|
o.push_back(st(r));
|
|
if (r == SM_SUCCESS)
|
|
put_vec(o, v);
|
|
break;
|
|
}
|
|
case OP_DROP_PTS:
|
|
case OP_DROP_VECS:
|
|
{
|
|
SmPoint2d uv = rd.uv();
|
|
SmBoolean ul = rd.bflag(), vl = rd.bflag();
|
|
std::vector<SmVector3d> v = read_vecs(rd);
|
|
std::vector<SmVector2d> res(v.size());
|
|
SmStatus r = op == OP_DROP_PTS
|
|
? s->DropPointsToTangentPlane(uv, ul, vl, (ULONG)v.size(), v.data(), res.data())
|
|
: s->DropVectors(uv, ul, vl, (ULONG)v.size(), v.data(), res.data());
|
|
o.push_back(st(r));
|
|
if (r == SM_SUCCESS)
|
|
for (const SmVector2d& x : res)
|
|
put_uv(o, x);
|
|
break;
|
|
}
|
|
case OP_DEGEN:
|
|
{
|
|
SmPoint2d uv = rd.uv();
|
|
SmVector3d dir = rd.vec();
|
|
SmBoolean from_pole = rd.bflag();
|
|
SmSurfParamType sdir = (SmSurfParamType)rd.idx();
|
|
double tol = rd.num();
|
|
SmStatus r = s->FindDegenParamForDirection(uv, dir, from_pole, sdir, tol);
|
|
o.push_back(st(r));
|
|
put_uv(o, uv);
|
|
break;
|
|
}
|
|
case OP_FLAT:
|
|
{
|
|
double ang = rd.num();
|
|
bool want = rd.flag();
|
|
SmTArray<SmPoint3d> pts;
|
|
ULONG r = s->GetFlatCorners(want ? &pts : NULL, ang);
|
|
o.push_back(0.0);
|
|
o.push_back((double)r);
|
|
if (want)
|
|
for (ULONG i = 0; i < pts.GetSize(); i++)
|
|
put_vec(o, pts[i]);
|
|
break;
|
|
}
|
|
case OP_BREP:
|
|
o.push_back(0.0);
|
|
o.push_back(flg(s->GetBrep() != NULL));
|
|
break;
|
|
case OP_GPS0:
|
|
{
|
|
SmExtent2d d = rd.dom();
|
|
SmSolverOperationType sop = (SmSolverOperationType)rd.idx();
|
|
SmPoint3d p = rd.vec();
|
|
double tol = rd.num();
|
|
double tgt = 0.0;
|
|
const double* pt = opt_target(rd, tgt);
|
|
SmSolutionRequestedType req = (SmSolutionRequestedType)rd.idx();
|
|
SmSolutionArray sols;
|
|
SmStatus r = s->GlobalPointSolve_0(d, sop, p, tol, pt, req, sols);
|
|
o.push_back(st(r));
|
|
o.push_back((double)sols.GetSize());
|
|
break;
|
|
}
|
|
case OP_GCS:
|
|
case OP_LCS:
|
|
{
|
|
SmExtent2d d = rd.dom();
|
|
SmBSplineCurve* c = read_curve(rd, ctx);
|
|
double a = rd.num(), b = rd.num();
|
|
SmSolverOperationType sop = (SmSolverOperationType)rd.idx();
|
|
double tol = rd.num();
|
|
std::vector<SmVector3d> vecs = read_vecs(rd);
|
|
const SmVector3d* pv = vecs.empty() ? NULL : vecs.data();
|
|
if (op == OP_GCS)
|
|
{
|
|
double tgt = 0.0;
|
|
const double* pt = opt_target(rd, tgt);
|
|
SmSolutionRequestedType req = (SmSolutionRequestedType)rd.idx();
|
|
SmSolutionArray sols;
|
|
SmStatus r = s->GlobalCurveSolve(d, *c, SmExtent1d(a, b), sop, tol, pt, pv, req, sols);
|
|
o.push_back(st(r));
|
|
o.push_back((double)sols.GetSize());
|
|
}
|
|
else
|
|
{
|
|
SmPoint2d guv = rd.uv();
|
|
double gt = rd.num();
|
|
SmBoolean found = FALSE;
|
|
SmSolution sol;
|
|
SmStatus r = s->LocalCurveSolve(d, *c, SmExtent1d(a, b), sop, tol, NULL, pv, guv, gt, found, sol);
|
|
o.push_back(st(r));
|
|
o.push_back(flg(found));
|
|
if (r == SM_SUCCESS && found)
|
|
{
|
|
o.push_back(sol.m_vStart.m_dSolutionValue);
|
|
o.push_back(sol.m_vStart[0]);
|
|
o.push_back(sol.m_vStart[1]);
|
|
o.push_back(sol.m_vStart[2]);
|
|
}
|
|
}
|
|
delete c;
|
|
break;
|
|
}
|
|
case OP_GSS:
|
|
{
|
|
SmExtent2d d = rd.dom();
|
|
SmSurface* s2 = read_surface(rd, ctx);
|
|
SmExtent2d d2 = rd.dom();
|
|
SmSolverOperationType sop = (SmSolverOperationType)rd.idx();
|
|
double tol = rd.num();
|
|
std::vector<SmVector3d> vecs = read_vecs(rd);
|
|
double tgt = 0.0;
|
|
const double* pt = opt_target(rd, tgt);
|
|
SmSolutionRequestedType req = (SmSolutionRequestedType)rd.idx();
|
|
SmSolutionArray sols;
|
|
SmStatus r = s->GlobalSurfaceSolve(d, *s2, d2, sop, tol, pt, vecs.empty() ? NULL : vecs.data(), req, sols);
|
|
o.push_back(st(r));
|
|
o.push_back((double)sols.GetSize());
|
|
delete s2;
|
|
break;
|
|
}
|
|
case OP_PROJ:
|
|
{
|
|
SmExtent2d d = rd.dom();
|
|
SmBSplineCurve* c = read_curve(rd, ctx);
|
|
SmVector3d v = rd.vec();
|
|
double dist = 0.0;
|
|
const double* pd = opt_target(rd, dist);
|
|
SmTArray<SmCurve*> c3d, cuv;
|
|
SmStatus r = s->CreateParallelProjectionCurves(ctx, d, *c, v, pd, NULL, NULL, &c3d, &cuv);
|
|
o.push_back(st(r));
|
|
o.push_back((double)c3d.GetSize());
|
|
for (ULONG i = 0; i < c3d.GetSize(); i++)
|
|
delete c3d[i];
|
|
for (ULONG i = 0; i < cuv.GetSize(); i++)
|
|
delete cuv[i];
|
|
delete c;
|
|
break;
|
|
}
|
|
case OP_LOAD_GUESSES:
|
|
{
|
|
SmExtent2d d = rd.dom();
|
|
SmPoint3d p = rd.vec();
|
|
SmSolverOperationType sop = (SmSolverOperationType)rd.idx();
|
|
SmPoint2d g[1];
|
|
ULONG n = 0;
|
|
SmStatus r = sc_srf_p7::sm_LoadGuesses(s, NULL, d, p, sop, g, n);
|
|
o.push_back(st(r));
|
|
if (r == SM_SUCCESS)
|
|
put_uv(o, g[0]);
|
|
break;
|
|
}
|
|
case OP_PASS_SC:
|
|
{
|
|
SmPoint2d uv = rd.uv();
|
|
SmBSplineCurve* c = read_curve(rd, ctx);
|
|
double t = rd.num();
|
|
o.push_back(0.0);
|
|
o.push_back(flg(sc_srf_p7::sm_PassSCConvergenceTest(*s, uv, *c, t)));
|
|
delete c;
|
|
break;
|
|
}
|
|
case OP_PASS_SS:
|
|
{
|
|
SmPoint2d uv = rd.uv();
|
|
SmSurface* s2 = read_surface(rd, ctx);
|
|
SmPoint2d uv2 = rd.uv();
|
|
o.push_back(0.0);
|
|
o.push_back(flg(sc_srf_p7::sm_PassSSConvergenceTest(*s, uv, *s2, uv2)));
|
|
delete s2;
|
|
break;
|
|
}
|
|
case OP_GOOD_DROP:
|
|
{
|
|
SmExtent2d d = rd.dom();
|
|
SmPoint3d p = rd.vec();
|
|
SmPoint2d g = rd.uv();
|
|
SmSolution sol;
|
|
sol.m_vStart.m_dSolutionValue = rd.num();
|
|
sol.m_vStart[0] = rd.num();
|
|
sol.m_vStart[1] = rd.num();
|
|
o.push_back(0.0);
|
|
o.push_back(flg(sc_srf_p7::sm_GoodDropResult(s, d, p, g, sol)));
|
|
break;
|
|
}
|
|
case OP_CHECK_SEAM:
|
|
{
|
|
SmPoint2d uv = rd.uv();
|
|
SmExtent2d d = rd.dom();
|
|
SmSurface* s2 = read_surface(rd, ctx);
|
|
SmPoint2d uv2 = rd.uv();
|
|
SmExtent2d d2 = rd.dom();
|
|
SmLocationType loc = (SmLocationType)rd.idx();
|
|
SmStatus r = sc_srf_p7::sm_CheckSeamDrop(s, uv, d, s2, uv2, d2, loc);
|
|
o.push_back(st(r));
|
|
if (r == SM_SUCCESS)
|
|
put_uv(o, uv);
|
|
delete s2;
|
|
break;
|
|
}
|
|
default:
|
|
o.push_back((double)SC_ERR_ARG);
|
|
break;
|
|
}
|
|
delete s;
|
|
}
|
|
} // namespace
|
|
|
|
SC_EXPORT int32_t sc_surface_surface_p7_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<double> 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
|
|
}
|