ON_BOOL32 ON_ArcCurve::SetEndPoint(ON_3dPoint end_point) { if (IsCircle()) return false; ON_BOOL32 rc = false; if ( m_dim == 3 || end_point.z == 0.0 ) { ON_3dPoint P; ON_3dVector T; double t = Domain()[0]; Ev1Der( t, P, T ); ON_Arc a; rc = a.Create( P, T, end_point ); if ( rc ) { m_arc = a; } else { ON_3dPoint start_point = PointAt(Domain()[0]); if (end_point.DistanceTo(start_point) < ON_ZERO_TOLERANCE*m_arc.Radius()){ //make arc into circle m_arc.plane.xaxis = start_point - m_arc.Center(); m_arc.plane.xaxis.Unitize(); m_arc.plane.yaxis = ON_CrossProduct(m_arc.Normal(), m_arc.plane.xaxis); m_arc.plane.yaxis.Unitize(); m_arc.SetAngleRadians(2.0*ON_PI); rc = true; } } } return rc; }
bool ON_Surface::IsContinuous( ON::continuity desired_continuity, double s, double t, int* hint, // default = NULL, double point_tolerance, // default=ON_ZERO_TOLERANCE double d1_tolerance, // default==ON_ZERO_TOLERANCE double d2_tolerance, // default==ON_ZERO_TOLERANCE double cos_angle_tolerance, // default==ON_DEFAULT_ANGLE_TOLERANCE_COSINE double curvature_tolerance // default==ON_SQRT_EPSILON ) const { int qi, span_count[2]; span_count[0] = SpanCount(0); span_count[1] = SpanCount(1); if ( span_count[0] <= 1 && span_count[1] <= 1 ) return true; ON_3dPoint P[4]; ON_3dVector Ds[4], Dt[4], Dss[4], Dst[4], Dtt[4], N[4], K1[4], K2[4]; double gauss[4], mean[4], kappa1[4], kappa2[4], sq[4], tq[4]; switch ( desired_continuity ) { case ON::C0_locus_continuous: case ON::C1_locus_continuous: case ON::C2_locus_continuous: case ON::G1_locus_continuous: case ON::G2_locus_continuous: { // 7 April 2005 Dale Lear // This locus continuity test was added. Prior to // this time, this function ignored the word "locus". // The reason for the change is that Chuck's filleting code // needs to query the continuity at the seams of closed surfaces. // See ON::continuity comments. The different sq[] values // must NOT be used when s == Domain(0)[0] and must always // be used when s == Domain(0)[1]. In particular, if a surface // is not closed in the "s" direction and s == Domain(1)[1], then // the answer to any locus query is false. ON_Interval d = Domain(0); if ( s == d[1] ) { sq[0] = sq[1] = d[0]; sq[2] = sq[3] = d[1]; } else { sq[0] = sq[1] = sq[2] = sq[3] = s; } d = Domain(1); // See ON::continuity comments. The different tq[] values // must NOT be used when t == Domain(1)[0] and must always // be used when t == Domain(1)[1]. In particular, if a surface // is not closed in the "t" direction and t == Domain(1)[1], then // the answer to any locus query is false. if ( t == d[1] ) { tq[0] = tq[3] = d[0]; tq[1] = tq[2] = d[1]; } else { tq[0] = tq[1] = tq[2] = tq[3] = t; } } break; default: sq[0] = sq[1] = sq[2] = sq[3] = s; tq[0] = tq[1] = tq[2] = tq[3] = t; break; } desired_continuity = ON::ParametricContinuity(desired_continuity); // this is slow and uses evaluation // virtual overrides on curve classes that can have multiple spans // are much faster because the avoid evaluation switch ( desired_continuity ) { case ON::C0_continuous: for ( qi = 0; qi < 4; qi++ ) { if ( !EvPoint( sq[qi], tq[qi], P[qi], qi+1 ) ) return false; if ( qi ) { if ( !(P[qi]-P[qi-1]).IsTiny(point_tolerance) ) return false; } } if ( !(P[3]-P[0]).IsTiny(point_tolerance) ) return false; break; case ON::C1_continuous: for ( qi = 0; qi < 4; qi++ ) { if ( !Ev1Der( sq[qi], tq[qi], P[qi], Ds[qi], Dt[qi], qi+1, hint ) ) return false; if ( qi ) { if ( !(P[qi]-P[qi-1]).IsTiny(point_tolerance) ) return false; if ( !(Ds[qi]-Ds[qi-1]).IsTiny(d1_tolerance) ) return false; if ( !(Dt[qi]-Dt[qi-1]).IsTiny(d1_tolerance) ) return false; } } if ( !(P[3]-P[0]).IsTiny(point_tolerance) ) return false; if ( !(Ds[3]-Ds[0]).IsTiny(d1_tolerance) ) return false; if ( !(Dt[3]-Dt[0]).IsTiny(d1_tolerance) ) return false; break; case ON::C2_continuous: for ( qi = 0; qi < 4; qi++ ) { if ( !Ev2Der( sq[qi], tq[qi], P[qi], Ds[qi], Dt[qi], Dss[qi], Dst[qi], Dtt[qi], qi+1, hint ) ) return false; if ( qi ) { if ( !(P[qi]-P[qi-1]).IsTiny(point_tolerance) ) return false; if ( !(Ds[qi]-Ds[qi-1]).IsTiny(d1_tolerance) ) return false; if ( !(Dt[qi]-Dt[qi-1]).IsTiny(d1_tolerance) ) return false; if ( !(Dss[qi]-Dss[qi-1]).IsTiny(d2_tolerance) ) return false; if ( !(Dst[qi]-Dst[qi-1]).IsTiny(d2_tolerance) ) return false; if ( !(Dtt[qi]-Dtt[qi-1]).IsTiny(d2_tolerance) ) return false; } } if ( !(P[3]-P[0]).IsTiny(point_tolerance) ) return false; if ( !(Ds[3]-Ds[0]).IsTiny(d1_tolerance) ) return false; if ( !(Dt[3]-Dt[0]).IsTiny(d1_tolerance) ) return false; if ( !(Dss[3]-Dss[0]).IsTiny(d2_tolerance) ) return false; if ( !(Dst[3]-Dst[0]).IsTiny(d2_tolerance) ) return false; if ( !(Dtt[3]-Dtt[0]).IsTiny(d2_tolerance) ) return false; break; case ON::G1_continuous: for ( qi = 0; qi < 4; qi++ ) { if ( !EvNormal( sq[qi], tq[qi], P[qi], N[qi], qi+1 ) ) return false; if ( qi ) { if ( !(P[qi]-P[qi-1]).IsTiny(point_tolerance) ) return false; if ( N[qi]*N[qi-1] < cos_angle_tolerance ) return false; } } if ( !(P[3]-P[0]).IsTiny(point_tolerance) ) return false; if ( N[3]*N[0] < cos_angle_tolerance ) return false; break; case ON::G2_continuous: case ON::Gsmooth_continuous: { bool bSmoothCon = (ON::Gsmooth_continuous == desired_continuity); for ( qi = 0; qi < 4; qi++ ) { if ( !Ev2Der( sq[qi], tq[qi], P[qi], Ds[qi], Dt[qi], Dss[qi], Dst[qi], Dtt[qi], qi+1, hint ) ) return false; ON_EvPrincipalCurvatures( Ds[qi], Dt[qi], Dss[qi], Dst[qi], Dtt[qi], N[qi], &gauss[qi], &mean[qi], &kappa1[qi], &kappa2[qi], K1[qi], K2[qi] ); if ( qi ) { if ( !(P[qi]-P[qi-1]).IsTiny(point_tolerance) ) return false; if ( N[qi]*N[qi-1] < cos_angle_tolerance ) return false; if ( !PrincipalCurvaturesAreContinuous(bSmoothCon,kappa1[qi],kappa2[qi],kappa1[qi-1],kappa2[qi-1],curvature_tolerance) ) return false; } if ( !(P[3]-P[0]).IsTiny(point_tolerance) ) return false; if ( N[3]*N[0] < cos_angle_tolerance ) return false; if ( !PrincipalCurvaturesAreContinuous(bSmoothCon,kappa1[3],kappa2[3],kappa1[0],kappa2[0],curvature_tolerance) ) return false; } } break; default: // intentionally ignoring other ON::continuity enum values break; } return true; }
bool ON_Surface::IsAtSingularity(double s, double t, bool bExact //true by default ) const { if (bExact){ if (s == Domain(0)[0]){ if (IsSingular(3)) return true; } else if (s == Domain(0)[1]){ if (IsSingular(1)) return true; } if (t == Domain(1)[0]){ if (IsSingular(0)) return true; } else if (t == Domain(1)[1]){ if (IsSingular(2)) return true; } return false; } if (IsAtSingularity(s, t, true)) return true; bool bCheckPartials[2] = {false, false}; int i; double m[2]; for (i=0; i<2; i++) m[i] = Domain(i).Mid(); if (s < m[0]){ if (IsSingular(3)) bCheckPartials[1] = true; } else { if (IsSingular(1)) bCheckPartials[1] = true; } if (!bCheckPartials[0] && !bCheckPartials[1]){ if (t < m[1]){ if (IsSingular(0)) bCheckPartials[0] = true; } else { if (IsSingular(2)) bCheckPartials[0] = true; } } if (!bCheckPartials[0] && !bCheckPartials[1]) return false; ON_3dPoint P; ON_3dVector M[2], S[2]; if (!Ev1Der(s, t, P, S[0], S[1])) return false; if (!Ev1Der(m[0], m[1], P, M[0], M[1])) return false; for (i=0; i<2; i++){ if (!bCheckPartials[i]) continue; if (S[i].Length() < 1.0e-6 * M[i].Length()) return true; } return false; }
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; }