/// <summary> /// Calculates the area of the Triangle formed by the three given points. /// The points shouldn't be colinear. /// </summary> /// <param name="A">Corner of the Triangle</param> /// <param name="B">Corner of the Triangle</param> /// <param name="C">Corner of the Triangle</param> /// <returns>Area of the Triangle</returns> public static double GetAreaOf(Vector A, Vector B, Vector C) { Vector cb = B - C; Vector ca = A - C; double a = cb.Length(); double b = ca.Length(); return(0.5 * a * b * Math.Sin(Vertex.Angle(cb, ca))); }
/// <summary> /// Fills the intial arrays, sets the extrema, the center and the scale. /// Sets the incident Triangles and the Neighborhood of each Vertex. /// Fills the Edge list. Calculates the Triangle normals. /// Sets the local coordinate system and the rotation matrix for each Triangle. /// Determines the area nearest each Vertex of a Triangle and the area of the entire Triangle. /// Calculates the angles of the Triangles. /// </summary> /// <param name="triNormals">If true, the Triangle normals and the centroid are calculated. /// If False, they are not calculated.</param> public void Finish(bool triNormals) { double oldMinLength = 0; if (edges.Count != 0) { oldMinLength = edges.Values[0].Length; } ClearRelations(); Edge edge; double edgeLength; float[] min = new float[3] { 0.0f, 0.0f, 0.0f }; float[] max = new float[3] { 0.0f, 0.0f, 0.0f }; // Calculates the minimum and maximum coordinates of every Triangle. for (int i = 0; i < this.Count; i++) { for (int j = 0; j < 3; j++) { if (this[i, 1][j] <= this[i, 0][j]) { this[i].Min[j] = (float)this[i, 1][j]; this[i].Max[j] = (float)this[i, 0][j]; } else { this[i].Min[j] = (float)this[i, 0][j]; this[i].Max[j] = (float)this[i, 1][j]; } if (this[i, 2][j] < this[i].Min[j]) { this[i].Min[j] = (float)this[i, 2][j]; } if (this[i, 2][j] > this[i].Max[j]) { this[i].Max[j] = (float)this[i, 2][j]; } } } // Initializes maximum and minimum with the values of the first Triangle. for (int h = 0; h < 3; h++) { if (this.Count > 0) { min[h] = this[0].Min[h]; max[h] = this[0].Max[h]; } else { min[h] = 0; max[h] = 1; } } for (int i = 0; i < this.Count; i++) { if (triNormals) { // Sets the Centroid for each Triangle. this[i].Centroid = ((vertices[this[i][0]] + vertices[this[i][1]] + vertices[this[i][2]]) / 3).ToVertex(); // Sets the Normal for each Triangle. this[i].Centroid.Normal = Triangle.GetNormalOf(this[i, 0], this[i, 1], this[i, 2]); } for (int j = 0; j < 3; j++) { if (this[i].Min[j] < min[j]) { min[j] = this[i].Min[j]; } if (this[i].Max[j] > max[j]) { max[j] = this[i].Max[j]; } // Sets the incident Triangles. this[i, j].AddIncidentTriangle(i); // Sets the Neighborhood. this[i, j].Neighborhood.AddNeighbors(this[i][(j + 1) % 3], this[i][(j + 2) % 3]); // Fills the Edge list. edgeLength = Vertex.Distance(this[i, j], this[i, (j + 1) % 3]); edge = new Edge(this[i][j], this[i][(j + 1) % 3], edgeLength); this[i].Edges.Add(edge); if (!edges.ContainsKey(edge.Key)) { edge.Triangles.Add(i); edges.Add(edge.Key, edge); } else { edges[edge.Key].Triangles.Add(i); } } // Sets the areas closest to each corner of a Triangle. // This was adapted from Szymon Rusinkiewicz C++ library trimesh2 (http://www.cs.princeton.edu/gfx/proj/trimesh2/). Vector[] e = new Vector[3] { this[i, 2] - this[i, 1], this[i, 0] - this[i, 2], this[i, 1] - this[i, 0] }; double area = 0.5 * (e[0] % e[1]).Length(); double[] l2 = new double[3] { e[0].SquaredLength(), e[1].SquaredLength(), e[2].SquaredLength() }; double[] ew = new double[3] { l2[0] * (l2[1] + l2[2] - l2[0]), l2[1] * (l2[2] + l2[0] - l2[1]), l2[2] * (l2[0] + l2[1] - l2[2]) }; if (ew[0] <= 0.0f) { this[i].CornerAreas[1] = -0.25 * l2[2] * area / (e[0].Dot(e[2])); this[i].CornerAreas[2] = -0.25 * l2[1] * area / (e[0].Dot(e[1])); this[i].CornerAreas[0] = area - this[i].CornerAreas[1] - this[i].CornerAreas[2]; } else if (ew[1] <= 0.0f) { this[i].CornerAreas[2] = -0.25 * l2[0] * area / (e[1].Dot(e[0])); this[i].CornerAreas[0] = -0.25 * l2[2] * area / (e[1].Dot(e[2])); this[i].CornerAreas[1] = area - this[i].CornerAreas[2] - this[i].CornerAreas[0]; } else if (ew[2] <= 0.0f) { this[i].CornerAreas[0] = -0.25 * l2[1] * area / (e[2].Dot(e[1])); this[i].CornerAreas[1] = -0.25 * l2[0] * area / (e[2].Dot(e[0])); this[i].CornerAreas[2] = area - this[i].CornerAreas[0] - this[i].CornerAreas[1]; } else { double ewscale = 0.5 * area / (ew[0] + ew[1] + ew[2]); for (int j = 0; j < 3; j++) { this[i].CornerAreas[j] = ewscale * (ew[(j + 1) % 3] + ew[(j + 2) % 3]); } } // The Voronoi area of a Vertex is caclulated by summing up the calculated corner areas. this[i, 0].Area += this[i].CornerAreas[0]; this[i, 1].Area += this[i].CornerAreas[1]; this[i, 2].Area += this[i].CornerAreas[2]; // Calculates the area for each Triangle. double a = this[i, 0].DistanceFrom(this[i, 1]); double b = this[i, 1].DistanceFrom(this[i, 2]); double c = this[i, 2].DistanceFrom(this[i, 0]); double s = 0.5 * (a + b + c); this[i].Area = Math.Sqrt(s * (s - a) * (s - b) * (s - c)); // Calculates the angles of each Triangle. Vector ab = this[i, 1] - this[i, 0]; Vector ac = this[i, 2] - this[i, 0]; Vector ba = this[i, 0] - this[i, 1]; Vector bc = this[i, 2] - this[i, 1]; Vector cb = this[i, 1] - this[i, 2]; Vector ca = this[i, 0] - this[i, 2]; this[i].Angles[0] = Vertex.Angle(ab, ac); this[i].Angles[1] = Vertex.Angle(ba, bc); this[i].Angles[2] = Vertex.Angle(cb, ca); } if (edges.Count != 0) { if ((oldMinLength != edges.Values[0].Length) && (MinEdgeLengthChanged != null)) { MinEdgeLengthChanged(edges.Values[0].Length); } } else { if (MinEdgeLengthChanged != null) { MinEdgeLengthChanged(0); } } // The center is calculated. for (int i = 0; i < 3; i++) { center[i] = 0.5 * (max[i] + min[i]); } // The scale is the maximum size in one coordinate direction. It is used for drawing. float oldScale = scale; scale = max[0] - min[0]; if (max[1] - min[1] > scale) { scale = max[1] - min[1]; } if (max[2] - min[2] > scale) { scale = max[2] - min[2]; } if ((oldScale != scale) && (ScaleChanged != null)) { ScaleChanged(); } // The colorDist is used to space the picking colors. int temp = 256 * 256 * 256; vertexColorDist = temp / (vertices.Count + 2); edgeColorDist = temp / (edges.Count + 2); triangleColorDist = temp / (this.Count + 2); }