/// <summary> /// Cleans up a simple polygon by removing duplicate adjacent positions and making /// the first position not equal the last position /// </summary> public static IList <T> Cleanup <T>(IEnumerable <T> positions) { IList <T> positionsList = CollectionAlgorithms.EnumerableToList(positions); if (positionsList.Count < 3) { throw new ArgumentOutOfRangeException("positions", "At least three positions are required."); } List <T> cleanedPositions = new List <T>(positionsList.Count); for (int i0 = positionsList.Count - 1, i1 = 0; i1 < positionsList.Count; i0 = i1++) { T v0 = positionsList[i0]; T v1 = positionsList[i1]; if (!v0.Equals(v1)) { cleanedPositions.Add(v1); } } cleanedPositions.TrimExcess(); return(cleanedPositions); }
public ICollection <Vector2D> ComputePositionsOnPlane(IEnumerable <Vector3D> positions) { if (positions == null) { throw new ArgumentNullException("positions"); } IList <Vector2D> positionsOnPlane = new List <Vector2D>(CollectionAlgorithms.EnumerableCount(positions)); foreach (Vector3D position in positions) { Vector3D intersectionPoint; if (IntersectionTests.TryRayPlane(Vector3D.Zero, position.Normalize(), _normal, _d, out intersectionPoint)) { Vector3D v = intersectionPoint - _origin; positionsOnPlane.Add(new Vector2D(_xAxis.Dot(v), _yAxis.Dot(v))); } else { // Ray does not intersect plane } } return(positionsOnPlane); }
public EllipsoidTangentPlane(Ellipsoid ellipsoid, IEnumerable <Vector3D> positions) { if (ellipsoid == null) { throw new ArgumentNullException("ellipsoid"); } if (positions == null) { throw new ArgumentNullException("positions"); } if (!CollectionAlgorithms.EnumerableCountGreaterThanOrEqual(positions, 1)) { throw new ArgumentOutOfRangeException("positions", "At least one position is required."); } AxisAlignedBoundingBox box = new AxisAlignedBoundingBox(positions); _origin = ellipsoid.ScaleToGeodeticSurface(box.Center); _normal = ellipsoid.GeodeticSurfaceNormal(_origin); _d = -_origin.Dot(_origin); _yAxis = _origin.Cross(_origin.MostOrthogonalAxis).Normalize(); _xAxis = _yAxis.Cross(_origin).Normalize(); }
public void EnumerableToList2() { Dictionary <int, int> dictionary = new Dictionary <int, int>(); dictionary.Add(0, 0); dictionary.Add(1, 1); IList <KeyValuePair <int, int> > returnedList = CollectionAlgorithms.EnumerableToList(dictionary); Assert.AreEqual(2, returnedList.Count); Assert.AreEqual(new KeyValuePair <int, int>(0, 0), returnedList[0]); Assert.AreEqual(new KeyValuePair <int, int>(1, 1), returnedList[1]); }
public void EnumerableToList() { IList <int> list = new List <int>(); list.Add(0); list.Add(1); IList <int> returnedList = CollectionAlgorithms.EnumerableToList(list); Assert.AreEqual(2, returnedList.Count); Assert.AreEqual(0, returnedList[0]); Assert.AreEqual(1, returnedList[1]); }
public void EnumerableCount() { int[] list = new int[] { 0, 1 }; Assert.AreEqual(2, CollectionAlgorithms.EnumerableCount(list)); Dictionary <int, int> dictionary = new Dictionary <int, int>(); dictionary.Add(0, 0); dictionary.Add(1, 1); IEnumerable <KeyValuePair <int, int> > enumerable = dictionary; Assert.AreEqual(2, CollectionAlgorithms.EnumerableCount(enumerable)); }
public ICollection <Geodetic2D> ToGeodetic2D(IEnumerable <Vector3D> positions) { if (positions == null) { throw new ArgumentNullException("positions"); } IList <Geodetic2D> geodetics = new List <Geodetic2D>(CollectionAlgorithms.EnumerableCount(positions)); foreach (Vector3D position in positions) { geodetics.Add(ToGeodetic2D(position)); } return(geodetics); }
public static double ComputeArea(IEnumerable <Vector2D> positions) { IList <Vector2D> positionsList = CollectionAlgorithms.EnumerableToList(positions); if (positionsList.Count < 3) { throw new ArgumentOutOfRangeException("positions", "At least three positions are required."); } double area = 0.0; // // Compute the area of the polygon. The sign of the area determines the winding order. // for (int i0 = positionsList.Count - 1, i1 = 0; i1 < positionsList.Count; i0 = i1++) { Vector2D v0 = positionsList[i0]; Vector2D v1 = positionsList[i1]; area += (v0.X * v1.Y) - (v1.X * v0.Y); } return(area * 0.5); }
public void EnumerableToListNull() { CollectionAlgorithms.EnumerableToList <int>(null); }
public void EnumerableCountNull() { CollectionAlgorithms.EnumerableCount <int>(null); }
public static TriangleMeshSubdivisionResult Compute(IEnumerable <Vector3D> positions, IndicesUnsignedInt indices, double granularity) { if (positions == null) { throw new ArgumentNullException("positions"); } if (indices == null) { throw new ArgumentNullException("positions"); } if (indices.Values.Count < 3) { throw new ArgumentOutOfRangeException("indices", "At least three indices are required."); } if (indices.Values.Count % 3 != 0) { throw new ArgumentException("indices", "The number of indices must be divisable by three."); } if (granularity <= 0.0) { throw new ArgumentOutOfRangeException("granularity", "Granularity must be greater than zero."); } // // Use two queues: one for triangles that need (or might need) to be // subdivided and other for triangles that are fully subdivided. // Queue <TriangleIndicesUnsignedInt> triangles = new Queue <TriangleIndicesUnsignedInt>(indices.Values.Count / 3); Queue <TriangleIndicesUnsignedInt> done = new Queue <TriangleIndicesUnsignedInt>(indices.Values.Count / 3); IList <uint> indicesValues = indices.Values; for (int i = 0; i < indicesValues.Count; i += 3) { triangles.Enqueue(new TriangleIndicesUnsignedInt(indicesValues[i], indicesValues[i + 1], indicesValues[i + 2])); } // // New positions due to edge splits are appended to the positions list. // IList <Vector3D> subdividedPositions = CollectionAlgorithms.CopyEnumerableToList(positions); // // Used to make sure shared edges are not split more than once. // Dictionary <Edge, int> edges = new Dictionary <Edge, int>(); // // Subdivide triangles until we run out // while (triangles.Count != 0) { TriangleIndicesUnsignedInt triangle = triangles.Dequeue(); Vector3D v0 = subdividedPositions[triangle.I0]; Vector3D v1 = subdividedPositions[triangle.I1]; Vector3D v2 = subdividedPositions[triangle.I2]; double g0 = v0.AngleBetween(v1); double g1 = v1.AngleBetween(v2); double g2 = v2.AngleBetween(v0); double max = Math.Max(g0, Math.Max(g1, g2)); if (max > granularity) { if (g0 == max) { Edge edge = new Edge(Math.Min(triangle.I0, triangle.I1), Math.Max(triangle.I0, triangle.I1)); int i; if (!edges.TryGetValue(edge, out i)) { subdividedPositions.Add((v0 + v1) * 0.5); i = subdividedPositions.Count - 1; edges.Add(edge, i); } triangles.Enqueue(new TriangleIndicesUnsignedInt(triangle.I0, i, triangle.I2)); triangles.Enqueue(new TriangleIndicesUnsignedInt(i, triangle.I1, triangle.I2)); } else if (g1 == max) { Edge edge = new Edge(Math.Min(triangle.I1, triangle.I2), Math.Max(triangle.I1, triangle.I2)); int i; if (!edges.TryGetValue(edge, out i)) { subdividedPositions.Add((v1 + v2) * 0.5); i = subdividedPositions.Count - 1; edges.Add(edge, i); } triangles.Enqueue(new TriangleIndicesUnsignedInt(triangle.I1, i, triangle.I0)); triangles.Enqueue(new TriangleIndicesUnsignedInt(i, triangle.I2, triangle.I0)); } else if (g2 == max) { Edge edge = new Edge(Math.Min(triangle.I2, triangle.I0), Math.Max(triangle.I2, triangle.I0)); int i; if (!edges.TryGetValue(edge, out i)) { subdividedPositions.Add((v2 + v0) * 0.5); i = subdividedPositions.Count - 1; edges.Add(edge, i); } triangles.Enqueue(new TriangleIndicesUnsignedInt(triangle.I2, i, triangle.I1)); triangles.Enqueue(new TriangleIndicesUnsignedInt(i, triangle.I0, triangle.I1)); } } else { done.Enqueue(triangle); } } // // New indices // IndicesUnsignedInt subdividedIndices = new IndicesUnsignedInt(done.Count * 3); foreach (TriangleIndicesUnsignedInt t in done) { subdividedIndices.AddTriangle(t); } return(new TriangleMeshSubdivisionResult(subdividedPositions, subdividedIndices)); }