예제 #1
0
        public static bool _IsSameDirectionToEdge(this BrepTrim trim, Surface srf,
                                                  Point3d trimT03d, Point3d trimT13d,
                                                  Point3d edgeT03d, Point3d edgeT13d, bool validateTrimType = true)
        {
            if (validateTrimType) // speed optimization - avoiding call to UnsafeNativeMethods.ON_BrepTrim_Type
            {
                if (trim.TrimType == BrepTrimType.Singular)
                {
                    return(false);
                }
            }
            return(_Vector3d._IsSameDirection(trimT03d, trimT13d, edgeT03d, edgeT13d));

            //            ON_BrepTrim&
            //ON_Brep::NewTrim( ON_BrepEdge& edge, ON_BOOL32 bRev3d, int c2i )
            //{
            //  m_is_solid = 0;
            //  ON_BrepTrim& trim = NewTrim( c2i );
            //  trim.m_ei = edge.m_edge_index;
            //  edge.m_ti.Append(trim.m_trim_index);
            //  trim.m_vi[0] = edge.m_vi[bRev3d?1:0];
            //  trim.m_vi[1] = edge.m_vi[bRev3d?0:1];
            //  trim.m_bRev3d = bRev3d?true:false;
            //  return trim;
            //}
        }
예제 #2
0
        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            Surface         Srf       = default(Surface);
            List <Curve>    Crvs      = new List <Curve>();
            List <BrepTrim> TrimsList = new List <BrepTrim>();
            double          Length    = 2;
            bool            IsSmooth  = true;

            if (!DA.GetData(0, ref Srf))
            {
                return;
            }
            if (!DA.GetDataList <Curve>(1, Crvs))
            {
                return;
            }
            if (!DA.GetData(2, ref Length))
            {
                return;
            }
            if (!DA.GetData(3, ref IsSmooth))
            {
                return;
            }


            Brep TempBrep = Srf.ToBrep();

            if (!TempBrep.IsSurface || TempBrep == null)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Unable to extend trimmed surfaces.:line 67");
                return;
            }
            //BrepTrimList is an reference object
            BrepTrimList BrepTrimList = TempBrep.Trims;

            for (int Index = 0; Index < Crvs.Count; Index++)
            {
                BrepTrim TrimItem = this.GetClosetBrepTrim(BrepTrimList, Crvs[Index]);
                TrimsList.Add(TrimItem);
            }
            var TempList = TrimsList.Where(item => item == null || item.TrimType == BrepTrimType.Seam).ToList();

            if (TempList.Count != 0)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Unable to extend trimmed surfaces. line 81");
            }
            ///<summary>
            ///如果输入的Surface为UntrimSurface,那么Extend会对Surface进行延伸,如果输入的Surface为Untrim Surface,Extend
            ///方法就会先对Surface 执行‘untrim’操作,然后再对面进行延伸
            /// </summary>
            for (int Index = 0; Index < TrimsList.Count; Index++)
            {
                Srf = Srf.Extend(TrimsList[Index].IsoStatus, Length, IsSmooth);
            }
            DA.SetData(0, Srf);
        }
예제 #3
0
        public static int _EndVertexIndex(this BrepTrim trim, double tol = 10, bool throwExceptionIfNotFound = true)
        {
            if (trim.Edge != null)
            {
                return(trim.Edge._GetEndVertex().VertexIndex);
            }
            var point = trim.Face.PointAt(trim.PointAtEnd.X, trim.PointAtEnd.Y);

            return(point._GetVertexIndex(trim.Brep.Vertices, tol, throwExceptionIfNotFound));
        }
예제 #4
0
        /// <summary>
        /// Get index of trim in loop to which it belongs.
        /// Dont use TrimIndex, since it is global index: index of trim in all trims from Brep.
        /// </summary>
        /// <param name="trim"></param>
        /// <param name="loopTrims"></param>
        /// <returns></returns>
        public static int _IndexInLoop(this BrepTrim trim, BrepTrimList loopTrims = null)
        {
            var trims = loopTrims ?? trim.Loop.Trims_ThreadSafe();

            for (int i = 0; i < trims.Count; i++)
            {
                if (trims[i].TrimIndex == trim.TrimIndex)
                {
                    return(i);
                }
            }
            throw new Exception("Cannot find trimindex in mehod: _BrepTrim._IndexInLoop(trim)");
        }
