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

256 lines
7.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}