From d80f374f0ffa78cf859459a30600790432ad2d6d Mon Sep 17 00:00:00 2001 From: wojciech buda Date: Fri, 16 Oct 2026 13:08:28 +0200 Subject: [PATCH 1/5] New methods added for initial review --- .../Compute/RemoveUnconnectedLines.cs | 58 +++++++++ .../Modify/CullSortedDuplicates.cs | 104 +++++++++++++++ Geometry_Engine/Modify/OffsetNonUniform.cs | 119 ++++++++++++++++++ Geometry_Engine/Modify/SimplifyMidPoints.cs | 57 +++++++++ Geometry_Engine/Modify/Thicken.cs | 95 ++++++++++++++ Geometry_Engine/Query/BisectorVector.cs | 55 ++++++++ Geometry_Engine/Query/BoxCorners.cs | 71 +++++++++++ Geometry_Engine/Query/BoxCornersOnXY.cs | 62 +++++++++ Geometry_Engine/Query/GridPlane.cs | 46 +++++++ Geometry_Engine/Query/IntersectionLines.cs | 110 ++++++++++++++++ Geometry_Engine/Query/IntersectsOrContains.cs | 75 +++++++++++ Geometry_Engine/Query/IsAlignedRectangle.cs | 78 ++++++++++++ Geometry_Engine/Query/IsStartToEndParallel.cs | 54 ++++++++ .../Query/MaxDistanceByProjection.cs | 69 ++++++++++ Geometry_Engine/Query/MinInternalDistance.cs | 61 +++++++++ Geometry_Engine/Query/NonClosingEndPoint.cs | 49 ++++++++ Geometry_Engine/Query/OverlapLength.cs | 80 ++++++++++++ Geometry_Engine/Query/StartToEndDirection.cs | 67 ++++++++++ Geometry_Engine/Query/TransformAngle.cs | 50 ++++++++ 19 files changed, 1360 insertions(+) create mode 100644 Geometry_Engine/Compute/RemoveUnconnectedLines.cs create mode 100644 Geometry_Engine/Modify/CullSortedDuplicates.cs create mode 100644 Geometry_Engine/Modify/OffsetNonUniform.cs create mode 100644 Geometry_Engine/Modify/SimplifyMidPoints.cs create mode 100644 Geometry_Engine/Modify/Thicken.cs create mode 100644 Geometry_Engine/Query/BisectorVector.cs create mode 100644 Geometry_Engine/Query/BoxCorners.cs create mode 100644 Geometry_Engine/Query/BoxCornersOnXY.cs create mode 100644 Geometry_Engine/Query/GridPlane.cs create mode 100644 Geometry_Engine/Query/IntersectionLines.cs create mode 100644 Geometry_Engine/Query/IntersectsOrContains.cs create mode 100644 Geometry_Engine/Query/IsAlignedRectangle.cs create mode 100644 Geometry_Engine/Query/IsStartToEndParallel.cs create mode 100644 Geometry_Engine/Query/MaxDistanceByProjection.cs create mode 100644 Geometry_Engine/Query/MinInternalDistance.cs create mode 100644 Geometry_Engine/Query/NonClosingEndPoint.cs create mode 100644 Geometry_Engine/Query/OverlapLength.cs create mode 100644 Geometry_Engine/Query/StartToEndDirection.cs create mode 100644 Geometry_Engine/Query/TransformAngle.cs diff --git a/Geometry_Engine/Compute/RemoveUnconnectedLines.cs b/Geometry_Engine/Compute/RemoveUnconnectedLines.cs new file mode 100644 index 000000000..d5d1bb698 --- /dev/null +++ b/Geometry_Engine/Compute/RemoveUnconnectedLines.cs @@ -0,0 +1,58 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using BH.oM.Base.Attributes; +using BH.oM.Geometry; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace BH.Engine.Geometry +{ + public static partial class Compute + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Removes lines that are not connected at both ends.")] + [Input("lines", "List of lines.")] + [Input("decimalPlaces", "The number of decimal places to round to, default 3.")] + [Output("connectedLines", "List of lines which all have connections at both ends.")] + public static List RemoveUnconnectedLines(this List lines, int decimalPlaces = 3) + { + if (lines == null) + { + Base.Compute.RecordError("Input of lines to clean up cannot be null."); + return new List(); + } + + List endPoints = lines.Select(x => x.EndPoint().RoundCoordinates(decimalPlaces)).ToList(); + List startPoints = lines.Select(x => x.StartPoint().RoundCoordinates(decimalPlaces)).ToList(); + endPoints.AddRange(startPoints); + List uniquePoints = endPoints.Where(x => endPoints.Where(y => y == x).Count() == 1).ToList(); + return lines.Where(x => !uniquePoints.Contains(x.EndPoint().RoundCoordinates(decimalPlaces)) && !uniquePoints.Contains(x.StartPoint().RoundCoordinates(decimalPlaces))).ToList(); + } + + /***************************************************/ + } +} diff --git a/Geometry_Engine/Modify/CullSortedDuplicates.cs b/Geometry_Engine/Modify/CullSortedDuplicates.cs new file mode 100644 index 000000000..ba259728a --- /dev/null +++ b/Geometry_Engine/Modify/CullSortedDuplicates.cs @@ -0,0 +1,104 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using BH.oM.Base.Attributes; +using BH.oM.Geometry; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace BH.Engine.Geometry +{ + public static partial class Modify + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Removes consecutive near-duplicate points from an ordered point list while keeping the first and last points.")] + [Input("points", "Ordered points to cull.")] + [Input("minSegmentLength", "Minimum kept segment length.")] + [Output("points", "Culled point list.")] + public static List CullSortedDuplicates(this List points, double minSegmentLength = Tolerance.Distance) + { + if (points.Count == 0) + return points; + + List output = new List { points.First() }; + double squaredMinLength = minSegmentLength * minSegmentLength; + + for (int i = 1; i < points.Count - 1; i++) + { + Point pnt = points[i]; + + if (pnt.SquareDistance(output.Last()) < squaredMinLength + || pnt.SquareDistance(points.Last()) < squaredMinLength) + continue; + + output.Add(pnt); + } + + if (output.Last().SquareDistance(points.Last()) > Tolerance.Distance * Tolerance.Distance) + output.Add(points.Last()); + + return output; + } + + /***************************************************/ + + [Description("Removes consecutive near-duplicate points from an ordered point list and reports skipped indexes.")] + [Input("points", "Ordered points to cull.")] + [Input("skippedIndexes", "Indexes of removed interior points.")] + [Input("minSegmentLength", "Minimum kept segment length.")] + [Output("points", "Culled point list.")] + public static List CullSortedDuplicates(this List points, out List skippedIndexes, double minSegmentLength = Tolerance.Distance) + { + skippedIndexes = new List(); + if (points.Count == 0) + return points; + + List output = new List { points.First() }; + double squaredMinLength = minSegmentLength * minSegmentLength; + + for (int i = 1; i < points.Count - 1; i++) + { + Point pnt = points[i]; + + if (pnt.SquareDistance(output.Last()) < squaredMinLength + || pnt.SquareDistance(points.Last()) < squaredMinLength) + { + skippedIndexes.Add(i); + continue; + } + + output.Add(pnt); + } + + if (output.Last().SquareDistance(points.Last()) > Tolerance.Distance * Tolerance.Distance) + output.Add(points.Last()); + + return output; + } + + /***************************************************/ + } +} diff --git a/Geometry_Engine/Modify/OffsetNonUniform.cs b/Geometry_Engine/Modify/OffsetNonUniform.cs new file mode 100644 index 000000000..c013ed3de --- /dev/null +++ b/Geometry_Engine/Modify/OffsetNonUniform.cs @@ -0,0 +1,119 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using BH.Engine.Base; +using BH.oM.Base.Attributes; +using BH.oM.Geometry; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace BH.Engine.Geometry +{ + public static partial class Modify + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Offset each segment of a polyline by a value from the input list of distances.")] + [Input("pLine", "The polyline to offset non-uniformly.")] + [Input("distances", "Distances to use when offsetting individual segments of the polyline.")] + [Input("normal", "The normal vector of a plane to use during the offset operation.")] + [Input("tolerance", "The tolerance to use during the offset operation.")] + [Output("polyline", "The input polyline once each of its segments has been offset by the respective distance.")] + public static Polyline OffsetNonUniform(this Polyline pLine, List distances, Vector normal = null, double tolerance = Tolerance.Distance) + { + if (pLine == null || pLine.Length() < tolerance) + return null; + + if (distances.Any(x => x < 0)) + { + Base.Compute.RecordError("This method currently supports non-negative offset distances only."); + return null; + } + + if (!pLine.IsPlanar(tolerance)) + { + Base.Compute.RecordError("Offset works only on planar curves"); + return null; + } + + if (pLine.SubParts().Count != distances.Count) + { + Base.Compute.RecordError("Count of offset distances must match the number of segments in the polyline"); + return null; + } + + if (!pLine.IsClosed(tolerance)) + { + Base.Compute.RecordError("Polyline must be closed"); + return null; + } + + if (distances.All(x => x == 0)) + return pLine; + + List segments = pLine.SubParts(); + List newLines = new List(); + normal = normal?.Normalise() ?? pLine.Normal(); + Point averagePnt = pLine.Bounds().Centre(); + + for (int i = 0; i < segments.Count; i++) + { + Line line = segments[i]; + double distance = distances[i]; + Line offsetLine = line.Offset(distances[i], normal); + + Vector directionToCenter = averagePnt - line.Start; + Vector newDirectionToCenter = averagePnt - offsetLine.Start; + bool directionMaintained = directionToCenter.Angle(newDirectionToCenter) < Math.PI / 2; + + if (!directionMaintained) + offsetLine = line.Offset(distances[i], -normal); + else + { + double distanceToCenter = line.Start.Distance(averagePnt); + double newDistanceToCenter = offsetLine.Start.Distance(averagePnt); + bool newLineIsOutside = newDistanceToCenter > distanceToCenter; + + if ((distance > 0 && !newLineIsOutside) || (distance < 0 && newLineIsOutside)) + offsetLine = line.Offset(distances[i], -normal); + } + + offsetLine.Infinite = true; + newLines.Add(offsetLine); + } + + List nextLines = newLines.ShiftList(1); + List intersections = new List(); + + for (int i = 0; i < newLines.Count; i++) + intersections.Add(newLines[i].LineIntersection(nextLines[i], true)); + + return new Polyline { ControlPoints = intersections }.Close(); + } + + /***************************************************/ + } +} diff --git a/Geometry_Engine/Modify/SimplifyMidPoints.cs b/Geometry_Engine/Modify/SimplifyMidPoints.cs new file mode 100644 index 000000000..df3f64a5a --- /dev/null +++ b/Geometry_Engine/Modify/SimplifyMidPoints.cs @@ -0,0 +1,57 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using BH.oM.Base.Attributes; +using BH.oM.Geometry; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace BH.Engine.Geometry +{ + public static partial class Modify + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Returns a simplified version of the input polyline where midpoints are simplified but endpoints are retained.")] + [Input("pLine", "A polyline to simplify.")] + [Output("polyline", "A simplified version of the input polyline where midpoints are simplified but endpoints are retained.")] + public static Polyline SimplifyMidPoints(this Polyline pLine) + { + List points = pLine.ControlPoints; + if (points.Count < 2) + return pLine; + + List simplified = new List { points.First() }; + List midPoints = points.Skip(1).Take(points.Count - 2).ToList(); + List cleaned = new Polyline { ControlPoints = midPoints }.DiscontinuityPoints(angleTolerance: 1); + + simplified.AddRange(cleaned); + simplified.Add(points.Last()); + return new Polyline { ControlPoints = simplified }; + } + + /***************************************************/ + } +} diff --git a/Geometry_Engine/Modify/Thicken.cs b/Geometry_Engine/Modify/Thicken.cs new file mode 100644 index 000000000..c77612038 --- /dev/null +++ b/Geometry_Engine/Modify/Thicken.cs @@ -0,0 +1,95 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using BH.oM.Base.Attributes; +using BH.oM.Geometry; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace BH.Engine.Geometry +{ + public static partial class Modify + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Thicken a line to create a closed polyline with the same direction and a custom thickness.")] + [Input("line", "A line to convert into a closed polyline via thickening.")] + [Input("thickness", "A custom thickness for the new closed polyline.")] + [Input("plane", "Plane that defines the thicken direction via its normal.")] + [Output("polyline", "A closed polyline with the same direction as the input line and a custom thickness.")] + public static Polyline Thicken(this Line line, double thickness, Plane plane) + { + if (line.StartToEndDirection().IsParallel(plane.Normal) != 0) + { + Base.Compute.RecordError("Can't thicken a line parallel to the plane normal."); + return null; + } + + Vector offsetVector = line.StartToEndDirection().CrossProduct(plane.Normal).Normalise() * thickness / 2; + + Point p1 = line.Start + offsetVector; + Point p2 = line.End + offsetVector; + Point p3 = line.End - offsetVector; + Point p4 = line.Start - offsetVector; + + return new Polyline { ControlPoints = new List { p1, p2, p3, p4, p1 } }; + } + + /***************************************************/ + + [Description("Thicken a curve to create a closed polyline with a custom thickness.")] + [Input("crv", "A curve to convert into a closed polyline via thickening.")] + [Input("thickness", "A custom thickness for the new closed polyline.")] + [Input("plane", "Plane that defines the thicken direction via its normal.")] + [Output("polyline", "A closed polyline thickened from the input curve.")] + public static Polyline Thicken(this ICurve crv, double thickness, Plane plane) + { + if (crv.StartToEndDirection().IsParallel(plane.Normal) != 0) + { + Base.Compute.RecordError("Can't thicken a curve parallel to the plane normal."); + return null; + } + + if (crv is Line line) + return line.Thicken(thickness, plane); + + if (crv is NurbsCurve) + { + Polyline pLine = new Polyline { ControlPoints = crv.IControlPoints().CullDuplicates() }; + return pLine.Thicken(thickness, plane); + } + + ICurve c1 = crv.IOffset(thickness, plane.Normal, true); + ICurve c2 = crv.IOffset(thickness, -plane.Normal, true); + List points2 = c2.IControlPoints(); + points2.Reverse(); + + List points = c1.IControlPoints().Concat(points2).ToList(); + return new Polyline { ControlPoints = points }.Close(); + } + + /***************************************************/ + } +} diff --git a/Geometry_Engine/Query/BisectorVector.cs b/Geometry_Engine/Query/BisectorVector.cs new file mode 100644 index 000000000..9365702fc --- /dev/null +++ b/Geometry_Engine/Query/BisectorVector.cs @@ -0,0 +1,55 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using BH.oM.Base.Attributes; +using BH.oM.Geometry; +using System; +using System.ComponentModel; + +namespace BH.Engine.Geometry +{ + public static partial class Query + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Returns the unit bisector of two vectors.")] + [Input("v1", "First vector.")] + [Input("v2", "Second vector.")] + [Output("bisector", "Normalised vector along the half-angle between v1 and v2.")] + public static Vector BisectorVector(this Vector v1, Vector v2) + { + Vector normalizedV1 = v1.Normalise(); + Vector normalizedV2 = v2.Normalise(); + + float angle = (float)Math.Acos(normalizedV1.DotProduct(normalizedV2)); + float halfAngle = angle / 2.0f; + Vector axis = normalizedV1.CrossProduct(normalizedV2); + TransformMatrix rotation = Create.RotationMatrix(Point.Origin, axis, halfAngle); + + return normalizedV1.Transform(rotation).Normalise(); + } + + /***************************************************/ + } +} diff --git a/Geometry_Engine/Query/BoxCorners.cs b/Geometry_Engine/Query/BoxCorners.cs new file mode 100644 index 000000000..95f3d5719 --- /dev/null +++ b/Geometry_Engine/Query/BoxCorners.cs @@ -0,0 +1,71 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using BH.oM.Base.Attributes; +using BH.oM.Geometry; +using System.Collections.Generic; +using System.ComponentModel; + +namespace BH.Engine.Geometry +{ + public static partial class Query + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Returns corners of a box that has the input center point, width, height and directions.")] + [Input("center", "Center of the new box.")] + [Input("width", "Width of the new box.")] + [Input("height", "Height of the new box.")] + [Input("xVector", "Direction of the new box's horizontal edges.")] + [Input("yVector", "Direction of the new box's vertical edges.")] + [Output("corners", "Corners of a box that has the input center point, width, height and directions.")] + public static List BoxCorners(this Point center, double width, double height, Vector xVector, Vector yVector) + { + return center.BoxCorners(width, height, xVector, yVector, Plane.XY.Origin); + } + + /***************************************************/ + + [Description("Returns corners of a box defined by center point, width, height, directions, and origin.")] + [Input("center", "Center of the new box.")] + [Input("width", "Width of the new box.")] + [Input("height", "Height of the new box.")] + [Input("xVector", "Direction of the new box's horizontal edges.")] + [Input("yVector", "Direction of the new box's vertical edges.")] + [Input("origin", "The origin point for the plane on which the box lies.")] + [Output("corners", "Corners of a box that has the input center point, width, height and directions.")] + public static List BoxCorners(this Point center, double width, double height, Vector xVector, Vector yVector, Point origin) + { + Plane xyPlane = Create.Plane(origin, xVector.CrossProduct(yVector)); + Point p0 = center.Project(xyPlane) - xVector * width / 2 + yVector * height / 2; + Point p1 = p0 + xVector * width; + Point p2 = p1 - yVector * height; + Point p3 = p2 - xVector * width; + + return new List { p0, p1, p2, p3 }; + } + + /***************************************************/ + } +} diff --git a/Geometry_Engine/Query/BoxCornersOnXY.cs b/Geometry_Engine/Query/BoxCornersOnXY.cs new file mode 100644 index 000000000..1fd8e3e81 --- /dev/null +++ b/Geometry_Engine/Query/BoxCornersOnXY.cs @@ -0,0 +1,62 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using BH.oM.Base.Attributes; +using BH.oM.Geometry; +using System.Collections.Generic; +using System.ComponentModel; + +namespace BH.Engine.Geometry +{ + public static partial class Query + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Returns the four corners of a bounding rectangle on the XY plane defined by two opposite points.")] + [Input("point1", "The first point defining the bounding rectangle.")] + [Input("point2", "The second point defining the bounding rectangle.")] + [Output("corners", "The four corner points of the bounding rectangle on the XY plane.")] + public static List BoxCornersOnXY(this Point point1, Point point2) + { + if (point1 == null || point2 == null) + return null; + + BoundingBox box = new List { point1, point2 }.Bounds(); + Point pMin = box.Min.Project(Plane.XY); + Point pMax = box.Max.Project(Plane.XY); + + Point p0 = new Line { Start = pMin, End = pMin + Vector.YAxis, Infinite = true } + .LineIntersection(new Line { Start = pMax, End = pMax - Vector.XAxis, Infinite = true }, true); + Point p1 = new Line { Start = pMin, End = pMin + Vector.XAxis, Infinite = true } + .LineIntersection(new Line { Start = pMax, End = pMax - Vector.YAxis, Infinite = true }, true); + + if (p0 == null || p1 == null) + return null; + + return new List { pMin, p0, pMax, p1 }; + } + + /***************************************************/ + } +} diff --git a/Geometry_Engine/Query/GridPlane.cs b/Geometry_Engine/Query/GridPlane.cs new file mode 100644 index 000000000..15f70f52c --- /dev/null +++ b/Geometry_Engine/Query/GridPlane.cs @@ -0,0 +1,46 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using BH.oM.Base.Attributes; +using BH.oM.Geometry; +using System.ComponentModel; + +namespace BH.Engine.Geometry +{ + public static partial class Query + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Creates a plane with origin at the start point of the line and normal being the cross product of the XY line direction and global Z.")] + [Input("line", "Line to be used to construct the plane.")] + [Output("plane", "Plane with origin at start point of the line and normal being the cross product of line direction and global Z vector.")] + public static Plane GridPlane(this Line line) + { + Vector dir = new Vector { X = line.End.X - line.Start.X, Y = line.End.Y - line.Start.Y, Z = 0 }.Normalise(); + return new Plane { Origin = line.Start, Normal = new Vector { X = -dir.Y, Y = dir.X, Z = 0 } }; + } + + /***************************************************/ + } +} diff --git a/Geometry_Engine/Query/IntersectionLines.cs b/Geometry_Engine/Query/IntersectionLines.cs new file mode 100644 index 000000000..7b201714c --- /dev/null +++ b/Geometry_Engine/Query/IntersectionLines.cs @@ -0,0 +1,110 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using BH.oM.Base.Attributes; +using BH.oM.Geometry; +using BH.oM.Quantities.Attributes; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace BH.Engine.Geometry +{ + public static partial class Query + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Returns the segments of a line that lie inside a closed planar region.")] + [Input("region", "Closed planar region.")] + [Input("line", "Line to clip against the region.")] + [Input("acceptOnEdges", "If true, segments that lie on the region boundary are kept.")] + [Input("tolerance", "Distance tolerance.", typeof(Length))] + [Output("lines", "Segments of the line inside the region.")] + public static List IntersectionLines(this PolyCurve region, Line line, bool acceptOnEdges = false, double tolerance = Tolerance.Distance) + { + if (region == null || line == null) + return new List(); + + // Honor line.Infinite. A finite line must not grow out to the infinite chord through the region. + List pts = region.LineIntersections(line, false, tolerance) ?? new List(); + if (!line.Infinite) + { + if (line.Start != null && region.IsContaining(new List { line.Start }, acceptOnEdges, tolerance)) + pts.Add(line.Start); + if (line.End != null && region.IsContaining(new List { line.End }, acceptOnEdges, tolerance)) + pts.Add(line.End); + } + + pts = pts.Where(p => p != null).ToList().CullDuplicates(tolerance); + if (pts.Count < 2) + return new List(); + + Vector dir = line.Direction(); + if (dir.SquareLength() <= tolerance * tolerance) + return new List(); + + pts = pts.OrderBy(p => (p - line.Start) * dir).ToList(); + + List result = new List(); + for (int i = 0; i < pts.Count - 1; i++) + { + Point mid = (pts[i] + pts[i + 1]) * 0.5; + if (!region.IsContaining(new List { mid }, acceptOnEdges, tolerance)) + continue; + + Line segment = new Line { Start = pts[i], End = pts[i + 1] }; + if (segment.Length() > tolerance) + result.Add(segment); + } + + return result; + } + + /***************************************************/ + + [Description("Returns the intersection lines of a closed planar region with a cutting plane.")] + [Input("region", "Closed planar region.")] + [Input("plane", "Cutting plane.")] + [Input("tolerance", "Distance tolerance.", typeof(Length))] + [Output("lines", "Intersection segments of the region with the plane.")] + public static List IntersectionLines(this PolyCurve region, Plane plane, double tolerance = Tolerance.Distance) + { + if (region == null || plane == null) + return new List(); + + Plane regionPlane = region.FitPlane(tolerance); + if (regionPlane == null) + return new List(); + + Line cut = regionPlane.PlaneIntersection(plane, tolerance); + if (cut == null) + return new List(); + + cut.Infinite = true; + return region.IntersectionLines(cut, false, tolerance); + } + + /***************************************************/ + } +} diff --git a/Geometry_Engine/Query/IntersectsOrContains.cs b/Geometry_Engine/Query/IntersectsOrContains.cs new file mode 100644 index 000000000..49798c275 --- /dev/null +++ b/Geometry_Engine/Query/IntersectsOrContains.cs @@ -0,0 +1,75 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using BH.oM.Base.Attributes; +using BH.oM.Geometry; +using BH.oM.Quantities.Attributes; +using System.Collections.Generic; +using System.ComponentModel; + +namespace BH.Engine.Geometry +{ + public static partial class Query + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Checks whether a polyline intersects or contains a curve. Lines and polylines use their own intersection tests. Any other curve is inside only when it does not cross the boundary and its start point is inside.")] + [Input("region", "Polyline region.")] + [Input("curve", "Line, polyline, or other curve to test.")] + [Input("tolerance", "Distance tolerance.", typeof(Length))] + [Output("intersectsOrContains", "True if the curve crosses the polyline or lies inside it.")] + public static bool IntersectsOrContains(this Polyline region, ICurve curve, double tolerance = Tolerance.Distance) + { + if (region == null || curve == null) + return false; + + if (curve is Line line) + { + if (region.LineIntersections(line, false, tolerance)?.Count > 0) + return true; + + return region.IsContaining(new List { line.Start, line.End }, true, tolerance); + } + + if (curve is Polyline other) + { + if (region.LineIntersections(other, tolerance)?.Count > 0) + return true; + + if (other.ControlPoints != null && other.ControlPoints.Count > 0 && region.IsContaining(other.ControlPoints, true, tolerance)) + return true; + + return region.ControlPoints != null && region.ControlPoints.Count > 0 && other.IsContaining(region.ControlPoints, true, tolerance); + } + + if (region.ICurveIntersections(curve, tolerance)?.Count > 0) + return true; + + Point sample = curve.IStartPoint(); + return sample != null && region.IsContaining(new List { sample }, true, tolerance); + } + + /***************************************************/ + } +} diff --git a/Geometry_Engine/Query/IsAlignedRectangle.cs b/Geometry_Engine/Query/IsAlignedRectangle.cs new file mode 100644 index 000000000..7106ae93f --- /dev/null +++ b/Geometry_Engine/Query/IsAlignedRectangle.cs @@ -0,0 +1,78 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using BH.oM.Base.Attributes; +using BH.oM.Geometry; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace BH.Engine.Geometry +{ + public static partial class Query + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Checks if a polyline is a closed, globally aligned rectangle with edges parallel to the specified X and Y vectors.")] + [Input("pLine", "The polyline to check if it is a globally aligned rectangle.")] + [Input("xVector", "The X direction vector that one pair of parallel edges should be parallel to.")] + [Input("yVector", "The Y direction vector that the other pair of parallel edges should be parallel to.")] + [Output("isAlignedRectangle", "True if the polyline is a closed rectangle with edges aligned to the specified vectors.")] + public static bool IsAlignedRectangle(this Polyline pLine, Vector xVector, Vector yVector) + { + if (pLine == null || xVector == null || yVector == null) + return false; + + if (!pLine.IsClosed()) + return false; + + List controlPoints = pLine.ControlPoints; + if (controlPoints.Count != 5) + return false; + + List edges = pLine.SubParts(); + if (edges.Count != 4) + return false; + + Vector firstDirection = edges[0].Direction(); + List group1 = edges.Where(x => x.Direction().IsParallel(firstDirection) != 0).ToList(); + List group2 = edges.Where(x => x.Direction().IsParallel(firstDirection) == 0).ToList(); + + if (group1.Count != 2 || group2.Count != 2) + return false; + + Vector group2Direction = group2[0].Direction(); + double angle = firstDirection.Angle(group2Direction); + if (Math.Abs(angle - Math.PI / 2) > Tolerance.Angle) + return false; + + bool group1Aligned = firstDirection.IsParallel(xVector) != 0 || firstDirection.IsParallel(yVector) != 0; + bool group2Aligned = group2Direction.IsParallel(xVector) != 0 || group2Direction.IsParallel(yVector) != 0; + return group1Aligned && group2Aligned; + } + + /***************************************************/ + } +} diff --git a/Geometry_Engine/Query/IsStartToEndParallel.cs b/Geometry_Engine/Query/IsStartToEndParallel.cs new file mode 100644 index 000000000..00608e4b9 --- /dev/null +++ b/Geometry_Engine/Query/IsStartToEndParallel.cs @@ -0,0 +1,54 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using BH.oM.Base.Attributes; +using BH.oM.Geometry; +using System.ComponentModel; + +namespace BH.Engine.Geometry +{ + public static partial class Query + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Checks whether two curves are parallel based on their start-to-end directions.")] + [Input("curve1", "The first curve whose start-to-end direction is used for comparison.")] + [Input("curve2", "The second curve whose start-to-end direction is used for comparison.")] + [Input("angleTolerance", "The maximum angle (in radians) between the two directions for them to be considered parallel.")] + [Output("isParallel", "True if the start-to-end directions of the two curves are parallel within the given tolerance, false otherwise.")] + public static bool IsStartToEndParallel(this ICurve curve1, ICurve curve2, double angleTolerance) + { + Vector hostVect = curve1.StartToEndDirection(); + Vector elemVect = curve2.StartToEndDirection(); + + if (hostVect.IsParallel(elemVect) != 0) + return true; + + double angle = hostVect.AcuteAngle(elemVect); + return angle < angleTolerance; + } + + /***************************************************/ + } +} diff --git a/Geometry_Engine/Query/MaxDistanceByProjection.cs b/Geometry_Engine/Query/MaxDistanceByProjection.cs new file mode 100644 index 000000000..f63649feb --- /dev/null +++ b/Geometry_Engine/Query/MaxDistanceByProjection.cs @@ -0,0 +1,69 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using BH.oM.Base.Attributes; +using BH.oM.Geometry; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace BH.Engine.Geometry +{ + public static partial class Query + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Gets the max distance along the projection vector between all input lines and the dividing line.")] + [Input("lines", "Lines to measure against the dividing line.")] + [Input("dividingLine", "A line crossing the list of input lines.")] + [Input("projectionVector", "Direction along which the max distance is measured.")] + [Input("useInfiniteLines", "If true, intersections use infinite lines.")] + [Output("maxDistanceByProjection", "The max distance along the projection vector between input lines and the dividing line.")] + public static double MaxDistanceByProjection(this IEnumerable lines, Line dividingLine, Vector projectionVector, bool useInfiniteLines = false) + { + double distance = double.NaN; + dividingLine.Infinite = true; + BoundingBox lineBox = lines.Select(x => x.Bounds()).ToList().Bounds(); + double extensionLength = lineBox.Min.Distance(lineBox.Max) * 5; + + foreach (Line edge in lines) + { + Point rayOrigin = edge.Start; + Line ray = new Line { Start = rayOrigin, End = rayOrigin + (projectionVector * extensionLength) }; + + Point intersection = ray.LineIntersection(dividingLine, useInfiniteLines); + if (intersection == null) + continue; + + double newDist = intersection.Distance(rayOrigin); + if (double.IsNaN(distance) || newDist > distance) + distance = newDist; + } + + return distance; + } + + /***************************************************/ + } +} diff --git a/Geometry_Engine/Query/MinInternalDistance.cs b/Geometry_Engine/Query/MinInternalDistance.cs new file mode 100644 index 000000000..d0014dd7c --- /dev/null +++ b/Geometry_Engine/Query/MinInternalDistance.cs @@ -0,0 +1,61 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using BH.oM.Base.Attributes; +using BH.oM.Geometry; +using System; +using System.Collections.Generic; +using System.ComponentModel; + +namespace BH.Engine.Geometry +{ + public static partial class Query + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Returns the minimum distance between any two distinct points in the list.")] + [Input("points", "Points to compare.")] + [Output("minDistance", "Smallest pairwise distance, or MaxValue if fewer than two points.")] + public static double MinInternalDistance(this List points) + { + double minDistance = double.MaxValue; + + foreach (Point point1 in points) + { + foreach (Point point2 in points) + { + if (point1 == point2) + continue; + + double distance = point1.Distance(point2); + minDistance = Math.Min(distance, minDistance); + } + } + + return minDistance; + } + + /***************************************************/ + } +} diff --git a/Geometry_Engine/Query/NonClosingEndPoint.cs b/Geometry_Engine/Query/NonClosingEndPoint.cs new file mode 100644 index 000000000..e9e04f7f9 --- /dev/null +++ b/Geometry_Engine/Query/NonClosingEndPoint.cs @@ -0,0 +1,49 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using BH.oM.Base.Attributes; +using BH.oM.Geometry; +using System.ComponentModel; +using System.Linq; + +namespace BH.Engine.Geometry +{ + public static partial class Query + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Returns the last control point of a polyline, skipping the closing duplicate when the polyline is closed.")] + [Input("pLine", "Polyline to query.")] + [Output("endPoint", "Last non-closing control point.")] + public static Point NonClosingEndPoint(this Polyline pLine) + { + if (pLine.IsClosed()) + return pLine.ControlPoints[pLine.ControlPoints.Count - 2]; + + return pLine.ControlPoints.Last(); + } + + /***************************************************/ + } +} diff --git a/Geometry_Engine/Query/OverlapLength.cs b/Geometry_Engine/Query/OverlapLength.cs new file mode 100644 index 000000000..c64c73b90 --- /dev/null +++ b/Geometry_Engine/Query/OverlapLength.cs @@ -0,0 +1,80 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using BH.oM.Base.Attributes; +using BH.oM.Geometry; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace BH.Engine.Geometry +{ + public static partial class Query + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Calculates the overlap length between multiple parallel lines when moved to coincide.")] + [Input("parallelLines", "Collection of parallel lines.")] + [Input("distanceTolerance", "Distance tolerance for geometric operations.")] + [Output("overlapLength", "Length of overlap when all lines are moved to coincide.")] + public static double OverlapLength(this List parallelLines, double distanceTolerance = Tolerance.Distance) + { + if (parallelLines == null || parallelLines.Count < 2) + return 0.0; + + Vector direction = parallelLines[0].Direction(); + + List<(double start, double end)> projections = new List<(double start, double end)>(); + foreach (Line line in parallelLines) + projections.Add(EndParametersOnVector(line, direction)); + + double overlapStart = projections.Max(p => p.start); + double overlapEnd = projections.Min(p => p.end); + + if (overlapEnd <= overlapStart) + return 0.0; + + return overlapEnd - overlapStart; + } + + /***************************************************/ + /**** Private Methods ****/ + /***************************************************/ + + private static (double start, double end) EndParametersOnVector(this Line line, Vector direction) + { + if (line == null || direction == null) + return (0.0, 0.0); + + Vector normalizedDir = direction.Normalise(); + double startParam = (line.Start - Point.Origin) * normalizedDir; + double endParam = (line.End - Point.Origin) * normalizedDir; + + return (Math.Min(startParam, endParam), Math.Max(startParam, endParam)); + } + + /***************************************************/ + } +} diff --git a/Geometry_Engine/Query/StartToEndDirection.cs b/Geometry_Engine/Query/StartToEndDirection.cs new file mode 100644 index 000000000..bbf45adc8 --- /dev/null +++ b/Geometry_Engine/Query/StartToEndDirection.cs @@ -0,0 +1,67 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using BH.oM.Base.Attributes; +using BH.oM.Geometry; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace BH.Engine.Geometry +{ + public static partial class Query + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Returns the chord direction from the first control point of a polyline to its last (or pre-close) control point.")] + [Input("pLine", "Polyline whose start-to-end direction is requested.")] + [Output("direction", "Vector from the first control point to the last non-closing control point.")] + public static Vector StartToEndDirection(this Polyline pLine) + { + if (pLine.ControlPoints.Count == 2) + return pLine.SubParts().First().StartToEndDirection(); + + Point p1 = pLine.ControlPoints.First(); + Point p2 = pLine.ControlPoints.Last(); + + if (pLine.IsClosed()) + p2 = pLine.ControlPoints[pLine.ControlPoints.Count - 2]; + + return p2 - p1; + } + + /***************************************************/ + + [Description("Returns the normalised chord direction from the first control point of a curve to its last.")] + [Input("curve", "Curve whose start-to-end direction is requested.")] + [Output("direction", "Normalised vector from the first control point to the last.")] + public static Vector StartToEndDirection(this ICurve curve) + { + List controlPoints = curve.IControlPoints(); + return (controlPoints.Last() - controlPoints.First()).Normalise(); + } + + /***************************************************/ + } +} diff --git a/Geometry_Engine/Query/TransformAngle.cs b/Geometry_Engine/Query/TransformAngle.cs new file mode 100644 index 000000000..3ebead1b9 --- /dev/null +++ b/Geometry_Engine/Query/TransformAngle.cs @@ -0,0 +1,50 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using BH.oM.Base.Attributes; +using BH.oM.Geometry; +using System; +using System.ComponentModel; + +namespace BH.Engine.Geometry +{ + public static partial class Query + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Extracts the rotation angle encoded in a 2D transform matrix.")] + [Input("transform", "The transform matrix from which to extract the rotation angle.")] + [Output("angle", "The rotation angle in radians as encoded in the transform matrix.")] + public static double TransformAngle(this TransformMatrix transform) + { + double[,] matrixArray = transform.Matrix; + double sinTheta = matrixArray[1, 0]; + double cosTheta = matrixArray[0, 0]; + + return Math.Atan2(sinTheta, cosTheta); + } + + /***************************************************/ + } +} From 06c53ffff23e2a9c87918e32aadcb4742451e74d Mon Sep 17 00:00:00 2001 From: wojciech buda Date: Sun, 18 Oct 2026 22:48:17 +0200 Subject: [PATCH 2/5] Fix BoxCorners elevation --- Geometry_Engine/Query/BoxCorners.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Geometry_Engine/Query/BoxCorners.cs b/Geometry_Engine/Query/BoxCorners.cs index 95f3d5719..59d946f74 100644 --- a/Geometry_Engine/Query/BoxCorners.cs +++ b/Geometry_Engine/Query/BoxCorners.cs @@ -33,7 +33,7 @@ public static partial class Query /**** Public Methods ****/ /***************************************************/ - [Description("Returns corners of a box that has the input center point, width, height and directions.")] + [Description("Returns corners of a box that has the input center point, width, height and directions. The box lies on the plane through the centre, so the centre keeps its elevation.")] [Input("center", "Center of the new box.")] [Input("width", "Width of the new box.")] [Input("height", "Height of the new box.")] @@ -42,7 +42,7 @@ public static partial class Query [Output("corners", "Corners of a box that has the input center point, width, height and directions.")] public static List BoxCorners(this Point center, double width, double height, Vector xVector, Vector yVector) { - return center.BoxCorners(width, height, xVector, yVector, Plane.XY.Origin); + return center.BoxCorners(width, height, xVector, yVector, center); } /***************************************************/ From 794b56942d4d47c4970f8263b5dad68ab515871c Mon Sep 17 00:00:00 2001 From: wojciech buda Date: Wed, 21 Oct 2026 13:12:46 +0200 Subject: [PATCH 3/5] Migration to Tagging_Tool and reanaming --- .../Modify/CullSortedDuplicates.cs | 104 --------------- Geometry_Engine/Modify/OffsetNonUniform.cs | 119 ------------------ Geometry_Engine/Modify/SimplifyMidPoints.cs | 57 --------- Geometry_Engine/Modify/Thicken.cs | 9 +- .../Query/{BisectorVector.cs => Bisector.cs} | 2 +- Geometry_Engine/Query/BoxCorners.cs | 71 ----------- Geometry_Engine/Query/GridPlane.cs | 46 ------- Geometry_Engine/Query/IntersectionLines.cs | 110 ---------------- Geometry_Engine/Query/IntersectsOrContains.cs | 75 ----------- Geometry_Engine/Query/IsAlignedRectangle.cs | 78 ------------ Geometry_Engine/Query/IsStartToEndParallel.cs | 54 -------- .../Query/MaxDistanceByProjection.cs | 69 ---------- ...{MinInternalDistance.cs => MinDistance.cs} | 2 +- Geometry_Engine/Query/NonClosingEndPoint.cs | 49 -------- Geometry_Engine/Query/OverlapLength.cs | 80 ------------ Geometry_Engine/Query/StartToEndDirection.cs | 67 ---------- Geometry_Engine/Query/TransformAngle.cs | 50 -------- 17 files changed, 8 insertions(+), 1034 deletions(-) delete mode 100644 Geometry_Engine/Modify/CullSortedDuplicates.cs delete mode 100644 Geometry_Engine/Modify/OffsetNonUniform.cs delete mode 100644 Geometry_Engine/Modify/SimplifyMidPoints.cs rename Geometry_Engine/Query/{BisectorVector.cs => Bisector.cs} (97%) delete mode 100644 Geometry_Engine/Query/BoxCorners.cs delete mode 100644 Geometry_Engine/Query/GridPlane.cs delete mode 100644 Geometry_Engine/Query/IntersectionLines.cs delete mode 100644 Geometry_Engine/Query/IntersectsOrContains.cs delete mode 100644 Geometry_Engine/Query/IsAlignedRectangle.cs delete mode 100644 Geometry_Engine/Query/IsStartToEndParallel.cs delete mode 100644 Geometry_Engine/Query/MaxDistanceByProjection.cs rename Geometry_Engine/Query/{MinInternalDistance.cs => MinDistance.cs} (97%) delete mode 100644 Geometry_Engine/Query/NonClosingEndPoint.cs delete mode 100644 Geometry_Engine/Query/OverlapLength.cs delete mode 100644 Geometry_Engine/Query/StartToEndDirection.cs delete mode 100644 Geometry_Engine/Query/TransformAngle.cs diff --git a/Geometry_Engine/Modify/CullSortedDuplicates.cs b/Geometry_Engine/Modify/CullSortedDuplicates.cs deleted file mode 100644 index ba259728a..000000000 --- a/Geometry_Engine/Modify/CullSortedDuplicates.cs +++ /dev/null @@ -1,104 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using BH.oM.Base.Attributes; -using BH.oM.Geometry; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; - -namespace BH.Engine.Geometry -{ - public static partial class Modify - { - /***************************************************/ - /**** Public Methods ****/ - /***************************************************/ - - [Description("Removes consecutive near-duplicate points from an ordered point list while keeping the first and last points.")] - [Input("points", "Ordered points to cull.")] - [Input("minSegmentLength", "Minimum kept segment length.")] - [Output("points", "Culled point list.")] - public static List CullSortedDuplicates(this List points, double minSegmentLength = Tolerance.Distance) - { - if (points.Count == 0) - return points; - - List output = new List { points.First() }; - double squaredMinLength = minSegmentLength * minSegmentLength; - - for (int i = 1; i < points.Count - 1; i++) - { - Point pnt = points[i]; - - if (pnt.SquareDistance(output.Last()) < squaredMinLength - || pnt.SquareDistance(points.Last()) < squaredMinLength) - continue; - - output.Add(pnt); - } - - if (output.Last().SquareDistance(points.Last()) > Tolerance.Distance * Tolerance.Distance) - output.Add(points.Last()); - - return output; - } - - /***************************************************/ - - [Description("Removes consecutive near-duplicate points from an ordered point list and reports skipped indexes.")] - [Input("points", "Ordered points to cull.")] - [Input("skippedIndexes", "Indexes of removed interior points.")] - [Input("minSegmentLength", "Minimum kept segment length.")] - [Output("points", "Culled point list.")] - public static List CullSortedDuplicates(this List points, out List skippedIndexes, double minSegmentLength = Tolerance.Distance) - { - skippedIndexes = new List(); - if (points.Count == 0) - return points; - - List output = new List { points.First() }; - double squaredMinLength = minSegmentLength * minSegmentLength; - - for (int i = 1; i < points.Count - 1; i++) - { - Point pnt = points[i]; - - if (pnt.SquareDistance(output.Last()) < squaredMinLength - || pnt.SquareDistance(points.Last()) < squaredMinLength) - { - skippedIndexes.Add(i); - continue; - } - - output.Add(pnt); - } - - if (output.Last().SquareDistance(points.Last()) > Tolerance.Distance * Tolerance.Distance) - output.Add(points.Last()); - - return output; - } - - /***************************************************/ - } -} diff --git a/Geometry_Engine/Modify/OffsetNonUniform.cs b/Geometry_Engine/Modify/OffsetNonUniform.cs deleted file mode 100644 index c013ed3de..000000000 --- a/Geometry_Engine/Modify/OffsetNonUniform.cs +++ /dev/null @@ -1,119 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using BH.Engine.Base; -using BH.oM.Base.Attributes; -using BH.oM.Geometry; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; - -namespace BH.Engine.Geometry -{ - public static partial class Modify - { - /***************************************************/ - /**** Public Methods ****/ - /***************************************************/ - - [Description("Offset each segment of a polyline by a value from the input list of distances.")] - [Input("pLine", "The polyline to offset non-uniformly.")] - [Input("distances", "Distances to use when offsetting individual segments of the polyline.")] - [Input("normal", "The normal vector of a plane to use during the offset operation.")] - [Input("tolerance", "The tolerance to use during the offset operation.")] - [Output("polyline", "The input polyline once each of its segments has been offset by the respective distance.")] - public static Polyline OffsetNonUniform(this Polyline pLine, List distances, Vector normal = null, double tolerance = Tolerance.Distance) - { - if (pLine == null || pLine.Length() < tolerance) - return null; - - if (distances.Any(x => x < 0)) - { - Base.Compute.RecordError("This method currently supports non-negative offset distances only."); - return null; - } - - if (!pLine.IsPlanar(tolerance)) - { - Base.Compute.RecordError("Offset works only on planar curves"); - return null; - } - - if (pLine.SubParts().Count != distances.Count) - { - Base.Compute.RecordError("Count of offset distances must match the number of segments in the polyline"); - return null; - } - - if (!pLine.IsClosed(tolerance)) - { - Base.Compute.RecordError("Polyline must be closed"); - return null; - } - - if (distances.All(x => x == 0)) - return pLine; - - List segments = pLine.SubParts(); - List newLines = new List(); - normal = normal?.Normalise() ?? pLine.Normal(); - Point averagePnt = pLine.Bounds().Centre(); - - for (int i = 0; i < segments.Count; i++) - { - Line line = segments[i]; - double distance = distances[i]; - Line offsetLine = line.Offset(distances[i], normal); - - Vector directionToCenter = averagePnt - line.Start; - Vector newDirectionToCenter = averagePnt - offsetLine.Start; - bool directionMaintained = directionToCenter.Angle(newDirectionToCenter) < Math.PI / 2; - - if (!directionMaintained) - offsetLine = line.Offset(distances[i], -normal); - else - { - double distanceToCenter = line.Start.Distance(averagePnt); - double newDistanceToCenter = offsetLine.Start.Distance(averagePnt); - bool newLineIsOutside = newDistanceToCenter > distanceToCenter; - - if ((distance > 0 && !newLineIsOutside) || (distance < 0 && newLineIsOutside)) - offsetLine = line.Offset(distances[i], -normal); - } - - offsetLine.Infinite = true; - newLines.Add(offsetLine); - } - - List nextLines = newLines.ShiftList(1); - List intersections = new List(); - - for (int i = 0; i < newLines.Count; i++) - intersections.Add(newLines[i].LineIntersection(nextLines[i], true)); - - return new Polyline { ControlPoints = intersections }.Close(); - } - - /***************************************************/ - } -} diff --git a/Geometry_Engine/Modify/SimplifyMidPoints.cs b/Geometry_Engine/Modify/SimplifyMidPoints.cs deleted file mode 100644 index df3f64a5a..000000000 --- a/Geometry_Engine/Modify/SimplifyMidPoints.cs +++ /dev/null @@ -1,57 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using BH.oM.Base.Attributes; -using BH.oM.Geometry; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; - -namespace BH.Engine.Geometry -{ - public static partial class Modify - { - /***************************************************/ - /**** Public Methods ****/ - /***************************************************/ - - [Description("Returns a simplified version of the input polyline where midpoints are simplified but endpoints are retained.")] - [Input("pLine", "A polyline to simplify.")] - [Output("polyline", "A simplified version of the input polyline where midpoints are simplified but endpoints are retained.")] - public static Polyline SimplifyMidPoints(this Polyline pLine) - { - List points = pLine.ControlPoints; - if (points.Count < 2) - return pLine; - - List simplified = new List { points.First() }; - List midPoints = points.Skip(1).Take(points.Count - 2).ToList(); - List cleaned = new Polyline { ControlPoints = midPoints }.DiscontinuityPoints(angleTolerance: 1); - - simplified.AddRange(cleaned); - simplified.Add(points.Last()); - return new Polyline { ControlPoints = simplified }; - } - - /***************************************************/ - } -} diff --git a/Geometry_Engine/Modify/Thicken.cs b/Geometry_Engine/Modify/Thicken.cs index c77612038..8784c21ae 100644 --- a/Geometry_Engine/Modify/Thicken.cs +++ b/Geometry_Engine/Modify/Thicken.cs @@ -41,13 +41,14 @@ public static partial class Modify [Output("polyline", "A closed polyline with the same direction as the input line and a custom thickness.")] public static Polyline Thicken(this Line line, double thickness, Plane plane) { - if (line.StartToEndDirection().IsParallel(plane.Normal) != 0) + Vector chordDirection = (line.End - line.Start).Normalise(); + if (chordDirection.IsParallel(plane.Normal) != 0) { Base.Compute.RecordError("Can't thicken a line parallel to the plane normal."); return null; } - Vector offsetVector = line.StartToEndDirection().CrossProduct(plane.Normal).Normalise() * thickness / 2; + Vector offsetVector = chordDirection.CrossProduct(plane.Normal).Normalise() * thickness / 2; Point p1 = line.Start + offsetVector; Point p2 = line.End + offsetVector; @@ -66,7 +67,9 @@ public static Polyline Thicken(this Line line, double thickness, Plane plane) [Output("polyline", "A closed polyline thickened from the input curve.")] public static Polyline Thicken(this ICurve crv, double thickness, Plane plane) { - if (crv.StartToEndDirection().IsParallel(plane.Normal) != 0) + List controlPoints = crv.IControlPoints(); + Vector chordDirection = (controlPoints.Last() - controlPoints.First()).Normalise(); + if (chordDirection.IsParallel(plane.Normal) != 0) { Base.Compute.RecordError("Can't thicken a curve parallel to the plane normal."); return null; diff --git a/Geometry_Engine/Query/BisectorVector.cs b/Geometry_Engine/Query/Bisector.cs similarity index 97% rename from Geometry_Engine/Query/BisectorVector.cs rename to Geometry_Engine/Query/Bisector.cs index 9365702fc..67d7de76f 100644 --- a/Geometry_Engine/Query/BisectorVector.cs +++ b/Geometry_Engine/Query/Bisector.cs @@ -37,7 +37,7 @@ public static partial class Query [Input("v1", "First vector.")] [Input("v2", "Second vector.")] [Output("bisector", "Normalised vector along the half-angle between v1 and v2.")] - public static Vector BisectorVector(this Vector v1, Vector v2) + public static Vector Bisector(this Vector v1, Vector v2) { Vector normalizedV1 = v1.Normalise(); Vector normalizedV2 = v2.Normalise(); diff --git a/Geometry_Engine/Query/BoxCorners.cs b/Geometry_Engine/Query/BoxCorners.cs deleted file mode 100644 index 59d946f74..000000000 --- a/Geometry_Engine/Query/BoxCorners.cs +++ /dev/null @@ -1,71 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using BH.oM.Base.Attributes; -using BH.oM.Geometry; -using System.Collections.Generic; -using System.ComponentModel; - -namespace BH.Engine.Geometry -{ - public static partial class Query - { - /***************************************************/ - /**** Public Methods ****/ - /***************************************************/ - - [Description("Returns corners of a box that has the input center point, width, height and directions. The box lies on the plane through the centre, so the centre keeps its elevation.")] - [Input("center", "Center of the new box.")] - [Input("width", "Width of the new box.")] - [Input("height", "Height of the new box.")] - [Input("xVector", "Direction of the new box's horizontal edges.")] - [Input("yVector", "Direction of the new box's vertical edges.")] - [Output("corners", "Corners of a box that has the input center point, width, height and directions.")] - public static List BoxCorners(this Point center, double width, double height, Vector xVector, Vector yVector) - { - return center.BoxCorners(width, height, xVector, yVector, center); - } - - /***************************************************/ - - [Description("Returns corners of a box defined by center point, width, height, directions, and origin.")] - [Input("center", "Center of the new box.")] - [Input("width", "Width of the new box.")] - [Input("height", "Height of the new box.")] - [Input("xVector", "Direction of the new box's horizontal edges.")] - [Input("yVector", "Direction of the new box's vertical edges.")] - [Input("origin", "The origin point for the plane on which the box lies.")] - [Output("corners", "Corners of a box that has the input center point, width, height and directions.")] - public static List BoxCorners(this Point center, double width, double height, Vector xVector, Vector yVector, Point origin) - { - Plane xyPlane = Create.Plane(origin, xVector.CrossProduct(yVector)); - Point p0 = center.Project(xyPlane) - xVector * width / 2 + yVector * height / 2; - Point p1 = p0 + xVector * width; - Point p2 = p1 - yVector * height; - Point p3 = p2 - xVector * width; - - return new List { p0, p1, p2, p3 }; - } - - /***************************************************/ - } -} diff --git a/Geometry_Engine/Query/GridPlane.cs b/Geometry_Engine/Query/GridPlane.cs deleted file mode 100644 index 15f70f52c..000000000 --- a/Geometry_Engine/Query/GridPlane.cs +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using BH.oM.Base.Attributes; -using BH.oM.Geometry; -using System.ComponentModel; - -namespace BH.Engine.Geometry -{ - public static partial class Query - { - /***************************************************/ - /**** Public Methods ****/ - /***************************************************/ - - [Description("Creates a plane with origin at the start point of the line and normal being the cross product of the XY line direction and global Z.")] - [Input("line", "Line to be used to construct the plane.")] - [Output("plane", "Plane with origin at start point of the line and normal being the cross product of line direction and global Z vector.")] - public static Plane GridPlane(this Line line) - { - Vector dir = new Vector { X = line.End.X - line.Start.X, Y = line.End.Y - line.Start.Y, Z = 0 }.Normalise(); - return new Plane { Origin = line.Start, Normal = new Vector { X = -dir.Y, Y = dir.X, Z = 0 } }; - } - - /***************************************************/ - } -} diff --git a/Geometry_Engine/Query/IntersectionLines.cs b/Geometry_Engine/Query/IntersectionLines.cs deleted file mode 100644 index 7b201714c..000000000 --- a/Geometry_Engine/Query/IntersectionLines.cs +++ /dev/null @@ -1,110 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using BH.oM.Base.Attributes; -using BH.oM.Geometry; -using BH.oM.Quantities.Attributes; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; - -namespace BH.Engine.Geometry -{ - public static partial class Query - { - /***************************************************/ - /**** Public Methods ****/ - /***************************************************/ - - [Description("Returns the segments of a line that lie inside a closed planar region.")] - [Input("region", "Closed planar region.")] - [Input("line", "Line to clip against the region.")] - [Input("acceptOnEdges", "If true, segments that lie on the region boundary are kept.")] - [Input("tolerance", "Distance tolerance.", typeof(Length))] - [Output("lines", "Segments of the line inside the region.")] - public static List IntersectionLines(this PolyCurve region, Line line, bool acceptOnEdges = false, double tolerance = Tolerance.Distance) - { - if (region == null || line == null) - return new List(); - - // Honor line.Infinite. A finite line must not grow out to the infinite chord through the region. - List pts = region.LineIntersections(line, false, tolerance) ?? new List(); - if (!line.Infinite) - { - if (line.Start != null && region.IsContaining(new List { line.Start }, acceptOnEdges, tolerance)) - pts.Add(line.Start); - if (line.End != null && region.IsContaining(new List { line.End }, acceptOnEdges, tolerance)) - pts.Add(line.End); - } - - pts = pts.Where(p => p != null).ToList().CullDuplicates(tolerance); - if (pts.Count < 2) - return new List(); - - Vector dir = line.Direction(); - if (dir.SquareLength() <= tolerance * tolerance) - return new List(); - - pts = pts.OrderBy(p => (p - line.Start) * dir).ToList(); - - List result = new List(); - for (int i = 0; i < pts.Count - 1; i++) - { - Point mid = (pts[i] + pts[i + 1]) * 0.5; - if (!region.IsContaining(new List { mid }, acceptOnEdges, tolerance)) - continue; - - Line segment = new Line { Start = pts[i], End = pts[i + 1] }; - if (segment.Length() > tolerance) - result.Add(segment); - } - - return result; - } - - /***************************************************/ - - [Description("Returns the intersection lines of a closed planar region with a cutting plane.")] - [Input("region", "Closed planar region.")] - [Input("plane", "Cutting plane.")] - [Input("tolerance", "Distance tolerance.", typeof(Length))] - [Output("lines", "Intersection segments of the region with the plane.")] - public static List IntersectionLines(this PolyCurve region, Plane plane, double tolerance = Tolerance.Distance) - { - if (region == null || plane == null) - return new List(); - - Plane regionPlane = region.FitPlane(tolerance); - if (regionPlane == null) - return new List(); - - Line cut = regionPlane.PlaneIntersection(plane, tolerance); - if (cut == null) - return new List(); - - cut.Infinite = true; - return region.IntersectionLines(cut, false, tolerance); - } - - /***************************************************/ - } -} diff --git a/Geometry_Engine/Query/IntersectsOrContains.cs b/Geometry_Engine/Query/IntersectsOrContains.cs deleted file mode 100644 index 49798c275..000000000 --- a/Geometry_Engine/Query/IntersectsOrContains.cs +++ /dev/null @@ -1,75 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using BH.oM.Base.Attributes; -using BH.oM.Geometry; -using BH.oM.Quantities.Attributes; -using System.Collections.Generic; -using System.ComponentModel; - -namespace BH.Engine.Geometry -{ - public static partial class Query - { - /***************************************************/ - /**** Public Methods ****/ - /***************************************************/ - - [Description("Checks whether a polyline intersects or contains a curve. Lines and polylines use their own intersection tests. Any other curve is inside only when it does not cross the boundary and its start point is inside.")] - [Input("region", "Polyline region.")] - [Input("curve", "Line, polyline, or other curve to test.")] - [Input("tolerance", "Distance tolerance.", typeof(Length))] - [Output("intersectsOrContains", "True if the curve crosses the polyline or lies inside it.")] - public static bool IntersectsOrContains(this Polyline region, ICurve curve, double tolerance = Tolerance.Distance) - { - if (region == null || curve == null) - return false; - - if (curve is Line line) - { - if (region.LineIntersections(line, false, tolerance)?.Count > 0) - return true; - - return region.IsContaining(new List { line.Start, line.End }, true, tolerance); - } - - if (curve is Polyline other) - { - if (region.LineIntersections(other, tolerance)?.Count > 0) - return true; - - if (other.ControlPoints != null && other.ControlPoints.Count > 0 && region.IsContaining(other.ControlPoints, true, tolerance)) - return true; - - return region.ControlPoints != null && region.ControlPoints.Count > 0 && other.IsContaining(region.ControlPoints, true, tolerance); - } - - if (region.ICurveIntersections(curve, tolerance)?.Count > 0) - return true; - - Point sample = curve.IStartPoint(); - return sample != null && region.IsContaining(new List { sample }, true, tolerance); - } - - /***************************************************/ - } -} diff --git a/Geometry_Engine/Query/IsAlignedRectangle.cs b/Geometry_Engine/Query/IsAlignedRectangle.cs deleted file mode 100644 index 7106ae93f..000000000 --- a/Geometry_Engine/Query/IsAlignedRectangle.cs +++ /dev/null @@ -1,78 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using BH.oM.Base.Attributes; -using BH.oM.Geometry; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; - -namespace BH.Engine.Geometry -{ - public static partial class Query - { - /***************************************************/ - /**** Public Methods ****/ - /***************************************************/ - - [Description("Checks if a polyline is a closed, globally aligned rectangle with edges parallel to the specified X and Y vectors.")] - [Input("pLine", "The polyline to check if it is a globally aligned rectangle.")] - [Input("xVector", "The X direction vector that one pair of parallel edges should be parallel to.")] - [Input("yVector", "The Y direction vector that the other pair of parallel edges should be parallel to.")] - [Output("isAlignedRectangle", "True if the polyline is a closed rectangle with edges aligned to the specified vectors.")] - public static bool IsAlignedRectangle(this Polyline pLine, Vector xVector, Vector yVector) - { - if (pLine == null || xVector == null || yVector == null) - return false; - - if (!pLine.IsClosed()) - return false; - - List controlPoints = pLine.ControlPoints; - if (controlPoints.Count != 5) - return false; - - List edges = pLine.SubParts(); - if (edges.Count != 4) - return false; - - Vector firstDirection = edges[0].Direction(); - List group1 = edges.Where(x => x.Direction().IsParallel(firstDirection) != 0).ToList(); - List group2 = edges.Where(x => x.Direction().IsParallel(firstDirection) == 0).ToList(); - - if (group1.Count != 2 || group2.Count != 2) - return false; - - Vector group2Direction = group2[0].Direction(); - double angle = firstDirection.Angle(group2Direction); - if (Math.Abs(angle - Math.PI / 2) > Tolerance.Angle) - return false; - - bool group1Aligned = firstDirection.IsParallel(xVector) != 0 || firstDirection.IsParallel(yVector) != 0; - bool group2Aligned = group2Direction.IsParallel(xVector) != 0 || group2Direction.IsParallel(yVector) != 0; - return group1Aligned && group2Aligned; - } - - /***************************************************/ - } -} diff --git a/Geometry_Engine/Query/IsStartToEndParallel.cs b/Geometry_Engine/Query/IsStartToEndParallel.cs deleted file mode 100644 index 00608e4b9..000000000 --- a/Geometry_Engine/Query/IsStartToEndParallel.cs +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using BH.oM.Base.Attributes; -using BH.oM.Geometry; -using System.ComponentModel; - -namespace BH.Engine.Geometry -{ - public static partial class Query - { - /***************************************************/ - /**** Public Methods ****/ - /***************************************************/ - - [Description("Checks whether two curves are parallel based on their start-to-end directions.")] - [Input("curve1", "The first curve whose start-to-end direction is used for comparison.")] - [Input("curve2", "The second curve whose start-to-end direction is used for comparison.")] - [Input("angleTolerance", "The maximum angle (in radians) between the two directions for them to be considered parallel.")] - [Output("isParallel", "True if the start-to-end directions of the two curves are parallel within the given tolerance, false otherwise.")] - public static bool IsStartToEndParallel(this ICurve curve1, ICurve curve2, double angleTolerance) - { - Vector hostVect = curve1.StartToEndDirection(); - Vector elemVect = curve2.StartToEndDirection(); - - if (hostVect.IsParallel(elemVect) != 0) - return true; - - double angle = hostVect.AcuteAngle(elemVect); - return angle < angleTolerance; - } - - /***************************************************/ - } -} diff --git a/Geometry_Engine/Query/MaxDistanceByProjection.cs b/Geometry_Engine/Query/MaxDistanceByProjection.cs deleted file mode 100644 index f63649feb..000000000 --- a/Geometry_Engine/Query/MaxDistanceByProjection.cs +++ /dev/null @@ -1,69 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using BH.oM.Base.Attributes; -using BH.oM.Geometry; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; - -namespace BH.Engine.Geometry -{ - public static partial class Query - { - /***************************************************/ - /**** Public Methods ****/ - /***************************************************/ - - [Description("Gets the max distance along the projection vector between all input lines and the dividing line.")] - [Input("lines", "Lines to measure against the dividing line.")] - [Input("dividingLine", "A line crossing the list of input lines.")] - [Input("projectionVector", "Direction along which the max distance is measured.")] - [Input("useInfiniteLines", "If true, intersections use infinite lines.")] - [Output("maxDistanceByProjection", "The max distance along the projection vector between input lines and the dividing line.")] - public static double MaxDistanceByProjection(this IEnumerable lines, Line dividingLine, Vector projectionVector, bool useInfiniteLines = false) - { - double distance = double.NaN; - dividingLine.Infinite = true; - BoundingBox lineBox = lines.Select(x => x.Bounds()).ToList().Bounds(); - double extensionLength = lineBox.Min.Distance(lineBox.Max) * 5; - - foreach (Line edge in lines) - { - Point rayOrigin = edge.Start; - Line ray = new Line { Start = rayOrigin, End = rayOrigin + (projectionVector * extensionLength) }; - - Point intersection = ray.LineIntersection(dividingLine, useInfiniteLines); - if (intersection == null) - continue; - - double newDist = intersection.Distance(rayOrigin); - if (double.IsNaN(distance) || newDist > distance) - distance = newDist; - } - - return distance; - } - - /***************************************************/ - } -} diff --git a/Geometry_Engine/Query/MinInternalDistance.cs b/Geometry_Engine/Query/MinDistance.cs similarity index 97% rename from Geometry_Engine/Query/MinInternalDistance.cs rename to Geometry_Engine/Query/MinDistance.cs index d0014dd7c..b8a62a5e8 100644 --- a/Geometry_Engine/Query/MinInternalDistance.cs +++ b/Geometry_Engine/Query/MinDistance.cs @@ -37,7 +37,7 @@ public static partial class Query [Description("Returns the minimum distance between any two distinct points in the list.")] [Input("points", "Points to compare.")] [Output("minDistance", "Smallest pairwise distance, or MaxValue if fewer than two points.")] - public static double MinInternalDistance(this List points) + public static double MinDistance(this List points) { double minDistance = double.MaxValue; diff --git a/Geometry_Engine/Query/NonClosingEndPoint.cs b/Geometry_Engine/Query/NonClosingEndPoint.cs deleted file mode 100644 index e9e04f7f9..000000000 --- a/Geometry_Engine/Query/NonClosingEndPoint.cs +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using BH.oM.Base.Attributes; -using BH.oM.Geometry; -using System.ComponentModel; -using System.Linq; - -namespace BH.Engine.Geometry -{ - public static partial class Query - { - /***************************************************/ - /**** Public Methods ****/ - /***************************************************/ - - [Description("Returns the last control point of a polyline, skipping the closing duplicate when the polyline is closed.")] - [Input("pLine", "Polyline to query.")] - [Output("endPoint", "Last non-closing control point.")] - public static Point NonClosingEndPoint(this Polyline pLine) - { - if (pLine.IsClosed()) - return pLine.ControlPoints[pLine.ControlPoints.Count - 2]; - - return pLine.ControlPoints.Last(); - } - - /***************************************************/ - } -} diff --git a/Geometry_Engine/Query/OverlapLength.cs b/Geometry_Engine/Query/OverlapLength.cs deleted file mode 100644 index c64c73b90..000000000 --- a/Geometry_Engine/Query/OverlapLength.cs +++ /dev/null @@ -1,80 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using BH.oM.Base.Attributes; -using BH.oM.Geometry; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; - -namespace BH.Engine.Geometry -{ - public static partial class Query - { - /***************************************************/ - /**** Public Methods ****/ - /***************************************************/ - - [Description("Calculates the overlap length between multiple parallel lines when moved to coincide.")] - [Input("parallelLines", "Collection of parallel lines.")] - [Input("distanceTolerance", "Distance tolerance for geometric operations.")] - [Output("overlapLength", "Length of overlap when all lines are moved to coincide.")] - public static double OverlapLength(this List parallelLines, double distanceTolerance = Tolerance.Distance) - { - if (parallelLines == null || parallelLines.Count < 2) - return 0.0; - - Vector direction = parallelLines[0].Direction(); - - List<(double start, double end)> projections = new List<(double start, double end)>(); - foreach (Line line in parallelLines) - projections.Add(EndParametersOnVector(line, direction)); - - double overlapStart = projections.Max(p => p.start); - double overlapEnd = projections.Min(p => p.end); - - if (overlapEnd <= overlapStart) - return 0.0; - - return overlapEnd - overlapStart; - } - - /***************************************************/ - /**** Private Methods ****/ - /***************************************************/ - - private static (double start, double end) EndParametersOnVector(this Line line, Vector direction) - { - if (line == null || direction == null) - return (0.0, 0.0); - - Vector normalizedDir = direction.Normalise(); - double startParam = (line.Start - Point.Origin) * normalizedDir; - double endParam = (line.End - Point.Origin) * normalizedDir; - - return (Math.Min(startParam, endParam), Math.Max(startParam, endParam)); - } - - /***************************************************/ - } -} diff --git a/Geometry_Engine/Query/StartToEndDirection.cs b/Geometry_Engine/Query/StartToEndDirection.cs deleted file mode 100644 index bbf45adc8..000000000 --- a/Geometry_Engine/Query/StartToEndDirection.cs +++ /dev/null @@ -1,67 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using BH.oM.Base.Attributes; -using BH.oM.Geometry; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; - -namespace BH.Engine.Geometry -{ - public static partial class Query - { - /***************************************************/ - /**** Public Methods ****/ - /***************************************************/ - - [Description("Returns the chord direction from the first control point of a polyline to its last (or pre-close) control point.")] - [Input("pLine", "Polyline whose start-to-end direction is requested.")] - [Output("direction", "Vector from the first control point to the last non-closing control point.")] - public static Vector StartToEndDirection(this Polyline pLine) - { - if (pLine.ControlPoints.Count == 2) - return pLine.SubParts().First().StartToEndDirection(); - - Point p1 = pLine.ControlPoints.First(); - Point p2 = pLine.ControlPoints.Last(); - - if (pLine.IsClosed()) - p2 = pLine.ControlPoints[pLine.ControlPoints.Count - 2]; - - return p2 - p1; - } - - /***************************************************/ - - [Description("Returns the normalised chord direction from the first control point of a curve to its last.")] - [Input("curve", "Curve whose start-to-end direction is requested.")] - [Output("direction", "Normalised vector from the first control point to the last.")] - public static Vector StartToEndDirection(this ICurve curve) - { - List controlPoints = curve.IControlPoints(); - return (controlPoints.Last() - controlPoints.First()).Normalise(); - } - - /***************************************************/ - } -} diff --git a/Geometry_Engine/Query/TransformAngle.cs b/Geometry_Engine/Query/TransformAngle.cs deleted file mode 100644 index 3ebead1b9..000000000 --- a/Geometry_Engine/Query/TransformAngle.cs +++ /dev/null @@ -1,50 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using BH.oM.Base.Attributes; -using BH.oM.Geometry; -using System; -using System.ComponentModel; - -namespace BH.Engine.Geometry -{ - public static partial class Query - { - /***************************************************/ - /**** Public Methods ****/ - /***************************************************/ - - [Description("Extracts the rotation angle encoded in a 2D transform matrix.")] - [Input("transform", "The transform matrix from which to extract the rotation angle.")] - [Output("angle", "The rotation angle in radians as encoded in the transform matrix.")] - public static double TransformAngle(this TransformMatrix transform) - { - double[,] matrixArray = transform.Matrix; - double sinTheta = matrixArray[1, 0]; - double cosTheta = matrixArray[0, 0]; - - return Math.Atan2(sinTheta, cosTheta); - } - - /***************************************************/ - } -} From 1cc8aa9155e803f656f3ffb30eec15649cee6db3 Mon Sep 17 00:00:00 2001 From: wojciech buda Date: Wed, 21 Oct 2026 17:04:39 +0200 Subject: [PATCH 4/5] Migration to ModelLaundry and Tagging_Tool --- .../Compute/RemoveUnconnectedLines.cs | 58 ----------------- Geometry_Engine/Query/BoxCornersOnXY.cs | 62 ------------------- 2 files changed, 120 deletions(-) delete mode 100644 Geometry_Engine/Compute/RemoveUnconnectedLines.cs delete mode 100644 Geometry_Engine/Query/BoxCornersOnXY.cs diff --git a/Geometry_Engine/Compute/RemoveUnconnectedLines.cs b/Geometry_Engine/Compute/RemoveUnconnectedLines.cs deleted file mode 100644 index d5d1bb698..000000000 --- a/Geometry_Engine/Compute/RemoveUnconnectedLines.cs +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using BH.oM.Base.Attributes; -using BH.oM.Geometry; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; - -namespace BH.Engine.Geometry -{ - public static partial class Compute - { - /***************************************************/ - /**** Public Methods ****/ - /***************************************************/ - - [Description("Removes lines that are not connected at both ends.")] - [Input("lines", "List of lines.")] - [Input("decimalPlaces", "The number of decimal places to round to, default 3.")] - [Output("connectedLines", "List of lines which all have connections at both ends.")] - public static List RemoveUnconnectedLines(this List lines, int decimalPlaces = 3) - { - if (lines == null) - { - Base.Compute.RecordError("Input of lines to clean up cannot be null."); - return new List(); - } - - List endPoints = lines.Select(x => x.EndPoint().RoundCoordinates(decimalPlaces)).ToList(); - List startPoints = lines.Select(x => x.StartPoint().RoundCoordinates(decimalPlaces)).ToList(); - endPoints.AddRange(startPoints); - List uniquePoints = endPoints.Where(x => endPoints.Where(y => y == x).Count() == 1).ToList(); - return lines.Where(x => !uniquePoints.Contains(x.EndPoint().RoundCoordinates(decimalPlaces)) && !uniquePoints.Contains(x.StartPoint().RoundCoordinates(decimalPlaces))).ToList(); - } - - /***************************************************/ - } -} diff --git a/Geometry_Engine/Query/BoxCornersOnXY.cs b/Geometry_Engine/Query/BoxCornersOnXY.cs deleted file mode 100644 index 1fd8e3e81..000000000 --- a/Geometry_Engine/Query/BoxCornersOnXY.cs +++ /dev/null @@ -1,62 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using BH.oM.Base.Attributes; -using BH.oM.Geometry; -using System.Collections.Generic; -using System.ComponentModel; - -namespace BH.Engine.Geometry -{ - public static partial class Query - { - /***************************************************/ - /**** Public Methods ****/ - /***************************************************/ - - [Description("Returns the four corners of a bounding rectangle on the XY plane defined by two opposite points.")] - [Input("point1", "The first point defining the bounding rectangle.")] - [Input("point2", "The second point defining the bounding rectangle.")] - [Output("corners", "The four corner points of the bounding rectangle on the XY plane.")] - public static List BoxCornersOnXY(this Point point1, Point point2) - { - if (point1 == null || point2 == null) - return null; - - BoundingBox box = new List { point1, point2 }.Bounds(); - Point pMin = box.Min.Project(Plane.XY); - Point pMax = box.Max.Project(Plane.XY); - - Point p0 = new Line { Start = pMin, End = pMin + Vector.YAxis, Infinite = true } - .LineIntersection(new Line { Start = pMax, End = pMax - Vector.XAxis, Infinite = true }, true); - Point p1 = new Line { Start = pMin, End = pMin + Vector.XAxis, Infinite = true } - .LineIntersection(new Line { Start = pMax, End = pMax - Vector.YAxis, Infinite = true }, true); - - if (p0 == null || p1 == null) - return null; - - return new List { pMin, p0, pMax, p1 }; - } - - /***************************************************/ - } -} From 6e336ded212ea179c5de7e82793322d15ad4bb8c Mon Sep 17 00:00:00 2001 From: wojciech buda Date: Thu, 22 Oct 2026 12:20:53 +0200 Subject: [PATCH 5/5] Loop distance tweaks and method migration --- Geometry_Engine/Query/IsSame.cs | 86 ++++++++++++++++++++++++++++ Geometry_Engine/Query/MinDistance.cs | 11 ++-- 2 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 Geometry_Engine/Query/IsSame.cs diff --git a/Geometry_Engine/Query/IsSame.cs b/Geometry_Engine/Query/IsSame.cs new file mode 100644 index 000000000..f432acc42 --- /dev/null +++ b/Geometry_Engine/Query/IsSame.cs @@ -0,0 +1,86 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using BH.oM.Base.Attributes; +using BH.oM.Geometry; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace BH.Engine.Geometry +{ + public static partial class Query + { + /***************************************************/ + /**** Public methods ****/ + /***************************************************/ + + [Description("Checks if two polylines have the same control points in the same order. Either list may be shifted, so a different starting point still matches. If plane is null, the control points are compared directly. If plane is not null, they are projected onto the plane before comparison.")] + [Input("pLine1", "First polyline.")] + [Input("pLine2", "Second polyline.")] + [Input("plane", "If null, control points are compared directly. If not null, control points are projected onto this plane before comparison.")] + [Input("tolerance", "Distance tolerance.")] + [Output("isSame", "True if the control points are equal in order, allowing a cyclic shift.")] + public static bool IsSame(this Polyline pLine1, Polyline pLine2, Plane plane = null, double tolerance = Tolerance.Distance) + { + if (pLine1 == null || pLine2 == null) + return false; + + if (pLine1.ControlPoints.Count != pLine2.ControlPoints.Count) + return false; + + List points1 = pLine1.ControlPoints; + List points2 = pLine2.ControlPoints; + + if (plane != null) + { + points1 = points1.Select(p => p.Project(plane)).ToList(); + points2 = points2.Select(p => p.Project(plane)).ToList(); + } + + int count = points1.Count; + + for (int i = 0; i < count; i++) + { + if (!points2[i].IsEqual(points1[0], tolerance)) + continue; + + bool matches = true; + for (int j = 0; j < count; j++) + { + if (!points1[j].IsEqual(points2[(i + j) % count], tolerance)) + { + matches = false; + break; + } + } + + if (matches) + return true; + } + + return false; + } + + /***************************************************/ + } +} diff --git a/Geometry_Engine/Query/MinDistance.cs b/Geometry_Engine/Query/MinDistance.cs index b8a62a5e8..7a5429f36 100644 --- a/Geometry_Engine/Query/MinDistance.cs +++ b/Geometry_Engine/Query/MinDistance.cs @@ -41,15 +41,12 @@ public static double MinDistance(this List points) { double minDistance = double.MaxValue; - foreach (Point point1 in points) + for (int i = 0; i < points.Count - 1; i++) { - foreach (Point point2 in points) + for (int j = i + 1; j < points.Count; j++) { - if (point1 == point2) - continue; - - double distance = point1.Distance(point2); - minDistance = Math.Min(distance, minDistance); + double distance = points[i].Distance(points[j]); + minDistance = Math.Min(minDistance, distance); } }