Reputation: 123
I have a certain requirement which becomes an interesting Mathematical problem.
Given a number n and fixed distance d and Point p(x,y) inside rectangle R of fixed width and height (which is screen). I want to draw n squares inside rectangle with maximum size possible (all squares same size) and squares not intersect each other and are separate from each other by minimum distance d (Distance from perimeter of square).
These squares should also be at least at distance d from a given point P (which is basically mouse's last recorded position).
Please let me know if there is a solution to this.
Solution should give size of square and coordinates for all squares.
The reverse interesting problem could be given size of square how many such squares can be drawn.
Upvotes: 0
Views: 143
Reputation: 8641
I've got a fiddle here that probably does a near-optimal tiling.
It's godawful ugly, though.
It reminds me of some customers of mine insisting on dabbling in detailed specifications instead of remaining at functional requirement level :).
The heart of the algorithm is here:
compute: function ()
{
function try_size (x1, x2, y1, y2, w, h, y)
{
var d = Math.sqrt((this.w+this.h)/this.n);
var delta = 10*d;
var n = 0;
while ((delta > 1e-12) || (n < this.n))
{
var res = {};
if (y < (d/2-this.d))
{
res.x1 = res.x2 = res.y1 = 0;
res.y2 = Math.floor ((h-y-this.d)/d);
res.c1 = true;
}
else if (y > (h-d+2*this.d))
{
res.x1 = res.x2 = res.y2 = 0;
res.y1 = Math.floor ((y-this.d)/d);
res.c2 = true;
}
else
{
res.y1 = Math.floor((y1-d/2)/d);
res.y2 = Math.floor((y2-d/2)/d);
res.x1 = Math.floor ((x1-this.d/2)/d);
res.x2 = Math.floor ((x2-this.d/2)/d);
}
res.w = Math.floor ((w+this.d)/d);
n = res.x1+res.x2+res.w*(res.y1+res.y2);
d += n > this.n ? delta : -delta;
if (delta > 1e-12) delta /=2;
}
res.d = d;
res.s = d-2*this.d;
return res;
}
The idea is to tile the rectangle regularily, except for the band around the center point. Horizontal and vertical variants of this band are tried to retain the highest square size.
I guess an optimal solution would not center the band around the center point, but given the awful looks of the result, I don't think it's worth the effort :)
(just a proof of concept; some edge cases are handled wrongly).
compute: function ()
{
var d = Math.sqrt((this.w+this.h)/this.n);
var delta = 100*d;
while ((delta > 1e-12) || (res.n < this.n))
{
var res = {};
res.x = Math.floor ((this.w-this.x%d)/d);
res.y = Math.floor ((this.h-this.y%d)/d);
res.n = res.x * res.y;
d += res.n > this.n ? delta : -delta;
if (delta > 1e-12) delta /=2;
}
res.d = d;
res.s = d-2*this.d;
res.a = 0;
this.res = res;
},
Moving the reference point still causes the square size to wobble.
Might be fun as a graphic effect, though.
Upvotes: 0
Reputation: 80187
Simple (probably not optimal) approach: with binary search find maximal value of a that
Floor((Width + d) / a) * Floor((Height + d) / a) >= n+1
and make regular grid of n squares with edge (a - d), excluding place with point
Upvotes: 1