package com.kreative.paint.draw; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Area; import java.awt.geom.GeneralPath; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.Collection; import java.util.List; import com.kreative.paint.document.draw.ControlPoint; import com.kreative.paint.document.draw.ControlPointType; import com.kreative.paint.document.draw.DrawObject; import com.kreative.paint.document.draw.PaintSettings; public class ThreeDBoxDrawObject extends DrawObject { private double x1, y1, x2, y2, dx, dy; public ThreeDBoxDrawObject(PaintSettings ps, double x, double y, double w, double h, double dx, double dy) { super(ps); this.x1 = x; this.y1 = y; this.x2 = x + w; this.y2 = y + h; this.dx = dx; this.dy = dy; } private ThreeDBoxDrawObject(ThreeDBoxDrawObject o) { super(o); this.x1 = o.x1; this.y1 = o.y1; this.x2 = o.x2; this.y2 = o.y2; this.dx = o.dx; this.dy = o.dy; } @Override public ThreeDBoxDrawObject clone() { return new ThreeDBoxDrawObject(this); } public double getX() { return x1; } public double getY() { return y1; } public double getWidth() { return x2 - x1; } public double getHeight() { return y2 - y1; } public double getDX() { return dx; } public double getDY() { return dy; } @Override protected Shape getBoundaryImpl() { Shape[] ss = getShapes(x1, y1, x2 - x1, y2 - y1, dx, dy); Area a = new Area(); for (Shape s : ss) a.add(new Area(s)); return a; } @Override protected Shape getPostTxHitAreaImpl(AffineTransform tx) { Area a = new Area(); Shape[] ss = getShapes(x1, y1, x2 - x1, y2 - y1, dx, dy); for (Shape s : ss) { if (tx != null) { try { s = tx.createTransformedShape(s); } catch (Exception e) {} } if (ps.isFilled()) { a.add(new Area(s)); } if (ps.isDrawn()) { try { a.add(new Area(ps.drawStroke.createStrokedShape(s))); } catch (Exception e) {} } } return a; } @Override protected Object getControlState() { return new double[]{ x1, y1, x2, y2, dx, dy }; } @Override protected void setControlState(Object o) { double[] state = (double[])o; x1 = state[0]; y1 = state[1]; x2 = state[2]; y2 = state[3]; dx = state[4]; dy = state[5]; } @Override public int getControlPointCount() { return 10; } @Override protected ControlPoint getControlPointImpl(int i) { switch (i) { case 0: return new ControlPoint(ControlPointType.CENTER, (x1 + x2) / 2, (y1 + y2) / 2); case 1: return new ControlPoint(ControlPointType.NORTHWEST, x1, y1); case 2: return new ControlPoint(ControlPointType.NORTHEAST, x2, y1); case 3: return new ControlPoint(ControlPointType.SOUTHWEST, x1, y2); case 4: return new ControlPoint(ControlPointType.SOUTHEAST, x2, y2); case 5: return new ControlPoint(ControlPointType.NORTH, (x1 + x2) / 2, y1); case 6: return new ControlPoint(ControlPointType.SOUTH, (x1 + x2) / 2, y2); case 7: return new ControlPoint(ControlPointType.WEST, x1, (y1 + y2) / 2); case 8: return new ControlPoint(ControlPointType.EAST, x2, (y1 + y2) / 2); case 9: return new ControlPoint(ControlPointType.PULL_TAB, (x1 + x2) / 2 + dx, (y1 + y2) / 2 + dy); default: return null; } } @Override protected List<ControlPoint> getControlPointsImpl() { List<ControlPoint> cpts = new ArrayList<ControlPoint>(); cpts.add(new ControlPoint(ControlPointType.CENTER, (x1 + x2) / 2, (y1 + y2) / 2)); cpts.add(new ControlPoint(ControlPointType.NORTHWEST, x1, y1)); cpts.add(new ControlPoint(ControlPointType.NORTHEAST, x2, y1)); cpts.add(new ControlPoint(ControlPointType.SOUTHWEST, x1, y2)); cpts.add(new ControlPoint(ControlPointType.SOUTHEAST, x2, y2)); cpts.add(new ControlPoint(ControlPointType.NORTH, (x1 + x2) / 2, y1)); cpts.add(new ControlPoint(ControlPointType.SOUTH, (x1 + x2) / 2, y2)); cpts.add(new ControlPoint(ControlPointType.WEST, x1, (y1 + y2) / 2)); cpts.add(new ControlPoint(ControlPointType.EAST, x2, (y1 + y2) / 2)); cpts.add(new ControlPoint(ControlPointType.PULL_TAB, (x1 + x2) / 2 + dx, (y1 + y2) / 2 + dy)); return cpts; } @Override protected Collection<Line2D> getControlLinesImpl() { return null; } @Override protected int setControlPointImpl(int i, double x, double y) { switch (i) { case 0: double width2 = (x2 - x1) / 2; double height2 = (y2 - y1) / 2; x1 = x - width2; y1 = y - height2; x2 = x + width2; y2 = y + height2; break; case 1: x1 = x; y1 = y; break; case 2: x2 = x; y1 = y; break; case 3: x1 = x; y2 = y; break; case 4: x2 = x; y2 = y; break; case 5: y1 = y; break; case 6: y2 = y; break; case 7: x1 = x; break; case 8: x2 = x; break; case 9: dx = x - (x1 + x2) / 2; dy = y - (y1 + y2) / 2; break; } return i; } @Override protected Point2D getLocationImpl() { return new Point2D.Double(x1, y1); } @Override protected void setLocationImpl(double x, double y) { this.x2 = x + (this.x2 - this.x1); this.y2 = y + (this.y2 - this.y1); this.x1 = x; this.y1 = y; } @Override protected void preTxPaintImpl(Graphics2D g, AffineTransform tx) { Shape[] ss = getShapes(x1, y1, x2 - x1, y2 - y1, dx, dy); for (Shape s : ss) { if (tx != null) { try { s = tx.createTransformedShape(s); } catch (Exception e) {} } if (ps.isFilled()) { ps.applyFill(g); g.fill(s); } if (ps.isDrawn()) { ps.applyDraw(g); g.draw(s); } } } private static Shape[] getShapes(double x, double y, double w, double h, double dx, double dy) { double hypot = Math.hypot(dy, dx); double angle = Math.atan2(dy, dx); double x2 = x + hypot * (3 * Math.sqrt(2) * Math.cos(angle) - 1) / 4; double y2 = y + hypot * (3 * Math.sqrt(2) * Math.sin(angle) - 1) / 4; double w2 = w + hypot / 2; double h2 = h + hypot / 2; Shape[] p = new Shape[6]; p[0] = makeBack(x, y, w, h, x2, y2, w2, h2); if (dx < 0) { if (dy < 0) { // dx is negative, dy is negative // draw top and left panel, then right and bottom panel p[1] = makeTop(x, y, w, h, x2, y2, w2, h2); p[2] = makeLeft(x, y, w, h, x2, y2, w2, h2); p[3] = makeBottom(x, y, w, h, x2, y2, w2, h2); p[4] = makeRight(x, y, w, h, x2, y2, w2, h2); } else { // dx is negative, dy is positive // draw left and bottom panel, then top and right panel p[1] = makeLeft(x, y, w, h, x2, y2, w2, h2); p[2] = makeBottom(x, y, w, h, x2, y2, w2, h2); p[3] = makeTop(x, y, w, h, x2, y2, w2, h2); p[4] = makeRight(x, y, w, h, x2, y2, w2, h2); } } else { if (dy < 0) { // dx is positive, dy is negative // draw top and right panel, then left and bottom panel p[1] = makeTop(x, y, w, h, x2, y2, w2, h2); p[2] = makeRight(x, y, w, h, x2, y2, w2, h2); p[3] = makeLeft(x, y, w, h, x2, y2, w2, h2); p[4] = makeBottom(x, y, w, h, x2, y2, w2, h2); } else { // dx is positive, dy is positive // draw right and bottom panel, then top and left panel p[1] = makeBottom(x, y, w, h, x2, y2, w2, h2); p[2] = makeRight(x, y, w, h, x2, y2, w2, h2); p[3] = makeTop(x, y, w, h, x2, y2, w2, h2); p[4] = makeLeft(x, y, w, h, x2, y2, w2, h2); } } p[5] = makeFront(x, y, w, h, x2, y2, w2, h2); return p; } private static GeneralPath makeBack(double x, double y, double w, double h, double x2, double y2, double w2, double h2) { GeneralPath p = new GeneralPath(); p.moveTo(x, y); p.lineTo(x + w, y); p.lineTo(x + w, y + h); p.lineTo(x, y + h); p.closePath(); return p; } private static GeneralPath makeTop(double x, double y, double w, double h, double x2, double y2, double w2, double h2) { GeneralPath p = new GeneralPath(); p.moveTo(x2, y2); p.lineTo(x2 + w2, y2); p.lineTo(x + w, y); p.lineTo(x, y); p.closePath(); return p; } private static GeneralPath makeBottom(double x, double y, double w, double h, double x2, double y2, double w2, double h2) { GeneralPath p = new GeneralPath(); p.moveTo(x, y + h); p.lineTo(x + w, y + h); p.lineTo(x2 + w2, y2 + h2); p.lineTo(x2, y2 + h2); p.closePath(); return p; } private static GeneralPath makeLeft(double x, double y, double w, double h, double x2, double y2, double w2, double h2) { GeneralPath p = new GeneralPath(); p.moveTo(x2, y2); p.lineTo(x, y); p.lineTo(x, y + h); p.lineTo(x2, y2 + h2); p.closePath(); return p; } private static GeneralPath makeRight(double x, double y, double w, double h, double x2, double y2, double w2, double h2) { GeneralPath p = new GeneralPath(); p.moveTo(x + w, y); p.lineTo(x2 + w2, y2); p.lineTo(x2 + w2, y2 + h2); p.lineTo(x + w, y + h); p.closePath(); return p; } private static GeneralPath makeFront(double x, double y, double w, double h, double x2, double y2, double w2, double h2) { GeneralPath p = new GeneralPath(); p.moveTo(x2, y2); p.lineTo(x2 + w2, y2); p.lineTo(x2 + w2, y2 + h2); p.lineTo(x2, y2 + h2); p.closePath(); return p; } }