计算两个 xy 点之间的四边形曲线

发布于 2024-12-12 10:10:33 字数 434 浏览 3 评论 0原文

我有两个 (x,y) 点开始和结束。我想从头到尾制作动画,但我不想采用线性方式,而是想创建一条弯曲的路径。

我很确定我不是在寻找缓动,因为我不想影响动画速度,我只想计算弯曲路径。

我发现我需要某种控制点,如下图所示:

在此处输入图像描述

但我不知道如何实施。我很想创建一个采用以下参数的函数

function calculateXY(start, end, controlpoint, percentage);

,其中百分比是 0 - 100% 之间的数字,其中 0 将返回开始位置,100% 将返回结束位置。

该解决方案不需要采用 Objective-C,它可以采用任何编程语言。我只是无法理解数学:)

I have two (x,y) points start and end. I want to animate from start to end but instead of going a linear way I want to create a curved path.

I am quite sure I'm not looking for an easing because I don't want to affect the animation speed, I just want to calculate a curved path.

I figured out I needed some sort of control point, like shown in this image:

enter image description here

But I have no idea how to implement it. I would love to create a function that took the following parameters

function calculateXY(start, end, controlpoint, percentage);

Where percentage would be a number from 0 - 100% and where 0 would return the start position and 100% the end position.

The solution doesn't need to be in Objective-C, it could be in any programming language. I just can't get my head around the math :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

辞别 2024-12-19 10:10:33

看看 Cocoa 的贝塞尔路径:(NSBezierPath)

看起来它可能不支持二次贝塞尔曲线,因此您需要 转换到立方体

Look at Cocoa's bezier paths: (NSBezierPath).

It looks like it may not support quadratic bezier curves, so you'll need to convert to cubic.

肩上的翅膀 2024-12-19 10:10:33

解决方案不需要采用 Objective-C,它可以采用任何编程语言。我就是无法理解数学

我无法提供代码,但如果您想了解所涉及的数学,我可以解释它如何适用于四边形曲线。

首先了解控制点在数学上的影响。控制点和两个定义点定义了当前点和端点处绘制线的渐变。您可以使用 m = (y - y1)/(x - x1) 计算两条线的梯度。

从数学上讲,您接下来要解决的是 a、b、c 的这组方程:

ax^2 + bx + c 包含起点和终点

2ax + b 等于相应 x 值处的相应梯度。

此时,您就有了可用于绘制直线的二次方程。

The solution doesn't need to be in Objective-C, it could be in any programming language. I just can't get my head around the math

I'm not in a position to give code but if you're after an understanding of the math involved I can explain how that works for the Quad curve.

First understand what the control point mathematically impacts. The control point and the two defined points define the gradients of the drawn line at the current point and the endpoint. You can calculate the gradient of both lines using m = (y - y1)/(x - x1).

Mathematically what your trying to solve next is this set of equations for a, b, c:

ax^2 + bx + c contains both start and end points

2ax + b equals the corresponding gradients at the corresponding x value.

At that point you have quadratic that can be used for drawing the line.

圈圈圆圆圈圈 2024-12-19 10:10:33

我在工作中看到了这个,想在家里尝试一下。查看 这个来自维基百科的示例后 一段时间以来,我想我明白了,该怎么做,下面你会找到一个例子,我现在将对此进行解释。

我将使用 0 到 1 之间的时间间隔。之间的任何数字都是动画的时间分数。您想要的是在给定的时间内获得“兴趣点”的位置。第一步是,您有由两条线连接的三个点 ABC (g => [AB ]h => [BC])。对于每条线,您都必须计算在起始点和权重点 P(g) 之间徘徊的点,分别在权重点和结束点 P(h) 之间徘徊在给定的时间内。

在这两个计算点(P(g)P(h))之间绘制第三条线(我们称之为 y)。这条线上的某个地方就是您的“兴趣点”。但在哪里呢?同样,您必须计算从 P(g)y 线上的点的位置(称为 P(y))。代码>P(h)。

P(y) 的位置就是您要寻找的位置。

function setup() {
  createCanvas(400, 400);
  fraction = 0;
  drawnPoints = [];
}

function draw() {
  background(100);
  let start = new Point(30, 50, 5);
  let end = new Point(300, 170, 5);
  let weight = new Point(200, 300, 5);

  let lineStartWeight = new Line(start, weight);
  let lineStartWeightPoint = lineStartWeight.getPointAt(fraction);
  let lineWeightEnd = new Line(weight, end);
  let lineWeightEndPoint = lineWeightEnd.getPointAt(fraction);

  let drawingLine = new Line(lineStartWeightPoint, lineWeightEndPoint);

  start.draw('red');
  end.draw('blue');
  weight.draw('#0f0');
  lineStartWeight.draw('#ff0');

  lineWeightEnd.draw('#0ff');

  lineStartWeightPoint.draw('#000');
  lineWeightEndPoint.draw('#fff')

  drawingLine.draw('#f66');

  drawnPoints.push(drawingLine.getPointAt(fraction));

  drawnPoints.forEach(p => p.draw(''));

  fraction += 0.01

  if (fraction > 1) {
    fraction = 0;
    drawnPoints = [];
  }

}

