bool ON_SetKnotVectorDomain( int order, int cv_count, double* knot, double t0, double t1 ) { bool rc = false; if ( order < 2 || cv_count < order || 0 == knot || t0 >= t1 || !ON_IsValid(t0) || !ON_IsValid(t1) ) { ON_ERROR("ON_SetKnotVectorDomain - invalid input"); } else if ( knot[order-2] >= knot[cv_count-1] || !ON_IsValid(knot[order-2]) || !ON_IsValid(knot[cv_count-2]) ) { ON_ERROR("ON_SetKnotVectorDomain - invalid input knot vector"); } else { const ON_Interval oldd(knot[order-2],knot[cv_count-1]); const ON_Interval newd(t0,t1); if ( oldd != newd ) { int i, knot_count = ON_KnotCount(order,cv_count); for ( i = 0; i < knot_count; i++ ) { knot[i] = newd.ParameterAt(oldd.NormalizedParameterAt(knot[i])); } } rc = true; } return rc; }
bool ON_Quaternion::IsNotZero() const { return ( (0.0 != a || 0.0 != b || 0.0 != c || 0.0 != d) && ON_IsValid(a) && ON_IsValid(b) && ON_IsValid(c) && ON_IsValid(d) ); }
bool ON_PlaneSurface::CreatePseudoInfinitePlane( const ON_Plane& plane, int point_count, const ON_3dPoint* point_list, double padding ) { if ( !plane.IsValid() ) return false; if ( point_count < 1 ) return false; if ( 0 == point_list ) return false; if ( !ON_IsValid(padding) || padding < 0.0 ) return false; ON_Interval plane_domain[2]; double s, t; s = ON_UNSET_VALUE; t = ON_UNSET_VALUE; if ( !plane.ClosestPointTo( point_list[0], &s, &t ) || !ON_IsValid(s) || !ON_IsValid(t) ) return 0; plane_domain[0].m_t[1] = plane_domain[0].m_t[0] = s; plane_domain[1].m_t[1] = plane_domain[1].m_t[0] = t; for ( int i = 1; i < point_count; i++ ) { s = ON_UNSET_VALUE; t = ON_UNSET_VALUE; if ( !plane.ClosestPointTo( point_list[i], &s, &t ) || !ON_IsValid(s) || !ON_IsValid(t) ) return 0; if ( s < plane_domain[0].m_t[0] ) plane_domain[0].m_t[0] = s; else if ( s > plane_domain[0].m_t[1] ) plane_domain[0].m_t[1] = s; if ( t < plane_domain[1].m_t[0] ) plane_domain[1].m_t[0] = t; else if ( t > plane_domain[1].m_t[1] ) plane_domain[1].m_t[1] = t; } s = padding*plane_domain[0].Length() + padding; if ( !(s > 0.0) && !plane_domain[0].IsIncreasing() ) s = 1.0; plane_domain[0].m_t[0] -= s; plane_domain[0].m_t[1] += s; t = padding*plane_domain[1].Length() + padding; if ( !(t > 0.0) && !plane_domain[1].IsIncreasing() ) t = 1.0; plane_domain[1].m_t[0] -= t; plane_domain[1].m_t[1] += t; m_plane = plane; m_domain[0] = plane_domain[0]; m_domain[1] = plane_domain[1]; m_extents[0] = plane_domain[0]; m_extents[1] = plane_domain[1]; return IsValid()?true:false; }
int ON_Box::IsDegenerate( double tolerance ) const { int rc = 0; // 0 box is not degenerate // 1 box is a rectangle (degenerate in one direction) // 2 box is a line (degenerate in two directions) // 3 box is a point (degenerate in three directions) // 4 box is not valid if ( !dx.IsIncreasing() || !dy.IsIncreasing() || !dz.IsIncreasing() ) { rc = 4; } else { const ON_3dVector diag(dx.Length(),dy.Length(),dz.Length()); if ( !ON_IsValid(tolerance) || tolerance < 0.0 ) { // compute scale invarient tolerance tolerance = diag.MaximumCoordinate()*ON_SQRT_EPSILON; } if ( diag.x <= tolerance ) rc++; if ( diag.y <= tolerance ) rc++; if ( diag.z <= tolerance ) rc++; } return rc; }
bool ON_Circle::IsValid() const { bool rc = ( ON_IsValid(radius) && radius > 0.0 && plane.IsValid() ); return rc; }
bool ON_Localizer::CreateSphereLocalizer( ON_3dPoint P, double r0, double r1 ) { Destroy(); if ( P.IsValid() && ON_IsValid(r0) && ON_IsValid(r1) && r0 > 0.0 && r1 > 0.0 && r0 != r1 ) { m_P = P; m_V.Zero(); m_d.Set(r0,r1); m_type = sphere_type; } return (sphere_type == m_type); }
bool ON_Localizer::CreatePlaneLocalizer( ON_3dPoint P, ON_3dVector N, double h0, double h1 ) { Destroy(); if ( P.IsValid() && N.IsValid() && N.Length() > 0.0 && ON_IsValid(h0) && ON_IsValid(h1) && h0 != h1 ) { m_V = N; m_V.Unitize(); m_P.Set( -(m_V.x*P.x + m_V.y*P.y + m_V.z*P.z), 0.0, 0.0 ); m_d.Set(h0,h1); m_type = plane_type; } return (plane_type == m_type); }
void ON_Light::SetSpotExponent( double e ) { // cos(h)^e = 0.5 if ( e < 0.0 || !ON_IsValid(e) ) m_spot_exponent = 0.0; else m_spot_exponent = e; m_hotspot = ON_UNSET_VALUE; // indicates hotspot should be computed from m_spot_exponent }
void ON_Light::SetHotSpot( double h ) { if ( h == ON_UNSET_VALUE || !ON_IsValid(h) ) m_hotspot = ON_UNSET_VALUE; else if ( h <= 0.0 ) m_hotspot = 0.0; else if ( h >= 1.0 ) m_hotspot = 1.0; else m_hotspot = h; }
bool ON_Localizer::CreateCylinderLocalizer( ON_3dPoint P, ON_3dVector V, double r0, double r1 ) { Destroy(); if ( P.IsValid() && V.IsValid() && V.Length() > 0.0 && ON_IsValid(r0) && ON_IsValid(r1) && r0 > 0.0 && r1 > 0.0 && r0 != r1 ) { m_P = P; m_V = V; m_V.Unitize(); m_d.Set(r0,r1); m_type = cylinder_type; } return (cylinder_type == m_type); }
double ON_X_EVENT::IntersectionTolerance( double intersection_tolerance ) { if ( intersection_tolerance <= 0.0 || !ON_IsValid(intersection_tolerance) ) { intersection_tolerance = 0.001; } else if ( intersection_tolerance < 1.0e-6 ) { intersection_tolerance = 1.0e-6; } return intersection_tolerance; }
double ON_X_EVENT::OverlapTolerance( double intersection_tolerance, double overlap_tolerance ) { if ( overlap_tolerance <= 0.0 || !ON_IsValid(overlap_tolerance) ) { overlap_tolerance = 2.0*IntersectionTolerance(intersection_tolerance); } else if ( overlap_tolerance < 1.0e-6 ) { overlap_tolerance = 1.0e-6; } return overlap_tolerance; }
bool ON_Light::GetSpotLightRadii( double* inner_radius, double* outer_radius ) const { bool rc = IsSpotLight()?true:false; if (rc) { double angle = SpotAngleRadians(); if ( !ON_IsValid(angle) || angle <= 0.0 || angle >= 0.5*ON_PI ) angle = 0.25*ON_PI; double spot = HotSpot(); if ( !ON_IsValid(spot) || spot < 0.0 || spot > 1.0 ) spot = 0.5; double cone_height = Direction().Length(); if ( !ON_IsValid(cone_height) || cone_height <= 0.0 ) cone_height = 1.0; if ( outer_radius ) *outer_radius = tan( angle) * cone_height; if ( inner_radius ) *inner_radius = tan( angle * spot) * cone_height; } return rc; }
static void DumpDistanceABHelper( ON_TextLog& text_log, ON_3dPoint A, ON_3dPoint B ) { const double tinyd = 1.0e-14; double d = A.DistanceTo(B); text_log.Print("distance A to B"); if ( !ON_IsValid(d) || d >= 1.0e-14 || d <= 0.0 ) { text_log.Print(" = "); } else { // This prevents diff from compaining about tiny changes. text_log.Print(" < "); d = tinyd; } text_log.Print(d); text_log.Print("\n"); }
CRhinoCommand::result CCommandSampleDimStyleTextHeight::RunCommand( const CRhinoCommandContext& context ) { // Get the current dimstyle const CRhinoDimStyle& dimstyle = context.m_doc.m_dimstyle_table.CurrentDimStyle(); ON_wString prompt; prompt.Format( L"New text height for \"%s\" dimension style", dimstyle.Name() ); // Prompt for a new text height value CRhinoGetNumber gn; gn.SetCommandPrompt( prompt ); gn.SetDefaultNumber( dimstyle.TextHeight() ); gn.SetLowerLimit( 0.0, TRUE ); gn.AcceptNothing(); gn.GetNumber(); if( gn.CommandResult() != CRhinoCommand::success ) return gn.CommandResult(); // New text height value double height = gn.Number(); // Validate new value if( height != dimstyle.TextHeight() && ON_IsValid(height) && height > ON_SQRT_EPSILON ) { int style_index = dimstyle.Index(); // Copy everything from the dimension's dimstyle ON_DimStyle modified_dimstyle( context.m_doc.m_dimstyle_table[style_index] ); // Modify the text height modified_dimstyle.SetTextHeight( height ); // Modify the dimension style if( context.m_doc.m_dimstyle_table.ModifyDimStyle(modified_dimstyle, style_index) ) context.m_doc.Redraw(); } return CRhinoCommand::success; }
double ON_Light::HotSpot() const { double h = m_hotspot; if ( h < 0.0 || h > 1.0 ) { // spotlight is using spot exponent interface if ( m_spot_exponent >= 65536.0 ) h = 0.0; else if ( m_spot_exponent <= 0.0 || m_spot_angle <= 0.0 || m_spot_angle > 90.0 ) h = 1.0; else { // compute HotSpot() from cos(h*angle)^e = hotspot_min double x, a, cos_ha; x = log_hotspot_min/m_spot_exponent; // note that x < 0.0 if ( x < -690.0 ) { // prevent underflow. cos_ha is close to zero so h = 1.0; } else { cos_ha = exp(x); if (!ON_IsValid(cos_ha)) cos_ha = 0.0; else if ( cos_ha > 1.0 ) cos_ha = 1.0; else if ( cos_ha < -1.0 ) cos_ha = -1.0; a = SpotAngleRadians(); h = acos(cos_ha)/a; if ( h < 0.0 ) h = 0.0; else if ( h > 1.0 ) { // happens for smaller e h = 1.0; } } } } return h; }
int ON_ArePointsOnPlane( // returns 0=no, 1 = yes, 2 = pointset is (to tolerance) a single point on the line int dim, // 2 or 3 int is_rat, int count, int stride, const double* point, const ON_BoundingBox& bbox, // if needed, use ON_GetBoundingBox(dim,is_rat,count,stride,point) const ON_Plane& plane, // line to test double tolerance ) { double w; int i, j, k; if ( count < 1 ) return 0; if ( !plane.IsValid() ) { ON_ERROR("plane parameter is not valid"); return 0; } if ( !bbox.IsValid() ) { ON_ERROR("bbox parameter is not valid"); return 0; } if ( !ON_IsValid(tolerance) || tolerance < 0.0 ) { ON_ERROR("tolerance must be >= 0.0"); return 0; } if ( dim < 2 || dim > 3 ) { ON_ERROR("dim must be 2 or 3"); return 0; } if ( stride < (is_rat?(dim+1):dim) ) { ON_ERROR("stride parameter is too small"); return 0; } if ( 0 == point ) { ON_ERROR("point parameter is null"); return 0; } int rc = 0; if ( tolerance == 0.0 ) { tolerance = bbox.Tolerance(); } ON_3dPoint Q; // test bounding box to quickly detect the common coordinate axis cases rc = (count == 1 || bbox.Diagonal().Length() <= tolerance) ? 2 : 1; for ( i = 0; rc && i < 2; i++ ) { Q.x = bbox[i].x; for ( j = 0; rc && j < 2; j++) { Q.y = bbox[j].y; for ( k = 0; rc && k < 2; k++) { Q.z = bbox[k].z; if ( Q.DistanceTo( plane.ClosestPointTo( Q ) ) > tolerance ) rc = 0; } } } if ( !rc ) { // test points one by one Q.Zero(); rc = (count == 1 || bbox.Diagonal().Length() <= tolerance) ? 2 : 1; if ( is_rat ) { for ( i = 0; i < count; i++ ) { w = point[dim]; if ( w == 0.0 ) { ON_ERROR("rational point has zero weight"); return 0; } ON_ArrayScale( dim, 1.0/w, point, &Q.x ); if ( Q.DistanceTo( plane.ClosestPointTo( Q ) ) > tolerance ) { rc = 0; break; } point += stride; } } else { for ( i = 0; i < count; i++ ) { memcpy( &Q.x, point, dim*sizeof(Q.x) ); if ( Q.DistanceTo( plane.ClosestPointTo( Q ) ) > tolerance ) { rc = 0; break; } point += stride; } } } return rc; }
ON_BOOL32 ON_Ellipse::IsCircle() const { double r0 = radius[0]; return ( ON_IsValid(r0) && fabs(r0-radius[1]) <= fabs(r0)*ON_ZERO_TOLERANCE && IsValid() ) ? true : false; }
int ON_FindLocalMinimum( int (*f)(void*,double,double*,double*), void* farg, double ax, double bx, double cx, double rel_stepsize_tol, double abs_stepsize_tol, int max_it, double *t_addr ) /* Use Brent's algorithm (with derivative) to Find a (local) minimum of a function * * INPUT: * ax, bx, cx a bracketed minimum satisfying conditions 1 and 2. * 1) either ax < bx < cx or cx < bx < ax. * 2) f(bx) < f(ax) and f(bx) < f(ax). * farg * pointer passed to function f() * f * evaluation function with prototype * int f(void* farg,double t,double* ft,double* dft) * f(farg,t,&ft,&dft) should compute ft = value of function at t * and dft = value of derivative at t. * -1: failure * 0: success * 1: |f(x)| is small enough - TL_NRdbrent() will return *t_addr = x * and the return code 1. * rel_stepsize_tol, abs_stepsize_tol (0 < rel_stepsize_tol < 1 and 0 < abs_stepsize_tol) * rel_stepsize_tol is a fractional tolerance and abs_stepsize_tol is an absolute tolerance * that determine the minimum step size for a given iteration. * minimum delta t = rel_stepsize_tol*|t| + abs_stepsize_tol. * When in doubt, use * rel_stepsize_tol = ON_EPSILON * abs_stepsize_tol = 1/2*(desired absolute precision for *t_addr). * max_it ( >= 2) * maximum number of iterations to permit (when in doubt use 100) * Closest Point to bezier minimizations typically take < 30 * iterations. * * OUTPUT: * *t_addr abcissa of a local minimum between ax and cx. * 0: failure * 1: success * 2: After max_iteration_cnt iterations the tolerance restrictions * where not satisfied. Try increasing max_it, rel_stepsize_tol and/or abs_stepsize_tol * or use the value of (*t_addr) with extreme caution. */ { // See Numerical Recipes in C's dbrent() for a description of the basic algorithm int rc,ok1,ok2; double a,b,d,d1,d2,du,dv,dw,dx,e,fu,fv,fw,fx,olde,tol1,tol2,u,u1,u2,v,w,x,xm; d=e=0.0; if ( 0 == t_addr ) { ON_ERROR("t_addr is NULL"); return 0; } *t_addr = bx; if ( max_it < 2 ) { ON_ERROR("max_it must be >= 2"); return 0; } if ( !ON_IsValid(rel_stepsize_tol) || rel_stepsize_tol <= 0.0 || rel_stepsize_tol >= 1.0 ) { ON_ERROR("rel_stepsize_tol must be strictly between 0.0 and 1.0"); return 0; } if ( !ON_IsValid(abs_stepsize_tol) || abs_stepsize_tol <= 0.0 ) { ON_ERROR("abs_stepsize_tol must be > 0"); return 0; } a=(ax < cx ? ax : cx); b=(ax > cx ? ax : cx); x=w=v=bx; rc = f(farg,x,&fx,&dx); if (rc) { // f() returned nonzero return code which means we need to bailout if ( rc < 0 ) { ON_ERROR("ON_FindLocalMinimum() f() failed to evaluate."); } *t_addr = x; return rc>0 ? 1 : 0; // return 1 means f() said result is good enough, return = 0 means f() failed } fw=fv=fx; dw=dv=dx; while(max_it--) { xm=0.5*(a+b); tol1=rel_stepsize_tol*fabs(x)+abs_stepsize_tol; tol2=2.0*tol1; if (fabs(x-xm) <= (tol2-0.5*(b-a))) { // further adjustments to x are smaller than stepsize tolerance *t_addr=x; return 1; } if (fabs(e) > tol1) { d1=2.0*(b-a); d2=d1; if (dw != dx) d1=(w-x)*dx/(dx-dw); if (dv != dx) d2=(v-x)*dx/(dx-dv); u1=x+d1; u2=x+d2; ok1 = (a-u1)*(u1-b) > 0.0 && dx*d1 <= 0.0; ok2 = (a-u2)*(u2-b) > 0.0 && dx*d2 <= 0.0; olde=e; e=d; if (ok1 || ok2) { if (ok1 && ok2) d=(fabs(d1) < fabs(d2) ? d1 : d2); else if (ok1) d=d1; else d=d2; if (fabs(d) <= fabs(0.5*olde)) { u=x+d; if (u-a < tol2 || b-u < tol2) {d = (xm >= x) ? tol1 : -tol1;} } else { d=0.5*(e=(dx >= 0.0 ? a-x : b-x)); } } else { d=0.5*(e=(dx >= 0.0 ? a-x : b-x)); } } else { d=0.5*(e=(dx >= 0.0 ? a-x : b-x)); } if (fabs(d) >= tol1) { u=x+d; rc = f(farg,u,&fu,&du); } else { u = (d >= 0.0) ? x+tol1 : x-tol1; rc = f(farg,u,&fu,&du); if (rc >= 0 && fu > fx) { // tweaking x any more increases function value - x is a numerical minimum *t_addr=x; return 1; } } if (rc) { // f() returned nonzero return code which means we need to bailout if ( rc < 0 ) { ON_ERROR("ON_FindLocalMinimum() f() failed to evaluate."); } else { *t_addr = (fu < fx) ? u : x; } return rc>0 ? 1 : 0; } if (fu <= fx) { if (u >= x) a=x; else b=x; v=w;fv=fw;dv=dw; w=x;fw=fx;dw=dx; x=u;fx=fu;dx=du; } else { if (u < x) a=u; else b=u; if (fu <= fw || w == x) { v=w;fv=fw;dv=dw; w=u;fw=fu;dw=du; } else if (fu < fv || v == x || v == w) { v=u;fv=fu;dv=du; } } } *t_addr = x; // best known answer ON_ERROR("ON_FindLocalMinimum() failed to converge"); return 2; // 2 means we failed to converge }
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; }
bool ON_OffsetSurfaceFunction::SetOffsetPoint( double s, double t, double distance, double radius ) { bool rc = false; if ( ON_IsValid(s) && ON_IsValid(t) && ON_IsValid(distance) && ON_IsValid(radius) ) { double u = m_domain[0].NormalizedParameterAt(s); // 14 Jan 2008, Mikko, TRR 29861: // Changing the clamping to happen when the // point is outside or nearly outside the domain. const double dTol = ON_SQRT_EPSILON; // tiny border around untrimmed edges if ( u < dTol) { s = m_domain[0][0]; u = 0.0; } if ( u > 1.0-dTol) { s = m_domain[0][1]; u = 1.0; } double v = m_domain[1].NormalizedParameterAt(t); if ( v < dTol) { t = m_domain[1][0]; v = 0.0; } if ( v > 1.0-dTol) { t = m_domain[1][1]; v = 1.0; } if ( u >= 0.0 && u <= 1.0 && v >= 0.0 && v <= 1.0 ) { ON_OffsetSurfaceValue offset_value; offset_value.m_s = s; offset_value.m_t = t; offset_value.m_distance = distance; offset_value.m_radius = (radius > 0.0) ? radius : 0.0; offset_value.m_index = (int)((u + v*4096.0)*4096.0); int i; for ( i = 0; i < m_offset_value.Count(); i++ ) { if ( m_offset_value[i].m_index == offset_value.m_index ) { m_offset_value[i] = offset_value; break; } } if (i == m_offset_value.Count()) { m_offset_value.Append(offset_value); m_bumps.SetCount(0); m_bValid = false; } rc = true; } } return rc; }
int ON_RowReduce( int row_count, int col_count, double zero_pivot, double** A, double** B, double pivots[2] ) { // returned A is identity, B = inverse of input A const int M = row_count; const int N = col_count; const size_t sizeof_row = N*sizeof(A[0][0]); int i, j, ii; double a, p, p0, p1; const double* ptr0; double* ptr1; if ( pivots ) { pivots[0] = 0.0; pivots[1] = 0.0; } if ( zero_pivot <= 0.0 || !ON_IsValid(zero_pivot) ) zero_pivot = 0.0; for ( i = 0; i < M; i++ ) { memset(B[i],0,sizeof_row); if ( i < N ) B[i][i] = 1.0; } p0 = p1 = A[0][0]; for ( i = 0; i < M; i++ ) { p = fabs(a = A[i][i]); if ( p < p0 ) p0 = p; else if (p > p1) p1 = p; if ( 1.0 != a ) { if ( p <= zero_pivot || !ON_IsValid(a) ) { break; } a = 1.0/a; //A[i][i] = 1.0; // no need to do this // The "ptr" voodoo is faster but does the same thing as // //for ( j = i+1; j < N; j++ ) // A[i][j] *= a; // j = i+1; ptr1 = A[i] + j; j = N - j; while(j--) *ptr1++ *= a; // The "ptr" voodoo is faster but does the same thing as // //for ( j = 0; j <= i; j++ ) // B[i][j] *= a; // ptr1 = B[i]; j = i+1; while(j--) *ptr1++ *= a; } for ( ii = i+1; ii < M; ii++ ) { a = A[ii][i]; if ( 0.0 == a ) continue; a = -a; //A[ii][i] = 0.0; // no need to do this // The "ptr" voodoo is faster but does the same thing as // //for( j = i+1; j < N; j++ ) // A[ii][j] += a*A[i][j]; // j = i+1; ptr0 = A[i] + j; ptr1 = A[ii] + j; j = N - j; while(j--) *ptr1++ += a* *ptr0++; for( j = 0; j <= i; j++ ) B[ii][j] += a*B[i][j]; } } if ( pivots ) { pivots[0] = p0; pivots[1] = p1; } if ( i < M ) { return i; } // A is now upper triangular with all 1s on diagonal // (That is, if the lines that say "no need to do this" are used.) // B is lower triangular with a nonzero diagonal for ( i = M-1; i >= 0; i-- ) { for ( ii = i-1; ii >= 0; ii-- ) { a = A[ii][i]; if ( 0.0 == a ) continue; a = -a; //A[ii][i] = 0.0; // no need to do this // The "ptr" voodoo is faster but does the same thing as // //for( j = 0; j < N; j++ ) // B[ii][j] += a*B[i][j]; // ptr0 = B[i]; ptr1 = B[ii]; j = N; while(j--) *ptr1++ += a* *ptr0++; } } // At this point, A is trash. // If the input A was really nice (positive definite....) // the B = inverse of the input A. If A was not nice, // B is also trash. return M; }
void ON_Sum::Plus( double x, double dx ) { Plus(x); if ( ON_IsValid(dx) ) m_sum_err += fabs(dx); }
// Copied from opennurbs_intersect.cpp but with a bug fix. // We can remove it once the bug is fixed in OpenNurbs and once // Grasshopper has dropped Rhino4 support. int PS_Intersect( const ON_Plane& plane, const ON_Sphere& sphere, ON_Circle& circle ) { // 16 April 2011 Dale Lear // Prior to this date, this function did not return the correct answer. int rc = 0; const double sphere_radius = fabs(sphere.radius); double tol = sphere_radius*ON_SQRT_EPSILON; if ( !(tol >= ON_ZERO_TOLERANCE) ) tol = ON_ZERO_TOLERANCE; const ON_3dPoint sphere_center = sphere.Center(); ON_3dPoint circle_center = plane.ClosestPointTo(sphere_center); double d = circle_center.DistanceTo(sphere_center); circle.radius = 0.0; if ( ON_IsValid(sphere_radius) && ON_IsValid(d) && d <= sphere_radius + tol ) { if ( sphere_radius > 0.0 ) { d /= sphere_radius; d = 1.0 - d*d; // The d > 4.0*ON_EPSILON was picked by testing spheres with // radius = 1 and center = (0,0,0). Do not make 4.0*ON_EPSILON // any smaller and please discuss changes with Dale Lear. circle.radius = (d > 4.0*ON_EPSILON) ? sphere_radius*sqrt(d) : 0.0; } else circle.radius = 0.0; if ( circle.radius <= ON_ZERO_TOLERANCE ) { // return a single point rc = 1; circle.radius = 0.0; // When tolerance is in play, put the point on the sphere. // If the caller prefers the plane, then they can adjust the // returned answer to get the plane. ON_3dVector R = circle_center - sphere_center; double r0 = R.Length(); if ( r0 > 0.0 ) { R.Unitize(); ON_3dPoint C1 = sphere_center + sphere_radius*R; double r1 = C1.DistanceTo(sphere_center); if ( fabs(sphere.radius-r1) < fabs(sphere.radius-r0) ) circle_center = C1; } } else { // return a circle rc = 2; } } // Update circle's plane here in case the input plane // is the circle's plane member. circle.plane = plane; circle.plane.origin = circle_center; circle.plane.UpdateEquation(); return rc; }
bool ON_IsValidKnotVector( int order, int cv_count, const double* knot, ON_TextLog* text_logx ) { // If low bit of text_log pointer is 1, then ON_Error is not called when the // knot vector is invalid. const ON__INT_PTR lowbit = 1; const ON__INT_PTR hightbits = ~lowbit; bool bSilentError = ( 0 != (lowbit & ((ON__INT_PTR)text_logx)) ); ON_TextLog* text_log = (ON_TextLog*)(((ON__INT_PTR)text_logx) & hightbits); const double *k0, *k1; int i; if ( order < 2 ) { if ( text_log ) { text_log->Print("Knot vector order = %d (should be >= 2 )\n",order); } return ON_KnotVectorIsNotValid(bSilentError); } if ( cv_count < order ) { if ( text_log ) { text_log->Print("Knot vector cv_count = %d (should be >= order=%d )\n",cv_count,order); } return ON_KnotVectorIsNotValid(bSilentError); } if ( knot == NULL ) { if ( text_log ) { text_log->Print("Knot vector knot array = NULL.\n"); } return ON_KnotVectorIsNotValid(bSilentError); } for ( i = 0; i < cv_count+order-2; i++ ) { if ( !ON_IsValid(knot[i]) ) { if ( text_log ) { text_log->Print("Knot vector knot[%d]=%g is not valid.\n",i,knot[i]); } return ON_KnotVectorIsNotValid(bSilentError); } } if ( !(knot[order-2] < knot[order-1]) ) { if ( text_log ) { text_log->Print("Knot vector order=%d and knot[%d]=%g >= knot[%d]=%g (should have knot[order-2] < knot[order-1]).\n", order,order-2,knot[order-2],order-1,knot[order-1]); } return ON_KnotVectorIsNotValid(bSilentError); } if ( !(knot[cv_count-2] < knot[cv_count-1]) ) { if ( text_log ) { text_log->Print("Knot vector cv_count=%d and knot[%d]=%g >= knot[%d]=%g (should have knot[cv_count-2] < knot[cv_count-1]).\n", cv_count,cv_count-2,knot[cv_count-2],cv_count-1,knot[cv_count-1]); } return ON_KnotVectorIsNotValid(bSilentError); } // entire array must be monotone increasing k0 = knot; k1 = knot+1; i = order + cv_count - 3; while (i--) { if ( !(*k1 >= *k0) ) { if ( text_log ) { text_log->Print("Knot vector must be increasing but knot[%d]=%g > knot[%d]=%g\n", order+cv_count-4-i, *k0, order+cv_count-3-i, *k1 ); } return ON_KnotVectorIsNotValid(bSilentError); } k0++; k1++; } // must have knot[i+order-1] > knot[i] k0 = knot; k1 = knot + order - 1; i = cv_count-1; while(i--) { if ( !(*k1 > *k0) ) { if ( text_log ) { text_log->Print("Knot vector order = %d but knot[%d]=%g >= knot[%d]=%g\n", order, cv_count-2-i, *k0, cv_count-1-i, *k1 ); } return ON_KnotVectorIsNotValid(bSilentError); } k0++; k1++; } return true; }
void ON_Layer::SetPlotWeight(double plot_weight_mm) { m_plot_weight_mm = (ON_IsValid(plot_weight_mm)) ? plot_weight_mm : 0.0; }
int ON_Brep::SplitEdgeAtParameters( int edge_index, int edge_t_count, const double* edge_t ) { // Default kink_tol_radians MUST BE ON_PI/180.0. // // The default kink tol must be kept in sync with the default for // TL_Brep::SplitKinkyFace() and ON_Brep::SplitKinkyFace(). // See comments in TL_Brep::SplitKinkyFace() for more details. if (0 == edge_t_count) return 0; if (0 == edge_t) return 0; if (edge_index < 0 || edge_index >= m_E.Count()) return 0; ON_BrepEdge& E = m_E[edge_index]; if (E.m_c3i < 0) return 0; ON_Curve* curve = m_C3[E.m_c3i]; if (!curve) return 0; ON_Interval Edomain; if ( !E.GetDomain(&Edomain.m_t[0],&Edomain.m_t[1]) ) return 0; if ( !Edomain.IsIncreasing() ) return 0; // get a list of unique and valid splitting parameters ON_SimpleArray<double> split_t(edge_t_count); { for (int i = 0; i < edge_t_count; i++) { double e = edge_t[i]; if ( !ON_IsValid(e) ) { ON_ERROR("Invalid edge_t[] value"); continue; } if ( e <= Edomain.m_t[0] ) { ON_ERROR("edge_t[] <= start of edge domain"); continue; } if ( e >= Edomain.m_t[1] ) { ON_ERROR("edge_t[] >= end of edge domain"); continue; } split_t.Append(e); } if ( split_t.Count() > 1 ) { // sort split_t[] and remove duplicates ON_SortDoubleArray( ON::heap_sort, split_t.Array(), split_t.Count() ); int count = 1; for ( int i = 1; i < split_t.Count(); i++ ) { if ( split_t[i] > split_t[count-1] ) { if ( i > count ) split_t[count] = split_t[i]; count++; } } split_t.SetCount(count); } } if (split_t.Count() <= 0) return 0; // Reverse split_t[] so the starting segment of the original // edge m_E[edge_index] is the one at m_E[edge_index]. split_t.Reverse(); ON_Curve* new_curve = TuneupSplitteeHelper(m_E[edge_index].ProxyCurve()); if ( 0 != new_curve ) { m_E[edge_index].m_c3i = AddEdgeCurve(new_curve); m_E[edge_index].SetProxyCurve(new_curve); new_curve = 0; } int eti, ti; int successful_split_count = 0; for (int i=0; i<split_t.Count(); i++) { double t0, t1; m_E[edge_index].GetDomain(&t0, &t1); if (t1 - t0 < 10.0*ON_ZERO_TOLERANCE) break; //6 Dec 2002 Dale Lear: // I added the relative edge_split_s and trm_split_s tests to detect // attempts to trim a nano-gnats-wisker off the end of a trim. double edge_split_s = ON_Interval(t0,t1).NormalizedParameterAt(split_t[i]); double trim_split_s = 0.5; if (split_t[i] - t0 <= ON_ZERO_TOLERANCE || edge_split_s <= ON_SQRT_EPSILON ) { // this split is not possible continue; } if (t1 - split_t[i] <= ON_ZERO_TOLERANCE || edge_split_s >= 1.0-ON_SQRT_EPSILON) { // this split is not possible continue; } // trim_t[] = corresponding trim parameters ON_SimpleArray<double> trim_t(m_E[edge_index].m_ti.Count()); for ( eti = 0; eti < m_E[edge_index].m_ti.Count(); eti++) { ti = m_E[edge_index].m_ti[eti]; if ( ti < 0 || ti >= m_T.Count() ) continue; ON_BrepTrim& trim = m_T[ti]; if ( 0 == i ) { // On the first split, make sure the trim curve is up to snuff. new_curve = TuneupSplitteeHelper(trim.ProxyCurve()); if (new_curve) { trim.m_c2i = AddTrimCurve(new_curve); trim.SetProxyCurve(new_curve); new_curve = 0; } } double t = ON_UNSET_VALUE; if (!GetTrimParameter(ti, split_t[i], &t) || !ON_IsValid(t)) break; trim_t.Append(t); const ON_Interval trim_domain = trim.Domain(); trim_split_s = trim_domain.NormalizedParameterAt(t); if ( trim_split_s <= ON_SQRT_EPSILON || t - trim_domain[0] <= ON_ZERO_TOLERANCE ) break; if ( trim_split_s >= 1.0-ON_SQRT_EPSILON || trim_domain[1] - t <= ON_ZERO_TOLERANCE ) break; } if ( trim_t.Count() != m_E[edge_index].m_ti.Count() ) continue; if (!SplitEdge(edge_index, split_t[i], trim_t)) { continue; } // SplitEdge generally adjusts proxy domains instead // of trimming the orginal curve. These DuplicateCurve() // calls make a new curve whose domain exactly matches // the edge. for ( int epart = 0; epart < 2; epart++ ) { ON_BrepEdge* newE = (0 == epart) ? &m_E[edge_index] : m_E.Last(); if ( 0 == newE ) continue; new_curve = TuneupEdgeOrTrimRealCurve(*newE,true); if (new_curve) { newE->m_c3i = AddEdgeCurve(new_curve); newE->SetProxyCurve(new_curve); } for ( eti = 0; eti < newE->m_ti.Count(); eti++ ) { ti = newE->m_ti[eti]; if ( ti < 0 || ti >= m_T.Count() ) continue; ON_BrepTrim& trim = m_T[ti]; new_curve = TuneupEdgeOrTrimRealCurve(trim,false); if (new_curve) { trim.m_c2i = AddTrimCurve(new_curve); trim.SetProxyCurve(new_curve); } } } successful_split_count++; } return successful_split_count; }
bool ON_Sphere::IsValid() const { return ( ON_IsValid(radius) && radius > 0.0 && plane.IsValid() ) ? true : false; }
void ON_SpaceMorph::SetTolerance(double tolerance) { m_tolerance = (ON_IsValid(tolerance) && tolerance > 0.0 ) ? tolerance : 0.0; }
bool ON_OffsetSurfaceFunction::SetOffsetPoint( double s, double t, double distance, double radius ) { bool rc = false; if ( ON_IsValid(s) && ON_IsValid(t) && ON_IsValid(distance) && ON_IsValid(radius) ) { double u = m_domain[0].NormalizedParameterAt(s); if (u >= -0.01 && u <= 0.0 ) { s = m_domain[0][0]; u = 0.0; } if (u >= 1.0 && u <= 1.01 ) { s = m_domain[0][1]; u = 1.0; } double v = m_domain[1].NormalizedParameterAt(t); if (v >= -0.01 && v <= 0.0 ) { t = m_domain[1][0]; v = 0.0; } if (v >= 1.0 && v <= 1.01 ) { t = m_domain[1][1]; v = 1.0; } if ( u >= 0.0 && u <= 1.0 && v >= 0.0 && v <= 1.0 ) { ON_OffsetSurfaceValue offset_value; offset_value.m_s = s; offset_value.m_t = t; offset_value.m_distance = distance; offset_value.m_radius = (radius > 0.0) ? radius : 0.0; offset_value.m_index = (int)((u + v*4096.0)*4096.0); int i; for ( i = 0; i < m_offset_value.Count(); i++ ) { if ( m_offset_value[i].m_index == offset_value.m_index ) { m_offset_value[i] = offset_value; break; } } if (i == m_offset_value.Count()) { m_offset_value.Append(offset_value); m_bumps.SetCount(0); m_bValid = false; } rc = true; } } return rc; }