package org.simantics.district.network.ui.nodes; import java.awt.geom.AffineTransform; import java.awt.geom.Path2D; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import org.simantics.district.network.ModelledCRS; import org.simantics.maps.MapScalingTransform; import org.simantics.scenegraph.utils.GeometryUtils; import gnu.trove.list.array.TDoubleArrayList; public class DistrictNetworkNodeUtils { public static ThreadLocal sharedTransform = new ThreadLocal() { protected AffineTransform initialValue() { return new AffineTransform(); } }; public static Rectangle2D calculateDrawnGeometry(Point2D p, Rectangle2D margin, Rectangle2D result, double scaleRecip) { if (result == null) result = new Rectangle2D.Double(); double mw = margin.getWidth(); double mh = margin.getHeight(); result.setFrame(p.getX() - (mw / 2 * scaleRecip), p.getY() - (mh / 2 * scaleRecip), mw * scaleRecip, mh * scaleRecip); return result; } public static Point2D calculatePoint2D(Point2D point, Point2D result) { double x = ModelledCRS.longitudeToX(point.getX()); double y = ModelledCRS.latitudeToY(-point.getY()); // Inverse because Simantics Diagram is inverted if (result == null) result = new Point2D.Double(x, y); else result.setLocation(x, y); return result; } public static AffineTransform getTransformToRectangle(Rectangle2D toDraw, AffineTransform transform) { if (transform == null) transform = new AffineTransform(); transform.setTransform(toDraw.getWidth(), 0.0, 0.0, toDraw.getHeight(), toDraw.getCenterX(), toDraw.getCenterY()); return transform; } public static double calculateScaleRecip(AffineTransform tr) { int zoomLevel = MapScalingTransform.zoomLevel(tr); if (zoomLevel == 0) zoomLevel = 1; return 1.0 / (getScale(tr) * Math.sqrt(zoomLevel)); } static double getScale(AffineTransform tr) { double scale; scale = GeometryUtils.getScale(tr); scale = Math.max(4096, scale); //Math.min(scale, 32768)); return scale; } /** * Finds the longest line segment from the provided path and sets * centerPoint to the middle of that line and * direction as the normalized direction vector of that line * segment. * *

* If the path has no points, both centerPoint and * direction are set to ({@link Double#NaN}, {@link Double#NaN}). * If the path has only one point then centerPoint is set to that * single point and direction is set to (1,0). * * @param path the path to process * @param centerPoint point for writing the output center point * @param direction point for writing the output direction vector * @return the amount of points in the path */ public static int calculateCenterPointAndDirection(Path2D path, Point2D centerPoint, Point2D direction) { PathIterator pi = path.getPathIterator(null); TDoubleArrayList segments = new TDoubleArrayList(20); double[] tmp = new double[6]; while (!pi.isDone()) { pi.currentSegment(tmp); segments.add(tmp[0]); segments.add(tmp[1]); pi.next(); } // Cover corner cases int segCount = segments.size(); if (segCount == 0) { centerPoint.setLocation(Double.NaN, Double.NaN); direction.setLocation(Double.NaN, Double.NaN); return 0; } else if (segCount == 2) { centerPoint.setLocation(segments.getQuick(0), segments.getQuick(1)); direction.setLocation(1, 0); return 1; } int longest = 2; double distance = -Double.MAX_VALUE; for (int i = 2; i < segCount; i += 2) { double dx = segments.getQuick(i) - segments.getQuick(i-2); double dy = segments.getQuick(i+1) - segments.getQuick(i-1); double d = dx * dx + dy * dy; if (d > distance) { distance = d; longest = i; } } double x0 = segments.getQuick(longest - 2); double y0 = segments.getQuick(longest - 1); double x1 = segments.getQuick(longest); double y1 = segments.getQuick(longest + 1); distance = Math.sqrt(distance); centerPoint.setLocation((x0 + x1) / 2, (y0 + y1) / 2); direction.setLocation((x1 - x0) / distance, (y1 - y0) / distance); return segCount / 2; } }