/// <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); }
public static Box2d GetBezierExtents(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { //equations for differentiations of the bezier polynoimial in x and y: double t2x = 9 * x2 - 9 * x3 + 3 * x4 - 3 * x1; double t1x = 6 * x1 - 12 * x2 + 6 * x3; double t0x = 3 * x2 - 3 * x1; double t2y = 9 * y2 - 9 * y3 + 3 * y4 - 3 * y1; double t1y = 6 * y1 - 12 * y2 + 6 * y3; double t0y = 3 * y2 - 3 * y1; double extrema1, extrema2, xp, yp; Box2d res = new Box2d(x1, y1, x4, y4); //solve x extremas if (MathUtil.SolveQuadratic(t2x, t1x, t0x, out extrema1, out extrema2)) { if (extrema1 > 0.0 && extrema1 < 1.0) { EvalBezier(x1, y1, x2, y2, x3, y3, x4, y4, extrema1, out xp, out yp); res.Append(xp, yp); } if (extrema2 > 0.0 && extrema2 < 1.0) { EvalBezier(x1, y1, x2, y2, x3, y3, x4, y4, extrema2, out xp, out yp); res.Append(xp, yp); } } //solve y extremas if (MathUtil.SolveQuadratic(t2y, t1y, t0y, out extrema1, out extrema2)) { if (extrema1 > 0.0 && extrema1 < 1.0) { EvalBezier(x1, y1, x2, y2, x3, y3, x4, y4, extrema1, out xp, out yp); res.Append(xp, yp); } if (extrema2 > 0.0 && extrema2 < 1.0) { EvalBezier(x1, y1, x2, y2, x3, y3, x4, y4, extrema2, out xp, out yp); res.Append(xp, yp); } } return(res); }
public static Box2d GetArcExtents(double x1, double y1, double x2, double y2, double bulge) { double cx, cy, rad, side; Box2d res = new Box2d(x1, y1, x2, y2); //append quadrants if included if (!GetArcCenterFromBulge(x1, y1, x2, y2, bulge, out cx, out cy)) { return(res); //arc is a line } rad = GetArcRadiusFromBulge(x1, y1, x2, y2, bulge); //include quadrant points of circle if on arc side = SideOfPoint(x1, y1, x2, y2, cx + rad, cy); if ((bulge < 0.0 && side >= 0.0) || (bulge > 0.0 && side <= 0.0)) { res.Append(cx + rad, cy); } side = SideOfPoint(x1, y1, x2, y2, cx, cy + rad); if ((bulge < 0.0 && side >= 0.0) || (bulge > 0.0 && side <= 0.0)) { res.Append(cx, cy + rad); } side = SideOfPoint(x1, y1, x2, y2, cx - rad, cy); if ((bulge < 0.0 && side >= 0.0) || (bulge > 0.0 && side <= 0.0)) { res.Append(cx - rad, cy); } side = SideOfPoint(x1, y1, x2, y2, cx, cy - rad); if ((bulge < 0.0 && side >= 0.0) || (bulge > 0.0 && side <= 0.0)) { res.Append(cx, cy - rad); } return(res); }
/// <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 AppendPathToExtents(bool uselinewidth, bool usetransform, GFXPath pth) { Box2d ext; if (usetransform) { ext = pth.GetTransformedExtents(Transform); } else { ext = pth.Extents; } if (uselinewidth) { AppendWithLineWidth(pth.Extents); } else { RecordedExtents.Append(ext.XMin, ext.YMin, ext.XMax, ext.YMax); } }
public static Box2d GetEllipticExtents(double cx, double cy, double aradius, double bradius, double startangle, double sweepangle, double tilt) { Box2d extents = new Box2d(); double vmaxx, vmaxy; if (MathUtil.IsZero(bradius)) //special case for zero bradius, assume maxima lies in tilt direction { vmaxy = tilt; } else { vmaxy = Math.Atan(bradius / (aradius * Math.Tan(tilt))); } if (MathUtil.IsZero(aradius)) //special case for zero bradius, assume maxima lies in tilt direction { vmaxx = tilt; } else { vmaxx = -Math.Atan((bradius * Math.Tan(tilt)) / aradius); } double startparam = EllipseAngleToParam(startangle, aradius, bradius); double endparam = EllipseAngleToParam(startangle + sweepangle, aradius, bradius); bool ccw = sweepangle >= 0.0; if (Math.Abs(sweepangle) < MathUtil.Deg360) { extents.Append(EvalEllipseParam(cx, cy, aradius, bradius, tilt, startparam)); extents.Append(EvalEllipseParam(cx, cy, aradius, bradius, tilt, endparam)); if (MathUtil.IsAngleBetween(startparam, endparam, vmaxy, ccw)) { extents.Append(EvalEllipseParam(cx, cy, aradius, bradius, tilt, vmaxy)); } if (MathUtil.IsAngleBetween(startparam, endparam, vmaxy + MathUtil.Deg180, ccw)) { extents.Append(EvalEllipseParam(cx, cy, aradius, bradius, tilt, vmaxy + MathUtil.Deg180)); } if (MathUtil.IsAngleBetween(startparam, endparam, vmaxx, ccw)) { extents.Append(EvalEllipseParam(cx, cy, aradius, bradius, tilt, vmaxx)); } if (MathUtil.IsAngleBetween(startparam, endparam, vmaxx + MathUtil.Deg180, ccw)) { extents.Append(EvalEllipseParam(cx, cy, aradius, bradius, tilt, vmaxx + MathUtil.Deg180)); } } else { //not an arc, all extreme ellipse points are included => a little faster extents.Append(EvalEllipseParam(cx, cy, aradius, bradius, tilt, vmaxy)); extents.Append(EvalEllipseParam(cx, cy, aradius, bradius, tilt, vmaxy + MathUtil.Deg180)); extents.Append(EvalEllipseParam(cx, cy, aradius, bradius, tilt, vmaxx)); extents.Append(EvalEllipseParam(cx, cy, aradius, bradius, tilt, vmaxx + MathUtil.Deg180)); } return(extents); }