diff --git a/CADability.Forms/GdiExtensions.cs b/CADability.Forms/GdiExtensions.cs
new file mode 100644
index 00000000..29fe5851
--- /dev/null
+++ b/CADability.Forms/GdiExtensions.cs
@@ -0,0 +1,184 @@
+using CADability.Curve2D;
+using CADability.Shapes;
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+
+namespace CADability.Forms
+{
+ ///
+ /// Converts CADability geometry to GDI+ (, ). These conversions used to be
+ /// members of the geometry types in the kernel (, ,
+ /// , ). GDI+ is only available on Windows, so they
+ /// live here, next to the other WinForms code, and the kernel stays platform independent (issue #412).
+ ///
+ public static class GdiExtensions
+ {
+ ///
+ /// Appends to . Lines, arcs and circles are added exactly, ellipses and
+ /// B-splines as an approximation through points on the curve.
+ ///
+ /// The graphics path to append to
+ /// The curve to add
+ /// true: add in the direction of the curve, false: add reversed
+ public static void AddCurve2D(this GraphicsPath path, ICurve2D curve, bool forward)
+ {
+ // Exact type checks: a derived class may have overridden the obsolete ICurve2D.AddToGraphicsPath.
+ Type type = curve.GetType();
+ if (type == typeof(Line2D)) AddLine(path, (Line2D)curve, forward);
+ else if (type == typeof(Arc2D)) AddArc(path, (Arc2D)curve, forward);
+ else if (type == typeof(Circle2D)) AddCircle(path, (Circle2D)curve, forward);
+ else if (type == typeof(EllipseArc2D)) AddEllipseArc(path, (EllipseArc2D)curve, forward);
+ else if (type == typeof(Ellipse2D)) AddEllipse(path, (Ellipse2D)curve, forward);
+ else if (type == typeof(Polyline2D)) AddPolyline(path, (Polyline2D)curve, forward);
+ else if (type == typeof(BSpline2D)) AddBSpline(path, (BSpline2D)curve, forward);
+ else if (type == typeof(Path2D)) AddPath(path, (Path2D)curve, forward);
+ else
+ {
+ // Other curves keep their own implementation as long as the kernel has it (1.x).
+#pragma warning disable CS0618 // Type or member is obsolete
+ curve.AddToGraphicsPath(path, forward);
+#pragma warning restore CS0618
+ }
+ }
+ ///
+ /// Appends the segments of to , e.g. for filling or clipping with
+ /// System.Drawing. With false the segments are added in reverse order and direction,
+ /// which is how adds the holes so that they stay unfilled.
+ ///
+ /// The graphics path to append to
+ /// The border to add
+ /// true: add in the direction of the border, false: add reversed
+ public static void AddBorder(this GraphicsPath path, Border border, bool counterClockWise)
+ {
+ if (counterClockWise)
+ {
+ for (int i = 0; i < border.Count; ++i) path.AddCurve2D(border[i], true);
+ }
+ else
+ {
+ for (int i = border.Count - 1; i >= 0; --i) path.AddCurve2D(border[i], false);
+ }
+ }
+ ///
+ /// Appends to : the outline counterclockwise and the holes clockwise, so
+ /// filling the path leaves the holes empty.
+ ///
+ /// The graphics path to append to
+ /// The shape to add
+ public static void AddShape(this GraphicsPath path, SimpleShape shape)
+ {
+ path.AddBorder(shape.Outline, true);
+ Border[] holes = shape.Holes;
+ for (int i = 0; i < holes.Length; ++i) path.AddBorder(holes[i], false);
+ }
+ ///
+ /// Appends all parts of to , see .
+ ///
+ /// The graphics path to append to
+ /// The shape to add
+ public static void AddShape(this GraphicsPath path, CompoundShape shape)
+ {
+ SimpleShape[] simpleShapes = shape.SimpleShapes;
+ for (int i = 0; i < simpleShapes.Length; ++i) path.AddShape(simpleShapes[i]);
+ }
+ ///
+ /// Converts to a new for drawing or clipping with System.Drawing,
+ /// see .
+ ///
+ /// The shape to convert
+ /// The graphics path
+ public static GraphicsPath ToGraphicsPath(this CompoundShape shape)
+ {
+ GraphicsPath res = new GraphicsPath();
+ res.AddShape(shape);
+ return res;
+ }
+ ///
+ /// Converts to a GDI+ with the same coefficients (in single precision), e.g. to
+ /// apply it when drawing with GDI+.
+ ///
+ /// The modification to convert
+ /// The equivalent matrix
+ public static Matrix ToGdiMatrix(this ModOp2D m)
+ {
+ return new Matrix((float)m[0, 0], (float)m[1, 0], (float)m[0, 1], (float)m[1, 1], (float)m[0, 2], (float)m[1, 2]);
+ }
+
+ private static void AddLine(GraphicsPath path, Line2D line, bool forward)
+ {
+ GeoPoint2D sp = forward ? line.StartPoint : line.EndPoint;
+ GeoPoint2D ep = forward ? line.EndPoint : line.StartPoint;
+ path.AddLine((float)sp.x, (float)sp.y, (float)ep.x, (float)ep.y);
+ }
+ private static void AddArc(GraphicsPath path, Arc2D arc, bool forward)
+ {
+ Angle start = arc.StartParameter;
+ SweepAngle sweep = arc.SweepAngle;
+ float startDegree = (float)(forward ? start.Degree : (start + sweep).Degree);
+ float sweepDegree = (float)(forward ? sweep.Degree : -sweep.Degree);
+ path.AddArc((float)(arc.Center.x - arc.Radius), (float)(arc.Center.y - arc.Radius), (float)(2 * arc.Radius), (float)(2 * arc.Radius),
+ startDegree, sweepDegree);
+ }
+ private static void AddCircle(GraphicsPath path, Circle2D circle, bool forward)
+ {
+ // AddArc and not AddEllipse, so that the direction is kept, which matters for FillMode.Winding
+ path.AddArc((float)(circle.Center.x - circle.Radius), (float)(circle.Center.y - circle.Radius), (float)(2 * circle.Radius), (float)(2 * circle.Radius),
+ 0.0f, forward ? 360.0f : -360.0f);
+ }
+ private static void AddEllipse(GraphicsPath path, Ellipse2D ellipse, bool forward)
+ {
+ AddCurveThroughPoints(path, ellipse, 36, forward);
+ }
+ private static void AddEllipseArc(GraphicsPath path, EllipseArc2D ellipseArc, bool forward)
+ {
+ // about one point every 10°
+ int n = (int)Math.Round(Math.Abs(ellipseArc.axisSweep) / Math.PI * 18);
+ AddCurveThroughPoints(path, ellipseArc, Math.Max(n, 2), forward);
+ }
+ private static void AddCurveThroughPoints(GraphicsPath path, ICurve2D curve, int n, bool forward)
+ {
+ PointF[] points = new PointF[n + 1];
+ double step = 1.0 / n;
+ for (int i = 0; i < n; ++i) points[i] = curve.PointAt(i * step).PointF;
+ points[n] = curve.PointAt(1.0).PointF;
+ if (!forward) Array.Reverse(points);
+ path.AddCurve(points);
+ }
+ private static void AddPolyline(GraphicsPath path, Polyline2D polyline, bool forward)
+ {
+ GeoPoint2D[] vertex = polyline.Vertex;
+ if (forward)
+ {
+ for (int i = 1; i < vertex.Length; ++i)
+ path.AddLine((float)vertex[i - 1].x, (float)vertex[i - 1].y, (float)vertex[i].x, (float)vertex[i].y);
+ }
+ else
+ {
+ for (int i = vertex.Length - 1; i > 0; --i)
+ path.AddLine((float)vertex[i].x, (float)vertex[i].y, (float)vertex[i - 1].x, (float)vertex[i - 1].y);
+ }
+ }
+ private static void AddBSpline(GraphicsPath path, BSpline2D bspline, bool forward)
+ {
+ // a polyline through points on the curve, four per pole
+ int n = bspline.Poles.Length * 4 + 2;
+ PointF[] points = new PointF[n];
+ for (int i = 0; i < n; ++i) points[i] = bspline.PointAt((double)i / (n - 1)).PointF;
+ if (!forward) Array.Reverse(points);
+ path.AddLines(points);
+ }
+ private static void AddPath(GraphicsPath path, Path2D path2D, bool forward)
+ {
+ ICurve2D[] subCurves = path2D.SubCurves;
+ if (forward)
+ {
+ for (int i = 0; i < subCurves.Length; ++i) path.AddCurve2D(subCurves[i], true);
+ }
+ else
+ {
+ for (int i = subCurves.Length - 1; i >= 0; --i) path.AddCurve2D(subCurves[i], false);
+ }
+ }
+ }
+}
diff --git a/CADability.Forms/PaintToGDI.cs b/CADability.Forms/PaintToGDI.cs
index 6f16beaa..3d093649 100644
--- a/CADability.Forms/PaintToGDI.cs
+++ b/CADability.Forms/PaintToGDI.cs
@@ -866,7 +866,7 @@ void IPaintTo3D.Arc(GeoPoint center, GeoVector majorAxis, GeoVector minorAxis, d
}
try
{
- Matrix r = fromHorizontal.Matrix2D;
+ Matrix r = fromHorizontal.ToGdiMatrix();
double maxRad = prmaj2D.Length;
double minRad = prmin2D.Length;
if ((maxRad + minRad) * Projection.WorldToDeviceFactor < 1)
diff --git a/CADability/Arc2D.cs b/CADability/Arc2D.cs
index 1584b61e..77957211 100644
--- a/CADability/Arc2D.cs
+++ b/CADability/Arc2D.cs
@@ -621,6 +621,7 @@ public override double MinDistance(ICurve2D Other)
return base.MinDistance(Other); // dort wird gleichermaßen für Bogen und Kreis gerechnet
}
///
+ [Obsolete("Use the GraphicsPath extension AddCurve2D of CADability.Forms.GdiExtensions instead. GDI+ leaves the kernel in CADability 2.0, see issue #412.")]
public override void AddToGraphicsPath(System.Drawing.Drawing2D.GraphicsPath path, bool forward)
{
if (forward)
diff --git a/CADability/BSpline2D.cs b/CADability/BSpline2D.cs
index 010a2975..61bf8b44 100644
--- a/CADability/BSpline2D.cs
+++ b/CADability/BSpline2D.cs
@@ -1663,15 +1663,15 @@ public override double Sweep
}
}
///
+ [Obsolete("Use the GraphicsPath extension AddCurve2D of CADability.Forms.GdiExtensions instead. GDI+ leaves the kernel in CADability 2.0, see issue #412.")]
public override void AddToGraphicsPath(System.Drawing.Drawing2D.GraphicsPath path, bool forward)
{
// Notfalls Darstellung als Polyline
int l = poles.Length * 4 + 2;
PointF[] ppf = new PointF[l];
- double du = (endParam - startParam) / (l - 1);
for (int i = 0; i < l; ++i)
{
- ppf[i] = PointAt(startParam + i * du).PointF;
+ ppf[i] = PointAt((double)i / (l - 1)).PointF; // PointAt expects 0..1, not the knot parameter
}
if (!forward) Array.Reverse(ppf);
path.AddLines(ppf);
diff --git a/CADability/Bitmap.cs b/CADability/Bitmap.cs
index 7f922863..9f8f00a6 100644
--- a/CADability/Bitmap.cs
+++ b/CADability/Bitmap.cs
@@ -223,7 +223,9 @@ public void Clip(Plane plane, CompoundShape shape)
prsh = prsh.GetModified(m);
m = ModOp2D.Translate(0, bitmap.Height);
prsh = prsh.GetModified(m);
+#pragma warning disable CS0618 // Picture moves away from GDI+ in issue #412, step 7
GraphicsPath gp = prsh.CreateGraphicsPath();
+#pragma warning restore CS0618
using (new Changing(this))
{
Region rg = new Region(gp);
diff --git a/CADability/Border.cs b/CADability/Border.cs
index 55fd8307..b8d581f8 100644
--- a/CADability/Border.cs
+++ b/CADability/Border.cs
@@ -3904,6 +3904,7 @@ internal void Trimm(int firstIndex, int lastIndex)
///
/// The graphics path to append to
/// true: add in the direction of the border, false: add reversed
+ [Obsolete("Use the GraphicsPath extension AddBorder of CADability.Forms.GdiExtensions instead. GDI+ leaves the kernel in CADability 2.0, see issue #412.")]
public void AddToGraphicsPath(System.Drawing.Drawing2D.GraphicsPath path, bool counterClockWise)
{
if (counterClockWise)
diff --git a/CADability/Circle2D.cs b/CADability/Circle2D.cs
index 3a29185b..f88c86ae 100644
--- a/CADability/Circle2D.cs
+++ b/CADability/Circle2D.cs
@@ -496,6 +496,7 @@ public override ICurve2D Project(Plane fromPlane, Plane toPlane)
return e.GetProjectedCurve(toPlane);
}
///
+ [Obsolete("Use the GraphicsPath extension AddCurve2D of CADability.Forms.GdiExtensions instead. GDI+ leaves the kernel in CADability 2.0, see issue #412.")]
public override void AddToGraphicsPath(System.Drawing.Drawing2D.GraphicsPath path, bool forward)
{ // forward oder nicht ist doch egal, oder?
// im Modus "System.Drawing.Drawing2D.FillMode.Alternate" scheint es egal zu sein,
diff --git a/CADability/DualSurfaceCurve.cs b/CADability/DualSurfaceCurve.cs
index ecc37e02..6e825c8b 100644
--- a/CADability/DualSurfaceCurve.cs
+++ b/CADability/DualSurfaceCurve.cs
@@ -499,6 +499,7 @@ ICurve2D ICurve2D.Project(Plane fromPlane, Plane toPlane)
{
return theCurve.Project(fromPlane, toPlane);
}
+ [Obsolete("Use the GraphicsPath extension AddCurve2D of CADability.Forms.GdiExtensions instead. GDI+ leaves the kernel in CADability 2.0, see issue #412.")]
void ICurve2D.AddToGraphicsPath(System.Drawing.Drawing2D.GraphicsPath path, bool forward)
{
theCurve.AddToGraphicsPath(path, forward);
diff --git a/CADability/Ellipse2D.cs b/CADability/Ellipse2D.cs
index d4c623c4..1623c26c 100644
--- a/CADability/Ellipse2D.cs
+++ b/CADability/Ellipse2D.cs
@@ -807,6 +807,7 @@ public override void Move(double dx, double dy)
Recalc();
}
///
+ [Obsolete("Use the GraphicsPath extension AddCurve2D of CADability.Forms.GdiExtensions instead. GDI+ leaves the kernel in CADability 2.0, see issue #412.")]
public override void AddToGraphicsPath(System.Drawing.Drawing2D.GraphicsPath path, bool forward)
{
// aus dem Bogen übernommen, evtl besser in Kreisbögen zerlegen...
diff --git a/CADability/EllipseArc2D.cs b/CADability/EllipseArc2D.cs
index ce132918..a17b33f0 100644
--- a/CADability/EllipseArc2D.cs
+++ b/CADability/EllipseArc2D.cs
@@ -598,6 +598,7 @@ public override double MinDistance(GeoPoint2D p)
return res;
}
///
+ [Obsolete("Use the GraphicsPath extension AddCurve2D of CADability.Forms.GdiExtensions instead. GDI+ leaves the kernel in CADability 2.0, see issue #412.")]
public override void AddToGraphicsPath(System.Drawing.Drawing2D.GraphicsPath path, bool forward)
{ // es wird ein Spline erzeugt in 10° Schritten
// hier sollte man überlegen, ob man nicht mit einer Kreisbogenannäherung
diff --git a/CADability/GeneralCurve2D.cs b/CADability/GeneralCurve2D.cs
index 55060752..37180954 100644
--- a/CADability/GeneralCurve2D.cs
+++ b/CADability/GeneralCurve2D.cs
@@ -416,6 +416,7 @@ public interface ICurve2D : IQuadTreeInsertable
/// the path to append to
/// true to append the curve in its own direction, false to append it reversed (from the end point to
/// the start point)
+ [Obsolete("Use the GraphicsPath extension AddCurve2D of CADability.Forms.GdiExtensions instead. GDI+ leaves the kernel in CADability 2.0, see issue #412.")]
void AddToGraphicsPath(System.Drawing.Drawing2D.GraphicsPath path, bool forward);
///
/// Determines, whether the given parameter denotes a point inside the bounds of the curve.
@@ -2436,6 +2437,7 @@ public virtual ICurve2D Project(Plane fromPlane, Plane toPlane)
}
///
+ [Obsolete("Use the GraphicsPath extension AddCurve2D of CADability.Forms.GdiExtensions instead. GDI+ leaves the kernel in CADability 2.0, see issue #412.")]
public virtual void AddToGraphicsPath(System.Drawing.Drawing2D.GraphicsPath path, bool forward)
{
throw new Exception("The method or operation is not implemented.");
diff --git a/CADability/Line2D.cs b/CADability/Line2D.cs
index 15a419c9..f536299c 100644
--- a/CADability/Line2D.cs
+++ b/CADability/Line2D.cs
@@ -485,6 +485,7 @@ public override ICurve2D Project(Plane fromPlane, Plane toPlane)
else return null;
}
///
+ [Obsolete("Use the GraphicsPath extension AddCurve2D of CADability.Forms.GdiExtensions instead. GDI+ leaves the kernel in CADability 2.0, see issue #412.")]
public override void AddToGraphicsPath(System.Drawing.Drawing2D.GraphicsPath path, bool forward)
{
if (forward)
diff --git a/CADability/ModOp.cs b/CADability/ModOp.cs
index b034b77e..b9719516 100644
--- a/CADability/ModOp.cs
+++ b/CADability/ModOp.cs
@@ -657,6 +657,7 @@ public static ModOp2D PlaneToplane(Plane FromPlane, Plane ToPlane)
/// Returns the object equivalent to this
/// modification.
///
+ [Obsolete("Use the extension ToGdiMatrix of CADability.Forms.GdiExtensions instead. GDI+ leaves the kernel in CADability 2.0, see issue #412.")]
public System.Drawing.Drawing2D.Matrix Matrix2D
{
get
@@ -1982,13 +1983,6 @@ public ModOp GetInverse()
throw new ModOpException(ModOpException.tExceptionType.InversionFailed);
}
}
- internal System.Drawing.Drawing2D.Matrix Matrix2D
- {
- get
- {
- return new System.Drawing.Drawing2D.Matrix((float)Matrix00, (float)Matrix01, (float)Matrix10, (float)Matrix11, (float)Matrix12, (float)Matrix02);
- }
- }
///
/// Returns the determinant of the matrix of this modification.
///
diff --git a/CADability/Path2D.cs b/CADability/Path2D.cs
index 7f51fcd5..9b610b6e 100644
--- a/CADability/Path2D.cs
+++ b/CADability/Path2D.cs
@@ -983,6 +983,7 @@ public override ICurve2D Project(Plane fromPlane, Plane toPlane)
return new Path2D((ICurve2D[])(curves.ToArray(typeof(ICurve2D))));
}
///
+ [Obsolete("Use the GraphicsPath extension AddCurve2D of CADability.Forms.GdiExtensions instead. GDI+ leaves the kernel in CADability 2.0, see issue #412.")]
public override void AddToGraphicsPath(System.Drawing.Drawing2D.GraphicsPath path, bool forward)
{
if (forward)
diff --git a/CADability/Polyline2D.cs b/CADability/Polyline2D.cs
index 630b99ac..c95353a4 100644
--- a/CADability/Polyline2D.cs
+++ b/CADability/Polyline2D.cs
@@ -217,6 +217,7 @@ public override void Copy(ICurve2D toCopyFrom)
UserData.CloneFrom(c.UserData);
}
///
+ [Obsolete("Use the GraphicsPath extension AddCurve2D of CADability.Forms.GdiExtensions instead. GDI+ leaves the kernel in CADability 2.0, see issue #412.")]
public override void AddToGraphicsPath(System.Drawing.Drawing2D.GraphicsPath path, bool forward)
{
if (forward)
diff --git a/CADability/PrintToGDI.cs b/CADability/PrintToGDI.cs
index 4e9e9b17..59df9d31 100644
--- a/CADability/PrintToGDI.cs
+++ b/CADability/PrintToGDI.cs
@@ -2732,7 +2732,9 @@ void IPaintTo3D.Arc(GeoPoint center, GeoVector majorAxis, GeoVector minorAxis, d
float stPar = (float)(ea2d.axisStart / Math.PI * 180);
try
{
+#pragma warning disable CS0618 // PrintToGDI moves to CADability.Forms with the printing (issue #412, step 7)
Matrix r = fromHorizontal.Matrix2D;
+#pragma warning restore CS0618
double maxRad = prmaj2D.Length;
double minRad = prmin2D.Length;
if (graphicsPath != null)
diff --git a/CADability/Shape.cs b/CADability/Shape.cs
index 6f3cb138..45b586a7 100644
--- a/CADability/Shape.cs
+++ b/CADability/Shape.cs
@@ -1054,6 +1054,7 @@ public SimpleShape GetModified(ModOp2D m)
}
return new SimpleShape(o, h);
}
+ [Obsolete("Use the GraphicsPath extension AddShape of CADability.Forms.GdiExtensions instead.")]
internal void AddToGraphicsPath(System.Drawing.Drawing2D.GraphicsPath path)
{
outline.AddToGraphicsPath(path, true);
@@ -3160,6 +3161,7 @@ public bool Contains(GeoPoint2D p, bool acceptOnCurve)
/// holes empty.
///
/// The graphics path
+ [Obsolete("Use the extension ToGraphicsPath of CADability.Forms.GdiExtensions instead. GDI+ leaves the kernel in CADability 2.0, see issue #412.")]
public System.Drawing.Drawing2D.GraphicsPath CreateGraphicsPath()
{
System.Drawing.Drawing2D.GraphicsPath res = new System.Drawing.Drawing2D.GraphicsPath();
diff --git a/tests/CADability.Tests/GdiExtensionsTests.cs b/tests/CADability.Tests/GdiExtensionsTests.cs
new file mode 100644
index 00000000..4b1e7ef4
--- /dev/null
+++ b/tests/CADability.Tests/GdiExtensionsTests.cs
@@ -0,0 +1,117 @@
+#if WINDOWS
+using CADability.Curve2D;
+using CADability.Forms;
+using CADability.Shapes;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+
+namespace CADability.Tests
+{
+ ///
+ /// The GDI+ conversions moved from the geometry types of the kernel into in CADability.Forms
+ /// (issue #412, step 5). The obsolete kernel members stay in 1.x; the extensions must produce the same paths.
+ /// GDI+ only works on Windows, so these tests only run there.
+ ///
+ [TestClass]
+ public class GdiExtensionsTests
+ {
+#pragma warning disable CS0618 // the obsolete kernel members are the reference
+ private static GraphicsPath Old(ICurve2D curve, bool forward)
+ {
+ GraphicsPath res = new GraphicsPath();
+ curve.AddToGraphicsPath(res, forward);
+ return res;
+ }
+#pragma warning restore CS0618
+ private static GraphicsPath New(ICurve2D curve, bool forward)
+ {
+ GraphicsPath res = new GraphicsPath();
+ res.AddCurve2D(curve, forward);
+ return res;
+ }
+ private static void AssertSamePath(GraphicsPath expected, GraphicsPath actual, string what)
+ {
+ CollectionAssert.AreEqual(expected.PathTypes, actual.PathTypes, what + ": path types");
+ CollectionAssert.AreEqual(expected.PathPoints, actual.PathPoints, what + ": path points");
+ }
+ private static ICurve2D[] Curves()
+ {
+ return new ICurve2D[]
+ {
+ new Line2D(new GeoPoint2D(1, 2), new GeoPoint2D(7, -3)),
+ new Arc2D(new GeoPoint2D(2, 1), 3, Angle.Deg(30), SweepAngle.Deg(120)),
+ new Arc2D(new GeoPoint2D(2, 1), 3, Angle.Deg(300), SweepAngle.Deg(-200)),
+ new Circle2D(new GeoPoint2D(-1, 4), 2.5),
+ new Ellipse2D(new GeoPoint2D(0, 0), new GeoVector2D(4, 1), new GeoVector2D(-0.5, 2)),
+ new Polyline2D(new[] { new GeoPoint2D(0, 0), new GeoPoint2D(3, 1), new GeoPoint2D(4, 5), new GeoPoint2D(-1, 2) }),
+ new Path2D(new ICurve2D[] { new Line2D(new GeoPoint2D(0, 0), new GeoPoint2D(4, 0)), new Arc2D(new GeoPoint2D(4, 2), 2, Angle.Deg(270), SweepAngle.Deg(180)) }),
+ // knots from 0 to 1: the only case in which the old implementation sampled the right parameters
+ new BSpline2D(new[] { new GeoPoint2D(0, 0), new GeoPoint2D(1, 3), new GeoPoint2D(4, 3), new GeoPoint2D(5, 0) }, null, new double[] { 0, 1 }, new[] { 4, 4 }, 3, false, 0, 1),
+ };
+ }
+
+ [TestMethod]
+ public void CurvesGiveTheSamePathAsTheObsoleteMembers()
+ {
+ foreach (ICurve2D curve in Curves())
+ {
+ AssertSamePath(Old(curve, true), New(curve, true), curve.GetType().Name + " forward");
+ AssertSamePath(Old(curve, false), New(curve, false), curve.GetType().Name + " reversed");
+ }
+ }
+
+ [TestMethod]
+ public void EllipseArcStartsAndEndsLikeTheObsoleteMember()
+ {
+ // the number of points comes from the polar sweep here, the obsolete member uses the parametric sweep
+ EllipseArc2D arc = EllipseArc2D.Create(new GeoPoint2D(1, 1), new GeoVector2D(5, 0), new GeoVector2D(0, 2), new GeoPoint2D(6, 1), new GeoPoint2D(1, 3), true);
+ foreach (bool forward in new[] { true, false })
+ {
+ PointF[] expected = Old(arc, forward).PathPoints, actual = New(arc, forward).PathPoints;
+ Assert.AreEqual(expected[0], actual[0]);
+ Assert.AreEqual(expected[expected.Length - 1], actual[actual.Length - 1]);
+ }
+ }
+
+ [TestMethod]
+ public void BSplineWithKnotsBeyondOneIsSampledOnTheCurve()
+ {
+ BSpline2D bsp = new BSpline2D(new[] { new GeoPoint2D(0, 0), new GeoPoint2D(1, 3), new GeoPoint2D(4, 3), new GeoPoint2D(5, 0) }, null, new double[] { 0, 5 }, new[] { 4, 4 }, 3, false, 0, 5);
+ PointF[] points = New(bsp, true).PathPoints;
+ Assert.AreEqual(bsp.StartPoint.PointF, points[0]);
+ Assert.AreEqual(bsp.EndPoint.PointF, points[points.Length - 1]);
+ // MinDistance and not Distance: BSpline2D.Distance returns double.MaxValue for these points
+ foreach (PointF p in points) Assert.AreEqual(0.0, bsp.MinDistance(new GeoPoint2D(p.X, p.Y)), 1e-4);
+ AssertSamePath(Old(bsp, true), New(bsp, true), "the obsolete member is fixed as well");
+ }
+
+ [TestMethod]
+ public void ShapesGiveTheSamePathAsTheObsoleteMembers()
+ {
+ Border outline = new Border(new ICurve2D[] { new Line2D(new GeoPoint2D(0, 0), new GeoPoint2D(10, 0)), new Line2D(new GeoPoint2D(10, 0), new GeoPoint2D(10, 8)),
+ new Line2D(new GeoPoint2D(10, 8), new GeoPoint2D(0, 8)), new Line2D(new GeoPoint2D(0, 8), new GeoPoint2D(0, 0)) });
+ Border hole = new Border(new ICurve2D[] { new Circle2D(new GeoPoint2D(5, 4), 2) });
+ CompoundShape shape = new CompoundShape(new SimpleShape(outline, hole));
+#pragma warning disable CS0618
+ GraphicsPath oldBorder = new GraphicsPath();
+ outline.AddToGraphicsPath(oldBorder, false);
+ GraphicsPath oldShape = shape.CreateGraphicsPath();
+#pragma warning restore CS0618
+ GraphicsPath newBorder = new GraphicsPath();
+ newBorder.AddBorder(outline, false);
+ AssertSamePath(oldBorder, newBorder, "border");
+ AssertSamePath(oldShape, shape.ToGraphicsPath(), "compound shape");
+ }
+
+ [TestMethod]
+ public void ModOp2DGivesTheSameMatrixAsTheObsoleteMember()
+ {
+ ModOp2D m = ModOp2D.Rotate(new GeoPoint2D(3, -2), SweepAngle.Deg(37)) * ModOp2D.Scale(2, 0.5);
+#pragma warning disable CS0618
+ CollectionAssert.AreEqual(m.Matrix2D.Elements, m.ToGdiMatrix().Elements);
+#pragma warning restore CS0618
+ }
+ }
+}
+#endif