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