Example #1
0
        public static BHE.Opening ToBHoM(this BHX.Opening gbOpening)
        {
            BHE.Opening opening = new BHE.Opening();

            BHG.Polyline pLine = gbOpening.PlanarGeometry.PolyLoop.ToBHoM();
            opening.Edges = pLine.ToEdges();

            string[] cadSplit = gbOpening.CADObjectID.Split('[');
            if (cadSplit.Length > 0)
            {
                opening.Name = cadSplit[0].Trim();
            }
            if (cadSplit.Length > 1)
            {
                BHP.OriginContextFragment envContext = new BHP.OriginContextFragment();
                envContext.ElementID = cadSplit[1].Split(']')[0].Trim();
                envContext.TypeName  = opening.Name;

                if (opening.Fragments == null)
                {
                    opening.Fragments = new List <IBHoMFragment>();
                }
                opening.Fragments.Add(envContext);
            }

            opening.Type = gbOpening.OpeningType.ToBHoMOpeningType();

            return(opening);
        }
Example #2
0
        public static BHX.Polyloop ToGBXML(this BHG.Polyline pLine, GBXMLSettings settings, double tolerance = BHG.Tolerance.Distance)
        {
            BHX.Polyloop polyloop = new BHX.Polyloop();

            pLine = pLine.CleanPolyline(minimumSegmentLength: tolerance);

            List <BHG.Point> pts = pLine.DiscontinuityPoints();

            if (pts.Count == 0)
            {
                return(polyloop);
            }

            int count = ((pts.First().SquareDistance(pts.Last()) < (tolerance * tolerance)) ? pts.Count - 1 : pts.Count);
            List <BHX.CartesianPoint> cartpoint = new List <BHX.CartesianPoint>();

            for (int i = 0; i < count; i++)
            {
                BHX.CartesianPoint cpt   = pts[i].ToGBXML(settings);
                List <string>      coord = new List <string>();
                cartpoint.Add(cpt);
            }
            polyloop.CartesianPoint = cartpoint.ToArray();
            return(polyloop);
        }
Example #3
0
        public static BHX.RectangularGeometry ToGBXMLGeometry(this BHE.Panel element, GBXMLSettings settings)
        {
            BHX.RectangularGeometry geom = new BHX.RectangularGeometry();

            BHG.Polyline pLine = element.Polyline();

            geom.Tilt           = Math.Round(element.Tilt(settings.AngleTolerance), settings.RoundingSettings.GeometryTilt);
            geom.Azimuth        = Math.Round(element.Azimuth(BHG.Vector.YAxis), settings.RoundingSettings.GeometryAzimuth);
            geom.Height         = Math.Round(element.Height(), settings.RoundingSettings.GeometryHeight);
            geom.Width          = Math.Round(element.Width(), settings.RoundingSettings.GeometryWidth);
            geom.CartesianPoint = pLine.ControlPoints.First().ToGBXML(settings);
            geom.ID             = "geom-" + Guid.NewGuid().ToString().Replace("-", "").Substring(0, 10);

            if (geom.Height == 0)
            {
                geom.Height = Math.Round(element.Area() / geom.Width, settings.RoundingSettings.GeometryHeight);
            }
            if (geom.Width == 0)
            {
                geom.Width = Math.Round(element.Area() / geom.Height, settings.RoundingSettings.GeometryWidth);
            }
            if (geom.Tilt == -1)
            {
                BH.Engine.Reflection.Compute.RecordWarning("Warning, panel " + element.BHoM_Guid + " has been calculated to have a tilt of -1.");
            }

            return(geom);
        }
