이 게시물의 경우, y = f (t) 여기서 t는 변경하는 매개 변수 (시간 / 진행)이고 y는 목표까지의 거리입니다. 가로축이 시간 / 진행이고 세로가 거리 인 2D 플롯에서 점으로 설명하겠습니다.
첫 번째 점이 (0, 1)이고 네 번째 (마지막) 점이 (1, 0) 인 입방 베 지어 곡선을 만들 수 있다고 생각합니다. 이 1x1 사각형 내에 두 개의 중간 점을 임의로 배치 할 수 있습니다 (x = rand, y = rand). 나는 이것을 분석적으로 확인할 수는 없지만 애플릿으로 놀아서 (예, 계속 웃어 라) 베 지어 곡선은 그런 제약으로 결코 줄어들지 않는 것 같습니다.
이것은 포인트 p1에서 포인트 p2까지 비 감소 경로를 제공하는 기본 함수 b (p1, p2)가됩니다.
이제 ab (p (1) = (0, 1), p (n) = (1, 0))을 생성 하고이 곡선을 따라 p (i)의 수를 1과 같이 선택할 수 있습니다
기본적으로 하나의 "일반"경로를 생성 한 후이를 세그먼트로 나누고 각 세그먼트를 재생성합니다.
수학 함수가 필요하기 때문에 : 위의 절차가 하나의 함수 y = f (t, s)로 패키지되어 시드 함수의 t 거리를 제공한다고 가정합니다. 필요할 것이예요:
- 메인 베 지어 스플라인의 중간 지점 2 개를 배치하기위한 4 개의 난수 ((0, 1)에서 (1, 0)까지)
- n 개의 세그먼트가있는 경우 각 세그먼트의 경계에 대한 n-1 숫자 (첫 번째 세그먼트는 항상 (0, 1)에서 시작합니다. 즉 t = 0이고 마지막은 (1,0)에서 끝납니다. 즉 t = 1)
- 세그먼트 수를 랜덤 화하려는 경우 1 개
- 당신의 t가 도달하는 세그먼트의 스플라인의 중간 지점을 배치하기위한 4 개의 숫자
따라서 각 시드는 다음 중 하나를 제공해야합니다.
- 0과 1 사이의 7 + n 실수 (세그먼트 수를 제어하려는 경우)
- 실수 7 개 및 1보다 큰 정수 1 (임의의 세그먼트 수)
시드로 숫자 배열을 제공하여 이들 중 하나를 수행 할 수 있다고 생각합니다. 또는 하나의 숫자 s를 시드로 제공 한 다음 rand (s), rand (s + 1), rand (s + 2) 등으로 내장 난수 생성기를 호출하거나 그런 다음 rand.NextNumber를 계속 호출하십시오.
전체 함수 f (t, s)가 많은 세그먼트로 구성되어 있지만 각 t에 대해 하나의 세그먼트 만 평가한다는 점에 유의하십시오. 당신은 것입니다 당신이 없는지를 두 개의 세그먼트가 겹치는 있도록으로 정렬해야하기 때문에, 반복이 방법으로 세그먼트의 경계를 계산해야합니다. 아마도이 여분의 작업을 최적화하고 제거하고 각 호출마다 하나의 세그먼트의 끝점 만 찾을 수는 있지만 지금 당장은 분명하지 않습니다.
또한 베 지어 곡선은 필요하지 않으며 적절하게 동작하는 스플라인이 수행합니다.
샘플 Matlab 구현을 만들었습니다.
베 지어 기능 (벡터화) :
function p = bezier(t, points)
% p = bezier(t, points) takes 4 2-dimensional points defined by 2-by-4 matrix
% points and gives the value of the Bezier curve between these points at t.
%
% t can be a number or 1-by-n vector. p will be an n-by-2 matrix.
coeffs = [
(1-t').^3, ...
3*(1-t').^2.*t', ...
3*(1-t').*t'.^2, ...
t'.^3
];
p = coeffs * points;
end
위에서 설명한 복합 베 지어 기능 (각 호출마다 얼마나 많은 평가가 필요한지 명확하게 알 수 있도록 벡터화되지 않은 상태로 남음) :
function p = bezier_compound(t, ends, s)
% p = bezier(t, points) takes 2 2-dimensional endpoints defined by a 2-by-2
% matrix ends and gives the value of a "compound" Bezier curve between
% these points at t.
%
% t can be a number or 1-by-n vector. s must be a 1-by-7+m vector of random
% numbers from 0 to 1. p will be an n-by-2 matrix.
%% Generate a list of segment boundaries
seg_bounds = [0, sort(s(9:end)), 1];
%% Find which segment t falls on
seg = find(seg_bounds(1:end-1)<=t, 1, 'last');
%% Find the points that segment boundaries evaluate to
points(1, :) = ends(1, :);
points(2, :) = [s(1), s(2)];
points(3, :) = [s(3), s(4)];
points(4, :) = ends(2, :);
p1 = bezier(seg_bounds(seg), points);
p4 = bezier(seg_bounds(seg+1), points);
%% Random middle points
p2 = [s(5), s(6)] .* (p4-p1) + p1;
p3 = [s(7), s(8)] .* (p4-p1) + p1;
%% Gather together these points
p_seg = [p1; p2; p3; p4];
%% Find what part of this segment t falls on
t_seg = (t-seg_bounds(seg))/(seg_bounds(seg+1)-seg_bounds(seg));
%% Evaluate
p = bezier(t_seg, p_seg);
end
임의의 시드에 대한 함수를 표시하는 스크립트 (이것은 임의의 함수가 호출되는 유일한 장소이며 다른 모든 코드에 대한 임의의 변수는이 하나의 임의의 배열에서 전파됨)에 유의하십시오.
clear
clc
% How many samples of the function to plot (higher = higher resolution)
points = 1000;
ends = [
0, 0;
1, 1;
];
% a row vector of 12 random points
r = rand(1, 12);
p = zeros(points, 2);
for i=0:points-1
t = i/points;
p(i+1, :) = bezier_compound(t, ends, r);
end
% We take a 1-p to invert along y-axis here because it was easier to
% implement a function for slowly moving away from a point towards another.
scatter(p(:, 1), 1-p(:, 2), '.');
xlabel('Time');
ylabel('Distance to target');
다음은 샘플 출력입니다.
대부분의 기준을 충족하는 것 같습니다. 하나:
- "코너"가 있습니다. 베 지어 곡선을보다 적절하게 사용하면이 기능을 사용할 수 있습니다.
- "분명히"스플라인처럼 보이지만 종자를 알지 못하면 사소한 시간이 지나면 어떻게 될지 추측 할 수 없습니다.
- 구석쪽으로 너무 많이 벗어나는 경우는 거의 없습니다 (시드 생성기의 분포로 재생하여 고정 할 수 있음).
- 3 차 베 지어 기능은 이러한 구속 조건이 주어지면 모퉁이 근처 영역에 도달 할 수 없습니다.
f'(x)>0
모든 노이즈 함수의 절대 값의 정규화 된 통합은 모든 요구 사항을 충족시킵니다. 불행히도 나는 그것을 계산하는 쉬운 방법을 모르지만 다른 누군가가 할 수 있습니다. :)