判断点是否在多边形区域内外

原理:

根据数学知识的射线法,射线与几何多边形相交的点的个数为奇数则是在几何内部,偶数在外部;

代码:

安装:

composer require cshaptx4869/boundary

 

代码示例:

 

Point.php

<?php

namespace Fairy;

class Point
{
    public $x;
    public $y;

    public function __construct(float $x, float $y)
    {
        $this->x = $x;
        $this->y = $y;
    }
}

 

Boundary.php

<?php

namespace Fairy;

class Boundary
{
    private $latitude = 'latitude';
    private $longitude = 'longitude';
    private static $instance = null;

    private function __construct()
    {
    }

    private function __clone()
    {
    }

    private function __wakeup()
    {
    }

    /**
     * @return Boundary
     */
    public static function getInstance()
    {
        if (is_null(static::$instance)) {
            static::$instance = new static();
        }

        return static::$instance;
    }

    /**
     * 设置纬度名
     * @param string $key
     * @return $this
     */
    public function latitudeKey(string $key)
    {
        $this->latitude = $key;

        return $this;
    }

    /**
     * 设置经度名
     * @param string $key
     * @return $this
     */
    public function longitudeKey(string $key)
    {
        $this->longitude = $key;

        return $this;
    }


    /**
     * 检查坐标范围点格式
     * @param array $points
     * @return bool
     */
    public function checkPointRange(array $points)
    {
        foreach ($points as $point) {
            if (!isset($point[$this->latitude]) || !isset($point[$this->longitude])) {
                return false;
            }
        }

        return true;
    }

    /**
     * 如果给定的点包含在边界内,则返回true
     * @param Point $point
     * @param array $points
     * @return bool
     */
    public function contains(Point $point, array $points)
    {
        if (!$this->checkPointRange($points)) {
            throw new \InvalidArgumentException('points data invalid');
        }

        $pointNum = count($points);
        $result = false;
        for ($i = 0, $j = $pointNum - 1; $i < $pointNum; $j = $i++) {
            if (
                ($points[$i][$this->longitude] > $point->y) != ($points[$j][$this->longitude] > $point->y) &&
                ($point->x < ($points[$j][$this->latitude] - $points[$i][$this->latitude]) *
                    ($point->y - $points[$i][$this->longitude]) /
                    ($points[$j][$this->longitude] - $points[$i][$this->longitude]) +
                    $points[$i][$this->latitude]
                )
            ) {
                $result = !$result;
            }
        }

        return $result;
    }
}

 run.php

<?php

require './vendor/autoload.php';

use Fairy\Boundary;
use Fairy\Point;

$points = [
    ['x' => 9.4, 'y' => 12.04],
    ['x' => 6.68, 'y' => 8.61],
    ['x' => 9.05, 'y' => 6.06],
    ['x' => 6.24, 'y' => 3.87],
    ['x' => 10.02, 'y' => 2.55],
    ['x' => 14.06, 'y' => 4.13],
    ['x' => 4.13, 'y' => 7.56],
    ['x' => 11.69, 'y' => 8.35],
];

// 9.97, 4.96  在内
// 15.73, 5.62  在外
echo Boundary::getInstance()
    ->latitudeKey('x')
    ->longitudeKey('y')
    ->contains(new Point(9.97, 4.96), $points) ? '内' : '外';

 

参考:

https://stackoverflow.com/questions/8721406/how-to-determine-if-a-point-is-inside-a-2d-convex-polygon

https://www.cnblogs.com/lxwphp/p/10784592.html

https://blog.csdn.net/shao941122/article/details/51504519?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.add_param_isCf&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.add_param_isCf

https://www.php.cn/php-class-code-336351.html

posted @ 2020-09-12 14:23  白開水  阅读(385)  评论(0)    收藏  举报