How can I better pack rectangles tangent to a sphere for a 3d gallery? - actionscript-3

I am creating a 3D sphere gallery with ActionScript 3 and the Flash 10 3D (2.5D) APIs. I have found a method that works but is not ideal. I would like to see if there is a better method.
My algorithm goes like this:
Let n = the number of images
h = the height of each image
w = the width of each image
Approximate the radius of the circle by assuming (incorrectly) that the surface area of the images is equal to the surface area of the sphere we want to create.To calculate the radius solve for r in nwh = 4πr2. This is the part that needs to be improved.
Calculate the angle between rows. rowAngle = 2atan(h / 2 / r).
Calculate the number of rows.rows = floor(π / rowAngle).
Because step one is an approximation, the number of rows will not fit perfectly, so for presentation add padding rowAngle.rowAngle += (π - rowAngle * rows) / rows.
For each i in rows:
Calculate the radius of the circle of latitude for the row.latitudeRadius = radius * cos(π / 2 - rowAngle * i.
Calculate the angle between columns.columnAngle = atan(w / 2 / latitudeRadius) * 2.
Calculate the number of colums.columns = floor(2 * π / columnAngle)
Because step one is an approximation, the number of columns will not fit perfectly, so for presentation add padding to columnAngle.columnAngle += (2 * π - columnAngle * column) / column.
For each j in columns, translate -radius along the Z axis, rotate π / 2 + rowAngle * i around the X axis, and rotate columnAngle * j around the Y axis.
To see this in action, click here. alternate link. Notice that with the default settings, the number of items actually in the sphere are less by 13. I believe is the error introduced by my approximation in the first step.
I am not able to figure out a method for determining what the exact radius of such a sphere should be. I'm hoping to learn either a better method, the correct method, or that what I am trying to do is hard or very hard (in which case I will be happy with what I have).

I would divide this problem into two connected problems.
Given a radius, how do you pack things on to the sphere?
Given a number of things, how do you find the right radius?
If you have a solution to the first problem, the second is easy to solve. Here it is in pseudo-code.
lowerRadius = somethingTooSmall
fittedItems = itemsForRadius(lowerRadius)
while fittedItems < wantedItems:
lowerRadius *= 2
fittedItems = itemsForRadius(lowerRadius)
upperRadius = 2 * lowerRadius
while threshold < upperRadius - lowerRadius:
middleRadius = (upperRadius + lowerRadius)/2
if itemsForRadius(middleRadius) < wantedItems:
lowerRadius = middleRadius
else:
upperRadius = middleRadius
This will find the smallest radius that will pack the desired number of things with your packing algorithm. If you wish you could start with a better starting point - your current estimate is pretty close. But I don't think that an analytic formula will do it.
Now let's turn to the first problem. You have a very reasonable approach. It does have one serious bug though. The bug is that your columnAngle should not be calculated for the middle of your row. What you need to do is figure out the latitude which your items are in that is closest to the pole, and use that for the calculation. This is why when you try to fit 10 items you find a packing that causes the corners to overlap.
If you want a denser packing, you can try squishing rows towards the equator. This will result in sometimes having room for more items in a row so you'll get more things in a smaller sphere. But visually it may not look as nice. Play with it, and decide whether you like the result.
BTW I like the idea. It looks nice.

In the case of squares, it seems to be an approximate formula for knowing the relationship between the radius, the square's side and the number of squares embedded.
Following this, the number of squares is:
Floor[4 Pi/Integrate[(x^2 + y^2 + r^2)^(-3/2), {x, -a/2, a/2}, {y, -a/2, a/2}]]
or
Floor[(Pi r)/ArcCot[(2 Sqrt[2] r Sqrt[a^2+2 r^2])/a^2]]
where
r = Radius
a = Square side
If you plot for r=1, as a function of a:
Where you can see the case a=2 is the boundary for n=6, meaning a cube:
Still working to see if it can be extended to the case of a generic rectangle.
Edit
For rectangles, the corresponding formula is:
Floor[4 Pi/Integrate[(x^2 + y^2 + r^2)^(-3/2), {x, -a/2, a/2}, {y, -b/2, b/2}]]
which gives:
Floor[(2 Pi r)/(Pi-2 ArcTan[(2 r Sqrt[a^2+b^2+4 r^2])/(a b)])]
where
r = Radius
a,b = Rectangle sides
Let's suppose we want rectangles with one side half of the other (b = a/2) and a sphere of radius 1.
So, the number of rectangles as a function of a gives:
Where you may see that a rectangle with a "large" side of size 2 allows 10 rectangles in the sphere, while a rectangle of "large" side 4 allows only 4 rectangles.

Related

PCA in 2D calculate center point in original data

I'm trying to create a bounding box around a given dataset.
My Idea therefore was to use a PCA. I read that it won't always find optimal solutions but this doesn't matter.
What I've done so far is that I calculate the covariance-matrix and use it to calculate a SVD of this matrix.
Lets say we have a sample input like
[40, 20], [-40, -20],[40, -20],[-40, 20],[30, 30]
The covariance matrix will become
[1780.0, 180.0] [180.0, 580.0]
With the SVD I get the rotation matrix U:
[0.99, 0.15]
[0.15, -0.99]
and the diagonal matrix D:
[1806.41, 0]
[0, 553.58]
With my eigenvectors I'm able to calculate the slope of the lines representing the box.
I now need to get the center of the PCA in the original space not in the 0-centered space.
And I also need to find out the length of those to vectors.
Does anyone has an idea how to get them?
Interesting question.Just some thoughts.
Is the centre you are referring to the mean of the data?
Think it this way, if we can project back (0,0) to the original space, it's the mean.
To find the length, assuming you are trying to include every point in the box, you can project every point in each principle component direction and record the largest and smallest coordinates. The difference will be the length.
By the way, I am under the impression that PCA on correlation matrix is usually the more appropriate choice and I think that applies to your question too.
I found a solution.
The idea was to use the two eigenvectors to calculte the maximum distance of all point to it.
The maximum distance will than be half the length of the rectangles width and height. As shown in the picture below
To position the rectangle I calculate the 4 points by
p1.x = max1 * eigenvector1(0) + max2 * eigenvector1(1)
p1.y = max1 * eigenvector2(0) + max2 * eigenvector2(1)
for all points.
Than I just had to transform the vertices and all datapoints by meanX and meanY and the rectangle enclosing the original dataset.
The problem in the solution above was that using just max was not the best idea, because it will always just be minimal in one direction of the eigenvectors.
By using min and max I'm now able to create minimal enclosing boxes in both directions of the principal components.
To calculate the points I used the code below, where minDistX is the absolute value of the minimum distance:
p1.setX(minDist2 * U[0][0] + maxDist1 * U[0][1]);
p1.setY(minDist2 * U[1][0] + maxDist1 * U[1][1]);
p2.setX(minDist2 * U[0][0] - minDist1 * U[0][1]);
p2.setY(minDist2 * U[1][0] - minDist1 * U[1][1]);
p3.setX(-(maxDist2 * U[0][0] + minDist1 * U[0][1]));
p3.setY(-(maxDist2 * U[1][0] + minDist1 * U[1][1]));
p4.setX(-(maxDist2 * U[0][0] - maxDist1 * U[0][1]));
p4.setY(-(maxDist2 * U[1][0] - maxDist1 * U[1][1]));

Calculating how many shapes of specific size fit inside polygon on Google Maps

I would like the user to draw a polygon shape on google maps - this isnt an issue and have this sorted.
When the user then clicks a button, I need to work out how many rectangular shapes of a specific size will fit inside this polygon.
The issue I have is if the polygon is for example 6m x 4m and the shape that needs to fit is 2m x 3m, then you can only fit 3 shapes (area totalling 6m x 3m if the shapes are side by side) and leaves 6m x 1m area remaining.
The remaining area is the same area as the shape, but its the wrong size.
How do I see how many "whole" shapes fit inside the polygon?
I will upload an image to show what I mean
This is actually a difficult problem a particular case of a packing problems a full solution would turn out to be quite complex, possibly NP-hard.
It should be fairly easy to derive a sub-optimal solution. We can consider two possible solutions with the rectangles horizontal or vertical with them in a uniform grid.
Let the size of the big rectangle be A X B and the small rectangle be a X b. For the unrotated version we can fit m=floor(A/a) horizontally and n=floor(B/b) vertically giving a total of n*m items fitted in. Rotating by 90º we have p=floor(A/b) and q=floor(B/a) with a total of p*q items.
There will be some which the above does not give the best solution, say a fitting 2X3 rectangles into 5 X 4. If two are horizontal and one is vertical then you can fit 3 in.
For an irregular polygon boundary you could arrange them in rows with the distance between each row equal to the height of the smaller rectangles.
A pseudocode solution might work something like
poly = getPolygon() // get the input polygon
a = rectangle.height // size of rectangle we are trying to fit
b = rectangle.width // size of rectangle
row_height = 10
bounds = poly.getBoundingBox()
offset_top = a/2 // y coord of the first row
// loop from top to bottom
for(y = bounds.top + offset_top ; y < bounds.bottom; y += a )
{
// find all the solutions of the polygon with a horizontal line
sols1 = poly.intersectWithHorizontalLine(y)
// find sols of bottom line
sols2 = poly.intersectWithHorizontalLine(y+a)
// find the left most and right most points
left = min(sols1,sols2)
right = max(sols1,sols2)
// now can draw the rectangles
for(x=left; x < right; x += b)
{
drawRectangle( x , y, width=b, height=a)
}
}

what's the appropriate algorithm for locating places using Cartesian coordinate system

what's the algorithm to be able locate and display places around me within a particular distance such as 100m,using easting and northing and name of the place where I'm based .
To be more clear, lets suppose I'm based in charing cross and I want to find all places within 100m using easting and northing data for example, easting =10000m and easting=20000m.
Thank you
Pythagoras is the relevant maths.
If your position is (x,y) then you can calc a distance to any other point (x2,y2) with:
distance = sqrt((x2-x)^2 + (y2-y)^2)
So you could just loop over all points, calc their distance and order the results by nearest first.
For large data sets this may become impractical, in which case you'll want to partition the points into large rectangles. The first stage then is to identify which rectangle your (x,y) is within and the adjacent rectangles, then loop through all points in those rectangles. You need the adjacent rectangles because your (x,y) might be right on the boundary of its rectangle.
More generally this partitioning approach comes under the general heading of spatial hashing. For very large areas you want a tree structure known as a quadtree, that breaks large areas down into smaller and smaller regions, but that might be overkill for what you want.
I am assuming by Cartesian coordinates you also mean linear. If you are trying to do this using actual earth coordinates this answer gets more complicated (as we aren't on a flat earth). For simple linear coordinates you could do something like:
bool contains( x, y)
{
return (x >= minx) && (x <= maxx) && (y >= miny) && (y <= maxy);
}
The min, max coordinates would be your current position + how far out you wanted to go. I think this is what you wanted to know. If you need accurate earth coordinates you might look into some geospatial libraries. If you need and estimate you can still use the algorithm above but I would use something like Rhumb lines to calculate the min, max coordinates.

How do I zoom into the mandelbrot set?

I can generate a 400x400 image of the Mandelbrot set from minReal to maxReal and from minImaginary to maxImaginary. So,
makeMandel(minReal, maxReal, minImaginary, maxImaginary);
I need to modify it so that I can have,
makeMandel(centerX, centerY, Zoomlevel);
// generates a region of the mandelbrot set centered at centerX,centerY at a zoom level of Zoomlevel
(Considering zoom level represents the distance between the pixels and is given by the formula Zoom level n = 2 ^ (-n) so that zoom level 1 means pixels are 0.5 units apart, zoom level 2, 0.25 and so on...)
My question is how do I calculate the arguments of the first makeMandel function from the arguments of the second one?
I know that the first function is capable of zooming and moving around but I don't know how to calculate the correct numbers for any given center and zoom level.
I've been trying to get this working for more than three days now and I'm really confused. I tried drawing tables, etc... on paper and working it out.
I read most documents that you find on Google when searching for the mandelbrot set and a couple of past stackoverflow questions but I still don't understand. Please help me out.
You may solve it the following way. If you have the two definitions
centerX = (minReal + maxReal)/2
sizeX = maxReal - minReal
you can calculate extends on the axis via
minReal = centerX - sizeX/2
maxReal = centerX + sizeX/2
The size then is calculated using the zoomLevel:
sizeX = 2^(-zoomLevel) * baseSize
The same formulas hold for y and imaginary axis.
sizeY = 2^(-zoomLevel) * baseSize
minImaginary = centerY - sizeY/2
maxImaginary = centerY + sizeY/2
The only thing to define as a constant is your baseSize, i.e. the extend in real and imaginary axis when zoomLevel is zero. You may consider different baseSize in real and imaginary direction to cover an non-square aspect ratio of your image.

Finding a free area in the stage

I'm drawing rectangles at random positions on the stage, and I don't want them to overlap.
So for each rectangle, I need to find a blank area to place it.
I've thought about trying a random position, verify if it is free with
private function containsRect(r:Rectangle):Boolean {
var free:Boolean = true;
for (var i:int = 0; i < numChildren; i++)
free &&= getChildAt(i).getBounds(this).containsRect(r);
return free;
}
and in case it returns false, to try with another random position.
The problem is that if there is no free space, I'll be stuck trying random positions forever.
There is an elegant solution to this?
Let S be the area of the stage. Let A be the area of the smallest rectangle we want to draw. Let N = S/A
One possible deterministic approach:
When you draw a rectangle on an empty stage, this divides the stage into at most 4 regions that can fit your next rectangle. When you draw your next rectangle, one or two regions are split into at most 4 sub-regions (each) that can fit a rectangle, etc. You will never create more than N regions, where S is the area of your stage, and A is the area of your smallest rectangle. Keep a list of regions (unsorted is fine), each represented by its four corner points, and each labeled with its area, and use weighted-by-area reservoir sampling with a reservoir size of 1 to select a region with probability proportional to its area in at most one pass through the list. Then place a rectangle at a random location in that region. (Select a random point from bottom left portion of the region that allows you to draw a rectangle with that point as its bottom left corner without hitting the top or right wall.)
If you are not starting from a blank stage then just build your list of available regions in O(N) (by re-drawing all the existing rectangles on a blank stage in any order, for example) before searching for your first point to draw a new rectangle.
Note: You can change your reservoir size to k to select the next k rectangles all in one step.
Note 2: You could alternatively store available regions in a tree with each edge weight equaling the sum of areas of the regions in the sub-tree over the area of the stage. Then to select a region in O(logN) we recursively select the root with probability area of root region / S, or each subtree with probability edge weight / S. Updating weights when re-balancing the tree will be annoying, though.
Runtime: O(N)
Space: O(N)
One possible randomized approach:
Select a point at random on the stage. If you can draw one or more rectangles that contain the point (not just one that has the point as its bottom left corner), then return a randomly positioned rectangle that contains the point. It is possible to position the rectangle without bias with some subtleties, but I will leave this to you.
At worst there is one space exactly big enough for our rectangle and the rest of the stage is filled. So this approach succeeds with probability > 1/N, or fails with probability < 1-1/N. Repeat N times. We now fail with probability < (1-1/N)^N < 1/e. By fail we mean that there is a space for our rectangle, but we did not find it. By succeed we mean we found a space if one existed. To achieve a reasonable probability of success we repeat either Nlog(N) times for 1/N probability of failure, or N² times for 1/e^N probability of failure.
Summary: Try random points until we find a space, stopping after NlogN (or N²) tries, in which case we can be confident that no space exists.
Runtime: O(NlogN) for high probability of success, O(N²) for very high probability of success
Space: O(1)
You can simplify things with a transformation. If you're looking for a valid place to put your LxH rectangle, you can instead grow all of the previous rectangles L units to the right, and H units down, and then search for a single point that doesn't intersect any of those. This point will be the lower-right corner of a valid place to put your new rectangle.
Next apply a scan-line sweep algorithm to find areas not covered by any rectangle. If you want a uniform distribution, you should choose a random y-coordinate (assuming you sweep down) weighted by free area distribution. Then choose a random x-coordinate uniformly from the open segments in the scan line you've selected.
I'm not sure how elegant this would be, but you could set up a maximum number of attempts. Maybe 100?
Sure you might still have some space available, but you could trigger the "finish" event anyway. It would be like when tween libraries snap an object to the destination point just because it's "close enough".
HTH
One possible check you could make to determine if there was enough space, would be to check how much area the current set of rectangels are taking up. If the amount of area left over is less than the area of the new rectangle then you can immediately give up and bail out. I don't know what information you have available to you, or whether the rectangles are being laid down in a regular pattern but if so you may be able to vary the check to see if there is obviously not enough space available.
This may not be the most appropriate method for you, but it was the first thing that popped into my head!
Assuming you define the dimensions of the rectangle before trying to draw it, I think something like this might work:
Establish a grid of possible centre points across the stage for the candidate rectangle. So for a 6x4 rectangle your first point would be at (3, 2), then (3 + 6 * x, 2 + 4 * y). If you can draw a rectangle between the four adjacent points then a possible space exists.
for (x = 0, x < stage.size / rect.width - 1, x++)
for (y = 0, y < stage.size / rect.height - 1, y++)
if can_draw_rectangle_at([x,y], [x+rect.width, y+rect.height])
return true;
This doesn't tell you where you can draw it (although it should be possible to build a list of the possible drawing areas), just that you can.
I think that the only efficient way to do this with what you have is to maintain a 2D boolean array of open locations. Have the array of sufficient size such that the drawing positions still appear random.
When you draw a new rectangle, zero out the corresponding rectangular piece of the array. Then checking for a free area is constant^H^H^H^H^H^H^H time. Oops, that means a lookup is O(nm) time, where n is the length, m is the width. There must be a range based solution, argh.
Edit2: Apparently the answer is here but in my opinion this might be a bit much to implement on Actionscript, especially if you are not keen on the geometry.
Here's the algorithm I'd use
Put down N number of random points, where N is the number of rectangles you want
iteratively increase the dimensions of rectangles created at each point N until they touch another rectangle.
You can constrain the way that the initial points are put down if you want to have a minimum allowable rectangle size.
If you want all the space covered with rectangles, you can then incrementally add random points to the remaining "free" space until there is no area left uncovered.