I have to avoid intersections among some basic 2-D shapes, mainly rectangles. Other shapes are circles and triangles. For instance, in the picture below I am checking against rectangles intersection using the separating-axis test. The shape [A,B,C,D] will translate horizontally while the shape [E,F,G,H] is costrained and can only rotate about the origin (0,0):
To avoid shape intersection, now I am rotating the collider [E,F,G,H] until the check against intersection returns false. The pseudo-code looks like this:
var polygonA = [array of points...];
var intersect = false;
do {
var polygonB= [array of points...];
intersect = doPolygonsIntersect(polygonA, polygonB);
if(intersect) {
setRotationPolyB(currentRotationPolyB - 1degree);
}
} while(intersect);
I wonder if there is a faster method to compute the rotation angle without this time-consuming loop.
Here is a complete playground:
function rotP(pX, pY, oX, oY, d) {
var r = d*Math.PI/180,
x = Math.cos(r)*(pX-oX)-Math.sin(r)*(pY-oY)+oX,
y = Math.sin(r)*(pX-oX)+Math.cos(r)*(pY-oY)+oY;
return {X:x, Y:y};
}
function doPolygonsIntersect(a, b) {
var polygons=[a, b], nA=a.length, nB=b.length;
var minA, maxA, minB, maxB, k = 0;
do {
var poly = polygons[k], n = poly.length;
for(var i1=0; i1<n; i1++) {
var i2=(i1 + 1) % poly.length;
var p1=poly[i1], p2=poly[i2];
var normX = p2.y - p1.y, normY = p1.x - p2.x;
minA = +Infinity;
maxA = -Infinity;
for(var j=0; j<nA; j++) {
var projected = normX * a[j].x + normY * a[j].y;
if (projected < minA) minA = projected;
if (projected > maxA) maxA = projected;
}
minB = +Infinity;
maxB = -Infinity;
for(var j=0; j<nB; j++) {
var projected = normX * b[j].x + normY * b[j].y;
if (projected < minB) minB = projected;
if (projected > maxB) maxB = projected;
}
if (maxA < minB || maxB < minA) return false;
}
} while (k++ < 1);
return true;
}
function drawOccluder() {
var y=-2, w=3, h=1, p=[];
p.push(board.create('point',
[function(){return sO.Value()+w},function(){return y}],
{color:'red'}));
p.push(board.create('point',
[function(){return sO.Value()},function(){return y}],
{color:'red'}));
p.push(board.create('point',
[function(){return sO.Value()},function(){return y-h}],
{color:'red'}));
p.push(board.create('point',
[function(){return sO.Value() + w},function(){return y-h}],
{color:'red'}));
var poly = board.create('polygon', p, {hasInnerPoints:true});
return p;
}
function drawCollider() {
var x0=-2.5, y0=1, w=5, h=6, p=[];
var r=[{x:x0, y:y0},{x:x0+w, y:y0},{x:x0+w, y:y0-h},{x:x0, y:y0-h}];
p.push(board.create('point',
[function(){var v=sC.Value(); return rotP(r[0].x,r[0].y,0,0,v).X},
function(){var v=sC.Value(); return rotP(r[0].x,r[0].y,0,0,v).Y}],
{color:'green'}));
p.push(board.create('point',
[function(){var v=sC.Value(); return rotP(r[1].x,r[1].y,0,0,v).X},
function(){var v=sC.Value(); return rotP(r[1].x,r[1].y,0,0,v).Y}],
{color:'green'}));
p.push(board.create('point',
[function(){var v=sC.Value(); return rotP(r[2].x,r[2].y,0,0,v).X},
function(){var v=sC.Value(); return rotP(r[2].x,r[2].y,0,0,v).Y}],
{color:'green'}));
p.push(board.create('point',
[function(){var v=sC.Value(); return rotP(r[3].x,r[3].y,0,0,v).X},
function(){var v=sC.Value(); return rotP(r[3].x,r[3].y,0,0,v).Y}],
{color:'green'}));
var poly = board.create('polygon', p, {hasInnerPoints:true});
return p;
}
var board, sO, sC, pO, pC;
document.addEventListener('DOMContentLoaded', function(e) {
board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox:[-8.0,8.0,8.0,-8.0],axis:true});
board.suspendUpdate();
sO = board.create('slider', [[3.5, -6],[-3.5, -6],[3.5, 3.5, -3.5]]);
sC = board.create('slider', [[2.5, 6],[-2.5, 6],[0, 0, -180]]);
pO = drawOccluder();
pC = drawCollider();
board.unsuspendUpdate();
document.getElementById('slider').addEventListener('input', function (e) {
sO.setValue(this.value);
board.update();
var polyO = [{x:pO[0].X(),y:pO[0].Y()},{x:pO[1].X(),y:pO[1].Y()},{x:pO[2].X(),y:pO[2].Y()},{x:pO[3].X(),y:pO[3].Y()}];
var loop = 0, intersect = false;
do {
if(loop++ > 180) break;
var polyC = [{x:pC[0].X(),y:pC[0].Y()},{x:pC[1].X(),y:pC[1].Y()},{x:pC[2].X(),y:pC[2].Y()},{x:pC[3].X(),y:pC[3].Y()}];
intersect = doPolygonsIntersect(polyO, polyC);
if(intersect) {
sC.setValue(sC.Value()-1);
board.update();
}
} while (intersect);
});
})
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/jsxgraph/1.3.2/jsxgraph.css" />
<script type="text/javascript" charset="UTF-8" src="//cdnjs.cloudflare.com/ajax/libs/jsxgraph/1.3.2/jsxgraphcore.js"></script>
</head>
<body>
<input type="range" min="-3.5" max="3.5" value="3.5" step="0.01" id="slider">
<div id="jxgbox" class="jxgbox" style="width:560px; height:560px;"></div>
</body>
</html>

