C# / A better way to Sort Mesh face around a vertex in 3D coordinate?

Hello everyone,

I want to sort a group of meshes in clockwise or counterclockwise order in a three-dimensional space. I’d like to use the “Plane.FitPlaneToPoints ()” of the face center point as the reference plane for sorting them in either clockwise or counterclockwise order. Then, I want to draw a polyline that won’t intersect itself after projecting it onto the FitPlane.

My current method is as follows:

  1. The “DataTree” is set up using a list of points generated from any arbitrary point on the mesh.
  2. The method “Mesh.Faces.GetFaceCenter (faceID)” is used to find the center point.
  3. The method “Plane.FitPlaneToPoints (CenterPoint's collection, out plane)” is used to find the FITPlane.
  4. The “Transform.PlaneToPlane” method is used to move the entire group of points to the origin of the world, and the X and Y coordinates of the points are then determined.
  5. The “Math.Acos” method is used to find the angle, and the Y value is used to determine its sign.
  6. The central points of the meshes are sorted according to the angle obtained in step 4, using the “System.Array.Sort” method.

Although this method produces my desired result, I was wondering if there is a more elegant approach? (My computer doesn’t run fast enough…)

sort mesh face & center point.gh (15.2 KB)

RC provides a suitable Method for that (MTV.SortEdges() - where MTV is the MeshTopologyVertex List). If this is what you are after I could provide an entry level take on that matter. That said MTV indexing (vertices on a per Mesh basis) is NOT the same as MV indexing (vertices on a per MeshFace basis) … but there’s RC Methods to “map” indices both ways.


BTW: Obviously you should take into account naked stuff (for more than obvious reasons). I do hope that you are familiar with basic Mesh Connectivity (V/E/F) matters - you can do 7 out of the 9 Conn Trees (VV, VE, VF … blah, blah) via available RC Methods.


1 Like

That what I need! Can I have your code ?

public void MakePolylineTree(bool connectivity, List<Mesh> mList, double move, int offset){

    for (int i = 0; i < mList.Count;i++){
      Mesh M = mList[i];
      var MTV = M.TopologyVertices;                   // MTV indexing us NOT the same as MV vertices
      bool[] isNaked = M.GetNakedEdgePointStatus();   // this indexing is same with MV indexibg

      for(int vIndex = 0; vIndex < MTV.Count;vIndex++){
        Point3f vertex = MTV[vIndex];
        int[] vIndexFC = MTV.ConnectedFaces(vIndex);
        int mvIndex = MTV.MeshVertexIndices(vIndex)[0]; // map MTV>MV in order to use naked indexing

        MTV.SortEdges(vIndex);
        int[] adjVIndices = MTV.ConnectedTopologyVertices(vIndex); //ordered vertices

        if(connectivity){
          vvTree.AddRange(adjVIndices, new GH_Path(i, vIndex));
          vfTree.AddRange(vIndexFC, new GH_Path(i, vIndex));
        }
        if(adjVIndices.Length <= 2)continue;

        Polyline poly = new Polyline();
        int limit = adjVIndices.Length;
        for(int index = 0; index < limit;index++){
          if(isNaked[mvIndex] && index == limit - 1) break;

          Point3f vAdj1 = MTV[adjVIndices[index]];
          int[] v1IndexFC = MTV.ConnectedFaces(adjVIndices[index]);
          Point3f vAdj2 = MTV[adjVIndices[(index + 1) % limit]];
          int[] v2IndexFC = MTV.ConnectedFaces(adjVIndices[(index + 1) % limit]);

          Point3d center = Point3d.Unset; Vector3d faceNormal = Vector3d.Unset;
          GetFaceNormalAndCenter(i, ref center, ref faceNormal, vIndexFC, v1IndexFC, v2IndexFC, offset);

          Line line = new Line(center, (Point3d) vertex); Point3d polyPt = line.PointAt(move);
          if(offset != 1) polyPt += faceNormal;
          poly.Add(polyPt); centerTree.Add(polyPt, new GH_Path(i, vIndex));
        }
        if(!isNaked[mvIndex])poly.Add(poly.First());
        polyTree.Add(poly, new GH_Path(i, vIndex));
      }
    }
  }

Plus assuming that you have fcTree, fnTree (both public) on hand (i.e. fc: face center, fn: face normal):

public void GetFaceNormalAndCenter(int i, ref Point3d fc, ref Vector3d fn, int[] set1, int[] set2, int[] set3, int offset){
    int faceIndex = set1.Intersect(set2.Intersect(set3)).ToArray()[0];
    fc = fcTree.Branch(i, faceIndex)[0];
    if(offset != 1) fn = fnTree.Branch(i, faceIndex)[0];
  }