根据半径计算从正方形中心到边缘的矢量

发布于 2024-08-02 22:53:42 字数 155 浏览 6 评论 0原文

给定一个正方形(由 x、y、宽度、高度描述)和一个角度(以弧度为单位),我需要计算一个向量,该向量源自正方形中心并终止于以给定角度与正方形边缘碰撞的点。

我真的对它的碰撞点最感兴趣,所以如果这会使计算更有效,请告诉我。

这可以推广到矩形吗?一般而言,多边形怎么样?

Given a square (described by x, y, width, height) and an angle (in radians) I need to calculate a vector that originates at the squares centre and terminates at the point that collides with the edge of the square at the given angle.

I'm really most interested in the point it collides at so if that would make calculation more efficient let me know.

Can this be generalized to Rectangles? How about polygons in general?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

紧拥背影 2024-08-09 22:53:42

该向量将为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);

显然,这适用于轴对齐的矩形。您可以通过查找测试向量与多边形中每条边之间最近的交点来执行类似的操作。 (您可以进一步优化,但这留给读者作为练习。)

The vector will be center + (cos(angle), sin(angle))*magnitude. Given that you want to intersect this with a square, you need to determine magnitude. You can get that with a square with:

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;
}

However, cos(angle) or sin(angle) could be zero, so you should cross multiply that out to get:

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;
}

And you can trivially get the end point from that.

EDIT: Here's a snippet you can drop in place to verify this works with the currently accepted answer:

    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);

Clearly this is applies to an axis aligned rectangle. You can do something similar by finding the closest intersection between the testing vector and every edge in a polygon. (You can optimize that further, but that's left as an exercise to the reader.)

羁绊已千年 2024-08-09 22:53:42

编辑:矩形的正确解决方案。如果宽度或高度为零,它甚至不会崩溃!
语言: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);
}

EDIT: the correct solution for rectangles. It even does not crash if width or height are zeros!
Language: C++.

tan(89.99999) thanks to James Fassett for testing my code.

#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);
}
浅语花开 2024-08-09 22:53:42

编辑: 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);
}

Edit: There is another working implementation from Pavel now (good dedication from him to put in effort debugging his solution) but I'll leave this here as another alternative that works only for squares (Pavel's works for Rectangles).

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);
}
失去的东西太少 2024-08-09 22:53:42

给定正方形的宽度和高度,您就可以确定正方形的中心 (x+.5w, y+.5h)。

从这里,您可以使用一些三角函数来确定矢量线的长度:

tan(angle) = 0.5x / a

其中 a = 正方形中心与正方形边缘之间的距离。那么你的点就是 x = a, y = (高度)。

请温柔一些,因为我已经有一段时间没有大量使用这些数学了! :-)

Given the square's width and height you can then determine the center of the square (x+.5w, y+.5h).

From there, you can use some trigonometry to determine the length of the vector line:

tan(angle) = 0.5x / a

where a = the distance between the center of the square and the edge of the square. Your points are then x = a, y = (height).

Please be gentle, as it has been some time since I've used a lot of this math! :-)

离旧人 2024-08-09 22:53:42

推广到矩形,如果 a = 向量与水平方向顺时针递增的角度,则可以通过以下方式计算点坐标:

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);

Generalized to rectangles, if a = the angle of vector from the horizontal increasing counter cloclkwise, then the points coordinates can be calculated by the following:

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)

Then coordinates of the point are:

   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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文