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