Example #4
0
        public static BHX.Surface ToGBXML(this BHE.Panel element)
        {
            BHP.OriginContextFragment contextProperties = element.FindFragment <BHP.OriginContextFragment>(typeof(BHP.OriginContextFragment));

            BHX.Surface surface = new BHX.Surface();
            surface.CADObjectID       = element.CADObjectID();
            surface.ConstructionIDRef = (contextProperties == null ? element.ConstructionID() : contextProperties.TypeName.CleanName());

            BHX.RectangularGeometry geom       = element.ToGBXMLGeometry();
            BHX.PlanarGeometry      planarGeom = new BHX.PlanarGeometry();
            planarGeom.ID = "PlanarGeometry-" + Guid.NewGuid().ToString().Replace("-", "").Substring(0, 10);

            BHG.Polyline pLine = element.Polyline();
            planarGeom.PolyLoop = pLine.ToGBXML();

            surface.PlanarGeometry      = planarGeom;
            surface.RectangularGeometry = geom;

            surface.Opening = new BHX.Opening[element.Openings.Count];
            for (int x = 0; x < element.Openings.Count; x++)
            {
                if (element.Openings[x].Polyline().IControlPoints().Count != 0)
                {
                    surface.Opening[x] = element.Openings[x].ToGBXML();
                }
            }

            return(surface);
        }
Example #5
0
        /***************************************************/
        /**** Public Methods                            ****/
        /***************************************************/

        public static List <BHG.Polyline> ClosedShellGeometry(this List <BuildingElement> buildingElements)
        {
            List <BHG.Polyline> pLinesCurtainWall = new List <BHG.Polyline>();
            List <BHG.Polyline> pLinesOther       = new List <BHG.Polyline>();

            //Merge curtain panels
            foreach (BuildingElement element in buildingElements)
            {
                BH.oM.Environment.Properties.ElementProperties beProperty = element.ElementProperties() as BH.oM.Environment.Properties.ElementProperties;
                BHG.Polyline pline = new BHG.Polyline()
                {
                    ControlPoints = element.PanelCurve.IControlPoints()
                };

                if (beProperty != null && beProperty.BuildingElementType == BuildingElementType.CurtainWall)
                {
                    pLinesCurtainWall.Add(pline);
                }
                else
                {
                    pLinesOther.Add(pline);
                }
            }

            //Add the rest of the geometries
            List <BHG.Polyline> mergedPolyLines = BH.Engine.Geometry.Compute.BooleanUnion(pLinesCurtainWall);

            mergedPolyLines.AddRange(pLinesOther);

            return(mergedPolyLines);
        }
        public static bool NormalTowardsSpace(this BHG.Polyline pline, BHE.Space space)
        {
            BHG.Point centrePt = pline.Centre();

            List <BHG.Point> pts = BH.Engine.Geometry.Query.DiscontinuityPoints(pline);

            BHG.Plane plane = BH.Engine.Geometry.Create.Plane(pts[0], pts[1], pts[2]);

            //The polyline can be locally concave. Check if the polyline is clockwise.
            if (!BH.Engine.Geometry.Query.IsClockwise(pline, plane.Normal))
            {
                plane.Normal = -plane.Normal;
            }

            //Move centrepoint along the normal. If inside - flip the panel
            if (IsContaining(space, centrePt.Translate(plane.Normal)))
            {
                return(true);
            }
            else
            {
                return(false);
            }

            /***************************************************/
        }
Example #7
0
        /***************************************************/

        public static Opening Opening(BHG.Polyline pLine)
        {
            return(new Opening
            {
                OpeningCurve = Geometry.Create.PolyCurve(new BHG.Polyline[] { pLine })
            });
        }
