Finding a second color knowing the distance - algorithm

I'm doing a project where im finding the patterns of 1 color duo and trying to find the unkown second color of the second color duo.
If for example i have 2 colors (first duo):
RGB(60, 90, 80)
RGB(70, 50, 120)
By using the simplest algorithim i find that:
distance = sqrt((r2 - r1)^2 + (g2 - g1)^2 + (b2 - b1)^2)
where distance is 57.
Then i have the second color duo:
RGB(80,45,150)
RGB(x,y,z)
Finding the second color here by only knowing first color + distance is a bit unrealistic, any suggestions on how i could find something like this, or any good insight on workarounds.

Welcome to StackOverflow!
If there is only 1 possible second color, you could calculate the distance simply by the difference of each R, G, and B elements. Therefore, the distance between RGB(60, 90, 80) and RGB(70, 50, 120) is (-10, +40, -40).
If the first color is RGB(80,45,150), then the second color with the same distance is RGB(90, 5, 190)
Another way is to use the distance as radial distance, however this will results in infinitely many possible second colors

You have a spherical surface around the first color point in RGB space (cutted sphere if distance is too long). For exact distance you have integer equation
dr^2 + dg^2 + db^2 = distance^2
that might have: no solutions, and symmetrical cases: 4 solutions, 8 solutions, 16/24 solutions, perhaps more. So task is to find triplets giving needed sum (c.f. Pythagorean triples for 2D case - there are 4 neighbors for distance 2, 8+4 neighbors for distance 5, no neighbors for distance 1.5 and so on).
If some tolerance is allowed, then you can find even more possible solutions.
Seems you need some kind of constraints to limit results.
Also it might be useful to consider another color model like HSV (if color perception is important)

Related

Cover a polygonal line using the least given rectangles while keeping her continuity

Given a list of points forming a polygonal line, and both height and width of a rectangle, how can I find the number and positions of all rectangles needed to cover all the points?
The rectangles should be rotated and may overlap, but must follow the path of the polyline (A rectangle may contain multiple segments of the line, but each rectangle must contain a segment that is contiguous with the previous one.)
Do the intersections on the smallest side of the rectangle, when it is possible, would be much appreciated.
All the solutions I found so far were not clean, here is the result I get:
You should see that it gives a good render in near-flat cases, but overlaps too much in big curbs. One rectangle could clearly be removed if the previous were offset.
Actually, I put a rectangle centered at width/2 along the line and rotate it using convex hull and modified rotating calipers algorithms, and reiterate starting at the intersection point of the previous rectangle and the line.
You may observe that I took inspiration from the minimum oriented rectangle bounding box algorithm, for the orientation, but it doesn't include the cutting aspect, nor the fixed size.
Thanks for your help!
I modified k-means to solve this. It's not fast, it's not optimal, it's not guaranteed, but (IMHO) it's a good start.
There are two important modifications:
1- The distance measure
I used a Chebyshev-distance-inspired measure to see how far points are from each rectangle. To find distance from points to each rectangle, first I transformed all points to a new coordinate system, shifted to center of rectangle and rotated to its direction:
Then I used these transformed points to calculate distance:
d = max(2*abs(X)/w, 2*abs(Y)/h);
It will give equal values for all points that have same distance from each side of rectangle. The result will be less than 1.0 for points that lie inside rectangle. Now we can classify points to their closest rectangle.
2- Strategy for updating cluster centers
Each cluster center is a combination of C, center of rectangle, and a, its rotation angle. At each iteration, new set of points are assigned to a cluster. Here we have to find C and a so that rectangle covers maximum possible number of points. I don’t now if there is an analytical solution for that, but I used a statistical approach. I updated the C using weighted average of points, and used direction of first principal component of points to update a. I used results of proposed distance, powered by 500, as weight of each point in weighted average. It moves rectangle towards points that are located outside of it.
How to Find K
Initiate it with 1 and increase it till all distances from points to their corresponding rectangles become less than 1.0, meaning all points are inside a rectangle.
The results
Iterations 0, 10, 20, 30, 40, and 50 of updating cluster centers (rectangles):
Solution for test case 1:
Trying Ks: 2, 4, 6, 8, 10, and 12 for complete coverage:
Solution for test case 2:
P.M: I used parts of Chalous Road as data. It was fun downloading it from Google Maps. The I used technique described here to sample a set of equally spaced points.
It’s a little late and you’ve probably figured this out. But, I was free today and worked on the constraint reflected in your last edit (continuity of segments). As I said before in the comments, I suggest using a greedy algorithm. It’s composed of two parts:
A search algorithm that looks for furthermost point from an initial point (I used binary search algorithm), so that all points between them lie inside a rectangle of given w and h.
A repeated loop that finds best rectangle at each step and advances the initial point.
The pseudo code of them are like these respectively:
function getBestMBR( P, iFirst, w, h )
nP = length(P);
iStart = iFirst;
iEnd = nP;
while iStart <= iEnd
m = floor((iStart + iEnd) / 2);
MBR = getMBR(P[iFirst->m]);
if (MBR.w < w) & (MBR.h < h) {*}
iStart = m + 1;
iLast = m;
bestMBR = MBR;
else
iEnd = m - 1;
end
end
return bestMBR, iLast;
end
function getRectList( P, w, h )
nP = length(P);
rects = [];
iFirst = 1;
iLast = iFirst;
while iLast < nP
[bestMBR, iLast] = getBestMBR(P, iFirst, w, h);
rects.add(bestMBR.x, bestMBR.y, bestMBR.a];
iFirst = iLast;
end
return rects;
Solution for test case 1:
Solution for test case 2:
Just keep in mind that it’s not meant to find the optimal solution, but finds a sub-optimal one in a reasonable time. It’s greedy after all.
Another point is that you can improve this a little in order to decrease number of rectangles. As you can see in the line marked with (*), I kept resulting rectangle in direction of MBR (Minimum Bounding Rectangle), even though you can cover larger MBRs with rectangles of same w and h if you rotate the rectangle. (1) (2)

