// SPDX-License-Identifier: Apache-2.0 // Calls the pinned SmIntegrator / SmODEIntegrator implementations, without copies // of the algorithm under test. Evaluator arrays are adapted to upstream's index 1. #include "sc_shim.h" #include "StdAfx.h" #include #include #include namespace { struct Eval : SmODEIntegFuncEvalObj { int kind; const double* c; int64_t n; Eval(int k, const double* p, int64_t count) : kind(k), c(p), n(count) {} SmStatus Evaluate(double t, SmTArray& y, SmTArray& dy) const override { for (int64_t i=0; i=p[0]) return SM_ERR; if (kind==0 || kind==3) dy[i+1]=p[0]+p[1]*t+p[2]*t*t+p[3]*y[i+1]; if (kind==1) dy[i+1]=p[0]*std::sin(p[1]*t+p[2])+p[3]*y[i+1]; if (kind==2) dy[i+1]=p[0]*std::exp(p[1]*t)+p[2]*y[i+1]+p[3]; if (!std::isfinite(dy[i+1])) return SM_ERR; } return SM_SUCCESS; } }; struct Scalar : SmIntegFuncEvalObj { const Eval& eval; explicit Scalar(const Eval& e) : eval(e) {} SmStatus Evaluate(double t, double& result) const override { SmTArray y(2, NULL, 2), dy(2, NULL, 2); y.SetAll(0.0); dy.SetAll(0.0); SmStatus st=eval.Evaluate(t,y,dy); result=dy[1]; return st; } }; } // op=0 scalar, 1 ODE, 2 adaptive step. controls: x1 x2 eps h1 hmin tiny algorithm. // Result: status then on success scalar, or y + good/reduced, or y+x+hdid+hnext+scale. SC_EXPORT int32_t sc_mass_integrator_eval(int32_t op, int32_t kind, const double* coeff, const double* initial, int64_t n, const double* scale, int64_t ns, const double* controls, int64_t max_steps, double* out, int64_t cap, int64_t* len) { if (op<0 || op>2 || kind<0 || kind>3 || n<0 || n>4096 || (ns!=0 && ns!=n) || (op==0 && n!=1) || (op==2 && ns!=n) || max_steps<0 || max_steps>1000000) return SC_ERR_ARG; SC_TRY Eval eval(kind,coeff,n); std::vector result; if (op==0) { Scalar scalar(eval); SmIntegrator integrator(scalar); double value=0.0; SmStatus st=integrator.IntegrateIt(controls[0],controls[1], controls[6]==0 ? SM_IA_ROMBERG : SM_IA_SIMPSONS,controls[2],value); result.push_back(st==SM_SUCCESS?0.0:(double)st); if (st==SM_SUCCESS) result.push_back(value); } else { SmODEIntegrator integrator(eval,(ULONG)max_steps,controls[5]); SmTArray y, ys; for (int64_t i=0;i y1(n+1,NULL,n+1), dy(n+1,NULL,n+1), s1(n+1,NULL,n+1); y1.SetAll(0.0); dy.SetAll(0.0); s1.SetAll(0.0); for(int64_t i=0;i #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { void put_moments(std::vector& o, const SmTArray& m) { for (ULONG i=0;i2||kind<0||kind>1)return SC_ERR_ARG; SC_TRY SmContext ctx; std::unique_ptr brep(new(ctx)SmBrep()); SmBSplineCurve* c=nullptr; if(kind==1)c=new(ctx)SmLine(SmPoint3d(p[0],p[1],p[2]),SmVector3d(p[3],p[4],p[5]),SmExtent1d(0,1),1.0,3,&ctx); else { gw_CURVE* cur=sm_AllocateNurbCurve(2,2,5); for(int i=0;i<3;++i){cur->pol->Pw[i].x=p[3*i];cur->pol->Pw[i].y=p[3*i+1];cur->pol->Pw[i].z=p[3*i+2];cur->pol->Pw[i].w=weights[i];} for(int i=0;i<6;++i)cur->knt->U[i]=i<3?0.0:1.0; c=new(ctx)SmBSplineCurve(cur,3,FALSE); } SmEdge* edge=nullptr; SmStatus st=brep->CreateWireEdgeFromCurve(c,SmExtent1d(controls[0],controls[1]),edge); std::vector result; if(st!=SM_SUCCESS){result.push_back(st==SM_SUCCESS?0.0:(double)st);return sc_copy_out(result.data(),result.size(),out,cap,len);} double length=0,area=0,volume=0,mass=0; SmTArray moments; SmPoint3d origin(controls[3],controls[4],controls[5]); if(op==0)st=edge->ComputePreciseProperties(controls[2],origin,controls[6],length,area,volume,moments); if(op==1)st=SmApiEdgeComputeLength(edge,controls[2],length); if(op==2){SmMassPropertyBehavior behavior(1,0,controls[6]);st=brep->ComputePreciseProperties(controls[2],origin,behavior,area,volume,mass,moments);} result.push_back(st==SM_SUCCESS?0.0:(double)st); if(st==SM_SUCCESS){if(op!=2)result.push_back(length);if(op!=1){result.push_back(area);result.push_back(volume);if(op==2)result.push_back(mass);put_moments(result,moments);}} return sc_copy_out(result.data(),result.size(),out,cap,len); SC_CATCH } // p: plane origin[3], UV scales[2], UV domain[4], computation origin[3], accuracy, // thickness, orientation (0 SAME, 1 OPPOSITE), property flags. // kind 0 rectangle, 1 disk, 2 annulus, 3 quadratic B-spline patch, 4 rotated plane, // 5 multi-span rational quadratic B-spline patch (u knot 0.4, double v knot 0.5). // op 0 properties, 1 export input UV domain/bbox scale/oriented trims (NURB, then 1 + SmLine members or 0), 2 API area, 3 API centroid, // 4 API Brep area, 5 API Brep volume, 6 API Brep mass properties (sheet rejection), 7 Surface::Area. SC_EXPORT int32_t sc_mass_integrator_face(int32_t op,int32_t kind,const double* p,double* out,int64_t cap,int64_t* len){ if(op<0||op>7||kind<0||kind>5)return SC_ERR_ARG; SC_TRY SmContext ctx; std::unique_ptr brep(new(ctx)SmBrep()); SmExtent2d dom(SmPoint2d(p[5],p[6]),SmPoint2d(p[7],p[8])); SmVector3d xaxis=kind==4?SmVector3d(.6,.8,0):SmVector3d(1,0,0); SmVector3d yaxis=kind==4?SmVector3d(-.8,.6,0):SmVector3d(0,1,0); SmSurface* surface=nullptr; if(kind==3){ gw_SURFACE* s=sm_AllocateNurbSurface(2,2,2,2,5,5); for(int i=0;i<3;++i)for(int j=0;j<3;++j){ s->net->Pw[i][j].x=p[0]+i*.5*p[3]; s->net->Pw[i][j].y=p[1]+j*.5*p[4]; s->net->Pw[i][j].z=p[2]+(i==1&&j==1?2.0:0.0); s->net->Pw[i][j].w=1.0; } for(int i=0;i<6;++i){s->knu->U[i]=i<3?0:1;s->knv->U[i]=i<3?0:1;} surface=new(ctx)SmBSplineSurface(s,FALSE,NULL); }else if(kind==5){ // 4 x 5 control points: knot spans [0,.4],[.4,1] in u and [0,.5],[.5,1] in v, // the v knot double (C0, as a rational circle's), weights .8 on the middle row. gw_SURFACE* s=sm_AllocateNurbSurface(3,4,2,2,6,7); for(int i=0;i<4;++i)for(int j=0;j<5;++j){ s->net->Pw[i][j].x=p[0]+i*p[3]/3.0; s->net->Pw[i][j].y=p[1]+j*p[4]/4.0; s->net->Pw[i][j].z=p[2]+(double)(i*(3-i)*j*(4-j))*0.125; s->net->Pw[i][j].w=j==2?0.8:1.0; } const double ku[7]={0,0,0,.4,1,1,1},kv[8]={0,0,0,.5,.5,1,1,1}; for(int i=0;i<7;++i)s->knu->U[i]=ku[i]; for(int i=0;i<8;++i)s->knv->U[i]=kv[i]; surface=new(ctx)SmBSplineSurface(s,FALSE,NULL); }else surface=new(ctx)SmPlane(SmPoint3d(p[0],p[1],p[2]),xaxis,yaxis,SmVector2d(p[3],p[4]),dom,&ctx); SmFace* face=nullptr; SmStatus st; if(kind==1||kind==2){ SmTArray loops;SmTArray curves;SmTArray orientations; for(int i=0;i<(kind==2?2:1);++i){ loops.Add(1);orientations.Add(i==0?SM_OT_SAME:SM_OT_OPPOSITE); curves.Add(new(ctx)SmCircle(SmPoint3d(p[0],p[1],p[2]),xaxis,yaxis,SmExtent1d(0,360),i==0?.5:.2,3,&ctx)); } SmShell* shell=nullptr;SmTArray faces; st=brep->CreateFacesWithCurves(NULL,loops,&curves,orientations,surface,shell,faces); if(st==SM_SUCCESS&&faces.GetSize()==1)face=faces[0];else if(st==SM_SUCCESS)st=SM_ERR; }else st=brep->CreateFaceFromSurface(surface,dom,face); std::vector result; if(st!=SM_SUCCESS){result.push_back(st==SM_SUCCESS?0.0:(double)st);return sc_copy_out(result.data(),result.size(),out,cap,len);} if(op==1){ SmTArray loops;SmTArray curves; // Match op 0's order: estimate the scale before creating oriented trims. SmExtent3d bbox;face->CalculateBoundingBox(bbox);SmVector3d size=bbox.GetSize(); double d=smos_Max(size.z,smos_Max(size.x,size.y)); st=face->CreateOrientedTrimBoundary(ctx,TRUE,TRUE,loops,curves); result.push_back(st==SM_SUCCESS?0.0:(double)st); if(st==SM_SUCCESS){ // Export integration inputs only: actual UV domain and bbox-derived scale. result.push_back(d*d/100.0); // ComputePreciseProperties' own face box, taken after the oriented trims. SmExtent3d fbox;face->CalculateBoundingBox(fbox); result.push_back(fbox.GetMin().x);result.push_back(fbox.GetMin().y);result.push_back(fbox.GetMin().z); result.push_back(fbox.GetMax().x);result.push_back(fbox.GetMax().y);result.push_back(fbox.GetMax().z); SmExtent2d domain=face->GetUVDomain(); result.push_back(domain.GetMin().x);result.push_back(domain.GetMin().y); result.push_back(domain.GetMax().x);result.push_back(domain.GetMax().y); result.push_back(curves.GetSize());for(ULONG i=0;iGetGwNurbPointer();result.push_back(c->pol->n);result.push_back(c->p);result.push_back(c->knt->m); for(gw_INDEX j=0;j<=c->pol->n;++j){result.push_back(c->pol->Pw[j].x);result.push_back(c->pol->Pw[j].y);result.push_back(c->pol->Pw[j].z);result.push_back(c->pol->Pw[j].w);} for(gw_INDEX j=0;j<=c->knt->m;++j)result.push_back(c->knt->U[j]); // Trims are often analytic SmLines, whose Evaluate differs from the NURB's. if(curves[i]->GetType()==SmLine_TYPE){const SmLine* l=(const SmLine*)curves[i]; const SmPoint3d& lp=l->GetLinePoint();const SmVector3d& lv=l->GetLineVector();SmExtent1d ad=l->GetSTEPInterval(); result.push_back(1.0);result.push_back(lp.x);result.push_back(lp.y);result.push_back(lp.z); result.push_back(lv.x);result.push_back(lv.y);result.push_back(lv.z);result.push_back(ad.GetMin());result.push_back(ad.GetMax()); result.push_back(l->GetLineScale());result.push_back(l->GetInsideOut()?1.0:0.0);} else result.push_back(0.0);}} for(ULONG i=0;i moments; SmPoint3d origin(p[9],p[10],p[11]); if(op==0){SmExtent3d bbox;face->CalculateBoundingBox(bbox);SmVector3d s=bbox.GetSize();double d=smos_Max(s.z,smos_Max(s.x,s.y)); st=face->ComputePreciseProperties(p[14]==0?SM_OT_SAME:SM_OT_OPPOSITE,p[12],origin,d*d/100.0,p[13],area,volume,moments,(ULONG)p[15]);} if(op==7)st=face->GetSurface()->Area(dom,p[12],area); if(op==2)st=SmApiFaceComputeArea(face,p[12],area); if(op==3)st=SmApiFaceComputeCentroid(face,p[12],area,centroid); if(op==4)st=SmApiBrepComputeArea(brep.get(),p[12],area); if(op==5)st=SmApiBrepComputeVolume(brep.get(),p[12],volume); if(op==6)st=SmApiBrepComputeMassProperties(brep.get(),p[12],1.0,origin,area,volume,mass,centroid,inertia,products); result.push_back(st==SM_SUCCESS?0.0:(double)st); if(st==SM_SUCCESS){if(op==5)result.push_back(volume);else{result.push_back(area);if(op==0){result.push_back(volume);put_moments(result,moments);}if(op==3){result.push_back(centroid.x);result.push_back(centroid.y);result.push_back(centroid.z);}}} } return sc_copy_out(result.data(),result.size(),out,cap,len); SC_CATCH }