Basic rectangle splitting - algorithm

I'm stuck on some trivial question and, well, I guess I need help here.
I have two rectangles and it's guaranteed that they have one common point from their 4 base points (upper part of the picture). It's also guaranteed that they are axis-aligned.
I know this common point (which also can be easily deduced), dimensions and the coordinates of these rectangles.
Now, I need to retrieve the coordinates of the rectangles named 1 and 2 and I'm seeking for an easy way to do that (lower part of the picture).
My current implementation relies on many if statements and I suspect I'm too stupid to find a better way.
Thank you.
Update: My current implementation.
Point commonPoint = getCommonPoint(bigRectangle, smallRectangle);
rectangle2 = new Rectangle(smallRectangle.getAdjacentVerticalPoint(commonPoint),
bigRectangle.getOppositePoint(commonPoint));
rectangle1 = new Rectangle(smallRectangle.getAdjacentHorizontalPoint(commonPoint)
bigRectangle.getOppositePoint(commonPoint));
// Now simply adjust one of these rectangles to remove the overlap,
// it's trivial - we take the 'opposite' points for 'small' and 'big'
// rectangles and then use their absolute coordinate difference as
// a fix for either width of 'rectangle2' or height of 'rectangle1'
// (in this situation it's going to be width).
adjustRectangle(rectangle2);
This is refactored, but still methods getCommonPoint and getAdjacent... and getOpposite have many if statements and I thought if this can be done better.

The top and bottom values of Rectangle 1 are the same as the big rectangle. The left and right values of rectangle 2 are the same as the small rectangle. We only need to obtain the left and right values of rectangle 1, and the top and bottom values for rectangle 2. So we only have 2 simple if-statements:
if (bigRectangle.Left == smallRectangle.Left)
left = smallRectangle.Right
right = bigRectangle.Right
else
left = bigRectangle.Left
right = smallRectangle.Left
rectangle1 = new Rectangle(left, bigRectangle.Top, right - left, bigRectangle.Height)
if (bigRectangle.Top == smallRectangle.Top)
top = smallRectangle.Bottom
bottom = bigRectangle.Bottom
else
top = bigRectangle.Top
bottom = smallRectangle.Top
rectangle2 = new Rectangle(smallRectangle.Left, top, smallRectangle.Width, bottom - top)
In the above, the Rectangle constructors takes as inputs: left, top, width, height.

From what I understand, seems like you need to have an if (or switch) statement to determine the orientation of the rectangle, and from there it would just be some easy adding and subtracting:
If you know the coords of the inner blue rectangle (and the dimensions of the rect as a whole), then finding the others should be no problem. One of the R1 and R2 points will always be the same: equal to the adjacent blue rect point. and the others is just a lil math.
Doesn't seem like you can get away from the initial if/switch statement. If the rectangle could only be up or down, then you could just make the offset negative or positive, but it can also be left or right..so you might be stuck there. You can make a -/+ offset for a vertical or horizontal state,but then you'd have to do a check on each calculation

Assuming you had RA and RB as your inputs, and whatever language you're using has a Rectangle class, here's a way to do it with 4 ifs, Math.Min, Math.Max, and Math.Abs:
Rectangle r1, r2; // Note - Rectangle constructor: new Rectangle(X, Y, Width, Height)
if (RA.X = RB.X) {
r1 = new Rectangle(Math.Min(RA.Right, RB.Right), Math.Min(RA.Y, RB.Y), Math.Abs(RA.Width - RB.Width), Math.Max(RA.Height, RB.Height));
if (RA.Y = RB.Y) {
// Intersects Top Left
r2 = new Rectangle(RA.X, Math.Min(RA.Bottom, RB.Bottom), Math.Min(RA.Width, RB.Width), Math.Abs(RA.Height - RB.Height));
} else {
// Intersects Bottom Left
r2 = new Rectangle(RA.X, Math.Max(RA.Bottom, RB.Bottom), Math.Min(RA.Width, RB.Width), Math.Abs(RA.Height - RB.Height));
}
} else {
r1 = new Rectangle(Math.Min(RA.X, RB.X), Math.Min(RA.Y, RB.Y), Math.Abs(RA.Width - RB.Width), Math.Max(RA.Height, RB.Height));
if (RA.Y = RB.Y) {
// Intersects Top Right
r2 = new Rectangle(Math.Max(RA.X, RB.X), Math.Min(RA.Bottom, RB.Bottom), Math.Min(RA.Width, RB.Width), Math.Abs(RA.Height - RB.Height));
} else {
// Intersects Bottom Right
r2 = new Rectangle(Math.Max(RA.X, RB.X), Math.Min(RA.X, RA.Y), Math.Min(RA.Width, RB.Width), Math.Abs(RA.Height - RB.Height));
}
}
This code was written in Notepad so it might have a typo or two, but the logic is sound.

