Ticket #3588: geometry1.2.patch
File geometry1.2.patch, 11.1 KB (added by , 8 years ago) |
---|
-
source/simulation2/components/CCmpPathfinder_Vertex.cpp
diff --git a/source/simulation2/components/CCmpPathfinder_Vertex.cpp b/source/simulation2/components/CCmpPathfinder_Vertex.cpp index 5ab11b6..17d43a1 100644
a b 39 39 #include "simulation2/components/ICmpObstructionManager.h" 40 40 #include "simulation2/helpers/PriorityQueue.h" 41 41 #include "simulation2/helpers/Render.h" 42 #include "simulation2/helpers/Geometry.h" 42 43 43 44 /* Quadrant optimisation: 44 45 * (loosely based on GPG2 "Optimizing Points-of-Visibility Pathfinding") … … inline static bool CheckVisibilityTop(const CFixedVector2D& a, const CFixedVecto 289 290 return true; 290 291 } 291 292 293 // Unaligned squares are handled here. 294 inline static bool CheckVisibilitySquares(const CFixedVector2D& a, const CFixedVector2D& b, const std::vector<ICmpObstructionManager::ObstructionSquare> squares) 295 { 296 for (size_t i = 0; i < squares.size(); ++i) 297 { 298 const CFixedVector2D center = CFixedVector2D(squares[i].x, squares[i].z); 299 const CFixedVector2D halfSize = CFixedVector2D(squares[i].hw, squares[i].hh); 300 if (Geometry::TestRaySquare(a - center, b - center, squares[i].u, squares[i].v, halfSize)) 301 return false; 302 } 303 return true; 304 } 305 292 306 typedef PriorityQueueHeap<u16, fixed, fixed> VertexPriorityQueue; 293 307 294 308 /** … … static void AddTerrainEdges(std::vector<Edge>& edges, std::vector<Vertex>& verte 483 497 static void SplitAAEdges(const CFixedVector2D& a, 484 498 const std::vector<Edge>& edges, 485 499 const std::vector<Square>& squares, 486 std::vector<Edge>& edgesUnaligned,487 500 std::vector<EdgeAA>& edgesLeft, std::vector<EdgeAA>& edgesRight, 488 501 std::vector<EdgeAA>& edgesBottom, std::vector<EdgeAA>& edgesTop) 489 502 { … … static void SplitAAEdges(const CFixedVector2D& a, 536 549 edgesTop.emplace_back(EdgeAA{ edge.p0, edge.p1.X }); 537 550 } 538 551 } 539 else540 edgesUnaligned.push_back(edge);541 552 } 542 553 } 543 554 … … void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter, 648 659 entity_pos_t pathfindClearance = clearance; 649 660 650 661 // Convert each obstruction square into collision edges and search graph vertexes 662 std::vector<ICmpObstructionManager::ObstructionSquare> squaresUnaligned; 651 663 for (size_t i = 0; i < squares.size(); ++i) 652 664 { 653 665 CFixedVector2D center(squares[i].x, squares[i].z); … … void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter, 677 689 678 690 // Add the edges: 679 691 680 CFixedVector2D h0(squares[i].hw + pathfindClearance, squares[i].hh + pathfindClearance); 681 CFixedVector2D h1(squares[i].hw + pathfindClearance, -(squares[i].hh + pathfindClearance)); 692 if(aa) 693 { 694 CFixedVector2D h0(squares[i].hw + pathfindClearance, squares[i].hh + pathfindClearance); 695 CFixedVector2D h1(squares[i].hw + pathfindClearance, -(squares[i].hh + pathfindClearance)); 682 696 683 CFixedVector2D ev0(center.X - h0.Dot(u), center.Y + h0.Dot(v)); 684 CFixedVector2D ev1(center.X - h1.Dot(u), center.Y + h1.Dot(v)); 685 CFixedVector2D ev2(center.X + h0.Dot(u), center.Y - h0.Dot(v)); 686 CFixedVector2D ev3(center.X + h1.Dot(u), center.Y - h1.Dot(v)); 687 if (aa) 697 CFixedVector2D ev1(center.X - h1.Dot(u), center.Y + h1.Dot(v)); 698 CFixedVector2D ev3(center.X + h1.Dot(u), center.Y - h1.Dot(v)); 688 699 edgeSquares.emplace_back(Square{ ev1, ev3 }); 689 else690 {691 edges.emplace_back(Edge{ ev0, ev1 });692 edges.emplace_back(Edge{ ev1, ev2 });693 edges.emplace_back(Edge{ ev2, ev3 });694 edges.emplace_back(Edge{ ev3, ev0 });695 700 } 701 else 702 squaresUnaligned.push_back(squares[i]); 696 703 697 704 // TODO: should clip out vertexes and edges that are outside the range, 698 705 // to reduce the search space … … void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter, 771 778 xz.push_back(s.p0.Y.ToFloat()); 772 779 SimRender::ConstructLineOnGround(GetSimContext(), xz, m_DebugOverlayShortPathLines.back(), true); 773 780 } 781 // Render the unaligned squares 782 for (size_t i = 0; i < squaresUnaligned.size(); ++i) 783 { 784 m_DebugOverlayShortPathLines.push_back(SOverlayLine()); 785 m_DebugOverlayShortPathLines.back().m_Color = CColor(0, 1, 1, 1); 786 std::vector<float> xz; 787 ICmpObstructionManager::ObstructionSquare s = squaresUnaligned[i]; 788 CFixedVector2D h0(s.hw + clearance, s.hh + clearance); 789 CFixedVector2D h1(s.hw + clearance, -(s.hh + clearance)); 790 CFixedVector2D u = s.u; 791 CFixedVector2D v = s.v; 792 CFixedVector2D center = CFixedVector2D(s.x, s.z); 793 794 CFixedVector2D ev0(center.X - h0.Dot(u), center.Y + h0.Dot(v)); 795 CFixedVector2D ev1(center.X - h1.Dot(u), center.Y + h1.Dot(v)); 796 CFixedVector2D ev2(center.X + h0.Dot(u), center.Y - h0.Dot(v)); 797 CFixedVector2D ev3(center.X + h1.Dot(u), center.Y - h1.Dot(v)); 798 xz.push_back(ev0.X.ToFloat()); 799 xz.push_back(ev0.Y.ToFloat()); 800 xz.push_back(ev1.X.ToFloat()); 801 xz.push_back(ev1.Y.ToFloat()); 802 xz.push_back(ev2.X.ToFloat()); 803 xz.push_back(ev2.Y.ToFloat()); 804 xz.push_back(ev3.X.ToFloat()); 805 xz.push_back(ev3.Y.ToFloat()); 806 xz.push_back(ev0.X.ToFloat()); 807 xz.push_back(ev0.Y.ToFloat()); 808 SimRender::ConstructLineOnGround(GetSimContext(), xz, m_DebugOverlayShortPathLines.back(), true); 809 } 774 810 } 775 811 776 812 // Do an A* search over the vertex/visibility graph: … … void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter, 810 846 // since they're more likely to block the rays 811 847 std::sort(edgeSquares.begin(), edgeSquares.end(), SquareSort(vertexes[curr.id].p)); 812 848 813 std::vector<Edge> edgesUnaligned;814 849 std::vector<EdgeAA> edgesLeft; 815 850 std::vector<EdgeAA> edgesRight; 816 851 std::vector<EdgeAA> edgesBottom; 817 852 std::vector<EdgeAA> edgesTop; 818 SplitAAEdges(vertexes[curr.id].p, edges, edgeSquares, edges Unaligned, edgesLeft, edgesRight, edgesBottom, edgesTop);853 SplitAAEdges(vertexes[curr.id].p, edges, edgeSquares, edgesLeft, edgesRight, edgesBottom, edgesTop); 819 854 820 855 // Check the lines to every other vertex 821 856 for (size_t n = 0; n < vertexes.size(); ++n) … … void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter, 871 906 CheckVisibilityRight(vertexes[curr.id].p, npos, edgesRight) && 872 907 CheckVisibilityBottom(vertexes[curr.id].p, npos, edgesBottom) && 873 908 CheckVisibilityTop(vertexes[curr.id].p, npos, edgesTop) && 874 CheckVisibility (vertexes[curr.id].p, npos, edgesUnaligned);909 CheckVisibilitySquares(vertexes[curr.id].p, npos, squaresUnaligned); 875 910 876 911 /* 877 912 // 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..c6e1b6a 100644
a b 1 /* Copyright (C) 201 5Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … bool Geometry::TestRaySquare(const CFixedVector2D& a, const CFixedVector2D& b, c 196 196 /* 197 197 * We only consider collisions to be when the ray goes from outside to inside the shape (and possibly out again). 198 198 * 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: 203 201 * if the ray's bounding box is outside the square -> no collision 204 202 * if the whole square is on the same side of the ray -> no collision 205 203 * otherwise -> collision … … bool Geometry::TestRaySquare(const CFixedVector2D& a, const CFixedVector2D& b, c 218 216 fixed bu = b.Dot(u); 219 217 fixed bv = b.Dot(v); 220 218 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 inside223 224 219 if ((au < -hw && bu < -hw) || (au > hw && bu > hw) || (av < -hh && bv < -hh) || (av > hh && bv > hh)) 225 220 return false; // ab is entirely above/below/side the square 226 221 227 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; 222 // Check if all points are on one side of a->b. 223 // This can be simplified by using the following equivalence: 224 // (x +- y +- z) are all > 0 or all < 0 <=> |x| > |y| + |z| 225 // and the linearity of scalar products. 226 // Furthermore, we already computed 227 // u.Dot((b-a).Perpendicular()) = (u.Perpendicular()).Dot(b-a) = av - bv, v.Dot(...) similarly 228 // Also, a.Dot(a.Perpendicular()) = 0. 229 fixed s0 = a.Dot(b.Perpendicular()).Absolute(); 230 fixed s1 = (av - bv).Absolute().Multiply(hw) + (bu - au).Absolute().Multiply(hh); 231 return (s0 <= s1); 240 232 } 241 233 242 234 // Exactly like TestRaySquare with u=(1,0), v=(0,1) … … bool Geometry::TestRayAASquare(const CFixedVector2D& a, const CFixedVector2D& b, 248 240 if (-hw <= a.X && a.X <= hw && -hh <= a.Y && a.Y <= hh) 249 241 return false; // a is inside 250 242 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 inside253 254 243 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)) 255 244 return false; // ab is entirely above/below/side the square 256 245 257 246 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; 247 fixed s0 = a.Dot(abp).Absolute(); 248 fixed s1 = abp.X.Absolute().Multiply(hw) + abp.Y.Absolute().Multiply(hh); 249 return (s0 <= s1); 270 250 } 271 251 272 252 /** … … static bool SquareSAT(const CFixedVector2D& a, const CFixedVector2D& axis, const 279 259 fixed hh = halfSize.Y; 280 260 281 261 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()) 262 // We only check the "counterclockwisest" point. 263 // But first we check if the center is on the wrong side. 264 fixed s0 = p.Dot(a); 265 if (s0 >= fixed::Zero()) 285 266 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; 267 s0 += u.Dot(p).Absolute().Multiply(hw) + v.Dot(p).Absolute().Multiply(hh); 268 return (s0 >= fixed::Zero()); 292 269 } 293 270 294 271 bool Geometry::TestSquareSquare(