/// <summary> /// Tests if a point is contained within this profile. Returns false for points that are outside of the profile (or within voids). /// </summary> /// <param name="point">The position to test.</param> /// <param name="containment">Whether the point is inside, outside, at an edge, or at a vertex.</param> /// <returns>True if the point is within the profile.</returns> public bool Contains(Vector3 point, out Containment containment) { IEnumerable <Line> allLines = Perimeter.Segments(); if (Voids != null) { allLines = allLines.Union(Voids.SelectMany(v => v.Segments())); } return(Polygon.Contains(allLines, point, out containment)); }
/// <summary> /// Moves all Rooms along a 3D vector calculated between the supplied Vector3 points. /// </summary> /// <param name="from">Vector3 base point of the move.</param> /// <param name="to">Vector3 target point of the move.</param> /// <returns> /// None. /// </returns> public void MoveFromTo(Vector3 from, Vector3 to) { foreach (Room room in Rooms) { room.MoveFromTo(from, to); } Perimeter = Perimeter.MoveFromTo(from, to); var ang = Perimeter.Segments().OrderByDescending(s => s.Length()).ToList().First(); Angle = Math.Atan2(ang.End.Y - ang.Start.Y, ang.End.X - ang.Start.X) * (180 / Math.PI); perimeterJig = Perimeter.Rotate(Vector3.Origin, Angle * -1); compass = perimeterJig.Compass(); insert.MoveFromTo(from, to); Row = new Line(compass.SW, compass.SE).Rotate(Vector3.Origin, Angle); }
/// <summary> /// Get all segments from a profile's perimeter and internal voids. /// </summary> public List <Line> Segments() { return(Perimeter.Segments().Union(Voids?.SelectMany(v => v.Segments()) ?? new Line[0]).ToList()); }
/// <summary> /// Creates a grid network of corridors within the Story and returns a list of spatially sorted RoomRows ready for population. /// </summary> /// <param name="rowLength">Distance between cross corridors.</param> /// <param name="roomDepth">Desired depth of Rooms.</param> /// <param name="corridorWidth">Width of all corridors.</param> /// <returns>A List of RoomRow</returns> public List <RoomRow> PlanGrid(double rowLength, double rowDepth, double corridorWidth = 3.0, bool split = true) { Corridors.Clear(); Rooms.Clear(); rowLength = rowLength.NearEqual(0.0) ? 1.0 : Math.Abs(rowLength); rowDepth = rowLength.NearEqual(0.0) ? 1.0 : Math.Abs(rowDepth); corridorWidth = rowLength.NearEqual(0.0) ? 1.0 : Math.Abs(corridorWidth); var row = Perimeter.Segments().OrderByDescending(s => s.Length()).First(); var ang = Math.Atan2(row.End.Y - row.Start.Y, row.End.X - row.Start.X) * (180 / Math.PI); var perimeterJig = Perimeter.Rotate(Vector3.Origin, ang * -1); var grid = new Grid2d(perimeterJig); grid.U.DivideByFixedLength(rowLength, FixedDivisionMode.RemainderAtBothEnds); grid.V.DivideByFixedLength(rowDepth, FixedDivisionMode.RemainderAtBothEnds); var uLines = grid.GetCellSeparators(GridDirection.U).Skip(1).Reverse().Skip(1).Reverse(); var vLines = grid.GetCellSeparators(GridDirection.V).Skip(1).Reverse().Skip(1).Reverse(); var ctrLines = new List <Line>(); foreach (var curve in uLines) { ctrLines.Add((Line)curve); } foreach (var curve in vLines) { ctrLines.Add((Line)curve); } foreach (var line in ctrLines) { var corridor = line.Thicken(corridorWidth); if (perimeterJig.Compass().Box.Covers(corridor)) { AddCorridor(new Room(corridor.Rotate(Vector3.Origin, ang), Height)); } } foreach (var cell in grid.CellsFlat) { var polygon = (Polygon)cell.GetCellGeometry(); var compass = polygon.Compass(); if (split) { var north = Polygon.Rectangle(compass.W, compass.NE).Rotate(Vector3.Origin, ang); var south = Polygon.Rectangle(compass.SW, compass.E).Rotate(Vector3.Origin, ang); AddRoom(new Room(north, Height)); AddRoom(new Room(south, Height)); continue; } else if (Math.Abs(compass.SizeY - rowDepth) <= 0.0001) { AddRoom(new Room(polygon.Rotate(Vector3.Origin, ang), Height)); } } var roomRows = new List <RoomRow>(); foreach (var room in Rooms) { roomRows.Add(new RoomRow(room.Perimeter)); } Rooms.Clear(); return(roomRows); }
/// <summary> /// Creates a Room plan from a Polygon centerline as the double-loaded corridor. Assumes sides of the Story Perimeter are parallel to the centerline. /// </summary> /// <param name="ctrLine">Polyline centerline of the Corridor.</param> /// <param name="roomArea">Desired area of each Room.</param> /// <param name="corridorWidth">Width of the Corridor.</param> /// <param name="corridorOffset">Offset of the Corridor end from the Perimeter.</param> public void PlanByCenterline(Polyline ctrLine, double roomArea, double corridorWidth, double corridorOffset) { var perLines = Perimeter.Segments(); var ctrLines = ctrLine.Segments(); var rows = new List <Polygon>(); foreach (var line in ctrLines) { var sides = new List <Line>(); foreach (var perLine in perLines) { if (perLine.IsParallelTo(line)) { sides.Add(perLine); } } if (sides.Count() < 2) { continue; } sides = sides.OrderBy(s => s.Midpoint().DistanceTo(line.Midpoint())).ToList(); sides = new List <Line>() { sides[0], sides[1] }; foreach (var side in sides) { var points = new List <Vector3>(); foreach (var vertex in new List <Vector3>() { line.Start, line.End, side.Start, side.End }) { points.Add(new Vector3(vertex.X, vertex.Y, 0.0)); } Polygon polygon; try { polygon = new Polygon(points); } catch (Exception) { polygon = new Polygon(new[] { points[0], points[1], points[3], points[2] }); } rows.Add(polygon); } } foreach (var row in rows) { var roomRow = new RoomRow(row); roomRow.Populate(roomArea, Height); foreach (var room in roomRow.Rooms) { AddRoom(room); } } var ctrPnts = new List <Vector3>() { ctrLines.First().PositionAt(corridorOffset) }; foreach (var line in ctrLines) { ctrPnts.Add(line.End); } ctrPnts.Reverse(); ctrPnts = ctrPnts.Skip(1).ToList(); ctrPnts.Reverse(); ctrPnts.Add(ctrLines.Last().PositionAt(ctrLines.Last().Length() - corridorOffset)); var ctrCorridor = new Polyline(ctrPnts); var corridor = new Room(ctrCorridor.Offset(corridorWidth * 0.5, EndType.Square).First(), Height); AddCorridor(corridor); }