public static SpaceBoundary[] SpaceBoundaryFromRevitArea(ADSK.Area area, Document doc, View view = null) { if (view == null) { view = GetViewWhereElemIsVisible(doc, area); } var geom = area.get_Geometry(new Options() { View = view }); var solid = geom.Where(g => typeof(ADSK.Solid) == g.GetType()).Cast <ADSK.Solid>().Where(s => s != null); var face = solid.First().Faces.get_Item(0) as PlanarFace; var boundaries = new List <SpaceBoundary>(); foreach (var p in face.GetProfiles(true)) { var boundary = new SpaceBoundary(p, new Elements.Geometry.Transform(), BuiltInMaterials.Default, null, false, Guid.NewGuid(), ""); boundaries.Add(boundary); } return(boundaries.ToArray()); }
private static void SplitZones(SpacePlanningZonesInputs input, double corridorWidth, LevelVolume lvl, List <Element> spaceBoundaries, List <Profile> corridorProfiles, Vector3 pt, bool addCorridor = true) { var containingBoundary = spaceBoundaries.OfType <SpaceBoundary>().FirstOrDefault(b => b.Boundary.Contains(pt)); if (containingBoundary != null) { if (input.Overrides != null) { var spaceOverrides = input.Overrides.ProgramAssignments.FirstOrDefault(s => s.Identity.IndividualCentroid.IsAlmostEqualTo(containingBoundary.Boundary.Perimeter.Centroid())); if (spaceOverrides != null) { containingBoundary.Name = spaceOverrides.Value.ProgramType; } } spaceBoundaries.Remove(containingBoundary); var perim = containingBoundary.Boundary.Perimeter; pt.DistanceTo(perim, out var cp); var line = new Line(pt, cp); var extension = line.ExtendTo(containingBoundary.Boundary); List <Profile> newSbs = new List <Profile>(); if (addCorridor) { var corridorShape = extension.ToPolyline(1).Offset(corridorWidth / 2, EndType.Square); var csAsProfiles = corridorShape.Select(s => new Profile(s)); var corridorShapesIntersected = Profile.Intersection(new[] { containingBoundary.Boundary }, csAsProfiles); corridorProfiles.AddRange(corridorShapesIntersected); newSbs = Profile.Difference(new[] { containingBoundary.Boundary }, csAsProfiles); } else { newSbs = Profile.Split(new[] { containingBoundary.Boundary }, new[] { extension.ToPolyline(1) }, Vector3.EPSILON); } spaceBoundaries.AddRange(newSbs.Select(p => SpaceBoundary.Make(p, containingBoundary.Name, containingBoundary.Transform, lvl.Height))); } }
public static SpaceBoundary[] SpaceBoundaries(this List <BHE.Panel> spaceBoundaries, List <BHE.Panel> uniqueBEs) { List <Polyloop> pLoops = new List <Polyloop>(); List <BHG.Polyline> panels = spaceBoundaries.Select(x => x.Polyline()).ToList(); foreach (BHG.Polyline pLine in panels) { if (BH.Engine.Environment.Query.NormalAwayFromSpace(pLine, spaceBoundaries)) { pLoops.Add(BH.Engine.XML.Convert.ToGBXML(pLine)); } else { pLoops.Add(BH.Engine.XML.Convert.ToGBXML(pLine.Flip())); } } SpaceBoundary[] boundaries = new SpaceBoundary[pLoops.Count]; for (int x = 0; x < pLoops.Count; x++) { PlanarGeometry planarGeom = new PlanarGeometry(); planarGeom.PolyLoop = pLoops[x]; planarGeom.ID = "pGeom" + Guid.NewGuid().ToString().Replace("-", "").Substring(0, 10); boundaries[x] = new SpaceBoundary { PlanarGeometry = planarGeom }; //Get the ID from the referenced element boundaries[x].SurfaceIDRef = "Panel-" + uniqueBEs.FindIndex(i => i.BHoM_Guid == spaceBoundaries[x].BHoM_Guid).ToString(); } return(boundaries); }
static public SpaceBoundary MakeSpaceBoundary(SpaceBoundary sb, List <List <double> > points, int surfacecount) { sb.surfaceIdRef = "su-" + surfacecount.ToString(); sb.PlanarGeometry = new PlanarGeometry(); sb.PlanarGeometry.PolyLoop = new PolyLoop(); sb.PlanarGeometry.PolyLoop = makePolyLoopsFromDbleList(sb.PlanarGeometry.PolyLoop, points); return(sb); }
public static SpaceBoundary TogbXML_SpaceBoundary(this Panel panel, double tolerance = Core.Tolerance.MicroDistance) { if (panel == null) { return(null); } Geometry.Spatial.Face3D face3D = panel.PlanarBoundary3D.GetFace3D(); if (face3D == null) { return(null); } SpaceBoundary spaceBoundary = new SpaceBoundary(); spaceBoundary.surfaceIdRef = Core.gbXML.Query.Id(panel, typeof(Surface)); spaceBoundary.PlanarGeometry = face3D.TogbXML(tolerance); return(spaceBoundary); }
public static List <Space> MakeSpacesFromEPObj(List <EPObj.MemorySafe_Spaces> myspace) { List <Space> retspaces = new List <Space>(); int spacecount = 0; foreach (EPObj.MemorySafe_Spaces space in myspace) { //foreach Space space in your ListofSpaces Space zespace = new Space(); zespace.id = "Space-1"; zespace.lightScheduleIdRef = "lightSchedule-1"; zespace.equipmentScheduleIdRef = "equipmentSchedule-1"; zespace.peopleScheduleIdRef = "peopleSchedule-1"; zespace.conditionType = "HeatedAndCooled"; zespace.buildingStoreyIdRef = "bldg-story-1"; zespace.Name = "Test Space-" + spacecount; zespace.peoplenum = 12; zespace.totalpeoplegain = 450; zespace.senspeoplegain = 250; zespace.latpeoplegain = 200; zespace.PeopleHeatGains = new PeopleHeatGain[3]; zespace.lpd = 1.2; zespace.epd = 1.5; zespace.Area = 2450; zespace.Volume = 24500; zespace.PlanarGeo = new PlanarGeometry(); zespace.ShellGeo = new ShellGeometry(); PeopleNumber pn = new PeopleNumber(); pn.unit = peopleNumberUnitEnum.NumberOfPeople; string people = gb.FormatDoubleToString(zespace.peoplenum); pn.valuefield = people; zespace.PeopleNumber = pn; PeopleHeatGain phg = new PeopleHeatGain(); phg.unit = peopleHeatGainUnitEnum.BtuPerHourPerson; phg.heatGainType = peopleHeatGainTypeEnum.Total; string totalpopload = gb.FormatDoubleToString(zespace.totalpeoplegain); phg.value = totalpopload; zespace.PeopleHeatGains[0] = phg; PeopleHeatGain shg = new PeopleHeatGain(); shg.unit = peopleHeatGainUnitEnum.BtuPerHourPerson; shg.heatGainType = peopleHeatGainTypeEnum.Sensible; string senspopload = gb.FormatDoubleToString(zespace.senspeoplegain); shg.value = senspopload; zespace.PeopleHeatGains[1] = shg; PeopleHeatGain lhg = new PeopleHeatGain(); lhg.unit = peopleHeatGainUnitEnum.BtuPerHourPerson; lhg.heatGainType = peopleHeatGainTypeEnum.Latent; string latpopload = gb.FormatDoubleToString(zespace.latpeoplegain); lhg.value = latpopload; zespace.PeopleHeatGains[2] = lhg; LightPowerPerArea lpd = new LightPowerPerArea(); lpd.unit = powerPerAreaUnitEnum.WattPerSquareFoot; lpd.lpd = gb.FormatDoubleToString(zespace.lpd); zespace.LightPowerPerArea = lpd; EquipPowerPerArea epd = new EquipPowerPerArea(); epd.unit = powerPerAreaUnitEnum.WattPerSquareFoot; epd.epd = gb.FormatDoubleToString(zespace.epd); zespace.EquipPowerPerArea = epd; Area spacearea = new Area(); spacearea.val = gb.FormatDoubleToString(zespace.Area); zespace.spacearea = spacearea; Volume spacevol = new Volume(); spacevol.val = gb.FormatDoubleToString(zespace.Volume); zespace.spacevol = spacevol; //same as the planar geometry of the floor planes above PlanarGeometry spaceplpoly = new PlanarGeometry(); //get a list of points that makes up the polyloop List <List <double> > spacepoints = prod.MakeFakeList(3); //make polyloop with points spaceplpoly.PolyLoop = new PolyLoop(); spaceplpoly.PolyLoop = prod.makePolyLoopsFromDbleList(spaceplpoly.PolyLoop, spacepoints); zespace.PlanarGeo = spaceplpoly; //@@ //ShellGeometry //similar to planar geometry, but with more planes ShellGeometry sg = new ShellGeometry(); sg.unit = lengthUnitEnum.Feet; sg.id = "sg" + space.name; sg.ClosedShell = new ClosedShell(); //up to 100 surfaces per space? base on the space instance surfaces sg.ClosedShell.PolyLoops = new PolyLoop[space.spaceSurfaces.Count()]; //I would have a list of surface elements that make up the space surfaces. //each surface would consist of a series of points that defines the surface. for (int i = 0; i < space.spaceSurfaces.Count(); i++) { //get points from the space surfaces List <List <double> > epluspoints = new List <List <double> >(); epluspoints = EnergyPlusClass.GetCoordinDoubles(space.spaceSurfaces[i].SurfaceCoords); sg.ClosedShell.PolyLoops[i] = new PolyLoop(); sg.ClosedShell.PolyLoops[i] = prod.makePolyLoopsFromDbleList(sg.ClosedShell.PolyLoops[i], epluspoints); } zespace.ShellGeo = sg; zespace.cadid = new CADObjectId(); zespace.cadid.id = "990099-" + spacecount; //make surface boundaries..special code needed so that space boundaries are not duplicated... //option 1 : the surfaces already declared as internal somehow and how shared. //option 2: the api tries to figure it out zespace.spbound = new SpaceBoundary[space.spaceSurfaces.Count()]; int psurfacecount = 0; for (int i = 0; i < space.spaceSurfaces.Count(); i++) { //get points from the space surfaces List <List <double> > epluspoints = new List <List <double> >(); epluspoints = EnergyPlusClass.GetCoordinDoubles(space.spaceSurfaces[i].SurfaceCoords); //if surface is exterior SpaceBoundary sb = new SpaceBoundary(); zespace.spbound[i] = prod.MakeSpaceBoundary(sb, epluspoints, psurfacecount); psurfacecount++; //else if surface is interior and it has not been listed before //then do the same //else do nothing because it is interior and it has already been listed //I also would like to keep track of all the surfaces that I create to better prepare me for the surface definition uniquesurf.Add(zespace.spbound[i].PlanarGeometry); //make a dictionary that stores the name of a surface and its planar geometry? uniqueplanes.Add(zespace.spbound[i].surfaceIdRef, zespace.spbound[i].PlanarGeometry); //make a dictionary that stores the name of a surface and create a surface as the value Surface newsurface = new Surface(); //this took a lot of customization...a user would have to make their own code to attach to my object here newsurface = prod.SetUpSurfaceFromIDF(space.spaceSurfaces[i], zespace.spbound[i].PlanarGeometry); uniquesurfaces.Add(zespace.spbound[i].surfaceIdRef, newsurface); } retspaces.Add(zespace); spacecount++; } return(retspaces); }
/// <summary> /// The OpenOfficeLayout function. /// </summary> /// <param name="model">The input model.</param> /// <param name="input">The arguments to the execution.</param> /// <returns>A OpenOfficeLayoutOutputs instance containing computed results and the model with any new elements.</returns> public static OpenOfficeLayoutOutputs Execute(Dictionary <string, Model> inputModels, OpenOfficeLayoutInputs input) { var catalog = JsonConvert.DeserializeObject <ContentCatalog>(File.ReadAllText("./catalog.json")); var spacePlanningZones = inputModels["Space Planning Zones"]; var levels = spacePlanningZones.AllElementsOfType <LevelElements>(); var deskCount = 0; var configJson = File.ReadAllText("OpenOfficeDeskConfigurations.json"); var configs = JsonConvert.DeserializeObject <SpaceConfiguration>(configJson); var defaultConfig = configs[Hypar.Model.Utilities.GetStringValueFromEnum(input.DeskType)]; var desksPerInstance = input.DeskType == OpenOfficeLayoutInputsDeskType.Enclosed_Pair || input.DeskType == OpenOfficeLayoutInputsDeskType.Double_Desk ? 2 : 1; var output = new OpenOfficeLayoutOutputs(); var overridesByCentroid = new Dictionary <Guid, SpaceSettingsOverride>(); foreach (var spaceOverride in input.Overrides?.SpaceSettings ?? new List <SpaceSettingsOverride>()) { var matchingBoundary = levels.SelectMany(l => l.Elements).OfType <SpaceBoundary>().OrderBy(ob => ((JObject)ob.AdditionalProperties["ParentCentroid"]).ToObject <Vector3>().DistanceTo(spaceOverride.Identity.ParentCentroid)).First(); if (overridesByCentroid.ContainsKey(matchingBoundary.Id)) { var mbCentroid = ((JObject)matchingBoundary.AdditionalProperties["ParentCentroid"]).ToObject <Vector3>(); if (overridesByCentroid[matchingBoundary.Id].Identity.ParentCentroid.DistanceTo(mbCentroid) > spaceOverride.Identity.ParentCentroid.DistanceTo(mbCentroid)) { overridesByCentroid[matchingBoundary.Id] = spaceOverride; } } else { overridesByCentroid.Add(matchingBoundary.Id, spaceOverride); } } foreach (var lvl in levels) { var corridors = lvl.Elements.OfType <Floor>(); var corridorSegments = corridors.SelectMany(p => p.Profile.Segments()); var officeBoundaries = lvl.Elements.OfType <SpaceBoundary>().Where(z => z.Name == "Open Office"); foreach (var ob in officeBoundaries) { // create a boundary we can use to override individual groups of desks. It's sunk slightly so that, if floors are on, you don't see it. var overridableBoundary = new SpaceBoundary(ob.Boundary, ob.Cells, ob.Transform.Concatenated(new Transform(0, 0, -0.05)), ob.Material, new Representation(new[] { new Lamina(ob.Boundary.Perimeter, false) }), false, Guid.NewGuid(), "DeskArea"); overridableBoundary.AdditionalProperties.Add("ParentCentroid", (ob.AdditionalProperties["ParentCentroid"] as JObject).ToObject <Vector3>()); overridableBoundary.AdditionalProperties.Add("Desk Type", Hypar.Model.Utilities.GetStringValueFromEnum(input.DeskType)); output.Model.AddElement(overridableBoundary); var spaceBoundary = ob.Boundary; Line orientationGuideEdge = FindEdgeAdjacentToCorridor(spaceBoundary.Perimeter, corridorSegments); 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>()); Grid2d grid; try { grid = new Grid2d(boundaryCurves, orientationTransform); } catch { Console.WriteLine("Something went wrong creating a grid."); continue; } var selectedConfig = defaultConfig; if (overridesByCentroid.ContainsKey(ob.Id)) { var spaceOverride = overridesByCentroid[ob.Id]; selectedConfig = configs[Hypar.Model.Utilities.GetStringValueFromEnum(spaceOverride.Value.DeskType)]; overridableBoundary.AdditionalProperties["Desk Type"] = Hypar.Model.Utilities.GetStringValueFromEnum(spaceOverride.Value.DeskType); } var aisleWidth = 1.0; grid.V.DivideByPattern(new[] { ("Desk", selectedConfig.Width), ("Desk", selectedConfig.Width), ("Desk", selectedConfig.Width), ("Desk", selectedConfig.Width), ("Aisle", aisleWidth) }, PatternMode.Cycle, FixedDivisionMode.RemainderAtBothEnds);
public static List<SpaceBoundary> GetSpaceBoundaryList(XmlDocument gbXMLDoc, XmlNamespaceManager gbXMLnsm) { List<SpaceBoundary> sbList = new List<SpaceBoundary>(); try { XmlNodeList nodes = gbXMLDoc.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space/gbXMLv5:SpaceBoundary", gbXMLnsm); foreach (XmlNode node in nodes) { SpaceBoundary sb = new SpaceBoundary(); string spaceboundaryId; spaceboundaryId = node.Attributes[0].Value.ToString(); sb.surfaceIdRef = spaceboundaryId; XmlNodeList sbchilds = node.ChildNodes; foreach (XmlNode sbpnode in sbchilds) { if (sbpnode.Name == "PlanarGeometry") { sb.sbplane = new PlanarGeometry(); XmlNodeList pgchilds = sbpnode.ChildNodes; MakeSBPlanarGeometry(sb, pgchilds); } } sbList.Add(sb); } } catch (Exception e) { throw e; } return sbList; }
public static List<gbXMLSpaces> getSimpleSpaces(XmlDocument xmldoc, XmlNamespaceManager xmlns) { List<gbXMLSpaces> retspaces = new List<gbXMLSpaces>(); try { XmlNodeList nodes = xmldoc.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space", xmlns); foreach (XmlNode spaceNode in nodes) { //initialize a new instance of the class gbXMLSpaces space = new gbXMLSpaces(); space.spacebounds = new List<SpaceBoundary>(); //get id and space XmlAttributeCollection spaceAtts = spaceNode.Attributes; foreach (XmlAttribute at in spaceAtts) { if (at.Name == "id") { space.id = at.Value; break; } } if (spaceNode.HasChildNodes) { XmlNodeList childNodes = spaceNode.ChildNodes; foreach (XmlNode node in childNodes) { if (node.Name == "PlanarGeometry") { space.pg = new PlanarGeometry(); XmlNodeList childnodes = node.ChildNodes; foreach (XmlNode node2 in childnodes) { if (node2.Name == "PolyLoop") { space.pg.pl = new PolyLoop(); space.pg.pl.plcoords = new List<Vector.MemorySafe_CartCoord>(); XmlNodeList cartPoints = node2.ChildNodes; foreach (XmlNode point in cartPoints) { if (point.Name == "CartesianPoint") { Vector.CartCoord coord = new Vector.CartCoord(); XmlNodeList val = point.ChildNodes; int pointcount = 1; foreach (XmlNode cpoint in val) { switch (pointcount) { case 1: coord.X = Convert.ToDouble(cpoint.InnerText); break; case 2: coord.Y = Convert.ToDouble(cpoint.InnerText); break; case 3: coord.Z = Convert.ToDouble(cpoint.InnerText); break; } pointcount++; } Vector.MemorySafe_CartCoord memsafecoord = Vector.convertToMemorySafeCoord(coord); space.pg.pl.plcoords.Add(memsafecoord); } } } } } else if (node.Name == "ShellGeometry") { space.sg = new ShellGeometry(); XmlAttributeCollection sgAtts = spaceNode.Attributes; foreach (XmlAttribute at in sgAtts) { if (at.Name == "id") { space.sg.id = at.Value; break; } } XmlNodeList childnodes = node.ChildNodes; foreach (XmlNode sgnode in childnodes) { if (sgnode.Name == "ClosedShell") { space.sg.cs = new ClosedShell(); space.sg.cs.ploops = new List<PolyLoop>(); foreach (XmlNode pl in sgnode) { if (pl.Name == "PolyLoop") { PolyLoop sgpl = new PolyLoop(); sgpl.plcoords = new List<Vector.MemorySafe_CartCoord>(); XmlNodeList cartPoints = pl.ChildNodes; foreach (XmlNode point in cartPoints) { if (point.Name == "CartesianPoint") { Vector.CartCoord coord = new Vector.CartCoord(); XmlNodeList val = point.ChildNodes; int pointcount = 1; foreach (XmlNode cpoint in val) { switch (pointcount) { case 1: coord.X = Convert.ToDouble(cpoint.InnerText); break; case 2: coord.Y = Convert.ToDouble(cpoint.InnerText); break; case 3: coord.Z = Convert.ToDouble(cpoint.InnerText); break; } pointcount++; } Vector.MemorySafe_CartCoord memsafecoord = Vector.convertToMemorySafeCoord(coord); sgpl.plcoords.Add(memsafecoord); } } space.sg.cs.ploops.Add(sgpl); } } } } } else if (node.Name == "SpaceBoundary") { SpaceBoundary sb = new SpaceBoundary(); XmlAttributeCollection spbatts = node.Attributes; foreach (XmlAttribute at in spbatts) { if (at.Name == "surfaceIdRef") { sb.surfaceIdRef = at.Value; break; } } XmlNodeList sbchilds = node.ChildNodes; foreach (XmlNode sbpnode in sbchilds) { if (sbpnode.Name == "PlanarGeometry") { sb.sbplane = new PlanarGeometry(); XmlNodeList pgchilds = sbpnode.ChildNodes; foreach (XmlNode pgchild in pgchilds) { if (pgchild.Name == "PolyLoop") { sb.sbplane.pl = new PolyLoop(); sb.sbplane.pl.plcoords = new List<Vector.MemorySafe_CartCoord>(); XmlNodeList cartPoints = pgchild.ChildNodes; foreach (XmlNode point in cartPoints) { if (point.Name == "CartesianPoint") { Vector.CartCoord coord = new Vector.CartCoord(); XmlNodeList val = point.ChildNodes; int pointcount = 1; foreach (XmlNode cpoint in val) { switch (pointcount) { case 1: coord.X = Convert.ToDouble(cpoint.InnerText); break; case 2: coord.Y = Convert.ToDouble(cpoint.InnerText); break; case 3: coord.Z = Convert.ToDouble(cpoint.InnerText); break; } pointcount++; } Vector.MemorySafe_CartCoord memsafecoord = Vector.convertToMemorySafeCoord(coord); sb.sbplane.pl.plcoords.Add(memsafecoord); } } } } } } //finally, add the thing here space.spacebounds.Add(sb); } } } else { //throw something } retspaces.Add(space); } } catch (Exception e) { } return retspaces; }
private static SpaceBoundary MakeSBPlanarGeometry(SpaceBoundary sb, XmlNodeList pgchilds) { try { foreach (XmlNode pgchild in pgchilds) { if (pgchild.Name == "PolyLoop") { sb.sbplane.pl = new PolyLoop(); sb.sbplane.pl.plcoords = new List<Vector.MemorySafe_CartCoord>(); XmlNodeList cartPoints = pgchild.ChildNodes; foreach (XmlNode point in cartPoints) { if (point.Name == "CartesianPoint") { Vector.CartCoord coord = new Vector.CartCoord(); XmlNodeList val = point.ChildNodes; int pointcount = 1; foreach (XmlNode cpoint in val) { switch (pointcount) { case 1: coord.X = Convert.ToDouble(cpoint.InnerText); break; case 2: coord.Y = Convert.ToDouble(cpoint.InnerText); break; case 3: coord.Z = Convert.ToDouble(cpoint.InnerText); break; } pointcount++; } Vector.MemorySafe_CartCoord memsafecoord = Vector.convertToMemorySafeCoord(coord); sb.sbplane.pl.plcoords.Add(memsafecoord); } } } } } catch (Exception e) { } return sb; }
/// <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); }
/// <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); }
public static Building TogbXML(this AdjacencyCluster adjacencyCluster, string name, string description, double tolerance = Tolerance.MicroDistance) { List <Panel> panels = adjacencyCluster?.GetPanels(); if (panels == null || panels.Count == 0) { return(null); } List <Space> spaces = adjacencyCluster.GetSpaces(); if (spaces == null) { return(null); } //Dictionary of Minimal Elevations and List of Panels Dictionary <double, List <Panel> > dictionary_MinElevations = Analytical.Query.MinElevationDictionary(panels, true, Tolerance.MacroDistance); //Dictionary of gbXML BuildingStoreys and its elevations Dictionary <BuildingStorey, double> dictionary_buildingStoreys = new Dictionary <BuildingStorey, double>(); //Dictionary of SAM Panels related buildingSorey, minimal elevation and maximal elevation Dictionary <Panel, Tuple <BuildingStorey, double, double, double> > dictionary_Panels = new Dictionary <Panel, Tuple <BuildingStorey, double, double, double> >(); foreach (KeyValuePair <double, List <Panel> > keyValuePair in dictionary_MinElevations) { BuildingStorey buildingStorey = Architectural.Create.Level(keyValuePair.Key).TogbXML(tolerance); dictionary_buildingStoreys[buildingStorey] = keyValuePair.Key; foreach (Panel panel in keyValuePair.Value) { dictionary_Panels[panel] = new Tuple <BuildingStorey, double, double, double> (buildingStorey, keyValuePair.Key, panel.MinElevation(), panel.MaxElevation()); } } List <gbXMLSerializer.Space> spaces_gbXML = new List <gbXMLSerializer.Space>(); Dictionary <Guid, SpaceBoundary> dictionary = new Dictionary <Guid, SpaceBoundary>(); foreach (Space space in spaces) { List <Panel> panels_Space = adjacencyCluster.GetRelatedObjects <Panel>(space); if (panels_Space == null || panels_Space.Count == 0) { continue; } double elevation_Level = panels_Space.ConvertAll(x => dictionary_Panels[x].Item2).Min(); double elevation_Min = panels_Space.ConvertAll(x => dictionary_Panels[x].Item3).Min(); double elevation_Max = panels_Space.ConvertAll(x => dictionary_Panels[x].Item4).Max(); BuildingStorey buildingStorey = null; foreach (KeyValuePair <BuildingStorey, double> keyValuePair in dictionary_buildingStoreys) { if (keyValuePair.Value.Equals(elevation_Level)) { buildingStorey = keyValuePair.Key; break; } } if (buildingStorey == null) { continue; } List <Panel> panels_PlanarGeometry = panels_Space.FindAll(x => x.PanelType.PanelGroup() == PanelGroup.Floor || (x.Normal.AlmostSimilar(Vector3D.WorldZ.GetNegated()) && dictionary_Panels[x].Item3 == elevation_Min)); panels_PlanarGeometry = panels_PlanarGeometry?.MergeCoplanarPanels(Tolerance.MacroDistance, false, false, Tolerance.MacroDistance); if (panels_PlanarGeometry == null || panels_PlanarGeometry.Count == 0) { continue; } panels_PlanarGeometry.Sort((x, y) => y.GetArea().CompareTo(x.GetArea())); Face3D face3D = panels_PlanarGeometry.First().PlanarBoundary3D?.GetFace3D(); if (face3D == null) { continue; } double area = face3D.GetArea(); if (area < Tolerance.MacroDistance) { continue; } double volume = Math.Abs(elevation_Max - elevation_Min) * area; if (volume < Tolerance.MacroDistance) { continue; } List <SpaceBoundary> spaceBoundaries = new List <SpaceBoundary>(); foreach (Panel panel in panels_Space) { if (panel == null) { continue; } SpaceBoundary spaceBoundary = null; if (!dictionary.TryGetValue(panel.Guid, out spaceBoundary)) { spaceBoundary = panel.TogbXML_SpaceBoundary(tolerance); dictionary[panel.Guid] = spaceBoundary; } spaceBoundaries.Add(spaceBoundary); } gbXMLSerializer.Space space_gbXML = new gbXMLSerializer.Space(); space_gbXML.Name = space.Name; space_gbXML.spacearea = new Area() { val = area.ToString() }; space_gbXML.spacevol = new Volume() { val = volume.ToString() }; space_gbXML.buildingStoreyIdRef = buildingStorey.id; space_gbXML.cadid = new CADObjectId() { id = space.Guid.ToString() }; space_gbXML.PlanarGeo = face3D.TogbXML(tolerance); space_gbXML.id = Core.gbXML.Query.Id(space, typeof(gbXMLSerializer.Space)); space_gbXML.spbound = spaceBoundaries.ToArray(); space_gbXML.ShellGeo = panels_Space.TogbXML(space, tolerance); spaces_gbXML.Add(space_gbXML); } Building building = new Building(); building.id = Core.gbXML.Query.Id(adjacencyCluster, typeof(Building)); building.Name = name; building.Description = description; building.bldgStories = dictionary_buildingStoreys.Keys.ToArray(); building.Area = Analytical.Query.Area(panels, PanelGroup.Floor); building.buildingType = buildingTypeEnum.Office; building.Spaces = spaces_gbXML.ToArray(); return(building); }