CharliePrynn
CharliePrynn

Reputation: 3080

Aligning rectangles around the inside of a circle and rotate

I have a program that generates an image.

It places x images around a circle with x circumference.

See below output of the current implementation. Current implementation example

I need all of the rectangles to be inside of the circle and to be evenly placed.

Note that on the image above, the current implementation, some of the rectangles are on the inside and some are on the outside.

I'm unsure what is wrong with my calculation, please see below code for placing the rectangles.

 /**
 * Draw the points around a circle
 * @param  $count
 * @param  $circumference
 */
public function drawWheel($count, $circumference)
{
    /**
     * The starting angle
     */
    $angle = 0;

    /**
     * The starting step between rectangles
     */
    $step = (2 * pi()) / $count;

    /**
     * The center X of the canvas
     */
    $startX = ($this->canvas['width'] / 2);

    /**
     * The center Y of the canvas
     */
    $startY = ($this->canvas['height'] / 2);


    for ($i = 0; $i < $count; $i++) {
        /**
         * Width of rectangle
         */
        $width = 85;

        /**
         * Height of rectangle
         */
        $height = 41;

        /**
         * Rectangle X position
         */
        $x = ($startX + ($circumference / 2) * cos($angle)) - $width / 2;

        /**
         * Rectangle Y position
         */
        $y = ($startY + ($circumference / 2) * sin($angle)) - $height / 2;

        /**
         * Degrees to rotate the rectangle around the circle
         */
        $rotateAngle = atan2((($startX - ($width / 2)) - $x), (($startY - ($height)) - $y)) * 180 / pi();

        /**
         * The rectangle image
         */
        $watermark = Image::make(base_path('test.png'));

        $watermark->opacity(75);
        $watermark->resize($width, $height);
        $watermark->rotate($rotateAngle);

        $this->image->insert($watermark, 'top-left', ceil($x), ceil($y));

        /**
         * Increment the angle
         */
        $angle += $step;
    }
}

The part of the function that makes the calculations is below.

$x = ($startX + ($circumference / 2) * cos($angle)) - $width / 2;

$y = ($startY + ($circumference / 2) * sin($angle)) - $height / 2;

$rotateAngle = atan2((($startX - ($width / 2)) - $x), (($startY - ($height)) - $y)) * 180 / pi();

The rotation point is the center of the rectangle.

Image is rotated using: http://php.net/manual/en/function.imagerotate.php

Circle is drawn using: http://php.net/manual/en/function.imagefilledarc.php

Upvotes: 1

Views: 375

Answers (2)

CharliePrynn
CharliePrynn

Reputation: 3080

The width/height will be flipped once the rectangle is rotated, this is something I did not factor in.

MBo's answer helped with the main x,y and rotation coordinates.

See amended code below.

for ($i = 0; $i < $count; $i++) {
            $width = 85;
            $height = 41;

            $x = ($startX + (($circumference - $height) / 2) * cos($angle));
            $y = ($startY + (($circumference - $height) / 2) * sin($angle));

            $rotateAngle = 90 - $angle * 180 / pi(); 

            $watermark = Image::make(base_path('test.png'));

            $watermark->opacity(75);
            $watermark->resize($width, $height);
            $watermark->rotate($rotateAngle);

            $this->image->insert($watermark, 'top-left', ceil($x - ($watermark->width() / 2)), ceil($y - ($watermark->height() / 2)));

            $this->drawCircle($x, $y, 10);
            $this->drawCircle($x, $y, 10);


            $angle += $step;
        }

Upvotes: 0

MBo
MBo

Reputation: 80197

These lines are suspicious:

$x = ($startX + ($circumference / 2) * cos($angle)) - $width / 2;
$y = ($startY + ($circumference / 2) * sin($angle)) - $height / 2;

To place rectangle center inside the circle at inner radius, you have to use something like this:

$x = ($startX + (($circumference - $height) / 2) * cos($angle));
$y = ($startY + (($circumference - $height) / 2) * sin($angle));

And rotation angle is simply

$rotateAngle = $angle * 180 / Pi - 90; // probably $angle+90 depending on coordinate system

Rotated watermark has bounding rectangle with dimensions

Fi = rotateAngle * Pi / 80 
New_Height = $width * Abs(Sin(Fi)) + $height * Abs(Cos(Fi))
New_Width = $width * Abs(Cos(Fi)) + $height * Abs(Sin(Fi))

Correct $x and $y for right output:

$x = $x - New_Width/2
$y = $y - New_Height/2

Upvotes: 1

Related Questions