I'm trying to create a circle of objects (boxes) for a mod from one game using this code:

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 

Objects can be placed only in the middle of the cell. that is, if the coordinates for example are x = 0.9 y = 0.9, then the object will be located on the coordinates x = 0.5 y = 0.5. Also with negative coordinates x = -0.9 y = -0.9 ==> x = -0.5 y = -0.5. Create a circle: circle (0,0,15)

Circle with a radius of 15.5

Blue arrows indicate that the object has been re-located in these places (double shadow is visible). I have highlighted inconsistencies with the orange rectangle. With a radius of 10 and a half cells, the circle becomes even, but re-placement in the same cell is present:

What should be corrected in this function so that the circle correctly passes through the middle of the cells? Perhaps the Brezenham algorithm or the Midpoint circle algorithm would help me, but I don’t know how to write them in lua, as I’m still quite weak in programming. UPD: I tried to convert this code to C ++ in 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 *(xy) else y=y - 1 delta = delta-2*y+1 end else x=x+1 delta = delta+ 2 * x + 1 end end end 

But I get an Oval, one square away from the center on both axes, and also having a double-placement in 4 places UPD2: Offset was decided by adding 0.5 to x and y Now my code looks like this:

 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 

No repetitions with any radius, but still no symmetry. Any tips?

  • one
    Yes, these algorithms will help to build a circle correctly. An implementation on Lua will not differ much, for example, from a Pascal implementation. When using the above concept, you can reduce the step and display the next object when either x or y (integer) for it differs from the previous one. - MBo
  • one
    What do you mean by "with a radius of 10 and a half cells the circle becomes even"? A circle rasterized on an isotropic raster should have four axes of symmetry (vertical, horizontal and two diagonals). And you do not have diagonal symmetry in the picture. - AnT
  • Something you have with the transformation "C + +" (which, by the way, not C + +) in Lua some nonsense turned out. Why do you suddenly have nested if? - AnT
  • In Lua, there is no continue, so I replaced it by "turning over" the condition and nested if. - WIZ4
  • Use an eighth, not a quarter of a circle - MBo pm

1 answer 1

Here is the Bresenham algorithm code, written with PascalABC, and working on "eight" - inside each quadrant, points are put in the direction from the edges of the quadrant inward. Initially, there was a drawback - the points are re-set at the positions 0, pi / 2, pi, 2pi / 3. This can be corrected by comparing the values ​​(y-y1) + y1 and - (y-y1) + y1, (x-x1) + x1 and - (x-x1) + x1. If there is at least one equality among them (from the change of the delta sign (that is, (y-y1) or (x-x1)) the coordinate has not changed), then do not put a full stop.

There are not many specific commands, I think it will be easy to rewrite to the language you need.

 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;