#алгоритм #lua
Я пытаюсь создать круг из объектов (ящиков) для мода из одной игры, используя этот код:
function circle(x,y,r)
local angle = 0
x = x + 0.5 - (x + 0.5) % 1
y = y + 0.5 - (x + 0.5) % 1
r = r + 0.5 прибавляю 0.5 чтобы объект появлялся в центре клетки
while angle < 2*math.pi do
angle = angle + r/r^2
local xs = (x + r * math.cos (angle))
local ys = (y + r * math.sin (angle))
game.surfaces[1].create_entity{name = "wooden-chest", position= {xs,ys},force='player'}
--создание объекта с указанными координатами
end end
Объекты могут размещаться только в середине клетки. то есть если координаты например
будут х=0.9 у=0.9, то объект разместиться на координатах х=0.5 у=0.5
Также и с отрицательными координатами х=-0.9 у=-0.9 ==> х=-0.5 у=-0.5.
Создаем окружность: circle(0,0,15)
Голубые стрелки указывают на то что обьект в этих местах разместился повторно(видна
двойная тень)
Оранжевым прямоугольником я выделил несоответствия.
При радиусе в 10 с половиной клеток круг становится ровным, но повторное размещение
в одной и той же клетке присутствует:
Что нужно поправить в этой функции, чтобы окружность правильно проходила через середины
клеток? Возможно мне бы помог Алгоритм Брезенхе́ма или алгоритм окружности Midpoint,
но я не знаю как написать их на lua, так как еще довольно слаб в программировании.
UPD: Я попробовал преобразовать этот код на C++ в Lua:
public static void BresenhamCircle(Graphics g, Color clr, int _x, int _y, int radius)
{
int x = 0, y = radius, gap = 0, delta = (2 - 2 * radius);
while (y >= 0)
{
PutPixel(g, clr, _x + x, _y + y, 255);
PutPixel(g, clr, _x + x, _y - y, 255);
PutPixel(g, clr, _x - x, _y - y, 255);
PutPixel(g, clr, _x - x, _y + y, 255);
gap = 2 * (delta + y) - 1;
if (delta < 0 && gap <= 0)
{
x++;
delta += 2 * x + 1;
continue;
}
if (delta > 0 && gap > 0)
{
y--;
delta -= 2 * y + 1;
continue;
}
x++;
delta += 2 * (x - y);
y--;
}
}
function bresenham_circle(X1,Y1,R)
local x = 0 local y = R local gap = 0 local delta = (2 - 2 * R)
while (y >= 0) do
game.surfaces[1].create_entity{name = "wooden-chest", position= {X1 + x,
Y1 + y},force='player'}
game.surfaces[1].create_entity{name = "wooden-chest", position= {X1 + x,
Y1 - y},force='player'}
game.surfaces[1].create_entity{name = "wooden-chest", position= {X1 - x,
Y1 + y},force='player'}
game.surfaces[1].create_entity{name = "wooden-chest", position= {X1 - x,
Y1 - y},force='player'}
gap = 2 * (delta + y) - 1
if (delta >= 0 and gap > 0) then
if (delta <= 0 and gap <= 0) then
y = y - 1
x =x+1
delta = delta +2 *(x-y)
else y=y - 1 delta = delta-2*y+1
end
else x=x+1 delta = delta+ 2 * x + 1
end
end
end
Но я получаю Овал, на одну клетку смещенный от центра по обоим осям, а также имеющий
дубль-размещение в 4 местах
UPD2: Смещение решилось добавлением 0.5 к x и y
Сейчас мой код выглядит так:
function bresenham_circle(X1,Y1,R)
local R = R+0.5
local x = 0.25
local y = R
local gap = 0
local delta = (2 - 2 * R)
while (y >= 0) do
game.surfaces[1].create_entity{name = "wooden-chest", position= {X1 + x, Y1 -
y},force='player'}
game.surfaces[1].create_entity{name = "wooden-chest", position= {X1 - x, Y1 -
y},force='player'}
game.surfaces[1].create_entity{name = "wooden-chest", position= {X1 - x, Y1 +
y},force='player'}
game.surfaces[1].create_entity{name = "wooden-chest", position= {X1 + x, Y1 +
y},force='player'}
gap = 2 * (delta + y) - 1
if (delta >= 0 and gap > 0) then
if (delta <= 0 and gap <= 0) then
y = y - 1
x =x+1
delta = delta +2 *((x)-(y))
else delta = delta-2*(y-1)+1 y=y - 1
end
else delta = delta+ 2 * (x+1) + 1 x=x+1
end
end end
Повторов нет с любым радиусом, но все еще нет симметрии. Любые подсказки?
Ответы
Ответ 1
Вот код алгоритма Брезенхема, написанный при помощи PascalABC, и работающий по "восьмушкам" - внутри каждого квадранта точки ставятся в направлении от краев квадранта вовнутрь. Изначально был недостаток - повторно ставятся точки на позициях 0,pi/2,pi,2pi/3. Это можно поправить сравнением величин (y-y1)+y1 и -(y-y1)+y1, (x-x1)+x1 и -(x-x1)+x1. Если среди них есть хоть одно равенство (от смены знака "дельты" (то есть (y-y1) или (x-x1)) не изменилась координата), то не ставить точку. Тут не много специфичных команд, думаю, будет несложно переписать на нужный Вам язык. procedure brez; var x,y,x1,y1,r:integer; e:real; begin x1:=250; y1:=250; r:=200; x:=x1; y:=y1+r; e:=3-2*(r); while (x-x1)<(y-y1) do begin putpixel((x-x1)+x1,(y-y1)+y1,clRed); putpixel((y-y1)+y1,-(x-x1)+x1,clRed); putpixel(-(x-x1)+x1,-(y-y1)+y1,clRed); putpixel(-(y-y1)+y1,(x-x1)+x1,clRed); if not( ( ((x-x1)+x1) = (-(x-x1)+x1) ) or ( ((y-y1)+y1)=(-(y-y1)+y1) ) ) then begin putpixel((y-y1)+y1,(x-x1)+x1,clRed); putpixel((x-x1)+x1,-(y-y1)+y1,clRed); putpixel(-(y-y1)+y1,-(x-x1)+x1,clRed); putpixel(-(x-x1)+x1,(y-y1)+y1,clRed) end; if e<0 then e:=e+4*(x-x1)+6 else begin e:=e+4*(x-x1-y+y1)+10; y:=y-1 end; x:=x+1 end; if x=y then begin putpixel((x-x1)+x1,(y-y1)+y1,clRed); putpixel((y-y1)+y1,(x-x1)+x1,clRed); putpixel((y-y1)+y1,-(x-x1)+x1,clRed); putpixel((x-x1)+x1,-(y-y1)+y1,clRed); putpixel(-(x-x1)+x1,-(y-y1)+y1,clRed); putpixel(-(y-y1)+y1,-(x-x1)+x1,clRed); putpixel(-(y-y1)+y1,(x-x1)+x1,clRed); putpixel(-(x-x1)+x1,(y-y1)+y1,clRed); end end;
Комментариев нет:
Отправить комментарий