View Javadoc
1   package fr.ifremer.dali.ui.swing.util.map.layer;
2   
3   /*-
4    * #%L
5    * Dali :: UI
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2014 - 2017 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU Affero General Public License as published by
13   * the Free Software Foundation, either version 3 of the License, or
14   * (at your option) any later version.
15   * 
16   * This program is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU General Public License for more details.
20   * 
21   * You should have received a copy of the GNU Affero General Public License
22   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23   * #L%
24   */
25  
26  import fr.ifremer.dali.dto.DaliBeans;
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.geotools.geometry.jts.ReferencedEnvelope;
30  import org.geotools.map.DirectLayer;
31  import org.geotools.map.MapContent;
32  import org.geotools.map.MapViewport;
33  import org.geotools.renderer.lite.RendererUtilities;
34  
35  import java.awt.BasicStroke;
36  import java.awt.Color;
37  import java.awt.FontMetrics;
38  import java.awt.Graphics2D;
39  import java.awt.geom.Rectangle2D;
40  
41  /**
42   * A layer drawing the scale on map in miles ans meters
43   *
44   * @author peck7 on 13/06/2017.
45   */
46  public class ScaleLayer extends DirectLayer {
47  
48      private static final Log log = LogFactory.getLog(ScaleLayer.class);
49  
50      private static final int MARGIN = 10;
51      private static final int SCALE_HEIGHT = 10;
52      private static final int SCALE_WIDTH_MAX = 200;
53  
54      private static final int METERS_BY_MILES = 1852;
55  
56      private int mileScaleWidth;
57      private int meterScaleWidth;
58  
59      private String mileLabelScaleUp;
60      private String meterLabelScaleUp;
61  
62      public ScaleLayer() {
63          setTitle("scaleLayer");
64      }
65  
66      @Override
67      public void draw(Graphics2D graphics, MapContent map, MapViewport viewport) {
68          if (viewport == null) {
69              viewport = map.getViewport(); // use the map viewport if one has not been provided
70          }
71          if (viewport == null || viewport.getScreenArea() == null) {
72              return; // renderer is not set up for use yet
73          }
74  
75          int viewWidth = graphics.getClipBounds().width;
76          int viewHeight = graphics.getClipBounds().height;
77  
78          ReferencedEnvelope displayArea = viewport.getBounds();
79          // Round the envelope to prevent lat/long out of range (ex lat=90.00000000000001)
80          ReferencedEnvelope roundDisplayArea = new ReferencedEnvelope(
81                  DaliBeans.roundDouble(displayArea.getMinX(), 4),
82                  DaliBeans.roundDouble(displayArea.getMaxX(), 4),
83                  DaliBeans.roundDouble(displayArea.getMinY(), 4),
84                  DaliBeans.roundDouble(displayArea.getMaxY(), 4),
85                  displayArea.getCoordinateReferenceSystem());
86  
87          double dpi = 2.54 / 100; // pour avoir l'echélle en metre/pixel
88  
89          try {
90              double meterPerPixel = RendererUtilities.calculateScale(roundDisplayArea, viewWidth, viewHeight, dpi);
91              double maxWidthMeter = SCALE_WIDTH_MAX * meterPerPixel;
92              {
93                  // Mile scale
94                  double maxWidthMiles = maxWidthMeter / METERS_BY_MILES;
95                  int nbDigit = (int) Math.floor(Math.log10(maxWidthMiles));
96                  int firstDigit = (int) Math.floor(maxWidthMiles / Math.pow(10, nbDigit));  // le premier chiffre significatif
97                  int useFirstDigit;
98                  if (firstDigit >= 5) {
99                      useFirstDigit = 5;
100                 } else if (firstDigit >= 2) {
101                     useFirstDigit = 2;
102                 } else {
103                     useFirstDigit = 1;
104                 }
105                 long scaleInMiles = useFirstDigit * (long) Math.pow(10, nbDigit);
106                 mileScaleWidth = (int) Math.round(scaleInMiles * METERS_BY_MILES / meterPerPixel);
107                 mileLabelScaleUp = String.format("%,d " + "milles", scaleInMiles);
108             }
109             {
110                 // Meter scale
111                 int nbDigit = (int) Math.floor(Math.log10(maxWidthMeter));
112                 int firstDigit = (int) Math.floor(maxWidthMeter / Math.pow(10, nbDigit));  // le premier chiffre significatif
113                 int useFirstDigit;
114                 if (firstDigit >= 5) {
115                     useFirstDigit = 5;
116                 } else if (firstDigit >= 2) {
117                     useFirstDigit = 2;
118                 } else {
119                     useFirstDigit = 1;
120                 }
121                 long scaleInMeter = useFirstDigit * (long) Math.pow(10, nbDigit);
122                 meterScaleWidth = (int) Math.round(scaleInMeter / meterPerPixel);
123                 meterLabelScaleUp = String.format("%,d " + "meters", scaleInMeter);
124             }
125 
126         } catch (Exception e) {
127             if (log.isErrorEnabled()) {
128                 log.error("error", e);
129             }
130         }
131 
132         graphics.setColor(Color.BLACK);
133         graphics.setStroke(new BasicStroke());
134         FontMetrics fm = graphics.getFontMetrics();
135 
136         {
137             // Draw Mile scale
138             Rectangle2D textArea = fm.getStringBounds(mileLabelScaleUp, graphics);
139             int labelLeft = viewWidth - MARGIN * 2 - mileScaleWidth - (int) textArea.getWidth();
140             graphics.drawString(mileLabelScaleUp, labelLeft, viewHeight - MARGIN);
141             int scalesEndX = viewWidth - MARGIN;
142             int scaleStartX = scalesEndX - mileScaleWidth;
143             int scalesEndY = viewHeight - MARGIN;
144             int scaleStartY = scalesEndY - SCALE_HEIGHT;
145 
146             graphics.drawLine(scaleStartX, scaleStartY, scaleStartX, scalesEndY);
147             graphics.drawLine(scaleStartX, scalesEndY, scalesEndX, scalesEndY);
148             graphics.drawLine(scalesEndX, scalesEndY, scalesEndX, scaleStartY);
149         }
150 
151         {
152             // Draw Meter scale
153             Rectangle2D textArea = fm.getStringBounds(meterLabelScaleUp, graphics);
154             int offsetHeight = (int) (textArea.getHeight());
155             int labelLeft = viewWidth - MARGIN * 2 - meterScaleWidth - (int) textArea.getWidth();
156             graphics.drawString(meterLabelScaleUp, labelLeft, viewHeight - MARGIN - offsetHeight);
157             int scalesEndX = viewWidth - MARGIN;
158             int scaleStartX = scalesEndX - meterScaleWidth;
159             int scalesEndY = viewHeight - MARGIN - offsetHeight;
160             int scaleStartY = scalesEndY - SCALE_HEIGHT;
161 
162             graphics.drawLine(scaleStartX, scaleStartY, scaleStartX, scalesEndY);
163             graphics.drawLine(scaleStartX, scalesEndY, scalesEndX, scalesEndY);
164             graphics.drawLine(scalesEndX, scalesEndY, scalesEndX, scaleStartY);
165         }
166 
167 
168     }
169 
170     @Override
171     public ReferencedEnvelope getBounds() {
172         return null;
173     }
174 }