好吧,只为将来可能会偶然发现此问题的人准备..
这是我在 javascript (ES6) 中提出的。但是将其移植到其他语言应该很容易..
/**
* Calculate the intersection of the border of the given rectangle
* and a circular arc.
* @param {Object} rectangle Rectangle object with dimensions and position properties.
* @param {Object} arc Arc object with center and radius properties.
* @return {Object} Resulting intersection point, with x- and y-coordinates.
*/
calculateBorderPoint(rectangle, arc) {
// Clone the rectangle, because we don't want to mutate the original.
const a = Object.assign({}, rectangle.position);
// Treat center of circle as coordinate origin.
a.x -= arc.center.x;
a.y -= arc.center.y;
let points = [];
// Check east & west with possible x values
const possibleX = [
a.x - rectangle.dimensions.width / 2,
a.x + rectangle.dimensions.width / 2,
];
possibleX.forEach((x) => {
const ySquared = [
Math.sqrt(Math.pow(arc.radius, 2) - Math.pow(x, 2)),
-Math.sqrt(Math.pow(arc.radius, 2) - Math.pow(x, 2)),
];
// Check if the derived y value is in range of rectangle
ySquared.forEach((y) => {
if (y >= a.y - rectangle.dimensions.height / 2 &&
y <= a.y + rectangle.dimensions.height / 2) {
points.push({x, y});
}
});
});
// Check north & south with possible y values
const possibleY = [
a.y - rectangle.dimensions.height / 2,
a.y + rectangle.dimensions.height / 2,
];
possibleY.forEach((y) => {
const xSquared = [
Math.sqrt(Math.pow(arc.radius, 2) - Math.pow(y, 2)),
-Math.sqrt(Math.pow(arc.radius, 2) - Math.pow(y, 2)),
];
// Check if the derived x value is in range of rectangle
xSquared.forEach((x) => {
if (x >= a.x - rectangle.dimensions.width / 2 &&
x <= a.x + rectangle.dimensions.width / 2) {
points.push({x, y});
}
});
});
// At this point you will propably have multiple possible solutions,
// because the circle might intersect the rectangle at multiple points.
// You need to select the point, that makes most sense in your case.
// One solution would be to select the one closest to the other rectangle.
// Translate it back.
points[0].x += arc.center.x;
points[0].y += arc.center.y;
return points[0];
}
它不漂亮,但它有效。我很高兴听到任何建议..