// Try to make up a 1st derivative if one is zero length static void CookDerivativesHelper( ON_3dVector& du, ON_3dVector& dv, ON_3dVector& duu, ON_3dVector& duv, ON_3dVector& dvv) { bool du_ok = du.LengthSquared() > ON_SQRT_EPSILON; bool dv_ok = dv.LengthSquared() > ON_SQRT_EPSILON; if( !du_ok || !dv_ok) { ON_3dVector normal; bool normal_ok = ON_EvNormal( 0, du, dv, duu, duv, dvv, normal ) ? true : false; if( normal_ok) normal_ok = normal.LengthSquared() > ON_SQRT_EPSILON; if( normal_ok) { if(( !du_ok) && ( dv_ok && normal_ok)) { du = ON_CrossProduct( dv, normal); du_ok = du.Unitize(); du *= (0.00390625*dv.Length()); } if( du_ok && ( !dv_ok) && normal_ok) { dv = ON_CrossProduct( normal, du); dv_ok = dv.Unitize(); dv *= (0.00390625*du.Length()); } } } }
bool ON_PolyEdgeCurve::EvSrfTangent( double t, bool bIsoDir, ON_3dPoint& srfpoint, ON_3dVector& srftangent, ON_3dVector& srfnormal ) const { ON_3dPoint srfpt; ON_3dVector du, dv, duu, duv, dvv; bool rc = EvSrfDerivatives(t,srfpoint,du,dv,duu,duv,dvv); if (rc ) rc = ON_EvNormal( 0, du, dv, duu, duv, dvv, srfnormal ) ? true : false; if (rc) { int segment_index = SegmentIndex(t); ON_PolyEdgeSegment* seg = SegmentCurve(segment_index); if ( seg ) { if ( bIsoDir && seg->IsoType() == ON_Surface::not_iso ) bIsoDir = false; ON_3dVector crvtangent = TangentAt(t); ON_3dVector binormal = ON_CrossProduct(crvtangent,srfnormal); binormal.Unitize(); if ( seg->ReversedTrimDir() ) binormal.Reverse(); // at this point, binormal points "out" and is tangent // to the surface. if ( bIsoDir ) { du.Unitize(); dv.Unitize(); double B_dot_du = binormal*du; double B_dot_dv = binormal*dv; if ( fabs(B_dot_dv) > fabs(B_dot_du) ) { if (B_dot_dv < 0.0) dv.Reverse(); srftangent = dv; } else { if (B_dot_du < 0.0) du.Reverse(); srftangent = du; } } else srftangent = binormal; if ( seg && seg->m_face && seg->m_face->m_bRev ) srfnormal.Reverse(); } else rc = false; } return rc; }
bool ON_PolyEdgeCurve::EvSrfNormalCurvature( double t, ON_3dVector srftangent, ON_3dVector& srfnormalcurvature, ON_3dVector& srfnormal ) const { ON_3dPoint srfpt; ON_3dVector du, dv, duu, duv, dvv; bool rc = EvSrfDerivatives(t,srfpt,du,dv,duu,duv,dvv); if (rc ) rc = ON_EvNormal( 0, du, dv, duu, duv, dvv, srfnormal )?true:false; if( rc) { srfnormalcurvature = ON_NormalCurvature( du, dv, duu, duv, dvv, srfnormal, srftangent ); } return rc; }
ON_BOOL32 ON_OffsetSurface::Evaluate( double s, double t, int der_count, int v_stride, double* v, int side, int* hint ) const { int vv_stride = v_stride; double* vv = v; ON_3dVector srf_value[6];//, normal_value[3]; if ( der_count < 2 ) { vv = &srf_value[0].x; vv_stride = 3; } ON_BOOL32 rc = ON_SurfaceProxy::Evaluate(s,t,(der_count>2?der_count:2),vv_stride,vv,side,hint); if ( v != vv ) { // save answer in v[] array v[0] = srf_value[0].x; v[1] = srf_value[0].y; v[2] = srf_value[0].z; if ( der_count > 0 ) { v[v_stride] = srf_value[1].x; v[v_stride+1] = srf_value[1].y; v[v_stride+2] = srf_value[1].z; v[2*v_stride] = srf_value[2].x; v[2*v_stride+1] = srf_value[2].y; v[2*v_stride+2] = srf_value[2].z; } } else { srf_value[0] = v; srf_value[1] = v+v_stride; srf_value[2] = v+2*v_stride; srf_value[3] = v+3*v_stride; srf_value[4] = v+4*v_stride; srf_value[5] = v+5*v_stride; } if (rc) { double darray[21]; // 21 = ((5+1)*(5+2)/2) = enough room for der_count <= 5 double* d = (der_count>5) ? (double*)onmalloc(((der_count+1)*(der_count+2))/2*sizeof(d[0])) : darray; rc = m_offset_function.EvaluateDistance(s,t,der_count,d); if (rc) { ON_3dVector N; ON_EvNormal(side, srf_value[1], srf_value[2], srf_value[3], srf_value[4], srf_value[5], N); v[0] += d[0]*N.x; v[1] += d[0]*N.y; v[2] += d[0]*N.z; if ( der_count > 0 ) { ON_3dVector Ns, Nt; ON_EvNormalPartials(srf_value[1], srf_value[2], srf_value[3], srf_value[4], srf_value[5], Ns, Nt); v[v_stride] += d[0]*Ns.x + d[1]*N.x; v[v_stride+1] += d[0]*Ns.y + d[1]*N.y; v[v_stride+2] += d[0]*Ns.z + d[1]*N.z; v[2*v_stride] += d[0]*Nt.x + d[2]*N.x; v[2*v_stride+1] += d[0]*Nt.y + d[2]*N.y; v[2*v_stride+2] += d[0]*Nt.z + d[2]*N.z; } } if ( d != darray ) onfree(d); } return rc; }
ON_BOOL32 ON_Surface::EvNormal( // returns false if unable to evaluate double s, double t, // evaluation parameters (s,t) ON_3dPoint& point, // returns value of surface ON_3dVector& ds, // first partial derivatives (Ds) ON_3dVector& dt, // (Dt) ON_3dVector& normal, // unit normal int side, // optional - determines which side to evaluate from // 0 = default // 1 from NE quadrant // 2 from NW quadrant // 3 from SW quadrant // 4 from SE quadrant int* hint // optional - evaluation hint (int[2]) used to speed // repeated evaluations ) const { // simple cross product normal - override to support singular surfaces ON_BOOL32 rc = Ev1Der( s, t, point, ds, dt, side, hint ); if ( rc ) { const double len_ds = ds.Length(); const double len_dt = dt.Length(); // do not reduce the tolerance used here - there is a retry in the code // below. if ( len_ds > ON_SQRT_EPSILON*len_dt && len_dt > ON_SQRT_EPSILON*len_ds ) { ON_3dVector a = ds/len_ds; ON_3dVector b = dt/len_dt; normal = ON_CrossProduct( a, b ); rc = normal.Unitize(); } else { // see if we have a singular point double v[6][3]; int normal_side = side; ON_BOOL32 bOnSide = false; ON_Interval sdom = Domain(0); ON_Interval tdom = Domain(1); if (s == sdom.Min()) { normal_side = (normal_side >= 3) ? 4 : 1; bOnSide = true; } else if (s == sdom.Max()) { normal_side = (normal_side >= 3) ? 3 : 2; bOnSide = true; } if (t == tdom.Min()) { normal_side = (normal_side == 2 || normal_side == 3) ? 2 : 1; bOnSide = true; } else if (t == tdom.Max()) { normal_side = (normal_side == 2 || normal_side == 3) ? 3 : 4; bOnSide = true; } if ( !bOnSide ) { // 2004 November 11 Dale Lear // Added a retry again with a more generous tolerance if ( len_ds > ON_EPSILON*len_dt && len_dt > ON_EPSILON*len_ds ) { ON_3dVector a = ds/len_ds; ON_3dVector b = dt/len_dt; normal = ON_CrossProduct( a, b ); rc = normal.Unitize(); } else { rc = false; } } else { rc = Evaluate( s, t, 2, 3, &v[0][0], normal_side, hint ); if ( rc ) { rc = ON_EvNormal( normal_side, v[1], v[2], v[3], v[4], v[5], normal); } } } } if ( !rc ) { normal.Zero(); } return rc; }