Ticket #3925: Squares.patch

File Squares.patch, 13.2 KB (added by fsincos, 8 years ago)

Unit shapes are squares; use that to optimize the TestRayAASquare-based approach even further. (+style adjustments)

  • source/simulation2/components/CCmpPathfinder_Vertex.cpp

    diff --git a/source/simulation2/components/CCmpPathfinder_Vertex.cpp b/source/simulation2/components/CCmpPathfinder_Vertex.cpp
    index 6ed042c..e9063da 100644
    a b inline static bool CheckVisibility(const CFixedVector2D& a, const CFixedVector2D  
    138138    CFixedVector2D abn = (b - a).Perpendicular();
    139139
    140140    // Edges of general non-axis-aligned shapes
    141     for (size_t i = 0; i < edges.size(); ++i)
     141    for (const Edge& edge : edges)
    142142    {
    143         CFixedVector2D p0 = edges[i].p0;
    144         CFixedVector2D p1 = edges[i].p1;
    145 
    146         CFixedVector2D d = (p1 - p0).Perpendicular();
     143        CFixedVector2D d = (edge.p1 - edge.p0).Perpendicular();
    147144
    148145        // If 'a' is behind the edge, we can't cross
    149         fixed q = (a - p0).Dot(d);
     146        fixed q = (a - edge.p0).Dot(d);
    150147        if (q < fixed::Zero())
    151148            continue;
    152149
    153150        // If 'b' is in front of the edge, we can't cross
    154         fixed r = (b - p0).Dot(d);
     151        fixed r = (b - edge.p0).Dot(d);
    155152        if (r > fixed::Zero())
    156153            continue;
    157154
    158155        // The ray is crossing the infinitely-extended edge from in front to behind.
    159156        // Check the finite edge is crossing the infinitely-extended ray too.
    160157        // (Given the previous tests, it can only be crossing in one direction.)
    161         fixed s = (p0 - a).Dot(abn);
     158        fixed s = (edge.p0 - a).Dot(abn);
    162159        if (s > fixed::Zero())
    163160            continue;
    164161
    165         fixed t = (p1 - a).Dot(abn);
     162        fixed t = (edge.p1 - a).Dot(abn);
    166163        if (t < fixed::Zero())
    167164            continue;
    168165
    inline static bool CheckVisibilityLeft(const CFixedVector2D& a, const CFixedVect  
    184181
    185182    CFixedVector2D abn = (b - a).Perpendicular();
    186183
    187     for (size_t i = 0; i < edges.size(); ++i)
     184    for (const EdgeAA& edge : edges)
    188185    {
    189         if (b.X < edges[i].p0.X)
     186        if (b.X < edge.p0.X)
    190187            continue;
    191188
    192         CFixedVector2D p0 (edges[i].p0.X, edges[i].c1);
    193         fixed s = (p0 - a).Dot(abn);
     189        CFixedVector2D p1 (edge.p0.X, edge.c1);
     190        fixed s = (p1 - a).Dot(abn);
    194191        if (s > fixed::Zero())
    195192            continue;
    196193
    197         CFixedVector2D p1 (edges[i].p0.X, edges[i].p0.Y);
    198         fixed t = (p1 - a).Dot(abn);
     194        fixed t = (edge.p0 - a).Dot(abn);
    199195        if (t < fixed::Zero())
    200196            continue;
    201197
    inline static bool CheckVisibilityRight(const CFixedVector2D& a, const CFixedVec  
    212208
    213209    CFixedVector2D abn = (b - a).Perpendicular();
    214210
    215     for (size_t i = 0; i < edges.size(); ++i)
     211    for (const EdgeAA& edge : edges)
    216212    {
    217         if (b.X > edges[i].p0.X)
     213        if (b.X > edge.p0.X)
    218214            continue;
    219215
    220         CFixedVector2D p0 (edges[i].p0.X, edges[i].c1);
    221         fixed s = (p0 - a).Dot(abn);
     216        CFixedVector2D p1 (edge.p0.X, edge.c1);
     217        fixed s = (p1 - a).Dot(abn);
    222218        if (s > fixed::Zero())
    223219            continue;
    224220
    225         CFixedVector2D p1 (edges[i].p0.X, edges[i].p0.Y);
    226         fixed t = (p1 - a).Dot(abn);
     221        fixed t = (edge.p0 - a).Dot(abn);
    227222        if (t < fixed::Zero())
    228223            continue;
    229224
    inline static bool CheckVisibilityBottom(const CFixedVector2D& a, const CFixedVe  
    240235
    241236    CFixedVector2D abn = (b - a).Perpendicular();
    242237
    243     for (size_t i = 0; i < edges.size(); ++i)
     238    for (const EdgeAA& edge : edges)
    244239    {
    245         if (b.Y < edges[i].p0.Y)
     240        if (b.Y < edge.p0.Y)
    246241            continue;
    247242
    248         CFixedVector2D p0 (edges[i].p0.X, edges[i].p0.Y);
    249         fixed s = (p0 - a).Dot(abn);
     243        fixed s = (edge.p0 - a).Dot(abn);
    250244        if (s > fixed::Zero())
    251245            continue;
    252246
    253         CFixedVector2D p1 (edges[i].c1, edges[i].p0.Y);
     247        CFixedVector2D p1 (edge.c1, edge.p0.Y);
    254248        fixed t = (p1 - a).Dot(abn);
    255249        if (t < fixed::Zero())
    256250            continue;
    inline static bool CheckVisibilityTop(const CFixedVector2D& a, const CFixedVecto  
    268262
    269263    CFixedVector2D abn = (b - a).Perpendicular();
    270264
    271     for (size_t i = 0; i < edges.size(); ++i)
     265    for (const EdgeAA& edge : edges)
    272266    {
    273         if (b.Y > edges[i].p0.Y)
     267        if (b.Y > edge.p0.Y)
    274268            continue;
    275269
    276         CFixedVector2D p0 (edges[i].p0.X, edges[i].p0.Y);
    277         fixed s = (p0 - a).Dot(abn);
     270        fixed s = (edge.p0 - a).Dot(abn);
    278271        if (s > fixed::Zero())
    279272            continue;
    280273
    281         CFixedVector2D p1 (edges[i].c1, edges[i].p0.Y);
     274        CFixedVector2D p1 (edge.c1, edge.p0.Y);
    282275        fixed t = (p1 - a).Dot(abn);
    283276        if (t < fixed::Zero())
    284277            continue;
    inline static bool CheckVisibilityTop(const CFixedVector2D& a, const CFixedVecto  
    289282    return true;
    290283}
    291284
     285inline static bool CheckVisibilitySquares(const CFixedVector2D& start, const CFixedVector2D& end, const std::vector<EdgeAA>& Squares)
     286{
     287    for (const EdgeAA& square : Squares)
     288    {
     289        CFixedVector2D a = start - square.p0;
     290        CFixedVector2D b = end - square.p0;
     291        fixed c = square.c1;
     292
     293        if (-c <= a.X && a.X <= c && -c <= a.Y && a.Y <= c)
     294            continue; // a is inside
     295
     296        if ((a.X < -c && b.X < -c) || (a.X > c && b.X > c) || (a.Y < -c && b.Y < -c) || (a.Y > c && b.Y > c))
     297            continue; // ab is entirely above/below/side the square
     298
     299        CFixedVector2D abp = (b - a).Perpendicular();
     300        fixed s0 = a.Dot(abp).Absolute();
     301        fixed s1 = (abp.X.Absolute() + abp.Y.Absolute()).Multiply(c);
     302        if (s0 > s1)
     303            continue;
     304
     305        return false;
     306    }
     307    return true;
     308}
     309
    292310typedef PriorityQueueHeap<u16, fixed, fixed> VertexPriorityQueue;
    293311
    294312/**
    struct SquareSort  
    548566{
    549567    CFixedVector2D src;
    550568    SquareSort(CFixedVector2D src) : src(src) { }
    551     bool operator()(const Square& a, const Square& b)
     569    bool operator()(const EdgeAA& a, const EdgeAA& b)
    552570    {
    553571        if ((a.p0 - src).CompareLength(b.p0 - src) < 0)
    554572            return true;
    void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter,  
    595613    // List of collision edges - paths must never cross these.
    596614    // (Edges are one-sided so intersections are fine in one direction, but not the other direction.)
    597615    std::vector<Edge> edges;
    598     std::vector<Square> edgeSquares; // axis-aligned squares; equivalent to 4 edges
     616    std::vector<Square> edgeSquares; // axis-aligned rectangles; equivalent to 4 edges
     617    std::vector<EdgeAA> aaSquares; // axis-aligned squares, p0 = center, c1 = hw = hh
    599618
    600619    // Create impassable edges at the max-range boundary, so we can't escape the region
    601620    // where we're meant to be searching
    void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter,  
    643662   
    644663    // Change array capacities to reduce reallocations
    645664    vertexes.reserve(vertexes.size() + squares.size()*4);
    646     edgeSquares.reserve(edgeSquares.size() + squares.size()); // (assume most squares are AA)
     665    edgeSquares.reserve(edgeSquares.size() + staticShapesNb); // (assume most squares are AA)
     666    aaSquares.reserve(squares.size() - staticShapesNb);
    647667
    648668    entity_pos_t pathfindClearance = clearance;
    649669   
    void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter,  
    685705        CFixedVector2D ev2(center.X + h0.Dot(u), center.Y - h0.Dot(v));
    686706        CFixedVector2D ev3(center.X + h1.Dot(u), center.Y - h1.Dot(v));
    687707        if (aa)
    688             edgeSquares.emplace_back(Square{ ev1, ev3 });
     708            if (h0.X == h0.Y)
     709                aaSquares.emplace_back(EdgeAA{ center, h0.X });
     710            else
     711                edgeSquares.emplace_back(Square{ ev1, ev3 });
    689712        else
    690713        {
    691714            edges.emplace_back(Edge{ ev0, ev1 });
    void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter,  
    698721        // to reduce the search space
    699722    }
    700723
    701     // Clip out vertices that are inside an edgeSquare (i.e. trivially unreachable)
    702     for (size_t i = 0; i < edgeSquares.size(); ++i)
     724    // Clip out vertices that are inside an aaSquare (i.e. trivially unreachable)
     725    for (const EdgeAA& sq : aaSquares)
    703726    {
    704727        // If the start point is inside the square, ignore it
    705         if (start.p.X >= edgeSquares[i].p0.X &&
    706             start.p.Y >= edgeSquares[i].p0.Y &&
    707             start.p.X <= edgeSquares[i].p1.X &&
    708             start.p.Y <= edgeSquares[i].p1.Y)
     728        if ((start.p.X - sq.p0.X).Absolute() <= sq.c1 &&
     729            (start.p.Y - sq.p0.Y).Absolute() <= sq.c1)
    709730            continue;
    710731
    711732        // Remove every non-start/goal vertex that is inside an edgeSquare;
    712733        // since remove() would be inefficient, just mark it as closed instead.
    713734        for (size_t j = 2; j < vertexes.size(); ++j)
    714             if (vertexes[j].p.X >= edgeSquares[i].p0.X &&
    715                 vertexes[j].p.Y >= edgeSquares[i].p0.Y &&
    716                 vertexes[j].p.X <= edgeSquares[i].p1.X &&
    717                 vertexes[j].p.Y <= edgeSquares[i].p1.Y)
     735            if ((vertexes[j].p.X - sq.p0.X).Absolute() <= sq.c1 &&
     736                (vertexes[j].p.Y - sq.p0.Y).Absolute() <= sq.c1)
    718737                vertexes[j].status = Vertex::CLOSED;
    719738    }
    720739
    void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter,  
    725744    {
    726745#define PUSH_POINT(p) STMT(xz.push_back(p.X.ToFloat()); xz.push_back(p.Y.ToFloat()))
    727746        // Render the vertexes as little Pac-Man shapes to indicate quadrant direction
    728         for (size_t i = 0; i < vertexes.size(); ++i)
     747        for (const Vertex& vtx : vertexes)
    729748        {
    730749            m_DebugOverlayShortPathLines.emplace_back();
    731750            m_DebugOverlayShortPathLines.back().m_Color = CColor(1, 1, 0, 1);
    732751
    733             float x = vertexes[i].p.X.ToFloat();
    734             float z = vertexes[i].p.Y.ToFloat();
     752            float x = vtx.p.X.ToFloat();
     753            float z = vtx.p.Y.ToFloat();
    735754
    736755            float a0 = 0, a1 = 0;
    737756            // Get arc start/end angles depending on quadrant (if any)
    738             if      (vertexes[i].quadInward == QUADRANT_BL) { a0 = -0.25f; a1 = 0.50f; }
    739             else if (vertexes[i].quadInward == QUADRANT_TR) { a0 =  0.25f; a1 = 1.00f; }
    740             else if (vertexes[i].quadInward == QUADRANT_TL) { a0 = -0.50f; a1 = 0.25f; }
    741             else if (vertexes[i].quadInward == QUADRANT_BR) { a0 =  0.00f; a1 = 0.75f; }
     757            if      (vtx.quadInward == QUADRANT_BL) { a0 = -0.25f; a1 = 0.50f; }
     758            else if (vtx.quadInward == QUADRANT_TR) { a0 =  0.25f; a1 = 1.00f; }
     759            else if (vtx.quadInward == QUADRANT_TL) { a0 = -0.50f; a1 = 0.25f; }
     760            else if (vtx.quadInward == QUADRANT_BR) { a0 =  0.00f; a1 = 0.75f; }
    742761
    743762            if (a0 == a1)
    744763                SimRender::ConstructCircleOnGround(GetSimContext(), x, z, 0.5f,
    void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter,  
    750769        }
    751770
    752771        // Render the edges
    753         for (size_t i = 0; i < edges.size(); ++i)
     772        for (const Edge& edg : edges)
    754773        {
    755774            m_DebugOverlayShortPathLines.emplace_back();
    756775            m_DebugOverlayShortPathLines.back().m_Color = CColor(0, 1, 1, 1);
    757776            std::vector<float> xz;
    758             PUSH_POINT(edges[i].p0);
    759             PUSH_POINT(edges[i].p1);
     777            PUSH_POINT(edg.p0);
     778            PUSH_POINT(edg.p1);
    760779
    761780            // Add an arrowhead to indicate the direction
    762             CFixedVector2D d = edges[i].p1 - edges[i].p0;
     781            CFixedVector2D d = edg.p1 - edg.p0;
    763782            d.Normalize(fixed::FromInt(1)/8);
    764             CFixedVector2D p2 = edges[i].p1 - d*2;
     783            CFixedVector2D p2 = edg.p1 - d*2;
    765784            CFixedVector2D p3 = p2 + d.Perpendicular();
    766785            CFixedVector2D p4 = p2 - d.Perpendicular();
    767786            PUSH_POINT(p3);
    768787            PUSH_POINT(p4);
    769             PUSH_POINT(edges[i].p1);
     788            PUSH_POINT(edg.p1);
    770789
    771790            SimRender::ConstructLineOnGround(GetSimContext(), xz, m_DebugOverlayShortPathLines.back(), true);
    772791        }
    773792#undef PUSH_POINT
    774793
    775         // Render the axis-aligned squares
    776         for (size_t i = 0; i < edgeSquares.size(); ++i)
     794        // Render the axis-aligned rectangles
     795        for (const Square& s : edgeSquares)
    777796        {
    778797            m_DebugOverlayShortPathLines.push_back(SOverlayLine());
    779798            m_DebugOverlayShortPathLines.back().m_Color = CColor(0, 1, 1, 1);
    780799            std::vector<float> xz;
    781             Square s = edgeSquares[i];
    782800            xz.push_back(s.p0.X.ToFloat());
    783801            xz.push_back(s.p0.Y.ToFloat());
    784802            xz.push_back(s.p0.X.ToFloat());
    void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter,  
    791809            xz.push_back(s.p0.Y.ToFloat());
    792810            SimRender::ConstructLineOnGround(GetSimContext(), xz, m_DebugOverlayShortPathLines.back(), true);
    793811        }
     812        // Render the axis-aligned squares
     813        for (const EdgeAA& sq : aaSquares)
     814        {
     815            m_DebugOverlayShortPathLines.push_back(SOverlayLine());
     816            m_DebugOverlayShortPathLines.back().m_Color = CColor(0, 1, 1, 1);
     817            std::vector<float> xz;
     818            CFixedVector2D sqp0 = sq.p0 - CFixedVector2D(sq.c1, sq.c1);
     819            CFixedVector2D sqp1 = sq.p0 + CFixedVector2D(sq.c1, sq.c1);
     820            xz.push_back(sqp0.X.ToFloat());
     821            xz.push_back(sqp0.Y.ToFloat());
     822            xz.push_back(sqp0.X.ToFloat());
     823            xz.push_back(sqp1.Y.ToFloat());
     824            xz.push_back(sqp1.X.ToFloat());
     825            xz.push_back(sqp1.Y.ToFloat());
     826            xz.push_back(sqp1.X.ToFloat());
     827            xz.push_back(sqp0.Y.ToFloat());
     828            xz.push_back(sqp0.X.ToFloat());
     829            xz.push_back(sqp0.Y.ToFloat());
     830            SimRender::ConstructLineOnGround(GetSimContext(), xz, m_DebugOverlayShortPathLines.back(), true);
     831        }
    794832    }
    795833
    796834    // Do an A* search over the vertex/visibility graph:
    void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter,  
    830868        // The heuristic based on distance is very rough, especially for squares that are further away;
    831869        // we're also only really interested in the closest squares since they are the only ones that block a lot of rays.
    832870        // Thus we only do a partial sort; the threshold is just a somewhat reasonable value.
    833         if (edgeSquares.size() > 8)
    834             std::partial_sort(edgeSquares.begin(), edgeSquares.begin() + 8, edgeSquares.end(), SquareSort(vertexes[curr.id].p));
     871        if (aaSquares.size() > 8)
     872            std::partial_sort(aaSquares.begin(), aaSquares.begin() + 8, aaSquares.end(), SquareSort(vertexes[curr.id].p));
    835873
    836874        std::vector<Edge> edgesUnaligned;
    837875        std::vector<EdgeAA> edgesLeft;
    void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter,  
    890928            }
    891929
    892930            visible = visible &&
     931                CheckVisibilitySquares(vertexes[curr.id].p, npos, aaSquares) &&
    893932                CheckVisibilityLeft(vertexes[curr.id].p, npos, edgesLeft) &&
    894933                CheckVisibilityRight(vertexes[curr.id].p, npos, edgesRight) &&
    895934                CheckVisibilityBottom(vertexes[curr.id].p, npos, edgesBottom) &&