c语言 直线 交点 坐标,如何找到直线和矩形之间的交点?

/**

* Finds the intersection point between

*     * the rectangle

*       with parallel sides to the x and y axes

*     * the half-line pointing towards (x,y)

*       originating from the middle of the rectangle

*

* Note: the function works given min[XY] <= max[XY],

*       even though minY may not be the "top" of the rectangle

*       because the coordinate system is flipped.

* Note: if the input is inside the rectangle,

*       the line segment wouldn't have an intersection with the rectangle,

*       but the projected half-line does.

* Warning: passing in the middle of the rectangle will return the midpoint itself

*          there are infinitely many half-lines projected in all directions,

*          so let's just shortcut to midpoint (GIGO).

*

* @param x:Number x coordinate of point to build the half-line from

* @param y:Number y coordinate of point to build the half-line from

* @param minX:Number the "left" side of the rectangle

* @param minY:Number the "top" side of the rectangle

* @param maxX:Number the "right" side of the rectangle

* @param maxY:Number the "bottom" side of the rectangle

* @param validate:boolean (optional) whether to treat point inside the rect as error

* @return an object with x and y members for the intersection

* @throws if validate == true and (x,y) is inside the rectangle

* @author TWiStErRob

* @licence Dual CC0/WTFPL/Unlicence, whatever floats your boat

* @see source

* @see based on

*/function pointOnRect(x, y, minX, minY, maxX, maxY, validate) {

//assert minX <= maxX;

//assert minY <= maxY;

if (validate && (minX 

throw "Point " + [x,y] + "cannot be inside "

+ "the rectangle: " + [minX, minY] + " - " + [maxX, maxY] + ".";

var midX = (minX + maxX) / 2;

var midY = (minY + maxY) / 2;

// if (midX - x == 0) -> m == ±Inf -> minYx/maxYx == x (because value / ±Inf = ±0)

var m = (midY - y) / (midX - x);

if (x <= midX) { // check "left" side

var minXy = m * (minX - x) + y;

if (minY <= minXy && minXy <= maxY)

return {x: minX, y: minXy};

}

if (x >= midX) { // check "right" side

var maxXy = m * (maxX - x) + y;

if (minY <= maxXy && maxXy <= maxY)

return {x: maxX, y: maxXy};

}

if (y <= midY) { // check "top" side

var minYx = (minY - y) / m + x;

if (minX <= minYx && minYx <= maxX)

return {x: minYx, y: minY};

}

if (y >= midY) { // check "bottom" side

var maxYx = (maxY - y) / m + x;

if (minX <= maxYx && maxYx <= maxX)

return {x: maxYx, y: maxY};

}

// edge case when finding midpoint intersection: m = 0/0 = NaN

if (x === midX && y === midY) return {x: x, y: y};

// Should never happen :) If it does, please tell me!

throw "Cannot find intersection for " + [x,y]

+ " inside rectangle " + [minX, minY] + " - " + [maxX, maxY] + ".";}(function tests() {

var left = 100, right = 200, top = 50, bottom = 150; // a square, really

var hMiddle = (left + right) / 2, vMiddle = (top + bottom) / 2;

function intersectTestRect(x, y) { return pointOnRect(x,y, left,top, right,bottom, true); }

function intersectTestRectNoValidation(x, y) { return pointOnRect(x,y, left,top, right,bottom, false); }

function checkTestRect(x, y) { return function() { return pointOnRect(x,y, left,top, right,bottom, true); }; }

QUnit.test("intersects left side", function(assert) {

var leftOfRect = 0, closerLeftOfRect = 25;

assert.deepEqual(intersectTestRect(leftOfRect, 25), {x:left, y:75}, "point above top");

assert.deepEqual(intersectTestRect(closerLeftOfRect, top), {x:left, y:80}, "point in line with top");

assert.deepEqual(intersectTestRect(leftOfRect, 70), {x:left, y:90}, "point above middle");

assert.deepEqual(intersectTestRect(leftOfRect, vMiddle), {x:left, y:100}, "point exact middle");

assert.deepEqual(intersectTestRect(leftOfRect, 130), {x:left, y:110}, "point below middle");

assert.deepEqual(intersectTestRect(closerLeftOfRect, bottom), {x:left, y:120}, "point in line with bottom");

assert.deepEqual(intersectTestRect(leftOfRect, 175), {x:left, y:125}, "point below bottom");

});

QUnit.test("intersects right side", function(assert) {

var rightOfRect = 300, closerRightOfRect = 250;

assert.deepEqual(intersectTestRect(rightOfRect, 25), {x:right, y:75}, "point above top");

assert.deepEqual(intersectTestRect(closerRightOfRect, top), {x:right, y:75}, "point in line with top");

assert.deepEqual(intersectTestRect(rightOfRect, 70), {x:right, y:90}, "point above middle");

assert.deepEqual(intersectTestRect(rightOfRect, vMiddle), {x:right, y:100}, "point exact middle");

assert.deepEqual(intersectTestRect(rightOfRect, 130), {x:right, y:110}, "point below middle");

assert.deepEqual(intersectTestRect(closerRightOfRect, bottom), {x:right, y:125}, "point in line with bottom");

assert.deepEqual(intersectTestRect(rightOfRect, 175), {x:right, y:125}, "point below bottom");

});

QUnit.test("intersects top side", function(assert) {

var aboveRect = 0;

assert.deepEqual(intersectTestRect(80, aboveRect), {x:115, y:top}, "point left of left");

assert.deepEqual(intersectTestRect(left, aboveRect), {x:125, y:top}, "point in line with left");

assert.deepEqual(intersectTestRect(120, aboveRect), {x:135, y:top}, "point left of middle");

assert.deepEqual(intersectTestRect(hMiddle, aboveRect), {x:150, y:top}, "point exact middle");

assert.deepEqual(intersectTestRect(180, aboveRect), {x:165, y:top}, "point right of middle");

assert.deepEqual(intersectTestRect(right, aboveRect), {x:175, y:top}, "point in line with right");

assert.deepEqual(intersectTestRect(220, aboveRect), {x:185, y:top}, "point right of right");

});

QUnit.test("intersects bottom side", function(assert) {

var belowRect = 200;

assert.deepEqual(intersectTestRect(80, belowRect), {x:115, y:bottom}, "point left of left");

assert.deepEqual(intersectTestRect(left, belowRect), {x:125, y:bottom}, "point in line with left");

assert.deepEqual(intersectTestRect(120, belowRect), {x:135, y:bottom}, "point left of middle");

assert.deepEqual(intersectTestRect(hMiddle, belowRect), {x:150, y:bottom}, "point exact middle");

assert.deepEqual(intersectTestRect(180, belowRect), {x:165, y:bottom}, "point right of middle");

assert.deepEqual(intersectTestRect(right, belowRect), {x:175, y:bottom}, "point in line with right");

assert.deepEqual(intersectTestRect(220, belowRect), {x:185, y:bottom}, "point right of right");

});

QUnit.test("intersects a corner", function(assert) {

assert.deepEqual(intersectTestRect(left-50, top-50), {x:left, y:top}, "intersection line aligned with top-left corner");

assert.deepEqual(intersectTestRect(right+50, top-50), {x:right, y:top}, "intersection line aligned with top-right corner");

assert.deepEqual(intersectTestRect(left-50, bottom+50), {x:left, y:bottom}, "intersection line aligned with bottom-left corner");

assert.deepEqual(intersectTestRect(right+50, bottom+50), {x:right, y:bottom}, "intersection line aligned with bottom-right corner");

});

QUnit.test("on the corners", function(assert) {

assert.deepEqual(intersectTestRect(left, top), {x:left, y:top}, "top-left corner");

assert.deepEqual(intersectTestRect(right, top), {x:right, y:top}, "top-right corner");

assert.deepEqual(intersectTestRect(right, bottom), {x:right, y:bottom}, "bottom-right corner");

assert.deepEqual(intersectTestRect(left, bottom), {x:left, y:bottom}, "bottom-left corner");

});

QUnit.test("on the edges", function(assert) {

assert.deepEqual(intersectTestRect(hMiddle, top), {x:hMiddle, y:top}, "top edge");

assert.deepEqual(intersectTestRect(right, vMiddle), {x:right, y:vMiddle}, "right edge");

assert.deepEqual(intersectTestRect(hMiddle, bottom), {x:hMiddle, y:bottom}, "bottom edge");

assert.deepEqual(intersectTestRect(left, vMiddle), {x:left, y:vMiddle}, "left edge");

});

QUnit.test("validates inputs", function(assert) {

assert.throws(checkTestRect(hMiddle, vMiddle), /cannot be inside/, "center");

assert.throws(checkTestRect(hMiddle-10, vMiddle-10), /cannot be inside/, "top left of center");

assert.throws(checkTestRect(hMiddle-10, vMiddle), /cannot be inside/, "left of center");

assert.throws(checkTestRect(hMiddle-10, vMiddle+10), /cannot be inside/, "bottom left of center");

assert.throws(checkTestRect(hMiddle, vMiddle-10), /cannot be inside/, "above center");

assert.throws(checkTestRect(hMiddle, vMiddle), /cannot be inside/, "center");

assert.throws(checkTestRect(hMiddle, vMiddle+10), /cannot be inside/, "below center");

assert.throws(checkTestRect(hMiddle+10, vMiddle-10), /cannot be inside/, "top right of center");

assert.throws(checkTestRect(hMiddle+10, vMiddle), /cannot be inside/, "right of center");

assert.throws(checkTestRect(hMiddle+10, vMiddle+10), /cannot be inside/, "bottom right of center");

assert.throws(checkTestRect(left+10, vMiddle-10), /cannot be inside/, "right of left edge");

assert.throws(checkTestRect(left+10, vMiddle), /cannot be inside/, "right of left edge");

assert.throws(checkTestRect(left+10, vMiddle+10), /cannot be inside/, "right of left edge");

assert.throws(checkTestRect(right-10, vMiddle-10), /cannot be inside/, "left of right edge");

assert.throws(checkTestRect(right-10, vMiddle), /cannot be inside/, "left of right edge");

assert.throws(checkTestRect(right-10, vMiddle+10), /cannot be inside/, "left of right edge");

assert.throws(checkTestRect(hMiddle-10, top+10), /cannot be inside/, "below top edge");

assert.throws(checkTestRect(hMiddle, top+10), /cannot be inside/, "below top edge");

assert.throws(checkTestRect(hMiddle+10, top+10), /cannot be inside/, "below top edge");

assert.throws(checkTestRect(hMiddle-10, bottom-10), /cannot be inside/, "above bottom edge");

assert.throws(checkTestRect(hMiddle, bottom-10), /cannot be inside/, "above bottom edge");

assert.throws(checkTestRect(hMiddle+10, bottom-10), /cannot be inside/, "above bottom edge");

});

QUnit.test("doesn't validate inputs", function(assert) {

assert.deepEqual(intersectTestRectNoValidation(hMiddle-10, vMiddle-10), {x:left, y:top}, "top left of center");

assert.deepEqual(intersectTestRectNoValidation(hMiddle-10, vMiddle), {x:left, y:vMiddle}, "left of center");

assert.deepEqual(intersectTestRectNoValidation(hMiddle-10, vMiddle+10), {x:left, y:bottom}, "bottom left of center");

assert.deepEqual(intersectTestRectNoValidation(hMiddle, vMiddle-10), {x:hMiddle, y:top}, "above center");

assert.deepEqual(intersectTestRectNoValidation(hMiddle, vMiddle), {x:hMiddle, y:vMiddle}, "center");

assert.deepEqual(intersectTestRectNoValidation(hMiddle, vMiddle+10), {x:hMiddle, y:bottom}, "below center");

assert.deepEqual(intersectTestRectNoValidation(hMiddle+10, vMiddle-10), {x:right, y:top}, "top right of center");

assert.deepEqual(intersectTestRectNoValidation(hMiddle+10, vMiddle), {x:right, y:vMiddle}, "right of center");

assert.deepEqual(intersectTestRectNoValidation(hMiddle+10, vMiddle+10), {x:right, y:bottom}, "bottom right of center");

});})();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值