Search code examples
javascriptarrayssvgbezierspline

Close an opened Catmull-Rom Spline generated from an array of points, with a smooth curve


I reached this [Catmull-Rom Spline][1] and i need to change the code to close the loop with the same smooth curve. if i add to the end of the array named "points" the first two numbers (x0,x1) the loop will close, but i get no smooth curve - example here. Thanks in advance.

[1]: https://codepen.io/osublake/pen/BowJed?editors=0010

Solution

  • You have to also add the last two pairs of coords to the start of the array. Then not draw the first section or last section of the curve.

    https://codepen.io/PaulLeBeau/pen/KBERmB?editors=0010

    var tension = 1;
    
    var poly = document.querySelector("polyline");
    var path = document.querySelector("path");
    
    var points = [
      600,200,
      700,350,
    
      100,350,  
      200,100,
      300,350,
      400,150,
      500,350,
      600,200,
      700,350,
      
      100,350,
      200,100
    ];
    
    poly.setAttribute("points", points);
    path.setAttribute("d", solve(points, tension));
    
    function solve(data, k) {
    
      if (k == null) k = 1;
      
      var size = data.length;
      var last = size - 4;    
    
      var path = "M" + [data[2], data[3]];
    
      for (var i = 2; i < size - 4; i +=2) {
    
        var x0 = i ? data[i - 2] : data[0];
        var y0 = i ? data[i - 1] : data[1];
    
        var x1 = data[i + 0];
        var y1 = data[i + 1];
    
        var x2 = data[i + 2];
        var y2 = data[i + 3];
    
        var x3 = i !== last ? data[i + 4] : x2;
        var y3 = i !== last ? data[i + 5] : y2;
        
        var cp1x = x1 + (x2 - x0) / 6 * k;
        var cp1y = y1 + (y2 - y0) / 6 * k;
    
        var cp2x = x2 - (x3 - x1) / 6 * k;
        var cp2y = y2 - (y3 - y1) / 6 * k;
       
        path += "C" + [cp1x, cp1y, cp2x, cp2y, x2, y2];
      } 
    
      return path;
    }
    body {
      background: #222;
    }
    
    svg {
      position: absolute;
      width: 100%;
      height: 100%;
    }
    
    polyline {
      fill: none;
      stroke: #888;
      stroke-width: 1;
    }
    
    path {
      fill: none;
      stroke: cornflowerblue;
      stroke-width: 2;
    }
    <svg>
      <polyline />
      <path />
    </svg>