private void BuildTerrain() { // Figure out where the extra ring of points should go double radius = BuildTerrainSprtRadius(_neurons.Select(o => o.Position.ToPoint2D()).ToArray()); // Figure out how many extra points to make int numExtra = BuildTerrainSprtNumExtra(_neurons.Length); // Lay down all the points into a single array _terrainPoints = UtilityCore.Iterate( _neurons.Select(o => o.Position), // first points are the neuron's locations (don't worry about Z right now, they will change each update) Math2D.GetCircle_Cached(numExtra).Select(o => new Point3D(o.X * radius, o.Y * radius, 0)) // tack on a bunch of points around the edge ).ToArray(); // Get the delaunay of these points TriangleIndexed[] triangles = Math2D.GetDelaunayTriangulation(_terrainPoints.Select(o => o.ToPoint2D()).ToArray(), _terrainPoints); // Convert into linked triangles List <TriangleIndexedLinked> trianglesLinked = triangles.Select(o => new TriangleIndexedLinked(o.Index0, o.Index1, o.Index2, o.AllPoints)).ToList(); TriangleIndexedLinked.LinkTriangles_Edges(trianglesLinked, true); _terrainTriangles = trianglesLinked.ToArray(); }
private static Point3D[] GetConnectingLinesSprtBetween(TriangleIndexedLinked[] hull, Tuple<int, Point3D> intersect1, Tuple<int, Point3D> intersect2, Tuple<TriangleEdge, Point3D> edgeIntersect1, Tuple<TriangleEdge, Point3D> edgeIntersect2) { // Start building the return points List<Point3D> retVal = new List<Point3D>(); retVal.Add(intersect1.Item2); retVal.Add(edgeIntersect1.Item2); // Walk neighbors until intersect2's triangle //TODO: To reduce mathmatical drift, go right one triangle from 1, then left one from 2, then right, etc and meet in the middle. But the //drift should be very small, and the polygon clip logic that's done by the caller will transform into/out of 2D anyway. //TODO: If the line goes exactly through a corner, this loop could fail TriangleIndexedLinked currentTriangle = hull[intersect1.Item1]; Tuple<TriangleEdge, Point3D> currentIntersect = edgeIntersect1; while (true) { currentTriangle = currentTriangle.GetNeighbor(currentIntersect.Item1); if (currentTriangle == null) { //TODO: Instead of choking here, go left from 2 as far as possible. Then just draw a line from the farthest points (jumping //over the hole) throw new ApplicationException("The hull passed in has holes"); } if (currentTriangle.Token == hull[intersect2.Item1].Token) { // This is the other side break; } //NOTE: There are some cases where intersect2 will lead backward. So an extra check is needed to make sure it's going //away from prevTriangle var attemptIntersect = GetPointOnTriangleEdge(currentTriangle, currentIntersect.Item2, intersect2.Item2); // not using outsideCenterPoint, because that's only some midpoint (between intersect1 and 2). Since this while loop is marching toward intersect2, then intersect2 is the best outside point to use if (attemptIntersect == null) { #region Reverse guidePoint // This is a copy of what GetPointOnTriangleEdge does Vector3D guideDirection = (intersect2.Item2 - currentIntersect.Item2).GetProjectedVector(currentTriangle); if (Math3D.IsInvalid(guideDirection)) { // Guide guideDirection is perpendicular to the triangle throw new ApplicationException("Couldn't find an intersect on the other side of the triangle"); } // Now reverse the guide direction attemptIntersect = GetPointOnTriangleEdge(currentTriangle, currentIntersect.Item2, currentIntersect.Item2 - guideDirection); if (attemptIntersect == null) { throw new ApplicationException("Couldn't find an intersect on the other side of the triangle"); } #endregion } currentIntersect = attemptIntersect; retVal.Add(currentIntersect.Item2); } if (!Math3D.IsNearValue(retVal[retVal.Count - 1], edgeIntersect2.Item2)) { retVal.Add(edgeIntersect2.Item2); // execution will only get here if hull[intersect1.Item1] is a neighbor to hull[intersect2.Item1] (basically, if the while loop didn't do anything) } retVal.Add(intersect2.Item2); return retVal.ToArray(); }