How can I increase the size of a CGRect by a certain percent value?
Solution 1
You can use CGRectInset
if you like:
double pct = 0.2;
CGRect newRect = CGRectInset(oldRect, -CGRectGetWidth(oldRect)*pct/2, -CGRectGetHeight(oldRect)*pct/2);
To decrease the size, remove the -
s.
Side note: A CGRect
that is 20% bigger than {10, 10, 100, 100}
is {0, 0, 120, 120}
.
Edit: If the intention is to increase by area, then this'll do it (even for rectangles that aren't square):
CGFloat width = CGRectGetWidth(oldRect);
CGFloat height = CGRectGetHeight(oldRect);
double pct = 1.2; // 20% increase
double newWidth = sqrt(width * width * pct);
double newHeight = sqrt(height * height * pct);
CGRect newRect = CGRectInset(oldRect, (width-newWidth)/2, (height-newHeight)/2);
Solution 2
In Swift:
func increaseRect(rect: CGRect, byPercentage percentage: CGFloat) -> CGRect {
let startWidth = CGRectGetWidth(rect)
let startHeight = CGRectGetHeight(rect)
let adjustmentWidth = (startWidth * percentage) / 2.0
let adjustmentHeight = (startHeight * percentage) / 2.0
return CGRectInset(rect, -adjustmentWidth, -adjustmentHeight)
}
let rect = CGRectMake(0, 0, 10, 10)
let adjusted = increaseRect(rect, byPercentage: 0.1)
// -0.5, -0.5, 11, 11
In ObjC:
- (CGRect)increaseRect:(CGRect)rect byPercentage:(CGFloat)percentage
{
CGFloat startWidth = CGRectGetWidth(rect);
CGFloat startHeight = CGRectGetHeight(rect);
CGFloat adjustmentWidth = (startWidth * percentage) / 2.0;
CGFloat adjustmentHeight = (startHeight * percentage) / 2.0;
return CGRectInset(rect, -adjustmentWidth, -adjustmentHeight);
}
CGRect rect = CGRectMake(0,0,10,10);
CGRect adjusted = [self increaseRect:rect byPercentage:0.1];
// -0.5, -0.5, 11, 11
Solution 3
Sure, using CGRectInset
works:
CGRect someRect = CGRectMake(10, 10, 100, 100);
someRect = CGRectInset(someRect, someRect.size.width * -0.2, someRect.size.height * -0.2);
Solution 4
Swift 4 extension inspired by several of the answers here with simplified calculations:
extension CGRect {
func scaleLinear(amount: Double) -> CGRect {
guard amount != 1.0, amount > 0.0 else { return self }
let ratio = ((1.0 - amount) / 2.0).cgFloat
return insetBy(dx: width * ratio, dy: height * ratio)
}
func scaleArea(amount: Double) -> CGRect {
return scaleLinear(percent: sqrt(amount))
}
func scaleLinear(percent: Double) -> CGRect {
return scaleLinear(amount: percent / 100)
}
func scaleArea(percent: Double) -> CGRect {
return scaleArea(amount: percent / 100)
}
}
Usage is simply:
rect.scaleLinear(percent: 120.0) OR (amount: 1.2)
rect.scaleArea(percent: 120.0) OR (amount: 1.2)
If you are interested in trying my testing methods:
/// Testing
extension CGRect {
var area: CGFloat { return width * height }
var center: CGPoint { return CGPoint(x: origin.x + width/2, y: origin.y + height/2)
}
func compare(_ r: CGRect) {
let centered = center.x == r.center.x && center.y == r.center.y
print("linear = \(r.width / width), area = \(r.area / area) centered \(centered)")
}
static func ScaleTest() {
let rect = CGRect(x: 17, y: 24, width: 200, height: 100)
let percent = 122.6
rect.compare(rect.scaleLinear(percent: percent))
rect.compare(rect.scaleArea(percent: percent))
}
}
Solution 5
I'm using CGRect > insetBy in my Swift code
https://developer.apple.com/documentation/coregraphics/cgrect/1454218-insetby
With this, your percent value will be the scaleX
as my example.
let dx = rectWidth*scaleX
let dy = rectHeight*scaleX
let rectangle = CGRect(x: rectX,
y: rectY,
width: rectWidth,
height: rectHeight).insetBy(dx: -dx, dy: -dy)
- use positive value to scale down
- use negative value to scale up
Related videos on Youtube
brandonscript
Quantum foam traveler. Purveyor of opinions. Product design https://delving.com. UX & Code. Advisor https://pacificaviator.co. Previously Google, Apigee. ADHD. Be kind. (He/him)
Updated on July 09, 2022Comments
-
brandonscript almost 2 years
How can I increase the size of a CGRect by a certain percent value? Should I use some form of
CGRectInset
to do it?Example:
Assume I have a CGRect:
{10, 10, 110, 110}
I want to increase its size (retaining the same center point) by 20% to:
{0, 0, 120, 120}
-
Fattie about 7 yearsfor 2017, it's
insetBy
-
-
rmaddy over 9 yearsThe question is tagged Objective-C. Best to give answers in the desired language.
-
thelaws over 9 yearsRe the sidenote: I think remus is correct that (110,110) gives an area 20% bigger than (100,100).
-
Ian MacDonald over 9 yearsI suppose it depends on your interpretation of "20% bigger". By area, the resulting square has edges of length
109.5445
, which isn't as pretty as just assuming he meant to increase the edge size by 20%. -
Tommy over 9 years+1 for being the only answerer so far to have obeyed Apple's statement that "your applications should avoid directly reading and writing the data stored in the CGRect data structure. Instead, use the functions described here to manipulate rectangles and to retrieve their characteristics." — developer.apple.com/Library/ios/documentation/GraphicsImaging/…
-
Ian MacDonald over 9 yearsApple's statement is silly. I updated my answer to conform to it anyways. :/
-
brandonscript over 9 yearsI meant increase edge sizes, but you're right, area would be an entirely different calculation, and this is a good answer.
-
Ian MacDonald over 9 yearsGood thing I included both. :)
-
brandonscript over 9 yearsSelected as answer because ^
-
brandonscript over 9 yearsClose second, and I actually like this answer too since it's got both Objc and Swift ;)
-
brandonscript over 7 yearsLooking at this one again, shouldn't the output rect be -1, -1, 11, 11?
-
Fattie about 7 yearsthis is insetBy in the latest Swift, cheers @IanMacDonald
-
lhunath about 6 yearsThis does not appear to scale relative to the center of the rectangle, thus does not change the x,y origin.
-
Harry Bloom about 6 yearsAs the above comment states, this doesn't keep the center point of the rect!
-
gheclipse over 5 yearsCGRect extension is convenient, but this code does not work correctly. newX and newY should be added to the origin (x, y). let newX = x + (w - newW) / 2