II, An extended separation coordinate axis method for Collision ResponseIt is very useful to detect the intersection of polygon, but more things can be done. When the polygon intersect, I want to remove them to avoid their intersection. The method of separating the axis can be used very well in this case, but some additional work is required. The depth of the intersection must be returned, and the direction in which the polygon is separated by the open polygon. The combination of the intersection depth and direction is called MTD, or the minimum translation distance. This is the smallest Vector used to separate objects. To calculate MTD, we can use the Separation Axis. When an object is at the intersection, we can calculate the projection interval between two objects on each split axis. The two overlapping parts provide a push vector. You need to apply it to one of the objects so that the projection of the objects on the axis stops overlap.
"Push vector" you need to apply to a to push a, so that a and B can be separated. Obviously, an object cannot be pushed along a random axis. The candidate axis is the one with the smallest overlap between the two intervals projected on the axis. The push vector provides the minimum translation distance.
Bool intersect (polygon A, polygon B, vector & MTD) { // Potential separation axes. They get converted into push Vectors vector axis [32]; // Max of 16 vertices per Polygon Int inumaxis = 0; For (j = A. num_vertices-1, I = 0; I <A. num_vertices; j = I, I ++) { Vector E = A. vertex [I]-A. vertex [J]; Axis [inumaxis ++] = vector (-E. Y, E. X );
If (axisseparatepolygons (n, a, B )) Return false; } For (j = B. num_vertices-1, I = 0; I <B. num_vertices; j = I, I ++) { Vector E = B. vertex [I]-B. vertex [J]; Axis [inumaxis ++] = vector (-E. Y, E. X );
If (axisseparatepolygons (n, a, B )) Return false; }
// Find the MTD among all the separation Vectors MTD = findmtd (axis, inumaxis ); // Makes sure the push vector is pushing a away from B Vector d = A. Position-B. position; If (d dot MTD <0.0f) MTD =-MTD; Return true; } |
Bool axisseparatepolygons (vector & axis, polygon A, polygon B) { Float Mina, maxa; Float minb, maxb; Calculateinterval (axis, A, Mina, maxa ); Calculateinterval (axis, B, minb, maxb ); If (Mina> maxb | minb> maxa) Return true; // Find the interval overlap Float D0 = maxa-minb; Float d1 = maxb-mina; Float depth = (D0 <d1 )? D0: d1; // Convert the Separation Axis into a push vector (re-normalise // The axis and multiply by interval overlap) Float axis_length_squared = Axis dot axis; Axis * = depth/axis_length_squared; Return false; } |
Vector findmtd (vector * pushvectors, int inumvectors) { Vector MTD = pushvector [0]; Float mind2 = pushvector [0] dot pushvector [0]; For (INT I = 1; I <inumvectors; I ++) { Float D2 = pushvector [I] * pushvector [I]; If (D2 <mind2) { Mind2 = d2; MTD = pushvector [I]; } } Return MTD; } |
Once the MTD vector is obtained, you can use the following method to separate them.
A. postion + = MTD * 0.5f; B. Position-= MTD * 0.5f; |
Obviously, if object A is static, B will be pushed away by the complete MTD (B. Position-= MTD), and a will not be pushed away.