向量法计算多边形面积

  计算多边形面积的方法为将多边形分解成多个三角形,然后把这些三角形的面积相加。三角形面积为两边向量叉积除以2。

  这是Java代码,目前是第3版 ,已经尽可能优化了,相比初版有25%的性能提升。

	/**
	 * 平面多边形面积算法3,用原点为基点(不需要从图形边线上取点)<br/>
	 * 多计算一条线段,但减少了每一步的两次减法(起于原点的向量等于节点的坐标),使误差减小,每一步的计算量减少。
	 * 
	 * @return 正方向(x轴向y轴旋转方向)圈成的面积(如果有反方向的圈,则面积会被抵消,导致结果小于直观观测的面积或为负数)
	 */
	private static final double getPolygonAreaMethodC(double... points) {
		if (points.length < 6) {
			// 无法构成多边形
			return 0;
		}
		final int pointArrayLength = points.length & (~1);
		// final int pointCount = pointArrayLength / 2;

		double area = 0.0;

		double dx1, dy1;
		double dx2, dy2;

		// 从原点到该点的向量
		dx1 = points[pointArrayLength - 2];
		dy1 = points[pointArrayLength - 1];
		for (int i = 0; i < pointArrayLength;) {
			// 从原点到该点的向量
			dx2 = points[i++];
			dy2 = points[i++];

			// 三角形的面积2倍,平行四边形面积。为提高性能,不在循环中进行面积减半
			final double subArea = dx1 * dy2 - dx2 * dy1;// 由jvm进行智能内联,分出这一步不会影响性能
			area += subArea;

			// 向量传递
			dx1 = dx2;
			dy1 = dy2;
		}

		// 最后统一除以2,提高性能
		return area / 2;
	}

  除了可以用来计算面积,还可以进行分布式计算π。把半径R的圆分解成很多边的多边形,每台计算机只计算其中的一部分。然后将每台计算机算出的面积相加得到面积S。π=S/(R^2)。这只是一种用法,事实上并不建议用此方法计算π。最好的办法仍然是可迭代的,所以分布式计算π并没有优势。

  下面是C++的版本,也是初版,作为参考。

        /**
	 * 平面多边形面积
	 *
	 * @return
	 */
double getPolygonArea(double *points, int length) {
    if (length < 6) {
        // 无法构成多边形
        return 0;
    }
    double area = 0.0;
    double x0 = points[0], y0 = points[1];

    double dx1, dy1;
    double dx2, dy2;

    dx1 = points[2] - x0;
    dy1 = points[3] - y0;
    for (int i = 4; i < length - 1; i += 2) {
        dx2 = points[i] - x0;
        dy2 = points[i + 1] - y0;

        double subArea = (dx1 * dy2 - dx2 * dy1) / 2.0;
        area += subArea;

        dx1 = dx2;
        dy1 = dy2;
    }
    return area;
}

Java并发版本(有依赖项,不可直接使用)。

依赖项1:ParallelTask.parallelFor其实是线程池。第一个参数0代表WorkSteal线程池。第二个参数代表Lambda执行的次数,一般取CPU核心数。Lambda的参数threadOrder代表此Lambda所在线程启动的顺序。静态的方法parallelFor代表内部生成线程池,并在返回之前关闭和等待线程池任务结束。ParallelTask是一个实现了十几种动态与静态parallelFor的大文件,不方便上传。

依赖项2:StaticSystemUtils.getCPUCoreCount就是Runtime.avaliableProcesses()。StaticSystemUtils是一个获取系统信息的大文件,不方便上传。

依赖项3:StaticMathUtils.sum就是一个求和函数。StaticMathUtils是一个包含数十种算术方法,几千行的大文件,不方便上传。

	/**
	 * 平面多边形面积算法3,用原点为基点(不需要从图形边线上取点)<br/>
	 * 多计算一条线段,但减少了每一步的两次减法(起于原点的向量等于节点的坐标),使误差减小,每一步的计算量减少。
	 * 
	 * @return 正方向(x轴向y轴旋转方向)圈成的面积(如果有反方向的圈,则面积会被抵消,导致结果小于直观观测的面积或为负数)
	 */
	public static final double getPolygonAreaParallel(double... points) {
		if (points.length < 6) {
			// 无法构成多边形
			return 0;
		}
		final int pointArrayLength = points.length & (~1);
		final int pointCount = pointArrayLength / 2;

		double area = 0.0;

		final int taskCount = Math.min(StaticSystemUtils.getCPUCoreCount(), pointCount);
		final double[] eachArea = new double[taskCount];
		ParallelTask.parallelFor(0, taskCount, threadOrder -> {
			final int from = (int) ((long) threadOrder * pointArrayLength / taskCount) & (~1);
			final int to = (int) ((long) (threadOrder + 1) * pointArrayLength / taskCount) & (~1);

			double threadArea = 0.0;

			double dx1, dy1;
			double dx2, dy2;

			// 从原点到该点的向量
			if (threadOrder == 0) {
				dx1 = points[pointArrayLength - 2];
				dy1 = points[pointArrayLength - 1];
			} else {
				dx1 = points[from - 2];
				dy1 = points[from - 1];
			}
			for (int i = from; i < to;) {
				// 从原点到该点的向量
				dx2 = points[i++];
				dy2 = points[i++];

				// 三角形的面积2倍,平行四边形面积。为提高性能,不在循环中进行面积减半
				final double subArea = dx1 * dy2 - dx2 * dy1;// 由jvm进行智能内联,分出这一步不会影响性能
				threadArea += subArea;

				// 向量传递
				dx1 = dx2;
				dy1 = dy2;
			}

			eachArea[threadOrder] = threadArea;
		});

		area = StaticMathUtils.sum(eachArea);

		// 最后统一除以2,提高性能
		return area / 2;

	}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值