geometry.cpp
author insilmaril
Fri, 01 Feb 2008 15:28:35 +0000
changeset 661 6a5e2c27f8a4
parent 656 53ef954e90b6
child 662 9abdd5e6c3dc
permissions -rw-r--r--
Added brasilian translation by Amadeu Júnior
     1 #include "geometry.h"
     2 
     3 #include <math.h>
     4 
     5 
     6 QRectF addBBox(QRectF r1, QRectF r2)
     7 {	
     8 	// Find smallest QRectF containing given rectangles
     9 
    10 	QRectF n;
    11 	// Set left border
    12 	if (r1.left() <= r2.left() )
    13 		n.setLeft(r1.left() );
    14 	else
    15 		n.setLeft(r2.left() );
    16 		
    17 	// Set top border		
    18 	if (r1.top() <= r2.top() )
    19 		n.setTop(r1.top() );
    20 	else
    21 		n.setTop(r2.top() );
    22 		
    23 	// Set right border
    24 	if (r1.right() <= r2.right() )
    25 		n.setRight(r2.right() );
    26 	else
    27 		n.setRight(r1.right() );
    28 		
    29 	// Set bottom 
    30 	if (r1.bottom() <= r2.bottom() )
    31 		n.setBottom(r2.bottom() );
    32 	else
    33 		n.setBottom(r1.bottom() );
    34 	return n;
    35 }
    36 
    37 bool inBox(const QPointF &p, const QRectF &box)
    38 {
    39     if (p.x() >= box.left() && p.x() <= box.right()  
    40 	&& p.y() <= box.bottom() && p.y() >= box.top() )
    41 		return true;
    42     return false;	
    43 }
    44 
    45 QPointF normalize (const QPointF &p)
    46 {
    47 	qreal n=sqrt ( p.x()*p.x() + p.y()*p.y() );
    48 	return QPointF (p.x()/n,p.y()/n);
    49 }
    50 
    51 // Dot product of two vectors
    52 qreal dotProduct (const QPointF &a, const QPointF &b)
    53 {
    54 	return a.x()*b.x() + a.y()*b.y();
    55 }
    56 
    57 // Structure that stores the results of the PolygonCollision function
    58 class PolygonCollisionResult {
    59 public:
    60     // Are the polygons going to intersect forward in time?
    61     bool WillIntersect;
    62 
    63     // Are the polygons currently intersecting?
    64     bool Intersect;
    65 
    66     // The translation to apply to the first polygon to push the polygons apart.
    67     QPointF MinimumTranslationVector;
    68 };
    69 
    70 
    71 /* Calculate the projection of a polygon on an axis
    72    and returns it as a [min, max] interval
    73 */
    74 void ProjectPolygon(QPointF axis, QPolygonF polygon, qreal &min, qreal &max) 
    75 {
    76     // To project a point on an axis use the dot product
    77 
    78     qreal d = dotProduct(axis,polygon.at(0));
    79     min = d;
    80     max = d;
    81     for (int i = 0; i < polygon.size(); i++) {
    82         d= dotProduct (polygon.at(i),axis);
    83         if (d < min) 
    84             min = d;
    85         else 
    86 		{
    87             if (d> max) max = d;
    88         }
    89     }
    90 }
    91 
    92 /* Calculate the signed distance between [minA, maxA] and [minB, maxB]
    93    The distance will be negative if the intervals overlap
    94 */
    95 
    96 
    97 qreal intervalDistance(qreal minA, qreal maxA, qreal minB, qreal maxB) {
    98     if (minA < minB) {
    99         return minB - maxA;
   100     } else {
   101         return minA - maxB;
   102     }
   103 }
   104 /*
   105  Check if polygon A is going to collide with polygon B.
   106  The last parameter is the *relative* velocity 
   107  of the polygons (i.e. velocityA - velocityB)
   108 
   109 */
   110 PolygonCollisionResult PolygonCollision(QPolygonF polygonA, 
   111                               QPolygonF polygonB, QPointF velocity) {
   112     PolygonCollisionResult result;
   113     result.Intersect = true;
   114     result.WillIntersect = true;
   115 
   116     int edgeCountA = polygonA.size();
   117     int edgeCountB = polygonB.size();
   118     qreal minIntervalDistance = 1000000000;
   119     QPointF translationAxis;
   120     QPointF edge;
   121 
   122     // Loop through all the edges of both polygons
   123 
   124     for (int i=0; i < edgeCountA + edgeCountB; i++) 
   125 	{
   126         if (i< edgeCountA) 
   127             edge = polygonA.at(i);
   128         else 
   129             edge = polygonB.at(i - edgeCountA);
   130 
   131         // ===== 1. Find if the polygons are currently intersecting =====
   132 
   133 
   134         // Find the axis perpendicular to the current edge
   135 
   136         QPointF axis (-edge.y(), edge.x());
   137         normalize(axis);
   138 
   139         // Find the projection of the polygon on the current axis
   140 
   141         qreal minA = 0; qreal minB = 0; qreal maxA = 0; qreal maxB = 0;
   142         ProjectPolygon(axis, polygonA, minA, maxA);
   143         ProjectPolygon(axis, polygonB, minB, maxB);
   144 
   145         // Check if the polygon projections are currentlty intersecting
   146 
   147         if (intervalDistance(minA, maxA, minB, maxB) > 0)\
   148             result.Intersect = false;
   149 
   150         // ===== 2. Now find if the polygons *will* intersect =====
   151 
   152 
   153         // Project the velocity on the current axis
   154 
   155         qreal velocityProjection = dotProduct(axis,velocity);
   156 
   157         // Get the projection of polygon A during the movement
   158 
   159         if (velocityProjection < 0) {
   160             minA += velocityProjection;
   161         } else {
   162             maxA += velocityProjection;
   163         }
   164 
   165         // Do the same test as above for the new projection
   166 
   167         qreal d = intervalDistance(minA, maxA, minB, maxB);
   168         if (d > 0) result.WillIntersect = false;
   169 
   170         // If the polygons are not intersecting and won't intersect, exit the loop
   171 
   172         if (!result.Intersect && !result.WillIntersect) break;
   173 
   174         // Check if the current interval distance is the minimum one. If so store
   175         // the interval distance and the current distance.
   176         // This will be used to calculate the minimum translation vector
   177 
   178         if (d<0) d=-d;
   179         if (d < minIntervalDistance) {
   180             minIntervalDistance = d;
   181             translationAxis = axis;
   182 
   183             //QPointF t = polygonA.Center - polygonB.Center;
   184             QPointF t = polygonA.at(0) - polygonB.at(0);
   185             if (dotProduct(t,translationAxis) < 0)
   186                 translationAxis = -translationAxis;
   187         }
   188     }
   189 
   190     // The minimum translation vector
   191     // can be used to push the polygons appart.
   192 
   193     if (result.WillIntersect)
   194         result.MinimumTranslationVector = 
   195                translationAxis * minIntervalDistance;
   196     
   197     return result;
   198 }
   199 
   200 /* The function can be used this way: 
   201    QPointF polygonATranslation = new QPointF();
   202 */   
   203 
   204 
   205 /*
   206 PolygonCollisionResult r = PolygonCollision(polygonA, polygonB, velocity);
   207 
   208 if (r.WillIntersect) 
   209   // Move the polygon by its velocity, then move
   210   // the polygons appart using the Minimum Translation Vector
   211   polygonATranslation = velocity + r.MinimumTranslationVector;
   212 else 
   213   // Just move the polygon by its velocity
   214   polygonATranslation = velocity;
   215 
   216 polygonA.Offset(polygonATranslation);
   217 
   218 */
   219 
   220