Confusion regarding ON_Brep::SetTrimTolerance vs. ON_Brep::IsValidLoop


Can somebody help me with the term “Trim tolerance” (and other tolerances ) in openNURBS, please?

If I check the code of ON_Brep::SetTrimTolerance method, it looks like this

ON_3dPoint prev_end = prev_trim.PointAtEnd(); //prev_c2->PointAt( prev_trim.m_t[1] );
          ON_3dPoint this_start = trim.PointAtStart(); //c2->PointAt( trim.m_t[0] );
          ON_3dPoint this_end = trim.PointAtEnd(); // c2->PointAt( trim.m_t[1] );
          ON_3dPoint next_start = next_trim.PointAtStart(); //prev_c2->PointAt( next_trim.m_t[0] );
          for ( dir = 0; dir < 2; dir++ )
            if ( trim.m_tolerance[dir] < 0.0 || !bLazy )
              ds = fabs(prev_end[dir] - this_start[dir] );
              de = fabs(this_end[dir] - next_start[dir] );
              d = (ds >= de) ? ds : de;
              trim.m_tolerance[dir] = ( d > ON_ZERO_TOLERANCE ) ? 1.001*d : 0.0;

This code snippet suggests that the trim tolerance is used to connect 2d parametric curves having end-points within the given trim tolerance value.

However, in the code of ON_Brep::IsValidLoop, there is no trim tolerances encountered during the validity check:

for ( lti = 0; lti < loop_trim_count; lti++ )
//double x_tol = ON_ZERO_TOLERANCE;
//double y_tol = ON_ZERO_TOLERANCE;
const ON_BrepTrim& trim0 = m_T[loop.m_ti[lti]];
next_lti = (lti+1)%loop_trim_count;
const ON_BrepTrim& trim1 = m_T[loop.m_ti[next_lti]];
ON_Interval trim0_domain = trim0.Domain();
ON_Interval trim1_domain = trim1.Domain();
ci0 = trim0.m_c2i;
ci1 = trim1.m_c2i;
pC0 = m_C2[ci0];
pC1 = m_C2[ci1];
P0 = pC0->PointAt( trim0_domain[1] ); // end of this 2d trim
P1 = pC1->PointAt( trim1_domain[0] ); // start of next 2d trim
if ( !(P0-P1).IsTiny() )
// 16 September 2003 Dale Lear - RR 11319
// Added relative tol check so cases with huge
// coordinate values that agreed to 10 places
// didn’t get flagged as bad.
double xtol = (fabs(P0.x) + fabs(P1.x))*1.0e-10;
double ytol = (fabs(P0.y) + fabs(P1.y))*1.0e-10;
if ( xtol < ON_ZERO_TOLERANCE )
if ( ytol < ON_ZERO_TOLERANCE )
double dx = fabs(P0.x-P1.x);
double dy = fabs(P0.y-P1.y);
if ( dx > xtol || dy > ytol )
if ( text_log )
text_log->Print(“brep.m_L[%d] loop is not valid.\n”,loop_index);
text_log->Print(“end of brep.m_T[loop.m_ti[%d]=%d]=(%g,%g) and start \n”, lti, loop.m_ti[lti],P0.x,P0.y);
text_log->Print(“of brep.m_T[loop.m_ti[%d]=%d]=(%g,%g) do not match.\n”,next_lti, loop.m_ti[next_lti],P1.x,P1.y);
return ON_BrepIsNotValid();

This is quite confusing…

Can anybody point to a good documentation about how to use different tolerances in openNURBS?

Thank you in advance…

This from opennurbs_brep.h:

// The values in m_tolerance[] record the accuracy of
// the parameter space trimming curves.
// Remarks:
//   m_tolerance[0] = accuracy of parameter space curve
//   in first ( "u" ) parameter
//   m_tolerance[1] = accuracy of parameter space curve
//   in second ( "v" ) parameter
//   A value of ON_UNSET_VALUE indicates that the 
//   tolerance should be computed. If the value >= 0.0, 
//   then the tolerance is set.  If the value is 
//   ON_UNSET_VALUE, then the tolerance needs to be
//   computed.
//   If the trim is not singular, then the trim must
//   have an edge.  If P is a 3d point on the edge's
//   curve and surface(u,v) = Q is the point on the 
//   surface that is closest to P, then there must
//   be a parameter t in the interval [m_t[0], m_t[1]]
//   such that
//   |u - curve2d(t)[0]| <= m_tolerance[0]
//   and 
//   |v - curve2d(t)[1]| <= m_tolerance[1]
//   If P is the 3d point for the vertex brep.m_V[m_vi[k]]
//   and (uk,vk) is the corresponding end of the trim's
//   parameter space curve, then there must be a surface
//   parameter (u,v) such that:
//   *  the distance from the 3d point surface(u,v) to P
//      is <= brep.m_V[m_vi[k]].m_tolerance,
//   *  |u-uk| <= m_tolerance[0].
//   *  |v-vk| <= m_tolerance[1].

Does this help?

– Dale

Dear Dale,

Thank you very much pointing the description!

However this description of “Trim Tolerance” doesn’t answer the code of SetTrimTolerance method which sets tollerances of the trims calculating the x and y distances of the neighbouring trim’s end-points…

Is this misleading code only a bug?


Hi @nandorcs,

After some discussions with our team, it appears the trim tolerance is not used anywhere in our code.

Sorry for the confusion.

– Dale

Hi Dale,

Thank you very much clarifying this !

However, this fact of lacking tolerance in parameter space raises further questions:

Brep’s IsValid checker method considers a loop being valid if the end points of adjacent trims are closer than the very-very small fix value of ON_ZERO_TOLERANCE.

Does this mean that if a model is not accurate enough in parameter space, i.e. the distance of the end points of the adjacent pcurves are larger than this very small ON_ZERO_TOLERANCE than you have to extend the pcurves to “intersect” each other (or at least get closer to each other than this zero tolerance) ?

Is there any other trick to handle parameter space inaccuracies?

Is the “extended pcurces” the only way to make a loop valid or should a brep be scaled somehow in the parameter space to become valid?

(Anyway, I have checked the Open Cascade source code which uses vertex tolerances to handle this kind of inaccuracy not only in 3d but in parameter space too…)


Hi @nandorcs,

Rhino always forces the trim ends to be the same. Perhaps this helps?

– Dale

Hi Dale,

Thanks, you answered my question…