随笔:电子围栏:矩形、圆与多边形的处理

一、电子围栏的实现(一):矩形、圆与多边形的处理

矩形区域处理

针对矩形区域处理,复杂度较低。设矩形ABCD的四个顶点分别为A、B、C、D,坐标分别为A(x1,y1)、B(x2,y2)、C(x3,y3)、D(x4,y4),设点E(x5,y5)是需要判断的点。那么判断点E是否在矩形区域的方法是:x5>x3且x5<x2,同时满足y5>y3且y5<y2,当然我们也可以把A、D两个点作为参照
在这里插入图片描述

/**
  * 判断是否在矩形范围内
  * @param lat		测试点纬度
  * @param lng		测试点经度
  * @param minLat	纬度范围限制1
  * @param maxLat	纬度范围限制2
  * @param minLng	经度范围限制1
  * @param maxLng	经度范围限制2
  * @return
  */
public static boolean isInRectangleArea(double lat, double lng, double minLat, double maxLat, double minLng, double maxLng){
		
    if(isInRange(lat, minLat, maxLat)){//如果在维度范围内
        if(minLng*maxLng>0){
	    if(isInRange(lng, minLng, maxLng)){
		return true;
	    }else{
	        return false;
	    }
        }else{
	    if(Math.abs(minLng)+Math.abs(maxLng)<180){
		if(isInRange(lng, minLng, maxLng)){
		    return true;
		}else{
		    return false;
		}
	    }else{
                double left = Math.max(minLng, maxLng);
	        double right = Math.min(minLng, maxLng);
	        if(isInRange(lng, left, 180) || isInRange(lng, right, -180)){
                    return true;
	         }else{
		    return false;
	         }
	    }
	}
    }else{
	return false;
    }
}
圆形区域处理

在这里插入图片描述

对于圆形区域,我们假设地球是正圆的,同时假设圆心为B(Xb,Yb),A(Xa,Ya)为判断的点,Xb,Yb为B点经纬度,Xa,Ya为A点经纬度,A,B是地球表面的两个点,如图2中的a所示,已知A、B两点的经度后,我们可以计算CD的地面长度为: 在这里插入图片描述
CD不但可以平移至B点,也可以 平移至A点,当然算出的结果不一样,这里将式(6)中的Yb取值为(Ya+Yb)/2,即去平均值,效果较佳。

/**
 * 地球半径
 */
private static double EARTH_RADIUS = 6378138.0;
 
private static double rad(double d){
	return d * Math.PI / 180.0;
}
 
/**
 * 计算是否在圆上(单位/千米)
 * @param radius	半径
 * @param lat1		维度
 * @param lng1		经度
 * @return
 */
public static boolean isInCircle(double radius, double lat1, double lng1, double lat2, double lng2){
	
	double radLat1 = rad(lat1);
	double radLat2 = rad(lat2);
	double a = radLat1 - radLat2;
	double b = rad(lng1) - rad(lng2);
	double s = 2 * Math.asin(Math.sqrt(Math.pow(
			Math.sin(a/2), 2) + 
			Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(b/2), 2)));
	s = s * EARTH_RADIUS;
	s = Math.round(s * 10000) / 10000;
	if(s > radius){//不在圆上
		return false;
	}else{
		return true;
	}
}
多边形区域处理

在这里插入图片描述
如图3,判断点p在多边形内的方法是:用点p的水平坐标去和多边形相交,得到若干个交点,如果点p两侧的交点数量都是奇数个时,说明p点在多边形内,即铅垂线内点法。使用这种方法,适合任意多边形,包括凸多边形和凹多边形,同时适用于有孔的多边形。下面给出这种算法的Java实现

/**
 * 判断点是否在多边形内
 * @param polygon	多边形
 * @param point		检测点
 * @return			点在多边形内返回true,否则返回false
 */
