1. 程式人生 > >php實現 計算坐標點在某區域

php實現 計算坐標點在某區域

php key div rect cross ray number oss 一個表

項目需求:通過地圖坐標和區域坐標點集合 判斷當前坐標是否在坐標點集合區域中
$area[array] 區域坐標點集合數組
$area = array(
  // 天通苑店
  0 => array(
    array(‘x‘=>116.38295, ‘y‘=>40.09416),
    array(‘x‘=>116.44037, ‘y‘=>40.095898),
    array(‘x‘=>116.448275,‘y‘=>40.083313),
    array(‘x‘=>116.448455,‘y‘=>40.050818),
    array(‘x‘=>116.448275,‘y‘=>40.038307),
    array
(‘x‘=>116.441448,‘y‘=>40.038418),     array(‘x‘=>116.436058,‘y‘=>40.038804),     array(‘x‘=>116.417302,‘y‘=>40.039136),     array(‘x‘=>116.414822,‘y‘=>40.039384),     array(‘x‘=>116.412738,‘y‘=>40.039329),     array(‘x‘=>116.407672,‘y‘=>40.039329),     array(‘x‘=>116.388628,‘y‘=>40.085162),     array
(‘x‘=>116.383633,‘y‘=>40.084997)   ),   //亞運村   1 => array(     array(‘x‘=>116.358804,‘y‘=>40.028474),     array(‘x‘=>116.41608, ‘y‘=>40.02875),     array(‘x‘=>116.41723, ‘y‘=>40.038915),     array(‘x‘=>116.447988,‘y‘=>40.037921),     array(‘x‘=>116.447844,‘y‘=>40.026761),     array
(‘x‘=>116.455821,‘y‘=>40.024164),     array(‘x‘=>116.446281,‘y‘=>39.994736),     array(‘x‘=>116.443532,‘y‘=>39.995372),     array(‘x‘=>116.376267,‘y‘=>39.993493),     array(‘x‘=>116.375908,‘y‘=>40.000015),     array(‘x‘=>116.372027,‘y‘=>39.999904),     array(‘x‘=>116.371452,‘y‘=>40.007366),     array(‘x‘=>116.359451,‘y‘=>40.006758)   ),   //望京店   2 => array(     array(‘x‘=>116.46387, ‘y‘=>40.021125),     array(‘x‘=>116.484495,‘y‘=>40.020462),     array(‘x‘=>116.515684,‘y‘=>39.995151),     array(‘x‘=>116.51519, ‘y‘=>39.976137),     array(‘x‘=>116.491906,‘y‘=>39.972985),     array(‘x‘=>116.476239,‘y‘=>39.977298),     array(‘x‘=>116.467472,‘y‘=>39.96917),     array(‘x‘=>116.443325,‘y‘=>39.984817),     array(‘x‘=>116.449506,‘y‘=>39.993109),     array(‘x‘=>116.446357,‘y‘=>39.994736),     array(‘x‘=>116.456037,‘y‘=>40.024109)   ), );

<?php
/**
 * 驗證坐標點是否在某區域內
 * @author xiaoliang <[email protected]>
 * Class validationMap
 */
class InareaAction extends CommonAction {
    // 一個表示區域的三維數組
    public $config = null;

    // 包含每個區域的四邊形
    public $rectangles = null;

    // 每個區域(多邊形)的所有邊
    public $lines = null;

    // 要判斷的點的x, y坐標
    public $_x = null;
    public $_y = null;

    public function __construct($config){
        $this->config = $config;
        $this->initRectangles();
        $this->initLines();
    }

    /*
        獲取包含每個配送區域的四邊形
    */
    public function initRectangles(){
        foreach ($this->config as $k => $v) {
            $this->rectangles[$k][‘minX‘] = $this->getMinXInEachConfig($k);
            $this->rectangles[$k][‘minY‘] = $this->getMinYInEachConfig($k);
            $this->rectangles[$k][‘maxX‘] = $this->getMaxXInEachConfig($k);
            $this->rectangles[$k][‘maxY‘] = $this->getMaxYInEachConfig($k);
        }
    }

