using Plankton;
using Rhino.Geometry;
using System;
using System.Collections.Generic;
using System.Linq;
namespace PlanktonGh
{
public static class RhinoSupport
{
public static string HelloWorld()
{
return "Hello World!";
}
Creates a Plankton halfedge mesh from a Rhino mesh. Uses the topology of the Rhino mesh directly.
A PlanktonMesh which represents the topology and geometry of the source mesh.
public static PlanktonMesh ToPlanktonMesh(this Mesh source)
{
PlanktonMesh pMesh = new PlanktonMesh();
source.Vertices.CombineIdentical(true, true);
source.Vertices.CullUnused();
source.UnifyNormals();
source.Weld(Math.PI);
foreach (Point3f v in source.TopologyVertices)
{
pMesh.Vertices.Add(v.X, v.Y, v.Z);
}
for (int i = 0; i < source.Faces.Count; i++)
{
pMesh.Faces.Add(new PlanktonFace());
}
for (int i = 0; i < source.TopologyEdges.Count; i++)
{
PlanktonHalfedge HalfA = new PlanktonHalfedge();
HalfA.StartVertex = source.TopologyEdges.GetTopologyVertices(i).I;
if (pMesh.Vertices [HalfA.StartVertex].OutgoingHalfedge == -1) {
pMesh.Vertices [HalfA.StartVertex].OutgoingHalfedge = pMesh.Halfedges.Count;
}
PlanktonHalfedge HalfB = new PlanktonHalfedge();
HalfB.StartVertex = source.TopologyEdges.GetTopologyVertices(i).J;
if (pMesh.Vertices [HalfB.StartVertex].OutgoingHalfedge == -1) {
pMesh.Vertices [HalfB.StartVertex].OutgoingHalfedge = pMesh.Halfedges.Count + 1;
}
bool[] Match;
int[] ConnectedFaces = source.TopologyEdges.GetConnectedFaces(i, out Match);
//Note for Steve Baer : This Match bool doesn't seem to work on triangulated meshes - it often returns true
//for both faces, even for a properly oriented manifold mesh, which can't be right
//So - making our own check for matching:
//(I suspect the problem is related to C being the same as D for triangles, so best to
//deal with them separately just to make sure)
//loop through the vertices of the face until finding the one which is the same as the start of the edge
//iff the next vertex around the face is the end of the edge then it matches.
Match[0] = false;
if (Match.Length > 1)
{Match[1] = true;}
int VertA = source.TopologyVertices.TopologyVertexIndex(source.Faces[ConnectedFaces[0]].A);
int VertB = source.TopologyVertices.TopologyVertexIndex(source.Faces[ConnectedFaces[0]].B);
int VertC = source.TopologyVertices.TopologyVertexIndex(source.Faces[ConnectedFaces[0]].C);
int VertD = source.TopologyVertices.TopologyVertexIndex(source.Faces[ConnectedFaces[0]].D);
if ((VertA == source.TopologyEdges.GetTopologyVertices(i).I)
&& (VertB == source.TopologyEdges.GetTopologyVertices(i).J))
{ Match[0] = true;
}
if ((VertB == source.TopologyEdges.GetTopologyVertices(i).I)
&& (VertC == source.TopologyEdges.GetTopologyVertices(i).J))
{
Match[0] = true;
}
if ((VertC == source.TopologyEdges.GetTopologyVertices(i).I)
&& (VertD == source.TopologyEdges.GetTopologyVertices(i).J))
{
Match[0] = true;
}
if ((VertD == source.TopologyEdges.GetTopologyVertices(i).I)
&& (VertA == source.TopologyEdges.GetTopologyVertices(i).J))
{
Match[0] = true;
}
//I don't think these next 2 should ever be needed, but just in case:
if ((VertC == source.TopologyEdges.GetTopologyVertices(i).I)
&& (VertA == source.TopologyEdges.GetTopologyVertices(i).J))
{
Match[0] = true;
}
if ((VertB == source.TopologyEdges.GetTopologyVertices(i).I)
&& (VertD == source.TopologyEdges.GetTopologyVertices(i).J))
{
Match[0] = true;
}
if (Match[0] == true)
{
HalfA.AdjacentFace = ConnectedFaces[0];
if (pMesh.Faces[HalfA.AdjacentFace].FirstHalfedge == -1) {
pMesh.Faces[HalfA.AdjacentFace].FirstHalfedge = pMesh.Halfedges.Count;
}
if (ConnectedFaces.Length > 1)
{
HalfB.AdjacentFace = ConnectedFaces[1];
if (pMesh.Faces[HalfB.AdjacentFace].FirstHalfedge == -1) {
pMesh.Faces[HalfB.AdjacentFace].FirstHalfedge = pMesh.Halfedges.Count + 1;
}
}
else
{
HalfB.AdjacentFace = -1;
pMesh.Vertices[HalfB.StartVertex].OutgoingHalfedge = pMesh.Halfedges.Count + 1;
}
}
else
{
HalfB.AdjacentFace = ConnectedFaces[0];
if (pMesh.Faces[HalfB.AdjacentFace].FirstHalfedge == -1) {
pMesh.Faces[HalfB.AdjacentFace].FirstHalfedge = pMesh.Halfedges.Count + 1;
}
if (ConnectedFaces.Length > 1)
{
HalfA.AdjacentFace = ConnectedFaces[1];
if (pMesh.Faces[HalfA.AdjacentFace].FirstHalfedge == -1) {
pMesh.Faces[HalfA.AdjacentFace].FirstHalfedge = pMesh.Halfedges.Count;
}
}
else
{
HalfA.AdjacentFace = -1;
pMesh.Vertices[HalfA.StartVertex].OutgoingHalfedge = pMesh.Halfedges.Count;
}
}
pMesh.Halfedges.Add(HalfA);
pMesh.Halfedges.Add(HalfB);
}
for (int i = 0; i < (pMesh.Halfedges.Count); i += 2)
{
int[] EndNeighbours = source.TopologyVertices.ConnectedTopologyVertices(pMesh.Halfedges[i + 1].StartVertex, true);
for (int j = 0; j < EndNeighbours.Length; j++)
{
if(EndNeighbours[j] == pMesh.Halfedges[i].StartVertex)
{
int EndOfNextHalfedge = EndNeighbours[(j - 1 + EndNeighbours.Length) % EndNeighbours.Length];
int StartOfPrevOfPairHalfedge = EndNeighbours[(j + 1) % EndNeighbours.Length];
int NextEdge = source.TopologyEdges.GetEdgeIndex(pMesh.Halfedges[i + 1].StartVertex,EndOfNextHalfedge);
int PrevPairEdge = source.TopologyEdges.GetEdgeIndex(pMesh.Halfedges[i + 1].StartVertex,StartOfPrevOfPairHalfedge);
if (source.TopologyEdges.GetTopologyVertices(NextEdge).I == pMesh.Halfedges[i + 1].StartVertex) {
pMesh.Halfedges[i].NextHalfedge = NextEdge * 2;
} else {
pMesh.Halfedges[i].NextHalfedge = NextEdge * 2 + 1;
}
if (source.TopologyEdges.GetTopologyVertices(PrevPairEdge).J == pMesh.Halfedges[i + 1].StartVertex) {
pMesh.Halfedges[i + 1].PrevHalfedge = PrevPairEdge * 2;
} else {
pMesh.Halfedges[i + 1].PrevHalfedge = PrevPairEdge * 2+1;
}
break;
}
}
int[] StartNeighbours = source.TopologyVertices.ConnectedTopologyVertices(pMesh.Halfedges[i].StartVertex, true);
for (int j = 0; j < StartNeighbours.Length; j++)
{
if (StartNeighbours[j] == pMesh.Halfedges[i+1].StartVertex)
{
int EndOfNextOfPairHalfedge = StartNeighbours[(j - 1 + StartNeighbours.Length) % StartNeighbours.Length];
int StartOfPrevHalfedge = StartNeighbours[(j + 1) % StartNeighbours.Length];
int NextPairEdge = source.TopologyEdges.GetEdgeIndex(pMesh.Halfedges[i].StartVertex, EndOfNextOfPairHalfedge);
int PrevEdge = source.TopologyEdges.GetEdgeIndex(pMesh.Halfedges[i].StartVertex, StartOfPrevHalfedge);
if (source.TopologyEdges.GetTopologyVertices(NextPairEdge).I == pMesh.Halfedges[i].StartVertex) {
pMesh.Halfedges[i + 1].NextHalfedge = NextPairEdge * 2;
} else {
pMesh.Halfedges[i + 1].NextHalfedge = NextPairEdge * 2 + 1;
}
if (source.TopologyEdges.GetTopologyVertices(PrevEdge).J == pMesh.Halfedges[i].StartVertex) {
pMesh.Halfedges[i].PrevHalfedge = PrevEdge * 2;
} else {
pMesh.Halfedges[i].PrevHalfedge = PrevEdge * 2 + 1;
}
break;
}
}
}
return pMesh;
}
Creates a Rhino mesh from a Plankton halfedge mesh. Uses the face-vertex information available in the halfedge data structure.
A Mesh which represents the source mesh (as best it can).
Any faces with five sides or more will be triangulated.
public static Mesh ToRhinoMesh(this PlanktonMesh source)
{
// could add different options for triangulating ngons later
Mesh rMesh = new Mesh();
foreach (PlanktonVertex v in source.Vertices)
{
rMesh.Vertices.Add(v.X, v.Y, v.Z);
}
for (int i = 0; i < source.Faces.Count; i++)
{
int[] fvs = source.Faces.GetFaceVertices(i);
if (fvs.Length == 3)
{
rMesh.Faces.AddFace(fvs[0], fvs[1], fvs[2]);
}
else if (fvs.Length == 4)
{
rMesh.Faces.AddFace(fvs[0], fvs[1], fvs[2], fvs[3]);
}
else if (fvs.Length > 4)
{
// triangulate about face center (fan)
var fc = source.Faces.GetFaceCenter(i);
rMesh.Vertices.Add(fc.X, fc.Y, fc.Z);
for (int j = 0; j < fvs.Length; j++)
{
rMesh.Faces.AddFace(fvs[j], fvs[(j + 1) % fvs.Length], rMesh.Vertices.Count - 1);
}
}
}
rMesh.Normals.ComputeNormals();
return rMesh;
}
Replaces the vertices of a PlanktonMesh with a new list of points
A list of closed polylines representing the boundary edges of each face.
public static PlanktonMesh ReplaceVertices(this PlanktonMesh source, List<Point3d> points)
{
PlanktonMesh pMesh = source;
for (int i = 0; i < points.Count; i++)
{
pMesh.Vertices.SetVertex(i, points[i]);
}
return pMesh;
}
Converts each face to a closed polyline.
A list of closed polylines representing the boundary edges of each face.
public static Polyline[] ToPolylines(this PlanktonMesh source)
{
int n = source.Faces.Count;
Polyline[] polylines = new Polyline[n];
for (int i = 0; i < n; i++)
{
Polyline facePoly = new Polyline();
int[] vs = source.Faces.GetFaceVertices(i);
for (int j = 0; j <= vs.Length; j++)
{
var v = source.Vertices[vs[j % vs.Length]];
facePoly.Add(v.X, v.Y, v.Z);
}
polylines[i] = facePoly;
}
return polylines;
}
Creates a Rhino Point3f from a Plankton vertex.
A Point3f with the same coordinates as the vertex.
public static Point3f ToPoint3f(this PlanktonVertex vertex)
{
return new Point3f(vertex.X, vertex.Y, vertex.Z);
}
Creates a Rhino Point3d from a Plankton vertex.
A Point3d with the same coordinates as the vertex.
public static Point3d ToPoint3d(this PlanktonVertex vertex)
{
return new Point3d(vertex.X, vertex.Y, vertex.Z);
}
Creates a Rhino Point3f from a Plankton vector.
A Point3f with the same XYZ components as the vector.
public static Point3f ToPoint3f(this PlanktonXYZ vector)
{
return new Point3f(vector.X, vector.Y, vector.Z);
}
Creates a Rhino Point3d from a Plankton vector.
A Point3d with the same XYZ components as the vector.
public static Point3d ToPoint3d(this PlanktonXYZ vector)
{
return new Point3d(vector.X, vector.Y, vector.Z);
}
Creates a Rhino Vector3f from a Plankton vector.
A Vector3f with the same XYZ components as the vector.
public static Vector3f ToVector3f(this PlanktonXYZ vector)
{
return new Vector3f(vector.X, vector.Y, vector.Z);
}
Sets or adds a vertex to the Vertex List.
If [index] is less than [Count], the existing vertex at [index] will be modified.
If [index] equals [Count], a new vertex is appended to the end of the vertex list.
If [index] is larger than [Count], the function will return false.
on success, on failure.
public static bool SetVertex(this PlanktonVertexList vertexList, int index, Point3f vertex)
{
return vertexList.SetVertex(index, vertex.X, vertex.Y, vertex.Z);
}
Sets or adds a vertex to the Vertex List.
If [index] is less than [Count], the existing vertex at [index] will be modified.
If [index] equals [Count], a new vertex is appended to the end of the vertex list.
If [index] is larger than [Count], the function will return false.
on success, on failure.
public static bool SetVertex(this PlanktonVertexList vertexList, int index, Point3d vertex)
{
return vertexList.SetVertex(index, vertex.X, vertex.Y, vertex.Z);
}
Moves a vertex by a vector.
on success, on failure.
public static bool MoveVertex(this PlanktonVertexList vertexList, int index, Vector3d vector)
{
return vertexList.SetVertex(index, vertexList[index].X + vector.X, vertexList[index].Y + vector.Y, vertexList[index].Z + vector.Z);
}
Adds a new vertex to the end of the Vertex list.
The index of the newly added vertex.
public static int Add(this PlanktonVertexList vertexList, Point3f vertex)
{
return vertexList.Add(vertex.X, vertex.Y, vertex.Z);
}
Adds a new vertex to the end of the Vertex list.
The index of the newly added vertex.
public static int Add(this PlanktonVertexList vertexList, Point3d vertex)
{
return vertexList.Add(vertex.X, vertex.Y, vertex.Z);
}
Gets positions of vertices
A list of Point3d
public static IEnumerable<Point3d> GetPositions(this PlanktonMesh source)
{
return Enumerable.Range(0, source.Vertices.Count).Select(i => source.Vertices[i].ToPoint3d());
}
}
}