/* * ********************************************************************************************************************* * * !! * .F88X * X8888Y * .}888888N; * i888888N; .:! .I$WI: * R888888I .'N88~ i8}+8Y&8"l8i$8>8W~'>W8}8]KW+8IIN"8& * .R888888I .;N8888~ .X8' "8I.!,/8" !%NY8`"8I8~~8>,88I * +888888N; .8888888Y "&&8Y.}8, * ./888888N; .R888888Y .'}~ .>}'.`+> i}! "i' +/' .'i~ !11,.:">, .~]! .i}i * ~888888%: .I888888l .]88~`1/iY88Ii+1'.R$8$8]"888888888> Y8$ W8E X8E W8888'188Il}Y88$* * 18888888 E8888881 .]W%8$`R8X'&8%++N8i,8N%N8+l8%` .}8N:.R$RE%N88N%N$K$R 188,FE$8%~Y88I * .E888888I .i8888888' .:$8I;88+`E8R:/8N,.>881.`$8E/1/]N8X.Y8N`"KF&&FK!'88*."88K./$88%RN888+~ * 8888888I .,N888888~ ~88i"8W,!N8*.I88.}888%F,i$88"F88" 888:E8X.>88!i88>`888*.}Fl1]*}1YKi' * i888888N' I888Y ]88;/EX*IFKFK88X K8R .l8W 88Y ~88}'88E&%8W.X8N``]88!.$8K .:W8I * .i888888N; I8Y .&8$ .X88! i881.:%888>I88 ;88] +88+.';;;;:.Y88X 18N.,88l .+88/ * .:R888888I * .&888888I Copyright (c) 2009-2020. 博锐尚格科技股份有限公司 * ~8888' * .!88~ All rights reserved. * * ********************************************************************************************************************* */ import { SLine, SPoint, SRect } from "@persagy-web/draw"; import { MinDis } from "../types/MinDis"; import { Point } from "../types/Point"; import { PointToLine } from "../types/PointToLine"; import { Outline } from "../types/Outline"; // @ts-ignore import { intersect } from "polybooljs"; export class SMathUtil { /** * 计算点到点距离 * * @return 距离 * @param x1 * @param y1 * @param x2 * @param y2 */ static pointDistance( x1: number, y1: number, x2: number, y2: number ): number { return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); } // Function pointDistance() /** * 计算点到点集中点最小距离,返回该点和该距离 * * @param p 第一个点 * @param arr 点集 * @return 距离,点坐标 */ static getMinDisPoint(p: SPoint, arr: Point[]): MinDis | null { if (!arr.length) { return null; } let minDis = { MinDis: SMathUtil.pointDistance(p.x, p.y, arr[0].X, -arr[0].Y), Point: arr[0] }; for (let i = 1; i < arr.length; i++) { let ds = SMathUtil.pointDistance(p.x, p.y, arr[i].X, -arr[i].Y); if (ds < minDis.MinDis) { minDis.MinDis = ds; minDis.Point = arr[i]; } } return minDis; } // Function getMinDisPoint() /** * 计算点到线段垂线与线段的交点 * * @param p 点 * @param l 线段 * @return 距离 */ static pointToLine(p: SPoint, l: SLine): PointToLine { let d = { MinDis: Number.MAX_SAFE_INTEGER, Line: new SLine(), Point: new SPoint() }; let bgX = Math.max(l.x1, l.x2); let smX = Math.min(l.x1, l.x2); if (l.dx == 0) { // l.dx为0 说明线段是垂直于x轴的 let bgY = Math.max(l.y1, l.y2); let smY = Math.min(l.y1, l.y2); if (p.y > smY && p.y < bgY) { d.MinDis = Math.abs(p.x - l.x1); d.Line = l; d.Point = new SPoint(l.x1, p.y); } } else if (l.dy == 0) { // l.dy为0 说明线段是平行于x轴的 if (p.x > smX && p.x < bgX) { d.MinDis = Math.abs(p.y - l.y1); d.Line = l; d.Point = new SPoint(p.x, l.y1); } } else { // 直线1 let k1 = (l.y1 - l.y2) / (l.x1 - l.x2); let b1 = l.y1 - k1 * l.x1; // 直线2 let k2 = -1 / k1; let b2 = p.y - k2 * p.x; // 交点 let x = (b1 - b2) / (k2 - k1); let y = k1 * x + b1; if (x > smX && x < bgX) { d.MinDis = SMathUtil.pointDistance(p.x, p.y, x, y); d.Line = l; d.Point = new SPoint(x, y); } } return d; } // Function pointDistance() /** * 计算点到点集中线段最小距离,返回该点和该距离 * * @param p 第一个点 * @param arr 点集 * @return 距离,点坐标 */ static getMinDisLine(p: SPoint, arr: Point[]): PointToLine | null { if (arr.length < 2) { return null; } let PTL = SMathUtil.pointToLine( p, new SLine( arr[arr.length - 1].X, -arr[arr.length - 1].Y, arr[0].X, -arr[0].Y ) ); for (let i = 0; i < arr.length - 1; i++) { let temp = SMathUtil.pointToLine( p, new SLine(arr[i].X, -arr[i].Y, arr[i + 1].X, -arr[i + 1].Y) ); if (temp.MinDis < PTL.MinDis) { PTL = temp; } } return PTL; } // Function getMinDisPoint() /** * 计算矩形是否有交集(外包矩形算法) * * @param rect1 矩形1 * @param rect2 矩形2 * @return boolean * */ static rectIntersection(rect1: SRect, rect2: SRect): boolean { let minX = rect1.x < rect2.x ? rect1.x : rect2.x; let minY = rect1.y < rect2.y ? rect1.y : rect2.y; let maxX = rect1.right > rect2.right ? rect1.right : rect2.right; let maxY = rect1.bottom > rect2.bottom ? rect2.bottom : rect2.bottom; return ( rect1.width + rect2.width > maxX - minX && rect1.height + rect2.height > maxY - minY ); } // Function rectIntersection() /** * 计算线段交点 * * @param line1 线段1 * @param line2 线段2 * @return SPoint 交点 null 平行但不重合 'repeat' 重合 */ static lineIntersection( line1: SLine, line2: SLine ): SPoint | null | string { let k1 = line1.dy / line1.dx; let b1 = line1.y1 - k1 * line1.x1; let k2 = line2.dy / line2.dx; let b2 = line2.y1 - k2 * line2.x1; if (k1 == k2) { if (b1 == b2) { return "repeat"; } return null; } let intersectionX = (b2 - b1) / (k1 - k2); let intersectionY = k1 * intersectionX + b1; let minX = Math.min(line1.x1, line1.x2); let maxX = Math.min(line2.x1, line2.x2); if (intersectionX >= minX && intersectionX <= maxX) { return new SPoint(intersectionX, intersectionY); } return null; } // Function lineIntersection() /** * 转化数据格式为[][] * * @param SP SPoint[] * @return Arr number[][] */ static transferToArray(SP: SPoint[]): number[][] { return SP.map((t): number[] => { return [t.x, t.y]; }); } // Function transferToArray() /** * 转化数据格式为SPoint[] * * @param arr number[][] * @return SP SPoint[] */ static transferToSPoint(arr: number[][]): SPoint[] { return arr.map( (t): SPoint => { return new SPoint(t[0], t[1]); } ); } // Function transferToSPoint() /** * 计算数组中每一项的交集,并返回外轮廓与内轮廓 * */ static getIntersectInArray(array: number[][][]): Outline[] { let outlineList: Outline[] = []; if (!array.length) { // 无数据不做处理 } else if (array.length == 1) { // 只有一条则为外轮廓 let outline: Outline = { Outer: [], Inner: [] }; outline.Outer = array[0].map( (t): SPoint => { return new SPoint(t[0], t[1]); } ); outlineList.push(outline); } else { // 多条的时候,最后一条未外轮廓,倒序遍历与之相交的为内轮廓,不相交为另外的外轮廓 let poly2 = { regions: [], inverted: false }; // @ts-ignore poly2.regions.push(array[array.length - 1]); let indexArr: number[] = [array.length - 1]; for (let i = array.length - 2; i > 0; i--) { let poly1 = { regions: [], inverted: false }; // @ts-ignore poly1.regions.push(array[i]); let intersectObj = intersect(poly1, poly2); console.log(intersectObj); if (!intersectObj.regions.length) { indexArr.unshift(i); poly2.regions = []; // @ts-ignore poly2.regions.push(array[i]); } } indexArr.unshift(0); console.log(indexArr); for (let i = 0; i < indexArr.length - 1; i++) { let axArr = array.slice( i == 0 ? 0 : indexArr[i] + 1, indexArr[i + 1] ); let outline: Outline = { Outer: [], Inner: [] }; outline.Outer = array[indexArr[i + 1]].map( (t): SPoint => { return new SPoint(t[0], t[1]); } ); outline.Inner = axArr.map((t): SPoint[] => { return t.map( (item): SPoint => { return new SPoint(item[0], item[1]); } ); }); outlineList.push(outline); } } console.log(outlineList); return outlineList; } // Function getIntersectInArray() /** * 计算轮廓线面积 * */ static calculateArea(arr: SPoint[]): number { let sum = 0; let n = arr.length; arr[n] = arr[0]; for (let i = 1; i <= n; i++) { sum += arr[i].x * arr[i - 1].y - arr[i - 1].x * arr[i].y; } return sum / 2; } // Function calculateArea() } // Class SMathUtil