I need to resize an image using bilinear interpolation and create an image pyramid.I will detect corners at the different levels of the pyramid and scale the pixel co-ordinates so that they are relative to the dimensions of the largest image.
If a corner of an object is detected as a corner/keypoint/feature in all the levels,after scaling the corresponding pixel co-ordinates from the different levels so that they fall on the largest image, ideally I would like them to have the same value. Thus when resizing the images, I am trying to be as accurate as possible.
Let's assume I am resizing an image L_n_minus_1 to create a smaller image L_n. My scale factor is "ratio" (ratio>1).
*I cannot use any library.
I can resize using the pseudocode below (which is what I generally find when I search online for resizing algorithms.)
int offset = 0;
for (int i = 0; i < height_of_L_n; i++){
for (int j = 0; j < width_of_L_n; j++){
//********* This part will differ in the later version I provided below
//
int xSrcInt = (int)(ratio * j);
float xDiff = ratio * j - xSrcInt;
int ySrcInt = (int)(ratio * i);
float yDiff = ratio * i - ySrcInt;
// The above code will differ in the later version I provided below
index = (ySrcInt * width_of_L_n_minus_1 + xSrcInt);
//Get the 4 pixel values to interpolate
a = L_n_minus_1[index];
b = L_n_minus_1[index + 1];
c = L_n_minus_1[index + width_of_L_n_minus_1];
d = L_n_minus_1[index + width_of_L_n_minus_1 + 1];
//Calculate the co-efficients for interpolation
float c0 = (1 - x_diff)*(1 - y_diff);
float c1 = (x_diff)*(1 - y_diff);
float c2 = (y_diff)*(1 - x_diff);
float c3 = (x_diff*y_diff);
//half is added for rounding the pixel intensity.
int intensity = (a*c0) + (b*c1) + (c*c2) + (d*c3) + 0.5;
if (intensity > 255)
intensity = 255;
L_n[offset++] = intensity;
}
}
Or I could use this modified piece of code below :
int offset = 0;
for (int i = 0; i < height_of_L_n; i++){
for (int j = 0; j < width_of_L_n; j++){
// Here the code differs from the first piece of code
// Assume pixel centers start from (0.5,0.5). The top left pixel has co-ordinate (0.5,0.5)
// 0.5 is added to go to the co-ordinates where top left pixel has co-ordinate (0.5,0.5)
// 0.5 is subtracted to go to the generally used co-ordinates where top left pixel has co-ordinate (0,0)
// or in other words map the new co-ordinates to array indices
int xSrcInt = int((ratio * (j + 0.5)) - 0.5);
float xDiff = (ratio * (j + 0.5)) - 0.5 - xSrcInt;
int ySrcInt = int((ratio * (i + 0.5)) - 0.5);
float yDiff = (ratio * (i + 0.5)) - 0.5 - ySrcInt;
// Difference with previous code ends here
index = (ySrcInt * width_of_L_n_minus_1 + xSrcInt);
//Get the 4 pixel values to interpolate
a = L_n_minus_1[index];
b = L_n_minus_1[index + 1];
c = L_n_minus_1[index + width_of_L_n_minus_1];
d = L_n_minus_1[index + width_of_L_n_minus_1 + 1];
//Calculate the co-efficients for interpolation
float c0 = (1 - x_diff)*(1 - y_diff);
float c1 = (x_diff)*(1 - y_diff);
float c2 = (y_diff)*(1 - x_diff);
float c3 = (x_diff*y_diff);
//half is added for rounding the pixel intensity.
int intensity = (a*c0) + (b*c1) + (c*c2) + (d*c3) + 0.5;
if (intensity > 255)
intensity = 255;
L_n[offset++] = intensity;
}
}
The second piece of code was developed assuming pixel centers having co-ordinates like (0.5, 0.5) as they have in textures.
This way the top left pixel will have co-ordinate (0.5, 0.5).
Let us assume :
a 2 by 2 Destination Image is being resized from a 4 by 4 Source Image.
In the first piece of code, it is assumed that the first pixel has co-ordinates (0,0), thus for example my ratio is 2. Then
xSrcInt = (int)(0*2); // 0
ySrcInt = (int)(0*2); // 0
xDiff = (0*2) - 0; // 0
yDiff = (0*2) - 0; // 0
Thus effectively I will just be copying the first pixel value from the source, as c0 will be 1 and c1,c2 and c3 will be 0.
But in the second piece of code I will get
xSrcInt = (int)((0.5*2) - 0.5); // 0;
ySrcInt = (int)((0.5*2) - 0.5); // 0;
xDiff = ((0.5*2) - 0.5) - 0; // 0.5;
yDiff = ((0.5*2) - 0.5) - 0; // 0.5;
In this case c0,c1,c2 and c3 will all be equal to 0.25. Thus I will be using the 4 pixels at the top left.
Please let me know what do you think and if there is any bug in my second piece of code. As far as visual results go they are working perfectly.
But yes I do seem to notice better alignment of keypoints with the second piece of code. But may be that's because I am judging with prejudice :-).
Thanks in advance.
So I am using CATiled layer to create my own floor plan. My floor plan works just fine on older devices like the 4, 4s, 5, 5s and 6. However, when I run my program on the 6 plus, my arithmetic for zoom level is off. Here's why: When I call my draw rect method, I get different tile width's based on the device. When I call my images, I call them in the sequence of ZoomLevel_COL_ROW.image . My zoom level is multiples of 2. So every time you pinch to zoom, my ZoomLevel is called in order: 2, 4, 8, 16 and 32. My problem I am having is I can't figure out how to divide the tiles width by 512 to get me the appropriate zoom level. So on a 6plus, my initial tile width when the view loads is 85.53. So 512/85.3 gets me 6 - which is not apart of my sequence. However, on a 5s I get a tile width of 128. So 512/128 gets me 4 - which is apart of my sequence, however skips level 2. So I am having a tough time determining what would be a consistent arithmetic to get all zoom level sequences every time you pinch to zoom. Recall that my sequence is 2, 4, 8, 16,32. Hopefully I am clear, and everyone understands. Thanks!
- (void)drawRect:(CGRect)rect
{
// NSLog(#"drawrect %#", NSStringFromCGRect(rect));
zoomLevel = (512 / (CGRectGetWidth(rect)));
int size = 512;
int zoom = 1;
while (size > rect.size.width) {
size /= 2;
zoom ++;
}
NSLog(#"Zoomlevel %d", zoomLevel);
CGSize tileSize = rect.size;
int firstCol = floorf(CGRectGetMinX(rect) / tileSize.width);
int lastCol = floorf((CGRectGetMaxX(rect)-1) / tileSize.width);
int firstRow = floorf(CGRectGetMinY(rect) / tileSize.height);
int lastRow = floorf((CGRectGetMaxY(rect)-1) / tileSize.height);
for (int row = firstRow; row <= lastRow; row++) {
for (int col = firstCol; col <= lastCol; col++) {
UIImage *tile = [self tileAtCol:col row:row];
float width = tileSize.width;
float height = tileSize.height;
if (tile.size.width != tile.size.height) {
// make sure that smaller tiles aren't stretched
float widthRatio = tile.size.width / 512;
float heightRatio = tile.size.height / 512;
width *= widthRatio;
height *= heightRatio;
}
CGRect tileRect = CGRectMake(tileSize.width * col,
tileSize.height * row,
width, height);
tileRect = CGRectIntersection(self.bounds, tileRect);
[tile drawInRect:tileRect];
}
}
}
Figured out why. It had to do with scale Factor! Because iPhone 6 plus has different resolution. Check out the code below:
scaleFactor = [UIScreen mainScreen].scale;
float width = rect.size.width;
width *= scaleFactor;
zoomLevel = (512/ width);
As my tile says that I want to get random number for origin (X-Axis & y-Axis) so in my whole screen in iPad landscape I have 1 rectangle, I want to get random number for origin which out of this rectangle, so obiously I want to get random number for X-Axis between max and min and same as for Y-Axis.
I tried with following answers but not helpful for me.
Generate Random Numbers Between Two Numbers in Objective-C
Generate a random float between 0 and 1
Generate random number in range in iOS?
For more clear see below image
In above image I just want to find random number (for origin) of GREEN screen. How can I achieve it ?
Edited
I had tried.
int randNum = rand() % ([max intValue] - [min intValue]) + [min intValue];
Same for both X-Axis & y-Axis.
If the blue exclusion rectangle is not "too large" compared to the green screen rectangle
then the easiest solution is to
create a random point inside the green rectangle,
check if the point lies inside the blue rectangle, and
repeat the process if necessary.
That would look like:
CGRect greenRect = ...;
CGRect blueRect = ...;
CGPoint p;
do {
p = CGPointMake(greenRect.origin.x + arc4random_uniform(greenRect.size.width),
greenRect.origin.y + arc4random_uniform(greenRect.size.height));
} while (CGRectContainsPoint(blueRect, p));
If I remember correctly, the expected number of iterations is G/(G - B), where G is
the area of the green rectangle and B is the area of the blue rectangle.
What if you first determined x within the green rectangle like this:
int randomX = arc4random()%greenRectangle.frame.size.width;
int randomY; // we'll do y later
Then check if this is inside the blue rectangle:
if(randomX < blueRectangle.frame.origin.x && randomX > (blueRectangle.frame.origin.x + blueRectangle.frame.size.width))
{
//in this case we are outside the rectangle with the x component
//so can randomly generate any y like this:
randomY = arc4random()%greenRectangle.frame.size.height;
}
//And if randomX is in the blue rectangle then we can use the space either before or after it:
else
{
//randomly decide if you are going to use the range to the left of blue rectangle or to the right
BOOL shouldPickTopRange = arc4random()%1;
if(shouldPickTopRange)
{
//in this case y can be any point before the start of blue rectangle
randomY = arc4random()%blueRectangle.frame.origin.y;
}
else
{
//in this case y can be any point after the blue rectangle
int minY = blueRectangle.frame.origin.y + blueRectangle.frame.size.height;
int maxY = greenRectangle.frame.size.height;
randomY = arc4random()%(maxY - minY + 1) + minY;
}
}
Then your random point would be:
CGPoint randomPoint = CGPointMake(randomX, randomY);
The only thing missing above is to check if your blue rectangle sits at y = 0 or at the very bottom of green rectangle.
[Apologies I did this with OS X, translation is straightforward]
A non-iterative solution:
- (NSPoint) randomPointIn:(NSRect)greenRect excluding:(NSRect)blueRect
{
// random point on green x-axis
int x = arc4random_uniform(NSWidth(greenRect)) + NSMinX(greenRect);
if (x < NSMinX(blueRect) || x > NSMaxX(blueRect))
{
// to the left or right of the blue, full height available
int y = arc4random_uniform(NSHeight(greenRect)) + NSMinY(greenRect);
return NSMakePoint(x, y);
}
else
{
// within the x-range of the blue, avoid it
int y = arc4random_uniform(NSHeight(greenRect) - NSHeight(blueRect)) + NSMinY(greenRect);
if (y >= NSMinY(blueRect))
{
// not below the blue, step over it
y += NSHeight(blueRect);
}
return NSMakePoint(x, y);
}
}
This picks a random x-coord in the range of green. If that point is outside the range of blue it picks a random y-coord in the range of green; otherwise it reduces the y range by the height of blue, produces a random point, and then increases it if required to avoid blue.
There are other solutions based on picking a uniform random point in the available area (green - blue) and then adjusting, but the complexity isn't worth it I think (I haven't done the stats).
Addendum
OK folk seem concerned over uniformity, so here is the algorithm mentioned in my last paragraph. We're picking an "point" with integer coords so the number of points to pick from is the green area minus the blue area. Pick a point randomly in this range. Now place it into one of the rectangles below, left, right or above the blue:
// convenience
int RectArea(NSRect r) { return (int)NSWidth(r) * (int)NSHeight(r); }
- (NSPoint) randomPointIn:(NSRect)greenRect excluding:(NSRect)blueRect
{
// not we are using "points" with integer coords so the
// bottom left point is 0,0 and the top right (width-1, height-1)
// you can adjust this to suit
// the number of points to pick from is the diff of the areas
int availableArea = RectArea(greenRect) - RectArea(blueRect);
int pointNumber = arc4random_uniform(availableArea);
// now "just" locate pointNumber into the available space
// we consider four rectangles, one each full width above and below the blue
// and one each to the left and right of the blue
int belowArea = NSWidth(greenRect) * (NSMinY(blueRect) - NSMinY(greenRect));
if (pointNumber < belowArea)
{
return NSMakePoint(pointNumber % (int)NSWidth(greenRect) + NSMinX(greenRect),
pointNumber / (int)NSWidth(greenRect) + NSMinY(greenRect));
}
// not below - consider to left
pointNumber -= belowArea;
int leftWidth = NSMinX(blueRect) - NSMinX(greenRect);
int leftArea = NSHeight(blueRect) * leftWidth;
if (pointNumber < leftArea)
{
return NSMakePoint(pointNumber % leftWidth + NSMinX(greenRect),
pointNumber / leftWidth + NSMinY(blueRect));
}
// not left - consider to right
pointNumber -= leftArea;
int rightWidth = NSMaxX(greenRect) - NSMaxX(blueRect);
int rightArea = NSHeight(blueRect) * rightWidth;
if (pointNumber < rightArea)
{
return NSMakePoint(pointNumber % rightWidth + NSMaxX(blueRect),
pointNumber / rightWidth + NSMinY(blueRect));
}
// it must be above
pointNumber -= rightArea;
return NSMakePoint(pointNumber % (int)NSWidth(greenRect) + NSMinX(greenRect),
pointNumber / (int)NSWidth(greenRect) + NSMaxY(blueRect));
}
This is uniform, but whether it is worth it you'll have to decide.
Okay. This was bothering me, so I did the work. It's a lot of source code, but computationally lightweight and probabilistically correct (haven't tested).
With all due respect to #MartinR, I think this is superior insofar as it doesn't loop (consider the case where the contained rect covers a very large portion of the outer rect). And with all due respect to #CRD, it's a pain, but not impossible to get the desired probabilities. Here goes:
// Find a random position in rect, excluding a contained rect called exclude
//
// It looks terrible, but it's just a lot of bookkeeping.
// Divide rect into 8 regions, like a tic-tac-toe board, excluding the center square
// Reading left to right, top to bottom, call these: A,B,C,D, (no E, it's the center) F,G,H,I
// The random point must be in one of these regions, choose by throwing a random dart, using
// cumulative probabilities to choose. The likelihood that the dart will be in regions A-I is
// the ratio of each's area to the total (less the center)
// With a target rect, correctly selected, we can easily pick a random point within it.
+ (CGPoint)pointInRect:(CGRect)rect excluding:(CGRect)exclude {
// find important points in the grid
CGFloat xLeft = CGRectGetMinX(rect);
CGFloat xCenter = CGRectGetMinX(exclude);
CGFloat xRight = CGRectGetMaxX(exclude);
CGFloat widthLeft = exclude.origin.x-CGRectGetMinX(rect);
CGFloat widthCenter = exclude.size.width;
CGFloat widthRight = CGRectGetMaxY(rect)-CGRectGetMaxX(exclude);
CGFloat yTop = CGRectGetMinY(rect);
CGFloat yCenter = exclude.origin.y;
CGFloat yBottom = CGRectGetMaxY(exclude);
CGFloat heightTop = exclude.origin.y-CGRectGetMinY(rect);
CGFloat heightCenter = exclude.size.height;
CGFloat heightBottom = CGRectGetMaxY(rect)-CGRectGetMaxY(exclude);
// compute the eight regions
CGFloat areaA = widthLeft * heightTop;
CGFloat areaB = widthCenter * heightTop;
CGFloat areaC = widthRight * heightTop;
CGFloat areaD = widthLeft * heightCenter;
CGFloat areaF = widthRight * heightCenter;
CGFloat areaG = widthLeft * heightBottom;
CGFloat areaH = widthCenter * heightBottom;
CGFloat areaI = widthRight * heightBottom;
CGFloat areaSum = areaA+areaB+areaC+areaD+areaF+areaG+areaH+areaI;
// compute the normalized probabilities
CGFloat pA = areaA/areaSum;
CGFloat pB = areaB/areaSum;
CGFloat pC = areaC/areaSum;
CGFloat pD = areaD/areaSum;
CGFloat pF = areaF/areaSum;
CGFloat pG = areaG/areaSum;
CGFloat pH = areaH/areaSum;
// compute cumulative probabilities
CGFloat cumB = pA+pB;
CGFloat cumC = cumB+pC;
CGFloat cumD = cumC+pD;
CGFloat cumF = cumD+pF;
CGFloat cumG = cumF+pG;
CGFloat cumH = cumG+pH;
// now pick which region we're in, using cumulatvie probabilities
// whew, maybe we should just use MartinR's loop. No No, we've come too far!
CGFloat dart = uniformRandomUpTo(1.0);
CGRect targetRect;
// top row
if (dart < pA) {
targetRect = CGRectMake(xLeft, yTop, widthLeft, heightTop);
} else if (dart >= pA && dart < cumB) {
targetRect = CGRectMake(xCenter, yTop, widthCenter, heightTop);
} else if (dart >= cumB && dart < cumC) {
targetRect = CGRectMake(xRight, yTop, widthRight, heightTop);
}
// middle row
else if (dart >= cumC && dart < cumD) {
targetRect = CGRectMake(xRight, yCenter, widthRight, heightCenter);
} else if (dart >= cumD && dart < cumF) {
targetRect = CGRectMake(xLeft, yCenter, widthLeft, heightCenter);
}
// bottom row
else if (dart >= cumF && dart < cumG) {
targetRect = CGRectMake(xLeft, yBottom, widthLeft, heightBottom);
} else if (dart >= cumG && dart < cumH) {
targetRect = CGRectMake(xCenter, yBottom, widthCenter, heightBottom);
} else {
targetRect = CGRectMake(xRight, yBottom, widthRight, heightBottom);
}
// yay. pick a point in the target rect
CGFloat x = uniformRandomUpTo(targetRect.size.width) + CGRectGetMinX(targetRect);
CGFloat y = uniformRandomUpTo(targetRect.size.height)+ CGRectGetMinY(targetRect);
return CGPointMake(x, y);
}
float uniformRandomUpTo(float max) {
return max * arc4random_uniform(RAND_MAX) / RAND_MAX;
}
Try this code, Worked for me.
-(CGPoint)randomPointInRect:(CGRect)r
{
CGPoint p = r.origin;
p.x += arc4random_uniform((u_int32_t) CGRectGetWidth(r));
p.y += arc4random_uniform((u_int32_t) CGRectGetHeight(r));
return p;
}
I don't like piling onto answers. However, the provided solutions do not work, so I feel obliged to chime in.
Martin's is fine, and simple... which may be all you need. It does have one major problem though... finding the answer when the inner rectangle dominates the containing rectangle could take quite a long time. If it fits your domain, then always choose the simplest solution that works.
jancakes solution is not uniform, and contains a fair amount of bias.
The second solution provided by dang just plain does not work... because arc4_random takes and returns uint32_t and not a floating point value. Thus, all generated numbers should fall into the first box.
You can address that by using drand48(), but it's not a great number generator, and has bias of its own. Furthermore, if you look at the distribution generated by that method, it has heavy bias that favors the box just to the left of the "inner box."
You can easily test the generation... toss a couple of UIViews in a controller, add a button handler that plots 100000 "random" points and you can see the bias clearly.
So, I hacked up something that is not elegant, but does provide a uniform distribution of random numbers in the larger rectangle that are not in the contained rectangle.
You can surely optimize the code and make it a bit easier to read...
Caveat: Will not work if you have more than 4,294,967,296 total points. There are multiple solutions to this, but this should get you moving in the right direction.
- (CGPoint)randomPointInRect:(CGRect)rect
excludingRect:(CGRect)excludeRect
{
excludeRect = CGRectIntersection(rect, excludeRect);
if (CGRectEqualToRect(excludeRect, CGRectNull)) {
return CGPointZero;
}
CGPoint result;
uint32_t rectWidth = rect.size.width;
uint32_t rectHeight = rect.size.height;
uint32_t rectTotal = rectHeight * rectWidth;
uint32_t excludeWidth = excludeRect.size.width;
uint32_t excludeHeight = excludeRect.size.height;
uint32_t excludeTotal = excludeHeight * excludeWidth;
if (rectTotal == 0) {
return CGPointZero;
}
if (excludeTotal == 0) {
uint32_t r = arc4random_uniform(rectHeight * rectWidth);
result.x = r % rectWidth;
result.y = r /rectWidth;
return result;
}
uint32_t numValidPoints = rectTotal - excludeTotal;
uint32_t r = arc4random_uniform(numValidPoints);
uint32_t numPointsAboveOrBelowExcludedRect =
(rectHeight * excludeWidth) - excludeTotal;
if (r < numPointsAboveOrBelowExcludedRect) {
result.x = (r % excludeWidth) + excludeRect.origin.x;
result.y = r / excludeWidth;
if (result.y >= excludeRect.origin.y) {
result.y += excludeHeight;
}
} else {
r -= numPointsAboveOrBelowExcludedRect;
uint32_t numPointsLeftOfExcludeRect =
rectHeight * excludeRect.origin.x;
if (r < numPointsLeftOfExcludeRect) {
uint32_t rowWidth = excludeRect.origin.x;
result.x = r % rowWidth;
result.y = r / rowWidth;
} else {
r -= numPointsLeftOfExcludeRect;
CGFloat startX =
excludeRect.origin.x + excludeRect.size.width;
uint32_t rowWidth = rectWidth - startX;
result.x = (r % rowWidth) + startX;
result.y = r / rowWidth;
}
}
return result;
}
I have a project that uses a tilemap. I have a separate tilemap for low-res (29x29 Tilesize) and high-res (58x58). I have these methods to calculate tileCoord to position and back again.
- (CGPoint)tileCoordForPosition:(CGPoint)position {
int x = position.x / _tileMap.tileSize.width;
int y = ((_tileMap.mapSize.height * _tileMap.tileSize.height) - position.y) / _tileMap.tileSize.height;
return ccp(x, y);
}
- (CGPoint)positionForTileCoord:(CGPoint)tileCoord {
int x = (tileCoord.x * _tileMap.tileSize.width) + _tileMap.tileSize.width/2;
int y = (_tileMap.mapSize.height * _tileMap.tileSize.height) - (tileCoord.y * _tileMap.tileSize.height) - _tileMap.tileSize.height/2;
return ccp(x, y);
}
I got this from RayWenderLich and I do honeslty not understand how it works, and why it has to be so complicated. But this doesn't work when I use retina tilemaps, only on 480x320. Can someone clever come up with a way to make this work for HD? Does not have to work on low-res either, I do not plan on supporting sub-iOS 7.
I want the output to be in the low-res coordinate scale tho, as you might know, cocos2d does the resizing to HD for you. (By multiplying by two)
i think this will work
- (CGPoint)tileCoordForPosition:(CGPoint)position {
int x = position.x/29;
int y = ((11*29)-position.y) / 29;
return ccp(x, y);
}
- (CGPoint)positionForTileCoord:(CGPoint)tileCoord {
double x = tileCoord.x * 29 + 14.5;
double y = (11*29) - (tileCoord.y * 29) - 14.5;
return ccp(x, y);
}
Here you're trying to compute your map X coordinate:
int x = position.x / _tileMap.tileSize.width;
The problem here is that (as of v0.99.5-rc0, cocos2d generally uses points for positions, but CCTMXTiledMap always uses pixels for tileSize. On a low-res device, 1 point = 1 pixel, but on a Retina device, 1 point = 2 pixels. Thus on a Retina device, you need to multiply by 2.
You can use the CC_CONTENT_SCALE_FACTOR() macro to fix this:
int x = CC_CONTENT_SCALE_FACTOR() * position.x / _tileMap.tileSize.width;
Here you're trying to compute yoru map Y coordinate:
int y = ((_tileMap.mapSize.height * _tileMap.tileSize.height) - position.y) / _tileMap.tileSize.height;
The extra math here is trying to account for the difference between Cocos2D's normal coordinate system and your map's flipped coordinate system. In standard Cartesian coordinates, the origin is at the lower left and Y coordinates increase as you move up. In a flipped coordinate system, the origin is at the upper left and Y coordinates increase as you move down. Thus you must subtract your position's Y coordinate from the height of the map (in scene units, which are points) to flip it to map coordinates.
The problem again is that _tileMap.tileSize is in pixels, not points. You can again fix that by using CC_CONTENT_SCALE_FACTOR():
CGFloat tileHeight = _tileMap.tileSize.height / CC_CONTENT_SCALE_FACTOR();
int y = ((_tileMap.mapSize.height * tileHeight) - position.y) / tileHeight;
I am working on this Lua script and I need to be able to find the largest 16:9 rectangle within another rectangle that doesn't have a specific aspect ratio. So can you tell me how I can do that? You don't have to write Lua - pseudocode works too.
Thanks!
This I have tried and can confirm that won't work on lower ratio outer rects.
if wOut > hOut then
wIn = wOut
hIn = (wIn / 16) *9
else
hIn = hOut
wIn = (hIn / 9) * 16
end
heightCount = originalHeight / 9;
widthCount = originalWidth / 16;
if (heightCount == 0 || widthCount == 0)
throw "No 16/9 rectangle";
recCount = min(heightCount, widthCount);
targetHeight = recCount * 9;
targetWidth = recCount * 16;
So far, any rectangle with left = 0..(originalWidth - targetWidth) and top = 0..(originalHeight - targetHeight) and width = targetWidth and height = targetHeight should satisfy your requirements.
Well, your new rectangle can be described as:
h = w / (16/9)
w = h * (16/9)
Your new rectangle should then be based on the width of the outer rectangle, so:
h = w0 / (16/9)
w = w0
Depending on how Lua works with numbers, you might want to make sure it is using real division as opposed to integer division - last time I looked was 2001, and my memory is deteriorating faster than coffee gets cold, but I seem to remember all numbers being floats anyway...