Related

Folding a selection of points on a 3D cube

I am trying to find an effective algorithm for the following 3D Cube Selection problem:
Imagine a 2D array of Points (lets make it square of size x size) and call it a side.
For ease of calculations lets declare max as size-1
Create a Cube of six sides, keeping 0,0 at the lower left hand side and max,max at top right.
Using z to track the side a single cube is located, y as up and x as right
public class Point3D {
public int x,y,z;
public Point3D(){}
public Point3D(int X, int Y, int Z) {
x = X;
y = Y;
z = Z;
}
}
Point3D[,,] CreateCube(int size)
{
Point3D[,,] Cube = new Point3D[6, size, size];
for(int z=0;z<6;z++)
{
for(int y=0;y<size;y++)
{
for(int x=0;x<size;x++)
{
Cube[z,y,x] = new Point3D(x,y,z);
}
}
}
return Cube;
}
Now to select a random single point, we can just use three random numbers such that:
Point3D point = new Point(
Random(0,size), // 0 and max
Random(0,size), // 0 and max
Random(0,6)); // 0 and 5
To select a plus we could detect if a given direction would fit inside the current side.
Otherwise we find the cube located on the side touching the center point.
Using 4 functions with something like:
private T GetUpFrom<T>(T[,,] dataSet, Point3D point) where T : class {
if(point.y < max)
return dataSet[point.z, point.y + 1, point.x];
else {
switch(point.z) {
case 0: return dataSet[1, point.x, max]; // x+
case 1: return dataSet[5, max, max - point.x];// y+
case 2: return dataSet[1, 0, point.x]; // z+
case 3: return dataSet[1, max - point.x, 0]; // x-
case 4: return dataSet[2, max, point.x]; // y-
case 5: return dataSet[1, max, max - point.x];// z-
}
}
return null;
}
Now I would like to find a way to select arbitrary shapes (like predefined random blobs) at a random point.
But would settle for adjusting it to either a Square or jagged Circle.
The actual surface area would be warped and folded onto itself on corners, which is fine and does not need compensating ( imagine putting a sticker on the corner on a cube, if the corner matches the center of the sticker one fourth of the sticker would need to be removed for it to stick and fold on the corner). Again this is the desired effect.
No duplicate selections are allowed, thus cubes that would be selected twice would need to be filtered somehow (or calculated in such a way that duplicates do not occur). Which could be a simple as using a HashSet or a List and using a helper function to check if the entry is unique (which is fine as selections will always be far below 1000 cubes max).
The delegate for this function in the class containing the Sides of the Cube looks like:
delegate T[] SelectShape(Point3D point, int size);
Currently I'm thinking of checking each side of the Cube to see which part of the selection is located on that side.
Calculating which part of the selection is on the same side of the selected Point3D, would be trivial as we don't need to translate the positions, just the boundary.
Next would be 5 translations, followed by checking the other 5 sides to see if part of the selected area is on that side.
I'm getting rusty in solving problems like this, so was wondering if anyone has a better solution for this problem.
#arghbleargh Requested a further explanation:
We will use a Cube of 6 sides and use a size of 16. Each side is 16x16 points.
Stored as a three dimensional array I used z for side, y, x such that the array would be initiated with: new Point3D[z, y, x], it would work almost identical for jagged arrays, which are serializable by default (so that would be nice too) [z][y][x] but would require seperate initialization of each subarray.
Let's select a square with the size of 5x5, centered around a selected point.
To find such a 5x5 square substract and add 2 to the axis in question: x-2 to x+2 and y-2 to y+2.
Randomly selectubg a side, the point we select is z = 0 (the x+ side of the Cube), y = 6, x = 6.
Both 6-2 and 6+2 are well within the limits of 16 x 16 array of the side and easy to select.
Shifting the selection point to x=0 and y=6 however would prove a little more challenging.
As x - 2 would require a look up of the side to the left of the side we selected.
Luckily we selected side 0 or x+, because as long as we are not on the top or bottom side and not going to the top or bottom side of the cube, all axis are x+ = right, y+ = up.
So to get the coordinates on the side to the left would only require a subtraction of max (size - 1) - x. Remember size = 16, max = 15, x = 0-2 = -2, max - x = 13.
The subsection on this side would thus be x = 13 to 15, y = 4 to 8.
Adding this to the part we could select on the original side would give the entire selection.
Shifting the selection to 0,6 would prove more complicated, as now we cannot hide behind the safety of knowing all axis align easily. Some rotation might be required. There are only 4 possible translations, so it is still manageable.
Shifting to 0,0 is where the problems really start to appear.
As now both left and down require to wrap around to other sides. Further more, as even the subdivided part would have an area fall outside.
The only salve on this wound is that we do not care about the overlapping parts of the selection.
So we can either skip them when possible or filter them from the results later.
Now that we move from a 'normal axis' side to the bottom one, we would need to rotate and match the correct coordinates so that the points wrap around the edge correctly.
As the axis of each side are folded in a cube, some axis might need to flip or rotate to select the right points.
The question remains if there are better solutions available of selecting all points on a cube which are inside an area. Perhaps I could give each side a translation matrix and test coordinates in world space?
Found a pretty good solution that requires little effort to implement.
Create a storage for a Hollow Cube with a size of n + 2, where n is the size of the cube contained in the data. This satisfies the : sides are touching but do not overlap or share certain points.
This will simplify calculations and translations by creating a lookup array that uses Cartesian coordinates.
With a single translation function to take the coordinates of a selected point, get the 'world position'.
Using that function we can store each point into the cartesian lookup array.
When selecting a point, we can again use the same function (or use stored data) and subtract (to get AA or min position) and add (to get BB or max position).
Then we can just lookup each entry between the AA.xyz and BB.xyz coordinates.
Each null entry should be skipped.
Optimize if required by using a type of array that return null if z is not 0 or size-1 and thus does not need to store null references of the 'hollow cube' in the middle.
Now that the cube can select 3D cubes, the other shapes are trivial, given a 3D point, define a 3D shape and test each part in the shape with the lookup array, if not null add it to selection.
Each point is only selected once as we only check each position once.
A little calculation overhead due to testing against the empty inside and outside of the cube, but array access is so fast that this solution is fine for my current project.

