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
129 graphics.setColor(this.getImage().getBackgroundColor());
130 graphics.fillRect(0, 0, (int) this.getImage().getSize().getWidth(),
131 (int) this.getImage().getSize().getHeight());
132
133
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
151 double scale = this.getScale();
152
153
154 graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
155 RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
156
157
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 }