Exemple #1
0
        public override string SolvePart2()
        {
            var step = 0;

            while (grid.GetCells(c => c.Value == 0).Count != grid.Count)
            {
                DoFlashes();
                step++;
            }

            return(step.ToString());
        }
Exemple #2
0
        public static void DrawGrid(Model model, Grid2d grid, List <Vector3> uPoints, List <Vector3> vPoints)
        {
            foreach (var cell in grid.GetCells())
            {
                var polygon = (Polygon)cell.GetCellGeometry();
                foreach (var vertex in polygon.Vertices)
                {
                    Debug.DrawPoint(model, vertex, MagentaMaterial);
                }
                var color = RandomExtensions.NextColor(random);
                foreach (var cellPiece in cell.GetTrimmedCellGeometry())
                {
                    var material = new Material(color.ToString(), new Color(color.Red, color.Green, color.Blue, 0.5), unlit: true);
                    var poly     = (Polygon)cellPiece;
                    if (poly.Vertices.Count >= 3)
                    {
                        model.AddElement(new Panel(poly, material: material));
                    }
                }
            }

            foreach (var pt in vPoints)
            {
                Debug.DrawPoint(model, pt, MagentaMaterial);
            }
            foreach (var pt in uPoints)
            {
                Debug.DrawPoint(model, pt, MagentaMaterial);
            }
        }
Exemple #3
0
        public void TrimBehavior()
        {
            Name = "TrimBehavior";
            var polygonjson = "[{\"discriminator\":\"Elements.Geometry.Polygon\",\"Vertices\":[{\"X\":-14.371519985751306,\"Y\":-4.8816304299427005,\"Z\":0.0},{\"X\":-17.661873645682569,\"Y\":9.2555712951713573,\"Z\":0.0},{\"X\":12.965610421927806,\"Y\":9.2555712951713573,\"Z\":0.0},{\"X\":12.965610421927806,\"Y\":3.5538269529982784,\"Z\":0.0},{\"X\":6.4046991240848143,\"Y\":3.5538269529982784,\"Z\":0.0},{\"X\":1.3278034769444158,\"Y\":-4.8816304299427005,\"Z\":0.0}]},{\"discriminator\":\"Elements.Geometry.Polygon\",\"Vertices\":[{\"X\":-9.4508365123690652,\"Y\":0.20473478280229102,\"Z\":0.0},{\"X\":-1.8745460850979974,\"Y\":0.20473478280229102,\"Z\":0.0},{\"X\":-1.8745460850979974,\"Y\":5.4378426037008651,\"Z\":0.0},{\"X\":-9.4508365123690652,\"Y\":5.4378426037008651,\"Z\":0.0}]}]\r\n";
            var polygons    = JsonConvert.DeserializeObject <List <Polygon> >(polygonjson);
            var grid        = new Grid2d(polygons);

            foreach (var pt in polygons[1].Vertices)
            {
                grid.SplitAtPoint(pt);
            }
            grid.CellsFlat.ForEach(c => c.U.DivideByApproximateLength(1.0, EvenDivisionMode.RoundDown));

            var trimmedCells = grid.GetCells().Select(c =>
                                                      (TrimmedGeometry: c.GetTrimmedCellGeometry(),
                                                       BaseRect: c.GetCellGeometry(),
                                                       IsTrimmed: c.IsTrimmed()));

            foreach (var trimGeometry in trimmedCells)
            {
                var trimGeo  = trimGeometry.TrimmedGeometry.OfType <Polygon>();
                var material = trimGeometry.IsTrimmed ? BuiltInMaterials.XAxis : BuiltInMaterials.ZAxis;
                foreach (var t in trimGeo)
                {
                    Model.AddElement(new ModelCurve(t));
                    Model.AddElement(new Mass(t, 1, material, new Transform(0, 0, -1.001)));
                }
            }
            Assert.Equal(87, trimmedCells.Count());
            Assert.Equal(18, trimmedCells.Count(c => c.IsTrimmed));
        }
Exemple #4
0
        public void Grid2d()
        {
            this.Name = "Elements_Spatial_Grid2d";

            // <example>
            // Create a 2d grid that's 40 x 30 in size
            var grid = new Grid2d(40, 30);

            // Access the U and V axes directly and use 1d subdivision methods on them
            grid.U.DivideByFixedLength(7, FixedDivisionMode.RemainderAtBothEnds);
            grid.V.DivideByPattern(new[] { 2.0, 5.0 });

            // Get a row by index
            var fifthRow = grid.GetRowAtIndex(4);

            // Divide U axis of all cells in row into panels of approximate width 1
            fifthRow.ForEach(c => c.U.DivideByApproximateLength(1));

            // Get a cell by u, v indices
            var cell = grid[1, 1];

            // Divide the cell in the V direction
            cell.V.DivideByCount(4);

            // Create a floor from the entire grid's boundary
            var floor = new Floor(new Profile((Polygon)grid.GetCellGeometry()), 0.5, new Transform(0, 0, -0.51));

            // Create model curves from all subdivided cells of the grid
            var modelCurves = grid.GetCells().Select(c => new ModelCurve(c.GetCellGeometry()));

            // </example>

            Model.AddElement(floor);
            Model.AddElements(modelCurves);
        }
        /// <summary>
        /// Construct a set of elements from this rule for a given definition.
        /// </summary>
        /// <param name="definition">The definition to instantiate.</param>
        public List <Element> Instantiate(ComponentDefinition definition)
        {
            var arrayElements = new List <Element>();
            var newVertices   = PolylinePlacementRule.TransformPolyline(this, definition);

            var path = new Polygon(newVertices);

            var grid2d = new Grid2d(path, definition.OrientationGuide);

            GridCreationRule(grid2d);

            var cells = grid2d.GetCells().Where(c => !c.IsTrimmed()).SelectMany(c => c.GetTrimmedCellGeometry()).OfType <Polygon>().Where(c => c.Area().ApproximatelyEquals(CellDefinition.CellLength * CellDefinition.CellWidth));

            foreach (var element in CellDefinition.Elements)
            {
                foreach (var cell in cells)
                {
                    var transform = new Transform(element.Transform);
                    transform.Concatenate(definition.OrientationGuide);
                    transform.Concatenate(new Transform(cell.Vertices[2]));
                    element.IsElementDefinition = true;
                    var instance = element.CreateInstance(transform, null);
                    arrayElements.Add(instance);
                }
            }

            arrayElements.AddRange(cells.Select(c => new ModelCurve(c)));
            return(arrayElements);
        }
Exemple #6
0
        public void Grid2dSerializes()
        {
            Name = "grid2d serializes";
            var polyline = new Polyline(new[] {
                new Vector3(0, 0, 0),
                new Vector3(10, 2, 0),
                new Vector3(30, 4, 0),
            });
            var uGrid  = new Grid1d(polyline);
            var p2     = new Line(Vector3.Origin, new Vector3(0, 20, 0));
            var vGrid  = new Grid1d(p2);
            var grid2d = new Grid2d(uGrid, vGrid);

            grid2d.U.DivideByCount(10);
            grid2d.V.DivideByCount(3);
            grid2d[2, 2].U.DivideByCount(4);
            var json         = JsonConvert.SerializeObject(grid2d);
            var deserialized = JsonConvert.DeserializeObject <Grid2d>(json);

            Assert.Equal(grid2d.GetCells().Count, deserialized.GetCells().Count);

            var grid2dElem = new Grid2dElement(grid2d, Guid.NewGuid(), "Grid");

            Model.AddElement(grid2dElem);
        }
Exemple #7
0
        public void CellComplexExample()
        {
            this.Name = "Elements_Spatial_CellComplex_CellComplex";

            // <example>

            // Assemble CellComplex from Grid2d
            var numLevels    = 10;
            var levelHeight  = 1;
            var cellSize     = 2;
            var complex      = new CellComplex();
            var boundary     = new Circle(new Vector3(), 10).ToPolygon();
            var grid         = new Grid2d(boundary, Vector3.Origin, Vector3.XAxis, Vector3.YAxis);
            var pathMaterial = new Material("Path", new Color(1, 0, 0, 0.75));

            grid.U.DivideByFixedLength(cellSize);
            grid.V.DivideByFixedLength(cellSize);


            for (var i = 0; i < numLevels; i++)
            {
                foreach (var cell in grid.GetCells())
                {
                    foreach (var crv in cell.GetTrimmedCellGeometry())
                    {
                        complex.AddCell((Polygon)crv, levelHeight, i * levelHeight, grid.U, grid.V);
                    }
                }
            }

            // Draw base CellComplex
            foreach (var face in complex.GetFaces())
            {
                this.Model.AddElement(new Panel(face.GetGeometry(), BuiltInMaterials.Mass));
            }

            // Traverse CellComplex
            var start = new Vector3(15, 15, 15);
            var end   = new Vector3(-15, -15, -15);

            // Draw lines from start and end to closest points, for reference
            foreach (var pt in new List <Vector3>()
            {
                start, end
            })
            {
                var closest = complex.GetClosestVertex(pt).GetGeometry();
                this.Model.AddElement(new ModelCurve(new Line(pt, closest), pathMaterial));
            }

            var curCell        = complex.GetClosestCell(start);
            var traversedCells = curCell.TraverseNeighbors(end);

            foreach (var cell in traversedCells)
            {
                var rep = new Representation(new[] { cell.GetGeometry() });
                this.Model.AddElement(new GeometricElement(new Transform(), pathMaterial, rep, false, Guid.NewGuid(), "Path"));
            }
            // </example>
        }
Exemple #8
0
        /// <summary>
        /// The ReceptionLayout function.
        /// </summary>
        /// <param name="model">The input model.</param>
        /// <param name="input">The arguments to the execution.</param>
        /// <returns>A ReceptionLayoutOutputs instance containing computed results and the model with any new elements.</returns>
        public static ReceptionLayoutOutputs Execute(Dictionary <string, Model> inputModels, ReceptionLayoutInputs input)
        {
            var         spacePlanningZones = inputModels["Space Planning Zones"];
            var         levelsModel        = inputModels["Levels"];
            var         levels             = spacePlanningZones.AllElementsOfType <LevelElements>();
            var         levelVolumes       = levelsModel.AllElementsOfType <LevelVolume>();
            var         output             = new ReceptionLayoutOutputs();
            var         configJson         = File.ReadAllText("./ReceptionConfigurations.json");
            var         configs            = JsonConvert.DeserializeObject <SpaceConfiguration>(configJson);
            var         hasCore            = inputModels.TryGetValue("Core", out var coresModel);
            List <Line> coreSegments       = new List <Line>();

            if (coresModel != null)
            {
                coreSegments.AddRange(coresModel.AllElementsOfType <ServiceCore>().SelectMany(c => c.Profile.Perimeter.Segments()));
            }
            foreach (var lvl in levels)
            {
                var corridors           = lvl.Elements.OfType <Floor>();
                var corridorSegments    = corridors.SelectMany(p => p.Profile.Segments());
                var meetingRmBoundaries = lvl.Elements.OfType <SpaceBoundary>().Where(z => z.Name == "Reception");
                var levelVolume         = levelVolumes.First(l => l.Name == lvl.Name);
                foreach (var room in meetingRmBoundaries)
                {
                    var  spaceBoundary        = room.Boundary;
                    Line orientationGuideEdge = hasCore ? FindEdgeClosestToCore(spaceBoundary.Perimeter, coreSegments) : FindEdgeAdjacentToSegments(spaceBoundary.Perimeter.Segments(), corridorSegments, out var wallCandidates);
                    var  orientationTransform = new Transform(Vector3.Origin, orientationGuideEdge.Direction(), Vector3.ZAxis);
                    var  boundaryCurves       = new List <Polygon>();
                    boundaryCurves.Add(spaceBoundary.Perimeter);
                    boundaryCurves.AddRange(spaceBoundary.Voids ?? new List <Polygon>());

                    var grid = new Grid2d(boundaryCurves, orientationTransform);
                    foreach (var cell in grid.GetCells())
                    {
                        var rect       = cell.GetCellGeometry() as Polygon;
                        var segs       = rect.Segments();
                        var width      = segs[0].Length();
                        var depth      = segs[1].Length();
                        var trimmedGeo = cell.GetTrimmedCellGeometry();
                        if (!cell.IsTrimmed() && trimmedGeo.Count() > 0)
                        {
                            output.Model.AddElement(InstantiateLayout(configs, width, depth, rect, room.Transform));
                        }
                        else if (trimmedGeo.Count() > 0)
                        {
                            var largestTrimmedShape = trimmedGeo.OfType <Polygon>().OrderBy(s => s.Area()).Last();
                            var cinchedVertices     = rect.Vertices.Select(v => largestTrimmedShape.Vertices.OrderBy(v2 => v2.DistanceTo(v)).First()).ToList();
                            var cinchedPoly         = new Polygon(cinchedVertices);
                            // output.Model.AddElement(new ModelCurve(cinchedPoly, BuiltInMaterials.ZAxis, levelVolume.Transform));
                            output.Model.AddElement(InstantiateLayout(configs, width, depth, cinchedPoly, room.Transform));
                            Console.WriteLine("­ЪциРђЇРЎѓ№ИЈ funny shape!!!");
                        }
                    }
                }
            }
            InstancePositionOverrides(input.Overrides, output.Model);
            return(output);
        }
