internal CalculatedArcValues GetCalculatedArcValues() { CalculatedArcValues calcVal = new CalculatedArcValues(); /* * This algorithm is taken from the Batik source. All cudos to the Batik crew. */ PointF startPoint = PreviousSeg.AbsXY; PointF endPoint = AbsXY; float x0 = startPoint.X; float y0 = startPoint.Y; float x = endPoint.X; float y = endPoint.Y; // Compute the half distance between the current and the final point double dx2 = (x0 - x) / 2.0; double dy2 = (y0 - y) / 2.0; // Convert angle from degrees to radians double radAngle = Angle * Math.PI / 180; double cosAngle = Math.Cos(radAngle); double sinAngle = Math.Sin(radAngle); // // Step 1 : Compute (x1, y1) // double x1 = (cosAngle * dx2 + sinAngle * dy2); double y1 = (-sinAngle * dx2 + cosAngle * dy2); // Ensure radii are large enough double rx = Math.Abs(R1); double ry = Math.Abs(R2); double Prx = rx * rx; double Pry = ry * ry; double Px1 = x1 * x1; double Py1 = y1 * y1; // check that radii are large enough double radiiCheck = Px1/Prx + Py1/Pry; if (radiiCheck > 1) { rx = Math.Sqrt(radiiCheck) * rx; ry = Math.Sqrt(radiiCheck) * ry; Prx = rx * rx; Pry = ry * ry; } // // Step 2 : Compute (cx1, cy1) // double sign = (LargeArcFlag == SweepFlag) ? -1 : 1; double sq = ((Prx*Pry)-(Prx*Py1)-(Pry*Px1)) / ((Prx*Py1)+(Pry*Px1)); sq = (sq < 0) ? 0 : sq; double coef = (sign * Math.Sqrt(sq)); double cx1 = coef * ((rx * y1) / ry); double cy1 = coef * -((ry * x1) / rx); // // Step 3 : Compute (cx, cy) from (cx1, cy1) // double sx2 = (x0 + x) / 2.0; double sy2 = (y0 + y) / 2.0; double cx = sx2 + (cosAngle * cx1 - sinAngle * cy1); double cy = sy2 + (sinAngle * cx1 + cosAngle * cy1); // // Step 4 : Compute the angleStart (angle1) and the angleExtent (dangle) // double ux = (x1 - cx1); // rx; double uy = (y1 - cy1); // ry; double vx = (-x1 - cx1); // rx; double vy = (-y1 - cy1); // ry; double p, n; // Compute the angle start n = Math.Sqrt((ux * ux) + (uy * uy)); p = ux; // (1 * ux) + (0 * uy) sign = (uy < 0) ? -1d : 1d; double angleStart = sign * Math.Acos(p / n); angleStart = angleStart * 180 / Math.PI; // Compute the angle extent n = Math.Sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy)); p = ux * vx + uy * vy; sign = (ux * vy - uy * vx < 0) ? -1d : 1d; double angleExtent = sign * Math.Acos(p / n); angleExtent = angleExtent * 180 / Math.PI; if(!sweepFlag && angleExtent > 0) { angleExtent -= 360f; } else if (sweepFlag && angleExtent < 0) { angleExtent += 360f; } angleExtent %= 360f; angleStart %= 360f; calcVal.CorrRx = (float)rx; calcVal.CorrRy = (float)ry; calcVal.Cx = (float)cx; calcVal.Cy = (float)cy; calcVal.AngleStart = (float)angleStart; calcVal.AngleExtent = (float)angleExtent; return calcVal; }
internal CalculatedArcValues GetCalculatedArcValues() { CalculatedArcValues calcVal = new CalculatedArcValues(); /* * This algorithm is taken from the Batik source. All cudos to the Batik crew. */ PointF startPoint = PreviousSeg.AbsXY; PointF endPoint = AbsXY; float x0 = startPoint.X; float y0 = startPoint.Y; float x = endPoint.X; float y = endPoint.Y; // Compute the half distance between the current and the final point double dx2 = (x0 - x) / 2.0; double dy2 = (y0 - y) / 2.0; // Convert angle from degrees to radians double radAngle = Angle * Math.PI / 180; double cosAngle = Math.Cos(radAngle); double sinAngle = Math.Sin(radAngle); // // Step 1 : Compute (x1, y1) // double x1 = (cosAngle * dx2 + sinAngle * dy2); double y1 = (-sinAngle * dx2 + cosAngle * dy2); // Ensure radii are large enough double rx = Math.Abs(R1); double ry = Math.Abs(R2); double Prx = rx * rx; double Pry = ry * ry; double Px1 = x1 * x1; double Py1 = y1 * y1; // check that radii are large enough double radiiCheck = Px1 / Prx + Py1 / Pry; if (radiiCheck > 1) { rx = Math.Sqrt(radiiCheck) * rx; ry = Math.Sqrt(radiiCheck) * ry; Prx = rx * rx; Pry = ry * ry; } // // Step 2 : Compute (cx1, cy1) // double sign = (LargeArcFlag == SweepFlag) ? -1 : 1; double sq = ((Prx * Pry) - (Prx * Py1) - (Pry * Px1)) / ((Prx * Py1) + (Pry * Px1)); sq = (sq < 0) ? 0 : sq; double coef = (sign * Math.Sqrt(sq)); double cx1 = coef * ((rx * y1) / ry); double cy1 = coef * -((ry * x1) / rx); // // Step 3 : Compute (cx, cy) from (cx1, cy1) // double sx2 = (x0 + x) / 2.0; double sy2 = (y0 + y) / 2.0; double cx = sx2 + (cosAngle * cx1 - sinAngle * cy1); double cy = sy2 + (sinAngle * cx1 + cosAngle * cy1); // // Step 4 : Compute the angleStart (angle1) and the angleExtent (dangle) // double ux = (x1 - cx1); // rx; double uy = (y1 - cy1); // ry; double vx = (-x1 - cx1); // rx; double vy = (-y1 - cy1); // ry; double p, n; // Compute the angle start n = Math.Sqrt((ux * ux) + (uy * uy)); p = ux; // (1 * ux) + (0 * uy) sign = (uy < 0) ? -1d : 1d; double angleStart = sign * Math.Acos(p / n); angleStart = angleStart * 180 / Math.PI; // Compute the angle extent n = Math.Sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy)); p = ux * vx + uy * vy; sign = (ux * vy - uy * vx < 0) ? -1d : 1d; double angleExtent = sign * Math.Acos(p / n); angleExtent = angleExtent * 180 / Math.PI; if (!sweepFlag && angleExtent > 0) { angleExtent -= 360f; } else if (sweepFlag && angleExtent < 0) { angleExtent += 360f; } angleExtent %= 360f; angleStart %= 360f; calcVal.CorrRx = (float)rx; calcVal.CorrRy = (float)ry; calcVal.Cx = (float)cx; calcVal.Cy = (float)cy; calcVal.AngleStart = (float)angleStart; calcVal.AngleExtent = (float)angleExtent; return(calcVal); }
public GraphicsPath GetGraphicsPath() { if (gp == null) { gp = new GraphicsPath(); PointF initPoint = new PointF(0, 0); PointF lastPoint = new PointF(0, 0); SvgPathSegList segments = (SvgPathSegList)PathSegList; SvgPathSeg segment; int nElems = segments.NumberOfItems; for (int i = 0; i < nElems; i++) { segment = (SvgPathSeg)segments.GetItem(i); if (segment is SvgPathSegMoveto) { SvgPathSegMoveto seg = (SvgPathSegMoveto)segment; gp.StartFigure(); lastPoint = initPoint = seg.AbsXY; } else if (segment is SvgPathSegLineto) { SvgPathSegLineto seg = (SvgPathSegLineto)segment; PointF p = seg.AbsXY; gp.AddLine(lastPoint.X, lastPoint.Y, p.X, p.Y); lastPoint = p; } else if (segment is SvgPathSegCurveto) { SvgPathSegCurveto seg = (SvgPathSegCurveto)segment; PointF xy = seg.AbsXY; PointF x1y1 = seg.CubicX1Y1; PointF x2y2 = seg.CubicX2Y2; gp.AddBezier(lastPoint.X, lastPoint.Y, x1y1.X, x1y1.Y, x2y2.X, x2y2.Y, xy.X, xy.Y); lastPoint = xy; } else if (segment is SvgPathSegArc) { SvgPathSegArc seg = (SvgPathSegArc)segment; PointF p = seg.AbsXY; if (lastPoint.Equals(p)) { // If the endpoints (x, y) and (x0, y0) are identical, then this // is equivalent to omitting the elliptical arc segment entirely. } else if (seg.R1 == 0 || seg.R2 == 0) { // Ensure radii are valid gp.AddLine(lastPoint, p); } else { CalculatedArcValues calcValues = seg.GetCalculatedArcValues(); GraphicsPath gp2 = new GraphicsPath(); gp2.StartFigure(); gp2.AddArc( calcValues.Cx - calcValues.CorrRx, calcValues.Cy - calcValues.CorrRy, calcValues.CorrRx * 2, calcValues.CorrRy * 2, calcValues.AngleStart, calcValues.AngleExtent ); Matrix matrix = new Matrix(); matrix.Translate( -calcValues.Cx, -calcValues.Cy ); gp2.Transform(matrix); matrix = new Matrix(); matrix.Rotate(seg.Angle); gp2.Transform(matrix); matrix = new Matrix(); matrix.Translate(calcValues.Cx, calcValues.Cy); gp2.Transform(matrix); gp.AddPath(gp2, true); } lastPoint = p; } else if (segment is SvgPathSegClosePath) { gp.CloseFigure(); lastPoint = initPoint; } } string fillRule = GetPropertyValue("fill-rule"); if (fillRule == "evenodd") { gp.FillMode = FillMode.Alternate; } else { gp.FillMode = FillMode.Winding; } } return(gp); }