9 QRectF addBBox(QRectF r1, QRectF r2)
11 // Find smallest QRectF containing given rectangles
15 if (r1.left() <= r2.left() )
16 n.setLeft(r1.left() );
18 n.setLeft(r2.left() );
21 if (r1.top() <= r2.top() )
27 if (r1.right() <= r2.right() )
28 n.setRight(r2.right() );
30 n.setRight(r1.right() );
33 if (r1.bottom() <= r2.bottom() )
34 n.setBottom(r2.bottom() );
36 n.setBottom(r1.bottom() );
40 bool isInBox(const QPointF &p, const QRectF &box)
42 if (p.x() >= box.left() && p.x() <= box.right()
43 && p.y() <= box.bottom() && p.y() >= box.top() )
48 QPointF normalize (const QPointF &p)
50 if (p==QPointF(0,0)) return p;
51 qreal l=sqrt ( p.x()*p.x() + p.y()*p.y() );
52 return QPointF (p.x()/l,p.y()/l);
55 // Dot product of two vectors
56 qreal dotProduct (const QPointF &a, const QPointF &b)
58 return a.x()*b.x() + a.y()*b.y();
62 /* Calculate the projection of a polygon on an axis
63 and returns it as a [min, max] interval
65 void ProjectPolygon(QPointF axis, QPolygonF polygon, qreal &min, qreal &max)
67 // To project a point on an axis use the dot product
69 qreal d = dotProduct(axis,polygon.at(0));
72 for (int i = 0; i < polygon.size(); i++) {
73 d= dotProduct (polygon.at(i),axis);
83 /* Calculate the signed distance between [minA, maxA] and [minB, maxB]
84 The distance will be negative if the intervals overlap
88 qreal intervalDistance(qreal minA, qreal maxA, qreal minB, qreal maxB) {
96 Check if polygon A is going to collide with polygon B.
97 The last parameter is the *relative* velocity
98 of the polygons (i.e. velocityA - velocityB)
101 PolygonCollisionResult PolygonCollision(QPolygonF polygonA,
102 QPolygonF polygonB, QPointF velocity) {
103 PolygonCollisionResult result;
104 result.intersect = true;
105 result.willIntersect = true;
107 int edgeCountA = polygonA.size();
108 int edgeCountB = polygonB.size();
109 qreal minIntervalDistance = 1000000000;
110 QPointF translationAxis;
114 for (int k=0; k<edgeCountA;k++)
115 cout <<polygonA.at(k);
117 for (int k=0; k<edgeCountB;k++)
118 cout <<polygonB.at(k);
121 // Loop through all the edges of both polygons
124 while (i<edgeCountA && j<edgeCountB)
128 if (i<edgeCountA - 1)
130 polygonA.at(i+1).x()-polygonA.at(i).x(),
131 polygonA.at(i+1).y()-polygonA.at(i).y());
134 polygonA.at(0).x()-polygonA.at(i).x(),
135 polygonA.at(0).y()-polygonA.at(i).y());
139 if (i < edgeCountB -1)
141 polygonB.at(j+1).x() - polygonA.at(i).x(),
142 polygonB.at(j+1).y() - polygonA.at(i).y());
145 polygonB.at(0).x() - polygonA.at(i).x(),
146 polygonB.at(0).y() - polygonA.at(i).y());
150 // ===== 1. Find if the polygons are currently intersecting =====
153 // Find the axis perpendicular to the current edge
155 QPointF axis (-edge.y(), edge.x());
156 axis=normalize(axis);
158 // Find the projection of the polygon on the current axis
160 qreal minA = 0; qreal minB = 0; qreal maxA = 0; qreal maxB = 0;
161 ProjectPolygon(axis, polygonA, minA, maxA);
162 ProjectPolygon(axis, polygonB, minB, maxB);
164 // Check if the polygon projections are currentlty intersecting
166 if (intervalDistance(minA, maxA, minB, maxB) > 0)
167 result.intersect = false;
169 result.intersect = true;
171 // ===== 2. Now find if the polygons *will* intersect =====
174 // Project the velocity on the current axis
176 qreal velocityProjection = dotProduct(axis,velocity);
178 // Get the projection of polygon A during the movement
180 if (velocityProjection < 0)
181 minA += velocityProjection;
183 maxA += velocityProjection;
186 // Do the same test as above for the new projection
188 qreal d = intervalDistance(minA, maxA, minB, maxB);
189 if (d > 0) result.willIntersect = false;
193 cout <<"minA="<<minA<<" ";
194 cout <<"maxA="<<maxA<<" ";
195 cout <<"minB="<<minB<<" ";
196 cout <<"maxB="<<maxB<<" ";
197 cout <<" d="<<d<<" ";
198 cout <<"minD="<<minIntervalDistance<<" ";
199 cout <<"axis="<<axis<<" ";
200 cout <<"int="<<result.intersect<<" ";
201 cout <<"wint="<<result.willIntersect<<" ";
202 //cout <<"velProj="<<velocityProjection<<" ";
207 if (result.intersect || result.willIntersect)
209 // Check if the current interval distance is the minimum one. If so
210 // store the interval distance and the current distance. This will
211 // be used to calculate the minimum translation vector
214 if (d < minIntervalDistance) {
215 minIntervalDistance = d;
216 translationAxis = axis;
217 cout << "tAxix="<<translationAxis<<endl;
219 //QPointF t = polygonA.Center - polygonB.Center;
220 QPointF t = polygonA.at(0) - polygonB.at(0);
221 if (dotProduct(t,translationAxis) < 0)
222 translationAxis = -translationAxis;
227 // The minimum translation vector
228 // can be used to push the polygons appart.
230 if (result.willIntersect)
231 result.minTranslation =
232 translationAxis * minIntervalDistance;
237 /* The function can be used this way:
238 QPointF polygonATranslation = new QPointF();
243 PolygonCollisionResult r = PolygonCollision(polygonA, polygonB, velocity);
246 // Move the polygon by its velocity, then move
247 // the polygons appart using the Minimum Translation Vector
248 polygonATranslation = velocity + r.minTranslation;
250 // Just move the polygon by its velocity
251 polygonATranslation = velocity;
253 polygonA.Offset(polygonATranslation);