public static bool ApplyLockRoom(AdvicePackage advice, ZoneManifest zm, ProgramManifest pm)
        {
            var bounds = advice.Bounds;

            foreach (ZonePackage zone in zm.Zones)
            {
                foreach (RoomPackage room in zone.Rooms)
                {
                    foreach (PlacementPackage item in room.PlacedItems)
                    {
                        PointContainment pc = bounds.Contains(item.Dims.Center);

                        if (pc == PointContainment.Inside)
                        {
                            if (advice.CapturedProgram == null)
                            {
                                advice.CapturedProgram = new List <PlacementPackage>();
                            }

                            advice.CapturedProgram.Add(item);

                            if (pm.ProgramPackages[item.Program.Priority].Quota > 0)
                            {
                                pm.ProgramPackages[item.Program.Priority].Quota--;
                            }
                        }
                    }
                }
            }

            zm.FloorPlan.ExemptionProfiles.Add(advice.Bounds);

            return(true);
        }
Beispiel #2
0
        public bool lineWithinRegion(Brep region, LineCurve line)
        {
            //Check if line is completely within a planar region
            int agreement = 0;

            Point3d midPt = line.PointAt((line.Domain.Max - line.Domain.Min) / 2);

            foreach (BrepLoop loop in region.Loops)
            {
                if (loop.LoopType == BrepLoopType.Outer)
                {
                    Curve iLoop = loop.To3dCurve();

                    PointContainment ptcontain = iLoop.Contains(midPt);

                    if (ptcontain != PointContainment.Inside)
                    {
                        agreement += 1;
                    }
                }

                if (loop.LoopType == BrepLoopType.Inner)
                {
                    Curve iLoop = loop.To3dCurve();

                    PointContainment ptcontain = iLoop.Contains(midPt);

                    if (ptcontain != PointContainment.Outside)
                    {
                        agreement += 1;
                    }
                }

                if (loop.LoopType == BrepLoopType.Slit)
                {
                    break;
                }

                if (loop.LoopType == BrepLoopType.Unknown)
                {
                    break;
                }
            }

            if (agreement == 0)
            {
                bool inside = true;
                return(inside);
            }
            else
            {
                bool inside = false;
                return(inside);
            }
        }
Beispiel #3
0
        /// <summary>
        /// Basic collision detection routine for single item placement.
        /// </summary>
        /// <param name="room">Room currently being populated.</param>
        /// <param name="candidate">PlacementPackaged being checked for fidelity.</param>
        /// <param name="pm"></param>
        /// <returns></returns>
        public static bool PlacementIsValid(RoomPackage room, PlacementPackage candidate, ProgramManifest pm)
        {
            //Verify placed item does not clash with previously placed items.
            foreach (PlacementPackage placedItem in room.PlacedItems)
            {
                if (Confirm.CurvesIntersect(placedItem.Bounds, candidate.Bounds, true))
                {
                    if (Confirm.CurvesIntersect(placedItem.Bounds, candidate.Bounds, false))
                    {
                        return(false);
                    }

                    CurveIntersections ccx = Intersection.CurveCurve(placedItem.Bounds, candidate.Bounds, 0.1, 0.1);

                    if (ccx.Count(x => x.IsOverlap) > 1)
                    {
                        return(false);
                    }
                }

                PointContainment insideCheck = placedItem.Bounds.Contains(candidate.Bounds.GetBoundingBox(Plane.WorldXY).Center);

                if (insideCheck == PointContainment.Inside || insideCheck == PointContainment.Coincident)
                {
                    return(false);
                }
            }

            //Verify item is completely within boundary of room.
            foreach (Curve edgeCurve in room.AllEdgeCurves)
            {
                if (Confirm.CurvesIntersect(candidate.Bounds, edgeCurve, false))
                {
                    return(false);
                }

                /*
                 * if (!Confirm.PointInRegion(room.Region, new CurveBounds(candidate.Bounds).Center))
                 * {
                 *  return false;
                 * }
                 */
            }

            //Verify program area is not larger than total room area.
            if (room.Region.GetArea() < pm.ProgramPackages[candidate.ProgramIndex].OccupationArea)
            {
                return(false);
            }

            return(true);
        }
