]> git.lizzy.rs Git - worldedit.git/blob - worldedit/primitives.lua
Super-speed a few primitives and visualization functions, including hollowsphere...
[worldedit.git] / worldedit / primitives.lua
1 worldedit = worldedit or {}\r
2 \r
3 --adds a hollow sphere centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added\r
4 worldedit.hollow_sphere = function(pos, radius, nodename)\r
5         local insert = table.insert\r
6         local node = {nodename, 0, 0}\r
7         local ignore = {"ignore", 0, 0}\r
8         local nodes = {}\r
9         local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1)\r
10         for x = -radius, radius do\r
11                 for y = -radius, radius do\r
12                         for z = -radius, radius do\r
13                                 local squared = x * x + y * y + z * z\r
14                                 if squared >= min_radius and squared <= max_radius then\r
15                                         insert(nodes, node)\r
16                                 else\r
17                                         insert(nodes, ignore)\r
18                                 end\r
19                         end\r
20                 end\r
21         end\r
22         minetest.place_schematic({x=pos.x - radius, y=pos.y - radius, z=pos.z - radius}, {size={x=radius * 2, y=radius * 2, z=radius * 2}, data=nodes})\r
23         return #nodes\r
24 end\r
25 \r
26 --adds a sphere centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added\r
27 worldedit.sphere = function(pos, radius, nodename)\r
28         local insert = table.insert\r
29         local node = {nodename, 0, 0}\r
30         local ignore = {"ignore", 0, 0}\r
31         local nodes = {}\r
32         local max_radius = radius * (radius + 1)\r
33         for x = -radius, radius do\r
34                 for y = -radius, radius do\r
35                         for z = -radius, radius do\r
36                                 if x * x + y * y + z * z <= max_radius then\r
37                                         insert(nodes, node)\r
38                                 else\r
39                                         insert(nodes, ignore)\r
40                                 end\r
41                         end\r
42                 end\r
43         end\r
44         minetest.place_schematic({x=pos.x - radius, y=pos.y - radius, z=pos.z - radius}, {size={x=radius * 2, y=radius * 2, z=radius * 2}, data=nodes})\r
45         return #nodes\r
46 end\r
47 \r
48 --adds a hollow dome centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added\r
49 worldedit.hollow_dome = function(pos, radius, nodename) --wip: use bresenham sphere for maximum speed\r
50         local insert = table.insert\r
51         local node = {nodename, 0, 0}\r
52         local ignore = {"ignore", 0, 0}\r
53         local nodes = {}\r
54         local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1)\r
55         for x = -radius, radius do\r
56                 for y = 0, radius do\r
57                         for z = -radius, radius do\r
58                                 local squared = x * x + y * y + z * z\r
59                                 if squared >= min_radius and squared <= max_radius then\r
60                                         insert(nodes, node)\r
61                                 else\r
62                                         insert(nodes, ignore)\r
63                                 end\r
64                         end\r
65                 end\r
66         end\r
67         minetest.place_schematic({x=pos.x - radius, y=pos.y, z=pos.z - radius}, {size={x=radius * 2, y=radius * 2, z=radius * 2}, data=nodes})\r
68         return #nodes\r
69 end\r
70 \r
71 --adds a dome centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added\r
72 worldedit.dome = function(pos, radius, nodename) --wip: use bresenham sphere for maximum speed\r
73         local insert = table.insert\r
74         local node = {nodename, 0, 0}\r
75         local ignore = {"ignore", 0, 0}\r
76         local nodes = {}\r
77         local max_radius = radius * (radius + 1)\r
78         for x = -radius, radius do\r
79                 for y = 0, radius do\r
80                         for z = -radius, radius do\r
81                                 if x * x + y * y + z * z <= max_radius then\r
82                                         insert(nodes, node)\r
83                                 else\r
84                                         insert(nodes, ignore)\r
85                                 end\r
86                         end\r
87                 end\r
88         end\r
89         minetest.place_schematic({x=pos.x - radius, y=pos.y, z=pos.z - radius}, {size={x=radius * 2, y=radius * 2, z=radius * 2}, data=nodes})\r
90         return #nodes\r
91 end\r
92 \r
93 --adds a hollow cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`, returning the number of nodes added\r
94 worldedit.hollow_cylinder = function(pos, axis, length, radius, nodename)\r
95         local other1, other2\r
96         if axis == "x" then\r
97                 other1, other2 = "y", "z"\r
98         elseif axis == "y" then\r
99                 other1, other2 = "x", "z"\r
100         else --axis == "z"\r
101                 other1, other2 = "x", "y"\r
102         end\r
103 \r
104         if env == nil then env = minetest.env end\r
105         local currentpos = {x=pos.x, y=pos.y, z=pos.z}\r
106         local node = {name=nodename}\r
107         local count = 0\r
108         local step = 1\r
109         if length < 0 then\r
110                 length = -length\r
111                 step = -1\r
112         end\r
113         for i = 1, length do\r
114                 local offset1, offset2 = 0, radius\r
115                 local delta = -radius\r
116                 while offset1 <= offset2 do\r
117                         --add node at each octant\r
118                         local first1, first2 = pos[other1] + offset1, pos[other1] - offset1\r
119                         local second1, second2 = pos[other2] + offset2, pos[other2] - offset2\r
120                         currentpos[other1], currentpos[other2] = first1, second1\r
121                         env:add_node(currentpos, node) --octant 1\r
122                         currentpos[other1] = first2\r
123                         env:add_node(currentpos, node) --octant 4\r
124                         currentpos[other2] = second2\r
125                         env:add_node(currentpos, node) --octant 5\r
126                         currentpos[other1] = first1\r
127                         env:add_node(currentpos, node) --octant 8\r
128                         local first1, first2 = pos[other1] + offset2, pos[other1] - offset2\r
129                         local second1, second2 = pos[other2] + offset1, pos[other2] - offset1\r
130                         currentpos[other1], currentpos[other2] = first1, second1\r
131                         env:add_node(currentpos, node) --octant 2\r
132                         currentpos[other1] = first2\r
133                         env:add_node(currentpos, node) --octant 3\r
134                         currentpos[other2] = second2\r
135                         env:add_node(currentpos, node) --octant 6\r
136                         currentpos[other1] = first1\r
137                         env:add_node(currentpos, node) --octant 7\r
138 \r
139                         count = count + 8 --wip: broken\r
140 \r
141                         --move to next location\r
142                         delta = delta + (offset1 * 2) + 1\r
143                         if delta >= 0 then\r
144                                 offset2 = offset2 - 1\r
145                                 delta = delta - (offset2 * 2)\r
146                         end\r
147                         offset1 = offset1 + 1\r
148                 end\r
149                 currentpos[axis] = currentpos[axis] + step\r
150         end\r
151         return count\r
152 end\r
153 \r
154 --adds a cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`, returning the number of nodes added\r
155 worldedit.cylinder = function(pos, axis, length, radius, nodename, env)\r
156         local other1, other2\r
157         if axis == "x" then\r
158                 other1, other2 = "y", "z"\r
159         elseif axis == "y" then\r
160                 other1, other2 = "x", "z"\r
161         else --axis == "z"\r
162                 other1, other2 = "x", "y"\r
163         end\r
164 \r
165         if env == nil then env = minetest.env end\r
166         local currentpos = {x=pos.x, y=pos.y, z=pos.z}\r
167         local node = {name=nodename}\r
168         local count = 0\r
169         local step = 1\r
170         if length < 0 then\r
171                 length = -length\r
172                 step = -1\r
173         end\r
174         for i = 1, length do\r
175                 local offset1, offset2 = 0, radius\r
176                 local delta = -radius\r
177                 while offset1 <= offset2 do\r
178                         --connect each pair of octants\r
179                         currentpos[other1] = pos[other1] - offset1\r
180                         local second1, second2 = pos[other2] + offset2, pos[other2] - offset2\r
181                         for i = 0, offset1 * 2 do\r
182                                 currentpos[other2] = second1\r
183                                 env:add_node(currentpos, node) --octant 1 to 4\r
184                                 currentpos[other2] = second2\r
185                                 env:add_node(currentpos, node) --octant 5 to 8\r
186                                 currentpos[other1] = currentpos[other1] + 1\r
187                         end\r
188                         currentpos[other1] = pos[other1] - offset2\r
189                         local second1, second2 = pos[other2] + offset1, pos[other2] - offset1\r
190                         for i = 0, offset2 * 2 do\r
191                                 currentpos[other2] = second1\r
192                                 env:add_node(currentpos, node) --octant 2 to 3\r
193                                 currentpos[other2] = second2\r
194                                 env:add_node(currentpos, node) --octant 6 to 7\r
195                                 currentpos[other1] = currentpos[other1] + 1\r
196                         end\r
197 \r
198                         count = count + (offset1 * 4) + (offset2 * 4) + 4 --wip: broken\r
199 \r
200                         --move to next location\r
201                         delta = delta + (offset1 * 2) + 1\r
202                         offset1 = offset1 + 1\r
203                         if delta >= 0 then\r
204                                 offset2 = offset2 - 1\r
205                                 delta = delta - (offset2 * 2)\r
206                         end\r
207                 end\r
208                 currentpos[axis] = currentpos[axis] + step\r
209         end\r
210         return count\r
211 end\r
212 \r
213 --adds a pyramid centered at `pos` with height `height`, composed of `nodename`, returning the number of nodes added\r
214 worldedit.pyramid = function(pos, height, nodename, env)\r
215         local pos1x, pos1y, pos1z = pos.x - height, pos.y, pos.z - height\r
216         local pos2x, pos2y, pos2z = pos.x + height, pos.y + height, pos.z + height\r
217         local pos = {x=0, y=pos1y, z=0}\r
218 \r
219         local count = 0\r
220         local node = {name=nodename}\r
221         if env == nil then env = minetest.env end\r
222         while pos.y <= pos2y do --each vertical level of the pyramid\r
223                 pos.x = pos1x\r
224                 while pos.x <= pos2x do\r
225                         pos.z = pos1z\r
226                         while pos.z <= pos2z do\r
227                                 env:add_node(pos, node)\r
228                                 pos.z = pos.z + 1\r
229                         end\r
230                         pos.x = pos.x + 1\r
231                 end\r
232                 count = count + ((pos2y - pos.y) * 2 + 1) ^ 2\r
233                 pos.y = pos.y + 1\r
234 \r
235                 pos1x, pos2x = pos1x + 1, pos2x - 1\r
236                 pos1z, pos2z = pos1z + 1, pos2z - 1\r
237 \r
238         end\r
239         return count\r
240 end\r
241 \r
242 --adds a spiral centered at `pos` with width `width`, height `height`, space between walls `spacer`, composed of `nodename`, returning the number of nodes added\r
243 worldedit.spiral = function(pos, width, height, spacer, nodename, env) --wip: clean this up\r
244         -- spiral matrix - http://rosettacode.org/wiki/Spiral_matrix#Lua\r
245         av, sn = math.abs, function(s) return s~=0 and s/av(s) or 0 end\r
246         local function sindex(z, x) -- returns the value at (x, z) in a spiral that starts at 1 and goes outwards\r
247                 if z == -x and z >= x then return (2*z+1)^2 end\r
248                 local l = math.max(av(z), av(x))\r
249                 return (2*l-1)^2+4*l+2*l*sn(x+z)+sn(z^2-x^2)*(l-(av(z)==l and sn(z)*x or sn(x)*z)) -- OH GOD WHAT\r
250         end\r
251         local function spiralt(side)\r
252                 local ret, id, start, stop = {}, 0, math.floor((-side+1)/2), math.floor((side-1)/2)\r
253                 for i = 1, side do\r
254                         for j = 1, side do\r
255                                 local id = side^2 - sindex(stop - i + 1,start + j - 1)\r
256                                 ret[id] = {x=i,z=j}\r
257                         end\r
258                 end\r
259                 return ret\r
260         end\r
261     if env == nil then env = minetest.env end\r
262         -- connect the joined parts\r
263         local spiral = spiralt(width)\r
264         height = tonumber(height)\r
265         if height < 1 then height = 1 end\r
266         spacer = tonumber(spacer)-1\r
267         if spacer < 1 then spacer = 1 end\r
268         local count = 0\r
269         local node = {name=nodename}\r
270         local np,lp\r
271         for y=0,height do\r
272                 lp = nil\r
273                 for _,v in ipairs(spiral) do\r
274                         np = {x=pos.x+v.x*spacer, y=pos.y+y, z=pos.z+v.z*spacer}\r
275                         if lp~=nil then\r
276                                 if lp.x~=np.x then \r
277                                         if lp.x<np.x then \r
278                                                 for i=lp.x+1,np.x do\r
279                                                         env:add_node({x=i, y=np.y, z=np.z}, node)\r
280                                                         count = count + 1\r
281                                                 end\r
282                                         else\r
283                                                 for i=np.x,lp.x-1 do\r
284                                                         env:add_node({x=i, y=np.y, z=np.z}, node)\r
285                                                         count = count + 1\r
286                                                 end\r
287                                         end\r
288                                 end\r
289                                 if lp.z~=np.z then \r
290                                         if lp.z<np.z then \r
291                                                 for i=lp.z+1,np.z do\r
292                                                         env:add_node({x=np.x, y=np.y, z=i}, node)\r
293                                                         count = count + 1\r
294                                                 end\r
295                                         else\r
296                                                 for i=np.z,lp.z-1 do\r
297                                                         env:add_node({x=np.x, y=np.y, z=i}, node)\r
298                                                         count = count + 1\r
299                                                 end\r
300                                         end\r
301                                 end\r
302                         end\r
303                         lp = np\r
304                 end\r
305         end\r
306         return count\r
307 end\r