1 package org.simantics.maps.sg;
3 import java.awt.AlphaComposite;
4 import java.awt.BasicStroke;
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;
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;
20 public class MapLocationZoomInfoNode extends G2DNode {
22 private static final long serialVersionUID = 7994492218791569147L;
24 private static final Color GRAY = new Color(100, 100, 100);
26 protected boolean enabled = true;
28 private MouseUtil util;
31 public void render(Graphics2D g2d) {
35 AffineTransform ot = g2d.getTransform();
36 Color originalColor = g2d.getColor();
37 g2d.transform(transform);
39 AffineTransform tr = g2d.getTransform();
41 g2d.setTransform(new AffineTransform());
42 // do the rendering magic
44 Font rulerFont = new Font("Tahoma", Font.PLAIN, DPIUtil.upscale(9));
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));
50 Rectangle2D bounds = g2d.getClipBounds();
54 int zoomLevel = MapScalingTransform.zoomLevel(ot);
55 MouseInfo mouseInfo = util.getMouseInfo(0);
59 if (mouseInfo != null && mouseInfo.canvasPosition != null) {
60 Point2D canvasPosition = mouseInfo.canvasPosition;
61 double cx = canvasPosition.getX();
62 double cy = canvasPosition.getY();
64 startLat = yToLatitude(-cy / transform.getScaleY());
65 startLon = xToLongitude(cx / transform.getScaleX());
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);
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));
83 Rectangle2D vertical = new Rectangle2D.Double(newScaleLeft, y, pixels, 20);
87 g2d.setFont(rulerFont);
90 g2d.setColor(Color.BLACK);
91 g2d.drawString(str, (int)newScaleLeft + 5, (int)y + 15);
93 g2d.setColor(originalColor);
98 public Rectangle2D getBoundsInLocal() {
102 public boolean isEnabled() {
106 public void setEnabled(boolean enabled) {
107 this.enabled = enabled;
110 public void setMouseUtil(MouseUtil util) {
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"
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)
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);
134 valueStr = valueStr.substring(0, trunc);
137 if (valueStr.charAt(trunc) != '0') {
138 valueStr = valueStr.substring(0, trunc + 1);
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('.');
148 valueStr = valueStr.substring(0, dotIndex);
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];
166 if (valueStr.equals("-0"))
172 // TODO: these only work with Spherical Mercator
173 private static double xToLongitude(double x) {
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);