PHP/JAVA判断点是否在围栏内,百度、高德、腾讯地图
坐标点,多边形区域,判断点是否在区域内
。具体的应用场景如:外卖派送,用户提供的
坐标是否是在外卖的派送范围之内
。用户的坐标可以通过手机设备获取到,派送范围就是通过在地图上,进行多边形的绘制,获取多个坐标点连接起来的配送范围。下面来看看代码上是如何简单判断的。
引射线法:从目标点出发引一条射线,看这条射线和多边形所有边的交点数射线法
适用范围:任意多边形,不需考虑精度误差和多边形点给出的顺序
以被测点Q为端点,向任意方向作射线(一般水平向右作射线),统计该射线与多边形的交点数。如果为奇数,Q在多边形内;如果为偶数,Q在多边形外。
PHP单区域判断点是否在多边形区域围栏内
函数判断多边形区域围栏
<?php
//php判断点是否在围栏内
function inArea($x, $y, $arr)
{
//点的数量
$count = count($arr);
$n = 0; //点与线相交的个数
$bool = false; //外
for ($i = 0, $j = $count - 1; $i < $count; $j = $i, $i++) {
//两个点一条线 取出两个连接点的定点
$px1 = $arr[$i]['jd'];
$py1 = $arr[$i]['wd'];
$px2 = $arr[$j]['jd'];
$py2 = $arr[$j]['wd'];
//$x的水平位置画射线
if ($x >= $px1 || $x >= $px2) {
//判断$y 是否在线的区域
if (($y >= $py1 && $y <= $py2) || ($y >= $py2 && $y <= $py1)) {
if (($y == $py1 && $x == $px1) || ($y == $py2 && $x == $px2)) {
#如果$x的值和点的坐标相同
$bool = 2; //在点上
return $bool;
} else {
$px = $px1 + ($y - $py1) / ($py2 - $py1) * ($px2 - $px1);
if ($px == $x) {
$bool = 3; //在线上
} elseif ($px < $x) {
$n++;
}
}
}
}
}
if ($n % 2 != 0) {
$bool = true;
}
return $bool;
}
$area_arr = [
[
'jd' => '113.923664',
'wd' => '30.802822'
],
[
'jd' => '113.959369',
'wd' => '30.393828'
],
[
'jd' => '114.879474',
'wd' => '30.789846'
],
[
'jd' => '114.873981',
'wd' => '30.404488'
],
];
var_dump(inArea('114.286212', '30.550064', $area_arr));
phpgeo库判断多边形区域围栏
mjaschen/phpgeo
是一个php的geo的库,提供了一些关于地理经纬度
相关的功能,例如地理围栏、距离计算等。首先composer
安装此包: PHP要求至少大于7
composer require mjaschen/phpgeo
实现
<?php
require './vendor/autoload.php';
//引入两个类
use Location\Coordinate;
use Location\Polygon;
//绘制一个多边形
$geo = new Polygon();
$geo->addPoint(new Coordinate(39.930131, 116.417301));
$geo->addPoint(new Coordinate(39.930131, 116.377476));
$geo->addPoint(new Coordinate(39.911305, 116.377476));
$geo->addPoint(new Coordinate(39.911305, 116.417301));
//两个坐标做测试
$a = new Coordinate(39.916527, 116.397128);
$b = new Coordinate(39.901305, 116.397128);
//判断是否在执行的多边形中
if ($geo->contains($a)) {
echo "a点在多边形的范围内";
} else {
echo "a点不在多边形的范围内";
}
echo "<br/>";
if ($geo->contains($b)) {
echo "b点在多边形的范围内";
} else {
echo "b点不在多边形的范围内";
}
PHP多区域判断点是否在多边形区域围栏内
<?php
// *** 配置文件(表示区域的三维数组)其内的点,必须按顺时针方向依次给出!
$area = array(
// 天通苑店
0 => array(
array('x' => 116.448275, 'y' => 40.083313),
array('x' => 116.441448, 'y' => 40.038418),
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.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)
)
);
/*
*** 配置文件(表示区域的三维数组)其内的点,必须按顺时针方向依次给出!
*** 确定一点是否在一区域(多边形)内:
1:过这一点(x0, y0),画一水平线(y=y0),与多边形的所有边进行交点判断。
2:获取交点集(其中不含多边形的顶点)
3:若该点(x0, y0)的左侧和右侧交点个数均为奇数个,则该点在区域(多边形)内。否则:不在。
*** 返回结果:
return === false : 点不在区域内
return 0, 1, 2, 3 ... 点所在的区域编号(配置文件中的区域编号。)
*** Author : Guojunzhou / Eric
*** Main : php20141104@163.com
*/
class Area
{
// 一个表示区域的三维数组
protected $config = null;
// 包含每个区域的四边形
protected $rectangles = null;
// 每个区域(多边形)的所有边
protected $lines = null;
// 要判断的点的x, y坐标
protected $_x = null;
protected $_y = null;
public function __construct($config)
{
$this->config = $config;
$this->initRectangles();
$this->initLines();
}
/*
获取包含每个配送区域的四边形
*/
private 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 条边
*/
private 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坐标最小值
*/
private function getMinXInEachConfig($index)
{
$minX = 200;
foreach ($this->config[$index] as $k => $v) {
if ($v['x'] < $minX) {
$minX = $v['x'];
}
}
return $minX;
}
/*
获取一组坐标中,y坐标最小值
*/
private 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 与特定区域的所有边的交点,并去除和顶点重复的,再将交点分为左和右两部分
*/
private 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);
var_dump($area->checkPoint(116.531748, 39.944229));
JAVA判断一个点是否在多边形内,射线法,电子围栏
/**
* 根据某点坐标判断该坐标是否在某区域坐标范围内
* @param px 目标点x坐标
* @param py 目标点y坐标
* @param polygonXA 目标范围xy坐标集合
* @return
*/
public boolean rayCasting(double px, double py, String polygon) {
boolean flag = false;
String[] points = polygon.split(",");
for (int i = 0, j = points.length - 2; i < points.length - 1; j = i, i = i + 2) {
double sx = Double.parseDouble(points[j]);// 从倒数第二依次读取;
double sy = Double.parseDouble(points[j + 1]);// 从倒第一依次读取;
double tx = Double.parseDouble(points[i]);// 从第一个依次读取;
double ty = Double.parseDouble(points[i + 1]);// 从第二个依次读取;
// 点与多边形顶点重合
if ((sx == px && sy == py) || (tx == px && ty == py)) {
return true;
}
// 判断线段两端点是否在射线两侧,射线为y轴;
if ((sy < py && ty >= py) || (sy >= py && ty < py)) {
// 线段上与射线 Y 坐标相同的点的 X 坐标
double x = sx + (py - sy) * ((tx - sx) / (ty - sy));
// 点在多边形的边上
if (x == px) {
return true;
}
// 射线穿过多边形的边界
if (x > px) {
flag = !flag;
}
}
}
// 射线穿过多边形边界的次数为奇数时点在多边形内
return flag;
}
原文连接:PHP/JAVA判断点是否在多边形区域围栏内
所有媒体,可在保留署名、
原文连接
的情况下转载,若非则不得使用我方内容。