GIS算法基础(三)计算几何基础(下)

 

判断线段在多边形内的算法:

算法思路:

如果线段与多边形内交,则线段一定在多边形外;如果线段和多边形的每一条边都不内交,如果有交点,则线段和多边形的交点一定是线段的端点或者多边形的顶点,然后只需要判断交点是否在线段上就可以了

算法步骤:

  1. 判断线段的两个端点是否在多边形内部
  2. 开始遍历多边形的每条边
  3. 判断线段的端点是否在多边形上
  4. 判断多边形的端点是否在线段上
  5. 如果2、3条件都不满足,判断线段是否与多边形的边是否相交,如果相交则说明内交
  6. 如果5得出不相交,则判断各交点的中点是否在多边形内部

算法实现(JAVA):

	public static boolean isSegmentAtPolygon(Line line,Polygon polygon) {
		//判断线段的两端点是否在多边形内部
		if(!isPointAtPolygon(polygon, line.getStart(), 0) || !isPointAtPolygon(polygon, line.getEnd(), 0)) {
			System.out.println("端点不在多边形内部");
			return false;
		}
		//交点集
		List<Point> pointSet = new ArrayList<>();
		//判断多边形的各条边与线段不内交
		for(Line bian : polygon.getLines()) {
			//判断线段的两端点是否在多边形上
			if(isPointAtSegment(bian, line.getStart()) || isPointAtSegment(bian, line.getEnd())) {
				if(isPointAtSegment(bian, line.getStart())) {
					pointSet.add(line.getStart());
				}
				if(isPointAtSegment(bian, line.getEnd())) {
					pointSet.add(line.getEnd());
				}
			//判断多边形的边的某个端点是否在线段上
			}else if (isPointAtSegment(line, bian.getStart())||isPointAtSegment(line, bian.getEnd())) {
				if(isPointAtSegment(line, bian.getStart())) {
					pointSet.add(bian.getStart());
				}
				if(isPointAtSegment(line, bian.getEnd())) {
					pointSet.add(bian.getEnd());
				}
			//判断是否相交,如果程序进行此次判断,则说明上两个判断都不满足,则说明线段与边内交
			}else if (isTwoSegmentIntersect(bian, line)) {
				System.out.println("线段与多边形内交");
				return false;
			}
		}
		
		//对交点集进行按照x,y排序,为了更方便的比较各交点的中点是否在多边形内
		Comparator<Point> XYcomparator = new Comparator<Point>() {
			//优先对X进行排序,x相等则对y进行排序
			@Override
			public int compare(Point arg0, Point arg1) {
				// TODO Auto-generated method stub
				if(arg0.getX()-arg1.getX()==0) {
					return (int) (arg0.getY()-arg1.getY());
				}else {
					return (int) (arg0.getX()-arg1.getX());
				}
				
			}
		};
		
		Collections.sort(pointSet, XYcomparator);
		//一次判断每两个相邻点的中点是否在多边形内
		for(int i=0;i<pointSet.size();i++) {
			//如果是最后一个点,循环结束
			if(i==pointSet.size()-1) {
				break;
			}
			Point a = pointSet.get(i);
			Point b = pointSet.get(i+1);
			Point center = new Point((a.getX()+b.getX())/2.0,(b.getY()+a.getY())/2.0);
			if(!isPointAtPolygon(polygon, center, 0)) {
				System.out.println("中点不在多边形内部");
				return false;
			}
		}
		return true;
	}

 

说明:isTwoSegmentIntersect函数判断两线段是否相交,思路是对两线段进行快速排斥试验与跨越试验。

isPointAtPolygon函数是上文已经实现了的判断点是否在多边形内,这里使用的是射线法法进行判断

isPointAtSegment函数判断点是否在线段上,思路是判断点与线段一端点的叉积与点是否在线所围成的矩形中

这些方法的实现我在计算几何基础(上),计算几何基础(中)中已经实现过了

https://blog.csdn.net/weixin_41154636/article/details/82968255

https://blog.csdn.net/weixin_41154636/article/details/82986381

下面附上isTwoSegmentIntersect函数实现与isPointAtSegment函数的实现

	/**
	 * 判断两线段是否相交
	 * @param a
	 * @param b
	 * @param c
	 * @param d
	 * @return
	 */
	public static boolean isTwoSegmentIntersect(Point a,Point b,Point c,Point d) {
		boolean flag1 = false;
		boolean flag2 = false;
		//快速排斥试验
		if(Math.min(a.getY(), b.getY())<=Math.max(c.getY(), d.getY()) && Math.min(c.getX(), d.getX())<=Math.max(a.getX(), b.getX())
				&& Math.min(c.getY(), d.getY())<= Math.max(a.getY(), b.getY()) && Math.min(a.getX(), b.getX())<= Math.max(c.getX(), d.getX())) {
			flag1 = true;
		}
		Vector2D ab = getVector(a, b);
		Vector2D ac = getVector(a, c);
		Vector2D bd = getVector(b, d);
		//跨立试验
		if(ac.crossProduct(ab) * bd.crossProduct(ab) <=0) {
			flag2 = true;
		}
		return flag1&&flag2;
	}
	/**
	 * 判断点是否在线段上
	 * @param p1 线段端点
	 * @param p2 线段端点
	 * @param q	需要判断的点
	 * @return
	 */
	public static boolean isPointAtSegment(Point p1,Point p2,Point q) {
		
		//判断是否在线段围成的区域内
		if(q.getX()<=Math.max(p1.getX(), p2.getX()) && q.getX()>=Math.min(p1.getX(), p2.getX())
				&& q.getY()<= Math.max(p1.getY(), p2.getY()) && q.getY()>=Math.min(p1.getY(), p2.getY()))
		{
		Vector2D qp1 = getVector(q, p1);
		Vector2D p2p1 = getVector(p2, p1);
		return qp1.crossProduct(p2p1)==0?true:false;
		}else {
			return false;
		}
		
	}

测试结果

测试数据1、
多边形数据
Point aPoint = new Point(0, 0);
Point bPoint = new Point(20, -20);
Point cPoint = new Point(50, 30);
Point dPoint = new Point(30, 30);
Point ePoint = new Point(60, -20);
Point fPoint = new Point(80, 0);
Point gPoint = new Point(40, 70);
待测线段数据:
Point p1 = new Point(0, 0);
Point p2 = new Point(100, 100);
Line line1 = new Line(p1,p2);

GUI绘制结果:

图像走丢了

计算几何还有一些别的算法,不过毕竟简单也挺好实现的,我就没有写出了

猜你喜欢

转载自blog.csdn.net/weixin_41154636/article/details/84647599