// Meshes
        public Mesh MeshToSpeckle(RH.Mesh mesh)
        {
            var verts = PointsToFlatArray(mesh.Vertices.ToPoint3dArray());

            var Faces = mesh.Faces.SelectMany(face =>
            {
                if (face.IsQuad)
                {
                    return new int[] { 1, face.A, face.B, face.C, face.D }
                }
                ;
                return(new int[] { 0, face.A, face.B, face.C });
            }).ToArray();

            var Colors = mesh.VertexColors.Select(cl => cl.ToArgb()).ToArray();

            return(new Mesh(verts, Faces, Colors, null, ModelUnits));
        }
        public RH.Mesh MeshToNative(Mesh mesh)
        {
            RH.Mesh m = new RH.Mesh();
            m.Vertices.AddVertices(PointListToNative(mesh.vertices, mesh.units));

            int i = 0;

            while (i < mesh.faces.Count)
            {
                if (mesh.faces[i] == 0)
                {
                    // triangle
                    m.Faces.AddFace(new MeshFace(mesh.faces[i + 1], mesh.faces[i + 2], mesh.faces[i + 3]));
                    i += 4;
                }
                else
                {
                    // quad
                    m.Faces.AddFace(new MeshFace(mesh.faces[i + 1], mesh.faces[i + 2], mesh.faces[i + 3], mesh.faces[i + 4]));
                    i += 5;
                }
            }

            try
            {
                m.VertexColors.AppendColors(mesh.colors.Select(c => System.Drawing.Color.FromArgb((int)c)).ToArray());
            }
            catch
            {
            }

            if (mesh.textureCoordinates != null)
            {
                for (int j = 0; j < mesh.textureCoordinates.Count; j += 2)
                {
                    m.TextureCoordinates.Add(mesh.textureCoordinates[j], mesh.textureCoordinates[j + 1]);
                }
            }

            return(m);
        }
        // Meshes
        public Mesh MeshToSpeckle(RH.Mesh mesh, string units = null)
        {
            var u     = units ?? ModelUnits;
            var verts = PointsToFlatArray(mesh.Vertices.ToPoint3dArray());

            var Faces = mesh.Faces.SelectMany(face =>
            {
                if (face.IsQuad)
                {
                    return new int[] { 1, face.A, face.B, face.C, face.D }
                }
                ;
                return(new int[] { 0, face.A, face.B, face.C });
            }).ToArray();

            var Colors = mesh.VertexColors.Select(cl => cl.ToArgb()).ToArray();

            var speckleMesh = new Mesh(verts, Faces, Colors, null, u);

            speckleMesh.volume = mesh.Volume();
            speckleMesh.bbox   = BoxToSpeckle(new RH.Box(mesh.GetBoundingBox(true)), u);

            return(speckleMesh);
        }
        /// <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 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);
        }