In a restricted space with n dimension, how to find the coordinates of p points, so that they are as far as possible from each other?

For example, in a 2D space, with x [0 ; 1] and y [0 ; 1]. For p = 4, intuitively, I will place each point at each corner of the square.
But what can be the general algorithm?
Edit: The algorithm needs modification if dimensions are not orthogonal to eachother
To uniformly place the points as described in your example you could do something like this:
var combinedSize = 0
for each dimension d in d0..dn {
combinedSize += d.length;
}
val listOfDistancesBetweenPointsAlongEachDimension = new List
for each d dimension d0..dn {
val percentageOfWholeDimensionSize = d.length/combinedSize
val pointsToPlaceAlongThisDimension = percentageOfWholeDimensionSize * numberOfPoints
listOfDistancesBetweenPointsAlongEachDimension[d.index] = d.length/(pointsToPlaceAlongThisDimension - 1)
}
Run on your example it gives:
combinedSize = 2
percentageOfWholeDimensionSize = 1 / 2
pointsToPlaceAlongThisDimension = 0.5 * 4
listOfDistancesBetweenPointsAlongEachDimension[0] = 1 / (2 - 1)
listOfDistancesBetweenPointsAlongEachDimension[1] = 1 / (2 - 1)
note: The minus 1 deals with the inclusive interval, allowing points at both endpoints of the dimension
2D case
In 2D (n=2) the solution is to place your p points evenly on some circle. If you want also to define the distance d between points then the circle should have radius around:
2*Pi*r = ~p*d
r = ~(p*d)/(2*Pi)
To be more precise you should use circumference of regular p-point polygon instead of circle circumference (I am too lazy to do that). Or you can compute the distance of produced points and scale up/down as needed instead.
So each point p(i) can be defined as:
p(i).x = r*cos((i*2.0*Pi)/p)
p(i).y = r*sin((i*2.0*Pi)/p)
3D case
Just use sphere instead of circle.
ND case
Use ND hypersphere instead of circle.
So your question boils down to place p "equidistant" points to a n-D hypersphere (either surface or volume). As you can see 2D case is simple, but in 3D this starts to be a problem. See:
Make a sphere with equidistant vertices
sphere subdivision triangulation
As you can see there are quite a few approaches to do this (there are much more of them even using Fibonacci sequence generated spiral) which are more or less hard to grasp or implement.
However If you want to generalize this into ND space you need to chose general approach. I would try to do something like this:
Place p uniformly distributed place inside bounding hypersphere
each point should have position,velocity and acceleration vectors. You can also place the points randomly (just ensure none are at the same position)...
For each p compute acceleration
each p should retract any other point (opposite of gravity).
update position
just do a Newton D'Alembert physics simulation in ND. Do not forget to include some dampening of speed so the simulation will stop in time. Bound the position and speed to the sphere so points will not cross it's border nor they would reflect the speed inwards.
loop #2 until max speed of any p crosses some threshold
This will more or less accurately place p points on the circumference of ND hypersphere. So you got minimal distance d between them. If you got some special dependency between n and p then there might be better configurations then this but for arbitrary numbers I think this approach should be safe enough.
Now by modifying #2 rules you can achieve 2 different outcomes. One filling hypersphere surface (by placing massive negative mass into center of surface) and second filling its volume. For these two options also the radius will be different. For one you need to use surface and for the other volume...
Here example of similar simulation used to solve a geometry problem:
How to implement a constraint solver for 2-D geometry?
Here preview of 3D surface case:
The number on top is the max abs speed of particles used to determine the simulations stopped and the white-ish lines are speed vectors. You need to carefully select the acceleration and dampening coefficients so the simulation is fast ...

