diff --git a/.editorconfig b/.editorconfig
index a4ac5b64..27feb2d7 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -254,8 +254,7 @@ dotnet_diagnostic.ca1506.severity = warning # Avoid excessive class coupling
dotnet_diagnostic.ca1507.severity = warning # Use nameof in place of string
dotnet_diagnostic.ca1508.severity = warning # Avoid dead conditional code
dotnet_diagnostic.ca1509.severity = warning # Invalid entry in code metrics configuration file
-dotnet_diagnostic.ca1861.severity = none # Prefer 'static readonly' fields over constant array arguments if the called method is called repeatedly and is not mutating the passed array (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1861)
-
+dotnet_diagnostic.ca1861.severity = suggestion # Prefer 'static readonly' fields over constant array arguments if the called method is called repeatedly and is not mutating the passed array (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1861)
# Performance rules
diff --git a/Speckle.Sdk.sln.DotSettings b/Speckle.Sdk.sln.DotSettings
index 9e5ec22f..691a8f91 100644
--- a/Speckle.Sdk.sln.DotSettings
+++ b/Speckle.Sdk.sln.DotSettings
@@ -1,2 +1,3 @@
- QL
\ No newline at end of file
+ QL
+ XYZ
\ No newline at end of file
diff --git a/src/Speckle.Objects/Geometry/Mesh.cs b/src/Speckle.Objects/Geometry/Mesh.cs
index 64079c69..27f2e60a 100644
--- a/src/Speckle.Objects/Geometry/Mesh.cs
+++ b/src/Speckle.Objects/Geometry/Mesh.cs
@@ -1,24 +1,46 @@
+using System.Diagnostics.Contracts;
using Speckle.Newtonsoft.Json;
using Speckle.Objects.Other;
+using Speckle.Objects.Utils;
using Speckle.Sdk;
using Speckle.Sdk.Common;
using Speckle.Sdk.Models;
namespace Speckle.Objects.Geometry;
+/// More docs on notion
[SpeckleType("Objects.Geometry.Mesh")]
public class Mesh : Base, IHasBoundingBox, IHasVolume, IHasArea, ITransformable
{
+ ///
+ /// Flat list of vertex data (flat x,y,z,x,y,z... list)
+ ///
[DetachProperty, Chunkable(31250)]
public required List vertices { get; set; }
+ ///
+ /// Flat list of face data
+ /// Each face starts with the length of the face (e.g. 3 in the case of triangles), followed by that many indices
+ ///
+ ///
+ /// N-gons are supported, but large values of n (> ~50) tend to cause significant performance problems for consumers (e.g. HostApps and .
+ ///
+ ///
+ /// [
+ /// 3, 0, 1, 2, //first face, a triangle (3-gon)
+ /// 4, 1, 2, 3, 4, //second face, a quad (4-gon)
+ /// 6, 4, 5, 6, 7, 8, 9, //third face, an n-gon (6-gon)
+ /// ];
[DetachProperty, Chunkable(62500)]
public required List faces { get; set; }
- /// Vertex colors as ARGB s
+ /// Vertex colors as ARGB s
+ /// Expected that there are either 1 color per vertex, or an empty
[DetachProperty, Chunkable(62500)]
public List colors { get; set; } = new();
+ /// Flat list of texture coordinates (flat u,v,u,v,u,v... list)
+ /// Expected that there are either 1 texture coordinate per vertex, or an empty
[DetachProperty, Chunkable(31250)]
public List textureCoordinates { get; set; } = new();
@@ -85,8 +107,6 @@ public bool TransformTo(Transform transform, out ITransformable transformed)
return res;
}
- #region Convenience Methods
-
[JsonIgnore]
public int VerticesCount => vertices.Count / 3;
@@ -98,6 +118,8 @@ public bool TransformTo(Transform transform, out ITransformable transformed)
///
/// The index of the vertex
/// Vertex as a
+ /// It is usually recommended to instead consume the list manually for better performance
+ [Pure]
public Point GetPoint(int index)
{
index *= 3;
@@ -106,6 +128,8 @@ public Point GetPoint(int index)
/// as list of s
/// when list is malformed
+ /// It is usually recommended to instead consume the list manually for better performance
+ [Pure]
public List GetPoints()
{
if (vertices.Count % 3 != 0)
@@ -129,78 +153,10 @@ public List GetPoints()
///
/// The index of the texture coordinate
/// Texture coordinate as a
+ [Pure]
public (double, double) GetTextureCoordinate(int index)
{
index *= 2;
return (textureCoordinates[index], textureCoordinates[index + 1]);
}
-
- ///
- /// If not already so, this method will align
- /// such that a vertex and its corresponding texture coordinates have the same index.
- /// This alignment is what is expected by most applications.
- ///
- ///
- /// If the calling application expects
- /// vertices.count == textureCoordinates.count
- /// Then this method should be called by the MeshToNative method before parsing and
- /// to ensure compatibility with geometry originating from applications that map to using vertex instance index (rather than vertex index)
- ///
- /// , , and lists will be modified to contain no shared vertices (vertices shared between polygons)
- ///
- public void AlignVerticesWithTexCoordsByIndex()
- {
- if (textureCoordinates.Count == 0)
- {
- return;
- }
-
- if (TextureCoordinatesCount == VerticesCount)
- {
- return; //Tex-coords already aligned as expected
- }
-
- var facesUnique = new List(faces.Count);
- var verticesUnique = new List(TextureCoordinatesCount * 3);
- bool hasColors = colors.Count > 0;
- var colorsUnique = hasColors ? new List(TextureCoordinatesCount) : null;
-
- int nIndex = 0;
- while (nIndex < faces.Count)
- {
- int n = faces[nIndex];
- if (n < 3)
- {
- n += 3; // 0 -> 3, 1 -> 4
- }
-
- if (nIndex + n >= faces.Count)
- {
- break; //Malformed face list
- }
-
- facesUnique.Add(n);
- for (int i = 1; i <= n; i++)
- {
- int vertIndex = faces[nIndex + i];
- int newVertIndex = verticesUnique.Count / 3;
-
- var (x, y, z) = GetPoint(vertIndex);
- verticesUnique.Add(x);
- verticesUnique.Add(y);
- verticesUnique.Add(z);
-
- colorsUnique?.Add(colors[vertIndex]);
- facesUnique.Add(newVertIndex);
- }
-
- nIndex += n + 1;
- }
-
- vertices = verticesUnique;
- colors = colorsUnique ?? colors;
- faces = facesUnique;
- }
-
- #endregion
}
diff --git a/src/Speckle.Objects/Geometry/Vector.cs b/src/Speckle.Objects/Geometry/Vector.cs
index 83114648..a0c06698 100644
--- a/src/Speckle.Objects/Geometry/Vector.cs
+++ b/src/Speckle.Objects/Geometry/Vector.cs
@@ -86,15 +86,9 @@ public bool TransformTo(Transform transform, out ITransformable transformed)
/// Returns the coordinates of this as a list of numbers
///
/// A list of coordinates {x, y, z}
- public List ToList()
- {
- return new List { x, y, z };
- }
+ public List ToList() => [x, y, z];
- public Point ToPoint()
- {
- return new Point(x, y, z, units, applicationId);
- }
+ public Point ToPoint() => new(x, y, z, units, applicationId);
///
/// Creates a new vector based on a list of coordinates and the unit they're drawn in.
@@ -176,11 +170,6 @@ public static Vector CrossProduct(Vector u, Vector v)
return new Vector(x, y, z, units: u.units);
}
- public static double Angle(Vector u, Vector v)
- {
- return Math.Acos(DotProduct(u, v) / (u.Length * v.Length));
- }
-
///
/// Compute and return a unit vector from this vector
///
@@ -205,23 +194,6 @@ public Vector Negate()
return this;
}
- ///
- /// Returns a normalized copy of this vector.
- ///
- /// A copy of this vector unitized.
- public Vector Unit()
- {
- return this / Length;
- }
-
- ///
- /// Constructs a new from a
- ///
- /// The point whose coordinates will be used
- /// The unique application ID of the object.
- [Obsolete($"Use {nameof(Point.ToVector)}", true)]
- public Vector(Point point, string? applicationId = null) { }
-
///
/// Gets or sets the coordinates of the vector
///
diff --git a/src/Speckle.Sdk/Common/Units.cs b/src/Speckle.Sdk/Common/Units.cs
index e6d4c854..f4a7e12f 100644
--- a/src/Speckle.Sdk/Common/Units.cs
+++ b/src/Speckle.Sdk/Common/Units.cs
@@ -1,4 +1,5 @@
using System.Diagnostics.Contracts;
+using Speckle.Sdk.Dependencies;
namespace Speckle.Sdk.Common;
@@ -19,7 +20,7 @@ public static class Units
/// US Survey foot, now not supported by Speckle, kept privately for backwards compatibility
private const string USFeet = "us_ft";
- internal static readonly List SupportedUnits = new()
+ internal static readonly IReadOnlyCollection SupportedUnits = new[]
{
Millimeters,
Centimeters,
@@ -30,7 +31,7 @@ public static class Units
Yards,
Miles,
None,
- };
+ }.Freeze();
///
/// if is a recognised/supported unit string, otherwise
diff --git a/tests/Speckle.Objects.Tests.Unit/Geometry/MeshTests.cs b/tests/Speckle.Objects.Tests.Unit/Geometry/MeshTests.cs
index f1ec0d5e..31a44bd4 100644
--- a/tests/Speckle.Objects.Tests.Unit/Geometry/MeshTests.cs
+++ b/tests/Speckle.Objects.Tests.Unit/Geometry/MeshTests.cs
@@ -6,22 +6,7 @@ namespace Speckle.Objects.Tests.Unit.Geometry;
public class MeshTests
{
- private static readonly Mesh[] TestCaseSource = { CreateBlenderStylePolygon(), CreateRhinoStylePolygon() };
-
- [Theory]
- [MemberData(nameof(GetTestCaseSource))]
- public void CanAlignVertices(Mesh inPolygon)
- {
- inPolygon.AlignVerticesWithTexCoordsByIndex();
-
- inPolygon.VerticesCount.Should().Be(inPolygon.TextureCoordinatesCount);
-
- var expectedPolygon = CreateRhinoStylePolygon();
-
- inPolygon.vertices.Should().BeEquivalentTo(expectedPolygon.vertices);
- inPolygon.faces.Should().BeEquivalentTo(expectedPolygon.faces);
- inPolygon.textureCoordinates.Should().BeEquivalentTo(expectedPolygon.textureCoordinates);
- }
+ private static readonly Mesh[] TestCaseSource = { CreateRhinoStylePolygon(), CreateEmpty() };
public static IEnumerable