How to Calculate a Random Cgpoint Which Does Not Touch a Uiview

Determining if UIView in array of UIView's overlap with each other at all, and then adjust position

Here's a quick option based on my comment above about moving the logic for comparing distance into creation of the random point:
This can be cleaned up, but I didn't want to fully rewrite it and used as much of your code as possible.

In the generateCirles function I only changed how you init your CircleView

func generateCircles() {
numberOfCircles = Int.random(in: 1..<50)

let circleWidth = CGFloat(25)
let circleHeight = circleWidth

for _ in 0..<numberOfCircles {
let circleView = CircleView(frame: CGRect(origin: getRandomPoint(), size: (CGSize(width: circleWidth, height: circleHeight))))
let number = Int.random(in: 0..<2)
if number == 1 {
circleView.mainColor = .yellow
} else {
circleView.mainColor = .blue
}

circles.append(circleView)
}
drawCircles()
}

In the getRandomPoint I added a check to see if the new point is a valid point based on your existing distance logic:

func getRandomPoint() -> CGPoint {
let viewMidX = self.circlesView.bounds.midX
let viewMidY = self.circlesView.bounds.midY

let xPosition = self.circlesView.frame.midX - viewMidX + CGFloat(arc4random_uniform(UInt32(viewMidX*2)))
let yPosition = self.circlesView.frame.midY - viewMidY + CGFloat(arc4random_uniform(UInt32(viewMidY*2)))
let point = CGPoint(x: xPosition, y: yPosition)

if !validatePoint(point) {
return getRandomPoint()
}
return point
}

func validatePoint(_ point: CGPoint) -> Bool {
for circle in circles {
if distance(circle.frame.origin, point) <= 25 {
return false
}
}
return true
}

And I removed all of your code from drawCircles that you posted.

Here's what it looks like with 300 circles: (I used the view frame as the circlesView frame, so that's why the circles are over lapping with the screen bounds) This shouldn't be an issue for you, as I assume your circlesView frame is set to be smaller.
Sample Image

Choosing a random point within a circular image in a UIImageView

If you want to generate a random point in a circle, you would do better to pick your point in polar coordinates and then convert it to Cartesian.

The polar coordinate space uses two dimesions, radius and angle. Radius is just the distance from the center, and angle usually starts at "due east" for 0, and goes around counter-clockwise up to 2π (that's in radians, 360˚ of course in degrees).

Presumably your wheel is divided into simple wedges, so the radius actually doesn't matter; you just need to pick a random angle.

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;

This function will give you a Cartesian point from your polar coordinates. Wikipedia explains the simple math if you're interested.

/** 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)};
}

The function uses radians for theta, because sin() and cos() do, so change the angle to radians, and then you can convert:

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

One last step: this circle has its origin at the same place as the view, that is, in the corner, so you need to translate the point to use the center as the origin.

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

And your new randomPoint will always be within the circle.

How to get random coordinates inside a swift UIView?

Your issue is with the line below

imageView.frame = self.view.convert(self.coinsView.frame, from: self.coinsView.superview!)

This line is setting the same frame of coinsView to imageView. And when you are trying to get random x and y points in the below code it will always return 0. because frame.size.width and imageView.bounds.size.width are same and same goes to height.

let x = randomInRange(lo: 0, hi: Int(frame.size.width - imageView.bounds.size.width))
let y = randomInRange(lo: 0, hi: Int(frame.size.height - imageView.bounds.size.height))

For better understanding add below line to your code to set imageView Frame, you need to set static frame to your image view initially.

imageView.frame = CGRect(x: 0, y: 0, width: 30, height: 30)

Make sure width and height should be smaller than the width and height of coinsView's width & height

Set Uibutton Random Position on UIView

1st, add buttons to an NSArray, only to make things easier:

NSArray *buttonArray = @[btn1,btn2,btn3,btn4,btn5];

Now, this code tries to Arrange them at random positions.

int xTemp, yTemp;
for (int i = 0; i < 5; i++) {
while (YES) {
xTemp = arc4random_uniform(view.frame.size.width - [buttonArray[i] frame].size.width);
yTemp = arc4random_uniform(view.frame.size.height - [buttonArray[i] frame].size.height);
if (![self positionx:xTemp y:yTemp intersectsAnyButtonTillIndex:i inButtonArray:buttonArray]) {
[AnimationView moveBubble:CGPointMake(xTemp, yTemp) duration:1 : buttonArray[i]];
break;
}
}
}

Implement this function somewhere too:

- (BOOL) positionx:(int)xTemp y:(int)yTemp intersectsAnyButtonTillIndex:(int)index inButtonArray:(NSArray *)buttonArray {
//Again please change the < to <= , I'm sorry, doing too many things at once.
for (int i = 0; i <= index; i++) {
CGRect frame = [buttonArray[i] frame];
//EDIT : In the logic earlier, I had wrongly done a minus where I should have done a plus.
if ((xTemp > frame.origin.x && xTemp < (frame.size.width + frame.origin.x)) && (yTemp > frame.origin.y && yTemp < (frame.size.height + frame.origin.y))) return YES;
}
return NO;

OK this is a workign soln., I hope, just added something to WolfLink's answer. Check This.

for (UIButton *button in buttonArray) {
button.frame = CGRectMake(arc4random_uniform(view.frame.size.width - button.frame.size.width), arc4random_uniform(view.frame.size.height - button.frame.size.height), button.frame.size.width, button.frame.size.height);
while ([self button:button intersectsButtonInArray:buttonArray]) {
button.frame = CGRectMake(arc4random_uniform(view.frame.size.width - button.frame.size.width), arc4random_uniform(view.frame.size.height - button.frame.size.height), button.frame.size.width, button.frame.size.height);
}

//another function
-(BOOL)button:(UIButton *)button intersectsButtonInArray:(NSArray *)array {
for (UIButton *testButton in array) {
if (CGRectIntersectsRect(button.frame, testButton.frame) && ![button isEqual:testButton]) {
return YES;
}
}
return NO;
}

UIView absolute screen point

So I ended up using UITapGestureRecognizer instead and calculating the position like this:

    CGPoint gestureViewLocation = [gesture locationInView:gesture.view];
CGPoint absoluteLocation = [gesture locationInView:self.parentViewController.view];
CGRect fromRect = CGRectMake(absoluteLocation.x-gestureViewLocation.x, //subtract to we get point relative to gesture view
absoluteLocation.y-gestureViewLocation.y, //subtract to we get point relative to gesture view
gesture.view.frame.size.width,
gesture.view.frame.size.height);


Related Topics



Leave a reply



Submit