Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 184 additions & 0 deletions CADability.Forms/GdiExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
using CADability.Curve2D;
using CADability.Shapes;
using System;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace CADability.Forms
{
/// <summary>
/// Converts CADability geometry to GDI+ (<see cref="GraphicsPath"/>, <see cref="Matrix"/>). These conversions used to be
/// members of the geometry types in the kernel (<see cref="ICurve2D.AddToGraphicsPath"/>, <see cref="Border.AddToGraphicsPath"/>,
/// <see cref="CompoundShape.CreateGraphicsPath"/>, <see cref="ModOp2D.Matrix2D"/>). GDI+ is only available on Windows, so they
/// live here, next to the other WinForms code, and the kernel stays platform independent (issue #412).
/// </summary>
public static class GdiExtensions
{
/// <summary>
/// Appends <paramref name="curve"/> to <paramref name="path"/>. Lines, arcs and circles are added exactly, ellipses and
/// B-splines as an approximation through points on the curve.
/// </summary>
/// <param name="path">The graphics path to append to</param>
/// <param name="curve">The curve to add</param>
/// <param name="forward">true: add in the direction of the curve, false: add reversed</param>
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
}
}
/// <summary>
/// Appends the segments of <paramref name="border"/> to <paramref name="path"/>, e.g. for filling or clipping with
/// System.Drawing. With <paramref name="counterClockWise"/> false the segments are added in reverse order and direction,
/// which is how <see cref="AddShape(GraphicsPath, SimpleShape)"/> adds the holes so that they stay unfilled.
/// </summary>
/// <param name="path">The graphics path to append to</param>
/// <param name="border">The border to add</param>
/// <param name="counterClockWise">true: add in the direction of the border, false: add reversed</param>
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);
}
}
/// <summary>
/// Appends <paramref name="shape"/> to <paramref name="path"/>: the outline counterclockwise and the holes clockwise, so
/// filling the path leaves the holes empty.
/// </summary>
/// <param name="path">The graphics path to append to</param>
/// <param name="shape">The shape to add</param>
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);
}
/// <summary>
/// Appends all parts of <paramref name="shape"/> to <paramref name="path"/>, see <see cref="AddShape(GraphicsPath, SimpleShape)"/>.
/// </summary>
/// <param name="path">The graphics path to append to</param>
/// <param name="shape">The shape to add</param>
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]);
}
/// <summary>
/// Converts <paramref name="shape"/> to a new <see cref="GraphicsPath"/> for drawing or clipping with System.Drawing,
/// see <see cref="AddShape(GraphicsPath, CompoundShape)"/>.
/// </summary>
/// <param name="shape">The shape to convert</param>
/// <returns>The graphics path</returns>
public static GraphicsPath ToGraphicsPath(this CompoundShape shape)
{
GraphicsPath res = new GraphicsPath();
res.AddShape(shape);
return res;
}
/// <summary>
/// Converts <paramref name="m"/> to a GDI+ <see cref="Matrix"/> with the same coefficients (in single precision), e.g. to
/// apply it when drawing with GDI+.
/// </summary>
/// <param name="m">The modification to convert</param>
/// <returns>The equivalent matrix</returns>
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);
}
}
}
}
2 changes: 1 addition & 1 deletion CADability.Forms/PaintToGDI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions CADability/Arc2D.cs
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,7 @@ public override double MinDistance(ICurve2D Other)
return base.MinDistance(Other); // dort wird gleichermaßen für Bogen und Kreis gerechnet
}
/// <inheritdoc/>
[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)
Expand Down
4 changes: 2 additions & 2 deletions CADability/BSpline2D.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1663,15 +1663,15 @@ public override double Sweep
}
}
/// <inheritdoc/>
[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);
Expand Down
2 changes: 2 additions & 0 deletions CADability/Bitmap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions CADability/Border.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3904,6 +3904,7 @@ internal void Trimm(int firstIndex, int lastIndex)
/// </summary>
/// <param name="path">The graphics path to append to</param>
/// <param name="counterClockWise">true: add in the direction of the border, false: add reversed</param>
[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)
Expand Down
1 change: 1 addition & 0 deletions CADability/Circle2D.cs
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ public override ICurve2D Project(Plane fromPlane, Plane toPlane)
return e.GetProjectedCurve(toPlane);
}
/// <inheritdoc/>
[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,
Expand Down
1 change: 1 addition & 0 deletions CADability/DualSurfaceCurve.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions CADability/Ellipse2D.cs
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,7 @@ public override void Move(double dx, double dy)
Recalc();
}
/// <inheritdoc/>
[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...
Expand Down
1 change: 1 addition & 0 deletions CADability/EllipseArc2D.cs
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,7 @@ public override double MinDistance(GeoPoint2D p)
return res;
}
/// <inheritdoc/>
[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
Expand Down
2 changes: 2 additions & 0 deletions CADability/GeneralCurve2D.cs
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ public interface ICurve2D : IQuadTreeInsertable
/// <param name="path">the path to append to</param>
/// <param name="forward">true to append the curve in its own direction, false to append it reversed (from the end point to
/// the start point)</param>
[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);
/// <summary>
/// Determines, whether the given parameter denotes a point inside the bounds of the curve.
Expand Down Expand Up @@ -2436,6 +2437,7 @@ public virtual ICurve2D Project(Plane fromPlane, Plane toPlane)
}

/// <inheritdoc/>
[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.");
Expand Down
1 change: 1 addition & 0 deletions CADability/Line2D.cs
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ public override ICurve2D Project(Plane fromPlane, Plane toPlane)
else return null;
}
/// <inheritdoc/>
[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)
Expand Down
8 changes: 1 addition & 7 deletions CADability/ModOp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,7 @@ public static ModOp2D PlaneToplane(Plane FromPlane, Plane ToPlane)
/// Returns the <see cref="System.Drawing.Drawing2D.Matrix"/> object equivalent to this
/// modification.
/// </value>
[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
Expand Down Expand Up @@ -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);
}
}
/// <summary>
/// Returns the determinant of the matrix of this modification.
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions CADability/Path2D.cs
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,7 @@ public override ICurve2D Project(Plane fromPlane, Plane toPlane)
return new Path2D((ICurve2D[])(curves.ToArray(typeof(ICurve2D))));
}
/// <inheritdoc/>
[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)
Expand Down
1 change: 1 addition & 0 deletions CADability/Polyline2D.cs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ public override void Copy(ICurve2D toCopyFrom)
UserData.CloneFrom(c.UserData);
}
/// <inheritdoc/>
[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)
Expand Down
2 changes: 2 additions & 0 deletions CADability/PrintToGDI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions CADability/Shape.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -3160,6 +3161,7 @@ public bool Contains(GeoPoint2D p, bool acceptOnCurve)
/// holes empty.
/// </summary>
/// <returns>The graphics path</returns>
[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();
Expand Down
Loading
Loading