Reputation: 2834
I have a a set of CGPoint
s which represent a shape which is a bit like an upside down 'T' shape, now I want to convert those points into a CGRect
which fits inside the shape, so to create a CGRect
which encompasses the entire shape I just loop through and work out the lowest x
and y
for the top left and the highest x
and y
for the bottom right which is great but leaves white areas outside of the image, how could I figure out the largest rectangle without white areas so the final shape is more like an '|' shape? My code so far:
CGPoint topLeft = CGPointZero;
CGPoint bottomRight = CGPointZero;
for( NSValue *value in points ) {
CGPoint point = [value CGPointValue];
if( topLeft.x == 0 || topLeft.x > point.x ) shapeRect.x = point.x;
if( topLeft.y == 0 || topLeft.y > point.y ) shapeRect.y = point.y;
if( bottomRight.x < point.x ) bottomRight.x = point.x;
if( bottomRight.y < point.y ) bottomRight.y = point.y;
}
CGRect shapeRect = CGRectMake(topLeft.x, topLeft.y, bottomRight.x - topLeft.x, bottomRight.y - topLeft.y);
EDIT: I've drawn some pics to show what I'm trying to achieve. Grey areas show the CGRect
.
Here's the image shape, I have coordinates for each point in the shape:
Image Hosted by ImageShack.us http://img684.imageshack.us/img684/121/crop1.png
Here's what my code above produces:
Image Hosted by ImageShack.us http://img26.imageshack.us/img26/2521/crop2j.png
Here's what I'm trying to achieve:
Image Hosted by ImageShack.us http://img689.imageshack.us/img689/5499/crop3.png
Upvotes: 3
Views: 3819
Reputation: 2670
If you want, you can use Core Graphics:
let path = CGMutablePath()
path.addLines(between: [p1, p2, p3, p4])
return path.boundingBoxOfPath
Upvotes: 2
Reputation: 749
Swift version of hfossli (it works great !) :
func pointToRect(pointsArray: [CGPoint]) -> CGRect {
var greatestXValue = pointsArray[0].x
var greatestYValue = pointsArray[0].y
var smallestXValue = pointsArray[0].x
var smallestYValue = pointsArray[0].y
for point in pointsArray {
greatestXValue = max(greatestXValue, point.x);
greatestYValue = max(greatestYValue, point.y);
smallestXValue = min(smallestXValue, point.x);
smallestYValue = min(smallestYValue, point.y);
}
let origin = CGPoint(x: smallestXValue, y: smallestYValue)
let size = CGSize(width: greatestXValue - smallestXValue, height: greatestYValue - smallestYValue)
return CGRect(origin: origin, size: size)
}
Upvotes: 3
Reputation: 22972
Hard to get a grip on what you are actually asking about. In regards to the title this function will create the smallest rect for any number of CGPoints.
CGRect CGRectSmallestWithCGPoints(CGPoint pointsArray[], int numberOfPoints)
{
CGFloat greatestXValue = pointsArray[0].x;
CGFloat greatestYValue = pointsArray[0].y;
CGFloat smallestXValue = pointsArray[0].x;
CGFloat smallestYValue = pointsArray[0].y;
for(int i = 1; i < numberOfPoints; i++)
{
CGPoint point = pointsArray[i];
greatestXValue = MAX(greatestXValue, point.x);
greatestYValue = MAX(greatestYValue, point.y);
smallestXValue = MIN(smallestXValue, point.x);
smallestYValue = MIN(smallestYValue, point.y);
}
CGRect rect;
rect.origin = CGPointMake(smallestXValue, smallestYValue);
rect.size.width = greatestXValue - smallestXValue;
rect.size.height = greatestYValue - smallestYValue;
return rect;
}
Can be used like this
CGPoint poinstArray[] = {topLeft, bottomRight};
CGRect smallestRect = CGRectSmallestWithCGPoints(poinstArray, 2);
Upvotes: 5
Reputation: 64022
Hopefully you're only talking about this one shape, always oriented this way, otherwise this becomes a tricky computational geometry problem (something like the largest enclosed rectangle in a concave polygon).
Given your list of points, the following should work:
a. Find the point with the largest y value.
b. Find the other point with an equally large y value.
c. Compare the x values of these two and determine which is leftmost.
Find the minimum y value of all the points.
Create two new points, each with an x value equal to one of the points you found in step 1, and with the y value found in step 2.
The two points from step 1 are your top left and right points, and the two created in step 3 are the bottom left and right. You can now construct the final rectangle.
Upvotes: 1
Reputation: 10864
If I did not misunderstand the question, your aim is to find the blue points:
If I'm correct, then it's enough for you to store two points (say topL
and topR
) and a value (say bottom
).
Iteratively:
y < topL.y
and eventually update topL
and topR
.
y == topL.y
check if current x
is less than topL.x
. If yes update topL
x>topR.x
; if yes update topR
.y>bottom
. If yes update bottom
.Note that when I say "update topL
" I mean both x
and y
.
At the end you can get your bottom-left and bottom-right points using x
coordinate of topL
and topR
and setting y
coordinate to bottom.
Upvotes: 2