I don't want to keep writing the same code over and over.

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.

Catmull-Rom-to-Bezier snippet

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();
}

Back to the main page

Download all


Written and maintained by Mike "Pomax" Kamermans. All code snippets on this site are "do whatever you want with it" licensed.