diff --git a/Geometry_Engine/Modify/Thicken.cs b/Geometry_Engine/Modify/Thicken.cs new file mode 100644 index 000000000..8784c21ae --- /dev/null +++ b/Geometry_Engine/Modify/Thicken.cs @@ -0,0 +1,98 @@ +/* + * 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) + { + 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 = chordDirection.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) + { + 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; + } + + 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/Bisector.cs b/Geometry_Engine/Query/Bisector.cs new file mode 100644 index 000000000..67d7de76f --- /dev/null +++ b/Geometry_Engine/Query/Bisector.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 Bisector(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/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 new file mode 100644 index 000000000..7a5429f36 --- /dev/null +++ b/Geometry_Engine/Query/MinDistance.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; +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 MinDistance(this List points) + { + double minDistance = double.MaxValue; + + for (int i = 0; i < points.Count - 1; i++) + { + for (int j = i + 1; j < points.Count; j++) + { + double distance = points[i].Distance(points[j]); + minDistance = Math.Min(minDistance, distance); + } + } + + return minDistance; + } + + /***************************************************/ + } +}