Beispiel #4
0
        public static Curve BooleanOpenCurve(Curve ClosedC, Curve C, out int result)
        {
            PointContainment cont0 = ClosedC.Contains(C.PointAtEnd, Plane.WorldXY, 0.01);
            PointContainment cont1 = ClosedC.Contains(C.PointAtStart, Plane.WorldXY, 0.01);


            bool isCurveInsideStart = (cont0 == PointContainment.Inside || cont0 == PointContainment.Coincident);
            bool isCurveInsideEnd   = (cont1 == PointContainment.Inside || cont1 == PointContainment.Coincident);

            Rhino.Geometry.Intersect.CurveIntersections ci = Rhino.Geometry.Intersect.Intersection.CurveCurve(C, ClosedC, 0.01, 0.01);
            Interval interval = C.Domain;


            if (isCurveInsideStart && isCurveInsideEnd)
            {
                result = 2;
                return(C);
            }
            else if (isCurveInsideStart && !isCurveInsideEnd)
            {
                result = 1;
                if (ci.Count == 0)
                {
                    result = 0;
                    return(null);
                }
                return(C.Trim(ci[0].ParameterA, interval.T0));
            }
            else if (!isCurveInsideStart && isCurveInsideEnd)
            {
                if (ci.Count == 0)
                {
                    result = 0;
                    return(null);
                }
                result = 1;
                return(C.Trim(interval.T1, ci[0].ParameterA));
            }
            else
            {
                if (ci.Count == 2)
                {
                    result = 1;
                    return(C.Trim(ci[0].ParameterA, ci[1].ParameterA));
                }
            }
            result = 0;
            return(null);
        }
Beispiel #5
0
        public static void PlaneSlice(this Brep brep, Plane sliceplane, ref List <Curve> curves)
        {
            //brep.Faces.StandardizeFaceSurfaces();
            //BrepSolidOrientation bso = brep.SolidOrientation;

            Curve[]   xCrvs;
            Point3d[] xPts;
            bool[]    inside;
            Rhino.Geometry.Intersect.Intersection.BrepPlane(brep, sliceplane, 0.001, out xCrvs, out xPts);
            if (xCrvs == null)
            {
                return;
            }

            xCrvs  = Rhino.Geometry.Curve.JoinCurves(xCrvs);
            curves = new List <Curve>();
            inside = new bool[xCrvs.Length];
            for (int i = 0; i < xCrvs.Length; ++i)
            {
                //int sign = 1;
                Point3d  tpt = xCrvs[i].PointAtNormalizedLength(0.5);
                Vector3d n   = brep.ClosestNormal(tpt);
                n = n.ProjectToPlane(sliceplane);
                tpt.Transform(Transform.Translation(n * 0.001));
                PointContainment pcon = xCrvs[i].Contains(tpt, sliceplane, 0.0001);
                if (pcon == PointContainment.Inside)
                {
                    inside[i] = true;
                    //sign = -1;
                }
                else
                {
                    inside[i] = false;
                    //sign = 1;
                }

                curves.Add(xCrvs[i]);
                Curve[] offsets = xCrvs[i].Offset(tpt, sliceplane.ZAxis, 3.0, 0.0001, CurveOffsetCornerStyle.Sharp);
                //Curve[] offsets = xCrvs[i].Offset(sliceplane, 3.0 * sign, 0.001, CurveOffsetCornerStyle.Sharp);
                curves.AddRange(offsets);
            }

            return;
        }
Beispiel #6
0
        private bool BoundaryContainsCurve(Curve shape, Curve boundary)
        {
            bool           IsContained = false;
            List <Point3d> vertices    = shape.ToNurbsCurve().Points.Select(p => p.Location).ToList();

            for (int i = 0; i < vertices.Count; i++)
            {
                Point3d          vertex       = vertices[i];
                PointContainment pContainment = boundary.Contains(vertex, Plane.WorldXY, 0.00001);
                if (pContainment.Equals(PointContainment.Inside))
                {
                    IsContained = true;
                }
                else
                {
                    IsContained = false;
                    break;
                }
            }

            return(IsContained);
        }
        public List <Curve> RemovePoly(List <Curve> bsp_tree, Curve int_crv)
        {
            List <Curve> del_crv = new List <Curve>();

            for (int i = 0; i < bsp_tree.Count; i++)
            {
                try
                {
                    Point3d          cen = AreaMassProperties.Compute(bsp_tree[i]).Centroid;
                    PointContainment t   = bsp_tree[i].Contains(cen, Plane.WorldXY, Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance);
                    if (t.ToString() == ("Inside"))
                    {
                        del_crv.Add(bsp_tree[i]);
                    }
                }
                catch (Exception) { }

                for (int j = 0; j < del_crv.Count; j++)
                {
                    bsp_tree.Remove(del_crv[j]);
                }
            }
            return(bsp_tree);
        }