예제 #5
0
        /* OLD CODE
         * public static void _RecreateCurves(this BrepTrim trim, Surface srf, SurfaceSingulars ssingulars, bool reverseCurveDirection, bool fixDeformedEdges, double tol_tol_fixDeformedEdges, bool recreate3dCurves, out NurbsCurve crv3d, out NurbsCurve crv2d)
         * {
         *  if (recreate3dCurves)
         *  {
         *      crv3d = trim._PullEdgeToSurface(srf, ssingulars, reverseCurveDirection, fixDeformedEdges, tol_tol_fixDeformedEdges);
         *
         *      ////DEBUG
         *      //foreach (var l in crv3d.Points)
         *      //{
         *      //    debugIndexEdge2++;
         *      //    string text = "#" + debugIndexEdge2;
         *      //    AddDebugPoint(Doc, text, l.Location, Color.Gold); //debug
         *      //}
         *
         *      //
         *      // Create 2d curve (trim) from new edge (that is already projected on surface)
         *      // High interpolation of 500 points makes mistakes almost unvisible
         *      //
         *      crv2d = srf._Convert3dCurveTo2d(crv3d, ssingulars, trim);
         *  }
         *  else
         *  {
         *      crv3d = trim.Edge._ToNurbsCurve();
         *      crv2d = trim._ToNurbsCurve();
         *
         *      if (reverseCurveDirection)
         *      {
         *          crv3d.Reverse();
         *      }
         *
         *      // Reverse 2d crv if needed
         *      var trimStartPoint = srf.PointAt(trim.PointAtStart.X, trim.PointAtStart.Y);
         *      var trimEndPoint = srf.PointAt(trim.PointAtEnd.X, trim.PointAtEnd.Y);
         *      if (crv3d.PointAtStart.DistanceTo(trimStartPoint) > crv3d.PointAtStart.DistanceTo(trimEndPoint))
         *      {
         *          crv2d.Reverse();
         *      }
         *  }
         * }
         *
         * public static NurbsCurve _PullEdgeToSurface(this BrepTrim trim, Surface srf, SurfaceSingulars ssingulars, bool reverseCurveDirection, bool fixDeformedEdges, double tol_tol_fixDeformedEdges)
         * {
         *  //
         *  // Project Edge to surface, and create new Edge from control points (edge devided by 100 points)
         *  //
         *  Curve edge = trim.Edge;
         *  NurbsCurve crv3d = null;
         *
         *  if (fixDeformedEdges)
         *  {
         *      NurbsCurve newedge;
         *      if (edge._ZigZagDeformations_TryRemove_old(srf, tol_tol_fixDeformedEdges, out newedge))
         *      {
         *          //log.temp("trim #{0} had zigzag ", trimIndex+1);
         *          edge = newedge;
         *      }
         *  }
         *  int DIVIDE_BY_COUNT_I = Math.Min(Math.Max(Convert.ToInt32(edge._GetLength_ThreadSafe() / 0.01), 10), 100);
         *  if (edge.Degree == 1)
         *  {
         *      DIVIDE_BY_COUNT_I = 10;
         *  }
         *
         *  Point3d[] edgeDevidedPoints;
         *  edge.DivideByCount(DIVIDE_BY_COUNT_I, true, out edgeDevidedPoints);
         *  if (edgeDevidedPoints != null)
         *  {
         *      if (reverseCurveDirection)
         *      {
         *          edgeDevidedPoints = edgeDevidedPoints.Reverse().ToArray();
         *      }
         *      var edgeDevidedUV = srf._ClosestPoints(edgeDevidedPoints);
         *
         *
         *      //DEBUG
         *      //Logger.log("+++");
         *      //foreach (var p in edgeDevidedUV)
         *      //{
         *      //    debugIndexEdge++;
         *      //    //bool inside = trim.Brep.IsPointInside(point, 0.000001,false);
         *      //    if (debugIndexEdge < debugIndexMAX)
         *      //    {
         *      //        string text = "#" + debugIndexEdge + ":   " + String.Format("{0:0.00}", p.u) + " - " + String.Format("{0:0.00}", p.v);
         *      //        //string text = "#" + debugIndexEdge;
         *      //        AddDebugPoint(Doc, text, srf.PointAt(p.u, p.v), Color.Red); //debug
         *      //        Logger.log(text);
         *      //    }
         *      //}
         *
         *      //
         *      // Fix U or V in singularities (in case where values are indentical at start of surface (like Point3d(u, v) == Point3d(u, v+100)));
         *      //
         *      var fixedSrf = srf._FixSurfacePoints(ref edgeDevidedUV, true, ssingulars, trim);
         *
         *      //
         *      // Contruct 3d curve on surface
         *      //
         *      var points2d = edgeDevidedUV.Select(o => new Point2d(o.u, o.v)).ToList();
         *      crv3d = srf.InterpolatedCurveOnSurfaceUV(points2d, 0.0000001);
         *
         *      if (crv3d == null)
         *      {
         *          var point3d = edgeDevidedUV.Select(o => srf.PointAt(o.u, o.v)).ToList();
         *          crv3d = srf.InterpolatedCurveOnSurface(point3d, 0.0001);
         *          //crv3d = crv3d;
         *          //var doc = RhinoDoc.ActiveDoc;
         *          //foreach (var p in point3d)
         *          //{
         *          //    debugIndexEdge2++;
         *          //    string text = "#" + debugIndexEdge2;
         *          //    AddDebugPoint(doc, text, p, Color.Gold); //debug
         *          //}
         *      }
         *  }
         *
         *
         *
         *  if (crv3d == null)
         *  {
         *      //log.error(g.IssueFixer, "Can't build crv3d from 2D points");
         *      throw new Exception("Can't rebuild " + trim._GUIEdgeName());
         *  }
         *
         *  return crv3d;
         * }
         *
         * private static void AddDebugPoint(RhinoDoc doc, string text, Point3d point, Color color = default(Color))
         * {
         *  // return;
         *
         *  color = (color == default(Color))
         *      ? Color.Aqua
         *      : color;
         *
         *  //doc.Objects.AddPoint(point, new ObjectAttributes()
         *  //{
         *  //    DisplayOrder = 12,
         *  //    LayerIndex = 0,
         *  //    Name = "temp",
         *  //    //Mode = ObjectMode.Locked,
         *  //    ColorSource = ObjectColorSource.ColorFromObject,
         *  //    ObjectColor = Color.Red,
         *  //    Visible = true
         *  //    //ObjectDecoration = ObjectDecoration.BothArrowhead,
         *  //});
         *  Guid id = doc.Objects.AddTextDot(text, point, new ObjectAttributes()
         *  {
         *      DisplayOrder = 5,
         *      LayerIndex = 0,
         *      //Name = "DebugPoint " + text,
         *      Name = text,
         *      //Mode = ObjectMode.Locked,
         *      ColorSource = ObjectColorSource.ColorFromObject,
         *      ObjectColor = color,
         *      Visible = true
         *  });
         *
         *
         * }
         *
         */

        #endregion

        //


        /// <summary>
        /// Recalculated iso status.
        /// Works always compare to internal Rhino method 'srf.IsIsoparametric(trim)'
        /// </summary>
        /// <param name="trim"></param>
        /// <param name="ssingulars">provide it for speed optimization. otherwise it will be calculated automatically.</param>
        /// <returns></returns>
        public static IsoStatus _IsoStatus(this BrepTrim trim, SurfaceSingulars ssingulars = null)
        {
            // COMMENTED - just to show what is a internal Rhino method to detect isoStatus
            //return srf.IsIsoparametric(trim); - doesnt work always properly!!!

            // COMMENTED - we want to be very sure and lets recalculate isostaus always
            // Calculate ony if status is invalid
            //var trimIsoStatus = trim.IsoStatus;
            //var isValidIso = trimIsoStatus == IsoStatus.East
            //                 || trimIsoStatus == IsoStatus.North
            //                 || trimIsoStatus == IsoStatus.South
            //                 || trimIsoStatus == IsoStatus.West;
            //if (isValidIso)
            //{
            //    return trimIsoStatus;
            //}


            if (ssingulars == null)
            {
                var srf = trim._Srf();
                ssingulars = new SurfaceSingulars(srf);
            }

            var T0          = trim.PointAtStart;
            var T1          = trim.PointAtEnd;
            var T0IsoStatus = ssingulars.GetIsoStatus(T0.X, T0.Y);
            var T1IsoStatus = ssingulars.GetIsoStatus(T1.X, T1.Y);

            if (T0IsoStatus == T1IsoStatus)
            {
                return(T0IsoStatus);
            }

            //  show warnig message only both iso statuses are not 'None' - when we substitute surface with no singulars we will have such situation when all iso statuses became 'None'
            if ((T0IsoStatus != IsoStatus.None || T1IsoStatus != IsoStatus.None))
            {
                if (ssingulars.Srf.IsAtSingularity(T0.X, T0.Y, true) || ssingulars.Srf.IsAtSingularity(T1.X, T1.Y, true))
                {
                    log.wrong("_BrepTrim._IsoStatus()    Cannot detect proper IsoStatus:  T0:{0}-T1:{1}  T0=[{2:0.000},{3:0.000}]   T1=[{4:0.000},{5:0.000}]", T0IsoStatus, T1IsoStatus, T0.X, T0.Y, T1.X, T1.Y);
                }
                else
                {
                    var temp = 0;
                }
            }
            return(IsoStatus.None);
        }
