1626 lines
42 KiB
TypeScript
1626 lines
42 KiB
TypeScript
|
export class Vector2d
|
|||
|
{
|
|||
|
m_X = 0
|
|||
|
m_Y = 0
|
|||
|
|
|||
|
/** 长度 */
|
|||
|
Length = 0
|
|||
|
/** 角度 */
|
|||
|
Angle = 0
|
|||
|
|
|||
|
constructor(x: number, y: number)
|
|||
|
{
|
|||
|
this.m_X = x
|
|||
|
this.m_Y = y
|
|||
|
|
|||
|
this.GetLength()
|
|||
|
this.GetAngle()
|
|||
|
}
|
|||
|
|
|||
|
private GetLength()
|
|||
|
{
|
|||
|
this.Length = Math.sqrt(this.m_X * this.m_X + this.m_Y * this.m_Y)
|
|||
|
}
|
|||
|
|
|||
|
// 角度
|
|||
|
private GetAngle()
|
|||
|
{
|
|||
|
let a = Math.atan2(this.m_Y, this.m_X)
|
|||
|
if (a < 0)
|
|||
|
a = Math.PI * 2 + a
|
|||
|
this.Angle = a
|
|||
|
}
|
|||
|
|
|||
|
Normal(): Vector2d
|
|||
|
{
|
|||
|
if (this.Length != 0)
|
|||
|
{
|
|||
|
let k = 1 / this.Length
|
|||
|
this.m_X *= k
|
|||
|
this.m_Y *= k
|
|||
|
this.Length = 1
|
|||
|
}
|
|||
|
return this
|
|||
|
}
|
|||
|
|
|||
|
static OpDivide(v: Vector2d, c: number): Vector2d
|
|||
|
{
|
|||
|
return new Vector2d(v.m_X / c, v.m_Y / c)
|
|||
|
}
|
|||
|
|
|||
|
static OpMultiply(v: Vector2d, c: number): Vector2d
|
|||
|
{
|
|||
|
return new Vector2d(v.m_X * c, v.m_Y * c)
|
|||
|
}
|
|||
|
|
|||
|
static OpAdd(v1: Vector2d, v2: Vector2d): Vector2d
|
|||
|
{
|
|||
|
return new Vector2d(v1.m_X + v2.m_X, v1.m_Y + v2.m_Y)
|
|||
|
}
|
|||
|
|
|||
|
static OpMultiplyValue(v1: Vector2d, v2: Vector2d): number
|
|||
|
{
|
|||
|
return v1.m_X * v2.m_X + v1.m_Y * v2.m_Y
|
|||
|
}
|
|||
|
|
|||
|
/** 点积 */
|
|||
|
DotProduct(v1: Vector2d): number
|
|||
|
{
|
|||
|
return Vector2d.OpMultiplyValue(this, v1)
|
|||
|
}
|
|||
|
|
|||
|
/** 叉积 */
|
|||
|
CrossProduct(v: Vector2d): number
|
|||
|
{
|
|||
|
return this.m_X * v.m_Y - this.m_Y * v.m_X
|
|||
|
}
|
|||
|
|
|||
|
IsEqual(v: Vector2d, fuzz = 1e-3): boolean
|
|||
|
{
|
|||
|
return DoubleUtil.EqualX(this.m_X, v.m_X, fuzz) && DoubleUtil.EqualX(this.m_Y, v.m_Y, fuzz)
|
|||
|
}
|
|||
|
|
|||
|
/** 返回和另外一个向量的夹角 */
|
|||
|
AngleTo(v: Vector2d): number
|
|||
|
{
|
|||
|
let an = Math.abs(this.Angle - v.Angle)
|
|||
|
if (DoubleUtil.EqualX(v.Length, 0, 1e-5) || DoubleUtil.EqualX(this.Length, 0, 1e-5))
|
|||
|
{
|
|||
|
return -Math.PI// 随缘给
|
|||
|
}
|
|||
|
else if (Math.abs(Math.sin(an)) < 0)
|
|||
|
{
|
|||
|
return this.Normal().IsEqual(v.Normal()) ? 0 : Math.PI
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
let p0 = new Point2d(0, 0)
|
|||
|
let p1 = Point2d.OpAdd(new Point2d(0, 0), this)
|
|||
|
let p2 = Point2d.OpAdd(new Point2d(0, 0), v)
|
|||
|
let s = this.sign(Utils.Det(p1, p0, p2))
|
|||
|
if (an > Math.PI)
|
|||
|
{
|
|||
|
return ((2 * Math.PI) - an) * s
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return an * s
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private sign(x: number): number
|
|||
|
{
|
|||
|
if (x == 0)
|
|||
|
{
|
|||
|
return 0
|
|||
|
}
|
|||
|
else if (x > 0)
|
|||
|
{
|
|||
|
return -1
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return 1
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/** CAD 点 */
|
|||
|
export class Point2d
|
|||
|
{
|
|||
|
m_X = 0
|
|||
|
m_Y = 0
|
|||
|
|
|||
|
constructor(x: number, y: number)
|
|||
|
{
|
|||
|
this.m_X = x
|
|||
|
this.m_Y = y
|
|||
|
}
|
|||
|
|
|||
|
DistensTo(pt: Point2d): number
|
|||
|
{
|
|||
|
return Point2d.OpSubtract(pt, this).Length
|
|||
|
}
|
|||
|
|
|||
|
Polar(angle: number, distens: number): Point2d
|
|||
|
{
|
|||
|
let x1 = this.m_X + Math.cos(angle) * distens
|
|||
|
let y1 = this.m_Y + Math.sin(angle) * distens
|
|||
|
return new Point2d(x1, y1)
|
|||
|
}
|
|||
|
|
|||
|
Mid(pt: Point2d): Point2d
|
|||
|
{
|
|||
|
return new Point2d((this.m_X + pt.m_X) * 0.5, (this.m_Y + pt.m_Y) * 0.5)
|
|||
|
}
|
|||
|
|
|||
|
AsVector(): Vector2d
|
|||
|
{
|
|||
|
return new Vector2d(this.m_X, this.m_Y)
|
|||
|
}
|
|||
|
|
|||
|
/** 减以 - */
|
|||
|
static OpSubtract(p1: Point2d, p2: Point2d): Vector2d
|
|||
|
{
|
|||
|
return new Vector2d(p1.m_X - p2.m_X, p1.m_Y - p2.m_Y)
|
|||
|
}
|
|||
|
|
|||
|
static OpAdd(p1: Point2d, p2: Vector2d): Point2d
|
|||
|
{
|
|||
|
return new Point2d(p1.m_X + p2.m_X, p1.m_Y + p2.m_Y)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function equaln(v1: number, v2: number, fuzz = 1e-5)
|
|||
|
{
|
|||
|
return Math.abs(v1 - v2) <= fuzz
|
|||
|
}
|
|||
|
function equalp(v1: Point2d, v2: Point2d, fuzz = 1e-5)
|
|||
|
{
|
|||
|
return equaln(v1.m_X, v2.m_X, fuzz) && equaln(v1.m_Y, v2.m_Y, fuzz)
|
|||
|
}
|
|||
|
|
|||
|
/** 二维曲线:直线,圆弧 */
|
|||
|
export abstract class Curve2d
|
|||
|
{
|
|||
|
// 求交点
|
|||
|
abstract IntersectWith(cu: Curve2d, retIns: Point2d[]): void
|
|||
|
abstract Offset(distens: number): Curve2d
|
|||
|
|
|||
|
// 点在线内部
|
|||
|
abstract PtInCurve(pt: Point2d): boolean
|
|||
|
abstract ClosePointTo(pt: Point2d): Point2d
|
|||
|
|
|||
|
// 获得参数 返回0或1
|
|||
|
abstract GetParametersAt(pt: Point2d): number
|
|||
|
|
|||
|
abstract Parse()
|
|||
|
|
|||
|
PtOnCurve(p: Point2d): boolean
|
|||
|
{
|
|||
|
return equalp(p, this.m_StartPoint) || equalp(p, this.m_EndPoint) || this.ParamOnCurve(this.GetParametersAt(p))
|
|||
|
}
|
|||
|
|
|||
|
ParamOnCurve(param: number, fuzz = 1e-6): boolean { return !Number.isNaN(param) && param >= -fuzz && param <= 1 + fuzz }
|
|||
|
|
|||
|
get EndPoint(): Point2d
|
|||
|
{
|
|||
|
return this.m_EndPoint
|
|||
|
}
|
|||
|
|
|||
|
set EndPoint(p: Point2d)
|
|||
|
{
|
|||
|
this.m_EndPoint = p
|
|||
|
try
|
|||
|
{
|
|||
|
this.Parse()
|
|||
|
} catch (error)
|
|||
|
{
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
get StartPoint(): Point2d
|
|||
|
{
|
|||
|
return this.m_StartPoint
|
|||
|
}
|
|||
|
|
|||
|
set StartPoint(p: Point2d)
|
|||
|
{
|
|||
|
this.m_StartPoint = p
|
|||
|
try
|
|||
|
{
|
|||
|
this.Parse()
|
|||
|
} catch (error)
|
|||
|
{
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
protected m_StartPoint: Point2d
|
|||
|
protected m_EndPoint: Point2d
|
|||
|
tagData: number // 特殊数据 异形边 封边值
|
|||
|
tagData2: number // 特殊数据 侧孔数
|
|||
|
}
|
|||
|
|
|||
|
/** 直线 */
|
|||
|
export class Line2d extends Curve2d
|
|||
|
{
|
|||
|
get toString()
|
|||
|
{
|
|||
|
return `[${this.m_StartPoint.m_X.toFixed(1)},${this.m_StartPoint.m_Y.toFixed(1)}] [${this.m_EndPoint.m_X.toFixed(1)},${this.m_EndPoint.m_Y.toFixed(1)}]`
|
|||
|
}
|
|||
|
|
|||
|
constructor(p1: Point2d, p2: Point2d)
|
|||
|
{
|
|||
|
super()
|
|||
|
this.m_StartPoint = p1
|
|||
|
this.m_EndPoint = p2
|
|||
|
this.Parse()
|
|||
|
}
|
|||
|
|
|||
|
/** 求交点 */
|
|||
|
IntersectWith(cu: Curve2d, retIns: Point2d[])
|
|||
|
{
|
|||
|
if (cu instanceof Line2d)
|
|||
|
{
|
|||
|
let l = cu as Line2d
|
|||
|
let dx1 = this.StartPoint.m_X - this.EndPoint.m_X
|
|||
|
let dx2 = l.StartPt.m_X - l.EndPt.m_X
|
|||
|
let dx3 = l.EndPt.m_X - this.EndPoint.m_X
|
|||
|
let dy1 = this.StartPoint.m_Y - this.EndPoint.m_Y
|
|||
|
let dy2 = l.StartPt.m_Y - l.EndPt.m_Y
|
|||
|
let dy3 = l.EndPt.m_Y - this.EndPoint.m_Y
|
|||
|
|
|||
|
let det = (dx2 * dy1) - (dy2 * dx1)
|
|||
|
let pt = new Point2d(0, 0)
|
|||
|
|
|||
|
if (DoubleUtil.EqualX(det, 0.0, 1e-5))
|
|||
|
{
|
|||
|
if (DoubleUtil.EqualX(dx2 * dy3, dy2 * dx3, 1e-5))
|
|||
|
{
|
|||
|
if (l.StartPoint.DistensTo(this.EndPoint) < 1e-3)
|
|||
|
{
|
|||
|
retIns.push(this.EndPoint)
|
|||
|
}
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
let ratio = ((dx1 * dy3) - (dy1 * dx3)) / det
|
|||
|
pt.m_X = (ratio * dx2) + l.EndPt.m_X
|
|||
|
pt.m_Y = (ratio * dy2) + l.EndPt.m_Y
|
|||
|
retIns.push(pt)
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
let arc = cu as Arc2d
|
|||
|
arc.IntersectWith(this, retIns)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/** 偏移 */
|
|||
|
Offset(distens: number): Curve2d
|
|||
|
{
|
|||
|
let an = Point2d.OpSubtract(this.EndPt, this.StartPt).Angle - Math.PI * 0.5
|
|||
|
return new Line2d(this.StartPt.Polar(an, distens), this.EndPt.Polar(an, distens))
|
|||
|
}
|
|||
|
|
|||
|
/** 判断点在线内 */
|
|||
|
PtInCurve(pt: Point2d): boolean
|
|||
|
{
|
|||
|
// 首先判断平行
|
|||
|
let minX = Math.min(this.m_StartPoint.m_X, this.m_EndPoint.m_X)
|
|||
|
let maxX = Math.max(this.m_StartPoint.m_X, this.m_EndPoint.m_X)
|
|||
|
|
|||
|
if (DoubleUtil.EqualX(minX, maxX, 1e-3))
|
|||
|
{
|
|||
|
let minY = Math.min(this.m_StartPoint.m_Y, this.m_EndPoint.m_Y)
|
|||
|
let maxY = Math.max(this.m_StartPoint.m_Y, this.m_EndPoint.m_Y)
|
|||
|
return (pt.m_Y >= minY - 1e-4 && pt.m_Y <= maxY + 1e-4)
|
|||
|
}
|
|||
|
|
|||
|
if (pt.m_X >= minX - 0.0001 && pt.m_X <= maxX + 0.0001)
|
|||
|
{
|
|||
|
let vec = Point2d.OpSubtract(this.m_EndPoint, this.m_StartPoint)// 标准向量
|
|||
|
let k = vec.m_Y / vec.m_X
|
|||
|
return DoubleUtil.EqualX(this.m_StartPoint.m_Y + k * (pt.m_X - this.m_StartPoint.m_X), pt.m_Y, 0.01)
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return false
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ClosePointTo(pt: Point2d): Point2d
|
|||
|
{
|
|||
|
let an = Point2d.OpSubtract(this.m_EndPoint, this.m_StartPoint).Angle + Math.PI / 2
|
|||
|
let vec = new Point2d(0, 0).Polar(an, 1).AsVector()
|
|||
|
let p2 = Point2d.OpAdd(pt, vec)
|
|||
|
let line = new Line2d(pt, p2)
|
|||
|
let ptLst: Point2d[] = []
|
|||
|
this.IntersectWith(line, ptLst)
|
|||
|
return ptLst[0]
|
|||
|
}
|
|||
|
|
|||
|
Parse()
|
|||
|
{
|
|||
|
if (this.EndPoint != null)
|
|||
|
{
|
|||
|
this.m_Length = this.StartPoint.DistensTo(this.EndPoint)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
GetParametersAt(pt: Point2d): number
|
|||
|
{
|
|||
|
let nearPt = this.ClosePointTo(pt)
|
|||
|
|
|||
|
let vec = Point2d.OpSubtract(nearPt, this.m_StartPoint)
|
|||
|
let vec2 = Point2d.OpSubtract(this.EndPoint, this.StartPoint)
|
|||
|
|
|||
|
let an = vec.DotProduct(vec2)
|
|||
|
|
|||
|
return Math.sign(an) * vec.Length / this.m_Length
|
|||
|
}
|
|||
|
|
|||
|
get StartPt(): Point2d { return this.StartPoint }
|
|||
|
get EndPt(): Point2d { return this.EndPoint }
|
|||
|
|
|||
|
m_Length: number
|
|||
|
|
|||
|
static New(x0: number, y0: number, x1: number, y1: number): Line2d
|
|||
|
{
|
|||
|
let p0 = new Point2d(x0, y0)
|
|||
|
let p1 = new Point2d(x1, y1)
|
|||
|
return new Line2d(p0, p1)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/** 圆弧 */
|
|||
|
export class Arc2d extends Curve2d
|
|||
|
{
|
|||
|
constructor(p1: Point2d, p2: Point2d, bul: number)
|
|||
|
{
|
|||
|
super()
|
|||
|
this.m_StartPoint = p1
|
|||
|
this.m_EndPoint = p2
|
|||
|
|
|||
|
this.m_Bul = bul
|
|||
|
let vec = Point2d.OpSubtract(p2, p1)
|
|||
|
let an = vec.Angle
|
|||
|
let length = vec.Length
|
|||
|
|
|||
|
this.m_Radius = length / Math.sin(2 * Math.atan(bul)) / 2
|
|||
|
this.m_AllAngle = Math.atan(bul) * 4
|
|||
|
let delDis = bul * length / 2
|
|||
|
|
|||
|
let toDis = this.m_Radius - delDis
|
|||
|
|
|||
|
an += Math.PI * 0.5
|
|||
|
|
|||
|
this.m_Center = p1.Mid(p2)
|
|||
|
this.m_Center = this.m_Center.Polar(an, toDis)
|
|||
|
|
|||
|
this.m_StartAngle = Point2d.OpSubtract(this.StartPoint, this.m_Center).Angle
|
|||
|
this.m_EndAngle = Point2d.OpSubtract(this.EndPoint, this.m_Center).Angle
|
|||
|
|
|||
|
if (this.m_Bul < 0)
|
|||
|
this.m_Radius = Math.abs(this.m_Radius)
|
|||
|
}
|
|||
|
|
|||
|
/** 圆心 */
|
|||
|
m_Center: Point2d
|
|||
|
/** 半径 */
|
|||
|
m_Radius: number
|
|||
|
/** 起始弧度 */
|
|||
|
m_StartAngle: number
|
|||
|
/** 结束弧度 */
|
|||
|
m_EndAngle: number
|
|||
|
/** 所有的弧度 */
|
|||
|
m_AllAngle: number
|
|||
|
|
|||
|
IntersectWith(cu: Curve2d, retIns: Point2d[])
|
|||
|
{
|
|||
|
if (cu instanceof Line2d)
|
|||
|
{
|
|||
|
let l = cu as Line2d
|
|||
|
let a = DoubleUtil.Sqr(l.EndPt.m_X - l.StartPt.m_X) + DoubleUtil.Sqr(l.EndPt.m_Y - l.StartPt.m_Y)
|
|||
|
|
|||
|
let b = (2.0) * ((l.EndPt.m_X - l.StartPt.m_X) * (l.StartPt.m_X - this.m_Center.m_X)
|
|||
|
+ (l.EndPt.m_Y - l.StartPt.m_Y) * (l.StartPt.m_Y - this.m_Center.m_Y))
|
|||
|
|
|||
|
let c = DoubleUtil.Sqr(this.m_Center.m_X) + DoubleUtil.Sqr(this.m_Center.m_Y)
|
|||
|
+ DoubleUtil.Sqr(l.StartPt.m_X) + DoubleUtil.Sqr(l.StartPt.m_Y)
|
|||
|
- (2.0) * (this.m_Center.m_X * l.StartPt.m_X + this.m_Center.m_Y * l.StartPt.m_Y) - DoubleUtil.Sqr(this.m_Radius)
|
|||
|
|
|||
|
let det = b * b - (4.0) * a * c
|
|||
|
|
|||
|
if (DoubleUtil.EqualX(det, 0.0, 0.1))
|
|||
|
{
|
|||
|
let delta = -b / ((2.0) * a)
|
|||
|
|
|||
|
let pt = new Point2d(l.StartPt.m_X + delta * (l.EndPt.m_X - l.StartPt.m_X), l.StartPt.m_Y + delta * (l.EndPt.m_Y - l.StartPt.m_Y))
|
|||
|
retIns.push(pt)
|
|||
|
return
|
|||
|
}
|
|||
|
else if (det > (0.0))
|
|||
|
{
|
|||
|
let sqrt_det = Math.sqrt(det)
|
|||
|
let delta = (-b + sqrt_det) / ((2.0) * a)
|
|||
|
let p2 = new Point2d(l.StartPt.m_X + delta * (l.EndPt.m_X - l.StartPt.m_X), l.StartPt.m_Y + delta * (l.EndPt.m_Y - l.StartPt.m_Y))
|
|||
|
|
|||
|
delta = (-b - sqrt_det) / ((2.0) * a)
|
|||
|
let p3 = new Point2d(l.StartPt.m_X + delta * (l.EndPt.m_X - l.StartPt.m_X), l.StartPt.m_Y + delta * (l.EndPt.m_Y - l.StartPt.m_Y))
|
|||
|
|
|||
|
retIns.push(p2)
|
|||
|
retIns.push(p3)
|
|||
|
return
|
|||
|
}
|
|||
|
}
|
|||
|
else if (cu instanceof Arc2d)
|
|||
|
{
|
|||
|
let arc = cu as (Arc2d)
|
|||
|
let dist = arc.m_Center.DistensTo(this.m_Center)
|
|||
|
|
|||
|
if (dist < Math.abs(this.m_Radius - cu.m_Radius) - 1e-3
|
|||
|
|| dist > (this.m_Radius + cu.m_Radius + 1e-3))
|
|||
|
return
|
|||
|
|
|||
|
let dstsqr = dist * dist
|
|||
|
let r1sqr = this.m_Radius * this.m_Radius
|
|||
|
let r2sqr = arc.m_Radius * arc.m_Radius
|
|||
|
|
|||
|
let a = (dstsqr - r2sqr + r1sqr) / (2 * dist)
|
|||
|
let h = Math.sqrt(Math.abs(r1sqr - (a * a)))
|
|||
|
|
|||
|
let ratio_a = a / dist
|
|||
|
let ratio_h = h / dist
|
|||
|
|
|||
|
let dx = arc.m_Center.m_X - this.m_Center.m_X
|
|||
|
let dy = arc.m_Center.m_Y - this.m_Center.m_Y
|
|||
|
|
|||
|
let phix = this.m_Center.m_X + (ratio_a * dx)
|
|||
|
let phiy = this.m_Center.m_Y + (ratio_a * dy)
|
|||
|
|
|||
|
dx = dx * ratio_h
|
|||
|
dy = dy * ratio_h
|
|||
|
|
|||
|
let pt = new Point2d(phix + dy, phiy - dx)
|
|||
|
let p2 = new Point2d(phix - dy, phiy + dx)
|
|||
|
retIns.push(pt)
|
|||
|
retIns.push(p2)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Offset(distens: number): Curve2d
|
|||
|
{
|
|||
|
let rn = new Arc2d(new Point2d(0, 0), new Point2d(0, 0), 0)
|
|||
|
rn.m_Center = this.m_Center
|
|||
|
rn.m_Radius = this.m_Radius
|
|||
|
rn.m_StartAngle = this.m_StartAngle
|
|||
|
rn.m_EndAngle = this.m_EndAngle
|
|||
|
if (this.m_Bul > 0)
|
|||
|
rn.m_Radius += distens
|
|||
|
else
|
|||
|
rn.m_Radius -= distens
|
|||
|
rn.Bul = this.m_Bul
|
|||
|
rn.ParsePointFormAngle()
|
|||
|
return rn
|
|||
|
}
|
|||
|
|
|||
|
Parse()
|
|||
|
{
|
|||
|
// 解析角度
|
|||
|
this.ParseAngleFormPoint()
|
|||
|
this.ParseAllAngle()
|
|||
|
this.ParseBul()
|
|||
|
}
|
|||
|
|
|||
|
ParseAllAngle()
|
|||
|
{
|
|||
|
this.m_AllAngle = this.ComputeAnlge(this.m_EndAngle)
|
|||
|
}
|
|||
|
|
|||
|
ComputeAnlge(endAngle: number)
|
|||
|
{
|
|||
|
// 顺时针
|
|||
|
if (this.m_Bul < 0)
|
|||
|
{
|
|||
|
if (this.m_StartAngle > endAngle)
|
|||
|
return this.m_StartAngle - endAngle
|
|||
|
else // 越过0点绘制圆弧
|
|||
|
return (Math.PI * 2) - (endAngle - this.m_StartAngle)
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (endAngle > this.m_StartAngle)
|
|||
|
return endAngle - this.m_StartAngle
|
|||
|
else
|
|||
|
return (Math.PI * 2) - (this.m_StartAngle - endAngle)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ParseBul()
|
|||
|
{
|
|||
|
this.m_Bul = Math.tan(this.m_AllAngle * 0.25) * (this.m_Bul < 0 ? -1 : 1)
|
|||
|
}
|
|||
|
|
|||
|
ParsePointFormAngle()
|
|||
|
{
|
|||
|
this.m_StartPoint = this.m_Center.Polar(this.m_StartAngle, this.m_Radius)
|
|||
|
this.m_EndPoint = this.m_Center.Polar(this.m_EndAngle, this.m_Radius)
|
|||
|
}
|
|||
|
|
|||
|
ParseAngleFormPoint()
|
|||
|
{
|
|||
|
this.m_StartAngle = Point2d.OpSubtract(this.StartPoint, this.m_Center).Angle
|
|||
|
this.m_EndAngle = Point2d.OpSubtract(this.EndPoint, this.m_Center).Angle
|
|||
|
}
|
|||
|
|
|||
|
PtInCurve(pt: Point2d): boolean
|
|||
|
{
|
|||
|
let param = this.GetParametersAt(pt)
|
|||
|
return param > -1e-3 && param < 1.0001
|
|||
|
}
|
|||
|
|
|||
|
ClosePointTo(pt: Point2d): Point2d
|
|||
|
{
|
|||
|
return null
|
|||
|
}
|
|||
|
|
|||
|
GetParametersAt(pt: Point2d): number
|
|||
|
{
|
|||
|
let vec = Point2d.OpSubtract(pt, this.m_Center)
|
|||
|
let an = vec.Angle
|
|||
|
this.ParseAllAngle()
|
|||
|
|
|||
|
// 如果以pt为终点,那么所有的角度为
|
|||
|
let ptAllAn = this.ComputeAnlge(an)
|
|||
|
let allAn = this.m_AllAngle
|
|||
|
|
|||
|
// 减去圆弧角度,剩余角度的一半
|
|||
|
let surplusAngleHalf = Math.PI - allAn / 2
|
|||
|
|
|||
|
if (ptAllAn > allAn + surplusAngleHalf)// 返回负数
|
|||
|
return ((ptAllAn - allAn) - (surplusAngleHalf * 2)) / allAn
|
|||
|
else// 返回正数
|
|||
|
return ptAllAn / allAn
|
|||
|
}
|
|||
|
|
|||
|
GetAngleAtParam(param: number)
|
|||
|
{
|
|||
|
return this.clampRad(this.m_StartAngle + param * this.m_AllAngle)
|
|||
|
}
|
|||
|
|
|||
|
private clampRad(an: number)
|
|||
|
{
|
|||
|
an = an % (Math.PI * 2)
|
|||
|
if (an < 0)
|
|||
|
an += Math.PI * 2
|
|||
|
return an
|
|||
|
}
|
|||
|
|
|||
|
/** 凸度. */
|
|||
|
m_Bul: number
|
|||
|
get Bul() { return this.m_Bul }
|
|||
|
set Bul(v: number) { this.m_Bul = v }
|
|||
|
|
|||
|
static New(x0: number, y0: number, x1: number, y1: number, bul: number): Arc2d
|
|||
|
{
|
|||
|
return new Arc2d(new Point2d(x0, y0), new Point2d(x1, y1), bul)
|
|||
|
}
|
|||
|
}
|
|||
|
/** 圆弧 */
|
|||
|
export class Arc2d_new extends Curve2d
|
|||
|
{
|
|||
|
constructor(p1: Point2d, p2: Point2d, bul: number)
|
|||
|
{
|
|||
|
super()
|
|||
|
this.m_StartPoint = p1
|
|||
|
this.m_EndPoint = p2
|
|||
|
|
|||
|
this.m_Bul = bul
|
|||
|
let vec = Point2d.OpSubtract(p2, p1)
|
|||
|
let an = vec.Angle
|
|||
|
let length = vec.Length
|
|||
|
|
|||
|
this.m_Radius = length / Math.sin(2 * Math.atan(bul)) / 2
|
|||
|
this.m_AllAngle = Math.atan(bul) * 4
|
|||
|
let delDis = bul * length / 2
|
|||
|
|
|||
|
let toDis = this.m_Radius - delDis
|
|||
|
|
|||
|
an += Math.PI * 0.5
|
|||
|
|
|||
|
this.m_Center = p1.Mid(p2)
|
|||
|
this.m_Center = this.m_Center.Polar(an, toDis)
|
|||
|
|
|||
|
this.m_StartAngle = Point2d.OpSubtract(this.StartPoint, this.m_Center).Angle
|
|||
|
this.m_EndAngle = Point2d.OpSubtract(this.EndPoint, this.m_Center).Angle
|
|||
|
|
|||
|
if (this.m_Bul < 0)
|
|||
|
this.m_Radius = Math.abs(this.m_Radius)
|
|||
|
}
|
|||
|
|
|||
|
/** 圆心 */
|
|||
|
m_Center: Point2d
|
|||
|
/** 半径 */
|
|||
|
m_Radius: number
|
|||
|
/** 起始弧度 */
|
|||
|
m_StartAngle: number
|
|||
|
/** 结束弧度 */
|
|||
|
m_EndAngle: number
|
|||
|
/** 所有的弧度 */
|
|||
|
m_AllAngle: number
|
|||
|
|
|||
|
IntersectWith(cu: Curve2d, retIns: Point2d[])
|
|||
|
{
|
|||
|
if (cu instanceof Line2d)
|
|||
|
{
|
|||
|
let l = cu as Line2d
|
|||
|
let a = DoubleUtil.Sqr(l.EndPt.m_X - l.StartPt.m_X) + DoubleUtil.Sqr(l.EndPt.m_Y - l.StartPt.m_Y)
|
|||
|
|
|||
|
let b = (2.0) * ((l.EndPt.m_X - l.StartPt.m_X) * (l.StartPt.m_X - this.m_Center.m_X)
|
|||
|
+ (l.EndPt.m_Y - l.StartPt.m_Y) * (l.StartPt.m_Y - this.m_Center.m_Y))
|
|||
|
|
|||
|
let c = DoubleUtil.Sqr(this.m_Center.m_X) + DoubleUtil.Sqr(this.m_Center.m_Y)
|
|||
|
+ DoubleUtil.Sqr(l.StartPt.m_X) + DoubleUtil.Sqr(l.StartPt.m_Y)
|
|||
|
- (2.0) * (this.m_Center.m_X * l.StartPt.m_X + this.m_Center.m_Y * l.StartPt.m_Y) - DoubleUtil.Sqr(this.m_Radius)
|
|||
|
|
|||
|
let det = b * b - (4.0) * a * c
|
|||
|
|
|||
|
if (DoubleUtil.EqualX(det, 0.0, 0.1))
|
|||
|
{
|
|||
|
let delta = -b / ((2.0) * a)
|
|||
|
|
|||
|
let pt = new Point2d(l.StartPt.m_X + delta * (l.EndPt.m_X - l.StartPt.m_X), l.StartPt.m_Y + delta * (l.EndPt.m_Y - l.StartPt.m_Y))
|
|||
|
retIns.push(pt)
|
|||
|
return
|
|||
|
}
|
|||
|
else if (det > (0.0))
|
|||
|
{
|
|||
|
let sqrt_det = Math.sqrt(det)
|
|||
|
let delta = (-b + sqrt_det) / ((2.0) * a)
|
|||
|
let p2 = new Point2d(l.StartPt.m_X + delta * (l.EndPt.m_X - l.StartPt.m_X), l.StartPt.m_Y + delta * (l.EndPt.m_Y - l.StartPt.m_Y))
|
|||
|
|
|||
|
delta = (-b - sqrt_det) / ((2.0) * a)
|
|||
|
let p3 = new Point2d(l.StartPt.m_X + delta * (l.EndPt.m_X - l.StartPt.m_X), l.StartPt.m_Y + delta * (l.EndPt.m_Y - l.StartPt.m_Y))
|
|||
|
|
|||
|
retIns.push(p2)
|
|||
|
retIns.push(p3)
|
|||
|
return
|
|||
|
}
|
|||
|
}
|
|||
|
else if (cu instanceof Arc2d)
|
|||
|
{
|
|||
|
let arc = cu as (Arc2d)
|
|||
|
let dist = arc.m_Center.DistensTo(this.m_Center)
|
|||
|
|
|||
|
if (dist < Math.abs(this.m_Radius - cu.m_Radius) - 1e-3
|
|||
|
|| dist > (this.m_Radius + cu.m_Radius + 1e-3))
|
|||
|
return
|
|||
|
|
|||
|
let dstsqr = dist * dist
|
|||
|
let r1sqr = this.m_Radius * this.m_Radius
|
|||
|
let r2sqr = arc.m_Radius * arc.m_Radius
|
|||
|
|
|||
|
let a = (dstsqr - r2sqr + r1sqr) / (2 * dist)
|
|||
|
let h = Math.sqrt(Math.abs(r1sqr - (a * a)))
|
|||
|
|
|||
|
let ratio_a = a / dist
|
|||
|
let ratio_h = h / dist
|
|||
|
|
|||
|
let dx = arc.m_Center.m_X - this.m_Center.m_X
|
|||
|
let dy = arc.m_Center.m_Y - this.m_Center.m_Y
|
|||
|
|
|||
|
let phix = this.m_Center.m_X + (ratio_a * dx)
|
|||
|
let phiy = this.m_Center.m_Y + (ratio_a * dy)
|
|||
|
|
|||
|
dx = dx * ratio_h
|
|||
|
dy = dy * ratio_h
|
|||
|
|
|||
|
let pt = new Point2d(phix + dy, phiy - dx)
|
|||
|
let p2 = new Point2d(phix - dy, phiy + dx)
|
|||
|
retIns.push(pt)
|
|||
|
retIns.push(p2)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Offset(distens: number): Curve2d
|
|||
|
{
|
|||
|
let rn = new Arc2d(new Point2d(0, 0), new Point2d(0, 0), 0)
|
|||
|
rn.m_Center = this.m_Center
|
|||
|
rn.m_Radius = this.m_Radius
|
|||
|
rn.m_StartAngle = this.m_StartAngle
|
|||
|
rn.m_EndAngle = this.m_EndAngle
|
|||
|
if (this.m_Bul > 0)
|
|||
|
rn.m_Radius += distens
|
|||
|
else
|
|||
|
rn.m_Radius -= distens
|
|||
|
rn.Bul = this.m_Bul
|
|||
|
rn.ParsePointFormAngle()
|
|||
|
return rn
|
|||
|
}
|
|||
|
|
|||
|
Parse()
|
|||
|
{
|
|||
|
// 解析角度
|
|||
|
this.ParseAngleFormPoint()
|
|||
|
this.ParseAllAngle()
|
|||
|
this.ParseBul()
|
|||
|
}
|
|||
|
|
|||
|
ParseAllAngle()
|
|||
|
{
|
|||
|
this.m_AllAngle = this.ComputeAnlge(this.m_EndAngle)
|
|||
|
}
|
|||
|
|
|||
|
ComputeAnlge(endAngle: number)
|
|||
|
{
|
|||
|
// 顺时针
|
|||
|
if (this.m_Bul < 0)
|
|||
|
{
|
|||
|
if (this.m_StartAngle > endAngle)
|
|||
|
return this.m_StartAngle - endAngle
|
|||
|
else // 越过0点绘制圆弧
|
|||
|
return (Math.PI * 2) - (endAngle - this.m_StartAngle)
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (endAngle > this.m_StartAngle)
|
|||
|
return endAngle - this.m_StartAngle
|
|||
|
else
|
|||
|
return (Math.PI * 2) - (this.m_StartAngle - endAngle)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ParseBul()
|
|||
|
{
|
|||
|
this.m_Bul = Math.tan(this.m_AllAngle * 0.25) * (this.m_Bul < 0 ? -1 : 1)
|
|||
|
}
|
|||
|
|
|||
|
ParsePointFormAngle()
|
|||
|
{
|
|||
|
this.m_StartPoint = this.m_Center.Polar(this.m_StartAngle, this.m_Radius)
|
|||
|
this.m_EndPoint = this.m_Center.Polar(this.m_EndAngle, this.m_Radius)
|
|||
|
}
|
|||
|
|
|||
|
ParseAngleFormPoint()
|
|||
|
{
|
|||
|
this.m_StartAngle = Point2d.OpSubtract(this.StartPoint, this.m_Center).Angle
|
|||
|
this.m_EndAngle = Point2d.OpSubtract(this.EndPoint, this.m_Center).Angle
|
|||
|
}
|
|||
|
|
|||
|
PtInCurve(pt: Point2d): boolean
|
|||
|
{
|
|||
|
let param = this.GetParametersAt(pt)
|
|||
|
return param > -1e-3 && param < 1.0001
|
|||
|
}
|
|||
|
|
|||
|
ClosePointTo(pt: Point2d): Point2d
|
|||
|
{
|
|||
|
return null
|
|||
|
}
|
|||
|
|
|||
|
GetParametersAt(pt: Point2d): number
|
|||
|
{
|
|||
|
let vec = Point2d.OpSubtract(pt, this.m_Center)
|
|||
|
let an = vec.Angle
|
|||
|
this.ParseAllAngle()
|
|||
|
|
|||
|
// 如果以pt为终点,那么所有的角度为
|
|||
|
let ptAllAn = this.ComputeAnlge(an)
|
|||
|
let allAn = this.m_AllAngle
|
|||
|
|
|||
|
// 减去圆弧角度,剩余角度的一半
|
|||
|
let surplusAngleHalf = Math.PI - allAn / 2
|
|||
|
|
|||
|
if (ptAllAn > allAn + surplusAngleHalf)// 返回负数
|
|||
|
return ((ptAllAn - allAn) - (surplusAngleHalf * 2)) / allAn
|
|||
|
else// 返回正数
|
|||
|
return ptAllAn / allAn
|
|||
|
}
|
|||
|
|
|||
|
GetAngleAtParam(param: number)
|
|||
|
{
|
|||
|
return this.clampRad(this.m_StartAngle + param * this.m_AllAngle)
|
|||
|
}
|
|||
|
|
|||
|
private clampRad(an: number)
|
|||
|
{
|
|||
|
an = an % (Math.PI * 2)
|
|||
|
if (an < 0)
|
|||
|
an += Math.PI * 2
|
|||
|
return an
|
|||
|
}
|
|||
|
|
|||
|
/** 凸度. */
|
|||
|
m_Bul: number
|
|||
|
get Bul() { return this.m_Bul }
|
|||
|
set Bul(v: number) { this.m_Bul = v }
|
|||
|
|
|||
|
static New(x0: number, y0: number, x1: number, y1: number, bul: number): Arc2d
|
|||
|
{
|
|||
|
return new Arc2d(new Point2d(x0, y0), new Point2d(x1, y1), bul)
|
|||
|
}
|
|||
|
}
|
|||
|
function EntityEncode(c: Curve2d)
|
|||
|
{
|
|||
|
if (c instanceof Line2d)
|
|||
|
return 1
|
|||
|
else return 2
|
|||
|
}
|
|||
|
function EntityEncode2(c1: Curve2d, c2: Curve2d)
|
|||
|
{
|
|||
|
return EntityEncode(c1) & EntityEncode(c2)
|
|||
|
}
|
|||
|
|
|||
|
/** CAD 运算库 */
|
|||
|
export class Utils
|
|||
|
{
|
|||
|
static Intersec(e1: Curve2d, e2: Curve2d, oldE1: Curve2d): Point2d
|
|||
|
{
|
|||
|
if (e1.EndPoint.DistensTo(e2.StartPoint) < 1e-2)
|
|||
|
{
|
|||
|
return e1.EndPoint
|
|||
|
}
|
|||
|
let ptsIns: Point2d[] = []
|
|||
|
e1.IntersectWith(e2, ptsIns)
|
|||
|
if (ptsIns.length == 1)
|
|||
|
{
|
|||
|
return ptsIns[0]
|
|||
|
}
|
|||
|
else if (ptsIns.length == 2)
|
|||
|
{
|
|||
|
// 求一个最近的点.
|
|||
|
let pt = oldE1.EndPoint
|
|||
|
let d1 = pt.DistensTo(ptsIns[0])
|
|||
|
let d2 = pt.DistensTo(ptsIns[1])
|
|||
|
return d1 < d2 ? ptsIns[0] : ptsIns[1]
|
|||
|
}
|
|||
|
else // 0点
|
|||
|
{
|
|||
|
return null
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/** 曲线偏移 */
|
|||
|
|
|||
|
static offsetPoints(points, offsetDistens: number): any[]
|
|||
|
{
|
|||
|
let ens: Curve2d[] = []
|
|||
|
for (let i = 0; i < points.length; i++)
|
|||
|
{
|
|||
|
let j = i + 1
|
|||
|
if (j == points.length)
|
|||
|
j = 0
|
|||
|
|
|||
|
let line = new Line2d(new Point2d(points[i].x, points[i].y), new Point2d(points[j].x, points[j].y))
|
|||
|
if (line.m_Length == 0)
|
|||
|
continue
|
|||
|
ens.push(line)
|
|||
|
}
|
|||
|
|
|||
|
let ens2 = Utils.OffsetCurveList(ens, offsetDistens)
|
|||
|
|
|||
|
let newPs = []
|
|||
|
for (let c of ens2)
|
|||
|
{
|
|||
|
newPs.push({ x: c.StartPoint.m_X, y: c.StartPoint.m_Y })
|
|||
|
}
|
|||
|
return newPs
|
|||
|
}
|
|||
|
|
|||
|
// 1.曲线外偏移.
|
|||
|
//* 2.曲线尝试首尾相连
|
|||
|
//* ->如果两条不相连,导致曲线连接失败,将添加圆弧过度
|
|||
|
//*
|
|||
|
//* 2017-11-17对曲线相连算法进行修改.
|
|||
|
//* 现在会先求出连接点,然后在重新进行曲线连接,避免连接点出错. 参见#118
|
|||
|
static OffsetCurveList(ens: Curve2d[], offsetDistens: number): Curve2d[]
|
|||
|
{
|
|||
|
// 只处理偏移的曲线
|
|||
|
let offEns: Curve2d[] = []
|
|||
|
|
|||
|
ens = ens.filter(e => e.StartPoint.DistensTo(e.EndPoint) > 0.05)
|
|||
|
for (const item of ens)
|
|||
|
{
|
|||
|
offEns.push(item.Offset(offsetDistens))
|
|||
|
}
|
|||
|
// 处理偏移 并且对交点进行处理
|
|||
|
let offEns2: Curve2d[] = []
|
|||
|
let linkPts: Point2d[] = []
|
|||
|
|
|||
|
// 计算链接点,如果有必要会新增圆弧
|
|||
|
for (let i = 0; i < offEns.length; i++)
|
|||
|
{
|
|||
|
let index2 = i + 1 == offEns.length ? 0 : i + 1
|
|||
|
|
|||
|
let e1 = offEns[i]
|
|||
|
let e2 = offEns[index2]
|
|||
|
|
|||
|
offEns2.push(offEns[i])
|
|||
|
|
|||
|
let iPts: Point2d[] = []
|
|||
|
e1.IntersectWith(e2, iPts)
|
|||
|
let tPts = iPts.filter(p => e1.PtOnCurve(p) && e2.PtOnCurve(p))
|
|||
|
|
|||
|
let code = EntityEncode2(e1, e2)
|
|||
|
if (code === 1)
|
|||
|
{
|
|||
|
if (tPts.length > 0)
|
|||
|
linkPts.push(tPts[0])// 直接连接
|
|||
|
else
|
|||
|
{
|
|||
|
let refP = ens[i].EndPoint
|
|||
|
let distSq = iPts[0].DistensTo(refP)
|
|||
|
if (distSq > offsetDistens ** 2 * 2.1) // 补圆弧
|
|||
|
{
|
|||
|
let arc = new Arc2d(e1.EndPoint, e2.StartPoint, Math.sign(offsetDistens))
|
|||
|
arc.m_Center = ens[i].EndPoint
|
|||
|
arc.m_Radius = offsetDistens// 半径
|
|||
|
|
|||
|
linkPts.push(e1.EndPoint)
|
|||
|
linkPts.push(e2.StartPoint)
|
|||
|
offEns2.push(arc)// 添加圆弧.
|
|||
|
}
|
|||
|
else
|
|||
|
linkPts.push(iPts[0])
|
|||
|
}
|
|||
|
}
|
|||
|
else if (
|
|||
|
code === 2
|
|||
|
&& (
|
|||
|
equalp((<Arc2d>e1).m_Center, (<Arc2d>e2).m_Center, 0.1) // 都是圆弧,且同心圆(由于精度丢失,这里我们给0.01的容差)
|
|||
|
|| equalp(e1.EndPoint, e2.StartPoint, 0.1))
|
|||
|
)
|
|||
|
linkPts.push(e1.EndPoint)
|
|||
|
else
|
|||
|
{
|
|||
|
function SelectNearP(pts: Point2d[], refPt: Point2d): Point2d
|
|||
|
{
|
|||
|
if (pts.length > 1)
|
|||
|
{
|
|||
|
let dist1 = refPt.DistensTo(pts[0])
|
|||
|
let dist2 = refPt.DistensTo(pts[1])
|
|||
|
return dist1 <= dist2 ? pts[0] : pts[1]
|
|||
|
}
|
|||
|
return pts[0]
|
|||
|
}
|
|||
|
|
|||
|
let refP = ens[i].EndPoint
|
|||
|
if (tPts.length > 0)
|
|||
|
linkPts.push(SelectNearP(iPts, refP))// 直接连接
|
|||
|
else
|
|||
|
{
|
|||
|
let arc = new Arc2d(e1.EndPoint, e2.StartPoint, Math.sign(offsetDistens))
|
|||
|
arc.m_Center = ens[i].EndPoint
|
|||
|
arc.m_Radius = offsetDistens// 半径
|
|||
|
|
|||
|
linkPts.push(e1.EndPoint)
|
|||
|
linkPts.push(e2.StartPoint)
|
|||
|
offEns2.push(arc)// 添加圆弧.
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 更新链接点位置
|
|||
|
for (let i = 0; i < offEns2.length; i++)
|
|||
|
{
|
|||
|
offEns2[i].EndPoint = linkPts[i]
|
|||
|
let nextIndex = i == offEns2.length - 1 ? 0 : i + 1
|
|||
|
offEns2[nextIndex].StartPoint = linkPts[i]
|
|||
|
}
|
|||
|
|
|||
|
// 测试数据
|
|||
|
// TestPolyline([ens, offEns2])
|
|||
|
|
|||
|
return offEns2
|
|||
|
}
|
|||
|
|
|||
|
/** //自交曲线优化 去除自交部分. */
|
|||
|
static RemoveSelfIntersect(cus: Curve2d[]): Curve2d[]
|
|||
|
{
|
|||
|
let res = new Array<Curve2d>()
|
|||
|
let cout = cus.length
|
|||
|
for (let i = 0; i < cout; i++)
|
|||
|
{
|
|||
|
let cu = cus[i]
|
|||
|
res.push(cu)
|
|||
|
for (let j = cout - 2; j > i + 1; j--)
|
|||
|
{
|
|||
|
let cu2 = cus[j]
|
|||
|
|
|||
|
let pts = new Array<Point2d>()
|
|||
|
cu.IntersectWith(cu2, pts)
|
|||
|
|
|||
|
//
|
|||
|
if (pts.length == 0)
|
|||
|
{
|
|||
|
continue
|
|||
|
}
|
|||
|
if (pts.length == 2)
|
|||
|
{
|
|||
|
if (cu instanceof Line2d)
|
|||
|
{
|
|||
|
if (cu.GetParametersAt(pts[0]) > cu.GetParametersAt(pts[1]))
|
|||
|
{
|
|||
|
pts[0] = pts[1]
|
|||
|
}
|
|||
|
}
|
|||
|
else if (cu instanceof Arc2d)
|
|||
|
{
|
|||
|
// 使用上一条线. 因为我们保证它和上一条线是有一个交点的
|
|||
|
|
|||
|
let arc = cu as Arc2d
|
|||
|
|
|||
|
// last cu
|
|||
|
let lastIndex = i - 1
|
|||
|
if (i == 0)
|
|||
|
lastIndex = cout - 1
|
|||
|
|
|||
|
let lastCu = cus[lastIndex]
|
|||
|
|
|||
|
let insPts = new Array<Point2d>()
|
|||
|
lastCu.IntersectWith(cu, insPts)
|
|||
|
|
|||
|
for (let insP of insPts)
|
|||
|
{
|
|||
|
let p1 = arc.GetParametersAt(insP)
|
|||
|
let p2 = arc.GetParametersAt(insP)
|
|||
|
// 从起点圆弧开始
|
|||
|
if (insP.DistensTo(cu.StartPoint) < 1e-3)
|
|||
|
{
|
|||
|
if (p1 > p2)
|
|||
|
{
|
|||
|
pts[0] = pts[1]
|
|||
|
}
|
|||
|
break
|
|||
|
}
|
|||
|
// 从终点圆弧开始.
|
|||
|
else if (insP.DistensTo(cu.EndPoint) < 1e-3)
|
|||
|
{
|
|||
|
if (p1 < p2)
|
|||
|
{
|
|||
|
pts[0] = pts[1]
|
|||
|
}
|
|||
|
break
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (cu.PtInCurve(pts[0]) && cu2.PtInCurve(pts[0]))
|
|||
|
{
|
|||
|
Utils.changeP(cus, cu, i, -1, pts[0])
|
|||
|
Utils.changeP(cus, cu, j, 1, pts[0])
|
|||
|
|
|||
|
i = j - 1
|
|||
|
break
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Utils.RemoveZeroCurve(res)
|
|||
|
return res
|
|||
|
}
|
|||
|
|
|||
|
static changeP(cus: Curve2d[], cu: Curve2d, index: number, next: number, _pt: Point2d)
|
|||
|
{
|
|||
|
let cout = cus.length
|
|||
|
let lastIndex = index + next
|
|||
|
|
|||
|
let _cu = cus[index]
|
|||
|
if (lastIndex == -1)
|
|||
|
lastIndex = cout - 1
|
|||
|
else if (lastIndex == cout)
|
|||
|
lastIndex = 0
|
|||
|
|
|||
|
let lastCu = cus[lastIndex]
|
|||
|
|
|||
|
let insPts = new Array<Point2d>()
|
|||
|
lastCu.IntersectWith(_cu, insPts)
|
|||
|
|
|||
|
for (const insP of insPts)
|
|||
|
{
|
|||
|
if (insP.DistensTo(_cu.StartPoint) < 1e-3)
|
|||
|
{
|
|||
|
_cu.EndPoint = _pt
|
|||
|
break
|
|||
|
}
|
|||
|
else if (insP.DistensTo(_cu.EndPoint) < 1e-3)
|
|||
|
{
|
|||
|
_cu.StartPoint = _pt
|
|||
|
break
|
|||
|
}
|
|||
|
}
|
|||
|
if (cu instanceof Arc2d)
|
|||
|
{
|
|||
|
cu.Parse()
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static RemoveZeroCurve(cus: Curve2d[])
|
|||
|
{
|
|||
|
// remove zero length curve
|
|||
|
/*
|
|||
|
cus.RemoveAll((Curve2d o) =>
|
|||
|
{
|
|||
|
if (o is Line2d)
|
|||
|
{
|
|||
|
return ((Line2d)o).m_Length < 1e-3;
|
|||
|
}
|
|||
|
else if (o is Arc2d)
|
|||
|
{
|
|||
|
return ((Arc2d)o).m_AllAngle < 1e-3;
|
|||
|
}
|
|||
|
return false;
|
|||
|
});
|
|||
|
*/
|
|||
|
|
|||
|
let length = cus.length
|
|||
|
let isZero = false
|
|||
|
for (let i = length - 1; i >= 0; i--)
|
|||
|
{
|
|||
|
let o = cus[i]
|
|||
|
|
|||
|
isZero = false
|
|||
|
if (o instanceof Line2d)
|
|||
|
{
|
|||
|
let line = o as Line2d
|
|||
|
isZero = line.m_Length < 1e-3
|
|||
|
}
|
|||
|
else if (o instanceof Arc2d)
|
|||
|
{
|
|||
|
let arc = o as Arc2d
|
|||
|
isZero = arc.m_AllAngle < 1e-3
|
|||
|
}
|
|||
|
|
|||
|
if (isZero)
|
|||
|
{
|
|||
|
cus.splice(i, 1)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/** 曲线倒角 */
|
|||
|
static FilletCurveList(culist: Curve2d[], offsetDistens: number): Curve2d[]
|
|||
|
{
|
|||
|
/*
|
|||
|
let rn = new List<Curve2d>();
|
|||
|
let len = cuList.Count;
|
|||
|
for (int i = 0; i < len; i++)
|
|||
|
{
|
|||
|
let en = cuList[i];
|
|||
|
let index =i==len-1 ? 0 : i + 1;
|
|||
|
rn.Add(en);
|
|||
|
if (en is Line2d && cuList[index] is Line2d)
|
|||
|
{
|
|||
|
let l1 = en as Line2d;
|
|||
|
let l2 = cuList[index] as Line2d;
|
|||
|
if (l1.m_Length < offsetDistens || l2.m_Length < offsetDistens
|
|||
|
|| (l1.EndPoint-l1.StartPoint).CrossProduct(l2.EndPoint-l2.StartPoint) <1e-3
|
|||
|
)
|
|||
|
{
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
let tempEn1 = en.Offset(-offsetDistens) as Line2d;
|
|||
|
let tempEn2 = cuList[index].Offset(-offsetDistens)as Line2d;
|
|||
|
|
|||
|
let pts = new List<Point2d>();
|
|||
|
tempEn1.IntersectWith(tempEn2, pts);
|
|||
|
if (pts.Count>0 && tempEn1.PtInCurve(pts.First()))
|
|||
|
{
|
|||
|
let pt = pts.First();
|
|||
|
//求交点.
|
|||
|
en.EndPoint= en.ClosePointTo(pt);
|
|||
|
let en2 = cuList[index];
|
|||
|
en2.StartPoint = en2.ClosePointTo(pt);
|
|||
|
|
|||
|
let arc2d = new Arc2d(en.EndPoint, en2.StartPoint, 1);//凸圆弧
|
|||
|
arc2d.m_Center = pt;
|
|||
|
arc2d.m_Radius = pt.DistensTo(en.EndPoint);
|
|||
|
arc2d.Parse();//解析凸度 角度
|
|||
|
rn.Add(arc2d);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return rn;
|
|||
|
*/
|
|||
|
|
|||
|
let rn = new Array<Curve2d>()
|
|||
|
let len = culist.length
|
|||
|
for (let i = 0; i < len; i++)
|
|||
|
{
|
|||
|
let en = culist[i]
|
|||
|
let index = i == len - 1 ? 0 : i + 1
|
|||
|
rn.push(en)
|
|||
|
|
|||
|
if (en instanceof Line2d && culist[index] instanceof Line2d)
|
|||
|
{
|
|||
|
let l1 = en as Line2d
|
|||
|
let l2 = culist[index] as Line2d
|
|||
|
if (l1.m_Length < offsetDistens || l2.m_Length < offsetDistens
|
|||
|
|| (Point2d.OpSubtract(l1.EndPoint, l1.StartPoint)).CrossProduct(Point2d.OpSubtract(l2.EndPoint, l2.StartPoint)) < 1e-3
|
|||
|
)
|
|||
|
{
|
|||
|
continue
|
|||
|
}
|
|||
|
|
|||
|
let tempEn1 = en.Offset(-offsetDistens) as Line2d
|
|||
|
let tempEn2 = culist[index].Offset(-offsetDistens) as Line2d
|
|||
|
|
|||
|
let pts = new Array<Point2d>()
|
|||
|
tempEn1.IntersectWith(tempEn2, pts)
|
|||
|
if (pts.length > 0 && tempEn1.PtInCurve(pts[0]))
|
|||
|
{
|
|||
|
let pt = pts[0]
|
|||
|
// 求交点.
|
|||
|
en.EndPoint = en.ClosePointTo(pt)
|
|||
|
let en2 = culist[index]
|
|||
|
en2.StartPoint = en2.ClosePointTo(pt)
|
|||
|
|
|||
|
let arc2d = new Arc2d(en.EndPoint, en2.StartPoint, 1)// 凸圆弧
|
|||
|
arc2d.m_Center = pt
|
|||
|
arc2d.m_Radius = pt.DistensTo(en.EndPoint)
|
|||
|
arc2d.Parse()// 解析凸度 角度
|
|||
|
rn.push(arc2d)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return rn
|
|||
|
}
|
|||
|
|
|||
|
/** 圆弧细分 如果大于90度则分割 */
|
|||
|
static SplitCurveListArc(cuList: Curve2d[]): Curve2d[]
|
|||
|
{
|
|||
|
/* C# 代码
|
|||
|
let rnList = new List<Curve2d>();//返回的曲线表
|
|||
|
foreach (let cu in cuList)
|
|||
|
{
|
|||
|
if (cu is Arc2d)
|
|||
|
{
|
|||
|
let arc = cu as Arc2d;
|
|||
|
arc.Parse();//解析圆弧的凸度 角度
|
|||
|
if (arc.m_AllAngle > Math.PI * 0.5)
|
|||
|
{
|
|||
|
int cout =(int)( arc.m_AllAngle / (Math.PI * 0.5)) + 1;
|
|||
|
let an = arc.m_AllAngle / cout;
|
|||
|
let startAn = arc.m_StartAngle;
|
|||
|
for (int i = 0; i < cout; i++)
|
|||
|
{
|
|||
|
let arcNew = new Arc2d(arc.StartPoint, arc.EndPoint, 0);
|
|||
|
arcNew.m_Radius = arc.m_Radius;
|
|||
|
arcNew.m_Center = arc.m_Center;
|
|||
|
arcNew.m_StartAngle = startAn;
|
|||
|
arcNew.m_EndAngle = arcNew.m_StartAngle + an;
|
|||
|
startAn = arcNew.m_EndAngle;
|
|||
|
rnList.Add(arcNew);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
rnList.Add(cu);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
rnList.Add(cu);
|
|||
|
}
|
|||
|
}
|
|||
|
return rnList;
|
|||
|
|
|||
|
*/
|
|||
|
let rnList = new Array<Curve2d>()// 返回的曲线表
|
|||
|
for (let cu of cuList)
|
|||
|
{
|
|||
|
if (cu instanceof Arc2d)
|
|||
|
{
|
|||
|
let arc = cu as Arc2d
|
|||
|
arc.Parse()// 解析圆弧的凸度 角度
|
|||
|
if (arc.m_AllAngle > Math.PI * 0.5)
|
|||
|
{
|
|||
|
let cout = arc.m_AllAngle / (Math.PI * 0.5) + 1
|
|||
|
let an = arc.m_AllAngle / cout
|
|||
|
let startAn = arc.m_StartAngle
|
|||
|
for (let i = 0; i < cout; i++)
|
|||
|
{
|
|||
|
let arcNew = new Arc2d(arc.StartPoint, arc.EndPoint, 0)
|
|||
|
arcNew.m_Radius = arc.m_Radius
|
|||
|
arcNew.m_Center = arc.m_Center
|
|||
|
arcNew.m_StartAngle = startAn
|
|||
|
arcNew.m_EndAngle = arcNew.m_StartAngle + an
|
|||
|
startAn = arcNew.m_EndAngle
|
|||
|
rnList.push(arcNew)
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
rnList.push(cu)
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
rnList.push(cu)
|
|||
|
}
|
|||
|
}
|
|||
|
return rnList
|
|||
|
}
|
|||
|
|
|||
|
// 三点面积
|
|||
|
static Det(p1: Point2d, p2: Point2d, p3: Point2d): number
|
|||
|
{
|
|||
|
return this.Det2(p1.AsVector(), p2.AsVector(), p3.AsVector())
|
|||
|
}
|
|||
|
|
|||
|
// 三点面积
|
|||
|
static Det2(p1: Vector2d, p2: Vector2d, p3: Vector2d): number
|
|||
|
{
|
|||
|
return p1.CrossProduct(p2) + p2.CrossProduct(p3) + p3.CrossProduct(p1)
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
static AngleForm3Pt(pSrc: Point2d, p1: Point2d, p2: Point2d): number
|
|||
|
{
|
|||
|
/*
|
|||
|
double angle = 0.0f; // 夹角
|
|||
|
|
|||
|
let vec1 = p1 - pSrc;
|
|||
|
let vec2 = p2 - pSrc;
|
|||
|
|
|||
|
double productValue = vec1 * vec2;
|
|||
|
double cosValue = productValue / (vec1.Length * vec2.Length); // 余弦公式
|
|||
|
|
|||
|
// acos的输入参数范围必须在[-1, 1]之间,否则会"domain error"
|
|||
|
// 对输入参数作校验和处理
|
|||
|
if (cosValue < -1 && cosValue > -2)
|
|||
|
cosValue = -1;
|
|||
|
else if (cosValue > 1 && cosValue < 2)
|
|||
|
cosValue = 1;
|
|||
|
|
|||
|
// acos返回的是弧度值,转换为角度值
|
|||
|
angle = Math.Acos(cosValue) * 180 / Math.PI;
|
|||
|
return angle;
|
|||
|
*/
|
|||
|
let angle = 0.0 // 夹角
|
|||
|
|
|||
|
let vec1 = Point2d.OpSubtract(p1, pSrc)
|
|||
|
let vec2 = Point2d.OpSubtract(p2, pSrc)
|
|||
|
|
|||
|
let productValue = Vector2d.OpMultiplyValue(vec1, vec2)
|
|||
|
let cosValue = productValue / (vec1.Length * vec2.Length) // 余弦公式
|
|||
|
|
|||
|
// acos的输入参数范围必须在[-1, 1]之间,否则会"domain error"
|
|||
|
// 对输入参数作校验和处理
|
|||
|
if (cosValue < -1 && cosValue > -2)
|
|||
|
cosValue = -1
|
|||
|
else if (cosValue > 1 && cosValue < 2)
|
|||
|
cosValue = 1
|
|||
|
|
|||
|
// acos返回的是弧度值,转换为角度值
|
|||
|
angle = Math.acos(cosValue) * 180 / Math.PI
|
|||
|
return angle
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
export class DoubleUtil
|
|||
|
{
|
|||
|
static EqualX(v1: number, v2: number, fuzz: number): boolean
|
|||
|
{
|
|||
|
return (Math.abs(v1 - v2) < fuzz)
|
|||
|
}
|
|||
|
|
|||
|
static Sqr(v: number): number
|
|||
|
{
|
|||
|
return v * v
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
export class CADExt
|
|||
|
{
|
|||
|
static GetX(arc: Curve2d): number
|
|||
|
{
|
|||
|
return Math.min(arc.StartPoint.m_X, arc.EndPoint.m_X)
|
|||
|
}
|
|||
|
|
|||
|
static GetY(arc: Curve2d): number
|
|||
|
{
|
|||
|
return Math.min(arc.StartPoint.m_Y, arc.EndPoint.m_Y)
|
|||
|
}
|
|||
|
|
|||
|
static GetWidth(arc: Curve2d): number
|
|||
|
{
|
|||
|
return Math.abs(arc.StartPoint.m_X - arc.EndPoint.m_X)
|
|||
|
}
|
|||
|
|
|||
|
static GetHeight(arc: Curve2d): number
|
|||
|
{
|
|||
|
return Math.abs(arc.StartPoint.m_Y - arc.EndPoint.m_Y)
|
|||
|
}
|
|||
|
|
|||
|
static GetRadius(p1: Point2d, p2: Point2d, bul: number): number
|
|||
|
{
|
|||
|
// let arc = new Arc2d(p1, p2, bul);
|
|||
|
// return arc.m_Radius;
|
|||
|
// this.m_Radius = length / Math.sin(2 * Math.atan(bul)) / 2;
|
|||
|
return CADExt.getR(p1.m_X, p1.m_Y, p2.m_X, p2.m_Y, bul)
|
|||
|
}
|
|||
|
|
|||
|
static getR(x1: number, y1: number, x2: number, y2: number, bul: number): number
|
|||
|
{
|
|||
|
let length = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2))
|
|||
|
return length / Math.sin(2 * Math.atan(bul)) / 2
|
|||
|
}
|
|||
|
|
|||
|
/** 圆弧分割成count段 */
|
|||
|
static SplitArc(arc: Arc2d, count: number): Arc2d[]
|
|||
|
{
|
|||
|
let list: Arc2d[]
|
|||
|
list = []
|
|||
|
|
|||
|
let an = arc.m_AllAngle / count
|
|||
|
let an_0 = arc.m_StartAngle
|
|||
|
for (let i = 0; i < count; i++)
|
|||
|
{
|
|||
|
let arcNew = new Arc2d(arc.StartPoint, arc.EndPoint, 0)
|
|||
|
arcNew.m_Radius = arc.m_Radius
|
|||
|
arcNew.m_Center = arc.m_Center
|
|||
|
arcNew.m_StartAngle = an_0
|
|||
|
arcNew.m_EndAngle = arcNew.m_StartAngle + an
|
|||
|
an_0 = arcNew.m_EndAngle
|
|||
|
arcNew.ParsePointFormAngle()
|
|||
|
|
|||
|
list.push(arcNew)
|
|||
|
}
|
|||
|
return list
|
|||
|
}
|
|||
|
|
|||
|
static SplitArcByCell(ar: Arc2d, cellWidth: number): any[]
|
|||
|
{
|
|||
|
// 弧长
|
|||
|
let fullLenth = Math.abs(ar.m_Radius * (ar.m_EndAngle - ar.m_StartAngle))
|
|||
|
let count = fullLenth / cellWidth
|
|||
|
if (count < 2)
|
|||
|
count = 2
|
|||
|
let childs = CADExt.SplitArc(ar, count)
|
|||
|
let pts = []
|
|||
|
for (let c of childs)
|
|||
|
{
|
|||
|
pts.push({ x: c.StartPoint.m_X, y: c.StartPoint.m_Y })
|
|||
|
}
|
|||
|
pts.push({ x: ar.EndPoint.m_X, y: ar.EndPoint.m_Y })
|
|||
|
return pts
|
|||
|
}
|
|||
|
|
|||
|
/** 根据两点,深的弧度 中间的n个点 */
|
|||
|
static getCurvePoints(x1: number, y1: number, x2: number, y2: number, d: number, num: number): any
|
|||
|
{
|
|||
|
// atan(h/(L/2)) * 4 h:
|
|||
|
let dis = 0.5 * Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2))
|
|||
|
let mul = d / dis
|
|||
|
let arc = new Arc2d(new Point2d(x1, y1), new Point2d(x2, y2), mul)
|
|||
|
|
|||
|
let arc_list = CADExt.SplitArc(arc, num - 1)
|
|||
|
let points = []
|
|||
|
for (let li of arc_list)
|
|||
|
{
|
|||
|
points.push({ x: li.StartPoint.m_X, y: li.StartPoint.m_Y })
|
|||
|
}
|
|||
|
points.push({ x: x2, y: y2 })
|
|||
|
return points
|
|||
|
}
|
|||
|
|
|||
|
/** 求弧长 */
|
|||
|
static getLength(arc: Arc2d): number
|
|||
|
{
|
|||
|
return arc.m_Radius * Math.abs(arc.m_AllAngle)
|
|||
|
}
|
|||
|
|
|||
|
/** 按固定线长分割圆弧 */
|
|||
|
static getPointsFromCurve(x1: number, y1: number, x2: number, y2: number, bul: number, dis: number)
|
|||
|
{
|
|||
|
let arc = new Arc2d(new Point2d(x1, y1), new Point2d(x2, y2), bul)
|
|||
|
let length = this.getLength(arc)
|
|||
|
let count = Math.max(4, Math.ceil(length / dis))
|
|||
|
let arc_list = CADExt.SplitArc(arc, count)
|
|||
|
let points = []
|
|||
|
for (let li of arc_list)
|
|||
|
{
|
|||
|
points.push({ x: li.StartPoint.m_X, y: li.StartPoint.m_Y })
|
|||
|
}
|
|||
|
points.push({ x: x2, y: y2 })
|
|||
|
return points
|
|||
|
}
|
|||
|
|
|||
|
/** 返回弧形中心点 (不是圆心点) */
|
|||
|
static getCenterPoint(arc: Arc2d): Point2d
|
|||
|
{
|
|||
|
let arcNew = new Arc2d(arc.StartPoint, arc.EndPoint, 0)
|
|||
|
arcNew.m_Radius = arc.m_Radius
|
|||
|
arcNew.m_Center = arc.m_Center
|
|||
|
arcNew.m_StartAngle = arc.m_StartAngle
|
|||
|
arcNew.m_EndAngle = arc.m_StartAngle + arc.m_AllAngle / 2
|
|||
|
arcNew.ParsePointFormAngle()
|
|||
|
return arcNew.EndPoint
|
|||
|
}
|
|||
|
|
|||
|
/** 获得第3点到前2点的距离差 */
|
|||
|
static getDisOff(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): number
|
|||
|
{
|
|||
|
let dis31 = Math.sqrt((x3 - x1) * (x3 - x1) + (y3 - y1) * (y3 - y1))
|
|||
|
let dis32 = Math.sqrt((x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2))
|
|||
|
let dis12 = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2))
|
|||
|
return dis31 + dis32 - dis12
|
|||
|
}
|
|||
|
}
|
|||
|
function TestPolyline(offEnsS: Curve2d[][])
|
|||
|
{
|
|||
|
let str = `[${offEnsS.length}`
|
|||
|
for (let i = 0; i < offEnsS.length; i++)
|
|||
|
{
|
|||
|
let offEns = offEnsS[i]
|
|||
|
let linedString = `${offEns.length},`
|
|||
|
for (let cu of offEns)
|
|||
|
{
|
|||
|
let bul = (cu instanceof Arc2d) ? cu.m_Bul : 0
|
|||
|
linedString += `[${cu.StartPoint.m_X},${cu.StartPoint.m_Y}],${bul},`
|
|||
|
}
|
|||
|
str += `,"Polyline",8,2,116,false,1,${7 + i % 2},0,[1,0,0,0,0,1,0,0,0,0,1,0,${Math.floor(i / 2) * 1000},0,0,1],0,0,true,[1,0,0,0,0,1,0,0,0,0,1,0,3000,0,0,1],0,2,${linedString}true`
|
|||
|
}
|
|||
|
str += ']'
|
|||
|
console.log(str)
|
|||
|
copyTextToClipboard(str)
|
|||
|
}
|
|||
|
|
|||
|
let DebugCurves: (Curve2d[])[] = []
|
|||
|
export function CADDebugInit()
|
|||
|
{
|
|||
|
DebugCurves = []
|
|||
|
}
|
|||
|
|
|||
|
export function CADCopyPolylines()
|
|||
|
{
|
|||
|
TestPolyline(DebugCurves)
|
|||
|
DebugCurves = []
|
|||
|
}
|
|||
|
|
|||
|
function fallbackCopyTextToClipboard(text: string)
|
|||
|
{
|
|||
|
let textArea = document.createElement('textarea')
|
|||
|
textArea.value = text
|
|||
|
document.body.appendChild(textArea)
|
|||
|
textArea.focus()
|
|||
|
textArea.select()
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
let successful = document.execCommand('copy')
|
|||
|
} catch (err)
|
|||
|
{
|
|||
|
}
|
|||
|
document.body.removeChild(textArea)
|
|||
|
}
|
|||
|
export async function copyTextToClipboard(text: string)
|
|||
|
{
|
|||
|
if (!navigator.clipboard)
|
|||
|
{
|
|||
|
fallbackCopyTextToClipboard(text)
|
|||
|
return
|
|||
|
}
|
|||
|
return await navigator.clipboard.writeText(text)
|
|||
|
}
|
|||
|
|
|||
|
// ref: https://stackoverflow.com/questions/400212/how-do-i-copy-to-the-clipboard-in-javascript
|
|||
|
|
|||
|
/**
|
|||
|
* 读取剪切板的字符串
|
|||
|
*/
|
|||
|
export async function readClipboardText()
|
|||
|
{
|
|||
|
if (navigator.clipboard)
|
|||
|
return await navigator.clipboard.readText()
|
|||
|
return ''
|
|||
|
}
|