Нахождение касательной линии в точке на рандомизированном склоне
У меня есть кусок кода обработки, который мне дали, который, кажется, устанавливает рандомизированный ряд Фурье. К сожалению, несмотря на мои усилия по улучшению моих математических навыков, я понятия не имею, что он делает, и статьи, которые я нашел, не очень помогают.
Я пытаюсь расширить этот код так, чтобы я мог нарисовать линию, касательную к точке на склоне, созданному кодом ниже. Ближайший ответ на этот вопрос я могу найти на математическом форуме. К сожалению, я не очень понимаю, о чем идет речь, и действительно ли это имеет отношение к моей ситуации.
Буду очень признателен за любую помощь в расчете касательной линии в определенной точке на этой кривой.
ОБНОВЛЕНИЕ С 17.06.13
Я пытался поиграть с этим, но без особого успеха. Это лучшее, что я могу сделать, и я сомневаюсь, что я правильно использую производную, чтобы найти касательную (или даже если я нашел производную в точке правильно). Кроме того, я начинаю беспокоиться, что неправильно рисую линию, даже если у меня все остальное правильно. Если кто-то может внести свой вклад в это, я был бы признателен.
final int w = 800;
final int h = 480;
double[] skyline;
PImage img;
int numOfDeriv = 800;
int derivModBy = 1; //Determines how many points will be checked
int time;
int timeDelay = 1000;
int iter;
double[] derivatives;
void setup() {
noStroke();
size(w, h);
fill(0,128,255);
rect(0,0,w,h);
int t[] = terrain(w,h);
fill(77,0,0);
for(int i=0; i < w; i++){
rect(i, h, 1, -1*t[i]);
}
time = millis();
timeDelay = 100;
iter =0;
img = get();
}
void draw() {
int dnum = 0; //Current position of derivatives
if(iter == numOfDeriv) iter = 0;
if (millis() > time + timeDelay){
image(img, 0, 0, width, height);
strokeWeight(4);
stroke(255,0,0);
point((float)iter*derivModBy, height-(float)skyline[iter*derivModBy]);
strokeWeight(1);
stroke(255,255,0);
print("At x = ");
print(iter);
print(", y = ");
print(skyline[iter]);
print(", derivative = ");
print((float)derivatives[iter]);
print('\n');
lineAngle(iter, (int)(height-skyline[iter]), (float)derivatives[iter], 100);
lineAngle(iter, (int)(height-skyline[iter]), (float)derivatives[iter], -100);
stroke(126);
time = millis();
iter += 1;
}
}
void lineAngle(int x, int y, float angle, float length)
{
line(x, y, x+cos(angle)*length, y-sin(angle)*length);
}
int[] terrain(int w, int h){
width = w;
height = h;
//min and max bracket the freq's of the sin/cos series
//The higher the max the hillier the environment
int min = 1, max = 6;
//allocating horizon for screen width
int[] horizon = new int[width];
skyline = new double[width];
derivatives = new double[numOfDeriv];
//ratio of amplitude of screen height to landscape variation
double r = (int) 2.0/5.0;
//number of terms to be used in sine/cosine series
int n = 4;
int[] f = new int[n*2];
//calculating omegas for sine series
for(int i = 0; i < n*2 ; i ++){
f[i] = (int) random(max - min + 1) + min;
}
//amp is the amplitude of the series
int amp = (int) (r*height);
int dnum = 0; //Current number of derivatives
for(int i = 0 ; i < width; i ++){
skyline[i] = 0;
double derivative = 0.0;
for(int j = 0; j < n; j++){
if(i % derivModBy == 0){
derivative += ( cos( (f[j]*PI*i/height) * f[j]*PI/height) -
sin(f[j+n]*PI*i/height) * f[j+n]*PI/height);
}
skyline[i] += ( sin( (f[j]*PI*i/height) ) + cos(f[j+n]*PI*i/height) );
}
skyline[i] *= amp/(n*2);
skyline[i] += (height/2);
skyline[i] = (int)skyline[i];
horizon[i] = (int)skyline[i];
derivative *= amp/(n*2);
if(i % derivModBy == 0){
derivatives[dnum++] = derivative;
derivative = 0;
}
}
return horizon;
}
void reset() {
time = millis();
}
2 ответа
Я получил ответ на эту проблему через "кварки" в форме processing.org. По сути, проблема в том, что я брал производную каждого члена ряда вместо того, чтобы брать производную суммы целого ряда. Кроме того, я все равно неправильно применял свой результат.
Вот код, который кварки при условии, что окончательно решает эту проблему.
final int w = 800;
final int h = 480;
float[] skyline;
PImage img;
int numOfDeriv = 800;
int derivModBy = 1; //Determines how many points will be checked
int time;
int timeDelay = 1000;
int iter;
float[] tangents;
public void setup() {
noStroke();
size(w, h);
fill(0, 128, 255);
rect(0, 0, w, h);
terrain(w, h);
fill(77, 0, 0);
for (int i=0; i < w; i++) {
rect(i, h, 1, -1*(int)skyline[i]);
}
time = millis();
timeDelay = 100;
iter =0;
img = get();
}
public void draw() {
if (iter == numOfDeriv) iter = 0;
if (millis() > time + timeDelay) {
image(img, 0, 0, width, height);
strokeWeight(4);
stroke(255, 0, 0);
point((float)iter*derivModBy, height-(float)skyline[iter*derivModBy]);
strokeWeight(1);
stroke(255, 255, 0);
print("At x = ");
print(iter);
print(", y = ");
print(skyline[iter]);
print(", derivative = ");
print((float)tangents[iter]);
print('\n');
lineAngle(iter, (int)(height-skyline[iter]), (float)tangents[iter], 100);
lineAngle(iter, (int)(height-skyline[iter]), (float)tangents[iter], -100);
stroke(126);
time = millis();
iter += 1;
}
}
public void lineAngle(int x, int y, float angle, float length) {
line(x, y, x+cos(angle)*length, y-sin(angle)*length);
}
public void terrain(int w, int h) {
//min and max bracket the freq's of the sin/cos series
//The higher the max the hillier the environment
int min = 1, max = 6;
skyline = new float[w];
tangents = new float[w];
//ratio of amplitude of screen height to landscape variation
double r = (int) 2.0/5.0;
//number of terms to be used in sine/cosine series
int n = 4;
int[] f = new int[n*2];
//calculating omegas for sine series
for (int i = 0; i < n*2 ; i ++) {
f[i] = (int) random(max - min + 1) + min;
}
//amp is the amplitude of the series
int amp = (int) (r*h);
for (int i = 0 ; i < w; i ++) {
skyline[i] = 0;
for (int j = 0; j < n; j++) {
skyline[i] += ( sin( (f[j]*PI*i/h) ) + cos(f[j+n]*PI*i/h) );
}
skyline[i] *= amp/(n*2);
skyline[i] += (h/2);
}
for (int i = 1 ; i < w - 1; i ++) {
tangents[i] = atan2(skyline[i+1] - skyline[i-1], 2);
}
tangents[0] = atan2(skyline[1] - skyline[0], 1);
tangents[w-1] = atan2(skyline[w-2] - skyline[w-1], 1);
}
void reset() {
time = millis();
}
Что ж, в данном конкретном случае кажется, что вам не нужно много понимать о серии Фурье, просто она имеет вид:
A0 + A1*cos(x) + A2*cos(2*x) + A3*cos(3*x) +... + B1*sin(x) + B2*sin(x) +...
Обычно вам дают функцию f(x)
и вам нужно найти значения An
а также Bn
такой, что ряд Фурье сходится к вашей функции (как вы добавляете больше терминов) для некоторого интервала [a, b]
,
В этом случае, однако, им нужна случайная функция, которая просто выглядит как разные комки и ямы (или холмы и долины, как можно предположить из контекста), поэтому они выбирают случайные члены из ряда Фурье между min и max и устанавливают их коэффициенты равными 1 (и концептуально 0 иначе). Они также удовлетворяются с помощью ряда Фурье из 4-х синусоидальных и 4-х косинусных терминов (которыми, безусловно, легче управлять, чем бесконечное число терминов). Это означает, что их ряды Фурье выглядят как различные функции синуса и косинуса разных частот, сложенных вместе (и все имеют одинаковую амплитуду).
Найти производную от этого легко, если вспомнить, что:
sin(n*x)' = n * cos(x)
cos(n*x)' = -n * sin(x)
(f(x) + g(x))' = f'(x) + g'(x)
Таким образом, цикл для вычисления производной будет выглядеть так:
for(int j = 0; j < n; j++){
derivative += ( cos( (f[j]*PI*i/height) * f[j]*PI/height) - \
sin(f[j+n]*PI*i/height) * f[j+n]*PI/height);
}
В какой-то момент i
(Обратите внимание, что производная берется в отношении i
так как это переменная, которая представляет нашу позицию х здесь).
Надеемся, что с этим вы сможете рассчитать уравнение касательной в точке i
,
ОБНОВИТЬ
В том месте, где вы делаете skyline[i] *= amp/(n*2);
Вы также должны скорректировать свою производную соответственно derivative *= amp/(n*2);
однако ваша производная не нуждается в корректировке, когда вы делаете skyline[i] += height/2;