예제 #6
0
        /// <summary>
        /// Find prev and next trim in same loop.
        ///
        /// </summary>
        /// <param name="trim"></param>
        /// <param name="prevTrim"></param>
        /// <param name="nextTrim"></param>
        /// <param name="loopTrims">Provide this parameter is possible. Speed optimization. If it is not provided - will be calculcated, what takes some time.</param>
        public static void _GetPrevNextTrims(this BrepTrim trim, out BrepTrim prevTrim, out BrepTrim nextTrim, BrepTrimList loopTrims = null)
        {
            var trims = loopTrims ?? trim.Loop.Trims_ThreadSafe();

            for (int i = 0; i < trims.Count; i++)
            {
                if (trims[i].TrimIndex == trim.TrimIndex)
                {
                    var iPrev = (i != 0) ? i - 1 : trims.Count - 1;
                    var iNext = (i != trims.Count - 1) ? i + 1 : 0;
                    prevTrim = trims[iPrev];
                    nextTrim = trims[iNext];
                    return;
                }
            }
            throw new Exception("Cannot find trimindex in mehod: _BrepTrim._GetPrevNextTrims(trim, out prevTrim, out nextTrim)");
        }
예제 #7
0
        public static bool _IsSameDirectionToEdge(this BrepTrim trim)
        {
            if (trim.TrimType == BrepTrimType.Singular)
            {
                return(false);
            }
            var srf = trim._Srf();
            var trimPointAtStart = trim.PointAtStart;
            var trimPointAtEnd   = trim.PointAtEnd;
            var trimT0srf        = srf.PointAt(trimPointAtStart.X, trimPointAtStart.Y);
            var trimT1srf        = srf.PointAt(trimPointAtEnd.X, trimPointAtEnd.Y);
            var Crv3d            = trim.Edge;
            var Domain           = Crv3d.Domain;
            var edgeT03d         = Crv3d.PointAt(Domain.T0);
            var edgeT13d         = Crv3d.PointAt(Domain.T1);

            return(trim._IsSameDirectionToEdge(srf, trimT0srf, trimT1srf, edgeT03d, edgeT13d, false));
        }
