static int AddSurface(Brep brep, DB.Face face, out List <BrepBoundary>[] shells, Dictionary <DB.Edge, BrepEdge> brepEdges = null) { // Extract base surface if (ToRhinoSurface(face, out var parametricOrientation) is Surface surface) { if (!parametricOrientation) { surface.Transpose(true); } int si = brep.AddSurface(surface); if (surface is PlaneSurface planar) { var nurbs = planar.ToNurbsSurface(); nurbs.KnotsU.InsertKnot(surface.Domain(0).Mid); nurbs.KnotsV.InsertKnot(surface.Domain(1).Mid); surface = nurbs; } else if (surface is SumSurface sum) { surface = sum.ToNurbsSurface(); } // Extract and classify Edge Loops var edgeLoops = new List <BrepBoundary>(face.EdgeLoops.Size); foreach (var edgeLoop in face.EdgeLoops.Cast <DB.EdgeArray>()) { if (edgeLoop.IsEmpty) { continue; } var edges = edgeLoop.Cast <DB.Edge>(); if (!face.MatchesSurfaceOrientation()) { edges = edges.Reverse(); } var loop = new BrepBoundary() { type = BrepLoopType.Unknown, edges = new List <BrepEdge>(edgeLoop.Size), trims = new PolyCurve(), orientation = new List <int>(edgeLoop.Size) }; foreach (var edge in edges) { var brepEdge = default(BrepEdge); if (brepEdges?.TryGetValue(edge, out brepEdge) != true) { var curve = edge.AsCurve(); if (curve is null) { continue; } brepEdge = brep.Edges.Add(brep.AddEdgeCurve(ToRhino(curve))); brepEdges?.Add(edge, brepEdge); } loop.edges.Add(brepEdge); var segment = ToRhino(edge.AsCurveFollowingFace(face)); if (!face.MatchesSurfaceOrientation()) { segment.Reverse(); } loop.orientation.Add(segment.TangentAt(segment.Domain.Mid).IsParallelTo(brepEdge.TangentAt(brepEdge.Domain.Mid))); var trim = surface.Pullback(segment, Revit.VertexTolerance); loop.trims.Append(trim); } loop.trims.MakeClosed(Revit.VertexTolerance); switch (loop.trims.ClosedCurveOrientation()) { case CurveOrientation.Undefined: loop.type = BrepLoopType.Unknown; break; case CurveOrientation.CounterClockwise: loop.type = BrepLoopType.Outer; break; case CurveOrientation.Clockwise: loop.type = BrepLoopType.Inner; break; } edgeLoops.Add(loop); } var outerLoops = edgeLoops.Where(x => x.type == BrepLoopType.Outer); var innerLoops = edgeLoops.Where(x => x.type == BrepLoopType.Inner); // Group Edge loops in shells with the outer loop as the first one shells = outerLoops. Select(x => new List <BrepBoundary>() { x }). ToArray(); if (shells.Length == 1) { shells[0].AddRange(innerLoops); } else { foreach (var edgeLoop in innerLoops) { foreach (var shell in shells) { var containment = Curve.PlanarClosedCurveRelationship(edgeLoop.trims, shell[0].trims, Plane.WorldXY, Revit.VertexTolerance); if (containment == RegionContainment.AInsideB) { shell.Add(edgeLoop); break; } } } } return(si); } shells = default; return(-1); }
static int AddSurface(Brep brep, Surface surface, Curve[] loops, out List <BrepBoundary>[] shells) { // Extract base surface if (surface is object) { double trimTolerance = Revit.VertexTolerance * 0.1; int si = brep.AddSurface(surface); if (surface is PlaneSurface) { var nurbs = surface.ToNurbsSurface(); nurbs.KnotsU.InsertKnot(surface.Domain(0).Mid); nurbs.KnotsV.InsertKnot(surface.Domain(1).Mid); surface = nurbs; } // Classify Loops var nesting = new int[loops.Length]; var edgeLoops = new BrepBoundary[loops.Length]; { var trims = new Curve[loops.Length]; int index = 0; foreach (var loop in loops) { if (loop is PolyCurve polycurve) { var trim = new PolyCurve(); for (int s = 0; s < polycurve.SegmentCount; s++) { var segment = polycurve.SegmentCurve(s); var trimSegment = surface.Pullback(segment, trimTolerance); trim.AppendSegment(trimSegment); } trims[index++] = trim; } else { trims[index++] = surface.Pullback(loop, trimTolerance); } } for (int i = 0; i < edgeLoops.Length; ++i) { for (int j = i + 1; j < edgeLoops.Length; ++j) { var containment = Curve.PlanarClosedCurveRelationship(trims[i], trims[j], Plane.WorldXY, Revit.VertexTolerance * Revit.ModelUnits); if (containment == RegionContainment.MutualIntersection) { edgeLoops[i].type = BrepLoopType.Outer; edgeLoops[j].type = BrepLoopType.Outer; } else if (containment == RegionContainment.AInsideB) { nesting[i]++; } else if (containment == RegionContainment.BInsideA) { nesting[j]++; } } } // Fix orientation if necessary index = 0; foreach (var loop in loops) { // Ignore intersecting loops if (edgeLoops[index].type == BrepLoopType.Unknown) { if (nesting[index] % 2 != 0) { edgeLoops[index].type = BrepLoopType.Inner; } else { edgeLoops[index].type = BrepLoopType.Outer; } } switch (trims[index].ClosedCurveOrientation()) { case CurveOrientation.Undefined: break; case CurveOrientation.CounterClockwise: if (edgeLoops[index].type == BrepLoopType.Inner) { loops[index].Reverse(); } break; case CurveOrientation.Clockwise: if (edgeLoops[index].type == BrepLoopType.Outer) { loops[index].Reverse(); } break; } ++index; } } // Create Brep Edges and compute trims { int index = 0; foreach (var edgeLoop in loops) { // Ignore unclasified loops if (edgeLoops[index].type == BrepLoopType.Unknown) { continue; } var kinks = new List <double>(); { var domain = edgeLoop.Domain; var t = domain.Min; while (edgeLoop.GetNextDiscontinuity(Continuity.C1_locus_continuous, t, domain.Max, out t)) { kinks.Add(t); } } var edges = kinks.Count > 0 ? edgeLoop.Split(kinks) : new Curve[] { edgeLoop }; edgeLoops[index].edges = new List <BrepEdge>(); edgeLoops[index].trims = new PolyCurve(); edgeLoops[index].orientation = new List <int>(); foreach (var edge in edges) { var brepEdge = default(BrepEdge); brepEdge = brep.Edges.Add(brep.AddEdgeCurve(edge)); edgeLoops[index].edges.Add(brepEdge); var segment = edge; edgeLoops[index].orientation.Add(segment.TangentAt(segment.Domain.Mid).IsParallelTo(brepEdge.TangentAt(brepEdge.Domain.Mid))); var trim = surface.Pullback(segment, trimTolerance); edgeLoops[index].trims.Append(trim); } edgeLoops[index].trims.MakeClosed(Revit.VertexTolerance); ++index; } } // Sort edgeLoops in nesting orther, shallow loops first Array.Sort(nesting, edgeLoops); var outerLoops = edgeLoops.Where(x => x.type == BrepLoopType.Outer); var innerLoops = edgeLoops.Where(x => x.type == BrepLoopType.Inner); // Group Edge loops in shells with the outer loop as the first one shells = outerLoops. Select(x => new List <BrepBoundary>() { x }). ToArray(); if (shells.Length == 1) { shells[0].AddRange(innerLoops); } else { // Iterate in reverse order to found deeper loops before others foreach (var innerLoop in innerLoops.Reverse()) { foreach (var shell in shells.Reverse()) { var containment = Curve.PlanarClosedCurveRelationship(innerLoop.trims, shell[0].trims, Plane.WorldXY, Revit.VertexTolerance); if (containment == RegionContainment.AInsideB) { shell.Add(innerLoop); break; } } } } return(si); } shells = default; return(-1); }
static int AddSurface(Brep brep, DB.Face face, out List <BrepBoundary>[] shells, Dictionary <DB.Edge, BrepEdge> brepEdges = null) { // Extract base surface if (ToRhinoSurface(face, out var parametricOrientation) is Surface surface) { if (!parametricOrientation) { surface.Transpose(true); } int si = brep.AddSurface(surface); if (surface is PlaneSurface planar) { var nurbs = planar.ToNurbsSurface(); nurbs.KnotsU.InsertKnot(surface.Domain(0).Mid); nurbs.KnotsV.InsertKnot(surface.Domain(1).Mid); surface = nurbs; } else if (surface is SumSurface sum) { surface = sum.ToNurbsSurface(); } // Extract and classify Edge Loops var edgeLoops = new List <BrepBoundary>(face.EdgeLoops.Size); foreach (var edgeLoop in face.EdgeLoops.Cast <DB.EdgeArray>()) { if (edgeLoop.IsEmpty) { continue; } var edges = edgeLoop.Cast <DB.Edge>(); if (!face.MatchesSurfaceOrientation()) { edges = edges.Reverse(); } var loop = new BrepBoundary() { type = BrepLoopType.Unknown, orientation = new List <int>(edgeLoop.Size), edges = new List <BrepEdge>(edgeLoop.Size), trims = new PolyCurve() }; var trims = new List <Curve>(edgeLoop.Size); foreach (var edge in edges) { var brepEdge = default(BrepEdge); if (brepEdges?.TryGetValue(edge, out brepEdge) != true) { var curve = edge.AsCurve(); if (curve is null) { continue; } brepEdge = brep.Edges.Add(brep.AddEdgeCurve(ToRhino(curve))); brepEdges?.Add(edge, brepEdge); } var segment = ToRhino(edge.AsCurveFollowingFace(face)); if (!face.MatchesSurfaceOrientation()) { segment.Reverse(); } if (surface.Pullback(segment, 1e-5) is Curve trim) { trims.Add(trim); loop.edges.Add(brepEdge); loop.orientation.Add(segment.TangentAt(segment.Domain.Mid).IsParallelTo(brepEdge.TangentAt(brepEdge.Domain.Mid))); } } // Add singular edges for (int ti = 0, ei = 0; ti < trims.Count; ++ti, ++ei) { int tA = ti; int tB = (ti + 1) % trims.Count; loop.trims.AppendSegment(trims[tA]); int eA = ei; int eB = (ei + 1) % loop.edges.Count; var start = loop.orientation[eA] > 0 ? (loop.edges[eA]).PointAtEnd : (loop.edges[eA]).PointAtStart; var end = loop.orientation[eB] > 0 ? (loop.edges[eB]).PointAtStart : (loop.edges[eB]).PointAtEnd; if (start.EpsilonEquals(end, Revit.VertexTolerance)) { var startTrim = new Point2d(trims[tA].PointAtEnd); var endTrim = new Point2d(trims[tB].PointAtStart); var midTrim = (endTrim + startTrim) * 0.5; if (surface.IsAtSingularity(midTrim.X, midTrim.Y, false)) { loop.orientation.Insert(eA + 1, 0); loop.edges.Insert(eA + 1, default); loop.trims.AppendSegment(new LineCurve(startTrim, endTrim)); ei++; } } else // Missing edge { Debug.WriteLine("Missing edge detected"); } } loop.trims.MakeClosed(Revit.VertexTolerance); switch (loop.trims.ClosedCurveOrientation()) { case CurveOrientation.Undefined: loop.type = BrepLoopType.Unknown; break; case CurveOrientation.CounterClockwise: loop.type = BrepLoopType.Outer; break; case CurveOrientation.Clockwise: loop.type = BrepLoopType.Inner; break; } edgeLoops.Add(loop); } var outerLoops = edgeLoops.Where(x => x.type == BrepLoopType.Outer); var innerLoops = edgeLoops.Where(x => x.type == BrepLoopType.Inner); // Group Edge loops in shells with the outer loop as the first one shells = outerLoops. Select(x => new List <BrepBoundary>() { x }). ToArray(); if (shells.Length == 1) { shells[0].AddRange(innerLoops); } else { foreach (var edgeLoop in innerLoops) { foreach (var shell in shells) { var containment = Curve.PlanarClosedCurveRelationship(edgeLoop.trims, shell[0].trims, Plane.WorldXY, Revit.VertexTolerance); if (containment == RegionContainment.AInsideB) { shell.Add(edgeLoop); break; } } } } return(si); } shells = default; return(-1); }