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