/// <summary> /// Converts a Speckle <see cref="Brep"/> instance to a Rhino <see cref="Rhino.Geometry.Brep"/> /// </summary> /// <param name="brep">The Speckle Brep to convert</param> /// <returns></returns> /// <exception cref="Exception">Throws exception if the provenance is not Rhino</exception> public RH.Brep BrepToNative(Brep brep) { var tol = RhinoDoc.ActiveDoc.ModelAbsoluteTolerance; try { // TODO: Provenance exception is meaningless now, must change for provenance build checks. // if (brep.provenance != Speckle.Core.Kits.Applications.Rhino) // throw new Exception("Unknown brep provenance: " + brep.provenance + // ". Don't know how to convert from one to the other."); var newBrep = new RH.Brep(); brep.Curve3D.ForEach(crv => newBrep.AddEdgeCurve(CurveToNative(crv))); brep.Curve2D.ForEach(crv => newBrep.AddTrimCurve(CurveToNative(crv))); brep.Surfaces.ForEach(surf => newBrep.AddSurface(SurfaceToNative(surf))); brep.Vertices.ForEach(vert => newBrep.Vertices.Add(PointToNative(vert).Location, tol)); brep.Edges.ForEach(edge => { if (edge.Domain == null || (edge.Domain.start == edge.Curve.domain.start && edge.Domain.end == edge.Curve.domain.end)) { newBrep.Edges.Add(edge.Curve3dIndex); } else { newBrep.Edges.Add(edge.StartIndex, edge.EndIndex, edge.Curve3dIndex, IntervalToNative(edge.Domain), tol); } }); brep.Faces.ForEach(face => { var f = newBrep.Faces.Add(face.SurfaceIndex); f.OrientationIsReversed = face.OrientationReversed; }); brep.Loops.ForEach(loop => { var f = newBrep.Faces[loop.FaceIndex]; var l = newBrep.Loops.Add((RH.BrepLoopType)loop.Type, f); loop.Trims.ToList().ForEach(trim => { RH.BrepTrim rhTrim; if (trim.EdgeIndex != -1) { rhTrim = newBrep.Trims.Add(newBrep.Edges[trim.EdgeIndex], trim.IsReversed, newBrep.Loops[trim.LoopIndex], trim.CurveIndex); } else if (trim.TrimType == BrepTrimType.Singular) { rhTrim = newBrep.Trims.AddSingularTrim(newBrep.Vertices[trim.EndIndex], newBrep.Loops[trim.LoopIndex], (RH.IsoStatus)trim.IsoStatus, trim.CurveIndex); } else { rhTrim = newBrep.Trims.Add(trim.IsReversed, newBrep.Loops[trim.LoopIndex], trim.CurveIndex); } rhTrim.IsoStatus = (IsoStatus)trim.IsoStatus; rhTrim.TrimType = (RH.BrepTrimType)trim.TrimType; rhTrim.SetTolerances(tol, tol); }); }); newBrep.Repair(tol); return(newBrep); } catch (Exception e) { ConversionErrors.Add(new Exception("Failed to convert brep.", e)); return(null); } }
/// <summary> /// Converts a Rhino <see cref="Rhino.Geometry.Brep"/> instance to a Speckle <see cref="Brep"/> /// </summary> /// <param name="brep">BREP to be converted.</param> /// <returns></returns> public Brep BrepToSpeckle(RH.Brep brep, string units = null) { var tol = RhinoDoc.ActiveDoc.ModelAbsoluteTolerance; //tol = 0; var u = units ?? ModelUnits; brep.Repair(tol); //should maybe use ModelAbsoluteTolerance ? // foreach (var f in brep.Faces) // { // f.RebuildEdges(tol, false, false); // } // Create complex var joinedMesh = new RH.Mesh(); var mySettings = MeshingParameters.Minimal; joinedMesh.Append(RH.Mesh.CreateFromBrep(brep, mySettings)); joinedMesh.Weld(Math.PI); joinedMesh.Vertices.CombineIdentical(true, true); joinedMesh.Compact(); var spcklBrep = new Brep(displayValue: MeshToSpeckle(joinedMesh, u), provenance: Applications.Rhino, units: u); // Vertices, uv curves, 3d curves and surfaces spcklBrep.Vertices = brep.Vertices .Select(vertex => PointToSpeckle(vertex, u)).ToList(); spcklBrep.Curve3D = brep.Curves3D .Select(curve3d => { Rhino.Geometry.Curve crv = curve3d; if (crv is NurbsCurve nurbsCurve) { // Nurbs curves of degree 2 have weird support in Revit, so we up everything to degree 3. if (nurbsCurve.Degree < 3) { nurbsCurve.IncreaseDegree(3); } // Check for invalid multiplicity in the curves. This is also to better support Revit. var invalid = HasInvalidMultiplicity(nurbsCurve); // If the curve has invalid multiplicity and is not closed, rebuild with same number of points and degree. // TODO: Figure out why closed curves don't like this hack? if (invalid) { nurbsCurve = nurbsCurve.Rebuild(nurbsCurve.Points.Count * 3, nurbsCurve.Degree, true);; var in1 = HasInvalidMultiplicity(nurbsCurve); Console.WriteLine(in1); } nurbsCurve.Domain = curve3d.Domain; crv = nurbsCurve; } var icrv = ConvertToSpeckle(crv) as ICurve; return(icrv); // And finally convert to speckle }).ToList(); spcklBrep.Curve2D = brep.Curves2D.ToList().Select(c => { var curve = c; if (c is NurbsCurve nurbsCurve) { var invalid = HasInvalidMultiplicity(nurbsCurve); if (invalid) { //nurbsCurve = nurbsCurve.Fit(nurbsCurve.Degree, 0, 0).ToNurbsCurve(); nurbsCurve = nurbsCurve.Rebuild(nurbsCurve.Points.Count * 3, nurbsCurve.Degree, true); var in1 = HasInvalidMultiplicity(nurbsCurve); } curve = nurbsCurve; } var crv = CurveToSpeckle(c, Units.None); return(crv); }).ToList(); spcklBrep.Surfaces = brep.Surfaces .Select(srf => SurfaceToSpeckle(srf.ToNurbsSurface(), u)).ToList(); spcklBrep.IsClosed = brep.IsSolid; spcklBrep.Orientation = (BrepOrientation)brep.SolidOrientation; // Faces spcklBrep.Faces = brep.Faces .Select(f => new BrepFace( spcklBrep, f.SurfaceIndex, f.Loops.Select(l => l.LoopIndex).ToList(), f.OuterLoop.LoopIndex, f.OrientationIsReversed )).ToList(); // Edges spcklBrep.Edges = brep.Edges .Select(edge => new BrepEdge( spcklBrep, edge.EdgeCurveIndex, edge.TrimIndices(), edge.StartVertex?.VertexIndex ?? -1, edge.EndVertex?.VertexIndex ?? -1, edge.ProxyCurveIsReversed, IntervalToSpeckle(edge.Domain) )).ToList(); // Loops spcklBrep.Loops = brep.Loops .Select(loop => new BrepLoop( spcklBrep, loop.Face.FaceIndex, loop.Trims.Select(t => t.TrimIndex).ToList(), (BrepLoopType)loop.LoopType )).ToList(); // Trims spcklBrep.Trims = brep.Trims .Select(trim => { var t = new BrepTrim( spcklBrep, trim.Edge?.EdgeIndex ?? -1, trim.Face.FaceIndex, trim.Loop.LoopIndex, trim.TrimCurveIndex, (int)trim.IsoStatus, (BrepTrimType)trim.TrimType, trim.IsReversed(), trim.StartVertex.VertexIndex, trim.EndVertex.VertexIndex ); t.Domain = IntervalToSpeckle(trim.Domain); return(t); }) .ToList(); spcklBrep.volume = brep.GetVolume(); spcklBrep.bbox = BoxToSpeckle(new RH.Box(brep.GetBoundingBox(true)), u); spcklBrep.area = brep.GetArea(); return(spcklBrep); }