用于围绕中心质量创建圆形路径的算法?

时间:2011-07-12 17:23:38

标签: ios algorithm trigonometry cosine sine

我试图简单围绕中心点制作物体轨道,例如

Orbiting Objects

绿色和蓝色物体表示在旋转时应保持与中心点的距离的物体,基于我传入方法的角度。

我试图在objective-c中创建一个函数,但如果没有静态数字它就无法正常工作。例如(它围绕中心旋转,但不是从物体的真实起始点或距离旋转。)

-(void) rotateGear: (UIImageView*) view heading:(int)heading
{
    // int distanceX = 160 - view.frame.origin.x;
    // int distanceY = 240 - view.frame.origin.y;

    float x = 160 - view.image.size.width / 2 + (50 * cos(heading * (M_PI / 180)));
    float y = 240 - view.image.size.height / 2 + (50 * sin(heading * (M_PI / 180)));
    view.frame = CGRectMake(x, y, view.image.size.width, view.image.size.height);
}

我的魔术数字 160和240是我正在绘制图像的画布的中心。 50是一个静态数字(和问题),它允许函数部分正确地工作 - 不保持对象的起始位置或正确的距离。不幸的是,我不知道该放什么。

heading是一个传递度数的参数,从0到359.它由计时器计算,并在此类之外递增。

基本上我希望能够将任何图像放到我的画布上,并且根据图像的起点,它会围绕我的圆圈旋转。这意味着,如果我要在点(10,10)处放置图像,则使用(10,10)作为起点,到圆心的距离将持续存在。物体将围绕中心旋转360度,并达到它的原始起点。

预期的结果是将例如(10,10)传递给方法,基于零度,并在5度时退出(15,25)(不是真实的)。

我知道这很简单(而且这个问题描述完全是矫枉过正的),但是我会睁大眼睛试图弄明白我在哪里搞砸了。我不关心你使用的语言示例,如果有的话。我将能够破译你的意思。

失败更新

我已经走得更远,但我仍然无法得到正确的计算方法。我的新代码如下所示:

heading设置为1度。

-(void) rotateGear: (UIImageView*) view heading:(int)heading
{
    float y1 = view.frame.origin.y + (view.frame.size.height/2); // 152
    float x1 = view.frame.origin.x + (view.frame.size.width/2); // 140.5

    float radius = sqrtf(powf(160 - x1 ,2.0f) + powf(240 - y1, 2.0f)); // 90.13

    // I know that I need to calculate 90.13 pixels from my center, at 1 degree.      
    float x = 160 + radius * (cos(heading * (M_PI / 180.0f))); // 250.12
    float y = 240 + radius * (sin(heading * (M_PI / 180.0f))); // 241.57

    // The numbers are very skewed.
    view.frame = CGRectMake(x, y, view.image.size.width, view.image.size.height);
}

我得到的结果并非接近应该指向的位置。问题在于x和y的分配。我哪里错了?

4 个答案:

答案 0 :(得分:1)

您可以很容易地找到该点与中心的距离:

  

radius = sqrt((160 - x)^ 2 +(240 - y)^ 2)

其中(x,y)是对象中心的初始位置。然后只需用半径替换50。

http://en.wikipedia.org/wiki/Pythagorean_theorem


然后你可以使用三角法计算出初始角度(tan =相反/相邻,所以使用中心质量和轨道物体的中心绘制一个直角三角形来显示这个):

  

angle = arctan((y - 240)/(x - 160))

如果x> 160,或:

  

angle = arctan((y - 240)/(x - 160))+ 180

如果x< 160

http://en.wikipedia.org/wiki/Inverse_trigonometric_functions


编辑:记住我实际上并不知道任何Objective-C,但这基本上是我认为你应该做的(你应该能够很容易地将它转换为正确的Obj-C,这只是为了演示) :

// Your object gets created here somewhere

float x1 = view.frame.origin.x + (view.frame.size.width/2); // 140.5
float y1 = view.frame.origin.y + (view.frame.size.height/2); // 152

float radius = sqrtf(powf(160 - x1 ,2.0f) + powf(240 - y1, 2.0f)); // 90.13

// Calculate the initial angle here, as per the first part of my answer
float initialAngle = atan((y1 - 240) / (x1 - 160)) * 180.0f / M_PI;
if(x1 < 160)
    initialAngle += 180;

// Calculate the adjustment we need to add to heading
int adjustment = (int)(initialAngle - heading);

所以我们只执行一次上面的代码(当对象被创建时)。我们需要稍后记住radiusadjustment。然后我们改变rotateGear以取一个角度和一个半径作为输入而不是heading(无论如何这都更加灵活):

-(void) rotateGear: (UIImageView*) view radius:(float)radius angle:(int)angle
{
    float x = 160 + radius * (cos(angle * (M_PI / 180.0f)));
    float y = 240 + radius * (sin(angle * (M_PI / 180.0f)));

    // The numbers are very skewed.
    view.frame = CGRectMake(x, y, view.image.size.width, view.image.size.height);
}

每次我们想要更新头寸时,我们都会这样打电话:

[objectName rotateGear radius:radius angle:(adjustment + heading)];
顺便说一句,一旦你设法让这个工作,我强烈建议你转换所有的角度,这样你就可以一直使用弧度,它会让它更整洁/更容易理解!

答案 1 :(得分:1)

基于弧度,半径和中心点的圆上点的x和y坐标公式:

x = cos(angle) * radius + center_x
y = sin(angle) * radius + center_y

您可以使用HappyPixel的公式找到半径。

一旦你弄清楚了半径和中心点,你可以简单地改变angle来得到你想要的圆圈上的所有点。

答案 2 :(得分:0)

如果我理解正确,你想要InitObject(x,y).后跟UpdateObject(angle),其中角度从0扫到360.(但是使用弧度而不是数学的度数)
因此,您需要跟踪每个对象的角度和半径。:

InitObject(x,y)
    relative_x = x-center.x
    relative_y = y-center.y
    object.radius = sqrt((relative_x)^2, (relative_y)^2)
    object.initial_angle = atan(relative_y,relative_x);

并且

UpdateObject(angle)
    newangle = (object.initial_angle + angle) % (2*PI )
    object.x = cos(newangle) * object.radius + center.x
    object.y = sin(newangle) * object.radius + center.y

答案 3 :(得分:0)

dx=dropx-centerx; //target-source
dy=-(dropy-centery); //minus = invert screen coords to cartesian coords
radius=sqrt(dy*dy+dx*dx); //faster if your compiler optimizer is bad

if dx=0 then dx=0.000001; //hackpatchfudgenudge*
angle=atan(dy/dx); //set this as start angle for the angle-incrementer

然后使用你拥有的代码,你会没事的。你似乎每次从当前位置计算半径?与角度一样,当物体掉落时,应该只进行一次,否则半径可能不恒定。

* ,而不是处理dx = 0的3个特殊情况,如果你需要&lt;开始角度的1/100度精度与谷歌极地Arctan相反。