Fully cover a rectangle with minimum amount of fixed radius circles

I've had this problem for a few years. It was on an informatics contest in my town a while back. I failed to solve it, and my teacher failed to solve it. I haven't met anyone who was able to solve it. Nobody I know knows the right way to give the answer, so I decided to post it here:
Ze problem
Given a rectangle, X by Y, find the minimum amount of circles N with a fixed given radius R, necessary to fully cover every part of the rectangle.
I have thought of ways to solve it, but I have nothing definite. If each circle defines an inner rectangle, then R^2 = Wi^2 + Hi^2, where Wi and Hi are the width and height of the practical area covered by each circle i. At first I thought I should make Wi equal to Wj for any i=j, the same for H. That way, I could simplify the problem by making the width/height ratios equal with the main rectangle (Wi/Hi = X/Y). That way, N=X/Wi. But that solution is surely wrong in case X greatly exceeds Y or vice versa.
The second idea was that Wi=Hi for any given i. That way, squares fill space most efficiently. However if a very narrow strip remains, it's much more optimal to use rectangles to fill it, or better yet - use rectangles for the last row before that too.
Then I realized that none of the ideas are the optimal, since I can always find better ways of doing it. It will always be close to final, but not final.
Edit
In some cases (large rectangle) joining hexagons seem to be a better solution than joining squares.
Further Edit
Here's a comparison of 2 methods: clover vs hexagonal. Hexagonal is, obviously, better, for large surfaces. I do think however that when the rectangle is small enough, rectangular method may be more efficient. It's a hunch. Now, in the picture you see 14 circles on the left, and 13 circles on the right. Though the surface differs much greater (double) than one circle. It's because on the left they overlap less, thus waste less surface.
The questions still remain:
Is the regular hexagon pattern itself optimal? Or certain adjustments should be made in parts of the main rectangle.
Are there reasons not to use regular shapes as "ultimate solution"?
Does this question even have an answer? :)
For X and Y large compared to R, a hexagonal (honeycomb) pattern is near optimal. The distance between the centers of the circles in the X-direction is sqrt(3)*R. The distance between rows in the Y-direction is 3*R/2, so you need roughly X*Y/R^2 * 2*/(3*sqrt(3)) circles.
If you use a square pattern, the horizontal distance is larger (2*R), but the vertical distance is much smaller (R), so you'd need about X*Y/R^2 * 1/2 circles. Since 2/(3*sqrt(3) < 1/2, the hexagonal pattern is the better deal.
Note that this is only an approximation. It is usually possible to jiggle the regular pattern a bit to make something fit where the standard pattern wouldn't. This is especially true if X and Y are small compared to R.
In terms of your specific questions:
The hexagonal pattern is an optimal covering of the entire plane. With X and Y finite, I would think it is often possible to get a better result. The trivial example is when the height is less than the radius. In that case you can move the circles in the one row further apart until the distance between the intersecting points of every pair of circles equals Y.
Having a regular pattern imposes additional restrictions on the solution, and so the optimal solution under those restrictions may not be optimal with those restrictions removed. In general, somewhat irregular patterns may be better (see the page linked to by mbeckish).
The examples on that same page are all specific solutions. The solutions with more circles resemble the hexagonal pattern somewhat. Still, there does not appear to be a closed-form solution.
This site attacks the problem from a slightly different angle: Given n unit circles, what is the largest square they can cover?
As you can see, as the number of circles changes, so does the covering pattern.
For your problem, I believe this implies: different rectangle dimensions and circle sizes will dictate different optimal covering patterns.
The hexagon is better than the diamond. Consider the percent area of the unit circle covered by each:
#!/usr/bin/env ruby
include Math
def diamond
# The distance from the center to a corner is the radius.
# On a unit circle, that is 1.
radius = 1
# The edge of the nested diamond is the hypotenuse of a
# right triangle whose legs are both radii.
edge = sqrt(radius ** 2 + radius ** 2)
# The area of the diamond is the square of the edge
edge ** 2
end
def hexagon
# The hexagon is composed of 6 equilateral triangles.
# Since the inner edges go from the center to a hexagon
# corner, their length is the radius (1).
radius = 1
# The base and height of an equilateral triangle whose
# edge is 'radius'.
base = radius
height = sin(PI / 3) * radius
# The area of said triangle
triangle_area = 0.5 * base * height
# The area of the hexagon is 6 such triangles
triangle_area * 6
end
def circle
radius = 1
PI * radius ** 2
end
puts "diamond == #{sprintf "%2.2f", (100 * diamond / circle)}%"
puts "hexagon == #{sprintf "%2.2f", (100 * hexagon / circle)}%"
And
$ ./geometrons.rb
diamond == 63.66%
hexagon == 82.70%
Further, regular hexagons are highest-vertex polygon that form a regular tessellation of the plane.
According my calculations the right answer is:
D=2*R; X >= 2*D, Y >= 2*D,
N = ceil(X/D) + ceil(Y/D) + 2*ceil(X/D)*ceil(Y/D)
In particular case if the remainder for X/D and Y/D equal to 0, then
N = (X + Y + X*Y/R)/D
Case 1: R = 1, X = 2, Y = 2, then N = 4
Case 2: R = 1, X = 4, Y = 6, then N = 17
Case 3: R = 1, X = 5, Y = 7, then N = 31
Hope it helps.
When the circles are disposed as a clover with four leafs with a fifth circle in the middle, a circle will cover an area equal to R * 2 * R. In this arrangement, the question becomes: how many circles that cover an area of R * 2 * R will cover an area of W * H?, or N * R * 2 * R = W * H. So N = W * H / R * 2 * R.

