From 03918f8a4b52c684046fcce6851890fef403b32c Mon Sep 17 00:00:00 2001 From: Mirco Bianchini Date: Sat, 11 Sep 2021 15:36:27 +1000 Subject: [PATCH 1/2] Circle inheritance NurbsBase. --- src/GShark.Test.XUnit/Geometry/ArcTests.cs | 4 +- src/GShark.Test.XUnit/Geometry/CircleTests.cs | 2 +- .../Geometry/NurbsCurveTests.cs | 4 +- src/GShark/Geometry/Arc.cs | 2 + src/GShark/Geometry/Circle.cs | 55 +++++++++++++------ src/GShark/Geometry/NurbsBase.cs | 2 +- src/GShark/Geometry/PolyCurve.cs | 25 +++------ 7 files changed, 56 insertions(+), 38 deletions(-) diff --git a/src/GShark.Test.XUnit/Geometry/ArcTests.cs b/src/GShark.Test.XUnit/Geometry/ArcTests.cs index a035d773..8bdcd032 100644 --- a/src/GShark.Test.XUnit/Geometry/ArcTests.cs +++ b/src/GShark.Test.XUnit/Geometry/ArcTests.cs @@ -123,7 +123,7 @@ public void It_Is_A_Curve_Representation_Of_The_Arc_From_0_To_90_Deg() }; // Act - NurbsBase arc = new Arc(Plane.PlaneYZ, 20, new Interval(0.0, 1.8)).ToNurbs(); + NurbsBase arc = new Arc(Plane.PlaneYZ, 20, new Interval(0.0, 1.8)); // Assert arc.ControlPointLocations.Count.Should().Be(5); @@ -162,7 +162,7 @@ public void It_Is_A_Curve_Representation_Of_ExampleArc3D() }; // Act - NurbsBase arc = _exampleArc3D.ToNurbs(); + NurbsBase arc = _exampleArc3D; // Assert arc.ControlPointLocations.Count.Should().Be(7); diff --git a/src/GShark.Test.XUnit/Geometry/CircleTests.cs b/src/GShark.Test.XUnit/Geometry/CircleTests.cs index d2a50932..8178bf18 100644 --- a/src/GShark.Test.XUnit/Geometry/CircleTests.cs +++ b/src/GShark.Test.XUnit/Geometry/CircleTests.cs @@ -67,7 +67,7 @@ public void It_Returns_A_Circle3D_With_Its_Nurbs_Representation() }; // Act - NurbsBase circleNurbs = _circle3D.ToNurbs(); + NurbsBase circleNurbs = _circle3D; // Assert circleNurbs.Knots.GetDomain(circleNurbs.Degree).Length.Should().Be(1.0); diff --git a/src/GShark.Test.XUnit/Geometry/NurbsCurveTests.cs b/src/GShark.Test.XUnit/Geometry/NurbsCurveTests.cs index 36d219a8..ebc7e675 100644 --- a/src/GShark.Test.XUnit/Geometry/NurbsCurveTests.cs +++ b/src/GShark.Test.XUnit/Geometry/NurbsCurveTests.cs @@ -332,7 +332,7 @@ public void Returns_A_Curve_Joining_Different_Types_Of_Curves() NurbsCurve curve = new NurbsCurve(pts, degree); Line ln = new Line(new Point3(5, 5, 0), new Point3(5, 5, -2.5)); Arc arc = Arc.ByStartEndDirection(new Point3(5, 5, -2.5), new Point3(10, 5, -5), new Vector3(0, 0, -1)); - NurbsBase[] curves = { ln, arc.ToNurbs(), curve }; + NurbsBase[] curves = { ln, arc, curve }; Point3 expectedPt1 = new Point3(5, 3.042501, 4.519036); Point3 expectedPt2 = new Point3(5, 5, -1.230175); @@ -407,7 +407,7 @@ public void Returns_A_Curve_Joining_Polylines_And_Arc() }); Arc arc = Arc.ByStartEndDirection(new Point3(5, 5, -2.5), new Point3(10, 5, -5), new Vector3(0, 0, -1)); - NurbsBase[] curves = { poly, arc.ToNurbs() }; + NurbsBase[] curves = { poly, arc }; Point3 expectedPt1 = new Point3(5, 0, 2.928932); Point3 expectedPt2 = new Point3(5, 4.428932, 5); diff --git a/src/GShark/Geometry/Arc.cs b/src/GShark/Geometry/Arc.cs index a943d538..35e5ce15 100644 --- a/src/GShark/Geometry/Arc.cs +++ b/src/GShark/Geometry/Arc.cs @@ -33,6 +33,7 @@ public Arc(Plane plane, double radius, Interval angleDomainRadians) : base(plane AngularDiff(angleDomainRadians.T1, Math.PI * 2.0)) : angleDomainRadians; _length = Math.Abs(Angle * Radius); + ToNurbs(); } /// @@ -64,6 +65,7 @@ public Arc(Point3 pt1, Point3 pt2, Point3 pt3) : base(pt1, pt2, pt3) _domain = new Interval(0.0, angle); _length = Math.Abs(Angle * Radius); + ToNurbs(); } /// diff --git a/src/GShark/Geometry/Circle.cs b/src/GShark/Geometry/Circle.cs index 1a09a3c1..b5013511 100644 --- a/src/GShark/Geometry/Circle.cs +++ b/src/GShark/Geometry/Circle.cs @@ -2,6 +2,7 @@ using GShark.Interfaces; using GShark.Intersection; using System; +using System.ComponentModel; using System.Linq; namespace GShark.Geometry @@ -13,7 +14,7 @@ namespace GShark.Geometry /// /// [!code-csharp[Example](../../src/GShark.Test.XUnit/Geometry/CircleTests.cs?name=example)] /// - public class Circle : ICurve, IEquatable, ITransformable + public class Circle : NurbsBase, IEquatable, ITransformable { internal Interval _domain = new Interval(0.0, 2.0 * Math.PI); internal double _length; @@ -28,6 +29,7 @@ public Circle(Plane plane, double radius) Plane = plane; Radius = Math.Abs(radius); _length = Math.Abs(2.0 * Math.PI * radius); + ToNurbs(); } /// @@ -69,6 +71,7 @@ public Circle(Point3 pt1, Point3 pt2, Point3 pt3) Plane = new Plane(center, xDir, yDir); Radius = xDir.Length; _length = Math.Abs(2.0 * Math.PI * Radius); + ToNurbs(); } /// @@ -94,27 +97,27 @@ public Circle(Point3 pt1, Point3 pt2, Point3 pt3) /// /// Gets the circumference of the circular curve. /// - public double Length => _length; + public override double Length => _length; /// /// Gets the start point of the circular curve. /// - public Point3 StartPoint => PointAt(0.0); + public override Point3 StartPoint => PointAt(0.0); /// /// Gets the mid-point of the circular curve. /// - public Point3 MidPoint => PointAt(_domain.Mid); + public override Point3 MidPoint => PointAt(_domain.Mid); /// /// Gets the end point of the circular curve. /// - public Point3 EndPoint => PointAt(_domain.T1); + public override Point3 EndPoint => PointAt(_domain.T1); /// /// Gets the bounding box of this circular curve. /// - public virtual BoundingBox GetBoundingBox() + public override BoundingBox GetBoundingBox() { double val1 = Radius * SelectionLength(Plane.ZAxis[1], Plane.ZAxis[2]); double val2 = Radius * SelectionLength(Plane.ZAxis[2], Plane.ZAxis[0]); @@ -138,7 +141,7 @@ public virtual BoundingBox GetBoundingBox() /// Parameter to evaluate derivative. A parameter between 0.0 and angle domain in radians. /// Which order of derivative is wanted. Valid values are 0,1,2,3. /// The derivative of the circle at the given parameter. - public Vector3 DerivativeAt(double t, int derivative = 0) + public new Vector3 DerivativeAt(double t, int derivative = 0) { if (t < 0.0) { @@ -180,7 +183,7 @@ public Vector3 DerivativeAt(double t, int derivative = 0) /// /// A parameter between 0.0 and angle domain in radians.> /// Point on the circular curve. - public Point3 PointAt(double t) + public override Point3 PointAt(double t) { if (t < 0.0) { @@ -200,7 +203,7 @@ public Point3 PointAt(double t) /// /// The length where to evaluate the point. /// The point at the length. - public Point3 PointAtLength(double length) + public override Point3 PointAtLength(double length) { if (length <= 0.0) { @@ -225,7 +228,7 @@ public Point3 PointAtLength(double length) /// /// The length factor is normalized between 0.0 and 1.0. /// The point at the length. - public Point3 PointAtNormalizedLength(double normalizedLength) + public override Point3 PointAtNormalizedLength(double normalizedLength) { double theta = _domain.T0 + (_domain.T1 - _domain.T0) * normalizedLength; return PointAt(theta); @@ -236,7 +239,7 @@ public Point3 PointAtNormalizedLength(double normalizedLength) /// /// A parameter between 0.0 and angle domain in radians. /// Unitized tangent vector at the parameter. - public Vector3 TangentAt(double t) + public override Vector3 TangentAt(double t) { if (t <= 0.0) { @@ -270,7 +273,7 @@ public Vector3 TangentAtLength(double length) /// /// A parameter between 0.0 and angle domain in radians. /// The curve length at t. - public double LengthAt(double t) + public override double LengthAt(double t) { if (t <= 0) { @@ -290,7 +293,7 @@ public double LengthAt(double t) /// /// The test point to project onto the circular curve. /// The point on the circular curve that is close to the test point. - public Point3 ClosestPoint(Point3 pt) + public override Point3 ClosestPoint(Point3 pt) { (double u, double v) = Plane.ClosestParameters(pt); if (Math.Abs(u) < GSharkMath.MinTolerance && Math.Abs(v) < GSharkMath.MinTolerance) @@ -308,7 +311,7 @@ public Point3 ClosestPoint(Point3 pt) /// /// The test point to project onto the circular curve. /// The parameter on the circular curve that is close to the test point. - public double ClosestParameter(Point3 pt) + public override double ClosestParameter(Point3 pt) { (double u, double v) = Plane.ClosestParameters(pt); if (Math.Abs(u) < GSharkMath.MinTolerance && Math.Abs(v) < GSharkMath.MinTolerance) @@ -339,35 +342,45 @@ public Circle Offset(double distance) /// Implementation of Algorithm A7.1 from The NURBS Book by Piegl and Tiller. /// /// A nurbs curve shaped like this arc. - public NurbsCurve ToNurbs() + internal void ToNurbs() { Vector3 axisX = Plane.XAxis; Vector3 axisY = Plane.YAxis; double curveAngle = _domain.Length; int numberOfArc; + Point3[] pts; Point4[] ctrPts; + double[] weights; // Number of arcs. double piNum = 0.5 * Math.PI; if ((curveAngle - piNum) <= GSharkMath.Epsilon) { numberOfArc = 1; + pts = new Point3[3]; ctrPts = new Point4[3]; + weights = new double[3]; } else if ((curveAngle - piNum * 2) <= GSharkMath.Epsilon) { numberOfArc = 2; + pts = new Point3[5]; ctrPts = new Point4[5]; + weights = new double[5]; } else if ((curveAngle - piNum * 3) <= GSharkMath.Epsilon) { numberOfArc = 3; + pts = new Point3[7]; ctrPts = new Point4[7]; + weights = new double[7]; } else { numberOfArc = 4; + pts = new Point3[9]; ctrPts = new Point4[9]; + weights = new double[9]; } double detTheta = curveAngle / numberOfArc; @@ -379,7 +392,9 @@ public NurbsCurve ToNurbs() int index = 0; double angle = _domain.T0; + pts[0] = p0; ctrPts[0] = new Point4(p0); + weights[0] = weight; for (int i = 1; i < numberOfArc + 1; i++) { @@ -387,6 +402,8 @@ public NurbsCurve ToNurbs() Point3 p2 = Center + (axisX * (Radius * Math.Cos(angle)) + axisY * (Radius * Math.Sin(angle))); ctrPts[index + 2] = new Point4(p2); + pts[index + 2] = p2; + weights[index + 2] = 1.0; Vector3 t2 = (axisY * Math.Cos(angle)) - (axisX * Math.Sin(angle)); Line ln0 = new Line(p0, t0.Unitize() + p0); @@ -395,6 +412,8 @@ public NurbsCurve ToNurbs() Point3 p1 = p0 + (t0 * u0); ctrPts[index + 1] = new Point4(p1, weight); + pts[index + 1] = p1; + weights[index + 1] = weight; index += 2; if (i >= numberOfArc) @@ -429,7 +448,11 @@ public NurbsCurve ToNurbs() break; } - return new NurbsCurve(2, knots, ctrPts.ToList()); + Weights = weights.ToList(); + Degree = 2; + Knots = knots; + ControlPoints = ctrPts.ToList(); + ControlPointLocations = pts.ToList(); } /// diff --git a/src/GShark/Geometry/NurbsBase.cs b/src/GShark/Geometry/NurbsBase.cs index 095dcc21..24ea57ec 100644 --- a/src/GShark/Geometry/NurbsBase.cs +++ b/src/GShark/Geometry/NurbsBase.cs @@ -215,7 +215,7 @@ public virtual Point3 PointAtNormalizedLength(double normalizedLength) /// /// The parameter to sample the curve. Parameter should be between 0.0 and 1.0. /// The unitized tangent vector at the given parameter. - public Vector3 TangentAt(double t) + public virtual Vector3 TangentAt(double t) { if (t <= 0.0) { diff --git a/src/GShark/Geometry/PolyCurve.cs b/src/GShark/Geometry/PolyCurve.cs index 7f0c1b27..307c2608 100644 --- a/src/GShark/Geometry/PolyCurve.cs +++ b/src/GShark/Geometry/PolyCurve.cs @@ -16,9 +16,7 @@ namespace GShark.Geometry /// public class PolyCurve : NurbsBase { - private readonly List _segments = new List(); - // ToDo: this list will be removed after all the other curve will inheritance from NurbsBase. - private readonly List _segmentsNurbs = new List(); + private readonly List _segments = new List(); /// /// Initializes a new empty polyCurve. @@ -35,7 +33,6 @@ public void Append(Line line) { HealthChecks(line); _segments.Add(line); - _segmentsNurbs.Add(line); ToNurbsForm(); } @@ -48,7 +45,6 @@ public void Append(Arc arc) { HealthChecks(arc); _segments.Add(arc); - _segmentsNurbs.Add(arc.ToNurbs()); ToNurbsForm(); } @@ -65,7 +61,6 @@ public void Append(NurbsCurve curve) } HealthChecks(curve); _segments.Add(curve); - _segmentsNurbs.Add(curve); ToNurbsForm(); } @@ -82,7 +77,6 @@ public void Append(PolyCurve polyCurve) } HealthChecks(polyCurve); _segments.Add(polyCurve); - _segmentsNurbs.Add(polyCurve); ToNurbsForm(); } @@ -94,14 +88,13 @@ public void Append(PolyCurve polyCurve) internal void Append(List curves) { _segments.AddRange(curves); - _segmentsNurbs.AddRange(curves); ToNurbsForm(); } /// /// The segments of the polyCurve. /// - public List Segments => _segments; + public List Segments => _segments; /// /// Defines the NURBS form of the polyline. @@ -110,19 +103,19 @@ private void ToNurbsForm() { if (_segments.Count == 1) { - Weights = Point4.GetWeights(_segmentsNurbs[0].ControlPoints); - Degree = _segmentsNurbs[0].Degree; - Knots = _segmentsNurbs[0].Knots; - ControlPointLocations = Point4.PointDehomogenizer1d(_segmentsNurbs[0].ControlPoints); - ControlPoints = _segmentsNurbs[0].ControlPoints; + Weights = Point4.GetWeights(_segments[0].ControlPoints); + Degree = _segments[0].Degree; + Knots = _segments[0].Knots; + ControlPointLocations = Point4.PointDehomogenizer1d(_segments[0].ControlPoints); + ControlPoints = _segments[0].ControlPoints; return; } // Extract the biggest degree between the curves. - int finalDegree = _segmentsNurbs.Max(c => c.Degree); + int finalDegree = _segments.Max(c => c.Degree); // Homogenized degree curves. - IEnumerable homogenizedCurves = _segmentsNurbs.Select(curve => curve.Degree != finalDegree ? Modify.Curve.ElevateDegree(curve, finalDegree) : curve); + IEnumerable homogenizedCurves = _segments.Select(curve => curve.Degree != finalDegree ? Modify.Curve.ElevateDegree(curve, finalDegree) : curve); // Join curves. List joinedKnots = new List(); From 22b116d13d1ceefa12171efee8cdba3cb8b03c82 Mon Sep 17 00:00:00 2001 From: Mirco Bianchini Date: Sat, 11 Sep 2021 15:37:49 +1000 Subject: [PATCH 2/2] Removed ICurve interface. --- src/GShark/Geometry/NurbsBase.cs | 3 +- src/GShark/Geometry/PolyCurve.cs | 2 +- src/GShark/Interfaces/ICurve.cs | 67 -------------------------------- 3 files changed, 2 insertions(+), 70 deletions(-) delete mode 100644 src/GShark/Interfaces/ICurve.cs diff --git a/src/GShark/Geometry/NurbsBase.cs b/src/GShark/Geometry/NurbsBase.cs index 24ea57ec..44be666f 100644 --- a/src/GShark/Geometry/NurbsBase.cs +++ b/src/GShark/Geometry/NurbsBase.cs @@ -1,7 +1,6 @@ #nullable enable using GShark.Core; using GShark.ExtendedMethods; -using GShark.Interfaces; using GShark.Operation.Utilities; using System; using System.Collections.Generic; @@ -14,7 +13,7 @@ namespace GShark.Geometry /// /// This class represents a base class that is common to most curve types. /// - public abstract class NurbsBase : ICurve, IEquatable + public abstract class NurbsBase : IEquatable { protected NurbsBase() { diff --git a/src/GShark/Geometry/PolyCurve.cs b/src/GShark/Geometry/PolyCurve.cs index 307c2608..8fc86ef8 100644 --- a/src/GShark/Geometry/PolyCurve.cs +++ b/src/GShark/Geometry/PolyCurve.cs @@ -143,7 +143,7 @@ private void ToNurbsForm() /// /// Checks to define if the curve can be appended to the polycurve. /// - private void HealthChecks(ICurve curve) + private void HealthChecks(NurbsBase curve) { if (_segments.Count <= 0) return; diff --git a/src/GShark/Interfaces/ICurve.cs b/src/GShark/Interfaces/ICurve.cs deleted file mode 100644 index f5ee9a9a..00000000 --- a/src/GShark/Interfaces/ICurve.cs +++ /dev/null @@ -1,67 +0,0 @@ -using GShark.Geometry; - -namespace GShark.Interfaces -{ - public interface ICurve - { - /// - /// Gets the length of the curve. - /// - public double Length { get; } - - /// - /// Gets the starting point of the curve. - /// - public Point3 StartPoint { get; } - - /// - /// Gets the middle point of the curve. - /// - public Point3 MidPoint { get; } - - /// - /// Gets the end point of the curve. - /// - public Point3 EndPoint { get; } - - /// - /// Gets the bounding box of the curve. - /// - public BoundingBox GetBoundingBox(); - - /// - /// Evaluates the length at the parameter t on the curve. - /// - /// Evaluation parameter. Parameter should be between 0.0 and 1.0. - /// The length of the curve coincides at the given parameter. - public double LengthAt(double t); - - /// - /// Evaluates the point at the parameter t on the curve. - /// - /// Evaluation parameter. Parameter should be between 0.0 and 1.0. - /// The point on the curve at the given parameter. - public Point3 PointAt(double t); - - /// - /// Evaluates the point at a certain length along the curve. - /// - /// Length along the curve between the start point and the returned point. - /// The point on the curve at the given length. - public Point3 PointAtLength(double length); - - /// - /// Evaluates the closest point on the curve that is close to the test point. - /// - /// The test point. - /// The closest point. - public Point3 ClosestPoint(Point3 pt); - - /// - /// Evaluates the closest parameter on the curve that is close to the test point. - /// - /// The test point. - /// The closest parameter between 0.0 and 1.0. - public double ClosestParameter(Point3 pt); - } -}