public Mesh GetRhinoMesh()
 {
     return(ptMesh.ToRhinoMesh());
 }
Ejemplo n.º 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)
        {
            //Global variables
            PlanktonMesh pMesh = new PlanktonMesh();

            DA.GetData <PlanktonMesh>(0, ref pMesh);

            Matrix mV = null;

            DA.GetData(1, ref mV);
            int vCount = mV.ColumnCount;

            List <Vector3d> displDirections = new List <Vector3d>();

            DA.GetDataList(2, displDirections);

            List <double> weights = new List <double>();

            DA.GetDataList(3, weights);

            if (weights.Count != vCount)
            {
                weights = new List <double>();
                for (int i = 0; i < vCount; i++)
                {
                    weights.Add(1.0);
                }
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, String.Format("The number of weights must equal {0}. Uniform weights are set as default", vCount));
            }

            double scale = 1.0;

            DA.GetData(4, ref scale);

            //----------------------------------------------------------------------------------------

            //Calculate nodal values from linear combination of eigenvectors
            double[] nodalValues = nodalLinearCombination(weights, mV);

            //Map nodal values to displacement vectors
            Vector3d[] displacements = mapToDisplacements(nodalValues, displDirections, scale);

            //Map nodal values to mesh vertex colours
            Color[] vertexColours = mapToColour(nodalValues);

            //New mesh from displacements
            PlanktonMesh pMeshNew = new PlanktonMesh(pMesh);

            for (int i = 0; i < pMeshNew.Vertices.Count; i++)
            {
                pMeshNew.Vertices[i].X += (float)displacements[i].X;
                pMeshNew.Vertices[i].Y += (float)displacements[i].Y;
                pMeshNew.Vertices[i].Z += (float)displacements[i].Z;
            }


            //Convert to Rhino Mesh and add vertex colouring if the same number of vertices exist
            Mesh rhinoMesh = pMeshNew.ToRhinoMesh();

            if (rhinoMesh.Vertices.Count == pMesh.Vertices.Count)
            {
                rhinoMesh.VertexColors.CreateMonotoneMesh(Color.White);

                for (int j = 0; j < rhinoMesh.VertexColors.Count; j++)
                {
                    rhinoMesh.VertexColors[j] = vertexColours[j];
                }
            }
            else
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Mesh colouring failed due to a different number of vertices in the Rhino Mesh and PlanktonMesh. This happens if n-gons with n>4 exist");
            }

            //----------------------------------------------------------------------------------------

            //Output
            DA.SetData(0, rhinoMesh);
        }
Ejemplo n.º 3
0
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            PlanktonMesh P1 = null;

            if (!DA.GetData(0, ref P1))
            {
                return;
            }
            List <double> RL = new List <double>();

            if (!DA.GetDataList(1, RL))
            {
                return;
            }
            bool D = false;

            if (!DA.GetData(2, ref D))
            {
                return;
            }

            if (D)
            {
                P1 = P1.Dual();
            }
            PlanktonMesh    P2      = new PlanktonMesh();
            int             vcount  = P1.Vertices.Count;
            List <Vector3d> Normals = new List <Vector3d>();
            List <int>      Outer   = new List <int>();
            List <int>      Inner   = new List <int>();
            List <int>      Elbow   = new List <int>();

            for (int i = 0; i < vcount; i++)
            {
                Point3d  Vertex   = P1.Vertices[i].ToPoint3d();
                Vector3d Normal   = new Vector3d();
                double   AvgAngle = 0;

                double R = 0;
                if (RL.Count == 1)
                {
                    R = RL[0];
                }
                else
                {
                    R = RL[i];
                }

                int[]      OutEdges   = P1.Vertices.GetHalfedges(i);
                int[]      Neighbours = P1.Vertices.GetVertexNeighbours(i);
                Vector3d[] OutVectors = new Vector3d[Neighbours.Length];
                int        Valence    = P1.Vertices.GetValence(i);

                for (int j = 0; j < Valence; j++)
                {
                    Vector3d OutVector = P1.Vertices[Neighbours[j]].ToPoint3d() - Vertex;
                    OutVector.Unitize();
                    OutVectors[j] = OutVector;
                }

                for (int j = 0; j < Valence; j++)
                {
                    if (P1.Halfedges[OutEdges[(j + 1) % Valence]].AdjacentFace != -1)
                    {
                        Normal += (Vector3d.CrossProduct(OutVectors[(j + 1) % Valence], OutVectors[j]));
                    }
                }

                Normal.Unitize();
                Normals.Add(Normal);

                for (int j = 0; j < Valence; j++)
                {
                    AvgAngle += Vector3d.VectorAngle(Normal, OutVectors[j]);
                }
                AvgAngle = AvgAngle * (1.0 / Valence);

                double Offset = R / (Math.Sin(AvgAngle));

                Outer.Add(P2.Vertices.Add(Vertex + (Normal * Offset))); //this adds the actual point to the mesh, as well as its index to Outer
                Inner.Add(P2.Vertices.Add(Vertex - (Normal * Offset)));
            }

            for (int i = 0; i < P1.Halfedges.Count; i++)
            {
                //get the 3 points of the angle
                int Prev  = P1.Halfedges[i].PrevHalfedge;
                int Next  = P1.Halfedges[i].NextHalfedge;
                int PrevV = P1.Halfedges[Prev].StartVertex;
                int NextV = P1.Halfedges[Next].StartVertex;
                int ThisV = P1.Halfedges[i].StartVertex;

                double R = 0;
                if (RL.Count == 1)
                {
                    R = RL[0];
                }
                else
                {
                    R = RL[ThisV];
                }

                Point3d PrevPt = P1.Vertices[PrevV].ToPoint3d();
                Point3d NextPt = P1.Vertices[NextV].ToPoint3d();
                Point3d ThisPt = P1.Vertices[ThisV].ToPoint3d();
                //construct the point at the inside of the 'elbow'
                Vector3d Arm1 = PrevPt - ThisPt;
                Vector3d Arm2 = NextPt - ThisPt;
                Arm1.Unitize(); Arm2.Unitize();
                double  alpha = Vector3d.VectorAngle(Arm1, Arm2);
                Point3d ThisElbow;

                Vector3d Bisect = new Vector3d();
                if (P1.Halfedges[i].AdjacentFace == -1)
                {
                    Bisect = Vector3d.CrossProduct(Normals[ThisV], -1.0 * Arm1) + Vector3d.CrossProduct(Normals[ThisV], Arm2);
                }
                else
                {
                    Bisect = Arm1 + Arm2;
                }

                Bisect.Unitize();
                ThisElbow = ThisPt + Bisect * (R / Math.Sin(alpha * 0.5));
                Elbow.Add(P2.Vertices.Add(ThisElbow));
            }

            for (int i = 0; i < P1.Halfedges.Count; i++)
            {
                int Next  = P1.Halfedges[i].NextHalfedge;
                int NextV = P1.Halfedges[Next].StartVertex;
                int ThisV = P1.Halfedges[i].StartVertex;
                P2.Faces.AddFace(Outer[ThisV], Outer[NextV], Elbow[Next], Elbow[i]);
                P2.Faces.AddFace(Elbow[i], Elbow[Next], Inner[NextV], Inner[ThisV]);
            }

            Mesh OutputMesh = P2.ToRhinoMesh();

            DA.SetData(0, OutputMesh);
        }
