1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.vectomatic.client.rep.controller;
19
20 import java.util.ArrayList;
21 import java.util.List;
22
23 import org.vectomatic.client.rep.RepApplication;
24 import org.vectomatic.client.rep.command.NewShapeCommand;
25 import org.vectomatic.client.rep.view.Cursor;
26 import org.vectomatic.client.rep.view.DrawingView;
27 import org.vectomatic.common.model.Attribute;
28 import org.vectomatic.common.model.geometry.BezierSegment;
29 import org.vectomatic.common.model.geometry.LineSegment;
30 import org.vectomatic.common.model.geometry.Path;
31 import org.vectomatic.common.model.geometry.Point;
32 import org.vectomatic.common.model.geometry.Segment;
33 import org.vectomatic.common.model.style.Color;
34
35
36
37
38
39 public class NewPathController extends ControllerBase {
40 private static final int VERTEX_SIZE = 3;
41 private static final int CONTROL_POINT_SIZE = 3;
42 private static final float T = 0.5f;
43 private enum State {
44 S0 {
45 @Override
46 State processActivate(NewPathController controller, DrawingView view) {
47 view.setCursor(Cursor.CURSOR_CROSSHAIR);
48 controller._segments.clear();
49 return S1;
50 }
51 },
52 S1 {
53 @Override
54 State processMouseDown(NewPathController controller, DrawingView view, Point p, int modifiers) {
55 view.toModelCoordinates(p, controller._p0);
56 controller._p0.copyTo(controller._p1);
57 return S2;
58 }
59 },
60 S2 {
61 @Override
62 State processMouseMove(NewPathController controller, DrawingView view, Point p, int modifiers) {
63 view.toModelCoordinates(p, controller._p1);
64 return this;
65 }
66 @Override
67 State processMouseUp(NewPathController controller, DrawingView view, Point p, int modifiers) {
68 view.toModelCoordinates(p, controller._p1);
69 if (controller._p1.distance(controller._p0) > T) {
70 controller._p1.copyTo(controller._p2);
71 controller._p1.copyTo(controller._p3);
72
73 return S3;
74 }
75
76 return S4;
77 }
78 },
79 S3 {
80 @Override
81 State processMouseMove(NewPathController controller, DrawingView view, Point p, int modifiers) {
82 view.toModelCoordinates(p, controller._p2);
83 controller._p2.copyTo(controller._p3);
84 if (controller._segments.size() > 0) {
85 float tol = view.convertToReferenceLength(VERTEX_SIZE * 2);
86 if (controller._p2.distance(controller._p0) < tol) {
87 view.setCursor(Cursor.CURSOR_OPEN_POLYLINE);
88 } else if (controller._p2.distance(controller._segments.get(0).getStartPoint()) < tol) {
89 view.setCursor(Cursor.CURSOR_CLOSED_POLYLINE);
90 } else {
91 view.setCursor(Cursor.CURSOR_CROSSHAIR);
92 }
93 }
94 return S3;
95 }
96 @Override
97 State processMouseDown(NewPathController controller, DrawingView view, Point p, int modifiers) {
98 return S7;
99 }
100 },
101 S4 {
102 @Override
103 State processMouseMove(NewPathController controller, DrawingView view, Point p, int modifiers) {
104 view.toModelCoordinates(p, controller._p1);
105 if (controller._segments.size() > 0) {
106 float tol = view.convertToReferenceLength(VERTEX_SIZE * 2);
107 if (controller._p1.distance(controller._p0) < tol) {
108 view.setCursor(Cursor.CURSOR_OPEN_POLYLINE);
109 } else if (controller._p1.distance(controller._segments.get(0).getStartPoint()) < tol) {
110 view.setCursor(Cursor.CURSOR_CLOSED_POLYLINE);
111 } else {
112 view.setCursor(Cursor.CURSOR_CROSSHAIR);
113 }
114 }
115 return this;
116 }
117 @Override
118 State processMouseDown(NewPathController controller, DrawingView view, Point p, int modifiers) {
119 view.toModelCoordinates(p, controller._p2);
120 controller._p2.copyTo(controller._p3);
121 return S5;
122 }
123 },
124 S5 {
125 @Override
126 State processMouseMove(NewPathController controller, DrawingView view, Point p, int modifiers) {
127 view.toModelCoordinates(p, controller._p2);
128 if (controller._p2.distance(controller._p3) > T) {
129 return S6;
130 }
131 return S5;
132 }
133 @Override
134 State processMouseUp(NewPathController controller, DrawingView view, Point p, int modifiers) {
135 float tol = view.convertToReferenceLength(VERTEX_SIZE * 2);
136 boolean pathHasSegments = controller._segments.size() > 0;
137 boolean done = false;
138 if (pathHasSegments && controller._p1.distance(controller._p0) < tol) {
139
140 done = true;
141 } else {
142 if (controller._p1.distance(controller._p0) > tol) {
143 if (pathHasSegments && controller._p1.distance(controller._segments.get(0).getStartPoint()) < tol) {
144
145 controller._segments.add(new LineSegment(new Point[]{controller._p0, controller._segments.get(0).getStartPoint()}));
146 done = true;
147 } else {
148
149 controller._segments.add(new LineSegment(new Point[]{controller._p0, controller._p1}));
150 }
151 }
152 }
153 if (done) {
154 return S8.processDeactivate(controller, view);
155 }
156 controller._p1.copyTo(controller._p0);
157 controller._p2.copyTo(controller._p1);
158 return S4;
159 }
160 },
161 S6 {
162 @Override
163 State processMouseMove(NewPathController controller, DrawingView view, Point p, int modifiers) {
164 view.toModelCoordinates(p).symetricPoint(controller._p3, controller._p2);
165 if (p.distance(controller._p3) > T) {
166 return S6;
167 }
168 return S5;
169 }
170 @Override
171 State processMouseUp(NewPathController controller, DrawingView view, Point p, int modifiers) {
172 return S7.processMouseUp(controller, view, p, modifiers);
173 }
174 },
175 S7 {
176 @Override
177 State processMouseMove(NewPathController controller, DrawingView view, Point p, int modifiers) {
178 view.toModelCoordinates(p).symetricPoint(controller._p3, controller._p2);
179 return S7;
180 }
181 @Override
182 State processMouseUp(NewPathController controller, DrawingView view, Point p, int modifiers) {
183 float tol = view.convertToReferenceLength(VERTEX_SIZE * 2);
184 boolean pathHasSegments = controller._segments.size() > 0;
185 boolean done = false;
186 if (pathHasSegments && controller._p2.distance(controller._p0) < tol) {
187
188 done = true;
189 } else {
190 if (controller._p2.distance(controller._p0) > tol) {
191 if (pathHasSegments && (controller._p2.distance(controller._segments.get(0).getStartPoint()) < tol || controller._p3.distance(controller._segments.get(0).getStartPoint()) < tol)) {
192
193 controller._segments.add(new BezierSegment(new Point[]{controller._p0, controller._p1, controller._p2, controller._segments.get(0).getStartPoint()}));
194 done = true;
195 } else {
196
197 controller._segments.add(new BezierSegment(new Point[]{controller._p0, controller._p1, controller._p2, controller._p3}));
198 }
199 }
200 }
201 if (done) {
202 return S8.processDeactivate(controller, view);
203 }
204 controller._p3.copyTo(controller._p0);
205 controller._p2.symetricPoint(controller._p3, controller._p1);
206 return controller._p2.equals(controller._p3) ? S4 : S3;
207 }
208 },
209 S8 {
210 State processDeactivate(NewPathController controller, DrawingView view) {
211 if (controller._segments.size() > 0) {
212 Path path = new Path(controller._segments);
213 path.setAttribute(Attribute.LINE_STYLE, controller._app.getLineStyleController().getStyle());
214 path.setAttribute(Attribute.LINE_OPACITY, controller._app.getLineStyleController().getOpacity());
215 path.setAttribute(Attribute.FILL_STYLE, controller._app.getFillStyleController().getStyle());
216 path.setAttribute(Attribute.FILL_OPACITY, controller._app.getFillStyleController().getOpacity());
217 path.setAttribute(Attribute.LINE_WIDTH, controller._app.getLineWidthController().getLineWidth());
218 NewShapeCommand command = new NewShapeCommand(controller._app, path);
219 command.execute();
220 controller._app.getHistory().addCommand(command);
221 }
222 return S0.processActivate(controller, view);
223 }
224 };
225 State processActivate(NewPathController controller, DrawingView view) {
226 throw new IllegalStateException("activate");
227 }
228 State processMouseDown(NewPathController controller, DrawingView view, Point p, int modifiers) {
229 return this;
230 }
231 State processMouseUp(NewPathController controller, DrawingView view, Point p, int modifiers) {
232 return this;
233 }
234 State processMouseMove(NewPathController controller, DrawingView view, Point p, int modifiers) {
235 return this;
236 }
237 State processKeyDown(NewPathController controller, int key, int modifiers) {
238 return this;
239 }
240 State processDeactivate(NewPathController controller, DrawingView view) {
241 throw new IllegalStateException("deactivate");
242 }
243 };
244 private Point _p0, _p1, _p2, _p3, _pTmp;
245 private State _state;
246 private List<Segment> _segments;
247 private MouseControllerButton _button;
248
249 public NewPathController(RepApplication app) {
250 super(app);
251 _p0 = new Point();
252 _p1 = new Point();
253 _p2 = new Point();
254 _p3 = new Point();
255 _pTmp = new Point();
256 _segments = new ArrayList<Segment>();
257 _button = new MouseControllerButton(_app.getIcons().pathIcon().createImage(), _app.getConstants().newPathCommand(), this);
258 }
259
260 @Override
261 public void mouseDown(DrawingView view, Point p, int modifiers) {
262 _state = _state.processMouseDown(this, view, p, modifiers);
263 }
264 @Override
265 public void mouseUp(DrawingView view, Point p, int modifiers) {
266 _state = _state.processMouseUp(this, view, p, modifiers);
267 }
268 @Override
269 public void mouseMove(DrawingView view, Point p, int modifiers) {
270 _state = _state.processMouseMove(this, view, p, modifiers);
271 }
272 @Override
273 public void keyDown(DrawingView view, char keyCode, int modifiers) {
274 _state = _state.processKeyDown(this, keyCode, modifiers);
275 }
276 @Override
277 public void activate(DrawingView view) {
278 _state = State.S0;
279 _state = _state.processActivate(this, view);
280 }
281 @Override
282 public String toString() {
283 return _state.toString();
284 }
285
286 @Override
287 public void render(DrawingView view) {
288
289 _app.getLineStyleController().getStyle().acceptVisitor(view.getStrokeStyleVisitor());
290 for (int i = 0, size = _segments.size(); i < size; i++) {
291 Segment segment = _segments.get(i);
292 if (i == 0) {
293 view.beginPath();
294 view.moveTo(segment.getStartPoint().x, segment.getStartPoint().y);
295 }
296 if (segment instanceof LineSegment) {
297 view.lineTo(segment.getEndPoint().x, segment.getEndPoint().y);
298 } else {
299 BezierSegment bezierSegment = (BezierSegment)segment;
300 view.bezierCurveTo(
301 bezierSegment.getStartControlPoint().x, bezierSegment.getStartControlPoint().y,
302 bezierSegment.getEndControlPoint().x, bezierSegment.getEndControlPoint().y,
303 bezierSegment.getEndPoint().x, bezierSegment.getEndPoint().y);
304 }
305 }
306 view.stroke();
307 Color.BLACK.acceptVisitor(view.getStrokeStyleVisitor());
308 Color.BLACK.acceptVisitor(view.getFillStyleVisitor());
309 view.setLineWidth(1f);
310 switch(_state) {
311 case S2:
312 case S4:
313 case S5:
314 view.moveTo(_p0.x, _p0.y);
315 view.lineTo(_p1.x, _p1.y);
316 view.stroke();
317 Color.WHITE.acceptVisitor(view.getFillStyleVisitor());
318 view.fillRect(_p0.x - VERTEX_SIZE, _p0.y - VERTEX_SIZE, VERTEX_SIZE * 2, VERTEX_SIZE * 2);
319 Color.BLACK.acceptVisitor(view.getStrokeStyleVisitor());
320 view.strokeRect(_p0.x - VERTEX_SIZE, _p0.y - VERTEX_SIZE, VERTEX_SIZE * 2, VERTEX_SIZE * 2);
321 view.beginPath();
322 view.moveTo(_p1.x - VERTEX_SIZE, _p1.y);
323 view.lineTo(_p1.x + VERTEX_SIZE, _p1.y);
324 view.moveTo(_p1.x, _p1.y - VERTEX_SIZE);
325 view.lineTo(_p1.x, _p1.y + VERTEX_SIZE);
326 view.stroke();
327 break;
328 case S3:
329 view.moveTo(_p0.x, _p0.y);
330 view.lineTo(_p1.x, _p1.y);
331 view.moveTo(_p0.x, _p0.y);
332 view.bezierCurveTo(_p1.x, _p1.y, _p2.x, _p2.y, _p3.x, _p3.y);
333 view.stroke();
334 view.beginPath();
335 view.arc(_p1.x, _p1.y, CONTROL_POINT_SIZE, 0, (float)(2 * Math.PI), true);
336 view.fill();
337 Color.WHITE.acceptVisitor(view.getFillStyleVisitor());
338 view.fillRect(_p0.x - VERTEX_SIZE, _p0.y - VERTEX_SIZE, VERTEX_SIZE * 2, VERTEX_SIZE * 2);
339 Color.BLACK.acceptVisitor(view.getStrokeStyleVisitor());
340 view.strokeRect(_p0.x - VERTEX_SIZE, _p0.y - VERTEX_SIZE, VERTEX_SIZE * 2, VERTEX_SIZE * 2);
341 break;
342 case S6:
343 case S7:
344 view.moveTo(_p0.x, _p0.y);
345 view.bezierCurveTo(_p1.x, _p1.y, _p2.x, _p2.y, _p3.x, _p3.y);
346 view.moveTo(_p2.x, _p2.y);
347 _p2.symetricPoint(_p3, _pTmp);
348 view.lineTo(_pTmp.x, _pTmp.y);
349 view.stroke();
350 view.beginPath();
351 view.arc(_p2.x, _p2.y, CONTROL_POINT_SIZE, 0, (float)(2 * Math.PI), true);
352 view.arc(_pTmp.x, _pTmp.y, CONTROL_POINT_SIZE, 0, (float)(2 * Math.PI), true);
353 view.fill();
354 break;
355 }
356 }
357
358 @Override
359 public void deactivate(DrawingView view) {
360 _state = State.S8.processDeactivate(this, view);
361 }
362
363 public MouseControllerButton getButton() {
364 return _button;
365 }
366 }