射线法判断点是否在多边形内-JAVA

1、定义点

public class Point {
	private BigDecimal x;
	private BigDecimal y;

	public Point() {
	};

	@Override
	public String toString() {
		DecimalFormat df = new DecimalFormat("#.000000000000000000000000000000");
		return "Point [x=" + df.format(x) + ", y=" + df.format(y) + "]";
	}

	public Point(BigDecimal x, BigDecimal y) {
		this.x = x;
		this.y = y;
	}

	public BigDecimal getX() {
		return x;
	}

	public void setX(BigDecimal x) {
		this.x = x;
	}

	public BigDecimal getY() {
		return y;
	}

	public void setY(BigDecimal y) {
		this.y = y;
	}
}

2、定义线(多边形的边)


public class Line {
	private Point apoint;
	private Point zpoint;
	private BigDecimal k;
	private BigDecimal b;

	public Line() {
	}

	public Line(Point a, Point z) {
		this.apoint = a;
		this.zpoint = z;
	}

	public Line(BigDecimal x1, BigDecimal y1, BigDecimal x2, BigDecimal y2) {
		this.apoint = new Point(x1, y1);
		this.zpoint = new Point(x2, y2);
	}

	/**
	 * 计算中点
	 * 
	 * @return
	 */
	public Point getMidPoint() {
		Point midPoint = null;
		if (apoint != null && zpoint != null) {
			BigDecimal x = (apoint.getX().add(zpoint.getX())).divide(
					new BigDecimal(2), PolygonUtil.ACCURACY,
					BigDecimal.ROUND_HALF_UP);
			BigDecimal y = (apoint.getY().add(zpoint.getY())).divide(
					new BigDecimal(2), PolygonUtil.ACCURACY,
					BigDecimal.ROUND_HALF_UP);
			midPoint = new Point(x, y);
		}
		return midPoint;
	}

	/**
	 * 获取斜率
	 * 
	 * @return
	 */
	public BigDecimal getK() {
		// k = (y1 - y2) / (x1 - x2)
		if (k == null) {
			k = BigDecimal.ZERO;
			if (apoint != null && zpoint != null) {
				if (apoint.getX().compareTo(zpoint.getX()) != 0) {
					k = (apoint.getY().subtract(zpoint.getY())).divide(apoint
							.getX().subtract(zpoint.getX()),
							PolygonUtil.ACCURACY, BigDecimal.ROUND_HALF_UP);
				}
			}
		}
		return k;
	}

	public BigDecimal getB() {
		// b = y - kx
		if (b == null) {
			b = BigDecimal.ZERO;
			if (apoint != null && zpoint != null) {
				BigDecimal k = getK();
				if (k.compareTo(BigDecimal.ZERO) == 0) {
					b = apoint.getY();
				} else {
					b = apoint.getY().subtract(apoint.getX().multiply(k));
				}
			}
		}
		return b;
	}

	@Override
	public String toString() {
		DecimalFormat df = new DecimalFormat("#.000000000000000000000000000000");

		return "Line [apoint=" + apoint + ", zpoint=" + zpoint
				+ ", getMidPoint()=" + getMidPoint() + ", getK()="
				+ df.format(getK()) + ", getB()=" + df.format(getB())
				+ ", getApoint()=" + getApoint() + ", getZpoint()="
				+ getZpoint() + ", getClass()=" + getClass() + ", hashCode()="
				+ hashCode() + ", toString()=" + super.toString() + "]";
	}

	public Point getApoint() {
		return apoint;
	}

	public void setApoint(Point apoint) {
		this.apoint = apoint;
	}

	public Point getZpoint() {
		return zpoint;
	}

	public void setZpoint(Point zpoint) {
		this.zpoint = zpoint;
	}
}

3、判断线是否在多边形内

public class PolygonUtil {
	private final static Logger logger = LoggerFactory
			.getLogger(GeoService.class);
	public static final int ACCURACY = 30;
	
	/**
	 * 将多边形拆除多条边(此处为超图多边形模型,可根据具体模型修改此方法)
	 * @param polygon
	 * @return
	 */
	public List<Line> getLineList(GeoRegion polygon) {
		List<Line> lines = new ArrayList<Line>();
		Point2D apt = null;
		Point2D zpt = null;
		Point2Ds pts = null;
		Line line = null;
		for (int i = 0; i < polygon.getPartCount(); i++) {
			pts = polygon.getPart(i);
			for (int j = 0; j < pts.getCount() - 1; j++) {
				apt = pts.getItem(j);
				zpt = pts.getItem(j + 1);
				line = new Line(new BigDecimal(apt.getX()), new BigDecimal(
						apt.getY()), new BigDecimal(zpt.getX()),
						new BigDecimal(zpt.getY()));
				lines.add(line);
			}
		}

		return lines;
	}