Beispiel #8
0
        private IList <Rectangle3d> CheckFit(BoundingBox bx, Rectangle3d rect, Curve boundary, double offset, bool withRotation, List <Point3d> outPts, double searchSpacing, bool axisAligned, List <Vector3d> vs)
        {
            bool IsRotated = false;
            bool searching = true;

            double angle = 1.5708;

            List <double>       spacing = FindSpacing(rect, offset);
            IList <Rectangle3d> tRects  = new List <Rectangle3d>();

            double  dX   = searchSpacing;
            double  dY   = searchSpacing;
            double  xMin = bx.Min.X;
            double  yMin = bx.Min.Y;
            Point3d p    = new Point3d(xMin, yMin, 0.0);

            Vector3d translationVector = new Vector3d(rect.Plane.XAxis.X, rect.Plane.YAxis.Y, 1);

            translationVector.Unitize();

            for (double y = yMin; y < bx.Max.Y; y += dY)
            {
                for (double x = xMin; x < bx.Max.X; x += dX)
                {
                    Vector3d v  = new Vector3d(x, y, 0.0);
                    Vector3d pv = new Vector3d(p);

                    if (axisAligned)
                    {
                        pv = new Vector3d(translationVector.X * dX, translationVector.Y * dY, 1);
                    }
                    Vector3d toVector = Vector3d.Add(v, pv);
                    Point3d  pNew     = new Point3d(toVector);

                    p = pNew;

                    PointContainment pc = boundary.Contains(p, Plane.WorldXY, 0.1);

                    if (pc == PointContainment.Inside)
                    {
                        // Translate rect to new position
                        Rectangle3d tRect = TranslateRect(p, rect);

                        // Check containment of rect
                        bool IsContained = BoundaryContainsCurve(tRect.ToNurbsCurve(), boundary);

                        if (!IsContained && withRotation && !searching)
                        {
                            tRect.Transform(Transform.Rotation(angle, p));
                            IsContained = BoundaryContainsCurve(tRect.ToNurbsCurve(), boundary);
                            IsRotated   = true;
                        }

                        if (IsContained)
                        {
                            if (searching)
                            {
                                searching = false;
                                dX        = spacing[0];
                                dY        = spacing[1];
                                xMin      = (1 - bx.Min.X % p.X) * p.X;
                            }
                            outPts.Add(p);
                            vs.Add(pv);
                            tRects.Add(tRect);
                        }
                        if (IsRotated && withRotation)
                        {
                            // Update spacing
                            double t = dX;
                            dX        = dY;
                            dY        = t;
                            IsRotated = false;
                        }
                    }
                }
            }

            return(tRects);
        }
Beispiel #9
0
        /// <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
        public static List <Polyline> RemoveLoop(Polyline looped, bool isCCW)
        {
            Curve loopedCrv = looped.ToNurbsCurve();

            //Search selfX params.
            List <double> selfXParams = new List <double>();

            var selfIntersect = Intersection.CurveSelf(loopedCrv, 0);

            foreach (IntersectionEvent e in selfIntersect)
            {
                selfXParams.Add(e.ParameterA);
                selfXParams.Add(e.ParameterB);
            }

            //Set trimming intervals.
            List <double> trimmingParams = new List <double>();

            for (int i = 0; i < looped.Count; i++)
            {
                trimmingParams.Add(i);
            }
            trimmingParams.AddRange(selfXParams);
            trimmingParams.Sort();

            List <Interval> trimmingInterval = new List <Interval>();
            int             paramCount       = trimmingParams.Count;

            for (int i = 0; i < paramCount - 1; i++)
            {
                trimmingInterval.Add(
                    new Interval(trimmingParams[i], trimmingParams[(paramCount + i + 1) % paramCount]));
            }

            //Get segments.
            List <LineCurve> trimmedSegs = new List <LineCurve>();

            foreach (Interval i in trimmingInterval)
            {
                trimmedSegs.Add(
                    new LineCurve(looped.PointAt(i.T0), looped.PointAt(i.T1)));
            }

            //Divide segments into in/out group.
            List <LineCurve> innerSegs = new List <LineCurve>();
            List <LineCurve> outerSegs = new List <LineCurve>();

            foreach (LineCurve i in trimmedSegs)
            {
                Vector3d toInnerCCW = i.TangentAtStart;
                toInnerCCW.Rotate(Math.PI / 2, Vector3d.ZAxis);
                Point3d inOutTestPoint = (i.PointAtStart + i.PointAtEnd) / 2 + toInnerCCW;

                PointContainment inOutResult = loopedCrv.Contains(inOutTestPoint);
                if (inOutResult == PointContainment.Inside)
                {
                    innerSegs.Add(i);
                }
                else
                {
                    outerSegs.Add(i);
                }
            }

            //Decided output by curve orientation.
            List <LineCurve> outputSegs;

            if (isCCW)
            {
                outputSegs = innerSegs;
            }
            else
            {
                outputSegs = outerSegs;
            }

            if (outputSegs.Count > 0)
            {
                Curve[] outputCrv = Curve.JoinCurves(outputSegs);
                return(outputCrv.Select(n => CurveTools.ToPolyline(n)).ToList());
            }

            return(new List <Polyline>());
        }