How to make rectangle from 4 points in cocoa? for resizable rect

How to make rectangle from 4 points? I'm creating resizable rectangle by the corners.
I can make it with two points like this:
NSMakeRect( MIN(point1.x, point3.x),
MIN(point1.y, point3.y),
fabs(point1.x - point3.x),
fabs(point1.y - point3.y));
It's working good if I move 1 (left bottom) or 3 (right top) corner, but if 2 (left top) or 4 (right bottom) - not. How to make it with 4 NSPoints - corners?
The previous answers have produced you rectangles, but you say they don't do what you want but not why they are wrong... So I'll have a guess, just in case I guess right:
I'm guessing that you have a rectangle and you wish to move one of its corners as you might when click-dragging in a graphical program. I further assume based on your sample code that the rectangle sides are parallel to the axes.
In this scenario the point diagonally opposite the one you move is the anchor - it stays put. The one you move obviously moves, and the other two move to keep the shape rectangular.
If this is the case then you calculate the rectangle based solely on the point you move and its diagonally opposite point. The code you give in your question handles the case if point1 or point3 is moved. You just need a code for the case point2 or point4 is moved, which you get by simple substitution:
NSMakeRect( MIN(point2.x, point4.x),
MIN(point2.y, point4.y),
fabs(point2.x - point4.x),
fabs(point2.y - point4.y));
You now just need to know which point you moved and select the appropriate code.
To build a Rectangle that includes all of your given NSPoints - no matter how many - you'd have to find the minimum and maximum values.
// start by initializing their opposite MIN/MAX values
CGFloat xmin = CGFLOAT_MAX, xmax = CGFLOAT_MIN,
ymin = CGFLOAT_MAX, ymax = CGFLOAT_MIN;
NSUInteger pointCount = ? // you'd have to add this
NSPoint points[pointCount] = { ... } // suppose you know your values :D
for (NSUInteger i = 0; i < pointCount; i++) {
xmin = MIN(xmin, points[i].x);
xmax = MAX(xmax, points[i].x);
ymin = MIN(ymin, points[i].y);
ymax = MAX(ymax, points[i].y);
}
// now create a rect from those points
NSRect rect = NSMakeRect(xmin, ymin, xmax - xmin, ymax - ymin);
I think the main problem for you is points, check them.
Rectangle from 4 points you can draw like this:
NSMakeRect(MIN(MIN(points[0].x, points[2].x), MIN(points[1].x, points[3].x)),
MIN(MIN(points[0].y, points[2].y), MIN(points[1].y, points[3].y)),
MAX(fabs((points[0].x - points[2].x)),fabs(points[1].x - points[3].x)),
MAX(fabs((points[0].y - points[2].y)), fabs((points[1].y - points[3].y))));

