library groupaddunitsnearline
globals
//upper bound for the collision size of units
private constant real MAX_COLLISSION = 128.
//this is aproximately how much space of the rects is used by the line
//a higher value yields less unnecessary checks but also more rects
private constant real desiredefficiency = 0.6
//---
private rect temprect = Rect(0,0,0,0)
private group tempenumgroup = CreateGroup()
private group tempgroup
private real temppx
private real temppy
private real tempdnx
private real tempdny
private real tempwidth
private real tempd
endglobals
//returns the maximum of 4 reals
private function max4 takes real a, real b, real c, real d returns real
local real max = a
if b > max then
set max = b
endif
if c > max then
set max = c
endif
if d > max then
set max = d
endif
return max
endfunction
//returns the minimum of 4 reals
private function min4 takes real a, real b, real c, real d returns real
local real min = a
if b < min then
set min = b
endif
if c < min then
set min = c
endif
if d < min then
set min = d
endif
return min
endfunction
private function Add takes nothing returns boolean
//position of unit
local real x = GetUnitX(GetFilterUnit())
local real y = GetUnitY(GetFilterUnit())
//vector from the beginning of the line to the unit
local real dx = x - temppx
local real dy = y - temppy
//distance from the beginning of the line to that point on the line which is closest to the unit (uses dot-product)
local real d = dx * tempdnx + dy * tempdny
local real cx
local real cy
//cut off points outside the line
if d <= 0 then
set d = 0
elseif d >= tempd then
set d = tempd
endif
//the closest point to the unit on the line
set cx = temppx + d * tempdnx
set cy = temppy + d * tempdny
if IsUnitInRangeXY(GetFilterUnit(), cx, cy, tempwidth) then
call GroupAddUnit(tempgroup, GetFilterUnit())
endif
return false
endfunction
function GroupAddUnitsNearLine takes group g, real px, real py, real qx, real qy, real width returns nothing
//the line width width
local real l1x
local real l1y
local real l2x
local real l2y
local real l3x
local real l3y
local real l4x
local real l4y
//d = from p to q
local real dx = qx - px
local real dy = qy - py
local real dlen = SquareRoot(dx*dx + dy*dy)
//normalized d
local real dxn = dx / dlen
local real dyn = dy / dlen
//divisions
local integer divisions = 1
//bonus for correct overlapping of rects
local real bonusx = 0.
local real bonusy = 0.
//integer for loop
local integer i
//the outer rect
local real rectminx
local real rectmaxx
local real rectminy
local real rectmaxy
set width = width + MAX_COLLISSION
//calculate the number of divisions needed to approximately match desiredefficiency
if dx != 0 and dy != 0 then
set divisions = 1 + R2I(SquareRoot(desiredefficiency*desiredefficiency / (width*width/(dx*dx) + width*width/(dy*dy))))
endif
//this calculates a bonus so that there are intersections between the different rects
//(without this we would miss some units between the rects)
if dy != 0 and divisions > 1 then
set bonusx = width / 2 * dlen / dx// ?dy
endif
if dx != 0 and divisions > 1 then
set bonusy = width / 2 * dlen / dy // ? dx
endif
//calculate first line segment
set l1x = - width*dyn
set l1y = width*dxn
set l2x = width*dyn
set l2y = - width*dxn
set l3x = l2x + dx/divisions + bonusx
set l3y = l2y + dy/divisions + bonusy
set l4x = l1x + dx/divisions + bonusx
set l4y = l1y + dy/divisions + bonusy
//calculate bounds of the first line segment
set rectminx = min4(l1x,l2x,l3x,l4x)
set rectmaxx = max4(l1x,l2x,l3x,l4x)
set rectminy = min4(l1y,l2y,l3y,l4y)
set rectmaxy = max4(l1y,l2y,l3y,l4y)
//set temp vars for groupenum
set tempgroup = g
set temppx = px
set temppy = py
set tempdnx = dxn
set tempdny = dyn
set tempwidth = width - MAX_COLLISSION
set tempd = dlen
set i = 0
loop
exitwhen i >= divisions
//---
//move rect to right position
call SetRect(temprect, px + i * dx / divisions + rectminx, py + i * dy / divisions + rectminy, px + i * dx / divisions + rectmaxx, py + i * dy / divisions + rectmaxy)
//enum units in rect
call GroupEnumUnitsInRect(tempenumgroup, temprect, Condition(function Add))
//---
set i = i + 1
endloop
endfunction
endlibrary