AppyMike
AppyMike

Reputation: 2064

Check view is completely covered by other views

I have a UIView that I have adjusted its layer to make it appear as a circle. (view.layer.cornerRadius = view.frame.size.height/2)

There is also n other smaller circles created this way.

The aim of the user is to completely cover the first circle with the smaller circles by dragging and dropping them over the circle.

How can I check that the large circle has been completely covered?

I have looked at this question Determine whether UIView is covered by other views? but I am unsure of how to obtain the UIBezierPath of the views layer.

Any help is appreciated, Thanks!

Upvotes: 10

Views: 689

Answers (3)

k06a
k06a

Reputation: 18745

You can construct accumulatedPath with this answer Determine whether UIView is covered by other views? using this method:

+ (UIBezierPath *)bezierPathWithOvalInRect:(CGRect)rect

Then you can enumerate some points on you view circle and ask path about:

- containsPoint:

Example code:

- (BOOL)isCircleView:(UIView *)view coveredWith:(UIBezierPath *)path
{
    if (![path containsPoint:view.center])
        return NO;
    CGFloat r = CGRectGetWidth(view.bounds)/2;
    for (CGFloat angle = 0; angle < 360; angle += 0.5) {
        CGFloat alpha = angle/180*M_PI;
        CGFloat x = view.center.x + r*cos(alpha);
        CGFloat y = view.center.y + r*sin(alpha);
        if (![path containsPoint:CGPointMake(x,y)])
            return NO;
    }
    return YES;
}

This algorithm uses 720 points on your circle view bounds and center point. More points you'll use – more accurate result you will get.

But there is possible situation when border line is hidden and center is hidden but some part are visible. So we can add one more loop to this method before return YES;:

for (CGFloat x = view.center.x - r; x < view.center.x + r; x += 4)
for (CGFloat y = view.center.y - r; y < view.center.y + r; y += 4)
{
    // Comparing distance to center with radius
    if (pow(x-view.center.x,2)+pow(y-view.center.y,2) > pow(r,2))
        continue;
    if (![path containsPoint:CGPointMake(x,y)])
        return NO;
}

You can also configure grid step for more accurate result.

UPDATE:

Here is more common method to check if one UIBezierPath is fully overlapped with another UIBezierPath. Third argument will help you to get more accurate result, try to use values like 10, 100.

- (BOOL)isPath:(UIBezierPath *)path overlappedBy:(UIBezierPath *)superPath granularity:(NSInteger)granularity
{
    for (NSInteger i = 0; i < granularity; i++)
    for (NSInteger j = 0; j < granularity; j++)
    {
        CGFloat x = CGRectGetMinX(path.bounds) + i*CGRectGetWidth(path.bounds)/granularity;
        CGFloat y = CGRectGetMinY(path.bounds) + j*CGRectGetHeight(path.bounds)/granularity;
        if (![path containsPoint:CGPointMake(x,y)])
            continue;
        if (![superPath containsPoint:CGPointMake(x,y)])
            return NO;
    }
    return YES;
}

For circles case I recommend to use first solution, for random shapes – second solution.

Upvotes: 2

Rajesh Maurya
Rajesh Maurya

Reputation: 3154

There would be another possible solution to get bezier path of a view. You should create a UIView class. Make this class a parent of all your circle view. Also declare a UIBezierPath as a property. When you create any circle view assign bezier path. Next time when you touch your view, you can get its path by accessing its property.

Upvotes: 0

pteofil
pteofil

Reputation: 4163

To get the UIBezierPath of the views you can use this method:

+ (UIBezierPath *)bezierPathWithOvalInRect:(CGRect)rect

using the views frame as the rect. As your views have a square shape, you'll get an UIBezierPath that corresponds to your circle.

You then combine all your path into one that you compare with the original circle path.

Upvotes: 1

Related Questions