Ejemplo n.º 4
0
        protected override Result RunCommand(RhinoDoc doc, RunMode mode)
        {
            // TODO: start here modifying the behaviour of your command.
            // ---
            RhinoApp.WriteLine("MeshMachine WIP test", EnglishName);

            Brep SB;

            using (GetObject getBrep = new GetObject())
            {
                getBrep.SetCommandPrompt("Please select the brep to remesh");
                getBrep.Get();
                SB = getBrep.Object(0).Brep();
            }

            //GetNumber TargetLength = new GetNumber();
            //double L = TargetLength.Number();

            Rhino.Input.Custom.GetNumber gn = new Rhino.Input.Custom.GetNumber();
            gn.SetCommandPrompt("Specify a Target Edge Length");
            gn.SetLowerLimit(0.5, false);
            gn.Get();
            if (gn.CommandResult() != Rhino.Commands.Result.Success)
            {
                return(gn.CommandResult());
            }
            double L = gn.Number();

            //Point3d pt0;
            //using (GetPoint getPointAction = new GetPoint())
            //{
            //    getPointAction.SetCommandPrompt("Please select the start point");
            //    if (getPointAction.Get() != GetResult.Point)
            //    {
            //        RhinoApp.WriteLine("No start point was selected.");
            //        return getPointAction.CommandResult();
            //    }
            //    pt0 = getPointAction.Point();
            //}

            //Point3d pt1;
            //using (GetPoint getPointAction = new GetPoint())
            //{
            //    getPointAction.SetCommandPrompt("Please select the end point");
            //    getPointAction.SetBasePoint(pt0, true);
            //    getPointAction.DynamicDraw +=
            //      (sender, e) => e.Display.DrawLine(pt0, e.CurrentPoint, System.Drawing.Color.DarkRed);
            //    if (getPointAction.Get() != GetResult.Point)
            //    {
            //        RhinoApp.WriteLine("No end point was selected.");
            //        return getPointAction.CommandResult();
            //    }
            //    pt1 = getPointAction.Point();
            //}

            //doc.Objects.AddLine(pt0, pt1);

            PlanktonMesh P = new PlanktonMesh();

            List <int> AnchorV        = new List <int>();
            List <int> FeatureV       = new List <int>();
            List <int> FeatureE       = new List <int>();
            double     FixT           = 0.00001;
            double     LengthTol      = 0.15; //a tolerance for when to split/collapse edges
            double     SmoothStrength = 0.8;  //smoothing strength
            double     PullStrength   = 0.8;  //pull to target mesh strength
            double     CurvDep        = 0;
            int        Flip           = 1;

            MeshingParameters MeshParams = new MeshingParameters();

            MeshParams.MaximumEdgeLength = 3 * L;
            MeshParams.MinimumEdgeLength = L;
            MeshParams.JaggedSeams       = false;
            MeshParams.SimplePlanes      = false;

            Mesh[] BrepMeshes = Mesh.CreateFromBrep(SB, MeshParams);
            Mesh   M          = new Mesh();

            foreach (var mesh in BrepMeshes)
            {
                M.Append(mesh);
            }

            M.Faces.ConvertQuadsToTriangles();
            P = M.ToPlanktonMesh();

            var FC = new List <Curve>();

            foreach (BrepEdge E in SB.Edges)
            {
                if (!E.IsSmoothManifoldEdge(0.01))
                {
                    FC.Add(E.ToNurbsCurve());
                }
            }
            var            Corners = SB.Vertices;
            List <Point3d> FV      = new List <Point3d>();

            foreach (Point Pt in Corners)
            {
                FV.Add(Pt.Location);
            }

            //Mark any vertices or edges lying on features
            for (int i = 0; i < P.Vertices.Count; i++)
            {
                Point3d Pt = P.Vertices[i].ToPoint3d();
                AnchorV.Add(-1);
                for (int j = 0; j < FV.Count; j++)
                {
                    if (Pt.DistanceTo(FV[j]) < FixT)
                    {
                        AnchorV[AnchorV.Count - 1] = j;
                    }
                }

                FeatureV.Add(-1);
                for (int j = 0; j < FC.Count; j++)
                {
                    double param = new double();
                    FC[j].ClosestPoint(Pt, out param);
                    if (Pt.DistanceTo(FC[j].PointAt(param)) < FixT)
                    {
                        FeatureV[FeatureV.Count - 1] = j;
                    }
                }
            }

            int EdgeCount = P.Halfedges.Count / 2;

            for (int i = 0; i < EdgeCount; i++)
            {
                FeatureE.Add(-1);
                int vStart = P.Halfedges[2 * i].StartVertex;
                int vEnd   = P.Halfedges[2 * i + 1].StartVertex;

                Point3d PStart = P.Vertices[vStart].ToPoint3d();
                Point3d PEnd   = P.Vertices[vEnd].ToPoint3d();

                for (int j = 0; j < FC.Count; j++)
                {
                    double paramS = new double();
                    double paramE = new double();
                    Curve  thisFC = FC[j];
                    thisFC.ClosestPoint(PStart, out paramS);
                    thisFC.ClosestPoint(PEnd, out paramE);
                    if ((PStart.DistanceTo(thisFC.PointAt(paramS)) < FixT) &&
                        (PEnd.DistanceTo(thisFC.PointAt(paramE)) < FixT))
                    {
                        FeatureE[FeatureE.Count - 1] = j;
                    }
                }
            }



            for (int iter = 0; iter < 30; iter++)
            {
                EdgeCount = P.Halfedges.Count / 2;
                double[]    EdgeLength = P.Halfedges.GetLengths();
                List <bool> Visited    = new List <bool>();
                Vector3d[]  Normals    = new Vector3d[P.Vertices.Count];

                for (int i = 0; i < P.Vertices.Count; i++)
                {
                    Visited.Add(false);
                    Normals[i] = Util.Normal(P, i);
                }

                double t      = LengthTol;      //a tolerance for when to split/collapse edges
                double smooth = SmoothStrength; //smoothing strength
                double pull   = PullStrength;   //pull to target mesh strength

                //    Split the edges that are too long
                for (int i = 0; i < EdgeCount; i++)
                {
                    if (P.Halfedges[2 * i].IsUnused == false)
                    {
                        int vStart = P.Halfedges[2 * i].StartVertex;
                        int vEnd   = P.Halfedges[2 * i + 1].StartVertex;

                        if ((Visited[vStart] == false) &&
                            (Visited[vEnd] == false))
                        {
                            double  L2  = L;
                            Point3d Mid = Util.MidPt(P, i);

                            //if (CurvDep > 0)
                            //{
                            //    double NormDiff = Vector3d.VectorAngle(Normals[vStart], Normals[vEnd]);
                            //    L2 = Math.Min((1.0 / (3.0 * NormDiff) * L), 5 * L);

                            //    if (CurvDep != 1)
                            //    {
                            //        L2 = L2 * (CurvDep) + L * (1.0 - CurvDep);
                            //    }

                            //}
                            //if (BoundScale != 1.0)
                            //{
                            //    double MinDist = 99954;

                            //    for (int j = 0; j < FC.Count; j++)
                            //    {
                            //        double param = new double();

                            //        FC[j].ClosestPoint(Mid, out param);
                            //        double ThisDist = Mid.DistanceTo(FC[j].PointAt(param));
                            //        if (ThisDist < MinDist)
                            //        { MinDist = ThisDist; }
                            //    }

                            //    if (MinDist < BoundDist)
                            //    {
                            //        L2 = L2 * BoundScale + (MinDist / BoundDist) * (L2 * (1 - BoundScale));
                            //    }
                            //}

                            //if (SizP.Count > 0)
                            //{
                            //    L2 = WeightedCombo(Mid, SizP, SizV, WExp, L2, BGW);
                            //    //  L2 = (WL * (1.0 - BGW)) + (BGW * L2);
                            //}

                            if (EdgeLength[2 * i] > (1 + t) * (4f / 3f) * L2)
                            {
                                int SplitHEdge = P.Halfedges.TriangleSplitEdge(2 * i);
                                if (SplitHEdge != -1)
                                {
                                    int SplitCenter = P.Halfedges[SplitHEdge].StartVertex;
                                    P.Vertices.SetVertex(SplitCenter, Util.MidPt(P, i));

                                    //update the feature information
                                    FeatureE.Add(FeatureE[i]);
                                    FeatureV.Add(FeatureE[i]);
                                    AnchorV.Add(-1);

                                    //2 additional new edges have also been created (or 1 if split was on a boundary)
                                    //mark these as non-features
                                    int CEdgeCount = P.Halfedges.Count / 2;
                                    while (FeatureE.Count < CEdgeCount)
                                    {
                                        FeatureE.Add(-1);
                                    }

                                    Visited.Add(true);
                                    int[] Neighbours = P.Vertices.GetVertexNeighbours(SplitCenter);
                                    foreach (int n in Neighbours)
                                    {
                                        Visited[n] = true;
                                    }
                                }
                            }
                        }
                    }
                }

                //Collapse the edges that are too short
                for (int i = 0; i < EdgeCount; i++)
                {
                    if (P.Halfedges[2 * i].IsUnused == false)
                    {
                        int vStart = P.Halfedges[2 * i].StartVertex;
                        int vEnd   = P.Halfedges[2 * i + 1].StartVertex;
                        if ((Visited[vStart] == false) &&
                            (Visited[vEnd] == false))
                        {
                            if (!(AnchorV[vStart] != -1 && AnchorV[vEnd] != -1)) // if both ends are anchored, don't collapse
                            {
                                int Collapse_option = 0;                         //0 for none, 1 for collapse to midpt, 2 for towards start, 3 for towards end
                                //if neither are anchorV
                                if (AnchorV[vStart] == -1 && AnchorV[vEnd] == -1)
                                {
                                    // if both on same feature (or neither on a feature)
                                    if (FeatureV[vStart] == FeatureV[vEnd])
                                    {
                                        Collapse_option = 1;
                                    }
                                    // if start is on a feature and end isn't
                                    if ((FeatureV[vStart] != -1) && (FeatureV[vEnd] == -1))
                                    {
                                        Collapse_option = 2;
                                    }
                                    // if end is on a feature and start isn't
                                    if ((FeatureV[vStart] == -1) && (FeatureV[vEnd] != -1))
                                    {
                                        Collapse_option = 3;
                                    }
                                }
                                else // so one end must be an anchor
                                {
                                    // if start is an anchor
                                    if (AnchorV[vStart] != -1)
                                    {
                                        // if both are on same feature, or if the end is not a feature
                                        if ((FeatureE[i] != -1) || (FeatureV[vEnd] == -1))
                                        {
                                            Collapse_option = 2;
                                        }
                                    }
                                    // if end is an anchor
                                    if (AnchorV[vEnd] != -1)
                                    {
                                        // if both are on same feature, or if the start is not a feature
                                        if ((FeatureE[i] != -1) || (FeatureV[vStart] == -1))
                                        {
                                            Collapse_option = 3;
                                        }
                                    }
                                }

                                double  L2  = L;
                                Point3d Mid = Util.MidPt(P, i);

                                if (CurvDep > 0)
                                {
                                    double NormDiff = Vector3d.VectorAngle(Normals[vStart], Normals[vEnd]);
                                    L2 = Math.Min((1.0 / (3.0 * NormDiff) * L), 5 * L);

                                    if (CurvDep != 1)
                                    {
                                        L2 = L2 * (CurvDep) + L * (1.0 - CurvDep);
                                    }
                                }

                                //if (BoundScale != 1.0)
                                //{
                                //    double MinDist = 99954;

                                //    for (int j = 0; j < FC.Count; j++)
                                //    {
                                //        double param = new double();

                                //        FC[j].ClosestPoint(Mid, out param);
                                //        double ThisDist = Mid.DistanceTo(FC[j].PointAt(param));
                                //        if (ThisDist < MinDist)
                                //        { MinDist = ThisDist; }
                                //    }

                                //    if (MinDist < BoundDist)
                                //    {
                                //        L2 = L2 * BoundScale + (MinDist / BoundDist) * (L2 * (1 - BoundScale));
                                //    }
                                //}

                                //if (SizP.Count > 0)
                                //{
                                //    L2 = WeightedCombo(Mid, SizP, SizV, WExp, L2, BGW);
                                //    //double WL = WeightedCombo(Mid, SizP, SizV, WExp);
                                //    //L2 = (WL * (1.0 - BGW)) + (BGW * L2);
                                //}

                                if ((Collapse_option != 0) && (EdgeLength[2 * i] < (1 - t) * 4f / 5f * L2))
                                {
                                    int Collapsed   = -1;
                                    int CollapseRtn = -1;
                                    if (Collapse_option == 1)
                                    {
                                        Collapsed = P.Halfedges[2 * i].StartVertex;
                                        P.Vertices.SetVertex(Collapsed, Util.MidPt(P, i));
                                        CollapseRtn = P.Halfedges.CollapseEdge(2 * i);
                                    }
                                    if (Collapse_option == 2)
                                    {
                                        Collapsed   = P.Halfedges[2 * i].StartVertex;
                                        CollapseRtn = P.Halfedges.CollapseEdge(2 * i);
                                    }
                                    if (Collapse_option == 3)
                                    {
                                        Collapsed   = P.Halfedges[2 * i + 1].StartVertex;
                                        CollapseRtn = P.Halfedges.CollapseEdge(2 * i + 1);
                                    }
                                    if (CollapseRtn != -1)
                                    {
                                        int[] Neighbours = P.Vertices.GetVertexNeighbours(Collapsed);
                                        foreach (int n in Neighbours)
                                        {
                                            Visited[n] = true;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                EdgeCount = P.Halfedges.Count / 2;

                if ((Flip == 0) && (PullStrength > 0))
                {
                    //Flip edges to reduce valence error
                    for (int i = 0; i < EdgeCount; i++)
                    {
                        if (!P.Halfedges[2 * i].IsUnused &&
                            (P.Halfedges[2 * i].AdjacentFace != -1) &&
                            (P.Halfedges[2 * i + 1].AdjacentFace != -1) &&
                            (FeatureE[i] == -1)   // don't flip feature edges
                            )
                        {
                            int Vert1 = P.Halfedges[2 * i].StartVertex;
                            int Vert2 = P.Halfedges[2 * i + 1].StartVertex;
                            int Vert3 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i].NextHalfedge].NextHalfedge].StartVertex;
                            int Vert4 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i + 1].NextHalfedge].NextHalfedge].StartVertex;

                            int Valence1 = P.Vertices.GetValence(Vert1);
                            int Valence2 = P.Vertices.GetValence(Vert2);
                            int Valence3 = P.Vertices.GetValence(Vert3);
                            int Valence4 = P.Vertices.GetValence(Vert4);

                            if (P.Vertices.NakedEdgeCount(Vert1) > 0)
                            {
                                Valence1 += 2;
                            }
                            if (P.Vertices.NakedEdgeCount(Vert2) > 0)
                            {
                                Valence2 += 2;
                            }
                            if (P.Vertices.NakedEdgeCount(Vert3) > 0)
                            {
                                Valence3 += 2;
                            }
                            if (P.Vertices.NakedEdgeCount(Vert4) > 0)
                            {
                                Valence4 += 2;
                            }

                            int CurrentError =
                                Math.Abs(Valence1 - 6) +
                                Math.Abs(Valence2 - 6) +
                                Math.Abs(Valence3 - 6) +
                                Math.Abs(Valence4 - 6);
                            int FlippedError =
                                Math.Abs(Valence1 - 7) +
                                Math.Abs(Valence2 - 7) +
                                Math.Abs(Valence3 - 5) +
                                Math.Abs(Valence4 - 5);
                            if (CurrentError > FlippedError)
                            {
                                P.Halfedges.FlipEdge(2 * i);
                            }
                        }
                    }
                }
                else
                {
                    //Flip edges based on angle
                    for (int i = 0; i < EdgeCount; i++)
                    {
                        if (!P.Halfedges[2 * i].IsUnused &&
                            (P.Halfedges[2 * i].AdjacentFace != -1) &&
                            (P.Halfedges[2 * i + 1].AdjacentFace != -1) &&
                            (FeatureE[i] == -1)  // don't flip feature edges
                            )
                        {
                            int Vert1 = P.Halfedges[2 * i].StartVertex;
                            int Vert2 = P.Halfedges[2 * i + 1].StartVertex;
                            int Vert3 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i].NextHalfedge].NextHalfedge].StartVertex;
                            int Vert4 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i + 1].NextHalfedge].NextHalfedge].StartVertex;

                            Point3d P1 = P.Vertices[Vert1].ToPoint3d();
                            Point3d P2 = P.Vertices[Vert2].ToPoint3d();
                            Point3d P3 = P.Vertices[Vert3].ToPoint3d();
                            Point3d P4 = P.Vertices[Vert4].ToPoint3d();

                            double A1 = Vector3d.VectorAngle(new Vector3d(P3 - P1), new Vector3d(P4 - P1))
                                        + Vector3d.VectorAngle(new Vector3d(P4 - P2), new Vector3d(P3 - P2));

                            double A2 = Vector3d.VectorAngle(new Vector3d(P1 - P4), new Vector3d(P2 - P4))
                                        + Vector3d.VectorAngle(new Vector3d(P2 - P3), new Vector3d(P1 - P3));

                            if (A2 > A1)
                            {
                                P.Halfedges.FlipEdge(2 * i);
                            }
                        }
                    }
                }

                //if (Minim)
                //{
                //    Vector3d[] SmoothC = LaplacianSmooth(P, 1, smooth);

                //    for (int i = 0; i < P.Vertices.Count; i++)
                //    {
                //        if (AnchorV[i] == -1) // don't smooth feature vertices
                //        {
                //            P.Vertices.MoveVertex(i, 0.5 * SmoothC[i]);
                //        }
                //    }
                //}

                Vector3d[] Smooth = Util.LaplacianSmooth(P, 0, smooth);

                for (int i = 0; i < P.Vertices.Count; i++)
                {
                    if (AnchorV[i] == -1) // don't smooth feature vertices
                    {
                        // make it tangential only
                        Vector3d VNormal    = Util.Normal(P, i);
                        double   ProjLength = Smooth[i] * VNormal;
                        Smooth[i] = Smooth[i] - (VNormal * ProjLength);

                        P.Vertices.MoveVertex(i, Smooth[i]);

                        if (P.Vertices.NakedEdgeCount(i) != 0)//special smoothing for feature edges
                        {
                            int[]   Neighbours = P.Vertices.GetVertexNeighbours(i);
                            int     ncount     = 0;
                            Point3d Avg        = new Point3d();

                            for (int j = 0; j < Neighbours.Length; j++)
                            {
                                if (P.Vertices.NakedEdgeCount(Neighbours[j]) != 0)
                                {
                                    ncount++;
                                    Avg = Avg + P.Vertices[Neighbours[j]].ToPoint3d();
                                }
                            }
                            Avg = Avg * (1.0 / ncount);
                            Vector3d move = Avg - P.Vertices[i].ToPoint3d();
                            move = move * smooth;
                            P.Vertices.MoveVertex(i, move);
                        }

                        if (FeatureV[i] != -1)//special smoothing for feature edges
                        {
                            int[]   Neighbours = P.Vertices.GetVertexNeighbours(i);
                            int     ncount     = 0;
                            Point3d Avg        = new Point3d();

                            for (int j = 0; j < Neighbours.Length; j++)
                            {
                                if ((FeatureV[Neighbours[j]] == FeatureV[i]) || (AnchorV[Neighbours[j]] != -1))
                                {
                                    ncount++;
                                    Avg = Avg + P.Vertices[Neighbours[j]].ToPoint3d();
                                }
                            }
                            Avg = Avg * (1.0 / ncount);
                            Vector3d move = Avg - P.Vertices[i].ToPoint3d();
                            move = move * smooth;
                            P.Vertices.MoveVertex(i, move);
                        }

                        //projecting points onto the target along their normals

                        if (pull > 0)
                        {
                            Point3d  Point  = P.Vertices[i].ToPoint3d();
                            Vector3d normal = Util.Normal(P, i);
                            Ray3d    Ray1   = new Ray3d(Point, normal);
                            Ray3d    Ray2   = new Ray3d(Point, -normal);
                            double   RayPt1 = Rhino.Geometry.Intersect.Intersection.MeshRay(M, Ray1);
                            double   RayPt2 = Rhino.Geometry.Intersect.Intersection.MeshRay(M, Ray2);
                            Point3d  ProjectedPt;

                            if ((RayPt1 < RayPt2) && (RayPt1 > 0) && (RayPt1 < 1.0))
                            {
                                ProjectedPt = Point * (1 - pull) + pull * Ray1.PointAt(RayPt1);
                            }
                            else if ((RayPt2 < RayPt1) && (RayPt2 > 0) && (RayPt2 < 1.0))
                            {
                                ProjectedPt = Point * (1 - pull) + pull * Ray2.PointAt(RayPt2);
                            }
                            else
                            {
                                ProjectedPt = Point * (1 - pull) + pull * M.ClosestPoint(Point);
                            }

                            P.Vertices.SetVertex(i, ProjectedPt);
                        }


                        if (FeatureV[i] != -1) //pull feature vertices onto feature curves
                        {
                            Point3d Point     = P.Vertices[i].ToPoint3d();
                            Curve   CF        = FC[FeatureV[i]];
                            double  param1    = 0.0;
                            Point3d onFeature = new Point3d();
                            CF.ClosestPoint(Point, out param1);
                            onFeature = CF.PointAt(param1);
                            P.Vertices.SetVertex(i, onFeature);
                        }
                    }
                    else
                    {
                        P.Vertices.SetVertex(i, FV[AnchorV[i]]); //pull anchor vertices onto their points
                    }
                }



                AnchorV  = Util.CompactByVertex(P, AnchorV); //compact the fixed points along with the vertices
                FeatureV = Util.CompactByVertex(P, FeatureV);
                FeatureE = Util.CompactByEdge(P, FeatureE);

                P.Compact(); //this cleans the mesh data structure of unused elements
            }


            Mesh MR = P.ToRhinoMesh();

            MR.Unweld(0.4, true);

            doc.Objects.AddMesh(MR);

            doc.Views.Redraw();
            RhinoApp.WriteLine("The {0} command added one mesh to the document.", EnglishName);

            // ---

            return(Result.Success);
        }