How can i extract rectangles from a rectangle intersection

Having a rectangle (A) and intersecting it with another rectangle (B), how could I extract the other rectangles created through that intersection (C,D,E & F)?
AAAAAAAAAAAAAA CCCFFFFDDDDDDD
AAABBBBAAAAAAA CCCBBBBDDDDDDD
AAABBBBAAAAAAA -> CCCBBBBDDDDDDD
AAAAAAAAAAAAAA CCCEEEEDDDDDDD
AAAAAAAAAAAAAA CCCEEEEDDDDDDD
And could this be extended to extract rectangles from several intersections, such as this example which intersects A with B & C and extracts D, E, F & G?
BBBBAAAAAAAAAA BBBBDDDDDDDDDD
BBBBAAAAAAAAAA BBBBDDDDDDDDDD
AAAAAACCCCCAAA -> EEEEEECCCCCFFF
AAAAAACCCCCAAA EEEEEECCCCCFFF
AAAAAAAAAAAAAA EEEEEEGGGGGFFF
If the answer to TJB's question is yes, then they are:
(left, top, right, bottom) notation
C = (A.left, A.top, B.left, A.bottom)
D = (B.right, A.top, A.right, A.bottom)
E = (B.left, B.bottom, B.right, A.bottom)
E = (B.left, A.top, B.right, B.top)
Assuming B is completely Contained in A, it would be something like:
Rectangle[] GetSurrounding( Rectangle outer, Rectangle inner )
{
Rectangle left, top, right, bottom; // Initialize all of these...
left = new Rectangle( outer.Left, outer.Top, outer.Height, inner.Left - outer.Left );
top = new Rectangle( inner.Left, outer.Top, inner.Top - outer.Top, inner.Width );
// So on and so forth...
return new Rectangle[]{ left, top, right, bottom };
}
// This assumes:
Rectangle( x , y , height, width ); // Constructor
Also, deciding weather you stretch the left and right rectangles the full height or the top and bottom rectangles the full width is arbitrary, and will either need to be a constant decision or a parameter to the method. Other cases where the rectangles only partially overlap will require more logic looking at the MAX/MIN of values to check for going out of bounds etc.
If A completly contains B:
Rectange C = new Rectangle(A.X,A.Y,B.X-A.X,A.Height);
Rectange D = new Rectangle(B.Right,A.Y,A.Right-B.Right,A.Height);
Rectange E = new Rectangle(B.X,B.Bottom,B.Width,A.Bottom-A.Bottom);
Rectange F = new Rectangle(B.X,A.Y,B.Width,B.Y-A.Y);
this is .NET, I'm not sure about the language of your code, but I think most of the structures look simular in different languages, in .NET the constructor of a System.Drawing.Rectangle is (X,Y,Width,Height)
for more arbitrary shapes a scanline algorithm would work. you will get different results depending on whether you scan horizontally or vertically (your example matches a vertical scan)
essentially you scan along each column or row and break it into intervals between each shape, intervals on the next column or row with the same start and end can be merged.
Given a large rectangle with any number of smaller rectangles punched out of it, you can use a greedy algorithm to break up the remaining area of the large rectangle into smaller rectangles.
Pick the leftmost, uppermost point that hasn't been covered yet.
Start a rectangle there.
Extend it downwards as far as it can go.
Then extend it rightwards as far as it can go.
Add that rectangle to your collection and repeat.
This is not guaranteed to produce the minimum number of rectangles.
The first step is the most complicated one. If you don't mind a little randomness, an easier thing to do would be to pick random points until you find one that isn't covered yet; then go left until you hit an edge; then go up until you hit an edge.
For a general solution to this (the second half of your question), you should use a corner-stitching data structure, which does exactly this (and more).
for all rectangles A
for all corners C of A
for all other rectangles B
if C is inside B
for all corners D of B
if D is inside A
got rectangle C-D
endif
endfor
endif
endfor
endfor
endfor

