public static OBBox CreateAlongSide(Vector2[] points, int index) { if (points.Length == 0) { Debug.LogError("No points sent!"); } int pointCount = points.Length; OBBox output = GetBox(); Vector2 p0 = points[index]; Vector2 p1 = points[index < pointCount - 1 ? index + 1 : 0]; Vector2 dir = (p1 - p0).normalized; float angle = JMath.SignAngle(dir); FlatBounds bounds = new FlatBounds(); for (int o = 0; o < pointCount; o++)//encapsulate rotated points { bounds.Encapsulate(JMath.Rotate(points[o], angle)); } Vector2 center = JMath.Rotate(bounds.center, -angle); output.SetValues(center, dir, bounds.height, JMath.Rotate(dir, 90), bounds.width); return(output); }
public static bool PointInsidePoly(Vector2Int point, Vector2Int[] poly) { FlatBounds bounds = new FlatBounds(); foreach (Vector2Int polyPoint in poly) { bounds.Encapsulate(polyPoint.vector2); } if (!bounds.Contains(point.vector2)) { return(false); } Vector2Int pointRight = point + new Vector2Int(bounds.width, 0); int numberOfPolyPoints = poly.Length; int numberOfCrossOvers = 0; for (int i = 0; i < numberOfPolyPoints; i++) { Vector2Int p0 = poly[i]; Vector2Int p1 = poly[(i + 1) % numberOfPolyPoints]; if (FastLineIntersection(point, pointRight, p0, p1)) { numberOfCrossOvers++; } } // if(numberOfCrossOvers % 2 != 0) bounds.DrawDebug(Color.green); return(numberOfCrossOvers % 2 != 0); }
public OBBox CreateConvex(Vector2[] points) { if (points.Length == 0) { Debug.LogError("No points sent!"); } int pointCount = points.Length; OBBox defaultBox = GetBox(); OBBox output = defaultBox; float minArea = Mathf.Infinity; for (int p = 0; p < pointCount; p++) { Vector2 p0 = points[p]; Vector2 p1 = points[(p + 1) % pointCount]; Vector2 dir = (p1 - p0).normalized; if (dir.sqrMagnitude < Mathf.Epsilon) { continue; //ignore duplicate points } float angle = JMath.SignAngle(dir); _bounds.Clear(); for (int o = 0; o < pointCount; o++)//encapsulate rotated points { _bounds.Encapsulate(JMath.Rotate(points[o], angle)); } Vector2 center = JMath.Rotate(_bounds.center, -angle); OBBox candidate = GetBox(center, dir, _bounds.height, JMath.Rotate(dir, 90), _bounds.width); if (_bounds.Area() < minArea) { if (output != defaultBox) { PutBox(output); } output = candidate; } else { PutBox(candidate); } } return(output); }
public void AddSegment(FloorSegment segment) { _segments.Add(segment); int size = segment.points.Length; for (int p = 0; p < size; p++) { _bounds.Encapsulate(segment.points[p].vx, segment.points[p].vy); } }
private void CalculatePlanBounds() { _bounds.Clear(); int pointCount = _points.Count; for (int p = 0; p < pointCount; p++) { _bounds.Encapsulate(_points[p].position.vector2); } }
private static Vector2 GetCenter(Vector2[] points) { FlatBounds bounds = new FlatBounds(); int pointCount = points.Length; for (int i = 0; i < pointCount; i++) { bounds.Encapsulate(points[i]); } return(bounds.center); }
public static float PolyAreaQuick(Vector2[] points) { BOUNDS.Clear(); for (int i = 0; i < points.Length; i++) { BOUNDS.Encapsulate(points[i]); } float output = BOUNDS.Area(); return(output); }
public FloorSegment(float area, params Vector2Int[] input) { int inputCount = input.Length; points = new Vector2Int[inputCount]; bounds = new FlatBounds(); for (int p = 0; p < inputCount; p++) { points[p] = input[p]; bounds.Encapsulate(input[p].vx, input[p].vy); } // CalculateNormals(); position = new Vector2Int(bounds.center); nBounds = new FlatBounds(bounds); nBounds.Expand(0.25f); this.area = area; neighbours = new List <FloorSegment>(); }
public static bool Generate(BuildRMesh mesh, BuildRCollider collider, Vector2[] points, int[] facadeIndices, float roofBaseHeight, IVolume volume, Rect clampUV) { Roof design = volume.roof; OffsetSkeleton offsetPoly = new OffsetSkeleton(points); offsetPoly.direction = 1; offsetPoly.Execute(); Shape shape = offsetPoly.shape; int submesh = mesh.submeshLibrary.SubmeshAdd(design.mainSurface); // surfaceMapping.IndexOf(design.mainSurface); int wallSubmesh = mesh.submeshLibrary.SubmeshAdd(design.wallSurface); //surfaceMapping.IndexOf(design.wallSurface); if (shape == null) { return(false); } List <Edge> edges = new List <Edge>(shape.edges); List <Edge> baseEdges = new List <Edge>(shape.baseEdges); float shapeHeight = shape.HeighestPoint(); float designHeight = design.height; float heightScale = designHeight / shapeHeight; Vector2 clampUVScale = Vector2.one; if (clampUV.width > 0) { FlatBounds bounds = new FlatBounds(); for (int fvc = 0; fvc < points.Length; fvc++) { bounds.Encapsulate(points[fvc]); } clampUVScale.x = bounds.width / clampUV.width; clampUVScale.y = bounds.height / clampUV.height; } Dictionary <Node, int> shapeConnectionCount = new Dictionary <Node, int>(); Dictionary <Node, List <Node> > shapeConnections = new Dictionary <Node, List <Node> >(); int edgeCount = edges.Count; for (int e = 0; e < edgeCount; e++) { Edge edge = edges[e]; if (edge.length < Mathf.Epsilon) { continue; } if (!shapeConnectionCount.ContainsKey(edge.nodeA)) { shapeConnectionCount.Add(edge.nodeA, 0);//start at zero - we need two edges to make a shape... shapeConnections.Add(edge.nodeA, new List <Node> { edge.nodeB }); } else { shapeConnectionCount[edge.nodeA]++; if (!shapeConnections[edge.nodeA].Contains(edge.nodeB)) { shapeConnections[edge.nodeA].Add(edge.nodeB); } } if (!shapeConnectionCount.ContainsKey(edge.nodeB)) { shapeConnectionCount.Add(edge.nodeB, 0);//start at zero - we need two edges to make a shape... shapeConnections.Add(edge.nodeB, new List <Node> { edge.nodeA }); } else { shapeConnectionCount[edge.nodeB]++; if (!shapeConnections[edge.nodeB].Contains(edge.nodeA)) { shapeConnections[edge.nodeB].Add(edge.nodeA); } } } int baseEdgeCount = baseEdges.Count; for (int b = 0; b < baseEdgeCount; b++) { Edge baseEdge = baseEdges[b]; Node nodeA = baseEdge.nodeA; Node nodeB = baseEdge.nodeB; Node currentNode = nodeA; Node lastNode = nodeB; int itMax = 50; List <Node> edgeShape = new List <Node>() { nodeA }; while (currentNode != nodeB) { List <Node> nodeConnections = shapeConnections[currentNode]; int nodeConnectionCount = nodeConnections.Count; float minAngle = Mathf.Infinity; Node nextNode = null; Vector2 currentDirection = (currentNode.position - lastNode.position).normalized; for (int n = 0; n < nodeConnectionCount; n++) { Node connectingNode = nodeConnections[n]; if (connectingNode == lastNode) { continue; } Vector2 nextDirection = (connectingNode.position - currentNode.position).normalized; float nodeAngle = JMath.SignAngleDirection(currentDirection, nextDirection); if (nodeAngle < minAngle) { minAngle = nodeAngle; nextNode = connectingNode; } } if (nextNode != null) { edgeShape.Add(nextNode); lastNode = currentNode; currentNode = nextNode; } itMax--; if (itMax < 0) { break; } } int edgeShapeCount = edgeShape.Count; if (edgeShapeCount < 3) { continue; } // Debug.Log("Generate edgeShapeCount "+ edgeShapeCount); Vector3[] verts = new Vector3[edgeShapeCount]; Vector2[] uvs = new Vector2[edgeShapeCount]; Vector3 baseShapeDirection = ShapeOffset.Utils.ToV3(nodeB.position - nodeA.position).normalized; float uvAngle = JMath.SignAngle(new Vector2(baseShapeDirection.x, baseShapeDirection.z).normalized) - 90; Vector2[] faceShape = new Vector2[edgeShapeCount]; Vector3[] normals = new Vector3[edgeShapeCount]; Vector4[] tangents = new Vector4[edgeShapeCount]; // Vector3 normal = Vector3.up;//BuildRMesh.CalculateNormal(); TODO Vector4 tangent = BuildRMesh.CalculateTangent(baseShapeDirection); for (int i = 0; i < edgeShapeCount; i++)//what on earth did I write here? { Vector3 newVert = new Vector3(edgeShape[i].position.x, edgeShape[i].height * heightScale + roofBaseHeight, edgeShape[i].position.y); verts[i] = newVert; Vector2 baseUV = new Vector2(newVert.x - verts[0].x, newVert.z - verts[0].z); Vector2 newUV = Vector2.zero; if (i != 0) { newUV = JMath.Rotate(baseUV, uvAngle); } if (clampUV.width > Mathf.Epsilon) { newUV.x = Mathf.Clamp(clampUV.x + newUV.x / clampUVScale.x, clampUV.xMin, clampUV.xMax); newUV.y = Mathf.Clamp(clampUV.y + newUV.y / clampUVScale.y, clampUV.yMin, clampUV.yMax); } else { if (i != 0) { float faceHeight = edgeShape[i].height * heightScale; newUV.y = Mathf.Sqrt((newUV.y * newUV.y) + (faceHeight * faceHeight));//hypotenuse of roof to give length of roof face if (design.mainSurface != null) { newUV = design.mainSurface.CalculateUV(newUV); } } } uvs[i] = newUV; faceShape[i] = edgeShape[i].position;//used for triangulation // normals[i] = normal; tangents[i] = tangent; } // int[] tris = EarClipper.Triangulate(faceShape, 0, -1); int[] tris = Poly2TriWrapper.Triangulate(faceShape, true); int triCount = tris.Length; Vector3 normal = (verts.Length > 2 && triCount > 2) ? BuildRMesh.CalculateNormal(verts[tris[0]], verts[tris[1]], verts[tris[2]]) : Vector3.up; for (int i = 0; i < edgeShapeCount; i++) { normals[i] = normal; } mesh.AddData(verts, uvs, tris, normals, tangents, submesh); //gable bool isGabled = volume[facadeIndices[b]].isGabled; if (isGabled) { for (int t = 0; t < triCount; t += 3) { if (tris[t] == 0 || tris[t + 1] == 0 || tris[t + 2] == 0) { int beB = edgeShapeCount - 1; if (tris[t] == beB || tris[t + 1] == beB || tris[t + 2] == beB) { Vector3 b0 = verts[0]; Vector3 b1 = verts[beB]; Vector3 g0 = b0; Vector3 g1 = b1; int topIndex = 0; for (int tx = 0; tx < 3; tx++) { if (tris[t + tx] != 0 && tris[t + tx] != beB) { topIndex = tris[t + tx]; } } Vector3 b2 = verts[topIndex]; Vector3 baseV = b1 - b0; Vector3 dir = baseV.normalized; Vector3 face = Vector3.Cross(Vector3.up, dir).normalized; Vector3 up = Vector3.Project(b2 - b0, Vector3.up); //clear triangle tris[t] = 0; tris[t + 1] = 0; tris[t + 2] = 0; bool simpleGable = volume[facadeIndices[b]].simpleGable; Gable gableStyle = volume[facadeIndices[b]].gableStyle; float thickness = volume[facadeIndices[b]].gableThickness; float additionalHeight = volume[facadeIndices[b]].gableHeight; float height = up.magnitude + additionalHeight; if (simpleGable || gableStyle != null) { Vector3 pitchVectorA = (b2 - b0).normalized; Vector3 pitchVectorB = (b2 - b1).normalized; float angle = Vector3.Angle(-face, pitchVectorA); float scale = Mathf.Cos(angle / 57.2957795f); b0 += pitchVectorA * (thickness * (1 / scale)); b1 += pitchVectorB * (thickness * (1 / scale)); } Vector3 center = Vector3.Lerp(b0, b1, 0.5f); up = Vector3.Project(b2 - b0, Vector3.up); //recalculate after b change(?) Vector3 b3 = center + up; if (simpleGable) //generate a simple gable { //generate simple gable based on roof Vector3 gCenter = Vector3.Lerp(g0, g1, 0.5f); Vector3 gBaseUp = Vector3.up * additionalHeight; Vector3 gUp = up.normalized * height; Vector3 gBack = -face * thickness; //todo further calculations //face mesh.AddPlane(g0, g1, g0 + gBaseUp, g1 + gBaseUp, wallSubmesh); mesh.AddTri(g1 + gBaseUp, g0 + gBaseUp, gCenter + gUp, dir, wallSubmesh); //backface mesh.AddPlane(g1 + gBack, g0 + gBack, g1 + gBaseUp + gBack, g0 + gBaseUp + gBack, wallSubmesh); mesh.AddTri(g0 + gBack + gBaseUp, g1 + gBack + gBaseUp, b3 + gBaseUp, -dir, wallSubmesh); //left mesh.AddPlane(g0 + gBack, g0, g0 + gBaseUp + gBack, g0 + gBaseUp, wallSubmesh); mesh.AddPlane(g0 + gBaseUp + gBack, g0 + gBaseUp, b3 + gBaseUp, gCenter + gUp, wallSubmesh); //right mesh.AddPlane(g1, g1 + gBack, g1 + gBaseUp, g1 + gBaseUp + gBack, wallSubmesh); mesh.AddPlane(g1 + gBaseUp, g1 + gBaseUp + gBack, gCenter + gUp, b3 + gBaseUp, wallSubmesh); } else if (volume[facadeIndices[b]].gableStyle != null) { Vector2 baseUV = new Vector2(0, volume.planHeight); GableGenerator.Generate(ref mesh, gableStyle, g0, g1, height, thickness, baseUV); } else { mesh.AddTri(b0, b3, b1, dir, submesh);//face - no separate gable } mesh.AddTri(b0, b2, b3, face, submesh); //left mesh.AddTri(b1, b3, b2, -face, submesh); //right } } } } } return(true); }
public static void BMesh(BuildRMesh mesh, float height, Surface surface, int submesh, Vector2[] shape, Rect clampUV, bool flipTri = false, Vector2[][] holes = null, BuildRCollider collider = null) { int shapeSize = shape.Length; bool[] useHole = new bool[0]; if (holes != null) { int holeCount = holes.Length; // Debug.Log("BMesh "+holeCount); useHole = new bool[holeCount]; for (int flc = 0; flc < holeCount; flc++) { useHole[flc] = true; int holeSize = holes[flc].Length; // for(int h = 0; h < holeSize; h++) // { // Vector2 holePoint = holes[flc][h]; // holeIntersections[h] = PointInShape(holePoint, shape); //// Debug.Log("intersection length " + intersections.Length); // useHole[flc] = holeIntersections[h].Length == 0; // } // for(int flcp = 0; flcp < holeSize; flcp++) // { // if(!PointInPolygon(holes[flc][flcp], shape)) // { // useHole[flc] = false; // break; // } // } if (useHole[flc]) { shapeSize += holeSize; } } } Vector2[] allFloorPoints = new Vector2[shapeSize]; int mainShapeLength = shape.Length; for (int ms = 0; ms < mainShapeLength; ms++) { allFloorPoints[ms] = shape[ms]; } int cutPointIterator = mainShapeLength; if (holes != null) { for (int flc = 0; flc < holes.Length; flc++) { if (!useHole[flc]) { continue; } for (int flcp = 0; flcp < holes[flc].Length; flcp++) { allFloorPoints[cutPointIterator] = holes[flc][flcp]; cutPointIterator++; } } } FlatBounds bounds = new FlatBounds(); if (clampUV.width > 0) { for (int fvc = 0; fvc < mainShapeLength; fvc++) { bounds.Encapsulate(shape[fvc]); } } Vector3[] floorPoints = new Vector3[shapeSize]; Vector2[] floorUvs = new Vector2[shapeSize]; Vector3[] floorNorms = new Vector3[shapeSize]; Vector4[] floorTangents = new Vector4[shapeSize]; Vector3 normal = flipTri ? Vector3.up : Vector3.down; Vector4 tangent = BuildRMesh.CalculateTangent(Vector3.right); for (int rp = 0; rp < shapeSize; rp++) { floorPoints[rp] = new Vector3(allFloorPoints[rp].x, height, allFloorPoints[rp].y); if (clampUV.width > 0) { Vector2 clampedUV = new Vector2(); clampedUV.x = ((floorPoints[rp].x - bounds.xMin) / bounds.width) * clampUV.width + clampUV.x; clampedUV.y = ((floorPoints[rp].z - bounds.yMin) / bounds.height) * clampUV.height + clampUV.y; floorUvs[rp] = clampedUV; } else { if (surface != null) { floorUvs[rp] = surface.CalculateUV(allFloorPoints[rp]); } else { floorUvs[rp] = allFloorPoints[rp]; } } floorNorms[rp] = normal; floorTangents[rp] = tangent; } int[] tris = Triangulate(shape, flipTri, holes); // Debug.Log(volumeFloor + " " + actualFloor + " " + floorPoints.Length + " " + tris.Length+" "+r); int useFloorSubmesh = submesh != -1 ? submesh : 0; mesh.AddData(floorPoints, floorUvs, tris, floorNorms, floorTangents, useFloorSubmesh); if (collider != null) { collider.mesh.AddData(floorPoints, floorUvs, tris, floorNorms, floorTangents, 0); } }
public void Execute(Plot plot, uint seed) { processPlots.Clear(); plots.Clear(); debug.Clear(); int plotSize = plot.numberOfEdges; bool[] plotExternals = new bool[plotSize]; for (int p = 0; p < plotSize; p++) { plotExternals[p] = true; } _parent = plot; ProcessPlot initialPlot = new ProcessPlot(_parent, obbFit.CreateSorted(plot.pointsV2)); processPlots.Add(initialPlot); float initialArea = initialPlot.obbs[0].area; if (plot.splitSettings.autoArea) { FlatBounds pBounds = new FlatBounds(); pBounds.Encapsulate(plot.getAllPointsV2); plot.splitSettings.minArea = Mathf.Min(pBounds.size.x, pBounds.size.y) * plot.splitSettings.autoAreaRatio; plot.splitSettings.maxArea = Mathf.Max(pBounds.size.x, pBounds.size.y) * plot.splitSettings.autoAreaRatio; } if (initialArea < plot.splitSettings.maxArea)// if the supplied plot is already small enough - return it { plots.Add(_parent); processPlots.Clear(); // Debug.Log("Plot size (" + initialArea + ") below max area " + plot.splitSettings.maxArea); return; } rGen = new RandomGen(seed); int it = 0; while (processPlots.Count > 0) { ProcessPlot processPlot = processPlots[0]; IPlot currentPlot = processPlot.plot; processPlots.RemoveAt(0); Subplot[] newPlots = SplitPlot(processPlot); bool earlyTermination = newPlots[0] == null; if (newPlots[1] == null) { earlyTermination = true; } if (rGen.output < plot.splitSettings.randomTerminationChance) { earlyTermination = true; } Subplot plotA = null, plotB = null; List <OBBox> obbsA = null; List <OBBox> obbsB = null; if (!earlyTermination) { plotA = newPlots[0]; plotB = newPlots[1]; if (plotA.plotAccessPercentage < plot.splitSettings.minimumAccessLengthPercent) { if (plot.splitSettings.log) { plotA.notes = "insufficient access"; } earlyTermination = true; } if (plotB.plotAccessPercentage < plot.splitSettings.minimumAccessLengthPercent) { if (plot.splitSettings.log) { plotB.notes = "insufficient access"; } earlyTermination = true; } if (plotA.numberOfEdges < 4 && !plot.splitSettings.allowTrianglularPlots) { if (plot.splitSettings.log) { plotA.notes = "triangular split"; } earlyTermination = true; } if (plotB.numberOfEdges < 4 && !plot.splitSettings.allowTrianglularPlots) { plotB.notes = "triangular split"; earlyTermination = true; } obbsA = obbFit.CreateSorted(plotA.pointsV2); if (obbsA.Count == 0) { if (plot.splitSettings.log) { plotA.notes = "no obb generated"; } earlyTermination = true; } else if (obbsA[0].aspect < plot.splitSettings.minimumAspect) { if (plot.splitSettings.log) { plotA.notes = "aspect issue"; } earlyTermination = true; } else if (obbsA[0].area < plot.splitSettings.minArea) { if (plot.splitSettings.log) { plotA.notes = "area smaller than minimum"; } earlyTermination = true; } obbsB = obbFit.CreateSorted(plotB.pointsV2); if (obbsB.Count == 0) { if (plot.splitSettings.log) { plotB.notes = "no obb generated"; } earlyTermination = true; } else if (obbsB[0].aspect < plot.splitSettings.minimumAspect) { if (plot.splitSettings.log) { plotB.notes = "aspect issue"; } earlyTermination = true; } else if (obbsB[0].area < plot.splitSettings.minArea) { if (plot.splitSettings.log) { plotB.notes = "area smaller than minimum"; } earlyTermination = true; } } if (earlyTermination) { if (plotA != null && plotB != null) { if (plot.splitSettings.log) { currentPlot.notes = string.Format("plotA:{0} plotB:{1} {2}", plotA.notes, plotB.notes, processPlot); } if (plot.splitSettings.debug)//output debug info { DebugSplitInfo info = new DebugSplitInfo(); info.plot = currentPlot; info.plotA = plotA; info.plotB = plotB; debug.Add(info); } } //figure on appropirate fallback if (!processPlot.longSplit && plot.splitSettings.fallbackSecondaryDivision)//divide along the longer split { processPlot.longSplit = true; processPlots.Insert(0, processPlot); } else { if (!processPlot.variationA && plot.splitSettings.fallbackVariations)//use a variation on the split { processPlot.variationA = true; processPlots.Insert(0, processPlot); } else { if (!processPlot.variationB && plot.splitSettings.fallbackVariations)//use a variation on the split { processPlot.variationB = true; processPlots.Insert(0, processPlot); } else { if (processPlot.obbs.Count > 1 && plot.splitSettings.fallbackAlternativeObb)//if there are other cut options - use them! { processPlot.obbs.RemoveAt(0); processPlot.longSplit = false; processPlot.variationA = false; processPlot.variationB = false; processPlots.Insert(0, processPlot); } else { plots.Add(currentPlot);//termination - all allowable fallbacks used } } } } continue;//next } OBBox obbA = obbsA[0]; OBBox obbB = obbsB[0]; bool terminateA = obbA.area < plot.splitSettings.maxArea && rGen.output < 0.3f; if (!terminateA) { processPlots.Add(new ProcessPlot(plotA, obbsA)); } else { if (plot.splitSettings.log) { plotA.notes = "small enough to end"; } plots.Add(plotA);//termination } bool terminateB = obbB.area < plot.splitSettings.maxArea && rGen.output < 0.3f; if (!terminateB) { processPlots.Add(new ProcessPlot(plotB, obbsB)); } else { if (plot.splitSettings.log) { plotB.notes = "small enough to end"; } plots.Add(plotB);//termination } it++; if (it > 5000) { UnityEngine.Profiling.Profiler.EndSample(); return; } } // Profiler.EndSample(); }
public void Execute() { calculatedPartitions.Clear(); //remvoe duplicate points for (int i = 0; i < shape.Count; i++) { Vector2Int p0 = shape[i]; Vector2Int p1 = shape[i < shape.Count - 1 ? i + 1 : 0]; float sqrM = Vector2Int.SqrMagnitudeFloat(p1, p0); if (sqrM < Mathf.Epsilon) { shape.RemoveAt(i); i--; } } //break poly down into convex shapes TPPLPoly poly = new TPPLPoly(); for (int i = 0; i < shape.Count; i++) { poly.Points.Add(new TPPLPoint(shape[i].x, shape[i].y)); } if (BuildrPolyClockwise.Check(shape)) { poly.SetOrientation(TPPLOrder.CW); } else { poly.SetOrientation(TPPLOrder.CCW); } List <TPPLPoly> parts = new List <TPPLPoly>(); TPPLPartition tpplPartition = new TPPLPartition(); tpplPartition.ConvexPartition_HM(poly, parts); //generate an irregular grid upon each convex poly int partCount = parts.Count; PlotSplitter plotSplitter = new PlotSplitter(); floorSegments.Clear(); for (int p = 0; p < partCount; p++) { TPPLPoly partPoly = parts[p]; int partSize = partPoly.Count; List <Vector2Int> plotPoints = new List <Vector2Int>(); for (int w = 0; w < partSize; w++) { TPPLPoint tpplPoint = partPoly[w]; Vector2Int p0 = new Vector2Int(tpplPoint.X, tpplPoint.Y); plotPoints.Add(p0); } Plot plot = new Plot(seed, plotPoints, minimumWallUnitSpacing); plot.splitSettings = splitSettings; plotSplitter.Execute(plot, seed); int splitCount = plotSplitter.plots.Count; for (int s = 0; s < splitCount; s++) { IPlot segmentPlot = plotSplitter.plots[s]; Vector2Int[] points = Vector2Int.Parse(segmentPlot.pointsV2); FloorSegment segment = new FloorSegment(segmentPlot.area, segmentPlot.flatbounds, points); floorSegments.Add(segment); } } int segmentCount = floorSegments.Count; List <FloorSegment> availableSegments = new List <FloorSegment>(floorSegments); int restrictedAreaCount = restrictedAreas.Count; Partition restrictedPartition = null; for (int r = 0; r < restrictedAreaCount; r++) { RestrictedArea area = restrictedAreas[r]; FlatBounds areaBounds = new FlatBounds(); areaBounds.Encapsulate(Vector2Int.Parse(area.shape)); for (int fs = 0; fs < segmentCount; fs++) { FloorSegment segment = availableSegments[fs]; if (areaBounds.Overlaps(segment.bounds)) { if (JMath.ShapesIntersect(Vector2Int.Parse(area.shape), Vector2Int.Parse(segment.points))) { if (restrictedPartition == null) { restrictedPartition = new Partition(); } restrictedPartition.AddSegment(segment); availableSegments.Remove(segment); segmentCount--; fs--; } } } } //Link up floor segments segmentCount = availableSegments.Count; for (int x = 0; x < segmentCount; x++) { FloorSegment subject = floorSegments[x]; FlatBounds subjectBounds = subject.nBounds; for (int y = 0; y < segmentCount; y++) { if (x == y) { continue; } FloorSegment candidate = floorSegments[y]; FlatBounds candidateBounds = candidate.nBounds; if (subjectBounds.Overlaps(candidateBounds)) { if (candidate.neighbours.Contains(subject)) { continue; } subject.neighbours.Add(candidate); candidate.neighbours.Add(subject); } } } //Grow out partitions to fill the available space List <PartitionGrowth> partitionGs = new List <PartitionGrowth>(); Dictionary <FloorSegment, FloorSegmentClaim> segmentClaims = new Dictionary <FloorSegment, FloorSegmentClaim>(); for (int i = 0; i < partitions.Count; i++) { partitionGs.Add(new PartitionGrowth(partitions[i])); } int it = 1000; while (true) { int growthCount = partitionGs.Count; int completePartitionGrowths = 0; int[] partitionGrowthAmount = new int[growthCount]; segmentClaims.Clear(); for (int g = 0; g < growthCount; g++) { PartitionGrowth partitionG = partitionGs[g]; if (!partitionG.active) { completePartitionGrowths++; continue; } if (availableSegments.Count == 0) { break; } //assign inital segment to begin partition from if (!partitionG.initialised) { float nearestSqrMag = float.PositiveInfinity; FloorSegment candidate = availableSegments[0]; for (int x = 0; x < availableSegments.Count; x++) { FloorSegment subject = availableSegments[x]; float sqrMag = Vector2Int.SqrMagnitudeFloat(partitionG.subject.position, subject.position); if (sqrMag < nearestSqrMag) { candidate = subject; nearestSqrMag = sqrMag; } } partitionG.capturedSegments.Add(candidate); partitionG.processSegments.Add(candidate); availableSegments.Remove(candidate); partitionG.initialised = true; partitionGrowthAmount[g] = 1; continue;//don't start growth until next iteration } //grow partition if (partitionG.initialised) { List <FloorSegment> neighbourCandiates = new List <FloorSegment>(); int processCount = partitionG.processSegments.Count; // float additionalArea = 0; for (int p = 0; p < processCount; p++) { FloorSegment processSegment = partitionG.processSegments[p]; int processNeighbourCount = processSegment.neighbours.Count; for (int n = 0; n < processNeighbourCount; n++) { FloorSegment neighbour = processSegment.neighbours[n]; bool isAvailable = availableSegments.Contains(neighbour); bool notDuplicateNeighbour = !neighbourCandiates.Contains(neighbour); if (isAvailable && notDuplicateNeighbour) { neighbourCandiates.Add(neighbour); float fit = processSegment.BestFit(neighbour); if (fit > Mathf.Epsilon) { FloorSegmentClaim newClaim = new FloorSegmentClaim(); newClaim.partition = partitionG; newClaim.growthIndex = g; newClaim.segment = neighbour; newClaim.priority = partitionG.subject.priority * fit; if (!segmentClaims.ContainsKey(neighbour)) { segmentClaims.Add(neighbour, newClaim); } else { FloorSegmentClaim currentClaim = segmentClaims[neighbour]; if (currentClaim.priority < newClaim.priority) { segmentClaims[neighbour] = newClaim; } } } // additionalArea += neighbour.area; } } } // int neighbourCandiatesCount = neighbourCandiates.Count; // for (int n = 0; n < neighbourCandiatesCount; n++) { // FloorSegment segement = neighbourCandiates[n]; // // if (segmentClaims.ContainsKey(segement)) { // // } // else { // // } // } // if (neighbourCandiatesCount > 0) { // // bool canAddAll = partitionG.AvailableArea(additionalArea); // if (canAddAll) { // partitionG.processSegments.Clear(); // for (int n = 0; n < neighbourCandiatesCount; n++) // availableSegments.Remove(neighbourCandiates[n]); //// partitionG.AddSegments(neighbourCandiates); // } // else { // // TODO partial add (?) //// partitionG.AddSegments(neighbourCandiates); // partitionG.Complete(); // } // } // else { // partitionG.Complete(); // } // if (partitionG.processSegments.Count == 0) // partitionG.Complete(); } } foreach (KeyValuePair <FloorSegment, FloorSegmentClaim> kv in segmentClaims) { //TODO - support instance when new areas to add are too large //TODO - fall back on partial adding of single side FloorSegmentClaim claim = kv.Value; claim.partition.AddSegment(claim.segment); availableSegments.Remove(claim.segment); partitionGrowthAmount[claim.growthIndex]++; } for (int g = 0; g < growthCount; g++) { PartitionGrowth partitionG = partitionGs[g]; if (!partitionG.active) { continue; } // Debug.Log(g+" "+ partitionG.AcceptableAreaUsed()+" " + partitionGrowthAmount[g]+" "+ partitionG.processSegments.Count); if (partitionG.AcceptableAreaUsed() || partitionGrowthAmount[g] == 0 || partitionG.processSegments.Count == 0) { completePartitionGrowths++; partitionG.Complete(); } } if (completePartitionGrowths == growthCount) //all partitions have been completed { break; } if (availableSegments.Count == 0) { foreach (PartitionGrowth part in partitionGs) { if (part.active) { part.Complete(); } } foreach (PartitionGrowth part in partitionGs) { int childCount = part.subject.children.Count; if (childCount > 0) { for (int c = 0; c < childCount; c++) { partitionGs.Add(new PartitionGrowth(part.subject.children[c])); } part.subject.children.Clear(); availableSegments.AddRange(part.capturedSegments); part.capturedSegments.Clear(); break; } } if (availableSegments.Count == 0) { break; } } it--; if (it == 0) { Debug.Log(" MAX reached!"); Debug.Log(availableSegments.Count); foreach (PartitionGrowth pg in partitionGs) { Debug.Log(pg.processSegments.Count); Debug.Log(pg.capturedSegments.Count); pg.Complete(); } break; } } foreach (PartitionGrowth part in partitionGs) { if (part.active) { part.Complete(); } calculatedPartitions.Add(part.subject); } // if (floorplan != null) // { // int roomCount = calculatedPartitions.Count; // // // // // Room floorplanRoom = new Room(); // // // floorplan.rooms.Add(); // } // foreach (Partition part in partitions) { // Debug.Log(part.segments.Count); // } }