public function __construct(Rectangle $bounds, $level = 0) { $this->level = $level; $this->objects = []; $this->bounds = $bounds->normalized(); $this->nodes = []; }
public function testInflated() { $rect = new Rectangle(1, 1, 3, 3); $rectInflated = $rect->inflated(1, 2); $this->assertIdentical(new Rectangle(0, -1, 4, 5), $rectInflated); $this->assertNotSame($rectInflated, $rect); }
public function makeCloud($width, $height, $outputPath, array $sortedWords, $debug = false) { $tmpDirectoryPath = dirname(dirname(__DIR__)) . '/tmp/'; if (!is_dir($tmpDirectoryPath)) { mkdir($tmpDirectoryPath); } $fontUrl = $this->env['STATIC_HOSTING_URL'] . 'fonts/' . $this->env['FONT_FILE']; $fontfile = $tmpDirectoryPath . uniqid(); file_put_contents($fontfile, fopen($fontUrl, 'r')); // Calculate bounding boxes for words and sum up area $rectangles = []; $area = 0; foreach ($sortedWords as $word => $count) { $bbox = imagettfbbox($this->fontSizeForCount($count), 0, $fontfile, $word); if ($bbox === false) { throw new \Exception("Error getting bounding box for string `{$word}` with fontfile `{$fontfile}`."); } $bboxRect = new Rectangle($bbox[0], $bbox[1], $bbox[4], $bbox[5]); $rectangles[$word] = new Rectangle($bboxRect->x1, $bboxRect->y1, $bboxRect->x1 + $bboxRect->width(), $bboxRect->y1 + $bboxRect->height()); $area += $rectangles[$word]->area(); } $fudgedArea = $area * 1.5; // Calculate playing field $pfAspect = $width / $height; $pfWidth = sqrt($fudgedArea * $pfAspect); $pfHeight = $fudgedArea / $pfWidth; $playingField = new Rectangle(0, 0, $pfWidth, $pfHeight); // Place rectangles into the cloud $quad = new Quadtree($playingField); $placedRectangles = []; foreach ($rectangles as $word => $rectangle) { $posX = $this->randFloatMinMax(0, $playingField->width() - $rectangle->width()) - $rectangle->x1; $posY = $this->randFloatMinMax(0, $playingField->height() - $rectangle->height()) - $rectangle->y1; // $placed = $rectangle->translated($posX, $posY); $placed = $rectangle->translated($pfWidth / 2, $pfHeight / 2); $originalPlaced = clone $placed; $loopCount = 0; while ($this->rectIntersects($placed, $quad->retrieve($placed))) { do { $t = $loopCount / self::SPIRAL_STEPS; list($spiralX, $spiralY) = $this->spiralOffset($t, 20, 20 * $this->fontSizeForCount($sortedWords[$word])); $placed = $originalPlaced->translated($spiralX, $spiralY); $loopCount++; } while ($loopCount < self::SPIRAL_STEPS && !$playingField->contains($placed)); } $placedRectangles[$word] = $placed; $quad->insert($placed); } // Find the min and max coordinates of placed rectangles $minX = current($placedRectangles)->x1; $minY = current($placedRectangles)->y1; $maxX = current($placedRectangles)->x2; $maxY = current($placedRectangles)->y2; foreach ($placedRectangles as $placedRectangle) { if ($placedRectangle->x1 < $minX) { $minX = $placedRectangle->x1; } if ($placedRectangle->y1 < $minY) { $minY = $placedRectangle->y1; } if ($placedRectangle->x2 > $maxX) { $maxX = $placedRectangle->x2; } if ($placedRectangle->y2 > $maxY) { $maxY = $placedRectangle->y2; } } // Get zoom factor to fit all text into playing field $widthZoomFactor = $playingField->width() / ($maxX - $minX); $heightZoomFactor = $playingField->height() / ($maxY - $minY); $textZoomFactor = min($widthZoomFactor, $heightZoomFactor); // Make the image! $image = imagecreatetruecolor($width, $height); $white = imagecolorallocate($image, 255, 255, 255); $gray = imagecolorallocate($image, 128, 128, 128); $black = imagecolorallocate($image, 0, 0, 0); imagefilledrectangle($image, 0, 0, $width - 1, $height - 1, $white); $scaleFactor = $textZoomFactor * ($width / $pfWidth); foreach ($placedRectangles as $word => $placed) { imagettftext($image, $this->fontSizeForCount($sortedWords[$word]) * $scaleFactor, 0, ($placed->x1 - $minX) * $scaleFactor, ($placed->y2 - $rectangles[$word]->y1 - $minY) * $scaleFactor, $black, $fontfile, $word); if ($debug) { imagerectangle($image, ($placed->x1 - $minX) * $scaleFactor, ($placed->y1 - $minY) * $scaleFactor, ($placed->x2 - $minX) * $scaleFactor, ($placed->y2 - $minY) * $scaleFactor, $gray); } } if ($debug) { imagerectangle($image, ($playingField->x1 - $minX) * $scaleFactor, ($playingField->y1 - $minY) * $scaleFactor, ($playingField->x2 - $minX) * $scaleFactor, ($playingField->y2 - $minY) * $scaleFactor, $black); } // Output the image if (!is_dir($outputPath)) { mkdir($outputPath); } $imageId = uniqid(); $imageUrl = "{$outputPath}/{$imageId}.png"; imagepng($image, $imageUrl); imagedestroy($image); // Delete the font unlink($fontfile); return $imageUrl; }