// 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? Vector3 steerToAvoid(AbstractVehicle v, float minTimeToCollision) { // minimum distance to obstacle before avoidance is required float minDistanceToCollision = minTimeToCollision * v.speed(); float minDistanceToCenter = minDistanceToCollision + radius; // contact distance: sum of radii of obstacle and vehicle float totalRadius = radius + v.radius(); // obstacle center relative to vehicle position Vector3 localOffset = center - v.Position; // distance along vehicle's forward axis to obstacle's center float forwardComponent = localOffset.DotProduct(v.forward()); Vector3 forwardOffset = forwardComponent * v.forward(); // offset from forward axis to obstacle's center Vector3 offForwardOffset = localOffset - forwardOffset; // test to see if sphere overlaps with obstacle-free corridor bool inCylinder = offForwardOffset.Length < totalRadius; bool nearby = forwardComponent < minDistanceToCenter; bool inFront = forwardComponent > 0; // if all three conditions are met, steer away from sphere center if (inCylinder && nearby && inFront) { return(offForwardOffset * -1); } else { return(Vector3.ZERO); } }
// Given the time until nearest approach (predictNearestApproachTime) // determine position of each vehicle at that time, and the distance // between them float computeNearestApproachPositions(AbstractVehicle other, float time) { Vector3 myTravel = forward() * speed() * time; Vector3 otherTravel = other.forward() * other.speed() * time; Vector3 myFinal = Position + myTravel; Vector3 otherFinal = other.Position + otherTravel; // xxx for annotation ourPositionAtNearestApproach = myFinal; hisPositionAtNearestApproach = otherFinal; return((myFinal - otherFinal).Length);//Vector3::distance (myFinal, otherFinal); }
// ---------------------------------------------------------------------------- // evasion of another vehicle public Vector3 steerForEvasion(AbstractVehicle menace, float maxPredictionTime) { // offset from this to menace, that distance, unit vector toward menace Vector3 offset = menace.Position - Position; float distance = offset.Length; float roughTime = distance / menace.speed(); float predictionTime = ((roughTime > maxPredictionTime) ? maxPredictionTime : roughTime); Vector3 target = menace.predictFuturePosition(predictionTime); return(steerForFlee(target)); }
// 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? Vector3 steerToAvoid(AbstractVehicle v, float minTimeToCollision) { // minimum distance to obstacle before avoidance is required float minDistanceToCollision = minTimeToCollision * v.speed(); float minDistanceToCenter = minDistanceToCollision + radius; // contact distance: sum of radii of obstacle and vehicle float totalRadius = radius + v.radius(); // obstacle center relative to vehicle position Vector3 localOffset = center - v.Position; // distance along vehicle's forward axis to obstacle's center float forwardComponent = localOffset.DotProduct(v.forward()); Vector3 forwardOffset = forwardComponent * v.forward(); // offset from forward axis to obstacle's center Vector3 offForwardOffset = localOffset - forwardOffset; // test to see if sphere overlaps with obstacle-free corridor bool inCylinder = offForwardOffset.Length < totalRadius; bool nearby = forwardComponent < minDistanceToCenter; bool inFront = forwardComponent > 0; // if all three conditions are met, steer away from sphere center if (inCylinder && nearby && inFront) { return offForwardOffset * -1; } else { return Vector3.ZERO; } }
// ---------------------------------------------------------------------------- // Unaligned collision avoidance behavior: avoid colliding with other nearby // vehicles moving in unconstrained directions. Determine which (if any) // other other vehicle we would collide with first, then steers to avoid the // site of that potential collision. Returns a steering force vector, which // is zero length if there is no impending collision. public Vector3 steerToAvoidNeighbors(float minTimeToCollision, ArrayList others) { // first priority is to prevent immediate interpenetration Vector3 separation = steerToAvoidCloseNeighbors(0, others); if (separation != Vector3.Zero) { return(separation); } // otherwise, go on to consider potential future collisions float steer = 0; AbstractVehicle threat = null; // Time (in seconds) until the most immediate collision threat found // so far. Initial value is a threshold: don't look more than this // many frames into the future. float minTime = minTimeToCollision; // xxx solely for annotation Vector3 xxxThreatPositionAtNearestApproach = new Vector3(); Vector3 xxxOurPositionAtNearestApproach = new Vector3(); // for each of the other vehicles, determine which (if any) // pose the most immediate threat of collision. //for (AVIterator i = others.begin(); i != others.end(); i++) for (int i = 0; i < others.Count; i++) { AbstractVehicle other = (AbstractVehicle)others[i]; if (other != this) { // avoid when future positions are this close (or less) float collisionDangerThreshold = radius() * 2; // predicted time until nearest approach of "this" and "other" float time = predictNearestApproachTime(other); // If the time is in the future, sooner than any other // threatened collision... if ((time >= 0) && (time < minTime)) { // if the two will be close enough to collide, // make a note of it if (computeNearestApproachPositions(other, time) < collisionDangerThreshold) { minTime = time; threat = other; xxxThreatPositionAtNearestApproach = hisPositionAtNearestApproach; xxxOurPositionAtNearestApproach = ourPositionAtNearestApproach; } } } } // if a potential collision was found, compute steering to avoid if (threat != null) { // parallel: +1, perpendicular: 0, anti-parallel: -1 float parallelness = forward().Dot(threat.forward()); float angle = 0.707f; if (parallelness < -angle) { // anti-parallel "head on" paths: // steer away from future threat position Vector3 offset = xxxThreatPositionAtNearestApproach - Position; float sideDot = offset.Dot(side()); steer = (sideDot > 0) ? -1.0f : 1.0f; } else { if (parallelness > angle) { // parallel paths: steer away from threat Vector3 offset = threat.Position - Position; float sideDot = offset.Dot(side()); steer = (sideDot > 0) ? -1.0f : 1.0f; } else { // perpendicular paths: steer behind threat // (only the slower of the two does this) if (threat.speed() <= speed()) { float sideDot = side().Dot(threat.velocity()); steer = (sideDot > 0) ? -1.0f : 1.0f; } } } annotateAvoidNeighbor(threat, steer, xxxOurPositionAtNearestApproach, xxxThreatPositionAtNearestApproach); } return(side() * steer); }
// Given the time until nearest approach (predictNearestApproachTime) // determine position of each vehicle at that time, and the distance // between them float computeNearestApproachPositions(AbstractVehicle other, float time) { Vector3 myTravel = forward () * speed () * time; Vector3 otherTravel = other.forward () * other.speed () * time; Vector3 myFinal = Position + myTravel; Vector3 otherFinal = other.Position + otherTravel; // xxx for annotation ourPositionAtNearestApproach = myFinal; hisPositionAtNearestApproach = otherFinal; return (myFinal - otherFinal).Length;//Vector3::distance (myFinal, otherFinal); }
// ---------------------------------------------------------------------------- // evasion of another vehicle public Vector3 steerForEvasion( AbstractVehicle menace, float maxPredictionTime) { // offset from this to menace, that distance, unit vector toward menace Vector3 offset = menace.Position - Position; float distance = offset.Length; float roughTime = distance / menace.speed(); float predictionTime = ((roughTime > maxPredictionTime) ? maxPredictionTime : roughTime); Vector3 target = menace.predictFuturePosition (predictionTime); return steerForFlee (target); }