package pipe.views; import pipe.constants.GUIConstants; import uk.ac.imperial.pipe.models.petrinet.Connectable; import uk.ac.imperial.pipe.models.petrinet.ArcPoint; import javax.swing.*; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.List; import static java.lang.Math.max; /** * Building tool for creating an arc, allows the user to go from source to * target before adding to petri net * * @param <T> source class */ @SuppressWarnings("serial") public class TemporaryArcView<T extends Connectable> extends JComponent { /** * Arc source, this source was clicked on to initialse the drawing of the remporary arc */ private T source; /** * Head shown when drawing the arc */ private final ArcHead arcHead; /** * Current end location of the mouse */ private Point2D end; /** * Intermediate points build up by clicking on the canvas * Press shift for curved points */ private List<ArcPoint> intermediatePoints = new ArrayList<>(); /** * Maximum intermediate point seen so far for setting rectangle x bounds */ private double maxX; /** * Maximum intermediate point seen so far for setting rectangle y bounds */ private double maxY; /** * Constructor * @param source start point of the arc * @param arcHead head to draw on the temporary arc */ public TemporaryArcView(T source, ArcHead arcHead) { super(); this.source = source; this.arcHead = arcHead; Point2D centre = source.getCentre(); end = new Point2D.Double(centre.getX(), centre.getY()); updateMax(end); setBounds(0, 0, (int) centre.getX(), (int) centre.getY()); } /** * Updates max points based on point */ private void updateMax(Point2D point) { maxX = max(maxX, point.getX()); maxY = max(maxY, point.getY()); } /** * * @param end 2D end point */ public void setEnd(Point2D end) { this.end = end; updateMax(end); updateBounds(); } /** * Updates bounds to maxX and maxY */ private void updateBounds() { int x = (int) maxX; int y = (int) maxY; setBounds(0, 0, x, y); } /** * Add this point to the arc when its created * @param point to add */ public void addIntermediatePoint(ArcPoint point) { intermediatePoints.add(point); updateMax(point.getPoint()); updateBounds(); } /** * * @return the source model of this arc */ public T getSourceConnectable() { return source; } /** * Paints the temporary arc with straight arc points and the specified head * @param g graphics */ @Override public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; g2.setPaint(GUIConstants.ELEMENT_LINE_COLOUR); GeneralPath path = new GeneralPath(); path.moveTo(source.getCentre().getX(), source.getCentre().getY()); for (ArcPoint arcPoint : intermediatePoints) { path.lineTo(arcPoint.getX(), arcPoint.getY()); } path.lineTo(end.getX(), end.getY()); g2.draw(path); g2.translate(end.getX(), end.getY()); g2.rotate(getRotationAngle()); arcHead.draw(g2); } /** * @return angle in radians between last point on the arc and the current end */ private double getRotationAngle() { Point2D lastPoint = getLastPoint(); double deltax = end.getX() - lastPoint.getX(); double deltay = end.getY() - lastPoint.getY(); return Math.atan2(deltay, deltax); } /** * This method always returns false as to avoid any interaction with the * temporary arc view * * @param x x location of mouse * @param y y location of mouse * @return false */ @Override public boolean contains(int x, int y) { return false; } /** * * @return the very last point of the temporary arc path points */ public Point2D getLastPoint() { if (!intermediatePoints.isEmpty()) { return intermediatePoints.get(intermediatePoints.size() - 1).getPoint(); } return source.getCentre(); } /** * * @return all intermediate path points created whilst creating the arc */ public List<ArcPoint> getIntermediatePoints() { return intermediatePoints; } }