This is a continuation of this post.
I have a circle or disk with some rectangles located on its circumference which have arbitrary widths, heights, and angles (by angle I mean the line connecting center of the circle to center of the rectangle). An example angle is shown for one of the rectangles with pink lines.
The center coordinate of the circle is (centerX, centerY) and its radius is r.
The widths and heights of the rectangles and angles of the lines connecting circle center to each rectangle center are available too.
How can I find a new radius r and a new centerX and CenterY for the disk so that it has maximum area and the previous bounding box of the disk (dashed green line) can fully accommodate all the rectangles?
A relaxed version of the problem
If the above problem is too hard to solve, then, how can I just modify the circle radius r (its center stays the same) so that its previous bounding box can contain all the rectangles?
If an axis-aligned box is centered at $(x, y)$, its width being $2 w$, height $2 h$, the distance from the box to origin is $d$, $$d = \begin{cases} \sqrt{c_x^2 + c_y^2}, & \text{if } c_x \gt 0 \text{ and } c_y \gt 0 \\ \max(0,\, c_x,\, c_y), & \text{otherwise} \\ \end{cases} \tag{1a}\label{G1a}$$ where $$c_x = \lvert x \rvert - w , \quad c_y = \lvert y \rvert - h \tag{1b}\label{G1b}$$ are the distance between the box and the $y$ axis, and the distance between the box and the $x$ axis, respectively.
If we use $$r = \sqrt{x^2 + y^2}, \quad a_x = \frac{\lvert x \rvert}{r}, \quad a_y = \frac{\lvert y \rvert}{r} \tag{1c}\label{G1c}$$ then we can solve $\eqref{G1a}$ for $r$ via $$\begin{aligned} b &= w a_x + h a_y \\ c &= h a_x - w a_y \\ r_{xy} &= b + \sqrt{d^2 - c^2} \\ r_{x} &= \frac{d + w}{a_x} \\ r_{y} &= \frac{d + h}{a_y} \\ r &= \begin{cases} r_{xy}, & d^2 \ge c^2 \text{ and } r_{xy} a_x \ge w \text{ and } r_{xy} a_y \ge h \\ r_{x}, & d^2 \ge c^2 \text{ and } r_{xy} a_x \ge w \text{ and } r_{xy} a_y \lt h \\ r_{y}, & d^2 \ge c^2 \text{ and } r_{xy} a_x \lt w \text{ and } r_{xy} a_y \ge h \\ 0, & d^2 \ge c^2 \text{ and } r_{xy} a_x \lt w \text{ and } r_{xy} a_y \lt h \\ r_{x}, & d^2 \lt c^2 \text{ and } c \gt 0 \\ r_{y}, & d^2 \lt c^2 \text{ and } c \lt 0 \\ \end{cases} \\ \end{aligned} \tag{1d}\label{G1d}$$
Here is an example Python 3 implementation,
rect.py. You can import the Rect type to use in your own code viafrom rect import Rect, runpydoc3 rectto see the documentation of the Rect class it implements, or run the file using e.g.python3 -B rect.pyto test it with randomly generated rectangles. It is licensed under the Creative Commons Zero v1.0 Universal license; so feel free to reuse as you wish.Another file,
disk.py, implements the disk (with associated rectangles) logic:If run, it constructs a disk of radius $4$ with four rectangles around it. It then uses the
resized_to()method of theDiskclass to resize the disk so that the resulting bounding box matches the specified width and/or height.The
size_at_radius()method computes the bounding box size, if the disk was resized to the specified radius and all rectangles moved correspondingly. Thecopy_at()method returns the same as a new Disk object, without modifying the original.Both functions use the
Rect.distancesetter method to compute the new location of each rectangle, with the calculations inRect._set_x_y_din the first file; which in turn is a straightforward implementation of $\eqref{G1d}$.The
resized_to()method uses thesize_at_radius()method to bracket the radius range, then a binary search to find the radius that yields the best bounding box size.I have not proven that the disk bounding box size is a smooth enough function for a binary search to be reasonable (converge to either the global extremum, or to a local one so near to the global one that the difference is within rounding error), but the behaviour of $\eqref{G1a}$ makes me believe so.
The code is not production quality; it probably contains typos and other bugs (none intentionally!), so anyone intending to use this should really test their code well with different datasets before relying on it. However, it should clearly show how $\eqref{G1a}$ is inverted (and running
rect.pyverifies this with lots of random rectangles), and how a binary search can be used to find a disk radius that yields a desired bounding box size.It may not behave sensibly when the origin (center of disk) is within a rectangle, though.
At minimum, consider limiting the binary search to meaningful differences in disk radiuses. As it is, the binary search only ends if a desired bounding box size is found, or when the limit of precision is reached.
The bracketing part extends the minimum and maximum radius, until it covers the desired bounding box size. Note that when the maximum has to be extended, we could set the minimum radius to the old maximum radius, so that we move the range rather than scale it; and vice versa for when extending the minimum. So, there are definitely lots of optimization opportunities.
It is just example code, after all.