/// <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);
        }
        /// <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)
        {
            //brep.Repair(0.0); //should maybe use ModelAbsoluteTolerance ?
            var joinedMesh = new RH.Mesh();
            var mySettings = new MeshingParameters(0);

            //brep.Compact();
            brep.Trims.MatchEnds();

            RH.Mesh.CreateFromBrep(brep, mySettings).All(meshPart =>
            {
                joinedMesh.Append(meshPart);
                return(true);
            });

            var spcklBrep = new Brep(displayValue: MeshToSpeckle(joinedMesh),
                                     provenance: Speckle.Core.Kits.Applications.Rhino, units: ModelUnits);

            // Vertices, uv curves, 3d curves and surfaces
            spcklBrep.Vertices = brep.Vertices
                                 .Select(vertex => PointToSpeckle(vertex)).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.IsClosed)
                    {
                        nurbsCurve = nurbsCurve.Rebuild(nurbsCurve.Points.Count, nurbsCurve.Degree, true);
                    }
                    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 nurbsCurve = c.ToNurbsCurve();
                //nurbsCurve.Knots.RemoveMultipleKnots(1, nurbsCurve.Degree, Doc.ModelAbsoluteTolerance );
                var rebuild = nurbsCurve.Rebuild(nurbsCurve.Points.Count, nurbsCurve.Degree, true);

                var crv = CurveToSpeckle(rebuild);
                return(crv);
            }).ToList();
            spcklBrep.Surfaces = brep.Surfaces
                                 .Select(srf => SurfaceToSpeckle(srf.ToNurbsSurface())).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,
                                          edge.EndVertex.VertexIndex,
                                          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();

            return(spcklBrep);
        }