【问题标题】:Center point on html quadratic curvehtml二次曲线上的中心点
【发布时间】:2012-02-29 23:04:14
【问题描述】:

我在 html 画布上使用 context.quadraticCurveTo(controlX, controlY, endX, endY); 绘制了一条二次曲线。

我有控制点和起点和终点,它们在水平方向上不一定是水平的。

如何使用这些参数找到曲线上的中心点?

其实我想在这个中心点上放一个div标签。 这个过程中是否涉及任何方程求解?

【问题讨论】:

  • 请解释您所说的“控制点”和“开始”和“结束”点是什么意思。
  • 控制点是负责曲线形状的点,起点是曲线的起点,终点是曲线的终点。
  • 没有一个点可以对曲线的形状负责——当以一般形式编写时,曲线的形状由 a、b、c 的值定义。你的起点和终点——它们水平是否一致?你有一个正在绘制的方程吗?
  • 请查看 htmlcanvas/javascript 中的 qudraticCurveTo(a,b,c) 函数。它根据控制点和端点绘制曲线

标签: javascript html5-canvas bezier curve quadratic


【解决方案1】:

quadraticCurveTo 绘制一个quadratic Bézier curve

曲线上任意给定位置(从0到1)点坐标的计算公式为

x(t) = (1-t)^2 * x1 + 2 * (1-t) * t * x2 + t^2 * x3
y(t) = (1-t)^2 * y1 + 2 * (1-t) * t * y2 + t^2 * y3

其中 (x1, y1) 是起点,(x2, y2) 是控制点, (x3, y3) 是终点。

所以,把它变成 JavaScript,我们最终会得到类似的东西

function _getQBezierValue(t, p1, p2, p3) {
    var iT = 1 - t;
    return iT * iT * p1 + 2 * iT * t * p2 + t * t * p3;
}

function getQuadraticCurvePoint(startX, startY, cpX, cpY, endX, endY, position) {
    return {
        x:  _getQBezierValue(position, startX, cpX, endX),
        y:  _getQBezierValue(position, startY, cpY, endY)
    };
}

如果您将起点、终点和控制点传递给那里的getQuadraticCurvePoint,以及中间位置的0.5,您应该会得到一个具有X 和Y 坐标的对象。

示例

function _getQBezierValue(t, p1, p2, p3) {
  var iT = 1 - t;
  return iT * iT * p1 + 2 * iT * t * p2 + t * t * p3;
}

function getQuadraticCurvePoint(startX, startY, cpX, cpY, endX, endY, position) {
  return {
    x: _getQBezierValue(position, startX, cpX, endX),
    y: _getQBezierValue(position, startY, cpY, endY),
  };
}

var position = 0.0;
var startPt = { x: 120, y: 10 };
var controlPt = { x: 410, y: 250 };
var endPt = { x: 10, y: 450 };
var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
function drawNextPoint() {
  var pt = getQuadraticCurvePoint(
    startPt.x,
    startPt.y,
    controlPt.x,
    controlPt.y,
    endPt.x,
    endPt.y,
    position,
  );
  position = (position + 0.006) % 1.0;

  ctx.fillStyle = "rgba(255,0,0,0.5)";
  ctx.fillRect(pt.x - 2, pt.y - 2, 5, 5);
}

ctx.strokeStyle = "black";
ctx.moveTo(startPt.x, startPt.y);
ctx.quadraticCurveTo(controlPt.x, controlPt.y, endPt.x, endPt.y);
ctx.stroke();

setInterval(drawNextPoint, 40);
<canvas id="c" width="500" height="500">

【讨论】:

    【解决方案2】:

    这是描述二次方程及其解的页面:wiki page。 这里有一个很好的教程,附有图表:tutorial

    【讨论】:

    • 这个页面我知道并且我正在查看它,但我想使用 javascript 计算中心点。我不知道如何找到中心点。
    • 如果你的起点和终点在水平方向上是水平的,那么曲线的 x 坐标将直接在中间(即)x_start + ((x_end - x_start) / 2) 和y坐标可以通过将这个x值代入原始方程而不是x并求解它来找到。你有方程式吗?
    • 这是真正的问题人。我有随机的起点和终点
    • 曲线从何而来?你有描述它的方程式吗?
    【解决方案3】:

    一种可能的方式:

    // compute coordinates of the middle point of a quadratic Bezier curve
    // need two functions: quadraticBezierCurvePoint and quadraticBezierCurvesMiddle
    
    function quadraticBezierCurvePoint(t, c) {
      // compute relative coordinates of a point on the curve using t and c
      // t is a number between 0 and 1
      // c is an array of 3 points:
      //     the initial point of the curve (always (0,0))
      //     the "handle" point of the curve
      //     the final point of the curve
      var t1, t1_2a, t1_2b, t1_2c;
      t1 = 1 - t;
      t1_2a = t1 * t1;
      t1_2b = (2 * t) * t1;
      t1_2c = t * t;
      return {
        x: (c[0].x * t1_2a) + (t1_2b * c[1].x) + (t1_2c * c[2].x),
        y: (c[0].y * t1_2a) + (t1_2b * c[1].y) + (t1_2c * c[2].y)
      };
    }
    
    function quadraticBezierCurvesMiddle(m, c) {
      var k, km = 1000,
        km2 = (km >> 1),
        len = 0,
        len2, x, y, a = new Array(km + 1);
      // compute curve lengths from start point to any point
      // store relative point coordinates and corresponding length in array a
      for (k = 0; k <= km; k++) {
        a[k] = {
          pt: quadraticBezierCurvePoint(k / km, c),
          len: 0
        };
        if (k > 0) {
          x = a[k].pt.x - a[k - 1].pt.x;
          y = a[k].pt.y - a[k - 1].pt.y;
          a[k].len = a[k - 1].len + Math.sqrt(x * x + y * y);
        }
      }
      // retrieve the point which is at a distance of half the whole curve length from start point
      // most of the time, this point is not the one at indice km2 in array a, but it is near it
      len2 = a[km].len / 2;
      if (a[km2].len > len2)
        for (k = km2; k >= 0; k--) {
          if (len2 >= a[k].len) break;
        } else
        for (k = km2; k <= km; k++) {
          if (len2 <= a[k].len) break;
        }
        // return absolute coordinates of the point
      return {
        x: Math.round((a[k].pt.x + m.x) * 100) / 100,
        y: Math.round((a[k].pt.y + m.y) * 100) / 100
      };
    }
    

    以及对应的jsfiddle:jsfiddle.net/pTccL/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-01
      • 2013-03-31
      相关资源
      最近更新 更多