Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fit a SVG curve to a polynomial

Assuming I have functions like x² or 2x + 3x² how does one go about creating a SVG path that fits these functions ?.

From my limited understanding of SVG and Bezier curves I believe I am looking for is a simple technique to construct the bezier control points that will ensure that the resulting graph fits the given function. You can safely assume (if you have not already guessed so) that I am a newbie in graphics programming. I know frameworks like gnuplot can perform this type of interpolation but I am looking more for a explanation on how to do it by hand using SVG and JavaScript.

EDIT: A exact fit is not a strict requirement, but the resulting graph has to be reasonably accurate (for teaching purposes).

like image 937
Lars Tackmann Avatar asked Jan 07 '12 20:01

Lars Tackmann


1 Answers

<?xml version="1.0" standalone="no"?>

SVG provides Bézier curves of orders 2 and 3, which should be good enough for quadratic and cubic polynomials.

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="20cm" height="20cm" viewBox="0 0 1000 1000"
    xmlns="http://www.w3.org/2000/svg" version="1.1">
  <style type="text/css"><![CDATA[
    .axis { fill: none; stroke: black; stroke-width: 3; }
    .tick { fill: none; stroke: black; stroke-width: 1; }
    .fun1 { fill: none; stroke: blue; stroke-width: 2; }
    .fun2 { fill: none; stroke: red; stroke-width: 2; }
  ]]></style>
  <polyline class="axis" points="0,500 1000,500" />
  <polyline class="tick" points="0,490 0,510" />
  <polyline class="tick" points="100,490 100,510" />
  <polyline class="tick" points="200,490 200,510" />
  <polyline class="tick" points="300,490 300,510" />
  <polyline class="tick" points="400,490 400,510" />
  <polyline class="tick" points="600,490 600,510" />
  <polyline class="tick" points="700,490 700,510" />
  <polyline class="tick" points="800,490 800,510" />
  <polyline class="tick" points="900,490 900,510" />
  <polyline class="tick" points="1000,490 1000,510" />
  <polyline class="axis" points="500,0 500,1000" />
  <polyline class="tick" points="490,0 510,0" />
  <polyline class="tick" points="490,100 510,100" />
  <polyline class="tick" points="490,200 510,200" />
  <polyline class="tick" points="490,300 510,300" />
  <polyline class="tick" points="490,400 510,400" />
  <polyline class="tick" points="490,600 510,600" />
  <polyline class="tick" points="490,700 510,700" />
  <polyline class="tick" points="490,800 510,800" />
  <polyline class="tick" points="490,900 510,900" />
  <polyline class="tick" points="490,1000 510,1000" />

Take y = x² - 4, with endpoints (-3, 5) and (3, 5); the tangents are y = -6x - 13 and y = 6x - 13. Place the one Q control point on both tangents, at (0, -13). This should work easily for any quadratic.

  <path class="fun1" d="M200,0 Q500,1800 800,0" />

Cubics are a bit tricker. With y = (x³ - 9x) / 16 from (-5, -5) to (5, 5), the tangents are y = (33x + 125) / 8 and y = (33x - 125) / 8. Seeing that the curve must pass through (0, 0) with slope -9/16, it's a simple calculation to find C control points (-5/3, 35/4) and (5/3, 35/4). It's probably not doable by hand most of the time but I think this approach should be numerically doable for any other cubic — two variables for how far along each tangent the control points lie, and two constraints forcing a particular point and direction.

  <path class="fun2" d="M0,1000 C333,-375 667,1375 1000,0" />

(Animated Bézier Curves was very helpful when I was working these out.)

</svg>

like image 53
ephemient Avatar answered Nov 16 '22 01:11

ephemient