Example #8
0
        public static BHX.Surface ToGBXML(this BHE.Panel element, List <List <BHE.Panel> > adjacentSpaces, List <BHE.Panel> space)
        {
            BHX.Surface surface = element.ToGBXML();

            surface.SurfaceType  = element.ToGBXMLType(adjacentSpaces);
            surface.ExposedToSun = Query.ExposedToSun(surface.SurfaceType).ToString().ToLower();

            BHG.Polyline pLine = element.Polyline();
            if (!pLine.NormalAwayFromSpace(space))
            {
                pLine = pLine.Flip();
                surface.PlanarGeometry.PolyLoop     = pLine.ToGBXML();
                surface.RectangularGeometry.Tilt    = Math.Round(pLine.Tilt(), 3);
                surface.RectangularGeometry.Azimuth = Math.Round(pLine.Azimuth(BHG.Vector.YAxis), 3);
            }

            List <BHX.AdjacentSpaceId> adjIDs = new List <BHX.AdjacentSpaceId>();

            foreach (List <BHE.Panel> sp in adjacentSpaces)
            {
                adjIDs.Add(sp.AdjacentSpaceID());
            }
            surface.AdjacentSpaceID = adjIDs.ToArray();

            return(surface);
        }
Example #9
0
        public static BHX.Opening ToGBXML(this BHE.Opening opening, List <BHE.Panel> space)
        {
            BHX.Opening gbOpening = opening.ToGBXML();

            BHG.Polyline pLine = opening.Polyline();
            if (pLine.NormalAwayFromSpace(space))
            {
                gbOpening.PlanarGeometry.PolyLoop = pLine.Flip().ToGBXML();
            }

            BHP.OriginContextFragment contextProperties = opening.FindFragment <BHP.OriginContextFragment>(typeof(BHP.OriginContextFragment));

            if (contextProperties != null)
            {
                string elementID  = contextProperties.ElementID;
                string familyName = contextProperties.TypeName;

                gbOpening.CADObjectID = opening.CADObjectID();
                gbOpening.OpeningType = opening.Type.ToGBXML();

                if (familyName == "System Panel") //No SAM_BuildingElementType for this one atm
                {
                    gbOpening.OpeningType = "FixedWindow";
                }

                if (gbOpening.OpeningType.Contains("Window") && opening.OpeningConstruction.Name.Contains("SLD")) //Change windows with SLD construction into doors
                {
                    gbOpening.OpeningType = "NonSlidingDoor";
                }
            }

            return(gbOpening);
        }
Example #10
0
        public static BHE.Panel OffsetOpening(BHE.Panel panel)
        {
            BHE.Panel energyPlusPanel = new BHE.Panel();
            //Checking if there are openings
            if (panel.Openings.Count == 0)
            {
                return(panel);
            }
            else
            {
                //OpeningArea
                List <BHE.Opening> openings          = panel.Openings;
                List <double>      openingAreas      = new List <double>();
                List <PolyCurve>   openingPolyCurves = new List <PolyCurve>();
                foreach (BHE.Opening opening in panel.Openings)
                {
                    List <ICurve> openingCrvs    = opening.Edges.Select(x => x.Curve).ToList();
                    PolyCurve     openingOutline = BH.Engine.Geometry.Create.PolyCurve(openingCrvs);
                    double        openingArea    = openingOutline.Area();
                    openingAreas.Add(openingArea);
                    openingPolyCurves.Add(openingOutline);
                }
                double totalOpeningArea = openingAreas.Sum();

                //PanelArea
                List <ICurve> panelCrvs    = panel.ExternalEdges.Select(x => x.Curve).ToList();
                PolyCurve     panelOutline = BH.Engine.Geometry.Create.PolyCurve(panelCrvs);
                double        panelArea    = panelOutline.Area();

                //Comparing the total opening area to the panel area, if equal: reduce the area of the opening(s).
                if (totalOpeningArea != panelArea)
                {
                    return(panel);
                }
                else
                {
                    List <BH.oM.Geometry.Polyline>         openingPolylines = new List <BH.oM.Geometry.Polyline>();
                    List <List <BH.oM.Geometry.Polyline> > offsetPolylines  = new List <List <BH.oM.Geometry.Polyline> >();
                    List <BHE.Opening> newOpenings = new List <BHE.Opening>();
                    double             distance    = new double();
                    distance = -0.01;
                    panel.Openings.Clear();
                    foreach (BH.oM.Geometry.PolyCurve openingPolyCurve in openingPolyCurves)
                    {
                        List <BH.oM.Geometry.Point> polyPoints      = openingPolyCurve.IDiscontinuityPoints();
                        BH.oM.Geometry.Polyline     openingPolyLine = BH.Engine.Geometry.Create.Polyline(polyPoints);
                        Polyline        offsetPolyline = Geometry.Modify.Offset(openingPolyLine, distance);
                        List <BHE.Edge> edges          = offsetPolyline.ToEdges().ToList();
                        BHE.Opening     newOpening     = new BHE.Opening()
                        {
                            Edges = edges
                        };
                        panel.Openings.Add(newOpening);
                    }
                    return(panel);
                }
            }
        }
