/** * Finds a control point index. Returns -1 if no control point could be found. FIXME - Move this * to BezierPath */ public int findNode(Point2D.Double p) { BezierPath tp = path; for (int i = 0; i < tp.size(); i++) { BezierPath.Node p2 = tp.get(i); if (p2.x[0] == p.x && p2.y[0] == p.y) { return i; } } return -1; }
@Override public <T> void set(AttributeKey<T> key, T newValue) { if (key == PATH_CLOSED) { path.setClosed((Boolean) newValue); } else if (key == WINDING_RULE) { path.setWindingRule( newValue == AttributeKeys.WindingRule.EVEN_ODD ? Path2D.Double.WIND_EVEN_ODD : Path2D.Double.WIND_NON_ZERO); } super.set(key, newValue); invalidate(); }
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); } }
/** * 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; }
/** Sets the point coordinate of control point 0 at the specified node. */ public void setPoint(int index, Point2D.Double p) { BezierPath.Node node = path.get(index); double dx = p.x - node.x[0]; double dy = p.y - node.y[0]; for (int i = 0; i < node.x.length; i++) { node.x[i] += dx; node.y[i] += dy; } invalidate(); }
@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(); }
@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; }
protected void readPoints(DOMInput in) throws IOException { path.clear(); in.openElement("points"); setClosed(in.getAttribute("closed", false)); for (int i = 0, n = in.getElementCount("p"); i < n; i++) { in.openElement("p", i); BezierPath.Node node = new BezierPath.Node( in.getAttribute("mask", 0), in.getAttribute("x", 0d), in.getAttribute("y", 0d), in.getAttribute("c1x", in.getAttribute("x", 0d)), in.getAttribute("c1y", in.getAttribute("y", 0d)), in.getAttribute("c2x", in.getAttribute("x", 0d)), in.getAttribute("c2y", in.getAttribute("y", 0d))); node.keepColinear = in.getAttribute("colinear", true); path.add(node); path.invalidatePath(); in.closeElement(); } in.closeElement(); }
@Override public Collection<Handle> createHandles(int detailLevel) { LinkedList<Handle> handles = new LinkedList<Handle>(); switch (detailLevel % 2) { case -1: // Mouse hover handles handles.add(new BezierOutlineHandle(this, true)); break; case 0: handles.add(new BezierOutlineHandle(this)); for (int i = 0, n = path.size(); i < n; i++) { handles.add(new BezierNodeHandle(this, i)); } break; case 1: TransformHandleKit.addTransformHandles(this, handles); handles.add(new BezierScaleHandle(this)); break; } return handles; }
@Override public Object getTransformRestoreData() { return path.clone(); }
@Override protected void validate() { super.validate(); path.invalidatePath(); cappedPath = null; }
/** Gets the node count. */ public int getNodeCount() { return path.size(); }
@Override public void restoreTransformTo(Object geometry) { path.setTo((BezierPath) geometry); }
@Override public void transform(AffineTransform tx) { path.transform(tx); invalidate(); }
/** Removes the Point2D.Double at the specified index. */ protected void removeAllNodes() { path.clear(); }
/** * Joins two segments into one if the given Point2D.Double hits a node of the polyline. * * @return true if the two segments were joined. */ public int joinSegments(Point2D.Double join, float tolerance) { return path.joinSegments(join, tolerance); }
@Override public void invalidate() { super.invalidate(); path.invalidatePath(); cappedPath = null; }
/** Gets the point coordinate of a control point. */ public Point2D.Double getPoint(int index, int coord) { return path.get(index).getControlPoint(coord); }
public Point2D.Double getCenter() { return path.getCenter(); }
/** * Convenience method for getting the point coordinate of the first control point of the specified * node. */ public Point2D.Double getPoint(int index) { return path.get(index).getControlPoint(0); }
/** Gets a control point. */ public BezierPath.Node getNode(int index) { return (BezierPath.Node) path.get(index).clone(); }
/** Sets a control point. */ public void setNode(int index, BezierPath.Node p) { path.set(index, p); invalidate(); }
/** Adds a node to the list of points. */ public void addNode(final int index, BezierPath.Node p) { path.add(index, p); invalidate(); }
public void setBezierPath(BezierPath newValue) { path = newValue.clone(); this.setClosed(newValue.isClosed()); }
public Point2D.Double getOutermostPoint() { return path.get(path.indexOfOutermostNode()).getControlPoint(0); }
/** Sets the point coordinate of a control point. */ public void setPoint(int index, int coord, Point2D.Double p) { BezierPath.Node cp = new BezierPath.Node(path.get(index)); cp.setControlPoint(coord, p); setNode(index, cp); }
/** * Splits the segment at the given Point2D.Double if a segment was hit. * * @return the index of the segment or -1 if no segment was hit. */ public int splitSegment(Point2D.Double split, float tolerance) { return path.splitSegment(split, tolerance); }
/** Returns a clone of the bezier path of this figure. */ public BezierPath getBezierPath() { return path.clone(); }
/** Removes the Node at the specified index. */ public BezierPath.Node removeNode(int index) { return path.remove(index); }
public Point2D.Double getPointOnPath(float relative, double flatness) { return path.getPointOnPath(relative, flatness); }