class DistanceCurve extends BezierCurve { DistanceCurve (BezierCurve bc) { bc.calcLength(true); for (int i=0, sz = bc.pts.size(); i < sz; ++i) { BezierControlPoint bcp = (BezierControlPoint) bc.pts.get(i); pt x = new pt(bcp.dist, bcp.dist ); pts.add ( new BezierControlPoint(x) ); } pt dir = new pt(0,0); for (int i=0, sz = pts.size(); i < sz; ++i) { BezierControlPoint bcp = (BezierControlPoint) pts.get(i); if ( i < sz-1) { BezierControlPoint bcp2 = (BezierControlPoint) pts.get(i+1); bcp.dir = new pt ( bcp2.p.x - bcp.p.x, bcp2.p.y - bcp.p.y ); bcp.dir.unit(); bcp.sleft = 0.05; bcp.sright = 0.05; } else bcp.dir = dir.makeCopy (); } calcLength(true); } void drawCurve (boolean midPoints) { pt val = new pt(0,0); pt tangent = new pt(0,0); for ( int j =0, m = pts.size(); j < m; ++j ) { BezierControlPoint bcp = (BezierControlPoint) pts.get(j); pt pl = bcp.p.makeCopy (); pt pld = bcp.getLeftAnchor (); mapPoint(pl); mapPoint(pld); stroke(255,0,0); fill (255,0,0); ellipseMode(CENTER); ellipse(pl.x,pl.y,6,6); if (j+1 < m) { stroke(0); BezierControlPoint bcp2 = (BezierControlPoint) pts.get(j+1); pt pr = bcp2.p.makeCopy (); pt prd = bcp2.getRightAnchor (); mapPoint (pr); mapPoint (prd); bezier ( pl.x, pl.y, pld.x, pld.y, prd.x, prd.y, pr.x, pr.y ); if (midPoints) { float t = sampleAt( (bcp.dist +bcp2.dist)*0.5,false); eval(t,val,tangent); stroke(0); noFill(); mapPoint(val); ellipse (val.x, val.y, 4, 4); } strokeWeight(2); stroke(0,0,255); fill (0,0,255); pt plt = bcp.getLeftTangent(); pt prt = bcp2.getRightTangent(); mapPoint(plt); mapPoint (prt); line ( pl.x, pl.y, plt.x, plt.y); ellipse (plt.x, plt.y,5,5); stroke(0,255,0); fill (0,255,0); line ( pr.x, pr.y, prt.x, prt.y); ellipse (prt.x, prt.y,5,5); strokeWeight(1); } } } boolean handleReleaseEvent () { calcLength(true); curControlPoint = -1; curAnchorPoint = -1; return false; } void handleDragEvent () { if (curControlPoint >= 0 ) { if ( mouseButton == RIGHT || ( keyPressed && mouseButton == LEFT && key == CODED && keyCode == CONTROL) ) { getPoint(curControlPoint).p.y = mouseY; limitTo (getPoint(curControlPoint).p, upleftDist, botrightDist,2 ); unmapPoint(getPoint(curControlPoint).p, 2); } else { float minX =0, maxX=1; if ( curControlPoint > 0 ) minX = getPoint(curControlPoint-1).p.x; if ( curControlPoint < pts.size()-2 ) maxX = getPoint(curControlPoint+1).p.x; pt tmp1 = new pt (minX,0); pt tmp2 = new pt (maxX,0); mapPoint(tmp1); mapPoint(tmp2); getPoint(curControlPoint).p.x = mouseX; limitTo (getPoint(curControlPoint).p, new pt(tmp1.x,upleftDist.y), new pt(tmp2.x,botrightDist.y),1); unmapPoint(getPoint(curControlPoint).p, 1); } calcLength(true); return; } if (curAnchorPoint >= 0 ) { if ( leftAnchor ) { getPoint (curAnchorPoint).setLeftTangentFromMouse (mouseButton == LEFT && (key == CODED ? (keyCode != CONTROL) : true), true); } else { getPoint (curAnchorPoint).setRightTangentFromMouse (mouseButton == LEFT && (key == CODED ? (keyCode != CONTROL) : true), true); } calcLength(true); } } void sampleTime (float t, pt vec, pt tangent) { eval (sampleTime(t), vec, tangent); // limit vec.y if ( vec.y <= 0 ) vec.y = 0; if ( vec.y >= 1) vec.y =1; } float sampleTime (float t) { // bisecion float left = 0; float right = pts.size()-1; pt val = new pt(0,0); pt tangent = new pt (0,0); if ( t <= left ) return left; if ( t>=right) return right; while (right-left > 1e-4) { float middle = (left+right)/2; eval(middle,val,tangent); if ( val.x < t ) { left = middle; } else { right = middle; } } return (left+right)/2; } }