33 #include "precompiled.h"
135 for (
size_t i = 0; i < edges.size(); ++i)
143 fixed q = (a - p0).Dot(d);
148 fixed r = (b - p0).Dot(d);
155 fixed s = (p0 - a).Dot(abn);
159 fixed t = (p1 - a).Dot(abn);
181 for (
size_t i = 0; i < edges.size(); ++i)
183 if (b.
X < edges[i].p0.X)
187 fixed s = (p0 - a).Dot(abn);
192 fixed t = (p1 - a).Dot(abn);
209 for (
size_t i = 0; i < edges.size(); ++i)
211 if (b.
X > edges[i].p0.X)
215 fixed s = (p0 - a).Dot(abn);
220 fixed t = (p1 - a).Dot(abn);
237 for (
size_t i = 0; i < edges.size(); ++i)
239 if (b.
Y < edges[i].p0.Y)
243 fixed s = (p0 - a).Dot(abn);
248 fixed t = (p1 - a).Dot(abn);
265 for (
size_t i = 0; i < edges.size(); ++i)
267 if (b.
Y > edges[i].p0.Y)
271 fixed s = (p0 - a).Dot(abn);
276 fixed t = (p1 - a).Dot(abn);
336 static void AddTerrainEdges(std::vector<Edge>& edgesAA, std::vector<Vertex>& vertexes,
342 std::vector<TileEdge> tileEdges;
345 for (
u16 j = j0; j <= j1; ++j)
347 for (
u16 i = i0; i <= i1; ++i)
356 tileEdges.push_back(e);
363 tileEdges.push_back(e);
370 tileEdges.push_back(e);
377 tileEdges.push_back(e);
388 edgesAA.push_back(e);
399 for (
size_t n = 0; n < tileEdges.size(); ++n)
401 u16 i = tileEdges[n].i;
402 u16 j = tileEdges[n].j;
408 switch (tileEdges[n].dir)
447 const std::vector<Edge>& edgesAA,
448 std::vector<EdgeAA>& edgesLeft, std::vector<EdgeAA>& edgesRight,
449 std::vector<EdgeAA>& edgesBottom, std::vector<EdgeAA>& edgesTop)
451 edgesLeft.reserve(edgesAA.size());
452 edgesRight.reserve(edgesAA.size());
453 edgesBottom.reserve(edgesAA.size());
454 edgesTop.reserve(edgesAA.size());
456 for (
size_t i = 0; i < edgesAA.size(); ++i)
458 if (a.
X <= edgesAA[i].p0.X)
460 EdgeAA e = { edgesAA[i].
p0, edgesAA[i].p1.
Y };
461 edgesLeft.push_back(e);
463 if (a.
X >= edgesAA[i].p1.X)
465 EdgeAA e = { edgesAA[i].p1, edgesAA[i].
p0.
Y };
466 edgesRight.push_back(e);
468 if (a.
Y <= edgesAA[i].p0.Y)
470 EdgeAA e = { edgesAA[i].
p0, edgesAA[i].p1.
X };
471 edgesBottom.push_back(e);
473 if (a.
Y >= edgesAA[i].p1.Y)
475 EdgeAA e = { edgesAA[i].p1, edgesAA[i].
p0.
X };
476 edgesTop.push_back(e);
490 if ((a.
p0 -
src).CompareLength(b.
p0 -
src) < 0)
535 std::vector<Edge> edges;
536 std::vector<Edge> edgesAA;
540 fixed rangeXMin = x0 - range;
541 fixed rangeXMax = x0 + range;
542 fixed rangeZMin = z0 - range;
543 fixed rangeZMax = z0 + range;
558 std::vector<Vertex> vertexes;
564 vertexes.push_back(start);
565 const size_t START_VERTEX_ID = 0;
571 vertexes.push_back(end);
572 const size_t GOAL_VERTEX_ID = 1;
584 std::vector<ICmpObstructionManager::ObstructionSquare> squares;
585 cmpObstructionManager->
GetObstructionsInRange(filter, rangeXMin - r, rangeZMin - r, rangeXMax + r, rangeZMax + r, squares);
588 vertexes.reserve(vertexes.size() + squares.size()*4);
589 edgesAA.reserve(edgesAA.size() + squares.size());
592 for (
size_t i = 0; i < squares.size(); ++i)
601 CFixedVector2D hd0(squares[i].hw + r + EDGE_EXPAND_DELTA, squares[i].hh + r + EDGE_EXPAND_DELTA);
602 CFixedVector2D hd1(squares[i].hw + r + EDGE_EXPAND_DELTA, -(squares[i].hh + r + EDGE_EXPAND_DELTA));
627 Edge e = { ev1, ev3 };
628 edgesAA.push_back(e);
632 Edge e0 = { ev0, ev1 };
633 Edge e1 = { ev1, ev2 };
634 Edge e2 = { ev2, ev3 };
635 Edge e3 = { ev3, ev0 };
646 ENSURE(vertexes.size() < 65536);
651 for (
size_t i = 0; i < edges.size(); ++i)
655 std::vector<float> xz;
656 xz.push_back(edges[i].p0.X.ToFloat());
657 xz.push_back(edges[i].p0.Y.ToFloat());
658 xz.push_back(edges[i].p1.X.ToFloat());
659 xz.push_back(edges[i].p1.Y.ToFloat());
663 for (
size_t i = 0; i < edgesAA.size(); ++i)
667 std::vector<float> xz;
668 xz.push_back(edgesAA[i].p0.X.ToFloat());
669 xz.push_back(edgesAA[i].p0.Y.ToFloat());
670 xz.push_back(edgesAA[i].p0.X.ToFloat());
671 xz.push_back(edgesAA[i].p1.Y.ToFloat());
672 xz.push_back(edgesAA[i].p1.X.ToFloat());
673 xz.push_back(edgesAA[i].p1.Y.ToFloat());
674 xz.push_back(edgesAA[i].p1.X.ToFloat());
675 xz.push_back(edgesAA[i].p0.Y.ToFloat());
676 xz.push_back(edgesAA[i].p0.X.ToFloat());
677 xz.push_back(edgesAA[i].p0.Y.ToFloat());
696 PriorityQueue::Item qiStart = { START_VERTEX_ID, start.
h };
699 u16 idBest = START_VERTEX_ID;
702 while (!open.
empty())
705 PriorityQueue::Item curr = open.
pop();
709 if (curr.id == GOAL_VERTEX_ID)
717 std::sort(edgesAA.begin(), edgesAA.end(),
EdgeSort(vertexes[curr.id].p));
719 std::vector<EdgeAA> edgesLeft;
720 std::vector<EdgeAA> edgesRight;
721 std::vector<EdgeAA> edgesBottom;
722 std::vector<EdgeAA> edgesTop;
723 SplitAAEdges(vertexes[curr.id].p, edgesAA, edgesLeft, edgesRight, edgesBottom, edgesTop);
726 for (
size_t n = 0; n < vertexes.size(); ++n)
733 if (n == GOAL_VERTEX_ID)
740 npos.
X =
clamp(npos.
X, rangeXMin, rangeXMax);
741 npos.
Y =
clamp(npos.
Y, rangeZMin, rangeZMax);
745 npos = vertexes[n].p;
750 if (vertexes[curr.id].p.X <= npos.
X && vertexes[curr.id].p.Y <= npos.
Y) quad |=
QUADRANT_BL;
751 if (vertexes[curr.id].p.X >= npos.
X && vertexes[curr.id].p.Y >= npos.
Y) quad |=
QUADRANT_TR;
752 if (vertexes[curr.id].p.X <= npos.
X && vertexes[curr.id].p.Y >= npos.
Y) quad |=
QUADRANT_TL;
753 if (vertexes[curr.id].p.X >= npos.
X && vertexes[curr.id].p.Y <= npos.
Y) quad |=
QUADRANT_BR;
756 if (!(vertexes[curr.id].quadOutward & quad))
760 if (n != GOAL_VERTEX_ID)
787 fixed g = vertexes[curr.id].g + (vertexes[curr.id].p - npos).
Length();
796 vertexes[n].pred = curr.id;
802 if (vertexes[n].quadInward && !(curr.id == START_VERTEX_ID && g <
fixed::FromInt(8)))
803 vertexes[n].quadOutward = ((~vertexes[n].quadInward) & quad) & 0xF;
805 if (n == GOAL_VERTEX_ID)
806 vertexes[n].p = npos;
808 PriorityQueue::Item t = { (
u16)n, g + vertexes[n].h };
812 if (vertexes[n].h < hBest)
815 hBest = vertexes[n].h;
822 if (g >= vertexes[n].g)
827 vertexes[n].pred = curr.id;
831 if (vertexes[n].quadInward)
832 vertexes[n].quadOutward = ((~vertexes[n].quadInward) & quad) & 0xF;
834 if (n == GOAL_VERTEX_ID)
835 vertexes[n].p = npos;
844 for (
u16 id = idBest;
id != START_VERTEX_ID;
id = vertexes[id].pred)
846 Waypoint w = { vertexes[id].p.X, vertexes[id].p.Y };
847 path.m_Waypoints.push_back(w);
858 if (!cmpObstructionManager)
861 if (cmpObstructionManager->
TestLine(filter, x0, z0, x1, z1, r))
870 std::vector<Edge> edgesAA;
871 std::vector<Vertex> vertexes;
874 NearestTile(std::min(x0, x1) - r, std::min(z0, z1) - r, i0, j0);
875 NearestTile(std::max(x0, x1) + r, std::max(z0, z1) + r, i1, j1);
881 std::vector<EdgeAA> edgesLeft;
882 std::vector<EdgeAA> edgesRight;
883 std::vector<EdgeAA> edgesBottom;
884 std::vector<EdgeAA> edgesTop;
885 SplitAAEdges(a, edgesAA, edgesLeft, edgesRight, edgesBottom, edgesTop);
std::vector< SOverlayLine > m_DebugOverlayShortPathLines
static bool CheckVisibility(CFixedVector2D a, CFixedVector2D b, const std::vector< Edge > &edges)
Check whether a ray from 'a' to 'b' crosses any of the edges.
A simple fixed-point number class.
Interface for ICmpObstructionManager Test functions to filter out unwanted shapes.
Declares CCmpPathfinder, whose implementation is split into multiple source files, and provides common code needed for more than one of those files.
void UpdateGrid()
Regenerates the grid based on the current obstruction list, if necessary.
Line-based overlay, with world-space coordinates, rendered in the world potentially behind other obje...
static fixed DistanceToGoal(CFixedVector2D pos, const CCmpPathfinder::Goal &goal)
const ssize_t TERRAIN_TILE_SIZE
metres [world space units] per tile in x and z
Functor for sorting edges by approximate proximity to a fixed point.
static void SplitAAEdges(CFixedVector2D a, const std::vector< Edge > &edgesAA, std::vector< EdgeAA > &edgesLeft, std::vector< EdgeAA > &edgesRight, std::vector< EdgeAA > &edgesBottom, std::vector< EdgeAA > &edgesTop)
bool operator()(const Edge &a, const Edge &b)
void Normalize()
Normalize the vector so that length is close to 1.
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.
void NearestTile(entity_pos_t x, entity_pos_t z, u16 &i, u16 &j)
Returns the tile containing the given position.
Priority queue implemented as a binary heap.
EdgeSort(CFixedVector2D src)
fixed Dot(const CFixedVector2D &v)
Compute the dot product of this vector with another.
#define PROFILE_END(name)
Grid< TerrainTile > * m_Grid
CFixedVector2D NearestPointOnSquare(CFixedVector2D point, CFixedVector2D u, CFixedVector2D v, CFixedVector2D halfSize)
Find point closest to the given point on the edge of the given square or rectangle.
static CFixedVector2D NearestPointOnGoal(CFixedVector2D pos, const CCmpPathfinder::Goal &goal)
static const u8 QUADRANT_BR
#define IS_TERRAIN_PASSABLE(item, classmask)
#define ENSURE(expr)
ensure the expression <expr> evaluates to non-zero.
static bool CheckVisibilityLeft(CFixedVector2D a, CFixedVector2D b, const std::vector< EdgeAA > &edges)
static bool CheckVisibilityRight(CFixedVector2D a, CFixedVector2D b, const std::vector< EdgeAA > &edges)
void ConstructCircleOnGround(const CSimContext &context, float x, float z, float radius, SOverlayLine &overlay, bool floating, float heightOffset=0.25f)
Constructs overlay line as a circle with given center and radius, conforming to terrain.
static const entity_pos_t EDGE_EXPAND_DELTA
void ConstructLineOnGround(const CSimContext &context, const std::vector< float > &xz, SOverlayLine &overlay, bool floating, float heightOffset=0.25f)
Constructs overlay line from given points, conforming to terrain.
float ToFloat() const
Convert to float. May be lossy - float can't represent all values.
static const u8 QUADRANT_TL
void promote(ID id, R newrank)
#define PROFILE_START(name)
static const u8 QUADRANT_TR
const CSimContext & GetSimContext() const
A simplified syntax for accessing entity components.
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.
static const u8 QUADRANT_TLBR
CEntityHandle GetSystemEntity() const
static CFixed FromInt(int n)
virtual CFixedVector2D GetNearestPointOnGoal(CFixedVector2D pos, const Goal &goal)
Returns the coordinates of the point on the goal that is closest to pos in a straight line...
Helper functions related to rendering.
PathfinderOverlay * m_DebugOverlay
enum ICmpPathfinder::Goal::Type type
static const u8 QUADRANT_ALL
T & get(int i, int j) const
static const u8 QUADRANT_BL
void ConstructSquareOnGround(const CSimContext &context, float x, float z, float w, float h, float a, SOverlayLine &overlay, bool floating, float heightOffset=0.25f)
Constructs overlay line as rectangle with given center and dimensions, conforming to terrain...
static const u8 QUADRANT_BLTR
#define debug_warn(expr)
display the error dialog with the given text.
static bool CheckVisibilityTop(CFixedVector2D a, CFixedVector2D b, const std::vector< EdgeAA > &edges)
static float Length(const SVec3 v)
PriorityQueueHeap< std::pair< u16, u16 >, u32 > PriorityQueue
void push(const Item &item)
static void AddTerrainEdges(std::vector< Edge > &edgesAA, std::vector< Vertex > &vertexes, u16 i0, u16 j0, u16 i1, u16 j1, fixed r, ICmpPathfinder::pass_class_t passClass, const Grid< TerrainTile > &terrain)
virtual void ComputeShortPath(const IObstructionTestFilter &filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t r, entity_pos_t range, const Goal &goal, pass_class_t passClass, Path &ret)
T clamp(T value, T min, T max)
static bool CheckVisibilityBottom(CFixedVector2D a, CFixedVector2D b, const std::vector< EdgeAA > &edges)
virtual bool CheckMovement(const IObstructionTestFilter &filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, pass_class_t passClass)
Check whether the given movement line is valid and doesn't hit any obstructions or impassable terrain...
static const u8 QUADRANT_NONE