Passed
Push — master ( 82dbb2...0f24f3 )
by Seth
08:38
created

getAsPath()   B

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 rotation 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 can be transformed.</p>
101
     *
102
     * <p>Note that the path returned by this method is a new object, separate from the original {@code Drawable2D} shape.</p>
103
     *
104
     * @return Path equivalent to the 2D shape
105
     */
106
    public Path getAsPath() {
107
        Path p = new Path(getDrawingPanel());
108
        p.setFillColor(getFillColor());
109
        p.setStroke(getStroke());
110
        p.setStrokeColor(getStrokeColor());
111
        PathIterator i = getPathIterator(null);
112
        double[] coords = new double[6];
113
        while (!i.isDone()) {
114
            switch (i.currentSegment(coords)) {
115
                case PathIterator.SEG_CLOSE:
116
                    p.closePath();
117
                    break;
118
                case PathIterator.SEG_CUBICTO:
119
                    p.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
120
                    break;
121
                case PathIterator.SEG_LINETO:
122
                    p.lineTo(coords[0], coords[1]);
123
                    break;
124
                case PathIterator.SEG_MOVETO:
125
                    p.moveTo(coords[0], coords[1]);
126
                    break;
127
                case PathIterator.SEG_QUADTO:
128
                    p.quadTo(coords[0], coords[1], coords[2], coords[3]);
129
                    break;
130
                default:
131
                    System.err.println("!");
132
            }
133
            i.next();
134
        }
135
        return p;
136
    }
137
}
138