|
@@ -0,0 +1,317 @@
|
|
|
+/*
|
|
|
+ * ********************************************************************************************************************
|
|
|
+ *
|
|
|
+ * :*$@@%$*: ;: ;; ;;
|
|
|
+ * :@@%! :!@@%: %! ;%%@@%$ =@@@@@@@%; @%@@@%%%%@@@@@
|
|
|
+ * :@%; :$= %%$$$%$$ ;$$ ;$@= !@$
|
|
|
+ * =@! %! @ $=;% !@@@%: !$$$$$$$$$$$$$$=
|
|
|
+ * =@* %! @ $= % %@= =%@! %=
|
|
|
+ * *$%%! @@= ;=$%%%$*: %! @ $= % =%%%%%%@$ *%: =%
|
|
|
+ * %@@!: !@@@%=$@@@@%! :*@@$: %! @ $= % $* ;@ @* :%*
|
|
|
+ * ;@@! ;!!!;: ;@%: =======@%========* @ $$ % $%*****$@ :@$=*********=@$
|
|
|
+ * $@* ;@@@%=!: *@*
|
|
|
+ * =@$ ;;;!=%@@@@=! =@!
|
|
|
+ * %@$: =@%: :*@@@* %@= Copyright (c) 2016-2019. 北京上格云技术有限公司
|
|
|
+ * ;%@@$=$@@%* *@@@$=%@@%;
|
|
|
+ * ::;:: ::;:: All rights reserved.
|
|
|
+ *
|
|
|
+ * ********************************************************************************************************************
|
|
|
+ */
|
|
|
+
|
|
|
+import { SLine, SPoint, SRect } from "@saga-web/draw/lib";
|
|
|
+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;
|
|
|
+ }
|
|
|
+} // Class SMathUtil
|