Skip to content

Commit

Permalink
Fix grid snapping on all zoom levels (#127)
Browse files Browse the repository at this point in the history
Before, dragging objects at non-100% zoom would sometimes result in
misaligned places, transitions, and arc points, which could never be
aligned again. See [video of before](https://streamable.com/dr5oj6).

Now, objects always snap to the grid and align perfectly. See [video of
now](https://streamable.com/hm76t5).

Resolved by making the `Grid::getModified` account for zoom level.
Renamed it `Grid::align`.
  • Loading branch information
srba authored Dec 15, 2023
2 parents 0d63205 + a63ce8f commit b965a7a
Show file tree
Hide file tree
Showing 11 changed files with 64 additions and 52 deletions.
4 changes: 2 additions & 2 deletions src/main/java/pipe/gui/canvas/DrawingSurfaceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,8 @@ public Point adjustPointToZoom(Point p, int zoom) {
}

public Point adjustPointToGrid(Point p) {
int x = Grid.getModifiedX(p.x);
int y = Grid.getModifiedY(p.y);
int x = Grid.align(p.x, getZoom());
int y = Grid.align(p.y, getZoom());

return new Point(x, y);
}
Expand Down
25 changes: 5 additions & 20 deletions src/main/java/pipe/gui/canvas/Grid.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,9 @@
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.GeneralPath;
import java.util.ArrayList;

import net.tapaal.gui.petrinet.undo.Command;
import net.tapaal.gui.petrinet.undo.MovePlaceTransitionObjectCommand;
import pipe.gui.Constants;
import pipe.gui.TAPAALGUI;
import pipe.gui.petrinet.graphicElements.PetriNetObject;
import pipe.gui.petrinet.graphicElements.PlaceTransitionObject;
import pipe.gui.petrinet.undo.UndoManager;

/**
* @author Peter Kyme
Expand Down Expand Up @@ -88,19 +80,12 @@ public static void drawGrid(Graphics g) {
g2d.draw(gridDisplay);
}

public static int getModifiedX(double x) {
public static int align(int x, int zoom) {
if (!enabled) {
return (int) x;
return x;
}
return (int) (Math.round(x / gridSpacing) * gridSpacing);

}

public static int getModifiedY(double y) {
if (!enabled) {
return (int) y;
}
return (int) (Math.round(y / gridSpacing) * gridSpacing);
double unzoomed = Zoomer.getUnzoomedValue(x, zoom);
double adjusted = Math.round(unzoomed / gridSpacing) * gridSpacing;
return Math.round(Zoomer.getZoomedValue(adjusted, zoom));
}

}
8 changes: 4 additions & 4 deletions src/main/java/pipe/gui/petrinet/PetriNetTab.java
Original file line number Diff line number Diff line change
Expand Up @@ -1584,8 +1584,8 @@ public void alignToGrid() {

for (PetriNetObject object : petriNetObjects) {
PlaceTransitionObject ptobject = (PlaceTransitionObject) object;
int x = Grid.getModifiedX(ptobject.getPositionX());
int y = Grid.getModifiedY(ptobject.getPositionY());
int x = Grid.align(ptobject.getPositionX(), drawingSurface.getZoom());
int y = Grid.align(ptobject.getPositionY(), drawingSurface.getZoom());
Point point = new Point(x, y);
Command command = new MovePlaceTransitionObjectCommand(ptobject, point, drawingSurface);
command.redo();
Expand Down Expand Up @@ -2602,8 +2602,8 @@ private void pnoDragged(PetriNetObject pno, MouseEvent e) {
}

// Calculate translation in mouse
int transX = Grid.getModifiedX(e.getX() - dragInit.x);
int transY = Grid.getModifiedY(e.getY() - dragInit.y);
int transX = Grid.align(e.getX() - dragInit.x, canvas.getZoom());
int transY = Grid.align(e.getY() - dragInit.y, canvas.getZoom());
canvas.getSelectionObject().translateSelection(transX, transY);

//Only register the actual distance and direction moved (in case of dragging past edge)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ public void mousePressed(MouseEvent e) {
public void mouseDragged(MouseEvent e) {
if(TAPAALGUI.getCurrentTab().isInAnimationMode()) return;

myPoint.drag(Grid.getModifiedX(e.getX() - start.x), Grid.getModifiedY(e.getY() - start.y));
myPoint.drag(Grid.align(e.getX() - start.x, getZoom()), Grid.align(e.getY() - start.y, getZoom()));
myPoint.myNote.updateBounds();
myPoint.repaint();
}
Expand Down
15 changes: 11 additions & 4 deletions src/main/java/pipe/gui/petrinet/graphicElements/Arc.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ public void setTarget(PlaceTransitionObject targetInput) {
protected void setLabelPosition() {

getNameLabel().setPosition(
Grid.getModifiedX(myPath.midPoint.x + Zoomer.getZoomedValue(getNameOffsetX(), getZoom())),
Grid.getModifiedY(myPath.midPoint.y + Zoomer.getZoomedValue(getNameOffsetY(), getZoom()))
Grid.align((int)myPath.midPoint.x + Zoomer.getZoomedValue(getNameOffsetX(), getZoom()), getZoom()),
Grid.align((int)myPath.midPoint.y + Zoomer.getZoomedValue(getNameOffsetY(), getZoom()), getZoom())
);

}
Expand Down Expand Up @@ -202,12 +202,19 @@ public PlaceTransitionObject getTarget() {
* the bounds
*/
public void updateArcPosition() {
if (source != null) {
// The positions of end points are mutually dependant, so we update both an extra time
if (target != null) {
target.updateEndPoint(this);
}
if (source != null) {
source.updateEndPoint(this);
}
if (target != null) {
target.updateEndPoint(this);
}
if (source != null) {
source.updateEndPoint(this);
}
myPath.createPath();
}

Expand Down Expand Up @@ -291,7 +298,7 @@ public void paintComponent(Graphics g) {
g2.translate(myPath.getPoint(myPath.getEndIndex()).getX(), myPath.getPoint(myPath.getEndIndex()).getY());

//Rotate to match arrowhead to arc angle
g2.rotate(myPath.getEndAngle() + Math.PI);
g2.rotate(-myPath.getEndAngle() - Math.PI/2);
g2.setColor(java.awt.Color.WHITE);

g2.transform(Zoomer.getTransform(getZoom()));
Expand Down
26 changes: 24 additions & 2 deletions src/main/java/pipe/gui/petrinet/graphicElements/ArcPathPoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,29 @@ public Point2D.Double getPoint() {
return new Point2D.Double(getPositionX(), getPositionY());
}

public void setPointLocation(int x, int y) {
@Override
public void setOriginalX(int positionXInput) {
if (myArcPath != null && !isEndPoint()) {
// Snap to grid
super.setOriginalX(positionXInput);
} else {
originalX = positionXInput;
positionX = Zoomer.getZoomedValue(originalX, getZoom());
}
}

@Override
public void setOriginalY(int positionYInput) {
if (myArcPath != null && !isEndPoint()) {
// Snap to grid
super.setOriginalY(positionYInput);
} else {
originalY = positionYInput;
positionY = Zoomer.getZoomedValue(originalY, getZoom());
}
}

public void setPointLocation(int x, int y) {
setPositionX(x);
setPositionY(y);
updateOnMoveOrZoom();
Expand Down Expand Up @@ -135,7 +157,7 @@ public void setVisibilityLock(boolean lock) {
public double getAngle(Point2D.Double p2) {
double angle;

angle = Math.atan2( (getPoint().x - p2.x), (p2.y - getPoint().y) );
angle = Math.atan2( (p2.y - getPoint().y), (getPoint().x - p2.x) );

return angle;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import net.tapaal.gui.petrinet.TAPNLens;
import net.tapaal.TAPAAL;
import pipe.gui.canvas.Grid;
import pipe.gui.petrinet.dataLayer.DataLayer;
import pipe.gui.TAPAALGUI;
import pipe.gui.canvas.DrawingSurfaceImpl;
Expand Down Expand Up @@ -198,12 +199,11 @@ public void translate(int x, int y) {}
* Double value for X-axis position
*/
public void setOriginalX(int positionXInput) {
originalX = positionXInput;
positionX = Zoomer.getZoomedValue(positionXInput, getZoom());
originalX = Grid.align(positionXInput, 100);
positionX = Zoomer.getZoomedValue(originalX, getZoom());
}
public void setPositionX(int positionXInput) {
positionX = positionXInput;
originalX = Zoomer.getUnzoomedValue(positionX, getZoom());
setOriginalX(Zoomer.getUnzoomedValue(positionXInput, getZoom()));
}

//XXX: pushed down from Placetransition object, might be dublicated //kyrke 2019-09-20
Expand All @@ -214,12 +214,11 @@ public void setPositionX(int positionXInput) {
* Double value for Y-axis position
*/
public void setOriginalY(int positionYInput) {
originalY = positionYInput;
positionY = Zoomer.getZoomedValue(positionYInput, getZoom());
originalY = Grid.align(positionYInput, 100);
positionY = Zoomer.getZoomedValue(originalY, getZoom());
}
public void setPositionY(int positionYInput) {
positionY = positionYInput;
originalY = Zoomer.getUnzoomedValue(positionY, getZoom());
setOriginalY(Zoomer.getUnzoomedValue(positionYInput, getZoom()));
}

//XXX: pushed down from Placetransition object, might be dublicated //kyrke 2019-09-20
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,13 @@ protected void setLabelHandler() {
getNameLabel().addMouseListener(labelHandler);
getNameLabel().addMouseMotionListener(labelHandler);
getNameLabel().addMouseWheelListener(labelHandler);

}

protected void updateLabelLocation(boolean alignToGrid) {
if(alignToGrid) {
this.getNameLabel().setPosition(
Grid.getModifiedX(positionX + Zoomer.getZoomedValue(nameOffsetX, getZoom())),
Grid.getModifiedY(positionY + Zoomer.getZoomedValue(nameOffsetY, getZoom()))
Grid.align(positionX + Zoomer.getZoomedValue(nameOffsetX, getZoom()), 100),
Grid.align(positionY + Zoomer.getZoomedValue(nameOffsetY, getZoom()), 100)
);
} else {
this.getNameLabel().setPosition(
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/pipe/gui/petrinet/graphicElements/Place.java
Original file line number Diff line number Diff line change
Expand Up @@ -131,19 +131,19 @@ public void updateEndPoint(Arc arc) {
+ (getDiameter() * 0.5));
double angle = arc.getArcPath().getStartAngle();
arc.setSourceLocation(positionX + centreOffsetLeft()
- (0.5 * getDiameter() * (Math.sin(angle))), positionY
- (0.5 * getDiameter() * (Math.cos(angle))), positionY
+ centreOffsetTop()
+ (0.5 * getDiameter() * (Math.cos(angle))));
+ (0.5 * getDiameter() * (Math.sin(angle))));
} else {
// Make it calculate the angle from the centre of the place rather
// than the current target point
arc.setTargetLocation(positionX + (getDiameter() * 0.5), positionY
+ (getDiameter() * 0.5));
double angle = arc.getArcPath().getEndAngle();
arc.setTargetLocation(positionX + centreOffsetLeft()
- (0.5 * getDiameter() * (Math.sin(angle))), positionY
- (0.5 * getDiameter() * (Math.cos(angle))), positionY
+ centreOffsetTop()
+ (0.5 * getDiameter() * (Math.cos(angle))));
+ (0.5 * getDiameter() * (Math.sin(angle))));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ public void updateEndPoints() {
transform.concatenate(Zoomer.getTransform(getZoom()));

arcIterator = top.iterator();
transform.transform(new Point2D.Double(1, 0.5 * TRANSITION_HEIGHT), transformed); // +1 due to rounding making it off by 1
transform.transform(new Point2D.Double(1, 0.5 * TRANSITION_HEIGHT), transformed); // 1 on x due to rounding error
while (arcIterator.hasNext()) {
ArcAngleCompare thisArc = arcIterator.next();

Expand All @@ -290,7 +290,7 @@ public void updateEndPoints() {
}

arcIterator = bottom.iterator();
transform.transform(new Point2D.Double(0, -0.5 * TRANSITION_HEIGHT), transformed);
transform.transform(new Point2D.Double(-1, -0.5 * TRANSITION_HEIGHT), transformed); // -1 on x due to rounding error
while (arcIterator.hasNext()) {
ArcAngleCompare thisArc = arcIterator.next();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ public TimedOutputArcComponent(TimedOutputArcComponent arc) {
this.setNameOffsetX(arc.getNameOffsetX());
this.setNameOffsetY(arc.getNameOffsetY());
this.getNameLabel().setPosition(
Grid.getModifiedX((int) (arc.getNameLabel().getXPosition() + Zoomer.getZoomedValue(getNameOffsetX(), getZoom()))),
Grid.getModifiedY((int) (arc.getNameLabel().getYPosition() + Zoomer.getZoomedValue(getNameOffsetY(), getZoom())))
Grid.align((int) (arc.getNameLabel().getXPosition() + Zoomer.getZoomedValue(getNameOffsetX(), getZoom())), getZoom()),
Grid.align((int) (arc.getNameLabel().getYPosition() + Zoomer.getZoomedValue(getNameOffsetY(), getZoom())), getZoom())
);
this.lens = arc.lens;
}
Expand Down

0 comments on commit b965a7a

Please sign in to comment.