Laying out overlapping rectangles

I am trying to layout a bunch of overlapping rectangles that start out like this:
alt text http://img690.imageshack.us/img690/209/picture1bp.png
The 2-pass algorithm I thought up is roughly:
// Pass 1 - Move all rectangles to the right until they do not overlap any other rectangles
rects = getRectsSortedOnTopLeft(); // topmost first, all rects same size
foreach(rect in rects)
{
while(rect.collidingRects().size() != 0)
{
rect.x += RECT_SIZE;
}
}
This (probably) ends up with rectangles laid out like:
alt text http://img685.imageshack.us/img685/9963/picture2bc.png
This is not aesthetically pleasing so I thought of a second pass which would move them all left starting again from the topmost:
// Pass 2
foreach(rect in rects)
{
while(rect.x >= LEFT_MARGIN)
{
assert(rect.collidingRects().size() == 0);
rect.x -= RECT_WIDTH;
if(rect.collidingRects().size() != 0)
{
rect.x += RECT_WIDTH;
break;
}
}
}
I think this should end up looking like below (looks exactly correct in practice):
alt text http://img511.imageshack.us/img511/7059/picture3za.png
However, I am wary of this algorithm because I am not sure if it will lay out correctly in all cases and it may be really slow. Do you think this algorithm can work? Can you make some suggestions on a better algorithm?
I think that this problem is of polynomial complexity. Assuming your example's limitation of only two rectangles overlapping at any given point is not a true limitation of the problem, you would need to try every possible order of bumping the rectangles to the right in order to produce the optimal (least wide) result. This is a form of space packing problem, and those are Hard unless your data set is small enough to brute force.
However, one small improvement to your pseudocode is possible, which would improve its performance in many cases.
Consider this desired final result:
A
A C
A C E
A C E
B C E
B D E
B D F
B D F
D F
F
(where all four of one character are a single rectangle)
Your first pass would move everything except A to the right, forming a staircase. Then in the second pass your code would decline to move B to the left margin, because the first attempt to move it would overlap with E. What you need to do is start at the left margin and check for the leftmost position you can move each rectangle to in pass 2.
Pseudocode:
// Pass 1 - Move all rectangles to the right until they do not overlap any other rectangles
rects = getRectsSortedOnTopLeft(); // topmost first, all rects same width
foreach(rect in rects)
while(rect.collidingRects())
rect.x += RECT_WIDTH;
// Pass 2 - Move all rectangles to the leftmost position in which they don't overlap any other rectangles
foreach(rect in rects)
for(i=LEFT_MARGIN; i+=RECT_WIDTH; i<rect.x)
{
o = rect.x;
rect.x = i;
if(rect.collidingRects())
rect.x = o;
}
You could use a physics-based approach, where the blocks are rigid bodies an fall to the left:
No, this wouldn't produce the best result all the time, but having watched your screencast I think it would be very intuitive to use in an interactive program, and it might be suitable :)