public static boolean IsPtInPoly(List<Point2D.Double> polygon, Point2D.Double point){
	
	int N = polygon.size();
	boolean boundOrVertex = true;//如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
	int intersectCount = 0;//cross points count of x--交叉点计数X
	double precision = 2e-10;//浮点类型计算时候与0比较时候的容差
	Point2D.Double p1, p2;//neighbour bound vertices--临近绑定顶点
	Point2D.Double p = point;//当前点
	
	p1 = polygon.get(0);//left vertex--左顶点
	for (int i = 1; i <= N; ++i) {//check all rays--检查所有射线
		if(p.equals(p1))
		return boundOrVertex;//p is an vertex--p是一个顶点
		
		p2 = polygon.get(i % N);//right vertex--右顶点
		if(p.x < Math.min(p1.x, p2.x) || p.x > Math.max(p1.x, p2.x)){//ray is outside of our interests--射线不在我们的兴趣范围之内
			p1 = p2;
			continue;//next ray left point--下一条射线的左边点
		}
		
		if(p.x > Math.min(p1.x, p2.x) && p.x < Math.max(p1.x, p2.x)){//ray is crossing over by the algorithm(common part of)--射线被算法穿越(常见的一部分)
			if(p.y <= Math.max(p1.y, p2.y)){//x is before of ray--x在射线之前
				if(p1.x == p2.x && p.y >= Math.min(p1.y, p2.y)){//overlies on a horizontal ray--在一条水平射线上
					return boundOrVertex;
				}
				
				if(p1.y == p2.y){//ray is vertical--射线是垂直的
					if(p1.y == p.y){//overlies on a vertical ray--覆盖在垂直光线上
						return boundOrVertex;
					}else{//before ray--射线之前
						++intersectCount;
					}
					
				}else{//cross point on the left side--左边的交叉点
					double xinters = (p.x - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;//cross point of y--y的交叉点
					if(Math.abs(p.y - xinters) < precision){//overlies on a ray--覆盖在射线
						return boundOrVertex;
					}
					
					if(p.y < xinters){//before ray--射线之前
						++intersectCount;
					}
				}
			}
		}else{//special case when ray is crossing through the vertex--特殊情况下,当射线穿过顶点
			if(p.x == p2.x && p.y <= p2.y){//p crossing over p2--p交叉p2
				Point2D.Double p3 = polygon.get((i+1) % N);//next vertex--下一个顶点
				if(p.x >= Math.min(p1.x, p3.x) && p.x <=Math.max(p1.x, p3.x)){//p.x lies between p1.x & p3.x--p.x在p1.x和p3.x之间
					++intersectCount;
				}else{
					intersectCount +=  2;
				}
			}
		}
		p1 = p2;//next ray left point--下一条射线的左边点
	}
	if(intersectCount % 2 == 0){//偶数在多边形外
		return false;
	}else{//奇数在多边形内
		return true;
	}
}
补充:铅垂线内点法

铅垂线内点法的基本思想是从待判别点向外引垂线,计算其与多边形交点的个数,若交点个数为奇数,则点在多边形内;若交点个数为偶数,则该点在多边形外,如下图上面两图。
在这里插入图片描述
这种方法不但适合于任意凸、凹多边形,而且适合于甚至于有孔的多边形,当然, 如果铅垂线恰好教育多边形的顶点或边上时,这时只需计算一侧的交点个数即可,如上图下面两图。

二、电子围栏的实现(二):几何路径法

注意:此方法复杂的多边形判断失败

在Java语言的开发环境中,提供了一种便捷的方法。类java.awt…geom.GeneralPath提供了根据直线、二次曲线和三次曲线构造的几何路径的方法,同时GeneralPath类继承类Path2D,通过Path2D类提供的方法contains(double x,double y)来判断某个点是否在曲线或直线构成的边界内。

package com.test;
 
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
 
public class ElectronicFence {
	
	/**
	 * 测试一个点是否在多边形内
	 * @param args
	 */
	public static void main(String[] args) {
		
		//点在多边形内
		Point2D.Double point = new Point2D.Double(116.395, 39.910);
		//点在多边形外
//		Point2D.Double point = new Point2D.Double(116.404072, 39.916605);
		
		List<Point2D.Double> polygon = new ArrayList<Point2D.Double>();
		polygon.add(new Point2D.Double(116.395, 39.910));
		polygon.add(new Point2D.Double(116.394, 39.914));
		polygon.add(new Point2D.Double(116.403, 39.920));
		polygon.add(new Point2D.Double(116.402, 39.914));
		polygon.add(new Point2D.Double(116.410, 39.913));
		
		if(polygon.contains(point)){
			System.out.println("点在多边形内");
		}else{
			System.out.println("点在多边形外");
		}
	}
		
	/**
	 * 判断点是否在多边形内
	 * 步骤:
	 * 		①声明一个“画笔”
	 * 		②将“画笔”移动到多边形的第一个顶点
	 * 		③用“画笔”按顺序将多边形的顶点连接起来
	 * 		④用“画笔”将多边形的第一个点连起来,最终形成一个封闭的多边形
	 * 		⑤用contains()方法判断点是否在多边形区域内
	 * @param polygon	多边形
	 * @param point		检测点
	 * @return			点在多边形内返回true,否则返回false
	 */
	public static boolean contains(List<Point2D.Double> polygon, Point2D.Double point){
		
		GeneralPath p = new GeneralPath();
		
		Point2D.Double first = polygon.get(0);
		p.moveTo(first.x, first.y);
		
		for(Point2D.Double d : polygon){
			p.lineTo(d.x, d.y);
		}
		
		p.lineTo(first.x, first.y);
		p.closePath();
		
		return p.contains(point);
	}
}

其中p为构造的GeneralPath对象,polygon包含了多边形顶点的List对象,每个顶点被定义为Point2D.Double类型。point则是要判断的点,其类型也为Point2D.Double。p.contains(point)返回true则表示点point包含在多边形polygon内。


作者:Johnson8702
原文:https://blog.csdn.net/johnson8702/article/details/82145220
原文:https://blog.csdn.net/johnson8702/article/details/82150371

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值