예제 #8
0
        /// <summary>
        /// Fix control points of trim
        /// </summary>
        /// <param name="trim"></param>
        /// <param name="singulars"></param>
        /// <param name="roundStart">Round value of singular axis (if surface is singular on V  - then round first value of V)</param>
        /// <param name="roundEnd">Round value of singular axis (if surface is singular on V  - then round last value of V)</param>
        /// <returns></returns>
        public static NurbsCurve _FixContorlPoints(this BrepTrim trim, SurfaceSingulars singulars = null, bool roundStart = false, bool roundEnd = false)
        {
            var srf      = trim._Srf();
            var trimNurb = trim._ToNurbsCurve();
            // v1 - full
            var res     = trimNurb._Fix2dContorlPoints(srf, singulars, trim.Edge, roundStart, roundEnd);
            var newtrim = res._ZigZagDeformations_TryRemove(srf);

            //if (newtrim != null)
            //{
            //    res = newtrim;
            //}

            // v2 - only zigzag
            //var res = trimNurb;
            //var newtrim = trimNurb._ZigZagDeformations_TryRemove(srf);
            //if (newtrim != null)
            //{
            //    res = newtrim;
            //}
            //res =  res._Fix2dContorlPoints(srf, singulars, trim.Edge, roundStart, roundEnd);

            return(res);
        }
예제 #9
0
        public static ComponentProblem Add(ref ComponentProblems problems, BrepEdge edge, BrepTrim trim, string problem, ComponentProblemTypes type, object data = null)
        {
            var componentReal = new ComponentIndex(ComponentIndexType.BrepEdge, edge.EdgeIndex);
            var componentGUI  = new ComponentIndex(ComponentIndexType.BrepEdge, trim.TrimIndex);

            return(Add(ref problems, componentReal, componentGUI, problem, type, data));
        }
