ON_Brep.m_T[3].m_bRev3d = false, but closed curve directions are opposite


I get the following error on some Brep trims:

ON_Brep.m_T[3].m_bRev3d = false, but closed curve directions are opposite.

How do I make sure I correctly reverse the trim? I already use:


This works most of the time, but not always. Is there a better way?

Hi @Mike_Johnson,

The code that tests for this is in ON_Brep::IsValid. If you are using openNURBS, you can either look at this code or trace into it during a debug session.

Basically, a trim curve and it’s cooresponding edge curve, should be oriented in opposite directions. If not, then set trim.m_bRev3d = true.

– Dale

Thanks for that, @dale. However, as I’m dealing with only NURBS data, I can’t be certain that the trim needs to be reversed. I was hoping for a easy check.

My only idea is to use BrepTrim.IsValidWithLog on every trim and check for this error message and reverse the trim if it occurs. I don’t like this. Do you have any other ideas, @dale?

Thanks for your help so far.

Hi @Mike_Johnson,

If the trim curve and it’s edge curve are going in the same direction, flip the trim. You can determine the direction by checking tangency at “similar” locations.

– Dale

Hi @dale,

Thanks for the advice. However, it doesn’t quite work right. I have the following code:

bool isReversed = false;

Vector3d edgeStartTangent = edge.EdgeCurve.TangentAt(Tolerance);

Vector3d trimStartTangent = trimmingCurve.TangentAt(Tolerance);

if (edgeStartTangent.EpsilonEquals(trimStartTangent, Tolerance))
	isReversed = true;

BrepTrim trim = brep.Trims.Add(edge, isReversed, loop, curve2DIndex);

Where trimmingCurve is 3D. I now get errors similar to:

Distance from start of ON_Brep.m_T[0] to 3d edge is 1.98572. (edge tol = 1e-05, trim tol ~ 9.02526e-05).

I think I’m reversing the trim when I shouldn’t be, as if I swap false and true, it works slightly better, but then I get the original error, but only on a few trims.

Hi @Mike_Johnson,

Here is the code you are fighting:

ON_3dPoint trim_pt0, trim_pt1, srf_pt0, srf_pt1;
ON_3dVector trim_der0, trim_der1, srf_du0, srf_dv0, srf_du1, srf_dv1;
ON_Interval trim_domain = trim.Domain();
// trim_pt0 should be closed to trim_pt1 except when
// trim starts and ends on opposite sides of a surface 
// seam.  Even when the trim curve is closed, the 
// derivatives can be different when there is
// a kink at the start/end of a trim.
trim.Ev1Der( trim_domain[0], trim_pt0, trim_der0 );
trim.Ev1Der( trim_domain[1], trim_pt1, trim_der1 );

const ON_Surface* trim_srf = m_F[ m_L[trim.m_li].m_fi ].SurfaceOf();
trim_srf->Ev1Der( trim_pt0.x, trim_pt0.y, srf_pt0, srf_du0, srf_dv0 );
trim_srf->Ev1Der( trim_pt1.x, trim_pt1.y, srf_pt1, srf_du1, srf_dv1 );

// estimate 3d tolerances from 2d trim tolerances
double t0_tol = srf_du0.Length()*trim.m_tolerance[0] + srf_dv0.Length()*trim.m_tolerance[1];
double t1_tol = srf_du1.Length()*trim.m_tolerance[0] + srf_dv1.Length()*trim.m_tolerance[1];
ON_3dVector trim_tangent0 = trim_der0.x*srf_du0 + trim_der0.y*srf_dv0;
ON_3dVector trim_tangent1 = trim_der1.x*srf_du1 + trim_der1.y*srf_dv1;
ON_3dVector edge_tangent0 = edge.TangentAt( edge.Domain()[trim.m_bRev3d ? 1 : 0] );
ON_3dVector edge_tangent1 = edge.TangentAt( edge.Domain()[trim.m_bRev3d ? 0 : 1] );
double d0 = trim_tangent0*edge_tangent0;
double d1 = trim_tangent1*edge_tangent1;
if ( trim.m_bRev3d )
  d0 = -d0;
  d1 = -d1;
if (    trim.m_vi[0] == trim.m_vi[1] 
      && edge.m_vi[0] == edge.m_vi[1] 
      && trim.m_vi[0] == edge.m_vi[0] 
  // For high quality models, d0 and d1 should be close to +1.
  // If both are close to -1, the trim.m_bRev3d flag is most
  // likely set opposite of what it should be.

  // check start tangent to see if m_bRev3d is set correctly
  if ( d0 < 0.0 || d1 < 0.0)
    if ( text_log )
      if ( trim.m_bRev3d )
        text_log->Print("ON_Brep.m_T[%d].m_bRev3d = true, but closed curve directions are the same.\n",ti);
        text_log->Print("ON_Brep.m_T[%d].m_bRev3d = false, but closed curve directions are opposite.\n",ti);
    return ON_BrepIsNotValid();


const ON_BrepEdge& edge = m_E[trim.m_ei];

Perhaps you can gleam something from this.

Building Breps from scratch can be hard. Perhaps there is another way to get what you want. Can you provide more information on what you have? Are you creating a single-surface Brep, or one that has multiple surfaces? Where did the edge and trim information come from?

– Dale