Beispiel #1
0
        static Arc ComputeArc(double x0, double y0,
                              double rx, double ry,
                              double angle,
                              bool largeArcFlag,
                              bool sweepFlag,
                              double x, double y)
        {
            //from Apache2, https://xmlgraphics.apache.org/

            /**
             * This constructs an unrotated Arc2D from the SVG specification of an
             * Elliptical arc.  To get the final arc you need to apply a rotation
             * transform such as:
             *
             * AffineTransform.getRotateInstance
             *     (angle, arc.getX()+arc.getWidth()/2, arc.getY()+arc.getHeight()/2);
             */
            //
            // Elliptical arc implementation based on the SVG specification notes
            //

            // 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
            angle = ((angle % 360.0) * Math.PI / 180f);
            double cosAngle = Math.Cos(angle);
            double sinAngle = Math.Sin(angle);
            //
            // Step 1 : Compute (x1, y1)
            //
            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;
            }

            //
            // 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)); // 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;
            }
            //angleExtent %= 360f;
            //angleStart %= 360f;

            //
            // We can now build the resulting Arc2D in double precision
            //
            //Arc2D.Double arc = new Arc2D.Double();
            //arc.x = cx - rx;
            //arc.y = cy - ry;
            //arc.width = rx * 2.0;
            //arc.height = ry * 2.0;
            //arc.start = -angleStart;
            //arc.extent = -angleExtent;
            Arc arc = new Arc();

            arc.Init(x, y, rx, ry, -(angleStart), -(angleExtent));
            return(arc);
        }
        IEnumerable <VertexData> GetVertexIter()
        {
            currentProcessingArc.UseStartEndLimit = true;
            currentProcessingArc.Init(bounds.Left + leftBottomRadius.x, bounds.Bottom + leftBottomRadius.y, leftBottomRadius.x, leftBottomRadius.y, Math.PI, Math.PI + Math.PI * 0.5);
            currentProcessingArc.SetStartEndLimit(bounds.Left, bounds.Bottom + leftBottomRadius.y,
                                                  bounds.Left + leftBottomRadius.x, bounds.Bottom);
            foreach (VertexData vertexData in currentProcessingArc.GetVertexIter())
            {
                if (VertexHelper.IsEmpty(vertexData.command))
                {
                    break;
                }
                yield return(vertexData);
            }


            currentProcessingArc.Init(bounds.Right - rightBottomRadius.x, bounds.Bottom + rightBottomRadius.y, rightBottomRadius.x, rightBottomRadius.y, Math.PI + Math.PI * 0.5, 0.0);
            currentProcessingArc.SetStartEndLimit(bounds.Right - rightBottomRadius.x,
                                                  bounds.Bottom, bounds.Right, bounds.Bottom + rightBottomRadius.y);
            foreach (VertexData vertexData in currentProcessingArc.GetVertexIter())
            {
                if (VertexHelper.IsMoveTo(vertexData.command))
                {
                    // skip the initial moveto
                    continue;
                }
                if (VertexHelper.IsEmpty(vertexData.command))
                {
                    break;
                }
                yield return(vertexData);
            }


            currentProcessingArc.Init(bounds.Right - rightTopRadius.x, bounds.Top - rightTopRadius.y, rightTopRadius.x, rightTopRadius.y, 0.0, Math.PI * 0.5);
            currentProcessingArc.SetStartEndLimit(bounds.Right, bounds.Top - rightTopRadius.y,
                                                  bounds.Right - rightTopRadius.x, bounds.Top);
            foreach (VertexData vertexData in currentProcessingArc.GetVertexIter())
            {
                if (VertexHelper.IsMoveTo(vertexData.command))
                {
                    // skip the initial moveto
                    continue;
                }
                if (VertexHelper.IsEmpty(vertexData.command))
                {
                    break;
                }
                yield return(vertexData);
            }


            currentProcessingArc.Init(bounds.Left + leftTopRadius.x, bounds.Top - leftTopRadius.y, leftTopRadius.x, leftTopRadius.y, Math.PI * 0.5, Math.PI);
            currentProcessingArc.SetStartEndLimit(bounds.Left - leftTopRadius.x, bounds.Top,
                                                  bounds.Left, bounds.Top - leftTopRadius.y);
            foreach (VertexData vertexData in currentProcessingArc.GetVertexIter())
            {
                switch (vertexData.command)
                {
                case VertexCmd.MoveTo:
                    continue;

                case VertexCmd.NoMore:
                    break;

                default:
                    yield return(vertexData);

                    break;
                }
            }

            yield return(new VertexData(VertexCmd.Close, (int)EndVertexOrientation.CCW, 0));

            yield return(new VertexData(VertexCmd.NoMore));
        }