/*************************************************************************** file : pit.cpp created : Thu Mai 15 2:43:00 CET 2003 copyright : (C) 2003-2004 by Bernhard Wymann email : berniw@bluewin.ch version : $Id: pit.cpp,v 1.9 2005/08/05 08:54:09 berniw Exp $ ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "pit.h" #ifdef USE_OLETHROS_NAMESPACE namespace olethros { #endif const float Pit::SPEED_LIMIT_MARGIN = 0.5; // [m/s] savety margin to avoid pit speeding. Pit::Pit(tSituation *s, Driver *driver) { track = driver->getTrackPtr(); car = driver->getCarPtr(); mypit = driver->getCarPtr()->_pit; pitinfo = &track->pits; pitstop = inpitlane = false; pittimer = 0.0; pit_state = NONE; if (mypit != NULL) { speedlimit = pitinfo->speedLimit - SPEED_LIMIT_MARGIN; speedlimitsqr = speedlimit*speedlimit; pitspeedlimitsqr = pitinfo->speedLimit*pitinfo->speedLimit; // Compute pit spline points along the track. p[3].x = mypit->pos.seg->lgfromstart + mypit->pos.toStart; p[2].x = p[3].x - pitinfo->len; p[4].x = p[3].x + pitinfo->len; p[0].x = pitinfo->pitEntry->lgfromstart; p[1].x = pitinfo->pitStart->lgfromstart; p[5].x = p[3].x + (pitinfo->nMaxPits - car->index)*pitinfo->len; p[6].x = pitinfo->pitExit->lgfromstart; pitentry = p[0].x; pitexit = p[6].x; // Normalizing spline segments to >= 0.0. int i; for (i = 0; i < NPOINTS; i++) { p[i].s = 0.0; p[i].x = toSplineCoord(p[i].x); } // Fix broken pit exit. if (p[6].x < p[5].x) { //printf("bt: Pitexit broken on track %s.\n", track->name); p[6].x = p[5].x + 50.0; } // Fix point for first pit if necessary. if (p[1].x > p[2].x) { p[1].x = p[2].x; } // Fix point for last pit if necessary. if (p[4].x > p[5].x) { p[5].x = p[4].x; } float sign = (pitinfo->side == TR_LFT) ? 1.0 : -1.0; p[0].y = 0.0; p[6].y = 0.0; for (i = 1; i < NPOINTS - 1; i++) { p[i].y = fabs(pitinfo->driversPits->pos.toMiddle) - pitinfo->width; p[i].y *= sign; } p[3].y = fabs(pitinfo->driversPits->pos.toMiddle)*sign; spline = new Spline(NPOINTS, p); } } Pit::~Pit() { if (mypit != NULL) { delete spline; } } // Transforms track coordinates to spline parameter coordinates. float Pit::toSplineCoord(float x) { x -= pitentry; while (x < 0.0) { x += track->length; } return x; } // Computes offset to track middle for trajectory. float Pit::getPitOffset(float offset, float fromstart) { if (mypit != NULL) { if (getInPit() || (getPitstop() && isBetween(fromstart))) { fromstart = toSplineCoord(fromstart); return spline->evaluate(fromstart); } } return offset; } // Sets the pitstop flag if we are not in the pit range. void Pit::setPitstop(bool pitstop) { if (mypit == NULL) { return; } float fromstart = car->_distFromStartLine; if (!isBetween(fromstart)) { this->pitstop = pitstop; } else if (!pitstop) { this->pitstop = pitstop; pittimer = 0.0; } } // Check if the argument fromstart is in the range of the pit. bool Pit::isBetween(float fromstart) { if (pitentry <= pitexit) { if (fromstart >= pitentry && fromstart <= pitexit) { return true; } else { return false; } } else { // Warning: TORCS reports sometimes negative values for "fromstart"! if (fromstart <= pitexit || fromstart >= pitentry) { return true; } else { return false; } } } // Checks if we stay too long without getting captured by the pit. // Distance is the distance to the pit along the track, when the pit is // ahead it is > 0, if we overshoot the pit it is < 0. bool Pit::isTimeout(float distance) { if (car->_speed_x > 1.0 || distance > 3.0 || !getPitstop()) { pittimer = 0.0f; return false; } else { pittimer += (float) RCM_MAX_DT_ROBOTS; if (pittimer > 3.0f) { pittimer = 0.0f; return true; } else { return false; } } } // Update pit data and strategy. void Pit::update() { if (mypit != NULL) { if (isBetween(car->_distFromStartLine)) { if (getPitstop()) { setInPit(true); } } else { setInPit(false); } if (getPitstop()) { car->_raceCmd = RM_CMD_PIT_ASKED; } } } float Pit::getSpeedLimitBrake(float speedsqr) { return (speedsqr-speedlimitsqr)/(pitspeedlimitsqr-speedlimitsqr); } #ifdef USE_OLETHROS_NAMESPACE } #endif