1 package org.simantics.district.network.ui.nodes;
3 import java.awt.geom.AffineTransform;
4 import java.awt.geom.Path2D;
5 import java.awt.geom.PathIterator;
6 import java.awt.geom.Point2D;
7 import java.awt.geom.Rectangle2D;
9 import org.simantics.district.network.ModelledCRS;
10 import org.simantics.maps.MapScalingTransform;
11 import org.simantics.scenegraph.utils.GeometryUtils;
13 import gnu.trove.list.array.TDoubleArrayList;
15 public class DistrictNetworkNodeUtils {
17 public static ThreadLocal<AffineTransform> sharedTransform = new ThreadLocal<AffineTransform>() {
18 protected AffineTransform initialValue() {
19 return new AffineTransform();
23 public static Rectangle2D calculateDrawnGeometry(Point2D p, Rectangle2D margin, Rectangle2D result, double scaleRecip) {
25 result = new Rectangle2D.Double();
26 double mw = margin.getWidth();
27 double mh = margin.getHeight();
28 result.setFrame(p.getX() - (mw / 2 * scaleRecip), p.getY() - (mh / 2 * scaleRecip), mw * scaleRecip, mh * scaleRecip);
32 public static Point2D calculatePoint2D(Point2D point, Point2D result) {
33 double x = ModelledCRS.longitudeToX(point.getX());
34 double y = ModelledCRS.latitudeToY(-point.getY()); // Inverse because Simantics Diagram is inverted
36 result = new Point2D.Double(x, y);
38 result.setLocation(x, y);
42 public static AffineTransform getTransformToRectangle(Rectangle2D toDraw, AffineTransform transform) {
43 if (transform == null)
44 transform = new AffineTransform();
46 transform.setTransform(toDraw.getWidth(), 0.0, 0.0, toDraw.getHeight(), toDraw.getCenterX(), toDraw.getCenterY());
50 public static double calculateScaleRecip(AffineTransform tr) {
51 int zoomLevel = MapScalingTransform.zoomLevel(tr);
52 return 1.0 / (getScale(tr) * Math.sqrt(zoomLevel));
55 static double getScale(AffineTransform tr) {
57 scale = GeometryUtils.getScale(tr);
58 scale = Math.max(4096, scale); //Math.min(scale, 32768));
63 * Finds the longest line segment from the provided <code>path</code> and sets
64 * <code>centerPoint</code> to the middle of that line and
65 * <code>direction</code> as the normalized direction vector of that line
69 * If the path has no points, both <code>centerPoint</code> and
70 * <code>direction</code> are set to ({@link Double#NaN}, {@link Double#NaN}).
71 * If the path has only one point then <code>centerPoint</code> is set to that
72 * single point and <code>direction</code> is set to <code>(1,0)</code>.
74 * @param path the path to process
75 * @param centerPoint point for writing the output center point
76 * @param direction point for writing the output direction vector
77 * @return the amount of points in the path
79 public static int calculateCenterPointAndDirection(Path2D path, Point2D centerPoint, Point2D direction) {
80 PathIterator pi = path.getPathIterator(null);
81 TDoubleArrayList segments = new TDoubleArrayList(20);
82 double[] tmp = new double[6];
83 while (!pi.isDone()) {
84 pi.currentSegment(tmp);
91 int segCount = segments.size();
93 centerPoint.setLocation(Double.NaN, Double.NaN);
94 direction.setLocation(Double.NaN, Double.NaN);
96 } else if (segCount == 2) {
97 centerPoint.setLocation(segments.getQuick(0), segments.getQuick(1));
98 direction.setLocation(1, 0);
103 double distance = -Double.MAX_VALUE;
104 for (int i = 2; i < segCount; i += 2) {
105 double dx = segments.getQuick(i) - segments.getQuick(i-2);
106 double dy = segments.getQuick(i+1) - segments.getQuick(i-1);
108 double d = dx * dx + dy * dy;
115 double x0 = segments.getQuick(longest - 2);
116 double y0 = segments.getQuick(longest - 1);
117 double x1 = segments.getQuick(longest);
118 double y1 = segments.getQuick(longest + 1);
120 distance = Math.sqrt(distance);
121 centerPoint.setLocation((x0 + x1) / 2, (y0 + y1) / 2);
122 direction.setLocation((x1 - x0) / distance, (y1 - y0) / distance);