View Javadoc

1   package nl.javel.gisbeans.map;
2   
3   import java.awt.Font;
4   import java.awt.FontMetrics;
5   import java.awt.Graphics2D;
6   import java.awt.RenderingHints;
7   import java.awt.geom.AffineTransform;
8   import java.awt.geom.NoninvertibleTransformException;
9   import java.awt.geom.Point2D;
10  import java.awt.geom.Rectangle2D;
11  import java.text.DecimalFormat;
12  import java.util.Iterator;
13  import java.util.List;
14  
15  import nl.javel.gisbeans.geom.GisObject;
16  import nl.javel.gisbeans.geom.SerializableGeneralPath;
17  import nl.javel.gisbeans.geom.SerializableRectangle2D;
18  
19  /***
20   * Provides the implementation of a Map.
21   */
22  public class Map implements MapInterface
23  {
24  	/*** the extent of the map */
25  	private Rectangle2D extent;
26  
27  	/*** the layers of the map */
28  	private List layers;
29  
30  	/*** the mapfileImage */
31  	private ImageInterface image;
32  
33  	/*** the name of the mapFile */
34  	private String name;
35  
36  	/*** the referenceMap */
37  	private ReferenceMapInterface referenceMap;
38  
39  	/*** the map units */
40  	private int units;
41  
42  	/*** the screen resolution */
43  	private final int RESOLUTION = 72;
44  
45  	/***
46  	 * constructs a new Map
47  	 */
48  	public Map()
49  	{
50  		super();
51  	}
52  
53  	/***
54  	 * @see nl.javel.gisbeans.map.MapInterface#addLayer(LayerInterface)
55  	 */
56  	public void addLayer(LayerInterface layer)
57  	{
58  		this.layers.add(layer);
59  	}
60  
61  
62  	/***
63  	 * @see nl.javel.gisbeans.map.MapInterface#drawLegend(java.awt.Graphics2D)
64  	 */
65  	public Graphics2D drawLegend(final Graphics2D graphics)
66  	{
67  		if (this.getImage().getLegend().isStatus())
68  		{
69  			graphics.setColor(this.getImage().getLegend().getBackgroundColor());
70  			graphics.fillRect(0, 0, (int) this.getImage().getLegend().getSize()
71  					.getWidth(), (int) this.getImage().getLegend().getSize()
72  					.getHeight());
73  
74  			graphics.setColor(this.getImage().getLegend().getOutlineColor());
75  			graphics.drawRect(0, 0, (int) this.getImage().getLegend().getSize()
76  					.getWidth(), (int) this.getImage().getLegend().getSize()
77  					.getHeight());
78  
79  			int space = 2;
80  			int position = space;
81  			int dPosition = (int) Math.floor((this.getImage().getLegend()
82  					.getSize().getHeight() - 2 * space)
83  					/ (1 + this.getLayers().size()));
84  			int nr = 0;
85  			for (Iterator i = this.getLayers().iterator(); i.hasNext();)
86  			{
87  				Layer layer = (Layer) i.next();
88  				graphics.setColor(layer.getColor());
89  				graphics.fillRect(space, position, dPosition - space, dPosition
90  						- space);
91  				if (layer.getOutlineColor() != null)
92  					graphics.setColor(layer.getOutlineColor());
93  				graphics.drawRect(space, position, dPosition - space - 1,
94  						dPosition - space - 1);
95  				graphics.setFont(this.getImage().getLegend().getFont());
96  
97  				FontMetrics fm = graphics.getFontMetrics(this.getImage()
98  						.getLegend().getFont());
99  
100 				while (fm.getStringBounds(layer.getName(), graphics).getWidth() > (this
101 						.getImage().getLegend().getSize().getWidth()
102 						- 2 * space - dPosition)
103 						|| fm.getStringBounds(layer.getName(), graphics)
104 								.getHeight() > dPosition - 2 * space)
105 				{
106 					graphics.setFont(new Font(this.getImage().getLegend()
107 							.getFont().getFontName(), Font.TRUETYPE_FONT,
108 							graphics.getFont().getSize() - 1));
109 					fm = graphics.getFontMetrics(graphics.getFont());
110 				}
111 
112 				graphics.setColor(this.getImage().getLegend().getFontColor());
113 				graphics.drawString(layer.getName(), 4 + dPosition, dPosition
114 						+ position - 4);
115 				position = nr++
116 						* (int) (this.getImage().getLegend().getSize()
117 								.getHeight() / (this.getLayers().size()));
118 			}
119 		}
120 		return graphics;
121 	}
122 
123 	/***
124 	 * @see nl.javel.gisbeans.map.MapInterface#drawMap(Graphics2D)
125 	 */
126 	public Graphics2D drawMap(Graphics2D graphics) throws GraphicsException
127 	{
128 		//We fill the background */
129 		graphics.setColor(this.getImage().getBackgroundColor());
130 		graphics.fillRect(0, 0, (int) this.getImage().getSize().getWidth(),
131 				(int) this.getImage().getSize().getHeight());
132 
133 		//We compute the transform of the map
134 		AffineTransform transform = new AffineTransform();
135 		transform.scale(this.getImage().getSize().getWidth()
136 				/ this.extent.getWidth(), -this.getImage().getSize()
137 				.getHeight()
138 				/ this.extent.getHeight());
139 		transform.translate(-this.extent.getX(), -this.extent.getY()
140 				- this.extent.getHeight());
141 		AffineTransform antiTransform = null;
142 		try
143 		{
144 			antiTransform = transform.createInverse();
145 		} catch (NoninvertibleTransformException e)
146 		{
147 			e.printStackTrace();
148 		}
149 
150 		//we cache the scale
151 		double scale = this.getScale();
152 
153 		//we set the rendering hints
154 		graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
155 				RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
156 
157 		//We loop over the layers
158 		for (Iterator i = this.getLayers().iterator(); i.hasNext();)
159 		{
160 			Layer layer = (Layer) i.next();
161 			try
162 			{
163 				if (layer.isStatus() && layer.getMaxScale() < scale
164 						&& layer.getMinScale() > scale)
165 				{
166 					List shapes = layer.getDataSource().getShapes(this.extent);
167 					SerializableGeneralPath shape = null;
168 					int shapeNumber = 0;
169 					for (Iterator shapeIterator = shapes.iterator(); shapeIterator
170 							.hasNext();)
171 					{
172 						GisObject gisObject = (GisObject) shapeIterator.next();
173 						if (layer.getDataSource().getType() == POINT)
174 						{
175 							shape = new SerializableGeneralPath();
176 							Point2D point = (Point2D) gisObject.getShape();
177 							shape.moveTo((float) point.getX(), (float) point
178 									.getY());
179 
180 						} else
181 						{
182 							shape = (SerializableGeneralPath) gisObject
183 									.getShape();
184 						}
185 						if (layer.isTransform())
186 						{
187 							shape.transform(transform);
188 						}
189 						graphics.setColor(layer.getColor());
190 						if (layer.getDataSource().getType() == POLYGON)
191 						{
192 							graphics.fill(shape);
193 						}
194 						if (layer.getOutlineColor() != null)
195 						{
196 							graphics.setColor(layer.getOutlineColor());
197 						}
198 						graphics.draw(shape);
199 						for (Iterator iA = layer.getAttributes().iterator(); iA
200 								.hasNext();)
201 						{
202 							AbstractAttribute attribute = (AbstractAttribute) iA
203 									.next();
204 							if (attribute.getMaxScale() < scale
205 									&& attribute.getMinScale() > scale)
206 							{
207 								graphics.setColor(attribute.getFontColor());
208 								graphics.setFont(attribute.getFont());
209 								if (layer.isTransform())
210 								{
211 									graphics.translate(shape.getBounds2D()
212 											.getCenterX(), shape.getBounds2D()
213 											.getCenterY());
214 									graphics.rotate(2 * Math.PI
215 											- attribute.getAngle(shapeNumber));
216 								}
217 								FontMetrics fm = graphics
218 										.getFontMetrics(attribute.getFont());
219 								int[] xy = new int[2];
220 								switch (attribute.getPosition())
221 								{
222 									case MapInterface.UL :
223 										xy[0] = (int) -fm
224 												.getStringBounds(
225 														attribute
226 																.getValue(shapeNumber),
227 														graphics).getWidth();
228 										xy[1] = 0;
229 										break;
230 									case MapInterface.UC :
231 										xy[0] = (int) -fm
232 												.getStringBounds(
233 														attribute
234 																.getValue(shapeNumber),
235 														graphics).getWidth() / 2;
236 										xy[1] = 0;
237 										break;
238 									case MapInterface.UR :
239 										xy[0] = 0;
240 										xy[1] = 0;
241 										break;
242 									case MapInterface.CL :
243 										xy[0] = (int) -fm
244 												.getStringBounds(
245 														attribute
246 																.getValue(shapeNumber),
247 														graphics).getWidth();
248 										xy[1] = (int) -fm
249 												.getStringBounds(
250 														attribute
251 																.getValue(shapeNumber),
252 														graphics).getHeight() / 2;
253 										break;
254 									case MapInterface.CC :
255 										xy[0] = (int) -fm
256 												.getStringBounds(
257 														attribute
258 																.getValue(shapeNumber),
259 														graphics).getWidth() / 2;
260 										xy[1] = (int) -fm
261 												.getStringBounds(
262 														attribute
263 																.getValue(shapeNumber),
264 														graphics).getHeight() / 2;
265 										break;
266 									case MapInterface.CR :
267 										xy[0] = 0;
268 										xy[1] = (int) -fm
269 												.getStringBounds(
270 														attribute
271 																.getValue(shapeNumber),
272 														graphics).getHeight() / 2;
273 										break;
274 									case MapInterface.LL :
275 										xy[0] = (int) -fm
276 												.getStringBounds(
277 														attribute
278 																.getValue(shapeNumber),
279 														graphics).getWidth();
280 										xy[1] = (int) -fm
281 												.getStringBounds(
282 														attribute
283 																.getValue(shapeNumber),
284 														graphics).getHeight();
285 										break;
286 									case MapInterface.LC :
287 										xy[0] = (int) -fm
288 												.getStringBounds(
289 														attribute
290 																.getValue(shapeNumber),
291 														graphics).getWidth() / 2;
292 										xy[1] = (int) -fm
293 												.getStringBounds(
294 														attribute
295 																.getValue(shapeNumber),
296 														graphics).getHeight();
297 										break;
298 									case MapInterface.LR :
299 										xy[0] = 0;
300 										xy[1] = (int) -fm
301 												.getStringBounds(
302 														attribute
303 																.getValue(shapeNumber),
304 														graphics).getHeight();
305 										break;
306 									default :
307 										xy[0] = 0;
308 										xy[1] = 0;
309 										break;
310 								}
311 								graphics.drawString(attribute
312 										.getValue(shapeNumber), xy[0], xy[1]);
313 								if (layer.isTransform())
314 								{
315 									graphics.rotate(-(2 * Math.PI - attribute
316 											.getAngle(shapeNumber)));
317 									graphics.translate(-shape.getBounds2D()
318 											.getCenterX(), -shape.getBounds2D()
319 											.getCenterY());
320 								}
321 							}
322 						}
323 						if (layer.isTransform())
324 						{
325 							shape.transform(antiTransform);
326 						}
327 						shapeNumber++;
328 					}
329 				}
330 			} catch (Exception exception)
331 			{
332 				exception.printStackTrace();
333 				throw new GraphicsException(exception.getMessage());
334 			}
335 		}
336 		return graphics;
337 	}
338 
339 	/***
340 	 * @see nl.javel.gisbeans.map.MapInterface#drawReferenceMap(Graphics2D)
341 	 */
342 	public Graphics2D drawReferenceMap(Graphics2D graphics)
343 	{
344 		return graphics;
345 	}
346 
347 	/***
348 	 * @see nl.javel.gisbeans.map.MapInterface#drawScalebar(Graphics2D)
349 	 */
350 	public Graphics2D drawScalebar(Graphics2D graphics)
351 	{
352 		if (this.getImage().getScalebar().isStatus())
353 		{
354 			graphics.setColor(this.getImage().getScalebar()
355 					.getBackgroundColor());
356 			graphics.fillRect(0, 0, (int) this.getImage().getScalebar()
357 					.getSize().getWidth(), (int) this.getImage().getScalebar()
358 					.getSize().getHeight());
359 
360 			graphics.setColor(this.getImage().getScalebar().getColor());
361 			graphics.drawRect(0, 0, (int) this.getImage().getScalebar()
362 					.getSize().getWidth() - 1, (int) this.getImage()
363 					.getScalebar().getSize().getHeight() - 1);
364 			graphics.drawRect(0, 0, (int) this.getImage().getScalebar()
365 					.getSize().getWidth() - 1, (int) this.getImage()
366 					.getScalebar().getSize().getHeight() / 2);
367 
368 			graphics.setFont(this.getImage().getScalebar().getFont());
369 			graphics.setColor(this.getImage().getScalebar().getFontColor());
370 
371 			String units = new String();
372 			switch (this.getImage().getScalebar().getUnits())
373 			{
374 				case FEET :
375 					units = " ft.";
376 					break;
377 				case INCHES :
378 					units = " in.";
379 					break;
380 				case KILOMETERS :
381 					units = " km.";
382 					break;
383 				case METERS :
384 					units = " m.";
385 					break;
386 				case MILES :
387 					units = " mi.";
388 					break;
389 				case DD :
390 					units = " dd.";
391 					break;
392 				default :
393 					units = " m.";
394 					break;
395 			}
396 
397 			DecimalFormat formatter = new DecimalFormat("#.00");
398 
399 			double[] factor = {FEET_TO_METER, INCH_TO_METER,
400 					KILOMETER_TO_METER, 1, MILES_TO_METER, DD_TO_METER};
401 			String scale = formatter.format(((this.getImage().getScalebar()
402 					.getSize().getWidth() / this.getImage().getSize()
403 					.getWidth()) * this.getExtent().getWidth())
404 					* (factor[this.getUnits()] / factor[this.getImage()
405 							.getScalebar().getUnits()]))
406 					+ units;
407 
408 			FontMetrics fm = graphics.getFontMetrics(this.getImage()
409 					.getScalebar().getFont());
410 			while (fm.getStringBounds(
411 					(formatter.format(this.getUnitImageRatio()) + units),
412 					graphics).getWidth() > this.getImage().getScalebar()
413 					.getSize().getWidth()
414 					|| fm
415 							.getStringBounds(
416 									(formatter.format(this.getUnitImageRatio()) + units),
417 									graphics).getHeight() > this.getImage()
418 							.getScalebar().getSize().getHeight() / 2)
419 			{
420 				graphics.setFont(new Font(this.getImage().getScalebar()
421 						.getFont().getFontName(), Font.TRUETYPE_FONT, graphics
422 						.getFont().getSize() - 1));
423 				fm = graphics.getFontMetrics(graphics.getFont());
424 			}
425 			graphics.drawString(scale, (int) this.getImage().getScalebar()
426 					.getSize().getWidth()
427 					- fm.stringWidth(scale) - 1, (int) this.getImage()
428 					.getScalebar().getSize().getHeight() - 2);
429 
430 			int x = 0;
431 			for (int i = 0; i <= this.getImage().getScalebar().getIntervals(); i++)
432 			{
433 				if (i % 2 != 0)
434 				{
435 					graphics.setColor(this.getImage().getScalebar().getColor());
436 					graphics.fillRect(x, 0, ((int) this.getImage()
437 							.getScalebar().getSize().getWidth() / this
438 							.getImage().getScalebar().getIntervals()),
439 							(int) this.getImage().getScalebar().getSize()
440 									.getHeight() / 2);
441 					x += (((int) this.getImage().getScalebar().getSize()
442 							.getWidth()) / this.getImage().getScalebar()
443 							.getIntervals()) * 2;
444 				}
445 			}
446 		}
447 		return graphics;
448 	}
449 
450 	/***
451 	 * @see nl.javel.gisbeans.map.MapInterface#getExtent()
452 	 */
453 	public Rectangle2D getExtent()
454 	{
455 		return this.extent;
456 	}
457 
458 	/***
459 	 * @see nl.javel.gisbeans.map.MapInterface#getImage()
460 	 */
461 	public ImageInterface getImage()
462 	{
463 		return this.image;
464 	}
465 
466 	/***
467 	 * @see nl.javel.gisbeans.map.MapInterface#getLayers()
468 	 */
469 	public List getLayers()
470 	{
471 		return this.layers;
472 	}
473 
474 	/***
475 	 * @see nl.javel.gisbeans.map.MapInterface#getName()
476 	 */
477 	public String getName()
478 	{
479 		return this.name;
480 	}
481 
482 	/***
483 	 * @see MapInterface#getScale()
484 	 */
485 	public double getScale()
486 	{
487 		return (this.getImage().getSize().getWidth() / (2.54 * this.RESOLUTION))
488 				* this.extent.getWidth();
489 	}
490 
491 	/***
492 	 * @see nl.javel.gisbeans.map.MapInterface#getReferenceMap()
493 	 */
494 	public ReferenceMapInterface getReferenceMap()
495 	{
496 		return this.referenceMap;
497 	}
498 
499 	/***
500 	 * returns the scale of the Image
501 	 * 
502 	 * @return double the unitPerPixel
503 	 */
504 	public double getUnitImageRatio()
505 	{
506 		return Math.min(this.extent.getWidth()
507 				/ this.image.getSize().getWidth(), this.extent.getHeight()
508 				/ this.image.getSize().getHeight());
509 	}
510 
511 	/***
512 	 * @see nl.javel.gisbeans.map.MapInterface#getUnits()
513 	 */
514 	public int getUnits()
515 	{
516 		return this.units;
517 	}
518 
519 	/***
520 	 * @see nl.javel.gisbeans.map.MapInterface#setExtent(java.awt.geom.Rectangle2D)
521 	 */
522 	public void setExtent(Rectangle2D extent)
523 	{
524 		this.extent = extent;
525 	}
526 
527 	/***
528 	 * @see nl.javel.gisbeans.map.MapInterface#setImage(ImageInterface)
529 	 */
530 	public void setImage(ImageInterface image)
531 	{
532 		this.image = image;
533 	}
534 
535 	/***
536 	 * @see nl.javel.gisbeans.map.MapInterface#setLayers(List)
537 	 */
538 	public void setLayers(List layers)
539 	{
540 		this.layers = layers;
541 	}
542 
543 	/***
544 	 * @see nl.javel.gisbeans.map.MapInterface#setLayer(int, LayerInterface)
545 	 */
546 	public void setLayer(int index, LayerInterface layer)
547 	{
548 		this.layers.set(index, layer);
549 	}
550 
551 	/***
552 	 * @see nl.javel.gisbeans.map.MapInterface#setName(String)
553 	 */
554 	public void setName(String name)
555 	{
556 		this.name = name;
557 	}
558 
559 	/***
560 	 * @see nl.javel.gisbeans.map.MapInterface#setReferenceMap(ReferenceMapInterface)
561 	 */
562 	public void setReferenceMap(ReferenceMapInterface referenceMap)
563 	{
564 		this.referenceMap = referenceMap;
565 	}
566 
567 	/***
568 	 * @see nl.javel.gisbeans.map.MapInterface#setUnits(int)
569 	 */
570 	public void setUnits(int units)
571 	{
572 		this.units = units;
573 	}
574 
575 	/***
576 	 * @see nl.javel.gisbeans.map.MapInterface#zoom(double)
577 	 */
578 	public void zoom(double zoomFactor)
579 	{
580 		if (zoomFactor == 0)
581 		{
582 			zoomFactor = 1;
583 		}
584 
585 		double maxX = (getUnitImageRatio() * this.getImage().getSize()
586 				.getWidth())
587 				+ this.extent.getMinX();
588 		double maxY = (getUnitImageRatio() * this.getImage().getSize()
589 				.getHeight())
590 				+ this.extent.getMinY();
591 
592 		double centerX = (maxX - this.extent.getMinX()) / 2
593 				+ this.extent.getMinX();
594 		double centerY = (maxY - this.extent.getMinY()) / 2
595 				+ this.extent.getMinY();
596 
597 		double width = (1.0 / zoomFactor) * (maxX - this.extent.getMinX());
598 		double height = (1.0 / zoomFactor) * (maxY - this.extent.getMinY());
599 
600 		this.extent = new Rectangle2D.Double(centerX - 0.5 * width, centerY
601 				- 0.5 * height, width, height);
602 	}
603 
604 	/***
605 	 * @see nl.javel.gisbeans.map.MapInterface #zoomPoint(java.awt.geom.Point2D,
606 	 *      double)
607 	 */
608 	public void zoomPoint(Point2D pixelPosition, double zoomFactor)
609 	{
610 		if (zoomFactor == 0)
611 			zoomFactor = 1;
612 
613 		double maxX = (getUnitImageRatio() * this.getImage().getSize()
614 				.getWidth())
615 				+ this.extent.getMinX();
616 		double maxY = (getUnitImageRatio() * this.getImage().getSize()
617 				.getHeight())
618 				+ this.extent.getMinY();
619 
620 		double centerX = (pixelPosition.getX() / this.getImage().getSize()
621 				.getWidth())
622 				* (maxX - this.extent.getMinX()) + this.extent.getMinX();
623 		double centerY = maxY
624 				- (pixelPosition.getY() / this.getImage().getSize().getHeight())
625 				* (maxY - this.extent.getMinY());
626 
627 		double width = (1.0 / zoomFactor) * (maxX - this.extent.getMinX());
628 		double height = (1.0 / zoomFactor)
629 				* (maxY - this.getExtent().getMinY());
630 
631 		this.extent = new Rectangle2D.Double(centerX - 0.5 * width, centerY
632 				- 0.5 * height, width, height);
633 	}
634 
635 	/***
636 	 * @see nl.javel.gisbeans.map.MapInterface
637 	 *      #zoomRectangle(nl.javel.gisbeans.geom.SerializableRectangle2D)
638 	 */
639 	public void zoomRectangle(SerializableRectangle2D rectangle)
640 	{
641 
642 		double maxX = (getUnitImageRatio() * this.getImage().getSize()
643 				.getWidth())
644 				+ this.extent.getMinX();
645 		double maxY = (getUnitImageRatio() * this.getImage().getSize()
646 				.getHeight())
647 				+ this.extent.getMinY();
648 
649 		double width = maxX - this.extent.getMinX();
650 		double height = maxY - this.extent.getMinY();
651 
652 		double minX = this.extent.getMinX()
653 				+ (rectangle.getMinX() / this.getImage().getSize().getWidth())
654 				* width;
655 		double minY = this.extent.getMinY()
656 				+ ((this.getImage().getSize().getHeight() - rectangle.getMaxY()) / this
657 						.getImage().getSize().getHeight()) * height;
658 
659 		maxX = minX
660 				+ (rectangle.getWidth() / this.getImage().getSize().getWidth())
661 				* width;
662 		maxY = minY
663 				+ ((this.getImage().getSize().getHeight() - rectangle
664 						.getHeight()) / this.getImage().getSize().getHeight())
665 				* height;
666 		this.extent = new Rectangle2D.Double(minX, minY, (maxX - minX),
667 				(maxY - minY));
668 	}
669 }