【问题标题】:Choosing a random point within a circular image in a UIImageView在 UIImageView 的圆形图像中选择一个随机点
【发布时间】:2016-07-25 19:47:14
【问题描述】:

我有一个带有色轮的应用程序,我正在尝试在色轮中选择一种随机颜色。但是,我在验证随机点是否在色轮内时遇到问题。

这是当前的代码:

CGPoint randomPoint = CGPointMake(arc4random() % (int)colorWheel.bounds.size.width, arc4random() % (int)colorWheel.bounds.size.height);
UIColor *randomColor = [self colorOfPoint:randomPoint];

CGPoint pointInView = [colorWheel convertPoint:randomPoint fromView:colorWheel.window];
if (CGRectContainsPoint(colorWheel.bounds, pointInView)) {
    NSLog(@"%@", randomColor);
}
else {
    NSLog(@"out of bounds");
}

我尝试过的验证点的其他几种方法都没有成功:

if (CGRectContainsPoint(colorWheel.frame, randomPoint)) {
 NSLog(@"%@", randomColor);
 }

if ([colorWheel pointInside:[self.view convertPoint:randomPoint toView: colorWheel] withEvent: nil]) {
    NSLog(@"%@", randomColor);
}

有时它会输出“超出范围”,有时它只会输出颜色为白色(色轮周围的背景当前为白色,但色轮图像中没有白色)。

色轮图像是一个圆圈,所以我不确定这是否会导致测试失败,尽管白色似乎过于频繁地弹出,以至于它只是图像周围的透明方形轮廓,呈现白色.

【问题讨论】:

  • 你的 colorWheel 是一个自定义的 UIView?那为什么不实现 func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) 并检查你的 colorWheel 的哪一块被触摸了?
  • @ReinierMelian 你发布了touchesBegan: 的Swift 版本。 OP 正在寻找一种 Objective-C 解决方案。可能会令人困惑。
  • @jsondwyer 你是对的,对不起这是objective-c版本- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
  • 我已经有办法触摸屏幕并得到点,想法是它随机生成点而不需要交互

标签: ios objective-c cocoa-touch uiview geometry


【解决方案1】:

如果您想在圆中生成一个随机点,最好在极坐标中选择您的点,然后将其转换为笛卡尔坐标。

极坐标空间使用两个维度,半径角度。半径只是到中心的距离,角度通常从“正东”开始为 0,逆时针旋转到 2π(以弧度为单位,当然是 360˚ 以度为单位)。

大概你的轮子被分成简单的楔子,所以半径实际上并不重要;你只需要选择一个随机的角度。

uint32_t angle = arc4random_uniform(360);
// Radius will just be halfway from the center to the edge.
// This assumes the circle is exactly enclosed, i.e., diameter == width
CGFloat radius = colorWheel.bounds.size.width / 4;

此功能将为您提供极坐标中的笛卡尔点。 Wikipedia explains the simple math如果你有兴趣。

/** Convert the polar point (radius, theta) to a Cartesian (x,y). */
CGPoint poltocar(CGFloat radius, CGFloat theta)
{
    return (CGPoint){radius * cos(theta), radius * sin(theta)};
}

函数用弧度表示theta,因为sin()cos()是这样,所以把角度换成弧度,然后就可以转换了:

CGFloat theta = (angle * M_PI) / 180.0
CGPoint randomPoint = poltocar(radius, theta);

最后一步:这个圆的原点与视图的原点在同一个地方,也就是在角落里,所以你需要平移这个点,以中心为原点。

CGPoint addPoints(CGPoint lhs, CGPoint rhs)
{
    return (CGPoint){lhs.x + rhs.x, lhs.y, rhs.y};
}

CGPoint offset = (CGPoint){colorWheel.bounds.size.width / 2,
                           colorWheel.bounds.size.height / 2};

randomPoint = addPoints(randomPoint, offset);

您的新randomPoint 将始终在圈内。

【讨论】:

  • 同意。仅供参考,添加了一个答案以纠正 OP 在笛卡尔空间中的方法。
  • 很高兴我能帮上忙,@lunadiviner。
【解决方案2】:

我同意@JoshCaswell 的方法,但仅供参考,OP 代码不起作用的原因是圆圈内的测试不正确。

坐标转换是不必要的,对矩形的测试肯定是错误的。相反,计算出随机点离中心有多远,并将其与半径进行比较。

CGFloat centerX = colorWheel.bounds.size.width / 2.0;
CGFloat centerY = colorWheel.bounds.size.height / 2.0;
CGFloat distanceX = centerX - randomPoint.x;
CGFloat distanceY = centerY - randomPoint.y;
CGFloat distance = distanceX*distanceX + distanceY*distanceY;

CGFloat radius = colorWheel.bounds.size.width / 2.0;  // just a guess
CGFloat r2 = radius*radius;

// this compares the square of the distance with r^2, to save a sqrt operation
BOOL isInCircle = distance < r2;

【讨论】:

    猜你喜欢
    • 2020-07-03
    • 2012-01-14
    • 2011-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多