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 org.vectomatic.client.rep.view.DrawingView;
21 import org.vectomatic.common.model.geometry.Point;
22 import org.vectomatic.common.model.geometry.TransformMatrix;
23 import org.vectomatic.common.model.style.Color;
24
25 import com.google.gwt.user.client.Timer;
26
27
28
29
30
31 public class Compass {
32 public static final int NONE = -1;
33 public static final int TRANSLATE_N = 0;
34 public static final int TRANSLATE_S = 1;
35 public static final int TRANSLATE_W = 2;
36 public static final int TRANSLATE_E = 3;
37 public static final int ROTATE = 4;
38 public static final int SCALE = 5;
39 private static final float A0 = (float)(Math.PI * 2 / 360 * 7);
40 private static final float A1 = (float)(Math.PI * 2 / 360 * 12);
41 private static final float A2 = (float)(Math.PI * 2 / 360 * 4);
42 private static final float W = 0.15f;
43 private static final Point[] WHEEL = new Point[10];
44 static {
45 WHEEL[0] = new Point(
46 (float)(Math.cos(Math.PI * 1.5 - A0) * (1 - 0.5* W)),
47 (float)(Math.sin(Math.PI * 1.5 - A0) * (1 - 0.5* W)));
48 WHEEL[1] = new Point(
49 (float)(Math.cos(Math.PI * 1.5 - A1)),
50 (float)(Math.sin(Math.PI * 1.5 - A1)));
51 WHEEL[2] = new Point(
52 (float)(Math.cos(Math.PI * 1.5 + A1)),
53 (float)(Math.sin(Math.PI * 1.5 + A1)));
54 WHEEL[3] = new Point(
55 (float)(Math.cos(Math.PI * 1.5 + A0) * (1 - 0.5* W)),
56 (float)(Math.sin(Math.PI * 1.5 + A0) * (1 - 0.5* W)));
57 WHEEL[4] = new Point(
58 (float)(Math.cos(Math.PI * 1.5 + A1)) * (1 - W),
59 (float)(Math.sin(Math.PI * 1.5 + A1)) * (1 - W));
60 WHEEL[5] = new Point(
61 (float)(Math.cos(Math.PI * 1.5 - A1)) * (1 - W),
62 (float)(Math.sin(Math.PI * 1.5 - A1)) * (1 - W));
63 WHEEL[6] = new Point(
64 (float)(Math.cos(Math.PI * 1.5 - A0 + A2)) * (1 - W),
65 (float)(Math.sin(Math.PI * 1.5 - A0 + A2)) * (1 - W));
66 WHEEL[7] = new Point(
67 (float)(Math.cos(Math.PI * 1.5 - A0 + A2)) * (1 - W),
68 -(float)(Math.sqrt(1 - Math.cos(Math.PI * 1.5 - A0 + A2) * (1 - W) * Math.cos(Math.PI * 1.5 - A0 + A2) * (1 - W))));
69 WHEEL[8] = new Point(
70 (float)(Math.cos(Math.PI * 1.5 + A0 - A2)) * (1 - W),
71 (float)(Math.sin(Math.PI * 1.5 + A0 - A2)) * (1 - W));
72 WHEEL[9] = new Point(
73 (float)(Math.cos(Math.PI * 1.5 + A0 - A2)) * (1 - W),
74 -(float)(Math.sqrt(1 - Math.cos(Math.PI * 1.5 - A0 + A2) * (1 - W) * Math.cos(Math.PI * 1.5 - A0 + A2) * (1 - W))));
75 }
76 private static final int DELAY = 100;
77
78 private DrawingView _view;
79 private Point[] _wheel;
80 private TransformMatrix _m, _mTmp;
81 private Point _p1, _p2, _c;
82 private float _r, _radius, _r0, _r1, _s;
83 private float[] _x, _y;
84 private int _pick;
85 private boolean _isMouseDown;
86 private Timer _northTimer = new Timer() {
87 @Override
88 public void run() {
89 _p1.x = 0f;
90 _p1.y = 10f;
91 translate(_p1);
92 if (_pick == TRANSLATE_N && _isMouseDown) {
93 schedule(DELAY);
94 }
95 }
96 };
97 private Timer _southTimer = new Timer() {
98 @Override
99 public void run() {
100 _p1.x = 0f;
101 _p1.y = -10f;
102 translate(_p1);
103 if (_pick == TRANSLATE_S && _isMouseDown) {
104 schedule(DELAY);
105 }
106 }
107 };
108 private Timer _westTimer = new Timer() {
109 @Override
110 public void run() {
111 _p1.x = 10f;
112 _p1.y = 0f;
113 translate(_p1);
114 if (_pick == TRANSLATE_W && _isMouseDown) {
115 schedule(DELAY);
116 }
117 }
118 };
119 private Timer _eastTimer = new Timer() {
120 @Override
121 public void run() {
122 _p1.x = -10f;
123 _p1.y = 0f;
124 translate(_p1);
125 if (_pick == TRANSLATE_E && _isMouseDown) {
126 schedule(DELAY);
127 }
128 }
129 };
130
131 public Compass(DrawingView view) {
132 _c = new Point();
133 _view = view;
134 _p1 = new Point();
135 _p2 = new Point();
136 _m = new TransformMatrix();
137 _mTmp = new TransformMatrix();
138 _wheel = new Point[WHEEL.length];
139 for (int i = 0; i < _wheel.length;i++) {
140 _wheel[i] = new Point();
141 }
142 _x = new float[29];
143 _y = new float[29];
144 }
145
146 public void setPosition(Point c) {
147 c.copyTo(_c);
148 update();
149 }
150
151 public Point getPosition() {
152 return _c;
153 }
154 public float getRadius() {
155 return _radius;
156 }
157 public void setRadius(float radius) {
158 _radius = radius;
159 update();
160 }
161
162 private void update() {
163 _r = 1f;
164 _s = 1f;
165 float D = _radius * 0.3f;
166 float H = _radius * 0.15f;
167 float E = _radius * 0.02f;
168 _x[0] = _c.x - D; _y[0] = _c.y - D - E;
169 _x[1] = _c.x - D; _y[1] = _c.y - D - H;
170 _x[2] = _c.x; _y[2] = _c.y -D - 2 * H;
171 _x[3] = _c.x + D; _y[3] = _c.y - D - H;
172 _x[4] = _c.x + D; _y[4] = _c.y - D - E;
173 _x[5] = _c.x - D; _y[5] = _c.y + D + E;
174 _x[6] = _c.x - D; _y[6] = _c.y + D + H;
175 _x[7] = _c.x; _y[7] = _c.y + D + 2 * H;
176 _x[8] = _c.x + D; _y[8] = _c.y + D + H;
177 _x[9] = _c.x + D; _y[9] = _c.y + D + E;
178 _x[10] = _c.x - D - E; _y[10] = _c.y - D;
179 _x[11] = _c.x - D - H; _y[11] = _c.y - D;
180 _x[12] = _c.x - D - 2 * H; _y[12] = _c.y;
181 _x[13] = _c.x - D - H; _y[13] = _c.y + D;
182 _x[14] = _c.x - D - E; _y[14] = _c.y + D;
183 _x[15] = _c.x + D + E; _y[15] = _c.y - D;
184 _x[16] = _c.x + D + H; _y[16] = _c.y - D;
185 _x[17] = _c.x + D + 2 * H; _y[17] = _c.y;
186 _x[18] = _c.x + D + H; _y[18] = _c.y + D;
187 _x[19] = _c.x + D + E; _y[19] = _c.y + D;
188 _x[20] = _c.x + _radius + H; _y[20] = _c.y - _radius;
189 _x[21] = _c.x + _radius + 2 * H; _y[21] = _c.y - _radius;
190 _x[22] = _c.x + _radius + 2 * H; _y[22] = _c.y + _radius;
191 _x[23] = _c.x + _radius + H; _y[23] = _c.y + _radius;
192 _x[24] = _c.x + _radius + H - E;
193 _x[25] = _c.x + _radius + 2 * H + E;
194 _x[26] = _c.x + _radius + 3 * H;
195 _x[27] = _c.x + _radius + 2 * H + E;
196 _x[28] = _c.x + _radius + H - E;
197 setRotation(0f);
198 setScaling(0.5f);
199 _pick = NONE;
200 }
201
202 public void translate(Point p) {
203 _view.vectorToRefCoordinates(p);
204 _view.getTranslation(_p2);
205 _p2.add(p);
206 _view.setTranslation(_p2);
207 }
208
209 public float getRotation() {
210 return _r;
211 }
212
213 public void setRotation(float r) {
214 if (_r != r) {
215 _r = r;
216 _m.rotation(r).preMultiply(_mTmp.scaling(_radius, _radius)).preMultiply(_mTmp.translation(_c.x, _c.y));
217 for (int i = 0; i < WHEEL.length;i++) {
218 WHEEL[i].transform(_m, _wheel[i]);
219 }
220 _view.setRotation(r);
221 }
222 }
223
224 public void setScaling(float s) {
225 if (_s != s) {
226 _s = s;
227 float H = 0.15f;
228 float y = s * ((2 - H) *_radius);
229 float h = _radius * H;
230 _y[24] = _c.y - _radius + y;
231 _y[25] = _c.y - _radius + y;
232 _y[26] = _c.y - _radius + y + h * 0.5f;
233 _y[27] = _c.y - _radius + y + h;
234 _y[28] = _c.y - _radius + y + h;
235 _p1.x = (s <= 0.5f) ? (0.125f + 1.75f * s) : ( 1 + (s - 0.5f) * 14f); _p1.y = _p1.x;
236 _view.setScaling(_p1);
237 }
238 }
239 public float getScaling() {
240 return _s;
241 }
242
243 public int pick(Point p) {
244 _pick = NONE;
245 float d = p.subtract(_c, _p1).length();
246 if (p.x > _x[0] && p.x < _x[3] && p.y > _y[2] && p.y < _y[0]) {
247 _pick = TRANSLATE_N;
248 } else if (p.x > _x[5] && p.x < _x[8] && p.y < _y[7] && p.y > _y[5]) {
249 _pick = TRANSLATE_S;
250 } else if (p.x > _x[12] && p.x < _x[10] && p.y > _y[10] && p.y < _y[13]) {
251 _pick = TRANSLATE_W;
252 } else if (p.x < _x[17] && p.x > _x[15] && p.y > _y[15] && p.y < _y[18]) {
253 _pick = TRANSLATE_E;
254 } else if (d < _radius && d > (1 - W) * _radius) {
255 _pick = ROTATE;
256 } else if (p.x > _x[24] && p.x < _x[26] && p.y > _y[24] && p.y < _y[27]) {
257 _pick = SCALE;
258 }
259 return _pick;
260 }
261
262 public void render() {
263 _view.beginPath();
264 _view.moveTo(_wheel[0].x, _wheel[0].y);
265 _view.lineTo(_wheel[1].x, _wheel[1].y);
266 _view.arc(_c.x, _c.y, _radius, (float)(Math.PI * 1.5 - A1) + _r, (float)(Math.PI * 1.5 + A1) + _r, true);
267 _view.lineTo(_wheel[3].x, _wheel[3].y);
268 _view.lineTo(_wheel[4].x, _wheel[4].y);
269 _view.arc(_c.x, _c.y, _radius * (1 - W), (float)(Math.PI * 1.5 + A1) + _r, (float)(Math.PI * 1.5 - A1) + _r, false);
270 _view.lineTo(_wheel[0].x, _wheel[0].y);
271 _view.moveTo(_wheel[6].x, _wheel[6].y);
272 _view.lineTo(_wheel[7].x, _wheel[7].y);
273 _view.lineTo(_wheel[8].x, _wheel[8].y);
274 _view.lineTo(_wheel[9].x, _wheel[9].y);
275 _view.setStrokeStyle(Color.BLACK.toString());
276 _view.setLineJoin("bevel");
277 _view.setFillStyle("#C3D9FF");
278 if (_pick == ROTATE) {
279 _view.fill();
280 }
281 _view.stroke();
282 _view.beginPath();
283 _view.moveTo(_x[0], _y[0]);
284 _view.lineTo(_x[1], _y[1]);
285 _view.lineTo(_x[2], _y[2]);
286 _view.lineTo(_x[3], _y[3]);
287 _view.lineTo(_x[4], _y[4]);
288 _view.lineTo(_x[0], _y[0]);
289 if (_pick == TRANSLATE_N) {
290 _view.fill();
291 }
292 _view.stroke();
293 _view.beginPath();
294 _view.moveTo(_x[5], _y[5]);
295 _view.lineTo(_x[6], _y[6]);
296 _view.lineTo(_x[7], _y[7]);
297 _view.lineTo(_x[8], _y[8]);
298 _view.lineTo(_x[9], _y[9]);
299 _view.lineTo(_x[5], _y[5]);
300 if (_pick == TRANSLATE_S) {
301 _view.fill();
302 }
303 _view.stroke();
304 _view.beginPath();
305 _view.moveTo(_x[10], _y[10]);
306 _view.lineTo(_x[11], _y[11]);
307 _view.lineTo(_x[12], _y[12]);
308 _view.lineTo(_x[13], _y[13]);
309 _view.lineTo(_x[14], _y[14]);
310 _view.lineTo(_x[10], _y[10]);
311 if (_pick == TRANSLATE_W) {
312 _view.fill();
313 }
314 _view.stroke();
315 _view.beginPath();
316 _view.moveTo(_x[15], _y[15]);
317 _view.lineTo(_x[16], _y[16]);
318 _view.lineTo(_x[17], _y[17]);
319 _view.lineTo(_x[18], _y[18]);
320 _view.lineTo(_x[19], _y[19]);
321 _view.lineTo(_x[15], _y[15]);
322 if (_pick == TRANSLATE_E) {
323 _view.fill();
324 }
325 _view.stroke();
326 _view.beginPath();
327 _view.moveTo(_x[20], _y[20]);
328 _view.lineTo(_x[21], _y[21]);
329 _view.lineTo(_x[22], _y[22]);
330 _view.lineTo(_x[23], _y[23]);
331 _view.lineTo(_x[20], _y[20]);
332 _view.stroke();
333 _view.beginPath();
334 _view.moveTo(_x[24], _y[24]);
335 _view.lineTo(_x[25], _y[25]);
336 _view.lineTo(_x[26], _y[26]);
337 _view.lineTo(_x[27], _y[27]);
338 _view.lineTo(_x[28], _y[28]);
339 _view.lineTo(_x[24], _y[24]);
340 if (_pick != SCALE) {
341 _view.setFillStyle("rgb(255,255,255)");
342 }
343 _view.fill();
344 _view.stroke();
345 }
346
347
348 public void mouseDown(Point p) {
349 _isMouseDown = true;
350 switch(_pick) {
351 case ROTATE:
352 _r0 = _r;
353 p.subtract(_c, _p1);
354 _r1 = (float)(Math.acos(_p1.x / _p1.length()));
355 if (p.y > _c.y) {
356 _r1 = (float)(2 * Math.PI - _r1);
357 }
358 break;
359 case TRANSLATE_N:
360 _northTimer.run();
361 break;
362 case TRANSLATE_S:
363 _southTimer.run();
364 break;
365 case TRANSLATE_W:
366 _westTimer.run();
367 break;
368 case TRANSLATE_E:
369 _eastTimer.run();
370 break;
371 }
372 }
373
374 public void mouseMove(Point p) {
375 if (_isMouseDown) {
376 if (_pick == ROTATE) {
377 p.subtract(_c, _p1);
378 float r2 = (float)(Math.acos(_p1.x / _p1.length()));
379 if (p.y > _c.y) {
380 r2 = (float)(2 * Math.PI - r2);
381 }
382 setRotation(_r0 - r2 + _r1);
383
384 } else if (_pick == SCALE) {
385 float s = 0f;
386 if (p.y > _c.y - _radius) {
387 if (p.y < _c.y + _radius) {
388 s = 0.5f * (p.y - (_c.y - _radius)) / _radius;
389 } else {
390 s = 1f;
391 }
392 }
393 setScaling(s);
394 }
395 }
396 }
397
398 public void mouseUp() {
399 _isMouseDown = false;
400 }
401
402 }