public static bool IsShapeConvex(Polygon shape) { PolygonShapeData shapeData = shape.Data as PolygonShapeData; for (int i = 0; i < shapeData.PolygonPoints.Count; i++) { Vector2 first = shapeData.PolygonPoints[i]; int sI = i == shapeData.PolygonPoints.Count - 1 ? 0 : i + 1; Vector2 second = shapeData.PolygonPoints[sI]; for (int j = 0; j < shapeData.PolygonPoints.Count; j++) { Vector2 pointToCheck = shapeData.PolygonPoints[j]; if (pointToCheck != first && pointToCheck != second) { bool isConvex = ((second.X - first.X) * (pointToCheck.Y - first.Y) - (second.Y - first.Y) * (pointToCheck.X - first.X)) > 0; if (!isConvex) { return(false); } } } } return(true); }
public PolygonShapeData(PolygonShapeData self) { Depth = self.Depth; Scalar = self.Scalar; PolygonPoints = new List <Vector2>(); for (int i = 0; i < self.PolygonPoints.Count; i++) { PolygonPoints.Add(self.PolygonPoints[i]); } }
public void CalculatePreGenerateData() { PolygonShapeData shapeData = Data as PolygonShapeData; for (int i = 0; i < shapeData.PolygonPoints.Count; i++) { int pointX = (int)MathF.Round(shapeData.PolygonPoints[i].X * shapeData.Scalar, 0, MidpointRounding.ToEven); int pointY = (int)MathF.Round(shapeData.PolygonPoints[i].Y * shapeData.Scalar, 0, MidpointRounding.ToEven); shapeData.PolygonPoints[i] = new Vector2(pointX, pointY); } }
public Vector2 GetCenter() { PolygonShapeData shapeData = Data as PolygonShapeData; Vector2 center = new Vector2(0, 0); for (int i = 0; i < shapeData.PolygonPoints.Count; i++) { center += shapeData.PolygonPoints[i] * shapeData.Scalar; } center /= shapeData.PolygonPoints.Count; return(center); }
public Polygon(Polygon self) : base(self) { ID = self.ID; Position = self.Position; if (self.Sides != null) { Sides = new SolidSide[self.Sides.Length]; } if (Sides != null) { for (int i = 0; i < self.Sides.Length; i++) { Sides[i] = self.Sides[i]; } } Data = new PolygonShapeData(self.Data as PolygonShapeData); }
private List <Shape> ConvertToConvex(Polygon shape) { PolygonShapeData shapeData = shape.Data as PolygonShapeData; List <List <Vector2> > result = PolygonTriangulator.Triangulate(shapeData.PolygonPoints); List <Shape> newShapeList = new List <Shape>(); for (int i = 0; i < result.Count; i++) { Polygon newShape = new Polygon(shape); List <Vector2> points = result[i]; //points.Reverse(); newShape.Data = new PolygonShapeData() { Depth = shapeData.Depth, Scalar = shapeData.Scalar, PolygonPoints = points }; newShapeList.Add(newShape); } return(newShapeList); }
public static void CombineShapes(List <Polygon> shapes, out List <Polygon> resultingShapes, int depth = 0) { List <Polygon> applicants = new List <Polygon>(); Polygon currentPolygonToEval = null; List <Polygon> options = new List <Polygon>(shapes); int save = 0; while (true) { if (currentPolygonToEval == null) { if (options.Count <= 0) { break; } currentPolygonToEval = options[0]; options.RemoveAt(0); } Polygon prev = null; Polygon found = null; bool anyCombination = false; for (int i = 0; i < options.Count; i++) { Polygon v = new Polygon(currentPolygonToEval); v = v.Combine(options[i]); if (v != null) { v = RemoveRedundantPoints(v); if (IsShapeConvex(v)) { found = options[i]; prev = new Polygon(currentPolygonToEval); currentPolygonToEval = v; options.RemoveAt(i); anyCombination = true; break; } } } VMFDebug.CreateDebugImage("CombiningStep" + (save++), onDraw: (g) => { Pen greyPen = new Pen(Color.Gray, 3); Pen blackPen = new Pen(Color.Black, 3); Pen redPen = new Pen(Color.Red, 3); Pen bluePen = new Pen(Color.Blue, 3); Pen greenPen = new Pen(Color.Green, 3); for (int i = 0; i < options.Count; i++) { VMFDebug.AddShapeToGraphics(g, options[i], greyPen); } for (int i = 0; i < applicants.Count; i++) { VMFDebug.AddShapeToGraphics(g, applicants[i], blackPen); } if (found != null) { VMFDebug.AddShapeToGraphics(g, found, bluePen); } if (prev != null) { VMFDebug.AddShapeToGraphics(g, prev, greenPen); } else { VMFDebug.AddShapeToGraphics(g, currentPolygonToEval, redPen); } }); if (!anyCombination) { applicants.Add(new Polygon(currentPolygonToEval)); currentPolygonToEval = null; } } List <Polygon> result = new List <Polygon>(); for (int i = 0; i < applicants.Count; i++) { bool canAdd = true; for (int j = 0; j < result.Count; j++) { PolygonShapeData rSD = result[j].Data as PolygonShapeData; PolygonShapeData aSD = applicants[i].Data as PolygonShapeData; if (rSD.PolygonPoints.SequenceEqual(aSD.PolygonPoints)) { canAdd = false; break; } } if (canAdd) { result.Add(applicants[i]); } } resultingShapes = result; }
private void GenerateData(out List <Shape> shapesResult, out List <string> entities) { List <GenerationMethod> generationMethods = new List <GenerationMethod>(); entities = new List <string>(); EasyInputLayer.GetInput(out generationMethods, out entities); //Start shape construction List <Shape> shapes = new List <Shape>(); for (int i = 0; i < generationMethods.Count; i++) { shapes.AddRange(generationMethods[i].GetBrushes()); } List <Shape> finalShapeList = new List <Shape>(); for (int i = shapes.Count - 1; i >= 0; i--) { if (shapes[i] is Polygon) { (shapes[i] as Polygon).CalculatePreGenerateData(); if (!IsShapeConvex(shapes[i] as Polygon)) { VMFDebug.CreateDebugImage("PreTriangulation" + (i), onDraw: (g) => { Pen greyPen = new Pen(Color.Gray, 3); Pen redPen = new Pen(Color.Red, 3); for (int j = 0; j < shapes.Count; j++) { if (shapes[j] is Polygon) { VMFDebug.AddShapeToGraphics(g, shapes[j] as Polygon, greyPen); } } VMFDebug.AddShapeToGraphics(g, shapes[i] as Polygon, redPen); }); Console.WriteLine("Found a concave shape. Attempting triangulation"); List <Polygon> replacements = new List <Polygon>(); List <Shape> temp = ConvertToConvex(shapes[i] as Polygon); for (int j = 0; j < temp.Count; j++) { replacements.Add(temp[j] as Polygon); } Console.WriteLine("Single shape converted into " + replacements.Count + " new shapes"); List <Polygon> combinedShapes = new List <Polygon>(); for (int j = replacements.Count - 1; j >= 0; j--) { if (!IsShapeConvex(replacements[j] as Polygon)) { replacements[j] = RemoveRedundantPoints(replacements[j] as Polygon); Console.WriteLine("An invalid shape was found in the replacement batch. Attempting to fix..."); if (((PolygonShapeData)replacements[j].Data).PolygonPoints.Count < 3 || !IsShapeConvex(replacements[j] as Polygon)) { Console.WriteLine("Could not fix invalid shape. Deleting."); replacements.RemoveAt(j); } else { Console.WriteLine("Invalid shape fixed!"); } } } combinedShapes = replacements; CombineShapes(replacements, out combinedShapes); PolygonShapeData shapeData = shapes[i].Data as PolygonShapeData; for (int j = 0; j < combinedShapes.Count; j++) { finalShapeList.Add(combinedShapes[j]); } } else { finalShapeList.Add(shapes[i] as Polygon); } } else { finalShapeList.Add(shapes[i]); } } int currId = 0; for (int i = 0; i < finalShapeList.Count; i++) { finalShapeList[i].ID = i; finalShapeList[i].GenerateSides(currId); currId += finalShapeList[i].Sides.Length; } //End shape construction shapesResult = finalShapeList; }
public static List <Polygon> CreateWalls(Polygon polygon, WallData wallData) { List <List <Vector2> > allPoints = new List <List <Vector2> >(); List <Vector2> points = new List <Vector2>(); List <Vector2> lastFace = new List <Vector2>(); List <List <Vector2> > normals = new List <List <Vector2> >(); PolygonShapeData polyData = polygon.Data as PolygonShapeData; List <Vector2> sharedValues = polyData.PolygonPoints.GroupBy(x => x).Where(g => g.Count() > 1).Select(x => x.Key).ToList(); for (int i = 0; i < polyData.PolygonPoints.Count; i++) { if (sharedValues.Contains(polyData.PolygonPoints[i])) { wallData.facesIndicesToSkip.Add(i); i++; } } for (int i = 0; i < polyData.PolygonPoints.Count; i++) { if (wallData.facesIndicesToSkip.Contains(i)) { continue; } //Okay basically all the shit I'm doing here is getting the vertex normal of the current point //and basing how the wall should be made based off that, so all the walls end up as trapazoids. //The only exception is if a wall piece is missing, I then get the intersection based on which //side of the wall it is, and try to flatten it. It's not perfect but it works? int index1 = (i - 1) % polyData.PolygonPoints.Count; if (index1 == -1) { index1 = polyData.PolygonPoints.Count - 1; } int index2 = i % polyData.PolygonPoints.Count; int index3 = (i + 1) % polyData.PolygonPoints.Count; int index4 = (i + 2) % polyData.PolygonPoints.Count; Vector2 a = polyData.PolygonPoints[index1] * polyData.Scalar; Vector2 b = polyData.PolygonPoints[index2] * polyData.Scalar; Vector2 c = polyData.PolygonPoints[index3] * polyData.Scalar; Vector2 d = polyData.PolygonPoints[index4] * polyData.Scalar; Vector2 abNormal = Vector2.Normalize(Shape.GetNormal2D(a, b)); Vector2 bcNormal = Vector2.Normalize(Shape.GetNormal2D(b, c)); Vector2 vertexNormalabc = Vector2.Normalize((abNormal + bcNormal)) * wallData.Thickness; Vector2 cdNormal = Vector2.Normalize(Shape.GetNormal2D(c, d)); Vector2 vertexNormalbcd = Vector2.Normalize((bcNormal + cdNormal)) * wallData.Thickness; Vector2 point = polyData.PolygonPoints[index2] * polyData.Scalar + vertexNormalabc; Vector2 point2 = polyData.PolygonPoints[index3] * polyData.Scalar + vertexNormalbcd; points.Add(point); points.Add(point2); points.Add(c); points.Add(b); if (wallData.facesIndicesToSkip.Contains(i + 1)) { LineEquation first = new LineEquation(points[2], points[2] - bcNormal); LineEquation second = new LineEquation(points[0], points[1]); Vector2 intersectPoint; if (first.IntersectsWithLine(second, out intersectPoint)) { points[1] = intersectPoint; } } if (wallData.facesIndicesToSkip.Contains(i - 1)) { LineEquation first = new LineEquation(points[3], points[3] - bcNormal); LineEquation second = new LineEquation(points[0], points[1]); Vector2 intersectPoint; if (first.IntersectsWithLine(second, out intersectPoint)) { points[0] = intersectPoint; } } allPoints.Add(points); points = new List <Vector2>(); } //Idk there were edge cases I had NAN values and they didnt seem to affect anything sooooooo for (int i = allPoints.Count - 1; i >= 0; i--) { bool hasNan = false; for (int j = 0; j < allPoints[i].Count; j++) { if (allPoints[i][j] != allPoints[i][j]) { hasNan = true; break; } } if (hasNan) { allPoints.RemoveAt(i); } } VMFDebug.CreateDebugImage("WallOutput", onDraw: (g) => { float scale = 0.1f; for (int i = 0; i < allPoints.Count; i++) { for (int j = 0; j < allPoints[i].Count; j++) { int iN = (j + 1) % allPoints[i].Count; Point p1 = new Point((int)(allPoints[i][j].X * scale + 100), (int)(allPoints[i][j].Y * scale + 100)); Point p2 = new Point((int)(allPoints[i][iN].X * scale + 100), (int)(allPoints[i][iN].Y * scale + 100)); g.DrawLine(new Pen(Color.Black, 3), p1, p2); } } }); List <Polygon> finalPolygons = new List <Polygon>(); for (int i = 0; i < allPoints.Count; i++) { finalPolygons.Add( new Polygon() { Position = polygon.Position + new Vector3(0, 0, wallData.Height * 0.5f), Data = new PolygonShapeData() { Depth = wallData.Height + ((PolygonShapeData)polygon.Data).Depth, Scalar = 1, PolygonPoints = allPoints[i] } }); } return(finalPolygons); }
public Polygon Combine(Polygon other) { PolygonShapeData myShapeData = Data as PolygonShapeData; PolygonShapeData shapeData = other.Data as PolygonShapeData; List <Vector2> sharedPoints = new List <Vector2>(); int lowestIndexMe = -1; int lowestIndexOther = -1; Vector2 lowestMe = new Vector2(99999999, 99999999); Vector2 lowestOther = new Vector2(99999999, 99999999); Vector2 lowest = new Vector2(99999999, 99999999); for (int i = 0; i < myShapeData.PolygonPoints.Count; i++) { if (shapeData.PolygonPoints.Contains(myShapeData.PolygonPoints[i])) { sharedPoints.Add(myShapeData.PolygonPoints[i]); } if (myShapeData.PolygonPoints[i].X < lowest.X || (myShapeData.PolygonPoints[i].X == lowest.X && myShapeData.PolygonPoints[i].Y < lowest.Y)) { lowest = myShapeData.PolygonPoints[i]; } if (myShapeData.PolygonPoints[i].X < lowestMe.X || (myShapeData.PolygonPoints[i].X == lowestMe.X && myShapeData.PolygonPoints[i].Y < lowestMe.Y)) { lowestMe = myShapeData.PolygonPoints[i]; lowestIndexMe = i; } } if (sharedPoints.Count <= 1) { return(null); } for (int i = 0; i < shapeData.PolygonPoints.Count; i++) { if (shapeData.PolygonPoints[i].X < lowest.X || (shapeData.PolygonPoints[i].X == lowest.X && shapeData.PolygonPoints[i].Y < lowest.Y)) { lowest = shapeData.PolygonPoints[i]; } if (shapeData.PolygonPoints[i].X < lowestOther.X || (shapeData.PolygonPoints[i].X == lowestOther.X && shapeData.PolygonPoints[i].Y < lowestOther.Y)) { lowestOther = shapeData.PolygonPoints[i]; lowestIndexOther = i; } } bool startOnMe = false; int currIndex = -1; if (lowestMe != lowestOther) { if (lowestMe.X == lowestOther.X) { startOnMe = lowestMe.Y < lowestOther.Y; } else { startOnMe = lowestMe.X < lowestOther.X; } } else { int lowestMeNext = lowestIndexMe + 1; if (lowestMeNext >= myShapeData.PolygonPoints.Count) { lowestMeNext = 0; } int lowestOtherNext = lowestIndexOther + 1; if (lowestOtherNext >= shapeData.PolygonPoints.Count) { lowestOtherNext = 0; } Vector2 mePointOption = myShapeData.PolygonPoints[lowestMeNext]; Vector2 otherPointOption = shapeData.PolygonPoints[lowestOtherNext]; float constantAngle = MathF.Atan2(0.5f, 1) * 180 / MathF.PI; Vector2 meDifference = Vector2.Normalize(mePointOption - lowest); float meAngle = MathF.Atan2(meDifference.X, meDifference.Y) * 180 / MathF.PI; Vector2 otherDifference = Vector2.Normalize(otherPointOption - lowest); float otherAngle = MathF.Atan2(otherDifference.X, otherDifference.Y) * 180 / MathF.PI; startOnMe = meAngle > otherAngle; } currIndex = startOnMe ? lowestIndexMe : lowestIndexOther; List <Vector2> startingList = startOnMe ? myShapeData.PolygonPoints : shapeData.PolygonPoints; Vector2 firstPosition = startingList[currIndex]; List <Vector2> newShapeList = new List <Vector2>(); int safety = 0; while (true) { Vector2 pos = startingList[currIndex]; if (pos == firstPosition && newShapeList.Count > 0) { break; } newShapeList.Add(pos); if (sharedPoints.Contains(pos) && newShapeList.Count > 1) { startingList = startOnMe ? shapeData.PolygonPoints : myShapeData.PolygonPoints; for (int i = 0; i < startingList.Count; i++) { if (startingList[i] == pos) { currIndex = i; break; } } startOnMe = !startOnMe; } currIndex++; if (currIndex >= startingList.Count) { currIndex = 0; } safety++; if (safety > 1000) { break; } } PolygonShapeData finalData = new PolygonShapeData(myShapeData); finalData.PolygonPoints = newShapeList; Polygon topVertex = new Polygon(other) { ID = other.ID, Position = other.Position, Sides = other.Sides, Data = finalData }; return(topVertex); }
public override void GenerateSides(int startingID) { PolygonShapeData shapeData = Data as PolygonShapeData; //For now we only do cubes Sides = new SolidSide[shapeData.PolygonPoints.Count + 2]; for (int i = 0; i < Sides.Length; i++) { Sides[i].ID = startingID + i; } //Top Sides[0].Plane = new Vector3[] { Position + new Vector3(-shapeData.Scalar, -shapeData.Scalar, (shapeData.Depth * 0.5f)), Position + new Vector3(-shapeData.Scalar, shapeData.Scalar, (shapeData.Depth * 0.5f)), Position + new Vector3(shapeData.Scalar, shapeData.Scalar, (shapeData.Depth * 0.5f)) }; Sides[0].UV = new Vector4[] { new Vector4(1, 0, 0, 0), new Vector4(0, 1, 0, 0) }; //Bottom Sides[1].Plane = new Vector3[] { Position + new Vector3(shapeData.Scalar, -shapeData.Scalar, -(shapeData.Depth * 0.5f)), Position + new Vector3(shapeData.Scalar, shapeData.Scalar, -(shapeData.Depth * 0.5f)), Position + new Vector3(-shapeData.Scalar, shapeData.Scalar, -(shapeData.Depth * 0.5f)) }; Sides[1].UV = new Vector4[] { new Vector4(1, 0, 0, 0), new Vector4(0, 1, 0, 0) }; for (int i = 0; i < shapeData.PolygonPoints.Count; i++) { int sidesIndex = 2 + i; Vector2 first = shapeData.PolygonPoints[i]; int sI = i == shapeData.PolygonPoints.Count - 1 ? 0 : i + 1; Vector2 second = shapeData.PolygonPoints[sI]; float angle = MathF.Atan2(second.Y - first.Y, second.X - first.X) * (180 / MathF.PI); if (angle < 0) { angle += 360; } Sides[sidesIndex].Plane = new Vector3[] { Position + new Vector3(first.X, first.Y, -(shapeData.Depth * 0.5f)), Position + new Vector3(first.X, first.Y, (shapeData.Depth * 0.5f)), Position + new Vector3(second.X, second.Y, (shapeData.Depth * 0.5f)) }; bool useFirstMethod = (angle > 0 && angle <= 90) || (angle > 180 && angle <= 270); if (useFirstMethod) { Sides[sidesIndex].UV = new Vector4[] { new Vector4(0, 1, 0, 0), new Vector4(0, 0, -1, 0) }; } else { Sides[sidesIndex].UV = new Vector4[] { new Vector4(1, 0, 0, 0), new Vector4(0, 0, -1, 0) }; } } base.GenerateSides(startingID); }