Example #11
0
        /***************************************************/
        /**** Public Methods                            ****/
        /***************************************************/

        public static bool NormalAwayFromSpace(this BHE.BuildingElement buildingElement, List <BHE.BuildingElement> elementsAsSpace)
        {
            BHG.Polyline bound = new BHG.Polyline()
            {
                ControlPoints = buildingElement.PanelCurve.IControlPoints()
            };

            return(NormalAwayFromSpace(bound, elementsAsSpace));
        }
Example #12
0
        /***************************************************/

        public static RHG.PolylineCurve ToRhino(this BHG.Polyline polyline)
        {
            if (polyline == null)
            {
                return(null);
            }

            return(new RHG.PolylineCurve(polyline.ControlPoints.Select(x => x.ToRhino())));
        }
Example #13
0
        /***************************************************/

        public static bool IsEqual(this BHG.Polyline bhPolyline, RHG.PolylineCurve rhPolylineCurve, double tolerance = BHG.Tolerance.Distance)
        {
            if (bhPolyline == null & rhPolylineCurve == null)
            {
                return(true);
            }

            RHG.Polyline rhPolyline; rhPolylineCurve.TryGetPolyline(out rhPolyline);
            return(bhPolyline.IsEqual(rhPolyline, tolerance));
        }
Example #14
0
        /***************************************************/
        /**** Public Methods                            ****/
        /***************************************************/

        public static double Azimuth(this BHEI.IBuildingObject buildingElementGeometry, BHG.Vector refVector)
        {
            BHG.Polyline pline = new BHG.Polyline {
                ControlPoints = BH.Engine.Geometry.Query.IControlPoints(buildingElementGeometry.ICurve())
            };

            double azimuth = Azimuth(pline, refVector);

            return(azimuth);
        }
Example #15
0
        public static BHG.Polyline ToBHoM(this Point3dVector osmLine)
        {
            BHG.Polyline pLine = new BHG.Polyline();

            foreach (Point3d p in osmLine)
            {
                pLine.ControlPoints.Add(p.ToBHoM());
            }

            return(pLine);
        }
Example #16
0
        /***************************************************/
        /**** Public Methods                            ****/
        /***************************************************/

        public static double Tilt(this BHEI.IBuildingObject buildingElementGeometry)
        {
            double tilt;

            BHG.Polyline pline = new BHG.Polyline {
                ControlPoints = BH.Engine.Geometry.Query.IControlPoints(buildingElementGeometry.ICurve())
            };

            tilt = Tilt(pline);
            return(tilt);
        }
