import type { PolylineProps } from 'cadapi' import { CADFiler, Circle, Polyline, Status, VKnifToolPath, isTargetCurInOrOnSourceCur } from 'cadapi' import type { Box3 } from 'three' import { Vector2, Vector3 } from 'three' import { arrayRemoveDuplicateBySort } from '../ArrayExt' import type { Curve2d } from '../base/CAD' import { Arc2d, Point2d, copyTextToClipboard } from '../base/CAD' import { CurveWrap } from './Curves2Parts' // import type { Curve2d } from '../../common/base/CAD' export class PolylineHelper { /** 创建闭合多段线 */ static create(pts: any[], closeMark = false): Polyline { let lined: PolylineProps[] = [] let count = pts.length for (let i = 0; i < count; i++) { let p0 = pts[i] lined.push({ pt: new Vector2(p0.x, p0.y), bul: p0.bul || 0 }) } let pls = new Polyline(lined) pls.CloseMark = closeMark return pls } static createByCurve2d(curs: Curve2d[], closeMark = true): Polyline { let lined: PolylineProps[] = [] for (let cur of curs) { let x = cur.StartPoint.m_X let y = cur.StartPoint.m_Y let bul = 0 if (cur instanceof Arc2d) bul = cur.Bul || 0 lined.push({ pt: new Vector2(x, y), bul }) } let pls = new Polyline(lined) pls.CloseMark = true return pls } static createByPts(pts: any[], buls: number[], closeMark = false): Polyline { let plps: PolylineProps[] = [] let count = pts.length for (let i = 0; i < count; i++) { let p0 = pts[i] plps.push({ pt: new Vector2(p0.x, p0.y), bul: buls[i] }) } let pls = new Polyline(plps) pls.CloseMark = closeMark return pls } static getSimplePoints(pts: any[], offset: number): any[] { let pl = PolylineHelper.create(pts) pl.CloseMark = true let cureW = new CurveWrap(pl, offset, true) let pts2 = cureW.GetOutsidePoints() arrayRemoveDuplicateBySort(pts2, (p1, p2) => (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y) < 1e-2) return pts2 } static createByWidthLength(w: number, l: number): Polyline { let plps: PolylineProps[] = [] plps.push({ pt: new Vector2(0, 0), bul: 0 }) plps.push({ pt: new Vector2(w, 0), bul: 0 }) plps.push({ pt: new Vector2(w, l), bul: 0 }) plps.push({ pt: new Vector2(0, l), bul: 0 }) let pls = new Polyline(plps) pls.CloseMark = true return pls } /** 多段线,添加位置移动 返回新多段线 */ static moveTo(pl: Polyline, x: number, y: number): Polyline { let lindData = pl.LineData let pos = pl.Position let newPts: PolylineProps[] = [] for (let p of lindData) { let nx = p.pt.x + pos.x + x let ny = p.pt.y + pos.y + y if (ny < 7.9) { // console.log('修边小于 7.9????', ny) } let bul = p.bul newPts.push({ pt: new Vector2(nx, ny), bul }) } let npl = new Polyline(newPts) npl.CloseMark = pl.CloseMark return npl } /** 重设 多段线的几点 */ static resetPosition(pl: Polyline): Polyline { let lindData = pl.LineData let pos = pl.Position let newPts: PolylineProps[] = [] for (let p of lindData) { let nx = p.pt.x + pos.x let ny = p.pt.y + pos.y let bul = p.bul newPts.push({ pt: new Vector2(nx, ny), bul }) } let npl = new Polyline(newPts) npl.CloseMark = pl.CloseMark return npl } /** 获得v型刀走刀路径 */o static getVModelPoints(pl: Polyline, depth: number, ang: number): any[] { // let ang = Math.PI * (0.5 * angle) / 180 ; let ps = [] let bx = pl.Position.x let by = pl.Position.y if (ang > 0.01) { let rt = VKnifToolPath(pl, depth, ang / 2) ps = rt.map((t) => { return { x: t.pt.x + bx, y: t.pt.y + by, z: t.pt.z, bul: t.bul, r: 0 } }) } else { ps = pl.LineData.map((t) => { return { x: t.pt.x + bx, y: t.pt.y + by, z: 0, bul: t.bul, r: 0 } }) } for (let i = 0; i < ps.length; i++) { let p = ps[i] if (p.bul == 0) continue let p2 = (i == ps.length - 1 ? ps[0] : ps[i + 1]) let r = this.getArcRadius(p.x, p.y, p2.x, p2.y, p.bul) p.r = r } return ps } static ConverPolyLin2Circle(polyline: Polyline, fuzz = 0.1): Circle | undefined { let box = polyline.BoundingBox let size = box.getSize(new Vector3()) if (!this.equaln(size.x, size.y, fuzz))// 盒子四方 return undefined let circleLength = 2 * Math.PI * size.x if (!this.equaln(circleLength, polyline.Length, fuzz * 2)) return undefined let circleArea = Math.PI * size.x * size.x if (!this.equaln(circleArea, polyline.Area, fuzz * 2)) return undefined let r = size.x// 必须备份(因为我们要复用这个vector变量) return new Circle(box.getCenter(size), r) } // 有问题 static getVModelPoints_offset(pl: Polyline, offset: number, depth: number, angle: number) { let npl = offset == 0 ? pl : pl.GetOffsetCurves(offset)[0] // if(offset != 0) // { // ClipboardTest.write2PolyLine(pl,npl); // } return PolylineHelper.getVModelPoints(npl, depth, angle) } static getArcRadius(x1: number, y1: number, x2: number, y2: number, bul: number): number { let bul2 = Math.abs(bul) let d = Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2) / 2 return 0.5 * d * (1 + bul2 ** 2) / bul2 } // 圆 转 多段线 static cicleToPolyline(c: Circle): Polyline { let arcs = c.GetSplitCurves([0, 0.5]) let pl = Polyline.FastCombine(arcs) return pl } /** 判断多段线是否 重叠 */ static isIntersect(pl1: Polyline, pl2: Polyline): boolean { let box1 = this.getBox(pl1) let box2 = this.getBox(pl2) if (!box1.intersectsBox(box2)) return false // 肯定不相交 let ipts = pl1.IntersectWith(pl2, 0) if (ipts.length === 0) { if (pl1.Area > pl2.Area)// 缓存面积 { if (isTargetCurInOrOnSourceCur(pl1, pl2)) return true // 包含 } else { if (isTargetCurInOrOnSourceCur(pl2, pl1)) return true // 包含 } return false } else { return true // 有交点 一定有交集 } } // 多段线 圆弧合并 static mergeCurve(pl2: Polyline): Polyline { const curves = pl2.Explode() arrayRemoveDuplicateBySort(curves, (c1, c2) => { return c1.Join(c2) === Status.True }) return Polyline.FastCombine(curves) } /** * pl2 包含在pl1 内 * */ // static isInside(pl1:Polyline,pl2:Polyline):boolean // { // let box1 = this.getBox(pl1); // let box2 = this.getBox(pl2); // if (!box1.intersectsBox(box2)) return false; //肯定不相交 // let ipts = pl1.IntersectWith(pl2, 0); // if (ipts.length > 0) return true; //有交点 一定有交集 // } /** * 两片板的干涉检查 * * @param pl1 * @param pls1_inner * @param pls1_model * @param pl2 * @param pls2_inner * @param pls2_model * @returns */ static isOverLap(pl1: Polyline, pls1_inner: Polyline[], pls1_model: Polyline[], pl2: Polyline, pls2_inner: Polyline[], pls2_model: Polyline[]) { // 是否干涉, 被包含在造型洞,不算干涉 let isOverlap = this.boxIsOverlap(pl1, pls1_inner, pl2, pls2_inner) if (isOverlap) return true // 造型 ,2v 刀路 是否干涉 for (let pl1_model of pls1_model) { if (pl1_model.IntersectWith(pl2, 0).length > 0) return true for (let pl2_inner of pls2_inner) { if (pl1_model.IntersectWith(pl2_inner, 0).length > 0) return true } } for (let pl2_model of pls2_model) { if (pl2_model.IntersectWith(pl1, 0).length > 0) return true for (let pl1_inner of pls1_inner) { if (pl2_model.IntersectWith(pl1_inner, 0).length > 0) return true } } return false } private static boxIsOverlap(pl1: Polyline, pls1_inner: Polyline[], pl2: Polyline, pls2_inner: Polyline[]) { let box1 = this.getBox(pl1) let box2 = this.getBox(pl2) if (!box1.intersectsBox(box2)) return false // 肯定不相交 let ipts = pl1.IntersectWith(pl2, 0) if (ipts.length > 0) return true // 有交点 一定有交集 if (pl1.Area > pl2.Area)// 缓存面积 { if (isTargetCurInOrOnSourceCur(pl1, pl2)) // pl1包含 pl2 { for (let mpl of pls1_inner) // 如果pl1有造型洞包含pl2, 则表示不干涉,返回false { if (isTargetCurInOrOnSourceCur(mpl, pl2) == true) return false } return true } } else { if (isTargetCurInOrOnSourceCur(pl2, pl1)) // pl2包含 pl1 { for (let mpl of pls2_inner) // 如果pl2有造型洞包含pl1, 则表示不干涉,返回false { if (isTargetCurInOrOnSourceCur(mpl, pl1) == true) return false } return true } } return false } /** 判断 点是否在多段线内 */ static isPointInPolyline(pl1: Polyline, x: number, y: number): boolean { return pl1.PtInCurve(new Vector3(x, y, 0)) } static getBox(pl1: Polyline): Box3 { if (!pl1.box_tp) pl1.box_tp = pl1.BoundingBox return pl1.box_tp as Box3 } static getArea(pl1: Polyline): number { if (!pl1.area_tp) pl1.area_tp = pl1.Area return pl1.area_tp as number } static getPath(pl: Polyline): Path2D { let path = new Path2D() let p0 = pl.LineData[0].pt path.moveTo(p0.x, p0.y) for (let i = 0; i < pl.LineData.length; i++) { let p0 = pl.LineData[i].pt let p1 = (i == pl.LineData.length - 1) ? pl.LineData[0].pt : pl.LineData[i + 1].pt let bul = pl.LineData[i].bul if (bul == 0) { path.lineTo(p1.x, p1.y) } else { let arc = new Arc2d(new Point2d(p0.x, p0.y), new Point2d(p1.x, p1.y), bul) path.arc(arc.m_Center.m_X, arc.m_Center.m_Y, arc.m_Radius, arc.m_StartAngle, arc.m_EndAngle, bul < 0) } } path.closePath() return path } static equaln(v1: number, v2: number, fuzz = 1e-5) { return Math.abs(v1 - v2) <= fuzz } static toClipboard(en: Polyline | any) { let f = new CADFiler() f.Write(1)// 实体个数 f.WriteObject(en) copyTextToClipboard(f.ToString()) } static getStrPLs(ens: any[]) { if (ens.length == 0) return '' let f = new CADFiler() f.Write(ens.length)// 实体个数 for (let en of ens) f.WriteObject(en) return f.ToString() } }