Ticket #3588: geometry1.patch

File geometry1.patch, 4.8 KB (added by fsincos, 8 years ago)

Small geometry cleanup to enable further optimizations.

  • 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) 2015 Wildfire Games.
     1/* Copyright (C) 2016 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
    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
    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);
    240232}
    241233
    242234// Exactly like TestRaySquare with u=(1,0), v=(0,1)
    bool Geometry::TestRayAASquare(const CFixedVector2D& a, const CFixedVector2D& b,  
    248240    if (-hw <= a.X && a.X <= hw && -hh <= a.Y && a.Y <= hh)
    249241        return false; // a is inside
    250242
    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 
    254243    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))
    255244        return false; // ab is entirely above/below/side the square
    256245
    257246    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);
    270250}
    271251
    272252/**
    static bool SquareSAT(const CFixedVector2D& a, const CFixedVector2D& axis, const  
    279259    fixed hh = halfSize.Y;
    280260
    281261    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())
    285266        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());
    292269}
    293270
    294271bool Geometry::TestSquareSquare(