public function testVectorMultiplyScalar() { $vector = new ezcGraphVector(1, 2); $result = $vector->scalar(2); $this->assertEquals(2, $vector->x); $this->assertEquals(4, $vector->y); $this->assertEquals($result, $vector, 'Result should be the vector itself'); }
/** * Reduce the size of an ellipse * * The method returns a the edgepoints and angles for an ellipse where all * borders are moved to the inner side of the ellipse by the give $size * value. * * The method returns an * array ( * 'center' => (ezcGraphCoordinate) New center point, * 'start' => (ezcGraphCoordinate) New outer start point, * 'end' => (ezcGraphCoordinate) New outer end point, * ) * * @param ezcGraphCoordinate $center * @param float $width * @param float $height * @param float $startAngle * @param float $endAngle * @param float $size * @throws ezcGraphReducementFailedException * @return array */ protected function reduceEllipseSize(ezcGraphCoordinate $center, $width, $height, $startAngle, $endAngle, $size) { $oldStartPoint = new ezcGraphVector($width * cos(deg2rad($startAngle)) / 2, $height * sin(deg2rad($startAngle)) / 2); $oldEndPoint = new ezcGraphVector($width * cos(deg2rad($endAngle)) / 2, $height * sin(deg2rad($endAngle)) / 2); // We always need radian values.. $degAngle = abs($endAngle - $startAngle); $startAngle = deg2rad($startAngle); $endAngle = deg2rad($endAngle); // Calculate normalized vectors for the lines spanning the ellipse $unifiedStartVector = ezcGraphVector::fromCoordinate($oldStartPoint)->unify(); $unifiedEndVector = ezcGraphVector::fromCoordinate($oldEndPoint)->unify(); $startVector = ezcGraphVector::fromCoordinate($oldStartPoint); $endVector = ezcGraphVector::fromCoordinate($oldEndPoint); $oldStartPoint->add($center); $oldEndPoint->add($center); // Use orthogonal vectors of normalized ellipse spanning vectors to $v = clone $unifiedStartVector; $v->rotateClockwise()->scalar($size); // calculate new center point // center + v + size / tan( angle / 2 ) * startVector $centerMovement = clone $unifiedStartVector; $newCenter = $v->add($centerMovement->scalar($size / tan(($endAngle - $startAngle) / 2)))->add($center); // Test if center is still inside the ellipse, otherwise the sector // was to small to be reduced $innerBoundingBoxSize = 0.7 * min($width, $height); if ($newCenter->x < $center->x + $innerBoundingBoxSize && $newCenter->x > $center->x - $innerBoundingBoxSize && $newCenter->y < $center->y + $innerBoundingBoxSize && $newCenter->y > $center->y - $innerBoundingBoxSize) { // Point is in inner bounding box -> everything is OK } elseif ($newCenter->x < $center->x - $width || $newCenter->x > $center->x + $width || $newCenter->y < $center->y - $height || $newCenter->y > $center->y + $height) { // Quick outer boundings check if ($degAngle > 180) { // Use old center for very big angles $newCenter = clone $center; } else { // Do not draw for very small angles throw new ezcGraphReducementFailedException(); } } else { // Perform exact check $distance = new ezcGraphVector($newCenter->x - $center->x, $newCenter->y - $center->y); // Convert elipse to circle for correct angle calculation $direction = clone $distance; $direction->y *= $width / $height; $angle = $direction->angle(new ezcGraphVector(0, 1)); $outerPoint = new ezcGraphVector(sin($angle) * $width / 2, cos($angle) * $height / 2); // Point is not in ellipse any more if (abs($distance->x) > abs($outerPoint->x)) { if ($degAngle > 180) { // Use old center for very big angles $newCenter = clone $center; } else { // Do not draw for very small angles throw new ezcGraphReducementFailedException(); } } } // Use start spanning vector and its orthogonal vector to calculate // new start point $newStartPoint = clone $oldStartPoint; // Create tangent vector from tangent angle // Ellipse tangent factor $ellipseTangentFactor = sqrt(pow($height, 2) * pow(cos($startAngle), 2) + pow($width, 2) * pow(sin($startAngle), 2)); $ellipseTangentVector = new ezcGraphVector($width * -sin($startAngle) / $ellipseTangentFactor, $height * cos($startAngle) / $ellipseTangentFactor); // Reverse spanning vector $innerVector = clone $unifiedStartVector; $innerVector->scalar($size)->scalar(-1); $newStartPoint->add($innerVector)->add($ellipseTangentVector->scalar($size)); $newStartVector = clone $startVector; $newStartVector->add($ellipseTangentVector); // Use end spanning vector and its orthogonal vector to calculate // new end point $newEndPoint = clone $oldEndPoint; // Create tangent vector from tangent angle // Ellipse tangent factor $ellipseTangentFactor = sqrt(pow($height, 2) * pow(cos($endAngle), 2) + pow($width, 2) * pow(sin($endAngle), 2)); $ellipseTangentVector = new ezcGraphVector($width * -sin($endAngle) / $ellipseTangentFactor, $height * cos($endAngle) / $ellipseTangentFactor); // Reverse spanning vector $innerVector = clone $unifiedEndVector; $innerVector->scalar($size)->scalar(-1); $newEndPoint->add($innerVector)->add($ellipseTangentVector->scalar($size)->scalar(-1)); $newEndVector = clone $endVector; $newEndVector->add($ellipseTangentVector); return array('center' => $newCenter, 'start' => $newStartPoint, 'end' => $newEndPoint, 'startAngle' => rad2deg($startAngle + $startVector->angle($newStartVector)), 'endAngle' => rad2deg($endAngle - $endVector->angle($newEndVector))); }