Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find edges in an array of UIViews

Is there a way find the edges in an NSArray of UIViews.

For instance, the diagram below shows a collection of UIViews (1 to 7). Each view abuts another view. So view 1 could be (0,0,70,20) and view 6 is (70,0,30,50).

How would I return an array of lines which are the separators between views. In the example below, there would be 6 separators (the internal lines).

    ---------------------
    |     1      |   6  |
    |            |      |
    -------------|      |
    |  2   |  3  |      |
    |      |-----|      |
    |      |  4  |------|
    -------------|      |
    |     5      |  7   |
    ---------------------

My first attempt gets the internal lines of each square (the lines which are not on the outside of the container view), removes the duplicates (ie those between 3 and 4),

..and then removes the lines which are touching other lines on the edge until there is one left. Unfortunately this removes the right-most vertical line.

My code for this last part:

NSMutableArray *sidesToDiscard = [[NSMutableArray alloc] init];
for (NSValue *rect1 in self.sides)
{
    for (NSValue *rect2 in self.sides)
    {
        if ([rect1 isEqualToValue:rect2])
        {

        } else
        {
            BOOL xIsSame = (rect2.CGRectValue.origin.x == rect1.CGRectValue.origin.x);
            BOOL bothAreVertical = (rect2.CGRectValue.size.width == 0 && rect1.CGRectValue.size.width == 0);
            BOOL areTouchingOnVertical = ((rect1.CGRectValue.origin.y + rect1.CGRectValue.size.height == rect2.CGRectValue.origin.y) || (rect1.CGRectValue.origin.y == rect1.CGRectValue.origin.y + rect2.CGRectValue.size.height));

            BOOL yIsSame = (rect2.CGRectValue.origin.y == rect1.CGRectValue.origin.y);
            BOOL bothAreHorizontal = (rect2.CGRectValue.size.height == 0 && rect1.CGRectValue.size.height == 0);
            BOOL areTouchingOnHorizontal = ((rect1.CGRectValue.origin.x + rect1.CGRectValue.size.width == rect2.CGRectValue.origin.x) || (rect1.CGRectValue.origin.x == rect2.CGRectValue.origin.x + rect2.CGRectValue.size.width));

            if (((xIsSame && bothAreVertical) && areTouchingOnVertical) || ((yIsSame && bothAreHorizontal) && areTouchingOnHorizontal))
            {
                // if are touching then remove, leaving one left...
            [sidesToDiscard addObject:rect1];
                [sidesToDiscard addObject:rect2];
            }
        }
    }
}
[self.sides removeObjectsInArray:sidesToDiscard];
like image 409
cannyboy Avatar asked Nov 27 '25 00:11

cannyboy


1 Answers

You can convert each view (rectangle) into 4 end points. Remove duplicated points. Since each line segment is formed by connecting two points, you can iterate through all possible line segments by iterating through all possible point pairs, and you want to find the line segments which are

  1. every point on the line segment is adjacent to some views
  2. as long as possible
  3. either vertical or horizontal
  4. not on the outside of the container view

To check 1, you have to iterate through all edges of views, remove the intersection of the line segment and the edges. If nothing is left, you know it might be the line segment you want.

3 and 4 are easy to check.

Iterate through all line segments which satisfy 1, 3, 4. If there are two line segments intersecting, remove the shorter one. What are left must satisfy 2.

like image 54
Hai Feng Kao Avatar answered Nov 28 '25 16:11

Hai Feng Kao