static void ComputeArc2(double x0, double y0, double rx, double ry, double xAngleRad, bool largeArcFlag, bool sweepFlag, double x, double y, ref CenterFormArc result) { //from SVG1.1 spec //---------------------------------- //step1: Compute (x1dash,y1dash) //---------------------------------- double dx2 = (x0 - x) / 2.0; double dy2 = (y0 - y) / 2.0; double cosAngle = Math.Cos(xAngleRad); double sinAngle = Math.Sin(xAngleRad); double x1 = (cosAngle * dx2 + sinAngle * dy2); double y1 = (-sinAngle * dx2 + cosAngle * dy2); // Ensure radii are large enough rx = Math.Abs(rx); ry = Math.Abs(ry); 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; result.scaleUp = true; } //---------------------------------- //step2: 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); //---------------------------------- //step3: 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); //---------------------------------- //step4: Compute theta and anfkediff 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)); // Math.toDegrees(sign * Math.Acos(p / n)); // 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));// Math.toDegrees(sign * Math.Acos(p / n)); //if (!sweepFlag && angleExtent > 0) //{ // angleExtent -= 360f; //} //else if (sweepFlag && angleExtent < 0) //{ // angleExtent += 360f; //} result.cx = cx; result.cy = cy; result.radStartAngle = angleStart; result.radSweepDiff = angleExtent; }
//--------------------------------------------------------------------- public void DrawArc( float fromX, float fromY, float endX, float endY, float xaxisRotationAngleDec, float rx, float ry, SvgArcSize arcSize, SvgArcSweep arcSweep) { //------------------ //SVG Elliptical arc ... //from Apache Batik //----------------- CenterFormArc centerFormArc = new CenterFormArc(); ComputeArc2(fromX, fromY, rx, ry, AggMath.deg2rad(xaxisRotationAngleDec), arcSize == SvgArcSize.Large, arcSweep == SvgArcSweep.Negative, endX, endY, ref centerFormArc); // using (VectorToolBox.Borrow(out Arc arcTool)) using (VxsTemp.Borrow(out var v1, out var v2, out var v3)) { arcTool.Init(centerFormArc.cx, centerFormArc.cy, rx, ry, centerFormArc.radStartAngle, (centerFormArc.radStartAngle + centerFormArc.radSweepDiff)); bool stopLoop = false; foreach (VertexData vertexData in arcTool.GetVertexIter()) { switch (vertexData.command) { case VertexCmd.NoMore: stopLoop = true; break; default: v1.AddVertex(vertexData.x, vertexData.y, vertexData.command); //yield return vertexData; break; } //------------------------------ if (stopLoop) { break; } } double scaleRatio = 1; if (centerFormArc.scaleUp) { int vxs_count = v1.Count; double px0, py0, px_last, py_last; v1.GetVertex(0, out px0, out py0); v1.GetVertex(vxs_count - 1, out px_last, out py_last); double distance1 = Math.Sqrt((px_last - px0) * (px_last - px0) + (py_last - py0) * (py_last - py0)); double distance2 = Math.Sqrt((endX - fromX) * (endX - fromX) + (endY - fromY) * (endY - fromY)); if (distance1 < distance2) { scaleRatio = distance2 / distance1; } else { } } if (xaxisRotationAngleDec != 0) { //also rotate if (centerFormArc.scaleUp) { //var mat = Affine.NewMatix( // new AffinePlan(AffineMatrixCommand.Translate, -centerFormArc.cx, -centerFormArc.cy), // new AffinePlan(AffineMatrixCommand.Scale, scaleRatio, scaleRatio), // new AffinePlan(AffineMatrixCommand.Rotate, DegToRad(xaxisRotationAngleDec)), // new AffinePlan(AffineMatrixCommand.Translate, centerFormArc.cx, centerFormArc.cy)); //mat1.TransformToVxs(v1, v2); //v1 = v2; AffineMat mat = AffineMat.Iden; mat.Translate(-centerFormArc.cx, -centerFormArc.cy); mat.Scale(scaleRatio); mat.RotateDeg(xaxisRotationAngleDec); mat.Translate(centerFormArc.cx, centerFormArc.cy); VertexStoreTransformExtensions.TransformToVxs(ref mat, v1, v2); v1 = v2; } else { //not scale //var mat = Affine.NewMatix( // AffinePlan.Translate(-centerFormArc.cx, -centerFormArc.cy), // AffinePlan.RotateDeg(xaxisRotationAngleDec), // AffinePlan.Translate(centerFormArc.cx, centerFormArc.cy)); //mat.TransformToVxs(v1, v2); //v1 = v2; AffineMat mat = AffineMat.Iden; mat.Translate(-centerFormArc.cx, -centerFormArc.cy); mat.RotateDeg(xaxisRotationAngleDec); mat.Translate(centerFormArc.cx, centerFormArc.cy); VertexStoreTransformExtensions.TransformToVxs(ref mat, v1, v2); v1 = v2; } } else { //no rotate if (centerFormArc.scaleUp) { //var mat = Affine.NewMatix( // new AffinePlan(AffineMatrixCommand.Translate, -centerFormArc.cx, -centerFormArc.cy), // new AffinePlan(AffineMatrixCommand.Scale, scaleRatio, scaleRatio), // new AffinePlan(AffineMatrixCommand.Translate, centerFormArc.cx, centerFormArc.cy)); //mat.TransformToVxs(v1, v2); //v1 = v2; AffineMat mat = AffineMat.Iden; mat.Translate(-centerFormArc.cx, -centerFormArc.cy); mat.RotateDeg(scaleRatio); mat.Translate(centerFormArc.cx, centerFormArc.cy); // VertexStoreTransformExtensions.TransformToVxs(ref mat, v1, v2); v1 = v2; } } //_stroke.Width = this.StrokeWidth; //_stroke.MakeVxs(v1, v3); //_pcx.DrawGfxPath(_pcx.StrokeColor, _pathRenderVxBuilder.CreatePathRenderVx(v3)); } }
//--------------------------------------------------------------------- public void DrawArc(float fromX, float fromY, float endX, float endY, float xaxisRotationAngleDec, float rx, float ry, SvgArcSize arcSize, SvgArcSweep arcSweep) { //------------------ //SVG Elliptical arc ... //from Apache Batik //----------------- CenterFormArc centerFormArc = new CenterFormArc(); ComputeArc2(fromX, fromY, rx, ry, DegToRad(xaxisRotationAngleDec), arcSize == SvgArcSize.Large, arcSweep == SvgArcSweep.Negative, endX, endY, ref centerFormArc); arcTool.Init(centerFormArc.cx, centerFormArc.cy, rx, ry, centerFormArc.radStartAngle, (centerFormArc.radStartAngle + centerFormArc.radSweepDiff)); VertexStore v1 = GetFreeVxs(); bool stopLoop = false; foreach (VertexData vertexData in arcTool.GetVertexIter()) { switch (vertexData.command) { case VertexCmd.NoMore: stopLoop = true; break; default: v1.AddVertex(vertexData.x, vertexData.y, vertexData.command); //yield return vertexData; break; } //------------------------------ if (stopLoop) { break; } } double scaleRatio = 1; if (centerFormArc.scaleUp) { int vxs_count = v1.Count; double px0, py0, px_last, py_last; v1.GetVertex(0, out px0, out py0); v1.GetVertex(vxs_count - 1, out px_last, out py_last); double distance1 = Math.Sqrt((px_last - px0) * (px_last - px0) + (py_last - py0) * (py_last - py0)); double distance2 = Math.Sqrt((endX - fromX) * (endX - fromX) + (endY - fromY) * (endY - fromY)); if (distance1 < distance2) { scaleRatio = distance2 / distance1; } else { } } if (xaxisRotationAngleDec != 0) { //also rotate if (centerFormArc.scaleUp) { var mat = PixelFarm.Agg.Transform.Affine.NewMatix( new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Translate, -centerFormArc.cx, -centerFormArc.cy), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Scale, scaleRatio, scaleRatio), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Rotate, DegToRad(xaxisRotationAngleDec)), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Translate, centerFormArc.cx, centerFormArc.cy)); var v2 = GetFreeVxs(); mat.TransformToVxs(v1, v2); ReleaseVxs(ref v1); v1 = v2; } else { //not scalue var mat = PixelFarm.Agg.Transform.Affine.NewMatix( new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Translate, -centerFormArc.cx, -centerFormArc.cy), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Rotate, DegToRad(xaxisRotationAngleDec)), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Translate, centerFormArc.cx, centerFormArc.cy)); var v2 = GetFreeVxs(); mat.TransformToVxs(v1, v2); ReleaseVxs(ref v1); v1 = v2; } } else { //no rotate if (centerFormArc.scaleUp) { var mat = PixelFarm.Agg.Transform.Affine.NewMatix( new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Translate, -centerFormArc.cx, -centerFormArc.cy), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Scale, scaleRatio, scaleRatio), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Translate, centerFormArc.cx, centerFormArc.cy)); var v2 = GetFreeVxs(); mat.TransformToVxs(v1, v2); ReleaseVxs(ref v1); v1 = v2; } } _aggStroke.Width = this.StrokeWidth; var v3 = _aggStroke.MakeVxs(v1, GetFreeVxs()); _canvas.DrawGfxPath(_canvas.StrokeColor, InternalGraphicsPath.CreateGraphicsPath(new VertexStoreSnap(v3))); ReleaseVxs(ref v3); ReleaseVxs(ref v1); }
public void DrawArc(float fromX, float fromY, float endX, float endY, float xaxisRotationAngleDec, float rx, float ry, SvgArcSize arcSize, SvgArcSweep arcSweep) { //------------------ //SVG Elliptical arc ... //from Apache Batik //----------------- CenterFormArc centerFormArc = new CenterFormArc(); ComputeArc2(fromX, fromY, rx, ry, DegToRad(xaxisRotationAngleDec), arcSize == SvgArcSize.Large, arcSweep == SvgArcSweep.Negative, endX, endY, ref centerFormArc); arcTool.Init(centerFormArc.cx, centerFormArc.cy, rx, ry, centerFormArc.radStartAngle, (centerFormArc.radStartAngle + centerFormArc.radSweepDiff)); VertexStore vxs = new VertexStore(); bool stopLoop = false; foreach (VertexData vertexData in arcTool.GetVertexIter()) { switch (vertexData.command) { case VertexCmd.Stop: stopLoop = true; break; default: vxs.AddVertex(vertexData.x, vertexData.y, vertexData.command); //yield return vertexData; break; } //------------------------------ if (stopLoop) { break; } } double scaleRatio = 1; if (centerFormArc.scaleUp) { int vxs_count = vxs.Count; double px0, py0, px_last, py_last; vxs.GetVertex(0, out px0, out py0); vxs.GetVertex(vxs_count - 1, out px_last, out py_last); double distance1 = Math.Sqrt((px_last - px0) * (px_last - px0) + (py_last - py0) * (py_last - py0)); double distance2 = Math.Sqrt((endX - fromX) * (endX - fromX) + (endY - fromY) * (endY - fromY)); if (distance1 < distance2) { scaleRatio = distance2 / distance1; } else { } } if (xaxisRotationAngleDec != 0) { //also rotate if (centerFormArc.scaleUp) { var mat = PixelFarm.Agg.Transform.Affine.NewMatix( new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Translate, -centerFormArc.cx, -centerFormArc.cy), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Scale, scaleRatio, scaleRatio), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Rotate, DegToRad(xaxisRotationAngleDec)), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Translate, centerFormArc.cx, centerFormArc.cy)); vxs = mat.TransformToVxs(vxs); } else { //not scalue var mat = PixelFarm.Agg.Transform.Affine.NewMatix( new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Translate, -centerFormArc.cx, -centerFormArc.cy), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Rotate, DegToRad(xaxisRotationAngleDec)), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Translate, centerFormArc.cx, centerFormArc.cy)); vxs = mat.TransformToVxs(vxs); } } else { //no rotate if (centerFormArc.scaleUp) { var mat = PixelFarm.Agg.Transform.Affine.NewMatix( new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Translate, -centerFormArc.cx, -centerFormArc.cy), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Scale, scaleRatio, scaleRatio), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Translate, centerFormArc.cx, centerFormArc.cy)); vxs = mat.TransformToVxs(vxs); } } vxs = aggStroke.MakeVxs(vxs); sclineRas.Reset(); sclineRas.AddPath(vxs); sclineRasToGL.DrawWithColor(sclineRas, sclinePack8, this.strokeColor); }
static void ComputeArc2(double x0, double y0, double rx, double ry, double xAngleRad, bool largeArcFlag, bool sweepFlag, double x, double y, ref CenterFormArc result) { //from SVG1.1 spec //---------------------------------- //step1: Compute (x1dash,y1dash) //---------------------------------- double dx2 = (x0 - x) / 2.0; double dy2 = (y0 - y) / 2.0; double cosAngle = Math.Cos(xAngleRad); double sinAngle = Math.Sin(xAngleRad); double x1 = (cosAngle * dx2 + sinAngle * dy2); double y1 = (-sinAngle * dx2 + cosAngle * dy2); // Ensure radii are large enough rx = Math.Abs(rx); ry = Math.Abs(ry); 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; result.scaleUp = true; } //---------------------------------- //step2: 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); //---------------------------------- //step3: 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); //---------------------------------- //step4: Compute theta and anfkediff 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)); // Math.toDegrees(sign * Math.Acos(p / n)); // 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));// Math.toDegrees(sign * Math.Acos(p / n)); //if (!sweepFlag && angleExtent > 0) //{ // angleExtent -= 360f; //} //else if (sweepFlag && angleExtent < 0) //{ // angleExtent += 360f; //} result.cx = cx; result.cy = cy; result.radStartAngle = angleStart; result.radSweepDiff = angleExtent; }
//--------------------------------------------------------------------- public void DrawArc(float fromX, float fromY, float endX, float endY, float xaxisRotationAngleDec, float rx, float ry, SvgArcSize arcSize, SvgArcSweep arcSweep) { //------------------ //SVG Elliptical arc ... //from Apache Batik //----------------- CenterFormArc centerFormArc = new CenterFormArc(); ComputeArc2(fromX, fromY, rx, ry, DegToRad(xaxisRotationAngleDec), arcSize == SvgArcSize.Large, arcSweep == SvgArcSweep.Negative, endX, endY, ref centerFormArc); arcTool.Init(centerFormArc.cx, centerFormArc.cy, rx, ry, centerFormArc.radStartAngle, (centerFormArc.radStartAngle + centerFormArc.radSweepDiff)); VertexStore v1 = GetFreeVxs(); bool stopLoop = false; foreach (VertexData vertexData in arcTool.GetVertexIter()) { switch (vertexData.command) { case VertexCmd.Stop: stopLoop = true; break; default: v1.AddVertex(vertexData.x, vertexData.y, vertexData.command); //yield return vertexData; break; } //------------------------------ if (stopLoop) { break; } } double scaleRatio = 1; if (centerFormArc.scaleUp) { int vxs_count = v1.Count; double px0, py0, px_last, py_last; v1.GetVertex(0, out px0, out py0); v1.GetVertex(vxs_count - 1, out px_last, out py_last); double distance1 = Math.Sqrt((px_last - px0) * (px_last - px0) + (py_last - py0) * (py_last - py0)); double distance2 = Math.Sqrt((endX - fromX) * (endX - fromX) + (endY - fromY) * (endY - fromY)); if (distance1 < distance2) { scaleRatio = distance2 / distance1; } else { } } if (xaxisRotationAngleDec != 0) { //also rotate if (centerFormArc.scaleUp) { var mat = PixelFarm.Agg.Transform.Affine.NewMatix( new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Translate, -centerFormArc.cx, -centerFormArc.cy), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Scale, scaleRatio, scaleRatio), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Rotate, DegToRad(xaxisRotationAngleDec)), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Translate, centerFormArc.cx, centerFormArc.cy)); var v2 = GetFreeVxs(); mat.TransformToVxs(v1, v2); ReleaseVxs(ref v1); v1 = v2; } else { //not scalue var mat = PixelFarm.Agg.Transform.Affine.NewMatix( new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Translate, -centerFormArc.cx, -centerFormArc.cy), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Rotate, DegToRad(xaxisRotationAngleDec)), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Translate, centerFormArc.cx, centerFormArc.cy)); var v2 = GetFreeVxs(); mat.TransformToVxs(v1, v2); ReleaseVxs(ref v1); v1 = v2; } } else { //no rotate if (centerFormArc.scaleUp) { var mat = PixelFarm.Agg.Transform.Affine.NewMatix( new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Translate, -centerFormArc.cx, -centerFormArc.cy), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Scale, scaleRatio, scaleRatio), new PixelFarm.Agg.Transform.AffinePlan(PixelFarm.Agg.Transform.AffineMatrixCommand.Translate, centerFormArc.cx, centerFormArc.cy)); var v2 = GetFreeVxs(); mat.TransformToVxs(v1, v2); ReleaseVxs(ref v1); v1 = v2; } } _aggStroke.Width = this.StrokeWidth; var v3 = _aggStroke.MakeVxs(v1, GetFreeVxs()); _canvas.DrawGfxPath(_canvas.StrokeColor, InternalGraphicsPath.CreateGraphicsPath(new VertexStoreSnap(v3))); ReleaseVxs(ref v3); ReleaseVxs(ref v1); }