KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > gvt > MarkerShapePainter


1 /*
2
3    Copyright 2001-2003 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.batik.gvt;
19
20 import java.awt.Graphics2D JavaDoc;
21 import java.awt.Shape JavaDoc;
22 import java.awt.geom.AffineTransform JavaDoc;
23 import java.awt.geom.Arc2D JavaDoc;
24 import java.awt.geom.PathIterator JavaDoc;
25 import java.awt.geom.Point2D JavaDoc;
26 import java.awt.geom.Rectangle2D JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.Vector JavaDoc;
29
30 import org.apache.batik.ext.awt.geom.ExtendedGeneralPath;
31 import org.apache.batik.ext.awt.geom.ExtendedPathIterator;
32 import org.apache.batik.ext.awt.geom.ExtendedShape;
33 import org.apache.batik.ext.awt.geom.ShapeExtender;
34
35 /**
36  * A shape painter that can be used to paint markers on a shape.
37  *
38  * @author <a HREF="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
39  * @version $Id: MarkerShapePainter.java,v 1.17 2005/03/27 08:58:34 cam Exp $
40  */

41 public class MarkerShapePainter implements ShapePainter {
42
43     /**
44      * The Shape to be painted.
45      */

46     protected ExtendedShape extShape;
47
48     /**
49      * Start Marker
50      */

51     protected Marker startMarker;
52     
53     /**
54      * Middle Marker
55      */

56     protected Marker middleMarker;
57
58     /**
59      * End Marker
60      */

61     protected Marker endMarker;
62
63     /**
64      * Start marker proxy.
65      */

66     private ProxyGraphicsNode startMarkerProxy;
67
68     /**
69      * Middle marker proxy.
70      */

71     private ProxyGraphicsNode middleMarkerProxies[];
72
73     /**
74      * End marker proxy.
75      */

76     private ProxyGraphicsNode endMarkerProxy;
77
78     /**
79      * Contains the various marker proxies.
80      */

81     private CompositeGraphicsNode markerGroup;
82
83     /**
84      * Internal Cache: Primitive bounds
85      */

86     private Rectangle2D JavaDoc dPrimitiveBounds;
87
88     /**
89      * Internal Cache: Geometry bounds
90      */

91     private Rectangle2D JavaDoc dGeometryBounds;
92
93     /**
94      * Constructs a new <tt>MarkerShapePainter</tt> that can be used to markers
95      * on top of a shape.
96      *
97      * @param shape Shape to be painted by this painter.
98      * Should not be null
99      */

100     public MarkerShapePainter(Shape JavaDoc shape) {
101         if (shape == null) {
102             throw new IllegalArgumentException JavaDoc();
103         }
104         if (shape instanceof ExtendedShape) {
105             this.extShape = (ExtendedShape)shape;
106         } else {
107             this.extShape = new ShapeExtender(shape);
108         }
109     }
110
111     /**
112      * Paints the specified shape using the specified Graphics2D.
113      *
114      * @param g2d the Graphics2D to use
115      */

116      public void paint(Graphics2D JavaDoc g2d) {
117      if (markerGroup == null) {
118          buildMarkerGroup();
119      }
120          if (markerGroup.getChildren().size() > 0) {
121              markerGroup.paint(g2d);
122          }
123      }
124
125     /**
126      * Returns the area painted by this shape painter.
127      */

128     public Shape JavaDoc getPaintedArea(){
129      if (markerGroup == null) {
130          buildMarkerGroup();
131      }
132         return markerGroup.getOutline();
133     }
134
135     /**
136      * Returns the bounds of the area painted by this shape painter
137      */

138     public Rectangle2D JavaDoc getPaintedBounds2D(){
139      if (markerGroup == null) {
140          buildMarkerGroup();
141      }
142          return markerGroup.getPrimitiveBounds();
143     }
144
145     /**
146      * Returns true if pt is in the area painted by this shape painter
147      */

148     public boolean inPaintedArea(Point2D JavaDoc pt){
149      if (markerGroup == null) {
150          buildMarkerGroup();
151      }
152          GraphicsNode gn = markerGroup.nodeHitAt(pt);
153          return (gn != null);
154     }
155
156     /**
157      * Returns the area covered by this shape painter (even if not painted).
158      * This is always null for Markers.
159      */

160     public Shape JavaDoc getSensitiveArea() { return null; }
161
162     /**
163      * Returns the bounds of the area covered by this shape painte
164      * (even if not painted). This is always null for Markers.
165      */

166     public Rectangle2D JavaDoc getSensitiveBounds2D() { return null; }
167
168     /**
169      * Returns true if pt is in the sensitive area.
170      * This is always false for Markers.
171      */

172     public boolean inSensitiveArea(Point2D JavaDoc pt) { return false; }
173
174
175     /**
176      * Sets the Shape this shape painter is associated with.
177      *
178      * @param shape new shape this painter should be associated with.
179      * Should not be null.
180      */

181     public void setShape(Shape JavaDoc shape){
182         if (shape == null) {
183             throw new IllegalArgumentException JavaDoc();
184         }
185         if (shape instanceof ExtendedShape) {
186             this.extShape = (ExtendedShape)shape;
187         } else {
188             this.extShape = new ShapeExtender(shape);
189         }
190
191         this.startMarkerProxy = null;
192         this.middleMarkerProxies = null;
193         this.endMarkerProxy = null;
194     this.markerGroup = null;
195     }
196
197     /**
198      * Gets the Shape this shape painter is associated with as an
199      * Extended Shape.
200      *
201      * @return shape associated with this painter */

202     public ExtendedShape getExtShape(){
203         return extShape;
204     }
205
206     /**
207      * Gets the Shape this shape painter is associated with.
208      *
209      * @return shape associated with this painter
210      */

211     public Shape JavaDoc getShape(){
212         return extShape;
213     }
214
215     /**
216      * Returns the marker that shall be drawn at the first vertex of the given
217      * shape.
218      */

219     public Marker getStartMarker(){
220         return startMarker;
221     }
222
223     /**
224      * Sets the marker that shall be drawn at the first vertex of the given
225      * shape.
226      *
227      * @param startMarker the start marker
228      */

229     public void setStartMarker(Marker startMarker){
230         this.startMarker = startMarker;
231         this.startMarkerProxy = null;
232     this.markerGroup = null;
233     }
234
235     /**
236      * Returns the marker that shall be drawn at every other vertex (not the
237      * first or the last one) of the given shape.
238      */

239     public Marker getMiddleMarker(){
240         return middleMarker;
241     }
242
243     /**
244      * Sets the marker that shall be drawn at every other vertex (not the first
245      * or the last one) of the given shape.
246      *
247      * @param middleMarker the middle marker
248      */

249     public void setMiddleMarker(Marker middleMarker){
250         this.middleMarker = middleMarker;
251         this.middleMarkerProxies = null;
252     this.markerGroup = null;
253     }
254
255     /**
256      * Returns the marker that shall be drawn at the last vertex of the given
257      * shape.
258      */

259     public Marker getEndMarker(){
260         return endMarker;
261     }
262
263     /**
264      * Sets the marker that shall be drawn at the last vertex of the given
265      * shape.
266      *
267      * @param endMarker the end marker
268      */

269     public void setEndMarker(Marker endMarker){
270         this.endMarker = endMarker;
271         this.endMarkerProxy = null;
272     this.markerGroup = null;
273     }
274
275     // ---------------------------------------------------------------------
276
// Internal methods to build GraphicsNode according to the Marker
277
// ---------------------------------------------------------------------
278

279     /**
280      * Builds a new marker group with the current set of markers.
281      */

282     protected void buildMarkerGroup(){
283         if (startMarker != null && startMarkerProxy == null) {
284             startMarkerProxy = buildStartMarkerProxy();
285         }
286
287         if (middleMarker != null && middleMarkerProxies == null) {
288             middleMarkerProxies = buildMiddleMarkerProxies();
289         }
290
291         if (endMarker != null && endMarkerProxy == null) {
292             endMarkerProxy = buildEndMarkerProxy();
293         }
294
295         CompositeGraphicsNode group = new CompositeGraphicsNode();
296         List JavaDoc children = group.getChildren();
297         if (startMarkerProxy != null) {
298             children.add(startMarkerProxy);
299         }
300     
301         if (middleMarkerProxies != null) {
302             for(int i=0; i<middleMarkerProxies.length; i++){
303                 children.add(middleMarkerProxies[i]);
304             }
305         }
306     
307         if (endMarkerProxy != null) {
308             children.add(endMarkerProxy);
309         }
310
311         markerGroup = group;
312     }
313
314     /**
315      * Builds a proxy <tt>GraphicsNode</tt> for the input <tt>Marker</tt> to be
316      * drawn at the start position
317      */

318     protected ProxyGraphicsNode buildStartMarkerProxy() {
319
320         ExtendedPathIterator iter = getExtShape().getExtendedPathIterator();
321
322         // Get initial point on the path
323
double coords[] = new double[7];
324         int segType = 0;
325
326         if (iter.isDone()) {
327             return null;
328         }
329
330         segType = iter.currentSegment(coords);
331         if (segType != ExtendedPathIterator.SEG_MOVETO) {
332             return null;
333         }
334         iter.next();
335
336         Point2D JavaDoc markerPosition = new Point2D.Double JavaDoc(coords[0], coords[1]);
337
338         // If the marker's orient property is NaN,
339
// the slope needs to be computed
340
double rotation = startMarker.getOrient();
341         if (Double.isNaN(rotation)) {
342             if (!iter.isDone()) {
343                 double next[] = new double[7];
344                 int nextSegType = 0;
345                 nextSegType = iter.currentSegment(next);
346                 if(nextSegType == PathIterator.SEG_CLOSE){
347                     nextSegType = PathIterator.SEG_LINETO;
348                     next[0] = coords[0];
349                     next[1] = coords[1];
350                 }
351                 rotation = computeRotation(null, 0, // no previous seg.
352
coords, segType, // segment ending on start point
353
next, nextSegType); // segment out of start point
354

355             }
356         }
357         
358         // Now, compute the marker's proxy transform
359
AffineTransform JavaDoc markerTxf = computeMarkerTransform(startMarker,
360                                markerPosition,
361                                rotation);
362                                    
363         ProxyGraphicsNode gn = new ProxyGraphicsNode();
364
365         gn.setSource(startMarker.getMarkerNode());
366         gn.setTransform(markerTxf);
367     
368         return gn;
369     }
370
371     /**
372      * Builds a proxy <tt>GraphicsNode</tt> for the input <tt>Marker</tt> to be
373      * drawn at the end position.
374      */

375     protected ProxyGraphicsNode buildEndMarkerProxy() {
376
377         ExtendedPathIterator iter = getExtShape().getExtendedPathIterator();
378
379         int nPoints = 0;
380
381         // Get first point, in case the last segment on the
382
// path is a close
383
if (iter.isDone()) {
384             return null;
385         }
386     
387         double coords[] = new double[7];
388         double moveTo[] = new double[2];
389         int segType = 0;
390         segType = iter.currentSegment(coords);
391         if (segType != ExtendedPathIterator.SEG_MOVETO) {
392             return null;
393         }
394         nPoints++;
395         moveTo[0] = coords[0];
396         moveTo[1] = coords[1];
397
398         iter.next();
399         
400         // Now, get the last two points on the path
401
double[] lastButOne = new double[7];
402         double[] last = {coords[0], coords[1], coords[2],
403                          coords[3], coords[4], coords[5], coords[6] };
404         double[] tmp = null;
405         int lastSegType = segType;
406         int lastButOneSegType = 0;
407
408         while (!iter.isDone()) {
409             tmp = lastButOne;
410             lastButOne = last;
411             last = tmp;
412             lastButOneSegType = lastSegType;
413
414             lastSegType = iter.currentSegment(last);
415
416             if (lastSegType == PathIterator.SEG_MOVETO) {
417                 moveTo[0] = last[0];
418                 moveTo[1] = last[1];
419             } else if (lastSegType == PathIterator.SEG_CLOSE) {
420                 lastSegType = PathIterator.SEG_LINETO;
421                 last[0] = moveTo[0];
422                 last[1] = moveTo[1];
423             }
424
425             iter.next();
426             nPoints++;
427         }
428
429         if (nPoints < 2) {
430             return null;
431         }
432
433         // Turn the last segment into a position
434
Point2D JavaDoc markerPosition = getSegmentTerminatingPoint(last, lastSegType);
435
436         // If the marker's orient property is NaN,
437
// the slope needs to be computed
438
double rotation = endMarker.getOrient();
439         if (Double.isNaN(rotation)) {
440             rotation = computeRotation(lastButOne,
441                                        lastButOneSegType,
442                                        last, lastSegType,
443                                        null, 0);
444         }
445
446         // Now, compute the marker's proxy transform
447
AffineTransform JavaDoc markerTxf = computeMarkerTransform(endMarker,
448                                markerPosition,
449                                rotation);
450                                    
451         ProxyGraphicsNode gn = new ProxyGraphicsNode();
452
453         gn.setSource(endMarker.getMarkerNode());
454         gn.setTransform(markerTxf);
455
456         return gn;
457     }
458
459     /**
460      * Builds a proxy <tt>GraphicsNode</tt> for the input
461      * <tt>Marker</tt> to be drawn at the middle positions
462      */

463     protected ProxyGraphicsNode[] buildMiddleMarkerProxies() {
464
465         ExtendedPathIterator iter = getExtShape().getExtendedPathIterator();
466
467         double[] prev = new double[7];
468         double[] curr = new double[7];
469         double[] next = new double[7], tmp = null;
470         int prevSegType = 0, currSegType = 0, nextSegType = 0;
471
472         // Get the first three points on the path
473
if (iter.isDone()) {
474             return null;
475         }
476
477         prevSegType = iter.currentSegment(prev);
478         double[] moveTo = new double[2];
479
480         if (prevSegType != PathIterator.SEG_MOVETO) {
481             return null;
482         }
483
484         moveTo[0] = prev[0];
485         moveTo[1] = prev[1];
486         iter.next();
487
488         if (iter.isDone()) {
489             return null;
490         }
491     
492         currSegType = iter.currentSegment(curr);
493
494         if (currSegType == PathIterator.SEG_MOVETO) {
495             moveTo[0] = curr[0];
496             moveTo[1] = curr[1];
497         } else if (currSegType == PathIterator.SEG_CLOSE) {
498             currSegType = PathIterator.SEG_LINETO;
499             curr[0] = moveTo[0];
500             curr[1] = moveTo[1];
501         }
502
503         iter.next();
504
505         Vector JavaDoc proxies = new Vector JavaDoc();
506         while (!iter.isDone()) {
507             nextSegType = iter.currentSegment(next);
508
509             if (nextSegType == PathIterator.SEG_MOVETO) {
510                 moveTo[0] = next[0];
511                 moveTo[1] = next[1];
512             } else if (nextSegType == PathIterator.SEG_CLOSE) {
513                 nextSegType = PathIterator.SEG_LINETO;
514                 next[0] = moveTo[0];
515                 next[1] = moveTo[1];
516             }
517         
518             proxies.addElement(createMiddleMarker(prev, prevSegType,
519                                                   curr, currSegType,
520                                                   next, nextSegType));
521             
522             tmp = prev;
523             prev = curr;
524             prevSegType = currSegType;
525             curr = next;
526             currSegType = nextSegType;
527             next = tmp;
528             
529             iter.next();
530         }
531
532         ProxyGraphicsNode [] gn = new ProxyGraphicsNode[proxies.size()];
533         proxies.copyInto(gn);
534
535         return gn;
536     }
537
538     /**
539      * Creates a ProxyGraphicsNode for a middle marker.
540      */

541     private ProxyGraphicsNode createMiddleMarker
542         (double[] prev, int prevSegType,
543          double[] curr, int currSegType,
544          double[] next, int nextSegType) {
545
546         // Turn the curr segment into a position
547
Point2D JavaDoc markerPosition = getSegmentTerminatingPoint(curr, currSegType);
548
549         // If the marker's orient property is NaN,
550
// the slope needs to be computed
551
double rotation = middleMarker.getOrient();
552         if (Double.isNaN(rotation)) {
553             rotation = computeRotation(prev, prevSegType,
554                                        curr, currSegType,
555                                        next, nextSegType);
556         }
557     
558         // Now, compute the marker's proxy transform
559
AffineTransform JavaDoc markerTxf = computeMarkerTransform(middleMarker,
560                                markerPosition,
561                                rotation);
562                                    
563         ProxyGraphicsNode gn = new ProxyGraphicsNode();
564
565         gn.setSource(middleMarker.getMarkerNode());
566         gn.setTransform(markerTxf);
567
568         return gn;
569     }
570
571     /**
572      * Returns the rotation according to the specified parameters.
573      */

574     private double computeRotation(double[] prev, int prevSegType,
575                                    double[] curr, int currSegType,
576                                    double[] next, int nextSegType){
577
578         // Compute in slope, i.e., the slope of the segment
579
// going into the current point
580
double[] inSlope = computeInSlope(prev, prevSegType,
581                                           curr, currSegType);
582
583         // Compute out slope, i.e., the slope of the segment
584
// going out of the current point
585
double[] outSlope = computeOutSlope(curr, currSegType,
586                                             next, nextSegType);
587
588         if (inSlope == null) {
589             inSlope = outSlope;
590         }
591
592         if (outSlope == null) {
593             outSlope = inSlope;
594         }
595
596         if (inSlope == null) {
597             return 0;
598         }
599
600         double dx = inSlope[0] + outSlope[0];
601         double dy = inSlope[1] + outSlope[1];
602
603         if (dx == 0 && dy == 0) {
604             // The two vectors are exact opposites. There is no way to
605
// know which direction to go (+90 or -90). Choose +90
606
return Math.atan2(inSlope[1], inSlope[0])*180./Math.PI + 90;
607         } else {
608             return Math.atan2(dy, dx)*180./Math.PI;
609         }
610     }
611
612     /**
613      * Returns dx/dy for the in slope.
614      */

615     private double[] computeInSlope(double[] prev, int prevSegType,
616                                     double[] curr, int currSegType){
617
618         // Compute point into which the slope runs
619
Point2D JavaDoc currEndPoint = getSegmentTerminatingPoint(curr, currSegType);
620
621         double dx = 0;
622         double dy = 0;
623
624         switch(currSegType){
625         case PathIterator.SEG_LINETO: {
626             // This is equivalent to a line from the previous segment's
627
// terminating point and the current end point.
628
Point2D JavaDoc prevEndPoint =
629                 getSegmentTerminatingPoint(prev, prevSegType);
630             dx = currEndPoint.getX() - prevEndPoint.getX();
631             dy = currEndPoint.getY() - prevEndPoint.getY();
632         }
633             break;
634         case PathIterator.SEG_QUADTO:
635             // If the current segment is a line, quad or cubic curve.
636
// the slope is about equal to that of the line from the
637
// last control point and the curEndPoint
638
dx = currEndPoint.getX() - curr[0];
639             dy = currEndPoint.getY() - curr[1];
640             break;
641         case PathIterator.SEG_CUBICTO:
642             // If the current segment is a quad or cubic curve.
643
// the slope is about equal to that of the line from the
644
// last control point and the curEndPoint
645
dx = currEndPoint.getX() - curr[2];
646             dy = currEndPoint.getY() - curr[3];
647             break;
648         case ExtendedPathIterator.SEG_ARCTO: {
649             // If the current segment is an ARCTO then we build the
650
// arc and ask for it's end angle and get the tangent there.
651
Point2D JavaDoc prevEndPoint =
652                 getSegmentTerminatingPoint(prev, prevSegType);
653             boolean large = (curr[3]!=0.);
654             boolean goLeft = (curr[4]!=0.);
655             Arc2D JavaDoc arc = ExtendedGeneralPath.computeArc
656                 (prevEndPoint.getX(), prevEndPoint.getY(),
657                  curr[0], curr[1], curr[2],
658                  large, goLeft, curr[5], curr[6]);
659             double theta = arc.getAngleStart()+arc.getAngleExtent();
660             theta = Math.toRadians(theta);
661             dx = -arc.getWidth()/2.0*Math.sin(theta);
662             dy = arc.getHeight()/2.0*Math.cos(theta);
663
664             // System.out.println("In Theta: " + Math.toDegrees(theta) +
665
// " Dx/Dy: " + dx + "/" + dy);
666
if (curr[2] != 0) {
667                 double ang = Math.toRadians(-curr[2]);
668                 double sinA = Math.sin(ang);
669                 double cosA = Math.cos(ang);
670                 double tdx = dx*cosA - dy*sinA;
671                 double tdy = dx*sinA + dy*cosA;
672                 dx = tdx;
673                 dy = tdy;
674             }
675             // System.out.println(" Rotate: " + curr[2] +
676
// " Dx/Dy: " + dx + "/" + dy);
677
if (goLeft) {
678                 dx = -dx;
679             } else {
680                 dy = -dy;
681             }
682             // System.out.println(" GoLeft? " + goLeft +
683
// " Dx/Dy: " + dx + "/" + dy);
684
}
685             break;
686         case PathIterator.SEG_CLOSE:
687             // Should not have any close at this point
688
throw new Error JavaDoc();
689         case PathIterator.SEG_MOVETO:
690             // Cannot compute the slope
691
default:
692             return null;
693         }
694
695         if (dx == 0 && dy == 0) {
696             return null;
697         }
698
699         return normalize(new double[] { dx, dy });
700     }
701
702     /**
703      * Returns dx/dy for the out slope.
704      */

705     private double[] computeOutSlope(double[] curr, int currSegType,
706                                      double[] next, int nextSegType){
707
708         Point2D JavaDoc currEndPoint = getSegmentTerminatingPoint(curr, currSegType);
709         
710         double dx = 0, dy = 0;
711
712         switch(nextSegType){
713         case PathIterator.SEG_CLOSE:
714             // Should not happen at this point, because all close
715
// segments have been replaced by lineTo segments.
716
break;
717         case PathIterator.SEG_CUBICTO:
718         case PathIterator.SEG_LINETO:
719         case PathIterator.SEG_QUADTO:
720             // If the next segment is a line, quad or cubic curve.
721
// the slope is about equal to that of the line from
722
// curEndPoint and the first control point
723
dx = next[0] - currEndPoint.getX();
724             dy = next[1] - currEndPoint.getY();
725             break;
726         case ExtendedPathIterator.SEG_ARCTO: {
727             // If the current segment is an ARCTO then we build the
728
// arc and ask for it's end angle and get the tangent there.
729
boolean large = (next[3]!=0.);
730             boolean goLeft = (next[4]!=0.);
731             Arc2D JavaDoc arc = ExtendedGeneralPath.computeArc
732                 (currEndPoint.getX(), currEndPoint.getY(),
733                  next[0], next[1], next[2],
734                  large, goLeft, next[5], next[6]);
735             double theta = arc.getAngleStart();
736             theta = Math.toRadians(theta);
737             dx = -arc.getWidth()/2.0*Math.sin(theta);
738             dy = arc.getHeight()/2.0*Math.cos(theta);
739             // System.out.println("Out Theta: " + Math.toDegrees(theta) +
740
// " Dx/Dy: " + dx + "/" + dy);
741
if (next[2] != 0) {
742                 double ang = Math.toRadians(-next[2]);
743                 double sinA = Math.sin(ang);
744                 double cosA = Math.cos(ang);
745                 double tdx = dx*cosA - dy*sinA;
746                 double tdy = dx*sinA + dy*cosA;
747                 dx = tdx;
748                 dy = tdy;
749             }
750             // System.out.println(" Rotate: " + next[2] +
751
// " Dx/Dy: " + dx + "/" + dy);
752

753             if (goLeft) {
754                 dx = -dx;
755             } else {
756                 dy = -dy;
757             }
758             // System.out.println(" GoLeft? " + goLeft +
759
// " Dx/Dy: " + dx + "/" + dy);
760
}
761             break;
762         case PathIterator.SEG_MOVETO:
763             // Cannot compute the out slope
764
default:
765             return null;
766         }
767
768         if (dx == 0 && dy == 0) {
769             return null;
770         }
771
772         return normalize(new double[] { dx, dy });
773     }
774
775     /**
776      * Normalizes the input vector. This assumes an non-zero length
777      */

778     public double[] normalize(double[] v) {
779         double n = Math.sqrt(v[0]*v[0]+v[1]*v[1]);
780         v[0] /= n;
781         v[1] /= n;
782         return v;
783     }
784
785     /**
786      * Computes the transform for the input marker, so that it is positioned at
787      * the given position with the specified rotation
788      */

789     private AffineTransform JavaDoc computeMarkerTransform(Marker marker,
790                            Point2D JavaDoc markerPosition,
791                            double rotation) {
792         Point2D JavaDoc ref = marker.getRef();
793         /*AffineTransform txf =
794             AffineTransform.getTranslateInstance(markerPosition.getX()
795                                                  - ref.getX(),
796                                                  markerPosition.getY()
797                                                  - ref.getY());*/

798         AffineTransform JavaDoc txf = new AffineTransform JavaDoc();
799
800         txf.translate(markerPosition.getX() - ref.getX(),
801                       markerPosition.getY() - ref.getY());
802
803         if (!Double.isNaN(rotation)) {
804             txf.rotate(rotation*Math.PI/180., ref.getX(), ref.getY());
805         }
806
807         return txf;
808     }
809
810     /**
811      * Extracts the terminating point, depending on the segment type.
812      */

813     protected Point2D JavaDoc getSegmentTerminatingPoint(double coords[], int segType) {
814         switch(segType){
815         case PathIterator.SEG_CUBICTO:
816             return new Point2D.Double JavaDoc(coords[4], coords[5]);
817         case PathIterator.SEG_LINETO:
818             return new Point2D.Double JavaDoc(coords[0], coords[1]);
819         case PathIterator.SEG_MOVETO:
820             return new Point2D.Double JavaDoc(coords[0], coords[1]);
821         case PathIterator.SEG_QUADTO:
822             return new Point2D.Double JavaDoc(coords[2], coords[3]);
823         case ExtendedPathIterator.SEG_ARCTO:
824             return new Point2D.Double JavaDoc(coords[5], coords[6]);
825         case PathIterator.SEG_CLOSE:
826         default:
827             throw new Error JavaDoc();
828             // Should never happen: close segments are replaced with lineTo
829
}
830     }
831 }
832
Popular Tags