Exemple #9
0
        // Utility
        private static CellComplex MakeASimpleCellComplex(
            double uCellSize              = 10,
            double vCellSize              = 10,
            double uNumCells              = 5,
            double vNumCells              = 5,
            double cellHeight             = 5,
            double numLevels              = 3,
            Nullable <Vector3> origin     = null,
            Nullable <Vector3> uDirection = null,
            Nullable <Vector3> vDirection = null,
            Polygon polygon = null
            )
        {
            var orig = origin == null ? new Vector3() : (Vector3)origin;
            var uDir = uDirection == null ? new Vector3(1, 0, 0) : ((Vector3)uDirection).Unitized();
            var vDir = vDirection == null ? new Vector3(0, 1, 0) : ((Vector3)vDirection).Unitized();

            var uLength = orig.X + uCellSize * uNumCells;
            var vLength = orig.Y + vCellSize * vNumCells;

            // Create Grid2d
            var boundary = polygon == null?Polygon.Rectangle(orig, new Vector3(uLength, vLength)) : polygon;

            // Using constructor with origin
            var grid = new Grid2d(boundary, orig, uDir, vDir);

            for (var u = uCellSize; u < uLength; u += uCellSize)
            {
                grid.SplitAtPoint(orig + (uDir * u));
            }
            for (var v = vCellSize; v < vLength; v += vCellSize)
            {
                grid.SplitAtPoint(orig + (vDir * v));
            }

            var cellComplex = new CellComplex(Guid.NewGuid(), "Test");

            for (var i = 0; i < numLevels; i++)
            {
                foreach (var cell in grid.GetCells())
                {
                    foreach (var crv in cell.GetTrimmedCellGeometry())
                    {
                        cellComplex.AddCell((Polygon)crv, 5, cellHeight * i, grid.U, grid.V);
                    }
                }
            }
            return(cellComplex);
        }
