var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
ctx.lineWidth=3;
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
var ray1={x:30,y:250,angle:-Math.PI/3.5};
var ray2={x:30,y:250,angle:-Math.PI/6};
var r={x:100,y:100,w:40,h:40};
ctx.strokeStyle='black';
ctx.strokeRect(r.x,r.y,r.w,r.h);
// this ray intersects the rect
drawRay(ray1,r);
// this ray doesn't intersect the rect
drawRay(ray2,r);
function drawRay(ray,rect){
var intersects=rayRectIntersect(ray,rect);
ctx.beginPath();
ctx.moveTo(ray.x,ray.y);
ctx.lineTo(ray.x+1000*Math.cos(ray.angle),ray.y+1000*Math.sin(ray.angle));
ctx.strokeStyle=(intersects)?'red':'green';
ctx.stroke();
}
function rayRectIntersect(ray,rect){
d0={x:rect.x,y:rect.y};
d1={x:rect.x+rect.w,y:rect.y+rect.h};
d2={x:rect.x,y:rect.y+rect.h};
d3={x:rect.x+rect.w,y:rect.y};
ray0={x:ray.x,y:ray.y};
ray1={x:ray.x+1000*Math.cos(ray.angle),y:ray.y+1000*Math.sin(ray.angle)};
var diag1Test=line2lineIntersection(ray0,ray1,d0,d1);
var diag2Test=line2lineIntersection(ray0,ray1,d2,d3);
return(diag1Test || diag2Test);
}
// Get interseting point of 2 line segments (if any)
// Attribution: http://paulbourke.net/geometry/pointlineplane/
function line2lineIntersection(p0,p1,p2,p3) {
var unknownA = (p3.x-p2.x) * (p0.y-p2.y) - (p3.y-p2.y) * (p0.x-p2.x);
var unknownB = (p1.x-p0.x) * (p0.y-p2.y) - (p1.y-p0.y) * (p0.x-p2.x);
var denominator = (p3.y-p2.y) * (p1.x-p0.x) - (p3.x-p2.x) * (p1.y-p0.y);
// Test if Coincident
// If the denominator and numerator for the ua and ub are 0
// then the two lines are coincident.
if(unknownA==0 && unknownB==0 && denominator==0){return(true);}
// Test if Parallel
// If the denominator for the equations for ua and ub is 0
// then the two lines are parallel.
if (denominator == 0) return false;
// If the intersection of line segments is required
// then it is only necessary to test if ua and ub lie between 0 and 1.
// Whichever one lies within that range then the corresponding
// line segment contains the intersection point.
// If both lie within the range of 0 to 1 then
// the intersection point is within both line segments.
unknownA /= denominator;
unknownB /= denominator;
var isIntersecting=(unknownA>=0 && unknownA<=1 && unknownB>=0 && unknownB<=1)
if(!isIntersecting){return(false);}
return({
x: p0.x + unknownA * (p1.x-p0.x),
y: p0.y + unknownA * (p1.y-p0.y)
});
}
body{ background-color: ivory; }
#canvas{border:1px solid red;}
<h4>Ray is red if intersecting, green if not</h4>
<canvas id="canvas" width=300 height=300></canvas>
@markE看我的编辑。 –
Upvote,简洁的工作! – markE
真的很不错! 我唯一缺少的是一个交叉点(OP没有要求这样做,但对于某些应用程序会很有趣),但我认为这是一个很好的快速预测方法。 –