z_mirror/flib

git clone https://git.raiguard.me/z_mirror/flib

Caleb HeuerRemove require guardsa9f2be7

trunk
8.3 KiB336 linesraw
1local flib_direction = require("__flib__.direction")
2local flib_math = require("__flib__.math")
3
4--- Utilities for manipulating positions. All functions support both the shorthand and explicit syntaxes and will
5--- preserve the syntax that was passed in.
6--- ```lua
7--- local flib_position = require("__flib__.position")
8--- ```
9--- @class flib_position
10local flib_position = {}
11
12--- FIXME: Sumneko doesn't properly handle generics yet and throws a bunch of bogus warnings.
13--- @diagnostic disable
14
15--- Return the absolute value of the position's coordinates.
16--- @generic P
17--- @param pos P
18--- @return P
19function flib_position.abs(pos)
20  if pos.x then
21    return { x = math.abs(pos.x), y = math.abs(pos.y) }
22  else
23    return { math.abs(pos[1]), math.abs(pos[2]) }
24  end
25end
26
27--- Add two positions.
28--- @generic P
29--- @param pos1 P
30--- @param pos2 P
31--- @return P
32function flib_position.add(pos1, pos2)
33  local x1 = pos1.x or pos1[1]
34  local y1 = pos1.y or pos1[2]
35  local x2 = pos2.x or pos2[1]
36  local y2 = pos2.y or pos2[2]
37  if pos1.x then
38    return { x = x1 + x2, y = y1 + y2 }
39  else
40    return { x1 + x2, y1 + y2 }
41  end
42end
43
44--- Ceil the given position.
45--- @generic P
46--- @param pos P
47--- @return P
48function flib_position.ceil(pos)
49  if pos.x then
50    return { x = math.ceil(pos.x), y = math.ceil(pos.y) }
51  else
52    return { math.ceil(pos[1]), math.ceil(pos[2]) }
53  end
54end
55
56--- Calculate the distance between two positions.
57--- @generic P
58--- @param pos1 P
59--- @param pos2 P
60--- @return number
61function flib_position.distance(pos1, pos2)
62  local x1 = pos1.x or pos1[1]
63  local y1 = pos1.y or pos1[2]
64  local x2 = pos2.x or pos2[1]
65  local y2 = pos2.y or pos2[2]
66  return math.sqrt((x1 - x2) ^ 2 + (y1 - y2) ^ 2)
67end
68
69--- Calculate the squared distance between two positions.
70--- @generic P
71--- @param pos1 P
72--- @param pos2 P
73--- @return number
74function flib_position.distance_squared(pos1, pos2)
75  local x1 = pos1.x or pos1[1]
76  local y1 = pos1.y or pos1[2]
77  local x2 = pos2.x or pos2[1]
78  local y2 = pos2.y or pos2[2]
79  return (x1 - x2) ^ 2 + (y1 - y2) ^ 2
80end
81
82--- Divide two positions.
83--- @generic P
84--- @param pos1 P
85--- @param pos2 P
86--- @return P
87function flib_position.div(pos1, pos2)
88  local x1 = pos1.x or pos1[1]
89  local y1 = pos1.y or pos1[2]
90  local x2 = pos2.x or pos2[1]
91  local y2 = pos2.y or pos2[2]
92  if pos1.x then
93    return { x = x1 / x2, y = y1 / y2 }
94  else
95    return { x1 / x2, y1 / y2 }
96  end
97end
98
99--- Return the position in explicit form.
100--- @generic P
101--- @param pos P
102--- @return P
103function flib_position.ensure_explicit(pos)
104  if pos.x then
105    return pos
106  else
107    return { x = pos[1], y = pos[2] }
108  end
109end
110
111--- Return the  position in shorthand form.
112--- @generic P
113--- @param pos P
114--- @return P
115function flib_position.ensure_short(pos)
116  if pos.x then
117    return { pos.x, pos.y }
118  else
119    return pos
120  end
121end
122
123--- Test if two positions are equal.
124--- @generic P
125--- @param pos1 P
126--- @param pos2 P
127--- @return boolean
128function flib_position.eq(pos1, pos2)
129  local x1 = pos1.x or pos1[1]
130  local y1 = pos1.y or pos1[2]
131  local x2 = pos2.x or pos2[1]
132  local y2 = pos2.y or pos2[2]
133  return x1 == x2 and y1 == y2
134end
135
136--- Floor the given position.
137--- @generic P
138--- @param pos P
139--- @return P
140function flib_position.floor(pos)
141  if pos.x then
142    return { x = math.floor(pos.x), y = math.floor(pos.y) }
143  else
144    return { math.floor(pos[1]), math.floor(pos[2]) }
145  end
146end
147
148--- Convert a `ChunkPosition` into a `TilePosition` by multiplying by 32.
149--- @param pos ChunkPosition
150--- @return TilePosition
151function flib_position.from_chunk(pos)
152  if pos.x then
153    return { x = pos.x * 32, y = pos.y * 32 }
154  else
155    return { pos[1] * 32, pos[2] * 32 }
156  end
157end
158
159--- Return a position created from the given direction and distance.
160--- @param direction defines.direction
161--- @param distance number
162--- @return MapPosition
163function flib_position.from_direction(direction, distance)
164  return flib_position.from_orientation(flib_direction.to_orientation(direction), distance)
165end
166
167--- Return a position created from the given orientation and distance.
168--- @param orientation RealOrientation
169--- @param distance number
170--- @return MapPosition
171function flib_position.from_orientation(orientation, distance)
172  -- We cannot use the standard x = cos theta and y = sin theta because Factorio's orientation space is rotated by 90
173  -- degrees and flipped vertically.
174  local x_factor = math.sin(flib_math.radian * orientation)
175  local y_factor = -math.cos(flib_math.radian * orientation)
176
177  return { x = distance * x_factor, y = distance * y_factor }
178end
179
180--- Test if `pos1` is greater than or equal to `pos2`.
181--- @generic P
182--- @param pos1 P
183--- @param pos2 P
184--- @return boolean
185function flib_position.ge(pos1, pos2)
186  local x1 = pos1.x or pos1[1]
187  local y1 = pos1.y or pos1[2]
188  local x2 = pos2.x or pos2[1]
189  local y2 = pos2.y or pos2[2]
190  return x1 >= x2 and y1 >= y2
191end
192
193--- Test if `pos1` is greater than `pos2`.
194--- @generic P
195--- @param pos1 P
196--- @param pos2 P
197--- @return boolean
198function flib_position.gt(pos1, pos2)
199  local x1 = pos1.x or pos1[1]
200  local y1 = pos1.y or pos1[2]
201  local x2 = pos2.x or pos2[1]
202  local y2 = pos2.y or pos2[2]
203  return x1 > x2 and y1 > y2
204end
205
206--- Test if `pos1` is less than or equal to `pos2`.
207--- @generic P
208--- @param pos1 P
209--- @param pos2 P
210--- @return boolean
211function flib_position.le(pos1, pos2)
212  local x1 = pos1.x or pos1[1]
213  local y1 = pos1.y or pos1[2]
214  local x2 = pos2.x or pos2[1]
215  local y2 = pos2.y or pos2[2]
216  return x1 <= x2 and y1 <= y2
217end
218
219--- Linearly interpolate between two positions. For example, an amount of 0.5 will return the midpoint.
220--- @generic P
221--- @param pos1 P
222--- @param pos2 P
223--- @param amount number
224--- @return P
225function flib_position.lerp(pos1, pos2, amount)
226  if pos1.x then
227    return { x = flib_math.lerp(pos1.x, pos2.x, amount), y = flib_math.lerp(pos1.y, pos2.y, amount) }
228  else
229    return { flib_math.lerp(pos1[1], pos2[1], amount), flib_math.lerp(pos1[2], pos2[2], amount) }
230  end
231end
232
233--- Test if `pos1` is less than `pos2`.
234--- @generic P
235--- @param pos1 P
236--- @param pos2 P
237--- @return boolean
238function flib_position.lt(pos1, pos2)
239  local x1 = pos1.x or pos1[1]
240  local y1 = pos1.y or pos1[2]
241  local x2 = pos2.x or pos2[1]
242  local y2 = pos2.y or pos2[2]
243  return x1 < x2 and y1 < y2
244end
245
246--- Take the remainder (modulus) of two positions.
247--- @generic P
248--- @param pos1 P
249--- @param pos2 P
250--- @return P
251function flib_position.mod(pos1, pos2)
252  local x1 = pos1.x or pos1[1]
253  local y1 = pos1.y or pos1[2]
254  local x2 = pos2.x or pos2[1]
255  local y2 = pos2.y or pos2[2]
256  if pos1.x then
257    return { x = x1 % x2, y = y1 % y2 }
258  else
259    return { x1 % x2, y1 % y2 }
260  end
261end
262
263--- Multiply two positions.
264--- @generic P
265--- @param pos1 P
266--- @param pos2 P
267--- @return P
268function flib_position.mul(pos1, pos2)
269  local x1 = pos1.x or pos1[1]
270  local y1 = pos1.y or pos1[2]
271  local x2 = pos2.x or pos2[1]
272  local y2 = pos2.y or pos2[2]
273  if pos1.x then
274    return { x = x1 * x2, y = y1 * y2 }
275  else
276    return { x1 * x2, y1 * y2 }
277  end
278end
279
280--- Subtract two positions.
281--- @generic P
282--- @param pos1 P
283--- @param pos2 P
284--- @return P
285function flib_position.sub(pos1, pos2)
286  local x1 = pos1.x or pos1[1]
287  local y1 = pos1.y or pos1[2]
288  local x2 = pos2.x or pos2[1]
289  local y2 = pos2.y or pos2[2]
290  if pos1.x then
291    return { x = x1 - x2, y = y1 - y2 }
292  else
293    return { x1 - x2, y1 - y2 }
294  end
295end
296
297--- Take the power of two positions. `pos1^pos2`.
298--- @generic P
299--- @param pos1 P
300--- @param pos2 P
301--- @return P
302function flib_position.pow(pos1, pos2)
303  local x1 = pos1.x or pos1[1]
304  local y1 = pos1.y or pos1[2]
305  local x2 = pos2.x or pos2[1]
306  local y2 = pos2.y or pos2[2]
307  if pos1.x then
308    return { x = x1 ^ x2, y = y1 ^ y2 }
309  else
310    return { x1 ^ x2, y1 ^ y2 }
311  end
312end
313
314--- Convert a `MapPosition` or `TilePosition` into a `ChunkPosition` by dividing by 32 and flooring.
315--- @param pos MapPosition|TilePosition
316--- @return ChunkPosition
317function flib_position.to_chunk(pos)
318  if pos.x then
319    return { x = math.floor(pos.x / 32), y = math.floor(pos.y / 32) }
320  else
321    return { math.floor(pos[1] / 32), math.floor(pos[2] / 32) }
322  end
323end
324
325--- Convert a `MapPosition` into a `TilePosition` by flooring.
326--- @param pos MapPosition
327--- @return TilePosition
328function flib_position.to_tile(pos)
329  if pos.x then
330    return { x = math.floor(pos.x), y = math.floor(pos.y) }
331  else
332    return { math.floor(pos[1]), math.floor(pos[2]) }
333  end
334end
335
336return flib_position