Source Code Cross Referenced for MarkerShapePainter.java in  » Graphic-Library » batik » org » apache » batik » gvt » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Graphic Library » batik » org.apache.batik.gvt 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:
003:           Licensed to the Apache Software Foundation (ASF) under one or more
004:           contributor license agreements.  See the NOTICE file distributed with
005:           this work for additional information regarding copyright ownership.
006:           The ASF licenses this file to You under the Apache License, Version 2.0
007:           (the "License"); you may not use this file except in compliance with
008:           the License.  You may obtain a copy of the License at
009:
010:               http://www.apache.org/licenses/LICENSE-2.0
011:
012:           Unless required by applicable law or agreed to in writing, software
013:           distributed under the License is distributed on an "AS IS" BASIS,
014:           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015:           See the License for the specific language governing permissions and
016:           limitations under the License.
017:
018:         */
019:        package org.apache.batik.gvt;
020:
021:        import java.awt.Graphics2D;
022:        import java.awt.Shape;
023:        import java.awt.geom.AffineTransform;
024:        import java.awt.geom.Arc2D;
025:        import java.awt.geom.PathIterator;
026:        import java.awt.geom.Point2D;
027:        import java.awt.geom.Rectangle2D;
028:        import java.util.List;
029:        import java.util.ArrayList;
030:
031:        import org.apache.batik.ext.awt.geom.ExtendedGeneralPath;
032:        import org.apache.batik.ext.awt.geom.ExtendedPathIterator;
033:        import org.apache.batik.ext.awt.geom.ExtendedShape;
034:        import org.apache.batik.ext.awt.geom.ShapeExtender;
035:
036:        /**
037:         * A shape painter that can be used to paint markers on a shape.
038:         *
039:         * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
040:         * @version $Id: MarkerShapePainter.java 504084 2007-02-06 11:24:46Z dvholten $
041:         */
042:        public class MarkerShapePainter implements  ShapePainter {
043:
044:            /**
045:             * The Shape to be painted.
046:             */
047:            protected ExtendedShape extShape;
048:
049:            /**
050:             * Start Marker
051:             */
052:            protected Marker startMarker;
053:
054:            /**
055:             * Middle Marker
056:             */
057:            protected Marker middleMarker;
058:
059:            /**
060:             * End Marker
061:             */
062:            protected Marker endMarker;
063:
064:            /**
065:             * Start marker proxy.
066:             */
067:            private ProxyGraphicsNode startMarkerProxy;
068:
069:            /**
070:             * Middle marker proxy.
071:             */
072:            private ProxyGraphicsNode[] middleMarkerProxies;
073:
074:            /**
075:             * End marker proxy.
076:             */
077:            private ProxyGraphicsNode endMarkerProxy;
078:
079:            /**
080:             * Contains the various marker proxies.
081:             */
082:            private CompositeGraphicsNode markerGroup;
083:
084:            /**
085:             * Internal Cache: Primitive bounds
086:             */
087:            private Rectangle2D dPrimitiveBounds;
088:
089:            /**
090:             * Internal Cache: Geometry bounds
091:             */
092:            private Rectangle2D dGeometryBounds;
093:
094:            /**
095:             * Constructs a new <tt>MarkerShapePainter</tt> that can be used to markers
096:             * on top of a shape.
097:             *
098:             * @param shape Shape to be painted by this painter.
099:             * Should not be null
100:             */
101:            public MarkerShapePainter(Shape shape) {
102:                if (shape == null) {
103:                    throw new IllegalArgumentException();
104:                }
105:                if (shape instanceof  ExtendedShape) {
106:                    this .extShape = (ExtendedShape) shape;
107:                } else {
108:                    this .extShape = new ShapeExtender(shape);
109:                }
110:            }
111:
112:            /**
113:             * Paints the specified shape using the specified Graphics2D.
114:             *
115:             * @param g2d the Graphics2D to use
116:             */
117:            public void paint(Graphics2D g2d) {
118:                if (markerGroup == null) {
119:                    buildMarkerGroup();
120:                }
121:                if (markerGroup.getChildren().size() > 0) {
122:                    markerGroup.paint(g2d);
123:                }
124:            }
125:
126:            /**
127:             * Returns the area painted by this shape painter.
128:             */
129:            public Shape getPaintedArea() {
130:                if (markerGroup == null) {
131:                    buildMarkerGroup();
132:                }
133:                return markerGroup.getOutline();
134:            }
135:
136:            /**
137:             * Returns the bounds of the area painted by this shape painter
138:             */
139:            public Rectangle2D getPaintedBounds2D() {
140:                if (markerGroup == null) {
141:                    buildMarkerGroup();
142:                }
143:                return markerGroup.getPrimitiveBounds();
144:            }
145:
146:            /**
147:             * Returns true if pt is in the area painted by this shape painter
148:             */
149:            public boolean inPaintedArea(Point2D pt) {
150:                if (markerGroup == null) {
151:                    buildMarkerGroup();
152:                }
153:                GraphicsNode gn = markerGroup.nodeHitAt(pt);
154:                return (gn != null);
155:            }
156:
157:            /**
158:             * Returns the area covered by this shape painter (even if not painted).
159:             * This is always null for Markers.
160:             */
161:            public Shape getSensitiveArea() {
162:                return null;
163:            }
164:
165:            /**
166:             * Returns the bounds of the area covered by this shape painte
167:             * (even if not painted). This is always null for Markers.
168:             */
169:            public Rectangle2D getSensitiveBounds2D() {
170:                return null;
171:            }
172:
173:            /**
174:             * Returns true if pt is in the sensitive area.
175:             * This is always false for Markers.
176:             */
177:            public boolean inSensitiveArea(Point2D pt) {
178:                return false;
179:            }
180:
181:            /**
182:             * Sets the Shape this shape painter is associated with.
183:             *
184:             * @param shape new shape this painter should be associated with.
185:             * Should not be null.
186:             */
187:            public void setShape(Shape shape) {
188:                if (shape == null) {
189:                    throw new IllegalArgumentException();
190:                }
191:                if (shape instanceof  ExtendedShape) {
192:                    this .extShape = (ExtendedShape) shape;
193:                } else {
194:                    this .extShape = new ShapeExtender(shape);
195:                }
196:
197:                this .startMarkerProxy = null;
198:                this .middleMarkerProxies = null;
199:                this .endMarkerProxy = null;
200:                this .markerGroup = null;
201:            }
202:
203:            /**
204:             * Gets the Shape this shape painter is associated with as an
205:             * Extended Shape.
206:             *
207:             * @return shape associated with this painter */
208:            public ExtendedShape getExtShape() {
209:                return extShape;
210:            }
211:
212:            /**
213:             * Gets the Shape this shape painter is associated with.
214:             *
215:             * @return shape associated with this painter
216:             */
217:            public Shape getShape() {
218:                return extShape;
219:            }
220:
221:            /**
222:             * Returns the marker that shall be drawn at the first vertex of the given
223:             * shape.
224:             */
225:            public Marker getStartMarker() {
226:                return startMarker;
227:            }
228:
229:            /**
230:             * Sets the marker that shall be drawn at the first vertex of the given
231:             * shape.
232:             *
233:             * @param startMarker the start marker
234:             */
235:            public void setStartMarker(Marker startMarker) {
236:                this .startMarker = startMarker;
237:                this .startMarkerProxy = null;
238:                this .markerGroup = null;
239:            }
240:
241:            /**
242:             * Returns the marker that shall be drawn at every other vertex (not the
243:             * first or the last one) of the given shape.
244:             */
245:            public Marker getMiddleMarker() {
246:                return middleMarker;
247:            }
248:
249:            /**
250:             * Sets the marker that shall be drawn at every other vertex (not the first
251:             * or the last one) of the given shape.
252:             *
253:             * @param middleMarker the middle marker
254:             */
255:            public void setMiddleMarker(Marker middleMarker) {
256:                this .middleMarker = middleMarker;
257:                this .middleMarkerProxies = null;
258:                this .markerGroup = null;
259:            }
260:
261:            /**
262:             * Returns the marker that shall be drawn at the last vertex of the given
263:             * shape.
264:             */
265:            public Marker getEndMarker() {
266:                return endMarker;
267:            }
268:
269:            /**
270:             * Sets the marker that shall be drawn at the last vertex of the given
271:             * shape.
272:             *
273:             * @param endMarker the end marker
274:             */
275:            public void setEndMarker(Marker endMarker) {
276:                this .endMarker = endMarker;
277:                this .endMarkerProxy = null;
278:                this .markerGroup = null;
279:            }
280:
281:            // ---------------------------------------------------------------------
282:            // Internal methods to build GraphicsNode according to the Marker
283:            // ---------------------------------------------------------------------
284:
285:            /**
286:             * Builds a new marker group with the current set of markers.
287:             */
288:            protected void buildMarkerGroup() {
289:                if (startMarker != null && startMarkerProxy == null) {
290:                    startMarkerProxy = buildStartMarkerProxy();
291:                }
292:
293:                if (middleMarker != null && middleMarkerProxies == null) {
294:                    middleMarkerProxies = buildMiddleMarkerProxies();
295:                }
296:
297:                if (endMarker != null && endMarkerProxy == null) {
298:                    endMarkerProxy = buildEndMarkerProxy();
299:                }
300:
301:                CompositeGraphicsNode group = new CompositeGraphicsNode();
302:                List children = group.getChildren();
303:                if (startMarkerProxy != null) {
304:                    children.add(startMarkerProxy);
305:                }
306:
307:                if (middleMarkerProxies != null) {
308:                    for (int i = 0; i < middleMarkerProxies.length; i++) {
309:                        children.add(middleMarkerProxies[i]);
310:                    }
311:                }
312:
313:                if (endMarkerProxy != null) {
314:                    children.add(endMarkerProxy);
315:                }
316:
317:                markerGroup = group;
318:            }
319:
320:            /**
321:             * Builds a proxy <tt>GraphicsNode</tt> for the input <tt>Marker</tt> to be
322:             * drawn at the start position
323:             */
324:            protected ProxyGraphicsNode buildStartMarkerProxy() {
325:
326:                ExtendedPathIterator iter = getExtShape()
327:                        .getExtendedPathIterator();
328:
329:                // Get initial point on the path
330:                double[] coords = new double[7];
331:                int segType = 0;
332:
333:                if (iter.isDone()) {
334:                    return null;
335:                }
336:
337:                segType = iter.currentSegment(coords);
338:                if (segType != ExtendedPathIterator.SEG_MOVETO) {
339:                    return null;
340:                }
341:                iter.next();
342:
343:                Point2D markerPosition = new Point2D.Double(coords[0],
344:                        coords[1]);
345:
346:                // If the marker's orient property is NaN,
347:                // the slope needs to be computed
348:                double rotation = startMarker.getOrient();
349:                if (Double.isNaN(rotation)) {
350:                    if (!iter.isDone()) {
351:                        double[] next = new double[7];
352:                        int nextSegType = 0;
353:                        nextSegType = iter.currentSegment(next);
354:                        if (nextSegType == PathIterator.SEG_CLOSE) {
355:                            nextSegType = PathIterator.SEG_LINETO;
356:                            next[0] = coords[0];
357:                            next[1] = coords[1];
358:                        }
359:                        rotation = computeRotation(null, 0, // no previous seg.
360:                                coords, segType, // segment ending on start point
361:                                next, nextSegType); // segment out of start point
362:
363:                    }
364:                }
365:
366:                // Now, compute the marker's proxy transform
367:                AffineTransform markerTxf = computeMarkerTransform(startMarker,
368:                        markerPosition, rotation);
369:
370:                ProxyGraphicsNode gn = new ProxyGraphicsNode();
371:
372:                gn.setSource(startMarker.getMarkerNode());
373:                gn.setTransform(markerTxf);
374:
375:                return gn;
376:            }
377:
378:            /**
379:             * Builds a proxy <tt>GraphicsNode</tt> for the input <tt>Marker</tt> to be
380:             * drawn at the end position.
381:             */
382:            protected ProxyGraphicsNode buildEndMarkerProxy() {
383:
384:                ExtendedPathIterator iter = getExtShape()
385:                        .getExtendedPathIterator();
386:
387:                int nPoints = 0;
388:
389:                // Get first point, in case the last segment on the
390:                // path is a close
391:                if (iter.isDone()) {
392:                    return null;
393:                }
394:
395:                double[] coords = new double[7];
396:                double[] moveTo = new double[2];
397:                int segType = 0;
398:                segType = iter.currentSegment(coords);
399:                if (segType != ExtendedPathIterator.SEG_MOVETO) {
400:                    return null;
401:                }
402:                nPoints++;
403:                moveTo[0] = coords[0];
404:                moveTo[1] = coords[1];
405:
406:                iter.next();
407:
408:                // Now, get the last two points on the path
409:                double[] lastButOne = new double[7];
410:                double[] last = { coords[0], coords[1], coords[2], coords[3],
411:                        coords[4], coords[5], coords[6] };
412:                double[] tmp = null;
413:                int lastSegType = segType;
414:                int lastButOneSegType = 0;
415:
416:                while (!iter.isDone()) {
417:                    tmp = lastButOne;
418:                    lastButOne = last;
419:                    last = tmp;
420:                    lastButOneSegType = lastSegType;
421:
422:                    lastSegType = iter.currentSegment(last);
423:
424:                    if (lastSegType == PathIterator.SEG_MOVETO) {
425:                        moveTo[0] = last[0];
426:                        moveTo[1] = last[1];
427:                    } else if (lastSegType == PathIterator.SEG_CLOSE) {
428:                        lastSegType = PathIterator.SEG_LINETO;
429:                        last[0] = moveTo[0];
430:                        last[1] = moveTo[1];
431:                    }
432:
433:                    iter.next();
434:                    nPoints++;
435:                }
436:
437:                if (nPoints < 2) {
438:                    return null;
439:                }
440:
441:                // Turn the last segment into a position
442:                Point2D markerPosition = getSegmentTerminatingPoint(last,
443:                        lastSegType);
444:
445:                // If the marker's orient property is NaN,
446:                // the slope needs to be computed
447:                double rotation = endMarker.getOrient();
448:                if (Double.isNaN(rotation)) {
449:                    rotation = computeRotation(lastButOne, lastButOneSegType,
450:                            last, lastSegType, null, 0);
451:                }
452:
453:                // Now, compute the marker's proxy transform
454:                AffineTransform markerTxf = computeMarkerTransform(endMarker,
455:                        markerPosition, rotation);
456:
457:                ProxyGraphicsNode gn = new ProxyGraphicsNode();
458:
459:                gn.setSource(endMarker.getMarkerNode());
460:                gn.setTransform(markerTxf);
461:
462:                return gn;
463:            }
464:
465:            /**
466:             * Builds a proxy <tt>GraphicsNode</tt> for the input
467:             * <tt>Marker</tt> to be drawn at the middle positions
468:             */
469:            protected ProxyGraphicsNode[] buildMiddleMarkerProxies() {
470:
471:                ExtendedPathIterator iter = getExtShape()
472:                        .getExtendedPathIterator();
473:
474:                double[] prev = new double[7];
475:                double[] curr = new double[7];
476:                double[] next = new double[7], tmp = null;
477:                int prevSegType = 0, currSegType = 0, nextSegType = 0;
478:
479:                // Get the first three points on the path
480:                if (iter.isDone()) {
481:                    return null;
482:                }
483:
484:                prevSegType = iter.currentSegment(prev);
485:                double[] moveTo = new double[2];
486:
487:                if (prevSegType != PathIterator.SEG_MOVETO) {
488:                    return null;
489:                }
490:
491:                moveTo[0] = prev[0];
492:                moveTo[1] = prev[1];
493:                iter.next();
494:
495:                if (iter.isDone()) {
496:                    return null;
497:                }
498:
499:                currSegType = iter.currentSegment(curr);
500:
501:                if (currSegType == PathIterator.SEG_MOVETO) {
502:                    moveTo[0] = curr[0];
503:                    moveTo[1] = curr[1];
504:                } else if (currSegType == PathIterator.SEG_CLOSE) {
505:                    currSegType = PathIterator.SEG_LINETO;
506:                    curr[0] = moveTo[0];
507:                    curr[1] = moveTo[1];
508:                }
509:
510:                iter.next();
511:
512:                List proxies = new ArrayList();
513:                while (!iter.isDone()) {
514:                    nextSegType = iter.currentSegment(next);
515:
516:                    if (nextSegType == PathIterator.SEG_MOVETO) {
517:                        moveTo[0] = next[0];
518:                        moveTo[1] = next[1];
519:                    } else if (nextSegType == PathIterator.SEG_CLOSE) {
520:                        nextSegType = PathIterator.SEG_LINETO;
521:                        next[0] = moveTo[0];
522:                        next[1] = moveTo[1];
523:                    }
524:
525:                    proxies.add(createMiddleMarker(prev, prevSegType, curr,
526:                            currSegType, next, nextSegType));
527:
528:                    tmp = prev;
529:                    prev = curr;
530:                    prevSegType = currSegType;
531:                    curr = next;
532:                    currSegType = nextSegType;
533:                    next = tmp;
534:
535:                    iter.next();
536:                }
537:
538:                ProxyGraphicsNode[] gn = new ProxyGraphicsNode[proxies.size()];
539:                proxies.toArray(gn);
540:
541:                return gn;
542:            }
543:
544:            /**
545:             * Creates a ProxyGraphicsNode for a middle marker.
546:             */
547:            private ProxyGraphicsNode createMiddleMarker(double[] prev,
548:                    int prevSegType, double[] curr, int currSegType,
549:                    double[] next, int nextSegType) {
550:
551:                // Turn the curr segment into a position
552:                Point2D markerPosition = getSegmentTerminatingPoint(curr,
553:                        currSegType);
554:
555:                // If the marker's orient property is NaN,
556:                // the slope needs to be computed
557:                double rotation = middleMarker.getOrient();
558:                if (Double.isNaN(rotation)) {
559:                    rotation = computeRotation(prev, prevSegType, curr,
560:                            currSegType, next, nextSegType);
561:                }
562:
563:                // Now, compute the marker's proxy transform
564:                AffineTransform markerTxf = computeMarkerTransform(
565:                        middleMarker, markerPosition, rotation);
566:
567:                ProxyGraphicsNode gn = new ProxyGraphicsNode();
568:
569:                gn.setSource(middleMarker.getMarkerNode());
570:                gn.setTransform(markerTxf);
571:
572:                return gn;
573:            }
574:
575:            /**
576:             * Returns the rotation according to the specified parameters in degrees.
577:             */
578:            private double computeRotation(double[] prev, int prevSegType,
579:                    double[] curr, int currSegType, double[] next,
580:                    int nextSegType) {
581:
582:                // Compute in slope, i.e., the slope of the segment
583:                // going into the current point
584:                double[] inSlope = computeInSlope(prev, prevSegType, curr,
585:                        currSegType);
586:
587:                // Compute out slope, i.e., the slope of the segment
588:                // going out of the current point
589:                double[] outSlope = computeOutSlope(curr, currSegType, next,
590:                        nextSegType);
591:
592:                if (inSlope == null) {
593:                    inSlope = outSlope;
594:                }
595:
596:                if (outSlope == null) {
597:                    outSlope = inSlope;
598:                }
599:
600:                if (inSlope == null) {
601:                    return 0;
602:                }
603:
604:                double dx = inSlope[0] + outSlope[0];
605:                double dy = inSlope[1] + outSlope[1];
606:
607:                if (dx == 0 && dy == 0) {
608:                    // The two vectors are exact opposites. There is no way to
609:                    // know which direction to go (+90 or -90). Choose +90
610:                    return Math.toDegrees(Math.atan2(inSlope[1], inSlope[0])) + 90;
611:                } else {
612:                    return Math.toDegrees(Math.atan2(dy, dx));
613:                }
614:            }
615:
616:            /**
617:             * Returns dx/dy for the in slope.
618:             */
619:            private double[] computeInSlope(double[] prev, int prevSegType,
620:                    double[] curr, int currSegType) {
621:
622:                // Compute point into which the slope runs
623:                Point2D currEndPoint = getSegmentTerminatingPoint(curr,
624:                        currSegType);
625:
626:                double dx = 0;
627:                double dy = 0;
628:
629:                switch (currSegType) {
630:                case PathIterator.SEG_LINETO: {
631:                    // This is equivalent to a line from the previous segment's
632:                    // terminating point and the current end point.
633:                    Point2D prevEndPoint = getSegmentTerminatingPoint(prev,
634:                            prevSegType);
635:                    dx = currEndPoint.getX() - prevEndPoint.getX();
636:                    dy = currEndPoint.getY() - prevEndPoint.getY();
637:                }
638:                    break;
639:                case PathIterator.SEG_QUADTO:
640:                    // If the current segment is a line, quad or cubic curve.
641:                    // the slope is about equal to that of the line from the
642:                    // last control point and the curEndPoint
643:                    dx = currEndPoint.getX() - curr[0];
644:                    dy = currEndPoint.getY() - curr[1];
645:                    break;
646:                case PathIterator.SEG_CUBICTO:
647:                    // If the current segment is a quad or cubic curve.
648:                    // the slope is about equal to that of the line from the
649:                    // last control point and the curEndPoint
650:                    dx = currEndPoint.getX() - curr[2];
651:                    dy = currEndPoint.getY() - curr[3];
652:                    break;
653:                case ExtendedPathIterator.SEG_ARCTO: {
654:                    // If the current segment is an ARCTO then we build the
655:                    // arc and ask for it's end angle and get the tangent there.
656:                    Point2D prevEndPoint = getSegmentTerminatingPoint(prev,
657:                            prevSegType);
658:                    boolean large = (curr[3] != 0.);
659:                    boolean goLeft = (curr[4] != 0.);
660:                    Arc2D arc = ExtendedGeneralPath.computeArc(prevEndPoint
661:                            .getX(), prevEndPoint.getY(), curr[0], curr[1],
662:                            curr[2], large, goLeft, curr[5], curr[6]);
663:                    double theta = arc.getAngleStart() + arc.getAngleExtent();
664:                    theta = Math.toRadians(theta);
665:                    dx = -arc.getWidth() / 2.0 * Math.sin(theta);
666:                    dy = arc.getHeight() / 2.0 * Math.cos(theta);
667:
668:                    // System.out.println("In  Theta:  " + Math.toDegrees(theta) +
669:                    //                    " Dx/Dy: " + dx + "/" + dy);
670:                    if (curr[2] != 0) {
671:                        double ang = Math.toRadians(-curr[2]);
672:                        double sinA = Math.sin(ang);
673:                        double cosA = Math.cos(ang);
674:                        double tdx = dx * cosA - dy * sinA;
675:                        double tdy = dx * sinA + dy * cosA;
676:                        dx = tdx;
677:                        dy = tdy;
678:                    }
679:                    // System.out.println("    Rotate: " + curr[2] +
680:                    //                    " Dx/Dy: " + dx + "/" + dy);
681:                    if (goLeft) {
682:                        dx = -dx;
683:                    } else {
684:                        dy = -dy;
685:                    }
686:                    // System.out.println("    GoLeft? " + goLeft +
687:                    //                    " Dx/Dy: " + dx + "/" + dy);
688:                }
689:                    break;
690:                case PathIterator.SEG_CLOSE:
691:                    // Should not have any close at this point
692:                    throw new Error("should not have SEG_CLOSE here");
693:                case PathIterator.SEG_MOVETO:
694:                    // Cannot compute the slope
695:                default:
696:                    return null;
697:                }
698:
699:                if (dx == 0 && dy == 0) {
700:                    return null;
701:                }
702:
703:                return normalize(new double[] { dx, dy });
704:            }
705:
706:            /**
707:             * Returns dx/dy for the out slope.
708:             */
709:            private double[] computeOutSlope(double[] curr, int currSegType,
710:                    double[] next, int nextSegType) {
711:
712:                Point2D currEndPoint = getSegmentTerminatingPoint(curr,
713:                        currSegType);
714:
715:                double dx = 0, dy = 0;
716:
717:                switch (nextSegType) {
718:                case PathIterator.SEG_CLOSE:
719:                    // Should not happen at this point, because all close
720:                    // segments have been replaced by lineTo segments.
721:                    break;
722:                case PathIterator.SEG_CUBICTO:
723:                case PathIterator.SEG_LINETO:
724:                case PathIterator.SEG_QUADTO:
725:                    // If the next segment is a line, quad or cubic curve.
726:                    // the slope is about equal to that of the line from
727:                    // curEndPoint and the first control point
728:                    dx = next[0] - currEndPoint.getX();
729:                    dy = next[1] - currEndPoint.getY();
730:                    break;
731:                case ExtendedPathIterator.SEG_ARCTO: {
732:                    // If the current segment is an ARCTO then we build the
733:                    // arc and ask for it's end angle and get the tangent there.
734:                    boolean large = (next[3] != 0.);
735:                    boolean goLeft = (next[4] != 0.);
736:                    Arc2D arc = ExtendedGeneralPath.computeArc(currEndPoint
737:                            .getX(), currEndPoint.getY(), next[0], next[1],
738:                            next[2], large, goLeft, next[5], next[6]);
739:                    double theta = arc.getAngleStart();
740:                    theta = Math.toRadians(theta);
741:                    dx = -arc.getWidth() / 2.0 * Math.sin(theta);
742:                    dy = arc.getHeight() / 2.0 * Math.cos(theta);
743:                    // System.out.println("Out Theta:  " + Math.toDegrees(theta) +
744:                    //                    " Dx/Dy: " + dx + "/" + dy);
745:                    if (next[2] != 0) {
746:                        double ang = Math.toRadians(-next[2]);
747:                        double sinA = Math.sin(ang);
748:                        double cosA = Math.cos(ang);
749:                        double tdx = dx * cosA - dy * sinA;
750:                        double tdy = dx * sinA + dy * cosA;
751:                        dx = tdx;
752:                        dy = tdy;
753:                    }
754:                    // System.out.println("    Rotate: " + next[2] +
755:                    //                    " Dx/Dy: " + dx + "/" + dy);
756:
757:                    if (goLeft) {
758:                        dx = -dx;
759:                    } else {
760:                        dy = -dy;
761:                    }
762:                    // System.out.println("    GoLeft? " + goLeft +
763:                    //                    " Dx/Dy: " + dx + "/" + dy);
764:                }
765:                    break;
766:                case PathIterator.SEG_MOVETO:
767:                    // Cannot compute the out slope
768:                default:
769:                    return null;
770:                }
771:
772:                if (dx == 0 && dy == 0) {
773:                    return null;
774:                }
775:
776:                return normalize(new double[] { dx, dy });
777:            }
778:
779:            /**
780:             * Normalizes the input vector. This assumes an non-zero length
781:             */
782:            public double[] normalize(double[] v) {
783:                double n = Math.sqrt(v[0] * v[0] + v[1] * v[1]);
784:                v[0] /= n;
785:                v[1] /= n;
786:                return v;
787:            }
788:
789:            /**
790:             * Computes the transform for the input marker, so that it is positioned at
791:             * the given position with the specified rotation
792:             */
793:            private AffineTransform computeMarkerTransform(Marker marker,
794:                    Point2D markerPosition, double rotation) {
795:                Point2D ref = marker.getRef();
796:                /*AffineTransform txf =
797:                    AffineTransform.getTranslateInstance(markerPosition.getX()
798:                                                         - ref.getX(),
799:                                                         markerPosition.getY()
800:                                                         - ref.getY());*/
801:                AffineTransform txf = new AffineTransform();
802:
803:                txf.translate(markerPosition.getX() - ref.getX(),
804:                        markerPosition.getY() - ref.getY());
805:
806:                if (!Double.isNaN(rotation)) {
807:                    txf
808:                            .rotate(Math.toRadians(rotation), ref.getX(), ref
809:                                    .getY());
810:                }
811:
812:                return txf;
813:            }
814:
815:            /**
816:             * Extracts the terminating point, depending on the segment type.
817:             */
818:            protected Point2D getSegmentTerminatingPoint(double[] coords,
819:                    int segType) {
820:                switch (segType) {
821:                case PathIterator.SEG_CUBICTO:
822:                    return new Point2D.Double(coords[4], coords[5]);
823:                case PathIterator.SEG_LINETO:
824:                    return new Point2D.Double(coords[0], coords[1]);
825:                case PathIterator.SEG_MOVETO:
826:                    return new Point2D.Double(coords[0], coords[1]);
827:                case PathIterator.SEG_QUADTO:
828:                    return new Point2D.Double(coords[2], coords[3]);
829:                case ExtendedPathIterator.SEG_ARCTO:
830:                    return new Point2D.Double(coords[5], coords[6]);
831:                case PathIterator.SEG_CLOSE:
832:                default:
833:                    throw new Error("invalid segmentType:" + segType);
834:                    // Should never happen: close segments are replaced with lineTo
835:                }
836:            }
837:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.