2016-09-22 3 views
1

В настоящее время я работаю над эскизом обработки (как на языке), который управляется логикой черепахи (см. https://en.wikipedia.org/wiki/Turtle_graphics). Это означает, что я рисую линию от текущей координаты до заданной координаты. Эта предоставленная координата станет новой текущей координатой. Я хочу аппроксимировать круг и написал простой кусок кода, используя тригонометрику. Код выглядит следующим образом:Рисование круга в программе черепахи

void drawCircle(int radius){ 
    // The circle center is radius amount to the left of the current xpos 
    int steps = 16; 
    double step = TWO_PI /steps; 

    for(double theta = step; theta <= TWO_PI; theta += step){ 
     float deltaX = cos((float)theta) - cos((float)(theta - step)); 
     float deltaY = sin((float)theta) - sin((float)(theta - step)); 

     moveXY(deltaX*radius, deltaY*radius); 
    } 

} 

Программная логика проста. Он будет использовать переменную theta для прокрутки всех радианов по кругу. Количество шагов будет указывать на то, насколько большой размер каждого блока theta. Затем он вычисляет значения x, y для конкретной точки в окружности, определяемой тетой. Затем он вычитает значения x, y предыдущего цикла (следовательно, theta-step), чтобы получить сумму, которую он должен будет переместить из этой позиции, чтобы достичь желаемой позиции x, y. Он, наконец, передаст эти значения дельта функции moveXY, которая рисует линию от текущей точки до поставленных значений и делает их новой текущей позицией.

Программа работает очень хорошо при использовании ограниченного количества шагов. Однако, когда количество шагов увеличивается, круги становятся все более похожими на спираль Фибоначчи. Я предполагаю, что это связано с неточностями с числом с плавающей точкой и вычислениями синуса и косинуса, и это добавляется с каждой итерацией.

Я что-то интерпретировал неправильно? Я хочу, чтобы порт этот код на Javascript в конечном итоге, поэтому я ищу решение в дизайне. Использование BigDecimal может не работать, тем более, что оно не содержит собственных функций косинуса и синуса. Я включил несколько изображений, чтобы детализировать проблему. Любая помощь высоко ценится!

Количество Шаг 16: Step count 16

Количество Шаг 32: Step count 32

Количество Шаг 64: Step count 64

отсчет шага 128: Step count 128

ответ

1

Float и синус/косинус должен быть достаточно точным. Вопрос в том, насколько точна ваша позиция в самолете? Если эта позиция измеряется в пикселях, то каждое из ваших значений с плавающей запятой округляется до целого после каждого шага. Затем теряется точность.

+0

Переменная позиции была сохранена как int, и это вызвало отклонение. После переключения на поплавок ошибка была исправлена. Все мои круги теперь совершенны! – Diaita

0

На каждой итерации вокруг цикла вы вычисляете дельту без учета того, что представляет собой текущая координата. Настолько эффективно, что вы «мертвые считаете», что всегда будет неточным, так как ошибки на каждом этапе нарастают.

Поскольку вы знаете, что вам нужен круг, на каждой итерации был бы альтернативный подход, чтобы сначала определить фактическую точку на круге, к которому вы хотите добраться, а затем вычислить дельту, чтобы добраться туда, - так что-то вроде (но я должен признать, что я его не тестировал!):

void drawCircle(int radius){ 
    // The circle center is radius amount to the left of the current xpos 
    int steps = 16; 
    double step = TWO_PI /steps; 

    float previousX = 0; 
    float previousY = radius; 

    for(double theta = step; theta <= TWO_PI; theta += step){ 
     float thisX = radius * sin((float)theta); 
     float thisY = radius * cos((float)theta); 

     moveXY(thisX - previousX, thisY - previousY); 

     previousX = thisX; 
     previousY = thisY; 
    } 

} 
+0

Но поскольку позиции генерируются по тому же алгоритму, позиции должны быть почти одинаковыми. Проблема оказалась в том, что позиции сохранены. Фиксация этого создает идеальные круги! Спасибо за ваш вклад. – Diaita

Смежные вопросы