Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ICmpObstructionManager.h
Go to the documentation of this file.
1 /* Copyright (C) 2012 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef INCLUDED_ICMPOBSTRUCTIONMANAGER
19 #define INCLUDED_ICMPOBSTRUCTIONMANAGER
20 
22 
25 
26 #include "maths/FixedVector2D.h"
27 
29 
30 /**
31  * Obstruction manager: provides efficient spatial queries over objects in the world.
32  *
33  * The class deals with two types of shape:
34  * "static" shapes, typically representing buildings, which are rectangles with a given
35  * width and height and angle;
36  * and "unit" shapes, representing units that can move around the world, which have a
37  * radius and no rotation. (Units sometimes act as axis-aligned squares, sometimes
38  * as approximately circles, due to the algorithm used by the short pathfinder.)
39  *
40  * Other classes (particularly ICmpObstruction) register shapes with this interface
41  * and keep them updated.
42  *
43  * The @c Test functions provide exact collision tests.
44  * The edge of a shape counts as 'inside' the shape, for the purpose of collisions.
45  * The functions accept an IObstructionTestFilter argument, which can restrict the
46  * set of shapes that are counted as collisions.
47  *
48  * Units can be marked as either moving or stationary, which simply determines whether
49  * certain filters include or exclude them.
50  *
51  * The @c Rasterise function approximates the current set of shapes onto a 2D grid,
52  * for use with tile-based pathfinding.
53  */
55 {
56 public:
57  /**
58  * External identifiers for shapes.
59  * (This is a struct rather than a raw u32 for type-safety.)
60  */
61  struct tag_t
62  {
63  tag_t() : n(0) {}
64  explicit tag_t(u32 n) : n(n) {}
65  bool valid() { return n != 0; }
66 
67  u32 n;
68  };
69 
70  /**
71  * Boolean flags affecting the obstruction behaviour of a shape.
72  */
73  enum EFlags
74  {
75  FLAG_BLOCK_MOVEMENT = (1 << 0), // prevents units moving through this shape
76  FLAG_BLOCK_FOUNDATION = (1 << 1), // prevents foundations being placed on this shape
77  FLAG_BLOCK_CONSTRUCTION = (1 << 2), // prevents buildings being constructed on this shape
78  FLAG_BLOCK_PATHFINDING = (1 << 3), // prevents the tile pathfinder choosing paths through this shape
79  FLAG_MOVING = (1 << 4) // indicates this unit is currently moving
80  };
81 
82  /**
83  * Bitmask of EFlag values.
84  */
85  typedef u8 flags_t;
86 
87  /**
88  * Set the bounds of the world.
89  * Any point outside the bounds is considered obstructed.
90  * @param x0,z0,x1,z1 Coordinates of the corners of the world
91  */
92  virtual void SetBounds(entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1) = 0;
93 
94  /**
95  * Register a static shape.
96  *
97  * @param ent entity ID associated with this shape (or INVALID_ENTITY if none)
98  * @param x,z coordinates of center, in world space
99  * @param a angle of rotation (clockwise from +Z direction)
100  * @param w width (size along X axis)
101  * @param h height (size along Z axis)
102  * @param flags a set of EFlags values
103  * @param group primary control group of the shape. Must be a valid control group ID.
104  * @param group2 Optional; secondary control group of the shape. Defaults to INVALID_ENTITY.
105  * @return a valid tag for manipulating the shape
106  * @see StaticShape
107  */
109  entity_pos_t w, entity_pos_t h, flags_t flags, entity_id_t group, entity_id_t group2 = INVALID_ENTITY) = 0;
110 
111  /**
112  * Register a unit shape.
113  *
114  * @param ent entity ID associated with this shape (or INVALID_ENTITY if none)
115  * @param x,z coordinates of center, in world space
116  * @param r radius of circle or half the unit's width/height
117  * @param flags a set of EFlags values
118  * @param group control group (typically the owner entity, or a formation controller entity
119  * - units ignore collisions with others in the same group)
120  * @return a valid tag for manipulating the shape
121  * @see UnitShape
122  */
123  virtual tag_t AddUnitShape(entity_id_t ent, entity_pos_t x, entity_pos_t z, entity_angle_t r, flags_t flags,
124  entity_id_t group) = 0;
125 
126  /**
127  * Adjust the position and angle of an existing shape.
128  * @param tag tag of shape (must be valid)
129  * @param x X coordinate of center, in world space
130  * @param z Z coordinate of center, in world space
131  * @param a angle of rotation (clockwise from +Z direction); ignored for unit shapes
132  */
133  virtual void MoveShape(tag_t tag, entity_pos_t x, entity_pos_t z, entity_angle_t a) = 0;
134 
135  /**
136  * Set whether a unit shape is moving or stationary.
137  * @param tag tag of shape (must be valid and a unit shape)
138  * @param moving whether the unit is currently moving through the world or is stationary
139  */
140  virtual void SetUnitMovingFlag(tag_t tag, bool moving) = 0;
141 
142  /**
143  * Set the control group of a unit shape.
144  * @param tag tag of shape (must be valid and a unit shape)
145  * @param group control group entity ID
146  */
147  virtual void SetUnitControlGroup(tag_t tag, entity_id_t group) = 0;
148 
149  /**
150  * Sets the control group of a static shape.
151  * @param tag Tag of the shape to set the control group for. Must be a valid and static shape tag.
152  * @param group Control group entity ID.
153  */
154  virtual void SetStaticControlGroup(tag_t tag, entity_id_t group, entity_id_t group2) = 0;
155 
156  /**
157  * Remove an existing shape. The tag will be made invalid and must not be used after this.
158  * @param tag tag of shape (must be valid)
159  */
160  virtual void RemoveShape(tag_t tag) = 0;
161 
162  /**
163  * Collision test a flat-ended thick line against the current set of shapes.
164  * The line caps extend by @p r beyond the end points.
165  * Only intersections going from outside to inside a shape are counted.
166  * @param filter filter to restrict the shapes that are counted
167  * @param x0 X coordinate of line's first point
168  * @param z0 Z coordinate of line's first point
169  * @param x1 X coordinate of line's second point
170  * @param z1 Z coordinate of line's second point
171  * @param r radius (half width) of line
172  * @return true if there is a collision
173  */
174  virtual bool TestLine(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r) = 0;
175 
176  /**
177  * Collision test a static square shape against the current set of shapes.
178  * @param filter filter to restrict the shapes that are being tested against
179  * @param x X coordinate of center
180  * @param z Z coordinate of center
181  * @param a angle of rotation (clockwise from +Z direction)
182  * @param w width (size along X axis)
183  * @param h height (size along Z axis)
184  * @param out if non-NULL, all colliding shapes' entities will be added to this list
185  * @return true if there is a collision
186  */
187  virtual bool TestStaticShape(const IObstructionTestFilter& filter,
189  std::vector<entity_id_t>* out) = 0;
190 
191  /**
192  * Collision test a unit shape against the current set of registered shapes, and optionally writes a list of the colliding
193  * shapes' entities to an output list.
194  *
195  * @param filter filter to restrict the shapes that are being tested against
196  * @param x X coordinate of shape's center
197  * @param z Z coordinate of shape's center
198  * @param r radius of the shape (half the unit's width/height)
199  * @param out if non-NULL, all colliding shapes' entities will be added to this list
200  *
201  * @return true if there is a collision
202  */
203  virtual bool TestUnitShape(const IObstructionTestFilter& filter,
205  std::vector<entity_id_t>* out) = 0;
206 
207  /**
208  * Bit-flags for Rasterise.
209  */
211  {
212  TILE_OBSTRUCTED_PATHFINDING = (1 << 0), // set if the tile pathfinder should consider this tile blocked
213  TILE_OBSTRUCTED_FOUNDATION = (1 << 1), // set if the AI foundation placement algorithm should consider this tile blocked
214  TILE_OUTOFBOUNDS = (1 << 2) // set if this tile is outside the world boundaries
215  };
216 
217  /**
218  * Convert the current set of shapes onto a grid.
219  * Tiles that are intersected by a pathfind-blocking shape will have TILE_OBSTRUCTED_PATHFINDING set;
220  * tiles that are intersected by a foundation-blocking shape will also have TILE_OBSTRUCTED_FOUNDATION;
221  * tiles that are outside the world bounds will also have TILE_OUTOFBOUNDS;
222  * others will be set to 0.
223  * This is very cheap if the grid has been rasterised before and the set of shapes has not changed.
224  * @param grid the grid to be updated
225  * @return true if any changes were made to the grid, false if it was already up-to-date
226  */
227  virtual bool Rasterise(Grid<u8>& grid) = 0;
228 
229  /**
230  * Standard representation for all types of shapes, for use with geometry processing code.
231  */
233  {
234  entity_pos_t x, z; // position of center
235  CFixedVector2D u, v; // 'horizontal' and 'vertical' orthogonal unit vectors, representing orientation
236  entity_pos_t hw, hh; // half width, half height of square
237  };
238 
239  /**
240  * Find all the obstructions that are inside (or partially inside) the given range.
241  * @param filter filter to restrict the shapes that are counted
242  * @param x0 X coordinate of left edge of range
243  * @param z0 Z coordinate of bottom edge of range
244  * @param x1 X coordinate of right edge of range
245  * @param z1 Z coordinate of top edge of range
246  * @param squares output list of obstructions
247  */
248  virtual void GetObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector<ObstructionSquare>& squares) = 0;
249 
250  /**
251  * Find a single obstruction that blocks a unit at the given point with the given radius.
252  * Static obstructions (buildings) are more important than unit obstructions, and
253  * obstructions that cover the given point are more important than those that only cover
254  * the point expanded by the radius.
255  */
257 
258  /**
259  * Get the obstruction square representing the given shape.
260  * @param tag tag of shape (must be valid)
261  */
262  virtual ObstructionSquare GetObstruction(tag_t tag) = 0;
263 
265 
267 
268  /**
269  * Set the passability to be restricted to a circular map.
270  */
271  virtual void SetPassabilityCircular(bool enabled) = 0;
272 
273  /**
274  * Toggle the rendering of debug info.
275  */
276  virtual void SetDebugOverlay(bool enabled) = 0;
277 
278  DECLARE_INTERFACE_TYPE(ObstructionManager)
279 };
280 
281 /**
282  * Interface for ICmpObstructionManager @c Test functions to filter out unwanted shapes.
283  */
285 {
286 public:
289 
291 
292  /**
293  * Return true if the shape with the specified parameters should be tested for collisions.
294  * This is called for all shapes that would collide, and also for some that wouldn't.
295  *
296  * @param tag tag of shape being tested
297  * @param flags set of EFlags for the shape
298  * @param group the control group of the shape (typically the shape's unit, or the unit's formation controller, or 0)
299  * @param group2 an optional secondary control group of the shape, or INVALID_ENTITY if none specified. Currently
300  * exists only for static shapes.
301  */
302  virtual bool TestShape(tag_t tag, flags_t flags, entity_id_t group, entity_id_t group2) const = 0;
303 };
304 
305 /**
306  * Obstruction test filter that will test against all shapes.
307  */
309 {
310 public:
311  virtual bool TestShape(tag_t UNUSED(tag), flags_t UNUSED(flags), entity_id_t UNUSED(group), entity_id_t UNUSED(group2)) const
312  {
313  return true;
314  }
315 };
316 
317 /**
318  * Obstruction test filter that will test only against stationary (i.e. non-moving) shapes.
319  */
321 {
322 public:
323  virtual bool TestShape(tag_t UNUSED(tag), flags_t flags, entity_id_t UNUSED(group), entity_id_t UNUSED(group2)) const
324  {
325  return !(flags & ICmpObstructionManager::FLAG_MOVING);
326  }
327 };
328 
329 /**
330  * Obstruction test filter that reject shapes in a given control group,
331  * and rejects shapes that don't block unit movement, and optionally rejects moving shapes.
332  */
334 {
337 
338 public:
340  m_AvoidMoving(avoidMoving), m_Group(group)
341  {}
342 
343  virtual bool TestShape(tag_t UNUSED(tag), flags_t flags, entity_id_t group, entity_id_t group2) const
344  {
345  if (group == m_Group || (group2 != INVALID_ENTITY && group2 == m_Group))
346  return false;
348  return false;
349  if ((flags & ICmpObstructionManager::FLAG_MOVING) && !m_AvoidMoving)
350  return false;
351  return true;
352  }
353 };
354 
355 /**
356  * Obstruction test filter that will test only against shapes that:
357  * - are part of neither one of the specified control groups
358  * - AND, depending on the value of the 'exclude' argument:
359  * - have at least one of the specified flags set.
360  * - OR have none of the specified flags set.
361  *
362  * The first (primary) control group to reject shapes from must be specified and valid. The secondary
363  * control group to reject entities from may be set to INVALID_ENTITY to not use it.
364  *
365  * This filter is useful to e.g. allow foundations within the same control group to be placed and
366  * constructed arbitrarily close together (e.g. for wall pieces that need to link up tightly).
367  */
369 {
370  bool m_Exclude;
373  flags_t m_Mask;
374 
375 public:
376  SkipControlGroupsRequireFlagObstructionFilter(bool exclude, entity_id_t group1, entity_id_t group2, flags_t mask) :
377  m_Exclude(exclude), m_Group(group1), m_Group2(group2), m_Mask(mask)
378  {
379  Init();
380  }
381 
383  m_Exclude(false), m_Group(group1), m_Group2(group2), m_Mask(mask)
384  {
385  Init();
386  }
387 
388  virtual bool TestShape(tag_t UNUSED(tag), flags_t flags, entity_id_t group, entity_id_t group2) const
389  {
390  // Don't test shapes that share one or more of our control groups.
391  if (group == m_Group || group == m_Group2 || (group2 != INVALID_ENTITY &&
392  (group2 == m_Group || group2 == m_Group2)))
393  return false;
394 
395  // If m_Exclude is true, don't test against shapes that have any of the
396  // obstruction flags specified in m_Mask.
397  if (m_Exclude)
398  return (flags & m_Mask) == 0;
399 
400  // Otherwise, only include shapes that match at least one flag in m_Mask.
401  return (flags & m_Mask) != 0;
402  }
403 private:
404  void Init()
405  {
406  // the primary control group to filter out must be valid
407  ENSURE(m_Group != INVALID_ENTITY);
408 
409  // for simplicity, if m_Group2 is INVALID_ENTITY (i.e. not used), then set it equal to m_Group
410  // so that we have fewer special cases to consider in TestShape().
411  if (m_Group2 == INVALID_ENTITY)
412  m_Group2 = m_Group;
413  }
414 };
415 
416 /**
417  * Obstruction test filter that will test only against shapes that:
418  * - are part of both of the specified control groups
419  * - AND have at least one of the specified flags set.
420  *
421  * The first (primary) control group to include shapes from must be specified and valid.
422  *
423  * This filter is useful for preventing entities with identical control groups
424  * from colliding e.g. building a new wall segment on top of an existing wall)
425  *
426  * @todo This filter needs test cases.
427  */
429 {
430  bool m_Exclude;
434  flags_t m_Mask;
435 
436 public:
438  m_Tag(tag), m_Group(group1), m_Group2(group2), m_Mask(mask)
439  {
440  ENSURE(m_Group != INVALID_ENTITY);
441  }
442 
443  virtual bool TestShape(tag_t tag, flags_t flags, entity_id_t group, entity_id_t group2) const
444  {
445  // To be included in testing, a shape must not have the specified tag, and must
446  // match at least one of the flags in m_Mask, as well as both control groups.
447  return (tag.n != m_Tag.n && (flags & m_Mask) != 0 && ((group == m_Group
448  && group2 == m_Group2) || (group2 == m_Group && group == m_Group2)));
449  }
450 };
451 
452 /**
453  * Obstruction test filter that will test only against shapes that do not have the specified tag set.
454  */
456 {
458 public:
459  SkipTagObstructionFilter(tag_t tag) : m_Tag(tag)
460  {
461  }
462 
463  virtual bool TestShape(tag_t tag, flags_t UNUSED(flags), entity_id_t UNUSED(group), entity_id_t UNUSED(group2)) const
464  {
465  return tag.n != m_Tag.n;
466  }
467 };
468 
469 /**
470  * Obstruction test filter that will test only against shapes that:
471  * - do not have the specified tag
472  * - AND have at least one of the specified flags set.
473  */
475 {
476  tag_t m_Tag;
477  flags_t m_Mask;
478 public:
479  SkipTagRequireFlagsObstructionFilter(tag_t tag, flags_t mask) : m_Tag(tag), m_Mask(mask)
480  {
481  }
482 
483  virtual bool TestShape(tag_t tag, flags_t flags, entity_id_t UNUSED(group), entity_id_t UNUSED(group2)) const
484  {
485  return (tag.n != m_Tag.n && (flags & m_Mask) != 0);
486  }
487 };
488 
489 #endif // INCLUDED_ICMPOBSTRUCTIONMANAGER
virtual bool TestStaticShape(const IObstructionTestFilter &filter, entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h, std::vector< entity_id_t > *out)=0
Collision test a static square shape against the current set of shapes.
#define u8
Definition: types.h:39
A simple fixed-point number class.
Definition: Fixed.h:115
Obstruction test filter that will test only against shapes that:
Interface for ICmpObstructionManager Test functions to filter out unwanted shapes.
Obstruction test filter that will test only against shapes that:
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
virtual void SetUnitControlGroup(tag_t tag, entity_id_t group)=0
Set the control group of a unit shape.
virtual tag_t AddStaticShape(entity_id_t ent, entity_pos_t x, entity_pos_t z, entity_angle_t a, entity_pos_t w, entity_pos_t h, flags_t flags, entity_id_t group, entity_id_t group2=INVALID_ENTITY)=0
Register a static shape.
virtual ObstructionSquare GetStaticShapeObstruction(entity_pos_t x, entity_pos_t z, entity_angle_t a, entity_pos_t w, entity_pos_t h)=0
virtual bool TestUnitShape(const IObstructionTestFilter &filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, std::vector< entity_id_t > *out)=0
Collision test a unit shape against the current set of registered shapes, and optionally writes a lis...
virtual void SetBounds(entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1)=0
Set the bounds of the world.
virtual void SetPassabilityCircular(bool enabled)=0
Set the passability to be restricted to a circular map.
virtual void Init(const CParamNode &paramNode)=0
Obstruction test filter that reject shapes in a given control group, and rejects shapes that don&#39;t bl...
virtual bool TestLine(const IObstructionTestFilter &filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r)=0
Collision test a flat-ended thick line against the current set of shapes.
static void out(const wchar_t *fmt,...)
Definition: wdbg_sym.cpp:419
ControlGroupMovementObstructionFilter(bool avoidMoving, entity_id_t group)
SkipControlGroupsRequireFlagObstructionFilter(entity_id_t group1, entity_id_t group2, flags_t mask)
virtual ObstructionSquare GetObstruction(tag_t tag)=0
Get the obstruction square representing the given shape.
virtual bool TestShape(tag_t tag, flags_t flags, entity_id_t group, entity_id_t group2) const
Return true if the shape with the specified parameters should be tested for collisions.
Obstruction test filter that will test against all shapes.
Obstruction test filter that will test only against stationary (i.e.
virtual bool TestShape(tag_t tag, flags_t flags, entity_id_t group, entity_id_t group2) const
Return true if the shape with the specified parameters should be tested for collisions.
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
virtual void SetUnitMovingFlag(tag_t tag, bool moving)=0
Set whether a unit shape is moving or stationary.
SkipControlGroupsRequireFlagObstructionFilter(bool exclude, entity_id_t group1, entity_id_t group2, flags_t mask)
virtual void SetStaticControlGroup(tag_t tag, entity_id_t group, entity_id_t group2)=0
Sets the control group of a static shape.
u8 flags_t
Bitmask of EFlag values.
virtual bool TestShape(tag_t tag, flags_t flags, entity_id_t group, entity_id_t group2) const
Return true if the shape with the specified parameters should be tested for collisions.
ICmpObstructionManager::flags_t flags_t
#define DECLARE_INTERFACE_TYPE(iname)
Definition: Interface.h:23
TileObstruction
Bit-flags for Rasterise.
virtual void GetObstructionsInRange(const IObstructionTestFilter &filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector< ObstructionSquare > &squares)=0
Find all the obstructions that are inside (or partially inside) the given range.
virtual bool TestShape(tag_t tag, flags_t flags, entity_id_t group, entity_id_t group2) const
Return true if the shape with the specified parameters should be tested for collisions.
Obstruction test filter that will test only against shapes that:
virtual bool TestShape(tag_t tag, flags_t flags, entity_id_t group, entity_id_t group2) const
Return true if the shape with the specified parameters should be tested for collisions.
virtual ObstructionSquare GetUnitShapeObstruction(entity_pos_t x, entity_pos_t z, entity_pos_t r)=0
#define u32
Definition: types.h:41
Obstruction test filter that will test only against shapes that do not have the specified tag set...
EFlags
Boolean flags affecting the obstruction behaviour of a shape.
ICmpObstructionManager::tag_t tag_t
virtual bool Rasterise(Grid< u8 > &grid)=0
Convert the current set of shapes onto a grid.
SkipTagRequireControlGroupsAndFlagObstructionFilter(tag_t tag, entity_id_t group1, entity_id_t group2, flags_t mask)
virtual bool TestShape(tag_t tag, flags_t flags, entity_id_t group, entity_id_t group2) const
Return true if the shape with the specified parameters should be tested for collisions.
virtual bool FindMostImportantObstruction(const IObstructionTestFilter &filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, ObstructionSquare &square)=0
Find a single obstruction that blocks a unit at the given point with the given radius.
virtual void RemoveShape(tag_t tag)=0
Remove an existing shape.
const entity_id_t INVALID_ENTITY
Invalid entity ID.
Definition: Entity.h:36
Entity coordinate types.
u32 entity_id_t
Entity ID type.
Definition: Entity.h:24
SkipTagRequireFlagsObstructionFilter(tag_t tag, flags_t mask)
virtual void MoveShape(tag_t tag, entity_pos_t x, entity_pos_t z, entity_angle_t a)=0
Adjust the position and angle of an existing shape.
Standard representation for all types of shapes, for use with geometry processing code...
virtual void SetDebugOverlay(bool enabled)=0
Toggle the rendering of debug info.
Obstruction manager: provides efficient spatial queries over objects in the world.
External identifiers for shapes.
virtual tag_t AddUnitShape(entity_id_t ent, entity_pos_t x, entity_pos_t z, entity_angle_t r, flags_t flags, entity_id_t group)=0
Register a unit shape.
virtual bool TestShape(tag_t tag, flags_t flags, entity_id_t group, entity_id_t group2) const