LCOV - code coverage report
Current view: top level - source/simulation2/helpers - Geometry.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 113 209 54.1 %
Date: 2023-01-19 00:18:29 Functions: 9 14 64.3 %

          Line data    Source code
       1             : /* Copyright (C) 2020 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "precompiled.h"
      19             : 
      20             : #include "Geometry.h"
      21             : 
      22             : namespace Geometry
      23             : {
      24             : 
      25             : // TODO: all of these things could be optimised quite easily
      26             : 
      27          13 : CFixedVector2D GetHalfBoundingBox(const CFixedVector2D& u, const CFixedVector2D& v, const CFixedVector2D& halfSize)
      28             : {
      29          65 :     return CFixedVector2D(
      30          39 :         u.X.Multiply(halfSize.X).Absolute() + v.X.Multiply(halfSize.Y).Absolute(),
      31          39 :         u.Y.Multiply(halfSize.X).Absolute() + v.Y.Multiply(halfSize.Y).Absolute()
      32          26 :     );
      33             : }
      34             : 
      35          76 : fixed DistanceToSquare(const CFixedVector2D& point, const CFixedVector2D& u, const CFixedVector2D& v, const CFixedVector2D& halfSize, bool countInsideAsZero)
      36             : {
      37             :     /*
      38             :      * Relative to its own coordinate system, we have a square like:
      39             :      *
      40             :      *  A  :    B    :  C
      41             :      *     :         :
      42             :      * - - ########### - -
      43             :      *     #         #
      44             :      *     # I       #
      45             :      *  D  #    0    #  E     v
      46             :      *     #         #        ^
      47             :      *     #         #        |
      48             :      * - - ########### - -      -->u
      49             :      *     :         :
      50             :      *  F  :    G    :  H
      51             :      *
      52             :      * where 0 is the center, u and v are unit axes,
      53             :      * and the square is hw*2 by hh*2 units in size.
      54             :      *
      55             :      * Points in the BIG regions should check distance to horizontal edges.
      56             :      * Points in the DIE regions should check distance to vertical edges.
      57             :      * Points in the ACFH regions should check distance to the corresponding corner.
      58             :      *
      59             :      * So we just need to check all of the regions to work out which calculations to apply.
      60             :      *
      61             :      */
      62             : 
      63             :     // By symmetry (taking absolute values), we work only in the 0-B-C-E quadrant
      64             :     // du, dv are the location of the point in the square's coordinate system
      65          76 :     fixed du = point.Dot(u).Absolute();
      66          76 :     fixed dv = point.Dot(v).Absolute();
      67             : 
      68          76 :     fixed hw = halfSize.X;
      69          76 :     fixed hh = halfSize.Y;
      70             : 
      71          76 :     if (du < hw) // regions B, I, G
      72             :     {
      73           7 :         if (dv < hh) // region I
      74           1 :             return countInsideAsZero ? fixed::Zero() : std::min(hw - du, hh - dv);
      75             :         else
      76           6 :             return dv - hh;
      77             :     }
      78          69 :     else if (dv < hh) // regions D, E
      79             :     {
      80          32 :         return du - hw; // vertical edges
      81             :     }
      82             :     else // regions A, C, F, H
      83             :     {
      84          37 :         CFixedVector2D distance(du - hw, dv - hh);
      85          37 :         return distance.Length();
      86             :     }
      87             : }
      88             : 
      89             : // Same as above except it does not use Length
      90             : // For explanations refer to DistanceToSquare
      91           0 : fixed DistanceToSquareSquared(const CFixedVector2D& point, const CFixedVector2D& u, const CFixedVector2D& v, const CFixedVector2D& halfSize, bool countInsideAsZero)
      92             : {
      93           0 :     fixed du = point.Dot(u).Absolute();
      94           0 :     fixed dv = point.Dot(v).Absolute();
      95             : 
      96           0 :     fixed hw = halfSize.X;
      97           0 :     fixed hh = halfSize.Y;
      98             : 
      99           0 :     if (du < hw) // regions B, I, G
     100             :     {
     101           0 :         if (dv < hh) // region I
     102           0 :             return countInsideAsZero ? fixed::Zero() : std::min((hw - du).Square(), (hh - dv).Square());
     103             :         else
     104           0 :             return (dv - hh).Square(); // horizontal edges
     105             :     }
     106           0 :     else if (dv < hh) // regions D, E
     107             :     {
     108           0 :         return (du - hw).Square(); // vertical edges
     109             :     }
     110             :     else // regions A, C, F, H
     111             :     {
     112           0 :         return (du - hw).Square() + (dv - hh).Square();
     113             :     }
     114             : }
     115             : 
     116           2 : CFixedVector2D NearestPointOnSquare(const CFixedVector2D& point, const CFixedVector2D& u, const CFixedVector2D& v, const CFixedVector2D& halfSize)
     117             : {
     118             :     /*
     119             :      * Relative to its own coordinate system, we have a square like:
     120             :      *
     121             :      *  A  :         :  C
     122             :      *     :         :
     123             :      * - - #### B #### - -
     124             :      *     #\       /#
     125             :      *     # \     / #
     126             :      *     D  --0--  E        v
     127             :      *     # /     \ #        ^
     128             :      *     #/       \#        |
     129             :      * - - #### G #### - -      -->u
     130             :      *     :         :
     131             :      *  F  :         :  H
     132             :      *
     133             :      * where 0 is the center, u and v are unit axes,
     134             :      * and the square is hw*2 by hh*2 units in size.
     135             :      *
     136             :      * Points in the BDEG regions are nearest to the corresponding edge.
     137             :      * Points in the ACFH regions are nearest to the corresponding corner.
     138             :      *
     139             :      * So we just need to check all of the regions to work out which calculations to apply.
     140             :      *
     141             :      */
     142             : 
     143             :     // du, dv are the location of the point in the square's coordinate system
     144           2 :     fixed du = point.Dot(u);
     145           2 :     fixed dv = point.Dot(v);
     146             : 
     147           2 :     fixed hw = halfSize.X;
     148           2 :     fixed hh = halfSize.Y;
     149             : 
     150           2 :     if (-hw < du && du < hw) // regions B, G; or regions D, E inside the square
     151             :     {
     152           1 :         if (-hh < dv && dv < hh && (du.Absolute() - hw).Absolute() < (dv.Absolute() - hh).Absolute()) // regions D, E
     153             :         {
     154           0 :             if (du >= fixed::Zero()) // E
     155           0 :                 return u.Multiply(hw) + v.Multiply(dv);
     156             :             else // D
     157           0 :                 return -u.Multiply(hw) + v.Multiply(dv);
     158             :         }
     159             :         else // B, G
     160             :         {
     161           1 :             if (dv >= fixed::Zero()) // B
     162           0 :                 return v.Multiply(hh) + u.Multiply(du);
     163             :             else // G
     164           1 :                 return -v.Multiply(hh) + u.Multiply(du);
     165             :         }
     166             :     }
     167           1 :     else if (-hh < dv && dv < hh) // regions D, E outside the square
     168             :     {
     169           0 :         if (du >= fixed::Zero()) // E
     170           0 :             return u.Multiply(hw) + v.Multiply(dv);
     171             :         else // D
     172           0 :             return -u.Multiply(hw) + v.Multiply(dv);
     173             :     }
     174             :     else // regions A, C, F, H
     175             :     {
     176           1 :         CFixedVector2D corner;
     177           1 :         if (du < fixed::Zero()) // A, F
     178           1 :             corner -= u.Multiply(hw);
     179             :         else // C, H
     180           0 :             corner += u.Multiply(hw);
     181           1 :         if (dv < fixed::Zero()) // F, H
     182           1 :             corner -= v.Multiply(hh);
     183             :         else // A, C
     184           0 :             corner += v.Multiply(hh);
     185             : 
     186           1 :         return corner;
     187             :     }
     188             : }
     189             : 
     190          18 : fixed DistanceSquareToSquare(const CFixedVector2D& relativePos, const CFixedVector2D& u1, const CFixedVector2D& v1, const CFixedVector2D& halfSize1, const CFixedVector2D& u2, const CFixedVector2D& v2, const CFixedVector2D& halfSize2)
     191             : {
     192             :     /*
     193             :      * The shortest distance between two non colliding squares equals the distance between a corner
     194             :      * and other square. Thus calculating all 8 those distances and taking the smallest.
     195             :      * For colliding squares we simply return 0. When one of the points is inside the other square
     196             :      * we depend on DistanceToSquare's countInsideAsZero. When no point is inside the other square,
     197             :      * it is enough to check that two adjacent edges of one square does not collide with the other square.
     198             :      */
     199          18 :     fixed hw1 = halfSize1.X;
     200          18 :     fixed hh1 = halfSize1.Y;
     201          18 :     fixed hw2 = halfSize2.X;
     202          18 :     fixed hh2 = halfSize2.Y;
     203          47 :     if (TestRaySquare(relativePos + u1.Multiply(hw1) + v1.Multiply(hh1), relativePos - u1.Multiply(hw1) + v1.Multiply(hh1), u2, v2, halfSize2) ||
     204          29 :         TestRaySquare(relativePos + u1.Multiply(hw1) + v1.Multiply(hh1), relativePos + u1.Multiply(hw1) - v1.Multiply(hh1), u2, v2, halfSize2))
     205           9 :         return fixed::Zero();
     206             : 
     207             :     return std::min(std::min(std::min(
     208          18 :             DistanceToSquare(relativePos + u1.Multiply(hw1) + v1.Multiply(hh1), u2, v2, halfSize2, true),
     209          18 :             DistanceToSquare(relativePos + u1.Multiply(hw1) - v1.Multiply(hh1), u2, v2, halfSize2, true)),
     210             :         std::min(
     211          18 :             DistanceToSquare(relativePos - u1.Multiply(hw1) + v1.Multiply(hh1), u2, v2, halfSize2, true),
     212          18 :             DistanceToSquare(relativePos - u1.Multiply(hw1) - v1.Multiply(hh1), u2, v2, halfSize2, true))),
     213             :         std::min(std::min(
     214          18 :             DistanceToSquare(relativePos + u2.Multiply(hw2) + v2.Multiply(hh2), u1, v1, halfSize1, true),
     215          18 :             DistanceToSquare(relativePos + u2.Multiply(hw2) - v2.Multiply(hh2), u1, v1, halfSize1, true)),
     216             :         std::min(
     217          18 :             DistanceToSquare(relativePos - u2.Multiply(hw2) + v2.Multiply(hh2), u1, v1, halfSize1, true),
     218          54 :             DistanceToSquare(relativePos - u2.Multiply(hw2) - v2.Multiply(hh2), u1, v1, halfSize1, true))));
     219             : }
     220             : 
     221          38 : fixed MaxDistanceToSquare(const CFixedVector2D& point, const CFixedVector2D& u, const CFixedVector2D& v, const CFixedVector2D& halfSize, bool countInsideAsZero)
     222             : {
     223          38 :     fixed hw = halfSize.X;
     224          38 :     fixed hh = halfSize.Y;
     225             : 
     226          38 :     if (point.Dot(u).Absolute() < hw && point.Dot(v).Absolute() < hh && countInsideAsZero)
     227           0 :         return fixed::Zero();
     228             : 
     229             :     /*
     230             :      * The maximum distance from a point to an edge of a square equals the greatest distance
     231             :      * from the point to the a corner. Thus calculating all and taking the greatest.
     232             :      */
     233             :     return std::max(std::max(
     234          76 :             (point + u.Multiply(hw) + v.Multiply(hh)).Length(),
     235          76 :             (point + u.Multiply(hw) - v.Multiply(hh)).Length()),
     236             :         std::max(
     237          76 :             (point - u.Multiply(hw) + v.Multiply(hh)).Length(),
     238         152 :             (point - u.Multiply(hw) - v.Multiply(hh)).Length()));
     239             : }
     240             : 
     241           9 : fixed MaxDistanceSquareToSquare(const CFixedVector2D& relativePos, const CFixedVector2D& u1, const CFixedVector2D& v1, const CFixedVector2D& halfSize1, const CFixedVector2D& u2, const CFixedVector2D& v2, const CFixedVector2D& halfSize2)
     242             : {
     243             :     /*
     244             :      * The maximum distance from an edge of a square to the edge of another square
     245             :      * equals the greatest distance from the any of the 16 corner corner distances.
     246             :     */
     247           9 :     fixed hw1 = halfSize1.X;
     248           9 :     fixed hh1 = halfSize1.Y;
     249             : 
     250             :     return std::max(std::max(
     251          18 :             MaxDistanceToSquare(relativePos + u1.Multiply(hw1) + v1.Multiply(hh1), u2, v2, halfSize2, true),
     252          18 :             MaxDistanceToSquare(relativePos + u1.Multiply(hw1) - v1.Multiply(hh1), u2, v2, halfSize2, true)),
     253          18 :         std::max(MaxDistanceToSquare(relativePos - u1.Multiply(hw1) + v1.Multiply(hh1), u2, v2, halfSize2, true),
     254          36 :             MaxDistanceToSquare(relativePos - u1.Multiply(hw1) - v1.Multiply(hh1), u2, v2, halfSize2, true)));
     255             : }
     256             : 
     257          29 : bool TestRaySquare(const CFixedVector2D& a, const CFixedVector2D& b, const CFixedVector2D& u, const CFixedVector2D& v, const CFixedVector2D& halfSize)
     258             : {
     259             :     /*
     260             :      * We only consider collisions to be when the ray goes from outside to inside the shape (and possibly out again).
     261             :      * Various cases to consider:
     262             :      *   'a' inside, 'b' inside -> no collision
     263             :      *   'a' inside, 'b' outside -> no collision
     264             :      *   'a' outside, 'b' inside -> collision
     265             :      *   'a' outside, 'b' outside -> depends; use separating axis theorem:
     266             :      *     if the ray's bounding box is outside the square -> no collision
     267             :      *     if the whole square is on the same side of the ray -> no collision
     268             :      *     otherwise -> collision
     269             :      * (Points on the edge are considered 'inside'.)
     270             :      */
     271             : 
     272          29 :     fixed hw = halfSize.X;
     273          29 :     fixed hh = halfSize.Y;
     274             : 
     275          29 :     fixed au = a.Dot(u);
     276          29 :     fixed av = a.Dot(v);
     277             : 
     278          29 :     if (-hw <= au && au <= hw && -hh <= av && av <= hh)
     279           2 :         return false; // a is inside
     280             : 
     281          27 :     fixed bu = b.Dot(u);
     282          27 :     fixed bv = b.Dot(v);
     283             : 
     284          27 :     if (-hw <= bu && bu <= hw && -hh <= bv && bv <= hh) // TODO: isn't this subsumed by the next checks?
     285           2 :         return true; // a is outside, b is inside
     286             : 
     287          25 :     if ((au < -hw && bu < -hw) || (au > hw && bu > hw) || (av < -hh && bv < -hh) || (av > hh && bv > hh))
     288          18 :         return false; // ab is entirely above/below/side the square
     289             : 
     290           7 :     CFixedVector2D abp = (b - a).Perpendicular();
     291           7 :     fixed s0 = abp.Dot((u.Multiply(hw) + v.Multiply(hh)) - a);
     292           7 :     fixed s1 = abp.Dot((u.Multiply(hw) - v.Multiply(hh)) - a);
     293           7 :     fixed s2 = abp.Dot((-u.Multiply(hw) - v.Multiply(hh)) - a);
     294           7 :     fixed s3 = abp.Dot((-u.Multiply(hw) + v.Multiply(hh)) - a);
     295           7 :     if (s0.IsZero() || s1.IsZero() || s2.IsZero() || s3.IsZero())
     296           7 :         return true; // ray intersects the corner
     297             : 
     298           0 :     bool sign = (s0 < fixed::Zero());
     299           0 :     if ((s1 < fixed::Zero()) != sign || (s2 < fixed::Zero()) != sign || (s3 < fixed::Zero()) != sign)
     300           0 :         return true; // ray cuts through the square
     301             : 
     302           0 :     return false;
     303             : }
     304             : 
     305             : // Exactly like TestRaySquare with u=(1,0), v=(0,1)
     306           0 : bool TestRayAASquare(const CFixedVector2D& a, const CFixedVector2D& b, const CFixedVector2D& halfSize)
     307             : {
     308           0 :     fixed hw = halfSize.X;
     309           0 :     fixed hh = halfSize.Y;
     310             : 
     311           0 :     if (-hw <= a.X && a.X <= hw && -hh <= a.Y && a.Y <= hh)
     312           0 :         return false; // a is inside
     313             : 
     314           0 :     if (-hw <= b.X && b.X <= hw && -hh <= b.Y && b.Y <= hh) // TODO: isn't this subsumed by the next checks?
     315           0 :         return true; // a is outside, b is inside
     316             : 
     317           0 :     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))
     318           0 :         return false; // ab is entirely above/below/side the square
     319             : 
     320           0 :     CFixedVector2D abp = (b - a).Perpendicular();
     321           0 :     fixed s0 = abp.Dot(CFixedVector2D(hw, hh) - a);
     322           0 :     fixed s1 = abp.Dot(CFixedVector2D(hw, -hh) - a);
     323           0 :     fixed s2 = abp.Dot(CFixedVector2D(-hw, -hh) - a);
     324           0 :     fixed s3 = abp.Dot(CFixedVector2D(-hw, hh) - a);
     325           0 :     if (s0.IsZero() || s1.IsZero() || s2.IsZero() || s3.IsZero())
     326           0 :         return true; // ray intersects the corner
     327             : 
     328           0 :     bool sign = (s0 < fixed::Zero());
     329           0 :     if ((s1 < fixed::Zero()) != sign || (s2 < fixed::Zero()) != sign || (s3 < fixed::Zero()) != sign)
     330           0 :         return true; // ray cuts through the square
     331             : 
     332           0 :     return false;
     333             : }
     334             : 
     335             : /**
     336             :  * Separating axis test; returns true if the square defined by u/v/halfSize at the origin
     337             :  * is not entirely on the clockwise side of a line in direction 'axis' passing through 'a'
     338             :  */
     339          37 : static bool SquareSAT(const CFixedVector2D& a, const CFixedVector2D& axis, const CFixedVector2D& u, const CFixedVector2D& v, const CFixedVector2D& halfSize)
     340             : {
     341          37 :     fixed hw = halfSize.X;
     342          37 :     fixed hh = halfSize.Y;
     343             : 
     344          37 :     CFixedVector2D p = axis.Perpendicular();
     345          37 :     if (p.RelativeOrientation(u.Multiply(hw) + v.Multiply(hh) - a) <= 0)
     346          25 :         return true;
     347          12 :     if (p.RelativeOrientation(u.Multiply(hw) - v.Multiply(hh) - a) <= 0)
     348           4 :         return true;
     349           8 :     if (p.RelativeOrientation(-u.Multiply(hw) - v.Multiply(hh) - a) <= 0)
     350           5 :         return true;
     351           3 :     if (p.RelativeOrientation(-u.Multiply(hw) + v.Multiply(hh) - a) <= 0)
     352           0 :         return true;
     353             : 
     354           3 :     return false;
     355             : }
     356             : 
     357           7 : bool TestSquareSquare(
     358             :         const CFixedVector2D& c0, const CFixedVector2D& u0, const CFixedVector2D& v0, const CFixedVector2D& halfSize0,
     359             :         const CFixedVector2D& c1, const CFixedVector2D& u1, const CFixedVector2D& v1, const CFixedVector2D& halfSize1)
     360             : {
     361             :     // TODO: need to test this carefully
     362             : 
     363           7 :     CFixedVector2D corner0a = c0 + u0.Multiply(halfSize0.X) + v0.Multiply(halfSize0.Y);
     364           7 :     CFixedVector2D corner0b = c0 - u0.Multiply(halfSize0.X) - v0.Multiply(halfSize0.Y);
     365           7 :     CFixedVector2D corner1a = c1 + u1.Multiply(halfSize1.X) + v1.Multiply(halfSize1.Y);
     366           7 :     CFixedVector2D corner1b = c1 - u1.Multiply(halfSize1.X) - v1.Multiply(halfSize1.Y);
     367             : 
     368             :     // Do a SAT test for each square vs each edge of the other square
     369           7 :     if (!SquareSAT(corner0a - c1, -u0, u1, v1, halfSize1))
     370           2 :         return false;
     371           5 :     if (!SquareSAT(corner0a - c1, v0, u1, v1, halfSize1))
     372           0 :         return false;
     373           5 :     if (!SquareSAT(corner0b - c1, u0, u1, v1, halfSize1))
     374           1 :         return false;
     375           4 :     if (!SquareSAT(corner0b - c1, -v0, u1, v1, halfSize1))
     376           0 :         return false;
     377           4 :     if (!SquareSAT(corner1a - c0, -u1, u0, v0, halfSize0))
     378           0 :         return false;
     379           4 :     if (!SquareSAT(corner1a - c0, v1, u0, v0, halfSize0))
     380           0 :         return false;
     381           4 :     if (!SquareSAT(corner1b - c0, u1, u0, v0, halfSize0))
     382           0 :         return false;
     383           4 :     if (!SquareSAT(corner1b - c0, -v1, u0, v0, halfSize0))
     384           0 :         return false;
     385             : 
     386           4 :     return true;
     387             : }
     388             : 
     389           0 : int GetPerimeterDistance(int x_max, int y_max, int x, int y)
     390             : {
     391           0 :     if (x_max <= 0 || y_max <= 0)
     392           0 :         return 0;
     393             : 
     394           0 :     int quarter = x_max + y_max;
     395           0 :     if (x == x_max && y >= 0)
     396           0 :         return y;
     397           0 :     if (y == y_max)
     398           0 :         return quarter - x;
     399           0 :     if (x == -x_max)
     400           0 :         return 2 * quarter - y;
     401           0 :     if (y == -y_max)
     402           0 :         return 3 * quarter + x;
     403           0 :     if (x == x_max)
     404           0 :         return 4 * quarter + y;
     405           0 :     return 0;
     406             : }
     407             : 
     408           0 : std::pair<int, int> GetPerimeterCoordinates(int x_max, int y_max, int k)
     409             : {
     410           0 :     if (x_max <= 0 || y_max <= 0)
     411           0 :         return std::pair<int, int>(0, 0);
     412             : 
     413           0 :     int quarter = x_max + y_max;
     414           0 :     k %= 4 * quarter;
     415           0 :     if (k < 0)
     416           0 :         k += 4 * quarter;
     417             : 
     418           0 :     if (k < y_max)
     419           0 :         return std::pair<int, int>(x_max, k);
     420           0 :     if (k < quarter + x_max)
     421           0 :         return std::pair<int, int>(quarter - k, y_max);
     422           0 :     if (k < 2 * quarter + y_max)
     423           0 :         return std::pair<int, int>(-x_max, 2 * quarter - k);
     424           0 :     if (k < 3 * quarter + x_max)
     425           0 :         return std::pair<int, int>(k - 3 * quarter, -y_max);
     426           0 :     return std::pair<int, int>(x_max, k - 4 * quarter);
     427             : }
     428             : 
     429           0 : fixed DistanceToSegment(
     430             :     const CFixedVector2D& point, const CFixedVector2D& a, const CFixedVector2D& b)
     431             : {
     432             :     // First we need to figure out from which part of the segment we should
     433             :     // calculate distance.
     434             :     // We split 2D space in three spaces:
     435             :     //               |                                |
     436             :     //             1 |                2               | 3
     437             :     //               A--------------------------------B
     438             :     // Here we need  | Between A and B we need to     | Here we need
     439             :     // distance to A | calculate distance to the line | distance to B
     440             :     //
     441           0 :     const CFixedVector2D dir = b - a;
     442             :     // We project the point, point A, and point B upon the direction of the
     443             :     // segment to figure out in which space the point is.
     444           0 :     const fixed pointDot = dir.Dot(point);
     445           0 :     const fixed aDot = dir.Dot(a);
     446             :     // The point is lying in space #1.
     447           0 :     if (pointDot <= aDot)
     448           0 :         return (point - a).Length();
     449           0 :     const fixed bDot = dir.Dot(b);
     450             :     // The point is lying in space #3.
     451           0 :     if (pointDot >= bDot)
     452           0 :         return (point - b).Length();
     453             :     // The point is lying in space #2.
     454           0 :     CFixedVector2D normal = dir.Perpendicular();
     455           0 :     normal.Normalize();
     456           0 :     return (normal.Dot(a) - normal.Dot(point)).Absolute();
     457             : }
     458             : 
     459             : } // namespace Geometry

Generated by: LCOV version 1.13