예제 #10
0
    static void MakeTwistedCubeTrimmingLoop(ref Brep brep, ref BrepFace face, // Indices of corner vertices listed in SW, SE, NW, NE order
                                            int eSi,                          // index of edge on south side of surface
                                            int eS_dir,                       // orientation of edge with respect to surface trim
                                            int eEi,                          // index of edge on south side of surface
                                            int eE_dir,                       // orientation of edge with respect to surface trim
                                            int eNi,                          // index of edge on south side of surface
                                            int eN_dir,                       // orientation of edge with respect to surface trim
                                            int eWi,                          // index of edge on south side of surface
                                            int eW_dir                        // orientation of edge with respect to surface trim
                                            )
    {
        Surface srf  = brep.Surfaces[face.SurfaceIndex];
        var     loop = brep.Loops.Add(BrepLoopType.Outer, face);

        // Create trimming curves running counter clockwise around the surface's domain.
        // Start at the south side
        // side: 0=south, 1=east, 2=north, 3=west
        for (int side = 0; side < 4; side++)
        {
            Curve trimming_curve = TwistedCubeTrimmingCurve(srf, side);
            int   curve_index    = brep.Curves2D.Add(trimming_curve);

            int       ei      = 0;
            bool      reverse = false;
            IsoStatus iso     = IsoStatus.None;
            switch (side)
            {
            case 0: // south
                ei      = eSi;
                reverse = (eS_dir == -1);
                iso     = IsoStatus.South;
                break;

            case 1: // east
                ei      = eEi;
                reverse = (eE_dir == -1);
                iso     = IsoStatus.East;
                break;

            case 2: // north
                ei      = eNi;
                reverse = (eN_dir == -1);
                iso     = IsoStatus.North;
                break;

            case 3: // west
                ei      = eWi;
                reverse = (eW_dir == -1);
                iso     = IsoStatus.West;
                break;
            }

            BrepEdge edge = brep.Edges[ei];
            BrepTrim trim = brep.Trims.Add(edge, reverse, loop, curve_index);
            trim.IsoStatus = iso;
            trim.TrimType  = BrepTrimType.Mated; // This b-rep is closed, so all trims have mates.
            trim.SetTolerances(0, 0);            // This simple example is exact - for models with
            // non-exact data, set tolerance as explained in
            // definition of BrepTrim.
        }
    }
예제 #11
0
        public static string _GUIEdgeNum(this BrepTrim trim)
        {
            var num = Shared.GUIComponentNum(trim.TrimIndex); // in GUI we show starting from 1 or from 0

            return(num._ToStringFastSharp());
        }
예제 #12
0
 public static string _GUIEdgeName(this BrepTrim trim)
 {
     return("Edge " + trim._GUIEdgeNum());
 }
예제 #13
0
 public static bool _NeedFixClosedCurve(this BrepTrim trim)
 {
     return(((Curve)trim)._NeedFixClosedCurve() ||
            (trim.Edge != null && trim.Edge._NeedFixClosedCurve()));
 }
예제 #14
0
 public static NurbsCurve _Simplify(this BrepTrim trim)
 {
     return(trim._Simplify(trim._Srf()));
 }
예제 #15
0
 public static Surface _Srf(this BrepTrim trim)
 {
     return(trim.Brep.Surfaces[trim.Face.SurfaceIndex]);
 }