Exemple #10
0
        private HashSet <Edge> AddFromGrid(Grid2d grid, IEnumerable <Edge> edgesToIntersect)
        {
            var cells          = grid.GetCells();
            var addedEdges     = new HashSet <Edge>();
            var edgeCandidates = new HashSet <(ulong, ulong)>();

            Action <Vector3, Vector3> add = (Vector3 start, Vector3 end) =>
            {
                var v0 = AddVertex(start);
                var v1 = AddVertex(end);
                if (v0 != v1)
                {
                    var pair = v0.Id < v1.Id ? (v0.Id, v1.Id) : (v1.Id, v0.Id);
                    edgeCandidates.Add(pair);
                }
Exemple #11
0
        public void GenerateAndSubdivide2d()
        {
            var grid = new Grid2d(10, 10);

            grid.U.SplitAtPosition(2);
            grid.U.SplitAtPosition(7);
            grid.V.SplitAtPosition(5);
            var subGrid = grid[1, 0];

            subGrid.U.DivideByCount(5);
            var subGrid2 = grid[1, 1];

            subGrid2.V.DivideByFixedLengthFromPosition(0.5, 8);

            Assert.Equal(6, grid.CellsFlat.Count);
            Assert.Equal(19, grid.GetCells().Count);
        }
Exemple #12
0
        public void TrimmedCellProfileAfterSplitting()
        {
            var outer = new Polygon(new List <Vector3> {
                new Vector3(0, 0, 0), new Vector3(10, 0, 0), new Vector3(10, 0, 10), new Vector3(0, 0, 10)
            });
            var inner1 = new Polygon(new List <Vector3> {
                new Vector3(3, 0, 9), new Vector3(3, 0, 7), new Vector3(1, 0, 7), new Vector3(1, 0, 9)
            });
            var inner2 = new Polygon(new List <Vector3> {
                new Vector3(9, 0, 3), new Vector3(9, 0, 1), new Vector3(7, 0, 1), new Vector3(7, 0, 3)
            });
            var inner3 = new Polygon(new List <Vector3> {
                new Vector3(6, 0, 6), new Vector3(6, 0, 3), new Vector3(3, 0, 3), new Vector3(3, 0, 6)
            });


            var polygons = new List <Polygon>();

            polygons.Add(outer);
            polygons.Add(inner1);
            polygons.Add(inner2);
            polygons.Add(inner3);
            var grid = new Grid2d(polygons);

            grid.SplitAtPoints(new List <Vector3> {
                new Vector3(4, 0, 0), new Vector3(6, 0, 0)
            });
            var cells = grid.GetCells();

            var cell     = cells[0];
            var profiles = cell.GetTrimmedCellProfiles();

            Assert.Single(profiles);
            Assert.Single(profiles.First().Voids);

            cell     = cells[1];
            profiles = cell.GetTrimmedCellProfiles();
            Assert.Equal(2, profiles.Count());
            Assert.Empty(profiles.First().Voids);
            Assert.Empty(profiles.Last().Voids);

            cell     = cells[2];
            profiles = cell.GetTrimmedCellProfiles();
            Assert.Single(profiles);
            Assert.Single(profiles.First().Voids);
        }
Exemple #13
0
        public void NoExceptionsThrownWithAnyRotation()
        {
            for (int rotation = 0; rotation < 360; rotation += 10)
            {
                var a = new Vector3(0.03, 5.08);
                var b = new Vector3(4.28, 9.80);
                var c = new Vector3(9.69, 9.50);
                var d = new Vector3(9.63, 2.43);
                var e = new Vector3(4.72, -0.86);
                var f = new Vector3(1.78, -0.75);

                var polygon = new Polygon(new[] { a, b, c, d, e, f });

                var g = new Vector3(7.735064, 5.746821);
                var h = new Vector3(6.233137, 7.248748);
                var i = new Vector3(3.660163, 4.675775);
                var j = new Vector3(5.162091, 3.173848);

                var polygon2 = new Polygon(new[] { g, h, i, j });

                var alignment = new Transform();
                alignment.Rotate(Vector3.ZAxis, 45);
                var grid = new Grid2d(new[] { polygon, polygon2 }, alignment);
                grid.U.DivideByCount(10);
                var panelA   = ("A", 1.0);
                var panelB   = ("B", 0.5);
                var panelC   = ("C", 1.5);
                var pattern  = new[] { panelA, panelB, panelC };
                var pattern2 = new[] { panelB, panelA };
                var patterns = new[] { pattern, pattern2 };

                for (int index = 0; index < grid.CellsFlat.Count; index++)
                {
                    var vDomain = grid.CellsFlat[index].V.Domain;
                    var start   = 0.1.MapToDomain(vDomain);
                    grid.CellsFlat[index].V.DivideByPattern(patterns[index % patterns.Count()], PatternMode.Cycle, FixedDivisionMode.RemainderAtBothEnds);
                }
                var cells   = grid.GetCells();
                var geo     = cells.Select(cl => cl.GetTrimmedCellGeometry());
                var types   = cells.Select(cl => cl.Type);
                var trimmed = cells.Select(cl => cl.IsTrimmed());
            }
            //Test verifies no exceptions are thrown at any rotation
        }
Exemple #14
0
        public void SeparatorsFromNestedGridFromPolygons()
        {
            var a = new Vector3(0.03, 5.08);
            var b = new Vector3(4.28, 9.80);
            var c = new Vector3(9.69, 9.50);
            var d = new Vector3(9.63, 2.43);
            var e = new Vector3(4.72, -0.86);
            var f = new Vector3(1.78, -0.75);

            var polygon = new Polygon(new[] { a, b, c, d, e, f });

            var g = new Vector3(7.735064, 5.746821);
            var h = new Vector3(6.233137, 7.248748);
            var i = new Vector3(3.660163, 4.675775);
            var j = new Vector3(5.162091, 3.173848);

            var polygon2 = new Polygon(new[] { g, h, i, j });

            var orientation = new Transform();

            orientation.Rotate(Vector3.ZAxis, 15);

            var grid = new Grid2d(new[] { polygon, polygon2 }, orientation);

            grid.U.DivideByCount(3);
            grid.V.SplitAtParameter(0.5);
            grid[1, 0].V.DivideByCount(5);
            var cells   = grid.GetCells();
            var geo     = cells.Select(cl => cl.GetTrimmedCellGeometry());
            var types   = cells.Select(cl => cl.Type);
            var trimmed = cells.Select(cl => cl.IsTrimmed());
            var uLines  = grid.GetCellSeparators(GridDirection.U);
            var vLines  = grid.GetCellSeparators(GridDirection.V);
            var dict    = new Dictionary <string, object>
            {
                { "Cell Geometry", geo },
                { "U Lines", uLines },
                { "V Lines", vLines }
            };
        }
Exemple #15
0
        public void TrimBehavior()
        {
            var polygonjson = "[{\"discriminator\":\"Elements.Geometry.Polygon\",\"Vertices\":[{\"X\":-14.371519985751306,\"Y\":-4.8816304299427005,\"Z\":0.0},{\"X\":-17.661873645682569,\"Y\":9.2555712951713573,\"Z\":0.0},{\"X\":12.965610421927806,\"Y\":9.2555712951713573,\"Z\":0.0},{\"X\":12.965610421927806,\"Y\":3.5538269529982784,\"Z\":0.0},{\"X\":6.4046991240848143,\"Y\":3.5538269529982784,\"Z\":0.0},{\"X\":1.3278034769444158,\"Y\":-4.8816304299427005,\"Z\":0.0}]},{\"discriminator\":\"Elements.Geometry.Polygon\",\"Vertices\":[{\"X\":-9.4508365123690652,\"Y\":0.20473478280229102,\"Z\":0.0},{\"X\":-1.8745460850979974,\"Y\":0.20473478280229102,\"Z\":0.0},{\"X\":-1.8745460850979974,\"Y\":5.4378426037008651,\"Z\":0.0},{\"X\":-9.4508365123690652,\"Y\":5.4378426037008651,\"Z\":0.0}]}]\r\n";
            var polygons    = JsonConvert.DeserializeObject <List <Polygon> >(polygonjson);
            var grid        = new Grid2d(polygons);

            foreach (var pt in polygons[1].Vertices)
            {
                grid.SplitAtPoint(pt);
            }
            grid.CellsFlat.ForEach(c => c.U.DivideByApproximateLength(1.0, EvenDivisionMode.RoundDown));

            var trimmedCells = grid.GetCells().Select(c => new Dictionary <string, object>
            {
                { "TrimmedGeometry", c.GetTrimmedCellGeometry() },
                { "BaseRect", c.GetCellGeometry() },
                { "IsTrimmed", c.IsTrimmed() }
            }
                                                      );

            Assert.Equal(87, trimmedCells.Count());
            Assert.Equal(18, trimmedCells.Count(c => (bool)c["IsTrimmed"]));
        }
        private static List <WallPanel> ProcessWallsByProfile(PanelsFromWallsInputs input, List <WallByProfile> allWallsByProfile, out int totalCount, out int uniqueCount, out int nonStandardCount)
        {
            var panelsOut = new List <WallPanel>();
            Dictionary <string, Color> colorMap = new Dictionary <string, Color>();

            uniqueCount      = 0;
            nonStandardCount = 0;
            var rand            = new Random();
            int uniqueIDCounter = 0;

            foreach (var wall in allWallsByProfile)
            {
                var centerline = wall.Centerline;
                var profile    = wall.Profile;
                var clVec      = centerline.Direction();
                var wallNormal = clVec.Cross(Vector3.ZAxis);
                var toWall     = new Transform(centerline.Start, clVec, wallNormal);
                var fromWall   = new Transform(toWall);

                fromWall.Invert();


                var flatProfile = fromWall.OfProfile(profile);
                var polygons = new[] { flatProfile.Perimeter }.Union(flatProfile.Voids).Select(p => Make2d(p)).ToList();
                var grid = new Grid2d(polygons);
                grid.U.DivideByFixedLength(input.PanelLength, FixedDivisionMode.RemainderAtEnd);
                foreach (var cell in grid.GetCells())
                {
                    var cellGeometry = cell.GetTrimmedCellGeometry().OfType <Polygon>();
                    var isTrimmed    = cell.IsTrimmed();
                    if (!isTrimmed)
                    {
                        var polygon = Make2d(cellGeometry.FirstOrDefault());
                        if (polygon == null)
                        {
                            continue;
                        }
                        var cellProfile = new Profile(polygon);

                        var thicknessTransform = new Transform(0, 0, -wall.Thickness / 2.0);
                        cellProfile = thicknessTransform.OfProfile(cellProfile);
                        var   extrude    = new Extrude(cellProfile, wall.Thickness, Vector3.ZAxis, false);
                        var   identifier = $"{Math.Round(cell.U.Domain.Length, 2)} x {Math.Round(cell.V.Domain.Length, 2)}";
                        Color color      = default(Color);
                        if (colorMap.ContainsKey(identifier))
                        {
                            color = colorMap[identifier];
                        }
                        else
                        {
                            color = new Color(rand.NextDouble(), rand.NextDouble(), rand.NextDouble(), 1.0);
                            colorMap.Add(identifier, color);
                        }
                        var material = input.ColorCodeByLength ? new Material(color, 0, 0, false, null, true, Guid.NewGuid(), color.ToString()) : BuiltInMaterials.Concrete;
                        var geomRep  = new Representation(new[] { extrude });
                        var panel    = new WallPanel(identifier, cellProfile, true, wall.Thickness, toWall, material, geomRep, false, Guid.NewGuid(), "");
                        panelsOut.Add(panel);
                    }
                    else
                    {
                        foreach (var polygon in cellGeometry)
                        {
                            var cellProfile        = new Profile(polygon);
                            var thicknessTransform = new Transform(0, 0, -wall.Thickness / 2.0);
                            cellProfile = thicknessTransform.OfProfile(cellProfile);
                            var extrude    = new Extrude(cellProfile, wall.Thickness, Vector3.ZAxis, false);
                            var identifier = $"C-{uniqueIDCounter++:00}";
                            var color      = new Color(rand.NextDouble(), rand.NextDouble(), rand.NextDouble(), 1.0);
                            colorMap.Add(identifier, color);
                            var material = input.ColorCodeByLength ? new Material(color, 0, 0, false, null, true, Guid.NewGuid(), color.ToString()) : BuiltInMaterials.Concrete;
                            var geomRep  = new Representation(new[] { extrude });
                            var panel    = new WallPanel(identifier, cellProfile, true, wall.Thickness, toWall, material, geomRep, false, Guid.NewGuid(), "");
                            panelsOut.Add(panel);
                        }
                    }
                }
            }

            totalCount = panelsOut.Count;

            return(panelsOut);
        }
Exemple #17
0
        /// <summary>
        /// The OpenCollaborationLayout function.
        /// </summary>
        /// <param name="model">The input model.</param>
        /// <param name="input">The arguments to the execution.</param>
        /// <returns>A OpenCollaborationLayoutOutputs instance containing computed results and the model with any new elements.</returns>
        public static OpenCollaborationLayoutOutputs Execute(Dictionary <string, Model> inputModels, OpenCollaborationLayoutInputs input)
        {
            varietyCounter = 0;
            var spacePlanningZones = inputModels["Space Planning Zones"];
            var levelsModel        = inputModels["Levels"];
            var hasOpenOffice      = inputModels.TryGetValue("Open Office Layout", out var openOfficeModel);

            var levels       = spacePlanningZones.AllElementsOfType <LevelElements>();
            var levelVolumes = levelsModel.AllElementsOfType <LevelVolume>();
            var output       = new OpenCollaborationLayoutOutputs();
            var configJson   = File.ReadAllText("./OpenCollaborationConfigurations.json");
            var configs      = JsonConvert.DeserializeObject <SpaceConfiguration>(configJson);

            if (hasOpenOffice)
            {
                foreach (var sb in openOfficeModel.AllElementsOfType <SpaceBoundary>())
                {
                    if (sb.AdditionalProperties.TryGetValue("Parent Level Id", out var lvlId))
                    {
                        var matchingLevel = levels.FirstOrDefault(l => l.Id.ToString() == lvlId as string);
                        matchingLevel?.Elements.Add(sb);
                    }
                }
            }

            foreach (var lvl in levels)
            {
                var corridors           = lvl.Elements.OfType <Floor>();
                var corridorSegments    = corridors.SelectMany(p => p.Profile.Segments());
                var meetingRmBoundaries = lvl.Elements.OfType <SpaceBoundary>().Where(z => z.Name == "Open Collaboration");
                var levelVolume         = levelVolumes.First(l => l.Name == lvl.Name);
                foreach (var room in meetingRmBoundaries)
                {
                    var  spaceBoundary        = room.Boundary;
                    Line orientationGuideEdge = FindEdgeAdjacentToSegments(spaceBoundary.Perimeter.Segments(), corridorSegments, out var wallCandidates);
                    var  orientationTransform = new Transform(Vector3.Origin, orientationGuideEdge.Direction(), Vector3.ZAxis);
                    var  boundaryCurves       = new List <Polygon>();
                    boundaryCurves.Add(spaceBoundary.Perimeter);
                    boundaryCurves.AddRange(spaceBoundary.Voids ?? new List <Polygon>());

                    var grid = new Grid2d(boundaryCurves, orientationTransform);
                    foreach (var cell in grid.GetCells())
                    {
                        var rect       = cell.GetCellGeometry() as Polygon;
                        var segs       = rect.Segments();
                        var width      = segs[0].Length();
                        var depth      = segs[1].Length();
                        var trimmedGeo = cell.GetTrimmedCellGeometry();
                        if (!cell.IsTrimmed() && trimmedGeo.Count() > 0)
                        {
                            output.Model.AddElement(InstantiateLayout(configs, width, depth, rect, room.Transform));
                        }
                        else if (trimmedGeo.Count() > 0)
                        {
                            var largestTrimmedShape = trimmedGeo.OfType <Polygon>().OrderBy(s => s.Area()).Last();
                            var cinchedVertices     = rect.Vertices.Select(v => largestTrimmedShape.Vertices.OrderBy(v2 => v2.DistanceTo(v)).First()).ToList();
                            var cinchedPoly         = new Polygon(cinchedVertices);
                            // output.Model.AddElement(new ModelCurve(cinchedPoly, BuiltInMaterials.ZAxis, levelVolume.Transform));
                            try
                            {
                                output.Model.AddElement(InstantiateLayout(configs, width, depth, cinchedPoly, room.Transform));
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine("Failed to instantiate config");
                            }
                            Console.WriteLine("­ЪциРђЇРЎѓ№ИЈ funny shape!!!");
                        }
                    }
                }
            }
            InstancePositionOverrides(input.Overrides, output.Model);
            return(output);
        }
Exemple #18
0
        /// <summary>
        /// The Structure function.
        /// </summary>
        /// <param name="model">The model.
        /// Add elements to the model to have them persisted.</param>
        /// <param name="input">The arguments to the execution.</param>
        /// <returns>A StructureOutputs instance containing computed results.</returns>
        public static StructureOutputs Execute(Dictionary <string, Model> models, StructureInputs input)
        {
            var model    = new Model();
            var warnings = new List <string>();

            Elements.Validators.Validator.DisableValidationOnConstruction = true;

            CellComplex cellComplex = null;
            Line        longestEdge = null;

#if DEBUG
            var sw = new Stopwatch();
            sw.Start();
#endif

            if (models.ContainsKey(BAYS_MODEL_NAME))
            {
                var cellsModel = models[BAYS_MODEL_NAME];
                cellComplex = cellsModel.AllElementsOfType <CellComplex>().First();
            }
            else
            {
                warnings.Add("Adding the Bays function to your workflow will give you more configurability. We'll use the default configuration for now.");

                // Create a cell complex with some defaults.
                if (!models.ContainsKey(LEVELS_MODEL_NAME))
                {
                    throw new Exception("If Bays are not supplied Levels are required.");
                }

                var levels       = models[LEVELS_MODEL_NAME];
                var levelVolumes = levels.AllElementsOfType <LevelVolume>().ToList();
                if (levelVolumes.Count == 0)
                {
                    throw new Exception("No LevelVolumes found in your Levels model. Please use a level function that generates LevelVolumes, such as Simple Levels by Envelope");
                }

                // Replicate the old behavior by creating a
                // grid using the envelope's first level base polygon's longest
                // edge as the U axis and its perpendicular as the
                // V axis.

                var firstLevel          = levelVolumes[0];
                var firstLevelPerimeter = firstLevel.Profile.Perimeter;
                longestEdge = firstLevelPerimeter.Segments().OrderBy(s => s.Length()).Last();

                var longestEdgeTransform = longestEdge.TransformAt(0.5);
                var t = new Transform(longestEdge.Start, longestEdgeTransform.XAxis, longestEdge.Direction(), Vector3.ZAxis);

                var toWorld = new Transform(t);
                toWorld.Invert();
                var bbox = new BBox3(firstLevelPerimeter.Vertices.Select(o => toWorld.OfVector(o)).ToList());

                var l = bbox.Max.Y - bbox.Min.Y;
                var w = bbox.Max.X - bbox.Min.X;

                var origin = t.OfVector(bbox.Min);

                var uGrid = new Grid1d(new Line(origin, origin + t.YAxis * l));
                uGrid.DivideByFixedLength(DEFAULT_U);

                var vGrid = new Grid1d(new Line(origin, origin + t.XAxis * w));

                vGrid.DivideByFixedLength(DEFAULT_V);
                var grid = new Grid2d(uGrid, vGrid);

                var u = grid.U;
                var v = grid.V;

                cellComplex = new CellComplex(Guid.NewGuid(), "Temporary Cell Complex");

                // Draw level volumes from each level down.
                for (var i = 1; i < levelVolumes.Count; i++)
                {
                    var levelVolume     = levelVolumes.ElementAt(i);
                    var perimeter       = levelVolume.Profile.Perimeter.Offset(-0.5)[0];
                    var g2d             = new Grid2d(perimeter, grid.U, grid.V);
                    var levelElevation  = levelVolume.Transform.Origin.Z;
                    var lastLevelVolume = levelVolumes.ElementAt(i - 1);
                    foreach (var cell in g2d.GetCells())
                    {
                        foreach (var crv in cell.GetTrimmedCellGeometry())
                        {
                            cellComplex.AddCell((Polygon)crv, lastLevelVolume.Height, levelElevation - lastLevelVolume.Height, g2d.U, g2d.V);
                            if (i == levelVolumes.Count - 1)
                            {
                                cellComplex.AddCell((Polygon)crv, levelVolume.Height, levelElevation, g2d.U, g2d.V);
                            }
                        }
                    }
                }
            }

#if DEBUG
            Console.WriteLine($"{sw.ElapsedMilliseconds} ms for getting or creating a cell complex.");
            sw.Restart();
#endif

            Vector3 primaryDirection;
            Vector3 secondaryDirection;
            IEnumerable <GridLine> gridLines = null;

            if (models.ContainsKey(GRIDS_MODEL_NAME))
            {
                var gridsModel = models[GRIDS_MODEL_NAME];
                gridLines = gridsModel.AllElementsOfType <GridLine>();

                // Group by direction.
                var gridGroups = gridLines.GroupBy(gl => gl.Curve.TransformAt(0).ZAxis).ToList();
                primaryDirection   = gridGroups[0].Key;
                secondaryDirection = gridGroups[1].Key;
            }
            else
            {
                warnings.Add("Adding the Grids function to your workflow will enable you to position and orient the grid. We'll use the default configuration for now with the grid oriented along the longest edge of the structure.");
                // Define the primary direction from the longest edge of the site.
                primaryDirection   = longestEdge.Direction();
                secondaryDirection = longestEdge.TransformAt(0.5).XAxis;
            }

#if DEBUG
            Console.WriteLine($"{sw.ElapsedMilliseconds} ms for getting or creating grids.");
            sw.Restart();
#endif

            var structureMaterial = new Material("Steel", Colors.Gray, 0.5, 0.3);
            model.AddElement(structureMaterial, false);
            model.AddElement(BuiltInMaterials.ZAxis, false);

            var wideFlangeFactory = new WideFlangeProfileFactory();
            var shsProfileFactory = new SHSProfileFactory();
            var rhsProfileFactory = new RHSProfileFactory();

            var columnTypeName   = input.ColumnType.ToString();
            var columnProfile    = GetProfileFromName(columnTypeName, wideFlangeFactory, rhsProfileFactory, shsProfileFactory);
            var colProfileBounds = columnProfile.Perimeter.Bounds();
            var colProfileDepth  = colProfileBounds.Max.Y - colProfileBounds.Min.Y;

            var     girderTypeName     = input.GirderType.ToString();
            Profile girderProfile      = null;
            double  girderProfileDepth = 0;
            if (girderTypeName.StartsWith("LH"))
            {
                girderProfileDepth = Units.InchesToMeters(double.Parse(girderTypeName.Split("LH")[1]));
            }
            else
            {
                girderProfile = GetProfileFromName(girderTypeName, wideFlangeFactory, rhsProfileFactory, shsProfileFactory);
                var girdProfileBounds = girderProfile.Perimeter.Bounds();
                girderProfileDepth = girdProfileBounds.Max.Y - girdProfileBounds.Min.Y;

                // Set the profile down by half its depth so that
                // it sits under the slab.
                girderProfile.Transform(new Transform(new Vector3(0, -girderProfileDepth / 2 - input.SlabThickness)));
            }

            Profile beamProfile      = null;
            double  beamProfileDepth = 0;

            var beamTypeName = input.BeamType.ToString();
            if (beamTypeName.StartsWith("LH"))
            {
                beamProfileDepth = Units.InchesToMeters(double.Parse(beamTypeName.Split("LH")[1]));
            }
            else
            {
                beamProfile = GetProfileFromName(beamTypeName, wideFlangeFactory, rhsProfileFactory, shsProfileFactory);
                var beamProfileBounds = beamProfile.Perimeter.Bounds();
                beamProfileDepth = beamProfileBounds.Max.Y - beamProfileBounds.Min.Y;

                // Set the profile down by half its depth so that
                // it sits under the slab.
                beamProfile.Transform(new Transform(new Vector3(0, -beamProfileDepth / 2 - input.SlabThickness)));
            }

            var edges               = cellComplex.GetEdges();
            var lowestTierSet       = false;
            var lowestTierElevation = double.MaxValue;

            var columnDefintions       = new Dictionary <(double memberLength, Profile memberProfile), Column>();
            var girderDefinitions      = new Dictionary <(double memberLength, Profile memberProfile), GeometricElement>();
            var beamDefinitions        = new Dictionary <(double memberLength, Profile memberProfile), GeometricElement>();
            var girderJoistDefinitions = new Dictionary <(double memberLength, double depth), GeometricElement>();
            var beamJoistDefinitions   = new Dictionary <(double memberLength, double depth), GeometricElement>();

            LProfileFactory lProfileFactory;
            LProfile        L8 = null;
            LProfile        L5 = null;
            LProfile        L2 = null;
            LProfile        L3 = null;

            if (girderProfile == null || beamProfile == null)
            {
                lProfileFactory = new LProfileFactory();
                L8 = Task.Run(async() => await lProfileFactory.GetProfileByTypeAsync(LProfileType.L8X8X1_2)).Result;
                L5 = Task.Run(async() => await lProfileFactory.GetProfileByTypeAsync(LProfileType.L5X5X1_2)).Result;
                L2 = Task.Run(async() => await lProfileFactory.GetProfileByTypeAsync(LProfileType.L2X2X1_8)).Result;
                L3 = Task.Run(async() => await lProfileFactory.GetProfileByTypeAsync(LProfileType.L3X2X3_16)).Result;
            }

#if DEBUG
            Console.WriteLine($"{sw.ElapsedMilliseconds} ms for getting all beam and column profiles.");
            sw.Restart();
#endif

            var xy = new Plane(Vector3.Origin, Vector3.ZAxis);

            // Order edges from lowest to highest.
            foreach (Elements.Spatial.CellComplex.Edge edge in edges.OrderBy(e =>
                                                                             Math.Min(cellComplex.GetVertex(e.StartVertexId).Value.Z, cellComplex.GetVertex(e.EndVertexId).Value.Z)
                                                                             ))
            {
                var memberLength = edge.Length(cellComplex);
                var start        = cellComplex.GetVertex(edge.StartVertexId).Value;
                var end          = cellComplex.GetVertex(edge.EndVertexId).Value;
                var direction    = (end - start).Unitized();

                var warningRepresentation = new Representation(new List <SolidOperation>()
                {
                    new Extrude(Polygon.Rectangle(0.01, 0.01), 0.01, Vector3.ZAxis, false)
                });

                if (edge.IsVertical(cellComplex))
                {
                    // For vertical edges that are not on the grid, we need
                    // a heuristic to determine when we should place a column.
                    // You don't want to place a column all the time because
                    // for non-grid-aligned structures, when you place columns
                    // at every intersection of the envelope and the grid, you
                    // can get columns that are too close together. Instead, we
                    // place a column based on the distance from that column along
                    // a grid line back to a primary grid intersection. If that
                    // distance exceeds the maximum allowable neighbor span,
                    // we place a column.
                    if (!edge.StartsOnGrid(cellComplex))
                    {
                        var maxDistance = double.MinValue;
                        foreach (var e in edge.GetCells().SelectMany(c => c.GetEdges().Where(e =>
                                                                                             e != edge &&
                                                                                             e.StartsOrEndsOnGrid(cellComplex) &&
                                                                                             e.StartsOrEndsAtThisVertex(edge.StartVertexId, cellComplex) &&
                                                                                             e.IsHorizontal(cellComplex))))
                        {
                            var d = e.Length(cellComplex);
                            maxDistance = Math.Max(maxDistance, d);
                        }

                        if (maxDistance < input.MaximumNeighborSpan)
                        {
                            continue;
                        }
                    }

                    var    origin   = start.IsLowerThan(end) ? start : end;
                    var    rotation = Vector3.XAxis.PlaneAngleTo(primaryDirection);
                    Column columnDefinition;
                    if (!columnDefintions.ContainsKey((memberLength, columnProfile)))
                    {
                        columnDefinition = new Column(Vector3.Origin, memberLength, columnProfile, structureMaterial, name: columnProfile.Name)
                        {
                            IsElementDefinition = true
                        };
                        columnDefinition.Representation.SkipCSGUnion = true;
                        columnDefintions.Add((memberLength, columnProfile), columnDefinition);
                        model.AddElement(columnDefinition, false);
                    }
                    else
                    {
                        columnDefinition = columnDefintions[(memberLength, columnProfile)];
        /// <summary>
        /// Subdivides an incoming Floor according to x- and y-axis distances and grid rotation.
        /// </summary>
        /// <param name="model">The input model.</param>
        /// <param name="input">The arguments to the execution.</param>
        /// <returns>A SubdivideSlabOutputs instance containing computed results and the model with any new elements.</returns>
        public static SubdivideSlabOutputs Execute(Dictionary <string, Model> inputModels, SubdivideSlabInputs input)
        {
            var allFloors = new List <Floor>();

            inputModels.TryGetValue("Floors", out var flrModel);
            if (flrModel == null || flrModel.AllElementsOfType <Floor>().Count() == 0)
            {
                throw new ArgumentException("No Floors found.");
            }
            allFloors.AddRange(flrModel.AllElementsOfType <Floor>());
            List <SlabSubdivision> subdivisions = new List <SlabSubdivision>();

            for (int i = 0; i < allFloors.Count; i++)
            {
                Floor floor      = allFloors[i];
                var   floorId    = StringExtensions.NumberToString(i);
                var   profile    = floor.Profile;
                var   perimeter  = profile.Perimeter;
                var   voids      = profile.Voids;
                var   openings   = floor.Openings.Select(o => o.Profile);
                var   elevation  = floor.Elevation;
                var   boundaries = new List <Polygon>();
                boundaries.Add(perimeter);
                if (voids != null)
                {
                    boundaries.AddRange(voids);
                }
                if (openings != null)
                {
                    boundaries.AddRange(openings.Select(o => o.Perimeter));
                }
                Transform transform = null;
                if (input.AlignToLongestEdge)
                {
                    var longestEdge = perimeter.Segments().OrderByDescending(p => p.Length()).First();
                    var xAxis       = (longestEdge.End - longestEdge.Start).Unitized();
                    if (perimeter.IsClockWise())
                    {
                        xAxis = xAxis * -1;
                    }
                    transform = new Transform(Vector3.Origin, xAxis, Vector3.ZAxis, 0);
                    // if (perimeter.IsClockWise())
                    // {
                    //     transform.Invert();
                    // }
                }
                var grid = new Grid2d(boundaries, transform);
                if (input.SubdivideAtVoidCorners && voids != null && voids.Count > 0)
                {
                    foreach (var voidCrv in voids)
                    {
                        grid.SplitAtPoints(voidCrv.Vertices);
                    }
                    foreach (var cell in grid.CellsFlat)
                    {
                        cell.U.DivideByApproximateLength(input.Length, EvenDivisionMode.RoundUp);
                        cell.V.DivideByApproximateLength(input.Width, EvenDivisionMode.RoundUp);
                    }
                }
                else
                {
                    grid.U.DivideByApproximateLength(input.Length, EvenDivisionMode.RoundUp);
                    grid.V.DivideByApproximateLength(input.Width, EvenDivisionMode.RoundUp);
                }

                var cells = grid.GetCells();

                for (int i1 = 0; i1 < cells.Count; i1++)
                {
                    var    id        = $"{floorId}-{i1:000}";
                    Grid2d cell      = cells[i1];
                    var    cellCrvs  = cell.GetTrimmedCellGeometry();
                    var    isTrimmed = cell.IsTrimmed();
                    if (cellCrvs != null && cellCrvs.Length > 0)
                    {
                        subdivisions.Add(CreateSlabSubdivision(id, cellCrvs, floor, isTrimmed));
                    }
                }
            }

            var output = new SubdivideSlabOutputs(subdivisions.Count);

            output.Model.AddElements(subdivisions);
            foreach (var subdiv in subdivisions)
            {
                var thicknessXform = new Transform(0, 0, subdiv.Depth);
                var profile        = subdiv.Transform.OfProfile(subdiv.Profile);
                profile = thicknessXform.OfProfile(profile);
                output.Model.AddElement(new ModelCurve(profile.Perimeter));
                if (profile.Voids != null && profile.Voids.Count > 0)
                {
                    output.Model.AddElements(profile.Voids.Select(v => new ModelCurve(v)));
                }
            }
            return(output);
        }
Exemple #20
0
        /// <summary>
        /// The SpacePlanningZones function.
        /// </summary>
        /// <param name="model">The input model.</param>
        /// <param name="input">The arguments to the execution.</param>
        /// <returns>A SpacePlanningZonesOutputs instance containing computed results and the model with any new elements.</returns>
        public static SpacePlanningZonesOutputs Execute(Dictionary <string, Model> inputModels, SpacePlanningZonesInputs input)
        {
            var corridorWidth = input.CorridorWidth;
            var corridorMat   = SpaceBoundary.MaterialDict["Circulation"];

            var output       = new SpacePlanningZonesOutputs();
            var levelsModel  = inputModels["Levels"];
            var levelVolumes = levelsModel.AllElementsOfType <LevelVolume>();

            inputModels.TryGetValue("Floors", out var floorsModel);
            var hasCore = inputModels.TryGetValue("Core", out var coresModel);
            var cores   = coresModel?.AllElementsOfType <ServiceCore>() ?? new List <ServiceCore>();

            var random        = new Random(5);
            var levels        = new List <LevelElements>();
            var levelMappings = new Dictionary <Guid, (SpaceBoundary boundary, LevelElements level)>();

            if (levelVolumes.Count() == 0)
            {
                throw new Exception("This function requires LevelVolumes, produced by functions like \"Simple Levels by Envelope\". Try using a different levels function.");
            }
            foreach (var lvl in levelVolumes)
            {
                if (floorsModel != null)
                {
                    var floorAtLevel = floorsModel.AllElementsOfType <Floor>().FirstOrDefault(f => Math.Abs(lvl.Transform.Origin.Z - f.Transform.Origin.Z) < (f.Thickness * 1.1));
                    if (floorAtLevel != null)
                    {
                        lvl.Height -= floorAtLevel.Thickness;
                        var floorFaceOffset = (floorAtLevel.Transform.Origin.Z + floorAtLevel.Thickness) - lvl.Transform.Origin.Z;
                        if (floorFaceOffset > 0.001)
                        {
                            lvl.Transform.Concatenate(new Transform(0, 0, floorFaceOffset));
                            lvl.Height -= floorFaceOffset;
                        }
                    }
                }
                var levelBoundary   = new Profile(lvl.Profile.Perimeter, lvl.Profile.Voids, Guid.NewGuid(), null);
                var coresInBoundary = cores.Where(c => levelBoundary.Contains(c.Centroid)).ToList();
                foreach (var core in coresInBoundary)
                {
                    levelBoundary.Voids.Add(new Polygon(core.Profile.Perimeter.Vertices).Reversed());
                    levelBoundary.OrientVoids();
                }

                var            spaceBoundaries  = new List <Element>();
                List <Profile> corridorProfiles = new List <Profile>();
                if (input.CirculationMode == SpacePlanningZonesInputsCirculationMode.Automatic)
                {
                    var perimeter         = levelBoundary.Perimeter;
                    var perimeterSegments = perimeter.Segments();

                    IdentifyShortEdges(perimeter, perimeterSegments, out var shortEdges, out var shortEdgeIndices);

                    // Single Loaded Zones
                    var singleLoadedZones = CalculateSingleLoadedZones(input, corridorWidth, perimeterSegments, shortEdgeIndices);

                    GenerateEndZones(input, corridorWidth, lvl, corridorProfiles, perimeterSegments, shortEdges, singleLoadedZones, out var thickenedEnds, out var thickerOffsetProfiles, out var innerOffsetMinusThickenedEnds, out var exclusionRegions);

                    // join single loaded zones to each other (useful in bent-bar case)
                    var allCenterLines = JoinSingleLoaded(singleLoadedZones);

                    // thicken and extend single loaded
                    ThickenAndExtendSingleLoaded(corridorWidth, corridorProfiles, coresInBoundary, thickenedEnds, innerOffsetMinusThickenedEnds, allCenterLines);

                    CorridorsFromCore(corridorWidth, corridorProfiles, levelBoundary, coresInBoundary, innerOffsetMinusThickenedEnds, exclusionRegions);

                    SplitCornersAndGenerateSpaceBoundaries(spaceBoundaries, input, lvl, corridorProfiles, levelBoundary, thickerOffsetProfiles);
                }
                else if (input.CirculationMode == SpacePlanningZonesInputsCirculationMode.Manual)
                {
                    if (input.Corridors != null && input.Corridors.Count > 0)
                    {
                        var corridorProfilesForUnion = new List <Profile>();
                        foreach (var corridorPolyline in input.Corridors)
                        {
                            if (corridorPolyline == null || corridorPolyline.Polyline == null)
                            {
                                continue;
                            }
                            var corrPgons = corridorPolyline.Polyline.OffsetOnSide(corridorPolyline.Width, corridorPolyline.Flip);
                            corridorProfilesForUnion.AddRange(corrPgons.Select(p => new Profile(p)));
                        }
                        corridorProfiles = Profile.UnionAll(corridorProfilesForUnion);
                    }
                    SplitCornersAndGenerateSpaceBoundaries(spaceBoundaries, input, lvl, corridorProfiles, levelBoundary);
                }

                // Construct Level
                var level = new LevelElements(new List <Element>(), Guid.NewGuid(), lvl.Name);
                levels.Add(level);

                // Manual Corridor Splits
                foreach (var pt in input.AdditionalCorridorLocations)
                {
                    SplitZones(input, corridorWidth, lvl, spaceBoundaries, corridorProfiles, pt);
                }

                // Manual Split Locations
                foreach (var pt in input.ManualSplitLocations)
                {
                    SplitZones(input, corridorWidth, lvl, spaceBoundaries, corridorProfiles, pt, false);
                }

                foreach (SpaceBoundary b in spaceBoundaries)
                {
                    levelMappings.Add(b.Id, (b, level));
                }
                corridorProfiles.Select(p => new Floor(p, 0.1, lvl.Transform, corridorMat)).ToList().ForEach(f => level.Elements.Add(f));
            }
            List <SpaceBoundary> SubdividedBoundaries = new List <SpaceBoundary>();

            // merge overrides
            if (input.Overrides != null && input.Overrides.MergeZones != null && input.Overrides.MergeZones.Count > 0)
            {
                var spaceBoundaries = levelMappings.Select(kvp => kvp.Value);
                foreach (var mz in input.Overrides.MergeZones)
                {
                    var identitiesToMerge = mz.Identities;
                    var matchingSbs       = identitiesToMerge.Select(mzI => spaceBoundaries.FirstOrDefault(
                                                                         sb => ((Vector3)sb.boundary.AdditionalProperties["ParentCentroid"]).DistanceTo(mzI.ParentCentroid) < 1.0)).Where(s => s != (null, null)).ToList();
                    foreach (var msb in matchingSbs)
                    {
                        levelMappings.Remove(msb.boundary.Id);
                    }
                    var sbsByLevel = matchingSbs.GroupBy(sb => sb.level?.Id ?? Guid.Empty);
                    foreach (var lvlGrp in sbsByLevel)
                    {
                        var level    = lvlGrp.First().level;
                        var profiles = lvlGrp.Select(sb => sb.boundary.Boundary);
                        var baseobj  = lvlGrp.FirstOrDefault(n => n.boundary.Name != null && n.boundary.Name != "unspecified");
                        if (baseobj == default)
                        {
                            baseobj = lvlGrp.First();
                        }
                        var baseSB = baseobj.boundary;
                        var union  = Profile.UnionAll(profiles);
                        foreach (var newProfile in union)
                        {
                            var rep = baseSB.Representation.SolidOperations.OfType <Extrude>().First();

                            var newSB = SpaceBoundary.Make(newProfile, baseSB.Name, baseSB.Transform, rep.Height, (Vector3)baseSB.AdditionalProperties["ParentCentroid"], (Vector3)baseSB.AdditionalProperties["ParentCentroid"]);
                            newSB.SetProgram(baseSB.Name);
                            levelMappings.Add(newSB.Id, (newSB, level));
                        }
                    }
                }
            }
            // assignment overrides
            if (input.Overrides != null && input.Overrides.ProgramAssignments != null && input.Overrides.ProgramAssignments.Count > 0)
            {
                var spaceBoundaries = levelMappings.Select(kvp => kvp.Value).ToList();
                // overrides where it is its own parent
                Console.WriteLine(JsonConvert.SerializeObject(input.Overrides.ProgramAssignments));
                foreach (var overrideValue in input.Overrides.ProgramAssignments.Where(o => o.Identity.IndividualCentroid.IsAlmostEqualTo(o.Identity.ParentCentroid)))
                {
                    var centroid   = overrideValue.Identity.ParentCentroid;
                    var matchingSB = spaceBoundaries
                                     .OrderBy(sb => ((Vector3)sb.boundary.AdditionalProperties["IndividualCentroid"]).DistanceTo(centroid))
                                     .FirstOrDefault(sb => ((Vector3)sb.boundary.AdditionalProperties["IndividualCentroid"]).DistanceTo(centroid) < 2.0);
                    // var allMatchingSBs = spaceBoundaries
                    //     .OrderBy(sb => sb.boundary.Transform.OfPoint(sb.boundary.Boundary.Perimeter.Centroid()).DistanceTo(centroid))
                    //     .Where(sb => sb.boundary.Transform.OfPoint(sb.boundary.Boundary.Perimeter.Centroid()).DistanceTo(centroid) < 2.0);
                    if (matchingSB.boundary != null)
                    {
                        if (overrideValue.Value.Split <= 1)
                        {
                            matchingSB.boundary.SetProgram(overrideValue.Value.ProgramType ?? input.DefaultProgramAssignment);
                            Identity.AddOverrideIdentity(matchingSB.boundary, "Program Assignments", overrideValue.Id, overrideValue.Identity);
                        }
                        else
                        {
                            levelMappings.Remove(matchingSB.boundary.Id);
                            var boundaries = new List <Polygon>(matchingSB.boundary.Boundary.Voids)
                            {
                                matchingSB.boundary.Boundary.Perimeter
                            };
                            var guideVector    = GetDominantAxis(boundaries.SelectMany(b => b.Segments()));
                            var alignmentXform = new Transform(boundaries[0].Start, guideVector, Vector3.ZAxis);
                            var grid           = new Grid2d(boundaries, alignmentXform);
                            grid.U.DivideByCount(Math.Max(overrideValue.Value.Split, 1));
                            foreach (var cell in grid.GetCells().SelectMany(c => c.GetTrimmedCellGeometry()))
                            {
                                var rep       = matchingSB.boundary.Representation.SolidOperations.OfType <Extrude>().First();
                                var newCellSb = SpaceBoundary.Make(cell as Polygon, overrideValue.Value.ProgramType ?? input.DefaultProgramAssignment, matchingSB.boundary.Transform, rep.Height, matchingSB.boundary.AdditionalProperties["ParentCentroid"] as Vector3?);
                                Identity.AddOverrideIdentity(newCellSb, "Program Assignments", overrideValue.Id, overrideValue.Identity);
                                newCellSb.AdditionalProperties["Split"] = overrideValue.Value.Split;
                                SubdividedBoundaries.Add(newCellSb);
                                levelMappings.Add(newCellSb.Id, (newCellSb, matchingSB.level));
                            }
                        }
                    }
                }
                // overrides where it's not its own parent
                foreach (var overrideValue in input.Overrides.ProgramAssignments.Where(o => !o.Identity.IndividualCentroid.IsAlmostEqualTo(o.Identity.ParentCentroid)))
                {
                    var matchingCell = SubdividedBoundaries.FirstOrDefault(b => (b.AdditionalProperties["IndividualCentroid"] as Vector3?)?.DistanceTo(overrideValue.Identity.IndividualCentroid) < 0.01);
                    if (matchingCell != null)
                    {
                        Identity.AddOverrideIdentity(matchingCell, "Program Assignments", overrideValue.Id, overrideValue.Identity);
                        matchingCell.SetProgram(overrideValue.Value.ProgramType);
                    }
                }
            }

            foreach (var levelMapping in levelMappings)
            {
                levelMapping.Value.level.Elements.Add(levelMapping.Value.boundary);
            }
            Dictionary <string, AreaTally> areas = new Dictionary <string, AreaTally>();

            foreach (var sb in levels.SelectMany(lev => lev.Elements.OfType <SpaceBoundary>()))
            {
                var area = sb.Boundary.Area();
                if (sb.Name == null)
                {
                    continue;
                }
                if (!areas.ContainsKey(sb.Name))
                {
                    areas[sb.Name] = new AreaTally(sb.Name, sb.Material.Color, area, area, 1, null, Guid.NewGuid(), sb.Name);
                }
                else
                {
                    var existingTally = areas[sb.Name];
                    existingTally.AchievedArea += area;
                    existingTally.AreaTarget   += area;
                    existingTally.DistinctAreaCount++;
                }
                output.Model.AddElements(sb.Boundary.ToModelCurves(sb.Transform.Concatenated(new Transform(0, 0, 0.03))));
            }
            output.Model.AddElements(areas.Select(kvp => kvp.Value).OrderByDescending(a => a.AchievedArea));
            output.Model.AddElements(levels);

            return(output);
        }
Exemple #21
0
        /// <summary>
        /// The SpacePlanningZones function.
        /// </summary>
        /// <param name="model">The input model.</param>
        /// <param name="input">The arguments to the execution.</param>
        /// <returns>A SpacePlanningZonesOutputs instance containing computed results and the model with any new elements.</returns>
        public static SpacePlanningZonesOutputs Execute(Dictionary <string, Model> inputModels, SpacePlanningZonesInputs input)
        {
            var corridorWidth = input.CorridorWidth;
            var corridorMat   = SpaceBoundary.MaterialDict["Circulation"];

            var output       = new SpacePlanningZonesOutputs();
            var levelsModel  = inputModels["Levels"];
            var levelVolumes = levelsModel.AllElementsOfType <LevelVolume>();

            inputModels.TryGetValue("Floors", out var floorsModel);
            var coresModel    = inputModels["Core"];
            var cores         = coresModel.AllElementsOfType <ServiceCore>();
            var random        = new Random(5);
            var levels        = new List <LevelElements>();
            var levelMappings = new Dictionary <Guid, (SpaceBoundary boundary, LevelElements level)>();

            if (levelVolumes.Count() == 0)
            {
                throw new Exception("This function requires LevelVolumes, produced by functions like \"Simple Levels by Envelope\". Try using a different levels function.");
            }
            if (cores.Count() == 0)
            {
                throw new Exception("No ServiceCore elements were found in the model.");
            }
            foreach (var lvl in levelVolumes)
            {
                var spaceBoundaries = new List <Element>();
                if (floorsModel != null)
                {
                    var floorAtLevel = floorsModel.AllElementsOfType <Floor>().FirstOrDefault(f => Math.Abs(lvl.Transform.Origin.Z - f.Transform.Origin.Z) < (f.Thickness * 1.1));
                    if (floorAtLevel != null)
                    {
                        lvl.Height -= floorAtLevel.Thickness;
                        var floorFaceOffset = (floorAtLevel.Transform.Origin.Z + floorAtLevel.Thickness) - lvl.Transform.Origin.Z;
                        if (floorFaceOffset > 0.001)
                        {
                            lvl.Transform.Concatenate(new Transform(0, 0, floorFaceOffset));
                            lvl.Height -= floorFaceOffset;
                        }
                    }
                }
                List <Profile> corridorProfiles = new List <Profile>();
                var            TOO_SHORT        = 9;
                var            levelBoundary    = new Profile(lvl.Profile.Perimeter, lvl.Profile.Voids, Guid.NewGuid(), null);
                var            coresInBoundary  = cores.Where(c => levelBoundary.Contains(c.Centroid)).ToList();
                foreach (var core in coresInBoundary)
                {
                    levelBoundary.Voids.Add(new Polygon(core.Profile.Perimeter.Vertices).Reversed());
                    levelBoundary.OrientVoids();
                }

                var perimeter         = levelBoundary.Perimeter;
                var perimeterSegments = perimeter.Segments();
                var perimeterAngles   = new List <double>();
                for (int i = 0; i < perimeter.Vertices.Count; i++)
                {
                    var nextIndex = (i + 1) % perimeter.Vertices.Count;
                    var prevIndex = (i + perimeter.Vertices.Count - 1) % perimeter.Vertices.Count;
                    var prevVec   = perimeter.Vertices[i] - perimeter.Vertices[prevIndex];
                    var nextVec   = perimeter.Vertices[nextIndex] - perimeter.Vertices[i];
                    var angle     = prevVec.PlaneAngleTo(nextVec);
                    perimeterAngles.Add(angle);
                }
                var allLengths       = perimeterSegments.Select(s => s.Length());
                var validLengths     = allLengths.Where(l => l > TOO_SHORT)?.OrderBy(l => l);
                var shortLength      = (validLengths?.FirstOrDefault() ?? 35 / 1.2) * 1.2;
                var longLength       = Math.Min(validLengths.SkipLast(1).Last(), 50);
                var shortEdges       = new List <Line>();
                var shortEdgeIndices = new List <int>();
                for (int i = 0; i < perimeterSegments.Count(); i++)
                {
                    var start = perimeterAngles[i];
                    var end   = perimeterAngles[(i + 1) % perimeterAngles.Count];
                    if (start > 80 && start < 100 && end > 80 && end < 100 && perimeterSegments[i].Length() < longLength)
                    {
                        shortEdges.Add(perimeterSegments[i]);
                        shortEdgeIndices.Add(i);
                    }
                }


                // Single Loaded Zones

                var singleLoadedZones           = new List <(Polygon hull, Line centerLine)>();
                var singleLoadedLengthThreshold = input.OuterBandDepth * 2 + corridorWidth * 2 + 5; // (two offsets, two corridors, and a usable space width)
                foreach (var sei in shortEdgeIndices)
                {
                    var ps = perimeterSegments;
                    if (ps[sei].Length() < singleLoadedLengthThreshold)
                    {
                        var legSegments = new[] {
                            ps[(sei + ps.Length - 1) % ps.Length],
                            ps[sei],
                            ps[(sei + 1) % ps.Length]
                        };
                        var legLength = Math.Min(legSegments[0].Length(), legSegments[2].Length());
                        legSegments[0] = new Line(ps[sei].Start, ps[sei].Start + legLength * (legSegments[0].Direction() * -1));
                        legSegments[2] = new Line(ps[sei].End, ps[sei].End + legLength * (legSegments[2].Direction()));
                        var hull       = ConvexHull.FromPolylines(legSegments.Select(l => l.ToPolyline(1)));
                        var centerLine = new Line((legSegments[0].Start + legSegments[2].Start) / 2, (legSegments[0].End + legSegments[2].End) / 2);

                        singleLoadedZones.Add((hull, centerLine));
                    }
                }

                var shortEdgesExtended = shortEdges.Select(l => new Line(l.Start - l.Direction() * 0.2, l.End + l.Direction() * 0.2));
                var longEdges          = perimeterSegments.Except(shortEdges);
                var shortEdgeDepth     = Math.Max(input.DepthAtEnds, input.OuterBandDepth);
                var longEdgeDepth      = input.OuterBandDepth;


                var perimeterMinusSingleLoaded = new List <Profile>();
                perimeterMinusSingleLoaded.AddRange(Profile.Difference(new[] { lvl.Profile }, singleLoadedZones.Select(p => new Profile(p.hull))));
                var innerOffset           = perimeterMinusSingleLoaded.SelectMany(p => p.Perimeter.Offset(-longEdgeDepth));
                var thickerOffsets        = shortEdgesExtended.SelectMany(s => s.ToPolyline(1).Offset(shortEdgeDepth, EndType.Butt)).ToList();
                var thickerOffsetProfiles = thickerOffsets.Select(o => new Profile(o.Offset(0.01))).ToList();
                var endOffsetSegments     = thickerOffsets.SelectMany(o => o.Segments()).Where(l => innerOffset.Any(o => o.Contains(l.PointAt(0.5))));

                var innerOffsetMinusThicker = innerOffset.SelectMany(i => Polygon.Difference(new[] { i }, thickerOffsets));

                var outerband = new Profile(lvl.Profile.Perimeter, innerOffsetMinusThicker.ToList(), Guid.NewGuid(), null);

                var outerbandLongEdges = Profile.Difference(new List <Profile> {
                    outerband
                }, thickerOffsetProfiles);
                var ends = Profile.Intersection(new List <Profile> {
                    outerband
                }, thickerOffsets.Select(o => new Profile(o)).ToList());
                var coreSegments = coresInBoundary.SelectMany(c => c.Profile.Perimeter.Offset((corridorWidth / 2) * 0.999).FirstOrDefault()?.Segments());


                var corridorInset = innerOffsetMinusThicker.Select(p => new Profile(p, p.Offset(-corridorWidth), Guid.NewGuid(), "Corridor"));
                corridorProfiles.AddRange(corridorInset);

                // join single loaded zones to each other (useful in bent-bar case)
                var allCenterLines    = singleLoadedZones.ToArray();
                var distanceThreshold = 10.0;
                for (int i = 0; i < allCenterLines.Count(); i++)
                {
                    var crvA = allCenterLines[i].centerLine;
                    for (int j = 0; j < i; j++)
                    {
                        var crvB          = allCenterLines[j].centerLine;
                        var doesIntersect = crvA.Intersects(crvB, out var intersection, true, true);
                        Console.WriteLine($"DOES INTERSECT: " + doesIntersect.ToString());

                        var nearPtA = intersection.ClosestPointOn(crvA);
                        var nearPtB = intersection.ClosestPointOn(crvB);
                        if (nearPtA.DistanceTo(intersection) + nearPtB.DistanceTo(intersection) < distanceThreshold)
                        {
                            if (nearPtA.DistanceTo(crvA.Start) < 0.01)
                            {
                                allCenterLines[i] = (allCenterLines[i].hull, new Line(intersection, crvA.End));
                            }
                            else
                            {
                                allCenterLines[i] = (allCenterLines[i].hull, new Line(crvA.Start, intersection));
                            }
                            if (nearPtB.DistanceTo(crvB.Start) < 0.01)
                            {
                                allCenterLines[j] = (allCenterLines[j].hull, new Line(intersection, crvB.End));
                            }
                            else
                            {
                                allCenterLines[j] = (allCenterLines[j].hull, new Line(crvB.Start, intersection));
                            }
                        }
                    }
                }


                // thicken and extend single loaded
                foreach (var singleLoadedZone in allCenterLines)
                {
                    var         cl          = singleLoadedZone.centerLine;
                    List <Line> centerlines = new List <Line> {
                        cl
                    };
                    foreach (var core in coresInBoundary)
                    {
                        List <Line> linesRunning = new List <Line>();
                        foreach (var curve in centerlines)
                        {
                            curve.Trim(core.Profile.Perimeter, out var linesTrimmedByCore);
                            linesRunning.AddRange(linesTrimmedByCore);
                        }
                        centerlines = linesRunning;
                    }
                    cl = centerlines.OrderBy(l => l.Length()).Last();
                    foreach (var clCandidate in centerlines)
                    {
                        var extended = clCandidate.ExtendTo(innerOffsetMinusThicker.SelectMany(p => p.Segments())).ToPolyline(1);
                        if (extended.Length() == cl.Length() && innerOffsetMinusThicker.Count() > 0)
                        {
                            var     end       = extended.End;
                            var     dist      = double.MaxValue;
                            Vector3?runningPt = null;
                            foreach (var boundary in innerOffsetMinusThicker)
                            {
                                var closestDist = end.DistanceTo(boundary, out var pt);
                                if (closestDist < dist)
                                {
                                    dist      = closestDist;
                                    runningPt = pt;
                                }
                            }
                            extended = new Polyline(new[] { extended.Start, extended.End, runningPt.Value });
                        }
                        //TODO - verify that newly constructed line is contained within building perimeter
                        var thickenedCorridor = extended.Offset(corridorWidth / 2.0, EndType.Square);
                        corridorProfiles.AddRange(Profile.Difference(thickenedCorridor.Select(c => new Profile(c)), thickerOffsets.Select(c => new Profile(c))));
                    }
                }

                foreach (var core in coresInBoundary)
                {
                    if (singleLoadedZones.Any(z => z.hull.Covers(core.Profile.Perimeter)))
                    {
                        continue;
                    }
                    var boundary            = core.Profile.Perimeter.Offset(corridorWidth / 2.0).FirstOrDefault();
                    var outerOffset         = boundary.Offset(corridorWidth).FirstOrDefault();
                    var coreWrap            = new Profile(outerOffset, boundary);
                    var coreWrapWithinFloor = Profile.Intersection(new[] { coreWrap }, new[] { levelBoundary });
                }

                var extendedLines    = new List <Line>();
                var corridorRegions  = new List <Polygon>();
                var exclusionRegions = innerOffsetMinusThicker.SelectMany(r => r.Offset(2 * corridorWidth, EndType.Square));
                foreach (var enclosedRegion in innerOffsetMinusThicker)
                {
                    foreach (var segment in coreSegments)
                    {
                        enclosedRegion.Contains(segment.Start, out var startContainment);
                        enclosedRegion.Contains(segment.End, out var endContainment);
                        if (endContainment == Containment.Outside && startContainment == Containment.Outside)
                        {
                            continue;
                        }
                        var extendedSegment = segment.ExtendTo(new Profile(enclosedRegion));
                        if (extendedSegment.Length() - segment.Length() < 2 * 8)
                        {
                            continue;
                        }
                        extendedLines.Add(extendedSegment);
                        var thickenedCorridor = extendedSegment.ToPolyline(1).Offset(corridorWidth / 2.0, EndType.Butt);
                        var difference        = new List <Profile>();

                        difference = Profile.Difference(corridorProfiles, exclusionRegions.Select(r => new Profile(r)));

                        if (difference.Count > 0 && difference.Sum(d => d.Perimeter.Area()) > 10)
                        {
                            corridorProfiles.AddRange(Profile.Intersection(thickenedCorridor.Select(c => new Profile(c)), new[] { levelBoundary }));
                        }
                    }
                }

                var remainingSpaces = Profile.Difference(new[] { levelBoundary }, corridorProfiles);
                foreach (var remainingSpace in remainingSpaces)
                {
                    try
                    {
                        if (remainingSpace.Perimeter.Vertices.Any(v => v.DistanceTo(levelBoundary.Perimeter) < 0.1))
                        {
                            var endCapZones = Profile.Intersection(new[] { remainingSpace }, thickerOffsetProfiles);
                            var linearZones = Profile.Difference(new[] { remainingSpace }, thickerOffsetProfiles);
                            foreach (var linearZone in linearZones)
                            {
                                var segmentsExtended = new List <Polyline>();
                                foreach (var line in linearZone.Segments())
                                {
                                    if (line.Length() < 2)
                                    {
                                        continue;
                                    }
                                    var l             = new Line(line.Start - line.Direction() * 0.1, line.End + line.Direction() * 0.1);
                                    var extended      = l.ExtendTo(linearZone);
                                    var endDistance   = extended.End.DistanceTo(l.End);
                                    var startDistance = extended.Start.DistanceTo(l.Start);
                                    var maxExtension  = Math.Max(input.OuterBandDepth, input.DepthAtEnds) * 1.6;
                                    if (startDistance > 0.1 && startDistance < maxExtension)
                                    {
                                        var startLine = new Line(extended.Start, line.Start);
                                        segmentsExtended.Add(startLine.ToPolyline(1));
                                    }
                                    if (endDistance > 0.1 && endDistance < maxExtension)
                                    {
                                        var endLine = new Line(extended.End, line.End);
                                        segmentsExtended.Add(endLine.ToPolyline(1));
                                    }
                                }
                                Console.WriteLine(JsonConvert.SerializeObject(linearZone.Perimeter));
                                Console.WriteLine(JsonConvert.SerializeObject(linearZone.Voids));
                                Console.WriteLine(JsonConvert.SerializeObject(segmentsExtended));
                                var splits = Profile.Split(new[] { linearZone }, segmentsExtended, Vector3.EPSILON);
                                spaceBoundaries.AddRange(splits.Select(s => SpaceBoundary.Make(s, input.DefaultProgramAssignment, lvl.Transform, lvl.Height)));
                            }
                            spaceBoundaries.AddRange(endCapZones.Select(s => SpaceBoundary.Make(s, input.DefaultProgramAssignment, lvl.Transform, lvl.Height)));
                        }
                        else
                        {
                            spaceBoundaries.Add(SpaceBoundary.Make(remainingSpace, input.DefaultProgramAssignment, lvl.Transform, lvl.Height));
                        }
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine("🚨");
                        Console.WriteLine(e.Message);
                        Console.WriteLine(e.StackTrace);
                        spaceBoundaries.Add(SpaceBoundary.Make(remainingSpace, input.DefaultProgramAssignment, lvl.Transform, lvl.Height));
                    }
                }
                var level = new LevelElements(new List <Element>(), Guid.NewGuid(), lvl.Name);
                levels.Add(level);

                foreach (var pt in input.AdditionalCorridorLocations)
                {
                    SplitZones(input, corridorWidth, lvl, spaceBoundaries, corridorProfiles, pt);
                }

                foreach (var pt in input.ManualSplitLocations)
                {
                    SplitZones(input, corridorWidth, lvl, spaceBoundaries, corridorProfiles, pt, false);
                }

                foreach (SpaceBoundary b in spaceBoundaries)
                {
                    levelMappings.Add(b.Id, (b, level));
                    output.Model.AddElements(b.Boundary.ToModelCurves(b.Transform.Concatenated(new Transform(0, 0, 0.03))));
                }
                corridorProfiles.Select(p => new Floor(p, 0.1, lvl.Transform, corridorMat)).ToList().ForEach(f => level.Elements.Add(f));
            }
            List <SpaceBoundary> SubdividedBoundaries = new List <SpaceBoundary>();

            if (input.Overrides != null && input.Overrides.ProgramAssignments.Count > 0)
            {
                var spaceBoundaries = levelMappings.Select(kvp => kvp.Value);
                foreach (var overrideValue in input.Overrides.ProgramAssignments.Where(o => o.Identity.IndividualCentroid.IsAlmostEqualTo(o.Identity.ParentCentroid)))
                {
                    var centroid   = overrideValue.Identity.ParentCentroid;
                    var matchingSB = spaceBoundaries
                                     .OrderBy(sb => sb.boundary.Transform.OfPoint(sb.boundary.Boundary.Perimeter.Centroid()).DistanceTo(centroid))
                                     .FirstOrDefault(sb => sb.boundary.Transform.OfPoint(sb.boundary.Boundary.Perimeter.Centroid()).DistanceTo(centroid) < 2.0);
                    var allMatchingSBs = spaceBoundaries
                                         .OrderBy(sb => sb.boundary.Transform.OfPoint(sb.boundary.Boundary.Perimeter.Centroid()).DistanceTo(centroid))
                                         .Where(sb => sb.boundary.Transform.OfPoint(sb.boundary.Boundary.Perimeter.Centroid()).DistanceTo(centroid) < 2.0);
                    if (matchingSB.boundary != null)
                    {
                        if (overrideValue.Value.Split <= 1)
                        {
                            matchingSB.boundary.SetProgram(overrideValue.Value.ProgramType ?? input.DefaultProgramAssignment);
                            Identity.AddOverrideIdentity(matchingSB.boundary, "Program Assignments", overrideValue.Id, overrideValue.Identity);
                        }
                        else
                        {
                            levelMappings.Remove(matchingSB.boundary.Id);
                            var boundaries = new List <Polygon>(matchingSB.boundary.Boundary.Voids)
                            {
                                matchingSB.boundary.Boundary.Perimeter
                            };
                            var guideVector    = GetDominantAxis(boundaries.SelectMany(b => b.Segments()));
                            var alignmentXform = new Transform(boundaries[0].Start, guideVector, Vector3.ZAxis);
                            var grid           = new Grid2d(boundaries, alignmentXform);
                            grid.U.DivideByCount(Math.Max(overrideValue.Value.Split, 1));
                            output.Model.AddElements(grid.GetCellSeparators(GridDirection.V, false).Select(c => new ModelCurve(c as Line, new Material("Grey", new Color(0.3, 0.3, 0.3, 1)), matchingSB.boundary.Transform.Concatenated(new Transform(0, 0, 0.02)))));
                            foreach (var cell in grid.GetCells().SelectMany(c => c.GetTrimmedCellGeometry()))
                            {
                                var rep       = matchingSB.boundary.Representation.SolidOperations.OfType <Extrude>().First();
                                var newCellSb = SpaceBoundary.Make(cell as Polygon, overrideValue.Value.ProgramType ?? input.DefaultProgramAssignment, matchingSB.boundary.Transform, rep.Height, matchingSB.boundary.AdditionalProperties["ParentCentroid"] as Vector3?);
                                Identity.AddOverrideIdentity(newCellSb, "Program Assignments", overrideValue.Id, overrideValue.Identity);
                                newCellSb.AdditionalProperties["Split"] = overrideValue.Value.Split;
                                SubdividedBoundaries.Add(newCellSb);
                                levelMappings.Add(newCellSb.Id, (newCellSb, matchingSB.level));
                            }
                        }
                    }
                }

                foreach (var overrideValue in input.Overrides.ProgramAssignments.Where(o => !o.Identity.IndividualCentroid.IsAlmostEqualTo(o.Identity.ParentCentroid)))
                {
                    var matchingCell = SubdividedBoundaries.FirstOrDefault(b => (b.AdditionalProperties["IndividualCentroid"] as Vector3?)?.DistanceTo(overrideValue.Identity.IndividualCentroid) < 0.01);
                    if (matchingCell != null)
                    {
                        Identity.AddOverrideIdentity(matchingCell, "Program Assignments", overrideValue.Id, overrideValue.Identity);
                        matchingCell.SetProgram(overrideValue.Value.ProgramType);
                    }
                }
            }
            foreach (var levelMapping in levelMappings)
            {
                levelMapping.Value.level.Elements.Add(levelMapping.Value.boundary);
            }
            Dictionary <string, AreaTally> areas = new Dictionary <string, AreaTally>();

            foreach (var sb in levels.SelectMany(lev => lev.Elements.OfType <SpaceBoundary>()))
            {
                var area = sb.Boundary.Area();
                if (sb.Name == null)
                {
                    continue;
                }
                if (!areas.ContainsKey(sb.Name))
                {
                    areas[sb.Name] = new AreaTally(sb.Name, sb.Material.Color, area, area, 1, null, Guid.NewGuid(), sb.Name);
                }
                else
                {
                    var existingTally = areas[sb.Name];
                    existingTally.AchievedArea += area;
                    existingTally.AreaTarget   += area;
                    existingTally.DistinctAreaCount++;
                }
            }
            output.Model.AddElements(areas.Select(kvp => kvp.Value).OrderByDescending(a => a.AchievedArea));
            output.Model.AddElements(levels);
            return(output);
        }
Exemple #22
0
        /// <summary>
        /// The SubdivideSlabNew function.
        /// </summary>
        /// <param name="model">The input model.</param>
        /// <param name="input">The arguments to the execution.</param>
        /// <returns>A SubdivideSlabNewOutputs instance containing computed results and the model with any new elements.</returns>
        public static SubdivideSlabNewOutputs Execute(Dictionary <string, Model> inputModels, SubdivideSlabNewInputs input)
        {
            var model     = new Model();
            var allFloors = new List <Floor>();

            inputModels.TryGetValue("Floors", out var flrModel);
            if (flrModel == null || flrModel.AllElementsOfType <Floor>().Count() == 0)
            {
                throw new ArgumentException("No Floors found.");
            }
            allFloors.AddRange(flrModel.AllElementsOfType <Floor>());
            List <SlabSubdivision> subdivisions = new List <SlabSubdivision>();
            List <ModelCurve>      modelCurves  = new List <ModelCurve>();
            List <Column>          columns      = new List <Column>();

            for (int i = 0; i < allFloors.Count; i++)
            {
                Floor floor      = allFloors[i];
                var   floorId    = StringExtensions.NumberToString(i);
                var   profile    = floor.Profile;
                var   perimeter  = profile.Perimeter;
                var   voids      = profile.Voids;
                var   elevation  = floor.Elevation;
                var   boundaries = new List <Polygon>();
                boundaries.Add(perimeter);
                if (voids != null)
                {
                    boundaries.AddRange(voids);
                }
                Transform transform = null;
                if (input.AlignToLongestEdge)
                {
                    var longestEdge = perimeter.Segments().OrderByDescending(p => p.Length()).First();
                    var xAxis       = (longestEdge.End - longestEdge.Start).Unitized();
                    transform = new Transform(Vector3.Origin, xAxis, Vector3.ZAxis, 0);
                    transform.Invert();
                }
                var grid = new Grid2d(boundaries, transform);
                if (input.SubdivideAtVoidCorners && voids != null && voids.Count > 0)
                {
                    foreach (var voidCrv in voids)
                    {
                        grid.SplitAtPoints(voidCrv.Vertices);
                    }
                    foreach (var cell in grid.CellsFlat)
                    {
                        cell.U.DivideByApproximateLength(input.Length, EvenDivisionMode.RoundUp);
                        cell.V.DivideByApproximateLength(input.Width, EvenDivisionMode.RoundUp);
                    }
                }
                else
                {
                    grid.U.DivideByApproximateLength(input.Length, EvenDivisionMode.RoundUp);
                    grid.V.DivideByApproximateLength(input.Width, EvenDivisionMode.RoundUp);
                }

                var cells = grid.GetCells();

                // foreach(var pt in grid.U.GetCellSeparators())
                // {
                // var column = new Column(new Vector3(pt.X, pt.Y, elevation), 5, Polygon.Rectangle(1.0, 1.0));
                // columns.Add(column);
                // }

                for (int i1 = 0; i1 < cells.Count; i1++)
                {
                    var    id        = $"{floorId}-{i1:000}";
                    Grid2d cell      = cells[i1];
                    var    cellCrvs  = cell.GetTrimmedCellGeometry();
                    var    isTrimmed = cell.IsTrimmed();
                    if (cellCrvs != null && cellCrvs.Length > 0)
                    {
                        subdivisions.Add(CreateSlabSubdivision(id, cellCrvs, floor, isTrimmed));
                        // var column = new Column(pt, 5, Polygon.Rectangle(0.05, 0.05));
                        // output.Model.AddElement(column);
                        var outerBoundary = cellCrvs.First();
                        var polygon       = (Polygon)outerBoundary;
                        var pt            = polygon.Centroid();
                        var column        = new Column(new Vector3(pt.X, pt.Y, elevation), 5, Polygon.Rectangle(1.0, 1.0));
                        columns.Add(column);
                    }
                    foreach (var crv in cellCrvs)
                    {
                        modelCurves.Add(ToModelCurve(crv, elevation + 1.0));
                    }
                }
            }

            var output = new SubdivideSlabNewOutputs(subdivisions.Count, columns.Count);

            output.Model = model;
            // output.Model.AddElements(subdivisions);
            output.Model.AddElements(modelCurves);
            output.Model.AddElements(columns);
            return(output);
        }
Exemple #23
0
        /// <summary>
        /// The PhoneBoothLayout function.
        /// </summary>
        /// <param name="model">The input model.</param>
        /// <param name="input">The arguments to the execution.</param>
        /// <returns>A PhoneBoothLayoutOutputs instance containing computed results and the model with any new elements.</returns>
        public static PhoneBoothLayoutOutputs Execute(Dictionary <string, Model> inputModels, PhoneBoothLayoutInputs input)
        {
            var spacePlanningZones = inputModels["Space Planning Zones"];
            var levelsModel        = inputModels["Levels"];
            var levels             = spacePlanningZones.AllElementsOfType <LevelElements>();
            var levelVolumes       = levelsModel.AllElementsOfType <LevelVolume>();
            var output             = new PhoneBoothLayoutOutputs();
            var configJson         = File.ReadAllText("./PhoneBoothConfigurations.json");
            var configs            = JsonConvert.DeserializeObject <SpaceConfiguration>(configJson);

            var wallMat    = new Material("Drywall", new Color(0.9, 0.9, 0.9, 1.0), 0.01, 0.01);
            var glassMat   = new Material("Glass", new Color(0.7, 0.7, 0.7, 0.3), 0.3, 0.6);
            var mullionMat = new Material("Storefront Mullions", new Color(0.5, 0.5, 0.5, 1.0));

            foreach (var lvl in levels)
            {
                var corridors           = lvl.Elements.OfType <Floor>();
                var corridorSegments    = corridors.SelectMany(p => p.Profile.Segments());
                var meetingRmBoundaries = lvl.Elements.OfType <SpaceBoundary>().Where(z => z.Name == "Phone Booth");
                var levelVolume         = levelVolumes.First(l => l.Name == lvl.Name);
                var wallCandidateLines  = new List <(Line line, string type)>();
                foreach (var room in meetingRmBoundaries)
                {
                    var  spaceBoundary        = room.Boundary;
                    Line orientationGuideEdge = FindEdgeAdjacentToSegments(spaceBoundary.Perimeter.Segments(), corridorSegments, out var wallCandidates);
                    var  exteriorWalls        = FindEdgeAdjacentToSegments(wallCandidates, levelVolume.Profile.Segments(), out var solidWalls, 0.6);
                    wallCandidateLines.AddRange(solidWalls.Select(s => (s, "Solid")));
                    var orientationTransform = new Transform(Vector3.Origin, orientationGuideEdge.Direction(), Vector3.ZAxis);
                    var boundaryCurves       = new List <Polygon>();
                    boundaryCurves.Add(spaceBoundary.Perimeter);
                    boundaryCurves.AddRange(spaceBoundary.Voids ?? new List <Polygon>());

                    var grid = new Grid2d(boundaryCurves, orientationTransform);
                    grid.U.DivideByApproximateLength(input.MinimumSize, EvenDivisionMode.RoundDown);
                    foreach (var cell in grid.GetCells())
                    {
                        var  rect       = cell.GetCellGeometry() as Polygon;
                        var  segs       = rect.Segments();
                        var  width      = segs[0].Length();
                        var  depth      = segs[1].Length();
                        Line glassWall  = null;
                        var  trimmedGeo = cell.GetTrimmedCellGeometry();
                        if (!cell.IsTrimmed() && trimmedGeo.Count() > 0)
                        {
                            glassWall = segs[0];
                            output.Model.AddElement(InstantiateLayout(configs, width, depth, rect, room.Transform));
                        }
                        else if (trimmedGeo.Count() > 0)
                        {
                            var largestTrimmedShape = trimmedGeo.OfType <Polygon>().OrderBy(s => s.Area()).Last();
                            glassWall = largestTrimmedShape.Segments().OrderBy(s => s.PointAt(0.5).DistanceTo(segs[0].PointAt(0.5))).FirstOrDefault();

                            var cinchedVertices = rect.Vertices.Select(v => largestTrimmedShape.Vertices.OrderBy(v2 => v2.DistanceTo(v)).First()).ToList();
                            var cinchedPoly     = new Polygon(cinchedVertices);
                            output.Model.AddElement(InstantiateLayout(configs, width, depth, cinchedPoly, room.Transform));
                        }
                        if (glassWall != null)
                        {
                            wallCandidateLines.Add((glassWall, "Glass"));
                        }
                    }
                    var cellSeparators = grid.GetCellSeparators(GridDirection.V, true);
                    wallCandidateLines.AddRange(grid.GetCellSeparators(GridDirection.V, true).OfType <Curve>().Select(c => (new Line(c.PointAt(0), c.PointAt(1)), "Partition")));
                }
                var mullionSize           = 0.07;
                var doorWidth             = 0.9;
                var doorHeight            = 2.1;
                var sideLightWidth        = 0.4;
                var totalStorefrontHeight = Math.Min(2.7, levelVolume.Height);
                var mullion = new StandardWall(new Line(new Vector3(-mullionSize / 2, 0, 0), new Vector3(mullionSize / 2, 0, 0)), mullionSize, totalStorefrontHeight, mullionMat);
                mullion.IsElementDefinition = true;
                if (input.CreateWalls)
                {
                    foreach (var wallCandidate in wallCandidateLines)
                    {
                        if (wallCandidate.type == "Solid")
                        {
                            output.Model.AddElement(new StandardWall(wallCandidate.line, 0.2, levelVolume.Height, wallMat, levelVolume.Transform));
                        }
                        else if (wallCandidate.type == "Partition")
                        {
                            output.Model.AddElement(new StandardWall(wallCandidate.line, 0.1, levelVolume.Height, wallMat, levelVolume.Transform));
                        }
                        else if (wallCandidate.type == "Glass")
                        {
                            var grid = new Grid1d(wallCandidate.line);
                            grid.SplitAtOffsets(new[] { sideLightWidth, sideLightWidth + doorWidth });
                            grid[2].DivideByApproximateLength(2);
                            var separators = grid.GetCellSeparators(true);
                            var beam       = new Beam(wallCandidate.line, Polygon.Rectangle(mullionSize, mullionSize), mullionMat, 0, 0, 0, isElementDefinition: true);
                            output.Model.AddElement(beam.CreateInstance(levelVolume.Transform, "Base Mullion"));
                            output.Model.AddElement(beam.CreateInstance(levelVolume.Transform.Concatenated(new Transform(0, 0, doorHeight)), "Base Mullion"));
                            output.Model.AddElement(beam.CreateInstance(levelVolume.Transform.Concatenated(new Transform(0, 0, totalStorefrontHeight)), "Base Mullion"));
                            foreach (var separator in separators)
                            {
                                // var line = new Line(separator, separator + new Vector3(0, 0, levelVolume.Height));
                                // output.Model.AddElement(new ModelCurve(line, BuiltInMaterials.XAxis, levelVolume.Transform));
                                var instance = mullion.CreateInstance(new Transform(separator, wallCandidate.line.Direction(), Vector3.ZAxis, 0).Concatenated(levelVolume.Transform), "Mullion");
                                output.Model.AddElement(instance);
                            }
                            output.Model.AddElement(new StandardWall(wallCandidate.line, 0.05, totalStorefrontHeight, glassMat, levelVolume.Transform));
                            var headerHeight = levelVolume.Height - totalStorefrontHeight;
                            if (headerHeight > 0.01)
                            {
                                output.Model.AddElement(new StandardWall(wallCandidate.line, 0.2, headerHeight, wallMat, levelVolume.Transform.Concatenated(new Transform(0, 0, totalStorefrontHeight))));
                            }
                        }
                    }
                }
            }
            InstancePositionOverrides(input.Overrides, output.Model);
            return(output);
        }