import Constant from "../Constant"; export default class MathUtil { constructor() {} getFixed(num, decimal) { if (!decimal) { decimal = 5; } // return Math.floor(num * 10000) / 10000; return parseFloat(num.toFixed(decimal)); } // 求两个点的距离 getDistance(p1, p2) { const x1 = p1.x; const y1 = p1.y; const x2 = p2.x; const y2 = p2.y; const num = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)); return this.getFixed(num); } createLine1(point1, point2) { if (point1.x == point2.x && point1.y == point2.y) { return null; } else if (this.getFixed(Math.abs(point1.x - point2.x)) == 0) { return { x: point1.x }; } else if (this.getFixed(Math.abs(point1.y - point2.y)) == 0) { return { y: point1.y }; } const parametera = (point1.y - point2.y) / (point1.x - point2.x); const parameterb = (point1.x * point2.y - point2.x * point1.y) / (point1.x - point2.x); if (this.getFixed(parametera) == 0) { return { y: this.getFixed(parameterb) }; } const parameter = { a: this.getFixed(parametera), b: this.getFixed(parameterb), }; return parameter; } createLine2(point, angle) { if (angle == Math.PI / 2 || angle == 1.5 * Math.PI) { return { x: point.x }; } let a = Math.tan(angle); let b = point.y - a * point.x; if (a != 0) { return { a: a, b: b }; } else { return { y: point.y }; } } // 与lineA平行并且point在线上 createLine3(lineA, point) { const parameter = {}; if (typeof lineA.a === "undefined") { if (typeof lineA.x !== "undefined") { parameter.x = point.x; } else if (typeof lineA.y !== "undefined") { parameter.y = point.y; } } else { parameter.a = lineA.a; parameter.b = point.y - point.x * lineA.a; } return parameter; } create2AngleLine(point, angle, driftAngle) { let line1 = this.createLine2(point, angle - driftAngle / 2); let line2 = this.createLine2(point, angle + driftAngle / 2); return { line1: line1, line2: line2 }; } distanceForPoints(point1, point2) { return Math.sqrt( Math.pow(point1.x - point2.x, 2) + Math.pow(point1.y - point2.y, 2) ); } //与line平行且两条线直接的距离是distance的两条线 getParallelLineForDistance(line, distance) { let line1 = {}; let line2 = {}; if (!line.hasOwnProperty("a")) { if (line.hasOwnProperty("x")) { let x = line.x; line1.x = x + distance; line2.x = x - distance; } else if (line.hasOwnProperty("y")) { let y = line.y; line1.y = y + distance; line2.y = y - distance; } } else { line1.a = line.a; line1.b = line.b; line2.a = line.a; line2.b = line.b; let angle = Math.atan(line.a); let db = Math.abs(distance / Math.cos(angle)); let b = line.b; line1.b = b + db; line2.b = b - db; } return { line1: line1, line2: line2 }; } //获取扇形的两个端点 getEndpoint(point, angle, sectorAngle) { const distance = 15; //line1是减,line2是加 let lines1 = this.create2AngleLine(point, angle, sectorAngle); let line = this.createLine2(point, angle); line = this.getLineForPoint(line, point); let lines2 = this.getParallelLineForDistance(line, distance); let point1 = this.getIntersectionPoint(lines1.line1, lines2.line1); let point2 = this.getIntersectionPoint(lines1.line1, lines2.line2); let point3 = this.getIntersectionPoint(lines1.line2, lines2.line1); let point4 = this.getIntersectionPoint(lines1.line2, lines2.line2); let angle1 = this.Angle(point, point1, { x: point.x + 1, y: point.y }); let angle2 = this.Angle(point, point2, { x: point.x + 1, y: point.y }); let angle3 = this.Angle(point, point3, { x: point.x + 1, y: point.y }); let angle4 = this.Angle(point, point4, { x: point.x + 1, y: point.y }); if (angle > Math.PI) { angle = 2 * Math.PI - angle; } if ( Math.abs((angle1 + angle3) / 2 - angle) < Math.abs((angle2 + angle4) / 2 - angle) ) { return { p1: point1, p2: point3 }; } else { return { p1: point2, p2: point4 }; } } // true表示逆时针,false表示顺时针 isClockwise(vertices) { let area = 0; for (let i = 0; i < vertices.length; i++) { const j = (i + 1) % vertices.length; area += vertices[i].x * vertices[j].y; area -= vertices[j].x * vertices[i].y; } const sub = area / 2; if (sub > 0) { // 逆时针 return true; } else { // 顺时针 return false; } } reverse(points) { const _points = []; for (let i = points.length - 1; i > -1; --i) { _points.push(points[i]); } return _points; } //两条线的交点 getIntersectionPoint(parameter1, parameter2) { if (this.isParallel(parameter1, parameter2)) { return null; } if ( typeof parameter1.a == "undefined" && typeof parameter2.a != "undefined" ) { if (parameter1.x) { return { x: parameter1.x, y: parameter2.a * parameter1.x + parameter2.b, }; } else if (parameter1.y) { return { x: (parameter1.y - parameter2.b) / parameter2.a, y: parameter1.y, }; } } else if ( typeof parameter2.a == "undefined" && typeof parameter1.a != "undefined" ) { if (parameter2.x) { return { x: parameter2.x, y: parameter1.a * parameter2.x + parameter1.b, }; } else if (parameter2.y) { return { x: (parameter2.y - parameter1.b) / parameter1.a, y: parameter2.y, }; } } else if ( typeof parameter2.a == "undefined" && typeof parameter1.a == "undefined" ) { if (parameter1.hasOwnProperty("x") && parameter2.hasOwnProperty("y")) { return { x: parameter1.x, y: parameter2.y }; } else if ( parameter1.hasOwnProperty("y") && parameter2.hasOwnProperty("x") ) { return { x: parameter2.x, y: parameter1.y }; } else { return null; } } if (parameter1.a == parameter2.a) { return null; } let joinpointx = (parameter2.b - parameter1.b) / (parameter1.a - parameter2.a); let joinpointy = (parameter1.a * parameter2.b - parameter2.a * parameter1.b) / (parameter1.a - parameter2.a); let point = { x: joinpointx, y: joinpointy }; return point; } // 直线的交点 getIntersectionPoint2(a, b, c, d) { /** 1 解线性方程组, 求线段交点. **/ // 如果分母为0 则平行或共线, 不相交 const denominator = (b.y - a.y) * (d.x - c.x) - (a.x - b.x) * (c.y - d.y); if (denominator == 0) { return null; } // 线段所在直线的交点坐标 (x , y) const x = ((b.x - a.x) * (d.x - c.x) * (c.y - a.y) + (b.y - a.y) * (d.x - c.x) * a.x - (d.y - c.y) * (b.x - a.x) * c.x) / denominator; const y = -( (b.y - a.y) * (d.y - c.y) * (c.x - a.x) + (b.x - a.x) * (d.y - c.y) * a.y - (d.x - c.x) * (b.y - a.y) * c.y ) / denominator; return { x: x, y: y }; } //两条线段交点 getIntersectionPoint3(a, b, c, d) { const join = this.getIntersectionPoint2(a, b, c, d); if (join) { const x = join.x; const y = join.y; // 交点在线段1上 且交点也在线段2上 /** 2 判断交点是否在两条线段上 **/ if ( (x - a.x) * (x - b.x) <= 0.001 && (y - a.y) * (y - b.y) <= 0.001 && (x - c.x) * (x - d.x) <= 0.001 && (y - c.y) * (y - d.y) <= 0.001 ) { // 返回交点p return { x: x, y: y, }; } return null; } return null; } // 线段和直线是否相交 getIntersectionPoint4(point1, point2, line) { const line1 = this.createLine1(point1, point2); const join = this.getIntersectionPoint(line1, line); if (join == null) { return null; } if (this.PointInSegment(join, point1, point2)) { return join; // 相交 } else { return null; } } //返回true表示平行 isParallel(line1, line2) { if (typeof line1.a == "undefined" && typeof line2.a == "undefined") { if (line1.hasOwnProperty("x") && line2.hasOwnProperty("x")) { return true; } else if (line1.hasOwnProperty("y") && line2.hasOwnProperty("y")) { return true; } else { return false; } } else if (typeof line1.a == "undefined" || typeof line2.a == "undefined") { return false; } else if (this.getFixed(line1.a) == this.getFixed(line2.a)) { return true; } else { return false; } } //两条相交的线段的夹角,永远小于180度 Angle(o, s, e) { let cosfi = 0, fi = 0, norm = 0; let dsx = s.x - o.x; let dsy = s.y - o.y; let dex = e.x - o.x; let dey = e.y - o.y; cosfi = dsx * dex + dsy * dey; norm = (dsx * dsx + dsy * dsy) * (dex * dex + dey * dey); cosfi /= Math.sqrt(norm); if (cosfi >= 1.0) return 0; //if (cosfi <= -1.0) return Math.PI; if (cosfi <= -1.0) return Math.PI; fi = Math.acos(cosfi); if ((180 * fi) / Math.PI < 180) { //return 180 * fi / Math.PI; return (fi * 180) / Math.PI; } else { //return 360 - 180 * fi / Math.PI; return ((2 * Math.PI - fi) * 180) / Math.PI; } } //经过point且与line垂直的线 getLineForPoint(line, point) { let parameter = {}; if (line.a == 0 || typeof line.a == "undefined") { if (line.hasOwnProperty("x")) { parameter.y = point.y; } else if (line.hasOwnProperty("y")) { parameter.x = point.x; } } else { parameter.a = -1 / line.a; parameter.b = point.y - point.x * parameter.a; } return parameter; } // 经过point且与line垂直的直线,该直线与line的交点 getJoinLinePoint(point, line) { const verticalLine = this.getVerticalLine(line, point); const join = this.getIntersectionPoint(line, verticalLine); return join; } // 点到直线的距离 getDisForPoinLine(point, line) { const join = this.getJoinLinePoint(point, line); return this.getDistance(point, join); } // 垂直线 getVerticalLine(line, point) { if (typeof line.a === "undefined") { if (line.hasOwnProperty("x")) { return { y: point.y }; } else if (line.hasOwnProperty("y")) { return { x: point.x }; } else { return null; } } else if (line.a == 0) { return { x: point.x }; } else { const tl = {}; tl.a = -1 / line.a; const result = this.createLine3(tl, point); return result; } } //point在直线上,只是不确定是否在线段上 //方法:point到startPoint和endPoint的距离之和与startPoint和endPoint之间的距离对比 isContainForSegment(point, startPoint, endPoint, minDis) { if (!minDis) { minDis = Constant.minLen; } let dis1 = this.getDistance(startPoint, point) + this.getDistance(endPoint, point); let dis2 = this.getDistance(startPoint, endPoint); if (Math.abs(dis1 - dis2) < minDis) { return true; } else { return false; } } /* //minDis isPointInPoly(point, points, minDis) { if (!minDis) { minDis = Constant.minRealDis } const x = point.x const y = point.y let inside = false // 是否在顶点附近 for (let i = 0; i < points.length; ++i) { let distance = this.getDistance(point, points[i]) if (distance < minDis) { return true } } // 是否在边沿 for (let i = 0, j = points.length - 1; i < points.length; j = i++) { let pt1 = points[i] let pt2 = points[j] const flag = this.isContainForSegment(point, pt1, pt2, minDis) if (flag) { return true } } for (let i = 0, j = points.length - 1; i < points.length; j = i++) { let pt1 = points[i] let pt2 = points[j] const xi = pt1.x const yi = pt1.y const xj = pt2.x const yj = pt2.y const intersect = yi > y != yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi if (intersect) inside = !inside } return inside } */ isPointInPoly(point, points) { const x = point.x; const y = point.y; let inside = false; for (let i = 0, j = points.length - 1; i < points.length; j = i++) { let pt1 = points[i]; let pt2 = points[j]; const xi = pt1.x; const yi = pt1.y; const xj = pt2.x; const yj = pt2.y; const intersect = yi > y != yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi; if (intersect) inside = !inside; } return inside; } // 点到线段的距离 // 在minDistance范围内,会吸附到point1/point2上 // 返回值:type是1表示吸附在point1,是2表示吸附在point2,是0表示在线段point1-point2上; getDisForPoinSegment(point, point1, point2, minDistance) { const line = this.createLine1(point1, point2); const join = this.getJoinLinePoint(point, line); const dis = this.getDistance(point1, point2); const dis1 = this.getDistance(join, point1); const dis2 = this.getDistance(join, point2); if ( this.getDistance(join, point1) > dis || this.getDistance(join, point2) > dis ) { // 在线段外 if (dis1 < dis2 && dis1 < minDistance) { return { type: 1, join: point1 }; } else if (dis2 < dis1 && dis2 < minDistance) { return { type: 2, join: point2 }; } else { return null; } } else { if (dis1 < minDistance) { return { type: 1, join: point1 }; } else if (dis2 < minDistance) { return { type: 2, join: point2 }; } else if (this.getDistance(point, join) < minDistance) { return { type: 0, join: join }; } } } PointInSegment(Q, pi, pj, minDis) { if ( this.getDistance(Q, pi) < Constant.minAdsorbPix || this.getDistance(Q, pj) < Constant.minAdsorbPix ) { return true; } if (!minDis) { minDis = 0.1; } minDis = minDis / 2; const offset1 = (Q.x - pi.x) * (pj.y - pi.y) - (pj.x - pi.x) * (Q.y - pi.y); const offset2 = Math.min(pi.x, pj.x) - Q.x; const offset3 = Q.x - Math.max(pi.x, pj.x); const offset4 = Math.min(pi.y, pj.y) - Q.y; const offset5 = Q.y - Math.max(pi.y, pj.y); if ( Math.abs(offset1) < minDis && (offset2 <= 0 || Math.abs(offset2) < minDis) && (offset3 <= 0 || Math.abs(offset3) < minDis) && (offset4 <= 0 || Math.abs(offset4) < minDis) && (offset5 <= 0 || Math.abs(offset5) < minDis) ) { return true; } else { return false; } } //点p是否在线段AB上 isPointOnSegment(p, A, B) { // 计算向量 AP 和 BP const AP = { x: p.x - A.x, y: p.y - A.y, }; const BP = { x: p.x - B.x, y: p.y - B.y, }; // 计算向量 AB 的长度和方向 const AB = { x: B.x - A.x, y: B.y - A.y, }; const AB_length = this.getDistance(A, B); const AB_direction = { x: AB.x / AB_length, y: AB.y / AB_length, }; // 检查 AP 和 BP 的方向是否与 AB 相同,并检查它们的长度是否小于等于 AB 的长度 const dot_product_AP = AP.x * AB_direction.x + AP.y * AB_direction.y; const dot_product_BP = BP.x * AB_direction.x + BP.y * AB_direction.y; //return dot_product_AP >= 0 && dot_product_BP <= 0 && Math.abs(AP.x * BP.y - AP.y * BP.x) <= AB_length * Number.EPSILON; return ( dot_product_AP >= 0 && dot_product_BP <= 0 && Math.abs(AP.x * BP.y - AP.y * BP.x) <= 0.01 ); } clonePoint(p1, p2) { p1.x = p2.x; p1.y = p2.y; } equalPoint(p1, p2) { if (p1.x == p2.x && p1.y == p2.y) { return true; } else { return false; } } crossTwoLines(point1, point2, point3, point4, dis) { if (typeof dis == "undefined") { dis = Constant.minAdsorbPix; } const join = this.getIntersectionPoint2(point1, point2, point3, point4); if (join != null) { if ( this.getDistance(point1, join) > dis && this.getDistance(point2, join) > dis && this.getDistance(point3, join) > dis && this.getDistance(point4, join) > dis ) { if ( this.getDistance(point1, join) < this.getDistance(point1, point2) && this.getDistance(point2, join) < this.getDistance(point1, point2) && this.getDistance(point3, join) < this.getDistance(point3, point4) && this.getDistance(point4, join) < this.getDistance(point3, point4) ) { return true; } else { return false; } } } else { if ( this.PointInSegment(point1, point3, point4) || this.PointInSegment(point2, point3, point4) ) { return true; } } return false; } getDisPointsLine(line, point, distance1, distance2) { const newpoint1 = {}; const newpoint2 = {}; const result = {}; if (line.hasOwnProperty("x")) { newpoint1.x = line.x; newpoint1.y = point.y - distance1; newpoint2.x = line.x; newpoint2.y = point.y + distance2; } else if (line.hasOwnProperty("y")) { newpoint1.y = line.y; newpoint1.x = point.x - distance1; newpoint2.y = line.y; newpoint2.x = point.x + distance2; } else { const a = Math.atan(line.a); const t_line = { a: -1 / line.a }; const line_ab2 = this.createLine3(t_line, point); const join = this.getIntersectionPoint(line, line_ab2); newpoint1.x = join.x - distance1 * Math.cos(a); newpoint1.y = join.y - distance1 * Math.sin(a); newpoint2.x = join.x + distance2 * Math.cos(a); newpoint2.y = join.y + distance2 * Math.sin(a); } result.newpoint1 = newpoint1; result.newpoint2 = newpoint2; return result; } getBoundingBox(points) { let minX = points[0].x; let maxX = points[0].x; let minY = points[0].y; let maxY = points[0].y; for (let i = 1; i < points.length; ++i) { const point = points[i]; if (minX > point.x) { minX = point.x; } if (minY > point.y) { minY = point.y; } if (maxX < point.x) { maxX = point.x; } if (maxY < point.y) { maxY = point.y; } } const box = {}; box.minX = minX; box.minY = minY; box.maxX = maxX; box.maxY = maxY; return box; } getBoundingBox2(points) { let minX = null; let maxX = null; let minY = null; let maxY = null; for (let key in points) { const point = points[key]; if (minX == null || minX > point.x) { minX = point.x; } if (minY == null || minY > point.y) { minY = point.y; } if (maxX == null || maxX < point.x) { maxX = point.x; } if (maxY == null || maxY < point.y) { maxY = point.y; } } const box = {}; box.minX = minX; box.minY = minY; box.maxX = maxX; box.maxY = maxY; return box; } ComputePolygonArea(points) { const point_num = points.length; if (point_num < 3) { return 0; } let s = points[0].y * (points[point_num - 1].x - points[1].x); for (let i = 1; i < point_num; ++i) s += points[i].y * (points[i - 1].x - points[(i + 1) % point_num].x); return Math.abs(s / 2.0); } // 获取多边形重心 getPolygonCore(points) { function Area(p0, p1, p2) { let area = 0.0; area = p0.x * p1.y + p1.x * p2.y + p2.x * p0.y - p1.x * p0.y - p2.x * p1.y - p0.x * p2.y; return area / 2; } let sum_x = 0; let sum_y = 0; let sum_area = 0; let p1 = points[1]; for (let i = 2; i < points.length; i++) { const p2 = points[i]; const area = Area(points[0], p1, p2); sum_area += area; sum_x += (points[0].x + p1.x + p2.x) * area; sum_y += (points[0].y + p1.y + p2.y) * area; p1 = p2; } const xx = sum_x / sum_area / 3; const yy = sum_y / sum_area / 3; return { x: xx, y: yy, }; } // points1是否在points2里 isPolyInPoly(points1, points2, minDis) { for (let i = 0; i < points1.length; ++i) { let flag = false; for (let j = 0; j < points2.length; ++j) { if (this.equalPoint(points1[i], points2[j])) { flag = true; break; } } if (!flag) { if (!this.isPointInPoly(points1[i], points2, minDis)) { return false; } } else { const nextIndex = i == points1.length - 1 ? 0 : i + 1; const mid = { x: (points1[i].x + points1[nextIndex].x) / 2, y: (points1[i].y + points1[nextIndex].y) / 2, }; if (!this.isPointInPoly(mid, points2, minDis)) { return false; } } } return true; } dotPoints(pt1, pt2, point1, point2) { let vt1 = {}; let vt2 = {}; vt1.start = {}; vt1.end = {}; vt1.start.x = 0; vt1.start.y = 0; vt1.end.x = pt2.x - pt1.x; vt1.end.y = pt2.y - pt1.y; vt2.start = {}; vt2.end = {}; vt2.start.x = 0; vt2.start.y = 0; vt2.end.x = point2.x - point1.x; vt2.end.y = point2.y - point1.y; let result = vt1.end.x * vt2.end.x + vt1.end.y * vt2.end.y; return result; } //start是起点,target是朝着目标移动,distance是移动的距离 translate(start, target, point, distance) { let dx = target.x - start.x; let dy = target.y - start.y; let dis = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); let result = { x: point.x + (dx * distance) / dis, y: point.y + (dy * distance) / dis, }; return result; } //射线与线段相交 // intersection(rayStart, rayEnd, segmentStart, segmentEnd) { // // 计算射线和线段的方向向量 // const rayDirection = { // x:rayEnd.x - rayStart.x, // y:rayEnd.y - rayStart.y, // }; // const segmentDirection = { // x:segmentEnd.x - segmentStart.x, // y:segmentEnd.y - segmentStart.y, // }; // // 计算射线和线段的起点之间的向量 // const startPointVector = { // x:rayStart.x - segmentStart.x, // y:rayStart.y - segmentStart.y, // }; // // 计算射线和线段的叉积 // const crossProduct = rayDirection.x * segmentDirection.y - rayDirection.y * segmentDirection.x; // // 如果叉积为0,则表示射线和线段平行 // if (crossProduct === 0) { // return null; // } // // 计算线段起点到射线的交点的向量 // const t = (startPointVector.x * segmentDirection.y - startPointVector.y * segmentDirection.x) / crossProduct; // // 如果t的值小于0,则交点在射线的起点之后 // if (t < 0) { // return null; // } // // 计算交点的坐标 // const intersectionX = rayStart.x + t * rayDirection.x; // const intersectionY = rayStart.y + t * rayDirection.y; // // 如果交点在线段的范围内,则返回交点坐标 // if ((intersectionX >= Math.min(segmentStart.x, segmentEnd.x)) && // (intersectionX <= Math.max(segmentStart.x, segmentEnd.x)) && // (intersectionY >= Math.min(segmentStart.y, segmentEnd.y)) && // (intersectionY <= Math.max(segmentStart.y, segmentEnd.y))) { // //return [intersectionX, intersectionY]; // return { // x:intersectionX, // y:intersectionY, // }; // } // // 否则返回null // return null; // } // raySegmentIntersection(rayOrigin, rayDirection, segmentStart, segmentEnd) { // // 计算射线和线段的交点 // const x1 = rayOrigin.x // const y1 = rayOrigin.y // const x2 = segmentStart.x // const y2 = segmentStart.y // const dx1 = rayDirection.x // const dy1 = rayDirection.y // const dx2 = segmentEnd.x - x2 // const dy2 = segmentEnd.y - y2 // const crossProduct = dx1 * dy2 - dx2 * dy1 // if (Math.abs(crossProduct) < 1e-8) { // // 射线和线段平行或共线 // return null // } // const t1 = (dx2 * (y1 - y2) - dy2 * (x1 - x2)) / crossProduct // const t2 = (dx1 * (y1 - y2) - dy1 * (x1 - x2)) / crossProduct // if (t1 >= 0 && t2 >= 0 && t2 <= 1) { // // 有交点,计算交点坐标 // const intersectionX = x1 + t1 * dx1 // const intersectionY = y1 + t1 * dy1 // return { // x: intersectionX, // y: intersectionY, // } // } else { // // 没有交点 // return null // } // } raySegmentIntersection(rayOrigin, rayDirection, segmentStart, segmentEnd) { const end = { x: rayOrigin.x + rayDirection.x, y: rayOrigin.y - rayDirection.z, }; const line = this.createLine1(rayOrigin, end); const join = this.getIntersectionPoint4(segmentStart, segmentEnd, line); if (join == null) { return null; } else { const dis = this.getDistance(end, join); const dis1 = this.getDistance(rayOrigin, join); const dis2 = this.getDistance(rayOrigin, end); if (dis - (dis1 + dis2) + 0.01 > 0) { return null; } else { return join; } } } RectangleVertex(startPoint, endPoint, width) { let line = this.createLine1(startPoint, endPoint); let lines = this.getParallelLineForDistance(line, width / 2); let leftEdgeStart, rightEdgeStart, rightEdgeEnd, leftEdgeEnd; let point = null; let points = []; //先计算start部分 point = startPoint; points.push(endPoint); points.push(startPoint); let point1 = this.getJoinLinePoint(point, lines.line1); let point2 = this.getJoinLinePoint(point, lines.line2); points[2] = point1; if (this.isClockwise(points)) { rightEdgeStart = point1; leftEdgeStart = point2; } else { rightEdgeStart = point2; leftEdgeStart = point1; } //再计算end部分 points = []; point = endPoint; points.push(startPoint); points.push(endPoint); point1 = this.getJoinLinePoint(point, lines.line1); point2 = this.getJoinLinePoint(point, lines.line2); points[2] = point1; if (this.isClockwise(points)) { rightEdgeEnd = point2; leftEdgeEnd = point1; } else { rightEdgeEnd = point1; leftEdgeEnd = point2; } return { leftEdgeStart: leftEdgeStart, rightEdgeStart: rightEdgeStart, rightEdgeEnd: rightEdgeEnd, leftEdgeEnd: leftEdgeEnd, }; } //start到end的射线中取一点point,start-end和end-point的距离相同 getPositionForExtendedLine(start, end) { const dx = end.x - start.x; const dy = end.y - start.y; const point = { x: end.x + dx, y: end.y + dy, }; return point; } isOnRay(start, dir, position) { const v1 = { x: dir.x - start.x, y: dir.y - start.y }; const v2 = { x: position.x - start.x, y: position.y - start.y }; return v1.x * v2.y - v1.y * v2.x; } //向量是否同样的方向 isSameDirForVector(point1, point2, p1, p2) { const v1 = { x: point2.x - point1.x, y: point2.y - point1.y, }; const v2 = { x: p2.x - p1.x, y: p2.y - p1.y, }; const value = this.dot(v1, v2); if (value > 0) { return true; } { return false; } } angleTo(v1, v2) { const denominator = Math.sqrt(this.lengthSq(v1) * this.lengthSq(v2)); if (denominator === 0) return Math.PI / 2; const theta = this.dot(v1, v2) / denominator; //return Math.acos(this.clamp(theta, -1, 1)); return (Math.acos(this.clamp(theta, -1, 1)) / Math.PI) * 180; } //点乘 dot(v1, v2) { return v1.x * v2.x + v1.y * v2.y; } //叉乘 cross(v1, v2) { return v1.x * v2.y - v1.y * v2.x; } clamp(value, min, max) { return Math.max(min, Math.min(max, value)); } lengthSq(v) { return v.x * v.x + v.y * v.y; } } const mathUtil = new MathUtil(); export { mathUtil };