Example #17
0
        /***************************************************/

        public static bool NormalAwayFromSpace(this BHG.Polyline pline, List <BHE.BuildingElement> elementsAsSpace)
        {
            List <BHG.Point> centrePtList = new List <BHG.Point>();

            BHG.Point centrePt = pline.Centre();
            centrePtList.Add(centrePt);

            if (!pline.IsClosed())
            {
                return(false);                   //Prevent failures of the clockwise check
            }
            List <BHG.Point> pts = BH.Engine.Geometry.Query.DiscontinuityPoints(pline);

            if (pts.Count < 3)
            {
                return(false);               //Protection in case there aren't enough points to make a plane
            }
            BHG.Plane plane = BH.Engine.Geometry.Create.Plane(pts[0], pts[1], pts[2]);



            //The polyline can be locally concave. Check if the polyline is clockwise.
            if (!BH.Engine.Geometry.Query.IsClockwise(pline, plane.Normal))
            {
                plane.Normal = -plane.Normal;
            }

            if (!BH.Engine.Geometry.Query.IsContaining(pline, centrePtList, false))
            {
                BHG.Point  pointOnLine = BH.Engine.Geometry.Query.ClosestPoint(pline, centrePt);
                BHG.Vector vector      = new BHG.Vector();
                if (BH.Engine.Geometry.Query.Distance(pointOnLine, centrePt) > BH.oM.Geometry.Tolerance.MicroDistance)
                {
                    vector = pointOnLine - centrePt;
                }
                else
                {
                    BHG.Line line = BH.Engine.Geometry.Query.GetLineSegment(pline, pointOnLine);
                    vector = ((line.Start - line.End).Normalise()).CrossProduct(plane.Normal);
                }

                centrePt = BH.Engine.Geometry.Modify.Translate(pointOnLine, BH.Engine.Geometry.Modify.Normalise(vector) * 0.001);
            }

            //Move centrepoint along the normal.
            if (BH.Engine.Environment.Query.IsContaining(elementsAsSpace, centrePt.Translate(plane.Normal * 0.01)))
            {
                return(false);
            }
            else
            {
                return(true);
            }
        }
Example #18
0
        public static TBD.Perimeter ToTAS(this BHG.Polyline polyline, TBD.Perimeter tbdPerimeter)
        {
            if (polyline == null)
            {
                return(tbdPerimeter);
            }

            TBD.Polygon poly = tbdPerimeter.CreateFace();
            poly = polyline.ToTASPolygon(poly);

            return(tbdPerimeter);
        }
Example #19
0
        public static SpecklePolyline ToSpeckle(this BHG.Polyline polyline)
        {
            if (polyline == null)
            {
                return(default(SpecklePolyline));
            }

            SpecklePolyline specklePolyline = new SpecklePolyline(polyline.ControlPoints.SelectMany(p => new List <double> {
                p.X, p.Y, p.Z
            }));

            return(specklePolyline);
        }
Example #20
0
        /***************************************************/
        /**** Public Methods                            ****/
        /***************************************************/

        public static double LongestSegment(BHG.Polyline pLine)
        {
            List <BHG.Point> pts    = pLine.DiscontinuityPoints();
            double           length = pts.Last().Distance(pts.First());

            for (int x = 0; x < pts.Count - 1; x++)
            {
                double dist = pts[x].Distance(pts[x + 1]);
                length = dist > length ? dist : length;
            }

            return(length);
        }
Example #21
0
        public static Point3dVector ToOSM(this BHG.Polyline pLine)
        {
            Point3dVector osmLine = new Point3dVector();

            foreach (BHG.Point p in pLine.ControlPoints)
            {
                osmLine.Add(p.ToOSM());
            }

            osmLine.RemoveAt(pLine.ControlPoints.Count - 1);

            return(osmLine);
        }
Example #22
0
        public static BHS.Level FromTAS(this TBD.BuildingStorey tbdStorey)
        {
            BHS.Level level = new BHS.Level();

            if (tbdStorey.GetPerimeter(0) != null)
            {
                BHG.Polyline levelCurve = tbdStorey.GetPerimeter(0).FromTAS();
                double       elevation  = levelCurve.ControlPoints.First().Z;
                level.Name      = "Level " + elevation.Round();
                level.Elevation = elevation.Round();
            }

            return(level);
        }
