public FaceEdge(Face face, MeshEdge meshEdge, Vertex vertex) { this.containingFace = face; this.meshEdge = meshEdge; this.firstVertex = vertex; nextFaceEdge = null; prevFaceEdge = null; radialNextFaceEdge = radialPrevFaceEdge = this; }
static public FaceTextureData Get(Face faceToGetTextureDataFor) { FaceTextureData plugin; facesWithTextureData.TryGetValue(faceToGetTextureDataFor, out plugin); if (plugin == null) { FaceTextureData newPlugin = new FaceTextureData(); facesWithTextureData.Add(faceToGetTextureDataFor, newPlugin); return newPlugin; } return plugin; }
public FaceEdge GetFaceEdge(Face faceToFindFaceEdgeFor) { foreach (FaceEdge faceEdge in faceToFindFaceEdgeFor.FaceEdges()) { if (faceEdge.containingFace == faceToFindFaceEdgeFor) { return faceEdge; } } return null; }
public Face(Face faceToUseAsModel) { }
public Face DeleteFace(Face faceToDelete) { throw new NotImplementedException(); }
private static void CreateFaceEdges(Vertex[] verticesToUse, List<MeshEdge> edgesToUse, Face createdFace) { FaceEdge prevFaceEdge = null; for (int i = 0; i < verticesToUse.Length - 1; i++) { MeshEdge currentMeshEdge = edgesToUse[i]; FaceEdge currentFaceEdge = new FaceEdge(createdFace, currentMeshEdge, verticesToUse[i]); if (i == 0) { createdFace.firstFaceEdge = currentFaceEdge; } else { prevFaceEdge.nextFaceEdge = currentFaceEdge; currentFaceEdge.prevFaceEdge = prevFaceEdge; } currentFaceEdge.AddToRadialLoop(currentMeshEdge); prevFaceEdge = currentFaceEdge; } // make the last FaceEdge { MeshEdge currentMeshEdge = edgesToUse[verticesToUse.Length - 1]; FaceEdge currentFaceEdge = new FaceEdge(createdFace, currentMeshEdge, verticesToUse[verticesToUse.Length - 1]); prevFaceEdge.nextFaceEdge = currentFaceEdge; currentFaceEdge.prevFaceEdge = prevFaceEdge; currentFaceEdge.nextFaceEdge = createdFace.firstFaceEdge; createdFace.firstFaceEdge.prevFaceEdge = currentFaceEdge; currentFaceEdge.AddToRadialLoop(currentMeshEdge); } }
public void ReverseFaceEdges(Face faceToReverse) { FaceEdge temp = null; FaceEdge current = faceToReverse.firstFaceEdge; // swap next and prev for all nodes of // doubly linked list do { temp = current.prevFaceEdge; current.prevFaceEdge = current.nextFaceEdge; current.nextFaceEdge = temp; current = current.prevFaceEdge; // go to the next } while (current != faceToReverse.firstFaceEdge); faceToReverse.CalculateNormal(); }
public Face CreateFace(Vertex[] verticesToUse, CreateOption createOption = CreateOption.ReuseExisting) { if (verticesToUse.Length == 3 && (verticesToUse[0].Position == verticesToUse[1].Position || verticesToUse[1].Position == verticesToUse[2].Position || verticesToUse[2].Position == verticesToUse[0].Position)) { return null; } if (verticesToUse.Length < 3) { throw new ArgumentException("A face cannot have less than 3 vertices."); } List<MeshEdge> edgesToUse = new List<MeshEdge>(); for (int i = 0; i < verticesToUse.Length - 1; i++) { edgesToUse.Add(CreateMeshEdge(verticesToUse[i], verticesToUse[i + 1], createOption)); } edgesToUse.Add(CreateMeshEdge(verticesToUse[verticesToUse.Length - 1], verticesToUse[0], createOption)); // make the face and set it's data Face createdFace = new Face(); CreateFaceEdges(verticesToUse, edgesToUse, createdFace); createdFace.CalculateNormal(); faces.Add(createdFace); return createdFace; }
public void SplitFace(Face faceToSplit, Vertex splitStartVertex, Vertex splitEndVertex, out MeshEdge meshEdgeCreatedDuringSplit, out Face faceCreatedDuringSplit) { if (!ContainsVertex(splitStartVertex) || !ContainsVertex(splitEndVertex)) { throw new Exception("The mesh must contain the vertices you intend to split between."); } // we may want to be able to double up an edge for some operations (we'll have to see). if (FindMeshEdges(splitStartVertex, splitEndVertex).Count > 0) { // this also ensures that the face is more than 2 sided. throw new Exception("You cannot split a face on an existing edge."); } FaceEdge faceEdgeAfterSplitStart = null; FaceEdge faceEdgeAfterSplitEnd = null; int count = 0; foreach (FaceEdge faceEdge in faceToSplit.FaceEdges()) { if (faceEdge.firstVertex == splitStartVertex) { faceEdgeAfterSplitStart = faceEdge; count++; } else if (faceEdge.firstVertex == splitEndVertex) { faceEdgeAfterSplitEnd = faceEdge; count++; } if (count == 2) { break; // stop if we found both face edges } } meshEdgeCreatedDuringSplit = CreateMeshEdge(splitStartVertex, splitEndVertex); faceCreatedDuringSplit = new Face(faceToSplit); faces.Add(faceCreatedDuringSplit); FaceEdge newFaceEdgeExistingFace = new FaceEdge(faceToSplit, meshEdgeCreatedDuringSplit, splitStartVertex); FaceEdge newFaceEdgeForNewFace = new FaceEdge(faceCreatedDuringSplit, meshEdgeCreatedDuringSplit, splitEndVertex); // get the new edges injected into the existing loop, spliting it in two. newFaceEdgeExistingFace.prevFaceEdge = faceEdgeAfterSplitStart.prevFaceEdge; newFaceEdgeForNewFace.prevFaceEdge = faceEdgeAfterSplitEnd.prevFaceEdge; faceEdgeAfterSplitStart.prevFaceEdge.nextFaceEdge = newFaceEdgeExistingFace; faceEdgeAfterSplitEnd.prevFaceEdge.nextFaceEdge = newFaceEdgeForNewFace; newFaceEdgeExistingFace.nextFaceEdge = faceEdgeAfterSplitEnd; newFaceEdgeForNewFace.nextFaceEdge = faceEdgeAfterSplitStart; faceEdgeAfterSplitStart.prevFaceEdge = newFaceEdgeForNewFace; faceEdgeAfterSplitEnd.prevFaceEdge = newFaceEdgeExistingFace; // make sure the first face edge of each face is valid faceToSplit.firstFaceEdge = newFaceEdgeExistingFace; faceCreatedDuringSplit.firstFaceEdge = newFaceEdgeForNewFace; // make sure the FaceEdges of the new face all point to the new face. foreach (FaceEdge faceEdge in faceCreatedDuringSplit.firstFaceEdge.NextFaceEdges()) { faceEdge.containingFace = faceCreatedDuringSplit; } newFaceEdgeExistingFace.AddToRadialLoop(meshEdgeCreatedDuringSplit); newFaceEdgeForNewFace.AddToRadialLoop(meshEdgeCreatedDuringSplit); }
public void UnsplitFace(Face faceToKeep, Face faceToDelete, MeshEdge meshEdgeToDelete) { if (faceToKeep == faceToDelete) { throw new Exception("Can't join face to itself"); } // validate the edgeToDelete is in both faces, edgeToDelete is only in these two faces, the two faces only share this one edge and no other edges FaceEdge faceEdgeToDeleteOnFaceToKeep = meshEdgeToDelete.GetFaceEdge(faceToKeep); FaceEdge faceEdgeToDeleteOnFaceToDelete = meshEdgeToDelete.GetFaceEdge(faceToDelete); if (faceEdgeToDeleteOnFaceToKeep.firstVertex == faceEdgeToDeleteOnFaceToDelete.firstVertex) { throw new Exception("The faces have oposite windings and you cannot merge the edge"); } faceEdgeToDeleteOnFaceToKeep.prevFaceEdge.nextFaceEdge = faceEdgeToDeleteOnFaceToDelete.nextFaceEdge; faceEdgeToDeleteOnFaceToDelete.nextFaceEdge.prevFaceEdge = faceEdgeToDeleteOnFaceToKeep.prevFaceEdge; faceEdgeToDeleteOnFaceToKeep.nextFaceEdge.prevFaceEdge = faceEdgeToDeleteOnFaceToDelete.prevFaceEdge; faceEdgeToDeleteOnFaceToDelete.prevFaceEdge.nextFaceEdge = faceEdgeToDeleteOnFaceToKeep.nextFaceEdge; // if the face we are deleting is the one that the face to keep was looking at as its starting face edge, move it to the next face edge if (faceToKeep.firstFaceEdge == faceEdgeToDeleteOnFaceToKeep) { faceToKeep.firstFaceEdge = faceToKeep.firstFaceEdge.nextFaceEdge; } // make sure the FaceEdges all point to the kept face. foreach (FaceEdge faceEdge in faceToKeep.firstFaceEdge.NextFaceEdges()) { faceEdge.containingFace = faceToKeep; } DeleteMeshEdge(meshEdgeToDelete); // clear the data on the deleted face edge to help with debugging faceEdgeToDeleteOnFaceToKeep.meshEdge.VertexOnEnd[0] = null; faceEdgeToDeleteOnFaceToKeep.meshEdge.VertexOnEnd[1] = null; faceToDelete.firstFaceEdge = null; // take the face out of the face list faces.Remove(faceToDelete); }
public bool DeleteMeshEdgeFromFace(Face faceToDeleteEdgeFrom, MeshEdge meshEdgeToDelete) { throw new NotImplementedException(); }
/// <summary> /// Split the face at the given plane. /// </summary> /// <param name="face">The face to split.</param> /// <param name="faceVertices">The list containing the vertices for the face.</param> /// <param name="plane">The plane to split at.</param> /// <param name="newFaces">The new faces created will be added to this list, not the mesh.</param> /// <param name="newVertices">The new vertices will be added to this list, not the mesh.</param> /// <param name="onPlaneDistance">Treat any distance less than this as not crossing the plane.</param> /// <param name="clipFace">An optional function that can be called to check if the given /// face should be clipped.</param> /// <returns>True if the face crosses the plane else false.</returns> public static bool Split(this Face face, List <Vector3Float> faceVertices, Plane plane, List <Face> newFaces, List <Vector3Float> newVertices, double onPlaneDistance, Func <Mesh.SplitData, bool> clipFace = null) { var v = new Vector3Float[] { faceVertices[face.v0], faceVertices[face.v1], faceVertices[face.v2] }; // get the distance from the crossing plane var dist = v.Select(a => plane.GetDistanceFromPlane(a)).ToArray(); // bool if each point is clipped var clipPoint = dist.Select(a => Math.Abs(a) > onPlaneDistance).ToArray(); // bool if there is a clip on a line segment (between points) var clipSegment = clipPoint.Select((a, i) => { var nextI = (i + 1) % 3; // if both points are clipped and they are on opposite sides of the clip plane return(clipPoint[i] && clipPoint[nextI] && ((dist[i] < 0 && dist[nextI] > 0) || (dist[i] > 0 && dist[nextI] < 0))); }).ToArray(); // the number of segments that need to be clipped var segmentsClipped = clipSegment[0] ? 1 : 0; segmentsClipped += clipSegment[1] ? 1 : 0; segmentsClipped += clipSegment[2] ? 1 : 0; void ClipEdge(int vi0) { var vi1 = (vi0 + 1) % 3; var vi2 = (vi0 + 2) % 3; var totalDistance = Math.Abs(dist[vi0]) + Math.Abs(dist[vi1]); var ratioTodist0 = Math.Abs(dist[vi0]) / totalDistance; var newPoint = v[vi0] + (v[vi1] - v[vi0]) * ratioTodist0; // add the new vertex newVertices.Add(newPoint); } switch (segmentsClipped) { // if 2 sides are clipped we will add 2 new vertices and 3 polygons case 2: if (clipFace?.Invoke(new Mesh.SplitData(face, dist)) != false) { // find the side we are not going to clip int vi0 = clipSegment[0] && clipSegment[1] ? 2 : clipSegment[0] && clipSegment[2] ? 1 : 0; var vi1 = (vi0 + 1) % 3; var vi2 = (vi0 + 2) % 3; // get the current count var vertexStart = newVertices.Count; // add the existing vertices newVertices.Add(v[vi0]); newVertices.Add(v[vi1]); newVertices.Add(v[vi2]); // clip the edges, will add the new points ClipEdge(vi1); ClipEdge(vi2); // add the new faces newFaces.Add(new Face(vertexStart, vertexStart + 1, vertexStart + 3, newVertices)); newFaces.Add(new Face(vertexStart, vertexStart + 3, vertexStart + 4, newVertices)); newFaces.Add(new Face(vertexStart + 3, vertexStart + 2, vertexStart + 4, newVertices)); return(true); } break; // if 1 side is clipped we will add 1 new vertex and 2 polygons case 1: { // find the side we are going to clip int vi0 = clipSegment[0] ? 0 : clipSegment[1] ? 1 : 2; var vi1 = (vi0 + 1) % 3; var vi2 = (vi0 + 2) % 3; // get the current count var vertexStart = newVertices.Count; // add the existing vertices newVertices.Add(v[vi0]); newVertices.Add(v[vi1]); newVertices.Add(v[vi2]); // clip the edge, will add the new point ClipEdge(vi0); // add the new faces newFaces.Add(new Face(vertexStart, vertexStart + 3, vertexStart + 2, newVertices)); newFaces.Add(new Face(vertexStart + 3, vertexStart + 1, vertexStart + 2, newVertices)); } return(true); } return(false); }
public SplitData(Face face, double[] dist) { this.Face = face; this.Dist = dist; }
public void ReverseFace(int faceIndex) { var hold = Faces[faceIndex]; Faces[faceIndex] = new Face(hold.v0, hold.v2, hold.v1, hold.normal); }
public MeshFaceTraceable(Face face) { this.face = face; }