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> }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="dataAccess"> /// The DA object is used to retrieve from inputs and store in outputs. /// </param> protected override void SolveInstance(IGH_DataAccess dataAccess) { List <GH_ObjectWrapper> objectWrapperList = new List <GH_ObjectWrapper>(); if (!dataAccess.GetDataList(0, objectWrapperList) || objectWrapperList == null) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid data"); return; } GH_ObjectWrapper objectWrapper = null; if (!dataAccess.GetData(1, ref objectWrapper) || objectWrapper.Value == null) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid data"); return; } GH_Number gHNumber = objectWrapper.Value as GH_Number; if (gHNumber == null) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid data"); return; } CellComplex cellComplex = CellComplex.ByFaces(objectWrapperList.ConvertAll(x => x.Value as global::Topologic.Face), gHNumber.Value); dataAccess.SetData(0, cellComplex); }
private static void DrawCellComplexSkeleton(Model model, CellComplex cellComplex) { foreach (var edge in cellComplex.GetEdges()) { model.AddElement(new ModelCurve(edge.GetGeometry(), DefaultPanelMaterial)); } }
public static Line ToLine(this Elements.Spatial.CellComplex.Edge edge, CellComplex cellComplex) { var start = cellComplex.GetVertex(edge.StartVertexId).Value; var end = cellComplex.GetVertex(edge.EndVertexId).Value; var l = new Line(start, end); return(l); }
public static bool TrySplit(this IEnumerable <Spatial.Shell> shells_In, out List <Spatial.Shell> shells_Out, out List <Topology> topologies, double tolerance = Core.Tolerance.Distance) { shells_Out = null; topologies = null; if (shells_In == null) { return(false); } List <Cell> cells = new List <Cell>(); foreach (Spatial.Shell shell in shells_In) { Cell cell = shell?.ToTopologic_Cell(tolerance); if (cell == null) { continue; } cells.Add(cell); } if (cells == null) { return(false); } CellComplex cellComplex = null; try { cellComplex = CellComplex.ByCells(cells); } catch (Exception exception) { } if (cellComplex == null) { return(false); } topologies = new List <Topology>() { cellComplex }; cells = cellComplex.Cells?.ToList(); if (cells == null || cells.Count == 0) { return(false); } shells_Out = cells.ToSAM(); return(shells_Out != null); }
private List <Object> ToBreps(CellComplex cellComplex, double tolerance) { List <Cell> cells = cellComplex.Cells; List <Object> ghBreps = new List <Object>(); foreach (Cell cell in cells) { List <Object> ghBrep = ToBrep(cell, tolerance); ghBreps.AddRange(ghBrep); } return(ghBreps); }
public static List <Brep> ToRhino_Breps(CellComplex cellComplex, double tolerance) { IList <Cell> cells = cellComplex.Cells; List <Brep> ghBreps = new List <Brep>(); foreach (Cell cell in cells) { List <Brep> ghBrep = ToRhino_Breps(cell, tolerance); ghBreps.AddRange(ghBrep); } return(ghBreps); }
// 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); }
private static bool TryGetSpaceAdjacency(this IList <Face> faces, IEnumerable <Topology> topologies, double tolerance, out List <Geometry.Spatial.ISAMGeometry3D> sAMGeometryList, out List <List <string> > names) { CellComplex cellComplex = CellComplex.ByFaces(faces, tolerance); if (cellComplex == null) { sAMGeometryList = null; names = null; return(false); } if (topologies != null) { cellComplex = (CellComplex)cellComplex.AddContents(topologies.ToList(), 32); } int index = 0; names = new List <List <string> >(); sAMGeometryList = new List <Geometry.Spatial.ISAMGeometry3D>(); foreach (Face face in cellComplex.Faces) { List <string> nameList = new List <string>(); names.Add(nameList); sAMGeometryList.Add(Geometry.Topologic.Convert.ToSAM(face)); foreach (Cell cell in face.Cells) { foreach (Topology topology in cell.Contents) { Vertex vertex = topology as Vertex; if (vertex == null) { continue; } nameList.Add(vertex.Dictionary["Name"] as string); } } index++; } return(true); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="dataAccess"> /// The DA object is used to retrieve from inputs and store in outputs. /// </param> protected override void SolveInstance(IGH_DataAccess dataAccess) { GH_ObjectWrapper objectWrapper = null; if (!dataAccess.GetData(0, ref objectWrapper) || objectWrapper.Value == null) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid data"); return; } CellComplex cellComplex = objectWrapper.Value as CellComplex; if (cellComplex == null) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid data"); return; } dataAccess.SetDataList(0, cellComplex.Faces); }
public static bool EndsOnGrid(this Elements.Spatial.CellComplex.Edge edge, CellComplex cellComplex) { return(!string.IsNullOrEmpty(cellComplex.GetVertex(edge.EndVertexId).Name)); }
public static AdjacencyCluster AdjacencyCluster(IEnumerable <Space> spaces, IEnumerable <Panel> panels, out List <Topology> topologies, out List <Panel> redundantPanels, double minArea = Tolerance.MacroDistance, bool updatePanels = true, bool tryCellComplexByCells = true, Log log = null, double silverSpacing = Tolerance.MacroDistance, double tolerance = Tolerance.Distance) { Core.Modify.Add(log, "Method Name: {0}, Tolerance: {1}, Update Panels: {2}", "SAM.Analytical.Topologic.Create.AdjacencyCluster", tolerance, updatePanels); topologies = null; redundantPanels = null; AdjacencyCluster result = new AdjacencyCluster(); result.AddObjects(spaces); result.AddObjects(panels); List <Face> faces = new List <Face>(); int index = 1; foreach (Panel panel in result.GetObjects <Panel>()) { if (panel == null) { continue; } Face face = Convert.ToTopologic(panel); if (face == null) { continue; } faces.Add(face); Core.Modify.Add(log, "Face {0:D4} added. Panel [{1}]", index, panel.Guid); index++; } if (faces == null || faces.Count == 0) { return(null); } topologies = new List <Topology>(); List <Cell> cells = null; if (tryCellComplexByCells) { try { Core.Modify.Add(log, "Trying to make CellComplex By Cells"); Cluster cluster = Cluster.ByTopologies(faces as IList <Topology>); Core.Modify.Add(log, "Cluster.ByTopologies Done"); Topology topology = cluster.SelfMerge(); Core.Modify.Add(log, "Cluster SelfMerge Done"); if (topology.Cells != null && topology.Cells.Count != 0) { cells = topology.Cells?.ToList(); CellComplex cellComplex = null; try { cellComplex = CellComplex.ByCells(cells); } catch (Exception exception) { Core.Modify.Add(log, "Cells could not be taken from CellComplex"); Core.Modify.Add(log, "Exception Message: {0}", exception.Message); } if (cellComplex != null && cellComplex.Cells != null && cellComplex.Cells.Count != 0) { topologies.Add(cellComplex); cells = cellComplex.Cells?.ToList(); } else { topologies.Add(topology); Core.Modify.Add(log, "Cells taken from Cluster"); } } } catch (Exception exception) { Core.Modify.Add(log, "Cannot create CellComplex By Cells or Cells form Cluster SelfMerge"); Core.Modify.Add(log, "Exception Message: {0}", exception.Message); cells = null; } } if (cells == null) { try { Core.Modify.Add(log, "Trying to make CellComplex By Faces"); CellComplex cellComplex = CellComplex.ByFaces(faces, tolerance); topologies.Add(cellComplex); cells = cellComplex.Cells?.ToList(); Core.Modify.Add(log, "CellComplex By Faces Created"); } catch (Exception exception) { Core.Modify.Add(log, "Cannot create CellComplex By Faces"); Core.Modify.Add(log, "Exception Message: {0}", exception.Message); cells = null; } } if (cells == null || cells.Count == 0) { Core.Modify.Add(log, "No cells found"); return(null); } List <Geometry.Spatial.Shell> shells = cells.ToSAM(); Core.Modify.Add(log, "Single CellComplex converted to shells"); if (shells == null) { return(null); } //Matching spaces with shells Dictionary <Geometry.Spatial.Shell, List <Space> > dictionary_Spaces = new Dictionary <Geometry.Spatial.Shell, List <Space> >(); if (spaces != null) { foreach (Space space in spaces) { if (space == null || space.Location == null || !space.IsPlaced()) { continue; } List <Geometry.Spatial.Shell> shells_Temp = Analytical.Query.SpaceShells(shells, space.Location, silverSpacing, tolerance); if (shells_Temp == null || shells_Temp.Count == 0) { continue; } foreach (Geometry.Spatial.Shell shell in shells_Temp) { if (!dictionary_Spaces.TryGetValue(shell, out List <Space> spaces_Shell)) { spaces_Shell = new List <Space>(); dictionary_Spaces[shell] = spaces_Shell; } spaces_Shell.Add(space); } } } HashSet <Guid> guids_Updated = new HashSet <Guid>(); Dictionary <Panel, Face3D> dictionary_Panel_Face3D = new Dictionary <Panel, Face3D>(); result.GetObjects <Panel>().ForEach(x => dictionary_Panel_Face3D[x] = x.GetFace3D()); index = 1; List <Tuple <Panel, Point3D> > tuples_InternalPoint3D = new List <Tuple <Panel, Point3D> >(); for (int i = 0; i < shells.Count; i++) { Geometry.Spatial.Shell shell = shells[i]; if (shell == null) { return(null); } Core.Modify.Add(log, "Simplifying shell"); //shell.Simplify(tolerance); // Low tolerance cause of rounding issues shell.Simplify(); Core.Modify.Add(log, "Extracting faces from shell"); List <Face3D> face3Ds = shell?.Face3Ds; if (face3Ds == null) { Core.Modify.Add(log, "No face2Ds found in Shell"); continue; } dictionary_Spaces.TryGetValue(shell, out List <Space> spaces_Shell); if (spaces_Shell == null || spaces_Shell.Count == 0) { Core.Modify.Add(log, "Creating new Space"); Point3D location = shell.CalculatedInternalPoint3D(silverSpacing, tolerance); if (location == null) { continue; } Space space = new Space("Cell " + index, location); index++; if (!result.AddObject(space)) { continue; } spaces_Shell = new List <Space>() { space }; dictionary_Spaces[shell] = spaces_Shell; } if (spaces_Shell == null || spaces_Shell.Count == 0) { continue; } double volume = double.NaN; if (cells[i] != null) { Core.Modify.Add(log, "Calculating Volume"); volume = CellUtility.Volume(cells[i]); foreach (Space space_Shell in spaces_Shell) { space_Shell.SetValue(SpaceParameter.Volume, volume); } } Core.Modify.Add(log, "Upadting Panels"); foreach (Face3D face3D in face3Ds) { if (minArea != 0 && face3D.GetArea() <= minArea) { Core.Modify.Add(log, "Face3D is too small"); continue; } Core.Modify.Add(log, "Looking for existing Panel"); Tuple <Panel, Point3D> tuple_InternalPoint3D = tuples_InternalPoint3D.Find(x => face3D.Inside(x.Item2, tolerance)); if (tuple_InternalPoint3D != null) { Core.Modify.Add(log, "Existing Panel found: {0}", tuple_InternalPoint3D.Item1.Guid); foreach (Space space in spaces_Shell) { if (result.AddRelation(space, tuple_InternalPoint3D.Item1)) { Core.Modify.Add(log, "Space [{0}] and Panel [{1}] relation added", space.Guid, tuple_InternalPoint3D.Item1.Guid); } } continue; } Core.Modify.Add(log, "Looking for old Panel"); //Panel panel_Old = Query.SimilarPanel(face3D, dictionary_Panel_Face3D); //if (panel_Old == null) // continue; List <Panel> panels_Old = Query.SimilarPanels(face3D, dictionary_Panel_Face3D); if (panels_Old == null || panels_Old.Count == 0) { continue; } Panel panel_Old = panels_Old.First(); if (panels_Old.Count > 1) { if (redundantPanels == null) { redundantPanels = new List <Panel>(); } panels_Old.RemoveAt(0); redundantPanels.AddRange(panels_Old); } Core.Modify.Add(log, "Old Panel found: {0}", panel_Old.Guid); Panel panel_New = null; if (updatePanels) { if (guids_Updated.Contains(panel_Old.Guid)) { panel_New = Analytical.Create.Panel(Guid.NewGuid(), panel_Old, face3D); Core.Modify.Add(log, "Creating new Panel for Old Panel [{0}]. New Panel [{1}]", panel_Old.Guid, panel_New.Guid); } else { panel_New = Analytical.Create.Panel(panel_Old.Guid, panel_Old, face3D); guids_Updated.Add(panel_Old.Guid); Core.Modify.Add(log, "Updating Panel [{0}] with new geometry", panel_New.Guid); } result.AddObject(panel_New); } else { panel_New = Analytical.Create.Panel(panel_Old.Guid, panel_Old, face3D); Core.Modify.Add(log, "Creating temporary Panel for Panel [{0}]", panel_New.Guid); } if (panel_New == null) { continue; } tuples_InternalPoint3D.Add(new Tuple <Panel, Point3D>(panel_New, face3D.InternalPoint3D(tolerance))); foreach (Space space in spaces_Shell) { if (result.AddRelation(space, panel_New)) { Core.Modify.Add(log, "Space [{0}] and Panel [{1}] relation added", space.Guid, panel_New.Guid); } } Core.Modify.Add(log, "Adding face finished"); } } if (redundantPanels != null && redundantPanels.Count != 0) { Core.Modify.Add(log, "Solving Redundant Panels"); foreach (Panel panel in redundantPanels) { result.RemoveObject <Panel>(panel.Guid); } } List <Panel> panels_Shading = Analytical.Query.CutShading(result.GetPanels(), panels, tolerance); if (panels_Shading != null || panels_Shading.Count != 0) { foreach (Panel panel_Shading in panels_Shading) { result.AddObject(panel_Shading); } } Core.Modify.Add(log, "AdjacencyCluster verification"); Log log_AdjacencyCluster = Analytical.Create.Log(result); if (log != null) { log.AddRange(log_AdjacencyCluster); } Core.Modify.Add(log, "Process completed"); return(result); }
public static List <Spatial.Shell> ToSAM(this CellComplex cellComplex) { return(ToSAM(cellComplex?.Cells)); }
private List <Object> ToGeometry(Topology topology, double tolerance) { if (topology == null) { return(null); } List <Object> geometries = new List <Object>(); Vertex vertex = topology as Vertex; if (vertex != null) { geometries.Add(ToPoint(vertex)); return(geometries); } Edge edge = topology as Edge; if (edge != null) { geometries.Add(ToCurve(edge)); return(geometries); } Wire wire = topology as Wire; if (wire != null) { return(ToCurves(wire)); } Face face = topology as Face; if (face != null) { geometries.Add(ToSurface(face, tolerance)); return(geometries); } Shell shell = topology as Shell; if (shell != null) { return(ToBrep(shell, tolerance)); } Cell cell = topology as Cell; if (cell != null) { return(ToBrep(cell, tolerance)); } CellComplex cellComplex = topology as CellComplex; if (cellComplex != null) { return(ToBreps(cellComplex, tolerance)); } Cluster cluster = topology as Cluster; if (cluster != null) { return(ToGeometries(cluster, tolerance)); } Aperture aperture = topology as Aperture; if (aperture != null) { return(ToGeometry(aperture.Topology, tolerance)); } throw new Exception("The type of the input topology is not recognized."); }
public static List <Spatial.Shell> Shells(IEnumerable <Face3D> face3Ds, out List <Topology> topologies, bool tryCellComplexByCells = true, double tolerance = Tolerance.Distance) { topologies = null; if (face3Ds == null || face3Ds.Count() == 0) { return(null); } List <global::Topologic.Face> faces = new List <global::Topologic.Face>(); foreach (Face3D face3D in face3Ds) { global::Topologic.Face face = Convert.ToTopologic(face3D); if (face == null) { continue; } faces.Add(face); } topologies = new List <Topology>(); List <Cell> cells = null; if (tryCellComplexByCells) { try { Cluster cluster = Cluster.ByTopologies(faces as IList <Topology>); Topology topology = cluster.SelfMerge(); if (topology.Cells != null && topology.Cells.Count != 0) { cells = topology.Cells?.ToList(); CellComplex cellComplex = null; try { cellComplex = CellComplex.ByCells(cells); } catch (Exception exception) { cellComplex = null; } if (cellComplex != null && cellComplex.Cells != null && cellComplex.Cells.Count != 0) { topologies.Add(cellComplex); cells = cellComplex.Cells?.ToList(); } else { topologies.Add(topology); } } } catch (Exception exception) { cells = null; } } if (cells == null) { try { CellComplex cellComplex = CellComplex.ByFaces(faces, tolerance); topologies.Add(cellComplex); cells = cellComplex.Cells?.ToList(); } catch (Exception exception) { cells = null; } } return(cells?.ToSAM()); }
public static bool StartsOrEndsAtThisVertex(this Elements.Spatial.CellComplex.Edge edge, ulong vertexId, CellComplex cellComplex) { return(edge.StartVertexId == vertexId || edge.EndVertexId == vertexId); }
public static bool TrySplit_Obsolete(this IEnumerable <Spatial.Shell> shells_In, out List <Spatial.Shell> shells_Out, out List <Topology> topologies, bool tryCellComplexByCells = true, double tolerance = Core.Tolerance.Distance) { shells_Out = null; topologies = null; if (shells_In == null) { return(false); } List <global::Topologic.Face> faces = new List <global::Topologic.Face>(); foreach (Spatial.Shell shell in shells_In) { List <Face3D> face3Ds = shell?.Face3Ds; if (face3Ds == null || face3Ds.Count == 0) { continue; } foreach (Face3D face3D in face3Ds) { global::Topologic.Face face = Convert.ToTopologic(face3D); if (face != null) { faces.Add(face); } } } topologies = new List <Topology>(); List <Cell> cells = null; if (tryCellComplexByCells) { try { Cluster cluster = Cluster.ByTopologies(faces as IList <Topology>); Topology topology = cluster.SelfMerge(); if (topology.Cells != null && topology.Cells.Count != 0) { cells = topology.Cells?.ToList(); CellComplex cellComplex = null; try { cellComplex = CellComplex.ByCells(cells); } catch (Exception exception) { } if (cellComplex != null && cellComplex.Cells != null && cellComplex.Cells.Count != 0) { topologies.Add(cellComplex); cells = cellComplex.Cells?.ToList(); } else { topologies.Add(topology); } } } catch (Exception exception) { cells = null; } } if (cells == null) { try { CellComplex cellComplex = CellComplex.ByFaces(faces, tolerance); topologies.Add(cellComplex); cells = cellComplex.Cells?.ToList(); } catch (Exception exception) { cells = null; } } if (cells == null || cells.Count == 0) { return(false); } shells_Out = cells.ToSAM(); return(shells_Out != null); }
public static double Length(this Elements.Spatial.CellComplex.Edge edge, CellComplex cellComplex) { return(cellComplex.GetVertex(edge.StartVertexId).Value.DistanceTo(cellComplex.GetVertex(edge.EndVertexId).Value)); }
public static bool IsVertical(this Elements.Spatial.CellComplex.Edge edge, CellComplex cellComplex) { return(cellComplex.GetVertex(edge.StartVertexId).Value.IsDirectlyUnder(cellComplex.GetVertex(edge.EndVertexId).Value) || cellComplex.GetVertex(edge.EndVertexId).Value.IsDirectlyUnder(cellComplex.GetVertex(edge.StartVertexId).Value)); }
public static bool IsHorizontal(this Elements.Spatial.CellComplex.Edge edge, CellComplex cellComplex) { return(cellComplex.GetVertex(edge.StartVertexId).Value.Z.ApproximatelyEquals(cellComplex.GetVertex(edge.EndVertexId).Value.Z)); }
/// <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)];
public static List <object> ToRhino(this Topology topology, double tolerance = Core.Tolerance.Distance) { if (topology == null) { return(null); } List <Object> geometries = new List <Object>(); Vertex vertex = topology as Vertex; if (vertex != null) { geometries.Add(ToRhino(vertex)); return(geometries); } Edge edge = topology as Edge; if (edge != null) { geometries.Add(ToRhino(edge)); return(geometries); } Wire wire = topology as Wire; if (wire != null) { return(ToRhino(wire)?.Cast <object>().ToList()); } global::Topologic.Face face = topology as global::Topologic.Face; if (face != null) { geometries.Add(ToRhino(face, tolerance)); return(geometries); } Shell shell = topology as Shell; if (shell != null) { return(ToRhino_Breps(shell, tolerance)?.Cast <object>().ToList()); } Cell cell = topology as Cell; if (cell != null) { return(ToRhino_Breps(cell, tolerance)?.Cast <object>().ToList()); } CellComplex cellComplex = topology as CellComplex; if (cellComplex != null) { return(ToRhino_Breps((CellComplex)cellComplex, tolerance)?.Cast <object>().ToList()); } Cluster cluster = topology as Cluster; if (cluster != null) { return(ToRhino(cluster.SubTopologies, tolerance)); } Aperture aperture = topology as Aperture; if (aperture != null) { return(ToRhino(aperture.Topology, tolerance)); } throw new Exception("The type of the input topology is not recognized."); }
public static bool StartsOrEndsOnGrid(this Elements.Spatial.CellComplex.Edge edge, CellComplex cellComplex) { return(StartsOnGrid(edge, cellComplex) || EndsOnGrid(edge, cellComplex)); }