Example #23
0
        public static TBD.Polygon ToTASPolygon(this BHG.Polyline polyline, TBD.Polygon tbdPolygon)
        {
            if (polyline == null)
            {
                return(tbdPolygon);
            }

            foreach (BHG.Point pt in polyline.ControlPoints)
            {
                TBD.TasPoint p = tbdPolygon.AddPoint();
                p = pt.ToTAS(p);
            }

            return(tbdPolygon);
        }
Example #24
0
        /***************************************************/
        /**** Public Methods                            ****/
        /***************************************************/

        public static double Orientation(IBuildingObject buildingPanel)
        {
            Panel panel = buildingPanel as Panel;

            BHG.Polyline pLine = new BHG.Polyline {
                ControlPoints = panel.PanelCurve.IControlPoints()
            };

            List <BHG.Point> pts = pLine.DiscontinuityPoints();

            BHG.Plane plane = BH.Engine.Geometry.Create.Plane(pts[0], pts[1], pts[2]); //Some protection on this needed maybe?

            BHG.Vector xyNormal = BH.Engine.Geometry.Create.Vector(0, 1, 0);

            return(BH.Engine.Geometry.Query.Angle(plane.Normal, xyNormal) * (180 / Math.PI));
        }
Example #25
0
        public static BHX.BuildingStorey ToGBXML(this BHG.SettingOut.Level level, BHG.Polyline storeyGeometry, GBXMLSettings settings)
        {
            BHX.BuildingStorey storey = new BHX.BuildingStorey();

            if (storeyGeometry != null)
            {
                storey.PlanarGeometry.PolyLoop = storeyGeometry.ToGBXML(settings);
            }

            storey.PlanarGeometry.ID = "LevelPlanarGeometry-" + Guid.NewGuid().ToString().Replace("-", "").Substring(0, 10);
            storey.Name  = level.Name;
            storey.ID    = "Level-" + level.Name.Replace(" ", "").ToLower();
            storey.Level = (float)level.Elevation;

            return(storey);
        }
Example #26
0
        public static BHX.Surface ToGBXMLShade(this BHE.Panel element, GBXMLSettings settings)
        {
            BHP.OriginContextFragment envContextProperties = element.FindFragment <BHP.OriginContextFragment>(typeof(BHP.OriginContextFragment));

            BHX.Surface gbSrf = new BHX.Surface();
            gbSrf.CADObjectID       = element.CADObjectID();
            gbSrf.ConstructionIDRef = (envContextProperties == null ? element.ConstructionID() : envContextProperties.TypeName.CleanName());

            BHX.RectangularGeometry geom       = element.ToGBXMLGeometry(settings);
            BHX.PlanarGeometry      planarGeom = new BHX.PlanarGeometry();
            planarGeom.ID = "PlanarGeometry-" + Guid.NewGuid().ToString().Replace("-", "").Substring(0, 10);

            BHG.Polyline pLine = element.Polyline();
            planarGeom.PolyLoop = pLine.ToGBXML(settings);

            gbSrf.PlanarGeometry      = planarGeom;
            gbSrf.RectangularGeometry = geom;

            gbSrf.Opening = new BHX.Opening[element.Openings.Count];
            for (int x = 0; x < element.Openings.Count; x++)
            {
                if (element.Openings[x].Polyline().IControlPoints().Count != 0)
                {
                    gbSrf.Opening[x] = element.Openings[x].ToGBXML(element, settings);
                }
            }

            string idName = "Panel_" + element.BHoM_Guid.ToString().Replace(" ", "").Replace("-", "").Substring(0, 10);

            gbSrf.ID   = idName;
            gbSrf.Name = idName;

            gbSrf.SurfaceType  = "Shade";
            gbSrf.ExposedToSun = BH.Engine.Environment.Query.ExposedToSun(element).ToString().ToLower();

            if (settings.IncludeConstructions)
            {
                gbSrf.ConstructionIDRef = element.ConstructionID();
            }
            else //We have to force null otherwise Construction will be created
            {
                gbSrf.ConstructionIDRef = null;
            }

            return(gbSrf);
        }
