ORTS

ST_ForceField.H

Go to the documentation of this file.
00001 #ifndef ST_FORCEFIELD_H
00002 #define ST_FORCEFIELD_H
00003 
00004 //Comments coming soon, sorry...
00005 // This is an ORTS file
00006 // (c) Michael Buro, Sami Wagiaalla, David Deutscher, Nick Wiebe
00007 // licensed under the GPL
00008 
00009 // Local Pathfinder using ForceFields to execute paths,
00010 // and interface to global (simple a*) pathfinder.
00011 
00012 
00013 #include "TerrainBasicImp.H"
00014 #include "Random.H"
00015 #include "Coord.H"
00016 #include "SimpleTerrain.H"
00017 
00018 #include "boost/shared_ptr.hpp"
00019 
00020 namespace SimpleTerrain{
00021 
00022   typedef TerrainBase::Loc      Loc;
00023   typedef TerrainBase::Segment  Segment;
00024   typedef TerrainBase::Task     Task;
00025 
00026   /** Structure to keep data associated to a path
00027       fixme: right now this inherits from UnitPath, from SimpleTerrain,
00028       but that doesn't make much sense. This was done primarily for convenience.
00029    */
00030   struct UnitPath_FF : public UnitPath
00031   {
00032     /// Path data
00033     //@{
00034     //const Object *obj;
00035     //Vector<Loc> path;
00036     //Loc goal;
00037     //int current_target; // index of current way point in path vector
00038     //bool no_orders_yet; // true at the beginning, before the first move command is issued
00039     //@}
00040 
00041     /// Collision avoidance and resolution
00042     //@{
00043     // If adding fields - check ST_Task::set_path for needed updates.
00044     //bool stopped_to_avoid_collision; // true if the object was stopped temporarily to avoid a collision
00045     //int collision_step; // this is incremented while solving unexpected stops
00046     //uint4 wakeup;       // if SDL_GetTicks() >= wakeup then this UnitPath is not
00047                         // sleeping ie not to be skipped over.
00048     //Loc spot;           // spot of the last unexpected collision
00049     //@}
00050 
00051     bool replanned;
00052 
00053     UnitPath_FF(const Object *obj_, const Vector<Loc> &path_) : UnitPath(obj_, path_), replanned(false){};
00054     ~UnitPath_FF() {};
00055 
00056     //void mark_spot(const Loc &p) { spot = p; };
00057     //void sleep(int time) { wakeup = SDL_GetTicks() + time; };
00058     //bool sleeping() const { return wakeup > SDL_GetTicks(); };
00059 
00060     //bool is_intersect(const Segment &) const;
00061   };
00062 
00063 
00064   /** Functor that allows Locations to be put into sets*/
00065   class Loc_less : public std::binary_function<Loc, Loc, bool>{
00066   public:
00067     bool operator() (Loc a, Loc b) const;
00068   };
00069 
00070   /** Two Dimensional Vector */
00071   class Vec_2D{
00072   public:
00073     sint4 x;/// x-coord
00074     sint4 y;/// y-coord
00075     Vec_2D(sint4 x_=0, sint4 y_=0) :  x(x_), y(y_){};
00076     Vec_2D(const Vec_2D &other) :  x(other.x), y(other.y){};
00077     Vec_2D(const Loc &a, const Loc &b) : x(b.x - a.x), y(b.y - a.y) {};
00078     Vec_2D operator+(const Vec_2D &other) const; ///Vector addition
00079     Vec_2D operator-(const Vec_2D &other) const; ///Vector subtraction
00080     Vec_2D project_onto(const Vec_2D &other) const; /// Project the vector onto the line defined by the given vector
00081     sint4 dot_prod(const Vec_2D &other) const;
00082     real8 length() const;
00083     Vec_2D multiply(real8 k) const;
00084     bool operator==(const Vec_2D &other) const;
00085     bool operator!= (const Vec_2D &other) const;
00086 
00087     inline static sint4 round(real8 real) {
00088       return (sint4)floor(real + 0.5);
00089     }
00090   };
00091 
00092   /// The internal data complementing Task data:
00093   struct FF_Task {
00094     Task task;
00095     bool isPending;
00096     bool isFailed;
00097     bool noPathFound;
00098     boost::shared_ptr<UnitPath_FF> path;    // todo: replace with a cleaner implementation
00099     //Vector<const Object*> followers;
00100     uint4 replanned;
00101     //sint4 ticks; //used for automatic replanning when moving to a mobile object
00102 
00103     FF_Task(const Task& task_)
00104       : task(task_), isPending(true), isFailed(false), noPathFound(false), replanned(0) {};
00105     FF_Task(const FF_Task& other)
00106       : task(other.task), isPending(other.isPending),
00107     isFailed(other.isFailed), noPathFound(other.noPathFound),
00108       path(other.path), /*followers(other.followers),*/ replanned(other.replanned) {};
00109     void set_path(const Object *obj_, const Vector<Loc> &path_);
00110     //void init_path(const Object *obj_, const Vector<Loc> &path_) { path=boost::shared_ptr<UnitPath>(new UnitPath(obj_, path_)); };
00111     bool isValid() const { return !isPending && !isFailed && !noPathFound && path; };
00112   private:
00113     FF_Task operator=(const FF_Task& other);
00114   };
00115 
00116   /// An implementation of the TerrainBase interface using forcefields for local
00117   /// pathfinding.
00118   class ST_ForceField : public TerrainBasicImp<FF_Task>
00119   {
00120   public:
00121 
00122     ST_ForceField();
00123     virtual ~ST_ForceField() {};
00124 
00125     /// add command-line options specific to this implementation, using static methods of class Options
00126     static void add_options(void);
00127 
00128     //---------------------------------------------------------------------
00129     /// \name Implementation of relevant parts of the TerrainBase interface
00130     //---------------------------------------------------------------------
00131     //@{
00132     virtual void init(sint4 tiles_x_, sint4 tiles_y_, sint4 tile_points_, sint4 client_pID_, sint4 neutral_pID);
00133 
00134     virtual void add_obj(const Object *obj);
00135     virtual void update_obj(const Object *obj);
00136     virtual void remove_obj(const Object *obj);
00137     virtual void add_segments(const Vector<TerrainBase::Segment> &s);
00138 
00139     virtual void cancel_task(const Object *obj);
00140     virtual void remove_task(TaskId tid);
00141     TaskId execute_task(const Task &task, const Path &path);
00142 
00143     virtual void execute_tasks(Vector<MoveCmd> &cmds, Vector<StatusMsg> &msgs);
00144     virtual bool plan_tasks(uint4 max_time=0);
00145 
00146     virtual real8 find_path(const Loc &l1, const Loc &l2, sint4 radius, Path *path, ConsiderObjects consider = CONSIDER_ALL);
00147     virtual real8 find_path(const Object *obj, const Goal &goal, Path *path, ConsiderObjects consider = CONSIDER_ALL);
00148 
00149     //@}
00150     //---------------------------------------------------------------------
00151 
00152     // public to allow REGISTER_TYPEOF definitions
00153     typedef std::map<const Object*, Loc>  Obj2LocMap;
00154     typedef std::map<Loc, bool, Loc_less> SegmentEndsMap;
00155 
00156   private:
00157 
00158     /** Perform PF for a single pending task, and insert results to data structures.
00159         Return true iff did some planning. */
00160     bool plan_pending_task(uint4 stop_time);
00161     /** Perform PF for a single failed task, and insert results to data structures.
00162         Return true iff did some planning. */
00163     bool plan_failed_task(uint4 stop_time);
00164     /** Accessory function for planning either a pending or a failed task. */
00165     void plan_task(TIter tit, uint4 stop_time);
00166     /** Randomly choose a failed task. Return tasks.end() if no failed task exists. */
00167     TIter get_random_failed_task(void);
00168     /** Invalidate existing paths that intersect a given new boundary. */
00169     void invalidate_paths(const Vector<Segment> &segments);
00170     /** Test if the object is at the given location,
00171         accounting for a 1-tick look-ahead for moving objects. */
00172     static bool is_at_location(const Object* obj, const Loc& target);
00173     /** Test if the distance from the object to the target is within the given range.*/
00174     static bool is_near_location(const Object* obj, const Loc& target, sint4 range);
00175     /** Test if the object is at the goal of the given task, implementing
00176         (some) of the various definitions of 'goal'. */
00177    bool is_at_goal(const Object* obj, const Task& task);
00178     /** Test if the object is within firing range */
00179     static bool is_in_range(const Object* moving_obj, const Object *goal_obj);
00180     static bool is_in_range(const Object *moving_obj, const Loc goal_loc);
00181 
00182     /** Add a move command to the Vector of commands, telling the object to
00183     move to the target location at maximum speed.
00184     Also, updates the location associated with the object for forcefield purposes
00185     */
00186     void add_move_command(const Object *obj, Loc target, Vector<TerrainBase::MoveCmd> &cmds);
00187     /** Determines what team an object is on.
00188     If the team cannot be determined, returns -1 */
00189     sint4 what_team(const Object *obj);
00190 
00191     //---------------------------------------------------------------------
00192     /// \name Force Field methods
00193     //---------------------------------------------------------------------
00194     //@{
00195     /**
00196     Calculates the direction that an object should move to, based on the path
00197     they are following and any obstacles in the vicinity.
00198     @param path Path data
00199     @param output reference to a location that in the direction that the object should
00200     move to.
00201     fixme: maybe a location should be returned, instead of the pass by reference
00202     */
00203     void get_forcefield_target(UnitPath_FF &path, Loc &output);
00204 
00205     /**
00206       @param object The object that is moving
00207       @param attractor The point that is attracting the object
00208       @param output reference to a location that is in the direction that the
00209       object should move to.
00210     */
00211     void get_forcefield_target(const Object *obj, const Loc &attractor, Loc &output);
00212 
00213     /** used for pushing, where there is no attractor*/
00214     void get_push_target(const Object *obj, Loc &output);
00215 
00216 
00217     /** Adjusts the vector so that it is not directed more than 90 degrees on either side
00218     of the target vector.*/
00219     void restrict_vector(const Vec_2D &target_vec, Vec_2D &vec);
00220 
00221     /** Finds the location of point on a line that is closest to the given location*/
00222     Loc find_point_on_line(Loc loc, Loc line_start, Loc line_end);
00223 
00224     /** Calculates the repulsion caused by a point on an object and returns
00225     it as a vector*/
00226     Vec_2D get_point_repulsion(const Object *moving_obj, const Loc &point, sint4 radius = 0);
00227 
00228     /** Calculates the repulsion caused by a line on an object and returns
00229     it as a vector */
00230     Vec_2D get_line_repulsion(const Object *moving_obj, const Segment &seg);
00231 
00232     /** Calculates the position of the attractor along the path.
00233     The attractor is positioned a set distance ahead of the point closest to the
00234     object on the path.
00235      */
00236     Loc get_attractor(UnitPath_FF &path);
00237 
00238     //@}
00239     Obj2LocMap      objects;      ///< Used to calculate object repulsion
00240     Vector<Segment> segments;     ///< Used to calculate wall repulsion
00241     SegmentEndsMap  segment_ends; ///< Used to calculate repulsion from the ends of walls
00242 
00243     boost::shared_ptr<ST_Terrain::PFEngine> pfEngine; ///< The internal Path Finding engine
00244     std::set<const Object*> objsToStop;   ///< Objects for which we should set a stop-moving action
00245     Random rand;
00246     bool pushing_on;
00247     bool wp_attract;
00248     bool stop_to_plan;
00249 
00250     /** This multiplied by the max speed of an object gives the range at which objects
00251     and walls will exert a force on the objec*/
00252     static const sint4 FIELD_RANGE_MULTIPLIER = 2;
00253 
00254     /** The strength of attractors (does not vary with distance)*/
00255     static const sint4 ATTRACTOR_FORCE = 26;
00256 
00257     /** This divided by the distance squared to the moving object gives the strength
00258     of the repulsors*/
00259     static const sint4 REPULSOR_BASELINE = 200;
00260 
00261     /** No longer used*/
00262     static const sint4 WAYPOINT_PROX = 2;
00263 
00264     /** this multiplied by the object max speed gives the distance
00265     ahead of the object on the path that the attractor will be set to*/
00266     static const sint4 PATH_LOOK_AHEAD = 3;
00267 
00268     //static const uint4 REPLAN_HARDCAP = 2; ///< Max number of replans for a task
00269     //static const sint4 REPLAN_TRIGGER = 5; ///< Number of occilation steps before a replan will be triggered
00270     //static const sint4 OCCILATION_TRIGGER = 15;  ///< Number of occilation steps before a path movement failure will be passed
00271 
00272     static const uint4 REPLAN_HARDCAP =2; ///< Max number of replans for a task
00273     static const sint4 REPLAN_TRIGGER = 5; ///< Number of occilation steps before a replan will be triggered
00274     static const sint4 OCCILATION_TRIGGER = 15;  ///< Number of occilation steps before a path movement failure will be passed
00275     //GameStateModule &gms;
00276 
00277     friend class SimpleTerrainWidget;
00278     friend class SimpleTerrainOverlay;
00279     friend class ST_Terrain::PFEngine;
00280   };
00281 
00282 }
00283 
00284 REGISTER_TYPEOF(2601, SimpleTerrain::ST_ForceField::Obj2LocMap::iterator);
00285 REGISTER_TYPEOF(2602, SimpleTerrain::ST_ForceField::Obj2LocMap::const_iterator);
00286 REGISTER_TYPEOF(2603, SimpleTerrain::ST_ForceField::SegmentEndsMap::iterator);
00287 REGISTER_TYPEOF(2604, SimpleTerrain::ST_ForceField::SegmentEndsMap::const_iterator);
00288 REGISTER_TYPEOFS_TerrainBasicImp_ForEach(2605, SimpleTerrain::FF_Task);
00289 
00290 #endif


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