예제 #16
0
        public Brep BrepToSpeckle(Solid solid)
        {
#if REVIT2021
            // TODO: Incomplete implementation!!

            var brep = new Brep();
            brep.units = ModelUnits;

            if (solid is null || solid.Faces.IsEmpty)
            {
                return(null);
            }

            var faceIndex    = 0;
            var edgeIndex    = 0;
            var curve2dIndex = 0;
            var curve3dIndex = 0;
            var loopIndex    = 0;
            var trimIndex    = 0;
            var surfaceIndex = 0;

            var speckleFaces       = new Dictionary <Face, BrepFace>();
            var speckleEdges       = new Dictionary <Edge, BrepEdge>();
            var speckleEdgeIndexes = new Dictionary <Edge, int>();
            var speckle3dCurves    = new ICurve[solid.Edges.Size];
            var speckle2dCurves    = new List <ICurve>();
            var speckleLoops       = new List <BrepLoop>();
            var speckleTrims       = new List <BrepTrim>();

            foreach (var face in solid.Faces.Cast <Face>())
            {
                var surface     = FaceToSpeckle(face, out bool orientation, 0.0);
                var iterator    = face.EdgeLoops.ForwardIterator();
                var loopIndices = new List <int>();

                while (iterator.MoveNext())
                {
                    var loop            = iterator.Current as EdgeArray;
                    var loopTrimIndices = new List <int>();
                    // Loop through the edges in the loop.
                    var loopIterator = loop.ForwardIterator();
                    while (loopIterator.MoveNext())
                    {
                        // Each edge should create a 2d curve, a 3d curve, a BrepTrim and a BrepEdge.
                        var edge  = loopIterator.Current as Edge;
                        var faceA = edge.GetFace(0);

                        // Determine what face side are we currently on.
                        var edgeSide = face == faceA ? 0 : 1;

                        // Get curve, create trim and save index
                        var trim       = edge.GetCurveUV(edgeSide);
                        var sTrim      = new BrepTrim(brep, edgeIndex, faceIndex, loopIndex, curve2dIndex, 0, BrepTrimType.Boundary, edge.IsFlippedOnFace(edgeSide), -1, -1);
                        var sTrimIndex = trimIndex;
                        loopTrimIndices.Add(sTrimIndex);

                        // Add curve and trim, increase index counters.
                        speckle2dCurves.Add(CurveToSpeckle(trim.As3DCurveInXYPlane()));
                        speckleTrims.Add(sTrim);
                        curve2dIndex++;
                        trimIndex++;

                        // Check if we have visited this edge before.
                        if (!speckleEdges.ContainsKey(edge))
                        {
                            // First time we visit this edge, add 3d curve and create new BrepEdge.
                            var edgeCurve = edge.AsCurve();
                            speckle3dCurves[curve3dIndex] = CurveToSpeckle(edgeCurve);
                            var sCurveIndex = curve3dIndex;
                            curve3dIndex++;

                            // Create a trim with just one of the trimIndices set, the second one will be set on the opposite condition.
                            var sEdge = new BrepEdge(brep, sCurveIndex, new[] { sTrimIndex }, -1, -1, edge.IsFlippedOnFace(face), null);
                            speckleEdges.Add(edge, sEdge);
                            speckleEdgeIndexes.Add(edge, edgeIndex);
                            edgeIndex++;
                        }
                        else
                        {
                            // Already visited this edge, skip curve 3d
                            var sEdge      = speckleEdges[edge];
                            var sEdgeIndex = speckleEdgeIndexes[edge];
                            sTrim.EdgeIndex = sEdgeIndex;

                            // Update trim indices with new item.
                            // TODO: Make this better.
                            var trimIndices = sEdge.TrimIndices.ToList();
                            trimIndices.Append(sTrimIndex);
                            sEdge.TrimIndices = trimIndices.ToArray();
                        }
                    }

                    var speckleLoop = new BrepLoop(brep, faceIndex, loopTrimIndices, BrepLoopType.Outer);
                    speckleLoops.Add(speckleLoop);
                    var sLoopIndex = loopIndex;
                    loopIndex++;
                    loopIndices.Add(sLoopIndex);
                }

                speckleFaces.Add(face,
                                 new BrepFace(brep, surfaceIndex, loopIndices, loopIndices[0], !face.OrientationMatchesSurfaceOrientation));
                faceIndex++;
                brep.Surfaces.Add(surface);
                surfaceIndex++;
            }

            var mesh = new Mesh();
            (mesh.faces, mesh.vertices) = GetFaceVertexArrFromSolids(new List <Solid> {
                solid
            });
            mesh.units = ModelUnits;
            // TODO: Revit has no brep vertices. Must call 'brep.SetVertices()' in rhino when provenance is revit.
            // TODO: Set tolerances and flags in rhino when provenance is revit.
            brep.Faces        = speckleFaces.Values.ToList();
            brep.Curve2D      = speckle2dCurves;
            brep.Curve3D      = speckle3dCurves.ToList();
            brep.Trims        = speckleTrims;
            brep.Edges        = speckleEdges.Values.ToList();
            brep.Loops        = speckleLoops;
            brep.displayValue = mesh;
            return(brep);
#else
            throw new Exception("Converting BREPs to Speckle is currently only supported in Revit 2021.");
#endif
        }