# Converting single-loop breps to curves

Is there a convenient way with RhinoCommon to convert a Brep that is known to consist of a single, simple loop into a Curve? I see that I can access the Brep’s trims as Curves, but I can’t find a convenient way to stitch them together. The best I can come up with is creating a new PolyCurve and calling Append for each trim, but that seems clunky.

Are you looking for a RhinoCommon way to do what the DupBorder command does?

I believe so. I’m still not totally familiar with the Rhino geometry model, but that looks right.

``````Brep b; // defined elsewhere
RhinoDoc doc; // the current document

double tolerance = doc.ModelAbsoluteTolerance;
Curve[] nakedEdges = b.DuplicateEdgeCurves(true);
Curve[] joined = Curve.JoinCurves(nakedEdges, 2.1*tolerance);
if (joined.Length < 1 || joined.Length > 1)
{
RhinoApp.WriteLine("Joining of curves failed....");
}
else
{
Curve loop = joined;
}

``````

Thank you! For curiosity’s sake, what’s the basis of the 2.1 factor?

Each curve was created with a certain tolerance. When joining you have to bridge that value twice in the worst case, so a factor of 2.1 seems safe. It is also used often in examples by McNeel.

To be more certain, I typically use this method with a much larger maximumTolerance:

``````public static bool TryJoinCurves(IEnumerable<Curve> curves, out Curve result, double maximumTolerance = 1e-2)
{
if (null == curves || !curves.Any())
{
result = null;
return false;
}

int n = -8;
// attempt to join with increasing tolerances
Curve[] joined = curves.ToArray();
double tolerance = Math.Pow(10, n);
while (tolerance <= maximumTolerance && null != joined && joined.Length > 1)
{
// Ignore curves that are shorter than the tolerance,
// if this is not done, it may lead to incorrect joins
double tol = tolerance;
IEnumerable<Curve> noShortCurves = curves.Where(c => c.GetLength(1e-8) > tol);
joined = Curve.JoinCurves(noShortCurves, tol, false);
tolerance = Math.Pow(10, ++n);
}

// if at some point joined has become null return false
if (null == joined)
{
result = curves.First();
return false;
}

// if the length of joined allows it, set the first curve as the result
result = joined.Length > 0 ? joined.ToNurbsCurve() : curves.First();
return joined.Length == 1;

}
``````

Here is a quick and dirty “DupBorder” equivalent:

``````Rhino.DocObjects.ObjectType filter = Rhino.DocObjects.ObjectType.Surface | Rhino.DocObjects.ObjectType.PolysrfFilter;
Rhino.DocObjects.ObjRef objref = null;
Rhino.Commands.Result rc = Rhino.Input.RhinoGet.GetOneObject("Select surface or polysurface", false, filter, out objref);
if (rc != Rhino.Commands.Result.Success || objref == null)
return rc;

Rhino.DocObjects.RhinoObject rhobj = objref.Object();
Rhino.Geometry.Brep brep = objref.Brep();
if (rhobj == null || brep == null)
return Rhino.Commands.Result.Failure;

rhobj.Select(false);

System.Collections.Generic.List<Rhino.Geometry.Curve> curves = new System.Collections.Generic.List<Rhino.Geometry.Curve>();
foreach (Rhino.Geometry.BrepEdge edge in brep.Edges)
{
// Find only the naked edges
{
Rhino.Geometry.Curve crv = edge.DuplicateCurve();
if (null != crv)