Страница 1 из 2
Рисование Арки, не могу понять один момент?
Добавлено:
14.02.2015 01:20:09
xterro
Доброго времени суток, нашёл в инете код, для рисования арки. У простил его немного, убрав функции рисования, оставил только код вычисления точек(для последующей отрисовки). Сначала код:
- Код: Выделить всё
procedure TArc.CalculateArc();
var
Coef, Delta : Real;
BAngle, EAngle : Real;
Iterations, i : Integer;
begin
{ x = R * cos(A) + X
y = R * sin(A) + Y }
// Переводим в радианы
BAngle := (FStartAngle / 180) * Pi;
EAngle := (FEndAngle / 180) * Pi;
// Определяем оптимальное количество итераций
Coef := (Pi*2) / Abs(EAngle - BAngle);
Iterations := Round((2 * FRadius ) / Coef);
Delta := (EAngle - BAngle) / Iterations;
SetLength(Points, Iterations);
WriteLn('Iterations: ', Iterations);
for i:=0 to Iterations-1 do begin
Points[i].X := FRadius * Cos(-BAngle) + FX;
Points[i].Y := FRadius * Sin(-BAngle) + FY;
BAngle := BAngle + Delta;
WriteLn(i, '. X: ', Points[i].X, ' Y: ', Points[i].Y);
end;
end;
Собственно проблема заключается в том, что в данном варианте, арка не дорисовывается, т.е например задаю угол от 0 до 90гр. на деле рисует от 0 до ~80-85 гр. но если увеличить количество точек в массиве на одну и соответсвенно увеличить количество итераций на 1,
- Код: Выделить всё
SetLength(Points, Iterations+1);
for i:=0 to Iterations do begin
Points[i].X := FRadius * Cos(-BAngle) + FX;
Points[i].Y := FRadius * Sin(-BAngle) + FY;
BAngle := BAngle + Delta;
end;
то всё становится красивенько и ровненько. Не могу понять почему так
Так же не даёт покоя строчка вычисления количества итераций, не могу понять зачем это сделано, зачем делить диаметр на часть окружности(для угла в 90гр. Coef=4)?
- Код: Выделить всё
Iterations := Round((2 * FRadius ) / Coef);
Вроде просто всё, а не въеду
Re: Рисование Арки, не могу понять один момент?
Добавлено:
14.02.2015 02:08:31
zub
ты забыл про последнюю точку. забей жестко колво итераций 1 - т.е. какбудьто дугу надо апроксимировать отрезком и прогони свой цикл, всё станет ясно
>>Так же не даёт покоя строчка вычисления количества итераций
не вникал, но зависеть должно не только от радиуса и угла а еще от масштаба на экране (т.е. от "фактического" радиуса, это ведь редактор насколько я понимаю). тут место для творчества - подбери формулу так, чтобы она давала приемлимую апроксимацию, с чего ты взял что нужно делать именно по этой формуле?
Re: Рисование Арки, не могу понять один момент?
Добавлено:
14.02.2015 14:22:44
xterro
с чего ты взял что нужно делать именно по этой формуле?
Даже не знаю, просто нашёл пример и по нему начал делать. Пытался делать ещё по другому: количество итераций - это разница между конечным и начальным углами в градусах, шаг - 1 градус, но картинка получалась не айс:
т.е если вот так:
- Код: Выделить всё
// Coef := (Pi*2) / Abs(EAngle - BAngle);
Iterations := Abs(FEndAngle - FStartAngle); //Round((2 * FRadius ) / Coef);
Delta := (1/180)*Pi; //(EAngle - BAngle) / Iterations;
SetLength(Points, Iterations);
for i:=0 to Iterations-1 do begin
// ....
end;
В таком варианте получалось что точки как-бы накладывались друг на друга, и получалось коряво:
- 2.png (283 байт) Просмотров: 26950
- 3.png (308 байт) Просмотров: 26950
Если следовать первноначальному коду, то картинка получалась вполне себе красивой:
- 1.png (269 байт) Просмотров: 26950
Вот и думал, может помогут разобраться, что за магия такая
Re: Рисование Арки, не могу понять один момент?
Добавлено:
14.02.2015 14:45:07
zub
>>шаг - 1 градус, но картинка получалась не айс:
шаг в идеале должен высчитываться от отклонения дуги от прямой (т.е. как отклонение набрало например 1 пиксел - ставим "корректирующую" точку), наверно можно считать по длине дуги за "итерацию", но никак не по просто углу - тогда на малых радиусах будет излишняя детализация (как на скриншоте, с "наездом" точек), а на больших радиусах детализации будет нехватать
Добавлено спустя 3 часа 49 минут 15 секунд:
или я чето я непонял и ты точками рисуешь? будет будет тормозилка, рисуй линиями
Re: Рисование Арки, не могу понять один момент?
Добавлено:
15.02.2015 10:47:18
xterro
Не, рисую как раз отрезками. В этой функции только расчитываю массив точек, по которому потом пробегаю, и соединяю эти точки последовательно отрезками.(1-2-3-4... и т.д)
Re: Рисование Арки, не могу понять один момент?
Добавлено:
15.02.2015 13:51:17
zub
Глянул че там у меня с дугой, всё печально лод не считается))
- Код: Выделить всё
procedure GDBObjARC.createpoint;
var
i: GDBInteger;
v:GDBvertex;
pv:GDBVertex;
begin
angle := endangle - startangle;
if angle < 0 then angle := 2 * pi + angle;
Vertex3D_in_WCS_Array.clear;
v.x:=cos(startangle);
v.y:=sin(startangle);
v.z:=0;
pv:=VectorTransform3D(v,objmatrix);
Vertex3D_in_WCS_Array.add(@pv);
lod:=100; { TODO : А кто лод считать будет? }
for i:=1 to lod do
begin
v.x:=cos(startangle+i / lod * angle);
v.y:=sin(startangle+i / lod * angle);
v.z:=0;
pv:=VectorTransform3D(v,objmatrix);
Vertex3D_in_WCS_Array.add(@pv);
end;
Vertex3D_in_WCS_Array.Shrink;
end;
сейчас попробую ченить сваять с лодом
Добавлено спустя 32 минуты 7 секунд:а ничего своять без тотальных переделок не получится, на момент генерации точек еще неизвестно с каким масштабом будет отображена дуга. т.е. в моем случае точки нужно генерировать с максимальной детализацией, оптимизации включаются в момент отрисовки - если масштаб маленький, дуга рисуется через точку, через две и т.д в зависимости от масштаба... Надо будет этот момент переделать
Re: Рисование Арки, не могу понять один момент?
Добавлено:
15.02.2015 20:06:10
xterro
Т.е получается lod это по сути количество итераций как у меня, и задаётся просто от фонаря?
И потом, как может быть не известен масштаб, или у тебя каждая фигура со своим масштабом рисуется? я думал, в такого рода программах, масштаб един для всей схемы
P.S. ради прикола, попробуй код, который у меня, глядишь получится чего ))
Re: Рисование Арки, не могу понять один момент?
Добавлено:
15.02.2015 21:19:17
zub
вообще у меня lod - абстрактный уровень детализации объекта, в данном случае совпадает с количеством сегментов апроксимирующих дугу.
>>И потом, как может быть не известен масштаб, или у тебя каждая фигура со своим масштабом рисуется? я думал, в такого рода программах, масштаб един для всей схемы
Крутишь колесико мышки - масштаб (отображения, но не примитивов) меняется, на этапе генерации примитивов в общем случае неизвесно с каким масштабом будет отображаться примитив (возможно дуга с радиусом 0.0001 будет занимать весь экран, а может будет видна в виде точки). Сейчас пока правлю чтоб вытащить масштаб на этап генерации, посгляжу что получится.
>>P.S. ради прикола, попробуй код, который у меня, глядишь получится чего ))
ничего хорошего не получится - будет лод зависеть от угла, а должен динамически подстраиваться под ситуацию на экране, чтобы экономить ресурсы не уменшая критически качество изображения
Re: Рисование Арки, не могу понять один момент?
Добавлено:
15.02.2015 21:34:00
xterro
Всё равно не понимаю
В начале ставишь коэф. масштабирования скажем 2, и рисуешь, например две дуги, одна с радиусом 0,00001 вторая с радиусом 10 (это всё условные единицы, никак не зависящие от координат), потом при выводе приводишь их в координаты экрана, в результате, дуга в 0,0001 будет точкой, дуга в 10 - нормальной дугой, вернее она будет значительно больше первой. Но коэф. масштабирования у обоих одинаковый - 2. крутишь колёсико и он меняется 2.1, 2,2, 2,3... 5... 10 соответственно меняется и картинка на экране. По крайней мере я так для себя думал )
Re: Рисование Арки, не могу понять один момент?
Добавлено:
15.02.2015 23:25:43
zub
Переделал, теперь это выглядит так:
- Код: Выделить всё
procedure GDBObjARC.createpoints(var DC:TDrawContext);
var
i: GDBInteger;
l: GDBDouble;
v:GDBvertex;
pv:GDBVertex;
begin
angle := endangle - startangle;
if angle < 0 then angle := 2 * pi + angle;
Vertex3D_in_WCS_Array.clear;
v.x:=cos(startangle);
v.y:=sin(startangle);
v.z:=0;
pv:=VectorTransform3D(v,objmatrix);
Vertex3D_in_WCS_Array.add(@pv);
l:=r*angle/(dc.zoom*3);
if l>255 then lod:=255
else
begin
lod:=round(l);
if lod<4 then lod:=4;
end;
for i:=1 to lod do
begin
v.x:=cos(startangle+i / lod * angle);
v.y:=sin(startangle+i / lod * angle);
v.z:=0;
pv:=VectorTransform3D(v,objmatrix);
Vertex3D_in_WCS_Array.add(@pv);
end;
Vertex3D_in_WCS_Array.Shrink;
end;
В процедуру приходит структура данных содержащая некоторые данные используемые при отрисовке, в 2D случае важен только dc.zoom - чем он больше, тем изображение на экране меньше и деталей требуется меньше. на основе его и длины дуги считаю lod, формула "экспериментальная", кофф. три взят от балды, но проде результаты нормальные)). lod ограничен 255 - потому что под него выделен байт))
Вот 3 картинки с одной и тойже дугой в разных масштабах, дуга радиусом ~145 едениц.
На первой она маленькая, lod=5, на таком масштабе больше и ненадо, зато экономия и памяти и проца, в случае если на чертеже несколько тысяч таких дуг.
На второй масштаб увеличен, lod не пересчитан, = 5, просто чтоб понимать что рисуется заместо такой дуги.
На третьей масштаб увеличен, lod пересчитан =231.
Re: Рисование Арки, не могу понять один момент?
Добавлено:
15.02.2015 23:45:48
xterro
Всё, теперь понял, просто для повышения производительности. Интересно, а экономия большая получается, если скажем масштаб как на 3-й картинке, а lod так и останется например 100, мол, ну подумаешь лишние 90-95 итераций прокрутим, для камня это семечки. Не сравнивал?
Re: Рисование Арки, не могу понять один момент?
Добавлено:
16.02.2015 01:14:34
zub
экономия очень сущестивенная, привожу циферки для dxf файла содержащего 60000 дуг, т.к там работают еще некоторые оптимизайии для отрисовки, привожу 2 время рендера - первое без дополнительных оптимизаций, второе с ними.
фиксированный lod=100
загрузка файла ~7.3сек (включает время первичной регенерации, от старта загрузки до появления картинки)
отъел памяти после загрузки ~639мб
время на отрисовку кадра ~200мсек\17мсек (в кадре видимы все 60000 дуг)
повторная регенерация ~1.5сек
lod "динамический"
загрузка файла ~1.5сек (включает время первичной регенерации, от старта загрузки до появления картинки)
отъел памяти после загрузки ~359мб
время на отрисовку кадра ~21мсек\17мсек (в кадре видимы все 60000 дуг)
повторная регенерация ~0.2сек
голая программа после старта перед загрузкой файла отъедает 154мб, цифры о памяти из диспетчера задач - графа "выделенная память"
Re: Рисование Арки, не могу понять один момент?
Добавлено:
16.02.2015 08:18:20
xterro
Мда, существенно, походу мне в будущем придётся с этим же вопросом столкнуться... в далёком будущем
Re: Рисование Арки, не могу понять один момент?
Добавлено:
16.02.2015 10:36:52
zub
дополнительно ограничил lod сверху - максимум 20 сегментов, для работы на экране потянет, но для печати этого мало
>>в далёком будущем
Вообще лучше сразу стресстестики гонять чтобы изначально закладывать разные "оптимизации", пусть даже не реализовывать, но понимать что рано или поздно это понадобится. Файл из теста выше в автокаде и грузится быстрее, и память не жрет, и рисуется быстрее. Например можно вообще не генерировать массив точек на каждую арку а использовать заранее расчитаный общий на все окружности\арки - рисовать крайние точки фактической арки, а между ними брать выборку с нужным шагом из предрасчитанного массива со сдвигом и масштабированием - рости есть куда))
Re: Рисование Арки, не могу понять один момент?
Добавлено:
16.02.2015 14:52:46
Снег Север
Может я не в теме, но если нужна качественная масштабируемая графика, то, может, стоит посмотреть в сторону векторной графики?
Например
http://wiki.lazarus.freepascal.org/fpvectorial