Ejemplo n.º 5
0
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            GH_Structure <IGH_GeometricGoo> iMeshTree    = new GH_Structure <IGH_GeometricGoo>();
            GH_Structure <GH_Integer>       iFaceIndices = new GH_Structure <GH_Integer>();
            GH_Structure <GH_Number>        iThicknesses = new GH_Structure <GH_Number>();
            GH_Structure <GH_Number>        iExtrudes    = new GH_Structure <GH_Number>();

            DA.GetDataTree <IGH_GeometricGoo>(0, out iMeshTree);
            DA.GetDataTree <GH_Integer>(1, out iFaceIndices);
            DA.GetDataTree <GH_Number>(2, out iThicknesses);
            DA.GetDataTree <GH_Number>(3, out iExtrudes);

            GH_Structure <IGH_GeometricGoo> oNewMeshTree = new GH_Structure <IGH_GeometricGoo>();


            for (int i = 0; i < iMeshTree.PathCount; i++)
            {
                GH_Path pathMesh = iMeshTree.get_Path(i);

                for (int j = 0; j < iMeshTree.Branches[i].Count; j++)
                {
                    Mesh mesh;
                    if (!iMeshTree.Branches[i][j].CastTo <Mesh>(out mesh))
                    {
                        continue;
                    }
                    else
                    {
                        PlanktonMesh     pMesh      = mesh.ToPlanktonMesh();
                        PlanktonMesh     pSMesh     = new PlanktonMesh();
                        List <Point3d[]> faceOffset = new List <Point3d[]>();

                        List <int>    facesIDs = new List <int>();
                        List <double> thicks   = new List <double>();
                        List <double> offsets  = new List <double>();

                        #region value initial
                        for (int vi = 0; vi < iFaceIndices.PathCount; vi++)
                        {
                            if (pathMesh != iFaceIndices.get_Path(vi))
                            {
                                continue;
                            }
                            else
                            {
                                foreach (var sv in iFaceIndices[vi].ToList())
                                {
                                    int number;
                                    sv.CastTo <int>(out number);
                                    facesIDs.Add(number);
                                }
                            }
                        }

                        for (int vi = 0; vi < iThicknesses.PathCount; vi++)
                        {
                            if (pathMesh != iThicknesses.get_Path(vi))
                            {
                                continue;
                            }
                            else
                            {
                                foreach (var sv in iThicknesses[vi].ToList())
                                {
                                    double number;
                                    sv.CastTo <double>(out number);
                                    thicks.Add(number);
                                }
                            }
                        }

                        for (int vi = 0; vi < iExtrudes.PathCount; vi++)
                        {
                            if (pathMesh != iExtrudes.get_Path(vi))
                            {
                                continue;
                            }
                            else
                            {
                                foreach (var sv in iExtrudes[vi].ToList())
                                {
                                    double number;
                                    sv.CastTo <double>(out number);
                                    offsets.Add(number);
                                }
                            }
                        }
                        #endregion

                        #region Create windows vertices
                        for (int k = 0; k < pMesh.Faces.Count; k++)
                        {
                            if (!facesIDs.Contains(k))
                            {
                                continue;
                            }

                            int id = facesIDs.IndexOf(k);

                            Point3d   center         = pMesh.Faces.GetFaceCenter(k).ToPoint3d();
                            int[]     fVertices      = pMesh.Faces.GetFaceVertices(k);
                            Point3d[] centerVertices = new Point3d[fVertices.Length];

                            //Vector3d normal = pMesh.Faces.GetFaceNormal(k).ToVector3d();
                            //!!!!!!!!!!!!!!!!! plankton vertices normal have bugs!!!!!!!

                            for (int fv = 0; fv < fVertices.Length; fv++)
                            {
                                Point3d  v   = pMesh.Vertices[fVertices[fv]].ToPoint3d();
                                Vector3d vec = center - v;

                                Point3d v2 = new Point3d();
                                if (fv == fVertices.Length - 1)
                                {
                                    v2 = pMesh.Vertices[fVertices[0]].ToPoint3d();
                                }
                                else
                                {
                                    v2 = pMesh.Vertices[fVertices[fv + 1]].ToPoint3d();
                                }

                                int thickID  = (id >= thicks.Count) ? thicks.Count - 1 : id;
                                int offsetID = (id >= offsets.Count) ? offsets.Count - 1 : id;

                                Vector3d normal = Vector3d.CrossProduct(vec, v - v2);
                                normal.Unitize();

                                centerVertices[fv] = v + vec * thicks[thickID] + normal * offsets[offsetID];
                            }
                            faceOffset.Add(centerVertices);
                        }
                        #endregion

                        // add vertices
                        #region add Vertices
                        foreach (PlanktonVertex v in pMesh.Vertices)
                        {
                            pSMesh.Vertices.Add(v.ToPoint3d());
                        }
                        #endregion

                        #region add frame vertices
                        // add offset vertices
                        foreach (Point3d[] pts in faceOffset)
                        {
                            foreach (Point3d p in pts)
                            {
                                pSMesh.Vertices.Add(p);
                            }
                        }
                        #endregion

                        // add mesh
                        int vc = 0; // vertice counter
                        for (int k = 0; k < pMesh.Faces.Count; k++)
                        {
                            if (!facesIDs.Contains(k))
                            {
                                int[] fVertices = pMesh.Faces.GetFaceVertices(k);

                                if (fVertices.Length == 3)
                                {
                                    pSMesh.Faces.AddFace(fVertices[0], fVertices[1], fVertices[2]);
                                }
                                else
                                {
                                    pSMesh.Faces.AddFace(fVertices[0], fVertices[1], fVertices[2], fVertices[3]);
                                }
                            }
                            else
                            {
                                int[] fVertices = pMesh.Faces.GetFaceVertices(k);

                                if (fVertices.Length == 3)
                                {
                                    pSMesh.Faces.AddFace(fVertices[0], fVertices[1], pMesh.Vertices.Count + vc + 1, pMesh.Vertices.Count + vc + 0);
                                    pSMesh.Faces.AddFace(fVertices[1], fVertices[2], pMesh.Vertices.Count + vc + 2, pMesh.Vertices.Count + vc + 1);
                                    pSMesh.Faces.AddFace(fVertices[2], fVertices[0], pMesh.Vertices.Count + vc + 0, pMesh.Vertices.Count + vc + 2);

                                    if (m_cap)
                                    {
                                        pSMesh.Faces.AddFace(pMesh.Vertices.Count + vc + 0, pMesh.Vertices.Count + vc + 1, pMesh.Vertices.Count + vc + 2);
                                    }

                                    vc += 3;
                                }
                                else
                                {
                                    pSMesh.Faces.AddFace(fVertices[0], fVertices[1], pMesh.Vertices.Count + vc + 1, pMesh.Vertices.Count + vc + 0);
                                    pSMesh.Faces.AddFace(fVertices[1], fVertices[2], pMesh.Vertices.Count + vc + 2, pMesh.Vertices.Count + vc + 1);
                                    pSMesh.Faces.AddFace(fVertices[2], fVertices[3], pMesh.Vertices.Count + vc + 3, pMesh.Vertices.Count + vc + 2);
                                    pSMesh.Faces.AddFace(fVertices[3], fVertices[0], pMesh.Vertices.Count + vc + 0, pMesh.Vertices.Count + vc + 3);

                                    if (m_cap)
                                    {
                                        pSMesh.Faces.AddFace(pMesh.Vertices.Count + vc + 0, pMesh.Vertices.Count + vc + 1, pMesh.Vertices.Count + vc + 2, pMesh.Vertices.Count + vc + 3);
                                    }

                                    vc += 4;
                                }
                            }
                        }


                        oNewMeshTree.Append(
                            GH_Convert.ToGeometricGoo(pSMesh.ToRhinoMesh()),
                            pathMesh);
                    }
                }
            }



            DA.SetDataTree(0, oNewMeshTree);
        }
