I am new to Rhino and developing a Grasshopper plugin. I am trying to create a Brep which just contains 1 face, but it gives the following error message.
Fails to create a valid Brep with the folowing message:
trim.m_v[0] = -1 is not valid
ON_Brep.m_T[0] is not valid
Does anyone know what the problem is and how I should fix it?
Please find the snippet below. Any class beginning with My* is my own classes. Apologies if the layout doesn’t look neat, I am on mobile. Thanks again.
Nicholas
// 1. Compute the base NURBS surface
// Based on https://developer.rhino3d.com/api/RhinoCommon/html/M_Rhino_Geometry_NurbsSurface_Create.htm
MyNurbsSurface nurbsSurface = ...;
int uDegree = nurbsSurface.UDegree;
int vDegree = nurbsSurface.VDegree;
bool isRational = nurbsSurface.IsURational && nurbsSurface.IsVRational;
int uCount = nurbsSurface.NumOfUControlVertices;
int vCount = nurbsSurface.NumOfVControlVertices;
Rhino.Geometry.NurbsSurface ghNurbsSurface = Rhino.Geometry.NurbsSurface.Create(
3,
isRational,
uDegree + 1,
vDegree + 1,
uCount,
vCount
);
int i = 0;
for (int u = 0; u < uCount; ++u)
{
for (int v = 0; v < vCount; ++v)
{
MyVertex controlVertex = ...;
ghNurbsSurface.Points.SetControlPoint(u, v, ToPoint(controlVertex));
++i;
}
}
List<double> uKnots = nurbsSurface.UKnots;
uKnots = uKnots.GetRange(1, uKnots.Count - 2);
for (int u = 0; u < uKnots.Count; u++)
{
ghNurbsSurface.KnotsU[u] = uKnots[u];
}
List<double> vKnots = nurbsSurface.VKnots;
vKnots = vKnots.GetRange(1, vKnots.Count - 2);
for (int v = 0; v < vKnots.Count; v++)
{
ghNurbsSurface.KnotsV[v] = vKnots[v];
}
if (!ghNurbsSurface.IsValid)
{
throw new Exception("A valid surface cannot be created from this Face.");
}
// 2. Create the Brep
Brep ghBrep = new Brep();
// 2a. Add vertices
List<Vertex> vertices = face.Vertices;
foreach (Vertex vertex in vertices)
{
Point3d ghPoint = ToPoint(vertex);
ghBrep.Vertices.Add(ghPoint, 0.0);
}
// 2b. Add 3D curves and edges
List<MyEdge> edges = face.Edges;
Dictionary<MyEdge, int> edge2DIndices = new Dictionary<MyEdge, int>();
Dictionary<MyEdge, int> edge3DIndices = new Dictionary<MyEdge, int>();
Dictionary<MyEdge, BrepEdge> edgeIndices = new Dictionary<MyEdge, BrepEdge>();
foreach (MyEdge edge in edges)
{
Curve ghCurve3D = ToCurve(edge);
Curve ghCurve2D = ghNurbsSurface.Pullback(ghCurve3D, 0.0001);
int curve3DID = ghBrep.Curves3D.Add(ghCurve3D);
int curve2DID = ghBrep.Curves2D.Add(ghCurve2D);
BrepEdge ghBrepEdge = ghBrep.Edges.Add(curve3DID);
edge3DIndices.Add(edge, curve3DID);
edge2DIndices.Add(edge, curve2DID);
edgeIndices.Add(edge, ghBrepEdge);
}
// 2c. Add surface
int ghSurfaceIndex = ghBrep.AddSurface(ghNurbsSurface);
// 2d. Add face
BrepFace ghBrepFace = ghBrep.Faces.Add(ghSurfaceIndex);
// 2e. Create outer loop
MyWire outerWire = face.ExternalBoundary;
List<MyEdge> outerEdges = outerWire.Edges;
BrepLoop ghBrepOuterLoop = ghBrep.Loops.Add(BrepLoopType.Outer, ghBrepFace);
// 2f. For each loop, add a trim (2D edge)
foreach (MyEdge outerEdge in outerEdges)
{
int outerEdge2DIndex = edge2DIndices.
Where(edgeIndexPair => edgeIndexPair.Key.IsSame(outerEdge)).
Select(edgeIndexPair => edgeIndexPair.Value).
FirstOrDefault();
//int outerEdge3DIndex = edge3DIndices.
// Where(edgeIndexPair => edgeIndexPair.Key.IsSame(outerEdge)).
// Select(edgeIndexPair => edgeIndexPair.Value).
// FirstOrDefault();
Curve ghOuterCurve2D = ghBrep.Curves2D[outerEdge2DIndex];
//Curve ghOuterCurve3D = ghBrep.Curves3D[outerEdge3DIndex];
BrepEdge ghBrepEdge = edgeIndices.
Where(edgeIndexPair => edgeIndexPair.Key.IsSame(outerEdge)).
Select(edgeIndexPair => edgeIndexPair.Value).
FirstOrDefault();
BrepTrim ghBrepTrim = ghBrep.Trims.Add(ghBrepEdge, false, ghBrepOuterLoop, outerEdge2DIndex);
ghBrepTrim.IsoStatus = IsoStatus.None;
ghBrepTrim.TrimType = BrepTrimType.Boundary;
}
// 2g. Create inner loops
List<MyWire innerWires = face.InternalBoundaries;
foreach (MyWire innerWire in innerWires)
{
BrepLoop ghBrepInnerLoop = ghBrep.Loops.Add(BrepLoopType.Inner, ghBrepFace);
List<MyEdge innerEdges = innerWire.Edges;
foreach (MyEdge innerEdge in innerEdges)
{
int innerEdge2DIndex = edge2DIndices.
Where(edgeIndexPair => edgeIndexPair.Key.IsSame(innerEdge)).
Select(edgeIndexPair => edgeIndexPair.Value).
FirstOrDefault();
//int innerEdge3DIndex = edge3DIndices.
// Where(edgeIndexPair => edgeIndexPair.Key.IsSame(innerEdge)).
// Select(edgeIndexPair => edgeIndexPair.Value).
// FirstOrDefault();
Curve ghinnerCurve2D = ghBrep.Curves2D[innerEdge2DIndex];
//Curve ghinnerCurve3D = ghBrep.Curves3D[innerEdge3DIndex];
BrepEdge ghBrepEdge = edgeIndices.
Where(edgeIndexPair => edgeIndexPair.Key.IsSame(innerEdge)).
Select(edgeIndexPair => edgeIndexPair.Value).
FirstOrDefault();
BrepTrim ghBrepTrim = ghBrep.Trims.Add(ghBrepEdge, false, ghBrepInnerLoop, innerEdge2DIndex);
ghBrepTrim.IsoStatus = IsoStatus.None;
ghBrepTrim.TrimType = BrepTrimType.Boundary;
}
}
//ghBrepFace.OrientationIsReversed = false;
String brepFaceLog = "";
if (!ghBrepFace.IsValidWithLog(out brepFaceLog))
{
throw new Exception("Fails to create a valid Face with the following message: " + brepFaceLog);
}
String brepLog = "";
if (!ghBrep.IsValidWithLog(out brepLog))
{
throw new Exception("Fails to create a valid Brep with the following message: " + brepLog);
}
return ghBrep;
is there a reason why you want to create the brep from scratch ? Using the linked example code (the python version) for getting a brep from the nurbs_surface could be done like this:
I am doing this to take into account arbitrary user-defined external and internal boundaries via trims/loops. I am under the impression and a NurbsSurface is always rectangular, but please correct me if I am wrong.
no idea if it’s technically still rectangular under the hood. For adding your own loops and building the brep from scratch, you might take a look at the links from this post. Note the last words too.
Thank you @clement. I was following the linked post, especially the Face with Hole example. After checking it again, I did indeed miss the vertices information (StartVertex and EndVertex of the edges are both null).
And then I tested the code line-by-line, starting with adding vertices and edges. While no OpenNURBS error message was shown, and the resulting Brep was valid, Rhino crashed at the end of the method with the following message in Visual Studio:
Exception thrown at 0x00007FFC5BBD05E3 (rhcommon_c.dll) in Rhino.exe: 0xC0000005: Access violation reading location 0x0000000000000000.
Is there another way to check the validity of the resulting Brep? I am using Rhino 5 64-bit, and it seems like brep.Repair is not available here.
Hi Nicholas, only if you could add the brep to the doc. In RH5 this was possible, in RH6 not anymore. But i guess you’re getting the crash before trying to add the brep to the doc. Can you add a brep.Compact before the crash and try the methods below to test if it is valid*
*note the Rhino 6 help file information about the 3 methods! I know you use RH5 but the help is more complete in V6). Only if log1 is Empty, check log2 and so on
Hi @clement, thank you again. I added brep.Compact and the three Is*() checks, but Rhino still crashed, unfortunately. I will keep checking update this thread.