What algorithm determines the nearness of a point to a Bezier curve?

I wish to determine when a point (mouse position) in on, or near a curve defined by a series of B-Spline control points.
The information I will have for the B-Spline is the list of n control points (in x,y coordinates). The list of control points can be of any length (>= 4) and define a B-spline consisting of (n−1)/3 cubic Bezier curves. The Bezier curves are are all cubic. I wish to set a parameter k,(in pixels) of the distance defined to be "near" the curve. If the mouse position is within k pixels of the curve then I need to return true, otherwise false.
Is there an algorithm that gives me this information. Any solution does not need to be precise - I am working to a tolerance of 1 pixel (or coordinate).
I have found the following questions seem to offer some help, but do not answer my exact question. In particular the first reference seems to be a solution only for 4 control points, and does not take into account the nearness factor I wish to define.
Position of a point relative to a Bezier curve
Intersection between bezier curve and a line segment
EDIT:
An example curve:
e, 63.068, 127.26
29.124, 284.61
25.066, 258.56
20.926, 212.47
34, 176
38.706, 162.87
46.556, 149.82
54.393, 138.78
The description of the format is: "Every edge is assigned a pos attribute, which consists of a list of 3n + 1 locations. These are B-spline control points: points p0, p1, p2, p3 are the first Bezier spline, p3, p4, p5, p6 are the second, etc. Points are represented by two integers separated by a comma, representing the X and Y coordinates of the location specified in points (1/72 of an inch). In the pos attribute, the list of control points might be preceded by a start point ps and/or an end point pe. These have the usual position representation with a "s," or "e," prefix, respectively."
EDIT2: Further explanation of the "e" point (and s if present).
In the pos attribute, the list of control points might be preceded by a start
point ps and/or an end point pe. These have the usual position representation with a
"s," or "e," prefix, respectively. A start point is present if there is an arrow at p0.
In this case, the arrow is from p0 to ps, where ps is actually on the node’s boundary.
The length and direction of the arrowhead is given by the vector (ps −p0). If there
is no arrow, p0 is on the node’s boundary. Similarly, the point pe designates an
arrow at the other end of the edge, connecting to the last spline point.
You may do this analitically, but a little math is needed.
A Bezier curve can be expressed in terms of the Bernstein Basis. Here I'll use Mathematica, that provides good support for the math involved.
So if you have the points:
pts = {{0, -1}, {1, 1}, {2, -1}, {3, 1}};
The eq. for the Bezier curve is:
f[t_] := Sum[pts[[i + 1]] BernsteinBasis[3, i, t], {i, 0, 3}];
Keep in mind that I am using the Bernstein basis for convenience, but ANY parametric representation of the Bezier curve would do.
Which gives:
Now to find the minimum distance to a point (say {3,-1}, for example) you have to minimize the function:
d[t_] := Norm[{3, -1} - f[t]];
For doing that you need a minimization algorithm. I have one handy, so:
NMinimize[{d[t], 0 <= t <= 1}, t]
gives:
{1.3475, {t -> 0.771653}}
And that is it.
HTH!
Edit Regarding your edit "B-spline with consisting of (n−1)/3 cubic Bezier curves."
If you constructed a piecewise B-spline representation you should iterate on all segments to find the minima. If you joined the pieces on a continuous parameter, then this same approach will do.
Edit
Solving your curve. I disregard the first point because I really didn't understand what it is.
I solved it using standard Bsplines instead of the mathematica features, for the sake of clarity.
Clear["Global`*"];
(*first define the points *)
pts = {{
29.124, 284.61}, {
25.066, 258.56}, {
20.926, 212.47}, {
34, 176}, {
38.706, 162.87}, {
46.556, 149.82}, {
54.393, 138.78}};
(*define a bspline template function *)
b[t_, p0_, p1_, p2_, p3_] :=
(1-t)^3 p0 + 3 (1-t)^2 t p1 + 3 (1-t) t^2 p2 + t^3 p3;
(* define two bsplines *)
b1[t_] := b[t, pts[[1]], pts[[2]], pts[[3]], pts[[4]]];
b2[t_] := b[t, pts[[4]], pts[[5]], pts[[6]], pts[[7]]];
(* Lets see the curve *)
Show[Graphics[{Red, Point[pts], Green, Line[pts]}, Axes -> True],
ParametricPlot[BSplineFunction[pts][t], {t, 0, 1}]]
.
( Rotated ! for screen space saving )
(*Now define the distance from any point u to a point in our Bezier*)
d[u_, t_] := If[(0 <= t <= 1), Norm[u - b1[t]], Norm[u - b2[t - 1]]];
(*Define a function that find the minimum distance from any point u \
to our curve*)
h[u_] := NMinimize[{d[u, t], 0.0001 <= t <= 1.9999}, t];
(*Lets test it ! *)
Plot3D[h[{x, y}][[1]], {x, 20, 55}, {y, 130, 300}]
This plot is the (minimum) distance from any point in space to our curve (of course the value over the curve is zero):
First, render the curve to a bitmap (black and white) with your favourite algorithm. Then, whenever you need, determine the nearest pixel to the mouse position using information from this question. You can modify the searching function so that it will return distance, so you can easilly compare it with your requirements. This method gives you the distance with tolerance of 1-2 pixels, which will do, I guess.
Definition: distance from a point to a line segment = distance from the original point to the closest point still on the segment.
Assumption: an algo to compute the distance from a point to a segment is known (e.g. compute the intercept with the segment of the normal to the segment passing through the original point. If the intersection is outside the segment, pick the closest end-point of the segment)
use the deCasteljau algo and subdivide your cubics until getting to a good enough daisy-chain of linear segments. Supplementary info the "Bezier curve flattening" section
consider the minimum of the distances between your point and the resulted segments as the distance from your point to the curve. Repeat for all the curves in your set.
Refinement at point 2: don't compute the actual distance, but the square of it, getting the minimum square distance is good enough - saves a sqrt call/segment.
Computation effort: empirically a cubic curve with a maximum extent (i.e. bounding box) of 200-300 results in about 64 line segments when flattened to a maximum tolerance of 0.5 (approx good enough for the naked eye).
Each deCasteljau step requires 12 division-by-2 and 12 additions.
Flatness evaluation - 8 multiplications + 4 additions (if using the TaxiCab distance to evaluate a distance)
the evaluation of point-to-segment distance requires at max 12 multiplications and 11 additions - but this will be a rare case in the context of Bezier flattening, I'd expect an average of 6 multiplications and 9 additions.
So, assuming a very bad case (100 straight segments/cubic), you finish in finding your distance with a cost of approx 2600 multiplications + 2500 additions per considered cubic.
Disclaimers:
don't ask me for a demonstration on the numbers in
the computational effort evaluation above,
I'll answer with "Use the source-code" (note: Java implementation).
other approaches may be possible and maybe less costly.
Regards,
Adrian Colomitchi

