-
Добрый день! Мастера подскажите как нарисовать спираль Fermat с отрисовкой в писелах? Что-то вроде этого:
procedure CreateSpiral(FWidth, FHeight : Integer; Rotangle : Double);
var X, Y, Ox, Oy : Integer;
Theta, Dist : Double;
clr : Byte;
temp : Double;
begin
Ox := MulDiv(FWidth, 1, 2);
Oy := MulDiv(FHeight, 1, 2);
Theta := 0;
for Y := 0 to Pred(FHeight) do
begin
for X := 0 to Pred(FWidth) do
begin
Dist := Sqrt(Sqr(X - Ox) + Sqr(Y - Oy));
Theta := -ArcTan2(y - Oy, x - Ox) + Rotangle;
temp := Theta + Dist;
clr := 255*Sign(Sin(temp));
if clr <> 255 then
если не равно белому цвету, то заполнять пикселами переднего плана (например, clBlue);
end;
end;
end;
-
procedure TForm1.Button2Click(Sender: TObject);
var
i, x, y, cx, cy, MaxR: Integer;
a, theta, R: Double;
begin
a := 20;
cx := 200;
cy := 200;
maxR := 200;
i := 0;
repeat
theta := i * 0.2 /(2 * pi);
R := a * Sqrt(theta);
if R > MaxR then
Break;
x := cx + Round(R * Cos(theta));
y := cy + Round(R * Sin(theta));
Canvas.Pixels[x, y] := clBlack;
Inc(i);
until False;
end;
-
Спасибо за пример, но а если все же ближе к моему коду как можно изменить код MBo?
-
с отрисовкой поп пикселам.
-
не вижу необходимости зарисовывать каждый пиксел картинки по отдельности.
-
Необходимость в том, чтобы ускорить отрисовку и сделать листья спирали (или лист спирали) с изменяемой шириной, а не просто линией или в виде отдельных пикселей. Все как можно приблизить код к моему примеру? Спасибо!
-
И еще - это R := a*Power(theta, 1/2) или R := a*Sqrt(theta) - спираль Ферма, R :=theta - это спираль Архимеда, а так R := a*1/Sqrt(theta) должна бы быть спираль Lituus, но выпадает постоянно ошибка неверного деления на ноль. Почему?
-
>*1/Sqrt(theta) должна бы быть спираль Lituus, но выпадает постоянно ошибка неверного деления на ноль. Почему?
проверяй, что theta не равно нулю (лучше - не меньше некой константы, скажем, 10e-3
-
1) все же остается необходимость в том, чтобы ускорить отрисовку и сделать листья спирали (или лист спирали) с изменяемой шириной, а не просто линией или в виде отдельных пикселей. Все как можно приблизить код к моему примеру? 2) проверка theta на 0 или 10e-3: if theta > 0 или 10e-3 then R := a * 1/Sqrt(theta) все равно вызывает прежнюю ошибку.
Спасибо!
-
пиши лог, можно будет посмотреть, где падает, или юзай средства Delphi
-
Доброе утро! Мастера, пожалуйста, подскажите, как все же соединить коды двух вариантов? Пример который привел Mbo работает отлично, но мне нужна конструкция именно такая (пока она строит спираль Архимеда, а мне нужны другие типы, например Ферат или Галилея): procedure CreateSpiral(FWidth, FHeight : Integer; Rotangle : Double);
var X, Y, Ox, Oy : Integer;
Theta, Dist : Double;
clr : Byte;
temp : Double;
begin
Ox := MulDiv(FWidth, 1, 2);
Oy := MulDiv(FHeight, 1, 2);
Theta := 0;
for Y := 0 to Pred(FHeight) do
begin
for X := 0 to Pred(FWidth) do
begin
Dist := Sqrt(Sqr(X - Ox) + Sqr(Y - Oy));
Theta := -ArcTan2(y - Oy, x - Ox) + Rotangle;
temp := Theta + Dist;
clr := 255*Sign(Sin(temp));
if clr <> 255 then
если не равно белому цвету, то заполнять пикселами переднего плана (например, clBlue);
end;
end;
end; Как можно код ниже модернизировать под мою конструкцию? procedure TForm1.Button2Click(Sender: TObject);
var
i, x, y, cx, cy, MaxR: Integer;
a, theta, R: Double;
begin
a := 20;
cx := 200;
cy := 200;
maxR := 200;
i := 0;
repeat
theta := i * 0.2 /(2 * pi);
R := a * Sqrt(theta);
if R > MaxR then
Break;
x := cx + Round(R * Cos(theta));
y := cy + Round(R * Sin(theta));
Canvas.Pixels[x, y] := clBlack;
Inc(i);
until False;
end; Все спасибо за практический совет!
-
Уважаемые мастера, может все же кто-то может подсказать хоть какую строчку надо менять в коде Вариант №1, чтобы он строил спираль Фермат? Всем спасибо!
-
> Dr. Andrew (28.08.07 12:44) [11]
> хоть какую строчку надо менять
17-ю извилину.
Начни думать, разбираться и все получится.
-
Спасибо за совет, если бы не думал и не разбирался, то не написал бы первый код. Но, в в том-то и дело что столкнулся с проблемой и поэтому обратился к более знающим Мастерам.
-
procedure TformMain.btnDrawClick(Sender: TObject);
var
Centre: TPoint;
SpiralWidth, SpiralHeight: Integer;
var
x, y: Integer;
angle: Extended;
a2, r2, delta: Extended;
ARect: TRect;
begin
Centre := Point(ClientWidth div 2, ClientHeight div 2);
SpiralWidth := 400; SpiralHeight := 300;
ARect := Rect(Centre.x - SpiralWidth div 2, Centre.y - SpiralHeight div 2,
Centre.x + SpiralWidth div 2, Centre.y + SpiralHeight div 2);
Canvas.DrawFocusRect(ARect);
a2 := sqr(40); delta := 0.03;
for y := ARect.Top to ARect.Bottom do
for x := ARect.Left to ARect.Right do
begin
angle := ArcTan2(Centre.y - y, x - Centre.x);
if (angle < 0) then angle := angle + 2 * pi;
r2 := sqr(x - Centre.x) + sqr(Centre.y - y);
delta := sqrt(r2) * 0.0002 + 0.01;
if (frac(abs((r2 / a2 - angle) / (2 * pi))) < delta) then
begin
Canvas.Pixels[x,y] := clBlack;
Canvas.Pixels[Centre.x - (x - Centre.x),
Centre.y - (y - Centre.y)] := clBlack;
end;
end;
end;
procedure TformMain.btnDraw2Click(Sender: TObject);
var
i, x, y, cx, cy, MaxR: Integer;
a, theta, R: Double;
begin
a := 40;
cx := ClientWidth div 2;
cy := ClientHeight div 2;
maxR := 200;
i := 0;
repeat
theta := i * 0.1 /(2 * pi);
R := a * Sqrt(theta);
if R > MaxR then Break;
x := cx - Round(R * Cos(theta));
y := cy + Round(R * Sin(theta));
Canvas.Pixels[x, y] := clSilver;
x := cx + Round(R * Cos(theta));
y := cy - Round(R * Sin(theta));
Canvas.Pixels[x, y] := clSilver;
Inc(i);
until False;
end;
2 способа, можешь сравнить.
-
Спасибо, sdubaruhnul! Первая процедура очень близка к моему первому варианту. Вы настоящий Мастер! Спасибо! Можно ли продолжить дискуссию с Вами? Меня интресует вот еще какие вопросы:
1) как сделать прорисовку с использованием ScanLine и сделать ширину витков регулируемой? Чтобы строилась спираль не сплошной линией в 1 пиксель, а в виде ленты, закручивающейся по спирали Фермат. 2) И еще, это (первый вариант) можно считать базовым? Как можно, например, из него нарисовать прочие спирали - например спираль Галилея? Спасибо и жду продолжения дискуссии.
-
Спасибо, sdubaruhnul! Спасибо протестировал - первый вариант (btnDrawClick) то, что нужно, только почему-то первый виток рисуется утолщенным в два раза. Как это исправить? Где погрешность или ошибка в коде?
-
> Dr. Andrew (30.08.07 07:07) [15], [16]Этот вариант сложно считать базовым, потому что естественная форма задания спиралей - в полярных координатах. В этих координатах спираль задаётся функцией - каждому углу Theta ставится в соответствие одно значение радиуса r (в случае ± разбиваем на две функции). И когда я говорю функция, подразумеваю явную функцию, заданную формулой, которую только и надо, что вычислить. В декартовой системе координат спираль задаётся уравнением, которое редко когда имеет приличную форму и которое надо заранее расчитать. Попробуй, например, вывести уравнение той же спирали Ферма. В моём варианте кода приходится переводить из декартовой в полярную, а однозначно перевести угол невозможно, только в общей форме (логично, что 0° это и 360° и 720° и т.д). Отсюда дополнительные сложности. В общем, если считать базовым такой вариант, в котором ты изменяешь всего одну строчку - формулу спирали, то нет, это не базовый вариант. Утолщённую линию не знаю точно как поправить, нужно варьировать коэффициенты в формуле: delta := sqrt(r2) * 0.0002 + 0.01; Другой способ - поменять систему проверки, а именно проверять в цикле все возможные углы:
procedure TformMain.btnDraw3Click(Sender: TObject);
var
Centre: TPoint;
SpiralWidth, SpiralHeight: Integer;
var
x, y: Integer;
angle, max_angle: Extended;
a2, r2, delta: Extended;
ARect: TRect;
begin
Centre := Point(ClientWidth div 2, ClientHeight div 2);
SpiralWidth := 400; SpiralHeight := 300;
ARect := Rect(Centre.x - SpiralWidth div 2, Centre.y - SpiralHeight div 2,
Centre.x + SpiralWidth div 2, Centre.y + SpiralHeight div 2);
Canvas.DrawFocusRect(ARect);
a2 := sqr(40); delta := 0.7;
max_angle := (sqr(SpiralWidth div 2) + sqr(SpiralWidth div 2)) / a2;
for y := ARect.Top to ARect.Bottom do
for x := ARect.Left to ARect.Right do
begin
angle := ArcTan2(Centre.y - y, x - Centre.x);
if (angle < 0) then angle := angle + 2 * pi;
r2 := sqr(x - Centre.x) + sqr(Centre.y - y);
while (angle <= max_angle) do
begin
if (abs(sqrt(a2 * angle) - sqrt(r2)) < delta) then
begin
Canvas.Pixels[x,y] := clBlack;
Canvas.Pixels[Centre.x - (x - Centre.x),
Centre.y - (y - Centre.y)] := clBlack;
end;
angle := angle + 2 * pi;
end;
end;
end;
Теперь delta - это погрешность расстояния пиксела до идеальной линии спирали. Варьируя delta можно изменять толщину линии.
-
Спасибо обязательно протестирую. Пожалуйста, останьтесь в диалоге со-мной, хотя бы по емайл (мой teachsoft@kharkov.ukrtel.net). Вы единственный кто так отлично разбирается в этих спиралях здесь. Спасибо!
-
Доброе утро, sdubaruhnul! Можете еще помочь со спиралью Галилея (r = a*(1 - m*θ^2)) и Poinsot (r=sech(θ/3))? Спасибо.
|