diff --git a/src/Aardvark.Base/Geometry/Geometry_auto.cs b/src/Aardvark.Base/Geometry/Geometry_auto.cs index 2319cb31..2b65ee3b 100644 --- a/src/Aardvark.Base/Geometry/Geometry_auto.cs +++ b/src/Aardvark.Base/Geometry/Geometry_auto.cs @@ -482,56 +482,105 @@ public static double ComputePerimeter(this Polygon2d polygon) #region Geometric Transformations - public static Polygon2d Scaled( - this Polygon2d polygon, double scale) + public static Polygon2d Scaled(this Polygon2d polygon, double scale) { - return polygon.Map(p => p * scale); + var pc = polygon.m_pointCount; + V2d[] opa = polygon.m_pointArray, npa = new V2d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = opa[pi] * scale; + return new Polygon2d(npa, pc); } - public static Polygon2d Scaled( - this Polygon2d polygon, V2d center, double scale) + public static Polygon2d Scaled(this Polygon2d polygon, V2d center, double scale) { - return polygon.Map(p => center + (p - center) * scale); + var pc = polygon.m_pointCount; + V2d[] opa = polygon.m_pointArray, npa = new V2d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = center + (opa[pi] - center) * scale; + return new Polygon2d(npa, pc); } - public static Polygon2d ScaledAboutVertexCentroid( - this Polygon2d polygon, double scale) + public static Polygon2d ScaledAboutVertexCentroid(this Polygon2d polygon, double scale) { return polygon.Scaled(polygon.ComputeVertexCentroid(), scale); } - public static Polygon2d Scaled( - this Polygon2d polygon, V2d scale) + public static Polygon2d Scaled(this Polygon2d polygon, V2d scale) { - return polygon.Map(p => p * scale); + var pc = polygon.m_pointCount; + V2d[] opa = polygon.m_pointArray, npa = new V2d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = opa[pi] * scale; + return new Polygon2d(npa, pc); } - public static Polygon2d Scaled( - this Polygon2d polygon, V2d center, V2d scale) + public static Polygon2d Scaled(this Polygon2d polygon, V2d center, V2d scale) { - return polygon.Map(p => center + (p - center) * scale); + var pc = polygon.m_pointCount; + V2d[] opa = polygon.m_pointArray, npa = new V2d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = center + (opa[pi] - center) * scale; + return new Polygon2d(npa, pc); } - public static Polygon2d ScaledAboutVertexCentroid( - this Polygon2d polygon, V2d scale) + public static Polygon2d ScaledAboutVertexCentroid(this Polygon2d polygon, V2d scale) { return polygon.Scaled(polygon.ComputeVertexCentroid(), scale); } - public static Polygon2d Transformed( - this Polygon2d polygon, M22d m) + public static Polygon2d Transformed(this Polygon2d polygon, M22d m) + { + var pc = polygon.m_pointCount; + V2d[] opa = polygon.m_pointArray, npa = new V2d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = m.Transform(opa[pi]); + return new Polygon2d(npa, pc); + } + + public static Polygon2d Transformed(this Polygon2d polygon, M33d m) + { + var pc = polygon.m_pointCount; + V2d[] opa = polygon.m_pointArray, npa = new V2d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = m.TransformPos(opa[pi]); + return new Polygon2d(npa, pc); + } + + public static Polygon2d Transformed(this Polygon2d polygon, Euclidean2d t) + { + var pc = polygon.m_pointCount; + V2d[] opa = polygon.m_pointArray, npa = new V2d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = t.TransformPos(opa[pi]); + return new Polygon2d(npa, pc); + } + + public static Polygon2d Transformed(this Polygon2d polygon, Similarity2d t) { - return polygon.Map(p => m.Transform(p)); + var pc = polygon.m_pointCount; + V2d[] opa = polygon.m_pointArray, npa = new V2d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = t.TransformPos(opa[pi]); + return new Polygon2d(npa, pc); } - public static Polygon2d Transformed( - this Polygon2d polygon, M33d m) + public static Polygon2d Transformed(this Polygon2d polygon, Affine2d t) { - return polygon.Map(p => m.TransformPos(p)); + var pc = polygon.m_pointCount; + V2d[] opa = polygon.m_pointArray, npa = new V2d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = t.TransformPos(opa[pi]); + return new Polygon2d(npa, pc); + } + + public static Polygon2d Transformed(this Polygon2d polygon, Shift2d t) + { + var pc = polygon.m_pointCount; + V2d[] opa = polygon.m_pointArray, npa = new V2d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = t.Transform(opa[pi]); + return new Polygon2d(npa, pc); + } + + public static Polygon2d Transformed(this Polygon2d polygon, Rot2d t) + { + var pc = polygon.m_pointCount; + V2d[] opa = polygon.m_pointArray, npa = new V2d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = t.Transform(opa[pi]); + return new Polygon2d(npa, pc); } - public static Polygon2d WithoutMultiplePoints( - this Polygon2d polygon, double eps = 1e-8) + public static Polygon2d WithoutMultiplePoints(this Polygon2d polygon, double eps = 1e-8) { eps *= eps; var opc = polygon.PointCount; @@ -2046,56 +2095,105 @@ public static double ComputePerimeter(this Polygon3d polygon) #region Geometric Transformations - public static Polygon3d Scaled( - this Polygon3d polygon, double scale) + public static Polygon3d Scaled(this Polygon3d polygon, double scale) { - return polygon.Map(p => p * scale); + var pc = polygon.m_pointCount; + V3d[] opa = polygon.m_pointArray, npa = new V3d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = opa[pi] * scale; + return new Polygon3d(npa, pc); } - public static Polygon3d Scaled( - this Polygon3d polygon, V3d center, double scale) + public static Polygon3d Scaled(this Polygon3d polygon, V3d center, double scale) { - return polygon.Map(p => center + (p - center) * scale); + var pc = polygon.m_pointCount; + V3d[] opa = polygon.m_pointArray, npa = new V3d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = center + (opa[pi] - center) * scale; + return new Polygon3d(npa, pc); } - public static Polygon3d ScaledAboutVertexCentroid( - this Polygon3d polygon, double scale) + public static Polygon3d ScaledAboutVertexCentroid(this Polygon3d polygon, double scale) { return polygon.Scaled(polygon.ComputeVertexCentroid(), scale); } - public static Polygon3d Scaled( - this Polygon3d polygon, V3d scale) + public static Polygon3d Scaled(this Polygon3d polygon, V3d scale) { - return polygon.Map(p => p * scale); + var pc = polygon.m_pointCount; + V3d[] opa = polygon.m_pointArray, npa = new V3d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = opa[pi] * scale; + return new Polygon3d(npa, pc); } - public static Polygon3d Scaled( - this Polygon3d polygon, V3d center, V3d scale) + public static Polygon3d Scaled(this Polygon3d polygon, V3d center, V3d scale) { - return polygon.Map(p => center + (p - center) * scale); + var pc = polygon.m_pointCount; + V3d[] opa = polygon.m_pointArray, npa = new V3d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = center + (opa[pi] - center) * scale; + return new Polygon3d(npa, pc); } - public static Polygon3d ScaledAboutVertexCentroid( - this Polygon3d polygon, V3d scale) + public static Polygon3d ScaledAboutVertexCentroid(this Polygon3d polygon, V3d scale) { return polygon.Scaled(polygon.ComputeVertexCentroid(), scale); } - public static Polygon3d Transformed( - this Polygon3d polygon, M33d m) + public static Polygon3d Transformed(this Polygon3d polygon, M33d m) + { + var pc = polygon.m_pointCount; + V3d[] opa = polygon.m_pointArray, npa = new V3d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = m.Transform(opa[pi]); + return new Polygon3d(npa, pc); + } + + public static Polygon3d Transformed(this Polygon3d polygon, M44d m) + { + var pc = polygon.m_pointCount; + V3d[] opa = polygon.m_pointArray, npa = new V3d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = m.TransformPos(opa[pi]); + return new Polygon3d(npa, pc); + } + + public static Polygon3d Transformed(this Polygon3d polygon, Euclidean3d t) + { + var pc = polygon.m_pointCount; + V3d[] opa = polygon.m_pointArray, npa = new V3d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = t.TransformPos(opa[pi]); + return new Polygon3d(npa, pc); + } + + public static Polygon3d Transformed(this Polygon3d polygon, Similarity3d t) { - return polygon.Map(p => m.Transform(p)); + var pc = polygon.m_pointCount; + V3d[] opa = polygon.m_pointArray, npa = new V3d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = t.TransformPos(opa[pi]); + return new Polygon3d(npa, pc); } - public static Polygon3d Transformed( - this Polygon3d polygon, M44d m) + public static Polygon3d Transformed(this Polygon3d polygon, Affine3d t) { - return polygon.Map(p => m.TransformPos(p)); + var pc = polygon.m_pointCount; + V3d[] opa = polygon.m_pointArray, npa = new V3d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = t.TransformPos(opa[pi]); + return new Polygon3d(npa, pc); + } + + public static Polygon3d Transformed(this Polygon3d polygon, Shift3d t) + { + var pc = polygon.m_pointCount; + V3d[] opa = polygon.m_pointArray, npa = new V3d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = t.Transform(opa[pi]); + return new Polygon3d(npa, pc); + } + + public static Polygon3d Transformed(this Polygon3d polygon, Rot3d t) + { + var pc = polygon.m_pointCount; + V3d[] opa = polygon.m_pointArray, npa = new V3d[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = t.Transform(opa[pi]); + return new Polygon3d(npa, pc); } - public static Polygon3d WithoutMultiplePoints( - this Polygon3d polygon, double eps = 1e-8) + public static Polygon3d WithoutMultiplePoints(this Polygon3d polygon, double eps = 1e-8) { eps *= eps; var opc = polygon.PointCount; diff --git a/src/Aardvark.Base/Geometry/Geometry_template.cs b/src/Aardvark.Base/Geometry/Geometry_template.cs index 7ab583d8..2b0ae958 100644 --- a/src/Aardvark.Base/Geometry/Geometry_template.cs +++ b/src/Aardvark.Base/Geometry/Geometry_template.cs @@ -23,6 +23,11 @@ namespace Aardvark.Base //# var tveci = "V" + di; //# var tmat = "M" + d + dd; //# var tmat1 = "M" + dp1 + dp1 + "d"; + //# var teucl = "Euclidean" + dd; + //# var tsimi = "Similarity" + dd; + //# var taffi = "Affine" + dd; + //# var tshif = "Shift" + dd; + //# var trot = "Rot" + dd; //# var plane = planeArray[d]; //# var tpolygon = "Polygon" + dd; //# var tplane = "Plane" + dd; @@ -670,56 +675,105 @@ public static double ComputePerimeter(this __tipolygon__ polygon) #region Geometric Transformations - public static __tpolygon__ Scaled( - this __tpolygon__ polygon, double scale) + public static __tpolygon__ Scaled(this __tpolygon__ polygon, double scale) { - return polygon.Map(p => p * scale); + var pc = polygon.m_pointCount; + __tvec__[] opa = polygon.m_pointArray, npa = new __tvec__[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = opa[pi] * scale; + return new __tpolygon__(npa, pc); } - public static __tpolygon__ Scaled( - this __tpolygon__ polygon, __tvec__ center, double scale) + public static __tpolygon__ Scaled(this __tpolygon__ polygon, __tvec__ center, double scale) { - return polygon.Map(p => center + (p - center) * scale); + var pc = polygon.m_pointCount; + __tvec__[] opa = polygon.m_pointArray, npa = new __tvec__[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = center + (opa[pi] - center) * scale; + return new __tpolygon__(npa, pc); } - public static __tpolygon__ ScaledAboutVertexCentroid( - this __tpolygon__ polygon, double scale) + public static __tpolygon__ ScaledAboutVertexCentroid(this __tpolygon__ polygon, double scale) { return polygon.Scaled(polygon.ComputeVertexCentroid(), scale); } - public static __tpolygon__ Scaled( - this __tpolygon__ polygon, __tvec__ scale) + public static __tpolygon__ Scaled(this __tpolygon__ polygon, __tvec__ scale) { - return polygon.Map(p => p * scale); + var pc = polygon.m_pointCount; + __tvec__[] opa = polygon.m_pointArray, npa = new __tvec__[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = opa[pi] * scale; + return new __tpolygon__(npa, pc); } - public static __tpolygon__ Scaled( - this __tpolygon__ polygon, __tvec__ center, __tvec__ scale) + public static __tpolygon__ Scaled(this __tpolygon__ polygon, __tvec__ center, __tvec__ scale) { - return polygon.Map(p => center + (p - center) * scale); + var pc = polygon.m_pointCount; + __tvec__[] opa = polygon.m_pointArray, npa = new __tvec__[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = center + (opa[pi] - center) * scale; + return new __tpolygon__(npa, pc); } - public static __tpolygon__ ScaledAboutVertexCentroid( - this __tpolygon__ polygon, __tvec__ scale) + public static __tpolygon__ ScaledAboutVertexCentroid(this __tpolygon__ polygon, __tvec__ scale) { return polygon.Scaled(polygon.ComputeVertexCentroid(), scale); } - public static __tpolygon__ Transformed( - this __tpolygon__ polygon, __tmat__ m) + public static __tpolygon__ Transformed(this __tpolygon__ polygon, __tmat__ m) + { + var pc = polygon.m_pointCount; + __tvec__[] opa = polygon.m_pointArray, npa = new __tvec__[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = m.Transform(opa[pi]); + return new __tpolygon__(npa, pc); + } + + public static __tpolygon__ Transformed(this __tpolygon__ polygon, __tmat1__ m) + { + var pc = polygon.m_pointCount; + __tvec__[] opa = polygon.m_pointArray, npa = new __tvec__[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = m.TransformPos(opa[pi]); + return new __tpolygon__(npa, pc); + } + + public static __tpolygon__ Transformed(this __tpolygon__ polygon, __teucl__ t) + { + var pc = polygon.m_pointCount; + __tvec__[] opa = polygon.m_pointArray, npa = new __tvec__[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = t.TransformPos(opa[pi]); + return new __tpolygon__(npa, pc); + } + + public static __tpolygon__ Transformed(this __tpolygon__ polygon, __tsimi__ t) { - return polygon.Map(p => m.Transform(p)); + var pc = polygon.m_pointCount; + __tvec__[] opa = polygon.m_pointArray, npa = new __tvec__[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = t.TransformPos(opa[pi]); + return new __tpolygon__(npa, pc); } - public static __tpolygon__ Transformed( - this __tpolygon__ polygon, __tmat1__ m) + public static __tpolygon__ Transformed(this __tpolygon__ polygon, __taffi__ t) { - return polygon.Map(p => m.TransformPos(p)); + var pc = polygon.m_pointCount; + __tvec__[] opa = polygon.m_pointArray, npa = new __tvec__[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = t.TransformPos(opa[pi]); + return new __tpolygon__(npa, pc); + } + + public static __tpolygon__ Transformed(this __tpolygon__ polygon, __tshif__ t) + { + var pc = polygon.m_pointCount; + __tvec__[] opa = polygon.m_pointArray, npa = new __tvec__[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = t.Transform(opa[pi]); + return new __tpolygon__(npa, pc); + } + + public static __tpolygon__ Transformed(this __tpolygon__ polygon, __trot__ t) + { + var pc = polygon.m_pointCount; + __tvec__[] opa = polygon.m_pointArray, npa = new __tvec__[pc]; + for (int pi = 0; pi < pc; pi++) npa[pi] = t.Transform(opa[pi]); + return new __tpolygon__(npa, pc); } - public static __tpolygon__ WithoutMultiplePoints( - this __tpolygon__ polygon, double eps = 1e-8) + public static __tpolygon__ WithoutMultiplePoints(this __tpolygon__ polygon, double eps = 1e-8) { eps *= eps; var opc = polygon.PointCount; diff --git a/src/Tests/Aardvark.Base.Benchmarks/PolygonTransform.cs b/src/Tests/Aardvark.Base.Benchmarks/PolygonTransform.cs new file mode 100644 index 00000000..2ca90b6f --- /dev/null +++ b/src/Tests/Aardvark.Base.Benchmarks/PolygonTransform.cs @@ -0,0 +1,71 @@ +using BenchmarkDotNet.Attributes; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Aardvark.Base.Benchmarks +{ + //BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042 + //Intel Core i7-8700K CPU 3.70GHz(Coffee Lake), 1 CPU, 12 logical and 6 physical cores + //.NET Core SDK = 5.0.201 + + // [Host] : .NET Core 3.1.13 (CoreCLR 4.700.21.11102, CoreFX 4.700.21.11602), X64 RyuJIT + // DefaultJob : .NET Core 3.1.13 (CoreCLR 4.700.21.11102, CoreFX 4.700.21.11602), X64 RyuJIT + + //| Method | Count | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated | + //|------------------- |------ |----------:|---------:|---------:|-------:|-------:|------:|----------:| + //| TransformMatrix | 5 | 40.59 ns | 0.301 ns | 0.281 ns | 0.0166 | - | - | 104 B | + //| TransformMatrixNew | 5 | 60.41 ns | 0.307 ns | 0.287 ns | 0.0408 | - | - | 256 B | + //| TransformShiftMap | 5 | 31.36 ns | 0.113 ns | 0.094 ns | 0.0318 | - | - | 200 B | + //| TransformShiftNew | 5 | 16.92 ns | 0.144 ns | 0.128 ns | 0.0166 | - | - | 104 B | + //| TransformMatrix | 20 | 128.61 ns | 0.418 ns | 0.391 ns | 0.0548 | - | - | 344 B | + //| TransformMatrixNew | 20 | 180.79 ns | 0.921 ns | 0.861 ns | 0.0789 | - | - | 496 B | + //| TransformShiftMap | 20 | 71.36 ns | 0.551 ns | 0.515 ns | 0.0701 | 0.0001 | - | 440 B | + //| TransformShiftNew | 20 | 43.27 ns | 0.820 ns | 0.767 ns | 0.0548 | 0.0001 | - | 344 B | + //| TransformMatrix | 100 | 531.93 ns | 1.654 ns | 1.466 ns | 0.2584 | 0.0010 | - | 1624 B | + //| TransformMatrixNew | 100 | 834.72 ns | 3.112 ns | 2.911 ns | 0.2823 | 0.0010 | - | 1776 B | + //| TransformShiftMap | 100 | 370.42 ns | 1.636 ns | 1.530 ns | 0.2737 | 0.0014 | - | 1720 B | + //| TransformShiftNew | 100 | 198.36 ns | 0.890 ns | 0.833 ns | 0.2587 | 0.0014 | - | 1624 B | + + [PlainExporter, MemoryDiagnoser] + public class PolygonTransform + { + public V2d offset = V2d.Zero; + public Polygon2d polyArray = new Polygon2d(new V2d[5].SetByIndex(i => new V2d(i))); + + [Params(5, 20, 100)] + public int Count; + + [GlobalSetup] + public void GlobalSetup() + { + polyArray = new Polygon2d(new V2d[Count].SetByIndex(i => new V2d(i))); + } + + [Benchmark] + public Polygon2d TransformMatrix() + { + return polyArray.Transformed(M33d.Translation(offset)); + } + + [Benchmark] + public Polygon2d TransformMatrixNew() + { + var m = M33d.Translation(offset); + return polyArray.Map(v => m.TransformPos(v)); + } + + [Benchmark] + public Polygon2d TransformShiftMap() + { + var o = offset; + return polyArray.Map(v => v + o); + } + + [Benchmark] + public Polygon2d TransformShiftNew() + { + return polyArray.Transformed(new Shift2d(offset)); + } + } +} diff --git a/src/Tests/Aardvark.Base.Benchmarks/Program.cs b/src/Tests/Aardvark.Base.Benchmarks/Program.cs index ddf27174..36fd7d84 100644 --- a/src/Tests/Aardvark.Base.Benchmarks/Program.cs +++ b/src/Tests/Aardvark.Base.Benchmarks/Program.cs @@ -83,7 +83,7 @@ public static void Main(string[] args) //new Enumerators().Test(); //BenchmarkRunner.Run(); - BenchmarkRunner.Run(); + BenchmarkRunner.Run(); } } }