/// <summary> /// Initializes a new instance of the <see cref="Point"/> class. /// </summary> /// <param name="vertex">The vertex.</param> /// <param name="x">The x.</param> /// <param name="y">The y.</param> /// <param name="z">The z.</param> public Point(Vertex vertex, double x, double y, double z) { References = new List<Vertex> { vertex }; X = x; Y = y; Z = z; }
/// <summary> /// Initializes a new instance of the <see cref="Edge" /> class. /// </summary> /// <param name="fromVertex">From vertex.</param> /// <param name="toVertex">To vertex.</param> /// <param name="ownedFace">The face.</param> /// <param name="otherFace">The other face.</param> /// <param name="doublyLinkedFaces"></param> /// <param name="doublyLinkedVertices"></param> public Edge(Vertex fromVertex, Vertex toVertex, PolygonalFace ownedFace, PolygonalFace otherFace, Boolean doublyLinkedFaces = false, Boolean doublyLinkedVertices = false) { From = fromVertex; To = toVertex; _ownedFace = ownedFace; _otherFace = otherFace; if (doublyLinkedVertices) { fromVertex.Edges.Add(this); toVertex.Edges.Add(this); } if (doublyLinkedFaces) { if (_ownedFace != null) _ownedFace.Edges.Add(this); if (_otherFace != null) _otherFace.Edges.Add(this); } Vector = new[] { (To.Position[0] - From.Position[0]), (To.Position[1] - From.Position[1]), (To.Position[2] - From.Position[2]) }; Length = Math.Sqrt(Vector[0] * Vector[0] + Vector[1] * Vector[1] + Vector[2] * Vector[2]); DefineInternalEdgeAngle(); }
internal static Vertex PointOnPlaneFromIntersectingLine(double[] normalOfPlane, double distOfPlane, Vertex point1, Vertex point2) { var d1 = normalOfPlane.dotProduct(point1.Position); var d2 = normalOfPlane.dotProduct(point2.Position); var fraction = (d1 - distOfPlane) / (d1 - d2); var position = new double[3]; for (var i = 0; i < 3; i++) position[i] = point2.Position[i] * fraction + point1.Position[i] * (1 - fraction); return new Vertex(position); }
private static int FindPrevContactElement(List<ContactElement> contacts, ContactElement current, out Vertex connectingVertex) { // this is the same as "FindNextContactElement" except it works backwards. Some subtle differences // in the queries between the two functions if (current is ThroughVertexContactElement) { for (int i = 0; i < contacts.Count; i++) { var ce = contacts[i]; if (ce is ThroughFaceContactElement && ce.SplitFacePositive == current.SplitFaceNegative) { connectingVertex = ce.StartVertex; return i; } } connectingVertex = null; return -1; } else if (current is CoincidentEdgeContactElement) { for (int i = 0; i < contacts.Count; i++) { var ce = contacts[i]; if (ce is CoincidentEdgeContactElement && ((CoincidentEdgeContactElement)ce).EndVertex == ((CoincidentEdgeContactElement)current).StartVertex) { connectingVertex = ((CoincidentEdgeContactElement)ce).EndVertex; return i; } else if (ce is ThroughFaceContactElement && ((ThroughFaceContactElement)ce).SplitFacePositive.OtherVertex( ((ThroughFaceContactElement)ce).SplitEdge) == ((CoincidentEdgeContactElement)current).EndVertex) { connectingVertex = ce.StartVertex; return i; } } connectingVertex = null; return -1; } for (int i = 0; i < contacts.Count; i++) { var ce = contacts[i]; if ((ce is CoincidentEdgeContactElement && current.SplitFacePositive.OtherVertex(((ThroughFaceContactElement)current).SplitEdge) == ((CoincidentEdgeContactElement)ce).EndVertex) || (!(ce is CoincidentEdgeContactElement) && ce.SplitFacePositive == current.SplitFaceNegative)) { connectingVertex = ce.StartVertex; return i; } } connectingVertex = null; return -1; }
private static List<TessellatedSolid> convertFaceListsToSolids(TessellatedSolid ts, List<List<PolygonalFace>> facesLists, List<Loop> loops, Boolean onPositiveSide, Flat plane) { List<TessellatedSolid> solids = new List<TessellatedSolid>(); foreach (var facesList in facesLists) { // get a list of the vertex indices from the original solid var vertIndices = facesList.SelectMany(f => f.Vertices.Select(v => v.IndexInList)) .Distinct().OrderBy(index => index).ToArray(); var numVertices = vertIndices.Count(); // get the set of connected loops for this list of faces. it could be one or it could be all var connectedLoops = loops.Where(loop => (onPositiveSide && loop.Any(ce => facesList.Contains(ce.SplitFacePositive))) || (!onPositiveSide && loop.Any(ce => facesList.Contains(ce.SplitFaceNegative)))) .ToList(); // put the vertices from vertIndices in subSolidVertices, except those that are on the loop. // you'll need to copy those. var subSolidVertices = new Vertex[numVertices]; var indicesToCopy = connectedLoops.SelectMany(loop => loop.Select(ce => ce.StartVertex.IndexInList)) .OrderBy(index => index).ToArray(); var numIndicesToCopy = indicesToCopy.GetLength(0); var newEdgeVertices = new Vertex[connectedLoops.Count][]; for (int i = 0; i < connectedLoops.Count; i++) newEdgeVertices[i] = new Vertex[connectedLoops[i].Count]; var copyIndex = 0; for (int i = 0; i < numVertices; i++) { Vertex vertexCopy; if (copyIndex < numIndicesToCopy && vertIndices[i] == indicesToCopy[copyIndex]) { var oldVertex = ts.Vertices[vertIndices[i]]; vertexCopy = oldVertex.Copy(); for (int j = 0; j < connectedLoops.Count; j++) { var k = connectedLoops[j].FindIndex(ce => ce.StartVertex == oldVertex); newEdgeVertices[j][k] = vertexCopy; } foreach (var face in oldVertex.Faces.Where(face => facesList.Contains(face))) { face.Vertices.Remove(oldVertex); face.Vertices.Add(vertexCopy); vertexCopy.Faces.Add(face); } while (copyIndex < numIndicesToCopy && vertIndices[i] >= indicesToCopy[copyIndex]) copyIndex++; } else vertexCopy = ts.Vertices[vertIndices[i]]; vertexCopy.IndexInList = i; subSolidVertices[i] = vertexCopy; } solids.Add(new TessellatedSolid(facesList, subSolidVertices, newEdgeVertices, onPositiveSide ? plane.Normal.multiply(-1) : plane.Normal, connectedLoops.Select(loop => loop.IsPositive).ToArray())); } return solids; }
private static int FindNextContactElement(List<ContactElement> contacts, ContactElement current, out Vertex connectingVertex) { // there are six cases to handle: A=ThroughFace (abbreviated as face below), ThroughVertex (vertex), CoincidentEdge (edge) // current contact element --> next contact element // 1. vertex --> face // 2. edge --> edge // 3. edge --> face // 4. face --> face // 5. face --> vertex // 6. face --> edge if (current is ThroughVertexContactElement) { // from a ThroughVertex, it only make sense that you could go to ThroughFace for (int i = 0; i < contacts.Count; i++) { var ce = contacts[i]; if (ce is ThroughFaceContactElement && ce.SplitFaceNegative == current.SplitFacePositive) { connectingVertex = ce.StartVertex; return i; } } connectingVertex = null; return -1; } else if (current is CoincidentEdgeContactElement) { // from a Coincident Edge, the valid options are another CoincidentEdge or ThroughFace. // It doesn't make sense that you could go to a ThroughVertex (redundant with this) for (int i = 0; i < contacts.Count; i++) { var ce = contacts[i]; if ((ce is CoincidentEdgeContactElement && ((CoincidentEdgeContactElement)ce).StartVertex == ((CoincidentEdgeContactElement)current).EndVertex) || (ce is ThroughFaceContactElement && ((ThroughFaceContactElement)ce).SplitFaceNegative.OtherVertex( ((ThroughFaceContactElement)ce).SplitEdge) == ((CoincidentEdgeContactElement)current).EndVertex)) { connectingVertex = ce.StartVertex; return i; } } connectingVertex = null; return -1; } // finally from ThroughFace, you can go to any of the other three. for (int i = 0; i < contacts.Count; i++) { var ce = contacts[i]; if ((ce is CoincidentEdgeContactElement && current.SplitFacePositive.OtherVertex(((ThroughFaceContactElement)current).SplitEdge) == ((CoincidentEdgeContactElement)ce).StartVertex) || (!(ce is CoincidentEdgeContactElement) && ce.SplitFaceNegative == current.SplitFacePositive)) { connectingVertex = ce.StartVertex; return i; } } connectingVertex = null; return -1; }
/// <summary> /// Initializes a new instance of the <see cref="Point"/> class. /// </summary> /// <param name="vertex">The vertex.</param> /// <param name="x">The x.</param> /// <param name="y">The y.</param> public Point(Vertex vertex, double x, double y) : this(vertex, x, y, 0.0) { }
internal TessellatedSolid(List<PolygonalFace> facesList, Vertex[] subSolidVertices, Vertex[][] newEdgeVertices, double[] normal, Boolean[] loopIsPositive) { Faces = facesList.ToArray(); Vertices = subSolidVertices; var numloops = newEdgeVertices.GetLength(0); var points2D = new Point[numloops][]; for (int i = 0; i < numloops; i++) points2D[i] = MinimumEnclosure.Get2DProjectionPoints(newEdgeVertices[i], normal); List<PolygonalFace> patchFaces = TriangulatePolygon.Run(points2D.ToList<Point[]>(), loopIsPositive); //todo: //1. make faces from list of points //2. connect to existing. MakeEdges(); CreateConvexHull(); DefineBoundingBoxAndCenter(); for (int i = 0; i < Faces.Length; i++) { var face = Faces[i]; var centerX = face.Vertices.Average(v => v.X); var centerY = face.Vertices.Average(v => v.Y); var centerZ = face.Vertices.Average(v => v.Z); face.Center = new[] { centerX, centerY, centerZ }; } ConnectConvexHullToObjects(); DefineVolumeAndAreas(); DefineFaceCurvature(); DefineVertexCurvature(); }
internal void AddVertex(Vertex newVertex) { var newVertices = new Vertex[NumberOfVertices + 1]; for (int i = 0; i < NumberOfVertices; i++) newVertices[i] = Vertices[i]; newVertices[NumberOfVertices] = newVertex; newVertex.IndexInList = NumberOfVertices; Vertices = newVertices; NumberOfVertices++; }
/// <summary> /// Initializes a new instance of the <see cref="Point"/> class. /// </summary> /// <param name="v">The v.</param> public Point(Vertex v) : this(v, v.Position[0], v.Position[1], v.Position[2]) { }
private void RemoveVertices(List<int> removeIndices) { var offset = 0; var numToRemove = removeIndices.Count; removeIndices.Sort(); NumberOfVertices -= numToRemove; var newVertices = new Vertex[NumberOfVertices]; for (int i = 0; i < NumberOfVertices; i++) { while (offset < numToRemove && (i + offset) == removeIndices[offset]) offset++; var v = Vertices[i + offset]; v.IndexInList = i; newVertices[i] = v; } Vertices = newVertices; }
internal ThroughVertexContactElement(Vertex onPlaneVertex, PolygonalFace negativeFace, PolygonalFace positiveFace) { StartVertex = onPlaneVertex; SplitFacePositive = positiveFace; SplitFaceNegative = negativeFace; }
private Edge[] MakeEdges(PolygonalFace[] localFaces, Vertex[] localVertices) { NumberOfEdges = 3 * NumberOfFaces / 2; var alreadyDefinedEdges = new Dictionary<int, Edge>(); for (var i = 0; i < NumberOfFaces; i++) { var face = localFaces[i]; var lastIndex = face.Vertices.Count - 1; for (var j = 0; j <= lastIndex; j++) { var fromIndex = face.Vertices[j].IndexInList; var toIndex = (j == lastIndex) ? face.Vertices[0].IndexInList : face.Vertices[j + 1].IndexInList; if (fromIndex == toIndex) throw new Exception("edge to same vertices."); var checksum = (fromIndex < toIndex) ? fromIndex + (NumberOfVertices * toIndex) : toIndex + (NumberOfVertices * fromIndex); if (alreadyDefinedEdges.ContainsKey(checksum)) { var edge = alreadyDefinedEdges[checksum]; edge.OtherFace = face; face.Edges.Add(edge); } else { var edge = new Edge(localVertices[fromIndex], localVertices[toIndex], face, null, true, true); alreadyDefinedEdges.Add(checksum, edge); } } } var badEdges = new List<Edge>(); foreach (var edge in alreadyDefinedEdges.Values) if (edge.OwnedFace == null || edge.OtherFace == null) { badEdges.Add(edge); edge.OwnedFace = edge.OtherFace = edge.OwnedFace ?? edge.OtherFace; Debug.WriteLine("Edge found with only face (face normal = " + edge.OwnedFace.Normal.MakePrintString() + ", between vertices " + edge.From.Position.MakePrintString() + " & " + edge.To.Position.MakePrintString()); } var localEdges = alreadyDefinedEdges.Values.ToArray(); NumberOfEdges = localEdges.GetLength(0); return localEdges; }
/// <summary> /// Given a direction, dir, this function returns the maximum length along this direction /// for the provided vertices as well as the two vertices that represent the extremes. /// </summary> /// <param name="dir">The dir.</param> /// <param name="vertices">The vertices.</param> /// <param name="vLow">The v low.</param> /// <param name="vHigh">The v high.</param> /// <returns>System.Double.</returns> public static double GetLengthAndExtremeVertices(double[] dir, IList<Vertex> vertices, out Vertex vLow, out Vertex vHigh) { var dotProducts = new double[vertices.Count]; var i = 0; foreach (var v in vertices) dotProducts[i++] = dir.dotProduct(v.Position); var min_d = dotProducts.Min(); var max_d = dotProducts.Max(); vLow = vertices[dotProducts.FindIndex(min_d)]; vHigh = vertices[dotProducts.FindIndex(max_d)]; return max_d - min_d; }
internal void RemoveVertex(int removeVIndex) { NumberOfVertices--; var newVertices = new Vertex[NumberOfVertices]; for (int i = 0; i < removeVIndex; i++) newVertices[i] = Vertices[i]; for (int i = removeVIndex; i < NumberOfVertices; i++) { var v = Vertices[i + 1]; v.IndexInList--; newVertices[i] = v; } Vertices = newVertices; }
internal void RemoveVertex(Vertex removeVertex) { RemoveVertex(Vertices.FindIndex(removeVertex)); }
internal void AddVertices(IList<Vertex> verticesToAdd) { var numToAdd = verticesToAdd.Count(); var newVertices = new Vertex[NumberOfVertices + numToAdd]; for (int i = 0; i < NumberOfVertices; i++) newVertices[i] = Vertices[i]; for (int i = 0; i < numToAdd; i++) { var newVertex = verticesToAdd[i]; newVertices[NumberOfVertices + i] = newVertex; newVertex.IndexInList = NumberOfVertices + i; } Vertices = newVertices; NumberOfVertices += numToAdd; }
/// <summary> /// Others the vertex. /// </summary> /// <param name="v">The v.</param> /// <returns>Vertex.</returns> /// <exception cref="System.Exception">OtherVertex: Vertex thought to connect to edge, but it doesn't.</exception> public Vertex OtherVertex(Vertex v) { if (v == To) return From; if (v == From) return To; throw new Exception("OtherVertex: Vertex thought to connect to edge, but it doesn't."); }
internal static Boolean FindNegativeAndPositiveFaces(Flat plane, Vertex onPlaneVertex, double[] vertexDistancesToPlane, out PolygonalFace negativeFace, out PolygonalFace positiveFace) { negativeFace = null; positiveFace = null; foreach (var face in onPlaneVertex.Faces) { var otherEdge = face.OtherEdge(onPlaneVertex); var toDistance = vertexDistancesToPlane[otherEdge.To.IndexInList]; var fromDistance = vertexDistancesToPlane[otherEdge.From.IndexInList]; if ((toDistance > 0 && fromDistance < 0) || (toDistance < 0 && fromDistance > 0)) if ((toDistance > 0) == (face == otherEdge.OwnedFace)) positiveFace = face; else negativeFace = face; } return (negativeFace != null && positiveFace != null); }
/// <summary> /// Makes the vertices. /// </summary> /// <param name="listOfVertices">The list of vertices.</param> private void MakeVertices(IList<double[]> listOfVertices) { NumberOfVertices = listOfVertices.Count; Vertices = new Vertex[NumberOfVertices]; for (var i = 0; i < NumberOfVertices; i++) Vertices[i] = new Vertex(listOfVertices[i], i); }
/// <summary> /// Copies this instance. /// </summary> /// <returns>TessellatedSolid.</returns> public TessellatedSolid Copy() { var copyOfFaces = new PolygonalFace[NumberOfFaces]; for (var i = 0; i < NumberOfFaces; i++) copyOfFaces[i] = Faces[i].Copy(); var copyOfVertices = new Vertex[NumberOfVertices]; for (var i = 0; i < NumberOfVertices; i++) copyOfVertices[i] = Vertices[i].Copy(); for (var fIndex = 0; fIndex < NumberOfFaces; fIndex++) { var thisFace = copyOfFaces[fIndex]; var oldFace = Faces[fIndex]; var vertexIndices = new List<int>(); foreach (var oldVertex in oldFace.Vertices) { var vIndex = oldVertex.IndexInList; vertexIndices.Add(vIndex); var thisVertex = copyOfVertices[vIndex]; thisFace.Vertices.Add(thisVertex); thisVertex.Faces.Add(thisFace); } } Edge[] copyOfEdges = MakeEdges(copyOfFaces, copyOfVertices); var copy = new TessellatedSolid { SurfaceArea = SurfaceArea, Center = (double[])Center.Clone(), Faces = copyOfFaces, Vertices = copyOfVertices, Edges = copyOfEdges, Name = Name, NumberOfFaces = NumberOfFaces, NumberOfVertices = NumberOfVertices, Volume = Volume, XMax = XMax, XMin = XMin, YMax = YMax, YMin = YMin, ZMax = ZMax, ZMin = ZMin }; copy.CreateConvexHull(); return copy; }