ORTS

TerrainBase.H

Go to the documentation of this file.
00001 #ifndef TerrainBase_H
00002 #define TerrainBase_H
00003 
00004 // $Id: TerrainBase.H 5279 2007-06-23 02:49:08Z mburo $
00005 // This is an ORTS file (c) Michael Buro, David Deutscher, licensed under the GPL
00006 
00007 // Terrain Base Class
00008 // detaches terrain code from ORTS
00009 
00010 #include "Global.H"
00011 #include "Object.H"
00012 
00013 class CWidget;
00014 
00015 /** A base interface to terrain (path-finding) implementations. 
00016 This interface detaches path-finding (PF) code from ORTS.
00017 A derived implementation is:
00018 1. notified of world changes, including object location/speed changes.
00019 2. requested to handle PF tasks in 3 stages:
00020    a. calls to add/remove tasks.
00021    b. calls to plan tasks - here the implementation can spend thinking time
00022    c. calls to execute_tasks - the implementation should return low-level 
00023       move commands and arrived/failed messages per path, where relevant.
00024 */
00025 class TerrainBase
00026 {
00027 public:
00028 //------------------------------------------------------------------------
00029   //old:  typedef const void* ObjId;   // address of object on heap; id factory better?
00030   typedef const void* PathId;  // address of object on heap; id factory better?
00031   typedef const void* TaskId;  // address of object on heap; id factory better?
00032   //static const ObjId NOT_AN_ID;
00033 
00034 
00035 //------------------------------------------------------------------------
00036   /// A terrain location
00037   struct Loc
00038   {
00039     sint4 x, y;
00040 
00041     Loc(sint4 x_=0, sint4 y_=0) : x(x_), y(y_) {}
00042 
00043     bool operator==(const Loc &other) const {
00044       return x == other.x && y == other.y;
00045     }
00046 
00047     bool operator!=(const Loc &other) const {
00048       return x != other.x || y != other.y;
00049     }
00050 
00051     bool operator<(const Loc &other) const { 
00052       return x < other.x || (x == other.x && y < other.y);
00053     }
00054     
00055     real8 distance(const Loc &other) const {
00056       const real8 dx = x - other.x;
00057       const real8 dy = y - other.y;
00058       return sqrt(dx*dx + dy*dy);
00059     }
00060   };
00061 
00062 //------------------------------------------------------------------------
00063   /// A pair of locations, representing boundaries etc.
00064   struct Segment
00065   {
00066     Loc l1, l2;
00067 
00068     Segment(sint4 x1=0, sint4 y1=0, sint4 x2=0, sint4 y2=0) : l1(x1,y1), l2(x2,y2) { };
00069     Segment(const Loc &l1_, const Loc &l2_) : l1(l1_), l2(l2_) { };
00070 
00071     /** positive if l3 is on the left of the line from l1 to l2;
00072         negative if l3 is on the right;
00073         0 if l3 is on the line containing the segment. 
00074         Adapted for the reversed y-axis used by ORTS. */
00075     sint4 is_left_turn(const Loc &l3) const { return (l2.y-l1.y)*(l3.x-l1.x) - (l2.x-l1.x)*(l3.y-l1.y); };
00076 
00077     /// true if the segments weakly intersect
00078     bool touches(const Segment &o) const { 
00079       return is_left_turn(o.l1)*is_left_turn(o.l2) <= 0 &&
00080         o.is_left_turn(l1)*o.is_left_turn(l2) <= 0;
00081     };
00082 
00083     /// true if the segments strictly intersect
00084     bool intersects(const Segment &o) const { 
00085       return is_left_turn(o.l1)*is_left_turn(o.l2) < 0 &&
00086         o.is_left_turn(l1)*o.is_left_turn(l2) < 0;
00087     };
00088   };
00089 
00090 
00091 //------------------------------------------------------------------------
00092   /// A path is a sequence of locations (waypoints)
00093   struct Path
00094   {       
00095     PathId id;        //< for identifying path information
00096 
00097     Vector<Loc> locs;
00098 
00099     Path() : id() { }
00100     Path(const Path &other) : id(other.id), locs(other.locs) {};
00101     Path& operator=(const Path &other) { 
00102       if( this != &other ) { 
00103         id = other.id;
00104         locs = other.locs;
00105       }
00106       return *this;
00107     };
00108   };
00109 
00110 
00111 //------------------------------------------------------------------------
00112   /// A movement goal
00113   struct Goal
00114   {
00115     /// target location or an object to reach?
00116     enum Target { LOCATION, OBJ }           target;
00117 
00118     /// reach vicinity, touch object, attack object?
00119     enum Mode   { VICINITY, TOUCH, ATTACK } mode;
00120 
00121     /// The goal location (if target==LOCATION)
00122     Loc loc;
00123     
00124     /** The goal object (if target==OBJ). 
00125         It's the implementation's responsibility to track remove_object() 
00126         calls and handle cases of a goal object dying or vanishing in the 
00127         FOW (and this pointer becoming invalid). */
00128     const Object *obj;
00129 
00130     /// The distance from the target that is 'close enough' (if mode==VICINITY)
00131     sint4 distance;
00132 
00133     Goal(Target t, Mode m) : target(t), mode(m), obj(NULL), distance(0) {};
00134     Goal(const Object *o, Mode m) : target(OBJ), mode(m), obj(o), distance(0) {};
00135     Goal(const Loc &l, Mode m) : target(LOCATION), mode(m), loc(l), obj(NULL), distance(0) {};
00136 
00137     Goal(const Goal &other) 
00138       : target(other.target), mode(other.mode), loc(other.loc), obj(other.obj),
00139         distance(other.distance) {};
00140     // private:
00141     //Goal& operator=(const Goal &other);
00142   };
00143 
00144   /// A pathfinding task to be executed
00145   struct Task
00146   {
00147     /// The goal of the movement.
00148     Goal goal;
00149 
00150     /// Units traveling at individual speeds or in formation?
00151     enum Group { INDIVIDUAL, FORMATION } group;
00152 
00153     /** The objects to be moved. 
00154         It's the implementation's responsibility to track remove_object() 
00155         calls and handle cases of a objects dying or vanishing in the 
00156         FOW (and pointers becoming invalid). */
00157     std::set<const Object*> objs;
00158 
00159     Task(Goal::Target t = Goal::LOCATION, Goal::Mode m = Goal::VICINITY, Group g = INDIVIDUAL) 
00160       : goal(t,m), group(g)  {};
00161     Task(const Task &other) : goal(other.goal), group(other.group), objs(other.objs) {};
00162     //private:
00163     //Task& operator=(const Task &other);
00164   };
00165 
00166 
00167 //------------------------------------------------------------------------
00168   /// Shortcut construction of a "move a single obj to a location target" Task
00169   struct Obj2LocTask : public TerrainBase::Task {
00170     Obj2LocTask(Object *obj, const Loc& goal_loc_) : Task(Goal::LOCATION, Goal::TOUCH, INDIVIDUAL) {
00171       goal.loc = goal_loc_;
00172       objs.insert(obj); 
00173     };
00174   };
00175 
00176 
00177 //------------------------------------------------------------------------
00178   /// Shortcut construction of a "move a single obj to an object target" Task
00179   struct Obj2ObjTask : public TerrainBase::Task {
00180     Obj2ObjTask(Object *obj, const Object *goal_obj_) : Task(Goal::OBJ, Goal::TOUCH, INDIVIDUAL) {
00181       goal.obj = goal_obj_;
00182       objs.insert(obj);
00183     };
00184   };
00185 
00186 
00187 //------------------------------------------------------------------------
00188   /// A low-level move command to be executed
00189   struct MoveCmd
00190   {
00191     const Object *obj;  // link
00192     sint4   speed;      // 0 -> stop
00193     Loc     next_loc;
00194 
00195     MoveCmd() : obj(0), speed(0) { }
00196   };
00197 
00198 
00199 //------------------------------------------------------------------------
00200   /** A task status notification to be sent. A seperate msg is
00201       created for each object in multi-object tasks, since each 
00202       can arrive/fail individually. */
00203   struct StatusMsg
00204   {
00205     enum Type { ARRIVED,          ///< object arrived at goal
00206                 NO_PATH_FAILURE,  ///< no path to goal could be computed
00207                 MOVEMENT_FAILURE  ///< failed to execute the planned task
00208     } type;
00209 
00210     TaskId task_id;
00211     const Object *obj; // link
00212 
00213     StatusMsg() : type(ARRIVED), task_id(), obj(0) { } 
00214   };
00215 
00216 //------------------------------------------------------------------------
00217   // TerrainBase interface itself
00218 
00219   TerrainBase()
00220   {
00221     tiles_x = tiles_y = tile_points = 0;
00222     client_pID = neutral_pID = -1;
00223     
00224   };
00225 
00226   TerrainBase(const TerrainBase &other)
00227     :tiles_x(other.tiles_x), tiles_y(other.tiles_y),
00228      tile_points(other.tile_points), client_pID(other.client_pID),
00229      neutral_pID(other.neutral_pID){};
00230 
00231   virtual ~TerrainBase();
00232 
00233   /// Set map dimensions
00234   /** set playfield dimensions and gives the pathfinder the IDs of the client
00235       and the neutral players
00236       tiles_x/y : dimensions in tiles
00237       tile_points : points on tile edge on fine grid 
00238   */
00239   virtual void init(sint4 tiles_x_, sint4 tiles_y_, sint4 tile_points_, sint4 client_pID_, sint4 neutral_pID_)
00240   {
00241     tiles_x = tiles_x_;
00242     tiles_y = tiles_y_;
00243     tile_points = tile_points_;
00244     client_pID = client_pID_;
00245     neutral_pID = neutral_pID_;
00246   };
00247 
00248   //---------------------------------------------------------------------
00249   /// \name Notifications on world changes
00250   //---------------------------------------------------------------------
00251   //@{
00252   virtual void add_obj(const Object *obj) = 0;
00253   virtual void remove_obj(const Object *obj) = 0;
00254   virtual void update_obj(const Object *obj) = 0;
00255   virtual void add_segments(const Vector<Segment> &segs) = 0;
00256   //}@
00257   //---------------------------------------------------------------------
00258 
00259 
00260   //---------------------------------------------------------------------
00261   /// \name Requests for an immediate planning of a path
00262   //---------------------------------------------------------------------
00263   //@{
00264   /// Flags that specify what objects to consider as obstacles.
00265   enum ConsiderObjects {
00266     CONSIDER_ALL                = 0,
00267     /// Ignore all friendly (owned) mobile objects.
00268     IGNORE_MOBILE_FRIENDS   = 0x001, 
00269     /// Ignore all enemy mobile objects.
00270     IGNORE_MOBILE_FOES      = 0x010,
00271     /// Ignore all neutral ("sheep") mobile objects.
00272     IGNORE_MOBILE_NEUTRALS  = 0x100,
00273     /// Ignore all mobile objects, considering only boundaries and non-mobile objects.
00274     IGNORE_ALL_MOBILE_OBJS      = IGNORE_MOBILE_FRIENDS | IGNORE_MOBILE_FOES | IGNORE_MOBILE_NEUTRALS,
00275   };
00276 
00277   /** Compute path between l1 and l2 for a circular object.
00278       @param l1         Start of requested path.
00279       @param l2         End of requested path.
00280       @param radius     Radius (half width) of the requested path.
00281       @param path       If != NULL, and a path was found, this will contain the it
00282                         (including l2 but not l1), with the first waypoint in locs[0].
00283       @param consider   What objects to consider as obstacles when searching for a path.
00284       @return           The length of the path (in tile_points); < 0 iff path doesn't exist. 
00285   */
00286   virtual real8 find_path(const Loc &l1, const Loc &l2, sint4 radius, Path *path,
00287                           ConsiderObjects consider = CONSIDER_ALL) = 0;
00288 
00289   /** Compute path for a given (circular only) Object with a given Goal,
00290       @param obj        The object to move, including the start position and radius.
00291       @param goal       Target of the requested path (location or object etc.).
00292       @param path       If != NULL, and a path was found, this will contain it 
00293                         (including the final but not the start position), with the 
00294                         first waypoint in locs[0].
00295       @param consider   What objects to consider as obstacles when searching for a path.
00296       @return           The length of the path (in tile_points); < 0 iff path doesn't exist. 
00297   */
00298   virtual real8 find_path(const Object *obj, const Goal &goal, Path *path,
00299                           ConsiderObjects consider = CONSIDER_ALL) = 0;
00300   //---------------------------------------------------------------------
00301   
00302 
00303   //---------------------------------------------------------------------
00304   /** \name Initiate/end pathfinding and execution
00305       These methods are expected to return quickly. */
00306   //---------------------------------------------------------------------
00307   //@{
00308   virtual TaskId add_task(const Task &task) = 0;
00309   virtual void remove_task(TaskId tid) = 0;  
00310   virtual void cancel_task(const Object *obj) = 0;
00311   //@}
00312   //---------------------------------------------------------------------
00313 
00314 
00315   //---------------------------------------------------------------------
00316   /// \name "Do some work" methods
00317   //---------------------------------------------------------------------
00318   //@{
00319   /** \brief Monitor path execution. Should return move commands and status 
00320       messages, and is expected to return quickly. */
00321   virtual void execute_tasks(Vector<MoveCmd> &cmds, Vector<StatusMsg> &msgs) = 0;
00322   /** Plan the paths you're handling. This is where long thinking should be done.
00323       Return true iff did some lengthy processing.
00324       Try to use only the specified amount of time (milliseconds) for planning before returning
00325       control to the caller. If max_time == 0 then there is no requested time limit. */
00326   virtual bool plan_tasks(uint4 max_time = 0) = 0;
00327   //@}
00328   //---------------------------------------------------------------------
00329 
00330 protected:
00331   // data
00332   sint4 tiles_x,          ///< playfield width
00333         tiles_y;          ///< playfield height
00334   sint4 tile_points;      ///< points on tile edge on fine grid
00335   sint4 client_pID,       ///< ID of the client player
00336         neutral_pID;      ///< ID of neutral player (eg. sheep)
00337 };
00338 
00339 extern std::ostream& operator<<(std::ostream& os, const TerrainBase::Loc& l);
00340 extern std::ostream& operator<<(std::ostream& os, const TerrainBase::Segment& s);
00341 
00342 REGISTER_TYPEOF(2401, Vector<TerrainBase::Segment>::iterator);
00343 REGISTER_TYPEOF(2402, Vector<TerrainBase::Segment>::const_iterator);
00344 
00345 REGISTER_TYPEOF(2403, Vector<TerrainBase::Loc>::iterator);
00346 REGISTER_TYPEOF(2404, Vector<TerrainBase::Loc>::const_iterator);
00347 
00348 REGISTER_TYPEOF(2405, Vector<TerrainBase::StatusMsg>::iterator);
00349 REGISTER_TYPEOF(2406, Vector<TerrainBase::StatusMsg>::const_iterator);
00350 
00351 REGISTER_TYPEOF(2407, Vector<TerrainBase::MoveCmd>::iterator);
00352 REGISTER_TYPEOF(2408, Vector<TerrainBase::MoveCmd>::const_iterator);
00353 
00354 REGISTER_TYPEOF(2409, Vector<TerrainBase::Loc>::reverse_iterator);
00355 REGISTER_TYPEOF(2410, Vector<TerrainBase::Loc>::const_reverse_iterator);
00356 
00357 REGISTER_TYPEOF(2411, Vector<TerrainBase::Path>::iterator);
00358 REGISTER_TYPEOF(2412, Vector<TerrainBase::Path>::const_iterator);
00359 
00360 #if 0
00361   // later
00362 
00363   struct Tile
00364   {
00365     enum Split {
00366       NO,
00367       TOPBOTTOM, //  |\|
00368       BOTTOMTOP, //  |/|
00369     } type;
00370     sint4 tx, ty;         // tile position
00371     sint4 type_w, type_e; // triangle types: west, east
00372   };
00373   
00374   virtual void remove_segment(const Segment &s) = 0;
00375   virtual void new_tile(const Tile &tile) = 0;
00376 
00377   // path finding
00378   virtual real8 path_len(const Loc &start, const Loc &goal, sint4 radius) = 0;
00379   virtual void  find_path(const Loc &start, const Loc &goal, sint4 radius,
00380               Path &path) = 0;
00381 #endif
00382 
00383 #endif


Generated on Fri May 18 2012 03:02:49 for ORTS by Doxygen1.7.3