sokol-luajit/lua/opensteer/os-obstacle.lua
2025-10-17 09:43:15 +10:30

83 lines
3.1 KiB
Lua

-- // ----------------------------------------------------------------------------
-- // Obstacle: a pure virtual base class for an abstract shape in space, to be
-- // used with obstacle avoidance.
-- //
-- // XXX this should define generic methods for querying the obstacle shape
-- // ----------------------------------------------------------------------------
-- // SphericalObstacle a simple concrete type of obstacle
local veclib = require("opensteer.os-vec")
local osmath, osvec, Vec3 = veclib.osmath, veclib.osvec, veclib.vec3
local obstacle = {
SphericalObstacle = function()
local self = {}
self.radius = 1.0
self.center = Vec3()
self._seenFrom = nil
-- // constructors
self.seenFrom = function() return _seenFrom end
self.setSeenFrom = function( s) self._seenFrom = s end
-- // XXX 4-23-03: Temporary work around (see comment above)
-- //
-- // Checks for intersection of the given spherical obstacle with a
-- // volume of "likely future vehicle positions": a cylinder along the
-- // current path, extending minTimeToCollision seconds along the
-- // forward axis from current position.
-- //
-- // If they intersect, a collision is imminent and this function returns
-- // a steering force pointing laterally away from the obstacle's center.
-- //
-- // Returns a zero vector if the obstacle is outside the cylinder
-- //
-- // xxx couldn't this be made more compact using localizePosition?
self.steerToAvoid = function( v, minTimeToCollision)
-- // minimum distance to obstacle before avoidance is required
local minDistanceToCollision = minTimeToCollision * v.speed()
local minDistanceToCenter = minDistanceToCollision + self.radius
-- // contact distance: sum of radii of obstacle and vehicle
local totalRadius = self.radius + v.radius()
-- // obstacle center relative to vehicle position
local localOffset = self.center.sub( v.position() )
-- // distance along vehicle's forward axis to obstacle's center
local forwardComponent = localOffset.dot (v.forward())
local forwardOffset = forwardComponent.mult( v.forward())
-- // offset from forward axis to obstacle's center
local offForwardOffset = localOffset.sub(forwardOffset)
-- // test to see if sphere overlaps with obstacle-free corridor
local inCylinder = offForwardOffset.length() < totalRadius
local nearby = forwardComponent < minDistanceToCenter
local inFront = forwardComponent > 0
-- // if all three conditions are met, steer away from sphere center
if (inCylinder and nearby and inFront) then
return offForwardOffset.mult( -1 )
else
return Vec3.zero
end
end
return self
end,
}
obstacle.SphericalObstacle1 = function( r, c )
local so = SphericalObstacle()
so.center = c
so.radius = r
return so
end
return obstacle