给定一个正方形(由x,y,宽度,高度描述)和一个角度(以弧度表示),我需要计算一个起始于正方形中心的矢量,并终止于与正方形边缘碰撞的点。给定的角度。
我真的对它碰撞的那一点感兴趣,所以如果能让计算更有效率,请告诉我。
这可以推广到矩形吗?一般多边形怎么样?
答案 0 :(得分:6)
矢量将为center + (cos(angle), sin(angle))*magnitude
。鉴于您想要将其与正方形相交,您需要确定幅度。您可以使用以下方格获得:
float abs_cos_angle= fabs(cos(angle));
float abs_sin_angle= fabs(sin(angle));
if (width/2/abs_cos_angle <= height/2/abs_sin_angle)
{
magnitude= fabs(width/2/abs_cos_angle);
}
else
{
magnitude= height/2/abs_sin_angle;
}
然而,cos(角度)或sin(角度)可能为零,因此您应该将其乘以得到:
float abs_cos_angle= fabs(cos(angle));
float abs_sin_angle= fabs(sin(angle));
if (width/2*abs_sin_angle <= height/2*abs_cos_angle)
{
magnitude= width/2/abs_cos_angle;
}
else
{
magnitude= height/2/abs_sin_angle;
}
你可以从中获得终点。
编辑:这是一个代码片段,您可以根据当前接受的答案进行验证:
double magnitude;
double abs_cos_angle= fabs(cos(angle));
double abs_sin_angle= fabs(sin(angle));
if (width/2*abs_sin_angle <= height/2*abs_cos_angle)
{
magnitude= width/2/abs_cos_angle;
}
else
{
magnitude= height/2/abs_sin_angle;
}
double check_x= x + cos(angle)*magnitude;
double check_y= y + sin(angle)*magnitude;
printf(" a = %d deg: x = %lf; y = %lf\n",(int)(angle/pi*180),check_x,check_y);
显然这适用于轴对齐的矩形。您可以通过查找测试向量与多边形中每条边之间最近的交点来执行类似的操作。 (你可以进一步优化,但这留给了读者。)
答案 1 :(得分:2)
编辑:矩形的正确解决方案。如果宽度或高度为零,它甚至不会崩溃! 语言:C ++。
tan(89.99999)感谢James Fassett测试我的代码。
#include <cstdio>
#include <math.h>
// declare nonstandard signum function
double sign(double x);
//define pi because I forgot where it's declared
double const pi = 3.14159;
//declare non-standard contangent function
double cot(double x);
int main()
{
for (double angle = 0.0 ; angle<2*pi; angle += 0.1){
//angle should be within [0, 2*pi) range
//x and y point to the _middle_ of the rectangle
double x = 0; double y = 0 ;
double width = 1, height = 4;
double base_angle = atan(height/width);
// the angle between rectangle diagonal and Ox axis
double px,py;
// Which side we're on?
bool left = (fabs(angle - pi) < base_angle);
bool right = (angle> 2*pi-base_angle || angle < base_angle);
bool top = (fabs(angle - pi/2) <= fabs(pi/2 - base_angle));
bool bottom = (fabs(angle - 3*pi/2) <= fabs(pi/2 - base_angle));
// The helper values used to adjust sides
int lr = (left?-1:0) + (right?1:0);
int tb = (bottom?-1:0) + (top?1:0);
if (lr) {
// we're on vertical edge of rectangle
px = x+width/2*lr;
py = y+width/2*tan(angle)*lr;
} else {
// we're on the horizontal edge or in the corner
px = x+height/2*cot(angle)*tb;
py = y+height/2*tb;
}
printf(" a = %d deg: x = %lf; y = %lf\n",(int)(angle/pi*180),px,py);
}
return 0;
}
// define nonstandard signum function
double sign(double x)
{
if (x<0) return -1;
if (x>0) return 1;
return 0;
}
//define non-standard contangent function
double cot(double x)
{
return tan(pi/2 - x);
}
答案 2 :(得分:0)
广义到矩形,如果a =来自水平增加计数器的矢量角度cloclkwise,则点坐标可以通过以下方式计算:
let dx = distance from center horizontally, and
dy = distance form the center vertically, then
dx = if (tan(a) == 0, then width/2, else Min( height / (2 * tan(a)), width/2)
dy = if ABS(a) == Pi/2 then height/2 else Min( (width/2) * tan(a)), height/2)
然后该点的坐标为:
px = (x+width/2) + dx for right quadrants (Pi/2 >= a >= - Pi/2);
= (x+width/2) - dx for left quadrants (Pi/2 <= a <= 3Pi/2)
py = (y+height/2) + dy for lower quadrants (Pi <= a <= 2Pi);
= (y+height/2) - dy for upper quadrants (0 <= a <= Pi);
答案 3 :(得分:0)
根据方形的宽度和高度,您可以确定方形的中心(x + .5w,y + .5h)。
从那里,您可以使用一些三角法来确定矢量线的长度:
tan(angle) = 0.5x / a
其中a =正方形中心与正方形边缘之间的距离。那么你的点是x = a,y =(高度)。
请保持温和,因为我已经使用了很多这样的数学已经有一段时间了! :-)
答案 4 :(得分:0)
编辑:现在还有另一个来自Pavel的工作实现(他很好地致力于调试他的解决方案)但我会把它留在这里作为另一种只适用于正方形的替代方案(Pavel的适用于矩形)。
private function calculatePointOnSquare(width:Number, angle:Number):Point
{
// simple angle wrapping
angle = (Math.PI*2 + angle) % (Math.PI*2);
// calculate a normalized vector from the centre
// of a square to the edge taking into account
// the eight possible quadrants
var myX:Number;
var myY:Number;
if(angle < Math.PI/4)
{
myX = 1;
myY = Math.tan(angle);
}
else if(angle < Math.PI/2)
{
myX = Math.tan(Math.PI/2 - angle);
myY = 1;
}
else if(angle < 3*Math.PI/4)
{
myX = -Math.tan(angle - Math.PI/2);
myY = 1;
}
else if(angle < Math.PI)
{
myX = -1;
myY = Math.tan(Math.PI - angle);
}
else if(angle < 5*Math.PI/4)
{
myX = -1;
myY = -Math.tan(angle - Math.PI);
}
else if(angle < 3*Math.PI/2)
{
myX = -Math.tan((3*Math.PI/2) - angle);
myY = -1;
}
else if(angle < 7*Math.PI/4)
{
myX = Math.tan(angle - (3*Math.PI/2));
myY = -1;
}
else
{
myX = 1;
myY = -Math.tan(Math.PI*2 - angle);
}
// scale and translate the vector
return new Point(
(myX * width/2) + width/2,
(myY * width/2) + width/2);
}