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); } }
public void AddSegment(FloorSegment segment) { capturedSegments.Add(segment); processSegments.Add(segment); if (segment.area < 0) { Debug.Log("AddSegment minus area"); } currentArea += segment.area; }
public float BestFit(FloorSegment target) { if (target == this) { return(-1); } int targetSize = target.points.Length; int pointSize = points.Length; float output = 0;//default is there is no fit for (int p = 0; p < pointSize; p++) { Vector2Int point = points[p]; for (int t = 0; t < targetSize; t++) { Vector2Int targetPoint = target.points[t]; float sqrMag = (targetPoint - point).SqrMagnitudeFloat(); if (sqrMag < 0.1f) { output += 0.5f; } else //test for two lines joined { Vector2Int pointB = points[p < pointSize - 1 ? p + 1 : 0]; if (Colinear(point, pointB, targetPoint)) { Vector2Int targetPointB = target.points[t < targetSize - 1 ? t + 1 : 0]; if (Colinear(point, pointB, targetPointB)) { output += 1f; } } } } } return(Mathf.Clamp01(output)); }
// Use this for initialization void Start() { FloorSegment = this.GetComponentInParent<FloorSegment>(); }
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); // } }
private void DrawData(int tileSize) { // Draw the floorplan MainCanvas.Children.Clear(); for (int top = 0; top < fpHeight; top++) { for (int left = 0; left < fpWidth; left++) { if (fp.floorGrid[top, left] != null) { FloorSegment thisSegment = fp.floorGrid[top, left]; if (!colorDict.ContainsKey(thisSegment.GroupID)) { colorDict.Add(thisSegment.GroupID, PickBrush()); } Rectangle newRect = new Rectangle() { Width = tileSize, Height = tileSize, Fill = colorDict[thisSegment.GroupID] }; RenderOptions.SetEdgeMode(newRect, EdgeMode.Aliased); // Draw the lines between squares if they belong to different rooms FloorSegment northSegment = fp.IsInBounds(top - 1, left) ? fp.floorGrid[top - 1, left] : null; bool drawNorthLine = northSegment == null ? true : (northSegment.RoomID != thisSegment.RoomID) ? true : false; if (drawNorthLine) { Line newLine = new Line() { Stroke = Brushes.Black, StrokeThickness = 2, X1 = left * tileSize, Y1 = top * tileSize, X2 = (left * tileSize) + tileSize, Y2 = top * tileSize }; MainCanvas.Children.Add(newLine); } FloorSegment westSegment = fp.IsInBounds(top, left - 1) ? fp.floorGrid[top, left - 1] : null; bool drawWestLine = westSegment == null ? true : (westSegment.RoomID != thisSegment.RoomID) ? true : false; if (drawWestLine) { Line newLine = new Line() { Stroke = Brushes.Black, StrokeThickness = 2, X1 = left * tileSize, Y1 = top * tileSize, X2 = left * tileSize, Y2 = (top * tileSize) + tileSize }; MainCanvas.Children.Add(newLine); } FloorSegment eastSegment = fp.IsInBounds(top, left + 1) ? fp.floorGrid[top, left + 1] : null; bool drawEastLine = eastSegment == null ? true : (eastSegment.RoomID != thisSegment.RoomID) ? true : false; if (drawEastLine) { Line newLine = new Line() { Stroke = Brushes.Black, StrokeThickness = 2, X1 = (left * tileSize) + tileSize, Y1 = top * tileSize, X2 = (left * tileSize) + tileSize, Y2 = (top * tileSize) + tileSize }; MainCanvas.Children.Add(newLine); } FloorSegment southSegment = fp.IsInBounds(top + 1, left) ? fp.floorGrid[top + 1, left] : null; bool drawSouthLine = southSegment == null ? true : (southSegment.RoomID != thisSegment.RoomID) ? true : false; if (drawSouthLine) { Line newLine = new Line() { Stroke = Brushes.Black, StrokeThickness = 2, X1 = left * tileSize, Y1 = (top * tileSize) + tileSize, X2 = (left * tileSize) + tileSize, Y2 = (top * tileSize) + tileSize }; MainCanvas.Children.Add(newLine); } MainCanvas.Children.Add(newRect); Canvas.SetLeft(newRect, left * tileSize); Canvas.SetTop(newRect, top * tileSize); if (drawRoomNumbers) { TextBlock tbRoomNum = new TextBlock(); tbRoomNum.Inlines.Add(new Run(fp.floorGrid[top, left].RoomID.ToString())); RenderOptions.SetEdgeMode(tbRoomNum, EdgeMode.Aliased); MainCanvas.Children.Add(tbRoomNum); Canvas.SetLeft(tbRoomNum, left * tileSize + 6); Canvas.SetTop(tbRoomNum, top * tileSize + 6); } else if (drawGroupNumbers) { TextBlock tbGroupNum = new TextBlock(); tbGroupNum.Inlines.Add(new Run(fp.floorGrid[top, left].GroupID.ToString())); RenderOptions.SetEdgeMode(tbGroupNum, EdgeMode.Aliased); MainCanvas.Children.Add(tbGroupNum); Canvas.SetLeft(tbGroupNum, left * tileSize + 6); Canvas.SetTop(tbGroupNum, top * tileSize + 6); } else if (drawCorridorGroups) { TextBlock tbGroupNum = new TextBlock(); HashSet <string> groupValues = fp.floorGrid[top, left].ConnectedCorridorIDs; if (groupValues.Count > 0) { string groupCSV = String.Join(",", groupValues.Select(x => x.ToString()).ToArray()); tbGroupNum.Inlines.Add(new Run(groupCSV)); RenderOptions.SetEdgeMode(tbGroupNum, EdgeMode.Aliased); MainCanvas.Children.Add(tbGroupNum); Canvas.SetLeft(tbGroupNum, left * tileSize + 6); Canvas.SetTop(tbGroupNum, top * tileSize + 6); } } } } } // Draw the remaining eligible segments if (fp.pause) { foreach (DirectionalSegment ds in fp.eligibleFloorSegments) { Rectangle newRect = new Rectangle() { Width = tileSize, Height = tileSize, Stroke = Brushes.Black, StrokeThickness = 1 }; MainCanvas.Children.Add(newRect); Canvas.SetLeft(newRect, ds.Left * tileSize); Canvas.SetTop(newRect, ds.Top * tileSize); } } // Signal the algorithm to continue fp.waitEvent.Set(); labelCountRoom.Content = fp.currRoomID.ToString(); }
private void DrawHallways(int tileSize, int hallwaySize) { // Create a path for drawing the hallways Path hallwayPath = new Path(); hallwayPath.Stroke = Brushes.Black; hallwayPath.StrokeThickness = 1; SolidColorBrush mySolidColorBrush = new SolidColorBrush(); mySolidColorBrush.Color = Colors.White; hallwayPath.Fill = mySolidColorBrush; // Use a composite geometry for adding the hallways to CombinedGeometry hallwayGeometryGroup = new CombinedGeometry(); hallwayGeometryGroup.GeometryCombineMode = GeometryCombineMode.Union; hallwayGeometryGroup.Geometry1 = null; hallwayGeometryGroup.Geometry2 = null; for (int top = 0; top < fpHeight; top++) { for (int left = 0; left < fpWidth; left++) { if (fp.floorGrid[top, left] != null) { FloorSegment thisSegment = fp.floorGrid[top, left]; // If the segment above is in bounds and from a different group, we draw a hallway. // Otherwise, if it's a different room of the same group, we draw a wall. FloorSegment northSegment = fp.IsInBounds(top - 1, left) ? fp.floorGrid[top - 1, left] : null; if (northSegment != null) { if (northSegment.GroupID != thisSegment.GroupID) { RectangleGeometry newHallwayGeometry = new RectangleGeometry( new Rect( (left * tileSize) - (hallwaySize / 2), (top * tileSize) - (hallwaySize / 2), tileSize + hallwaySize, hallwaySize)); hallwayGeometryGroup = new CombinedGeometry() { Geometry1 = hallwayGeometryGroup, Geometry2 = newHallwayGeometry }; } } FloorSegment southSegment = fp.IsInBounds(top + 1, left) ? fp.floorGrid[top + 1, left] : null; if (southSegment != null) { if (southSegment.GroupID != thisSegment.GroupID) { RectangleGeometry newHallwayGeometry = new RectangleGeometry( new Rect( (left * tileSize) - (hallwaySize / 2), ((top * tileSize) + tileSize) - (hallwaySize / 2), tileSize + hallwaySize, hallwaySize)); hallwayGeometryGroup = new CombinedGeometry() { Geometry1 = hallwayGeometryGroup, Geometry2 = newHallwayGeometry }; } } FloorSegment eastSegment = fp.IsInBounds(top, left + 1) ? fp.floorGrid[top, left + 1] : null; if (eastSegment != null) { if (eastSegment.GroupID != thisSegment.GroupID) { RectangleGeometry newHallwayGeometry = new RectangleGeometry( new Rect( ((left * tileSize) + tileSize) - (hallwaySize / 2), (top * tileSize) - (hallwaySize / 2), hallwaySize, tileSize + hallwaySize)); hallwayGeometryGroup = new CombinedGeometry() { Geometry1 = hallwayGeometryGroup, Geometry2 = newHallwayGeometry }; } } FloorSegment westSegment = fp.IsInBounds(top, left - 1) ? fp.floorGrid[top, left - 1] : null; if (westSegment != null) { if (westSegment.GroupID != thisSegment.GroupID) { RectangleGeometry newHallwayGeometry = new RectangleGeometry( new Rect( (left * tileSize) - (hallwaySize / 2), (top * tileSize) - (hallwaySize / 2), hallwaySize, tileSize + hallwaySize)); hallwayGeometryGroup = new CombinedGeometry() { Geometry1 = hallwayGeometryGroup, Geometry2 = newHallwayGeometry }; } } } } } hallwayPath.Data = hallwayGeometryGroup; RenderOptions.SetEdgeMode(hallwayPath, EdgeMode.Aliased); MainCanvas.Children.Add(hallwayPath); // Draw the remaining eligible segments if (fp.pause) { foreach (DirectionalSegment ds in fp.eligibleFloorSegments) { Rectangle newRect = new Rectangle() { Width = tileSize, Height = tileSize, Stroke = Brushes.Black, StrokeThickness = 1 }; MainCanvas.Children.Add(newRect); Canvas.SetLeft(newRect, ds.Left * tileSize); Canvas.SetTop(newRect, ds.Top * tileSize); } } // Signal the algorithm to continue fp.waitEvent.Set(); labelCountRoom.Content = fp.currRoomID.ToString(); }
private void DrawDoors(int tileSize, int hallwaySize) { // Create a path for drawing the hallways Path doorsPath = new Path(); doorsPath.Stroke = Brushes.Black; doorsPath.StrokeThickness = 1; SolidColorBrush mySolidColorBrush = new SolidColorBrush(); mySolidColorBrush.Color = Colors.Black; doorsPath.Fill = mySolidColorBrush; // Use a composite geometry for adding the doors to CombinedGeometry doorsGeometryGroup = new CombinedGeometry(); doorsGeometryGroup.GeometryCombineMode = GeometryCombineMode.Union; doorsGeometryGroup.Geometry1 = null; doorsGeometryGroup.Geometry2 = null; for (int top = 0; top < fpHeight; top++) { for (int left = 0; left < fpWidth; left++) { if (fp.floorGrid[top, left] != null) { FloorSegment thisSegment = fp.floorGrid[top, left]; double doorX = 0; double doorY = 0; double doorWidth = 0; double doorHeight = 0; // position the doors differently depending on weather or not there's a hallway. Math, bitches. foreach (enumDirection nextDoorDir in thisSegment.Doors) { switch (nextDoorDir) { case enumDirection.North: FloorSegment northSegment = fp.IsInBounds(top - 1, left) ? fp.floorGrid[top - 1, left] : null; doorX = (left * tileSize) + (tileSize / 2) - (hallwaySize / 2); doorY = northSegment != null ? northSegment.GroupID != thisSegment.GroupID ? (top * tileSize) + (hallwaySize / 4) : (top * tileSize) - (hallwaySize / 4) : (top * tileSize) - (hallwaySize / 4); doorWidth = hallwaySize; doorHeight = hallwaySize / 2; break; case enumDirection.South: FloorSegment southSegment = fp.IsInBounds(top + 1, left) ? fp.floorGrid[top + 1, left] : null; doorX = (left * tileSize) + (tileSize / 2) - (hallwaySize / 2); doorY = southSegment != null ? southSegment.GroupID != thisSegment.GroupID ? ((top * tileSize) + tileSize) - ((hallwaySize / 4) * 3) : ((top * tileSize) + tileSize) - (hallwaySize / 4) : ((top * tileSize) + tileSize) - (hallwaySize / 4); doorWidth = hallwaySize; doorHeight = hallwaySize / 2; break; case enumDirection.East: FloorSegment eastSegment = fp.IsInBounds(top, left + 1) ? fp.floorGrid[top, left + 1] : null; doorX = eastSegment != null ? eastSegment.GroupID != thisSegment.GroupID ? ((left * tileSize) + tileSize) - ((hallwaySize / 4) * 3) : ((left * tileSize) + tileSize) - (hallwaySize / 4) : ((left * tileSize) + tileSize) - (hallwaySize / 4); doorY = (top * tileSize) + (tileSize / 2) - (hallwaySize / 2); doorWidth = hallwaySize / 2; doorHeight = hallwaySize; break; case enumDirection.West: FloorSegment westSegment = fp.IsInBounds(top, left - 1) ? fp.floorGrid[top, left - 1] : null; doorX = westSegment != null ? westSegment.GroupID != thisSegment.GroupID ? (left * tileSize) + (hallwaySize / 4) : (left * tileSize) - (hallwaySize / 4) : (left * tileSize) - (hallwaySize / 4); doorY = (top * tileSize) + (tileSize / 2) - (hallwaySize / 2); doorWidth = hallwaySize / 2; doorHeight = hallwaySize; break; } RectangleGeometry newDoorGeometry = new RectangleGeometry(new Rect(doorX, doorY, doorWidth, doorHeight)); doorsGeometryGroup = new CombinedGeometry() { Geometry1 = doorsGeometryGroup, Geometry2 = newDoorGeometry }; } } } } doorsPath.Data = doorsGeometryGroup; RenderOptions.SetEdgeMode(doorsPath, EdgeMode.Aliased); MainCanvas.Children.Add(doorsPath); }