class Point {
  constructor(x, y, size = 1) {
    this.x = x;
    this.y = y;
    this.size = size;
  }

  draw(color) {
    fill(color);
    noStroke();
    ellipse(this.x, this.y, this.size, this.size);
  }
}

class Line {
  constructor(pointStart, pointEnd) {
    this.pointStart = pointStart;
    this.pointEnd = pointEnd;
  }

  draw(color) {
    stroke(color);
    line(this.pointStart.x, this.pointStart.y, this.pointEnd.x, this.pointEnd.y);
  }

  getPointAt(fraction) {
    let xCoord = (this.pointEnd.x - this.pointStart.x) * fraction + this.pointStart.x;
    let yCoord = (this.pointEnd.y - this.pointStart.y) * fraction + this.pointStart.y;
    return new Point(xCoord, yCoord, 5);
  }
}
html, body {
  margin: 0;
  padding: 0;
}
<html>
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.1/p5.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.1/addons/p5.dom.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.1/addons/p5.sound.min.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css">
  </head>
  <body>
    <script src="sketch.js"></script>
  </body>
</html>


编辑

它归结为一个简单的函数。我将仅针对 x 值进行说明,但 y 的工作方式类似。

开始(x1|y1), 结束(x2|y2) , 控制点(x< sub>3|y3), f = 动画时间的一部分

要获取时间点 f 的 x 值,您可以:

x = (((x2-x3)*f+x3)-((x3-x 1)*f+x1))*f+((x3-x1)*f+ x1)

经过一些简化后,您得到:

x = f2(x1+x2-2x3)
+2f(x3-x1)+x1

I saw this at work and wanted to take a shot at it at home. After looking at this example from Wikipedia for some time I think I understood, what to do and below you will find an example, which I will explain now.

I will use a time interval between 0 and 1. Any number in between is the time fraction of the animation. What you want is to get the location of you "point of interest" at a given fraction of time. The first step is, that you have three points A,B,C connected by two lines (g => [AB], h => [BC]). For each of these lines you will have to calulate points, that are wandering between the startPoint and the weightPoint P(g) respectively between the weightPoint and the endPoint P(h) at a given fraction of time.

Between these two calculated points (P(g) and P(h)) you draw a third line (let's call it y). Somewhere on that line is your "point of interest". But where? Again you have to calculate the position of a point on the line y (called P(y)) travelling from P(g) to P(h).

The position of your P(y) is what you're looking for.

function setup() {
  createCanvas(400, 400);
  fraction = 0;
  drawnPoints = [];
}

function draw() {
  background(100);
  let start = new Point(30, 50, 5);
  let end = new Point(300, 170, 5);
  let weight = new Point(200, 300, 5);

  let lineStartWeight = new Line(start, weight);
  let lineStartWeightPoint = lineStartWeight.getPointAt(fraction);
  let lineWeightEnd = new Line(weight, end);
  let lineWeightEndPoint = lineWeightEnd.getPointAt(fraction);

  let drawingLine = new Line(lineStartWeightPoint, lineWeightEndPoint);

  start.draw('red');
  end.draw('blue');
  weight.draw('#0f0');
  lineStartWeight.draw('#ff0');

  lineWeightEnd.draw('#0ff');

  lineStartWeightPoint.draw('#000');
  lineWeightEndPoint.draw('#fff')

  drawingLine.draw('#f66');

  drawnPoints.push(drawingLine.getPointAt(fraction));

  drawnPoints.forEach(p => p.draw(''));

  fraction += 0.01

  if (fraction > 1) {
    fraction = 0;
    drawnPoints = [];
  }

}

class Point {
  constructor(x, y, size = 1) {
    this.x = x;
    this.y = y;
    this.size = size;
  }

  draw(color) {
    fill(color);
    noStroke();
    ellipse(this.x, this.y, this.size, this.size);
  }
}

class Line {
  constructor(pointStart, pointEnd) {
    this.pointStart = pointStart;
    this.pointEnd = pointEnd;
  }

  draw(color) {
    stroke(color);
    line(this.pointStart.x, this.pointStart.y, this.pointEnd.x, this.pointEnd.y);
  }

  getPointAt(fraction) {
    let xCoord = (this.pointEnd.x - this.pointStart.x) * fraction + this.pointStart.x;
    let yCoord = (this.pointEnd.y - this.pointStart.y) * fraction + this.pointStart.y;
    return new Point(xCoord, yCoord, 5);
  }
}
html, body {
  margin: 0;
  padding: 0;
}
<html>
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.1/p5.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.1/addons/p5.dom.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.1/addons/p5.sound.min.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css">
  </head>
  <body>
    <script src="sketch.js"></script>
  </body>
</html>


EDIT

It boils down to one simple function. I will only illustrate it for the x values, but y works analogous.

start(x1|y1), end(x2|y2) , controlpoint(x3|y3), f = fraction of time of the animation

To get the x value at a point in time f you have:

x = (((x2-x3)*f+x3)-((x3-x1)*f+x1))*f+((x3-x1)*f+x1)

After a few simplifications you come out with:

x = f2(x1+x2-2x3)
+2f(x3-x1)+x1

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文