1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package triptracker.client.map.ui;
21
22 import java.awt.BasicStroke;
23 import java.awt.Color;
24 import java.awt.Graphics;
25 import java.awt.Graphics2D;
26 import java.awt.Shape;
27 import java.awt.event.MouseListener;
28 import java.awt.geom.QuadCurve2D;
29 import java.awt.geom.CubicCurve2D;
30 import java.util.Iterator;
31 import java.util.List;
32
33 import javax.swing.ImageIcon;
34
35 import triptracker.client.map.core.WMSMapProvider;
36 import triptracker.client.net.MapSocket;
37 import triptracker.client.net.MapSocketAdapter;
38 import triptracker.core.Coordinate;
39
40 @SuppressWarnings("serial")
41 public class Map extends SuperPanel {
42 private BasicStroke stroke = new BasicStroke(2.0f);
43 private boolean drawNumbers = false;
44 private boolean drawPoints = true;
45 private boolean drawMap = true;
46
47 private MapViewPanel view;
48
49 private int OVAL_SIZE = 2;
50 private Graphics2D g2;
51
52 private int follow = 2;
53 private boolean update = true;
54 private int action = 1;
55
56 private double centerX, centerY;
57
58 private double[] limits, mapLim;
59 private double ratio = 1;
60
61 private WMSMapProvider mapProvider;
62 private ImageIcon mapImage;
63
64 public Map(MapSocket model, MapViewPanel view) {
65 this.view = view;
66 this.setBackground(Color.white);
67
68 mapProvider = new WMSMapProvider(getHeight(), getWidth());
69
70 new MapController(this);
71 model.addListener(new MapListener());
72 }
73
74 public void addMapListener(MouseListener listener) {
75 this.addMouseListener(listener);
76 }
77
78 private void update() {
79 update = true;
80 }
81
82 /***
83 * Update the map image in the background.
84 */
85 private void updateMap() {
86 if (limits == null) {
87 return;
88 }
89
90 double minX, minY, maxX, maxY;
91 minX = mapLim[0];
92 minY = mapLim[1];
93 maxX = mapLim[2];
94 maxY = mapLim[3];
95 mapProvider.setSize(getWidth(), getHeight());
96 mapImage = mapProvider.getMap(minX, minY, maxX, maxY);
97 }
98
99 @Override
100 protected void paintComponent(Graphics g) {
101 super.paintComponent(g);
102 g2 = (Graphics2D) g;
103 g2.setColor(Color.red);
104 g2.drawRect(0, 0, getSize().width - 1, getSize().height - 1);
105 g2.setColor(Color.black);
106 if (!coordList.isEmpty()) {
107 ratio = getRatio(limits);
108 if (action != 3 && follow != 3 && update && drawMap)
109 updateMap();
110 update = false;
111 }
112
113 if (mapImage != null && follow != 3 && action != 3 && drawMap) {
114 g2.drawImage(mapImage.getImage(), 0, 0, getWidth(), getHeight(),
115 this);
116 }
117
118 g2.setStroke(stroke);
119 if (!coordList.isEmpty()) {
120 drawStraightRoute(coordList);
121 }
122 }
123
124 /*** Sets route to plot */
125 public void setCoordList(List<Coordinate> coordList) {
126
127 update();
128 this.coordList = coordList;
129 limits = getLimits(coordList);
130 ratio = getRatio(limits);
131 mapLim = getLimits(coordList);
132
133 double x = calcX(limits[2]);
134 double y = calcY(limits[1]);
135 mapLim[2] = mapLim[2] + (((getWidth() - x)/ratio));
136 mapLim[1] = mapLim[1] - (((getHeight() - y)/ratio));
137
138
139
140 repaint();
141 }
142
143 /*** Resets map to initial size */
144 public void reset(){
145 setCoordList(coordList);
146 }
147
148 /*** Sets realtime if route is plotted realtime */
149 public void setRealtime(boolean realtime) {
150 this.realtime = realtime;
151 }
152
153 public void setView(boolean nr, boolean dot, boolean map, int thick){
154 drawNumbers = nr;
155 drawPoints = dot;
156 drawMap = map;
157 stroke = new BasicStroke(thick);
158 }
159
160 /*** Sets mouseklick to zoom to position */
161 public void setZoom() {
162 action = 2;
163 }
164
165 /*** Sets mouseklick to move to position */
166 public void setMove() {
167 action = 1;
168 }
169
170 /*** If selected, will follow coordinates under realtime plotting */
171 public void setFollow(int follow) {
172
173
174
175
176
177 this.follow = follow;
178 if (follow != 3){
179 update();
180 repaint();
181 }
182
183 }
184
185 /***
186 * Return edge limits for the given set of coordinates.
187 *
188 * @param coordList list of coordinates
189 * @return edge limits for coordinate set
190 */
191 public double[] getLimits(List<Coordinate> coordList) {
192
193 double[] limits = { Double.MAX_VALUE, Double.MAX_VALUE,
194 Double.MIN_VALUE, Double.MIN_VALUE };
195 for (Coordinate coord : coordList) {
196 if (coord.getX() < limits[0]) {
197 limits[0] = coord.getX();
198 }
199 if (coord.getY() < limits[1]) {
200 limits[1] = coord.getY();
201 }
202 if (coord.getX() > limits[2]) {
203 limits[2] = coord.getX();
204 }
205 if (coord.getY() > limits[3]) {
206 limits[3] = coord.getY();
207 }
208 }
209 int factor = 10;
210 double width = limits[2] - limits[0];
211 double height = limits[3] - limits[1];
212 limits[0] -= width/factor;
213 limits[1] -= height/factor;
214 limits[2] += width/factor;
215 limits[3] += height/factor;
216 return limits;
217 }
218
219 /*** Returns borders of what to show */
220 public double[] setBorders(double[] limits) {
221 double[] borders = { Double.MAX_VALUE, Double.MAX_VALUE,
222 Double.MIN_VALUE, Double.MIN_VALUE };
223 borders[0] = 0;
224 borders[1] = 0;
225 borders[2] = limits[2] - limits[0];
226 borders[3] = limits[3] - limits[1];
227 return borders;
228 }
229
230 /***
231 * Sets the ratio between route bounds and actual window size. Used for
232 * scaling route.
233 *
234 * @param limits = limits of route
235 * @return ratio
236 */
237 public double getRatio(double[] limits) {
238 double ratio;
239 double xWidth = limits[2] - limits[0];
240 double yWidth = limits[3] - limits[1];
241
242 if ((xWidth / getWidth()) > yWidth / (getHeight())) {
243 ratio = getWidth() / xWidth;
244 } else {
245 ratio = getHeight() / yWidth;
246 }
247
248
249 return ratio;
250 }
251
252 /***
253 * Draw route.
254 *
255 * @param coordList list of coordinates for route
256 */
257 public void drawStraightRoute(List<Coordinate> coordList) {
258 int x = 0, y = 0, prevX = 0, prevY = 0;
259 int nr = 0;
260 Iterator itr = coordList.iterator();
261 Coordinate coord = (Coordinate) itr.next();
262
263
264 x = (int) calcX(coord.getX());
265 y = (int) calcY(coord.getY());
266 nr ++;
267 if (drawPoints)
268 g2.drawOval(x,y,OVAL_SIZE,OVAL_SIZE);
269 if (drawNumbers)
270 g2.drawString(nr + "",x,y);
271
272
273 while (itr.hasNext()) {
274 coord = (Coordinate) itr.next();
275 prevX = x;
276 prevY = y;
277 nr++;
278
279 x = (int) calcX(coord.getX());
280 y = (int) calcY(coord.getY());
281
282
283
284 g2.drawLine(x, y, prevX, prevY);
285 if (drawPoints)
286 g2.drawOval(x, y, OVAL_SIZE, OVAL_SIZE);
287
288 if (drawNumbers)
289 g2.drawString(nr + "", x, y);
290
291
292 }
293 }
294
295 /*** Drawing route in bezier splines */
296
297 public void drawBezierRoute(List<Coordinate> coordList) {
298 double x1, x2, x3, x4, y1, y2, y3, y4;
299 Shape curve = null;
300
301 Iterator itr = coordList.iterator();
302 Coordinate coord = (Coordinate) itr.next();
303 x2 = calcX(coord.getX());
304 y2 = calcY(coord.getY());
305
306 coord = (Coordinate) itr.next();
307 x3 = calcX(coord.getX());
308 y3 = calcY(coord.getY());
309
310 coord = (Coordinate) itr.next();
311 x4 = calcX(coord.getX());
312 y4 = calcY(coord.getY());
313
314 for (Coordinate coordz : coordList) {
315 x1 = x2; x2 = x3; x3 = x4; x4 = calcX(coordz.getX());
316 y1 = y2; y2 = y3; y3 = y4; y4 = calcY(coordz.getY());
317
318
319
320
321
322
323 double wx1 = x2 + (x2-x1);
324 double wy1 = y2 + (y2-y1);
325 double wx2 = x3 + (x4-x3);
326 double wy2 = y3 + (y4-y3);
327
328
329
330
331
332
333
334
335
336
337
338 curve = new CubicCurve2D.Double(x2, y2, wx1, wy1,
339 wx2, wy2, x3, y3);
340 g2.draw(curve);
341 }
342
343 curve = new QuadCurve2D.Double(100, 100, 150, 150, 200, 100);
344
345 g2.draw(curve);
346 }
347
348 /*** For adding coordinate while route is beeing plotted realtime. */
349 public void addCoordinate(Coordinate coord) {
350 double x = calcX(coord.getX());
351 double y = calcY(coord.getY());
352
353
354 coordList.add(coord);
355
356
357 switch(follow) {
358 case 1:
359 repaint();
360 break;
361 case 2:
362 checkLimits((int) x ,(int) y);
363 repaint();
364 break;
365 case 3:
366 setCenter(x, y);
367 break;
368 }
369 }
370
371
372 /*** Checking if coordinate is outside of window */
373 public void checkLimits(int x, int y){
374 int factor = 10;
375 int w = (getWidth() / factor);
376 int h = (getHeight() / factor);
377 if ( x < (0 + w) || x > (getWidth() - w) || y < (0 + h) || y > (getHeight() - h))
378 setCenter(x,y);
379 }
380
381 /*** Calculates x coordinate for plotting */
382 public double calcX(double x) {
383 return (ratio * (x - limits[0]));
384 }
385
386 /*** Calculates y coordinate for plotting */
387 public double calcY(double y) {
388 return -(ratio * (y - limits[3]));
389 }
390
391 /***
392 * Magnifies route with specified zoomRatio
393 *
394 */
395 public void zoomIn() {
396 limits = zoomInMatrix(limits);
397 mapLim = zoomInMatrix(mapLim);
398 update();
399 repaint();
400 }
401
402 /*** Zooms out route with specified zoomRatio */
403 public void zoomOut() {
404 limits = zoomOutMatrix(limits);
405 mapLim = zoomOutMatrix(mapLim);
406 update();
407 repaint();
408 }
409
410 /*** Handles action for mouseclick. */
411 public void mouseClick(double x, double y, int button) {
412 switch (action) {
413 case 1:
414 if (!coordList.isEmpty())
415 setCenter(x, y);
416 else
417 view.setState("No route is set! ");
418 break;
419 case 2:
420 if (!coordList.isEmpty() && button != 3){
421 setCenter(x, y);
422 zoomIn();
423 }
424 else if (!coordList.isEmpty()) {
425 setCenter(x, y);
426 zoomOut();
427 }
428 else
429 view.setState("No route is set! ");
430 break;
431 }
432 }
433
434 /*** Sets position x,y to center of view */
435 public void setCenter(double x, double y) throws NullPointerException {
436 centerX = getWidth() / 2;
437 centerY = getHeight() / 2;
438 double moveX = x - centerX;
439 double moveY = y - centerY;
440 go(moveX, moveY);
441 }
442
443 /*** Moves window specified pixel length, from center. */
444 public void go(double mvX, double mvY) {
445 double moveXFactor, moveYFactor;
446 moveXFactor = mvX / (getWidth()/2);
447 moveYFactor = mvY / (getHeight()/2);
448 mvX = (((mapLim[2] - mapLim[0])/2) * moveXFactor) ;
449 mvY = -(((mapLim[3] - mapLim[1])/2) * moveYFactor) ;
450 mapLim = moveMatrix(mapLim, mvX,mvY);
451 limits = moveMatrix(limits, mvX,mvY);
452
453 update();
454 repaint();
455 }
456
457 public double[] zoomInMatrix(double[] x) {
458
459 double distX = (mapLim[2] - mapLim[0])/2;
460 double distY = (mapLim[3] - mapLim[1])/2;
461
462
463 x[0] = x[0] + (distX/2);
464 x[1] = x[1] + (distY/2);
465 x[2] = x[2] - (distX/2);
466 x[3] = x[3] - (distY/2);
467 return x;
468 }
469
470 public double[] zoomOutMatrix(double[] x) {
471
472
473
474 double distX = (mapLim[2] - mapLim[0])/2;
475 double distY = (mapLim[3] - mapLim[1])/2;
476 x[0] = x[0] - distX;
477 x[1] = x[1] - distY;
478 x[2] = x[2] + distX;
479 x[3] = x[3] + distY;
480 return x;
481 }
482
483 public double[] moveMatrix(double[] matrix, double mvX, double mvY) {
484 matrix[0] = matrix[0] + mvX;
485 matrix[1] = matrix[1] + mvY;
486 matrix[2] = matrix[2] + mvX;
487 matrix[3] = matrix[3] + mvY;
488 return matrix;
489 }
490
491 /*** Listens for events from MapSocket */
492 private class MapListener extends MapSocketAdapter {
493 /*** {@inheritDoc} */
494 @Override
495 public void coordReceived(int routeId, Coordinate coord) {
496
497 int limit = 40;
498
499 if (coordList.size() < limit){
500
501 coordList.add(coord);
502 view.setCoordList(coordList);
503 return;
504 } else if (coordList.size() == limit){
505
506 setCoordList(coordList);
507 view.setState("Received route");
508 }
509 addCoordinate(coord);
510 }
511
512 /*** {@inheritDoc} */
513 @Override
514 public void coordsReceived(List<Coordinate> coords) {
515
516 int limit = 30;
517 if ((coordList.size() + coords.size()) < limit){
518
519 coordList.addAll(coords);
520 view.setCoordList(coordList);
521 return;
522 } else if ((coordList.size() + coords.size()) >= limit){
523
524 coordList.addAll(coords);
525 setCoordList(coordList);
526 view.setState("Received route");
527 }
528 }
529 }
530 }