From a2b01c0bbb2b48c79aff9cb3e815f72f48e4eaa0 Mon Sep 17 00:00:00 2001 From: kekesidavid Date: Tue, 4 Feb 2025 16:09:47 +0100 Subject: [PATCH] switched from trianglenet to libtessdotnet (#559) --- .../packages.lock.json | 16 ++-- .../packages.lock.json | 16 ++-- .../packages.lock.json | 16 ++-- .../packages.lock.json | 16 ++-- .../ToSpeckle/Raw/SolidToSpeckleConverter.cs | 2 +- Directory.Packages.props | 1 + .../LibTessTriangulator.cs | 53 +++++++++++++ .../Speckle.Common.MeshTriangulation.csproj | 2 +- .../TriangleNetTriangulator.cs | 75 ------------------- .../packages.lock.json | 24 +++--- 10 files changed, 100 insertions(+), 121 deletions(-) create mode 100644 Sdk/Speckle.Common.MeshTriangulation/LibTessTriangulator.cs delete mode 100644 Sdk/Speckle.Common.MeshTriangulation/TriangleNetTriangulator.cs diff --git a/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json b/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json index ea7ad0799..7edcede72 100644 --- a/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json +++ b/Connectors/Tekla/Speckle.Connector.Tekla2023/packages.lock.json @@ -325,8 +325,8 @@ "speckle.common.meshtriangulation": { "type": "Project", "dependencies": { - "Speckle.DoubleNumerics": "[4.1.0, )", - "Speckle.Triangle": "[1.0.0, )" + "LibTessDotNet": "[1.1.15, )", + "Speckle.DoubleNumerics": "[4.1.0, )" } }, "speckle.connectors.common": { @@ -374,6 +374,12 @@ "Speckle.Objects": "[3.1.0-dev.251, )" } }, + "LibTessDotNet": { + "type": "CentralTransitive", + "requested": "[1.1.15, )", + "resolved": "1.1.15", + "contentHash": "KuA7N3Nv/lIeawJdQBQJR6oqWD9KETHLbWzBqapwFs+Tby+R5I4crkKujKMm5bXcSuFZ8LNtflFQVadsWCbBjg==" + }, "Microsoft.Extensions.DependencyInjection": { "type": "CentralTransitive", "requested": "[2.2.0, )", @@ -435,12 +441,6 @@ "requested": "[3.1.0-dev.251, )", "resolved": "3.1.0-dev.251", "contentHash": "M8MNH+yeIkEmhnb4GxrKyewCotaP+MZ+FUbkuHDaMbnG7xbJ0Y83nDA7v77v2v/UczCFmdVqroFnV4i6OQew7g==" - }, - "Speckle.Triangle": { - "type": "CentralTransitive", - "requested": "[1.0.0, )", - "resolved": "1.0.0", - "contentHash": "3fWYy5IG9EpkxvqSkRWtgWraYg7ylkg8Ea3WesIqAodjOySYzv+ntdcCP7EW7a5NB3nUhlp27woMAwyKFEF5XQ==" } } } diff --git a/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json b/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json index 8c8962735..273287de5 100644 --- a/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json +++ b/Connectors/Tekla/Speckle.Connector.Tekla2024/packages.lock.json @@ -406,8 +406,8 @@ "speckle.common.meshtriangulation": { "type": "Project", "dependencies": { - "Speckle.DoubleNumerics": "[4.1.0, )", - "Speckle.Triangle": "[1.0.0, )" + "LibTessDotNet": "[1.1.15, )", + "Speckle.DoubleNumerics": "[4.1.0, )" } }, "speckle.connectors.common": { @@ -455,6 +455,12 @@ "Speckle.Objects": "[3.1.0-dev.251, )" } }, + "LibTessDotNet": { + "type": "CentralTransitive", + "requested": "[1.1.15, )", + "resolved": "1.1.15", + "contentHash": "KuA7N3Nv/lIeawJdQBQJR6oqWD9KETHLbWzBqapwFs+Tby+R5I4crkKujKMm5bXcSuFZ8LNtflFQVadsWCbBjg==" + }, "Microsoft.Extensions.DependencyInjection": { "type": "CentralTransitive", "requested": "[2.2.0, )", @@ -516,12 +522,6 @@ "requested": "[3.1.0-dev.251, )", "resolved": "3.1.0-dev.251", "contentHash": "M8MNH+yeIkEmhnb4GxrKyewCotaP+MZ+FUbkuHDaMbnG7xbJ0Y83nDA7v77v2v/UczCFmdVqroFnV4i6OQew7g==" - }, - "Speckle.Triangle": { - "type": "CentralTransitive", - "requested": "[1.0.0, )", - "resolved": "1.0.0", - "contentHash": "3fWYy5IG9EpkxvqSkRWtgWraYg7ylkg8Ea3WesIqAodjOySYzv+ntdcCP7EW7a5NB3nUhlp27woMAwyKFEF5XQ==" } } } diff --git a/Converters/Tekla/Speckle.Converter.Tekla2023/packages.lock.json b/Converters/Tekla/Speckle.Converter.Tekla2023/packages.lock.json index 8e2a706e2..34ba62233 100644 --- a/Converters/Tekla/Speckle.Converter.Tekla2023/packages.lock.json +++ b/Converters/Tekla/Speckle.Converter.Tekla2023/packages.lock.json @@ -294,8 +294,8 @@ "speckle.common.meshtriangulation": { "type": "Project", "dependencies": { - "Speckle.DoubleNumerics": "[4.1.0, )", - "Speckle.Triangle": "[1.0.0, )" + "LibTessDotNet": "[1.1.15, )", + "Speckle.DoubleNumerics": "[4.1.0, )" } }, "speckle.converters.common": { @@ -305,6 +305,12 @@ "Speckle.Objects": "[3.1.0-dev.251, )" } }, + "LibTessDotNet": { + "type": "CentralTransitive", + "requested": "[1.1.15, )", + "resolved": "1.1.15", + "contentHash": "KuA7N3Nv/lIeawJdQBQJR6oqWD9KETHLbWzBqapwFs+Tby+R5I4crkKujKMm5bXcSuFZ8LNtflFQVadsWCbBjg==" + }, "Microsoft.Extensions.Logging": { "type": "CentralTransitive", "requested": "[2.2.0, )", @@ -361,12 +367,6 @@ "resolved": "3.1.0-dev.251", "contentHash": "M8MNH+yeIkEmhnb4GxrKyewCotaP+MZ+FUbkuHDaMbnG7xbJ0Y83nDA7v77v2v/UczCFmdVqroFnV4i6OQew7g==" }, - "Speckle.Triangle": { - "type": "CentralTransitive", - "requested": "[1.0.0, )", - "resolved": "1.0.0", - "contentHash": "3fWYy5IG9EpkxvqSkRWtgWraYg7ylkg8Ea3WesIqAodjOySYzv+ntdcCP7EW7a5NB3nUhlp27woMAwyKFEF5XQ==" - }, "Tekla.Structures.Dialog": { "type": "CentralTransitive", "requested": "[2024.0.4, )", diff --git a/Converters/Tekla/Speckle.Converter.Tekla2024/packages.lock.json b/Converters/Tekla/Speckle.Converter.Tekla2024/packages.lock.json index 5cd60bd37..b5d745fac 100644 --- a/Converters/Tekla/Speckle.Converter.Tekla2024/packages.lock.json +++ b/Converters/Tekla/Speckle.Converter.Tekla2024/packages.lock.json @@ -335,8 +335,8 @@ "speckle.common.meshtriangulation": { "type": "Project", "dependencies": { - "Speckle.DoubleNumerics": "[4.1.0, )", - "Speckle.Triangle": "[1.0.0, )" + "LibTessDotNet": "[1.1.15, )", + "Speckle.DoubleNumerics": "[4.1.0, )" } }, "speckle.converters.common": { @@ -346,6 +346,12 @@ "Speckle.Objects": "[3.1.0-dev.251, )" } }, + "LibTessDotNet": { + "type": "CentralTransitive", + "requested": "[1.1.15, )", + "resolved": "1.1.15", + "contentHash": "KuA7N3Nv/lIeawJdQBQJR6oqWD9KETHLbWzBqapwFs+Tby+R5I4crkKujKMm5bXcSuFZ8LNtflFQVadsWCbBjg==" + }, "Microsoft.Extensions.Logging": { "type": "CentralTransitive", "requested": "[2.2.0, )", @@ -402,12 +408,6 @@ "resolved": "3.1.0-dev.251", "contentHash": "M8MNH+yeIkEmhnb4GxrKyewCotaP+MZ+FUbkuHDaMbnG7xbJ0Y83nDA7v77v2v/UczCFmdVqroFnV4i6OQew7g==" }, - "Speckle.Triangle": { - "type": "CentralTransitive", - "requested": "[1.0.0, )", - "resolved": "1.0.0", - "contentHash": "3fWYy5IG9EpkxvqSkRWtgWraYg7ylkg8Ea3WesIqAodjOySYzv+ntdcCP7EW7a5NB3nUhlp27woMAwyKFEF5XQ==" - }, "Tekla.Structures.Plugins": { "type": "CentralTransitive", "requested": "[2024.0.4, )", diff --git a/Converters/Tekla/Speckle.Converters.TeklaShared/ToSpeckle/Raw/SolidToSpeckleConverter.cs b/Converters/Tekla/Speckle.Converters.TeklaShared/ToSpeckle/Raw/SolidToSpeckleConverter.cs index 621c99219..60692cb11 100644 --- a/Converters/Tekla/Speckle.Converters.TeklaShared/ToSpeckle/Raw/SolidToSpeckleConverter.cs +++ b/Converters/Tekla/Speckle.Converters.TeklaShared/ToSpeckle/Raw/SolidToSpeckleConverter.cs @@ -96,7 +96,7 @@ public class SolidToSpeckleConverter : ITypedConverter private SOG.Mesh ExtrudeFromPolygons(List face1, List face2) { var point = face2[0].Vertices[0]; - var generator = new MeshGenerator(new BaseTransformer(), new TriangleNetTriangulator()); + var generator = new MeshGenerator(new BaseTransformer(), new LibTessTriangulator()); var mesh3 = generator.ExtrudeMesh(face1, point); return Mesh3ToSpeckleMesh(mesh3); diff --git a/Directory.Packages.props b/Directory.Packages.props index bfe0beda9..4bc984492 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -10,6 +10,7 @@ + diff --git a/Sdk/Speckle.Common.MeshTriangulation/LibTessTriangulator.cs b/Sdk/Speckle.Common.MeshTriangulation/LibTessTriangulator.cs new file mode 100644 index 000000000..cf3def845 --- /dev/null +++ b/Sdk/Speckle.Common.MeshTriangulation/LibTessTriangulator.cs @@ -0,0 +1,53 @@ +using Speckle.DoubleNumerics; + +namespace Speckle.Common.MeshTriangulation; + +public class LibTessTriangulator : ITriangulator +{ + public Mesh2 Triangulate(IReadOnlyList polygons) + { + var tess = new LibTessDotNet.Tess(); + + for (int polygonIndex = 0; polygonIndex < polygons.Count; polygonIndex++) + { + var numPoints = polygons[polygonIndex].Vertices.Count; + var contour = new LibTessDotNet.ContourVertex[numPoints]; + for (int vertexIndex = 0; vertexIndex < numPoints; vertexIndex++) + { + var v = polygons[polygonIndex].Vertices[vertexIndex]; + contour[vertexIndex].Position = new LibTessDotNet.Vec3((float)v.X, (float)v.Y, 0); + } + + // the outer contour has to be in clockwise order + var orientation = + polygonIndex == 0 + ? LibTessDotNet.ContourOrientation.Clockwise + : LibTessDotNet.ContourOrientation.CounterClockwise; + tess.AddContour(contour, orientation); + } + + tess.Tessellate(); + + var vertices = new List(); + var triangles = new List(); + int tc = 0; + + int numTriangles = tess.ElementCount; + for (int i = 0; i < numTriangles; i++) + { + var v1 = tess.Vertices[tess.Elements[i * 3]].Position; + var v2 = tess.Vertices[tess.Elements[i * 3 + 1]].Position; + var v3 = tess.Vertices[tess.Elements[i * 3 + 2]].Position; + + vertices.Add(new Vector2(v1.X, v1.Y)); + vertices.Add(new Vector2(v2.X, v2.Y)); + vertices.Add(new Vector2(v3.X, v3.Y)); + + triangles.Add(tc++); + triangles.Add(tc++); + triangles.Add(tc++); + } + + return new Mesh2(vertices, triangles); + } +} diff --git a/Sdk/Speckle.Common.MeshTriangulation/Speckle.Common.MeshTriangulation.csproj b/Sdk/Speckle.Common.MeshTriangulation/Speckle.Common.MeshTriangulation.csproj index 4e551b066..c19b49f5b 100644 --- a/Sdk/Speckle.Common.MeshTriangulation/Speckle.Common.MeshTriangulation.csproj +++ b/Sdk/Speckle.Common.MeshTriangulation/Speckle.Common.MeshTriangulation.csproj @@ -5,8 +5,8 @@ + - diff --git a/Sdk/Speckle.Common.MeshTriangulation/TriangleNetTriangulator.cs b/Sdk/Speckle.Common.MeshTriangulation/TriangleNetTriangulator.cs deleted file mode 100644 index 67ff6093a..000000000 --- a/Sdk/Speckle.Common.MeshTriangulation/TriangleNetTriangulator.cs +++ /dev/null @@ -1,75 +0,0 @@ -using Speckle.DoubleNumerics; -using TriangleNet.Geometry; - -namespace Speckle.Common.MeshTriangulation; - -public class TriangleNetTriangulator : ITriangulator -{ - public Mesh2 Triangulate(IReadOnlyList polygons) - { - var poly = new Polygon(); - - AddContour(poly, polygons[0]); - - for (int i = 1; i < polygons.Count; i++) - { - AddHole(poly, polygons[i]); - } - - var mesh = poly.Triangulate(); - var vertices = new List(); - var triangles = new List(); - int tc = 0; - - foreach (var triangle in mesh.Triangles) - { - var v1 = triangle.GetVertex(0); - var v2 = triangle.GetVertex(1); - var v3 = triangle.GetVertex(2); - - vertices.Add(new Vector2(v1.X, v1.Y)); - vertices.Add(new Vector2(v2.X, v2.Y)); - vertices.Add(new Vector2(v3.X, v3.Y)); - - triangles.Add(tc++); - triangles.Add(tc++); - triangles.Add(tc++); - } - - return new Mesh2(vertices, triangles); - } - - private void AddContour(Polygon p, Poly2 poly2) - { - var verts = new List(); - foreach (var v in poly2.Vertices) - { - verts.Add(new Vertex(v.X, v.Y, 1)); - } - - p.Add(new TriangleNet.Geometry.Contour(verts, 1)); - } - - private void AddHole(Polygon p, Poly2 poly2) - { - var verts = new List(); - foreach (var v in poly2.Vertices) - { - verts.Add(new Vertex(v.X, v.Y, 2)); - } - - // we need a point inside the hole to add it - var pointInHole = GetRightPointOfEdge(poly2.Vertices[0], poly2.Vertices[1]); - p.Add(new TriangleNet.Geometry.Contour(verts, 2), new Point(pointInHole.X, pointInHole.Y)); - } - - // picks a point on the right side of the given edge - private Vector2 GetRightPointOfEdge(Vector2 a, Vector2 b) - { - Vector2 ab = b - a; - var normal = Vector2.Normalize(new Vector2(-ab.Y, ab.X)); - var right = -0.01 * normal; - var midPoint = Vector2.Lerp(a, b, 0.5f); - return midPoint + right; - } -} diff --git a/Sdk/Speckle.Common.MeshTriangulation/packages.lock.json b/Sdk/Speckle.Common.MeshTriangulation/packages.lock.json index 295816215..328d15196 100644 --- a/Sdk/Speckle.Common.MeshTriangulation/packages.lock.json +++ b/Sdk/Speckle.Common.MeshTriangulation/packages.lock.json @@ -2,6 +2,12 @@ "version": 2, "dependencies": { ".NETStandard,Version=v2.0": { + "LibTessDotNet": { + "type": "Direct", + "requested": "[1.1.15, )", + "resolved": "1.1.15", + "contentHash": "KuA7N3Nv/lIeawJdQBQJR6oqWD9KETHLbWzBqapwFs+Tby+R5I4crkKujKMm5bXcSuFZ8LNtflFQVadsWCbBjg==" + }, "Microsoft.NETFramework.ReferenceAssemblies": { "type": "Direct", "requested": "[1.0.3, )", @@ -48,12 +54,6 @@ "resolved": "0.9.6", "contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w==" }, - "Speckle.Triangle": { - "type": "Direct", - "requested": "[1.0.0, )", - "resolved": "1.0.0", - "contentHash": "3fWYy5IG9EpkxvqSkRWtgWraYg7ylkg8Ea3WesIqAodjOySYzv+ntdcCP7EW7a5NB3nUhlp27woMAwyKFEF5XQ==" - }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", "resolved": "8.0.0", @@ -76,6 +76,12 @@ } }, "net8.0": { + "LibTessDotNet": { + "type": "Direct", + "requested": "[1.1.15, )", + "resolved": "1.1.15", + "contentHash": "KuA7N3Nv/lIeawJdQBQJR6oqWD9KETHLbWzBqapwFs+Tby+R5I4crkKujKMm5bXcSuFZ8LNtflFQVadsWCbBjg==" + }, "Microsoft.NETFramework.ReferenceAssemblies": { "type": "Direct", "requested": "[1.0.3, )", @@ -113,12 +119,6 @@ "resolved": "0.9.6", "contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w==" }, - "Speckle.Triangle": { - "type": "Direct", - "requested": "[1.0.0, )", - "resolved": "1.0.0", - "contentHash": "3fWYy5IG9EpkxvqSkRWtgWraYg7ylkg8Ea3WesIqAodjOySYzv+ntdcCP7EW7a5NB3nUhlp27woMAwyKFEF5XQ==" - }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", "resolved": "8.0.0",