001: /*
002: Copyright 2006 Jerry Huxtable
003:
004: Licensed under the Apache License, Version 2.0 (the "License");
005: you may not use this file except in compliance with the License.
006: You may obtain a copy of the License at
007:
008: http://www.apache.org/licenses/LICENSE-2.0
009:
010: Unless required by applicable law or agreed to in writing, software
011: distributed under the License is distributed on an "AS IS" BASIS,
012: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: See the License for the specific language governing permissions and
014: limitations under the License.
015: */
016: package it.businesslogic.ireport.util;
017:
018: import java.awt.*;
019: import java.awt.geom.*;
020:
021: public class ShapeStroke implements Stroke {
022: private Shape shapes[];
023: private float advance;
024: private boolean stretchToFit = false;
025: private boolean repeat = true;
026: private AffineTransform t = new AffineTransform();
027: private static final float FLATNESS = 1;
028:
029: public ShapeStroke(Shape shapes, float advance) {
030: this (new Shape[] { shapes }, advance);
031: }
032:
033: public ShapeStroke(Shape shapes[], float advance) {
034: this .advance = advance;
035: this .shapes = new Shape[shapes.length];
036:
037: for (int i = 0; i < this .shapes.length; i++) {
038: Rectangle2D bounds = shapes[i].getBounds2D();
039: t.setToTranslation(-bounds.getCenterX(), -bounds
040: .getCenterY());
041: this .shapes[i] = t.createTransformedShape(shapes[i]);
042: }
043: }
044:
045: public Shape createStrokedShape(Shape shape) {
046: GeneralPath result = new GeneralPath();
047: PathIterator it = new FlatteningPathIterator(shape
048: .getPathIterator(null), FLATNESS);
049: float points[] = new float[6];
050: float moveX = 0, moveY = 0;
051: float lastX = 0, lastY = 0;
052: float this X = 0, this Y = 0;
053: int type = 0;
054: boolean first = false;
055: float next = 0;
056: int currentShape = 0;
057: int length = shapes.length;
058:
059: float factor = 1;
060:
061: while (currentShape < length && !it.isDone()) {
062: type = it.currentSegment(points);
063: switch (type) {
064: case PathIterator.SEG_MOVETO:
065: moveX = lastX = points[0];
066: moveY = lastY = points[1];
067: result.moveTo(moveX, moveY);
068: first = true;
069: next = 0;
070: break;
071:
072: case PathIterator.SEG_CLOSE:
073: points[0] = moveX;
074: points[1] = moveY;
075: // Fall into....
076:
077: case PathIterator.SEG_LINETO:
078: this X = points[0];
079: this Y = points[1];
080: float dx = this X - lastX;
081: float dy = this Y - lastY;
082: float distance = (float) Math.sqrt(dx * dx + dy * dy);
083: if (distance >= next) {
084: float r = 1.0f / distance;
085: float angle = (float) Math.atan2(dy, dx);
086: while (currentShape < length && distance >= next) {
087: float x = lastX + next * dx * r;
088: float y = lastY + next * dy * r;
089: t.setToTranslation(x, y);
090: t.rotate(angle);
091: result
092: .append(
093: t
094: .createTransformedShape(shapes[currentShape]),
095: false);
096: next += advance;
097: currentShape++;
098: if (repeat)
099: currentShape %= length;
100: }
101: }
102: next -= distance;
103: first = false;
104: lastX = thisX;
105: lastY = thisY;
106: break;
107: }
108: it.next();
109: }
110:
111: return result;
112: }
113:
114: }
|