About: Extracting Region From Bitmap

i am trying to extract outline path from given bitmap, i create a fast algorithm (for me) on as3 and that is:
//#v source bitmap's vector data
//#x x to starting extraction
//#y y to stating extraction
//#w extraction width
//#h extraction height
//#mw source bitmap width
//#mh source bitmap height
private function extractRects(v:Vector.<uint>, x:int, y:int,
w:int, h:int, mw:int, mh:int):Array
{
var ary:Array = [], yy:int=y, vStart:int, _xx:int, xx:int;
var lcold:int = 0, lc:int;
//first line to last line
while(yy < h)
{
//first index of current vector
vStart = yy * mw + x;
xx = x;
lc = 0;
//first vector to last on current scan
while(xx < w)
{
/*
if current vector value (color) is
empty (transparent) then
check next
*/
while(xx < w && !v[vStart])
{
vStart++;
xx++;
}
//it is not empty so copy first index
_xx = xx;
//check till value is not empty
while(xx < w && v[vStart])
{
xx++;
vStart++;
}
//create rectangle
var rr:Rectangle = new Rectangle(_xx, yy, (xx-_xx), 1);
//if previous line has the same rectangle index
if(lc < lcold)
{
var oldrr:Rectangle = ary[ary.length - lcold];
//if previous neighbour rect on top
//has same horizontal position then
//resize its height
if(oldrr.left == rr.left && oldrr.width == rr.width)
oldrr.height++;
else
ary.push(rr);
}
else
ary.push(rr);
lc++;
xx++;
}
lcold = lc;
yy++;
}
return ary;
}
With the above method, I extract the region and create shape by drawing rectangles..
Drawing rectangles does not seem to be a good solution because of non-smooth view.
In order to have a smoother view, I must use lines or curves but, using point neighbouring technique is really big headache for me right now.
Could anyone please recommend me any better solution?
as3, c++, c#, vb.net, vb6, delphi, java or similar languages will be fine for answers.
EDIT FOR CLEARIFICATION
I am trying to extract non-transparent pixels' x, y coordinates from a bitmap to draw on different path data. (32 bit ARGB) (creating shape)
For drawing, I could use lineTo, curveTo, moveTo operations.
moveTo(x, y)
lineTo(x, y)
curveTo(cx, cy, ax, ay)
in my code, I thought that I could extract the rectangles of current non-transparent blocks and I could use the same rectangles with moveTo and lineTo operations on further graphic methods
The problem is that this method gives non-smooth look on edges which is neither horizontal nor vertical.
So, the solution is creating a point map on edges, detecting the point neighborhood, using the lineTo operation (because it generates antialiased lines) between neighbour points on rows, or calculating the points placement on nearest circle area and using curveTo method..
Question Could anyone recommend me some algorithms or methods for extracting job?
Thanks in advance
What you're looking for is bitmap/raster image to vector software. To get a good quality result, there are many non-trivial steps that must be performed. There is an open source project called Potrace which does this - click here for a technical description of how it works. If you'd like to try its algorithm in an GUI program, you can use Inkscape with its Trace Bitmap function.

Resources