    /*
        初始化每個區域(多邊形)的邊(線段:直線的一部分【限制x或者y坐標範圍】)
        n 個頂點構成的多邊形,有 n-1 條邊
    */
    public function initLines(){
        foreach ($this->config as $k => $v) {
            $pointNum = count($v);		// 區域的頂點個數
            $lineNum = $pointNum - 1; 	// 區域的邊條數
            for($i=0; $i<$lineNum; $i++){
                // y=kx+b : k
                if($this->config[$k][$i][‘x‘] - $this->config[$k][$i+1][‘x‘] == 0) $this->lines[$k][$i][‘k‘] = 0;
                else $this->lines[$k][$i][‘k‘] =
                    ($this->config[$k][$i][‘y‘] - $this->config[$k][$i+1][‘y‘])/($this->config[$k][$i][‘x‘] - $this->config[$k][$i+1][‘x‘]);
                // y=kx+b : b
                $this->lines[$k][$i][‘b‘] = $this->config[$k][$i+1][‘y‘] - $this->lines[$k][$i][‘k‘] * $this->config[$k][$i+1][‘x‘];
                $this->lines[$k][$i][‘lx‘] = min($this->config[$k][$i][‘x‘], $this->config[$k][$i+1][‘x‘]);
                $this->lines[$k][$i][‘rx‘] = max($this->config[$k][$i][‘x‘], $this->config[$k][$i+1][‘x‘]);
            }
            $pointNum-=1;
            if($this->config[$k][$pointNum][‘x‘] - $this->config[$k][0][‘x‘] == 0) $this->lines[$k][$pointNum][‘k‘] = 0;
            else $this->lines[$k][$pointNum][‘k‘] =
                ($this->config[$k][$pointNum][‘y‘] - $this->config[$k][0][‘y‘])/($this->config[$k][$pointNum][‘x‘] - $this->config[$k][0][‘x‘]);
            // y=kx+b : b
            $this->lines[$k][$pointNum][‘b‘] = $this->config[$k][0][‘y‘] - $this->lines[$k][$pointNum][‘k‘] * $this->config[$k][0][‘x‘];
            $this->lines[$k][$pointNum][‘lx‘] = min($this->config[$k][$pointNum][‘x‘], $this->config[$k][0][‘x‘]);
            $this->lines[$k][$pointNum][‘rx‘] = max($this->config[$k][$pointNum][‘x‘], $this->config[$k][0][‘x‘]);
        }
    }

    /*
        獲取一組坐標中,x坐標最小值
    */
    public function getMinXInEachConfig($index){
        $minX = 200;
        foreach ($this->config[$index] as $k => $v) {
            if($v[‘x‘] < $minX){
                $minX = $v[‘x‘];
            }
        }
        return $minX;
    }

    /*
        獲取一組坐標中,y坐標最小值
    */
    public function getMinYInEachConfig($index){
        $minY = 200;
        foreach ($this->config[$index] as $k => $v) {
            if($v[‘y‘] < $minY){
                $minY = $v[‘y‘];
            }
        }
        return $minY;
    }

    /*
        獲取一組坐標中,x坐標最大值
    */
    public function getMaxXInEachConfig($index){
        $maxX = 0;
        foreach ($this->config[$index] as $k => $v) {
            if($v[‘x‘] > $maxX){
                $maxX = $v[‘x‘];
            }
        }
        return $maxX;
    }

    /*
        獲取一組坐標中,y坐標最大值
    */
    public function getMaxYInEachConfig($index){
        $maxY = 0;
        foreach ($this->config[$index] as $k => $v) {
            if($v[‘y‘] > $maxY){
                $maxY = $v[‘y‘];
            }
        }
        return $maxY;
    }

    /*
        獲取 y=y0 與特定區域的所有邊的交點,並去除和頂點重復的,再將交點分為左和右兩部分
    */
    public function getCrossPointInCertainConfig($index){
        $crossPoint = null;
        foreach ($this->lines[$index] as $k => $v) {
            if($v[‘k‘] == 0) return true;
            $x0 = ($this->_y - $v[‘b‘]) / $v[‘k‘];	// 交點x坐標
            if($x0 == $this->_x) return true;		// 點在邊上
            if($x0 > $v[‘lx‘] && $x0 < $v[‘rx‘]){
                if($x0 < $this->_x) $crossPoint[‘left‘][] = $x0;
                if($x0 > $this->_x) $crossPoint[‘right‘][] = $x0;
            }
        }
        return $crossPoint;
    }

    /*
        檢測一個點,是否在區域內
        返回結果:
            return === false : 點不在區域內
            return 0, 1, 2, 3 ... 點所在的區域編號(配置文件中的區域編號。)
    */
    public function checkPoint($x, $y){
        $this->_x = $x;
        $this->_y = $y;
        $contain = null;
        foreach ($this->rectangles as $k => $v) {
            if($x > $v[‘maxX‘] || $x < $v[‘minX‘] || $y > $v[‘maxY‘] || $y < $v[‘minY‘]){
                continue;
            }else{
                $contain = $k;
                break;
            }
        }
        if($contain === null) return false;
        $crossPoint = $this->getCrossPointInCertainConfig($contain);
        if($crossPoint === true) return $contain;
        if(count($crossPoint[‘left‘])%2 == 1 && count($crossPoint[‘right‘])%2 == 1) return $contain;
        return false;
    }
}

//實例化對象
$area = new Area($area);
//判斷坐標點是否在區域中 如果坐標點在某一區域返回區域編號 否則返回false;
var_dump($area->checkPoint(116.531748,39.944229))

  

php實現 計算坐標點在某區域