/** Constrains a point to the current grid. */ protected Point constrainPoint(Point p) { // constrain to view size Dimension size = getSize(); // p.x = Math.min(size.width, Math.max(1, p.x)); // p.y = Math.min(size.height, Math.max(1, p.y)); p.x = Geom.range(1, size.width, p.x); p.y = Geom.range(1, size.height, p.y); if (fConstrainer != null) { return fConstrainer.constrainPoint(p); } return p; }
/** * Returns a path which is cappedPath at the ends, to prevent it from drawing under the end caps. */ protected BezierPath getCappedPath() { if (cappedPath == null) { cappedPath = path.clone(); if (isClosed()) { cappedPath.setClosed(true); } else { if (cappedPath.size() > 1) { if (get(START_DECORATION) != null) { BezierPath.Node p0 = cappedPath.get(0); BezierPath.Node p1 = cappedPath.get(1); Point2D.Double pp; if ((p0.getMask() & BezierPath.C2_MASK) != 0) { pp = p0.getControlPoint(2); } else if ((p1.getMask() & BezierPath.C1_MASK) != 0) { pp = p1.getControlPoint(1); } else { pp = p1.getControlPoint(0); } double radius = get(START_DECORATION).getDecorationRadius(this); double lineLength = Geom.length(p0.getControlPoint(0), pp); cappedPath.set( 0, 0, Geom.cap(pp, p0.getControlPoint(0), -Math.min(radius, lineLength))); } if (get(END_DECORATION) != null) { BezierPath.Node p0 = cappedPath.get(cappedPath.size() - 1); BezierPath.Node p1 = cappedPath.get(cappedPath.size() - 2); Point2D.Double pp; if ((p0.getMask() & BezierPath.C1_MASK) != 0) { pp = p0.getControlPoint(1); } else if ((p1.getMask() & BezierPath.C2_MASK) != 0) { pp = p1.getControlPoint(2); } else { pp = p1.getControlPoint(0); } double radius = get(END_DECORATION).getDecorationRadius(this); double lineLength = Geom.length(p0.getControlPoint(0), pp); cappedPath.set( cappedPath.size() - 1, 0, Geom.cap(pp, p0.getControlPoint(0), -Math.min(radius, lineLength))); } cappedPath.invalidatePath(); } } } return cappedPath; }
@Override public boolean contains(Point2D.Double p) { double tolerance = Math.max(2f, AttributeKeys.getStrokeTotalWidth(this) / 2d); if (isClosed() || get(FILL_COLOR) != null && get(UNCLOSED_PATH_FILLED)) { if (path.contains(p)) { return true; } double grow = AttributeKeys.getPerpendicularHitGrowth(this) * 2d; GrowStroke gs = new GrowStroke(grow, AttributeKeys.getStrokeTotalWidth(this) * get(STROKE_MITER_LIMIT)); if (gs.createStrokedShape(path).contains(p)) { return true; } else { if (isClosed()) { return false; } } } if (!isClosed()) { if (getCappedPath().outlineContains(p, tolerance)) { return true; } if (get(START_DECORATION) != null) { BezierPath cp = getCappedPath(); Point2D.Double p1 = path.get(0, 0); Point2D.Double p2 = cp.get(0, 0); // FIXME - Check here, if caps path contains the point if (Geom.lineContainsPoint(p1.x, p1.y, p2.x, p2.y, p.x, p.y, tolerance)) { return true; } } if (get(END_DECORATION) != null) { BezierPath cp = getCappedPath(); Point2D.Double p1 = path.get(path.size() - 1, 0); Point2D.Double p2 = cp.get(path.size() - 1, 0); // FIXME - Check here, if caps path contains the point if (Geom.lineContainsPoint(p1.x, p1.y, p2.x, p2.y, p.x, p.y, tolerance)) { return true; } } } return false; }
public Rectangle2D.Double getDrawingArea() { double strokeTotalWidth = AttributeKeys.getStrokeTotalWidth(this); double width = strokeTotalWidth / 2d; if (STROKE_JOIN.get(this) == BasicStroke.JOIN_MITER) { width *= STROKE_MITER_LIMIT.get(this); } else if (STROKE_CAP.get(this) != BasicStroke.CAP_BUTT) { width += strokeTotalWidth * 2; } width++; Rectangle2D.Double r = getBounds(); Geom.grow(r, width, width); return r; }
public Point2D.Double chop(Point2D.Double p) { if (isClosed()) { double grow = AttributeKeys.getPerpendicularHitGrowth(this); if (grow == 0d) { return path.chop(p); } else { GrowStroke gs = new GrowStroke(grow, AttributeKeys.getStrokeTotalWidth(this) * get(STROKE_MITER_LIMIT)); return Geom.chop(gs.createStrokedShape(path), p); } } else { return path.chop(p); } }
@Override public Rectangle2D.Double getDrawingArea() { if (cachedDrawingArea == null) { Rectangle2D rx = getBounds(); Rectangle2D.Double r = (rx instanceof Rectangle2D.Double) ? (Rectangle2D.Double) rx : new Rectangle2D.Double(rx.getX(), rx.getY(), rx.getWidth(), rx.getHeight()); double g = SVGAttributeKeys.getPerpendicularHitGrowth(this); Geom.grow(r, g, g); if (TRANSFORM.get(this) == null) { cachedDrawingArea = r; } else { cachedDrawingArea = new Rectangle2D.Double(); cachedDrawingArea.setRect(TRANSFORM.get(this).createTransformedShape(r).getBounds2D()); } } return (Rectangle2D.Double) cachedDrawingArea.clone(); }
@Override public Rectangle2D.Double getDrawingArea() { if (cachedDrawingArea == null) { if (get(TRANSFORM) == null) { cachedDrawingArea = path.getBounds2D(); } else { BezierPath p2 = (BezierPath) path.clone(); p2.transform(get(TRANSFORM)); cachedDrawingArea = p2.getBounds2D(); } double strokeTotalWidth = AttributeKeys.getStrokeTotalWidth(this); double width = strokeTotalWidth / 2d; if (get(STROKE_JOIN) == BasicStroke.JOIN_MITER) { width *= get(STROKE_MITER_LIMIT); } else if (get(STROKE_CAP) != BasicStroke.CAP_BUTT) { width += strokeTotalWidth * 2; } Geom.grow(cachedDrawingArea, width, width); } return (Rectangle2D.Double) cachedDrawingArea.clone(); }
/** Gets the drawing area without taking the decorator into account. */ @Override protected Rectangle2D.Double getFigureDrawingArea() { if (getText() == null) { return getBounds(); } else { TextLayout layout = getTextLayout(); Rectangle2D.Double r = new Rectangle2D.Double(origin.x, origin.y, layout.getAdvance(), layout.getAscent()); Rectangle2D lBounds = layout.getBounds(); if (!lBounds.isEmpty() && !Double.isNaN(lBounds.getX())) { r.add( new Rectangle2D.Double( lBounds.getX() + origin.x, (lBounds.getY() + origin.y + layout.getAscent()), lBounds.getWidth(), lBounds.getHeight())); } // grow by two pixels to take antialiasing into account Geom.grow(r, 2d, 2d); return r; } }
public void lineout(ConnectionFigure figure) { BezierPath path = ((LineConnectionFigure) figure).getBezierPath(); Connector start = figure.getStartConnector(); Connector end = figure.getEndConnector(); if (start == null || end == null || path == null) { return; } // Special treatment if the connection connects the same figure if (figure.getStartFigure() == figure.getEndFigure()) { // Ensure path has exactly 4 nodes while (path.size() < 4) { path.add(1, new BezierPath.Node(0, 0)); } while (path.size() > 4) { path.remove(1); } Point2D.Double sp = start.findStart(figure); Point2D.Double ep = end.findEnd(figure); Rectangle2D.Double sb = start.getBounds(); Rectangle2D.Double eb = end.getBounds(); int soutcode = sb.outcode(sp); if (soutcode == 0) { soutcode = Geom.outcode(sb, eb); } int eoutcode = eb.outcode(ep); if (eoutcode == 0) { eoutcode = Geom.outcode(sb, eb); } path.get(0).moveTo(sp); path.get(path.size() - 1).moveTo(ep); switch (soutcode) { case Geom.OUT_TOP: eoutcode = Geom.OUT_LEFT; break; case Geom.OUT_RIGHT: eoutcode = Geom.OUT_TOP; break; case Geom.OUT_BOTTOM: eoutcode = Geom.OUT_RIGHT; break; case Geom.OUT_LEFT: eoutcode = Geom.OUT_BOTTOM; break; default: eoutcode = Geom.OUT_TOP; soutcode = Geom.OUT_RIGHT; break; } // path.get(0).moveTo(sp.x + shoulderSize, sp.y); path.get(0).mask = BezierPath.C2_MASK; if ((soutcode & Geom.OUT_RIGHT) != 0) { path.get(0).x[2] = sp.x + shoulderSize; path.get(0).y[2] = sp.y; } else if ((soutcode & Geom.OUT_LEFT) != 0) { path.get(0).x[2] = sp.x - shoulderSize; path.get(0).y[2] = sp.y; } else if ((soutcode & Geom.OUT_BOTTOM) != 0) { path.get(0).x[2] = sp.x; path.get(0).y[2] = sp.y + shoulderSize; } else { path.get(0).x[2] = sp.x; path.get(0).y[2] = sp.y - shoulderSize; } path.get(1).mask = BezierPath.C2_MASK; path.get(1).moveTo(sp.x + shoulderSize, (sp.y + ep.y) / 2); path.get(1).x[2] = sp.x + shoulderSize; path.get(1).y[2] = ep.y - shoulderSize; path.get(2).mask = BezierPath.C1_MASK; path.get(2).moveTo((sp.x + ep.x) / 2, ep.y - shoulderSize); path.get(2).x[1] = sp.x + shoulderSize; path.get(2).y[1] = ep.y - shoulderSize; path.get(3).mask = BezierPath.C1_MASK; if ((eoutcode & Geom.OUT_RIGHT) != 0) { path.get(3).x[1] = ep.x + shoulderSize; path.get(3).y[1] = ep.y; } else if ((eoutcode & Geom.OUT_LEFT) != 0) { path.get(3).x[1] = ep.x - shoulderSize; path.get(3).y[1] = ep.y; } else if ((eoutcode & Geom.OUT_BOTTOM) != 0) { path.get(3).x[1] = ep.x; path.get(3).y[1] = ep.y + shoulderSize; } else { path.get(3).x[1] = ep.x; path.get(3).y[1] = ep.y - shoulderSize; } } else { Point2D.Double sp = start.findStart(figure); Point2D.Double ep = end.findEnd(figure); path.clear(); if (sp.x == ep.x || sp.y == ep.y) { path.add(new BezierPath.Node(ep.x, ep.y)); } else { Rectangle2D.Double sb = start.getBounds(); sb.x += 5d; sb.y += 5d; sb.width -= 10d; sb.height -= 10d; Rectangle2D.Double eb = end.getBounds(); eb.x += 5d; eb.y += 5d; eb.width -= 10d; eb.height -= 10d; int soutcode = sb.outcode(sp); if (soutcode == 0) { soutcode = Geom.outcode(sb, eb); } int eoutcode = eb.outcode(ep); if (eoutcode == 0) { eoutcode = Geom.outcode(eb, sb); } if ((soutcode & (Geom.OUT_TOP | Geom.OUT_BOTTOM)) != 0 && (eoutcode & (Geom.OUT_TOP | Geom.OUT_BOTTOM)) != 0) { path.add( new BezierPath.Node( BezierPath.C2_MASK, sp.x, sp.y, sp.x, sp.y, sp.x, (sp.y + ep.y) / 2)); path.add( new BezierPath.Node( BezierPath.C1_MASK, ep.x, ep.y, ep.x, (sp.y + ep.y) / 2, ep.x, ep.y)); } else if ((soutcode & (Geom.OUT_LEFT | Geom.OUT_RIGHT)) != 0 && (eoutcode & (Geom.OUT_LEFT | Geom.OUT_RIGHT)) != 0) { path.add( new BezierPath.Node( BezierPath.C2_MASK, sp.x, sp.y, sp.x, sp.y, (sp.x + ep.x) / 2, sp.y)); path.add( new BezierPath.Node( BezierPath.C1_MASK, ep.x, ep.y, (sp.x + ep.x) / 2, ep.y, ep.x, ep.y)); } else if (soutcode == Geom.OUT_BOTTOM || soutcode == Geom.OUT_TOP) { path.add(new BezierPath.Node(BezierPath.C2_MASK, sp.x, sp.y, sp.x, sp.y, sp.x, ep.y)); path.add(new BezierPath.Node(ep.x, ep.y)); } else { path.add(new BezierPath.Node(BezierPath.C2_MASK, sp.x, sp.y, sp.x, sp.y, ep.x, sp.y)); path.add(new BezierPath.Node(ep.x, ep.y)); } } } path.invalidatePath(); }