/*
* Created on 28-Feb-2004
* @author Michael Camacho (and whoever wrote the first bit!)
* @author Edwin Chung 16 Mar 2007: modified the constructor and several other
* functions so that DataLayer objects can be created outside the GUI
*/
package pipe.views;
import pipe.constants.GUIConstants;
import pipe.controllers.PetriNetController;
import uk.ac.imperial.pipe.models.petrinet.ArcPoint;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RectangularShape;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
/**
* This class represents each point on the arc path graphically.
* It's old code so the Bezier maths etc. needs to be addressed
*/
@SuppressWarnings("serial")
public class ArcPathPoint extends AbstractPetriNetViewComponent<ArcPoint> {
/**
* Boolean value determining if the arc is straight or a curve
*/
public static final boolean STRAIGHT = false;
private static final int SIZE_OFFSET = 1;
/**
* Size of the point
*/
private static final int SIZE = 3;
/**
* Underlying point model
*/
private final ArcPoint model;
/**
* Control used for Bezier curve
*/
private final Point2D.Double control1 = new Point2D.Double();
/**
* Control used for Bezier curve
*/
private final Point2D.Double control = new Point2D.Double();
/**
* Path point belongs to
*/
private ArcPath arcPath;
/**
* Sets copyPastable to false because we cant copy paste individual arc points
*/
private void setup() {
copyPasteable = false;
}
public void setPointLocation(double x, double y) {
setBounds((int) x - SIZE, (int) y - SIZE, 2 * SIZE + SIZE_OFFSET, 2 * SIZE + SIZE_OFFSET);
}
/**
* Constructor
* @param point on the arc
* @param arcPath path of the arc
* @param petriNetController Petri net controller
* @param parent container
*/
public ArcPathPoint(ArcPoint point, ArcPath arcPath, PetriNetController petriNetController, Container parent) {
super("", point, petriNetController, parent);
setup();
model = point;
setPointLocation(model.getPoint());
this.arcPath = arcPath;
model.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent propertyChangeEvent) {
if (propertyChangeEvent.getPropertyName().equals(ArcPoint.UPDATE_LOCATION_CHANGE_MESSAGE)) {
Point2D point = (Point2D) propertyChangeEvent.getNewValue();
setPointLocation(point.getX(), point.getY());
}
}
});
}
public final void setPointLocation(Point2D point) {
setPointLocation(point.getX(), point.getY());
}
public Point2D getPoint() {
return model.getPoint();
}
public boolean isCurved() {
return model.isCurved();
}
public void setVisibilityLock(boolean lock) {
arcPath.setPointVisibilityLock(lock);
}
public double getAngle(Point2D.Double p2) {
double angle;
if (model.getPoint().getY() <= p2.y) {
angle = Math.atan((model.getPoint().getX() - p2.x) / (p2.y - model.getPoint().getY()));
} else {
angle = Math.atan((model.getPoint().getX() - p2.x) / (p2.y - model.getPoint().getY())) + Math.PI;
}
// Needed to eliminate an exception on Windows
if (model.getPoint().equals(p2)) {
angle = 0;
}
return angle;
}
public Point2D.Double getMidPoint(ArcPathPoint target) {
return new Point2D.Double((target.model.getPoint().getX() + model.getPoint().getX()) / 2,
(target.model.getPoint().getY() + model.getPoint().getY()) / 2);
}
public Point2D.Double getControl1() {
return control1;
}
public void setControl1(Point2D.Double p) {
control1.x = p.x;
control1.y = p.y;
}
public Point2D.Double getControl() {
return control;
}
public void setControl(Point2D.Double p) {
control.x = p.x;
control.y = p.y;
}
public void setControl1(double _x, double _y) {
control1.x = _x;
control1.y = _y;
}
public void setControl2(double _x, double _y) {
control.x = _x;
control.y = _y;
}
@Override
public void addToContainer(Container container) {
// Nothing needed
}
@Override
public String getName() {
return this.getArcPath().getArc().getModel().getName() + " - Point " + this.getIndex();
}
public int getIndex() {
for (int i = 0; i < arcPath.getNumPoints(); i++) {
if (arcPath.getPathPoint(i) == this) {
return i;
}
}
return -1;
}
public ArcPath getArcPath() {
return arcPath;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + model.hashCode();
return result;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
ArcPathPoint pathPoint = (ArcPathPoint) o;
if (!model.equals(pathPoint.model)) {
return false;
}
return true;
}
/**
* Performs a delete only if there are more than two points left after deleting this one
*/
@Override
public void componentSpecificDelete() {
if (isDeleteable()) {
if (getArcPath().getArc().isSelected()) {
return;
}
kill();
}
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (!ignoreSelection) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
RectangularShape shape;
if (model.isCurved()) {
shape = new Ellipse2D.Double(0, 0, 2 * SIZE, 2 * SIZE);
} else {
shape = new Rectangle2D.Double(0, 0, 2 * SIZE, 2 * SIZE);
}
if (isSelected()) {
g2.setPaint(GUIConstants.SELECTION_FILL_COLOUR);
g2.fill(shape);
g2.setPaint(GUIConstants.SELECTION_LINE_COLOUR);
g2.draw(shape);
} else {
g2.setPaint(GUIConstants.ELEMENT_FILL_COLOUR);
g2.fill(shape);
g2.setPaint(GUIConstants.ELEMENT_LINE_COLOUR);
g2.draw(shape);
}
}
}
public boolean isDeleteable() {
int i = getIndex();
return i > 0 && i != arcPath.getNumPoints() - 1;
}
public void kill() {
// called internally by ArcPoint and parent ArcPath
super.removeFromContainer();
}
}