]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/gui/map/ScaleBar.java
3f3f848ee505f55938b88a7d121d644d705d37b0
[GpsPrune.git] / tim / prune / gui / map / ScaleBar.java
1 package tim.prune.gui.map;
2
3 import java.awt.Color;
4 import java.awt.Dimension;
5 import java.awt.Graphics;
6 import javax.swing.JPanel;
7
8 import tim.prune.I18nManager;
9 import tim.prune.config.ColourScheme;
10 import tim.prune.config.Config;
11
12 /**
13  * Class to show a scale bar on the main map of GpsPrune
14  */
15 public class ScaleBar extends JPanel
16 {
17         /** zoom level */
18         private int _zoomLevel = -1;
19         /** y position */
20         private double _yPos = 0.0;
21
22         // Dimensions
23         /** Offset from left side in pixels */
24         private static final int LEFT_OFFSET = 20;
25         /** Offset from top in pixels */
26         private static final int Y_OFFSET = 10;
27         /** Tick height in pixels */
28         private static final int TICK_HEIGHT = 5;
29         /** Margin between bar and end text in pixels */
30         private static final int MARGIN_WIDTH = 8;
31
32         /** scales for each zoom level */
33         private static final int[] _scales = {10000, 5000, 2000, 2000, 1000, 500, 200, 100,
34                 50, 20, 10, 5, 2, 2, 1,
35                 -2, -5, -10, -20, -50, -100, -200};
36         /** pixel counts for each zoom level (metric) */
37         private static final double[] _metricPixels = {64, 64, 51, 102, 102, 102, 81, 81,
38                 81, 65, 65, 65, 52, 105, 105,
39                 105, 83, 83, 83, 67, 67, 67};
40
41
42         /**
43          * Constructor
44          */
45         public ScaleBar()
46         {
47                 super();
48                 setOpaque(false);
49                 setPreferredSize(new Dimension(100, 20));
50         }
51
52         /**
53          * Paint method to override display
54          * @param inG graphics object
55          */
56         public void paint(Graphics inG)
57         {
58                 super.paint(inG);
59                 if (_zoomLevel > -1)
60                 {
61                         try {
62                                 boolean useMetric = Config.getConfigBoolean(Config.KEY_METRIC_UNITS);
63                                 double drightSide = LEFT_OFFSET + _metricPixels[_zoomLevel] * (useMetric?1:1.609);
64                                 int scale = _scales[_zoomLevel];
65
66                                 // work out cos(latitude) from y position, and apply to scale
67                                 final double angle = Math.PI * (1 - 2*_yPos);
68                                 final double lat = Math.atan(Math.sinh(angle));
69                                 final double cosLat = Math.cos(lat);
70                                 int rightSide = (int) (drightSide / cosLat);
71                                 // Adjust if scale is too large
72                                 while (rightSide > 300)
73                                 {
74                                         rightSide /= 2;
75                                         scale /= 2;
76                                         // Abort if scale is now less than 1 unit (shouldn't ever be)
77                                         if (scale < 1) {return;}
78                                 }
79                                 // Abort if scale is negative (around poles)
80                                 if (rightSide < 1) {return;}
81
82                                 // Determine colours to use
83                                 Color barColour = Config.getColourScheme().getColour(ColourScheme.IDX_TEXT);
84                                 Color blankColour = new Color(255-barColour.getRed(), 255-barColour.getGreen(), 255-barColour.getBlue());
85                                 // Should this blank colour be set to saturation zero?
86                                 // Draw blank bars behind
87                                 inG.setColor(blankColour);
88                                 inG.drawLine(LEFT_OFFSET, Y_OFFSET-1, rightSide+2, Y_OFFSET-1);
89                                 inG.drawLine(LEFT_OFFSET, Y_OFFSET+2, rightSide+2, Y_OFFSET+2);
90                                 inG.drawLine(LEFT_OFFSET-1, Y_OFFSET+2, LEFT_OFFSET-1, Y_OFFSET-TICK_HEIGHT);
91                                 inG.drawLine(LEFT_OFFSET+2, Y_OFFSET+2, LEFT_OFFSET+2, Y_OFFSET-TICK_HEIGHT);
92                                 inG.drawLine(rightSide-1, Y_OFFSET+2, rightSide-1, Y_OFFSET-TICK_HEIGHT);
93                                 inG.drawLine(rightSide+2, Y_OFFSET+2, rightSide+2, Y_OFFSET-TICK_HEIGHT);
94                                 // horizontal
95                                 inG.setColor(barColour);
96                                 inG.drawLine(LEFT_OFFSET, Y_OFFSET, rightSide, Y_OFFSET);
97                                 inG.drawLine(LEFT_OFFSET, Y_OFFSET+1, rightSide, Y_OFFSET+1);
98                                 // 0 tick
99                                 inG.drawLine(LEFT_OFFSET, Y_OFFSET, LEFT_OFFSET, Y_OFFSET-TICK_HEIGHT);
100                                 inG.drawLine(LEFT_OFFSET+1, Y_OFFSET, LEFT_OFFSET+1, Y_OFFSET-TICK_HEIGHT);
101                                 // end tick
102                                 inG.drawLine(rightSide, Y_OFFSET+1, rightSide, Y_OFFSET-TICK_HEIGHT);
103                                 inG.drawLine(rightSide+1, Y_OFFSET+1, rightSide+1, Y_OFFSET-TICK_HEIGHT);
104                                 // text
105                                 String text = getScaleText(scale, useMetric);
106                                 inG.setColor(blankColour);
107                                 inG.drawString(text, rightSide+MARGIN_WIDTH-1, Y_OFFSET);
108                                 inG.drawString(text, rightSide+MARGIN_WIDTH+1, Y_OFFSET);
109                                 inG.drawString(text, rightSide+MARGIN_WIDTH, Y_OFFSET-1);
110                                 inG.drawString(text, rightSide+MARGIN_WIDTH, Y_OFFSET+1);
111                                 inG.setColor(barColour);
112                                 inG.drawString(text, rightSide+MARGIN_WIDTH, Y_OFFSET);
113                         }
114                         catch (ArrayIndexOutOfBoundsException ai) {}
115                 }
116         }
117
118         /**
119          * Get the scale text for the given scale
120          * @param inScale scale number
121          * @param inUseMetric true to use km/m, false for miles/ft
122          * @return scale text as string
123          */
124         private static String getScaleText(int inScale, boolean inUseMetric)
125         {
126                 if (inScale > 0) {
127                         // Positive scale means km or miles
128                         return "" + inScale     + " " +
129                                 I18nManager.getText(inUseMetric?"units.kilometres.short":"units.miles.short");
130                 }
131                 if (inUseMetric) {
132                         // negative scale means m
133                         return "" + (-1000 / inScale) + " " + I18nManager.getText("units.metres.short");
134                 }
135                 // fallen through to feet
136                 return "" + (-5280 / inScale) + " " + I18nManager.getText("units.feet.short");
137         }
138
139         /**
140          * Update the scale level
141          * @param inZoom new zoom level
142          * @param inYPos y position, where 0 is north pole, 1 is south pole
143          */
144         public void updateScale(int inZoom, double inYPos)
145         {
146                 _zoomLevel = inZoom;
147                 _yPos = inYPos;
148         }
149 }