//EDGE VECTOR /* return the edge vector from a halfedge index pointing from halfedge start towards halfedge end */ public Vector3d edgeVector(PlanktonMesh pMesh, int halfedgeIndex) { PlanktonHalfedge pHalfedge = pMesh.Halfedges[halfedgeIndex]; //start vertex PlanktonVertex pVStart = pMesh.Vertices[pHalfedge.StartVertex]; Point3d startVertex = new Point3d(pVStart.X, pVStart.Y, pVStart.Z); //end vertex PlanktonVertex pVEnd = pMesh.Vertices[pMesh.Halfedges[pHalfedge.NextHalfedge].StartVertex]; Point3d endVertex = new Point3d(pVEnd.X, pVEnd.Y, pVEnd.Z); //edge vector Vector3d vecEdge = new Vector3d(endVertex - startVertex); return vecEdge; }
private void ProcessEdgeLengthConstraint() { int halfedgeCount = ptMesh.Halfedges.Count; for (int k = 0; k < halfedgeCount; k += 2) { PlanktonHalfedge halfedge = ptMesh.Halfedges[k]; int i = halfedge.StartVertex; int j = ptMesh.Halfedges[halfedge.NextHalfedge].StartVertex; Vector3d d = ptMesh.Vertices[j].ToPoint3d() - ptMesh.Vertices[i].ToPoint3d(); if (d.Length > CollisionDistance) { Vector3d move = EdgeLengthConstraintWeight * 0.5 * (d); totalWeightedMoves[i] += move; totalWeightedMoves[j] -= move; totalWeights[i] += EdgeLengthConstraintWeight; totalWeights[j] += EdgeLengthConstraintWeight; } } }
/// <summary> /// Creates a Plankton halfedge mesh from a Rhino mesh. /// Uses the topology of the Rhino mesh directly. /// </summary> /// <returns>A <see cref="PlanktonMesh"/> which represents the topology and geometry of the source mesh.</returns> /// <param name="source">A Rhino mesh to convert from.</param> 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; } } 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.Halfedges.Add(HalfA); //pMesh.Halfedges[2 * i].Index = 2 * i; // pMesh.Halfedges.Add(HalfB); //pMesh.Halfedges[2 * i + 1].Index = 2 * i + 1; // } 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); }