svg中的arc转化为java中的arc

最近项目需要解析svg中的path.直线和贝塞尔曲线都好办,唯独arc不太好办.

svg中的arc是由弧上两点,角度确定的,而java中的arc是由弧的外接矩形和角度决定的.

所有中间需要一个转换工作.

好吧,我自己是转化不来的,apache的batik提供了全套的svg解析,它肯定转化过来了.于是去拔它的算法.

中间辛苦不用说,找到了相关的计算类.

 

仿照PathIterator做一个遍历接口

 

Java代码   收藏代码
  1. import java.awt.geom.PathIterator;  
  2.   
  3. /** 
  4.  * The <code>ExtendedPathIterator</code> class represents a geometric 
  5.  * path constructed from straight lines, quadratic and cubic (Bezier) 
  6.  * curves and elliptical arcs.  This interface is identical to that of 
  7.  * PathIterator except it can return SEG_ARCTO from currentSegment, 
  8.  * also the array of values passed to currentSegment must be of length 
  9.  * 7 or an error will be thrown. 
  10.  *  
  11.  * This does not extend PathIterator as it would break the interface 
  12.  * contract for that class. 
  13.  * 
  14.  * @author <a href="mailto:deweese@apache.org">Thomas DeWeese</a> 
  15.  * @version $Id: ExtendedPathIterator.java,v 1.1 2011/05/27 03:01:11 zhengll Exp $ 
  16.  */  
  17. public interface ExtendedPathIterator {  
  18.   
  19.     /** 
  20.      * The segment type constant that specifies that the preceding 
  21.      * subpath should be closed by appending a line segment back to 
  22.      * the point corresponding to the most recent SEG_MOVETO. 
  23.      */  
  24.     int SEG_CLOSE   = PathIterator.SEG_CLOSE;  
  25.   
  26.     /**  
  27.      * The segment type constant for a point that specifies the end 
  28.      * point of a line to be drawn from the most recently specified 
  29.      * point.  */  
  30.     int SEG_MOVETO  = PathIterator.SEG_MOVETO;  
  31.   
  32.     /** 
  33.      * The segment type constant for a point that specifies the end 
  34.      * point of a line to be drawn from the most recently specified 
  35.      * point. 
  36.      */  
  37.     int SEG_LINETO  = PathIterator.SEG_LINETO;  
  38.   
  39.     /** 
  40.      * The segment type constant for the pair of points that specify a 
  41.      * quadratic parametric curve to be drawn from the most recently 
  42.      * specified point. The curve is interpolated by solving the 
  43.      * parametric control equation in the range (t=[0..1]) using the 
  44.      * most recently specified (current) point (CP), the first control 
  45.      * point (P1), and the final interpolated control point (P2).  
  46.      */  
  47.     int SEG_QUADTO  = PathIterator.SEG_QUADTO;  
  48.   
  49.     /** 
  50.      * The segment type constant for the set of 3 points that specify 
  51.      * a cubic parametric curve to be drawn from the most recently 
  52.      * specified point. The curve is interpolated by solving the 
  53.      * parametric control equation in the range (t=[0..1]) using the 
  54.      * most recently specified (current) point (CP), the first control 
  55.      * point (P1), the second control point (P2), and the final 
  56.      * interpolated control point (P3). 
  57.      */  
  58.     int SEG_CUBICTO = PathIterator.SEG_CUBICTO;  
  59.   
  60.     /** The segment type constant for an elliptical arc.  This consists of 
  61.      *  Seven values [rx, ry, angle, largeArcFlag, sweepFlag, x, y]. 
  62.      *  rx, ry are the radious of the ellipse. 
  63.      *  angle is angle of the x axis of the ellipse. 
  64.      *  largeArcFlag is zero if the smaller of the two arcs are to be used. 
  65.      *  sweepFlag is zero if the 'left' branch is taken one otherwise. 
  66.      *  x and y are the destination for the ellipse.  */  
  67.     int SEG_ARCTO = 4321;  
  68.   
  69.     /** The winding rule constant for specifying an even-odd rule for 
  70.      * determining the interior of a path. The even-odd rule specifies 
  71.      * that a point lies inside the path if a ray drawn in any 
  72.      * direction from that point to infinity is crossed by path 
  73.      * segments an odd number of times.   
  74.      */   
  75.     int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD;   
  76.   
  77.     /** 
  78.      * The winding rule constant for specifying a non-zero rule for 
  79.      * determining the interior of a path. The non-zero rule specifies 
  80.      * that a point lies inside the path if a ray drawn in any 
  81.      * direction from that point to infinity is crossed by path 
  82.      * segments a different number of times in the counter-clockwise 
  83.      * direction than the clockwise direction. 
  84.      */  
  85.     int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO;  
  86.   
  87.     int currentSegment();  
  88.     int currentSegment(double[] coords);  
  89.     int currentSegment(float[] coords);  
  90.     int getWindingRule();   
  91.     boolean isDone();  
  92.     void next();  
  93. }  

 