	/**
	 * 判断点是否在多边形内
	 * 
	 * @param point
	 * @param lines
	 * @return
	 */
	public boolean withIn(Point point, List<Line> lines) {
		// 根据面第一条边中点确认射线
		Line ray = new Line(point, lines.get(0).getMidPoint());
		Line line = null;
		Point meetPoint = null;
		// logger.info(ray.toString());
		// logger.info(lines.get(0).getMidPoint().toString());
		// 因为第一条边必定与射线相交,则从第二条边开始判断
		int count = 1;
		for (int i = 1; i < lines.size(); i++) {
			// logger.info("---------------------");
			line = lines.get(i);
			meetPoint = getMeetPoint(ray, line);
			if (line.getK().compareTo(ray.getK()) != 0) {
				if (isInline(meetPoint, line) && isInRay(meetPoint, ray)) {
					count++;
				}
			}
			// logger.info(line.toString());
			// logger.info(meetPoint.toString());
		}

		return count % 2 == 0 ? false : true;
	}

	/**
	 * 获取交汇点
	 * 
	 * @param ray
	 * @param line
	 * @return
	 */
	public Point getMeetPoint(Line ray, Line line) {
		// x = (b1 - b2) / (k2 - k1)
		// y = kx + b
		Point point = null;
		BigDecimal x = BigDecimal.ZERO;
		BigDecimal y = BigDecimal.ZERO;
		// logger.info("KK:{}", line.getK().compareTo(ray.getK()));
		if (line.getK().compareTo(ray.getK()) != 0) {
			if (line.getK().compareTo(BigDecimal.ONE) == 0) {
				x = line.getApoint().getX();
			} else {
				x = (ray.getB().subtract(line.getB())).divide(line.getK()
						.subtract(ray.getK()), PolygonUtil.ACCURACY,
						BigDecimal.ROUND_HALF_UP);
			}
			if (line.getK().compareTo(BigDecimal.ZERO) == 0) {
				y = line.getApoint().getY();
			} else {
				y = ray.getK().multiply(x).add(ray.getB());
			}
			point = new Point(x, y);
		}
		return point;
	}

	/**
	 * 判断交汇点是否在线段上
	 * 
	 * @param point
	 * @param line
	 * @return
	 */
	public boolean isInline(Point point, Line line) {

		boolean result = false;
		if (point == null || point.getX() == null || point.getY() == null) {
			result = false;
		} else if ((line.getApoint().getX().compareTo(point.getX()) == -1 && line
				.getZpoint().getX().compareTo(point.getX()) == -1)
				|| (line.getApoint().getX().compareTo(point.getX()) == 1 && line
						.getZpoint().getX().compareTo(point.getX()) == 1)
				|| (line.getApoint().getY().compareTo(point.getY()) == -1 && line
						.getZpoint().getY().compareTo(point.getY()) == -1)
				|| (line.getApoint().getY().compareTo(point.getY()) == 1 && line
						.getZpoint().getY().compareTo(point.getY()) == 1)) {
			result = false;
		} else {
			result = true;
		}
		// logger.info("AX:{}",
		// line.getApoint().getX().compareTo(point.getX()));
		// logger.info("ZX:{}",
		// line.getZpoint().getX().compareTo(point.getX()));
		// logger.info("AY:{}",
		// line.getApoint().getY().compareTo(point.getY()));
		// logger.info("ZY:{}",
		// line.getZpoint().getY().compareTo(point.getY()));
		// logger.info("RESULT:{}", result);
		return result;
	}

	/**
	 * 判断点是否在射线上
	 * 
	 * @param point
	 * @param ray
	 * @return
	 */
	public boolean isInRay(Point point, Line ray) {
		boolean result = false;
		if (point == null || point.getX() == null || point.getY() == null) {
			result = false;
		} else {
			BigDecimal x = (ray.getApoint().getX().subtract(ray.getZpoint()
					.getX())).multiply(ray.getApoint().getX()
					.subtract(point.getX()));
			BigDecimal y = (ray.getApoint().getY().subtract(ray.getZpoint()
					.getY())).multiply(ray.getApoint().getY()
					.subtract(point.getY()));
			if (x.compareTo(new BigDecimal(0)) < 0
					|| y.compareTo(new BigDecimal(0)) < 0) {
				result = false;
			} else {
				result = true;
			}
		}
		return result;
	}
	
	/**
	 * 测试
	 * @param args
	 */
	public static void main(String[] args) {
		// 组成多边形的边集合
		List<Line> lines = new ArrayList<Line>();
		Point a = new Point(new BigDecimal(1D), new BigDecimal(1D));
		Point b = new Point(new BigDecimal(2D), new BigDecimal(5D));
		Point c = new Point(new BigDecimal(5D), new BigDecimal(6D));
		Point d = new Point(new BigDecimal(4D), new BigDecimal(2D));
		lines.add(new Line(a, b));
		lines.add(new Line(b, c));
		lines.add(new Line(c, d));
		lines.add(new Line(d, a));
		
		List<Point> pointList = new ArrayList<Point>();
		pointList.add(new Point(new BigDecimal(3.1D), new BigDecimal(3.1D)));
		pointList.add(new Point(new BigDecimal(7D), new BigDecimal(7D)));
		
		PolygonUtil test = new PolygonUtil();
		
		for (Point point: pointList) {
			if (test.withIn(point, lines)) {
				System.out.printf("点在多边形内:%s\n", point.toString());
			} else {
				System.out.printf("点不在多边形内:%s\n", point.toString());
			}
		}
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值