From: jsimomaa Date: Thu, 28 Feb 2019 07:11:50 +0000 (+0200) Subject: Refactoring MapNode rendering & zooming to even zoom levels (0-20) X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fdistrict.git;a=commitdiff_plain;h=835710a4f22ec2d91c287295fb176a0af62d1186 Refactoring MapNode rendering & zooming to even zoom levels (0-20) * With this change the map background bitmap-images are always sharp and not blurred on e.g. zooming level 5.42 which was previously possible gitlab #32 Change-Id: I1fd84ef25154f454efbff0b0195c447d90bd30fd --- diff --git a/org.simantics.district.maps/src/org/simantics/maps/MapScalingTransform.java b/org.simantics.district.maps/src/org/simantics/maps/MapScalingTransform.java index f64a99f4..e29e8e55 100644 --- a/org.simantics.district.maps/src/org/simantics/maps/MapScalingTransform.java +++ b/org.simantics.district.maps/src/org/simantics/maps/MapScalingTransform.java @@ -6,8 +6,8 @@ public class MapScalingTransform { private MapScalingTransform() { } - - public static final AffineTransform INSTANCE = new AffineTransform(10000, 0, 0, 10000, 0, 0); + public static final double scale = 256.0d / 360.0d; + public static final AffineTransform INSTANCE = new AffineTransform(scale, 0, 0, scale, 0, 0); public static double getScaleX() { return INSTANCE.getScaleX(); @@ -16,4 +16,15 @@ public class MapScalingTransform { public static double getScaleY() { return INSTANCE.getScaleY(); } + + public static int zoomLevel(AffineTransform current) { + double org = INSTANCE.getScaleX(); + double cur = current.getScaleX(); + double f = cur / org; + double zoomLevel = Math.log10(f) / Math.log10(2); + if (zoomLevel < 0) { + zoomLevel = 0; + } + return (int) zoomLevel; + } } diff --git a/org.simantics.district.maps/src/org/simantics/maps/eclipse/MapPainter.java b/org.simantics.district.maps/src/org/simantics/maps/eclipse/MapPainter.java index 85398221..c519b9a5 100644 --- a/org.simantics.district.maps/src/org/simantics/maps/eclipse/MapPainter.java +++ b/org.simantics.district.maps/src/org/simantics/maps/eclipse/MapPainter.java @@ -138,6 +138,7 @@ public class MapPainter extends AbstractCanvasParticipant { protected void updateNode() { node.setEnabled(isPaintingEnabled()); + node.setEnabled(isMapEnabled()); node.setBackgroundColor(getBackgroundColor()); } diff --git a/org.simantics.district.maps/src/org/simantics/maps/sg/MapNode.java b/org.simantics.district.maps/src/org/simantics/maps/sg/MapNode.java index f9c6abf9..7ca092cf 100644 --- a/org.simantics.district.maps/src/org/simantics/maps/sg/MapNode.java +++ b/org.simantics.district.maps/src/org/simantics/maps/sg/MapNode.java @@ -36,6 +36,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import org.simantics.maps.MapScalingTransform; import org.simantics.maps.WebService; import org.simantics.maps.osm.OSMTileProvider; import org.simantics.maps.pojo.TileJobQueue; @@ -233,14 +234,16 @@ public class MapNode extends G2DNode implements ITileListener { AffineTransform ot = g2d.getTransform(); + //System.err.println("ot " + ot); g2d.transform(transform); AffineTransform tr = g2d.getTransform(); - + //System.err.println("tr " + tr); // Graphics2D g = (Graphics2D)g2d.create(); // AffineTransform tr = (AffineTransform)g.getTransform().clone(); double scaleX = Math.abs(tr.getScaleX()); + //System.err.println("scaleX : " + scaleX); double scaleY = Math.abs(tr.getScaleY()); if (scaleX <= 0 || scaleY <= 0) { // Make sure that we don't end up in an eternal loop below. @@ -255,20 +258,21 @@ public class MapNode extends G2DNode implements ITileListener { Rectangle2D b = (Rectangle2D)((Rectangle)g2d.getRenderingHint(G2DRenderingHints.KEY_CONTROL_BOUNDS)).getBounds2D(); // getClipBounds is not accurate enough, use original clipbounds and scale here Rectangle2D viewbox = new Rectangle2D.Double(offsetX/scaleX, offsetY/scaleY, b.getWidth()/sp.getWidth(), b.getHeight()/sp.getHeight()); //g.getClipBounds(); - if (enabled) { - - double smallerViewboxDimension = viewbox.getWidth() < viewbox.getHeight() ? viewbox.getWidth() * MAP_SCALE : viewbox.getHeight() * MAP_SCALE; - int level = 0; - double tileSize = 360 * MAP_SCALE*2; - while (level < MAX_TILE_LEVEL) { - double ratio = smallerViewboxDimension / tileSize; - if (ratio >= 0.85) { - break; - } - tileSize *= 0.5; - level++; - } + + int level = MapScalingTransform.zoomLevel(ot); + +// double smallerViewboxDimension = viewbox.getWidth() < viewbox.getHeight() ? viewbox.getWidth() * MAP_SCALE : viewbox.getHeight() * MAP_SCALE; +// int level = 0; +// double tileSize = 360 * MAP_SCALE*2.5; +// while (level < MAX_TILE_LEVEL) { +// double ratio = smallerViewboxDimension / tileSize; +// if (ratio >= 0.85) { +// break; +// } +// tileSize *= 0.5; +// level++; +// } /* * To convert y-coordinates to map coordinates in ruler, use: * double val = (y-offsetY)/scaleY; @@ -281,26 +285,31 @@ public class MapNode extends G2DNode implements ITileListener { double miny = Math.min(360, Math.max(viewbox.getMinY()+180, 0)); double maxy = Math.min(360, Math.max(viewbox.getMaxY()+180, 0)); - + //System.err.println("minx " + minx + " maxx " + maxx + " miny " + miny + " maxy " + maxy); g2d.setTransform(new AffineTransform()); g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); int levels = (1 << level); - + //System.err.println("level " + level); + //System.err.println("levels " + levels); // http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames int left = (int)Math.floor( (minx + 180) / 360 * (1<= levels) continue; - for(int ty = top; ty <= bottom; ty++) { - if(ty < 0 || ty >= levels) continue; + //System.err.println("tileSize " + tsx); + for (int tx = left; tx <= right; tx++) { + if (tx < 0 || tx >= levels) + continue; + for (int ty = top; ty <= bottom; ty++) { + if (ty < 0 || ty >= levels) + continue; TileKey tile = new TileKey(level, tx, ty); - double y = (double)ty - (double)levels/2; // In level 0 we have only one tile - paintTile(tileCache, g2d, tr, tile, tx*tsx-180, y*tsx, tsx); + double y = (double) ty - (double) levels / 2; // In level 0 we have only one tile + + paintTile(tileCache, g2d, tr, tile, tx * tsx - 180, y * tsx, tsx); } } // g.dispose(); diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/DistrictDiagramViewer.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/DistrictDiagramViewer.java index f0c76954..6175ace7 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/DistrictDiagramViewer.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/DistrictDiagramViewer.java @@ -1,6 +1,7 @@ package org.simantics.district.network.ui; import java.awt.Color; +import java.awt.geom.AffineTransform; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.Supplier; @@ -26,6 +27,7 @@ import org.simantics.g2d.participant.BackgroundPainter; import org.simantics.g2d.participant.GridPainter; import org.simantics.g2d.participant.PanZoomRotateHandler; import org.simantics.g2d.participant.RenderingQualityInteractor; +import org.simantics.g2d.participant.TransformUtil; import org.simantics.g2d.participant.ZoomToAreaHandler; import org.simantics.maps.MapScalingTransform; import org.simantics.maps.eclipse.MapPainter; @@ -48,9 +50,10 @@ public class DistrictDiagramViewer extends DiagramViewer { ctx.add(new ElementPainter()); ctx.add(new DNPointerInteractor()); - ctx.add(new MapPainter(MapScalingTransform.INSTANCE)); + AffineTransform tr = new AffineTransform(MapScalingTransform.INSTANCE); + ctx.add(new MapPainter(tr)); - ctx.add(new NetworkDrawingParticipant(MapScalingTransform.INSTANCE)); + ctx.add(new NetworkDrawingParticipant(tr)); } protected String getPopupId() { @@ -80,6 +83,11 @@ public class DistrictDiagramViewer extends DiagramViewer { } protected void addViewManipulationParticipants(CanvasContext ctx) { + // Let's replace with our special util + TransformUtil util = ctx.getAtMostOneItemOfClass(TransformUtil.class); + if (util != null) + ctx.remove(util); + ctx.add(new DistrictTransformUtil()); ctx.add(new DistrictPanZoomRotateHandler()); //ctx.add(new MousePanZoomInteractor()); //ctx.add(new MultitouchPanZoomRotateInteractor()); diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/DistrictPanZoomRotateHandler.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/DistrictPanZoomRotateHandler.java index 1a4f83d8..f9d9fccc 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/DistrictPanZoomRotateHandler.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/DistrictPanZoomRotateHandler.java @@ -1,23 +1,117 @@ package org.simantics.district.network.ui; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.util.Set; + +import org.simantics.g2d.canvas.ICanvasContext; +import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency; +import org.simantics.g2d.canvas.impl.DependencyReflection.Reference; +import org.simantics.g2d.diagram.participant.Selection; +import org.simantics.g2d.element.ElementUtils; +import org.simantics.g2d.element.IElement; +import org.simantics.g2d.participant.CanvasBoundsParticipant; import org.simantics.g2d.participant.PanZoomRotateHandler; +import org.simantics.maps.MapScalingTransform; +import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler; import org.simantics.scenegraph.g2d.events.MouseEvent.MouseWheelMovedEvent; +import org.simantics.scenegraph.g2d.events.command.Command; +import org.simantics.scenegraph.g2d.events.command.CommandEvent; +import org.simantics.scenegraph.g2d.events.command.Commands; import org.simantics.scenegraph.g2d.nodes.NavigationNode; public class DistrictPanZoomRotateHandler extends PanZoomRotateHandler { + public static final int DISTRICT_TRANSLATE_AMOUNT = 2; + + @Dependency DistrictTransformUtil util; + @Reference Selection selection; + public DistrictPanZoomRotateHandler() { } + + @Override + public void addedToContext(ICanvasContext ctx) { + super.addedToContext(ctx); + setHint(KEY_TRANSLATE_AMOUNT, DISTRICT_TRANSLATE_AMOUNT); + } @Override protected Class getNavigationNodeClass() { return DistrictNavigationNode.class; } + @Override + public double getTranslateAmount() { + return 15 * super.getTranslateAmount(); + } + + @Override + public double limitScaleFactor(double scaleFactor) { + return scaleFactor; + } + + @Override + @EventHandler(priority = 1) + public boolean handleEvent(CommandEvent e) { + super.update(); + Command c = e.command; + boolean zoomDisabled = Boolean.TRUE.equals(getHint(KEY_DISABLE_ZOOM)) ? true : false; + // custom handling of zoom to fit & selection + if (Commands.ZOOM_TO_FIT.equals(c) && !zoomDisabled) { + boolean result = zoomToFit(); + if (!result) + result = zoomToPage(); + return result; + } + if (Commands.ZOOM_TO_PAGE.equals(c) && !zoomDisabled) { + return zoomToPage(); + } + if (Commands.ZOOM_TO_SELECTION.equals(c) && !zoomDisabled) { + return zoomToSelection(); + } + return super.handleEvent(e); + } + + private boolean zoomToFit() { + return false; + } + + private boolean zoomToPage() { + int currentZoomLevel = MapScalingTransform.zoomLevel(util.getTransform()); + + util.setTransform(new AffineTransform(2,0,0,2,270,270)); +// util.setTransform(new AffineTransform(MapScalingTransform.INSTANCE)); + return true; + } + + private boolean zoomToSelection() { + CanvasBoundsParticipant boundsParticipant = getContext().getAtMostOneItemOfClass(CanvasBoundsParticipant.class); + if (boundsParticipant == null) + return false; + + final Rectangle2D controlBounds = boundsParticipant.getControlBounds().getFrame(); + if (controlBounds == null || controlBounds.isEmpty()) + return false; + + Set selections = selection.getAllSelections(); + Rectangle2D diagramRect = ElementUtils.getSurroundingElementBoundsOnDiagram(selections); + + // Make sure that even empty bounds can be zoomed into. + org.simantics.scenegraph.utils.GeometryUtils.expandRectangle(diagramRect, 1); + + util.fitArea(controlBounds, diagramRect, null); + return true; + } + public static class DistrictNavigationNode extends NavigationNode { private static final long serialVersionUID = 5452897272925816875L; + public DistrictNavigationNode() { + setAdaptViewportToResizedControl(false); + } + @Override public Double getZoomInLimit() { return super.getZoomInLimit(); @@ -28,23 +122,40 @@ public class DistrictPanZoomRotateHandler extends PanZoomRotateHandler { return super.getZoomOutLimit(); } + @Override + public void setAdaptViewportToResizedControl(Boolean adapt) { + super.setAdaptViewportToResizedControl(false); + // no op + } + + @Override + public boolean getAdaptViewportToResizedControl() { + return false; + } + @Override public boolean mouseWheelMoved(MouseWheelMovedEvent me) { if (navigationEnabled && zoomEnabled) { - double scroll = Math.min(0.9, -me.wheelRotation / 20.0); - double z = 1 - scroll; + double z; + if (me.wheelRotation > 0) { + z = DISTRICT_TRANSLATE_AMOUNT; + } else { + z = 1.0d / DISTRICT_TRANSLATE_AMOUNT; + } + //double scroll = Math.min(0.9, -me.wheelRotation / 20.0); + //double z = 1 - scroll; double dx = (me.controlPosition.getX() - transform.getTranslateX()) / transform.getScaleX(); double dy = (me.controlPosition.getY() - transform.getTranslateY()) / transform.getScaleY(); dx = dx * (1 - z); dy = dy * (1 - z); - double limitedScale = limitScaleFactor(z); - if (limitedScale != 1.0) { +// double limitedScale = limitScaleFactor(z); +// if (limitedScale != 1.0) { translate(dx, dy); scale(z, z); transformChanged(); dropQuality(); repaint(); - } +// } } return false; } diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/DistrictTransformUtil.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/DistrictTransformUtil.java new file mode 100644 index 00000000..230c17cd --- /dev/null +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/DistrictTransformUtil.java @@ -0,0 +1,75 @@ +package org.simantics.district.network.ui; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; + +import org.simantics.g2d.participant.TransformUtil; +import org.simantics.scenegraph.utils.GeometryUtils; +import org.simantics.utils.page.MarginUtils; +import org.simantics.utils.page.MarginUtils.Margins; + +public class DistrictTransformUtil extends TransformUtil { + + @Override + public void fitArea(Rectangle2D controlArea, Rectangle2D diagramArea, Margins margins) { + if (margins == null) { + MarginUtils.Margin margin = MarginUtils.marginOf(40, 0, 0); + margins = new MarginUtils.Margins(margin, margin, margin, margin); + } + org.simantics.scenegraph.utils.GeometryUtils.expandRectangle(diagramArea, -1); + diagramArea = GeometryUtils.expandRectangle(diagramArea, + margins.top.diagramAbsolute, + margins.bottom.diagramAbsolute, + margins.left.diagramAbsolute, + margins.right.diagramAbsolute); + controlArea = GeometryUtils.expandRectangle(controlArea, + -margins.top.controlAbsolute - margins.top.controlRelative * controlArea.getHeight(), + -margins.bottom.controlAbsolute - margins.bottom.controlRelative * controlArea.getHeight(), + -margins.left.controlAbsolute - margins.left.controlRelative * controlArea.getWidth(), + -margins.right.controlAbsolute - margins.right.controlRelative * controlArea.getWidth()); + + double controlAspectRatio = controlArea.getWidth() / controlArea.getHeight(); + double canvasAspectRatio = diagramArea.getWidth() / diagramArea.getHeight(); + // Control is really wide => center canvas horizontally, match vertically + double scale = 1.0; + double tx = 0.0; + double ty = 0.0; + if (controlAspectRatio>canvasAspectRatio) + { + scale = controlArea.getHeight() / diagramArea.getHeight(); + tx = ( controlArea.getWidth() - diagramArea.getWidth() * scale ) / 2; + } else + // Control is really tall => center canvas vertically, match horizontally + { + scale = controlArea.getWidth() / diagramArea.getWidth(); + ty = ( controlArea.getHeight() - diagramArea.getHeight() * scale ) / 2; + } + AffineTransform current = getTransform(); + double currentX = current.getScaleX(); + double targetX = scale; + double toBeX = currentX; + if (targetX > 0) { + if (toBeX < targetX) { + while ((toBeX) < targetX) { + toBeX = toBeX * 2; + } + } else { + while ((toBeX * 0.5) > targetX) { + toBeX = toBeX * 0.5; + } + } + //tx = tx * (1 - toBeX); + //ty = ty * (1 - toBeX); + AffineTransform at = new AffineTransform(); + at.translate(tx, ty); + at.translate(controlArea.getMinX(), controlArea.getMinY()); + at.scale(toBeX, toBeX); + at.translate(-diagramArea.getMinX(), -diagramArea.getMinY()); + + setTransform(at); + } else { + // negative, how, no can do? + + } + } +} diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/NetworkDrawingParticipant.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/NetworkDrawingParticipant.java index 73abf31e..69d1f724 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/NetworkDrawingParticipant.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/NetworkDrawingParticipant.java @@ -59,7 +59,7 @@ public class NetworkDrawingParticipant extends AbstractDiagramParticipant { } public boolean pickHoveredElement(Point2D currentMousePos) { - PickRequest req = new PickRequest(currentMousePos.getX(), currentMousePos.getY()).context(getContext()); + PickRequest req = new PickRequest(currentMousePos).context(getContext()); List pickables = new ArrayList(); pick.pick(diagram, req, pickables); diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/adapters/DistrictNetworkEdgeElement.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/adapters/DistrictNetworkEdgeElement.java index d4758007..ce57e0a2 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/adapters/DistrictNetworkEdgeElement.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/adapters/DistrictNetworkEdgeElement.java @@ -163,7 +163,7 @@ public class DistrictNetworkEdgeElement { } private boolean pickIntersectingObjects(DistrictNetworkEdge edge, Rectangle2D bounds) { - double tolerance = (bounds.getHeight() + bounds.getHeight()) * 0.25 / MapScalingTransform.getScaleX(); + double tolerance = (bounds.getHeight() + bounds.getHeight()) * 1 / MapScalingTransform.getScaleX(); Line2D line = new Line2D.Double(edge.getStartPoint(), edge.getEndPoint()); double sx = bounds.getCenterX() / MapScalingTransform.getScaleX(); double sy = bounds.getCenterY() / MapScalingTransform.getScaleY(); diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/adapters/DistrictNetworkVertexElement.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/adapters/DistrictNetworkVertexElement.java index 7be6a14f..b3e7fda3 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/adapters/DistrictNetworkVertexElement.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/adapters/DistrictNetworkVertexElement.java @@ -1,21 +1,28 @@ package org.simantics.district.network.ui.adapters; import java.awt.Color; +import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; +import org.simantics.diagram.elements.DiagramNodeUtil; import org.simantics.district.network.ui.nodes.DistrictNetworkVertexNode; +import org.simantics.g2d.canvas.Hints; +import org.simantics.g2d.canvas.ICanvasContext; +import org.simantics.g2d.diagram.handler.PickRequest.PickPolicy; import org.simantics.g2d.element.ElementClass; import org.simantics.g2d.element.ElementUtils; import org.simantics.g2d.element.IElement; import org.simantics.g2d.element.SceneGraphNodeKey; import org.simantics.g2d.element.handler.InternalSize; +import org.simantics.g2d.element.handler.Pick; import org.simantics.g2d.element.handler.SceneGraph; import org.simantics.g2d.element.handler.impl.DefaultTransform; import org.simantics.g2d.element.handler.impl.SimpleElementLayers; import org.simantics.scenegraph.INode; import org.simantics.scenegraph.g2d.G2DParentNode; import org.simantics.scenegraph.g2d.nodes.SVGNode; +import org.simantics.scenegraph.utils.GeometryUtils; import org.simantics.utils.datastructures.hints.IHintContext.Key; import org.simantics.utils.datastructures.hints.IHintContext.KeyOf; @@ -77,7 +84,7 @@ public class DistrictNetworkVertexElement { } } - static final class DNVertexInternalSize implements InternalSize { + static final class DNVertexInternalSize implements InternalSize, Pick { public static final DNVertexInternalSize INSTANCE = new DNVertexInternalSize(); @@ -87,9 +94,42 @@ public class DistrictNetworkVertexElement { public Rectangle2D getBounds(IElement e, Rectangle2D size) { DistrictNetworkVertexNode node = e.getHint(KEY_DN_VERTEX_NODE); Rectangle2D boundsInLocal = node.getBoundsInLocal(); - size.setFrame(boundsInLocal); + ICanvasContext ctx = DiagramNodeUtil.getCanvasContext(node); + AffineTransform canvasTransform = ctx.getHintStack().getHint(Hints.KEY_CANVAS_TRANSFORM); + // for some reason PickContextImpl expands the rectangle by 0.001 (too much) - let's counter it + double counterExpansion = 0.001; + double x = boundsInLocal.getX() + counterExpansion; + double y = boundsInLocal.getY() + counterExpansion; + double scaledWidth = boundsInLocal.getWidth() / canvasTransform.getScaleX() / 10000.0; + double scaledHeight = boundsInLocal.getHeight() / canvasTransform.getScaleY() / 10000.0; + double width = scaledWidth - 2*counterExpansion; + double height = scaledHeight - 2*counterExpansion; + size.setFrame(x, y, width, height); + return size; } + + @Override + public boolean pickTest(IElement e, Shape s, PickPolicy policy) { + DistrictNetworkVertexNode node = e.getHint(KEY_DN_VERTEX_NODE); + Rectangle2D boundsInLocal = node.getBounds(); + ICanvasContext ctx = DiagramNodeUtil.getCanvasContext(node); + AffineTransform canvasTransform = ctx.getHintStack().getHint(Hints.KEY_CANVAS_TRANSFORM); + Rectangle2D scaledBounds = new Rectangle2D.Double(boundsInLocal.getX(), boundsInLocal.getY(), boundsInLocal.getWidth() / canvasTransform.getScaleX() * 2, boundsInLocal.getHeight() / canvasTransform.getScaleY() * 2); + Rectangle2D bounds = getBounds(s); + switch (policy) { + case PICK_CONTAINED_OBJECTS: + return org.simantics.g2d.utils.GeometryUtils.contains(bounds, boundsInLocal); + case PICK_INTERSECTING_OBJECTS: + return org.simantics.g2d.utils.GeometryUtils.intersects(boundsInLocal, bounds); + } + return false; + } + private Rectangle2D getBounds(Shape shape) { + if (shape instanceof Rectangle2D) + return (Rectangle2D) shape; + return shape.getBounds2D(); + } } } diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkNodeUtils.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkNodeUtils.java index 8a369e26..c48693ac 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkNodeUtils.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkNodeUtils.java @@ -5,6 +5,8 @@ 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; public class DistrictNetworkNodeUtils { @@ -35,4 +37,11 @@ public class DistrictNetworkNodeUtils { return transform; } + public static double calculateScaleRecip(AffineTransform tr) { + int zoomLevel = MapScalingTransform.zoomLevel(tr); + double scale = GeometryUtils.getScale(tr); + double sqrt = Math.sqrt(scale / zoomLevel); + double viewScaleRecip = (sqrt / zoomLevel); + return viewScaleRecip; + } } diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkVertexNode.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkVertexNode.java index 377c7f7e..6fb075eb 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkVertexNode.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkVertexNode.java @@ -23,13 +23,13 @@ public class DistrictNetworkVertexNode extends G2DParentNode implements ISelecti private static final long serialVersionUID = -2641639101400236719L; - private static final BasicStroke STROKE = new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); - private static final Color SELECTION_COLOR = new Color(255, 0, 255, 96); + private static final double left = -0.00005; + private static final double top = left; + public static final double width = 0.0001; + private static final double height = width; - private static final double left = -0.25; - private static final double top = -0.25; - private static final double width = 0.5; - private static final double height = 0.5; + private static final BasicStroke STROKE = new BasicStroke((float)width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); + private static final Color SELECTION_COLOR = new Color(255, 0, 255, 96); private static final Rectangle2D NORMAL = new Rectangle2D.Double(left, top, width, height); private static final Rectangle2D HOVERED = new Rectangle2D.Double(left * 3, top * 3, width * 3, height * 3); @@ -63,7 +63,7 @@ public class DistrictNetworkVertexNode extends G2DParentNode implements ISelecti AffineTransform t = getTransform(); if (t != null && !t.isIdentity()) { ot = g2d.getTransform(); - g2d.transform(getTransform()); + g2d.transform(t); } Object oaaHint = null; @@ -77,11 +77,9 @@ public class DistrictNetworkVertexNode extends G2DParentNode implements ISelecti Color newColor = dynamicColor != null ? dynamicColor : color; boolean changeColor = !oldColor.equals(newColor); - double viewScaleRecip = 10; + double viewScaleRecip = 1; if (scaleStroke) { - double scale = GeometryUtils.getScale(g2d.getTransform()); - scale = Math.max(10000, Math.min(scale, 50000)); - viewScaleRecip /= scale; + viewScaleRecip *= DistrictNetworkNodeUtils.calculateScaleRecip(g2d.getTransform()); } double scaleRecip = viewScaleRecip * nodeSize; @@ -152,7 +150,11 @@ public class DistrictNetworkVertexNode extends G2DParentNode implements ISelecti private Rectangle2D calculateBounds(Rectangle2D rect) { Point2D calcPoint = DistrictNetworkNodeUtils.calculatePoint2D(vertex.getPoint(), point); AffineTransform at = getTransform(); - return new Rectangle2D.Double(calcPoint.getX(), calcPoint.getY(), width / at.getScaleX(), height / at.getScaleY()).getBounds2D(); + double x = calcPoint.getX(); + double y = calcPoint.getY(); + double widthh = width / at.getScaleX(); + double heighth = height / at.getScaleY(); + return new Rectangle2D.Double(x - widthh, y - heighth, widthh * 2, heighth * 2).getBounds2D(); } public void setVertex(DistrictNetworkVertex vertex) { diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/NetworkDrawingNode.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/NetworkDrawingNode.java index 71ccb781..674702b8 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/NetworkDrawingNode.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/NetworkDrawingNode.java @@ -4,6 +4,7 @@ import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Stroke; +import java.awt.geom.AffineTransform; import java.awt.geom.Path2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; @@ -16,11 +17,13 @@ import org.simantics.db.Resource; import org.simantics.db.WriteGraph; import org.simantics.db.common.request.WriteRequest; import org.simantics.db.exception.DatabaseException; +import org.simantics.diagram.elements.DiagramNodeUtil; import org.simantics.diagram.ui.DiagramModelHints; import org.simantics.district.network.ModelledCRS; import org.simantics.district.network.ui.DNEdgeBuilder; import org.simantics.district.network.ui.NetworkDrawingParticipant; import org.simantics.g2d.canvas.Hints; +import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.canvas.IToolMode; import org.simantics.g2d.diagram.IDiagram; import org.simantics.scenegraph.g2d.G2DNode; @@ -158,8 +161,14 @@ public class NetworkDrawingNode extends G2DNode { private void createEdge(Point2D start, Point2D end) { - double padding = GeometryUtils.getScale(getTransform()); - + double currentPadding = DistrictNetworkVertexNode.width; + AffineTransform test = getTransform(); + ICanvasContext ctx = DiagramNodeUtil.getCanvasContext(this); + AffineTransform tr = ctx.getHintStack().getHint(Hints.KEY_CANVAS_TRANSFORM); + AffineTransform testing = new AffineTransform(tr); + testing.concatenate(test); + double calculateScaleRecip = DistrictNetworkNodeUtils.calculateScaleRecip(testing); + double padding = currentPadding * calculateScaleRecip; /* * To convert y-coordinates to map coordinates in ruler, use: * double val = (y-offsetY)/scaleY; @@ -184,7 +193,7 @@ public class NetworkDrawingNode extends G2DNode { @Override public void perform(WriteGraph graph) throws DatabaseException { - builder.create(graph, startCoords, endCoords, 1 / padding); + builder.create(graph, startCoords, endCoords, padding); } }); diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/DNPointerInteractor.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/DNPointerInteractor.java index c61adba9..9df6e5ef 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/DNPointerInteractor.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/DNPointerInteractor.java @@ -81,4 +81,8 @@ public class DNPointerInteractor extends PointerInteractor { return false; } + @Override + public double getPickDistance() { + return 0.00001; + } } diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/MapRulerPainter.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/MapRulerPainter.java index ecdbf275..cdf0b530 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/MapRulerPainter.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/MapRulerPainter.java @@ -1,5 +1,7 @@ package org.simantics.district.network.ui.participants; +import java.awt.geom.AffineTransform; + import org.simantics.district.network.ui.nodes.MapRulerNode; import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit; import org.simantics.g2d.participant.RulerPainter; @@ -12,7 +14,7 @@ public class MapRulerPainter extends RulerPainter { @Override public void initSG(G2DParentNode parent) { node = parent.addNode("ruler", getNodeClass()); - node.setTransform(MapScalingTransform.INSTANCE); + node.setTransform(new AffineTransform(MapScalingTransform.INSTANCE)); node.setZIndex(PAINT_PRIORITY); updateNode(); }