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