3

I having trouble building a curve that goes through all the points but not outside of those points as the bezier curve does in SVG.

I have tried Bezier Curve, Quadratic Curve, Smooth Curve, and Casteljau

Here is a link to my example https://dotnetfiddle.net/KEqts0

Unfortunately, I can use a 3rd party to do the mapping.

I do not want to place the output in because that will just be noise, I have included a picture for reference. enter image description here

Randy Casburn
  • 13,840
  • 1
  • 16
  • 31
user1730289
  • 273
  • 4
  • 15

1 Answers1

8

Observation: The initial question was tagged javascript. After posting my answer the javascript tag was deleted (not by the OP).

Given a points array pointsRy you will need to calculate the position of the control points for the Bézier curves. The first & the last curve are quadratic Bezier. All the other curves are cubic Bézier.

This is an image where I'm marking the points and the tangent to the curve through each point. The control points are the starting and ending points of the tangent.

The size of the tangent is calculated relative to the distance between the points: let t = 1 / 5; Change this to change the curvature.

the curve with the marked points

let svg = document.querySelector("svg")

let t = 1 / 5;// change this to change the curvature

let pointsRy = [[100,100],[250,150],[300,300],[450,250], [510,140],[590,250],[670,140]];

thePath.setAttribute("d", drawCurve(pointsRy));

function drawCurve(p) {

  var pc = controlPoints(pointsRy); // the control points array

  let d="";
  d += `M${p[0][0]}, ${p[0][1]}`
  
  // the first & the last curve are quadratic Bezier
  // because I'm using push(), pc[i][1] comes before pc[i][0]
  d += `Q${pc[1][1].x}, ${pc[1][1].y}, ${p[1][0]}, ${p[1][1]}`;


  if (p.length > 2) {
    // central curves are cubic Bezier
    for (var i = 1; i < p.length - 2; i++) {
      
     d+= `C${pc[i][0].x}, ${pc[i][0].y} ${pc[i + 1][1].x},${pc[i + 1][1].y} ${p[i + 1][0]},${p[i + 1][1]}`; 

    }//end for
    // the first & the last curve are quadratic Bezier
    let n = p.length - 1;
    d+=`Q${pc[n - 1][0].x}, ${pc[n - 1][0].y} ${p[n][0]},${p[n][1]}`;
  }
  return d;
}
function controlPoints(p) {
  // given the points array p calculate the control points
  let pc = [];
  for (var i = 1; i < p.length - 1; i++) {
    let dx = p[i - 1][0] - p[i + 1][0]; // difference x
    let dy = p[i - 1][1] - p[i + 1][1]; // difference y
    // the first control point
    let x1 = p[i][0] - dx * t;
    let y1 = p[i][1] - dy * t;
    let o1 = {
      x: x1,
      y: y1
    };

    // the second control point
    var x2 = p[i][0] + dx * t;
    var y2 = p[i][1] + dy * t;
    var o2 = {
      x: x2,
      y: y2
    };

    // building the control points array
    pc[i] = [];
    pc[i].push(o1);
    pc[i].push(o2);
  }
  return pc;
}
body{background:black; margin:1em;}
svg{border: 1px solid #999;}
path{fill:none; stroke:white;}
<svg viewBox="0 0 800 400">  
  <path id="thePath" stroke="white"/>
</svg>
enxaneta
  • 31,608
  • 5
  • 29
  • 42
  • 2
    You deserve 1,000,000 upvotes for this. You have no idea how hard it is to find a solid piece of code that performs this function (makes a bezier + cubic curved path that goes **through** an array of 0..N points). Thank you so much for this! It works perfectly. – Eric Jun 27 '21 at 02:49