I have written generic Point classes, line/line intersection algorithms and Layer administration code more times than I can remember. I don't like menial programming, so this is effectively my code library. But you can use it too!
The language used is Processing, which is a mostly-Java-syntax language. I hardly ever use Java-specific ninja code, so rewriting any of these snippets to your favourite language is less than a minute's worth of work, typically.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | /**
* Convert a Catmull-Rom multipoint curve
* to a cubic Bezier multipoint curve.
*/
// our points
ArrayList<PVector> points;
// curve tightness
float cmr_tightness;
// cmr-tightness to bezier-control-offset factor
float cmr_to_bezier;
// preamble
void setup() {
size(800,400);
points = new ArrayList<PVector>();
ellipseMode(CENTER);
noFill();
stroke(0);
noLoop();
setTightness(0);
}
// set catmull-rom tightness, and corresponding
// bezier control point offset factor. These are
// correlated with a relatively simple function.
void setTightness(float v) {
curveTightness(v);
cmr_tightness = v;
cmr_to_bezier = -6/(v-1);
}
// do we have enough points to draw a catmull-rom curve?
boolean allpoints = false;
// draw the points collected so far,
// connecting them as Catmull-Rom interpolation
// curve if there's more than three, and showig
// the corresponding cubic Bezier curve overlayed.
void draw() {
background(255);
curveTightness(cmr_tightness);
// Draw the catmull-rom curve.
stroke(0);
if(allpoints) { beginShape(); }
for(PVector p: points) {
ellipse(p.x, p.y, 5, 5);
if(allpoints) curveVertex(p.x,p.y);
}
if(allpoints) { endShape(); }
// Then draw its bezier approximation.
if(allpoints) {
stroke(255,0,0,50);
beginShape();
vertex(points.get(1).x, points.get(1).y);
for(int i=1, last=points.size()-2; i<last; i++) {
PVector pT = points.get(i-1);
PVector p1 = points.get(i);
PVector p2 = points.get(i+1);
PVector p3 = points.get(i+2);
// Every catmull rom point has a tangent
// equal to dx(p-1,p+1)/dy(p-1,p+1), with
// the curve tightness determining the
// strength of the control point, i.e. how
// far from the on-curve point it lies.
float dx1 = (p2.x - pT.x)/cmr_to_bezier;
float dy1 = (p2.y - pT.y)/cmr_to_bezier;
float dx2 = (p3.x - p1.x)/cmr_to_bezier;
float dy2 = (p3.y - p1.y)/cmr_to_bezier;
bezierVertex(p1.x+dx1, p1.y+dy1, p2.x-dx2, p2.y-dy2, p2.x, p2.y);
}
endShape();
}
}
// add a new point when we click on the sketch.
void mouseClicked() {
points.add(new PVector(mouseX,mouseY));
allpoints = points.size()>=4;
redraw();
}
// let's see what happens when we change the tightness values
void keyPressed() {
if(key=='w') { setTightness(cmr_tightness+0.05); }
if(key=='s') { setTightness(cmr_tightness-0.05); }
redraw();
} |
Written and maintained by Mike "Pomax" Kamermans. All code snippets on this site are "do whatever you want with it" licensed.