/// <summary> /// Transforms a general elliptical arc. Returns true if the transformed arc is a circular arc. /// </summary> public static bool TransformEllipseArc(ref double centerx, ref double centery, ref double aradius, ref double bradius, ref double startangle, ref double sweepangle, ref double tilt, Transform2d mat) { double endangle = startangle + sweepangle; //we do our calculations here with endangle rather than sweepangle mat.Apply(centerx, centery, out centerx, out centery, true); //get points on the untranformed ellipse and transform them to be //points on the central, tranformed ellipse double spx, spy, epx, epy; GeomUtil.GetPointOnCentralEllipse(aradius, bradius, tilt, startangle, out spx, out spy); GeomUtil.GetPointOnCentralEllipse(aradius, bradius, tilt, endangle, out epx, out epy); mat.Apply(spx, spy, out spx, out spy, false); mat.Apply(epx, epy, out epx, out epy, false); bool res = GeomUtil.TransformCentralEllipse(ref aradius, ref bradius, ref tilt, mat, ref sweepangle); startangle = Angle(0, 0, spx, spy) - tilt; endangle = Angle(0, 0, epx, epy) - tilt; //convert endangle back to startangle if (sweepangle > 0.0 && endangle < startangle) { endangle += Math.PI * 2.0; } else if (sweepangle < 0.0 && endangle > startangle) { endangle -= Math.PI * 2.0; } sweepangle = endangle - startangle; return(res); }
public virtual void DrawArcT(double x1, double y1, double x2, double y2, double bulge) { var t = Transform; if (t.IsUniform) { //the arc will still be an arc after transform //transform it an draw with standrad arc function t.Apply(x1, y1, out x1, out y1, true); t.Apply(x2, y2, out x2, out y2, true); DrawArc(x1, y1, x2, y2, t.Determinant < 0.0 ? -bulge : bulge); //-buylge to support mirrored arcs return; } else { //the arc might change into an elliptic arc double cx, cy, rad; if (!GeomUtil.GetArcCenterFromBulge(x1, y1, x2, y2, bulge, out cx, out cy)) { //the arc is a line DrawLineT(x1, y1, x2, y2); return; } rad = GeomUtil.GetArcRadiusFromBulge(x1, y1, x2, y2, bulge); DrawEllipticArcT(cx, cy, rad, rad, 0.0, GeomUtil.Angle(cx, cy, x1, y1), GeomUtil.GetArcSweepAngleFromBulge(bulge)); } }
public virtual void DrawRectangleT(double x1, double y1, double x2, double y2) { double xx1 = x1, yy1 = y1; double xx2 = x2, yy2 = y1; double xx3 = x2, yy3 = y2; double xx4 = x1, yy4 = y2; Transform.Apply(xx1, yy1, out xx1, out yy1, true); Transform.Apply(xx2, yy2, out xx2, out yy2, true); Transform.Apply(xx3, yy3, out xx3, out yy3, true); Transform.Apply(xx4, yy4, out xx4, out yy4, true); //check if rectangle becomes a line to avoid duplicate drawing if (GeomUtil.SquaredDistance(xx1, yy1, xx4, yy4) < 1.225) //rect. is a horizontal line ( height<sqrt(1.5) ) { DrawLine(xx1, yy1, xx2, yy2); } else if (GeomUtil.SquaredDistance(xx1, yy1, xx2, yy2) <= 1.225) //rect. is a verical line ( width<sqrt(1.5) ) { DrawLine(xx1, yy1, xx4, yy4); } else { DrawPolyLine(true, xx1, yy1, xx2, yy2, xx3, yy3, xx4, yy4); } }
/// <summary> /// Computes the extents of the path, if the path had been transformed with /// the given transform. /// </summary> /// <param name="t"></param> /// <returns></returns> public Box2d GetTransformedExtents(Transform2d t) { Box2d res = new Box2d(); double penx = 0.0, peny = 0.0; double x, y; foreach (GFXPathMoveTo node in PathPoints) { if (node is GFXPathLineTo) { t.Apply(node.X, node.Y, out x, out y, true); res.Append(x, y); t.Apply(penx, peny, out x, out y, true); res.Append(x, y); } else if (node is GFXPathArcTo) { res.Append(GeomUtil.GetTransformedArcExtents(penx, peny, node.X, node.Y, ((GFXPathArcTo)node).Bulge, t)); } else if (node is GFXPathBezierTo) { GFXPathBezierTo bn = (GFXPathBezierTo)node; res.Append(GeomUtil.GetTransformedBezierExtents(penx, peny, bn.XC1, bn.YC1, bn.XC2, bn.YC2, bn.X, bn.Y, t)); } penx = node.X; peny = node.Y; } return(res); }
internal override void TransformFlatten(ref double penx, ref double peny, double tol, Transform2d t, FlattenCallback lcb) { double xs, ys, c1x, c1y, c2x, c2y, xe, ye; t.Apply(penx, peny, out xs, out ys, true); t.Apply(XC1, YC1, out c1x, out c1y, true); t.Apply(XC2, YC2, out c2x, out c2y, true); t.Apply(X, Y, out xe, out ye, true); GeomUtil.FlattenBezier(xs, ys, c1x, c1y, c2x, c2y, xe, ye, false, tol, lcb); penx = X; peny = Y; }
public virtual void DrawEllipseT(double cx, double cy, double aradius, double bradius, double tilt) { bool circular = GeomUtil.TransformEllipse(ref cx, ref cy, ref aradius, ref bradius, ref tilt, Transform); if (circular) //draw with circle if possible=>faster { DrawCircle(cx, cy, aradius); return; } DrawEllipse(cx, cy, aradius, bradius, tilt); }
public virtual void DrawArc(double x1, double y1, double x2, double y2, double bulge) { double cx, cy, rad; if (!GeomUtil.GetArcCenterFromBulge(x1, y1, x2, y2, bulge, out cx, out cy)) { DrawLine(x1, y1, x2, y2); return; } rad = GeomUtil.GetArcRadiusFromBulge(x1, y1, x2, y2, bulge); DrawEllipticArc(cx, cy, rad, rad, 0.0, GeomUtil.Angle(cx, cy, x1, y1), GeomUtil.GetArcSweepAngleFromBulge(bulge)); }
public override void DrawEllipticArc(double cx, double cy, double aradius, double bradius, double tilt, double startangle, double sweepangle) { /* int prevx=0,prevy=0; * int nextx,nexty; * bool first=true; * * GeomUtil.FlattenEllipticArc(cx, cy, aradius, bradius, tilt, startangle, sweepangle, flattentol, true, (x, y,moveto) => * { * if (first) * { * prevx = GFXUtil.RealToInt(x); * prevy = GFXUtil.RealToInt(y); * first = false; * } * else * { * nextx = GFXUtil.RealToInt(x); * nexty = GFXUtil.RealToInt(y); * DrawLine(prevx,prevy,nextx,nexty); * //target.Add(prevx, prevy, nextx, nexty, currentobject); * prevx = nextx; * prevy = nexty; * } * });*/ int px = 0, py = 0, nx, ny; int num = Clipper.ClipEllipticArc(cx, cy, aradius, bradius, tilt, startangle, sweepangle, clipbuffer, Clip.XMin, Clip.YMin, Clip.XMax, Clip.YMax); for (int l = 0; l < num; l += 2) { GeomUtil.FlattenEllipticArc(cx, cy, aradius, bradius, tilt, clipbuffer[l], clipbuffer[l + 1] - clipbuffer[l], flattentol, true, (x, y, moveto) => { nx = GFXUtil.FloatToInt(x); ny = GFXUtil.FloatToInt(y); if (!moveto) { DrawLine(px, py, nx, ny); } px = nx; py = ny; }); } }
public virtual void DrawEllipticArcT(double cx, double cy, double aradius, double bradius, double tilt, double startangle, double sweepangle) { bool circular = GeomUtil.TransformEllipseArc(ref cx, ref cy, ref aradius, ref bradius, ref startangle, ref sweepangle, ref tilt, Transform); if (circular) { double bulge = GeomUtil.GetArcBulgeFromSweepAngle(sweepangle); double x1 = cx + Math.Cos(startangle) * aradius; double y1 = cy + Math.Sin(startangle) * aradius; double x2 = cx + Math.Cos(startangle + sweepangle) * aradius; double y2 = cy + Math.Sin(startangle + sweepangle) * aradius; DrawArc(x1, y1, x2, y2, bulge); return; } DrawEllipticArc(cx, cy, aradius, bradius, tilt, startangle, sweepangle); }
public override void DrawArc(double x1, double y1, double x2, double y2, double bulge) { int prevx = GFXUtil.FloatToInt(x1); int prevy = GFXUtil.FloatToInt(y1); int clipres = Clipper.ClipArc(x1, y1, x2, y2, bulge, clipbuffer, Clip.XMin, Clip.YMin, Clip.XMax, Clip.YMax); for (int idx = 0; idx < clipres; idx += 5) { int cx = GFXUtil.FloatToInt(clipbuffer[idx]), cy = GFXUtil.FloatToInt(clipbuffer[idx + 1]), nx, ny; GeomUtil.FlattenArc(clipbuffer[idx], clipbuffer[idx + 1], clipbuffer[idx + 2], clipbuffer[idx + 3], clipbuffer[idx + 4], false, flattentol, (x, y, moveto) => { nx = GFXUtil.FloatToInt(x); ny = GFXUtil.FloatToInt(y); target.Add(cx, cy, nx, ny, currentobject); cx = nx; cy = ny; }); } }
/// <summary> /// Checks if this path, after a given transformation will have a bounding box smaller than a given size. THis can be done quickly since the /// check can be terminated as soon as it finds a segment large enough. /// </summary> public bool IsTransformedSmallerThan(Transform2d tr, double maxwidth, double maxheight) { double penx = 0.0, peny = 0.0; Box2d ext = new Box2d(); foreach (GFXPathMoveTo mt in PathPoints) { if (mt is GFXPathBezierTo) { var bez = mt as GFXPathBezierTo; Box2d bext = GeomUtil.GetTransformedBezierExtents(penx, peny, bez.XC1, bez.YC1, bez.XC2, bez.YC2, bez.X, bez.Y, tr); ext.Append(bext); } else if (mt is GFXPathArcTo) { var arc = mt as GFXPathArcTo; Box2d aext = GeomUtil.GetTransformedArcExtents(penx, peny, arc.X, arc.Y, arc.Bulge, tr); ext.Append(aext); } else if (mt is GFXPathLineTo) { double x1, y1, x2, y2; tr.Apply(penx, peny, out x1, out y1, true); tr.Apply(mt.X, mt.Y, out x2, out y2, true); ext.Append(x1, y1, x2, y2); } // closepath and moveto needs no special handling... if (!ext.Empty && (ext.Width > maxwidth || ext.Height > maxheight)) { return(false); } penx = mt.X; peny = mt.Y; } return(true); }
private void InternalDrawBezier(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { int n = Clipper.ClipBezier(x1, y1, x2, y2, x3, y3, x4, y4, clipbuffer, Clip.XMin, Clip.YMin, Clip.XMax, Clip.YMax); int penx = 0, peny = 0; for (int l = 0; l < n; l += 2) { GeomUtil.FlattenBezier(x1, y1, x2, y2, x3, y3, x4, y4, true, flattentol, (x, y, moveto) => { int nextx = GFXUtil.FloatToInt(x); int nexty = GFXUtil.FloatToInt(y); if (!moveto) { DrawLine(penx, peny, nextx, nexty); } penx = nextx; peny = nexty; }, clipbuffer[l], clipbuffer[l + 1]); } }
internal override void TransformFlatten(ref double penx, ref double peny, double tol, Transform2d t, FlattenCallback lcb) { GeomUtil.TransformFlattenArc(penx, peny, X, Y, Bulge, false, tol, t, lcb); penx = X; peny = Y; }
internal override void Flatten(ref double penx, ref double peny, double tol, FlattenCallback lcb) { GeomUtil.FlattenBezier(penx, peny, XC1, YC1, XC2, YC2, X, Y, false, tol, lcb); penx = X; peny = Y; }
public override void DrawEllipticArc(double cx, double cy, double aradius, double bradius, double tilt, double startangle, double sweepangle) { var ellipext = GeomUtil.GetEllipticExtents(cx, cy, aradius, bradius, startangle, sweepangle, tilt); AppendWithLineWidth(ellipext); }
public override void DrawArc(double x1, double y1, double x2, double y2, double bulge) { Box2d rect = GeomUtil.GetArcExtents(x1, y1, x2, y2, bulge); AppendWithLineWidth(rect); }
internal override void Flatten(ref double penx, ref double peny, double tol, FlattenCallback lcb) { GeomUtil.FlattenArc(penx, peny, X, Y, Bulge, false, tol, lcb); penx = X; peny = Y; }