private void Triangulate() { TPPLPoly poly = new TPPLPoly(); foreach (PointF p in _points) { poly.Points.Add(new TPPLPoint(p.X, p.Y)); } poly.SetOrientation(TPPLOrder.CCW); List <TPPLPoly> triangles = new List <TPPLPoly>(); TPPLPartition part = new TPPLPartition(); part.Triangulate_EC(poly, triangles); _triangles.Clear(); foreach (TPPLPoly triangle in triangles) { Triangle tr = new Triangle(); triangle.SetOrientation(TPPLOrder.CW); tr.Alpha = new PointF(triangle[0].X, triangle[0].Y); tr.Bravo = new PointF(triangle[1].X, triangle[1].Y); tr.Charlie = new PointF(triangle[2].X, triangle[2].Y); _triangles.Add(tr); } }
public static float PolyArea2(Vector2[] points) { TPPLPoly poly = new TPPLPoly(); for (int i = 0; i < points.Length; i++) { poly.Points.Add(new TPPLPoint(points[i].x, points[i].y)); } if (BuildrPolyClockwise.Check(points)) { poly.SetOrientation(TPPLOrder.CW); } else { poly.SetOrientation(TPPLOrder.CCW); } List <TPPLPoly> triangles = new List <TPPLPoly>(); TPPLPartition part = new TPPLPartition(); part.Triangulate_EC(poly, triangles); int triCount = triangles.Count; float output = 0; for (int t = 0; t < triCount; t += 3) { TPPLPoint tv0 = triangles[t][0]; TPPLPoint tv1 = triangles[t][1]; TPPLPoint tv2 = triangles[t][2]; Vector2 v0 = new Vector2(tv0.X, tv0.Y); Vector2 v1 = new Vector2(tv1.X, tv1.Y); Vector2 v2 = new Vector2(tv2.X, tv2.Y); float a = Vector2.Distance(v0, v1); float b = Vector2.Distance(v1, v2); float c = Vector2.Distance(v2, v0); output += TriangleAreaHeron(a, b, c); } return(output); }
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); // } }