Вход Регистрация
Файл: vendor/intervention/image/src/Drivers/Gd/Modifiers/DrawBezierModifier.php
Строк: 309
<?php

declare(strict_types=1);

namespace 
InterventionImageDriversGdModifiers;

use 
RuntimeException;
use 
InterventionImageExceptionsGeometryException;
use 
InterventionImageInterfacesImageInterface;
use 
InterventionImageInterfacesSpecializedInterface;
use 
InterventionImageModifiersDrawBezierModifier as ModifiersDrawBezierModifier;

class 
DrawBezierModifier extends ModifiersDrawBezierModifier implements SpecializedInterface
{
    
/**
     * {@inheritdoc}
     *
     * @see ModifierInterface::apply()
     * @throws RuntimeException
     * @throws GeometryException
     */
    
public function apply(ImageInterface $image): ImageInterface
    
{
        foreach (
$image as $frame) {
            if (
$this->drawable->count() !== && $this->drawable->count() !== 4) {
                throw new 
GeometryException('You must specify either 3 or 4 points to create a bezier curve');
            }

            [
$polygon$polygon_border_segments] = $this->calculateBezierPoints();

            if (
$this->drawable->hasBackgroundColor() || $this->drawable->hasBorder()) {
                
imagealphablending($frame->native(), true);
                
imageantialias($frame->native(), true);
            }

            if (
$this->drawable->hasBackgroundColor()) {
                
$background_color $this->driver()->colorProcessor($image->colorspace())->colorToNative(
                    
$this->backgroundColor()
                );

                
imagesetthickness($frame->native(), 0);
                
imagefilledpolygon(
                    
$frame->native(),
                    
$polygon,
                    
$background_color
                
);
            }

            if (
$this->drawable->hasBorder() && $this->drawable->borderSize() > 0) {
                
$border_color $this->driver()->colorProcessor($image->colorspace())->colorToNative(
                    
$this->borderColor()
                );

                if (
$this->drawable->borderSize() === 1) {
                    
imagesetthickness($frame->native(), $this->drawable->borderSize());

                    
$count count($polygon);
                    for (
$i 0$i $count$i += 2) {
                        if (
array_key_exists($i 2$polygon) && array_key_exists($i 3$polygon)) {
                            
imageline(
                                
$frame->native(),
                                
$polygon[$i 0],
                                
$polygon[$i 1],
                                
$polygon[$i 2],
                                
$polygon[$i 3],
                                
$border_color
                            
);
                        }
                    }
                } else {
                    
$polygon_border_segments_total count($polygon_border_segments);

                    for (
$i 0$i $polygon_border_segments_total$i += 1) {
                        
imagefilledpolygon(
                            
$frame->native(),
                            
$polygon_border_segments[$i],
                            
$border_color
                        
);
                    }
                }
            }
        }

        return 
$image;
    }

    
/**
     * Calculate interpolation points for quadratic beziers using the Bernstein polynomial form
     *
     * @param float $t
     * @return array{'x': float, 'y': float}
     */
    
private function calculateQuadraticBezierInterpolationPoint(float $t 0.05): array
    {
        
$remainder $t;
        
$control_point_1_multiplier $remainder $remainder;
        
$control_point_2_multiplier $remainder $t 2;
        
$control_point_3_multiplier $t $t;

        
$x = (
            
$this->drawable->first()->x() * $control_point_1_multiplier +
            
$this->drawable->second()->x() * $control_point_2_multiplier +
            
$this->drawable->last()->x() * $control_point_3_multiplier
        
);
        
$y = (
            
$this->drawable->first()->y() * $control_point_1_multiplier +
            
$this->drawable->second()->y() * $control_point_2_multiplier +
            
$this->drawable->last()->y() * $control_point_3_multiplier
        
);

        return [
'x' => $x'y' => $y];
    }

    
/**
     * Calculate interpolation points for cubic beziers using the Bernstein polynomial form
     *
     * @param float $t
     * @return array{'x': float, 'y': float}
     */
    
private function calculateCubicBezierInterpolationPoint(float $t 0.05): array
    {
        
$remainder $t;
        
$t_squared $t $t;
        
$remainder_squared $remainder $remainder;
        
$control_point_1_multiplier $remainder_squared $remainder;
        
$control_point_2_multiplier $remainder_squared $t 3;
        
$control_point_3_multiplier $t_squared $remainder 3;
        
$control_point_4_multiplier $t_squared $t;

        
$x = (
            
$this->drawable->first()->x() * $control_point_1_multiplier +
            
$this->drawable->second()->x() * $control_point_2_multiplier +
            
$this->drawable->third()->x() * $control_point_3_multiplier +
            
$this->drawable->last()->x() * $control_point_4_multiplier
        
);
        
$y = (
            
$this->drawable->first()->y() * $control_point_1_multiplier +
            
$this->drawable->second()->y() * $control_point_2_multiplier +
            
$this->drawable->third()->y() * $control_point_3_multiplier +
            
$this->drawable->last()->y() * $control_point_4_multiplier
        
);

        return [
'x' => $x'y' => $y];
    }

    
/**
     * Calculate the points needed to draw a quadratic or cubic bezier with optional border/stroke
     *
     * @throws GeometryException
     * @return array{0: array<mixed>, 1: array<mixed>}
     */
    
private function calculateBezierPoints(): array
    {
        if (
$this->drawable->count() !== && $this->drawable->count() !== 4) {
            throw new 
GeometryException('You must specify either 3 or 4 points to create a bezier curve');
        }

        
$polygon = [];
        
$inner_polygon = [];
        
$outer_polygon = [];
        
$polygon_border_segments = [];

        
// define ratio t; equivalent to 5 percent distance along edge
        
$t 0.05;

        
$polygon[] = $this->drawable->first()->x();
        
$polygon[] = $this->drawable->first()->y();
        for (
$i $t$i 1$i += $t) {
            if (
$this->drawable->count() === 3) {
                
$ip $this->calculateQuadraticBezierInterpolationPoint($i);
            } elseif (
$this->drawable->count() === 4) {
                
$ip $this->calculateCubicBezierInterpolationPoint($i);
            }
            
$polygon[] = (int) $ip['x'];
            
$polygon[] = (int) $ip['y'];
        }
        
$polygon[] = $this->drawable->last()->x();
        
$polygon[] = $this->drawable->last()->y();

        if (
$this->drawable->hasBorder() && $this->drawable->borderSize() > 1) {
            
// create the border/stroke effect by calculating two new curves with offset positions
            // from the main polygon and then connecting the inner/outer curves to create separate
            // 4-point polygon segments
            
$polygon_total_points count($polygon);
            
$offset = ($this->drawable->borderSize() / 2);

            for (
$i 0$i $polygon_total_points$i += 2) {
                if (
array_key_exists($i 2$polygon) && array_key_exists($i 3$polygon)) {
                    
$dx $polygon[$i 2] - $polygon[$i];
                    
$dy $polygon[$i 3] - $polygon[$i 1];
                    
$dxy_sqrt = ($dx $dx $dy $dy) ** 0.5;

                    
// inner polygon
                    
$scale $offset $dxy_sqrt;
                    
$ox = -$dy $scale;
                    
$oy $dx $scale;

                    
$inner_polygon[] = $ox $polygon[$i 0];
                    
$inner_polygon[] = $oy $polygon[$i 1];
                    
$inner_polygon[] = $ox $polygon[$i 2];
                    
$inner_polygon[] = $oy $polygon[$i 3];

                    
// outer polygon
                    
$scale = -$offset $dxy_sqrt;
                    
$ox = -$dy $scale;
                    
$oy $dx $scale;

                    
$outer_polygon[] = $ox $polygon[$i 0];
                    
$outer_polygon[] = $oy $polygon[$i 1];
                    
$outer_polygon[] = $ox $polygon[$i 2];
                    
$outer_polygon[] = $oy $polygon[$i 3];
                }
            }

            
$inner_polygon_total_points count($inner_polygon);

            for (
$i 0$i $inner_polygon_total_points$i += 2) {
                if (
array_key_exists($i 2$inner_polygon) && array_key_exists($i 3$inner_polygon)) {
                    
$polygon_border_segments[] = [
                        
$inner_polygon[$i 0],
                        
$inner_polygon[$i 1],
                        
$outer_polygon[$i 0],
                        
$outer_polygon[$i 1],
                        
$outer_polygon[$i 2],
                        
$outer_polygon[$i 3],
                        
$inner_polygon[$i 2],
                        
$inner_polygon[$i 3],
                    ];
                }
            }
        }

        return [
$polygon$polygon_border_segments];
    }
}
Онлайн: 2
Реклама