The code below draws a closed Bezier spline through a set of points stored as PVector objects the array called path. Note that the points all have a z value of 0 and are in order arround the contour.
Depending on how your data is stored in the array then you will have to extract all the points for a given height (z value) then work out the order they are to be linked. A brute force approach would be to select a point at random, then find the point nearest to it (ignoring itself) then find the nearest point to that one (ignoring the two points already selected) and repeat for all points.
- // Adapted from information found at
- // http://scaledinnovation.com/analytics/splines/aboutSplines.html
- PVector[] path;
- // The arrays hold the control points calculated
- PVector[] p1;
- PVector[] p2;
- void setup() {
- size(400, 400);
- ellipseMode(CENTER);
- noFill();
- // Calculate the contour
- getPath();
- getControlPoints();
- // Draw the contour
- drawContour();
- // Draw the countour points (red)
- drawContourPoints();
- // Draw the calculated control points (blue)
- // drawControlPoints();
- }
- public void drawContourPoints() {
- noStroke();
- fill(255, 0, 0);
- for (int i = 0; i < path.length; i++)
- ellipse(path[i].x, path[i].y, 8, 8);
- }
- public void drawControlPoints() {
- noStroke();
- fill(0, 0, 255);
- for (int i = 0; i < path.length; i++) {
- ellipse(p1[i].x, p1[i].y, 8, 8);
- ellipse(p2[i].x, p2[i].y, 8, 8);
- }
- }
- public void drawContour() {
- PVector next, curr, cp1, cp2;
- strokeWeight(1.5);
- int n = path.length;
- int i1;
- for (int i = 0; i < n; i++) {
- i1 = (i + 1) % n;
- curr = path[i];
- cp1 = p2[i];
- cp2 = p1[i1];
- next = path[i1];
- bezier(curr.x, curr.y, cp1.x, cp1.y, cp2.x, cp2.y, next.x, next.y);
- }
- }
- public void getControlPoints() {
- int n = path.length;
- p1 = new PVector[path.length];
- p2 = new PVector[path.length];
- int leftIdx, rightIdx;
- PVector left, right, curr;
- float s = 0.65; // scale factor
- for (int i = 0; i < path.length; i++) {
- leftIdx = (i == 0) ? n-1 : i-1;
- rightIdx = (i == n - 1) ? 0 : i + 1;
- left = path[leftIdx];
- right = path[rightIdx];
- curr = path[i];
- float d01 = PVector.dist(left, curr);
- float d12 = PVector.dist(right, curr);
- float fa = s * d01 / (d01 + d12);
- float fb = s * d12 / (d01 + d12);
- p1[i] = new PVector(curr.x - fa * (right.x - left.x), curr.y - fb * (right.y - left.y));
- p2[i] = new PVector(curr.x + fb * (right.x - left.x), curr.y + fb * (right.y - left.y));
- }
- }
- public void getPath() {
- path = new PVector[] {
- new PVector(100, 100),
- new PVector(250, 100),
- new PVector(350, 200),
- new PVector(100, 250)
- };
- }