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

256 lines
7.4 KiB
TypeScript
Raw Normal View History

import type { PolylineProps } from 'cadapi'
import { Circle, Polyline, Polyline2Points } from 'cadapi'
import { EndType, JoinType } from 'js-angusj-clipper/web'
import type { Box3, Vector3 } from 'three'
import { Vector2 } from 'three'
import { clipperCpp } from '../ClipperCpp'
import type { Point } from '../Point'
import { Path, PathScale } from '../core/Path'
import type { IOffset } from './Simplify2'
import { SimplifyDouglasPeucker } from './Simplify2'
/** 内外接多边形 */
export function Circle2Points(circle: Circle, knifRadius: number, splitSize = 10, outside = false): Point[] {
let radius = circle.Radius
const an = Math.PI * 2 / splitSize
if (outside)
radius = radius / Math.cos(an / 2) + knifRadius
else
radius -= knifRadius
const cenP = circle.Center
const pts: Vector3[] = []
for (let i = 0; i < splitSize; i++)
pts.push(polar(cenP.clone(), an * i, radius))
return pts as Point[]
}
export function Curve2Path(curve: Polyline, outside = false): Path {
if (curve.IsClockWise)
curve.Reverse()
const w = new CurveWrap(curve, 3, outside)
return new Path(outside ? w.GetOutsidePoints() : w.GetInsidePoints())
}
export class CurveWrap {
BoundingBox: Box3
Area: number
SimplyPolyline: Polyline
SimplyOffset: IOffset
Used = false
Holes: CurveWrap[] = []
Points: Point[]
constructor(public Curve: Polyline | Circle, public KnifRadius: number, public IsOutside: boolean) {
this.BoundingBox = Curve.BoundingBox
if (Curve instanceof Polyline) {
const pts = Polyline2Points(Curve, IsOutside, 0)[1]
/**
* SimplifyDouglasPeucker
* QQ聊天记录 23.9.18
* 23.10.9 by lrx
*/
const [spts, offset] = SimplifyDouglasPeucker(pts, KnifRadius ** 2 + KnifRadius)
if (spts.length !== pts.length && spts.length > 2) {
this.SimplyOffset = offset
this.SimplyPolyline = Path2Polyline(spts)
this.Curve = this.SimplyPolyline// 保险起见,也更新它
this.Area = this.SimplyPolyline.Area
}
else// 此处更新多段线
{ this.Curve = Path2Polyline(pts) }
this.Points = spts
// 以下修改后的
// this.Curve = Path2Polyline(pts);
// this.Points = pts;
}
if (this.Area === undefined)
this.Area = this.Curve.Area
}
ContainsCurve(curve: CurveWrap): boolean {
if (this.SimplyPolyline)
return this.SimplyPolyline.PtInCurve(curve.Curve.StartPoint)
return this.Curve.PtInCurve(curve.Curve.StartPoint)
}
GetOutsidePoints(): Point[] {
if (this.Curve instanceof Circle) {
const pts = Circle2Points(this.Curve, this.KnifRadius, 10, true)
return pts
}
else {
const pl = this.SimplyPolyline || this.Curve
let offset = this.KnifRadius
if (this.SimplyOffset)
offset += this.SimplyOffset.positiveOffset
if (offset > 0) {
let pts = pl.GetStretchPoints() as Point[]
pts = clipperCpp.lib.offsetToPaths({
delta: offset * 1e4,
offsetInputs: [{ data: PathScale(pts, 1e4), joinType: JoinType.Miter, endType: EndType.ClosedPolygon }],
})[0]
try {
PathScale(pts, 1e-4)
}
catch {
console.log('err')
}
return pts
}
else { return this.Points }
}
}
GetInsidePoints(): Point[] {
return this.GetInsidePoints2(this.KnifRadius)
}
GetInsidePoints2(d: number): Point[] {
if (this.Curve instanceof Circle) {
const pts = Circle2Points(this.Curve, d, 10, false)
return pts
}
else {
const pl = this.SimplyPolyline || this.Curve
let offset = -d
if (this.SimplyOffset)
offset += this.SimplyOffset.negativeOffset
if (offset < -0.01) {
const pls = pl.GetOffsetCurves(offset)
if (pls.length)
return pls[0].GetStretchPoints()
}
else { return this.Points }
}
}
/** 引入Polyline 已经含刀半径, 获得精简后的点阵 */
GetOrgPoints(outside = true): Point[] {
if (this.Curve instanceof Circle) {
const pts = Circle2Points(this.Curve, 0, 10, outside)
return pts
}
else {
const pl = this.SimplyPolyline || this.Curve
let offset = 0
if (this.SimplyOffset)
offset += this.SimplyOffset.positiveOffset
if (offset > 0) {
let pts = pl.GetStretchPoints() as Point[]
pts = clipperCpp.lib.offsetToPaths({
delta: offset * 1e4,
offsetInputs: [{ data: PathScale(pts, 1e4), joinType: JoinType.Miter, endType: EndType.ClosedPolygon }],
})[0]
try {
PathScale(pts, 1e-4)
}
catch {
console.log('err')
}
return pts
}
else {
return this.Points
}
}
}
}
/** 多段线 转点整 已弃用整合到CAD api 23.11.2 */
// export function Polylin2Points(pl: Polyline, outside: boolean, knifRadius: number): [Polyline, Point[]]
// {
// let pts: Point[] = [];
// if (!outside) knifRadius = -knifRadius;
// if (pl.IsClockWise) pl.Reverse();
// for (let i = 0; i < pl.EndParam; i++)
// {
// pts.push(pl.GetPointAtParam(i));
// let bul = pl.GetBulgeAt(i);
// if (bul !== 0)
// {
// let arc = pl.GetCurveAtIndex(i) as Arc;
// let allAngle = arc.AllAngle;
// let arcLength = arc.Length;
// // let splitCount = Math.round(allAngle / 0.4);
// // if (arcLength < 300)
// // splitCount = 2;
// // else
// // splitCount = Math.max(arcLength / 200, splitCount,2);
// let minCount = Math.floor(allAngle * 4 / Math.PI);
// let splitCount = Math.round(allAngle / 0.4);
// if (arcLength < 300)
// splitCount = Math.max(2, minCount);
// else
// splitCount = Math.max(Math.floor(arcLength / 200), splitCount,2, minCount);
// let radius = arc.Radius;
// if (outside === bul > 0)
// radius = radius / Math.cos(allAngle / (splitCount * 2));
// let cp = arc.Center;
// for (let j = outside ? 0.5 : 0; j < splitCount; j++)
// {
// let a = arc.GetAngleAtParam(j * (1 / splitCount));
// let p = polar(cp.clone(), a, radius);
// pts.push(p);
// }
// }
// }
// if (knifRadius !== 0)
// {
// pts = clipperCpp.lib.offsetToPaths({
// delta: knifRadius * 1e4,
// offsetInputs: [{ data: PathScale(pts, 1e4), joinType: JoinType.Miter, endType: EndType.ClosedPolygon }]
// })[0];
// PathScale(pts, 1e-4);
// }
// return [pl, pts];
// }
export function Path2Polyline(path: Point[]): Polyline {
const pl = new Polyline()
pl.LineData = path.map((p) => {
return { pt: new Vector2(p.x, p.y), bul: 0 }
})
pl.CloseMark = true
return pl
}
export function Points2Polyline(pts: any[]): Polyline {
const lined: PolylineProps[] = []
const count = pts.length
for (let i = 0; i < count; i++) {
const p0 = pts[i]
lined.push({ pt: new Vector2(p0.x, p0.y), bul: p0.bul })
}
const pls = new Polyline(lined)
pls.CloseMark = true
return pls
}
export function polar<T extends Vector2 | Vector3>(v: T, an: number, dis: number): T {
v.x += Math.cos(an) * dis
v.y += Math.sin(an) * dis
return v
}