private static double GetBldgHeight(OsmSharp.OsmGeo osmGeo) { ///Height determination ///https://wiki.openstreetmap.org/wiki/Simple_3D_Buildings double defaultHeight = 2.0 * 3 * scaleFromMetric; //default number of floors (2) at 3 meters per floor double keyHeightDimensioned = 0.0; double keyHeightLevels = 0.0; //height from height key if (osmGeo.Tags.ContainsKey("height")) { string heightText = osmGeo.Tags.GetValue("height"); keyHeightDimensioned = GetHeightDimensioned(heightText); } //height from building:levels key if (osmGeo.Tags.ContainsKey("building:levels")) { string levelsText = osmGeo.Tags.GetValue("building:levels"); keyHeightLevels = GetHeightLevels(levelsText); } double keyHeight = Math.Max(keyHeightDimensioned, keyHeightLevels); double height = Math.Max(defaultHeight, keyHeight); return(height); }
private static double GetBldgHeight(OsmSharp.OsmGeo osmGeo) { //height determination double defaultHeight = 2.0 * 3; //default number of floors (2) at 3 meters per floor double keyHeight = 0.0; //height from height key if (osmGeo.Tags.ContainsKey("height")) { string heightText = osmGeo.Tags.GetValue("height").Split(' ')[0]; //clear trailing m //check if in feet if (heightText.Contains("'")) { keyHeight = System.Convert.ToDouble(heightText.Split('\'')[0]) / 3.28084; //convert feet to meters } //if not feet assume meters else { keyHeight = System.Convert.ToDouble(heightText); } } //height from building:levels key if (osmGeo.Tags.ContainsKey("building:levels")) { string levelsText = osmGeo.Tags.GetValue("building:levels"); if (levelsText != null) { double levelsDouble = 0; Double.TryParse(levelsText, out levelsDouble); if (levelsDouble > 0) { keyHeight = Math.Max(keyHeight, System.Convert.ToDouble(levelsText) * 3); //3 meters per floor } } } double height = Math.Max(defaultHeight, keyHeight); return(height); }
private static double GetMinBldgHeight(OsmSharp.OsmGeo osmGeo) { //height determination double keyHeight = 0.0; //height from height key if (osmGeo.Tags.ContainsKey("min_height")) { string heightText = osmGeo.Tags.GetValue("min_height"); keyHeight = GetHeightDimensioned(heightText); } //height from building:levels key if (osmGeo.Tags.ContainsKey("building:min_level")) { string levelsText = osmGeo.Tags.GetValue("building:min_level"); keyHeight = GetHeightLevels(levelsText); } return(keyHeight); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { ///Gather GHA inputs Curve boundary = null; DA.GetData <Curve>(0, ref boundary); string osmFilePath = string.Empty; DA.GetData <string>("OSM Data Location", ref osmFilePath); //string userSRStext = "WGS84"; //DA.GetData<string>(2, ref userSRStext); List <string> filterWords = new List <string>(); DA.GetDataList <string>(2, filterWords); List <string> filterKeyValue = new List <string>(); DA.GetDataList <string>(3, filterKeyValue); Transform xformToMetric = new Transform(Rhino.RhinoMath.UnitScale(RhinoDoc.ActiveDoc.ModelUnitSystem, Rhino.UnitSystem.Meters)); Transform xformFromMetric = new Transform(Rhino.RhinoMath.UnitScale(Rhino.UnitSystem.Meters, RhinoDoc.ActiveDoc.ModelUnitSystem)); ///Declare trees Rectangle3d recs = new Rectangle3d(); GH_Structure <GH_String> fieldNames = new GH_Structure <GH_String>(); GH_Structure <GH_String> fieldValues = new GH_Structure <GH_String>(); GH_Structure <IGH_GeometricGoo> geometryGoo = new GH_Structure <IGH_GeometricGoo>(); GH_Structure <IGH_GeometricGoo> buildingGoo = new GH_Structure <IGH_GeometricGoo>(); Point3d max = new Point3d(); Point3d min = new Point3d(); if (boundary != null) { Point3d maxM = boundary.GetBoundingBox(true).Corner(true, false, true); max = Heron.Convert.XYZToWGS(maxM); Point3d minM = boundary.GetBoundingBox(true).Corner(false, true, true); min = Heron.Convert.XYZToWGS(minM); } /// get extents (why is this not part of OsmSharp?) System.Xml.Linq.XDocument xdoc = System.Xml.Linq.XDocument.Load(osmFilePath); if (xdoc.Root.Element("bounds") != null) { double minlat = System.Convert.ToDouble(xdoc.Root.Element("bounds").Attribute("minlat").Value); double minlon = System.Convert.ToDouble(xdoc.Root.Element("bounds").Attribute("minlon").Value); double maxlat = System.Convert.ToDouble(xdoc.Root.Element("bounds").Attribute("maxlat").Value); double maxlon = System.Convert.ToDouble(xdoc.Root.Element("bounds").Attribute("maxlon").Value); Point3d boundsMin = Heron.Convert.WGSToXYZ(new Point3d(minlon, minlat, 0)); Point3d boundsMax = Heron.Convert.WGSToXYZ(new Point3d(maxlon, maxlat, 0)); recs = new Rectangle3d(Plane.WorldXY, boundsMin, boundsMax); } else { AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Cannot determine the extents of the OSM file. A 'bounds' element may not be present in the file."); } using (var fileStreamSource = File.OpenRead(osmFilePath)) { /// create a source. OsmSharp.Streams.XmlOsmStreamSource source = new OsmSharp.Streams.XmlOsmStreamSource(fileStreamSource); /// filter by bounding box OsmSharp.Streams.OsmStreamSource sourceClipped = source; if (clipped) { sourceClipped = source.FilterBox((float)max.X, (float)max.Y, (float)min.X, (float)min.Y, true); } /// create a dictionary of elements OsmSharp.Db.Impl.MemorySnapshotDb sourceMem = new OsmSharp.Db.Impl.MemorySnapshotDb(sourceClipped); /// filter the source var filtered = from osmGeos in sourceClipped where osmGeos.Tags != null select osmGeos; if (filterWords.Any()) { filtered = from osmGeos in filtered where osmGeos.Tags.ContainsAnyKey(filterWords) select osmGeos; } if (filterKeyValue.Any()) { List <Tag> tags = new List <Tag>(); foreach (string term in filterKeyValue) { string[] kv = term.Split(','); Tag tag = new Tag(kv[0], kv[1]); tags.Add(tag); } filtered = from osmGeos in filtered where osmGeos.Tags.Intersect(tags).Any() select osmGeos; } source.Dispose(); /// loop over all objects and count them. int nodes = 0, ways = 0, relations = 0; foreach (OsmSharp.OsmGeo osmGeo in filtered) { //NODES if (osmGeo.Type == OsmGeoType.Node) { OsmSharp.Node n = (OsmSharp.Node)osmGeo; GH_Path nodesPath = new GH_Path(0, nodes); //populate Fields and Values for each node fieldNames.AppendRange(GetKeys(osmGeo), nodesPath); fieldValues.AppendRange(GetValues(osmGeo), nodesPath); //get geometry for node Point3d nPoint = Heron.Convert.WGSToXYZ(new Point3d((double)n.Longitude, (double)n.Latitude, 0)); geometryGoo.Append(new GH_Point(nPoint), nodesPath); //increment nodes nodes++; } //////////////////////////////////////////////////////////// //WAYS if (osmGeo.Type == OsmGeoType.Way) { OsmSharp.Way w = (OsmSharp.Way)osmGeo; GH_Path waysPath = new GH_Path(1, ways); //populate Fields and Values for each way fieldNames.AppendRange(GetKeys(osmGeo), waysPath); fieldValues.AppendRange(GetValues(osmGeo), waysPath); //get polyline geometry for way List <Point3d> wayNodes = new List <Point3d>(); foreach (long j in w.Nodes) { OsmSharp.Node n = (OsmSharp.Node)sourceMem.Get(OsmGeoType.Node, j); wayNodes.Add(Heron.Convert.WGSToXYZ(new Point3d((double)n.Longitude, (double)n.Latitude, 0))); } PolylineCurve pL = new PolylineCurve(wayNodes); if (pL.IsClosed) { //create base surface Brep[] breps = Brep.CreatePlanarBreps(pL, DocumentTolerance()); geometryGoo.Append(new GH_Brep(breps[0]), waysPath); } else { geometryGoo.Append(new GH_Curve(pL), waysPath); } //building massing if (w.Tags.ContainsKey("building") || w.Tags.ContainsKey("building:part")) { if (pL.IsClosed) { CurveOrientation orient = pL.ClosedCurveOrientation(Plane.WorldXY); if (orient != CurveOrientation.CounterClockwise) { pL.Reverse(); } Vector3d hVec = new Vector3d(0, 0, GetBldgHeight(osmGeo)); hVec.Transform(xformFromMetric); Extrusion ex = Extrusion.Create(pL, hVec.Z, true); IGH_GeometricGoo bldgGoo = GH_Convert.ToGeometricGoo(ex); buildingGoo.Append(bldgGoo, waysPath); } } //increment ways ways++; } /////////////////////////////////////////////////////////// //RELATIONS if (osmGeo.Type == OsmGeoType.Relation) { OsmSharp.Relation r = (OsmSharp.Relation)osmGeo; GH_Path relationPath = new GH_Path(2, relations); //populate Fields and Values for each relation fieldNames.AppendRange(GetKeys(osmGeo), relationPath); fieldValues.AppendRange(GetValues(osmGeo), relationPath); List <Curve> pLines = new List <Curve>(); // start members loop for (int mem = 0; mem < r.Members.Length; mem++) { GH_Path memberPath = new GH_Path(2, relations, mem); OsmSharp.RelationMember rMem = r.Members[mem]; OsmSharp.OsmGeo rMemGeo = sourceMem.Get(rMem.Type, rMem.Id); if (rMemGeo != null) { //get geometry for node if (rMemGeo.Type == OsmGeoType.Node) { long memNodeId = rMem.Id; OsmSharp.Node memN = (OsmSharp.Node)sourceMem.Get(rMem.Type, rMem.Id); Point3d memPoint = Heron.Convert.WGSToXYZ(new Point3d((double)memN.Longitude, (double)memN.Latitude, 0)); geometryGoo.Append(new GH_Point(memPoint), memberPath); } //get geometry for way if (rMem.Type == OsmGeoType.Way) { long memWayId = rMem.Id; OsmSharp.Way memWay = (OsmSharp.Way)rMemGeo; //get polyline geometry for way List <Point3d> memNodes = new List <Point3d>(); foreach (long memNodeId in memWay.Nodes) { OsmSharp.Node memNode = (OsmSharp.Node)sourceMem.Get(OsmGeoType.Node, memNodeId); memNodes.Add(Heron.Convert.WGSToXYZ(new Point3d((double)memNode.Longitude, (double)memNode.Latitude, 0))); } PolylineCurve memPolyline = new PolylineCurve(memNodes); geometryGoo.Append(new GH_Curve(memPolyline.ToNurbsCurve()), memberPath); CurveOrientation orient = memPolyline.ClosedCurveOrientation(Plane.WorldXY); if (orient != CurveOrientation.CounterClockwise) { memPolyline.Reverse(); } pLines.Add(memPolyline.ToNurbsCurve()); } //get nested relations if (rMem.Type == OsmGeoType.Relation) { ///not sure if this is needed } } } //end members loop bool allClosed = true; foreach (Curve pc in pLines) { if (!pc.IsClosed) { allClosed = false; } } if (pLines.Count > 0 && allClosed) { //create base surface Brep[] breps = Brep.CreatePlanarBreps(pLines, DocumentTolerance()); geometryGoo.RemovePath(relationPath); foreach (Brep b in breps) { geometryGoo.Append(new GH_Brep(b), relationPath); //building massing if (r.Tags.ContainsKey("building") || r.Tags.ContainsKey("building:part")) { Vector3d hVec = new Vector3d(0, 0, GetBldgHeight(osmGeo)); hVec.Transform(xformFromMetric); //create extrusion from base surface buildingGoo.Append(new GH_Brep(Brep.CreateFromOffsetFace(b.Faces[0], hVec.Z, DocumentTolerance(), false, true)), relationPath); } } } //increment relations relations++; } ///end relation loop } ///end filtered loop } ///end osm source loop if (recs.IsValid) { DA.SetData(0, recs); } DA.SetDataTree(1, fieldNames); DA.SetDataTree(2, fieldValues); DA.SetDataTree(3, geometryGoo); DA.SetDataTree(4, buildingGoo); } ///end SolveInstance
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { ///Gather GHA inputs Curve boundary = null; DA.GetData <Curve>(0, ref boundary); string osmFilePath = string.Empty; DA.GetData <string>("OSM Data Location", ref osmFilePath); //string userSRStext = "WGS84"; //DA.GetData<string>(2, ref userSRStext); List <string> filterWords = new List <string>(); DA.GetDataList <string>(2, filterWords); List <string> filterKeyValue = new List <string>(); DA.GetDataList <string>(3, filterKeyValue); Transform xformToMetric = new Transform(scaleToMetric); Transform xformFromMetric = new Transform(scaleFromMetric); ///Declare trees Rectangle3d recs = new Rectangle3d(); GH_Structure <GH_String> fieldNames = new GH_Structure <GH_String>(); GH_Structure <GH_String> fieldValues = new GH_Structure <GH_String>(); GH_Structure <IGH_GeometricGoo> geometryGoo = new GH_Structure <IGH_GeometricGoo>(); GH_Structure <IGH_GeometricGoo> buildingGoo = new GH_Structure <IGH_GeometricGoo>(); Point3d max = new Point3d(); Point3d min = new Point3d(); if (boundary != null) { Point3d maxM = boundary.GetBoundingBox(true).Corner(true, false, true); max = Heron.Convert.XYZToWGS(maxM); Point3d minM = boundary.GetBoundingBox(true).Corner(false, true, true); min = Heron.Convert.XYZToWGS(minM); } /// get extents (why is this not part of OsmSharp?) System.Xml.Linq.XDocument xdoc = System.Xml.Linq.XDocument.Load(osmFilePath); if (xdoc.Root.Element("bounds") != null) { double minlat = System.Convert.ToDouble(xdoc.Root.Element("bounds").Attribute("minlat").Value); double minlon = System.Convert.ToDouble(xdoc.Root.Element("bounds").Attribute("minlon").Value); double maxlat = System.Convert.ToDouble(xdoc.Root.Element("bounds").Attribute("maxlat").Value); double maxlon = System.Convert.ToDouble(xdoc.Root.Element("bounds").Attribute("maxlon").Value); Point3d boundsMin = Heron.Convert.WGSToXYZ(new Point3d(minlon, minlat, 0)); Point3d boundsMax = Heron.Convert.WGSToXYZ(new Point3d(maxlon, maxlat, 0)); recs = new Rectangle3d(Plane.WorldXY, boundsMin, boundsMax); } else { AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Cannot determine the extents of the OSM file. A 'bounds' element may not be present in the file. " + "Try turning off clipping in this component's menu."); } using (var fileStreamSource = File.OpenRead(osmFilePath)) { /// create a source. OsmSharp.Streams.XmlOsmStreamSource source = new OsmSharp.Streams.XmlOsmStreamSource(fileStreamSource); /// filter by bounding box OsmSharp.Streams.OsmStreamSource sourceClipped = source; if (clipped) { sourceClipped = source.FilterBox((float)max.X, (float)max.Y, (float)min.X, (float)min.Y, true); } /// create a dictionary of elements OsmSharp.Db.Impl.MemorySnapshotDb sourceMem = new OsmSharp.Db.Impl.MemorySnapshotDb(sourceClipped); /// filter the source var filtered = from osmGeos in sourceClipped where osmGeos.Tags != null select osmGeos; if (filterWords.Any()) { filtered = from osmGeos in filtered where osmGeos.Tags.ContainsAnyKey(filterWords) select osmGeos; } if (filterKeyValue.Any()) { List <Tag> tags = new List <Tag>(); foreach (string term in filterKeyValue) { string[] kv = term.Split(','); Tag tag = new Tag(kv[0], kv[1]); tags.Add(tag); } filtered = from osmGeos in filtered where osmGeos.Tags.Intersect(tags).Any() select osmGeos; } source.Dispose(); /// loop over all objects and count them. int nodes = 0, ways = 0, relations = 0; Dictionary <PolylineCurve, GH_Path> bldgOutlines = new Dictionary <PolylineCurve, GH_Path>(); List <BuildingPart> buildingParts = new List <BuildingPart>(); foreach (OsmSharp.OsmGeo osmGeo in filtered) { //NODES if (osmGeo.Type == OsmGeoType.Node) { OsmSharp.Node n = (OsmSharp.Node)osmGeo; GH_Path nodesPath = new GH_Path(0, nodes); //populate Fields and Values for each node fieldNames.AppendRange(GetKeys(osmGeo), nodesPath); fieldValues.AppendRange(GetValues(osmGeo), nodesPath); //get geometry for node Point3d nPoint = Heron.Convert.WGSToXYZ(new Point3d((double)n.Longitude, (double)n.Latitude, 0)); geometryGoo.Append(new GH_Point(nPoint), nodesPath); //increment nodes nodes++; } //////////////////////////////////////////////////////////// //WAYS if (osmGeo.Type == OsmGeoType.Way) { OsmSharp.Way w = (OsmSharp.Way)osmGeo; GH_Path waysPath = new GH_Path(1, ways); //populate Fields and Values for each way fieldNames.AppendRange(GetKeys(osmGeo), waysPath); fieldValues.AppendRange(GetValues(osmGeo), waysPath); //get polyline geometry for way List <Point3d> wayNodes = new List <Point3d>(); foreach (long j in w.Nodes) { OsmSharp.Node n = (OsmSharp.Node)sourceMem.Get(OsmGeoType.Node, j); wayNodes.Add(Heron.Convert.WGSToXYZ(new Point3d((double)n.Longitude, (double)n.Latitude, 0))); } PolylineCurve pL = new PolylineCurve(wayNodes); if (pL.IsClosed) { //create base surface Brep[] breps = Brep.CreatePlanarBreps(pL, DocumentTolerance()); geometryGoo.Append(new GH_Brep(breps[0]), waysPath); } else { geometryGoo.Append(new GH_Curve(pL), waysPath); } //building massing if ((w.Tags.ContainsKey("building") || w.Tags.ContainsKey("building:part")))// && !w.Tags.ContainsKey("construction")) { if (pL.IsClosed) { ///Populate dictionary for sorting building parts later if (w.Tags.ContainsKey("building")) { bldgOutlines.Add(pL, waysPath); } CurveOrientation orient = pL.ClosedCurveOrientation(Plane.WorldXY); if (orient != CurveOrientation.CounterClockwise) { pL.Reverse(); } ///Move polylines to min height double minHeightWay = GetMinBldgHeight(osmGeo); Vector3d minVec = new Vector3d(0, 0, minHeightWay); //minVec.Transform(xformFromMetric); if (minHeightWay > 0.0) { var minHeightTranslate = Transform.Translation(minVec); pL.Transform(minHeightTranslate); } Vector3d hVec = new Vector3d(0, 0, GetBldgHeight(osmGeo) - minHeightWay); //hVec.Transform(xformFromMetric); Extrusion ex = Extrusion.Create(pL, hVec.Z, true); IGH_GeometricGoo bldgGoo = GH_Convert.ToGeometricGoo(ex); ///Save building parts for sorting later and remove part from geometry goo tree if (w.Tags.ContainsKey("building:part")) { BuildingPart bldgPart = new BuildingPart(pL, bldgGoo, fieldNames[waysPath], fieldValues[waysPath], osmGeo); buildingParts.Add(bldgPart); fieldNames.RemovePath(waysPath); fieldValues.RemovePath(waysPath); geometryGoo.RemovePath(waysPath); ways = ways - 1; } else { buildingGoo.Append(bldgGoo, waysPath); } } } //increment ways ways++; } /////////////////////////////////////////////////////////// //RELATIONS if (osmGeo.Type == OsmGeoType.Relation) { OsmSharp.Relation r = (OsmSharp.Relation)osmGeo; GH_Path relationPath = new GH_Path(2, relations); //populate Fields and Values for each relation fieldNames.AppendRange(GetKeys(osmGeo), relationPath); fieldValues.AppendRange(GetValues(osmGeo), relationPath); List <Curve> pLines = new List <Curve>(); // start members loop for (int mem = 0; mem < r.Members.Length; mem++) { GH_Path memberPath = new GH_Path(2, relations, mem); OsmSharp.RelationMember rMem = r.Members[mem]; OsmSharp.OsmGeo rMemGeo = sourceMem.Get(rMem.Type, rMem.Id); if (rMemGeo != null) { //get geometry for node if (rMemGeo.Type == OsmGeoType.Node) { long memNodeId = rMem.Id; OsmSharp.Node memN = (OsmSharp.Node)sourceMem.Get(rMem.Type, rMem.Id); Point3d memPoint = Heron.Convert.WGSToXYZ(new Point3d((double)memN.Longitude, (double)memN.Latitude, 0)); geometryGoo.Append(new GH_Point(memPoint), memberPath); } //get geometry for way if (rMem.Type == OsmGeoType.Way) { long memWayId = rMem.Id; OsmSharp.Way memWay = (OsmSharp.Way)rMemGeo; //get polyline geometry for way List <Point3d> memNodes = new List <Point3d>(); foreach (long memNodeId in memWay.Nodes) { OsmSharp.Node memNode = (OsmSharp.Node)sourceMem.Get(OsmGeoType.Node, memNodeId); memNodes.Add(Heron.Convert.WGSToXYZ(new Point3d((double)memNode.Longitude, (double)memNode.Latitude, 0))); } PolylineCurve memPolyline = new PolylineCurve(memNodes); geometryGoo.Append(new GH_Curve(memPolyline.ToNurbsCurve()), memberPath); CurveOrientation orient = memPolyline.ClosedCurveOrientation(Plane.WorldXY); if (orient != CurveOrientation.CounterClockwise) { memPolyline.Reverse(); } pLines.Add(memPolyline.ToNurbsCurve()); } //get nested relations if (rMem.Type == OsmGeoType.Relation) { ///not sure if this is needed } } } //end members loop bool allClosed = true; foreach (Curve pc in pLines) { if (!pc.IsClosed) { allClosed = false; } } if (pLines.Count > 0 && allClosed) { ///Move polylines to min height double minHeight = GetMinBldgHeight(osmGeo); if (minHeight > 0.0) { Vector3d minVec = new Vector3d(0, 0, minHeight); //minVec.Transform(xformFromMetric); var minHeightTranslate = Transform.Translation(minVec); for (int i = 0; i < pLines.Count; i++) { pLines[i].Transform(minHeightTranslate); } } ///Create base surface Brep[] breps = Brep.CreatePlanarBreps(pLines, DocumentTolerance()); geometryGoo.RemovePath(relationPath); foreach (Brep b in breps) { geometryGoo.Append(new GH_Brep(b), relationPath); ///Building massing if (r.Tags.ContainsKey("building") || r.Tags.ContainsKey("building:part")) { Vector3d hVec = new Vector3d(0, 0, GetBldgHeight(osmGeo) - minHeight); //hVec.Transform(xformFromMetric); ///Create extrusion from base surface buildingGoo.Append(new GH_Brep(Brep.CreateFromOffsetFace(b.Faces[0], hVec.Z, DocumentTolerance(), false, true)), relationPath); } } } ///Increment relations relations++; } ///End relation loop } ///End filtered loop ///Add building parts to sub-branches under main building for (int partIndex = 0; partIndex < buildingParts.Count; partIndex++) { BuildingPart bldgPart = buildingParts[partIndex]; Point3d partPoint = bldgPart.PartFootprint.PointAtStart; partPoint.Z = 0; bool replaceBuidingMass = false; GH_Path mainBuildingMassPath = new GH_Path(); PolylineCurve massOutline = new PolylineCurve(); bool isRoof = bldgPart.PartOsmGeo.Tags.TryGetValue("roof:shape", out string isRoofString); if (isRoof) { bldgPart.PartGoo = BldgPartToRoof(bldgPart); } foreach (KeyValuePair <PolylineCurve, GH_Path> pair in bldgOutlines) { PointContainment pc = pair.Key.Contains(partPoint, Plane.WorldXY, DocumentTolerance()); if (pc != PointContainment.Outside) { ///Create new sub-branch int numSubBranches = 0; GH_Path partPath = pair.Value.AppendElement(numSubBranches); while (buildingGoo.PathExists(partPath)) { numSubBranches++; partPath = pair.Value.AppendElement(numSubBranches); } ///Add data to sub-branch fieldNames.AppendRange(bldgPart.PartFieldNames, partPath); fieldValues.AppendRange(bldgPart.PartFieldValues, partPath); buildingGoo.Append(bldgPart.PartGoo, partPath); ///Remove the main building mass replaceBuidingMass = true; mainBuildingMassPath = pair.Value; massOutline = pair.Key; } } ///Remove the main building mass if (replaceBuidingMass) { buildingGoo.RemovePath(mainBuildingMassPath); buildingGoo.Append(new GH_Curve(massOutline), mainBuildingMassPath); } else { GH_Path extrasPath = new GH_Path(3, partIndex); buildingGoo.Append(bldgPart.PartGoo, extrasPath); fieldNames.AppendRange(bldgPart.PartFieldNames, extrasPath); fieldValues.AppendRange(bldgPart.PartFieldValues, extrasPath); } } } ///end osm source loop if (recs.IsValid) { DA.SetData(0, recs); } DA.SetDataTree(1, fieldNames); DA.SetDataTree(2, fieldValues); DA.SetDataTree(3, geometryGoo); DA.SetDataTree(4, buildingGoo); } ///end SolveInstance