private void paintMatcher(Graphics2D g, Color fillClr, int leftX, int rightX, int upL, int upR, int doR, int doL) { int topY = Math.min(upL, upR), bottomY = Math.max(doL, doR); // try rendering only curves in viewable area if (!g.hitClip(leftX, topY, rightX - leftX, bottomY - topY)) { return; } CubicCurve2D upper = new CubicCurve2D.Float(leftX, upL, (rightX -leftX)*.3f, upL, (rightX -leftX)*.7f, upR, rightX, upR); CubicCurve2D bottom = new CubicCurve2D.Float(rightX, doR, (rightX - leftX)*.7f, doR, (rightX -leftX)*.3f, doL, leftX, doL); GeneralPath path = new GeneralPath(); path.append(upper, false); path.append(bottom, true); path.closePath(); g.setColor(fillClr); g.fill(path); g.setColor(master.getColorLines()); g.draw(upper); g.draw(bottom); }
/** Chop the start of this curve. */ public void chopStart(double t) { int n = list.size(); t = t * n; double di = StrictMath.floor(t); int i = (int) di; // if (i < 0) return; if (i >= n) list.clear(); while (i > 0 && !list.isEmpty()) { list.remove(0); i--; } if (list.isEmpty()) { list.add(new CubicCurve2D.Double(startX = endX, startY = endY, endX, endY, endX, endY, endX, endY)); return; } CubicCurve2D.Double tmp = new CubicCurve2D.Double(); divide(t - di, list.get(0), new CubicCurve2D.Double(), tmp); list.get(0).setCurve(tmp); startX = tmp.x1; startY = tmp.y1; }
/** Chop the end of this curve. */ public void chopEnd(double t) { int n = list.size(); t = t * n; double di = StrictMath.floor(t); int i = (int) di; // if (i < 0) list.clear(); if (i >= n) return; while (i + 1 < list.size()) list.remove(i + 1); if (list.isEmpty()) { endX = startX; endY = startY; list.add(new CubicCurve2D.Double(endX, endY, endX, endY, endX, endY, endX, endY)); return; } CubicCurve2D.Double tmp = new CubicCurve2D.Double(); divide(t - di, list.get(i), tmp, new CubicCurve2D.Double()); list.get(i).setCurve(tmp); endX = tmp.x2; endY = tmp.y2; }
/** * Given 0<=t<=1 and an existing curve, divide it into two chunks and store * the two chunks into "first" and "second" */ public static void divide(double t, CubicCurve2D.Double curve, CubicCurve2D.Double first, CubicCurve2D.Double second) { // This algorithm uses de Casteljau's algorithm for chopping one bezier // curve into two bezier curves first.x1 = curve.x1; second.x2 = curve.x2; first.ctrlx1 = (1 - t) * curve.x1 + t * curve.ctrlx1; double x = (1 - t) * curve.ctrlx1 + t * curve.ctrlx2; second.ctrlx2 = (1 - t) * curve.ctrlx2 + t * curve.x2; first.ctrlx2 = (1 - t) * first.ctrlx1 + t * x; second.ctrlx1 = (1 - t) * x + t * second.ctrlx2; second.x1 = first.x2 = (1 - t) * first.ctrlx2 + t * second.ctrlx1; // now that we've computed the x coordinates, we now compute the y // coordinates first.y1 = curve.y1; second.y2 = curve.y2; first.ctrly1 = (1 - t) * curve.y1 + t * curve.ctrly1; double y = (1 - t) * curve.ctrly1 + t * curve.ctrly2; second.ctrly2 = (1 - t) * curve.ctrly2 + t * curve.y2; first.ctrly2 = (1 - t) * first.ctrly1 + t * y; second.ctrly1 = (1 - t) * y + t * second.ctrly2; second.y1 = first.y2 = (1 - t) * first.ctrly2 + t * second.ctrly1; }
/** Draws the given curve smoothly (assuming the curve is monotonic vertically) */ public void drawSmoothly(Curve curve) { final int smooth=15; double cx=0, cy=0, slope; for(int n=curve.list.size(), i=0; i<n; i++) { CubicCurve2D.Double c=new CubicCurve2D.Double(), c2=(i+1<n)?curve.list.get(i+1):null; c.setCurve(curve.list.get(i)); if (i>0) { c.ctrlx1=cx; c.ctrly1=cy; } if (c2==null) { draw(c,false); return; } if ((c.x1<c.x2 && c2.x2<c2.x1) || (c.x1>c.x2 && c2.x2>c2.x1)) slope=0; else slope=(c2.x2-c.x1)/(c2.y2-c.y1); double tmp=c.y2-smooth, tmpx=c.x2-smooth*slope; if (tmp>c.ctrly1 && tmp<c.y2 && in(c.x1, tmpx, c.x2)) { c.ctrly2=tmp; c.ctrlx2=tmpx; } double tmp2=c2.y1+smooth, tmp2x=c2.x1+smooth*slope; if (tmp2>c2.y1 && tmp2<c2.ctrly2 && in(c2.x1, tmp2x, c2.x2)) { cy=tmp2; cx=tmp2x; } else { cy=c2.ctrly1; cx=c2.ctrlx1; } draw(c,false); } }
/** Chop the start of this curve. */ public void chopStart(double t) { int n=list.size(); t=t*n; double di=StrictMath.floor(t); int i=(int)di; // if (i<0) return; if (i>=n) list.clear(); while(i>0 && !list.isEmpty()) { list.remove(0); i--; } if (list.isEmpty()) { list.add(new CubicCurve2D.Double(startX=endX, startY=endY, endX,endY, endX,endY, endX,endY)); return; } CubicCurve2D.Double tmp=new CubicCurve2D.Double(); divide(t-di, list.get(0), new CubicCurve2D.Double(), tmp); list.get(0).setCurve(tmp); startX=tmp.x1; startY=tmp.y1; }
/** Chop the end of this curve. */ public void chopEnd(double t) { int n=list.size(); t=t*n; double di=StrictMath.floor(t); int i=(int)di; // if (i<0) list.clear(); if (i>=n) return; while(i+1<list.size()) list.remove(i+1); if (list.isEmpty()) { endX=startX; endY=startY; list.add(new CubicCurve2D.Double(endX,endY, endX,endY, endX,endY, endX,endY)); return; } CubicCurve2D.Double tmp=new CubicCurve2D.Double(); divide(t-di, list.get(i), tmp, new CubicCurve2D.Double()); list.get(i).setCurve(tmp); endX=tmp.x2; endY=tmp.y2; }
/** Given 0<=t<=1 and an existing curve, divide it into two chunks and store the two chunks into "first" and "second" */ public static void divide(double t, CubicCurve2D.Double curve, CubicCurve2D.Double first, CubicCurve2D.Double second) { // This algorithm uses de Casteljau's algorithm for chopping one bezier curve into two bezier curves first.x1 = curve.x1; second.x2 = curve.x2; first.ctrlx1 = (1-t)*curve.x1 + t*curve.ctrlx1; double x = (1-t)*curve.ctrlx1 + t*curve.ctrlx2; second.ctrlx2 = (1-t)*curve.ctrlx2 + t*curve.x2; first.ctrlx2 = (1-t)*first.ctrlx1 + t*x; second.ctrlx1 = (1-t)*x + t*second.ctrlx2; second.x1 = first.x2 = (1-t)*first.ctrlx2 + t*second.ctrlx1; // now that we've computed the x coordinates, we now compute the y coordinates first.y1 = curve.y1; second.y2 = curve.y2; first.ctrly1 = (1-t)*curve.y1 + t*curve.ctrly1; double y = (1-t)*curve.ctrly1 + t*curve.ctrly2; second.ctrly2 = (1-t)*curve.ctrly2 + t*curve.y2; first.ctrly2 = (1-t)*first.ctrly1 + t*y; second.ctrly1 = (1-t)*y + t*second.ctrly2; second.y1 = first.y2 = (1-t)*first.ctrly2 + t*second.ctrly1; }
public Shape getRegiaoDocumento() { if (Regiao == null) { final int v1 = getHeight() / 3; final int h1 = getWidth() / 2; final int repo = v1 / 3; final int L = getLeft(); final int T = getTop(); final int TH = T + getHeight() - repo; final int LW = L + getWidth(); CubicCurve2D c = new CubicCurve2D.Double(); c.setCurve(L, TH, L + h1, TH + v1, LW - h1, TH - v1, LW, TH); GeneralPath pa = new GeneralPath(); pa.moveTo(LW, TH); pa.lineTo(LW, T); pa.lineTo(L, T); pa.lineTo(L, TH); pa.append(c, true); Regiao = pa; final int ptToMove = 3; this.reposicionePonto[ptToMove] = new Point(0, -repo); ptsToMove[ptToMove] = 1; } return Regiao; }
@Override public Shape getRegiao() { if (Regiao == null) { final int v1 = getHeight() / 3; final int h1 = getWidth() / 2; final int repo = v1 / 3; final int L = getLeft(); final int T = getTop(); final int TH = T + getHeight() - repo; final int LW = L + getWidth(); CubicCurve2D c = new CubicCurve2D.Double(); c.setCurve(L, TH, L + h1, TH + v1, LW - h1, TH - v1, LW, TH); GeneralPath pa = new GeneralPath(); pa.moveTo(LW, TH); pa.lineTo(LW, T); pa.lineTo(L, T); pa.lineTo(L, TH); pa.append(c, true); Regiao = pa; setReposicionePontoAbaixo(new Point(0, -repo)); ptsToMove[ptToMove] = 1; } return Regiao; }
@Override protected void paint (Graphics2D g, Params p, Point location, Alignment alignment) { Point loc = alignment.translatedPoint(TOP_LEFT, p.rect, location); CubicCurve2D curve = new CubicCurve2D.Double( loc.x, loc.y + p.rect.height, loc.x + ((3 * p.rect.width) / 10), loc.y + (p.rect.height / 5), loc.x + (p.rect.width / 2), loc.y, loc.x + p.rect.width, loc.y); // Slur g.draw(curve); }
public void drawRoute(Graphics2D g, double lon1, double lat1, double lon2, double lat2, boolean straight, boolean dashed) { int x1 = translateLongitudeToX(lon1); int y1 = translateLatitudeToY(lat1); int x2 = translateLongitudeToX(lon2); int y2 = translateLatitudeToY(lat2); if (dashed) { g.setStroke(TangoColorFactory.FAT_DASHED_STROKE); } if (straight) { g.drawLine(x1, y1, x2, y2); } else { double xDistPart = (x2 - x1) / 3.0; double yDistPart = (y2 - y1) / 3.0; double ctrlx1 = x1 + xDistPart + yDistPart; double ctrly1 = y1 - xDistPart + yDistPart; double ctrlx2 = x2 - xDistPart - yDistPart; double ctrly2 = y2 + xDistPart - yDistPart; g.draw(new CubicCurve2D.Double(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2)); } if (dashed) { g.setStroke(TangoColorFactory.NORMAL_STROKE); } }
@Override public void draw(DrawRequest r) { Graphics2D g = r.getGraphics(); PartialCurveInfo curveInfo = getCurveInfo(); CubicCurve2D visibleCurve = getVisibleCurve(); Color color = Coloriser.colorise(connectionInfo.getDrawColor(), r.getDecoration().getColorisation()); g.setColor(color); g.setStroke(connectionInfo.getStroke()); g.draw(visibleCurve); if (connectionInfo.hasArrow()) { DrawHelper.drawArrowHead(g, curveInfo.headPosition, curveInfo.headOrientation, connectionInfo.getArrowLength(), connectionInfo.getArrowWidth(), color); } if (connectionInfo.hasBubble()) { DrawHelper.drawBubbleHead(g, curveInfo.headPosition, curveInfo.headOrientation, connectionInfo.getBubbleSize(), color, connectionInfo.getStroke()); } }
@Override public Point2D getNearestPointOnCurve(Point2D pt) { // FIXME: should be done using some proper algorithm CubicCurve2D curve = getCurve(); Point2D nearest = new Point2D.Double(curve.getX1(), curve.getY1()); double nearestDist = Double.MAX_VALUE; for (double t = 0.01; t <= 1.0; t += 0.01) { Point2D samplePoint = Geometry.getPointOnCubicCurve(curve, t); double distance = pt.distance(samplePoint); if (distance < nearestDist) { nearestDist = distance; nearest = samplePoint; } } return nearest; }
/** * Draws random cubic curves within the given dimensions. * * @param g The Graphics2D object that is used to paint. * @param size The size of the canvas. */ private void test_drawCubicCurve(Graphics2D g, Dimension size) { int maxTests = testSize; int minSize = 10; long startTime = System.currentTimeMillis(); for (int i = 0; i < maxTests; i += 1) { setRandom(g, size); int x1 = (int) (Math.random() * (size.width - minSize)); int y1 = (int) (Math.random() * (size.height - minSize)); int xc1 = (int) (Math.random() * (size.width - minSize)); int yc1 = (int) (Math.random() * (size.height - minSize)); int xc2 = (int) (Math.random() * (size.width - minSize)); int yc2 = (int) (Math.random() * (size.height - minSize)); int x2 = (int) (Math.random() * (size.width - minSize)); int y2 = (int) (Math.random() * (size.height - minSize)); CubicCurve2D curve = new CubicCurve2D.Double(x1, y1, xc1, yc1, xc2, yc2, x2, y2); g.draw(curve); } long endTime = System.currentTimeMillis(); recordTest("draw(CubicCurve2D.Double) " + maxTests + " times", (endTime - startTime)); }
private static void subdivide(CubicCurve2D src, CubicCurve2D left, CubicCurve2D right, final double coef) { final double coef1 = coef; final double coef2 = 1 - coef; final double centerxA = src.getCtrlX1() * coef1 + src.getCtrlX2() * coef2; final double centeryA = src.getCtrlY1() * coef1 + src.getCtrlY2() * coef2; final double x1 = src.getX1(); final double y1 = src.getY1(); final double x2 = src.getX2(); final double y2 = src.getY2(); final double ctrlx1 = x1 * coef1 + src.getCtrlX1() * coef1; final double ctrly1 = y1 * coef1 + src.getCtrlY1() * coef1; final double ctrlx2 = x2 * coef1 + src.getCtrlX2() * coef1; final double ctrly2 = y2 * coef1 + src.getCtrlY2() * coef1; final double ctrlx12 = ctrlx1 * coef1 + centerxA * coef1; final double ctrly12 = ctrly1 * coef1 + centeryA * coef1; final double ctrlx21 = ctrlx2 * coef1 + centerxA * coef1; final double ctrly21 = ctrly2 * coef1 + centeryA * coef1; final double centerxB = ctrlx12 * coef1 + ctrlx21 * coef1; final double centeryB = ctrly12 * coef1 + ctrly21 * coef1; left.setCurve(x1, y1, ctrlx1, ctrly1, ctrlx12, ctrly12, centerxB, centeryB); right.setCurve(centerxB, centeryB, ctrlx21, ctrly21, ctrlx2, ctrly2, x2, y2); }
public ArrayList<Shape> getCurves(){ ArrayList<Shape> s = new ArrayList<Shape>(); for (int i = 0; i < N()-1; i++) { CubicCurve2D.Double cubic = new CubicCurve2D.Double(get(i).getX(), get(i).getY(), cP[2*getIndex(i)].getX(), cP[2*getIndex(i)].getY(), cP[2*getIndex(i)+1].getX(), cP[2*getIndex(i)+1].getY(), get(i+1).getX(), get(i+1).getY()); s.add(cubic); } return s; }
public CubicCurve2D getCurveAt(int i){ if (i < 0 || i >= N() - 1 ) throw new IndexOutOfBoundsException( String.format("Interpolation Class: cannot " + "retrieve curve with index : %d" , i)); CubicCurve2D.Double cubic = new CubicCurve2D.Double( get(i).getX(), get(i).getY(), cP[2*getIndex(i)].getX(), cP[2*getIndex(i)].getY(), cP[2*getIndex(i)+1].getX(), cP[2*getIndex(i)+1].getY(), get(i+1).getX(), get(i+1).getY()); return cubic; }
protected int maxIndex(ArrayList<Point2D> p, int init, int end, CubicCurve2D curve) { int index = -1; if (init > end) return index; if (end-init <= PIXEL_STEPS) return index; double max=0; for (int i = init+1; i < end; i++){ Point2D pn = new Point2D.Double(); double sqDis = NearestPoint.onCurve(curve,p.get(i),pn ); if (sqDis > max){ max = sqDis; index = i; } } return (max > THRESHOLD)?index: -1; }
public CubicCurve2D getCurveAt(int i){ if (i < 0 || i >= N() - 1 ) throw new IndexOutOfBoundsException( String.format("Interpolation Class: cannot " + "retrieve curve with index : %d" , i)); CubicCurve2D.Double cubic = new CubicCurve2D.Double( get(i).getX(), get(i).getY(), cP[2*i].getX(), cP[2*i].getY(), cP[2*i+1].getX(), cP[2*i+1].getY(), get(i+1).getX(), get(i+1).getY()); return cubic; }
public ArrayList<Shape> getCurves(){ ArrayList<Shape> s = new ArrayList<Shape>(); for (int i = 0; i < N()-1; i++) { CubicCurve2D.Double cubic = new CubicCurve2D.Double(get(i).getX(), get(i).getY(), cP[2*i].getX(), cP[2*i].getY(), cP[2*i+1].getX(), cP[2*i+1].getY(), get(i+1).getX(), get(i+1).getY()); s.add(cubic); } return s; }
public void drawNoteTie(Note note1, Note note2) { g.setStroke(music_stroke_tie); float grid = getGridSize(); float y1 = cy - (note1.note*grid*0.5f); float y2 = cy - (note2.note*grid*0.5f); float x1 = note1.x + grid*0.5f; float x2 = note2.x + grid*0.5f; CubicCurve2D.Float curve = new CubicCurve2D.Float( x1,y1, x1,y1+grid*1f, x2,y2+grid*1f, x2,y2); g.draw(curve); }
public PointDirected getIntersection(CubicCurve2D.Double bez) { if (contains(bez.x1, bez.y1) == contains(bez.x2, bez.y2)) { return null; } final double dist = bez.getP1().distance(bez.getP2()); if (dist < 2) { final double angle = BezierUtils.getStartingAngle(bez); return new PointDirected(bez.getP1(), angle); } final CubicCurve2D.Double left = new CubicCurve2D.Double(); final CubicCurve2D.Double right = new CubicCurve2D.Double(); bez.subdivide(left, right); final PointDirected int1 = getIntersection(left); if (int1 != null) { return int1; } final PointDirected int2 = getIntersection(right); if (int2 != null) { return int2; } throw new IllegalStateException(); }
public double getMinDist(Point2D ref) { double result = Double.MAX_VALUE; for (CubicCurve2D.Double c : beziers) { final double d1 = ref.distance(c.x1, c.y1); if (d1 < result) { result = d1; } final double d2 = ref.distance(c.x2, c.y2); if (d2 < result) { result = d2; } final double d3 = ref.distance(c.ctrlx1, c.ctrly1); if (d3 < result) { result = d3; } final double d4 = ref.distance(c.ctrlx2, c.ctrly2); if (d4 < result) { result = d4; } } return result; }
private Point2D getFrontierIntersection(Shape shape, Rectangle2D... notIn) { final List<CubicCurve2D.Double> all = new ArrayList<CubicCurve2D.Double>(beziers); for (int i = 0; i < 8; i++) { for (CubicCurve2D.Double immutable : all) { if (contains(immutable, notIn)) { continue; } final CubicCurve2D.Double bez = new CubicCurve2D.Double(); bez.setCurve(immutable); if (BezierUtils.isCutting(bez, shape)) { while (BezierUtils.dist(bez) > 1.0) { BezierUtils.shorten(bez, shape); } final Point2D.Double result = new Point2D.Double((bez.x1 + bez.x2) / 2, (bez.y1 + bez.y2) / 2); if (contains(result, notIn) == false) { return result; } } } cutAllCubic(all); } throw new IllegalArgumentException("shape=" + shape); }
private DotPath manageRect(Rectangle2D start, Rectangle2D end) { final List<CubicCurve2D.Double> list = new ArrayList<CubicCurve2D.Double>(this.beziers); while (true) { if (BezierUtils.isCutting(list.get(0), start) == false) { throw new IllegalStateException(); } if (BezierUtils.dist(list.get(0)) <= 1.0) { break; } final CubicCurve2D.Double left = new CubicCurve2D.Double(); final CubicCurve2D.Double right = new CubicCurve2D.Double(); list.get(0).subdivide(left, right); list.set(0, left); list.add(1, right); if (BezierUtils.isCutting(list.get(1), start)) { list.remove(0); } } return new DotPath(list); }
static void shorten(CubicCurve2D.Double bez, Shape shape) { final boolean contains1 = shape.contains(bez.x1, bez.y1); final boolean contains2 = shape.contains(bez.x2, bez.y2); if (contains1 ^ contains2 == false) { throw new IllegalArgumentException(); } if (contains1 == false) { bez.setCurve(bez.x2, bez.y2, bez.ctrlx2, bez.ctrly2, bez.ctrlx1, bez.ctrly1, bez.x1, bez.y1); } assert shape.contains(bez.x1, bez.y1) && shape.contains(bez.x2, bez.y2) == false; final CubicCurve2D.Double left = new CubicCurve2D.Double(); final CubicCurve2D.Double right = new CubicCurve2D.Double(); subdivide(bez, left, right, 0.5); if (isCutting(left, shape) ^ isCutting(right, shape) == false) { throw new IllegalArgumentException(); } if (isCutting(left, shape)) { bez.setCurve(left); } else { bez.setCurve(right); } }
public static Shape shapeFromSvgRelativeBezierPath(String pathString, float scalingFactor) { String[] points = pathString.split(" "); float x1, y1, x2, y2, cx1, cy1, cx2, cy2; x2 = y2 = 0; float s = scalingFactor; Path2D.Float path = new Path2D.Float(); for (int i = 0; i < points.length / 3; ++i) { String c1String = points[i * 3 + 0]; String c2String = points[i * 3 + 1]; String targetString = points[i * 3 + 2]; String[] c1Split = c1String.split(","); String[] c2Split = c2String.split(","); String[] targetSplit = targetString.split(","); x1 = x2; y1 = y2; x2 = s * Float.parseFloat(targetSplit[0]) + x1; y2 = s * Float.parseFloat(targetSplit[1]) + y1; cx1 = s * Float.parseFloat(c1Split[0]) + x1; cy1 = s * Float.parseFloat(c1Split[1]) + y1; cx2 = s * Float.parseFloat(c2Split[0]) + x1; cy2 = s * Float.parseFloat(c2Split[1]) + y1; CubicCurve2D.Float curve = new CubicCurve2D.Float(x1, y1, cx1, cy1, cx2, cy2, x2, y2); path.append(curve, true); } return path; }
/** * Draws the given curve smoothly (assuming the curve is monotonic * vertically) */ public void drawSmoothly(Curve curve) { final int smooth = 15; double cx = 0, cy = 0, slope; for (int n = curve.list.size(), i = 0; i < n; i++) { CubicCurve2D.Double c = new CubicCurve2D.Double(), c2 = (i + 1 < n) ? curve.list.get(i + 1) : null; c.setCurve(curve.list.get(i)); if (i > 0) { c.ctrlx1 = cx; c.ctrly1 = cy; } if (c2 == null) { draw(c, false); return; } if ((c.x1 < c.x2 && c2.x2 < c2.x1) || (c.x1 > c.x2 && c2.x2 > c2.x1)) slope = 0; else slope = (c2.x2 - c.x1) / (c2.y2 - c.y1); double tmp = c.y2 - smooth, tmpx = c.x2 - smooth * slope; if (tmp > c.ctrly1 && tmp < c.y2 && in(c.x1, tmpx, c.x2)) { c.ctrly2 = tmp; c.ctrlx2 = tmpx; } double tmp2 = c2.y1 + smooth, tmp2x = c2.x1 + smooth * slope; if (tmp2 > c2.y1 && tmp2 < c2.ctrly2 && in(c2.x1, tmp2x, c2.x2)) { cy = tmp2; cx = tmp2x; } else { cy = c2.ctrly1; cx = c2.ctrlx1; } draw(c, false); } }
/** Make a deep copy of this Curve object. */ public Curve dup() { Curve ans = new Curve(startX, startY); ans.endX = endX; ans.endY = endY; for (CubicCurve2D.Double x : list) { CubicCurve2D.Double c = new CubicCurve2D.Double(); c.setCurve(x); ans.list.add(c); } return ans; }
/** * Add a cubic bezier segment to (cx,cy) using (ax,ay) and (bx,by) as the * two control points. */ public Curve cubicTo(double ax, double ay, double bx, double by, double cx, double cy) { list.add(new CubicCurve2D.Double(endX, endY, ax, ay, bx, by, cx, cy)); this.endX = cx; this.endY = cy; return this; }
void bendUp(double x, double y1, double y2, double gap) { for (int i = 0; i < list.size(); i++) { CubicCurve2D.Double c = list.get(i); if (intersects(c.x1, c.y1, c.x2, c.y2, x, y1, y2)) { list.set(i, makeline(c.x1, c.y1, x, y1 - gap)); list.add(i + 1, makeline(x, y1 - gap, c.x2, c.y2)); return; } } }
void bendDown(double x, double y1, double y2, double gap) { for (int i = 0; i < list.size(); i++) { CubicCurve2D.Double c = list.get(i); if (intersects(c.x1, c.y1, c.x2, c.y2, x, y1, y2)) { list.set(i, makeline(c.x1, c.y1, x, y2 + gap)); list.add(i + 1, makeline(x, y2 + gap, c.x2, c.y2)); return; } } }
/** * Returns the x position of the given segment at the given point 0 <= t <= * 1 */ private double getX(CubicCurve2D.Double curve, double t) { double px = (curve.ctrlx1 - curve.x1) * t + curve.x1, qx = (curve.ctrlx2 - curve.ctrlx1) * t + curve.ctrlx1, rx = (curve.x2 - curve.ctrlx2) * t + curve.ctrlx2; double sx = (qx - px) * t + px, tx = (rx - qx) * t + qx; return (tx - sx) * t + sx; }
/** * Returns the y position of the given segment at the given point 0 <= t <= * 1 */ private double getY(CubicCurve2D.Double curve, double t) { double py = (curve.ctrly1 - curve.y1) * t + curve.y1, qy = (curve.ctrly2 - curve.ctrly1) * t + curve.ctrly1, ry = (curve.y2 - curve.ctrly2) * t + curve.ctrly2; double sy = (qy - py) * t + py, ty = (ry - qy) * t + qy; return (ty - sy) * t + sy; }