Ticket #1942: short-range_otp.patch
File short-range_otp.patch, 5.7 KB (added by , 8 years ago) |
---|
-
source/simulation2/helpers/PriorityQueue.h
34 34 { 35 35 bool operator()(const Item& a, const Item& b) const 36 36 { 37 if (!b.secondPass && a.secondPass) // return to already opened ones last 38 return true; 39 if (!a.secondPass && b.secondPass) 40 return false; 37 41 if (CMP()(b.rank, a.rank)) // higher costs are lower priority 38 42 return true; 39 43 if (CMP()(a.rank, b.rank)) … … 69 73 ID id; 70 74 R rank; // f = g+h (estimated total cost of path through here) 71 75 H h; // heuristic cost 76 bool secondPass; 72 77 }; 73 78 74 79 void push(const Item& item) -
source/simulation2/components/CCmpPathfinder_Vertex.cpp
90 90 UNEXPLORED, 91 91 OPEN, 92 92 CLOSED, 93 UNDERSTUDY, 93 94 }; 94 95 95 96 CFixedVector2D p; … … 795 796 PROFILE_START("Short pathfinding - A*"); 796 797 797 798 VertexPriorityQueue open; 798 VertexPriorityQueue::Item qiStart = { START_VERTEX_ID, start.h, start.h };799 VertexPriorityQueue::Item qiStart = { START_VERTEX_ID, start.h, start.h, false }; 799 800 open.push(qiStart); 800 801 801 802 u16 idBest = START_VERTEX_ID; 802 803 fixed hBest = start.h; 803 804 805 fixed maxDistFirstPass = entity_pos_t::FromInt(15); 806 bool hadASecondPass = false; 807 static u64 totalExam = 0; 808 804 809 while (!open.empty()) 805 810 { 806 811 // Move best tile from open to closed 807 812 VertexPriorityQueue::Item curr = open.pop(); 813 // If this is the second pass we need to remember it and we'll be closed at the end of this loop. 814 bool secondPass = (vertexes[curr.id].status == Vertex::UNDERSTUDY); 808 815 vertexes[curr.id].status = Vertex::CLOSED; 816 if (secondPass) 817 hadASecondPass = true; 809 818 810 819 // If we've reached the destination, stop 811 820 if (curr.id == GOAL_VERTEX_ID) … … 828 837 // Check the lines to every other vertex 829 838 for (size_t n = 0; n < vertexes.size(); ++n) 830 839 { 831 if (vertexes[n].status == Vertex::CLOSED )840 if (vertexes[n].status == Vertex::CLOSED || vertexes[n].status == Vertex::UNDERSTUDY) 832 841 continue; 833 842 834 843 // If this is the magical goal vertex, move it to near the current vertex … … 866 875 } 867 876 } 868 877 878 fixed distFromN = (vertexes[curr.id].p - npos).Length(); 879 fixed g = vertexes[curr.id].g + distFromN; 880 881 // Try and be clever based on distance to not check visibility to unwanted points. 882 // We do not study points we know that wouldn't improve our path anyway 883 // This first optimization does not change the algorithm itself. 884 // The second optimization assumes we won't be stuck in a unit-made U-shaped dead-end 885 // And tries to consider only potentially interesting vertices. 886 // Those are those closer to the goal than us, and those not too far away 887 // However sometimes we have to backtrack, usually the overall behavior is either 888 // much better or about equivalent. 889 if(g >= vertexes[n].g && vertexes[n].status != Vertex::UNEXPLORED) 890 continue; 891 892 fixed h = goal.DistanceToPoint(npos); 893 if (!hadASecondPass && (h > (hBest + entity_pos_t::FromInt(4)) || distFromN > maxDistFirstPass)) 894 { 895 if (vertexes[curr.id].status != Vertex::UNDERSTUDY) 896 { 897 // add us back to the list for a second pass if necessary. 898 VertexPriorityQueue::Item newMe = curr; 899 newMe.secondPass = true; 900 open.push(newMe); 901 vertexes[curr.id].status = Vertex::UNDERSTUDY; 902 } 903 continue; 904 } 905 906 ++totalExam; 907 869 908 bool visible = 870 909 CheckVisibilityLeft(vertexes[curr.id].p, npos, edgesLeft) && 871 910 CheckVisibilityRight(vertexes[curr.id].p, npos, edgesRight) && … … 883 922 xz.push_back(npos.X.ToFloat()); 884 923 xz.push_back(npos.Y.ToFloat()); 885 924 SimRender::ConstructLineOnGround(GetSimContext(), xz, m_DebugOverlayShortPathLines.back(), false); 886 //*/925 }//*/ 887 926 888 927 if (visible) 889 928 { 890 fixed g = vertexes[curr.id].g + (vertexes[curr.id].p - npos).Length();891 892 929 // If this is a new tile, compute the heuristic distance 893 930 if (vertexes[n].status == Vertex::UNEXPLORED) 894 931 { … … 895 932 // Add it to the open list: 896 933 vertexes[n].status = Vertex::OPEN; 897 934 vertexes[n].g = g; 898 vertexes[n].h = goal.DistanceToPoint(npos);935 vertexes[n].h = h; 899 936 vertexes[n].pred = curr.id; 900 937 901 938 // If this is an axis-aligned shape, the path must continue in the same quadrant … … 908 945 if (n == GOAL_VERTEX_ID) 909 946 vertexes[n].p = npos; // remember the new best goal position 910 947 911 VertexPriorityQueue::Item t = { (u16)n, g + vertexes[n].h, vertexes[n].h };948 VertexPriorityQueue::Item t = { (u16)n, g + vertexes[n].h, vertexes[n].h, false }; 912 949 open.push(t); 913 950 914 951 // Remember the heuristically best vertex we've seen so far, in case we never actually reach the target … … 920 957 } 921 958 else // must be OPEN 922 959 { 923 // If we've already seen this tile, and the new path to this tile does not have a924 // better cost, then stop now925 if (g >= vertexes[n].g)926 continue;927 960 928 // Otherwise, we have a better path, soreplace the old one with the new cost/parent961 // Since this new tile is a better path, replace the old one with the new cost/parent 929 962 fixed gprev = vertexes[n].g; 930 963 vertexes[n].g = g; 931 964 vertexes[n].pred = curr.id; … … 944 977 } 945 978 } 946 979 980 std::cout << totalExam << std::endl; 947 981 // Reconstruct the path (in reverse) 948 982 for (u16 id = idBest; id != START_VERTEX_ID; id = vertexes[id].pred) 949 983 path.m_Waypoints.emplace_back(Waypoint{ vertexes[id].p.X, vertexes[id].p.Y });