The flat top surface was trimmed from it’s original size by the fillet command. This presents an issue when getting the edge curves of the surface. The attached Grasshopper script shows the issue:
When querying the surface points, the original surface points are returned. When querying the brep edges, different coordinates are returned. The original surface edge (0,0,0) to (5,0,0) was trimmed to (0,1,0) to (5,1,0).
Up to this point I have been using the following logic to get the edges of a brep:
foreach (var face in brep.Faces) {
var outerTrims = face.Loops.Where(l => l.LoopType == BrepLoopType.Outer).Select(l => l.Trims).First();
foreach (var trim in outerTrims) {
if (trim.Edge != null) {
var curve = trim.Edge.EdgeCurve;
}
}
}
For the specific brep, the edge curves returned, weirdly enough, are a mix of the original surface edge curves together with the newly trimmed edge curve. I have attached the Grasshopper script which has a C# component that proves this case. My question is: am I doing it wrong? Should I be getting some other property of the brep to get the correct edge curves? wtf_surface.gh (8.3 KB) wtf_surface.3dm (67.6 KB)
The easiest change is to remove the .EdgeCurve from your code. The BrepEdge is a “proxy curve” that is defined on subdomain of the underlying edge curve.
The following seems to work as well, and is also more concise:
foreach (var face in brep.Faces)
{
foreach(int ei in face.AdjacentEdges())
{
curves.Add(brep.Edges[ei]);
}
}
Thank you, this works for the perimeter edges indeed. I am confused as to why the EdgeCurve property returns a different geometry though. I have been following this guide for breps so far: Brep data structure.
I have also a lot of other code that looks at internal loops defining holes trying to export all of a NURB surface definition to an external application.
What you are suggesting is that if I just look at the Edge property instead of the Edge.EdgeCurve itself the 3D curve will be correct?
Yes. Also, a BrepEdge may be reversed w.r.t. the referenced curve, so to get the correct head-t-tail orientation of edges along the face boundary, use the Edge , not Edge.EdgeCurve
The curves in the Brep.Curves3D collection are referenced by the BrepEdge, but a BrepEdge may have a sub-domain of the curve it references.
For example a Brep with 4 edges
Brep
Curves3D [0…4]
Curve[0], domain (-2,3)
Curve[1], domain(1,6)
Curve[2], domain(0,5)
Curve[3], domain(2,3)
Edges [0…4]
Edge[0]
references Curves3d[0] with domain (-2,3)
Edge[1]
references Curves3d[1] with domain(1,6)
Edge[2]
references Curves3d[2] with domain (1,5) ← this is a subdomain on the referenced curve.
This is very clear, however, since you seem to be knowledgeable on the matter, I would like to run by you my logic of extracting all surface information (especially for NURBS), which I have updated as per your suggestion.
convertEdge3D and convertEdge2D are just placeholder methods for converting Rhino’s Curve objects to my own curve objects. I then use the converted 3D curves to define the NURB surface and the converted 2D curves to create the surface maps.
foreach (var face in brep.Faces) {
// Convert outer loop.
var outerTrims = face.Loops.Where(l => l.LoopType == BrepLoopType.Outer).Select(l => l.Trims).First();
foreach (var trim in outerTrims) {
// Singular trims will not have a valid edge (e.g. sphere apex).
if (trim.Edge != null) {
convertEdge3D(trim.Edge);
convertEdge2D(trim.TrimCurve);
}
}
// Convert inner loops.
var innerTrimLists = face.Loops.Where(l => l.LoopType == BrepLoopType.Inner).Select(l => l.Trims).ToList();
foreach (var innerTrimList in innerTrimLists) {
foreach (var trim in innerTrimList) {
convertEdge3D(trim.Edge);
convertEdge2D(trim.TrimCurve);
}
}
}