]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.maps/src/org/simantics/maps/sg/MapLocationZoomInfoNode.java
9e027ecbbf27b535960a3574830b4fa480cb5b41
[simantics/district.git] / org.simantics.district.maps / src / org / simantics / maps / sg / MapLocationZoomInfoNode.java
1 package org.simantics.maps.sg;
2
3 import java.awt.AlphaComposite;
4 import java.awt.BasicStroke;
5 import java.awt.Color;
6 import java.awt.Font;
7 import java.awt.FontMetrics;
8 import java.awt.Graphics2D;
9 import java.awt.geom.AffineTransform;
10 import java.awt.geom.Point2D;
11 import java.awt.geom.Rectangle2D;
12 import java.util.Locale;
13
14 import org.simantics.g2d.participant.MouseUtil;
15 import org.simantics.g2d.participant.MouseUtil.MouseInfo;
16 import org.simantics.maps.MapScalingTransform;
17 import org.simantics.scenegraph.g2d.G2DNode;
18 import org.simantics.scenegraph.utils.DPIUtil;
19
20 public class MapLocationZoomInfoNode extends G2DNode {
21
22     private static final long serialVersionUID = 7994492218791569147L;
23
24     private static final Color GRAY              = new Color(100, 100, 100);
25
26     protected boolean enabled = true;
27
28     private MouseUtil util;
29     
30     @Override
31     public void render(Graphics2D g2d) {
32         if (!enabled)
33             return;
34         
35         AffineTransform ot = g2d.getTransform();
36         Color originalColor = g2d.getColor();
37         g2d.transform(transform);
38         
39         AffineTransform tr = g2d.getTransform();
40         
41         g2d.setTransform(new AffineTransform());
42         // do the rendering magic
43         
44         Font rulerFont = new Font("Tahoma", Font.PLAIN, DPIUtil.upscale(9));
45         
46         //g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
47         g2d.setStroke(new BasicStroke(1));
48         g2d.setColor(new Color(0.9f, 0.9f, 0.9f, 0.75f));
49         
50         Rectangle2D bounds = g2d.getClipBounds();
51         if (bounds == null)
52             return; // FIXME
53
54         int zoomLevel = MapScalingTransform.zoomLevel(ot);
55         MouseInfo mouseInfo = util.getMouseInfo(0);
56         
57         double startLat;
58         double startLon;
59         if (mouseInfo != null && mouseInfo.canvasPosition != null) {
60             Point2D canvasPosition = mouseInfo.canvasPosition;
61             double cx = canvasPosition.getX();
62             double cy = canvasPosition.getY();
63             
64             startLat = yToLatitude(-cy / transform.getScaleY());
65             startLon = xToLongitude(cx / transform.getScaleX());
66         } else {
67             startLat = 0;
68             startLon = 0;
69         }
70         
71         String str = "X: " + formatValue(startLon, MAX_DIGITS) + ", Y: " + formatValue(startLat, MAX_DIGITS) + ", Z: " + zoomLevel;
72         g2d.setFont(rulerFont);
73         FontMetrics fm = g2d.getFontMetrics();
74         Rectangle2D r = fm.getStringBounds(str, g2d);
75
76         double pixels = r.getWidth() + 10;
77         double scaleRight = bounds.getMaxX() - 20;
78         double newScaleLeft = scaleRight - pixels;
79         double y = bounds.getMaxY() - 65;
80         g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f));
81         
82         
83         Rectangle2D vertical = new Rectangle2D.Double(newScaleLeft, y, pixels, 20);
84         g2d.fill(vertical);
85         
86         g2d.setColor(GRAY);
87         g2d.setFont(rulerFont);
88         
89         
90         g2d.setColor(Color.BLACK);
91         g2d.drawString(str, (int)newScaleLeft + 5, (int)y + 15);
92         
93         g2d.setColor(originalColor);
94         g2d.setTransform(ot);
95     }
96
97     @Override
98     public Rectangle2D getBoundsInLocal() {
99         return null;
100     }
101
102     public boolean isEnabled() {
103         return enabled;
104     }
105
106     public void setEnabled(boolean enabled) {
107         this.enabled = enabled;
108     }
109
110     public void setMouseUtil(MouseUtil util) {
111         this.util = util;
112     }
113
114     private static final transient int    MAX_DIGITS = 7;
115     private static final transient double EPSILON    = 0.01;
116     private static final transient double TRIM_THRESHOLD_MAX_VALUE = Math.pow(10, 4);
117     private static final transient String[] SI_UNIT_LARGE_PREFIXES = {
118         "k", "M", "G", "T", "P", "E", "Z", "Y"
119     };
120
121     private static String formatValue(double value, int maxDigits) {
122         int magnitude = (int) Math.round(Math.log10(value));
123         //System.out.println("magnitude: " + magnitude + ", " + value);
124         int allowedDecimals = maxDigits;
125         allowedDecimals -= Math.abs(magnitude);
126         if (allowedDecimals < 0)
127             allowedDecimals = 0;
128
129         String valueStr = String.format(Locale.US, "%." + allowedDecimals + "f", value);
130         if (allowedDecimals > 0) {
131             for (int trunc = valueStr.length() - 1; trunc > 0; --trunc) {
132                 char ch = valueStr.charAt(trunc);
133                 if (ch == '.') {
134                     valueStr = valueStr.substring(0, trunc);
135                     break;
136                 }
137                 if (valueStr.charAt(trunc) != '0') {
138                     valueStr = valueStr.substring(0, trunc + 1);
139                     break;
140                 }
141             }
142             if (Math.abs(value) + EPSILON > TRIM_THRESHOLD_MAX_VALUE) {
143                 // Cut anything beyond a possible decimal dot out since they
144                 // should not show anyway. This is a complete hack that tries to
145                 // circumvent floating-point inaccuracy problems.
146                 int dotIndex = valueStr.lastIndexOf('.');
147                 if (dotIndex > -1) {
148                     valueStr = valueStr.substring(0, dotIndex);
149                 }
150             }
151         }
152
153         double trimValue = value;
154         if (Math.abs(value)+EPSILON >= TRIM_THRESHOLD_MAX_VALUE) {
155             for (int i = 0; Math.abs(trimValue)+EPSILON >= TRIM_THRESHOLD_MAX_VALUE; ++i) {
156                 double trim = trimValue / 1000;
157                 if (Math.abs(trim)-EPSILON < TRIM_THRESHOLD_MAX_VALUE) {
158                     valueStr = valueStr.substring(0, valueStr.length() - (i + 1) * 3);
159                     valueStr += SI_UNIT_LARGE_PREFIXES[i];
160                     break;
161                 }
162                 trimValue = trim;
163             }
164         }
165
166         if (valueStr.equals("-0"))
167             valueStr = "0";
168
169         return valueStr;
170     }
171
172     // TODO: these only work with Spherical Mercator
173     private static double xToLongitude(double x) {
174         return x;
175     }
176
177     private static double yToLatitude(double y) {
178         double rad = Math.toRadians(y);
179         double sinh = Math.sinh(rad);
180         double atan = Math.atan(sinh);
181         double finald = Math.toDegrees(atan);
182         return finald;
183     }
184 }