public static void DistanceWithinRectangle(double height, Vector2d rectangleCenterLineStart, Vector2d rectangleCenterLineEnd, double rectangleHalfWitdth, double influenceDistance, List <EPMPoint> pointList, CurveMode curveMode = CurveMode.ReverseLinear, CombineMode combineMode = CombineMode.Add, double limitation = 0) { Vector2d dir = rectangleCenterLineEnd - rectangleCenterLineStart; double lineLength = dir.Length(); dir.Normalize(); Vector2d normal = new Vector2d(-dir.y, dir.x); for (int i = 0; i < pointList.Count; i++) { EPMPoint p = pointList[i]; Vector2d v2 = p.pos2d - rectangleCenterLineStart; double hlength = v2 * dir; double vlength = v2 * normal; double distance = 0; if (hlength >= 0 && hlength <= lineLength && System.Math.Abs(vlength) <= rectangleHalfWitdth) { //The point is in the rectangle distance = EPMGlobal.Min(rectangleHalfWitdth - System.Math.Abs(vlength), hlength, lineLength - hlength); if (distance <= influenceDistance) { double y = GetHeightByCurveMode(distance / influenceDistance, curveMode) * height; SetHeightByCombineMode(p, y, combineMode, limitation); } } else { //The point is outside the rectangle, ignore it. continue; } } }
public static void DistanceToLine(double height, Vector2d lineStart, Vector2d lineEnd, double radius, List <EPMPoint> pointList, CurveMode curveMode = CurveMode.ReverseLinear, CombineMode combineMode = CombineMode.Add, double limitation = 0) { Vector2d dir = lineEnd - lineStart; double lineLength = dir.Length(); dir.Normalize(); Vector2d normal = new Vector2d(-dir.y, dir.x); for (int i = 0; i < pointList.Count; i++) { EPMPoint p = pointList[i]; Vector2d v2 = p.pos2d - lineStart; double dot = v2 * dir; double distance = 0; if (dot < 0 || dot > lineLength) { //Check the distance to LineStart point and LineEndPoint distance = System.Math.Min(v2.Length(), (p.pos2d - lineEnd).Length()); } else { //check the distance to line distance = System.Math.Abs(v2 * normal); } if (distance < radius) { double y = GetHeightByCurveMode(distance / radius, curveMode) * height; SetHeightByCombineMode(p, y, combineMode, limitation); } } }
public EPMTriangle(EPMPoint p1, EPMPoint p2, EPMPoint p3) { g_pointList.Clear(); g_pointList.Add(p1); g_pointList.Add(p2); g_pointList.Add(p3); }
public void GeneratingPoints_Line(int number, EPMPoint.PointType type, Vector2d lineStart, Vector2d lineEnd, double maxDistance, bool uniformly = true) { Vector2d dir = lineEnd - lineStart; double lineLength = dir.Length(); double uniLength = lineLength / number; dir.Normalize(); Vector2d normal = new Vector2d(-dir.y, dir.x); for (int i = 0; i < number; i++) { Vector2d v2 = new Vector2d(); if (uniformly) { v2.x = RandomDouble(i * uniLength, (i + 1) * uniLength); } else { v2.x = RandomDouble(0, lineLength); } v2.y = RandomDouble(-maxDistance, maxDistance); v2 = lineStart + v2.x * dir + v2.y * normal; if (IsPointInValidRange(v2)) { EPMPoint p = new EPMPoint(type, new Vector3d(v2.x, 0, v2.y)); m_vertexList.Add(p); } } }
public static void DistanceToBorderOfRectangle(double height, Vector2d rectangleCenterLineStart, Vector2d rectangleCenterLineEnd, double rectangleHalfWitdth, double influenceDistance, List <EPMPoint> pointList, CurveMode curveMode = CurveMode.ReverseLinear, CombineMode combineMode = CombineMode.Add, double limitation = 0) { Vector2d dir = rectangleCenterLineEnd - rectangleCenterLineStart; double lineLength = dir.Length(); dir.Normalize(); Vector2d normal = new Vector2d(-dir.y, dir.x); Vector2d corner1, corner2, corner3, corner4; corner1 = rectangleCenterLineStart + normal * rectangleHalfWitdth; corner2 = rectangleCenterLineStart - normal * rectangleHalfWitdth; corner3 = rectangleCenterLineEnd + normal * rectangleHalfWitdth; corner4 = rectangleCenterLineEnd - normal * rectangleHalfWitdth; for (int i = 0; i < pointList.Count; i++) { EPMPoint p = pointList[i]; Vector2d v2 = p.pos2d - rectangleCenterLineStart; double hlength = v2 * dir; double vlength = v2 * normal; double distance = 0; if (hlength >= 0 && hlength <= lineLength && System.Math.Abs(vlength) <= rectangleHalfWitdth) { //The point is in the rectangle, ignore it. continue; } else { if (hlength >= 0 && hlength <= lineLength) { distance = System.Math.Abs(vlength - rectangleHalfWitdth); } else if (System.Math.Abs(vlength) <= rectangleHalfWitdth) { if (hlength > 0) { distance = hlength - lineLength; } else { distance = -hlength; } } else { v2 = p.pos2d; distance = EPMGlobal.Min((v2 - corner1).Length(), (v2 - corner2).Length(), (v2 - corner3).Length(), (v2 - corner4).Length()); } if (distance <= influenceDistance) { double y = GetHeightByCurveMode(distance / influenceDistance, curveMode) * height; SetHeightByCombineMode(p, y, combineMode, limitation); } } } }
public override void TryDetermineType() { EPMPoint.PointType t1, t2, t3; t1 = g_pointList[0].g_type; t2 = g_pointList[1].g_type; t3 = g_pointList[2].g_type; int sign = EPMPoint.GenerateTypesInt(false, t1, t2, t3); //If one of the vertex is ocean point and not all the points are ocean point. It is a oceanside for sure if ((sign & (int)EPMPoint.PointType.Ocean) != 0 && (sign - (int)EPMPoint.PointType.Ocean) != 0) { g_shapeType = EPMPoint.PointType.OceanSide; g_isTypeDetermined = true; return; } int grounds = EPMPoint.GetGroundEnums(); //If one of the vertice's type is ground, set the tile type to this ground. if ((sign & grounds) != 0) { if ((sign & (int)EPMPoint.PointType.Ground) != 0) { g_shapeType = EPMPoint.PointType.Ground; //Ground has highest priority. } else if ((sign & (int)EPMPoint.PointType.Sand) != 0) { g_shapeType = EPMPoint.PointType.Sand; } else if ((sign & (int)EPMPoint.PointType.Soil) != 0) { g_shapeType = EPMPoint.PointType.Soil; } else { g_shapeType = EPMPoint.PointType.Ground; } g_isTypeDetermined = true; } else { //Find the type that appears 3 times. Set the tile to this type if (t1 == t2 && t1 == t3) { g_shapeType = t1; g_isTypeDetermined = true; } else { //Vertices have different types, simply set the tiles type to ground, but leave the determine sign to false, the tile's type depend on its neighbors. g_shapeType = EPMPoint.PointType.Ground; g_isTypeDetermined = false; } } }
public static bool UserDefineSampler(DoubleCallback <EPMPoint> userDefineFunc, List <EPMPoint> pointList, CombineMode mode = CombineMode.Add, double limitation = 0) { for (int i = 0; i < pointList.Count; i++) { EPMPoint p = pointList[i]; double y = userDefineFunc(p); SetHeightByCombineMode(p, y, mode, limitation); } return(true); }
public virtual bool HasPoint(EPMPoint p) { for (int i = 0; i < g_pointList.Count; i++) { if (g_pointList[i] == p) { return(true); } } return(false); }
public bool HasPoint(EPMPoint p) { for (int i = 0; i < g_pointList.Length; i++) { if (g_pointList[i] == p) { return(true); } } return(false); }
public void GeneratingPoints_Square(int number, EPMPoint.PointType type, Vector2d startPos, Vector2d endPos) { for (int i = 0; i < number; i++) { Vector2d v2 = new Vector2d(RandomDouble(startPos.x, endPos.x), RandomDouble(startPos.y, endPos.y)); if (IsPointInValidRange(v2)) { EPMPoint p = new EPMPoint(type, new Vector3d(v2.x, 0, v2.y)); m_vertexList.Add(p); } } }
private static void SetHeightByCombineMode(EPMPoint point, double height, CombineMode mode, double limitation) { switch (mode) { case CombineMode.Add: point.g_height += height; break; case CombineMode.Subtract: point.g_height -= height; break; case CombineMode.Replace: point.g_height = height; break; case CombineMode.ReplaceHighest: if (point.g_height <= height) { point.g_height = height; } break; case CombineMode.ReplaceLowest: if (point.g_height >= height) { point.g_height = height; } break; case CombineMode.AddWithLimitation: if (point.g_height + height < limitation) { point.g_height += height; } else { point.g_height = limitation; } break; case CombineMode.SubtractWithLimitation: if (point.g_height - height > limitation) { point.g_height -= height; } else { point.g_height = limitation; } break; } }
public static void DistanceToPoint(double height, Vector2d center, double radius, List <EPMPoint> pointList, CurveMode curveMode = CurveMode.ReverseLinear, CombineMode combineMode = CombineMode.Add, double limitation = 0) { for (int i = 0; i < pointList.Count; i++) { EPMPoint p = pointList[i]; double distance = center.Distance(p.pos2d); if (distance < radius) { double y = GetHeightByCurveMode(distance / radius, curveMode) * height; SetHeightByCombineMode(p, y, combineMode, limitation); } } }
public static void DistanceWithinCircle(double height, Vector2d center, double radius, double influenceDistance, List <EPMPoint> pointList, CurveMode curveMode = CurveMode.ReverseLinear, CombineMode combineMode = CombineMode.Add, double limitation = 0) { for (int i = 0; i < pointList.Count; i++) { EPMPoint p = pointList[i]; double distance = radius - center * p.pos2d; if (distance >= 0 && distance < influenceDistance) { double y = GetHeightByCurveMode(distance / influenceDistance, curveMode) * height; SetHeightByCombineMode(p, y, combineMode, limitation); } } }
public EPMEdge(EPMPoint p1, EPMPoint p2) { g_startPoint = p1; g_endPoint = p2; g_visited = false; if (g_startPoint.g_indexInList < g_endPoint.g_indexInList) { m_longHash = g_startPoint.g_indexInList + (((long)g_endPoint.g_indexInList) << 31); } else { m_longHash = g_endPoint.g_indexInList + (((long)g_startPoint.g_indexInList) << 31); } }
public void GeneratingPoints_Ring(int number, EPMPoint.PointType type, Vector2d center, double minRadius, double maxRadius, bool uniformly = true) { double uniDegree = System.Math.PI * 2 / number; double c1 = (maxRadius - minRadius) / 3 + minRadius; double c2 = maxRadius - (maxRadius - minRadius) / 3; for (int i = 0; i < number;) { Vector2d v2 = new Vector2d(); if (uniformly) { double radius = RandomDouble(minRadius, c1); v2.x = System.Math.Cos(uniDegree * i) * radius + center.x; v2.y = System.Math.Sin(uniDegree * i) * radius + center.y; if (IsPointInValidRange(v2)) { EPMPoint p = new EPMPoint(type, new Vector3d(v2.x, 0, v2.y)); m_vertexList.Add(p); } radius = RandomDouble(c2, maxRadius); v2.x = System.Math.Cos(uniDegree * (i + 1)) * radius + center.x; v2.y = System.Math.Sin(uniDegree * (i + 1)) * radius + center.y; if (IsPointInValidRange(v2)) { EPMPoint p = new EPMPoint(type, new Vector3d(v2.x, 0, v2.y)); m_vertexList.Add(p); } i += 2; } else { double radius = RandomDouble(minRadius, maxRadius); double degree = (double)RandomDouble(0, 2 * System.Math.PI); v2.x = System.Math.Cos(degree) * radius + center.x; v2.y = System.Math.Sin(degree) * radius + center.y; if (IsPointInValidRange(v2)) { EPMPoint p = new EPMPoint(type, new Vector3d(v2.x, 0, v2.y)); m_vertexList.Add(p); } i++; } } }
public void GeneratingBase(int number, EPMPoint.PointType type) { m_vertexList.Add(new EPMPoint(type, g_startPoint)); m_vertexList.Add(new EPMPoint(type, new Vector2d(g_endPoint.x, g_startPoint.y))); m_vertexList.Add(new EPMPoint(type, g_endPoint)); m_vertexList.Add(new EPMPoint(type, new Vector2d(g_startPoint.x, g_endPoint.y))); for (int i = 0; i < number; i++) { Vector2d v2 = new Vector2d(RandomDouble(g_startPoint.x, g_endPoint.x), RandomDouble(g_startPoint.y, g_endPoint.y)); EPMPoint p = new EPMPoint(type, new Vector3d(v2.x, 0, v2.y)); m_vertexList.Add(p); } GeneratingPoints_Line((int)(getXLength() / 5), type, g_startPoint, new Vector2d(g_endPoint.x, g_startPoint.y), 0, true); GeneratingPoints_Line((int)(getZlength() / 5), type, new Vector2d(g_endPoint.x, g_startPoint.y), g_endPoint, 0, true); GeneratingPoints_Line((int)(getXLength() / 5), type, g_endPoint, new Vector2d(g_startPoint.x, g_endPoint.y), 0, true); GeneratingPoints_Line((int)(getZlength() / 5), type, new Vector2d(g_startPoint.x, g_endPoint.y), g_startPoint, 0, true); }
public void GeneratingPoints_Circle(int number, EPMPoint.PointType type, Vector2d center, double radius) { double SquaredRadius = radius * radius; for (int i = 0; i < number; i++) { Vector2d v2 = new Vector2d(center.x + RandomDouble(-radius, radius), center.y + RandomDouble(-radius, radius)); if (v2.SquaredDistance(center) > SquaredRadius) { i--; } else { if (IsPointInValidRange(v2)) { EPMPoint p = new EPMPoint(type, new Vector3d(v2.x, 0, v2.y)); m_vertexList.Add(p); } } } }
public EPMLiteTriangle(EPMPoint p1, EPMPoint p2, EPMPoint p3) { g_pointList[0] = p1; g_pointList[1] = p2; g_pointList[2] = p3; }
public bool HasShapeType(EPMPoint.PointType type) { return(HasShapeType(EPMPoint.GenerateTypesInt(false, type))); }
//The divideYCount is set by experiment.... public static List <EPMTriangle> DoDelaunay(List <EPMPoint> pointList, Vector2d regionStart, Vector2d regionEnd, int divideYCount = 12) { //Shift point's the postion, Treat regionStart as Origin Point; if (regionStart.x != 0 || regionStart.y != 0) { for (int i = 0; i < pointList.Count; i++) { pointList[i].pos2d -= regionStart; } } regionEnd -= regionStart; //Make a super triangle, All the points are in this super triangle. EPMPoint p1, p2, p3; double regionWidth = regionEnd.x; double regionHeight = regionEnd.y; p1 = new EPMPoint(EPMPoint.PointType.Ground, new Vector3d(-regionHeight, 0, -100)); p2 = new EPMPoint(EPMPoint.PointType.Ground, new Vector3d(regionEnd.x + regionHeight, 0, p1.posZ)); double tempRatio = regionHeight / (regionHeight + regionWidth / 2); double p3y = (regionHeight + 100f) / tempRatio - 100f; p3y += regionHeight; p3 = new EPMPoint(EPMPoint.PointType.Ground, new Vector3d((regionEnd.x) / 2, 0, p3y)); p1.g_indexInList = pointList.Count; p2.g_indexInList = p1.g_indexInList + 1; p3.g_indexInList = p2.g_indexInList + 1; EPMLiteTriangle superTriangle = new EPMLiteTriangle(p1, p2, p3); superTriangle.CalculateOuterCircle(); //triangleList saves the determined triangle. List <EPMLiteTriangle> triangleList = new List <EPMLiteTriangle>(); //tempTriangleList save all the uncertain triangles, put the triangle into different groups according by its outerCircle's coverage on Y-Axis. EPMLinkedList <EPMLiteTriangle>[] tempTriangleList = new EPMLinkedList <EPMLiteTriangle> [divideYCount]; //the pointer to current section of tempTriangleList. EPMLinkedList <EPMLiteTriangle> currentSection = null; //Use Dictionary to quickly remove duplicate edge. In the test, the edgeDic can at most contains less than 100 edges. But I still can't figure out a way to defeat C#'s dictionary.... Dictionary <long, EPMEdge> tempEdgeDic = new Dictionary <long, EPMEdge>(); //Sort the input points by x coordinate. pointList.Sort(delegate(EPMPoint comparePoint1, EPMPoint comparePoint2) { if (comparePoint1.posX > comparePoint2.posX) { return(1); } else if (comparePoint1.posX == comparePoint2.posX) { return(0); } else { return(-1); } }); //reset the index saved in each point,index is used by edges to generate hash. Hash could accelerate comparation. for (int i = 0; i < pointList.Count; i++) { pointList[i].g_indexInList = i; } //Put the super triangle into tempList, Super triangle absolutely cover all groups of tempTriangleList. for (int i = 0; i < tempTriangleList.Length; i++) { tempTriangleList[i] = new EPMLinkedList <EPMLiteTriangle>(); tempTriangleList[i].Push_Back(superTriangle); } double YSEGMENT = regionHeight / tempTriangleList.Length; //Begin Algorithm. for (int i = 0; i < pointList.Count; i++) { tempEdgeDic.Clear(); EPMPoint cp = pointList[i]; int section = (int)((cp.posZ) / YSEGMENT); if (section >= tempTriangleList.Length) { section = tempTriangleList.Length - 1; } currentSection = tempTriangleList[section]; currentSection.ResetCurrentToHead(); EPMLiteTriangle ct = currentSection.MoveForward(); while (ct != null) { if (ct.g_visited) { ct = currentSection.DeleteCurrentAndMoveForward(); continue; } Vector2d origin = ct.g_outerCircleOrigin; double radius = ct.g_outerCicleRadius; if (cp.posX - origin.x > radius) { triangleList.Add(ct); ct.g_visited = true; ct = currentSection.DeleteCurrentAndMoveForward(); continue; } else if (cp.pos2d.SquaredDistance(origin) > radius * radius) { ct = currentSection.MoveForward(); continue; } else { TryAddEdge(ref tempEdgeDic, new EPMEdge(ct[0], ct[1])); TryAddEdge(ref tempEdgeDic, new EPMEdge(ct[1], ct[2])); TryAddEdge(ref tempEdgeDic, new EPMEdge(ct[2], ct[0])); ct.g_visited = true; ct = currentSection.DeleteCurrentAndMoveForward(); } } foreach (EPMEdge e in tempEdgeDic.Values) { if (e.g_visited) { continue; } EPMLiteTriangle tt = new EPMLiteTriangle(cp, e.g_startPoint, e.g_endPoint); tt.CalculateOuterCircle(); int lowerBound = (int)((tt.g_outerCircleOrigin.y - tt.g_outerCicleRadius) / YSEGMENT); if (lowerBound < 0) { lowerBound = 0; } int upperBound = (int)((tt.g_outerCircleOrigin.y + tt.g_outerCicleRadius) / YSEGMENT); if (upperBound >= tempTriangleList.Length) { upperBound = tempTriangleList.Length - 1; } for (int k = lowerBound; k <= upperBound; k++) { tempTriangleList[k].Push_Back(tt); } } } for (int i = 0; i < tempTriangleList.Length; i++) { currentSection = tempTriangleList[i]; currentSection.ResetCurrentToHead(); for (EPMLiteTriangle ct = currentSection.MoveForward(); ct != null; ct = currentSection.MoveForward()) { if (ct.g_visited == false) { triangleList.Add(ct); } } } List <EPMTriangle> buffer = new List <EPMTriangle>(); for (int i = triangleList.Count - 1; i >= 0; i--) { EPMLiteTriangle lt = triangleList[i]; if (lt.HasPoint(p1) || lt.HasPoint(p2) || lt.HasPoint(p3)) { } else { buffer.Add(new EPMTriangle(lt[0], lt[1], lt[2])); lt[0].g_neighbors.Add(lt[1]); lt[0].g_neighbors.Add(lt[2]); lt[1].g_neighbors.Add(lt[0]); lt[1].g_neighbors.Add(lt[2]); lt[2].g_neighbors.Add(lt[0]); lt[2].g_neighbors.Add(lt[1]); } } for (int i = 0; i < pointList.Count; i++) { pointList[i].TidyNeighbors(); } //Shift point's position Back. if (regionStart.x != 0 || regionStart.y != 0) { for (int i = 0; i < pointList.Count; i++) { pointList[i].pos2d += regionStart; } } return(buffer); }