You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-dev@xmlgraphics.apache.org by de...@apache.org on 2002/07/09 19:17:54 UTC

cvs commit: xml-batik/test-resources/org/apache/batik/test samplesRendering.xml

deweese     2002/07/09 10:17:54

  Modified:    sources/org/apache/batik/ext/awt/geom
                        ExtendedGeneralPath.java
               sources/org/apache/batik/gvt MarkerShapePainter.java
               test-resources/org/apache/batik/test samplesRendering.xml
  Added:       samples/tests/spec/painting markersExt.svg
               sources/org/apache/batik/ext/awt/geom
                        ExtendedPathIterator.java ExtendedShape.java
                        ShapeExtender.java
  Log:
  1) Created an ExtendedShape class that can give an ExtendedPathIterator
     that may return SEG_ARCTO.  So we can properly implement markers on
     paths that have elliptical arcs in them.
  
  2) These new interfaces also do not collapse multiple moveTo calls into
     one moveTo.  This allows a path consisting of many 'm' or 'M' commands
     to place markers on the canvas.
  
     This update fixes a long standing bug in the rendering of
     markersOrientA.svg
  
  3) Updated MarkerShapePainter to take advantage of these interfaces
     (calculating the tangent at the end of an elliptical arc is a pain).
  
  4) Added a new test 'paints/markersExt.svg' for move paths and
     elliptical arc paths (it's funny to look at in the old Batik).
  
  5) Added new markers test and the 'filters/feGaussianDefault.svg' to
     samplesRendering.xml
  
  PR: 5806
  
  Revision  Changes    Path
  1.1                  xml-batik/samples/tests/spec/painting/markersExt.svg
  
  Index: markersExt.svg
  ===================================================================
  <?xml version="1.0" standalone="no"?>
  <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
  "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
  
  <!-- ====================================================================== -->
  <!-- Copyright (C) The Apache Software Foundation. All rights reserved.     -->
  <!--                                                                        -->
  <!-- This software is published under the terms of the Apache Software      -->
  <!-- License version 1.1, a copy of which has been included with this       -->
  <!-- distribution in  the LICENSE file.                                     -->
  <!-- ====================================================================== -->
  
  <!-- ====================================================================== -->
  <!-- This test validates arcto and multiple move to                         -->
  <!--                                                                        -->
  <!-- @author deweese@apache.org                                             -->
  <!-- @version $Id: markersExt.svg,v 1.1 2002/07/09 17:17:53 deweese Exp $  -->
  <!-- ====================================================================== -->
  <?xml-stylesheet type="text/css" href="../../resources/style/test.css" ?>  
  
  <svg id="body" width="450" height="500" viewBox="0 0 450 500"
       xmlns="http://www.w3.org/2000/svg" 
       xmlns:xlink="http://www.w3.org/1999/xlink" >
  
      <title>Marker Test</title>
  
      <style type="text/css"><![CDATA[
          .markedPath { fill:none; stroke:black; stroke-width:4; }
          .label { filter:url(#textBG); }
      ]]></style>
  
      <g id="content">
  
          <g transform="translate(0, 40)">
              <text class="title" x="50%" y="0">Markers on paths with just moves</text>
              <text class="title" x="50%" y="1em">and elliptical arcs</text>
          </g>
  
          <defs>
              <filter id="textBG" x="-5%" y="-5%" width="110%" height="110%"
                      color-interpolation-filters="sRGB">
                 <feFlood flood-color="lightGrey" result="foo"/>
                 <feComposite in="SourceGraphic" in2="foo" />
              </filter>
  
              <path id="testPathMoves" d="M 0 0 m 60 0 m 60 0" />
  
              <path id="testPathMoves2" d="M 0 0 m 40 -15 m 40 30 m 40 -15" />
  
              <path id="testPathArcs1" 
                    d="M 0 0 a 50 30 30 1 1 60 0 a 50 30 30 1 0 60 0" />
  
              <path id="testPathArcs2" 
                    d="M 0 0 a 60 30  0 1 1 60 0 a 60 30  0 1 0 60 0" />
  
              <path id="testPathArcs3" 
                    d="M 0 0 a 30 15  0 1 1 60 0 a 30 15 0 1 0 60 0" />
  
              <path id="testPathArcs4" 
                    d="M 0 0 a 60 30  0 0 1 60 0 a 60 30  0 0 0 60 0" />
  
              <path id="testPathArcs5" 
                    d="M 0 0 
                       a 60 30 30 0 1 40 -15 
                       a 60 30 30 0 0 40 30 
                       a 60 30 30 0 0 40 -15" />
  
  
              <g id="crossHair" style="marker:none" stroke="black">
                  <line y1="-5" x2="0" y2="5" />
                  <line x1="-5" x2="5" y2="0" />
              </g>
  
              <g id="startEndCrossHairs">
                  <use x="0" y="20" xlink:href="#crossHair" />
                  <use x="30" y="0" xlink:href="#crossHair" />
              </g>
  
              <g id="startMidEndCrossHairs">
                  <use x="0" y="20" xlink:href="#crossHair" />
                  <use x="20" y="0" xlink:href="#crossHair" />
                  <use x="50" y="10" xlink:href="#crossHair" />
              </g>
  
              <g id="testPathCrossHairs">
                  <use xlink:href="#crossHair" />
                  <use x="60" xlink:href="#crossHair" />
                  <use x="120" xlink:href="#crossHair" />
              </g>
  
              <g id="testPathCrossHairs2">
                  <use xlink:href="#crossHair" />
                  <use x="40" y="-15" xlink:href="#crossHair" />
                  <use x="80" y="15"  xlink:href="#crossHair" />
                  <use x="120" xlink:href="#crossHair" />
              </g>
  
              <!-- ============================= -->
              <!-- Simple Marker Definition      -->
              <!-- ============================= -->
              <marker id="markerStart" markerWidth="20" markerHeight="20" 
                      viewBox="-1 -1 2 2" orient="auto" refX="0" refY="0" 
                      markerUnits="strokeWidth" overflow="visible">
                  <g opacity="0.5">
                  <circle r="1.8" stroke="black" fill="blue" stroke-width=".4" />
                  <path d="M 0 -1.8 L 0.3 -0.3 L 1.8 0  L 0.3 0.3 L 0 1.8 L -.2 0.3 L -1.8 0 L -0.3 -0.3 Z" 
                        fill="yellow" stroke="none" /> 
                  <circle r="0.2" cx="0" cy="-1.8" fill="gold"/>
                  </g>
              </marker>
  
              <marker id="markerMid" markerWidth="20" markerHeight="20" 
                      viewBox="-1 -1 2 2" orient="auto" refX="0" refY="0" 
                      markerUnits="strokeWidth" overflow="visible">
                  <g opacity="0.5">
                  <circle r="1.8" stroke="black" fill="crimson" stroke-width=".4" />
                  <path d="M 0 -1.8 L 0.3 -0.3 L 1.8 0  L 0.3 0.3 L 0 1.8 L -.2 0.3 L -1.8 0 L -0.3 -0.3 Z" 
                        fill="yellow" stroke="none" /> 
                  <circle r="0.2" cx="0" cy="-1.8" fill="gold"/>
                  </g>
              </marker>
  
              <marker id="markerEnd" markerWidth="20" markerHeight="20" 
                      viewBox="-1 -1 2 2" orient="auto" refX="0" refY="0" 
                      markerUnits="strokeWidth" overflow="visible">
                  <g opacity="0.5">
                  <circle r="1.8" stroke="black" fill="green" stroke-width=".4" />
                  <path d="M 0 -1.8 L 0.3 -0.3 L 1.8 0  L 0.3 0.3 L 0 1.8 L -.2 0.3 L -1.8 0 L -0.3 -0.3 Z" 
                        fill="yellow" stroke="none" /> 
                  <circle r="0.2" cx="0" cy="-1.8" fill="gold"/>
                  </g>
              </marker>
  
          </defs>
  
          <g transform="translate(50, 100)">
  
          <!-- ==================================== -->
          <!-- Move Tests -->
          <!-- ==================================== -->
          <g transform="translate(0, 0)"  >
              <!-- Top reference point -->
              <use xlink:href="#testPathMoves" 
                   marker-start="url(#markerStart)" 
                   marker-mid="url(#markerMid)" 
                   marker-end="url(#markerEnd)" 
                   class="markedPath" style="stroke-width:1"/>
              <use xlink:href="#testPathCrossHairs" /> 
  
              <g class="label" transform="translate(60, 35)" text-anchor="middle">
                  <text y="0">Simple test of multiple moves</text>
              </g>
          </g>
  
          <!-- ==================================== -->
          <!-- Move Tests2  -->
          <!-- ==================================== -->
          <g transform="translate(230, 0)"  >
              <!-- Top reference point -->
              <use xlink:href="#testPathMoves2" 
                   marker-start="url(#markerStart)" 
                   marker-mid="url(#markerMid)" 
                   marker-end="url(#markerEnd)" 
                   class="markedPath" style="stroke-width:1"/>
              <use xlink:href="#testPathCrossHairs2" /> 
  
              <g class="label" transform="translate(60, 50)" text-anchor="middle">
                  <text y="0">Another test of multiple moves</text>
              </g>
          </g>
  
          <!-- ==================================== -->
          <!-- Arc Test 1         -->
          <!-- ==================================== -->
          <g transform="translate(0, 110)"  >
              <!-- Top reference point -->
              <use xlink:href="#testPathArcs1" 
                   marker-start="url(#markerStart)" 
                   marker-mid="url(#markerMid)" 
                   marker-end="url(#markerEnd)" 
                   class="markedPath" style="stroke-width:1"/>
              <use xlink:href="#testPathCrossHairs" /> 
  
              <g class="label" transform="translate(60, 50)" 
                 text-anchor="middle">
                  <text y="0">Test of rotated arcs</text>
              </g>
          </g>
  
  
  
          <!-- ==================================== -->
          <!-- Arc Test 2         -->
          <!-- ==================================== -->
          <g transform="translate(230, 110)"  >
              <!-- Top reference point -->
              <use xlink:href="#testPathArcs2" 
                   marker-start="url(#markerStart)" 
                   marker-mid="url(#markerMid)" 
                   marker-end="url(#markerEnd)" 
                   class="markedPath" style="stroke-width:1"/>
              <use xlink:href="#testPathCrossHairs" /> 
  
              <g class="label" transform="translate(60, 50)" text-anchor="middle">
                  <text y="0">Test of arcs 2</text>
              </g>
          </g>
  
  
  
          <!-- ==================================== -->
          <!-- Arc Test 3         -->
          <!-- ==================================== -->
          <g transform="translate(0, 220)"  >
              <!-- Top reference point -->
              <use xlink:href="#testPathArcs3" 
                   marker-start="url(#markerStart)" 
                   marker-mid="url(#markerMid)" 
                   marker-end="url(#markerEnd)" 
                   class="markedPath" style="stroke-width:1"/>
              <use xlink:href="#testPathCrossHairs" /> 
  
              <g class="label" transform="translate(60, 50)" text-anchor="middle">
                  <text y="0">Test of arcs 3</text>
              </g>
          </g>
  
  
  
          <!-- ==================================== -->
          <!-- Arc Test 4         -->
          <!-- ==================================== -->
          <g transform="translate(230, 220)"  >
              <!-- Top reference point -->
              <use xlink:href="#testPathArcs4" 
                   marker-start="url(#markerStart)" 
                   marker-mid="url(#markerMid)" 
                   marker-end="url(#markerEnd)" 
                   class="markedPath" style="stroke-width:1"/>
              <use xlink:href="#testPathCrossHairs" /> 
  
              <g class="label" transform="translate(60, 50)" text-anchor="middle">
                  <text y="0">Test of arcs 4</text>
              </g>
          </g>
  
  
          <!-- ==================================== -->
          <!-- Arc Test 5         -->
          <!-- ==================================== -->
          <g transform="translate(115, 320)"  >
              <!-- Top reference point -->
              <use xlink:href="#testPathArcs5" 
                   marker-start="url(#markerStart)" 
                   marker-mid="url(#markerMid)" 
                   marker-end="url(#markerEnd)" 
                   class="markedPath" style="stroke-width:1"/>
              <use xlink:href="#testPathCrossHairs2" /> 
  
              <g class="label" transform="translate(60, 50)" text-anchor="middle">
                  <text y="0">Test of arcs 5</text>
              </g>
          </g>
  
  
          </g>
      </g>
  
      <!-- ============================================================= -->
      <!-- Batik sample mark                                             -->
      <!-- ============================================================= -->
      <use xlink:href="../../../batikLogo.svg#Batik_Tag_Box" />
  
  </svg>
  
  
  
  1.3       +326 -20   xml-batik/sources/org/apache/batik/ext/awt/geom/ExtendedGeneralPath.java
  
  Index: ExtendedGeneralPath.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/ext/awt/geom/ExtendedGeneralPath.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ExtendedGeneralPath.java	6 Sep 2001 09:01:26 -0000	1.2
  +++ ExtendedGeneralPath.java	9 Jul 2002 17:17:53 -0000	1.3
  @@ -8,8 +8,13 @@
   
   package org.apache.batik.ext.awt.geom;
   
  -import java.awt.*;
  -import java.awt.geom.*;
  +import java.awt.Shape;
  +import java.awt.geom.AffineTransform;
  +import java.awt.geom.Arc2D;
  +import java.awt.geom.GeneralPath;
  +import java.awt.geom.PathIterator;
  +import java.awt.geom.Point2D;
  +import java.awt.geom.Rectangle2D;
   
   /**
    * The <code>ExtendedGeneralPath</code> class represents a geometric
  @@ -24,12 +29,17 @@
    * @author <a href="mailto:Thierry.Kormann@sophia.inria.fr">Thierry Kormann</a>
    * @version $Id$
    */
  -public class ExtendedGeneralPath implements Shape, Cloneable {
  +public class ExtendedGeneralPath implements ExtendedShape, Cloneable {
   
       /** The enclosed general path. */
       protected GeneralPath path;
   
  -    /**
  +    int       numVals = 0;
  +    int       numSeg  = 0;
  +    double [] values  = null;
  +    int    [] types   = null;
  +
  +   /**
        * Constructs a new <code>ExtendedGeneralPath</code>.
        */
       public ExtendedGeneralPath() {
  @@ -59,7 +69,8 @@
        * an arbitrary <code>Shape</code> object.
        */
       public ExtendedGeneralPath(Shape s) {
  -        path = new GeneralPath(s);
  +        this();
  +        append(s, false);
       }
   
       /**
  @@ -89,24 +100,62 @@
                                      boolean largeArcFlag,
                                      boolean sweepFlag,
                                      double x, double y) {
  -        //
  -        // Elliptical arc implementation based on the SVG specification notes
  -        //
   
           // Ensure radii are valid
           if (rx == 0 || ry == 0) {
               lineTo((float) x, (float) y);
               return;
           }
  +
           // Get the current (x, y) coordinates of the path
           Point2D p2d = path.getCurrentPoint();
           double x0 = p2d.getX();
           double y0 = p2d.getY();
  -	if (x0 == x && y0 == y) {
  -	    // If the endpoints (x, y) and (x0, y0) are identical, then this
  -	    // is equivalent to omitting the elliptical arc segment entirely.
  -	    return;
  -	}
  +        if (x0 == x && y0 == y) {
  +            // If the endpoints (x, y) and (x0, y0) are identical, then this
  +            // is equivalent to omitting the elliptical arc segment entirely.
  +            return;
  +        }
  +
  +        Arc2D arc = computeArc(x0, y0, rx, ry, angle, 
  +                               largeArcFlag, sweepFlag, x, y);
  +        if (arc == null) return;
  +
  +        AffineTransform t = AffineTransform.getRotateInstance
  +            (Math.toRadians(angle), arc.getCenterX(), arc.getCenterY());
  +        Shape s = t.createTransformedShape(arc);
  +        path.append(s, true);
  +
  +        makeRoom(7);
  +        types [numSeg++]  = ExtendedPathIterator.SEG_ARCTO;
  +        values[numVals++] = rx;
  +        values[numVals++] = ry;
  +        values[numVals++] = angle;
  +        values[numVals++] = largeArcFlag?1:0;
  +        values[numVals++] = sweepFlag?1:0;
  +        values[numVals++] = x;
  +        values[numVals++] = y;
  +    }
  +
  +
  +    /** 
  +     * 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);
  +     */
  +    public static Arc2D computeArc(double x0, double y0,
  +                                   double rx, double ry,
  +                                   double angle,
  +                                   boolean largeArcFlag,
  +                                   boolean sweepFlag,
  +                                   double x, double y) {
  +        //
  +        // 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;
  @@ -191,9 +240,8 @@
           arc.height = ry * 2.0;
           arc.start = -angleStart;
           arc.extent = -angleExtent;
  -        AffineTransform t = AffineTransform.getRotateInstance(angle, cx, cy);
  -        Shape s = t.createTransformedShape(arc);
  -        append(s, true);
  +
  +        return arc;
       }
   
       /**
  @@ -201,6 +249,11 @@
        */
       public synchronized void moveTo(float x, float y) {
           path.moveTo(x, y);
  +
  +        makeRoom(2);
  +        types [numSeg++]  = PathIterator.SEG_MOVETO;
  +        values[numVals++] = x;
  +        values[numVals++] = y;
       }
   
       /**
  @@ -208,6 +261,11 @@
        */
       public synchronized void lineTo(float x, float y) {
           path.lineTo(x, y);
  +
  +        makeRoom(2);
  +        types [numSeg++]  = PathIterator.SEG_LINETO;
  +        values[numVals++] = x;
  +        values[numVals++] = y;
       }
   
       /**
  @@ -215,6 +273,13 @@
        */
       public synchronized void quadTo(float x1, float y1, float x2, float y2) {
           path.quadTo(x1, y1, x2, y2);
  +
  +        makeRoom(4);
  +        types [numSeg++]  = PathIterator.SEG_QUADTO;
  +        values[numVals++] = x1;
  +        values[numVals++] = y1;
  +        values[numVals++] = x2;
  +        values[numVals++] = y2;
       }
   
       /**
  @@ -224,6 +289,15 @@
                                        float x2, float y2,
                                        float x3, float y3) {
           path.curveTo(x1, y1, x2, y2, x3, y3);
  +
  +        makeRoom(6);
  +        types [numSeg++]  = PathIterator.SEG_CUBICTO;
  +        values[numVals++] = x1;
  +        values[numVals++] = y1;
  +        values[numVals++] = x2;
  +        values[numVals++] = y2;
  +        values[numVals++] = x3;
  +        values[numVals++] = y3;
       }
   
       /**
  @@ -231,20 +305,107 @@
        */
       public synchronized void closePath() {
           path.closePath();
  +
  +        makeRoom(0);
  +        types [numSeg++]  = PathIterator.SEG_CLOSE;
       }
   
       /**
        * Delegates to the enclosed <code>GeneralPath</code>.
        */
       public void append(Shape s, boolean connect) {
  -        path.append(s, connect);
  +        append(s.getPathIterator(new AffineTransform()), connect);
       }
   
       /**
        * Delegates to the enclosed <code>GeneralPath</code>.
        */
       public void append(PathIterator pi, boolean connect) {
  -        path.append(pi, connect);
  +        
  +        while (!pi.isDone()) {
  +            double [] vals = new double[6];
  +            int type = pi.currentSegment(vals);
  +            pi.next();
  +            if (connect && (numVals != 0)) {
  +                if (type == PathIterator.SEG_MOVETO) {
  +                    double x = vals[0];
  +                    double y = vals[1];
  +                    if ((x != values[numVals-2]) ||
  +                        (y != values[numVals-1])) {
  +                        // Change MOVETO to LINETO.
  +                        type = PathIterator.SEG_LINETO;
  +                    } else {
  +                        // Redundent segment (move to current loc) drop it...
  +                        if (pi.isDone()) break; // Nothing interesting
  +                        type = pi.currentSegment(vals);
  +                        pi.next();
  +                    }
  +                }
  +                connect = false;
  +            }
  +
  +            switch(type) {
  +            case PathIterator.SEG_CLOSE:   closePath(); break;
  +            case PathIterator.SEG_MOVETO:  
  +                moveTo ((float)vals[0], (float)vals[1]); break;
  +            case PathIterator.SEG_LINETO:  
  +                lineTo ((float)vals[0], (float)vals[1]); break;
  +            case PathIterator.SEG_QUADTO:  
  +                quadTo ((float)vals[0], (float)vals[1], 
  +                        (float)vals[2], (float)vals[3]); break;
  +            case PathIterator.SEG_CUBICTO: 
  +                curveTo((float)vals[0], (float)vals[1], 
  +                        (float)vals[2], (float)vals[3],
  +                        (float)vals[4], (float)vals[5]); break;
  +            }
  +        }
  +    }
  +
  +    /**
  +     * Delegates to the enclosed <code>GeneralPath</code>.
  +     */
  +    public void append(ExtendedPathIterator epi, boolean connect) {
  +        while (!epi.isDone()) {
  +            double [] vals = new double[7];
  +            int type = epi.currentSegment(vals);
  +            epi.next();
  +            if (connect && (numVals != 0)) {
  +                if (type == PathIterator.SEG_MOVETO) {
  +                    double x = vals[0];
  +                    double y = vals[1];
  +                    if ((x != values[numVals-2]) ||
  +                        (y != values[numVals-1])) {
  +                        // Change MOVETO to LINETO.
  +                        type = PathIterator.SEG_LINETO;
  +                    } else {
  +                        // Redundent segment (move to current loc) drop it...
  +                        if (epi.isDone()) break; // Nothing interesting
  +                        type = epi.currentSegment(vals);
  +                        epi.next();
  +                    }
  +                }
  +                connect = false;
  +            }
  +
  +            switch(type) {
  +            case PathIterator.SEG_CLOSE:   closePath(); break;
  +            case PathIterator.SEG_MOVETO:  
  +                moveTo ((float)vals[0], (float)vals[1]); break;
  +            case PathIterator.SEG_LINETO:  
  +                lineTo ((float)vals[0], (float)vals[1]); break;
  +            case PathIterator.SEG_QUADTO:  
  +                quadTo ((float)vals[0], (float)vals[1], 
  +                        (float)vals[2], (float)vals[3]); break;
  +            case PathIterator.SEG_CUBICTO: 
  +                curveTo((float)vals[0], (float)vals[1], 
  +                        (float)vals[2], (float)vals[3],
  +                        (float)vals[4], (float)vals[5]); break;
  +            case ExtendedPathIterator.SEG_ARCTO:   
  +                arcTo  (vals[0], vals[1], vals[2], 
  +                        (vals[3]!=0), (vals[4]!=0), 
  +                        vals[5], vals[6]); break;
  +            }
  +        }
       }
   
       /**
  @@ -273,13 +434,18 @@
        */
       public synchronized void reset() {
           path.reset();
  +
  +        numSeg = 0;
  +        numVals = 0;
       }
   
       /**
        * Delegates to the enclosed <code>GeneralPath</code>.
        */
       public void transform(AffineTransform at) {
  -        path.transform(at);
  +        if (at.getType() != AffineTransform.TYPE_IDENTITY)
  +            throw new IllegalArgumentException
  +                ("ExtendedGeneralPaths can not be transformed");
       }
   
       /**
  @@ -362,12 +528,152 @@
       /**
        * Delegates to the enclosed <code>GeneralPath</code>.
        */
  +    public ExtendedPathIterator getExtendedPathIterator() {
  +        return new EPI();
  +    }
  +
  +    class EPI implements ExtendedPathIterator {
  +        int segNum = 0;
  +        int valsIdx = 0;
  +
  +        public int currentSegment(double[] coords) {
  +            int ret = types[segNum];
  +            switch (ret) {
  +            case SEG_CLOSE: break;
  +            case SEG_MOVETO: 
  +            case SEG_LINETO: 
  +                coords[0] = values[valsIdx];
  +                coords[1] = values[valsIdx+1];
  +                break;
  +            case SEG_QUADTO:
  +                coords[0] = values[valsIdx];
  +                coords[1] = values[valsIdx+1];
  +                coords[2] = values[valsIdx+2];
  +                coords[3] = values[valsIdx+3];
  +                break;
  +            case SEG_CUBICTO:
  +                coords[0] = values[valsIdx];
  +                coords[1] = values[valsIdx+1];
  +                coords[2] = values[valsIdx+2];
  +                coords[3] = values[valsIdx+3];
  +                coords[4] = values[valsIdx+4];
  +                coords[5] = values[valsIdx+5];
  +                break;
  +            case SEG_ARCTO:
  +                coords[0] = values[valsIdx];
  +                coords[1] = values[valsIdx+1];
  +                coords[2] = values[valsIdx+2];
  +                coords[3] = values[valsIdx+3];
  +                coords[4] = values[valsIdx+4];
  +                coords[5] = values[valsIdx+5];
  +                coords[6] = values[valsIdx+6];
  +                break;
  +            }
  +            // System.out.println("Seg: [" + segNum + "] type: " + ret + 
  +            //                    " vals: [" + coords[0] + ", " + coords[1] +
  +            //                    "]");
  +            return ret;
  +        }
  +
  +        public int currentSegment(float[] coords) {
  +            int ret = types[segNum];
  +            switch (ret) {
  +            case SEG_CLOSE: break;
  +            case SEG_MOVETO: 
  +            case SEG_LINETO: 
  +                coords[0] = (float)values[valsIdx];
  +                coords[1] = (float)values[valsIdx+1];
  +                break;
  +            case SEG_QUADTO:
  +                coords[0] = (float)values[valsIdx];
  +                coords[1] = (float)values[valsIdx+1];
  +                coords[2] = (float)values[valsIdx+2];
  +                coords[3] = (float)values[valsIdx+3];
  +                break;
  +            case SEG_CUBICTO:
  +                coords[0] = (float)values[valsIdx];
  +                coords[1] = (float)values[valsIdx+1];
  +                coords[2] = (float)values[valsIdx+2];
  +                coords[3] = (float)values[valsIdx+3];
  +                coords[4] = (float)values[valsIdx+4];
  +                coords[5] = (float)values[valsIdx+5];
  +                break;
  +            case SEG_ARCTO:
  +                coords[0] = (float)values[valsIdx];
  +                coords[1] = (float)values[valsIdx+1];
  +                coords[2] = (float)values[valsIdx+2];
  +                coords[3] = (float)values[valsIdx+3];
  +                coords[4] = (float)values[valsIdx+4];
  +                coords[5] = (float)values[valsIdx+5];
  +                coords[6] = (float)values[valsIdx+6];
  +                break;
  +            }
  +            return ret;
  +        }
  +
  +        public int getWindingRule() {
  +            return path.getWindingRule();
  +        }
  +        public boolean isDone() {
  +            return segNum == numSeg;
  +        }
  +        public void next() {
  +            int type = types[segNum++];
  +            switch (type) {
  +            case SEG_CLOSE: break;
  +            case SEG_MOVETO: 
  +            case SEG_LINETO: valsIdx+=2; break;
  +            case SEG_QUADTO: valsIdx+=4; break;
  +            case SEG_CUBICTO:valsIdx+=6; break;
  +            case SEG_ARCTO:  valsIdx+=7; break;
  +            }
  +        }
  +    };
  +
  +    /**
  +     * Delegates to the enclosed <code>GeneralPath</code>.
  +     */
       public Object clone() {
           try {
               ExtendedGeneralPath result = (ExtendedGeneralPath) super.clone();
               result.path = (GeneralPath) path.clone();
  +
  +            result.values = new double[values.length];
  +            System.arraycopy(result.values, 0, values, 0, values.length);
  +            result.numVals = numVals;
  +
  +            result.types = new int[types.length];
  +            System.arraycopy(result.types, 0, types, 0, types.length);
  +            result.numSeg = numSeg;
  +
               return result;
           } catch (CloneNotSupportedException ex) {}
           return null;
  +    }
  +
  +    private void makeRoom(int numValues) {
  +        if (values == null) {
  +            values = new double[2*numValues];
  +            types  = new int[2];
  +            numVals = 0;
  +            numSeg  = 0;
  +            return;
  +        }
  +        
  +        if ((numVals + numValues) > values.length) {
  +            int nlen = values.length*2;
  +            if (nlen < (numVals + numValues))
  +                nlen = numVals + numValues;
  +        
  +            double [] nvals = new double[nlen];
  +            System.arraycopy(values, 0, nvals, 0, numVals);
  +            values = nvals;
  +        }
  +
  +        if (numSeg == types.length) {
  +            int [] ntypes = new int[types.length*2];
  +            System.arraycopy(types, 0, ntypes, 0, types.length);
  +            types = ntypes;
  +        }
       }
   }
  
  
  
  1.1                  xml-batik/sources/org/apache/batik/ext/awt/geom/ExtendedPathIterator.java
  
  Index: ExtendedPathIterator.java
  ===================================================================
  /*****************************************************************************
   * Copyright (C) The Apache Software Foundation. All rights reserved.        *
   * ------------------------------------------------------------------------- *
   * This software is published under the terms of the Apache Software License *
   * version 1.1, a copy of which has been included with this distribution in  *
   * the LICENSE file.                                                         *
   *****************************************************************************/
  
  package org.apache.batik.ext.awt.geom;
  
  import java.awt.geom.PathIterator;
  
  /**
   * The <code>ExtendedPathIterator</code> class represents a geometric
   * path constructed from straight lines, quadratic and cubic (B�zier)
   * curves and elliptical arcs.  This interface is identical to that of
   * PathIterator except it can return SEG_ARCTO from currentSegment,
   * also the array of values passed to currentSegment must be of length
   * 7 or an error will be thrown.
   * 
   * This does not extend PathIterator as it would break the interface
   * contract for that class.
   *
   * @author <a href="mailto:deweese@apache.org">Thomas DeWeese</a>
   * @version $Id: ExtendedPathIterator.java,v 1.1 2002/07/09 17:17:53 deweese Exp $ */
  public interface ExtendedPathIterator {
  
      /**
       * The segment type constant that specifies that the preceding
       * subpath should be closed by appending a line segment back to
       * the point corresponding to the most recent SEG_MOVETO.
       */
      public static final int SEG_CLOSE   = PathIterator.SEG_CLOSE;
      /** 
       * The segment type constant for a point that specifies the end
       * point of a line to be drawn from the most recently specified
       * point.  */
      public static final int SEG_MOVETO  = PathIterator.SEG_MOVETO;
      /**
       * The segment type constant for a point that specifies the end
       * point of a line to be drawn from the most recently specified
       * point.
       */
      public static final int SEG_LINETO  = PathIterator.SEG_LINETO;
      /**
       * The segment type constant for the pair of points that specify a
       * quadratic parametric curve to be drawn from the most recently
       * specified point. The curve is interpolated by solving the
       * parametric control equation in the range (t=[0..1]) using the
       * most recently specified (current) point (CP), the first control
       * point (P1), and the final interpolated control point (P2). 
       */
      public static final int SEG_QUADTO  = PathIterator.SEG_QUADTO;
      /**
       * The segment type constant for the set of 3 points that specify
       * a cubic parametric curve to be drawn from the most recently
       * specified point. The curve is interpolated by solving the
       * parametric control equation in the range (t=[0..1]) using the
       * most recently specified (current) point (CP), the first control
       * point (P1), the second control point (P2), and the final
       * interpolated control point (P3).
       */
      public static final int SEG_CUBICTO = PathIterator.SEG_CUBICTO;
  
      /** The segment type constant for an elliptical arc.  This consists of
       *  Seven values [rx, ry, angle, largeArcFlag, sweepFlag, x, y].
       *  rx, ry are the radious of the ellipse.
       *  angle is angle of the x axis of the ellipse.
       *  largeArcFlag is zero if the smaller of the two arcs are to be used.
       *  sweepFlag is zero if the 'left' branch is taken one otherwise.
       *  x and y are the destination for the ellipse.  */
      public static final int SEG_ARCTO = 4321;
  
      /** The winding rule constant for specifying an even-odd rule for
       * determining the interior of a path. The even-odd rule specifies
       * that a point lies inside the path if a ray drawn in any
       * direction from that point to infinity is crossed by path
       * segments an odd number of times.  
       */ 
      public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD; 
      /**
       * The winding rule constant for specifying a non-zero rule for
       * determining the interior of a path. The non-zero rule specifies
       * that a point lies inside the path if a ray drawn in any
       * direction from that point to infinity is crossed by path
       * segments a different number of times in the counter-clockwise
       * direction than the clockwise direction.
       */
       public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO;
  
  
      public int currentSegment(double[] coords);
      public int currentSegment(float[] coords);
      public int getWindingRule(); 
      public boolean isDone();
      public void next();
  }
  
  
  
  
  1.1                  xml-batik/sources/org/apache/batik/ext/awt/geom/ExtendedShape.java
  
  Index: ExtendedShape.java
  ===================================================================
  /*****************************************************************************
   * Copyright (C) The Apache Software Foundation. All rights reserved.        *
   * ------------------------------------------------------------------------- *
   * This software is published under the terms of the Apache Software License *
   * version 1.1, a copy of which has been included with this distribution in  *
   * the LICENSE file.                                                         *
   *****************************************************************************/
  
  package org.apache.batik.ext.awt.geom;
  
  import java.awt.Shape;
  
  /**
   * The <code>ExtendedShape</code> class represents a geometric
   * path constructed from straight lines, quadratic and cubic (B�zier)
   * curves and elliptical arcs.
   * @author <a href="mailto:deweese@apache.org">Thomas DeWeese</a>
   * @version $Id: ExtendedShape.java,v 1.1 2002/07/09 17:17:54 deweese Exp $
   */
  public interface ExtendedShape extends Shape {
      /**
       * Get an extended Path iterator that may return SEG_ARCTO commands
       */
      public ExtendedPathIterator getExtendedPathIterator();
  
  }
  
  
  
  1.1                  xml-batik/sources/org/apache/batik/ext/awt/geom/ShapeExtender.java
  
  Index: ShapeExtender.java
  ===================================================================
  /*****************************************************************************
   * Copyright (C) The Apache Software Foundation. All rights reserved.        *
   * ------------------------------------------------------------------------- *
   * This software is published under the terms of the Apache Software License *
   * version 1.1, a copy of which has been included with this distribution in  *
   * the LICENSE file.                                                         *
   *****************************************************************************/
  
  package org.apache.batik.ext.awt.geom;
  
  import java.awt.Shape;
  import java.awt.Rectangle;
  import java.awt.geom.Point2D;
  import java.awt.geom.Rectangle2D;
  import java.awt.geom.AffineTransform;
  import java.awt.geom.PathIterator;
  
  /**
   * This class wraps a normal path into an extended path.
   * @author <a href="mailto:deweese@apache.org">Thomas DeWeese</a>
   * @version $Id: ShapeExtender.java,v 1.1 2002/07/09 17:17:54 deweese Exp $
   */
  public class ShapeExtender implements ExtendedShape {
      Shape shape;
  
      public ShapeExtender(Shape shape) {
          this.shape = shape;
      }
  
      public boolean contains(double x, double y) {
          return shape.contains(x, y);
      }
      public boolean contains(double x, double y, double w, double h) {
          return shape.contains(x, y, w, h);
      }
  
      public boolean contains(Point2D p) {
          return shape.contains(p);
      }
  
      public boolean contains(Rectangle2D r) {
          return shape.contains(r);
      }
  
      public Rectangle getBounds() {
          return shape.getBounds();
      }
  
      public Rectangle2D getBounds2D() {
          return shape.getBounds2D();
      }
  
      public PathIterator getPathIterator(AffineTransform at) {
          return shape.getPathIterator(at);
      }
  
      public PathIterator getPathIterator(AffineTransform at, double flatness) {
          return shape.getPathIterator(at, flatness);
      }
  
      public ExtendedPathIterator getExtendedPathIterator() {
          return new EPIWrap(shape.getPathIterator(null));
      }
  
      public boolean intersects(double x, double y, double w, double h) {
          return shape.intersects(x, y, w, h);
      }
  
      public boolean intersects(Rectangle2D r) {
          return shape.intersects(r);
      }
  
  
      public static class EPIWrap implements ExtendedPathIterator {
          PathIterator pi = null;
          public EPIWrap(PathIterator pi) {
              this.pi = pi;
          }
  
          public int currentSegment(double[] coords) { 
              return pi.currentSegment(coords); }
  
          public int currentSegment(float[] coords) {
              return pi.currentSegment(coords); }
  
          public int getWindingRule() {
              return pi.getWindingRule();
          }
  
          public boolean isDone() {
              return pi.isDone(); }
  
          public void next() {
              pi.next();
          }
      };
  }
  
  
  
  1.8       +177 -84   xml-batik/sources/org/apache/batik/gvt/MarkerShapePainter.java
  
  Index: MarkerShapePainter.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/gvt/MarkerShapePainter.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- MarkerShapePainter.java	6 Feb 2002 17:52:37 -0000	1.7
  +++ MarkerShapePainter.java	9 Jul 2002 17:17:54 -0000	1.8
  @@ -12,6 +12,7 @@
   import java.awt.Graphics2D;
   
   import java.awt.geom.AffineTransform;
  +import java.awt.geom.Arc2D;
   import java.awt.geom.Point2D;
   import java.awt.geom.Rectangle2D;
   import java.awt.geom.PathIterator;
  @@ -19,6 +20,11 @@
   import java.util.List;
   import java.util.Vector;
   
  +import org.apache.batik.ext.awt.geom.ExtendedGeneralPath;
  +import org.apache.batik.ext.awt.geom.ExtendedPathIterator;
  +import org.apache.batik.ext.awt.geom.ExtendedShape;
  +import org.apache.batik.ext.awt.geom.ShapeExtender;
  +
   /**
    * A shape painter that can be used to paint markers on a shape.
    *
  @@ -30,7 +36,7 @@
       /** 
        * The Shape to be painted.
        */
  -    protected Shape shape;
  +    protected ExtendedShape extShape;
   
       /**
        * Start Marker
  @@ -88,7 +94,11 @@
           if (shape == null) {
               throw new IllegalArgumentException();
           }
  -        this.shape = shape;
  +        if (shape instanceof ExtendedShape) {
  +            this.extShape = (ExtendedShape)shape;
  +        } else {
  +            this.extShape = new ShapeExtender(shape);
  +        }
       }
   
       /**
  @@ -138,7 +148,12 @@
           if (shape == null) {
               throw new IllegalArgumentException();
           }
  -        this.shape = shape;
  +        if (shape instanceof ExtendedShape) {
  +            this.extShape = (ExtendedShape)shape;
  +        } else {
  +            this.extShape = new ShapeExtender(shape);
  +        }
  +
           this.startMarkerProxy = null;
           this.middleMarkerProxies = null;
           this.endMarkerProxy = null;
  @@ -146,12 +161,21 @@
       }
   
       /**
  +     * Gets the Shape this shape painter is associated with as an
  +     * Extended Shape.
  +     *
  +     * @return shape associated with this painter */
  +    public ExtendedShape getExtShape(){
  +        return extShape;
  +    }
  +
  +    /**
        * Gets the Shape this shape painter is associated with.
        *
        * @return shape associated with this painter
        */
       public Shape getShape(){
  -        return shape;
  +        return extShape;
       }
   
       /**
  @@ -259,10 +283,10 @@
        */
       protected ProxyGraphicsNode buildStartMarkerProxy() {
   
  -        PathIterator iter = getShape().getPathIterator(null);
  +        ExtendedPathIterator iter = getExtShape().getExtendedPathIterator();
   
           // Get initial point on the path
  -        double coords[] = new double[6];
  +        double coords[] = new double[7];
           int segType = 0;
   
           if (iter.isDone()) {
  @@ -282,7 +306,7 @@
           double rotation = startMarker.getOrient();
           if (Double.isNaN(rotation)) {
               if (!iter.isDone()) {
  -                double next[] = new double[6];
  +                double next[] = new double[7];
                   int nextSegType = 0;
                   nextSegType = iter.currentSegment(next);
                   if(nextSegType == PathIterator.SEG_CLOSE){
  @@ -316,7 +340,7 @@
        */
       protected ProxyGraphicsNode buildEndMarkerProxy() {
   
  -        PathIterator iter = getShape().getPathIterator(null);
  +        ExtendedPathIterator iter = getExtShape().getExtendedPathIterator();
   
           int nPoints = 0;
   
  @@ -326,7 +350,7 @@
               return null;
           }
   	
  -        double coords[] = new double[6];
  +        double coords[] = new double[7];
           double moveTo[] = new double[2];
           int segType = 0;
           segType = iter.currentSegment(coords);
  @@ -340,9 +364,10 @@
           iter.next();
           
           // Now, get the last two points on the path
  -        double[] lastButOne = new double[6];
  +        double[] lastButOne = new double[7];
           double[] last = {coords[0], coords[1], coords[2],
  -                         coords[3], coords[4], coords[5] }, tmp = null;
  +                         coords[3], coords[4], coords[5], coords[6] };
  +        double[] tmp = null;
           int lastSegType = segType;
           int lastButOneSegType = 0;
   
  @@ -398,17 +423,17 @@
       }
   
       /**
  -     * Builds a proxy <tt>GraphicsNode</tt> for the input <tt>Marker</tt> to be
  -     * drawn at the middle positions 
  +     * Builds a proxy <tt>GraphicsNode</tt> for the input
  +     * <tt>Marker</tt> to be drawn at the middle positions 
        */
       protected ProxyGraphicsNode[] buildMiddleMarkerProxies() {
   
  -        PathIterator iter = getShape().getPathIterator(null);
  +        ExtendedPathIterator iter = getExtShape().getExtendedPathIterator();
   
  -        double[] prev = new double[6];
  -        double[] cur = new double[6];
  -        double[] next = new double[6], tmp = null;
  -        int prevSegType = 0, curSegType = 0, nextSegType = 0;
  +        double[] prev = new double[7];
  +        double[] curr = new double[7];
  +        double[] next = new double[7], tmp = null;
  +        int prevSegType = 0, currSegType = 0, nextSegType = 0;
   
           // Get the first three points on the path
           if (iter.isDone()) {
  @@ -430,15 +455,15 @@
               return null;
           }
   	
  -        curSegType = iter.currentSegment(cur);
  +        currSegType = iter.currentSegment(curr);
   
  -        if (curSegType == PathIterator.SEG_MOVETO) {
  -            moveTo[0] = cur[0];
  -            moveTo[1] = cur[1];
  -        } else if (curSegType == PathIterator.SEG_CLOSE) {
  -            curSegType = PathIterator.SEG_LINETO;
  -            cur[0] = moveTo[0];
  -            cur[1] = moveTo[1];
  +        if (currSegType == PathIterator.SEG_MOVETO) {
  +            moveTo[0] = curr[0];
  +            moveTo[1] = curr[1];
  +        } else if (currSegType == PathIterator.SEG_CLOSE) {
  +            currSegType = PathIterator.SEG_LINETO;
  +            curr[0] = moveTo[0];
  +            curr[1] = moveTo[1];
           }
   
           iter.next();
  @@ -457,14 +482,14 @@
               }
   	    
               proxies.addElement(createMiddleMarker(prev, prevSegType,
  -                                                  cur, curSegType,
  +                                                  curr, currSegType,
                                                     next, nextSegType));
               
               tmp = prev;
  -            prev = cur;
  -            prevSegType = curSegType;
  -            cur = next;
  -            curSegType = nextSegType;
  +            prev = curr;
  +            prevSegType = currSegType;
  +            curr = next;
  +            currSegType = nextSegType;
               next = tmp;
               
               iter.next();
  @@ -479,22 +504,20 @@
       /**
        * Creates a ProxyGraphicsNode for a middle marker.
        */
  -    private ProxyGraphicsNode createMiddleMarker(double[] prev,
  -						 int prevSegType,
  -						 double[] cur,
  -						 int curSegType,
  -						 double[] next,
  -						 int nextSegType){
  +    private ProxyGraphicsNode createMiddleMarker
  +        (double[] prev, int prevSegType,
  +         double[] curr, int currSegType,
  +         double[] next, int nextSegType) {
   
  -        // Turn the cur segment into a position
  -        Point2D markerPosition = getSegmentTerminatingPoint(cur, curSegType);
  +        // Turn the curr segment into a position
  +        Point2D markerPosition = getSegmentTerminatingPoint(curr, currSegType);
   
           // If the marker's orient property is NaN,
           // the slope needs to be computed
           double rotation = middleMarker.getOrient();
           if (Double.isNaN(rotation)) {
               rotation = computeRotation(prev, prevSegType,
  -                                       cur, curSegType,
  +                                       curr, currSegType,
                                          next, nextSegType);
           }
   	
  @@ -514,21 +537,18 @@
       /**
        * Returns the rotation according to the specified parameters.
        */
  -    private double computeRotation(double[] prev,
  -                                   int prevSegType,
  -                                   double[] cur,
  -                                   int curSegType,
  -                                   double[] next,
  -                                   int nextSegType){
  +    private double computeRotation(double[] prev, int prevSegType,
  +                                   double[] curr, int currSegType,
  +                                   double[] next, int nextSegType){
   
           // Compute in slope, i.e., the slope of the segment
           // going into the current point
           double[] inSlope = computeInSlope(prev, prevSegType, 
  -                                          cur, curSegType);
  +                                          curr, currSegType);
   
           // Compute out slope, i.e., the slope of the segment
           // going out of the current point
  -        double[] outSlope = computeOutSlope(cur, curSegType, 
  +        double[] outSlope = computeOutSlope(curr, currSegType, 
                                               next, nextSegType);
   
           if (inSlope == null) {
  @@ -553,39 +573,76 @@
       /**
        * Returns dx/dy for the in slope.
        */
  -    private double[] computeInSlope(double[] prev,
  -                                    int prevSegType,
  -                                    double[] cur,
  -                                    int curSegType){
  +    private double[] computeInSlope(double[] prev, int prevSegType,
  +                                    double[] curr, int currSegType){
   
           // Compute point into which the slope runs
  -        Point2D curEndPoint = getSegmentTerminatingPoint(cur, curSegType);
  +        Point2D currEndPoint = getSegmentTerminatingPoint(curr, currSegType);
   
           double dx = 0;
  -	double dy = 0;
  +        double dy = 0;
   
  -        switch(curSegType){
  -        case PathIterator.SEG_QUADTO:
  -            // If the current segment is a line, quad or cubic curve.  the slope
  -            // is about equal to that of the line from the last control point
  -            // and the curEndPoint
  -            dx = curEndPoint.getX() - cur[0];
  -            dy = curEndPoint.getY() - cur[1];
  -            break;
  -        case PathIterator.SEG_LINETO:
  +        switch(currSegType){
  +        case PathIterator.SEG_LINETO: {
               // This is equivalent to a line from the previous segment's
               // terminating point and the current end point.
               Point2D prevEndPoint = 
  -		getSegmentTerminatingPoint(prev, prevSegType);
  -            dx = curEndPoint.getX() - prevEndPoint.getX();
  -            dy = curEndPoint.getY() - prevEndPoint.getY();
  +                getSegmentTerminatingPoint(prev, prevSegType);
  +            dx = currEndPoint.getX() - prevEndPoint.getX();
  +            dy = currEndPoint.getY() - prevEndPoint.getY();
  +        }
  +            break;
  +        case PathIterator.SEG_QUADTO:
  +            // If the current segment is a line, quad or cubic curve.
  +            // the slope is about equal to that of the line from the
  +            // last control point and the curEndPoint
  +            dx = currEndPoint.getX() - curr[0];
  +            dy = currEndPoint.getY() - curr[1];
               break;
           case PathIterator.SEG_CUBICTO:
  -            // If the current segment is a line, quad or cubic curve.  the slope
  -            // is about equal to that of the line from the last control point
  -            // and the curEndPoint
  -            dx = curEndPoint.getX() - cur[2];
  -            dy = curEndPoint.getY() - cur[3];
  +            // If the current segment is a quad or cubic curve.
  +            // the slope is about equal to that of the line from the
  +            // last control point and the curEndPoint
  +            dx = currEndPoint.getX() - curr[2];
  +            dy = currEndPoint.getY() - curr[3];
  +            break;
  +        case ExtendedPathIterator.SEG_ARCTO: {
  +            // If the current segment is an ARCTO then we build the
  +            // arc and ask for it's end angle and get the tangent there.
  +            Point2D prevEndPoint = 
  +                getSegmentTerminatingPoint(prev, prevSegType);
  +            boolean large   = (curr[3]!=0.);
  +            boolean goLeft = (curr[4]!=0.);
  +            Arc2D arc = ExtendedGeneralPath.computeArc
  +                (prevEndPoint.getX(), prevEndPoint.getY(),
  +                 curr[0], curr[1], curr[2],
  +                 large, goLeft, curr[5], curr[6]);
  +            double theta = arc.getAngleStart()+arc.getAngleExtent();
  +            theta = Math.toRadians(theta);
  +            dx = -arc.getWidth()/2.0*Math.sin(theta);
  +            dy = arc.getHeight()/2.0*Math.cos(theta);
  +
  +            // System.out.println("In  Theta:  " + Math.toDegrees(theta) +  
  +            //                    " Dx/Dy: " + dx + "/" + dy);
  +            if (curr[2] != 0) {
  +                double ang = Math.toRadians(-curr[2]);
  +                double sinA = Math.sin(ang);
  +                double cosA = Math.cos(ang);
  +                double tdx = dx*cosA - dy*sinA;
  +                double tdy = dx*sinA + dy*cosA;
  +                dx = tdx;
  +                dy = tdy;
  +            }
  +            // System.out.println("    Rotate: " + curr[2] + 
  +            //                    " Dx/Dy: " + dx + "/" + dy);
  +            if (goLeft) {
  +                dx = -dx;
  +            } else {
  +                dy = -dy;
  +            }
  +            // System.out.println("    GoLeft? " + goLeft + 
  +            //                    " Dx/Dy: " + dx + "/" + dy);
  +        }
               break;
           case PathIterator.SEG_CLOSE:
               // Should not have any close at this point
  @@ -606,28 +663,62 @@
       /**
        * Returns dx/dy for the out slope.
        */
  -    private double[] computeOutSlope(double[] cur,
  -                                     int curSegType,
  -                                     double[] next,
  -                                     int nextSegType){
  +    private double[] computeOutSlope(double[] curr, int currSegType,
  +                                     double[] next, int nextSegType){
   
  -        Point2D curEndPoint = getSegmentTerminatingPoint(cur, curSegType);
  +        Point2D currEndPoint = getSegmentTerminatingPoint(curr, currSegType);
           
           double dx = 0, dy = 0;
   
           switch(nextSegType){
           case PathIterator.SEG_CLOSE:
  -            // Should not happen at this point, because all close segments have
  -            // been replaced by lineTo segments.
  +            // Should not happen at this point, because all close
  +            // segments have been replaced by lineTo segments.
               break;
           case PathIterator.SEG_CUBICTO:
           case PathIterator.SEG_LINETO:
           case PathIterator.SEG_QUADTO:
  -            // If the next segment is a line, quad or cubic curve.  the slope is
  -            // about equal to that of the line from curEndPoint and the first
  -            // control point
  -            dx = next[0] - curEndPoint.getX();
  -            dy = next[1] - curEndPoint.getY();
  +            // If the next segment is a line, quad or cubic curve.
  +            // the slope is about equal to that of the line from
  +            // curEndPoint and the first control point
  +            dx = next[0] - currEndPoint.getX();
  +            dy = next[1] - currEndPoint.getY();
  +            break;
  +        case ExtendedPathIterator.SEG_ARCTO: {
  +            // If the current segment is an ARCTO then we build the
  +            // arc and ask for it's end angle and get the tangent there.
  +            boolean large   = (next[3]!=0.);
  +            boolean goLeft = (next[4]!=0.);
  +            Arc2D arc = ExtendedGeneralPath.computeArc
  +                (currEndPoint.getX(), currEndPoint.getY(),
  +                 next[0], next[1], next[2],
  +                 large, goLeft, next[5], next[6]);
  +            double theta = arc.getAngleStart();
  +            theta = Math.toRadians(theta);
  +            dx = -arc.getWidth()/2.0*Math.sin(theta);
  +            dy = arc.getHeight()/2.0*Math.cos(theta);
  +            // System.out.println("Out Theta:  " + Math.toDegrees(theta) +  
  +            //                    " Dx/Dy: " + dx + "/" + dy);
  +            if (next[2] != 0) {
  +                double ang = Math.toRadians(-next[2]);
  +                double sinA = Math.sin(ang);
  +                double cosA = Math.cos(ang);
  +                double tdx = dx*cosA - dy*sinA;
  +                double tdy = dx*sinA + dy*cosA;
  +                dx = tdx;
  +                dy = tdy;
  +            }
  +            // System.out.println("    Rotate: " + next[2] + 
  +            //                    " Dx/Dy: " + dx + "/" + dy);
  +
  +            if (goLeft) {
  +                dx = -dx;
  +            } else {
  +                dy = -dy;
  +            }
  +            // System.out.println("    GoLeft? " + goLeft + 
  +            //                    " Dx/Dy: " + dx + "/" + dy);
  +        }
               break;
           case PathIterator.SEG_MOVETO:
               // Cannot compute the out slope
  @@ -680,6 +771,8 @@
               return new Point2D.Double(coords[0], coords[1]);
           case PathIterator.SEG_QUADTO:
               return new Point2D.Double(coords[2], coords[3]);
  +        case ExtendedPathIterator.SEG_ARCTO:
  +            return new Point2D.Double(coords[5], coords[6]);
           case PathIterator.SEG_CLOSE:
           default:
               throw new Error(); 
  
  
  
  1.80      +3 -1      xml-batik/test-resources/org/apache/batik/test/samplesRendering.xml
  
  Index: samplesRendering.xml
  ===================================================================
  RCS file: /home/cvs/xml-batik/test-resources/org/apache/batik/test/samplesRendering.xml,v
  retrieving revision 1.79
  retrieving revision 1.80
  diff -u -r1.79 -r1.80
  --- samplesRendering.xml	4 Jul 2002 07:19:02 -0000	1.79
  +++ samplesRendering.xml	9 Jul 2002 17:17:54 -0000	1.80
  @@ -96,6 +96,7 @@
           <test id="samples/tests/spec/filters/feComposite.svg" />
           <test id="samples/tests/spec/filters/feConvolveMatrix.svg" />
           <test id="samples/tests/spec/filters/feDisplacementMap.svg" />
  +        <test id="samples/tests/spec/filters/feGaussianDefault.svg" />
           <test id="samples/tests/spec/filters/feImage.svg" />
           <test id="samples/tests/spec/filters/feMerge.svg" />
           <test id="samples/tests/spec/filters/feMorphology.svg" />
  @@ -161,6 +162,7 @@
           <test id="samples/tests/spec/painting/bboxOnText.svg" />
           <test id="samples/tests/spec/painting/display.svg" />
           <test id="samples/tests/spec/painting/image-rendering.svg" />
  +        <test id="samples/tests/spec/painting/markersExt.svg" />
           <test id="samples/tests/spec/painting/markersMisc.svg" />
           <test id="samples/tests/spec/painting/markersOrientA.svg" />
           <test id="samples/tests/spec/painting/markersOrientB.svg" />
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-dev-help@xml.apache.org