123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- import { SLine, SPoint } from "@persagy-web/draw/lib";
- // @ts-ignore
- import { intersect, polygon, segments, combine, selectUnion, selectDifference, selectDifferenceRev } from "polybooljs";
- export class generate {
- /**
- * 计算角平分线上的距离这两条直线l的点
- *
- * @param p1 第一个点
- * @param p2 第二个点 也是2条线的交点
- * @param p3 第三个点
- * @param l 距离2条线的距离
- * @return number Array(4) 两个点
- */
- static getBisector(p1: SPoint, p2: SPoint, p3: SPoint, l: number): [number, number, number, number] {
- const dy1 = p1.y - p2.y;
- const dx1 = p1.x - p2.x;
- const dy2 = p3.y - p2.y;
- const dx2 = p3.x - p2.x;
- // 线1的斜率
- const k1 = dy1 / dx1;
- // 线2的斜率
- const k2 = dy2 / dx2;
- // 线1与x轴的夹角
- const temp1 = Math.atan(k1)
- let a1 = dx1 >= 0 ? temp1 : temp1 + Math.PI;
- // 线2与x轴的夹角
- const temp2 = Math.atan(k2)
- let a2 = dx2 >= 0 ? temp2 : temp2 + Math.PI;
- // 角平分线斜率
- const k = Math.tan((a1 + a2) / 2);
- // 角平分线b
- const b = p2.y - k * p2.x;
- // 距离两条线l的点 到交点p2的距离
- const Lb2 = l / Math.sin(Math.abs(a1 - a2) / 2);
- // 特殊情况-角分线垂直或平行X轴
- if (k1 / k2 == -1) {
- if (dx2 * dx1 > 0 && dy2 * dy1 < 0) { // 上下开角
- return [Number((p2.x - Lb2).toFixed(6)), Number(p2.y.toFixed(6)), Number((p2.x + Lb2).toFixed(6)), Number(p2.y.toFixed(6))]
- } else if (dx2 * dx1 < 0 && dy2 * dy1 > 0) { // 左右开角
- return [Number(p2.x.toFixed(6)), Number((p2.y - Lb2).toFixed(6)), Number(p2.x.toFixed(6)), Number((p2.y + Lb2).toFixed(6))]
- }
- }
- // 将距离公式与直线方程连立,并且将直线方程代入,得到一元二次方程 Ax^2 + Bx + C = 0;然后根据得根公式得到2个解
- const A = k * k + 1;
- const B = 2 * k * b - 2 * p2.x - 2 * k * p2.y;
- const C = b * b - Lb2 * Lb2 + p2.x * p2.x + p2.y * p2.y - 2 * b * p2.y;
- // 求解
- const X1 = (-B + Math.sqrt(B * B - 4 * A * C)) / (2 * A);
- const X2 = (-B - Math.sqrt(B * B - 4 * A * C)) / (2 * A);
- const Y1 = k * X1 + b;
- const Y2 = k * X2 + b;
- return [Number(X1.toFixed(6)), Number(Y1.toFixed(6)), Number(X2.toFixed(6)), Number(Y2.toFixed(6))]
- }
- /**
- * 计算一条线的过p1垂线上距离线l的2个点
- *
- * @param p1 点1
- * @param p2 点2
- * @param l 距离这条线的距离
- * @return number Array(4) 两个点
- */
- static getVertical(p1: SPoint, p2: SPoint, l: number): [number, number, number, number] {
- const dy1 = p1.y - p2.y;
- const dx1 = p1.x - p2.x;
- if (dy1 == 0) {
- return [Number(p1.x.toFixed(6)), Number((p1.y - l).toFixed(6)), Number(p1.x.toFixed(6)), Number((p1.y + l).toFixed(6))]
- }
- if (dx1 == 0) {
- return [Number((p1.x - l).toFixed(6)), Number(p1.y.toFixed(6)), Number((p1.x + l).toFixed(6)), Number(p1.y.toFixed(6))]
- }
- // 线1的斜率
- const k1 = dy1 / dx1;
- // 垂线的斜率
- const k = -1 / k1;
- // 垂线的b
- const b = p1.y - k * p1.x;
- // 将距离公式与直线方程连立,并且将直线方程代入,得到一元二次方程 Ax^2 + Bx + C = 0;然后根据得根公式得到2个解
- const A = k * k + 1;
- const B = 2 * k * b - 2 * p1.x - 2 * k * p1.y;
- const C = b * b - l * l + p1.x * p1.x + p1.y * p1.y - 2 * b * p1.y;
- // 求解
- const X1 = (-B + Math.sqrt(B * B - 4 * A * C)) / (2 * A);
- const X2 = (-B - Math.sqrt(B * B - 4 * A * C)) / (2 * A);
- const Y1 = k * X1 + b;
- const Y2 = k * X2 + b;
- return [Number(X1.toFixed(6)), Number(Y1.toFixed(6)), Number(X2.toFixed(6)), Number(Y2.toFixed(6))]
- }
- /**
- * 计算线段交点
- *
- * @param line1 线段1
- * @param line2 线段2
- * @return SPoint 交点 null 平行但不重合 'repeat' 重合
- */
- static lineIntersection(
- p1: SPoint, p2: SPoint, p3: SPoint, p4: SPoint
- ): SPoint | null | string {
- let k1 = (p2.y - p1.y) / (p2.x - p1.x);
- let b1 = p2.y - k1 * p2.x;
- let k2 = (p4.y - p3.y) / (p4.x - p3.x);
- let b2 = p3.y - k2 * p3.x;
- 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(p1.x, p2.x);
- let maxX = Math.max(p3.x, p4.x);
- if (intersectionX >= minX && intersectionX <= maxX) {
- return new SPoint(intersectionX, intersectionY);
- }
- return null;
- }
- /**
- * 一条线生成的4个点,根据这4个点和这条线,将轮廓线排序
- *
- * @description 计算3条线的斜率,差值小的一组
- *
- * @param [number, number, number, number]
- * @param [number, number, number, number]
- * @param SLine
- * @return 两组线的数组
- */
- static generateOrderLine(arr1: [number, number, number, number], arr2: [number, number, number, number], line: SLine) {
- if (arr1.length && arr2.length) {
- // 排除特殊情况
- if (line.dy == 0) { // 线本身是水平的
- if (generate.isEqual(arr1[1], arr2[1])) {
- return [
- [Number(arr1[0].toFixed(6)), Number(arr1[1].toFixed(6)), Number(arr2[0].toFixed(6)), Number(arr2[1].toFixed(6))],
- [Number(arr1[2].toFixed(6)), Number(arr1[3].toFixed(6)), Number(arr2[2].toFixed(6)), Number(arr2[3].toFixed(6))],
- ]
- } else {
- return [
- [Number(arr1[0].toFixed(6)), Number(arr1[1].toFixed(6)), Number(arr2[2].toFixed(6)), Number(arr2[3].toFixed(6))],
- [Number(arr1[2].toFixed(6)), Number(arr1[3].toFixed(6)), Number(arr2[0].toFixed(6)), Number(arr2[1].toFixed(6))],
- ]
- }
- }
- if (line.dx == 0) { // 线本身是垂直的
- if (generate.isEqual(arr1[0], arr2[0])) { // 与另外一组的第一个点的连线是水平的
- return [
- [Number(arr1[0].toFixed(6)), Number(arr1[1].toFixed(6)), Number(arr2[0].toFixed(6)), Number(arr2[1].toFixed(6))],
- [Number(arr1[2].toFixed(6)), Number(arr1[3].toFixed(6)), Number(arr2[2].toFixed(6)), Number(arr2[3].toFixed(6))],
- ]
- } else { // 与另外一组的第二个点的连线是竖直的
- return [
- [Number(arr1[0].toFixed(6)), Number(arr1[1].toFixed(6)), Number(arr2[2].toFixed(6)), Number(arr2[3].toFixed(6))],
- [Number(arr1[2].toFixed(6)), Number(arr1[3].toFixed(6)), Number(arr2[0].toFixed(6)), Number(arr2[1].toFixed(6))],
- ]
- }
- }
- // 标准线的斜率
- const k = line.dy / line.dx;
- // 第一条线
- const l1 = new SLine(arr1[0], arr1[1], arr2[0], arr2[1]);
- // 第一条线的斜率
- const k1 = l1.dy / l1.dx;
- // 第一条线斜率差值
- const dk1 = Math.abs(k1 - k);
- // 第二条线
- const l2 = new SLine(arr1[0], arr1[1], arr2[2], arr2[3]);
- // 第二条线的斜率
- const k2 = l2.dy / l2.dx;
- // 第二条线斜率差值
- const dk2 = Math.abs(k2 - k);
- // 判断差值小的放一组
- if (dk1 < dk2) {
- return [
- [Number(arr1[0].toFixed(6)), Number(arr1[1].toFixed(6)), Number(arr2[0].toFixed(6)), Number(arr2[1].toFixed(6))],
- [Number(arr1[2].toFixed(6)), Number(arr1[3].toFixed(6)), Number(arr2[2].toFixed(6)), Number(arr2[3].toFixed(6))],
- ]
- } else {
- return [
- [Number(arr1[0].toFixed(6)), Number(arr1[1].toFixed(6)), Number(arr2[2].toFixed(6)), Number(arr2[3].toFixed(6))],
- [Number(arr1[2].toFixed(6)), Number(arr1[3].toFixed(6)), Number(arr2[0].toFixed(6)), Number(arr2[1].toFixed(6))],
- ]
- }
- }
- return []
- }
- /**
- * 删除轮廓线中共线的点
- *
- * @description 连续2条线的斜率相等则这3点共线,删除中间的一个点
- * @param outline 轮廓线数据
- * @return 简化后的轮廓线数据
- */
- static simplyOutline(outline: SPoint[]): SPoint[] {
- for (let i = 0; i < outline.length - 1; i++) {
- if (outline[i].x - outline[i + 1].x == 0 && outline[i].y - outline[i + 1].y == 0) {
- outline.splice(i, 1);
- i--;
- }
- }
- if (outline.length > 2) {
- for (let i = 1; i < outline.length - 1; i++) {
- if (outline[i].y - outline[i - 1].y == 0 && outline[i + 1].y - outline[i].y == 0) {
- outline.splice(i, 1);
- i--;
- } else if (outline[i].x - outline[i - 1].x == 0 && outline[i + 1].x - outline[i].x == 0) {
- outline.splice(i, 1);
- i--;
- } else if (
- outline[i].y - outline[i - 1].y == outline[i + 1].y - outline[i].y &&
- outline[i].x - outline[i - 1].x == outline[i + 1].x - outline[i].x
- ) {
- outline.splice(i, 1);
- i--;
- }
- }
- }
- return outline
- }
- /**
- * 解决0.1+0.2!=0.3的问题
- *
- * @param a 第一个数
- * @param b 第二个数
- * @return 是否相等
- */
- static isEqual(a: number, b: number) {
- return Math.abs(a - b) < Math.pow(2, -52);
- }
- static llll() {
- const a = {
- regions: [
- [[0, 0], [0, 200], [200, 200], [200, 0]],
- // [[150, 150], [250, 150], [250, 250], [150, 250]],
- ],
- inverted: false
- }
- const b = {
- regions: [
- [[150, 150], [250, 150], [250, 250], [150, 250]],
- ],
- inverted: false
- }
- const start = +new Date()
- const sa = segments(a)
- const sb = segments(b)
- const comb = combine(sa, sb)
- // const start = +new Date()
- // const poly = segments(a)
- // console.log(segments(a))
- // const end = +new Date();
- // console.log(end - start);
- // console.log(polygon(poly));
- console.log(comb);
- const selecomb = selectDifference(comb)
- console.log(selecomb)
- console.log(polygon(selecomb))
- const end = +new Date();
- console.log(end - start);
- }
- }
|