여러분도 알다시피, 스플라인은 길이가 다른 선분을 생성합니다. 곡선이 가늘수록 세그먼트가 짧아집니다. 이것은 디스플레이 목적으로 좋으며, 모바일을위한 경로 생성에는 그리 유용하지 않습니다.
스플라인 경로의 일정 속도 탐색에 대한 합리적인 근사값을 얻으려면 커브의 세그먼트를 따라 보간을 수행해야합니다. 이미 라인 세그먼트 집합 (Vector2.CatmullRom()
에 의해 반환 된 점 쌍 사이)이 있으므로이 세그먼트를 일정한 속도로 걷는 방법이 필요합니다.
이러한 점 사이의 선으로 정의 된 경로를 따라 이동하는 점 집합과 총 거리가 주어지면 다음 (더 많거나 적은 의사 코드)은 경로를 따라 특정 거리에있는 점을 찾습니다.
Point2D WalkPath(Point2D[] path, double distance)
{
Point curr = path[0];
for (int i = 1; i < path.Length; ++i)
{
double dist = Distance(curr, path[i]);
if (dist < distance)
return Interpolate(curr, path[i], distance/dist;
distance -= dist;
curr = path[i];
}
return curr;
}
는 쉽게 산책 작업 중 조회 할 수 있도록 경로의 각 지점과 경로 거리를 저장 등이 속도를 위해 할 수있는 다양한 최적화가 있습니다. 이것은 경로가 복잡 해짐에 따라 더 중요 해지지만 경로가 적은 세그먼트로 인해 과도하게 발생할 가능성이 있습니다.
편집 :Here's an example 나는이 방법으로 JavaScript에서 잠시 동안했다. 그것은 개념 증명, 그래서 코드에서 너무 비판적으로 보지 않는다 : P 편집
'매듭'의 집합을 감안할 때 스플라인 생성
에 대한 자세한 내용은 포인트 - 인 점 곡선은 반드시 그 순서대로 통과하십시오 - 곡선 알고리즘에 가장 잘 맞는 것은 Catmull-Rom입니다. 단점은 C-R이 자동으로 생성하기에는 어색한 두 개의 추가 제어 지점이 필요하다는 것입니다.
나는 올바른 길잡이를 찾을 수없는 온라인 유용한 문서를 발견했다.이 문서는 경로 내의 점 집합의 위치를 기반으로 일련의 제어점을 계산했다.여기 내 C# 코드는 제어 포인트를 계산하는 방법에 대해 다음과 같습니다
// Calculate control points for Point 'p1' using neighbour points
public static Point2D[] GetControlsPoints(Point2D p0, Point2D p1, Point2D p2, double tension = 0.5)
{
// get length of lines [p0-p1] and [p1-p2]
double d01 = Distance(p0, p1);
double d12 = Distance(p1, p2);
// calculate scaling factors as fractions of total
double sa = tension * d01/(d01 + d12);
double sb = tension * d12/(d01 + d12);
// left control point
double c1x = p1.X - sa * (p2.X - p0.X);
double c1y = p1.Y - sa * (p2.Y - p0.Y);
// right control point
double c2x = p1.X + sb * (p2.X - p0.X);
double c2y = p1.Y + sb * (p2.Y - p0.Y);
// return control points
return new Point2D[] { new Point2D(c1x, c1y), new Point2D(c2x, c2y) };
}
tension
파라미터는 곡선의 견고성을 변경하는 제어 포인트 생성을 조절한다. 값이 높을수록 커브가 커지고, 커브가 작을수록 값이 낮아집니다. 그것을 가지고 놀고 어떤 가치가 당신에게 가장 잘 맞는지보십시오.
, 우리가 노트의 쌍 사이의 곡선을 생성하는 데 사용되는 제어 점 세트 생성 할 수있는 'N'노트 (곡선상의 점)의 집합을 감안할 때 : 그래서 지금
// Generate all control points for a set of knots
public static List<Point2D> GenerateControlPoints(List<Point2D> knots)
{
if (knots == null || knots.Count < 3)
return null;
List<Point2D> res = new List<Point2D>();
// First control point is same as first knot
res.Add(knots.First());
// generate control point pairs for each non-end knot
for (int i = 1; i < knots.Count - 1; ++i)
{
Point2D[] cps = GetControlsPoints(knots[i - 1], knots[i], knots[i+1]);
res.AddRange(cps);
}
// Last control points is same as last knot
res.Add(knots.Last());
return res;
}
당신 2*(n-1)
개의 제어점 배열을 가지며,이를 사용하여 매듭 점 사이의 실제 커브 세그먼트를 생성 할 수 있습니다. 당신이 당신의 노트를 통해이 작업을 실행하면
public static Point2D LinearInterp(Point2D p0, Point2D p1, double fraction)
{
double ix = p0.X + (p1.X - p0.X) * fraction;
double iy = p0.Y + (p1.Y - p0.Y) * fraction;
return new Point2D(ix, iy);
}
public static Point2D BezierInterp(Point2D p0, Point2D p1, Point2D c0, Point2D c1, double fraction)
{
// calculate first-derivative, lines containing end-points for 2nd derivative
var t00 = LinearInterp(p0, c0, fraction);
var t01 = LinearInterp(c0, c1, fraction);
var t02 = LinearInterp(c1, p1, fraction);
// calculate second-derivate, line tangent to curve
var t10 = LinearInterp(t00, t01, fraction);
var t11 = LinearInterp(t01, t02, fraction);
// return third-derivate, point on curve
return LinearInterp(t10, t11, fraction);
}
// generate multiple points per curve segment for entire path
public static List<Point2D> GenerateCurvePoints(List<Point2D> knots, List<Point2D> controls)
{
List<Point2D> res = new List<Point2D>();
// start curve at first knot
res.Add(knots[0]);
// process each curve segment
for (int i = 0; i < knots.Count - 1; ++i)
{
// get knot points for this curve segment
Point2D p0 = knots[i];
Point2D p1 = knots[i + 1];
// get control points for this curve segment
Point2D c0 = controls[i * 2];
Point2D c1 = controls[i * 2 + 1];
// calculate 20 points along curve segment
int steps = 20;
for (int s = 1; s < steps; ++s)
{
double fraction = (double)s/steps;
res.Add(BezierInterp(p0, p1, c0, c1, fraction));
}
}
return res;
}
당신은 지금 거리가 라인의 굴곡에 따라 따로 따로 변수 거리입니다 보간 점 세트가 있습니다. 여기에서 원래 WalkPath 방법을 반복적으로 실행하여 일정한 거리만큼 떨어져있는 점 집합을 생성합니다.이 점 집합은 일정한 속도로 곡선을 따라 휴대 전화의 진행을 정의합니다.
경로의 어느 지점에서든 휴대 기기의 제목은 어느 한 쪽의 점 사이의 각도 (대략)입니다. 경로의 모든 점 n
에 대해 p[n-1]
과 p[n+1]
사이의 각도가 머리글 각도입니다. 소수점 연산, 보간 등 - - 나는 기능을 많이 가지고 내가 나이 전에 쓴 Point2D를 클래스 사용하기 때문에
// get angle (in Radians) from p0 to p1
public static double AngleBetween(Point2D p0, Point2D p1)
{
return Math.Atan2(p1.X - p0.X, p1.Y - p0.Y);
}
나는, 내 코드에서 위를 채택했습니다. 내장을 좀을 추가했을 수 버그는 번역 중에 있지만 잘하면 그들이 놀 때 쉽게 발견 할 수 있습니다.
어떻게 진행되는지 알려주세요. 어떤 어려움에 처했을 때 나는 내가 도울 수있는 것을 보게 될 것이다.
그래서 스플라인 곡선이 생성되었지만이를 따라 일정한 속도로 움직여야합니까? – Corey
@Corey 내 생각 엔 ... 내가 지금까지 한 일을 대략 보여주기 위해 질문을 편집하겠다. – Bushes
@ Corey question edited – Bushes