getAsPath()   B
last analyzed

Complexity

Conditions 8

Size

Total Lines 30
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 28
c 0
b 0
f 0
dl 0
loc 30
rs 7.3333
1
package org.gannacademy.cdf.graphics;
2
3
import org.gannacademy.cdf.graphics.geom.Path;
4
5
import java.awt.*;
6
import java.awt.geom.PathIterator;
7
import java.awt.geom.RectangularShape;
8
9
/**
10
 * <p>Superclass of two-dimensional ("rectangular") drawable components</p>
11
 *
12
 * <p>What makes a component "rectangular"? It's defined by an origin, width and height &mdash; like a
13
 * {@link org.gannacademy.cdf.graphics.geom.Rectangle} or an {@link org.gannacademy.cdf.graphics.geom.Ellipse}.</p>
14
 *
15
 * @author <a href="http://github.com/gann-cdf/graphics/issues">Seth Battis</a>
16
 */
17
abstract public class Drawable2D extends Drawable {
18
    private RectangularShape shape;
19
20
    @Override
21
    public Shape getShape() {
22
        return shape;
23
    }
24
25
    /**
26
     * <p>Replace the underlying {@link Shape} geometry of the component</p>
27
     *
28
     * <p>Replacing the {@link Shape} geometry leaves other characteristics (fill, stroke) untouched.</p>
29
     *
30
     * @param shape of geometry
31
     * @throws DrawableException if {@code shape} is incompatible with the class
32
     */
33
    @Override
34
    public void setShape(Shape shape) throws DrawableException {
35
        if (shape instanceof RectangularShape) {
36
            this.shape = (RectangularShape) shape;
37
        } else {
38
            throw new DrawableException("Cannot convert a Shape to a RectangularShape");
39
        }
40
    }
41
42
    /**
43
     * Underlying {@link RectangularShape} geometry
44
     *
45
     * @return Underlying {@link RectangularShape} geometry
46
     */
47
    protected RectangularShape getShapeAsRectangularShape() {
48
        return shape;
49
    }
50
51
    @Override
52
    public void setWidth(double width) {
53
        getShapeAsRectangularShape().setFrame(getX(), getY(), width, getHeight());
54
    }
55
56
    @Override
57
    public void setHeight(double height) {
58
        getShapeAsRectangularShape().setFrame(getX(), getY(), getWidth(), height);
59
    }
60
61
    @Override
62
    public void translate(double dx, double dy) {
63
        getShapeAsRectangularShape().setFrame(getX() + dx, getY() + dy, getWidth(), getHeight());
64
    }
65
66
    @Override
67
    public void setLocation(double x, double y) {
68
        translate(x - getX(), y - getY());
69
    }
70
71
    /**
72
     * Test if shape geometry is defined
73
     *
74
     * @return {@code true} if the shape does not contain geometry, {@code false} otherwise
75
     */
76
    public boolean isEmpty() {
77
        return shape.isEmpty();
78
    }
79
80
    /**
81
     * <p>Adjust the frame of the shape's enclosing bounding box</p>
82
     *
83
     * <p>Adjusting the frame of the shape resizes the geometry to fit within the new bounds</p>
84
     *
85
     * @param x      coordinate of the origin of the new frame
86
     * @param y      coordinate of the origin of the new frame
87
     * @param width  of the new frame
88
     * @param height of the new frame
89
     */
90
    public void setFrame(double x, double y, double width, double height) {
91
        shape.setFrame(x, y, width, height);
92
    }
93
94
    /**
95
     * <p>Convert a {@code Drawable2D} shape into its equivalent {@code Path}</p>
96
     *
97
     * <p>{@code Drawable2D} shapes are aligned to the rectangular grid of the cartesian coordinate system: a rectangle
98
     * always has sides aligned with the X- and Y-axes of the coordinate system. This means that transformations other
99
     * than translation and scale cannot be performed on {@code Drawable2D} shapes, as that would shift them out of
100
     * alignment with the axes. However, this method converts the shape into a Path, which <i>can</i> be
101
     * transformed.</p>
102
     *
103
     * <p>Note that the path returned by this method is a new object, separate from the original {@code Drawable2D}
104
     * shape.</p>
105
     *
106
     * @return Path equivalent to the 2D shape
107
     */
108
    public Path getAsPath() {
109
        Path p = new Path(getDrawingPanel());
110
        p.setFillColor(getFillColor());
111
        p.setStroke(getStroke());
112
        p.setStrokeColor(getStrokeColor());
113
        PathIterator i = getPathIterator(null);
114
        double[] coords = new double[6];
115
        while (!i.isDone()) {
116
            switch (i.currentSegment(coords)) {
117
                case PathIterator.SEG_CLOSE:
118
                    p.closePath();
119
                    break;
120
                case PathIterator.SEG_CUBICTO:
121
                    p.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
122
                    break;
123
                case PathIterator.SEG_LINETO:
124
                    p.lineTo(coords[0], coords[1]);
125
                    break;
126
                case PathIterator.SEG_MOVETO:
127
                    p.moveTo(coords[0], coords[1]);
128
                    break;
129
                case PathIterator.SEG_QUADTO:
130
                    p.quadTo(coords[0], coords[1], coords[2], coords[3]);
131
                    break;
132
                default:
133
                    System.err.println("!");
134
            }
135
            i.next();
136
        }
137
        return p;
138
    }
139
}
140