再做一个保存信息的中间集合图形

 

Java代码   收藏代码
  1. import java.awt.Shape;  
  2.   
  3. /** 
  4.  * The <code>ExtendedShape</code> class represents a geometric 
  5.  * path constructed from straight lines, quadratic and cubic (Bezier) 
  6.  * curves and elliptical arcs. 
  7.  * @author <a href="mailto:deweese@apache.org">Thomas DeWeese</a> 
  8.  * @version $Id: ExtendedShape.java,v 1.1 2011/05/27 03:01:11 zhengll Exp $ 
  9.  */  
  10. public interface ExtendedShape extends Shape {  
  11.     /** 
  12.      * Get an extended Path iterator that may return SEG_ARCTO commands 
  13.      */  
  14.     ExtendedPathIterator getExtendedPathIterator();  
  15.   
  16. }  

 

重头戏来了,计算逻辑

 

Java代码   收藏代码
  1. import java.awt.Shape;  
  2. import java.awt.Rectangle;  
  3. import java.awt.geom.AffineTransform;  
  4. import java.awt.geom.Arc2D;  
  5. import java.awt.geom.GeneralPath;  
  6. import java.awt.geom.PathIterator;  
  7. import java.awt.geom.Point2D;  
  8. import java.awt.geom.Rectangle2D;  
  9. import java.util.Arrays;  
  10.   
  11. /** 
  12.  * The <code>ExtendedGeneralPath</code> class represents a geometric 
  13.  * path constructed from straight lines, quadratic and cubic (Bezier) 
  14.  * curves and elliptical arc. This class delegates lines and curves to 
  15.  * an enclosed <code>GeneralPath</code>. Elliptical arc is implemented 
  16.  * using an <code>Arc2D</code> in float precision. 
  17.  * 
  18.  * <p><b>Warning</b> : An elliptical arc may be composed of several 
  19.  * path segments. For futher details, see the SVG Appendix&nbsp;F.6 
  20.  * 
  21.  * @author <a href="mailto:Thierry.Kormann@sophia.inria.fr">Thierry Kormann</a> 
  22.  * @version $Id: ExtendedGeneralPath.java,v 1.1 2011/05/27 03:01:11 zhengll Exp $ 
  23.  */  
  24. public class ExtendedGeneralPath implements ExtendedShape, Cloneable {  
  25.   
  26.     /** The enclosed general path. */  
  27.     protected GeneralPath path;  
  28.   
  29.     int      numVals = 0;  
  30.     int      numSeg  = 0;  
  31.     float [] values  = null;  
  32.     int   [] types   = null;  
  33.   
  34.     float    mx, my, cx, cy;  
  35.   
  36.    /** 
  37.      * Constructs a new <code>ExtendedGeneralPath</code>. 
  38.      */  
  39.     public ExtendedGeneralPath() {  
  40.         path = new GeneralPath();  
  41.     }  
  42.   
  43.     /** 
  44.      * Constructs a new <code>ExtendedGeneralPath</code> with the 
  45.      * specified winding rule to control operations that require the 
  46.      * interior of the path to be defined. 
  47.      */  
  48.     public ExtendedGeneralPath(int rule) {  
  49.         path = new GeneralPath(rule);  
  50.     }  
  51.   
  52.     /** 
  53.      * Constructs a new <code>ExtendedGeneralPath</code> object with 
  54.      * the specified winding rule and the specified initial capacity 
  55.      * to store path coordinates. 
  56.      */  
  57.     public ExtendedGeneralPath(int rule, int initialCapacity) {  
  58.         path = new GeneralPath(rule, initialCapacity);  
  59.     }  
  60.   
  61.     /** 
  62.      * Constructs a new <code>ExtendedGeneralPath</code> object from 
  63.      * an arbitrary <code>Shape</code> object. 
  64.      */  
  65.     public ExtendedGeneralPath(Shape s) {  
  66.         this();  
  67.         append(s, false);  
  68.     }  
  69.   
  70.     /** 
  71.      * Adds an elliptical arc, defined by two radii, an angle from the 
  72.      * x-axis, a flag to choose the large arc or not, a flag to 
  73.      * indicate if we increase or decrease the angles and the final 
  74.      * point of the arc. 
  75.      * 
  76.      * @param rx the x radius of the ellipse 
  77.      * @param ry the y radius of the ellipse 
  78.      * 
  79.      * @param angle the angle from the x-axis of the current 
  80.      * coordinate system to the x-axis of the ellipse in degrees. 
  81.      * 
  82.      * @param largeArcFlag the large arc flag. If true the arc 
  83.      * spanning less than or equal to 180 degrees is chosen, otherwise 
  84.      * the arc spanning greater than 180 degrees is chosen 
  85.      * 
  86.      * @param sweepFlag the sweep flag. If true the line joining 
  87.      * center to arc sweeps through decreasing angles otherwise it 
  88.      * sweeps through increasing angles 
  89.      * 
  90.      * @param x the absolute x coordinate of the final point of the arc. 
  91.      * @param y the absolute y coordinate of the final point of the arc. 
  92.      */  
  93.     public synchronized void arcTo(float rx, float ry,  
  94.                                    float angle,  
  95.                                    boolean largeArcFlag,  
  96.                                    boolean sweepFlag,  
  97.                                    float x, float y) {  
  98.   
  99.         // Ensure radii are valid  
  100.         if (rx == 0 || ry == 0) {  
  101.             lineTo(x, y);  
  102.             return;  
  103.         }  
  104.   
  105.         checkMoveTo();  // check if prev command was moveto  
  106.   
  107.         // Get the current (x, y) coordinates of the path  
  108.         double x0 = cx;  
  109.         double y0 = cy;  
  110.         if (x0 == x && y0 == y) {  
  111.             // If the endpoints (x, y) and (x0, y0) are identical, then this  
  112.             // is equivalent to omitting the elliptical arc segment entirely.  
  113.             return;  
  114.         }  
  115.   
  116.         Arc2D arc = computeArc(x0, y0, rx, ry, angle,  
  117.                                largeArcFlag, sweepFlag, x, y);  
  118.         if (arc == nullreturn;  
  119.   
  120.         AffineTransform t = AffineTransform.getRotateInstance  
  121.             (Math.toRadians(angle), arc.getCenterX(), arc.getCenterY());  
  122.         Shape s = t.createTransformedShape(arc);  
  123.         path.append(s, true);  
  124.   
  125.         makeRoom(7);  
  126.         types [numSeg++]  = ExtendedPathIterator.SEG_ARCTO;  
  127.         values[numVals++] = rx;  
  128.         values[numVals++] = ry;  
  129.         values[numVals++] = angle;  
  130.         values[numVals++] = largeArcFlag?1:0;  
  131.         values[numVals++] = sweepFlag?1:0;  
  132.         cx = values[numVals++] = x;  
  133.         cy = values[numVals++] = y;  
  134.     }  
  135.   
  136.   
  137.     /** 
  138.      * This constructs an unrotated Arc2D from the SVG specification of an 
  139.      * Elliptical arc.  To get the final arc you need to apply a rotation 
  140.      * transform such as: 
  141.      * 
  142.      * AffineTransform.getRotateInstance 
  143.      *     (angle, arc.getX()+arc.getWidth()/2, arc.getY()+arc.getHeight()/2); 
  144.      */  
  145.     public static Arc2D computeArc(double x0, double y0,  
  146.                                    double rx, double ry,  
  147.                                    double angle,  
  148.                                    boolean largeArcFlag,  
  149.                                    boolean sweepFlag,  
  150.                                    double x, double y) {  
  151.         //  
  152.         // Elliptical arc implementation based on the SVG specification notes  
  153.         //  
  154.   
  155.         // Compute the half distance between the current and the final point  
  156.         double dx2 = (x0 - x) / 2.0;  
  157.         double dy2 = (y0 - y) / 2.0;  
  158.         // Convert angle from degrees to radians  
  159.         angle = Math.toRadians(angle % 360.0);  
  160.         double cosAngle = Math.cos(angle);  
  161.         double sinAngle = Math.sin(angle);  
  162.   
  163.         //  
  164.         // Step 1 : Compute (x1, y1)  
  165.         //  
  166.         double x1 = (cosAngle * dx2 + sinAngle * dy2);  
  167.         double y1 = (-sinAngle * dx2 + cosAngle * dy2);  
  168.         // Ensure radii are large enough  
  169.         rx = Math.abs(rx);  
  170.         ry = Math.abs(ry);  
  171.         double Prx = rx * rx;  
  172.         double Pry = ry * ry;  
  173.         double Px1 = x1 * x1;  
  174.         double Py1 = y1 * y1;  
  175.         // check that radii are large enough  
  176.         double radiiCheck = Px1/Prx + Py1/Pry;  
  177.         if (radiiCheck > 1) {  
  178.             rx = Math.sqrt(radiiCheck) * rx;  
  179.             ry = Math.sqrt(radiiCheck) * ry;  
  180.             Prx = rx * rx;  
  181.             Pry = ry * ry;  
  182.         }  
  183.   
  184.         //  
  185.         // Step 2 : Compute (cx1, cy1)  
  186.         //  
  187.         double sign = (largeArcFlag == sweepFlag) ? -1 : 1;  
  188.         double sq = ((Prx*Pry)-(Prx*Py1)-(Pry*Px1)) / ((Prx*Py1)+(Pry*Px1));  
  189.         sq = (sq < 0) ? 0 : sq;  
  190.         double coef = (sign * Math.sqrt(sq));  
  191.         double cx1 = coef * ((rx * y1) / ry);  
  192.         double cy1 = coef * -((ry * x1) / rx);  
  193.   
  194.         //  
  195.         // Step 3 : Compute (cx, cy) from (cx1, cy1)  
  196.         //  
  197.         double sx2 = (x0 + x) / 2.0;  
  198.         double sy2 = (y0 + y) / 2.0;  
  199.         double cx = sx2 + (cosAngle * cx1 - sinAngle * cy1);  
  200.         double cy = sy2 + (sinAngle * cx1 + cosAngle * cy1);  
  201.   
  202.         //  
  203.         // Step 4 : Compute the angleStart (angle1) and the angleExtent (dangle)  
  204.         //  
  205.         double ux = (x1 - cx1) / rx;  
  206.         double uy = (y1 - cy1) / ry;  
  207.         double vx = (-x1 - cx1) / rx;  
  208.         double vy = (-y1 - cy1) / ry;  
  209.         double p, n;  
  210.         // Compute the angle start  
  211.         n = Math.sqrt((ux * ux) + (uy * uy));  
  212.         p = ux; // (1 * ux) + (0 * uy)  
  213.         sign = (uy < 0) ? -1.0 : 1.0;  
  214.         double angleStart = Math.toDegrees(sign * Math.acos(p / n));  
  215.   
  216.         // Compute the angle extent  
  217.         n = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));  
  218.         p = ux * vx + uy * vy;  
  219.         sign = (ux * vy - uy * vx < 0) ? -1.0 : 1.0;  
  220.         double angleExtent = Math.toDegrees(sign * Math.acos(p / n));  
  221.         if(!sweepFlag && angleExtent > 0) {  
  222.             angleExtent -= 360f;  
  223.         } else if (sweepFlag && angleExtent < 0) {  
  224.             angleExtent += 360f;  
  225.         }  
  226.         angleExtent %= 360f;  
  227.         angleStart %= 360f;  
  228.   
  229.         //  
  230.         // We can now build the resulting Arc2D in double precision  
  231.         //  
  232.         Arc2D.Double arc = new Arc2D.Double();  
  233.         arc.x = cx - rx;  
  234.         arc.y = cy - ry;  
  235.         arc.width = rx * 2.0;  
  236.         arc.height = ry * 2.0;  
  237.         arc.start = -angleStart;  
  238.         arc.extent = -angleExtent;  
  239.   
  240.         return arc;  
  241.     }  
  242.   
  243.     /** 
  244.      * Delegates to the enclosed <code>GeneralPath</code>. 
  245.      */  
  246.     public synchronized void moveTo(float x, float y) {  
  247.         // Don't add moveto to general path unless there is a reason.  
  248.         makeRoom(2);  
  249.         types [numSeg++]  = PathIterator.SEG_MOVETO;  
  250.         cx = mx = values[numVals++] = x;  
  251.         cy = my = values[numVals++] = y;  
  252.   
  253.     }  
  254.   
  255.     /** 
  256.      * Delegates to the enclosed <code>GeneralPath</code>. 
  257.      */  
  258.     public synchronized void lineTo(float x, float y) {  
  259.         checkMoveTo();  // check if prev command was moveto  
  260.         path.lineTo(x, y);  
  261.   
  262.         makeRoom(2);  
  263.         types [numSeg++]  = PathIterator.SEG_LINETO;  
  264.         cx = values[numVals++] = x;  
  265.         cy = values[numVals++] = y;  
  266.     }  
  267.   
  268.     /** 
  269.      * Delegates to the enclosed <code>GeneralPath</code>. 
  270.      */  
  271.     public synchronized void quadTo(float x1, float y1, float x2, float y2) {  
  272.         checkMoveTo();  // check if prev command was moveto  
  273.         path.quadTo(x1, y1, x2, y2);  
  274.   
  275.         makeRoom(4);  
  276.         types [numSeg++]  = PathIterator.SEG_QUADTO;  
  277.         values[numVals++] = x1;  
  278.         values[numVals++] = y1;  
  279.         cx = values[numVals++] = x2;  
  280.         cy = values[numVals++] = y2;  
  281.     }  
  282.   
  283.     /** 
  284.      * Delegates to the enclosed <code>GeneralPath</code>. 
  285.      */  
  286.     public synchronized void curveTo(float x1, float y1,  
  287.                                      float x2, float y2,  
  288.                                      float x3, float y3) {  
  289.         checkMoveTo();   // check if prev command was moveto  
  290.         path.curveTo(x1, y1, x2, y2, x3, y3);  
  291.   
  292.         makeRoom(6);  
  293.         types [numSeg++]  = PathIterator.SEG_CUBICTO;  
  294.         values[numVals++] = x1;  
  295.         values[numVals++] = y1;  
  296.         values[numVals++] = x2;  
  297.         values[numVals++] = y2;  
  298.         cx = values[numVals++] = x3;  
  299.         cy = values[numVals++] = y3;  
  300.     }  
  301.   
  302.     /** 
  303.      * Delegates to the enclosed <code>GeneralPath</code>. 
  304.      */  
  305.     public synchronized void closePath() {  
  306.         // Don't double close path.  
  307.         if ((numSeg != 0) && (types[numSeg-1] == PathIterator.SEG_CLOSE))  
  308.             return;  
  309.   
  310.         // Only close path if the previous command wasn't a moveto  
  311.         if ((numSeg != 0) && (types[numSeg-1] != PathIterator.SEG_MOVETO))  
  312.             path.closePath();  
  313.   
  314.         makeRoom(0);  
  315.         types [numSeg++]  = PathIterator.SEG_CLOSE;  
  316.         cx = mx;  
  317.         cy = my;  
  318.     }  
  319.   
  320.     /** 
  321.      * Checks if previous command was a moveto command, 
  322.      * skipping a close command (if present). 
  323.      */  
  324.     protected void checkMoveTo() {  
  325.         if (numSeg == 0return;  
  326.   
  327.         switch(types[numSeg-1]) {  
  328.   
  329.         case PathIterator.SEG_MOVETO:  
  330.             path.moveTo(values[numVals-2], values[numVals-1]);  
  331.             break;  
  332.   
  333.         case PathIterator.SEG_CLOSE:  
  334.             if (numSeg == 1return;  
  335.             if (types[numSeg-2] == PathIterator.SEG_MOVETO)  
  336.                 path.moveTo(values[numVals-2], values[numVals-1]);  
  337.             break;  
  338.   
  339.         default:  
  340.             break;  
  341.         }  
  342.     }  
  343.   
  344.     /** 
  345.      * Delegates to the enclosed <code>GeneralPath</code>. 
  346.      */  
  347.     public void append(Shape s, boolean connect) {  
  348.         append(s.getPathIterator(new AffineTransform()), connect);  
  349.     }  
  350.   
  351.     /** 
  352.      * Delegates to the enclosed <code>GeneralPath</code>. 
  353.      */  
  354.     public void append(PathIterator pi, boolean connect) {  
  355.         double [] vals = new double[6];  
  356.   
  357.         while (!pi.isDone()) {  
  358.             Arrays.fill( vals, 0 );  
  359.             int type = pi.currentSegment(vals);  
  360.             pi.next();  
  361.             if (connect && (numVals != 0)) {  
  362.                 if (type == PathIterator.SEG_MOVETO) {  
  363.                     double x = vals[0];  
  364.                     double y = vals[1];  
  365.                     if ((x != cx) ||  
  366.                         (y != cy)) {  
  367.                         // Change MOVETO to LINETO.  
  368.                         type = PathIterator.SEG_LINETO;  
  369.                     } else {  
  370.                         // Redundent segment (move to current loc) drop it...  
  371.                         if (pi.isDone()) break// Nothing interesting  
  372.                         type = pi.currentSegment(vals);  
  373.                         pi.next();  
  374.                     }  
  375.                 }  
  376.                 connect = false;  
  377.             }  
  378.   
  379.             switch(type) {  
  380.             case PathIterator.SEG_CLOSE:   closePath(); break;  
  381.             case PathIterator.SEG_MOVETO:  
  382.                 moveTo ((float)vals[0], (float)vals[1]); break;  
  383.             case PathIterator.SEG_LINETO:  
  384.                 lineTo ((float)vals[0], (float)vals[1]); break;  
  385.             case PathIterator.SEG_QUADTO:  
  386.                 quadTo ((float)vals[0], (float)vals[1],  
  387.                         (float)vals[2], (float)vals[3]); break;  
  388.             case PathIterator.SEG_CUBICTO:  
  389.                 curveTo((float)vals[0], (float)vals[1],  
  390.                         (float)vals[2], (float)vals[3],  
  391.                         (float)vals[4], (float)vals[5]); break;  
  392.             }  
  393.         }  
  394.     }  
  395.   
  396.     /** 
  397.      * Delegates to the enclosed <code>GeneralPath</code>. 
  398.      */  
  399.     public void append(ExtendedPathIterator epi, boolean connect) {  
  400.         float[] vals = new float7 ];  
  401.         while (!epi.isDone()) {  
  402.             Arrays.fill( vals, 0 );  
  403.             int type = epi.currentSegment(vals);  
  404.             epi.next();  
  405.             if (connect && (numVals != 0)) {  
  406.                 if (type == PathIterator.SEG_MOVETO) {  
  407.                     float x = vals[0];  
  408.                     float y = vals[1];  
  409.                     if ((x != cx) ||  
  410.                         (y != cy)) {  
  411.                         // Change MOVETO to LINETO.  
  412.                         type = PathIterator.SEG_LINETO;  
  413.                     } else {  
  414.                         // Redundant segment (move to current loc) drop it...  
  415.                         if (epi.isDone()) break// Nothing interesting  
  416.                         type = epi.currentSegment(vals);  
  417.                         epi.next();  
  418.                     }  
  419.                 }  
  420.                 connect = false;  
  421.             }  
  422.   
  423.             switch(type) {  
  424.             case PathIterator.SEG_CLOSE:   closePath(); break;  
  425.             case PathIterator.SEG_MOVETO:  
  426.                 moveTo (vals[0], vals[1]); break;  
  427.             case PathIterator.SEG_LINETO:  
  428.                 lineTo (vals[0], vals[1]); break;  
  429.             case PathIterator.SEG_QUADTO:  
  430.                 quadTo (vals[0], vals[1],  
  431.                         vals[2], vals[3]); break;  
  432.             case PathIterator.SEG_CUBICTO:  
  433.                 curveTo(vals[0], vals[1],  
  434.                         vals[2], vals[3],  
  435.                         vals[4], vals[5]); break;  
  436.             case ExtendedPathIterator.SEG_ARCTO:  
  437.                 arcTo  (vals[0], vals[1], vals[2],  
  438.                         (vals[3]!=0), (vals[4]!=0),  
  439.                         vals[5], vals[6]); break;  
  440.             }  
  441.         }  
  442.     }  
  443.   
  444.     /** 
  445.      * Delegates to the enclosed <code>GeneralPath</code>. 
  446.      */  
  447.     public synchronized int getWindingRule() {  
  448.         return path.getWindingRule();  
  449.     }  
  450.   
  451.     /** 
  452.      * Delegates to the enclosed <code>GeneralPath</code>. 
  453.      */  
  454.     public void setWindingRule(int rule) {  
  455.         path.setWindingRule(rule);  
  456.     }  
  457.   
  458.     /** 
  459.      * get the current position or <code>null</code>. 
  460.      */  
  461.     public synchronized Point2D getCurrentPoint() {  
  462.         if (numVals == 0return null;  
  463.         return new Point2D.Double(cx, cy);  
  464.     }  
  465.   
  466.     /** 
  467.      * Delegates to the enclosed <code>GeneralPath</code>. 
  468.      */  
  469.     public synchronized void reset() {  
  470.         path.reset();  
  471.   
  472.         numSeg = 0;  
  473.         numVals = 0;  
  474.         values = null;  
  475.         types = null;  
  476.     }  
  477.   
  478.     /** 
  479.      * Delegates to the enclosed <code>GeneralPath</code>. 
  480.      */  
  481.     public void transform(AffineTransform at) {  
  482.         if (at.getType() != AffineTransform.TYPE_IDENTITY)  
  483.             throw new IllegalArgumentException  
  484.                 ("ExtendedGeneralPaths can not be transformed");  
  485.     }  
  486.   
  487.     /** 
  488.      * Delegates to the enclosed <code>GeneralPath</code>. 
  489.      */  
  490.     public synchronized Shape createTransformedShape(AffineTransform at) {  
  491.         return path.createTransformedShape(at);  
  492.     }  
  493.   
  494.     /** 
  495.      * Delegates to the enclosed <code>GeneralPath</code>. 
  496.      */  
  497.     public synchronized Rectangle getBounds() {  
  498.         return path.getBounds();  
  499.     }  
  500.   
  501.     /** 
  502.      * Delegates to the enclosed <code>GeneralPath</code>. 
  503.      */  
  504.     public synchronized Rectangle2D getBounds2D() {  
  505.         return path.getBounds2D();  
  506.     }  
  507.   
  508.     /** 
  509.      * Delegates to the enclosed <code>GeneralPath</code>. 
  510.      */  
  511.     public boolean contains(double x, double y) {  
  512.         return path.contains(x, y);  
  513.     }  
  514.   
  515.     /** 
  516.      * Delegates to the enclosed <code>GeneralPath</code>. 
  517.      */  
  518.     public boolean contains(Point2D p) {  
  519.         return path.contains(p);  
  520.     }  
  521.   
  522.     /** 
  523.      * Delegates to the enclosed <code>GeneralPath</code>. 
  524.      */  
  525.     public boolean contains(double x, double y, double w, double h) {  
  526.         return path.contains(x, y, w, h);  
  527.     }  
  528.   
  529.     /** 
  530.      * Delegates to the enclosed <code>GeneralPath</code>. 
  531.      */  
  532.     public boolean contains(Rectangle2D r) {  
  533.         return path.contains(r);  
  534.     }  
  535.   
  536.     /** 
  537.      * Delegates to the enclosed <code>GeneralPath</code>. 
  538.      */  
  539.     public boolean intersects(double x, double y, double w, double h) {  
  540.         return path.intersects(x, y, w, h);  
  541.     }  
  542.   
  543.     /** 
  544.      * Delegates to the enclosed <code>GeneralPath</code>. 
  545.      */  
  546.     public boolean intersects(Rectangle2D r) {  
  547.         return path.intersects(r);  
  548.     }  
  549.   
  550.     /** 
  551.      * Delegates to the enclosed <code>GeneralPath</code>. 
  552.      */  
  553.     public PathIterator getPathIterator(AffineTransform at) {  
  554.         return path.getPathIterator(at);  
  555.     }  
  556.   
  557.     /** 
  558.      * Delegates to the enclosed <code>GeneralPath</code>. 
  559.      */  
  560.     public PathIterator getPathIterator(AffineTransform at, double flatness) {  
  561.         return path.getPathIterator(at, flatness);  
  562.     }  
  563.   
  564.     /** 
  565.      * Delegates to the enclosed <code>GeneralPath</code>. 
  566.      */  
  567.     public ExtendedPathIterator getExtendedPathIterator() {  
  568.         return new EPI();  
  569.     }  
  570.   
  571.     class EPI implements ExtendedPathIterator {  
  572.         int segNum = 0;  
  573.         int valsIdx = 0;  
  574.   
  575.         public int currentSegment() {  
  576.             return types[segNum];  
  577.         }  
  578.   
  579.         public int currentSegment(double[] coords) {  
  580.             int ret = types[segNum];  
  581.             switch (ret) {  
  582.             case SEG_CLOSE: break;  
  583.             case SEG_MOVETO:  
  584.             case SEG_LINETO:  
  585.                 coords[0] = values[valsIdx];  
  586.                 coords[1] = values[valsIdx+1];  
  587.                 break;  
  588.             case SEG_QUADTO:  
  589.                 coords[0] = values[valsIdx];  
  590.                 coords[1] = values[valsIdx+1];  
  591.                 coords[2] = values[valsIdx+2];  
  592.                 coords[3] = values[valsIdx+3];  
  593.                 break;  
  594.             case SEG_CUBICTO:  
  595.                 coords[0] = values[valsIdx];  
  596.                 coords[1] = values[valsIdx+1];  
  597.                 coords[2] = values[valsIdx+2];  
  598.                 coords[3] = values[valsIdx+3];  
  599.                 coords[4] = values[valsIdx+4];  
  600.                 coords[5] = values[valsIdx+5];  
  601.                 break;  
  602.             case SEG_ARCTO:  
  603.                 coords[0] = values[valsIdx];  
  604.                 coords[1] = values[valsIdx+1];  
  605.                 coords[2] = values[valsIdx+2];  
  606.                 coords[3] = values[valsIdx+3];  
  607.                 coords[4] = values[valsIdx+4];  
  608.                 coords[5] = values[valsIdx+5];  
  609.                 coords[6] = values[valsIdx+6];  
  610.                 break;  
  611.             }  
  612.             // System.out.println("Seg: [" + segNum + "] type: " + ret +  
  613.             //                    " vals: [" + coords[0] + ", " + coords[1] +  
  614.             //                    "]");  
  615.             return ret;  
  616.         }  
  617.   
  618.         public int currentSegment(float[] coords) {  
  619.             int ret = types[segNum];  
  620.             switch (ret) {  
  621.             case SEG_CLOSE: break;  
  622.             case SEG_MOVETO:  
  623.             case SEG_LINETO:  
  624.                 coords[0] = values[valsIdx];  
  625.                 coords[1] = values[valsIdx+1];  
  626.                 break;  
  627.             case SEG_QUADTO:  
  628.                 System.arraycopy( values, valsIdx, coords, 04 );  
  629.                 break;  
  630.             case SEG_CUBICTO:  
  631.                 System.arraycopy( values, valsIdx, coords, 06 );  
  632.                 break;  
  633.             case SEG_ARCTO:  
  634.                 System.arraycopy( values, valsIdx, coords, 07 );  
  635.                 break;  
  636.             }  
  637.             return ret;  
  638.         }  
  639.   
  640.         public int getWindingRule() {  
  641.             return path.getWindingRule();  
  642.         }  
  643.         public boolean isDone() {  
  644.             return segNum == numSeg;  
  645.         }  
  646.         public void next() {  
  647.             int type = types[segNum++];  
  648.             switch (type) {  
  649.             case SEG_CLOSE: break;  
  650.             case SEG_MOVETO:                   // fallthrough is intended  
  651.             case SEG_LINETO: valsIdx+=2break;  
  652.             case SEG_QUADTO: valsIdx+=4break;  
  653.             case SEG_CUBICTO:valsIdx+=6break;  
  654.             case SEG_ARCTO:  valsIdx+=7break;  
  655.             }  
  656.         }  
  657.     }  
  658.   
  659.     /** 
  660.      * Delegates to the enclosed <code>GeneralPath</code>. 
  661.      */  
  662.     public Object clone() {  
  663.         try {  
  664.             ExtendedGeneralPath result = (ExtendedGeneralPath) super.clone();  
  665.             result.path = (GeneralPath) path.clone();  
  666.   
  667.             if ( values != null ){  
  668.                 result.values = new float[values.length];  
  669.                 System.arraycopy(values, 0, result.values, 0, values.length);  
  670.             }  
  671.             result.numVals = numVals;  
  672.   
  673.             if ( types != null ){  
  674.                 result.types = new int[types.length];  
  675.                 System.arraycopy(types, 0, result.types, 0, types.length);  
  676.             }  
  677.             result.numSeg = numSeg;  
  678.   
  679.             return result;  
  680.         } catch (CloneNotSupportedException ex) {}  
  681.         return null;  
  682.     }  
  683.   
  684.     /** 
  685.      * Make sure, that the requested number of slots in vales[] are available. 
  686.      * Must be called even for numValues = 0, because it is also 
  687.      * used for initialization of those arrays. 
  688.      * 
  689.      * @param numValues number of requested coordinates 
  690.      */  
  691.     private void makeRoom(int numValues) {  
  692.         if (values == null) {  
  693.             values = new float[2*numValues];  
  694.             types  = new int[2];  
  695.             numVals = 0;  
  696.             numSeg  = 0;  
  697.             return;  
  698.         }  
  699.   
  700.         int newSize = numVals + numValues;  
  701.         if ( newSize > values.length) {  
  702.             int nlen = values.length*2;  
  703.             if ( nlen < newSize )  
  704.                 nlen = newSize;  
  705.   
  706.             float [] nvals = new float[nlen];  
  707.             System.arraycopy(values, 0, nvals, 0, numVals);  
  708.             values = nvals;  
  709.         }  
  710.   
  711.         if (numSeg == types.length) {  
  712.             int [] ntypes = new int[types.length*2];  
  713.             System.arraycopy(types, 0, ntypes, 0, types.length);  
  714.             types = ntypes;  
  715.         }  
  716.     }  
  717. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值