6 QRectF addBBox(QRectF r1, QRectF r2)
8 // Find smallest QRectF containing given rectangles
12 if (r1.left() <= r2.left() )
13 n.setLeft(r1.left() );
15 n.setLeft(r2.left() );
18 if (r1.top() <= r2.top() )
24 if (r1.right() <= r2.right() )
25 n.setRight(r2.right() );
27 n.setRight(r1.right() );
30 if (r1.bottom() <= r2.bottom() )
31 n.setBottom(r2.bottom() );
33 n.setBottom(r1.bottom() );
37 bool inBox(const QPointF &p, const QRectF &box)
39 if (p.x() >= box.left() && p.x() <= box.right()
40 && p.y() <= box.bottom() && p.y() >= box.top() )
45 QPointF normalize (const QPointF &p)
47 qreal n=sqrt ( p.x()*p.x() + p.y()*p.y() );
48 return QPointF (p.x()/n,p.y()/n);
51 // Dot product of two vectors
52 qreal dotProduct (const QPointF &a, const QPointF &b)
54 return a.x()*b.x() + a.y()*b.y();
57 // Structure that stores the results of the PolygonCollision function
58 class PolygonCollisionResult {
60 // Are the polygons going to intersect forward in time?
63 // Are the polygons currently intersecting?
66 // The translation to apply to the first polygon to push the polygons apart.
67 QPointF MinimumTranslationVector;
71 /* Calculate the projection of a polygon on an axis
72 and returns it as a [min, max] interval
74 void ProjectPolygon(QPointF axis, QPolygonF polygon, qreal &min, qreal &max)
76 // To project a point on an axis use the dot product
78 qreal d = dotProduct(axis,polygon.at(0));
81 for (int i = 0; i < polygon.size(); i++) {
82 d= dotProduct (polygon.at(i),axis);
92 /* Calculate the signed distance between [minA, maxA] and [minB, maxB]
93 The distance will be negative if the intervals overlap
97 qreal intervalDistance(qreal minA, qreal maxA, qreal minB, qreal maxB) {
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)
110 PolygonCollisionResult PolygonCollision(QPolygonF polygonA,
111 QPolygonF polygonB, QPointF velocity) {
112 PolygonCollisionResult result;
113 result.Intersect = true;
114 result.WillIntersect = true;
116 int edgeCountA = polygonA.size();
117 int edgeCountB = polygonB.size();
118 qreal minIntervalDistance = 1000000000;
119 QPointF translationAxis;
122 // Loop through all the edges of both polygons
124 for (int i=0; i < edgeCountA + edgeCountB; i++)
127 edge = polygonA.at(i);
129 edge = polygonB.at(i - edgeCountA);
131 // ===== 1. Find if the polygons are currently intersecting =====
134 // Find the axis perpendicular to the current edge
136 QPointF axis (-edge.y(), edge.x());
139 // Find the projection of the polygon on the current axis
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);
145 // Check if the polygon projections are currentlty intersecting
147 if (intervalDistance(minA, maxA, minB, maxB) > 0)\
148 result.Intersect = false;
150 // ===== 2. Now find if the polygons *will* intersect =====
153 // Project the velocity on the current axis
155 qreal velocityProjection = dotProduct(axis,velocity);
157 // Get the projection of polygon A during the movement
159 if (velocityProjection < 0) {
160 minA += velocityProjection;
162 maxA += velocityProjection;
165 // Do the same test as above for the new projection
167 qreal d = intervalDistance(minA, maxA, minB, maxB);
168 if (d > 0) result.WillIntersect = false;
170 // If the polygons are not intersecting and won't intersect, exit the loop
172 if (!result.Intersect && !result.WillIntersect) break;
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
179 if (d < minIntervalDistance) {
180 minIntervalDistance = d;
181 translationAxis = axis;
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;
190 // The minimum translation vector
191 // can be used to push the polygons appart.
193 if (result.WillIntersect)
194 result.MinimumTranslationVector =
195 translationAxis * minIntervalDistance;
200 /* The function can be used this way:
201 QPointF polygonATranslation = new QPointF();
206 PolygonCollisionResult r = PolygonCollision(polygonA, polygonB, velocity);
209 // Move the polygon by its velocity, then move
210 // the polygons appart using the Minimum Translation Vector
211 polygonATranslation = velocity + r.MinimumTranslationVector;
213 // Just move the polygon by its velocity
214 polygonATranslation = velocity;
216 polygonA.Offset(polygonATranslation);