View Javadoc

1   /*
2    * Trip Tracker, a real-time position tracking system for the Internet.
3    * Copyright (C) 2006  Team Trip Tracker
4    *
5    * This program is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License as published by the
7    * Free Software Foundation; either version 2 of the License, or (at your
8    * option) any later version.
9    *
10   * This program is distributed in the hope that it will be useful, but
11   * WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13   * General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License along
16   * with this program; if not, write to the Free Software Foundation, Inc.,
17   * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
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  //	private Coordinate lastCoord;
52  	private int follow = 2; // 1 = Don't follow, 2 = Always inside, 3 = Center on last
53  	private boolean update = true;
54  	private int action = 1; //1 = move, 2 = zoom
55  //	private final double weight = 3;
56  	private double centerX, centerY;
57  //	limits[0] = xMin, limits[1] = yMin, limits[2] = xMax, limits[3] = yMax
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 //    	limits[0] = xMin, limits[1] = yMin, limits[2] = xMax, limits[3] = yMax	
127     		update();
128 		this.coordList = coordList;
129 		limits = getLimits(coordList);
130 		ratio = getRatio(limits);
131 		mapLim = getLimits(coordList);
132 //		lastCoord = coordList.get(coordList.size() -1);
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 //		System.out.println("mapLim: " + Arrays.toString(mapLim));
139 //		System.out.println("limits: " + Arrays.toString(limits));
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 //		if (follow)
173 //			action = 3;
174 //		else {
175 //			action = 1;
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 //    	limits[0] = xMin, limits[1] = yMin, limits[2] = xMax, limits[3] = yMax
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; // limits[0] - limits[0];
224 		borders[1] = 0; // limits[1] - limits[1];
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 //		System.out.println("Ratio: " + ratio + ", width: " + xWidth
248 //				+ ", " + yWidth + " size: " + getWidth() + ", " + getHeight());
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 		//Draw first point
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 		//Draw rest of route
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 //			System.out.println("Drawing: " + x + ", " + y + ", " + prevX
283 //					+ ", " + prevY);
284 			g2.drawLine(x, y, prevX, prevY);// (startx, starty, prevx, prevy);
285 			if (drawPoints)
286 				g2.drawOval(x, y, OVAL_SIZE, OVAL_SIZE);									
287 			//g2.drawString("Pos: " + coord.getX() + ", " + coord.getY(),x,y);
288 			if (drawNumbers)
289 				g2.drawString(nr + "", x, y);
290 			// + coord.getX() + ", " + coord.getY(), x, y);
291 //			drawBezierRoute(coordList);
292 		}
293 	}
294     
295     /*** Drawing route in bezier splines */
296     // TODO make this work nicely
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 	//    		curve = new QuadCurve2D.Double(x1, y1, x2, y2, x3, y3);
318 //				double wx1 = x2 + (sqrt(pow(x1 - x2, 2))) / weight * x1 - x3;
319 //				double wy1 = y2 + (sqrt(pow(y1 - y2, 2))) / weight * y1 - y3;
320 //				double wx2 = x3 + (sqrt(pow(x2 - x3, 2))) / weight * x2 - x4;
321 //				double wy2 = y3 + (sqrt(pow(y2 - y3, 2))) / weight * y2 - y4;
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 	//			double wx1 = x2 + (sqrt(pow(x2 - x1, 2)
329 	//					+ (pow(y2 - y1, 2)))) / weight * x3 - x1;
330 	//			double wy1 = y2 + (sqrt(pow((x2 - x1), 2)
331 	//					+ (pow(y2 - y1, 2)))) / weight * y3 - y1;
332 	//			double wx2 = x3 + (sqrt(pow((x3 - x2), 2)
333 	//					+ (pow(y3 - y2, 2)))) / weight * x4 - x2;
334 	//			double wy2 = y3 + (sqrt(pow((x3 - x2), 2)
335 	//					+ (pow(y3 - y2, 2)))) / weight * y4 - y2;
336 	    			
337 	//    		curve = new CubicCurve2D.Double(x1,y1,x2,y2,x3,y3,x4,y4);
338 				curve = new CubicCurve2D.Double(x2, y2, wx1, wy1,
339 						wx2, wy2, x3, y3);
340 				g2.draw(curve);
341 	    	}
342 //		curve = new QuadCurve2D.Float(x, y, prevX, prevY, w * .9f, yy);
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 //		double prevX = calcX(lastCoord.getX());
353 //		double prevY = calcY(lastCoord.getY());
354 		coordList.add(coord);
355 //		System.out.println("Added coordinate, " + coordList.size());
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 //		limits[0] = xMin, limits[1] = yMin, limits[2] = xMax, limits[3] = yMax
459     		double distX = (mapLim[2] - mapLim[0])/2;
460     		double distY = (mapLim[3] - mapLim[1])/2;
461 //		double distX = (x[2] - x[0])/2;
462 //		double distY = (x[3] - x[1])/2;
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 //		limits[0] = xMin, limits[1] = yMin, limits[2] = xMax, limits[3] = yMax
472 //		double distX = (x[2] - x[0])/2;
473 //		double distY = (x[3] - x[1])/2;
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 		//	if (coordList == null){
497 			int limit = 40;
498 //			System.out.println("Size: " + coordList.size());
499 			if (coordList.size() < limit){
500 //				System.out.println("CoordList is < " + limit);
501 				coordList.add(coord);
502 				view.setCoordList(coordList);
503 				return;
504 			} else if (coordList.size() == limit){
505 //				System.out.println("Setting coordList");
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 //			System.out.println("Size: " + coordList.size());
516 			int limit = 30;
517 			if ((coordList.size() + coords.size()) < limit){
518 //				System.out.println("CoordList is < " + limit);
519 				coordList.addAll(coords);
520 				view.setCoordList(coordList);
521 				return;
522 			} else if ((coordList.size() + coords.size()) >= limit){
523 //				System.out.println("Setting coordList");
524 				coordList.addAll(coords);
525 				setCoordList(coordList);
526 				view.setState("Received route");
527 			}
528 		}
529 	}
530 }