z_mirror/flib
git clone https://git.raiguard.me/z_mirror/flib
a9f2be7
trunk
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 ) 20if pos . x then 21return { x =math . abs ( pos . x ), y =math . abs ( pos . y ) } 22else 23return { math . abs ( pos [ 1 ]), math . abs ( pos [ 2 ]) } 24end 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 ) 33local x1 =pos1 . x or pos1 [ 1 ] 34local y1 =pos1 . y or pos1 [ 2 ] 35local x2 =pos2 . x or pos2 [ 1 ] 36local y2 =pos2 . y or pos2 [ 2 ] 37if pos1 . x then 38return { x =x1 + x2 , y =y1 + y2 } 39else 40return { x1 + x2 , y1 + y2 } 41end 42end 43 44--- Ceil the given position. 45--- @generic P 46--- @param pos P 47--- @return P 48function flib_position . ceil ( pos ) 49if pos . x then 50return { x =math . ceil ( pos . x ), y =math . ceil ( pos . y ) } 51else 52return { math . ceil ( pos [ 1 ]), math . ceil ( pos [ 2 ]) } 53end 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 ) 62local x1 =pos1 . x or pos1 [ 1 ] 63local y1 =pos1 . y or pos1 [ 2 ] 64local x2 =pos2 . x or pos2 [ 1 ] 65local y2 =pos2 . y or pos2 [ 2 ] 66return 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 ) 75local x1 =pos1 . x or pos1 [ 1 ] 76local y1 =pos1 . y or pos1 [ 2 ] 77local x2 =pos2 . x or pos2 [ 1 ] 78local y2 =pos2 . y or pos2 [ 2 ] 79return ( 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 ) 88local x1 =pos1 . x or pos1 [ 1 ] 89local y1 =pos1 . y or pos1 [ 2 ] 90local x2 =pos2 . x or pos2 [ 1 ] 91local y2 =pos2 . y or pos2 [ 2 ] 92if pos1 . x then 93return { x =x1 / x2 , y =y1 / y2 } 94else 95return { x1 / x2 , y1 / y2 } 96end 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 ) 104if pos . x then 105return pos 106else 107return { x =pos [ 1 ], y =pos [ 2 ] } 108end 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 ) 116if pos . x then 117return { pos . x , pos . y } 118else 119return pos 120end 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 ) 129local x1 =pos1 . x or pos1 [ 1 ] 130local y1 =pos1 . y or pos1 [ 2 ] 131local x2 =pos2 . x or pos2 [ 1 ] 132local y2 =pos2 . y or pos2 [ 2 ] 133return 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 ) 141if pos . x then 142return { x =math . floor ( pos . x ), y =math . floor ( pos . y ) } 143else 144return { math . floor ( pos [ 1 ]), math . floor ( pos [ 2 ]) } 145end 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 ) 152if pos . x then 153return { x =pos . x * 32 , y =pos . y * 32 } 154else 155return { pos [ 1 ] * 32 , pos [ 2 ] * 32 } 156end 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 ) 164return 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. 174local x_factor =math . sin ( flib_math . radian * orientation ) 175local y_factor =- math . cos ( flib_math . radian * orientation ) 176 177return { 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 ) 186local x1 =pos1 . x or pos1 [ 1 ] 187local y1 =pos1 . y or pos1 [ 2 ] 188local x2 =pos2 . x or pos2 [ 1 ] 189local y2 =pos2 . y or pos2 [ 2 ] 190return 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 ) 199local x1 =pos1 . x or pos1 [ 1 ] 200local y1 =pos1 . y or pos1 [ 2 ] 201local x2 =pos2 . x or pos2 [ 1 ] 202local y2 =pos2 . y or pos2 [ 2 ] 203return 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 ) 212local x1 =pos1 . x or pos1 [ 1 ] 213local y1 =pos1 . y or pos1 [ 2 ] 214local x2 =pos2 . x or pos2 [ 1 ] 215local y2 =pos2 . y or pos2 [ 2 ] 216return 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 ) 226if pos1 . x then 227return { x =flib_math . lerp ( pos1 . x , pos2 . x , amount ), y =flib_math . lerp ( pos1 . y , pos2 . y , amount ) } 228else 229return { flib_math . lerp ( pos1 [ 1 ], pos2 [ 1 ], amount ), flib_math . lerp ( pos1 [ 2 ], pos2 [ 2 ], amount ) } 230end 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 ) 239local x1 =pos1 . x or pos1 [ 1 ] 240local y1 =pos1 . y or pos1 [ 2 ] 241local x2 =pos2 . x or pos2 [ 1 ] 242local y2 =pos2 . y or pos2 [ 2 ] 243return 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 ) 252local x1 =pos1 . x or pos1 [ 1 ] 253local y1 =pos1 . y or pos1 [ 2 ] 254local x2 =pos2 . x or pos2 [ 1 ] 255local y2 =pos2 . y or pos2 [ 2 ] 256if pos1 . x then 257return { x =x1 % x2 , y =y1 % y2 } 258else 259return { x1 % x2 , y1 % y2 } 260end 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 ) 269local x1 =pos1 . x or pos1 [ 1 ] 270local y1 =pos1 . y or pos1 [ 2 ] 271local x2 =pos2 . x or pos2 [ 1 ] 272local y2 =pos2 . y or pos2 [ 2 ] 273if pos1 . x then 274return { x =x1 * x2 , y =y1 * y2 } 275else 276return { x1 * x2 , y1 * y2 } 277end 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 ) 286local x1 =pos1 . x or pos1 [ 1 ] 287local y1 =pos1 . y or pos1 [ 2 ] 288local x2 =pos2 . x or pos2 [ 1 ] 289local y2 =pos2 . y or pos2 [ 2 ] 290if pos1 . x then 291return { x =x1 - x2 , y =y1 - y2 } 292else 293return { x1 - x2 , y1 - y2 } 294end 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 ) 303local x1 =pos1 . x or pos1 [ 1 ] 304local y1 =pos1 . y or pos1 [ 2 ] 305local x2 =pos2 . x or pos2 [ 1 ] 306local y2 =pos2 . y or pos2 [ 2 ] 307if pos1 . x then 308return { x =x1 ^ x2 , y =y1 ^ y2 } 309else 310return { x1 ^ x2 , y1 ^ y2 } 311end 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 ) 318if pos . x then 319return { x =math . floor ( pos . x / 32 ), y =math . floor ( pos . y / 32 ) } 320else 321return { math . floor ( pos [ 1 ] / 32 ), math . floor ( pos [ 2 ] / 32 ) } 322end 323end 324 325--- Convert a `MapPosition` into a `TilePosition` by flooring. 326--- @param pos MapPosition 327--- @return TilePosition 328function flib_position . to_tile ( pos ) 329if pos . x then 330return { x =math . floor ( pos . x ), y =math . floor ( pos . y ) } 331else 332return { math . floor ( pos [ 1 ]), math . floor ( pos [ 2 ]) } 333end 334end 335 336return flib_position