1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.vectomatic.client.rep.view;
19
20 import static org.vectomatic.common.model.geometry.Ellipse.K;
21
22 import java.util.List;
23
24 import org.vectomatic.common.model.Attribute;
25 import org.vectomatic.common.model.FloatAttributeValue;
26 import org.vectomatic.common.model.IShapeVisitor;
27 import org.vectomatic.common.model.Shape;
28 import org.vectomatic.common.model.geometry.BezierSegment;
29 import org.vectomatic.common.model.geometry.BoundingBox;
30 import org.vectomatic.common.model.geometry.Ellipse;
31 import org.vectomatic.common.model.geometry.LineSegment;
32 import org.vectomatic.common.model.geometry.Path;
33 import org.vectomatic.common.model.geometry.Point;
34 import org.vectomatic.common.model.geometry.Polyline;
35 import org.vectomatic.common.model.geometry.Rect;
36 import org.vectomatic.common.model.geometry.Segment;
37 import org.vectomatic.common.model.geometry.ShapeGroup;
38 import org.vectomatic.common.model.geometry.TransformMatrix;
39 import org.vectomatic.common.model.style.IStyle;
40
41
42
43
44
45 public class RenderVisitor implements IShapeVisitor {
46 private class Context {
47 TransformMatrix m;
48 Shape shape;
49 public Context() {
50 m = new TransformMatrix();
51 }
52 }
53
54 private DrawingView _view;
55 private Point _p0, _p1, _p2, _p3;
56 private Context[] _stack;
57 private int _index;
58
59 public RenderVisitor(DrawingView view) {
60 _view = view;
61 _stack = new Context[8];
62 _p0 = new Point();
63 _p1 = new Point();
64 _p2 = new Point();
65 _p3 = new Point();
66 }
67
68 public TransformMatrix pushShape(Shape shape) {
69
70 if (_index >= _stack.length) {
71 Context[] stack = new Context[2 * _stack.length];
72 for (int i = 0; i < _stack.length; i++) {
73 stack[i] = _stack[i];
74 }
75 _stack = stack;
76 }
77
78
79 if (_stack[_index] == null) {
80 _stack[_index] = new Context();
81 }
82
83 TransformMatrix m;
84 if (_index == 0) {
85 m = _stack[_index].m = shape.getTransform();
86 } else {
87 m = shape.getTransform().preMultiply(_stack[_index - 1].m, _stack[_index].m);
88 }
89 _stack[_index].shape = shape;
90 _index++;
91 return m;
92 }
93
94 public void popShape() {
95 _index--;
96 }
97
98 public void visitEllipse(Ellipse ellipse) {
99 BoundingBox bbox = ellipse.getBoundingBox();
100 TransformMatrix m = pushShape(ellipse);
101 _view.beginPath();
102 _p0.x = -1f;
103 _p0.y = 0f;
104 _p0.transform(m, _p1);
105 _view.moveTo(_p1.x, _p1.y);
106
107 _p0.x = -1f;
108 _p0.y = -K;
109 _p0.transform(m, _p1);
110 _p0.x = -K;
111 _p0.y = -1f;
112 _p0.transform(m, _p2);
113 _p0.x = 0f;
114 _p0.y = -1f;
115 _p0.transform(m, _p3);
116 _view.bezierCurveTo(_p1.x, _p1.y, _p2.x, _p2.y, _p3.x, _p3.y);
117
118 _p0.x = K;
119 _p0.y = -1f;
120 _p0.transform(m, _p1);
121 _p0.x = 1f;
122 _p0.y = -K;
123 _p0.transform(m, _p2);
124 _p0.x = 1f;
125 _p0.y = 0f;
126 _p0.transform(m, _p3);
127 _view.bezierCurveTo(_p1.x, _p1.y, _p2.x, _p2.y, _p3.x, _p3.y);
128
129 _p0.x = 1f;
130 _p0.y = K;
131 _p0.transform(m, _p1);
132 _p0.x = K;
133 _p0.y = 1f;
134 _p0.transform(m, _p2);
135 _p0.x = 0f;
136 _p0.y = 1f;
137 _p0.transform(m, _p3);
138 _view.bezierCurveTo(_p1.x, _p1.y, _p2.x, _p2.y, _p3.x, _p3.y);
139
140 _p0.x = -K;
141 _p0.y = bbox.ymax;
142 _p0.transform(m, _p1);
143 _p0.x = -1f;
144 _p0.y = K;
145 _p0.transform(m, _p2);
146 _p0.x = -1f;
147 _p0.y = 0f;
148 _p0.transform(m, _p3);
149 _view.bezierCurveTo(_p1.x, _p1.y, _p2.x, _p2.y, _p3.x, _p3.y);
150
151 _view.closePath();
152 if (applyFillStyle()) {
153 _view.fill();
154 }
155 if (applyStrokeStyle()) {
156 _view.stroke();
157 }
158 popShape();
159 }
160
161 public void visitPolyline(Polyline polyline) {
162 TransformMatrix m = pushShape(polyline);
163 Point[] pts = polyline.getVertices();
164
165 _view.beginPath();
166 pts[0].transform(m, _p0);
167 _view.moveTo(_p0.x, _p0.y);
168 for (int i = 1; i < pts.length; i++) {
169 pts[i].transform(m, _p0);
170 _view.lineTo(_p0.x, _p0.y);
171 }
172 if (polyline.isClosed()) {
173 _view.closePath();
174 if (applyFillStyle()) {
175 _view.fill();
176 }
177 }
178 if (applyStrokeStyle()) {
179 _view.stroke();
180 }
181
182 popShape();
183 }
184
185 public void visitRect(Rect rect) {
186 TransformMatrix m = pushShape(rect);
187
188 _view.beginPath();
189 _p0.x = -1f;
190 _p0.y = -1f;
191 _p0.transform(m, _p1);
192 _view.moveTo(_p1.x, _p1.y);
193
194 _p0.x = 1f;
195 _p0.y = -1f;
196 _p0.transform(m, _p2);
197 _view.lineTo(_p2.x, _p2.y);
198
199 _p0.x = 1f;
200 _p0.y = 1f;
201 _p0.transform(m, _p2);
202 _view.lineTo(_p2.x, _p2.y);
203
204 _p0.x = -1f;
205 _p0.y = 1f;
206 _p0.transform(m, _p2);
207 _view.lineTo(_p2.x, _p2.y);
208
209 _view.lineTo(_p1.x, _p1.y);
210
211 _view.closePath();
212
213 if (applyFillStyle()) {
214 _view.fill();
215 }
216 if (applyStrokeStyle()) {
217 _view.stroke();
218 }
219 popShape();
220 }
221
222 public void visitShapeGroup(ShapeGroup group) {
223 pushShape(group);
224 List<Shape> shapes = group.getShapes();
225 for (int i = 0, size = shapes.size(); i < size; i++) {
226 Shape shape = shapes.get(i);
227 shape.acceptVisitor(this);
228 }
229 popShape();
230 }
231
232 public void visitPath(Path path) {
233 TransformMatrix m = pushShape(path);
234 _view.beginPath();
235 List<Segment> segments = path.getSegments();
236 for (int i = 0, size = segments.size(); i < size; i++) {
237 Segment segment = segments.get(i);
238 if (i == 0) {
239 _view.beginPath();
240 segment.getStartPoint().transform(m, _p0);
241 _view.moveTo(_p0.x, _p0.y);
242 }
243 if (segment instanceof LineSegment) {
244 segment.getEndPoint().transform(m, _p0);
245 _view.lineTo(_p0.x, _p0.y);
246 } else {
247 BezierSegment bezierSegment = (BezierSegment)segment;
248 bezierSegment.getStartControlPoint().transform(m, _p0);
249 bezierSegment.getEndControlPoint().transform(m, _p1);
250 bezierSegment.getEndPoint().transform(m, _p2);
251 _view.bezierCurveTo(_p0.x, _p0.y, _p1.x, _p1.y, _p2.x, _p2.y);
252 }
253 }
254 if (path.isClosed()) {
255 _view.closePath();
256 if (applyFillStyle()) {
257 _view.fill();
258 }
259 }
260 if (applyStrokeStyle()) {
261 _view.stroke();
262 }
263
264 popShape();
265 }
266
267 private boolean applyStrokeStyle() {
268 boolean doStroke = false;
269 IStyle strokeStyle = (IStyle)getAttribute(Attribute.LINE_STYLE);
270 if (strokeStyle != null && strokeStyle.getKind() != IStyle.NONE) {
271 float opacity = ((FloatAttributeValue)getAttribute(Attribute.LINE_OPACITY)).getValue();
272 if (opacity > 0.0f) {
273 doStroke = true;
274 strokeStyle.acceptVisitor(_view.getStrokeStyleVisitor());
275 float viewOpacity = _view.getGlobalAlpha();
276 if (viewOpacity != opacity) {
277 _view.setGlobalAlpha(opacity);
278 }
279 float lineWidth = ((FloatAttributeValue)getAttribute(Attribute.LINE_WIDTH)).getValue();
280 if (_view.getLineWidth() != lineWidth) {
281 _view.setLineWidth(lineWidth);
282 }
283 }
284 }
285 return doStroke;
286 }
287
288 private boolean applyFillStyle() {
289 boolean doFill = false;
290 IStyle fillStyle = (IStyle)getAttribute(Attribute.FILL_STYLE);
291 if (fillStyle != null && fillStyle.getKind() != IStyle.NONE) {
292 float opacity = ((FloatAttributeValue)getAttribute(Attribute.FILL_OPACITY)).getValue();
293 if (opacity > 0.0f) {
294 doFill = true;
295 fillStyle.acceptVisitor(_view.getFillStyleVisitor());
296 float viewOpacity = _view.getGlobalAlpha();
297 if (viewOpacity != opacity) {
298 _view.setGlobalAlpha(opacity);
299 }
300 }
301 }
302 return doFill;
303 }
304
305 private Object getAttribute(Attribute attr) {
306 Object attrValue = null;
307 for (int i = 0; i < _index; i++) {
308 if (_stack[i].shape.definesAttribute(attr)) {
309 attrValue = _stack[i].shape.getAttribute(attr);
310 break;
311 }
312 }
313 return attrValue;
314 }
315
316 }