Positioning squares on a circle with minimum diameter

Given n squares with edge length l, how can I determine the minimum radius r of the circle so that I can distribute all squares evenly along the perimeter of the circle without them overlapping? (Constraint: the first square will always be positioned at 12 o'clock.)
Followup question: how can I place n identical rectangles with height h and width w?
(source: n3rd.org)
There may be a mathematically clever way to do this, but I wouldn't know.
I think it's complicated a bit by the fact that the geometry is different for every different number of squares; for 4 it's a rhombus, for 5 it's a pentagon and so on.
What I'd do is place those squares on a 1 unit circle (much too small, I know, bear with me) distributed equally on it. That's easy enough, just subtend (divide) your 360 degrees by the number of squares. Then just test all your squares for overlap against their neighbors; if they overlap, increase the radius.
You can make this procedure less stupid than it sounds by using an intelligent algorithm to approach the right size. I'm thinking of something like Newton's algorithm: Given two successive guesses, of which one is too small and one is too big, your next guess needs to be the average of those two.
You can iterate down to any precision you like. Stop whenever the distance between guesses is smaller than some arbitrary small margin of error.
EDIT I have a better solution:
I was thinking about what to tell you if you asked "how will I know if squares overlap?" This gave me an idea on how to calculate the circle size exactly, in one step:
Place your squares on a much-too-small circle. You know how: Calculate the points on the circle where your 360/n angles intersect it, and put the center of the square there. Actually, you don't need to place squares yet, the next steps only require midpoints.
To calculate the minimum distance of a square to its neighbor: Calculate the difference in X and the difference in Y of the midpoints, and take the minimum of those. The X's and Y's are actually just cosines and sines on the circle.
You'll want the minimum of any square against its neighbor (clockwise, say). So you need to work your way around the circle to find the very smallest one.
The minimum (X or Y) distance between the squares needs to become 1.0 . So just take the reciprocal of the minimum distance and multiply the circle's size by that. Presto, your circle is the right size.
EDIT
Without losing generality, I think it's possible to nail my solution down a bit so it's close to coding. Here's a refinement:
Assume the squares have size 1, i.e. each side has a length of 1 unit. In the end, your boxes will surely be larger than 1 pixel but it's just a matter of scaling.
Get rid of the corner cases:
if (n < 2) throw new IllegalArgumentException();
if (n == 2) return 0.5; // 2 squares will fit exactly on a circle of radius 0.5
Start with a circle size r of 0.5, which will surely be too small for any number of squares > 2.
r = 0.5;
dmin = 1.0; // start assuming minimum distance is fine
a = 2 * PI / n;
for (p1 = 0.0; p1 <= PI; p1+=a) { // starting with angle 0, try all points till halfway around
// (yeah, we're starting east, not north. doesn't matter)
p2 = p1 + a; // next point on the circle
dx = abs(r * cos(p2) - r * cos(p1))
dy = abs(r * sin(p2) - r * sin(p1))
dmin = min(dmin, dx, dy)
}
r = r / dmin;
EDIT
I turned this into real Java code and got something quite similar to this to run. Code and results here: http://ideone.com/r9aiu
I created graphical output using GnuPlot. I was able to create simple diagrams of boxes arranged in a circle by cut-and-pasting the point sets from the output into a data file and then running
plot '5.dat' with boxxyerrorbars
The .5's in the file serve to size the boxes... lazy but working solution. The .5 is applied to both sides of the center, so the boxes end up being exactly 1.0 in size.
Alas, my algorithm doesn't work. It makes the radii far too large, thus placing the boxes much further apart than necessary. Even scaling down by a factor of 2 (could have been a mistake to use 0.5 in some places) didn't help.
Sorry, I give up. Maybe my approach can be salvaged, but it doesn't work the way I had though it would. :(
EDIT
I hate giving up. I was about to leave my PC when I thought of a way to salvage my algorithm:
The algorithm was adjusting the smaller of the X or Y distances to be at least 1. It's easy to demonstrate that's just plain silly. When you have a lot of boxes then at the eastern and western edges of the circle you have boxes stacked almost directly on top of each other, with their X's very close to one another but they are saved from touching by having just enough Y distance between them.
So... to make this work, you must scale the maximum of dx and dy to be (for all cases) at least the radius (or was it double the radius?).
Corrected code is here: http://ideone.com/EQ03g http://ideone.com/VRyyo
Tested again in GnuPlot, it produces beautiful little circles of boxes where sometimes just 1 or 2 boxes are exactly touching. Problem solved! :)
(These images are wider than they are tall because GnuPlot didn't know I wanted proportional layout. Just imagine the whole works squeezed into a square shape :) )
I would calculate an upper bound of the minimum radius, by working with circles enclosing the squares instead of with the squares themselves.
My calculation results in:
Rmin <= X / (sqrt(2) * sin (180/N) )
Where:
X is the square side length, and N is the required number of squares.
I assume that the circles are positioned such that their centers fall on the big circle's circumference.
-- EDIT --
Using the idea of Dave in the comment below, we can also calculate a nice lower bound, by considering the circles to be inside the squares (thus having radius X/2). This bound is:
Rmin >= X / (2 * sin (180/N) )
As already noted, the problem of positioning n points equally spaced round the circumference of a circle is trivial. The (not-terribly) difficult part of the problem is to figure out the radius of the circle needed to give a pleasing layout of the squares. I suggest you follow one of the other answers and think of the squares being inside a circular 'buffer' big enough to contain the square and enough space to satisfy your aesthetic requirements. Then check the formula for the chord length between the centres of neighbouring squares. Now you have the angle, at the centre of the circle, subtended by the chord between square centres, and can easily compute the radius of the circle from the trigonometry of a triangle.
And, as to your follow up question: I suggest that you work out the problem for squares of side length min(h,w) on a circle, then transform the squares to rectangles and the circle to an ellipse with eccentricity h/w (or w/h).
I would solve it like this:
To find the relation between the radius r and length l let's analyze dimensionless representation
get the centres on a circle (x1,y1)..(xn,yn)
from each center get lower right corner of the i-th square and upper left corner of the i+1-th square
the two points should either have equal x or equal y, whichever yields smaller l
procedure should be repeated for each center and the one that yields smallest l is the final solution.
This is the optimal solution and can be solved it terms of r = f(l).
The solution can be adapted to rectangles by adjusting the formula for xLR[i] and yUL[i+1].
Will try to give some pseudo code.
EDIT:
There's a bug in the procedure, lower right and upper left are not necessary closest points for two neighbouring squares/rectangles.
Let's assume you solved the problem for 3 or 4 squares.
If you have n >= 5 squares, and position one square at the top of the circle, you'll have another square fall into the first quadrant of a cartesian plane concentric with your circle.
The problem is then to find a radius r for the circle such that the left side of the circle next to the top one, and the right side of the top circle do not 'cross' each other.
The x coordinate of the right side of the top circle is x1 = L/2, where L is the side of a square. The x coordinate of the left side of the circle next to the top one is x2 = r cos a - L/2, where r is the radius and a is the angle between each pair of square centres (a = 360/n degrees).
So we need to solve x1 <= x2, which leads to
r >= L / cos a.
L and a are known, so we're done :-)
You start with an arbitrary circle (e.g., with a diameter of (* n l)) and position the squares evenly on the circumference. Then you go through each pair of adjacent squares and:
calculate the straight line connecting their mid points,
calculate the intersection of this line with the intervening square sides (M1 and M2 are the mid points, S1 and S2 the corresponding intersections with the square side:
S2 S1
M1--------------*----------*---------------M2
------------------------
| |
| |
| |
| |
| M1 |
| \ |
| \ |
| -------*------- +--------
| | \ | |
| | \ | |
-------+---------*------ |
| \ |
| M2 |
| |
| |
| |
| |
-------------------------
calculate the scale factor you would need to make S1 and S2 fall together (simply the ratio of the sum of M1-S1 and S2-M2 to M1-M2), and
finally scale the circle by the maximum of the found scale factors.
Edit: This is the exact solution. However, a little thought can optimize this further for speed:
You only need to do this for the squares closest to 45° (if n is even) resp. 45° and 135° (if n is odd; actually, you might prove that only one of these is necessary).
For large n, the optimal spacing of the squares on the circle will quickly approach the length of a diagonal of a square. You could thus precompute the scaling factors for a few small n (up to a dozen or so), and then have a good enough approximation with the diagonal.

Resources