diff --git a/Geometry_Engine/Geometry_Engine.csproj b/Geometry_Engine/Geometry_Engine.csproj
index c15e2aba9..12d259093 100644
--- a/Geometry_Engine/Geometry_Engine.csproj
+++ b/Geometry_Engine/Geometry_Engine.csproj
@@ -150,6 +150,7 @@
+
diff --git a/Geometry_Engine/Query/IsOrthogonal.cs b/Geometry_Engine/Query/IsOrthogonal.cs
new file mode 100644
index 000000000..250cc2ee1
--- /dev/null
+++ b/Geometry_Engine/Query/IsOrthogonal.cs
@@ -0,0 +1,54 @@
+/*
+ * This file is part of the Buildings and Habitats object Model (BHoM)
+ * Copyright (c) 2015 - 2021, 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.Geometry;
+using BH.oM.Reflection.Attributes;
+using System;
+using System.ComponentModel;
+
+namespace BH.Engine.Geometry
+{
+ public static partial class Query
+ {
+ /***************************************************/
+ /**** Public Methods - Vectors ****/
+ /***************************************************/
+
+ [Description("Queries whether a vector is orthogonal in relation to global X, Y or Z axis.")]
+ [Input("vector", "The vector to evaluate.")]
+ [Input("angleTolerance", "Optional, the angle discrepancy in radians from the global axis to consider as tolerance.")]
+ [Output("isOrthogonal", "The boolean value of whether the vector is orthogonal or not.")]
+ public static bool IsOrthogonal(this Vector vector, double angleTolerance = Tolerance.Angle)
+ {
+ if (vector == null || angleTolerance == null)
+ {
+ BH.Engine.Reflection.Compute.RecordError("One or more of the inputs is empty or null.");
+ return false;
+ }
+
+ return (vector.IsParallel(Vector.XAxis, angleTolerance) != 0 || vector.IsParallel(Vector.YAxis, angleTolerance) != 0 || vector.IsParallel(Vector.ZAxis, angleTolerance) != 0);
+ }
+
+ /***************************************************/
+
+ }
+}
diff --git a/Spatial_Engine/Query/DominantVector.cs b/Spatial_Engine/Query/DominantVector.cs
new file mode 100644
index 000000000..45e16f6e8
--- /dev/null
+++ b/Spatial_Engine/Query/DominantVector.cs
@@ -0,0 +1,139 @@
+/*
+ * This file is part of the Buildings and Habitats object Model (BHoM)
+ * Copyright (c) 2015 - 2021, 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.Geometry;
+using BH.oM.Geometry;
+using BH.oM.Dimensional;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using BH.oM.Reflection.Attributes;
+
+namespace BH.Engine.Spatial
+{
+ public static partial class Query
+ {
+ /******************************************/
+ /**** IElement1D ****/
+ /******************************************/
+
+ [Description("Gets the the dominant vector (orientation) of an Element1D based on its lines lengths.")]
+ [Input("element1D", "Element1D to evaluate.")]
+ [Input("orthogonalPriority", "Optional, if true gives priority to curves that are on the orthogonal axis (X, Y or Z vectors).")]
+ [Input("orthogonalLengthFactor", "Optional, tests the orthogonal vector length's in relation to the actual non-orthogonal dominant vector. For example if the dominant vector is 10 in length but the orthogonal is only 5 in length, then this number should be 0.5 for it to pass the test.")]
+ [Input("angleTolerance", "Optional, angle in radians that vectors will be considered similar.")]
+ [Output("dominantVector", "The dominant vector of an Element1D.")]
+ public static BH.oM.Geometry.Vector DominantVector(this IElement1D element1D, bool orthogonalPriority = true, double orthogonalLengthFactor = 0.5, double angleTolerance = BH.oM.Geometry.Tolerance.Angle)
+ {
+ if (element1D == null || orthogonalPriority == null || orthogonalLengthFactor == null || angleTolerance == null)
+ {
+ BH.Engine.Reflection.Compute.RecordError("One or more of the inputs is empty or null.");
+ return null;
+ }
+
+ List curves = element1D.IGeometry().ISubParts().ToList();
+
+ if(!curves.Any(x=> x.IIsLinear()))
+ BH.Engine.Reflection.Compute.RecordWarning("Non-linear curves are using an approximate vector between its start and end.");
+
+ List vectors = curves.Select(x => (x.IStartPoint() -x.IEndPoint())).ToList();
+
+ //group vectors by direction whilst comparing angle for tolerance
+ List> groupByNormal = GroupSimilarVectorsWithTolerance(vectors, angleTolerance);
+ groupByNormal = groupByNormal.OrderByDescending(x => x.Sum(y => y.Length())).ToList();
+ List largestGlobal = groupByNormal[0];
+
+ Vector dominantVector = largestGlobal[0].Normalise();
+ if (!orthogonalPriority)
+ return dominantVector;
+
+ List largestOrthogonal = groupByNormal.FirstOrDefault(x => (x.First().IsOrthogonal(angleTolerance)));
+ if (largestOrthogonal != null)
+ {
+ if (largestGlobal.Sum(x => x.Length()) * orthogonalLengthFactor > largestOrthogonal.Sum(x => x.Length()))
+ BH.Engine.Reflection.Compute.RecordWarning("Orthogonal vector was found but didn't pass the length tolerance in relation to the actual non-orthogonal dominant vector. The actual dominant vector is the output.");
+ else
+ dominantVector = largestOrthogonal[0].Normalise();
+ }
+
+ return dominantVector;
+ }
+
+ /******************************************/
+ /**** IElement2D ****/
+ /******************************************/
+
+ [Description("Gets the the dominant vector (orientation) of an Element2D based on its lines lengths.")]
+ [Input("element2D", "Element2D to evaluate.")]
+ [Input("orthogonalPriority", "Optional, if true gives priority to curves that are on the orthogonal axis (X, Y or Z vectors.")]
+ [Input("orthogonalLengthFactor", "Optional, tests the orthogonal vector length's in relation to the actual non-orthogonal dominant vector. For example if the dominant vector is 10 in length but the orthogonal is only 5 in length, then this number should be 0.5 for it to pass the test.")]
+ [Input("angleTolerance", "Optional, angle in radians that vectors will be considered similar.")]
+ [Output("dominantVector", "The dominant vector of an Element2D.")]
+ public static BH.oM.Geometry.Vector DominantVector(this IElement2D element2D, bool orthogonalPriority = true, double orthogonalLengthFactor = 0.5, double angleTolerance = BH.oM.Geometry.Tolerance.Angle)
+ {
+ if (element2D == null || orthogonalPriority == null || orthogonalLengthFactor == null || angleTolerance == null)
+ {
+ BH.Engine.Reflection.Compute.RecordError("One or more of the inputs is empty or null.");
+ return null;
+ }
+
+ IElement1D outline = BH.Engine.Geometry.Create.PolyCurve(element2D.IOutlineElements1D().Select(x =>x.IGeometry()));
+ return DominantVector(outline, orthogonalPriority, orthogonalLengthFactor, angleTolerance);
+ }
+
+ /******************************************/
+ /**** Private ****/
+ /******************************************/
+
+ [Description("Groups vectors by direction whilst allowing for an angle discrepancy tolerance.")]
+ [Input("vectors", "Vectors to evaluate.")]
+ [Input("angleTolerance", "The angle in radians to compare vectors with each other for tolerance when grouping.")]
+ [Output("GroupSimilarVectorsWithTolerance", "The grouped vectors.")]
+ private static List> GroupSimilarVectorsWithTolerance(List vectors, double angleTolerance)
+ {
+ List> result = new List>();
+ List orderByLength = vectors.OrderByDescending(x => x.Length()).ToList();
+
+ while (orderByLength.Count != 0)
+ {
+ List sublist = new List();
+ sublist.Add(orderByLength[0]);
+
+ for (int i = orderByLength.Count - 1; i > 0; i--)
+ {
+ if (orderByLength[0].IsParallel(orderByLength[i],angleTolerance) != 0)
+ {
+ sublist.Add(orderByLength[i]);
+ orderByLength.RemoveAt(i);
+ }
+ }
+ orderByLength.RemoveAt(0);
+ result.Add(sublist);
+ }
+
+ return result;
+ }
+
+ /******************************************/
+ }
+}
diff --git a/Spatial_Engine/Spatial_Engine.csproj b/Spatial_Engine/Spatial_Engine.csproj
index fa089a8af..24ec8848b 100644
--- a/Spatial_Engine/Spatial_Engine.csproj
+++ b/Spatial_Engine/Spatial_Engine.csproj
@@ -100,6 +100,7 @@
+