From d07190dfc57b90f24737c5bf714f0293ef4fac5f Mon Sep 17 00:00:00 2001 From: Dmytro Muravskyi Date: Fri, 1 Sep 2023 17:03:35 +0300 Subject: [PATCH 1/5] Make IndexedPolycurve.GetSubdivisionParameters, Polyline.Frames and Polygon.Frames work with startSetback and endSetback --- Elements/src/Geometry/IndexedPolycurve.cs | 25 +++++-- Elements/src/Geometry/Polygon.cs | 70 ++++++++++++++++---- Elements/src/Geometry/Polyline.cs | 80 ++++++++++++++++------- Elements/src/Geometry/Solids/Solid.cs | 4 +- Elements/test/IndexedPolyCurveTests.cs | 41 ++++++++++++ Elements/test/PolygonTests.cs | 38 +++++++++++ Elements/test/PolylineTests.cs | 32 +++++++++ Elements/test/SolidTests.cs | 27 ++++++++ 8 files changed, 275 insertions(+), 42 deletions(-) diff --git a/Elements/src/Geometry/IndexedPolycurve.cs b/Elements/src/Geometry/IndexedPolycurve.cs index 35cfd4e63..0af0a9603 100644 --- a/Elements/src/Geometry/IndexedPolycurve.cs +++ b/Elements/src/Geometry/IndexedPolycurve.cs @@ -277,14 +277,18 @@ public override BBox3 Bounds() public override double[] GetSubdivisionParameters(double startSetbackDistance = 0, double endSetbackDistance = 0) { - var parameters = new List(); - for (var i = 0; i < _curves.Count; i++) + var startParam = ParameterAtDistanceFromParameter(startSetbackDistance, Domain.Min); + var endParam = ParameterAtDistanceFromParameter(Length() - endSetbackDistance, Domain.Min); + + var startCurveIndex = (int)Math.Floor(startParam); + var endCurveIndex = Math.Min(_curves.Count - 1, (int)Math.Floor(endParam)); + + var parameters = new List() { startParam }; + for (var i = startCurveIndex; i < endCurveIndex + 1; i++) { - var startParam = i; - var endParam = i + 1; var curve = _curves[i]; var localParameters = curve.GetSubdivisionParameters(); - var localDomain = new Domain1d(startParam, endParam); + var localDomain = new Domain1d(i, i + 1); for (var j = 0; j < localParameters.Length; j++) { var localParameter = localParameters[j]; @@ -292,14 +296,21 @@ public override double[] GetSubdivisionParameters(double startSetbackDistance = // into a domain that is a subsection of the larger domain. var remapped = localParameter.MapBetweenDomains(curve.Domain, localDomain); - // De-duplicate the end vertices. - if (parameters.Count > 0 && parameters[parameters.Count - 1].ApproximatelyEquals(remapped)) + // Filter parameters outside of setbacks and de-duplicate the end vertices. + if (remapped < startParam || remapped > endParam || + parameters[parameters.Count - 1].ApproximatelyEquals(remapped)) { continue; } parameters.Add(remapped); } } + + if (!parameters[parameters.Count - 1].ApproximatelyEquals(endParam)) + { + parameters.Add(endParam); + } + return parameters.ToArray(); } diff --git a/Elements/src/Geometry/Polygon.cs b/Elements/src/Geometry/Polygon.cs index fa0e11f2d..30072ba7e 100644 --- a/Elements/src/Geometry/Polygon.cs +++ b/Elements/src/Geometry/Polygon.cs @@ -1,4 +1,5 @@ using ClipperLib; +using Elements.Geometry.Profiles; using Elements.Search; using Elements.Spatial; using Newtonsoft.Json; @@ -2071,26 +2072,73 @@ public Polygon CollinearPointsRemoved(double tolerance = Vector3.EPSILON) } /// - public override Transform[] Frames(double startSetback = 0.0, - double endSetback = 0.0, + public override Transform[] Frames(double startSetbackDistance = 0.0, + double endSetbackDistance = 0.0, double additionalRotation = 0.0) { - // Create an array of transforms with the same - // number of items as the vertices. - var result = new Transform[this.Vertices.Count]; + var startParam = ParameterAtDistanceFromParameter(startSetbackDistance, Domain.Min); + var endParam = ParameterAtDistanceFromParameter(Length() - endSetbackDistance, Domain.Min); - // Cache the normal so we don't have to recalculate - // using Newell for every frame. + if (startParam >= endParam) + { + return new Transform[0]; + } + + var startIndex = (int)Math.Ceiling(startParam); + var endIndex = (int)Math.Floor(endParam); + bool startAtVertex = false; + bool endsAtVertex = false; + + // Calculate number of frames. 2 frames corresponding to end parameters. + // 1 if startIndex == endIndex. + var lenght = endIndex - startIndex + 3; + + // startIndex is set to the first distinct vertex after startParam. + if (startParam.ApproximatelyEquals(startIndex)) + { + startAtVertex = true; + lenght--; + } + + // endIndex is set to the first distinct vertex before endParam. + if (endParam.ApproximatelyEquals(endIndex)) + { + endsAtVertex = true; + lenght--; + } + + var result = new Transform[lenght]; var up = this.Normal(); - for (var i = 0; i < result.Length; i++) + + int index = 0; + if (!startAtVertex) + { + var tangent = (Vertices[startIndex] - Vertices[startIndex - 1]).Unitized(); + result[0] = new Transform(PointAt(startParam), up.Cross(tangent), tangent); + index++; + } + + // CreateMiterTransform expects index of previous and next vertex, that's why index must be adjusted. + for (var i = startIndex; i <= endIndex; i++, index++) { - var a = this.Vertices[i]; - result[i] = CreateMiterTransform(i, a, up); - if (additionalRotation != 0.0) + var adjusted = i == Vertices.Count ? 0 : i; + result[index] = CreateMiterTransform(adjusted, Vertices[adjusted], up); + } + + if (!endsAtVertex) + { + var tangent = (Vertices[endIndex + 1] - Vertices[endIndex]).Unitized(); + result[index] = new Transform(PointAt(endParam), up.Cross(tangent), tangent); + } + + if (additionalRotation != 0.0) + { + for (int i = 0; i < result.Length; i++) { result[i].RotateAboutPoint(result[i].Origin, result[i].ZAxis, additionalRotation); } } + return result; } diff --git a/Elements/src/Geometry/Polyline.cs b/Elements/src/Geometry/Polyline.cs index b33e77545..d4458a006 100644 --- a/Elements/src/Geometry/Polyline.cs +++ b/Elements/src/Geometry/Polyline.cs @@ -88,7 +88,7 @@ public virtual Line[] Segments() /// Get the transform at the specified parameter along the polyline. /// /// The parameter on the polygon between 0.0 and length. - /// A transform with its Z axis aligned trangent to the polyline. + /// A transform with its Z axis aligned tangent to the polyline. public override Transform TransformAt(double u) { if (!Domain.Includes(u, true)) @@ -288,32 +288,68 @@ public override Transform[] Frames(double startSetbackDistance = 0.0, double endSetbackDistance = 0.0, double additionalRotation = 0.0) { + var startParam = ParameterAtDistanceFromParameter(startSetbackDistance, Domain.Min); + var endParam = ParameterAtDistanceFromParameter(Length() - endSetbackDistance, Domain.Min); + + if (startParam >= endParam) + { + return new Transform[0]; + } + + var startIndex = (int)Math.Ceiling(startParam); + var endIndex = (int)Math.Floor(endParam); + bool startAtVertex = false; + bool endsAtVertex = false; + + // Calculate number of frames. 2 frames corresponding to end parameters. + // 1 if startIndex == endIndex. + var lenght = endIndex - startIndex + 3; + + // startIndex is set to the first distinct vertex after startParam. + if (startParam.ApproximatelyEquals(startIndex)) + { + startAtVertex = true; + lenght--; + } + + // endIndex is set to the first distinct vertex before endParam. + if (endParam.ApproximatelyEquals(endIndex)) + { + endsAtVertex = true; + lenght--; + } + + var result = new Transform[lenght]; var normals = this.NormalsAtVertices(); - // Create an array of transforms with the same number of items as the vertices. - var result = new Transform[this.Vertices.Count]; - var l = Length(); - for (var i = 0; i < result.Length; i++) + int index = 0; + // CreateOrthogonalTransform expects index of previous vertex, that's why index must be adjusted. + if (!startAtVertex) { - Vector3 a; - if (i == 0) - { - a = PointAt(ParameterAtDistanceFromParameter(startSetbackDistance, this.Domain.Min)); - } - else if (i == Vertices.Count - 1) - { - a = PointAt(ParameterAtDistanceFromParameter(l - endSetbackDistance, this.Domain.Min)); - } - else - { - a = this.Vertices[i]; - } - result[i] = CreateOrthogonalTransform(i, a, normals[i]); - if (additionalRotation != 0.0) + var tangent = (Vertices[startIndex] - Vertices[startIndex - 1]).Unitized(); + result[0] = new Transform(PointAt(startParam), normals[startIndex - 1].Cross(tangent), tangent); + index++; + } + + for (var i = startIndex; i <= endIndex; i++, index++) + { + result[index] = CreateOrthogonalTransform(i, Vertices[i], normals[i]); + } + + if (!endsAtVertex) + { + var tangent = (Vertices[endIndex + 1] - Vertices[endIndex]).Unitized(); + result[index] = new Transform(PointAt(endParam), normals[endIndex].Cross(tangent), tangent); + } + + if (additionalRotation != 0.0) + { + for (int i = 0; i < result.Length; i++) { result[i].RotateAboutPoint(result[i].Origin, result[i].ZAxis, additionalRotation); } } + return result; } @@ -351,7 +387,7 @@ protected Transform CreateMiterTransform(int i, Vector3 a, Vector3 up) var x1 = l1.Cross(up); var x2 = l2.Cross(up); var x = x1.Average(x2); - return new Transform(this.Vertices[i], x, x.Cross(up)); + return new Transform(a, x, x.Cross(up)); } private Transform CreateOrthogonalTransform(int i, Vector3 origin, Vector3 up) @@ -380,7 +416,7 @@ private Transform CreateOrthogonalTransform(int i, Vector3 origin, Vector3 up) if (tangent.IsZero()) { tangent = v1; - } + } } tangent = tangent.Negate(); return new Transform(origin, up.Cross(tangent), tangent); diff --git a/Elements/src/Geometry/Solids/Solid.cs b/Elements/src/Geometry/Solids/Solid.cs index 91d7755f5..a8dfad0d6 100644 --- a/Elements/src/Geometry/Solids/Solid.cs +++ b/Elements/src/Geometry/Solids/Solid.cs @@ -131,9 +131,9 @@ public static Solid SweepFaceAlongCurve(Polygon perimeter, if (curve is Polygon) { - for (var i = 0; i < transforms.Length; i++) + for (var i = 0; i < transforms.Length - 1; i++) { - var next = i == transforms.Length - 1 ? transforms[0] : transforms[i + 1]; + var next = transforms[i + 1]; solid.SweepPolygonBetweenPlanes(perimeter, transforms[i], next); } } diff --git a/Elements/test/IndexedPolyCurveTests.cs b/Elements/test/IndexedPolyCurveTests.cs index f45ab29a9..2ddf1a349 100644 --- a/Elements/test/IndexedPolyCurveTests.cs +++ b/Elements/test/IndexedPolyCurveTests.cs @@ -186,5 +186,46 @@ public void Intersects() Assert.Contains(new Vector3(5, 2), results); Assert.Contains(new Vector3(2.5, 7.5), results); } + + [Fact] + public void GetSubdivisionParameters() + { + var pc = new IndexedPolycurve(new List() + { + (0, 0), (2, 0), (2, 2), (0, 2), (0, 3) + }); + var parameters = pc.GetSubdivisionParameters(); + Assert.Equal(5, parameters.Count()); + Assert.Equal(0.0, parameters[0]); + Assert.Equal(1.0, parameters[1]); + Assert.Equal(2.0, parameters[2]); + Assert.Equal(3.0, parameters[3]); + Assert.Equal(4.0, parameters[4]); + + parameters = pc.GetSubdivisionParameters(1.5, 1.5); + Assert.Equal(4, parameters.Count()); + Assert.Equal(0.75, parameters[0]); + Assert.Equal(1.0, parameters[1]); + Assert.Equal(2.0, parameters[2]); + Assert.Equal(2.75, parameters[3]); + + parameters = pc.GetSubdivisionParameters(1, 1); + Assert.Equal(4, parameters.Count()); + Assert.Equal(0.5, parameters[0]); + Assert.Equal(1.0, parameters[1]); + Assert.Equal(2.0, parameters[2]); + Assert.Equal(3.0, parameters[3]); + + parameters = pc.GetSubdivisionParameters(2, 2); + Assert.Equal(3, parameters.Count()); + Assert.Equal(1.0, parameters[0]); + Assert.Equal(2.0, parameters[1]); + Assert.Equal(2.5, parameters[2]); + + parameters = pc.GetSubdivisionParameters(2.5, 3.5); + Assert.Equal(2, parameters.Count()); + Assert.Equal(1.25, parameters[0]); + Assert.Equal(1.75, parameters[1]); + } } } \ No newline at end of file diff --git a/Elements/test/PolygonTests.cs b/Elements/test/PolygonTests.cs index adbfa83fc..44df3c1af 100644 --- a/Elements/test/PolygonTests.cs +++ b/Elements/test/PolygonTests.cs @@ -2213,5 +2213,43 @@ public void BigRectangleContainsSmallRectangle() var r2 = Polygon.Rectangle(1, 1).TransformedPolygon(new Transform(new Vector3(0.5, 0.5), Vector3.ZAxis)); Assert.True(r1.Contains3D(r2)); } + + [Fact] + public void Frames() + { + var polygon = new Polygon((0, 0), (2, 0), (2, 2), (0, 2)); + var frames = polygon.Frames(); + Assert.Equal(5, frames.Count()); + Assert.Equal(polygon.Vertices[0], frames[0].Origin); + Assert.True((Vector3.YAxis - Vector3.XAxis).IsParallelTo(frames[0].ZAxis)); + Assert.Equal(polygon.Vertices[1], frames[1].Origin); + Assert.True((Vector3.XAxis + Vector3.YAxis).IsParallelTo(frames[1].ZAxis)); + Assert.Equal(polygon.Vertices[2], frames[2].Origin); + Assert.True((Vector3.XAxis - Vector3.YAxis).IsParallelTo(frames[2].ZAxis)); + Assert.Equal(polygon.Vertices[3], frames[3].Origin); + Assert.True((Vector3.XAxis + Vector3.YAxis).IsParallelTo(frames[3].ZAxis)); + Assert.Equal(polygon.Vertices[0], frames[4].Origin); + Assert.True((Vector3.YAxis - Vector3.XAxis).IsParallelTo(frames[4].ZAxis)); + + frames = polygon.Frames(2, 2); + Assert.Equal(3, frames.Count()); + Assert.Equal(polygon.Vertices[1], frames[0].Origin); + Assert.True((Vector3.XAxis + Vector3.YAxis).IsParallelTo(frames[0].ZAxis)); + Assert.Equal(polygon.Vertices[2], frames[1].Origin); + Assert.True((Vector3.XAxis - Vector3.YAxis).IsParallelTo(frames[1].ZAxis)); + Assert.Equal(polygon.Vertices[3], frames[2].Origin); + Assert.True((Vector3.XAxis + Vector3.YAxis).IsParallelTo(frames[2].ZAxis)); + + frames = polygon.Frames(1, 3); + Assert.Equal(4, frames.Count()); + Assert.Equal((1, 0), frames[0].Origin); + Assert.True(Vector3.XAxis.IsParallelTo(frames[0].ZAxis)); + Assert.Equal(polygon.Vertices[1], frames[1].Origin); + Assert.True((Vector3.XAxis + Vector3.YAxis).IsParallelTo(frames[1].ZAxis)); + Assert.Equal(polygon.Vertices[2], frames[2].Origin); + Assert.True((Vector3.XAxis - Vector3.YAxis).IsParallelTo(frames[2].ZAxis)); + Assert.Equal((1, 2), frames[3].Origin); + Assert.True(Vector3.XAxis.IsParallelTo(frames[3].ZAxis)); + } } } \ No newline at end of file diff --git a/Elements/test/PolylineTests.cs b/Elements/test/PolylineTests.cs index 2ce511e3b..e71a15fe5 100644 --- a/Elements/test/PolylineTests.cs +++ b/Elements/test/PolylineTests.cs @@ -774,5 +774,37 @@ public void PolylineForceAngleComplianceWithZeroAngle() Assert.True(CheckPolylineAngles(angles, normalizedPathEnd)); Assert.True(CheckPolylineAngles(angles, normalizedPathEndYAxisReferenceVector)); } + + [Fact] + public void Frames() + { + var polyline = new Polyline((0, 0), (2, 0), (2, 2), (0, 2)); + var frames = polyline.Frames(); + Assert.Equal(4, frames.Count()); + Assert.Equal(polyline.Vertices[0], frames[0].Origin); + Assert.True(Vector3.XAxis.IsParallelTo(frames[0].ZAxis)); + Assert.Equal(polyline.Vertices[1], frames[1].Origin); + Assert.True((Vector3.XAxis + Vector3.YAxis).IsParallelTo(frames[1].ZAxis)); + Assert.Equal(polyline.Vertices[2], frames[2].Origin); + Assert.True((Vector3.XAxis - Vector3.YAxis).IsParallelTo(frames[2].ZAxis)); + Assert.Equal(polyline.Vertices[3], frames[3].Origin); + Assert.True(Vector3.XAxis.IsParallelTo(frames[3].ZAxis)); + + frames = polyline.Frames(2, 2); + Assert.Equal(2, frames.Count()); + Assert.Equal(polyline.Vertices[1], frames[0].Origin); + Assert.True((Vector3.XAxis + Vector3.YAxis).IsParallelTo(frames[0].ZAxis)); + Assert.Equal(polyline.Vertices[2], frames[1].Origin); + Assert.True((Vector3.XAxis - Vector3.YAxis).IsParallelTo(frames[1].ZAxis)); + + frames = polyline.Frames(1, 3); + Assert.Equal(3, frames.Count()); + Assert.Equal((1, 0), frames[0].Origin); + Assert.True(Vector3.XAxis.IsParallelTo(frames[0].ZAxis)); + Assert.Equal(polyline.Vertices[1], frames[1].Origin); + Assert.True((Vector3.XAxis + Vector3.YAxis).IsParallelTo(frames[1].ZAxis)); + Assert.Equal((2, 1), frames[2].Origin); + Assert.True(Vector3.YAxis.IsParallelTo(frames[2].ZAxis)); + } } } \ No newline at end of file diff --git a/Elements/test/SolidTests.cs b/Elements/test/SolidTests.cs index 86bbcd844..96aabafea 100644 --- a/Elements/test/SolidTests.cs +++ b/Elements/test/SolidTests.cs @@ -506,6 +506,33 @@ public void SolidIntersectPlaneTwice() this.Model.AddElement(solidElement); } + [Fact] + public void SweepWithSetbacksRegressionTest() + { + Name = nameof(SweepWithSetbacksRegressionTest); + Polygon crossSection = Polygon.Rectangle(0.25, 0.25); + + Polyline curve = new(new List + { + new Vector3(x: 20.0, y: 15.0, z:0.0), + new Vector3(x: 20.0, y: 15.0, z:1.0), + new Vector3(x: 20.0, y: 14.5, z:1.5), + new Vector3(x: 19.5, y: 14.5, z:1.5), + } + ); + + var sweep = new Sweep( + new Profile(crossSection), + curve, + startSetback: 1, + endSetback: 1, + profileRotation: 0, + isVoid: false + ); + var rep = new Representation(new List() { sweep }); + Model.AddElement(new GeometricElement(representation: rep, material: BuiltInMaterials.Black)); + } + [Theory] [InlineData("SolidIntersectionTest1", "../../../models/Geometry/SolidPlaneIntersection/debug-case-1.json")] [InlineData("SolidIntersectionTest2", "../../../models/Geometry/SolidPlaneIntersection/debug-case-2.json")] From a2bdd7b88e7968cc8a5cdc5142cb4edbfe33eb8b Mon Sep 17 00:00:00 2001 From: Dmytro Muravskyi Date: Fri, 1 Sep 2023 18:23:49 +0300 Subject: [PATCH 2/5] Add CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0e040dc1..68e7e9cd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,9 @@ - `Polygon.Contains3D` passed wrong `out Containment containment` parameter in some cases. - Code generation supports `Vector3?` and `Color?` types. +- `IndexedPolycurve.GetSubdivisionParameters` now works correctly with `startSetbackDistance` and `endSetbackDistance` parameters. +- `Polyline.Frames` now works correctly with `startSetbackDistance` and `endSetbackDistance` parameters. +- `Polygon.Frames` now works correctly with `startSetbackDistance` and `endSetbackDistance` parameters. ## 2.0.0 From 1b680b47ca1a071598830ca78faf03dd1d0e147c Mon Sep 17 00:00:00 2001 From: Dmytro Muravskyi Date: Wed, 4 Oct 2023 10:59:16 +0300 Subject: [PATCH 3/5] Fix typo --- Elements/src/Geometry/Polygon.cs | 8 ++++---- Elements/src/Geometry/Polyline.cs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Elements/src/Geometry/Polygon.cs b/Elements/src/Geometry/Polygon.cs index 30072ba7e..44bb7d414 100644 --- a/Elements/src/Geometry/Polygon.cs +++ b/Elements/src/Geometry/Polygon.cs @@ -2091,23 +2091,23 @@ public override Transform[] Frames(double startSetbackDistance = 0.0, // Calculate number of frames. 2 frames corresponding to end parameters. // 1 if startIndex == endIndex. - var lenght = endIndex - startIndex + 3; + var length = endIndex - startIndex + 3; // startIndex is set to the first distinct vertex after startParam. if (startParam.ApproximatelyEquals(startIndex)) { startAtVertex = true; - lenght--; + length--; } // endIndex is set to the first distinct vertex before endParam. if (endParam.ApproximatelyEquals(endIndex)) { endsAtVertex = true; - lenght--; + length--; } - var result = new Transform[lenght]; + var result = new Transform[length]; var up = this.Normal(); int index = 0; diff --git a/Elements/src/Geometry/Polyline.cs b/Elements/src/Geometry/Polyline.cs index d4458a006..f4da41793 100644 --- a/Elements/src/Geometry/Polyline.cs +++ b/Elements/src/Geometry/Polyline.cs @@ -303,23 +303,23 @@ public override Transform[] Frames(double startSetbackDistance = 0.0, // Calculate number of frames. 2 frames corresponding to end parameters. // 1 if startIndex == endIndex. - var lenght = endIndex - startIndex + 3; + var length = endIndex - startIndex + 3; // startIndex is set to the first distinct vertex after startParam. if (startParam.ApproximatelyEquals(startIndex)) { startAtVertex = true; - lenght--; + length--; } // endIndex is set to the first distinct vertex before endParam. if (endParam.ApproximatelyEquals(endIndex)) { endsAtVertex = true; - lenght--; + length--; } - var result = new Transform[lenght]; + var result = new Transform[length]; var normals = this.NormalsAtVertices(); int index = 0; From a1269f427dc4bcfc63fb0c51e98ee5a17a6eacb4 Mon Sep 17 00:00:00 2001 From: Dmytro Muravskyi Date: Wed, 4 Oct 2023 11:06:53 +0300 Subject: [PATCH 4/5] Fix Polygon.Frame if frame is part of the last segment --- Elements/src/Geometry/Polygon.cs | 3 ++- Elements/test/PolygonTests.cs | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Elements/src/Geometry/Polygon.cs b/Elements/src/Geometry/Polygon.cs index 44bb7d414..dd151f814 100644 --- a/Elements/src/Geometry/Polygon.cs +++ b/Elements/src/Geometry/Polygon.cs @@ -2127,7 +2127,8 @@ public override Transform[] Frames(double startSetbackDistance = 0.0, if (!endsAtVertex) { - var tangent = (Vertices[endIndex + 1] - Vertices[endIndex]).Unitized(); + var nextIndex = (endIndex + 1) % Vertices.Count; + var tangent = (Vertices[nextIndex] - Vertices[endIndex]).Unitized(); result[index] = new Transform(PointAt(endParam), up.Cross(tangent), tangent); } diff --git a/Elements/test/PolygonTests.cs b/Elements/test/PolygonTests.cs index 44df3c1af..0c4c3e933 100644 --- a/Elements/test/PolygonTests.cs +++ b/Elements/test/PolygonTests.cs @@ -2231,6 +2231,13 @@ public void Frames() Assert.Equal(polygon.Vertices[0], frames[4].Origin); Assert.True((Vector3.YAxis - Vector3.XAxis).IsParallelTo(frames[4].ZAxis)); + frames = polygon.Frames(1, 1); + Assert.Equal(5, frames.Count()); + Assert.Equal((1, 0), frames[0].Origin); + Assert.True(Vector3.XAxis.IsParallelTo(frames[0].ZAxis)); + Assert.Equal((0, 1), frames[4].Origin); + Assert.True(Vector3.YAxis.IsParallelTo(frames[4].ZAxis)); + frames = polygon.Frames(2, 2); Assert.Equal(3, frames.Count()); Assert.Equal(polygon.Vertices[1], frames[0].Origin); From 47eeb2325a0c26496735afd24177948bb26b782b Mon Sep 17 00:00:00 2001 From: Dmytro Muravskyi Date: Wed, 4 Oct 2023 15:34:08 +0300 Subject: [PATCH 5/5] Properly align first and last frames with other frames. --- Elements/src/Geometry/Polygon.cs | 4 ++-- Elements/src/Geometry/Polyline.cs | 6 +++--- Elements/test/PolygonTests.cs | 24 ++++++++++++------------ Elements/test/PolylineTests.cs | 25 ++++++++++++++++--------- 4 files changed, 33 insertions(+), 26 deletions(-) diff --git a/Elements/src/Geometry/Polygon.cs b/Elements/src/Geometry/Polygon.cs index dd151f814..54d67bda1 100644 --- a/Elements/src/Geometry/Polygon.cs +++ b/Elements/src/Geometry/Polygon.cs @@ -2113,7 +2113,7 @@ public override Transform[] Frames(double startSetbackDistance = 0.0, int index = 0; if (!startAtVertex) { - var tangent = (Vertices[startIndex] - Vertices[startIndex - 1]).Unitized(); + var tangent = (Vertices[startIndex - 1] - Vertices[startIndex]).Unitized(); result[0] = new Transform(PointAt(startParam), up.Cross(tangent), tangent); index++; } @@ -2128,7 +2128,7 @@ public override Transform[] Frames(double startSetbackDistance = 0.0, if (!endsAtVertex) { var nextIndex = (endIndex + 1) % Vertices.Count; - var tangent = (Vertices[nextIndex] - Vertices[endIndex]).Unitized(); + var tangent = (Vertices[endIndex] - Vertices[nextIndex]).Unitized(); result[index] = new Transform(PointAt(endParam), up.Cross(tangent), tangent); } diff --git a/Elements/src/Geometry/Polyline.cs b/Elements/src/Geometry/Polyline.cs index f4da41793..0af338570 100644 --- a/Elements/src/Geometry/Polyline.cs +++ b/Elements/src/Geometry/Polyline.cs @@ -326,7 +326,7 @@ public override Transform[] Frames(double startSetbackDistance = 0.0, // CreateOrthogonalTransform expects index of previous vertex, that's why index must be adjusted. if (!startAtVertex) { - var tangent = (Vertices[startIndex] - Vertices[startIndex - 1]).Unitized(); + var tangent = (Vertices[startIndex - 1] - Vertices[startIndex]).Unitized(); result[0] = new Transform(PointAt(startParam), normals[startIndex - 1].Cross(tangent), tangent); index++; } @@ -338,7 +338,7 @@ public override Transform[] Frames(double startSetbackDistance = 0.0, if (!endsAtVertex) { - var tangent = (Vertices[endIndex + 1] - Vertices[endIndex]).Unitized(); + var tangent = (Vertices[endIndex] - Vertices[endIndex + 1]).Unitized(); result[index] = new Transform(PointAt(endParam), normals[endIndex].Cross(tangent), tangent); } @@ -416,7 +416,7 @@ private Transform CreateOrthogonalTransform(int i, Vector3 origin, Vector3 up) if (tangent.IsZero()) { tangent = v1; - } + } } tangent = tangent.Negate(); return new Transform(origin, up.Cross(tangent), tangent); diff --git a/Elements/test/PolygonTests.cs b/Elements/test/PolygonTests.cs index 0c4c3e933..13f84bd53 100644 --- a/Elements/test/PolygonTests.cs +++ b/Elements/test/PolygonTests.cs @@ -2221,40 +2221,40 @@ public void Frames() var frames = polygon.Frames(); Assert.Equal(5, frames.Count()); Assert.Equal(polygon.Vertices[0], frames[0].Origin); - Assert.True((Vector3.YAxis - Vector3.XAxis).IsParallelTo(frames[0].ZAxis)); + Assert.True((Vector3.XAxis - Vector3.YAxis).Unitized().Negate().IsAlmostEqualTo(frames[0].ZAxis)); Assert.Equal(polygon.Vertices[1], frames[1].Origin); - Assert.True((Vector3.XAxis + Vector3.YAxis).IsParallelTo(frames[1].ZAxis)); + Assert.True((Vector3.XAxis + Vector3.YAxis).Unitized().Negate().IsAlmostEqualTo(frames[1].ZAxis)); Assert.Equal(polygon.Vertices[2], frames[2].Origin); - Assert.True((Vector3.XAxis - Vector3.YAxis).IsParallelTo(frames[2].ZAxis)); + Assert.True((Vector3.YAxis - Vector3.XAxis).Unitized().Negate().IsAlmostEqualTo(frames[2].ZAxis)); Assert.Equal(polygon.Vertices[3], frames[3].Origin); - Assert.True((Vector3.XAxis + Vector3.YAxis).IsParallelTo(frames[3].ZAxis)); + Assert.True((Vector3.XAxis + Vector3.YAxis).Unitized().IsAlmostEqualTo(frames[3].ZAxis)); Assert.Equal(polygon.Vertices[0], frames[4].Origin); - Assert.True((Vector3.YAxis - Vector3.XAxis).IsParallelTo(frames[4].ZAxis)); + Assert.True((Vector3.XAxis - Vector3.YAxis).Unitized().Negate().IsAlmostEqualTo(frames[4].ZAxis)); frames = polygon.Frames(1, 1); Assert.Equal(5, frames.Count()); Assert.Equal((1, 0), frames[0].Origin); - Assert.True(Vector3.XAxis.IsParallelTo(frames[0].ZAxis)); + Assert.True(Vector3.XAxis.Negate().IsAlmostEqualTo(frames[0].ZAxis)); Assert.Equal((0, 1), frames[4].Origin); - Assert.True(Vector3.YAxis.IsParallelTo(frames[4].ZAxis)); + Assert.True(Vector3.YAxis.IsAlmostEqualTo(frames[4].ZAxis)); frames = polygon.Frames(2, 2); Assert.Equal(3, frames.Count()); Assert.Equal(polygon.Vertices[1], frames[0].Origin); - Assert.True((Vector3.XAxis + Vector3.YAxis).IsParallelTo(frames[0].ZAxis)); + Assert.True((Vector3.XAxis + Vector3.YAxis).Unitized().Negate().IsAlmostEqualTo(frames[0].ZAxis)); Assert.Equal(polygon.Vertices[2], frames[1].Origin); - Assert.True((Vector3.XAxis - Vector3.YAxis).IsParallelTo(frames[1].ZAxis)); + Assert.True((Vector3.YAxis - Vector3.XAxis).Unitized().Negate().IsAlmostEqualTo(frames[1].ZAxis)); Assert.Equal(polygon.Vertices[3], frames[2].Origin); - Assert.True((Vector3.XAxis + Vector3.YAxis).IsParallelTo(frames[2].ZAxis)); + Assert.True((Vector3.XAxis + Vector3.YAxis).Unitized().IsAlmostEqualTo(frames[2].ZAxis)); frames = polygon.Frames(1, 3); Assert.Equal(4, frames.Count()); Assert.Equal((1, 0), frames[0].Origin); Assert.True(Vector3.XAxis.IsParallelTo(frames[0].ZAxis)); Assert.Equal(polygon.Vertices[1], frames[1].Origin); - Assert.True((Vector3.XAxis + Vector3.YAxis).IsParallelTo(frames[1].ZAxis)); + Assert.True((Vector3.XAxis + Vector3.YAxis).Unitized().IsParallelTo(frames[1].ZAxis)); Assert.Equal(polygon.Vertices[2], frames[2].Origin); - Assert.True((Vector3.XAxis - Vector3.YAxis).IsParallelTo(frames[2].ZAxis)); + Assert.True((Vector3.XAxis - Vector3.YAxis).Unitized().IsParallelTo(frames[2].ZAxis)); Assert.Equal((1, 2), frames[3].Origin); Assert.True(Vector3.XAxis.IsParallelTo(frames[3].ZAxis)); } diff --git a/Elements/test/PolylineTests.cs b/Elements/test/PolylineTests.cs index e71a15fe5..645c406f1 100644 --- a/Elements/test/PolylineTests.cs +++ b/Elements/test/PolylineTests.cs @@ -782,29 +782,36 @@ public void Frames() var frames = polyline.Frames(); Assert.Equal(4, frames.Count()); Assert.Equal(polyline.Vertices[0], frames[0].Origin); - Assert.True(Vector3.XAxis.IsParallelTo(frames[0].ZAxis)); + Assert.True(Vector3.XAxis.Negate().IsAlmostEqualTo(frames[0].ZAxis)); Assert.Equal(polyline.Vertices[1], frames[1].Origin); - Assert.True((Vector3.XAxis + Vector3.YAxis).IsParallelTo(frames[1].ZAxis)); + Assert.True((Vector3.XAxis + Vector3.YAxis).Unitized().Negate().IsAlmostEqualTo(frames[1].ZAxis)); Assert.Equal(polyline.Vertices[2], frames[2].Origin); - Assert.True((Vector3.XAxis - Vector3.YAxis).IsParallelTo(frames[2].ZAxis)); + Assert.True((Vector3.YAxis - Vector3.XAxis).Unitized().Negate().IsAlmostEqualTo(frames[2].ZAxis)); Assert.Equal(polyline.Vertices[3], frames[3].Origin); - Assert.True(Vector3.XAxis.IsParallelTo(frames[3].ZAxis)); + Assert.True(Vector3.XAxis.IsAlmostEqualTo(frames[3].ZAxis)); + + frames = polyline.Frames(1, 1); + Assert.Equal(4, frames.Count()); + Assert.Equal((1, 0), frames[0].Origin); + Assert.True(Vector3.XAxis.Negate().IsAlmostEqualTo(frames[0].ZAxis)); + Assert.Equal((1, 2), frames[3].Origin); + Assert.True(Vector3.XAxis.IsAlmostEqualTo(frames[3].ZAxis)); frames = polyline.Frames(2, 2); Assert.Equal(2, frames.Count()); Assert.Equal(polyline.Vertices[1], frames[0].Origin); - Assert.True((Vector3.XAxis + Vector3.YAxis).IsParallelTo(frames[0].ZAxis)); + Assert.True((Vector3.XAxis + Vector3.YAxis).Unitized().Negate().IsAlmostEqualTo(frames[0].ZAxis)); Assert.Equal(polyline.Vertices[2], frames[1].Origin); - Assert.True((Vector3.XAxis - Vector3.YAxis).IsParallelTo(frames[1].ZAxis)); + Assert.True((Vector3.YAxis - Vector3.XAxis).Unitized().Negate().IsAlmostEqualTo(frames[1].ZAxis)); frames = polyline.Frames(1, 3); Assert.Equal(3, frames.Count()); Assert.Equal((1, 0), frames[0].Origin); - Assert.True(Vector3.XAxis.IsParallelTo(frames[0].ZAxis)); + Assert.True(Vector3.XAxis.Negate().IsAlmostEqualTo(frames[0].ZAxis)); Assert.Equal(polyline.Vertices[1], frames[1].Origin); - Assert.True((Vector3.XAxis + Vector3.YAxis).IsParallelTo(frames[1].ZAxis)); + Assert.True((Vector3.XAxis + Vector3.YAxis).Unitized().Negate().IsAlmostEqualTo(frames[1].ZAxis)); Assert.Equal((2, 1), frames[2].Origin); - Assert.True(Vector3.YAxis.IsParallelTo(frames[2].ZAxis)); + Assert.True(Vector3.YAxis.Negate().IsAlmostEqualTo(frames[2].ZAxis)); } } } \ No newline at end of file