Ticket #3588: geometry2.patch

File geometry2.patch, 9.8 KB (added by fsincos, 8 years ago)

Rough first version of the mentioned CheckVisibility trick.

  • source/simulation2/components/CCmpPathfinder_Vertex.cpp

    diff --git a/source/simulation2/components/CCmpPathfinder_Vertex.cpp b/source/simulation2/components/CCmpPathfinder_Vertex.cpp
    index 5ab11b6..b42fb62 100644
    a b  
    3939#include "simulation2/components/ICmpObstructionManager.h"
    4040#include "simulation2/helpers/PriorityQueue.h"
    4141#include "simulation2/helpers/Render.h"
     42#include "simulation2/helpers/Geometry.h"
    4243
    4344/* Quadrant optimisation:
    4445 * (loosely based on GPG2 "Optimizing Points-of-Visibility Pathfinding")
    inline static bool CheckVisibilityLeft(const CFixedVector2D& a, const CFixedVect  
    186187
    187188    for (size_t i = 0; i < edges.size(); ++i)
    188189    {
    189         if (b.X < edges[i].p0.X)
     190        if (a.X > edges[i].p0.X || b.X < edges[i].p0.X)
    190191            continue;
    191192
    192193        CFixedVector2D p0 (edges[i].p0.X, edges[i].c1);
    inline static bool CheckVisibilityRight(const CFixedVector2D& a, const CFixedVec  
    214215
    215216    for (size_t i = 0; i < edges.size(); ++i)
    216217    {
    217         if (b.X > edges[i].p0.X)
     218        if (a.X < edges[i].p0.X || b.X > edges[i].p0.X)
    218219            continue;
    219220
    220221        CFixedVector2D p0 (edges[i].p0.X, edges[i].c1);
    inline static bool CheckVisibilityBottom(const CFixedVector2D& a, const CFixedVe  
    242243
    243244    for (size_t i = 0; i < edges.size(); ++i)
    244245    {
    245         if (b.Y < edges[i].p0.Y)
     246        if (a.Y > edges[i].p0.Y || b.Y < edges[i].p0.Y)
    246247            continue;
    247248
    248249        CFixedVector2D p0 (edges[i].p0.X, edges[i].p0.Y);
    inline static bool CheckVisibilityTop(const CFixedVector2D& a, const CFixedVecto  
    270271
    271272    for (size_t i = 0; i < edges.size(); ++i)
    272273    {
    273         if (b.Y > edges[i].p0.Y)
     274        if (a.Y < edges[i].p0.Y || b.Y > edges[i].p0.Y)
    274275            continue;
    275276
    276277        CFixedVector2D p0 (edges[i].p0.X, edges[i].p0.Y);
    inline static bool CheckVisibilityTop(const CFixedVector2D& a, const CFixedVecto  
    289290    return true;
    290291}
    291292
     293inline static bool CheckVisibilityAASquares(const CFixedVector2D& a, const CFixedVector2D& b, const std::vector<Square> edgeSquares)
     294{
     295    for (size_t i = 0; i < edgeSquares.size(); ++i)
     296    {
     297        CFixedVector2D offset = (edgeSquares[i].p0 + edgeSquares[i].p1)/2;
     298        CFixedVector2D halfSize = (edgeSquares[i].p1 - edgeSquares[i].p0)/2;
     299        if (Geometry::TestRayAASquare(a - offset, b - offset, halfSize))
     300            return false;
     301    }
     302    return true;
     303}
     304
    292305typedef PriorityQueueHeap<u16, fixed, fixed> VertexPriorityQueue;
    293306
    294307/**
    static void AddTerrainEdges(std::vector<Edge>& edges, std::vector<Vertex>& verte  
    480493    }
    481494}
    482495
    483 static void SplitAAEdges(const CFixedVector2D& a,
    484         const std::vector<Edge>& edges,
    485         const std::vector<Square>& squares,
     496static void SplitAAEdges(const std::vector<Edge>& edges,
    486497        std::vector<Edge>& edgesUnaligned,
    487498        std::vector<EdgeAA>& edgesLeft, std::vector<EdgeAA>& edgesRight,
    488499        std::vector<EdgeAA>& edgesBottom, std::vector<EdgeAA>& edgesTop)
    489500{
    490     edgesLeft.reserve(squares.size());
    491     edgesRight.reserve(squares.size());
    492     edgesBottom.reserve(squares.size());
    493     edgesTop.reserve(squares.size());
    494 
    495     for (const Square& square : squares)
    496     {
    497         if (a.X <= square.p0.X)
    498             edgesLeft.emplace_back(EdgeAA{ square.p0, square.p1.Y });
    499         if (a.X >= square.p1.X)
    500             edgesRight.emplace_back(EdgeAA{ square.p1, square.p0.Y });
    501         if (a.Y <= square.p0.Y)
    502             edgesBottom.emplace_back(EdgeAA{ square.p0, square.p1.X });
    503         if (a.Y >= square.p1.Y)
    504             edgesTop.emplace_back(EdgeAA{ square.p1, square.p0.X });
    505     }
    506 
    507501    for (const Edge& edge : edges)
    508502    {
    509503        if (edge.p0.X == edge.p1.X)
    510504        {
    511505            if (edge.p1.Y < edge.p0.Y)
    512             {
    513                 if (!(a.X <= edge.p0.X))
    514                     continue;
    515506                edgesLeft.emplace_back(EdgeAA{ edge.p1, edge.p0.Y });
    516             }
    517507            else
    518             {
    519                 if (!(a.X >= edge.p0.X))
    520                     continue;
    521508                edgesRight.emplace_back(EdgeAA{ edge.p1, edge.p0.Y });
    522             }
    523509        }
    524510        else if (edge.p0.Y == edge.p1.Y)
    525511        {
    526512            if (edge.p0.X < edge.p1.X)
    527             {
    528                 if (!(a.Y <= edge.p0.Y))
    529                     continue;
    530513                edgesBottom.emplace_back(EdgeAA{ edge.p0, edge.p1.X });
    531             }
    532514            else
    533             {
    534                 if (!(a.Y >= edge.p0.Y))
    535                     continue;
    536515                edgesTop.emplace_back(EdgeAA{ edge.p0, edge.p1.X });
    537             }
    538516        }
    539517        else
    540518            edgesUnaligned.push_back(edge);
    void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter,  
    793771    u16 idBest = START_VERTEX_ID;
    794772    fixed hBest = start.h;
    795773
     774    // Detect axis-aligned edges for faster visibility checking.
     775    std::vector<Edge> edgesUnaligned;
     776    std::vector<EdgeAA> edgesLeft;
     777    std::vector<EdgeAA> edgesRight;
     778    std::vector<EdgeAA> edgesBottom;
     779    std::vector<EdgeAA> edgesTop;
     780    SplitAAEdges(edges, edgesUnaligned, edgesLeft, edgesRight, edgesBottom, edgesTop);
     781
    796782    while (!open.empty())
    797783    {
    798784        // Move best tile from open to closed
    void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter,  
    810796        // since they're more likely to block the rays
    811797        std::sort(edgeSquares.begin(), edgeSquares.end(), SquareSort(vertexes[curr.id].p));
    812798
    813         std::vector<Edge> edgesUnaligned;
    814         std::vector<EdgeAA> edgesLeft;
    815         std::vector<EdgeAA> edgesRight;
    816         std::vector<EdgeAA> edgesBottom;
    817         std::vector<EdgeAA> edgesTop;
    818         SplitAAEdges(vertexes[curr.id].p, edges, edgeSquares, edgesUnaligned, edgesLeft, edgesRight, edgesBottom, edgesTop);
    819 
    820799        // Check the lines to every other vertex
    821800        for (size_t n = 0; n < vertexes.size(); ++n)
    822801        {
    void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter,  
    871850                CheckVisibilityRight(vertexes[curr.id].p, npos, edgesRight) &&
    872851                CheckVisibilityBottom(vertexes[curr.id].p, npos, edgesBottom) &&
    873852                CheckVisibilityTop(vertexes[curr.id].p, npos, edgesTop) &&
    874                 CheckVisibility(vertexes[curr.id].p, npos, edgesUnaligned);
     853                CheckVisibility(vertexes[curr.id].p, npos, edgesUnaligned) &&
     854                CheckVisibilityAASquares(vertexes[curr.id].p, npos, edgeSquares);
    875855
    876856            /*
    877857            // Render the edges that we examine
  • source/simulation2/helpers/Geometry.cpp

    diff --git a/source/simulation2/helpers/Geometry.cpp b/source/simulation2/helpers/Geometry.cpp
    index 4173a7a..0fcc5b3 100644
    a b bool Geometry::TestRaySquare(const CFixedVector2D& a, const CFixedVector2D& b, c  
    196196    /*
    197197     * We only consider collisions to be when the ray goes from outside to inside the shape (and possibly out again).
    198198     * Various cases to consider:
    199      *   'a' inside, 'b' inside -> no collision
    200      *   'a' inside, 'b' outside -> no collision
    201      *   'a' outside, 'b' inside -> collision
    202      *   'a' outside, 'b' outside -> depends; use separating axis theorem:
     199     *   'a' inside -> no collision
     200     *   use separating axis theorem:
    203201     *     if the ray's bounding box is outside the square -> no collision
    204202     *     if the whole square is on the same side of the ray -> no collision
    205203     *     otherwise -> collision
    bool Geometry::TestRaySquare(const CFixedVector2D& a, const CFixedVector2D& b, c  
    218216    fixed bu = b.Dot(u);
    219217    fixed bv = b.Dot(v);
    220218
    221     if (-hw <= bu && bu <= hw && -hh <= bv && bv <= hh) // TODO: isn't this subsumed by the next checks?
    222         return true; // a is outside, b is inside
    223 
    224219    if ((au < -hw && bu < -hw) || (au > hw && bu > hw) || (av < -hh && bv < -hh) || (av > hh && bv > hh))
    225220        return false; // ab is entirely above/below/side the square
    226221
    227222    CFixedVector2D abp = (b - a).Perpendicular();
    228     fixed s0 = abp.Dot((u.Multiply(hw) + v.Multiply(hh)) - a);
    229     fixed s1 = abp.Dot((u.Multiply(hw) - v.Multiply(hh)) - a);
    230     fixed s2 = abp.Dot((-u.Multiply(hw) - v.Multiply(hh)) - a);
    231     fixed s3 = abp.Dot((-u.Multiply(hw) + v.Multiply(hh)) - a);
    232     if (s0.IsZero() || s1.IsZero() || s2.IsZero() || s3.IsZero())
    233         return true; // ray intersects the corner
    234 
    235     bool sign = (s0 < fixed::Zero());
    236     if ((s1 < fixed::Zero()) != sign || (s2 < fixed::Zero()) != sign || (s3 < fixed::Zero()) != sign)
    237         return true; // ray cuts through the square
    238 
    239     return false;
     223    fixed s0 = a.Dot(abp).Absolute();
     224    fixed s1 = u.Dot(abp).Absolute().Multiply(hw) + v.Dot(abp).Absolute().Multiply(hh);
     225    return (s0 <= s1);
    240226}
    241227
    242228// Exactly like TestRaySquare with u=(1,0), v=(0,1)
    bool Geometry::TestRayAASquare(const CFixedVector2D& a, const CFixedVector2D& b,  
    248234    if (-hw <= a.X && a.X <= hw && -hh <= a.Y && a.Y <= hh)
    249235        return false; // a is inside
    250236
    251     if (-hw <= b.X && b.X <= hw && -hh <= b.Y && b.Y <= hh) // TODO: isn't this subsumed by the next checks?
    252         return true; // a is outside, b is inside
    253 
    254237    if ((a.X < -hw && b.X < -hw) || (a.X > hw && b.X > hw) || (a.Y < -hh && b.Y < -hh) || (a.Y > hh && b.Y > hh))
    255238        return false; // ab is entirely above/below/side the square
    256239
    257240    CFixedVector2D abp = (b - a).Perpendicular();
    258     fixed s0 = abp.Dot(CFixedVector2D(hw, hh) - a);
    259     fixed s1 = abp.Dot(CFixedVector2D(hw, -hh) - a);
    260     fixed s2 = abp.Dot(CFixedVector2D(-hw, -hh) - a);
    261     fixed s3 = abp.Dot(CFixedVector2D(-hw, hh) - a);
    262     if (s0.IsZero() || s1.IsZero() || s2.IsZero() || s3.IsZero())
    263         return true; // ray intersects the corner
    264 
    265     bool sign = (s0 < fixed::Zero());
    266     if ((s1 < fixed::Zero()) != sign || (s2 < fixed::Zero()) != sign || (s3 < fixed::Zero()) != sign)
    267         return true; // ray cuts through the square
    268 
    269     return false;
     241    fixed s0 = a.Dot(abp).Absolute();
     242    fixed s1 = abp.X.Absolute().Multiply(hw) + abp.Y.Absolute().Multiply(hh);
     243    return (s0 <= s1);
    270244}
    271245
    272246/**
    static bool SquareSAT(const CFixedVector2D& a, const CFixedVector2D& axis, const  
    279253    fixed hh = halfSize.Y;
    280254
    281255    CFixedVector2D p = axis.Perpendicular();
    282     if (p.Dot((u.Multiply(hw) + v.Multiply(hh)) - a) <= fixed::Zero())
    283         return true;
    284     if (p.Dot((u.Multiply(hw) - v.Multiply(hh)) - a) <= fixed::Zero())
     256    fixed s0 = p.Dot(a);
     257    if (s0 >= fixed::Zero())
    285258        return true;
    286     if (p.Dot((-u.Multiply(hw) - v.Multiply(hh)) - a) <= fixed::Zero())
    287         return true;
    288     if (p.Dot((-u.Multiply(hw) + v.Multiply(hh)) - a) <= fixed::Zero())
    289         return true;
    290 
    291     return false;
     259    s0 += u.Dot(p).Absolute().Multiply(hw) + v.Dot(p).Absolute().Multiply(hh);
     260    return (s0 >= fixed::Zero());
    292261}
    293262
    294263bool Geometry::TestSquareSquare(