package es.iiia.shapegrammar.shape;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import org.eclipse.ui.views.properties.IPropertySource;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import es.iiia.shapegrammar.model.GeometryModel;
import es.iiia.shapegrammar.model.GeometryPropertySource;
import es.iiia.shapegrammar.model.IModifyByPoint;
import es.iiia.shapegrammar.model.NodeModel;
import es.iiia.shapegrammar.utils.MathUtils;
import es.iiia.shapegrammar.utils.XmlUtils;
public class LineGroupModel extends GeometryModel implements IModifyByPoint {
private AffineTransform currentTransform;
private ArrayList<Point2D> points;
public LineGroupModel() {
}
public LineGroupModel(Element config) {
super(config);
this.setName(config.getAttribute("name"));
this.currentTransform = parseTransform(config);
// init points
NodeList content = config.getChildNodes();
for (int i = 0; i < content.getLength(); i++) {
if (content.item(i) instanceof Element) {
this.addChild(new LineModel((Element) content.item(i)));
}
}
}
@Override
public Element getXml() {
Element root = XmlUtils.createXml("lineGroup");
// set id
root.setAttribute("id", Integer.toString(this.getId()));
// set color
root.setAttribute("color", getColorString());
// set name
root.setAttribute("name", this.getName());
appendTransform(getCurrentTransform(), root);
for (NodeModel line : this.getChildrenArray()) {
root.appendChild(root.getOwnerDocument().importNode(((LineModel)line).getXml(), true));
}
return root;
}
@Override
public LineGroupModel clone() {
// Create new model
LineGroupModel model = new LineGroupModel();
model.setId(this.getId());
model.setName(this.getName());
model.currentTransform = new AffineTransform(this.currentTransform);
// Clone all point
for (LineModel line : this.getLines()) {
model.addChild(line.clone());
}
return model;
}
public ArrayList<LineModel> getLines() {
// TODO: Optimize !!!
ArrayList<LineModel> list = new ArrayList<LineModel>();
for (NodeModel line : this.getChildrenArray()) {
list.add((LineModel) line);
}
return list;
}
// public void setLine(int index, ArrayList<PointModel> points) {
// ((LineModel)this.getChildrenArray().get(index)).setPoints(points);
//
// this.fireChangeListeners(null, this.points);
// }
// public void translate(PointModel point) {
// this.translate(point.x, point.y);
//
// this.fireChangeListeners(null, point);
// }
@Override
public void translate(double x, double y) {
for (int i=0; i<this.getLines().size(); i++)
(this.getLines().get(i)).translate(x, y);
this.fireChangeListeners(null, this.getChildrenArray());
}
@Override
public void transform(AffineTransform transform) {
for (LineModel line : this.getLines()) {
line.transform(transform);
}
// remember current transform
this.getCurrentTransform().preConcatenate(transform);
// notify listeners
this.fireChangeListeners(null, transform);
}
public Point2D getLocation() {
return new Point2D.Double(
this.getBounds().getCenterX(),
this.getBounds().getCenterY());
}
public Rectangle getBounds() {
ArrayList<LineModel> lines = this.getLines();
if (lines.size() > 0) {
Rectangle rect = new Rectangle((int)lines.get(0).getP1().getX(), (int)lines.get(0).getP1().getY(), 0, 0);
for (LineModel line : lines) {
rect.add(line.getP1().getX(), line.getP1().getY());
rect.add(line.getP2().getX(), line.getP2().getY());
}
return rect;
}
return new Rectangle();
}
public void setLocation(Point2D p) {
// public PointModel getDifference(PointModel pt) {
// return new PointModel(this.x - pt.x, this.y - pt.y);
// }
Point2D diff = MathUtils.difference(this.getLocation(), p);
this.translate(diff.getX(), diff.getY());
}
// these methods are specific to VWBT .. shame, I know
private AffineTransform getCurrentTransform() {
if (currentTransform == null) {
currentTransform = new AffineTransform();
}
return currentTransform;
}
public double getCurrentAngleRad() {
// returns in degrees
// atan(-m00/m01)
if ((currentTransform.getScaleX() < 0 && currentTransform.getShearX() == 0) ||
(currentTransform.getScaleY() < 0 && currentTransform.getShearY() == 0)) {
return Math.PI;
} else if (currentTransform.getScaleX() < 0 && currentTransform.getScaleY() > 0 ||
currentTransform.getScaleX() > 0 && currentTransform.getScaleY() < 0) {
return - Math.atan(-currentTransform.getShearX() / currentTransform.getScaleX());
}
return Math.atan(-currentTransform.getShearX() / currentTransform.getScaleX());
}
public double getCurrentAngleDeg() {
// returns in degrees
// atan(-m00/m01) * (180/PI)
return getCurrentAngleRad() * (180/Math.PI);
}
public double[] getCurrentResize() {
// m00 / angle
double[] resize = new double[2];
resize[0] = Math.abs(getCurrentTransform().getScaleX() / Math.cos(getCurrentAngleRad()));
resize[1] = Math.abs(getCurrentTransform().getScaleY() / Math.cos(getCurrentAngleRad()));
return resize;
}
public double[] getCurrentTranslate() {
double[] resize = new double[2];
resize[0] = getCurrentTransform().getTranslateX();
resize[1] = getCurrentTransform().getTranslateY();
return resize;
}
public static void appendTransform(AffineTransform transform, Node root) {
if (transform != null) {
double[] matrix = new double[6];
transform.getMatrix(matrix);
XmlUtils.appendAttribute(root, "transform", matrix[0] + "," + matrix[2] + ","
+ matrix[4] + "," + matrix[1] + "," + matrix[3] + "," + matrix[5]);
}
}
public static AffineTransform parseTransform(Element content) {
String transValue = content.getAttribute("transform");
if (transValue != null && transValue.length() > 0) {
String[] trans = transValue.split(",");
return new AffineTransform(Double.parseDouble(trans[0]), Double
.parseDouble(trans[3]), Double.parseDouble(trans[1]), Double
.parseDouble(trans[4]), Double.parseDouble(trans[2]), Double
.parseDouble(trans[5]));
}
return null;
}
public ArrayList<Point2D> getPoints() {
if (this.points == null || this.points.size() == 0) {
this.points = new ArrayList<Point2D>();
for (LineModel model : this.getLines()) {
for (Point2D point : model.getPoints()) {
this.points.add(point);
}
}
}
return points;
}
@Override
public Object getAdapter(Class adapter) {
if (adapter == IPropertySource.class) {
if (propertySource == null)
propertySource = new GeometryPropertySource(this);
return propertySource;
}
return null;
}
public void setPoint(int index, Point2D point) {
getPoints().get(index).setLocation(point);
}
}