常见的threejs图形算法类。

<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title>ThreeJS之常见几何高级图形算法13种</title>
		<script src="../js/three.js"></script>
	</head>

	<body>
		<script>
			/**
			 * 求直线的斜率
			 * @param x1 起点x坐标
			 * @param y1 起点y坐标
			 * @param x2 终点x坐标
			 * @param y2 终点y坐标
			 * @returns {Number} 直线的斜率
			 */
			function getSlopeOfLine(x1, y1, x2, y2) {
				let ox = x2 - x1,
					oy = y2 - y1;
				let sign = ox > 0 ? 1 : -1;
				if(Math.abs(ox - 0) < 0.001) { //直线与x轴垂直
					return sign * Number.MAX_VALUE;
				} else if(Math.abs(oy - 0) < 0.001) { //直线与x轴平行
					return 0;
				} else { //其它情况
					return oy / ox;
				}
			}

			/**
			 * 计算线段与圆的交点
			 * @param x1 直线的点P1的x坐标
			 * @param y1 直线的点P1的y坐标
			 * @param x2 直线的点P2的x坐标
			 * @param y2 直线的点P2的y坐标
			 * @param cx 圆心位置C的x坐标
			 * @param cy 圆心位置C的y坐标
			 * @param r 圆的半径
			 *  @param segment 将P1P2视为线段还是直线,true是线段,false是直线,默认是true
			 * @returns {{x1: Number, y1: Number, x2: Number, y2: Number,length: Number}} 返回交点坐标,length指出交点的个数
			 */
			function intersection(x1, y1, x2, y2, cx, cy, r, segment) {
				/*
				  算法参考链接:http://mathworld.wolfram.com/Circle-LineIntersection.html
				 */
				/*
				保存原有数据,并将设置直线偏移(原因是下面的算法中的圆的圆心是在原点的)
				 */
				let ox1 = x1,
					ox2 = x2,
					oy1 = y1,
					oy2 = y2;
				x1 -= cx;
				y1 -= cy;
				x2 -= cx;
				y2 -= cy;
				/*
				计算交点
				 */
				let dx = x2 - x1,
					dy = y2 - y1,
					dr = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)),
					D = x1 * y2 - x2 * y1,
					sign = dy > 0 ? 1 : -1;
				let theta = Math.sqrt(r * r * dr * dr - D * D);
				let ix1 = (D * dy - sign * dx * theta) / (dr * dr);
				let iy1 = (-D * dy - Math.abs(dy) * theta) / (dr * dr);
				let ix2 = (D * dy + sign * dx * theta) / (dr * dr);
				let iy2 = (-D * dy + Math.abs(dy) * theta) / (dr * dr);
				let rx1 = cx + ix1,
					ry1 = cy + iy1,
					rx2 = cx + ix2,
					ry2 = cy + iy2;
				/*
				检查交点是否线段上
				 */
				let flag1, flag2;
				segment = segment === false ? false : true;
				if(segment) {
					flag1 = ox1 < ox2 ? (rx1 >= ox1 && rx1 <= ox2) : (rx1 <= ox1 && rx1 >= ox2);
					flag1 = flag1 && (oy1 < oy2 ? (ry1 >= oy1 && ry1 <= oy2) : (ry1 <= oy1 && ry1 >= oy2));
					flag2 = ox1 < ox2 ? (rx2 >= ox1 && rx2 <= ox2) : (rx2 <= ox1 && rx2 >= ox2);
					flag2 = flag2 && (oy1 < oy2 ? (ry2 >= oy1 && ry2 <= oy2) : (ry2 <= oy1 && ry2 >= oy2));
				} else {
					flag1 = flag2 = true;
				}
				let length = (flag1 ? 1 : 0) + (flag2 ? 1 : 0);
				return {
					x1: flag1 ? rx1 : undefined,
					y1: flag1 ? ry1 : undefined,
					x2: flag2 ? rx2 : undefined,
					y2: flag2 ? ry2 : undefined,
					length: length
				};
			}

			/**
			 * 计算线段的长度
			 * @param x1 起点x坐标
			 * @param y1 起点y坐标
			 * @param x2 终点x坐标
			 * @param y2 终点y坐标
			 * @returns {Number} 线段的长度
			 */
		function lengthOfLine(x1, y1, x2, y2) {
				let ox = Math.pow((x2 - x1), 2);
				let oy = Math.pow((y2 - y1), 2);
				return Math.sqrt(ox + oy);
			}

			//		判断折线是否在多边形内:
			//
			//  只要判断折线的每条线段是否都在多边形内即可。设折线有m条线段,多边形有n个顶点,则该算法的时间复杂度为O(m*n)。
			//
			//  判断多边形是否在多边形内:
			//
			//  只要判断多边形的每条边是否都在多边形内即可。判断一个有m个顶点的多边形是否在一个有n个顶点的多边形内复杂度为O(m*n)。
			//
			//  判断矩形是否在多边形内:
			//
			//  将矩形转化为多边形,然后再判断是否在多边形内。
			//
			//  判断圆是否在多边形内:
			//
			//  只要计算圆心到多边形的每条边的最短距离,如果该距离大于等于圆半径则该圆在多边形内。计算圆心到多边形每条边最短距离的算法在后文阐述。
			//
			//  判断点是否在圆内:
			//
			//  计算圆心到该点的距离,如果小于等于半径则该点在圆内。
			//
			//  判断线段、折线、矩形、多边形是否在圆内:
			//
			//  因为圆是凸集,所以只要判断是否每个顶点都在圆内即可。
			//
			//  判断圆是否在圆内:
			//
			//  设两圆为O1,O2,半径分别为r1, r2,要判断O2是否在O1内。先比较r1,r2的大小,如果r1<r2则O2不可能在O1内;否则如果两圆心的距离大于r1 - r2 ,则O2不在O1内;否则O2在O1内。
			//
			//  计算点到线段的最近点:
			//
			//  如果该线段平行于X轴(Y轴),则过点point作该线段所在直线的垂线,垂足很容易求得,然后计算出垂足,如果垂足在线段上则返回垂足,否则返回离垂足近的端点;如果该线段不平行于X轴也不平行于Y轴,则斜率存在且不为0。设线段的两端点为pt1和pt2,斜率为:k = ( pt2.y - pt1. y ) / (pt2.x - pt1.x );该直线方程为:y = k* ( x - pt1.x) + pt1.y。其垂线的斜率为 - 1 / k,垂线方程为:y = (-1/k) * (x - point.x) + point.y 。
			//
			//  联立两直线方程解得:x = ( k^2 * pt1.x + k * (point.y - pt1.y ) + point.x ) / ( k^2 + 1) ,y = k * ( x - pt1.x) + pt1.y;然后再判断垂足是否在线段上,如果在线段上则返回垂足;如果不在则计算两端点到垂足的距离,选择距离垂足较近的端点返回。
			//
			//  计算点到折线、矩形、多边形的最近点:
			//
			//  只要分别计算点到每条线段的最近点,记录最近距离,取其中最近距离最小的点即可。
			//
			//  计算点到圆的最近距离及交点坐标:
			//
			//  如果该点在圆心,因为圆心到圆周任一点的距离相等,返回UNDEFINED。
			//
			//  连接点P和圆心O,如果PO平行于X轴,则根据P在O的左边还是右边计算出最近点的横坐标为centerPoint.x - radius 或 centerPoint.x + radius。如果PO平行于Y轴,则根据P在O的上边还是下边计算出最近点的纵坐标为 centerPoint.y -+radius或 centerPoint.y - radius。如果PO不平行于X轴和Y轴,则PO的斜率存在且不为0,这时直线PO斜率为k = ( P.y - O.y )/ ( P.x - O.x )。直线PO的方程为:y = k * ( x - P.x) + P.y。设圆方程为:(x - O.x ) ^2 + ( y - O.y ) ^2 = r ^2,联立两方程组可以解出直线PO和圆的交点,取其中离P点较近的交点即可。
		</script>
	</body>

</html>

猜你喜欢

转载自blog.csdn.net/qq_29335275/article/details/85137034