首页 > 代码库 > 地图区域划分转换成数学模型解决问题

地图区域划分转换成数学模型解决问题

计算机与数学是息息相关的,计算机模型中无时无刻不体现数学的理念。例如余弦定理用来求两个文案的相似度。今天我这里解决的问题也与数学有关。实际需求是这样的,在项目当中,需要人工在百度地图中划分配送区域,要求划分出来的区域不能是杂乱无章的,即线段与线段之间不能相穿。当时接到这个需求有点懵逼,如何是好,开完会坐下来,慢慢画图发现划出的图形只要是凹凸多边形即可,突然茅塞顿开,问题迎刃而解,因为规则的凹凸多边形的顶点数与边数相等,根据这段理念简单写了一段验证,结果验证无误。


public function checkMapIsRegularAction()
{
   $aPoint         = $_POST[‘point‘];
   $aPoint         = array(
       ‘123.465132,41.870508‘,
       ‘123.46082,41.833756‘,
       ‘123.510262,41.827951‘,
       ‘123.525785,41.879532‘,
       ‘123.430349,41.849663‘,
       ‘116.404355,39.914444‘,
       ‘123.480942,41.830961‘
   );

   $aPoint         = array(
       ‘116.401696,39.907333‘,
       ‘123.46082,41.833756‘,
       ‘116.41801,39.917626‘,
       ‘116.425052,39.910985‘,
       ‘116.414345,39.906004‘
   );

   $aFormatPoint   = array();
   $aFormatLine    = array();
   try {
       if ($aPoint) {
           foreach ($aPoint as $item) {
               list($pointX,$pointY) = explode(‘,‘ ,$item);
               $aFormatPoint[] = array(‘x‘ => $pointX, ‘y‘ => $pointY);
           }

           $index  = count($aFormatPoint) - 1;
           //把顺序坐标转换成线段
           foreach ($aFormatPoint as $key=>$point) {
               $aFormatLine[][‘start‘] = $point;
               if ($index == $key) {
                   $aFormatLine[$key][‘end‘]   = $aFormatPoint[0];
               } else {
                   $aFormatLine[$key][‘end‘]   = $aFormatPoint[$key+1];
               }
           }
       }
       $flag = Lib_base::checkIsRegularPolygon($aFormatLine);
   }catch (\Exception $e) {
       return $e->getMessage();
   }
}
/**
* 检测是不是规则的凹凸多边形(判断标准是顶点数和边数相等)
* $aPoint = array(array(‘start‘=>array(‘x‘=>1,‘y‘=>2),‘end‘=>array(‘x‘=>1,‘y‘=>2)),array(‘start‘=>array(‘x‘=>1,‘y‘=>2),‘end‘=>array(‘x‘=>1,‘y‘=>2)))
*/
function checkIsRegularPolygon($aPoint)
{
   $vertexCount    = count($aPoint);

   $aOutPoint      = $aPoint;
   $edgeCount      = 0;
   array_shift($aPoint);
   //两两求交点
   foreach ($aOutPoint as $key=>$aLine) {
       if (empty($aPoint)) {
           continue;
       }
       foreach ($aPoint as $innerKey => $aInnerLine) {

           $isIntersect = self::checkLineSegIsIntersect($aOutPoint[$key], $aPoint[$innerKey]);
           if ($isIntersect) {
               $edgeCount += 1;
           }
       }
       array_shift($aPoint);
   }

   if ($vertexCount == $edgeCount) {
       return true;
   }
   return false;
}

/**
* @param $lineSegA
* @param $lineSegB
* @return bool
*/
function checkLineSegIsIntersect($lineSegA, $lineSegB)
{
   return self::isIntersect($lineSegA[‘start‘],$lineSegA[‘end‘],$lineSegB[‘start‘],$lineSegB[‘end‘]);
   //return self::sideIntersectSide($lineSegA[‘start‘],$lineSegA[‘end‘],$lineSegB[‘start‘],$lineSegB[‘end‘]);
}


/**
* 求叉积
* @param $pointA
* @param $pointB
* @param $pointC
* @return mixed
*/
function  vectorProduct($pointA, $pointB, $pointC)
{
   $AXPoint                = $pointA[‘x‘];
   $AYPoint                = $pointA[‘Y‘];
   $BXPoint                = $pointB[‘x‘];
   $BYPoint                = $pointB[‘y‘];
   $CXPoint                = $pointC[‘x‘];
   $CYPoint                = $pointC[‘y‘];

   return ($AXPoint - $CXPoint) * ($BYPoint - $CYPoint) - ( $BXPoint - $CXPoint ) * ( $AYPoint - $CYPoint);
}


/**
* 检测两条线段是否相等
* $pointA, $pointB为一条线段两端点 $pointC,$pointD为另一条线段的两端点 相交返回true, 不相交返回false
* @param $pointA
* @param $pointB
* @param $pointC
* @param $pointD
* @return bool
*/
function isIntersect($pointA, $pointB, $pointC,$pointD)
{
   $AXPoint                = $pointA[‘x‘];
   $AYPoint                = $pointA[‘Y‘];
   $BXPoint                = $pointB[‘x‘];
   $BYPoint                = $pointB[‘y‘];
   $CXPoint                = $pointC[‘x‘];
   $CYPoint                = $pointC[‘y‘];
   $DXPoint                = $pointD[‘x‘];
   $DYPoint                = $pointD[‘y‘];

   if ( max($AXPoint, $BXPoint) < min($CXPoint, $DXPoint) )
   {
       return false;
   }

   if ( max($AYPoint,$BYPoint) < min($CYPoint, $DYPoint) )
   {
       return false;
   }

   if ( max($CXPoint,$DXPoint) < min($AXPoint, $BXPoint) )
   {
       return false;
   }

   if ( max($CYPoint, $DYPoint) < min($AYPoint,$BYPoint) )
   {
       return false;
   }

   if ( (self::vectorProduct($pointC, $pointB, $pointA ) * self::vectorProduct ($pointB,$pointD,$pointA)) < 0 )
   {
       return false;
   }

   if ( (self::vectorProduct($pointA, $pointD, $pointC) * self::vectorProduct($pointD, $pointB, $pointC)) < 0 )
   {
       return false;
   }

   return true;
}

后续会按面向对象的方式封装坐标和线段,欢迎点评。

本文出自 “我相信” 博客,请务必保留此出处http://mrcelite.blog.51cto.com/2977858/1863142

地图区域划分转换成数学模型解决问题