ON_BOOL32 ON_PlaneSurface::GetSpanVector( int dir, double* s ) const { ON_Interval d = Domain(dir); s[0] = d.Min(); s[1] = d.Max(); return d.IsIncreasing(); }
double ON_PolyEdgeSegment::EdgeParameter(double t) const { double edge_t = ON_UNSET_VALUE; if ( m_edge ) { if ( m_t == t && m_edge_t != ON_UNSET_VALUE ) edge_t = m_edge_t; else { ON_PolyEdgeSegment* p = const_cast<ON_PolyEdgeSegment*>(this); if ( t != m_t ) { p->m_t = t; p->m_trim_t = ON_UNSET_VALUE; p->m_srf_uv[0] = ON_UNSET_VALUE; p->m_srf_uv[1] = ON_UNSET_VALUE; } ON_Interval d = Domain(); bool bReversedEdgeDir = ReversedEdgeDir(); if ( bReversedEdgeDir || m_edge_domain != d ) { double s = d.NormalizedParameterAt(t); if ( bReversedEdgeDir ) s = 1.0 - s; edge_t = m_edge_domain.ParameterAt(s); } else edge_t = t; p->m_edge_t = edge_t; } } return edge_t; }
ON_BOOL32 ON_Surface::GetDomain( int dir, double* t0, double* t1 ) const { ON_Interval d = Domain(dir); if ( t0 ) *t0 = d[0]; if ( t1 ) *t1 = d[1]; return d.IsIncreasing(); }
bool ON_Arc::SetAngleIntervalRadians( ON_Interval angle_in_radians ) { bool rc = angle_in_radians.IsIncreasing() && angle_in_radians.Length() < (1.0+ON_SQRT_EPSILON)*2.0*ON_PI; if (rc) { m_angle = angle_in_radians; } return rc; }
ON_Interval ON_CurveProxy::RealCurveInterval( const ON_Interval* sub_domain ) const { if ( !sub_domain ) return m_real_curve_domain; ON_Interval d = m_this_domain; d.Intersection(*sub_domain); double t0 = RealCurveParameter( d[m_bReversed?1:0] ); double t1 = RealCurveParameter( d[m_bReversed?0:1] ); return ON_Interval(t0,t1); }
ON_Color CZAnalysisVAM::FalseColor(double z) const { // Simple example of one way to change a number // into a color. double s = m_z_range.NormalizedParameterAt(z); if ( s < 0.0 ) s = 0.0; else if (s > 1.0) s = 1.0; double hue = m_hue_range.ParameterAt(s); ON_Color c; c.SetHSV( hue, 1.0, 1.0 ); return c; }
ON_BOOL32 ON_Surface::IsClosed(int dir) const { ON_Interval d = Domain(dir); if ( d.IsIncreasing() && Dimension() <= 3 ) { const int span_count = SpanCount(dir?0:1); const int span_degree = Degree(dir?0:1); if ( span_count > 0 && span_degree > 0 ) { ON_SimpleArray<double> s(span_count+1); s.SetCount(span_count+1); int n = 2*span_degree+1; double delta = 1.0/n; ON_3dPoint P, Q; P.Zero(); Q.Zero(); int hintP[2] = {0,0}; int hintQ[2] = {0,0}; double *u0, *u1, *v0, *v1; double t; ON_Interval sp; if ( dir ) { v0 = &d.m_t[0]; v1 = &d.m_t[1]; u0 = &t; u1 = &t; } else { u0 = &d.m_t[0]; u1 = &d.m_t[1]; v0 = &t; v1 = &t; } if ( GetSpanVector( dir?0:1, s.Array() ) ) { int span_index, i; for ( span_index = 0; span_index < span_count; span_index++ ) { sp.Set(s[span_index],s[span_index+1]); for ( i = 0; i < n; i++ ) { t = sp.ParameterAt(i*delta); if ( !Evaluate( *u0, *v0, 1, 3, P, 0, hintP ) ) return false; if ( !Evaluate( *u1, *v1, 2, 3, Q, 0, hintQ ) ) return false; if ( false == ON_PointsAreCoincident( 3, 0, &P.x, &Q.x ) ) return false; } } return true; } } } return false; }
ON_BOOL32 ON_LineCurve::GetNormalizedArcLengthPoint( double s, double* t, double fractional_tolerance, const ON_Interval* sub_domain ) const { ON_Interval domain = (sub_domain) ? *sub_domain : Domain(); if ( t ) *t = domain.ParameterAt(s); return true; }
ON_BOOL32 ON_Surface::GetParameterTolerance( // returns tminus < tplus: parameters tminus <= s <= tplus int dir, double t, // t = parameter in domain double* tminus, // tminus double* tplus // tplus ) const { ON_BOOL32 rc = false; ON_Interval d = Domain( dir ); if ( d.IsIncreasing() ) rc = ON_GetParameterTolerance( d.Min(), d.Max(), t, tminus, tplus ); return rc; }
CRhinoCommand::result CCommandSampleSubCrvLength::RunCommand( const CRhinoCommandContext& context ) { CRhinoGetObject go; go.SetCommandPrompt( L"Select curve to measure" ); go.SetGeometryFilter( CRhinoGetObject::curve_object ); go.GetObjects( 1, 1 ); if( go.CommandResult() != CRhinoCommand::success ) return go.CommandResult(); const CRhinoObjRef& ref = go.Object(0); const ON_Curve* crv = ref.Curve(); if( !crv ) return CRhinoCommand::failure; CRhinoGetPoint gp; gp.SetCommandPrompt( L"First point on curve" ); gp.Constrain( *crv ); gp.GetPoint(); if( gp.CommandResult() != CRhinoCommand::success ) return gp.CommandResult(); double t0; if( !crv->GetClosestPoint(gp.Point(), &t0) ) return CRhinoCommand::nothing; gp.SetCommandPrompt( L"Second point on curve" ); gp.GetPoint(); if( gp.CommandResult() != CRhinoCommand::success ) return gp.CommandResult(); double t1; if( !crv->GetClosestPoint(gp.Point(), &t1) ) return CRhinoCommand::nothing; ON_Interval dom; if( t0 < t1 ) dom.Set( t0, t1 ); else dom.Set( t1, t0 ); double len; if( crv->GetLength(&len, 0.0, &dom) ) RhinoApp().Print( L"Subcurve length = %f.\n", len ); else RhinoApp().Print( L"Unable to calculate length of subcurve.\n" ); return CRhinoCommand::success; }
bool ON_Surface::SetDomain( int dir, ON_Interval domain ) { return ( dir >= 0 && dir <= 1 && domain.IsIncreasing() && SetDomain( dir, domain[0], domain[1] )) ? true : false; }
double ON_PolyEdgeCurve::TrimParameter(double t) const { double trim_t = ON_UNSET_VALUE; int segment_index = SegmentIndex(t); ON_PolyEdgeSegment* seg = SegmentCurve( segment_index ); if ( seg ) { ON_Interval pdom = SegmentDomain(segment_index); ON_Interval sdom = seg->Domain(); if ( sdom != pdom ) { double s = pdom.NormalizedParameterAt(t); t = sdom.ParameterAt(s); } trim_t = seg->TrimParameter(t); } return trim_t; }
ON_2dPoint ON_PolyEdgeCurve::SurfaceParameter(double t) const { ON_2dPoint srf_uv(ON_UNSET_VALUE,ON_UNSET_VALUE); int segment_index = SegmentIndex(t); ON_PolyEdgeSegment* seg = SegmentCurve( segment_index ); if ( seg ) { ON_Interval pdom = SegmentDomain(segment_index); ON_Interval sdom = seg->Domain(); if ( sdom != pdom ) { double s = pdom.NormalizedParameterAt(t); t = sdom.ParameterAt(s); } srf_uv = seg->SurfaceParameter(t); } return srf_uv; }
bool ON_CurveProxy::SetProxyCurveDomain( ON_Interval proxy_curve_subdomain ) { bool rc = proxy_curve_subdomain.IsIncreasing(); if ( rc ) { if ( m_real_curve ) { ON_Interval cdom = m_real_curve->Domain(); cdom.Intersection( proxy_curve_subdomain ); rc = cdom.IsIncreasing(); if (rc ) m_real_curve_domain = cdom; } else { m_real_curve_domain = proxy_curve_subdomain; } } return rc; }
static ON_NurbsSurface* ON_BrepExtrudeHelper_MakeConeSrf( const ON_3dPoint& apex_point, const ON_BrepEdge& edge, ON_BOOL32 bRev ) { // The "s" parameter runs along the edge. // The "t" parameter is the ruling parameter; // t=0 is at the base_edge and t=max is at the apex. // surface side location // south base_edge // east line from bRev?START:END of edge to apex // north singular side at apex // west line from bRev?END:START of edge to apex. ON_NurbsSurface* cone_srf = new ON_NurbsSurface(); if ( cone_srf->CreateConeSurface( apex_point, edge ) ) { if ( bRev ) cone_srf->Reverse(0); // get a decent interval for the ruling parameter double d = 0.0; ON_Interval edom = edge.Domain(); ON_3dPoint pt; int i, hint=0; for ( i = 0; i <= 16; i++ ) { if ( !edge.EvPoint( edom.ParameterAt(i/16.0), pt, 0, &hint ) ) continue; if ( pt.DistanceTo(apex_point) > d ) d = pt.DistanceTo(apex_point); } if ( d > ON_SQRT_EPSILON ) cone_srf->SetDomain(1,0.0,d); } else { delete cone_srf; cone_srf = 0; } return cone_srf; }
bool ON_PlaneSurface::SetExtents( int dir, ON_Interval extents, bool bSyncDomain ) { if ( dir < 0 || dir > 1 || !extents.IsIncreasing() ) return false; m_extents[dir] = extents; if ( bSyncDomain ) m_domain[dir] = m_extents[dir]; return true; }
ON_BOOL32 ON_ArcCurve::Trim( const ON_Interval& in ) { ON_BOOL32 rc = in.IsIncreasing(); if (rc) { double t0 = m_t.NormalizedParameterAt(in.m_t[0]); double t1 = m_t.NormalizedParameterAt(in.m_t[1]); const ON_Interval arc_angle0 = m_arc.DomainRadians(); double a0 = arc_angle0.ParameterAt(t0); double a1 = arc_angle0.ParameterAt(t1); // Resulting ON_Arc must pass IsValid() if ( a1 - a0 > ON_ZERO_TOLERANCE && m_arc.SetAngleIntervalRadians(ON_Interval(a0,a1)) ) { m_t = in; } else { rc = false; } } return rc; }
ON_BOOL32 ON_PolyEdgeCurve::Prepend( ON_PolyEdgeSegment* new_segment ) { DestroyRuntimeCache(); ON_BOOL32 rc = false; if ( new_segment ) { if ( Count() > 0 ) { // keep segment domains in synch with polycurve domain // so that parameter bookkeeping is easy. ON_Interval cdom = Domain(); ON_Interval sdom = new_segment->Domain(); if ( sdom[1] != cdom[0] ) { sdom[0] = cdom[0] - sdom.Length(); sdom[1] = cdom[0]; new_segment->SetDomain(sdom[0],sdom[1]); } } rc = ON_PolyCurve::Prepend(new_segment); } return rc; }
void ON_CurveProxy::SetProxyCurve( const ON_Curve* real_curve, ON_Interval real_curve_subdomain) { if ( real_curve != this ) { // setting m_real_curve=0 prevents crashes if user has deleted // the "real" curve before calling SetProxyCurve(). m_real_curve = 0; DestroyCurveTree(); m_real_curve_domain.Destroy(); m_this_domain.Destroy(); m_bReversed = false; } else { // If you are debugging and end up here, there is a 99% chance // that you passed the wrong pointer to SetProxyCurve(). // However, I will assume you really meant to use a fancy self // reference to adjust domains. if ( IsValid() && m_this_domain.Includes(real_curve_subdomain) ) { real_curve = m_real_curve; // because input real_curve_subdomain was with respect to "this". double r0 = RealCurveParameter(real_curve_subdomain[0]); double r1 = RealCurveParameter(real_curve_subdomain[1]); real_curve_subdomain.Set(r0,r1); } else { real_curve = 0; } // setting m_real_curve=0 prevents crashes if user has deleted // the "real" curve before calling SetProxyCurve(). m_real_curve = 0; DestroyCurveTree(); } m_real_curve = real_curve; if ( m_real_curve ) { SetProxyCurveDomain( real_curve_subdomain ); } else { m_real_curve_domain = real_curve_subdomain; } m_this_domain = m_real_curve_domain; }
ON_BOOL32 ON_LineCurve::Trim( const ON_Interval& domain ) { ON_BOOL32 rc = false; if ( domain.IsIncreasing() ) { ON_3dPoint p = PointAt( domain[0] ); ON_3dPoint q = PointAt( domain[1] ); if( p.DistanceTo(q)>0){ // 2 April 2003 Greg Arden A successfull trim // should return an IsValid ON_LineCurve . m_line.from = p; m_line.to = q; m_t = domain; rc = true; } } return rc; }
bool ON_PolyEdgeCurve::EvSrfDerivatives( double t, ON_3dPoint& srfpoint, ON_3dVector& du, ON_3dVector& dv, ON_3dVector& duu, ON_3dVector& duv, ON_3dVector& dvv ) const { bool rc = false; int segment_index = SegmentIndex(t); ON_PolyEdgeSegment* seg = SegmentCurve( segment_index ); if ( seg ) { ON_Interval pdom = SegmentDomain(segment_index); ON_Interval sdom = seg->Domain(); double s = t; if ( sdom != pdom ) { double x = pdom.NormalizedParameterAt(t); s = sdom.ParameterAt(x); } // s is the segment parameter at the polyedge parameter t // Get the corresponding surfaces parameters ON_2dPoint srf_uv = seg->SurfaceParameter(s); if ( ON_IsValid(srf_uv.x) ) { if ( srf_uv.x == seg->m_evsrf_uv[0] && srf_uv.y == seg->m_evsrf_uv[1] ) { rc = true; srfpoint = seg->m_evsrf_pt; du = seg->m_evsrf_du; dv = seg->m_evsrf_dv; duu = seg->m_evsrf_duu; duv = seg->m_evsrf_duv; dvv = seg->m_evsrf_dvv; } else if ( seg->m_surface ) { rc = seg->m_surface->Ev2Der( srf_uv.x, srf_uv.y, srfpoint, du, dv, duu, duv, dvv, 0, seg->m_evsrf_hint ) ? true : false; if ( rc ) { CookDerivativesHelper( du, dv, duu, duv, dvv); seg->m_evsrf_uv[0] = srf_uv.x; seg->m_evsrf_uv[1] = srf_uv.y; seg->m_evsrf_pt = srfpoint; seg->m_evsrf_du = du; seg->m_evsrf_dv = dv; seg->m_evsrf_duu = duu; seg->m_evsrf_duv = duv; seg->m_evsrf_dvv = dvv; } } } } return rc; }
// override of virtual ON_Curve::Split ON_BOOL32 ON_CurveProxy::Split( double t, ON_Curve*& left_side, ON_Curve*& right_side ) const { ON_BOOL32 rc = false; if ( m_this_domain.IsIncreasing() && m_real_curve_domain.IsIncreasing() && m_this_domain.Includes(t,true) ) { double crv_t = RealCurveParameter(t); if ( m_real_curve_domain.Includes(crv_t,true) ) { ON_CurveProxy* left_proxy = 0; ON_CurveProxy* right_proxy = 0; if ( left_side ) { left_proxy = ON_CurveProxy::Cast(left_side); if ( !left_proxy ) return false; } if ( right_side ) { right_proxy = ON_CurveProxy::Cast(right_side); if ( !right_proxy ) return false; if ( right_side == left_side ) return false; } bool bRev = m_bReversed; ON_Interval left_real_dom, right_real_dom; if ( bRev ) { left_real_dom.Set(crv_t,m_real_curve_domain[1]); right_real_dom.Set(m_real_curve_domain[0],crv_t); } else { left_real_dom.Set(m_real_curve_domain[0],crv_t); right_real_dom.Set(crv_t,m_real_curve_domain[1]); } ON_Interval left_this_dom(m_this_domain[0],t); ON_Interval right_this_dom(t,m_this_domain[1]); if ( left_real_dom.IsIncreasing() && right_real_dom.IsIncreasing() && left_this_dom.IsIncreasing() && right_this_dom.IsIncreasing() ) { // note well that left_proxy or right_proxy might also be this const ON_Curve* real_crv = m_real_curve; if ( real_crv ) { ON_Interval d = real_crv->Domain(); if ( !d.Includes(left_real_dom) ) return false; if ( !d.Includes(right_real_dom) ) return false; } if ( !left_proxy ) left_proxy = new ON_CurveProxy(); if ( !right_proxy ) right_proxy = new ON_CurveProxy(); left_proxy->SetProxyCurve( real_crv, left_real_dom ); right_proxy->SetProxyCurve( real_crv, right_real_dom ); if ( bRev ) { left_proxy->Reverse(); right_proxy->Reverse(); } left_proxy->SetDomain(left_this_dom[0],left_this_dom[1]); right_proxy->SetDomain(right_this_dom[0],right_this_dom[1]); if (!left_side) left_side = left_proxy; if (!right_side) right_side = right_proxy; rc = true; } } } return rc; }
int ON_CurveProxy::IsPolyline( ON_SimpleArray<ON_3dPoint>* pline_points, ON_SimpleArray<double>* pline_t ) const { ON_SimpleArray<double> tmp_t; if ( pline_points ) pline_points->SetCount(0); if ( pline_t ) pline_t->SetCount(0); if ( !m_real_curve_domain.IsIncreasing() ) return 0; if ( !m_real_curve ) return 0; const ON_Interval cdom = m_real_curve->Domain(); if ( !cdom.Includes(m_real_curve_domain) ) return 0; // See if the "real" curve is a polyline int rc = 0; if ( m_real_curve_domain == cdom ) { // proxy uses entire curve rc = m_real_curve->IsPolyline(pline_points,pline_t); if ( rc < 2 ) rc = 0; if ( pline_points && pline_points->Count() != rc) { // The pline_points info is bogus, clear everything and // return 0. pline_points->SetCount(0); if ( pline_t ) pline_t->SetCount(0); rc = 0; } if ( pline_t && pline_t->Count() != rc) { // The pline_t info is bogus, clear everything and // return 0. pline_t->SetCount(0); if ( pline_points ) pline_points->SetCount(0); rc = 0; } if ( rc ) { if ( m_bReversed ) { if ( pline_points ) pline_points->Reverse(); if ( pline_t ) pline_t->Reverse(); } if ( pline_points && IsClosed() && pline_points->Count() > 3 ) { // 27 February 2003 Dale Lear // If proxy curve says it's closed, then // make sure end point of returned polyline // is exactly equal to start point. *pline_points->Last() = *pline_points->First(); } if ( pline_t && (m_bReversed || m_real_curve_domain != m_this_domain) ) { int i; for ( i = 0; i < rc; i++ ) { (*pline_t)[i] = ThisCurveParameter( (*pline_t)[i] ); } } } } else { // 12 December 2003 Dale Lear // We have to extract a sub curve for the test, because // the region in question may be a polyline and the unused // portion may not be a polyline. This tends to happen // when the "real" curve is a polycurve that contains // a polyline and the polycurve has been parametrically // trimmed during a brep operation (like a boolean). // // The ON_CurveProxy::DuplicateCurve() scope is critical // because there are situation where people derive a // class from ON_CurveProxy, and override the virtual // DuplicateCurve(). In this situation I rely on getting // the result returned by ON_CurveProxy::DuplicateCurve(). ON_Curve* temp_curve = ON_CurveProxy::DuplicateCurve(); if ( temp_curve ) { rc = temp_curve->IsPolyline(pline_points,pline_t); delete temp_curve; } } return rc; }
ON_Surface::ISO ON_Surface::IsIsoparametric( const ON_Curve& curve, const ON_Interval* subdomain ) const { ISO iso = not_iso; if ( subdomain ) { ON_Interval cdom = curve.Domain(); double t0 = cdom.NormalizedParameterAt(subdomain->Min()); double t1 = cdom.NormalizedParameterAt(subdomain->Max()); if ( t0 < t1-ON_SQRT_EPSILON ) { if ( (t0 > ON_SQRT_EPSILON && t0 < 1.0-ON_SQRT_EPSILON) || (t1 > ON_SQRT_EPSILON && t1 < 1.0-ON_SQRT_EPSILON) ) { cdom.Intersection(*subdomain); if ( cdom.IsIncreasing() ) { ON_NurbsCurve nurbs_curve; if ( curve.GetNurbForm( nurbs_curve, 0.0,&cdom) ) { return IsIsoparametric( nurbs_curve, 0 ); } } } } } ON_BoundingBox bbox; double tolerance = 0.0; const int dim = curve.Dimension(); if ( (dim == 2 || dim==3) && curve.GetBoundingBox(bbox) ) { iso = IsIsoparametric( bbox ); switch (iso) { case x_iso: case W_iso: case E_iso: // make sure curve is a (nearly) vertical line // and weed out vertical scribbles tolerance = bbox.m_max.x - bbox.m_min.x; if ( tolerance < ON_ZERO_TOLERANCE && ON_ZERO_TOLERANCE*1024.0 <= (bbox.m_max.y-bbox.m_min.y) ) { // 26 March 2007 Dale Lear // If tolerance is tiny, then use ON_ZERO_TOLERANCE // This fixes cases where iso curves where not getting // the correct flag because tol=1e-16 and the closest // point to line had calculation errors of 1e-15. tolerance = ON_ZERO_TOLERANCE; } if ( !curve.IsLinear( tolerance ) ) iso = not_iso; break; case y_iso: case S_iso: case N_iso: // make sure curve is a (nearly) horizontal line // and weed out horizontal scribbles tolerance = bbox.m_max.y - bbox.m_min.y; if ( tolerance < ON_ZERO_TOLERANCE && ON_ZERO_TOLERANCE*1024.0 <= (bbox.m_max.x-bbox.m_min.x) ) { // 26 March 2007 Dale Lear // If tolerance is tiny, then use ON_ZERO_TOLERANCE // This fixes cases where iso curves where not getting // the correct flag because tol=1e-16 and the closest // point to line had calculation errors of 1e-15. tolerance = ON_ZERO_TOLERANCE; } if ( !curve.IsLinear( tolerance ) ) iso = not_iso; break; default: // nothing here break; } } return iso; }
int ON_CurveProxy::GetNurbForm( // returns 0: unable to create NURBS representation // with desired accuracy. // 1: success - returned NURBS parameterization // matches the curve's to wthe desired accuracy // 2: success - returned NURBS point locus matches // the curve's to the desired accuracy but, on // the interior of the curve's domain, the // curve's parameterization and the NURBS // parameterization may not match to the // desired accuracy. ON_NurbsCurve& nurbs, double tolerance, // (>=0) const ON_Interval* sub_domain // OPTIONAL subdomain of ON::ProxyCurve::Domain() ) const { ON_BOOL32 rc = false; if ( m_real_curve ) { ON_Interval scratch_domain = RealCurveInterval( sub_domain ); rc = m_real_curve->GetNurbForm(nurbs,tolerance,&scratch_domain); if ( rc ) { if ( m_bReversed ) nurbs.Reverse(); ON_Interval d = m_this_domain; if ( sub_domain ) d.Intersection( *sub_domain ); nurbs.SetDomain( d[0], d[1] ); if ( nurbs.m_dim <= 3 && nurbs.m_dim >= 1 ) { double t0 = Domain()[0]; double t1 = Domain()[1]; if ( 0 != sub_domain ) { if ( t0 < sub_domain->Min() ) t0 = sub_domain->Min(); if ( sub_domain->Max() < t1 ) t1 = sub_domain->Max(); } // set ends of NURBS curve to be exactly on ends of proxy curve ON_3dPoint P0 = PointAt(t0); ON_3dPoint P1 = PointAt(t1); ON_3dPoint N0 = nurbs.PointAtStart(); ON_3dPoint N1 = nurbs.PointAtEnd(); // 22 September 2003, GBA. The end tuning code below should only be applied // to clamped nurbs curves. In particular it should not be used on // periodic nurbs curves. Fixes TRR#11502. ON_BOOL32 clamped = nurbs.IsClamped(2); if ( clamped && (P0 != N0 || P1 != N1) ) { if ( 0==nurbs.m_is_rat ) { nurbs.SetCV(0,P0); nurbs.SetCV(nurbs.m_cv_count-1,P1); } else { ON_4dPoint H0, H1; H0 = P0; H0.w = nurbs.Weight(0); H0.x *= H0.w; H0.y *= H0.w; H0.z *= H0.w; nurbs.SetCV(0,H0); H1 = P1; H1.w = nurbs.Weight(nurbs.m_cv_count-1); H1.x *= H1.w; H1.y *= H1.w; H1.z *= H1.w; nurbs.SetCV(nurbs.m_cv_count-1,H1); } } } } } return rc; }
CRhinoCommand::result CCommandSampleCageEdit::RunCommand( const CRhinoCommandContext& context ) { ON_Workspace ws; CRhinoCommand::result rc = CRhinoCommand::success; // Get the captive object CRhinoGetObject go; go.SetCommandPrompt( L"Select captive surface or polysurface" ); go.SetGeometryFilter( CRhinoGetObject::surface_object | CRhinoGetObject::polysrf_object ); go.GetObjects( 1, 1 ); rc = go.CommandResult(); if( CRhinoCommand::success != rc ) return rc; const CRhinoObject* captive = go.Object(0).Object(); if( 0 == captive ) return CRhinoCommand::failure; // Define the control line ON_Line line; CArgsRhinoGetLine args; rc = RhinoGetLine( args, line ); if( CRhinoCommand::success != rc ) return rc; // Get the curve parameters int degree = 3; int cv_count = 4; for(;;) { CRhinoGetOption gl; gl.SetCommandPrompt( L"NURBS Parameters" ); gl.AcceptNothing(); int d_opt = gl.AddCommandOptionInteger( RHCMDOPTNAME(L"Degree"), °ree, L"Curve degree", 1.0, 100.0 ); int p_opt = gl.AddCommandOptionInteger( RHCMDOPTNAME(L"PointCount"), &cv_count, L"Number of control points", 2.0, 100.0 ); gl.GetOption(); rc = gl.CommandResult(); if( CRhinoCommand::success != rc ) return rc; if( CRhinoGet::nothing == gl.Result() ) break; if( cv_count <= degree ) { if( CRhinoGet::option != gl.Result() ) continue; const CRhinoCommandOption* opt = go.Option(); if( 0 == opt ) continue; if( d_opt == opt->m_option_index ) cv_count = degree + 1; else degree = cv_count - 1; } } // Set up morph control ON_MorphControl* control = new ON_MorphControl(); control->m_varient = 1; // 1= curve // Specify the source line curve control->m_nurbs_curve0.Create( 3, false, 2, 2 ); control->m_nurbs_curve0.MakeClampedUniformKnotVector(); control->m_nurbs_curve0.SetCV( 0, line.from ); control->m_nurbs_curve0.SetCV( 1, line.to ); // Specify the destination NURBS curve control->m_nurbs_curve.Create( 3, false, degree + 1, cv_count ); control->m_nurbs_curve.MakeClampedUniformKnotVector(); double* g = ws.GetDoubleMemory( control->m_nurbs_curve.m_cv_count ); control->m_nurbs_curve.GetGrevilleAbcissae( g ); ON_Interval d = control->m_nurbs_curve.Domain(); double s = 0.0; int i; for( i = 0; i < control->m_nurbs_curve.m_cv_count; i++ ) { s = d.NormalizedParameterAt( g[i] ); control->m_nurbs_curve.SetCV( i, line.PointAt(s) ); } // Make sure domains match s = line.Length(); if( s > ON_SQRT_EPSILON ) control->m_nurbs_curve0.SetDomain( 0.0, s ); d = control->m_nurbs_curve0.Domain(); control->m_nurbs_curve.SetDomain( d[0], d[1] ); // Create the morph control object CRhinoMorphControl* control_object = new CRhinoMorphControl(); control_object->SetControl( control ); context.m_doc.AddObject( control_object ); // Set up the capture RhinoCaptureObject( control_object, const_cast<CRhinoObject*>(captive) ); // Clean up display context.m_doc.UnselectAll(); // Turn on the control grips control_object->EnableGrips( true ); context.m_doc.Redraw( CRhinoView::mark_display_hint ); 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; }
ON_BOOL32 ON_PolyEdgeCurve::ChangeClosedCurveSeam( double t ) { //int saved_is_closed_helper = m_is_closed_helper; if ( SegmentCount() == 1 ) { // A ON_PolyEdgeSegment cannot have its start/end // changed. Split it into two segments and let // ON_PolyCurve::ChangeClosedCurveSeam() do the work. if ( !IsClosed() ) return false; ON_Interval crvd = Domain(); double s = crvd.NormalizedParameterAt(t); if ( s <= ON_SQRT_EPSILON || s >= (1.0 - ON_SQRT_EPSILON) ) { s = fmod(s,1.0); if ( s < 0.0 ) s += 1.0; if ( fabs(s) <= ON_SQRT_EPSILON || fabs(1.0-s) <= ON_SQRT_EPSILON ) { // split parameter is at start/end of this segemnt if ( t != crvd[0] ) { DestroyRuntimeCache(); SetDomain(t,t+crvd.Length() ); //m_is_closed_helper = saved_is_closed_helper; } return true; } return false; } ON_PolyEdgeSegment* left_seg = SegmentCurve(0); if ( 0 == left_seg ) return false; DestroyRuntimeCache(); ON_Curve* left = left_seg; ON_Curve* right = 0; double segt = SegmentCurveParameter(t); if ( !left_seg->Split(segt,left,right) ) return false; SetDomain(crvd[0],t); ON_PolyEdgeSegment* right_seg = ON_PolyEdgeSegment::Cast(right); if ( 0 == right_seg ) return false; Append(right_seg); double st[3]; st[0] = crvd[0]; st[1] = t; st[2] = crvd[1]; SetParameterization( st ); } // ON_PolyCurve::ChangeClosedCurveSeam works fine on // two or more segments. ON_BOOL32 rc = ON_PolyCurve::ChangeClosedCurveSeam(t); //if ( saved_is_closed_helper ) // m_is_closed_helper = saved_is_closed_helper; return rc; }
bool ON_Arc::GetNurbFormParameterFromRadian(double RadianParameter, double* NurbParameter ) const { if(!IsValid() || NurbParameter==NULL) return false; ON_Interval ADomain = DomainRadians(); double endtol = 10.0*ON_EPSILON*(fabs(ADomain[0]) + fabs(ADomain[1])); double del = RadianParameter - ADomain[0]; if(del <= endtol && del >= -ON_SQRT_EPSILON) { *NurbParameter=ADomain[0]; return true; } else { del = ADomain[1] - RadianParameter; if(del <= endtol && del >= -ON_SQRT_EPSILON){ *NurbParameter=ADomain[1]; return true; } } if( !ADomain.Includes(RadianParameter ) ) return false; ON_NurbsCurve crv; if( !GetNurbForm(crv)) return false; //Isolate a bezier that contains the solution int cnt = crv.SpanCount(); int si =0; //get span index int ki=0; //knot index double ang = ADomain[0]; ON_3dPoint cp; cp = crv.PointAt( crv.Knot(0) ) - Center(); double x = ON_DotProduct(Plane().Xaxis(),cp); double y = ON_DotProduct(Plane().Yaxis(),cp); double at = atan2( y, x); //todo make sure we dont go to far for( si=0, ki=0; si<cnt; si++, ki+=crv.KnotMultiplicity(ki) ){ cp = crv.PointAt( crv.Knot(ki+2)) - Center(); x = ON_DotProduct(Plane().Xaxis(),cp); y = ON_DotProduct(Plane().Yaxis(),cp); double at2 = atan2(y,x); if(at2>at) ang+=(at2-at); else ang += (2*ON_PI + at2 - at); at = at2; if( ang>RadianParameter) break; } // Crash Protection trr#55679 if( ki+2>= crv.KnotCount()) { *NurbParameter=ADomain[1]; return true; } ON_Interval BezDomain(crv.Knot(ki), crv.Knot(ki+2)); ON_BezierCurve bez; if(!crv.ConvertSpanToBezier(ki,bez)) return false; ON_Xform COC; COC.ChangeBasis( ON_Plane(),Plane()); bez.Transform(COC); // change coordinates to circles local frame double a[3]; // Bez coefficients of a quadratic to solve for(int i=0; i<3; i++) a[i] = tan(RadianParameter)* bez.CV(i)[0] - bez.CV(i)[1]; //Solve the Quadratic double descrim = (a[1]*a[1]) - a[0]*a[2]; double squared = a[0]-2*a[1]+a[2]; double tbez; if(fabs(squared)> ON_ZERO_TOLERANCE){ ON_ASSERT(descrim>=0); descrim = sqrt(descrim); tbez = (a[0]-a[1] + descrim)/(a[0]-2*a[1]+a[2]); if( tbez<0 || tbez>1){ double tbez2 = (a[0]-a[1]-descrim)/(a[0] - 2*a[1] + a[2]); if( fabs(tbez2 - .5)<fabs(tbez-.5) ) tbez = tbez2; } ON_ASSERT(tbez>=-ON_ZERO_TOLERANCE && tbez<=1+ON_ZERO_TOLERANCE); } else{ // Quadratic degenerates to linear tbez = 1.0; if(a[0]-a[2]) tbez = a[0]/(a[0]-a[2]); } if(tbez<0) tbez=0.0; else if(tbez>1.0) tbez=1.0; //Debug ONLY Code - check the result // double aa = a[0]*(1-tbez)*(1-tbez) + 2*a[1]*tbez*(1-tbez) + a[2]*tbez*tbez; // double tantheta= tan(RadianParameter); // ON_3dPoint bezp; // bez.Evaluate(tbez, 0, 3, bezp); // double yx = bezp.y/bezp.x; *NurbParameter = BezDomain.ParameterAt(tbez); return true; }
ON_Surface::ISO ON_Surface::IsIsoparametric( const ON_BoundingBox& bbox ) const { ISO iso = not_iso; if ( bbox.m_min.z == bbox.m_max.z ) { const double ds = bbox.m_max.x - bbox.m_min.x; const double dt = bbox.m_max.y - bbox.m_min.y; double a, b, s0, s1, t0, t1; ON_Interval d = Domain(0); s0 = d.Min(); s1 = d.Max(); d = Domain(1); t0 = d.Min(); t1 = d.Max(); double stol = (s1-s0)/32.0; double ttol = (t1-t0)/32.0; if ( s0 < s1 && t0 < t1 && ( ds <= stol || dt <= ttol) ) { if ( ds*(t1-t0) <= dt*(s1-s0) ) { // check for s = constant iso if ( bbox.m_max.x <= s0+stol ) { // check for west side iso GetParameterTolerance( 0, s0, &a, &b); if ( a <= bbox.m_min.x && bbox.m_max.x <= b ) iso = W_iso; } else if ( bbox.m_min.x >= s1-stol ) { // check for east side iso GetParameterTolerance( 0, s1, &a, &b); if ( a <= bbox.m_min.x && bbox.m_max.x <= b ) iso = E_iso; } if ( iso == not_iso && (s0 < bbox.m_max.x || bbox.m_min.x < s1) ) { // check for interior "u = constant" iso GetParameterTolerance( 0, 0.5*(bbox.m_min.x+bbox.m_max.x), &a, &b); if ( a <= bbox.m_min.x && bbox.m_max.x <= b ) iso = x_iso; } } else { // check for t = constant iso if ( bbox.m_max.y <= t0+ttol ) { // check for south side iso GetParameterTolerance( 1, t0, &a, &b); if ( a < bbox.m_min.y && bbox.m_max.y <= b ) iso = S_iso; } else if ( bbox.m_min.y >= t1-ttol ) { // check for north side iso GetParameterTolerance( 1, t1, &a, &b); if ( a < bbox.m_min.y && bbox.m_max.y <= b ) iso = N_iso; } if ( iso == not_iso && (t0 < bbox.m_max.x || bbox.m_min.x < t1) ) { // check for interior "t = constant" iso GetParameterTolerance( 1, 0.5*(bbox.m_min.y+bbox.m_max.y), &a, &b); if ( a < bbox.m_min.y && bbox.m_max.y <= b ) iso = y_iso; } } } } return iso; }