Example #27
0
        /***************************************************/

        public static bool IsEqual(this BHG.Polyline bhPolyline, RHG.Polyline rhPolyline, double tolerance = BHG.Tolerance.Distance)
        {
            if (bhPolyline == null & rhPolyline == null)
            {
                return(true);
            }

            RHG.Point3d[]    rhPoints    = rhPolyline.ToArray();
            List <BHG.Point> bhPoints    = bhPolyline.ControlPoints;
            bool             pointsEqual = false;

            for (int i = 0; i < bhPoints.Count; i++)
            {
                pointsEqual = bhPoints[i].IsEqual(rhPoints[i], tolerance);
            }

            return(pointsEqual);
        }
Example #28
0
        public static BHX.BuildingStorey ToGBXML(this BHA.Level level, List <List <BHE.Panel> > spaces = null)
        {
            BHX.BuildingStorey storey = new BHX.BuildingStorey();

            if (spaces != null)
            {
                BHG.Polyline storeyGeometry = level.StoreyGeometry(spaces);
                if (storeyGeometry != null)
                {
                    storey.PlanarGeometry.PolyLoop = storeyGeometry.ToGBXML();
                }
            }

            storey.PlanarGeometry.ID = "level-planar-geometry-" + Guid.NewGuid().ToString().Replace("-", "").Substring(0, 10);
            storey.Name  = level.Name;
            storey.ID    = "Level-" + level.Name.Replace(" ", "").ToLower();
            storey.Level = (float)level.Elevation;

            return(storey);
        }
Example #29
0
        public static BHG.Polyline FromGBXML(this BHX.Polyloop pLoop, double tolerance = BHG.Tolerance.Distance)
        {
            BHG.Polyline pLine = new BHG.Polyline();

            List <BHX.CartesianPoint> pts = pLoop.CartesianPoint.ToList();

            List <BHG.Point> bhomPts = new List <BHG.Point>();

            for (int x = 0; x < pts.Count; x++)
            {
                bhomPts.Add(pts[x].FromGBXML());
            }

            if (bhomPts.First().SquareDistance(bhomPts.Last()) > (tolerance * tolerance))
            {
                bhomPts.Add(bhomPts.First());
            }

            pLine.ControlPoints = bhomPts;
            return(pLine);
        }
Example #30
0
        /***************************************************/

        public static double Azimuth(this BHG.Polyline pline, BHG.Vector refVector)
        {
            double azimuth;

            List <BHG.Point> pts = BH.Engine.Geometry.Query.DiscontinuityPoints(pline);

            if (pts.Count < 3 || !BH.Engine.Geometry.Query.IsClosed(pline))
            {
                return(-1);                                                            //Protection in case there aren't enough points to make a plane
            }
            BHG.Plane plane = BH.Engine.Geometry.Create.Plane(pts[0], pts[1], pts[2]);

            //The polyline can be locally concave. Check if the polyline is clockwise.
            if (!BH.Engine.Geometry.Query.IsClockwise(pline, plane.Normal))
            {
                plane.Normal = -plane.Normal;
            }

            if (Geometry.Modify.Normalise(plane.Normal).Z == 1)
            {
                azimuth = 0;
            }
            else if (Geometry.Modify.Normalise(plane.Normal).Z == -1)
            {
                azimuth = 180;
            }
            else
            {
                BHG.Vector v1 = Geometry.Modify.Project(plane.Normal, BHG.Plane.XY);
                BHG.Vector v2 = (Geometry.Modify.Project(refVector, BHG.Plane.XY));

                azimuth = (BH.Engine.Geometry.Query.SignedAngle(v1, v2, BHG.Vector.ZAxis) * (180 / Math.PI));
                if (azimuth < 0)
                {
                    azimuth = 360 + azimuth;
                }
            }
            return(azimuth);
        }