Ejemplo n.º 6
0
        public static Mesh ReMesh(Mesh mesh, double targetLength)
        {
            double       L = targetLength;
            PlanktonMesh P = new PlanktonMesh();

            List <int> AnchorV        = new List <int>();
            List <int> FeatureV       = new List <int>();
            List <int> FeatureE       = new List <int>();
            double     FixT           = 0.00001;
            double     LengthTol      = 0.1; //a tolerance for when to split/collapse edges
            double     SmoothStrength = 0.8; //smoothing strength
            double     PullStrength   = 0.8; //pull to target mesh strength
            double     CurvDep        = 0;
            int        Flip           = 0;
            int        iterations     = 200;

            Mesh M = mesh.DuplicateMesh();

            M.Faces.ConvertQuadsToTriangles();
            P = M.ToPlanktonMesh();

            var FC         = new List <Curve>();
            var boundaries = M.GetNakedEdges();
            var curves     = boundaries.Select(p => p.ToPolylineCurve());

            FC.AddRange(curves);

            List <Point3d> FV = new List <Point3d>();

            foreach (var boundary in boundaries)
            {
                for (int i = 0; i < boundary.Count; i++)
                {
                    int      j     = i == boundary.Count - 1 ? 0 : i + 1;
                    int      k     = i == 0 ? boundary.Count - 1 : i - 1;
                    Point3d  p     = boundary[i];
                    Point3d  pa    = boundary[j];
                    Point3d  pb    = boundary[k];
                    Vector3d va    = pa - p;
                    Vector3d vb    = pb - p;
                    double   angle = Vector3d.VectorAngle(va, vb);
                    if (angle < Math.PI * 0.6666)
                    {
                        FV.Add(p);
                    }
                }
            }

            //Mark any vertices or edges lying on features
            for (int i = 0; i < P.Vertices.Count; i++)
            {
                Point3d Pt = P.Vertices[i].ToPoint3d();
                AnchorV.Add(-1);
                for (int j = 0; j < FV.Count; j++)
                {
                    if (Pt.DistanceTo(FV[j]) < FixT)
                    {
                        AnchorV[AnchorV.Count - 1] = j;
                    }
                }

                FeatureV.Add(-1);
                for (int j = 0; j < FC.Count; j++)
                {
                    double param = new double();
                    FC[j].ClosestPoint(Pt, out param);
                    if (Pt.DistanceTo(FC[j].PointAt(param)) < FixT)
                    {
                        FeatureV[FeatureV.Count - 1] = j;
                    }
                }
            }

            int EdgeCount = P.Halfedges.Count / 2;

            for (int i = 0; i < EdgeCount; i++)
            {
                FeatureE.Add(-1);
                int vStart = P.Halfedges[2 * i].StartVertex;
                int vEnd   = P.Halfedges[2 * i + 1].StartVertex;

                Point3d PStart = P.Vertices[vStart].ToPoint3d();
                Point3d PEnd   = P.Vertices[vEnd].ToPoint3d();

                for (int j = 0; j < FC.Count; j++)
                {
                    double paramS = new double();
                    double paramE = new double();
                    Curve  thisFC = FC[j];
                    thisFC.ClosestPoint(PStart, out paramS);
                    thisFC.ClosestPoint(PEnd, out paramE);
                    if ((PStart.DistanceTo(thisFC.PointAt(paramS)) < FixT) &&
                        (PEnd.DistanceTo(thisFC.PointAt(paramE)) < FixT))
                    {
                        FeatureE[FeatureE.Count - 1] = j;
                    }
                }
            }

            for (int iter = 0; iter < iterations; iter++)
            {
                EdgeCount = P.Halfedges.Count / 2;
                double[]    EdgeLength = P.Halfedges.GetLengths();
                List <bool> Visited    = new List <bool>();
                Vector3d[]  Normals    = new Vector3d[P.Vertices.Count];

                for (int i = 0; i < P.Vertices.Count; i++)
                {
                    Visited.Add(false);
                    Normals[i] = Util.Normal(P, i);
                }

                double t      = LengthTol;      //a tolerance for when to split/collapse edges
                double smooth = SmoothStrength; //smoothing strength
                double pull   = PullStrength;   //pull to target mesh strength

                //    Split the edges that are too long
                for (int i = 0; i < EdgeCount; i++)
                {
                    if (P.Halfedges[2 * i].IsUnused == false)
                    {
                        int vStart = P.Halfedges[2 * i].StartVertex;
                        int vEnd   = P.Halfedges[2 * i + 1].StartVertex;

                        if ((Visited[vStart] == false) &&
                            (Visited[vEnd] == false))
                        {
                            double  L2  = L;
                            Point3d Mid = Util.MidPt(P, i);

                            //if (CurvDep > 0)
                            //{
                            //    double NormDiff = Vector3d.VectorAngle(Normals[vStart], Normals[vEnd]);
                            //    L2 = Math.Min((1.0 / (3.0 * NormDiff) * L), 5 * L);

                            //    if (CurvDep != 1)
                            //    {
                            //        L2 = L2 * (CurvDep) + L * (1.0 - CurvDep);
                            //    }

                            //}
                            //if (BoundScale != 1.0)
                            //{
                            //    double MinDist = 99954;

                            //    for (int j = 0; j < FC.Count; j++)
                            //    {
                            //        double param = new double();

                            //        FC[j].ClosestPoint(Mid, out param);
                            //        double ThisDist = Mid.DistanceTo(FC[j].PointAt(param));
                            //        if (ThisDist < MinDist)
                            //        { MinDist = ThisDist; }
                            //    }

                            //    if (MinDist < BoundDist)
                            //    {
                            //        L2 = L2 * BoundScale + (MinDist / BoundDist) * (L2 * (1 - BoundScale));
                            //    }
                            //}

                            //if (SizP.Count > 0)
                            //{
                            //    L2 = WeightedCombo(Mid, SizP, SizV, WExp, L2, BGW);
                            //    //  L2 = (WL * (1.0 - BGW)) + (BGW * L2);
                            //}

                            if (EdgeLength[2 * i] > (1 + t) * (4f / 3f) * L2)
                            {
                                int SplitHEdge = P.Halfedges.TriangleSplitEdge(2 * i);
                                if (SplitHEdge != -1)
                                {
                                    int SplitCenter = P.Halfedges[SplitHEdge].StartVertex;
                                    P.Vertices.SetVertex(SplitCenter, Util.MidPt(P, i));

                                    //update the feature information
                                    FeatureE.Add(FeatureE[i]);
                                    FeatureV.Add(FeatureE[i]);
                                    AnchorV.Add(-1);

                                    //2 additional new edges have also been created (or 1 if split was on a boundary)
                                    //mark these as non-features
                                    int CEdgeCount = P.Halfedges.Count / 2;
                                    while (FeatureE.Count < CEdgeCount)
                                    {
                                        FeatureE.Add(-1);
                                    }

                                    Visited.Add(true);
                                    int[] Neighbours = P.Vertices.GetVertexNeighbours(SplitCenter);
                                    foreach (int n in Neighbours)
                                    {
                                        Visited[n] = true;
                                    }
                                }
                            }
                        }
                    }
                }

                //Collapse the edges that are too short
                for (int i = 0; i < EdgeCount; i++)
                {
                    if (P.Halfedges[2 * i].IsUnused == false)
                    {
                        int vStart = P.Halfedges[2 * i].StartVertex;
                        int vEnd   = P.Halfedges[2 * i + 1].StartVertex;
                        if ((Visited[vStart] == false) &&
                            (Visited[vEnd] == false))
                        {
                            if (!(AnchorV[vStart] != -1 && AnchorV[vEnd] != -1)) // if both ends are anchored, don't collapse
                            {
                                int Collapse_option = 0;                         //0 for none, 1 for collapse to midpt, 2 for towards start, 3 for towards end
                                //if neither are anchorV
                                if (AnchorV[vStart] == -1 && AnchorV[vEnd] == -1)
                                {
                                    // if both on same feature (or neither on a feature)
                                    if (FeatureV[vStart] == FeatureV[vEnd])
                                    {
                                        Collapse_option = 1;
                                    }
                                    // if start is on a feature and end isn't
                                    if ((FeatureV[vStart] != -1) && (FeatureV[vEnd] == -1))
                                    {
                                        Collapse_option = 2;
                                    }
                                    // if end is on a feature and start isn't
                                    if ((FeatureV[vStart] == -1) && (FeatureV[vEnd] != -1))
                                    {
                                        Collapse_option = 3;
                                    }
                                }
                                else // so one end must be an anchor
                                {
                                    // if start is an anchor
                                    if (AnchorV[vStart] != -1)
                                    {
                                        // if both are on same feature, or if the end is not a feature
                                        if ((FeatureE[i] != -1) || (FeatureV[vEnd] == -1))
                                        {
                                            Collapse_option = 2;
                                        }
                                    }
                                    // if end is an anchor
                                    if (AnchorV[vEnd] != -1)
                                    {
                                        // if both are on same feature, or if the start is not a feature
                                        if ((FeatureE[i] != -1) || (FeatureV[vStart] == -1))
                                        {
                                            Collapse_option = 3;
                                        }
                                    }
                                }

                                double  L2  = L;
                                Point3d Mid = Util.MidPt(P, i);

                                if (CurvDep > 0)
                                {
                                    double NormDiff = Vector3d.VectorAngle(Normals[vStart], Normals[vEnd]);
                                    L2 = Math.Min((1.0 / (3.0 * NormDiff) * L), 5 * L);

                                    if (CurvDep != 1)
                                    {
                                        L2 = L2 * (CurvDep) + L * (1.0 - CurvDep);
                                    }
                                }

                                //if (BoundScale != 1.0)
                                //{
                                //    double MinDist = 99954;

                                //    for (int j = 0; j < FC.Count; j++)
                                //    {
                                //        double param = new double();

                                //        FC[j].ClosestPoint(Mid, out param);
                                //        double ThisDist = Mid.DistanceTo(FC[j].PointAt(param));
                                //        if (ThisDist < MinDist)
                                //        { MinDist = ThisDist; }
                                //    }

                                //    if (MinDist < BoundDist)
                                //    {
                                //        L2 = L2 * BoundScale + (MinDist / BoundDist) * (L2 * (1 - BoundScale));
                                //    }
                                //}

                                //if (SizP.Count > 0)
                                //{
                                //    L2 = WeightedCombo(Mid, SizP, SizV, WExp, L2, BGW);
                                //    //double WL = WeightedCombo(Mid, SizP, SizV, WExp);
                                //    //L2 = (WL * (1.0 - BGW)) + (BGW * L2);
                                //}

                                if ((Collapse_option != 0) && (EdgeLength[2 * i] < (1 - t) * 4f / 5f * L2))
                                {
                                    int Collapsed   = -1;
                                    int CollapseRtn = -1;
                                    if (Collapse_option == 1)
                                    {
                                        Collapsed = P.Halfedges[2 * i].StartVertex;
                                        P.Vertices.SetVertex(Collapsed, Util.MidPt(P, i));
                                        CollapseRtn = P.Halfedges.CollapseEdge(2 * i);
                                    }
                                    if (Collapse_option == 2)
                                    {
                                        Collapsed   = P.Halfedges[2 * i].StartVertex;
                                        CollapseRtn = P.Halfedges.CollapseEdge(2 * i);
                                    }
                                    if (Collapse_option == 3)
                                    {
                                        Collapsed   = P.Halfedges[2 * i + 1].StartVertex;
                                        CollapseRtn = P.Halfedges.CollapseEdge(2 * i + 1);
                                    }
                                    if (CollapseRtn != -1)
                                    {
                                        int[] Neighbours = P.Vertices.GetVertexNeighbours(Collapsed);
                                        foreach (int n in Neighbours)
                                        {
                                            Visited[n] = true;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                EdgeCount = P.Halfedges.Count / 2;

                if ((Flip == 0) && (PullStrength > 0))
                {
                    //Flip edges to reduce valence error
                    for (int i = 0; i < EdgeCount; i++)
                    {
                        if (!P.Halfedges[2 * i].IsUnused &&
                            (P.Halfedges[2 * i].AdjacentFace != -1) &&
                            (P.Halfedges[2 * i + 1].AdjacentFace != -1) &&
                            (FeatureE[i] == -1)   // don't flip feature edges
                            )
                        {
                            int Vert1 = P.Halfedges[2 * i].StartVertex;
                            int Vert2 = P.Halfedges[2 * i + 1].StartVertex;
                            int Vert3 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i].NextHalfedge].NextHalfedge].StartVertex;
                            int Vert4 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i + 1].NextHalfedge].NextHalfedge].StartVertex;

                            int Valence1 = P.Vertices.GetValence(Vert1);
                            int Valence2 = P.Vertices.GetValence(Vert2);
                            int Valence3 = P.Vertices.GetValence(Vert3);
                            int Valence4 = P.Vertices.GetValence(Vert4);

                            if (P.Vertices.NakedEdgeCount(Vert1) > 0)
                            {
                                Valence1 += 2;
                            }
                            if (P.Vertices.NakedEdgeCount(Vert2) > 0)
                            {
                                Valence2 += 2;
                            }
                            if (P.Vertices.NakedEdgeCount(Vert3) > 0)
                            {
                                Valence3 += 2;
                            }
                            if (P.Vertices.NakedEdgeCount(Vert4) > 0)
                            {
                                Valence4 += 2;
                            }

                            int CurrentError =
                                Math.Abs(Valence1 - 6) +
                                Math.Abs(Valence2 - 6) +
                                Math.Abs(Valence3 - 6) +
                                Math.Abs(Valence4 - 6);
                            int FlippedError =
                                Math.Abs(Valence1 - 7) +
                                Math.Abs(Valence2 - 7) +
                                Math.Abs(Valence3 - 5) +
                                Math.Abs(Valence4 - 5);
                            if (CurrentError > FlippedError)
                            {
                                P.Halfedges.FlipEdge(2 * i);
                            }
                        }
                    }
                }
                else
                {
                    //Flip edges based on angle
                    for (int i = 0; i < EdgeCount; i++)
                    {
                        if (!P.Halfedges[2 * i].IsUnused &&
                            (P.Halfedges[2 * i].AdjacentFace != -1) &&
                            (P.Halfedges[2 * i + 1].AdjacentFace != -1) &&
                            (FeatureE[i] == -1)  // don't flip feature edges
                            )
                        {
                            int Vert1 = P.Halfedges[2 * i].StartVertex;
                            int Vert2 = P.Halfedges[2 * i + 1].StartVertex;
                            int Vert3 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i].NextHalfedge].NextHalfedge].StartVertex;
                            int Vert4 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i + 1].NextHalfedge].NextHalfedge].StartVertex;

                            Point3d P1 = P.Vertices[Vert1].ToPoint3d();
                            Point3d P2 = P.Vertices[Vert2].ToPoint3d();
                            Point3d P3 = P.Vertices[Vert3].ToPoint3d();
                            Point3d P4 = P.Vertices[Vert4].ToPoint3d();

                            double A1 = Vector3d.VectorAngle(new Vector3d(P3 - P1), new Vector3d(P4 - P1))
                                        + Vector3d.VectorAngle(new Vector3d(P4 - P2), new Vector3d(P3 - P2));

                            double A2 = Vector3d.VectorAngle(new Vector3d(P1 - P4), new Vector3d(P2 - P4))
                                        + Vector3d.VectorAngle(new Vector3d(P2 - P3), new Vector3d(P1 - P3));

                            if (A2 > A1)
                            {
                                P.Halfedges.FlipEdge(2 * i);
                            }
                        }
                    }
                }

                //if (Minim)
                //{
                //    Vector3d[] SmoothC = LaplacianSmooth(P, 1, smooth);

                //    for (int i = 0; i < P.Vertices.Count; i++)
                //    {
                //        if (AnchorV[i] == -1) // don't smooth feature vertices
                //        {
                //            P.Vertices.MoveVertex(i, 0.5 * SmoothC[i]);
                //        }
                //    }
                //}

                Vector3d[] Smooth = Util.LaplacianSmooth(P, 0, smooth);

                for (int i = 0; i < P.Vertices.Count; i++)
                {
                    if (AnchorV[i] == -1) // don't smooth feature vertices
                    {
                        // make it tangential only
                        Vector3d VNormal    = Util.Normal(P, i);
                        double   ProjLength = Smooth[i] * VNormal;
                        Smooth[i] = Smooth[i] - (VNormal * ProjLength);

                        P.Vertices.MoveVertex(i, Smooth[i]);

                        if (P.Vertices.NakedEdgeCount(i) != 0)//special smoothing for feature edges
                        {
                            int[]   Neighbours = P.Vertices.GetVertexNeighbours(i);
                            int     ncount     = 0;
                            Point3d Avg        = new Point3d();

                            for (int j = 0; j < Neighbours.Length; j++)
                            {
                                if (P.Vertices.NakedEdgeCount(Neighbours[j]) != 0)
                                {
                                    ncount++;
                                    Avg = Avg + P.Vertices[Neighbours[j]].ToPoint3d();
                                }
                            }
                            Avg = Avg * (1.0 / ncount);
                            Vector3d move = Avg - P.Vertices[i].ToPoint3d();
                            move = move * smooth;
                            P.Vertices.MoveVertex(i, move);
                        }

                        if (FeatureV[i] != -1)//special smoothing for feature edges
                        {
                            int[]   Neighbours = P.Vertices.GetVertexNeighbours(i);
                            int     ncount     = 0;
                            Point3d Avg        = new Point3d();

                            for (int j = 0; j < Neighbours.Length; j++)
                            {
                                if ((FeatureV[Neighbours[j]] == FeatureV[i]) || (AnchorV[Neighbours[j]] != -1))
                                {
                                    ncount++;
                                    Avg = Avg + P.Vertices[Neighbours[j]].ToPoint3d();
                                }
                            }
                            Avg = Avg * (1.0 / ncount);
                            Vector3d move = Avg - P.Vertices[i].ToPoint3d();
                            move = move * smooth;
                            P.Vertices.MoveVertex(i, move);
                        }

                        //projecting points onto the target along their normals

                        if (pull > 0)
                        {
                            Point3d  Point  = P.Vertices[i].ToPoint3d();
                            Vector3d normal = Util.Normal(P, i);
                            Ray3d    Ray1   = new Ray3d(Point, normal);
                            Ray3d    Ray2   = new Ray3d(Point, -normal);
                            double   RayPt1 = Rhino.Geometry.Intersect.Intersection.MeshRay(M, Ray1);
                            double   RayPt2 = Rhino.Geometry.Intersect.Intersection.MeshRay(M, Ray2);
                            Point3d  ProjectedPt;

                            if ((RayPt1 < RayPt2) && (RayPt1 > 0) && (RayPt1 < 1.0))
                            {
                                ProjectedPt = Point * (1 - pull) + pull * Ray1.PointAt(RayPt1);
                            }
                            else if ((RayPt2 < RayPt1) && (RayPt2 > 0) && (RayPt2 < 1.0))
                            {
                                ProjectedPt = Point * (1 - pull) + pull * Ray2.PointAt(RayPt2);
                            }
                            else
                            {
                                ProjectedPt = Point * (1 - pull) + pull * M.ClosestPoint(Point);
                            }

                            P.Vertices.SetVertex(i, ProjectedPt);
                        }


                        if (FeatureV[i] != -1) //pull feature vertices onto feature curves
                        {
                            Point3d Point     = P.Vertices[i].ToPoint3d();
                            Curve   CF        = FC[FeatureV[i]];
                            double  param1    = 0.0;
                            Point3d onFeature = new Point3d();
                            CF.ClosestPoint(Point, out param1);
                            onFeature = CF.PointAt(param1);
                            P.Vertices.SetVertex(i, onFeature);
                        }
                    }
                    else
                    {
                        P.Vertices.SetVertex(i, FV[AnchorV[i]]); //pull anchor vertices onto their points
                    }
                }


                AnchorV  = Util.CompactByVertex(P, AnchorV); //compact the fixed points along with the vertices
                FeatureV = Util.CompactByVertex(P, FeatureV);
                FeatureE = Util.CompactByEdge(P, FeatureE);

                P.Compact(); //this cleans the mesh data structure of unused elements
            }

            Mesh MR = P.ToRhinoMesh();

            MR.Unweld(0.4, true);

            return(MR);
        }