Files
cut-abstractions/samples/handleAbility/common/LayoutEngine/PolylineHelper.ts

370 lines
10 KiB
TypeScript
Raw Normal View History

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()
}
}