Afforess / Factorio-Stdlib

Factorio Standard Library Project
ISC License
162 stars 45 forks source link

Suggestion/request: Position function to get new pos at X dist along vector #130

Closed kyranf closed 5 years ago

kyranf commented 6 years ago

I have a situation where I'd like a unit to move 'towards' a point, but not quite at the point, some arbitrary amount away from the end point, but along the same line vector from Unit's position to the target position.

So it's kind of like "Unit at pos A, go towards pos B, but stop at intermediate pos C"

I imagine the inputs to the function would need to be Position A( the source pos), Position B (the target pos), Distance C (from B) to stop along the line.

if the user needs Distance C to the 'from A' instead, then they could achieve the same result with a call to distance_C = util.distance(A,B) - stopdist) and pass that into the function... otherwise "stopdist" in that situation would just be passed in. The Return of the function is the new simple position (table with X=.. Y=..)

Possible name: Position.offsetAlongLineVec(posA, posB, distC)

Example function usage: Unit entity A needs to be moved 'towards' Building entity B, but stop 10 tiles away from the Building's position.

local intermediatePosition = Position.offsetAlongLineVec(unit.position, building.position, 10)
unit.set_command({type=defines.command.go_to_location, destination=intermediatePosition , distraction=defines.distraction.by_nothing})
kyranf commented 6 years ago
--- Returns the position along line between source and target, at the distance from target
-- @tparam LuaPosition simple position table where the line starts and extends from.
-- @tparam LuaPosition simple position table where the line ends and is offset back from.
-- @tparam int distance backwards from end point along line for the new position.
-- @treturn LuaPosition at point along line between source and target, at requested offset back from target. 
function Position.offset_along_linevec(source_position, target_position, distance_from_target)

    local posA = Position.new(source_position)
    local posB = Position.new(target_position)
    local retPos =  Position.new(source_position)

    -- debug printing  Game.print_all("source pos: " .. Position.tostring(posA) .. " target pos: " .. Position.tostring(posB) )

    local angle = math.atan2( target_position.y - source_position.y  , target_position.x - source_position.x )
    local dist = Position.distance(source_position, target_position)
    local veclength = dist - distance_from_target

    -- debug printing  Game.print_all("Angle: " .. angle .. " length: " .. dist .. " length w offset: " .. veclength )

    --from source_position, project the point along the vector at angle, and veclength
    retPos.x = posA.x + math.cos(angle)*veclength
    retPos.y = posA.y + math.sin(angle)*veclength

    -- debug printing  Game.print_all("ret pos: " .. Position.tostring(retPos) )
    return retPos
end

Tested and working.

Nexela commented 5 years ago

Implemented in 274f5350122eeb25cd2e735da6f1b29db9d9116f