|
|
|
@ -1,6 +1,7 @@
|
|
|
|
|
import { Vector2, Vector3 } from "three";
|
|
|
|
|
import { arrayLast } from "../Common/ArrayExt";
|
|
|
|
|
import { Vec2DTo3D, Vec3DTo2D, curveLinkGroup, getCirAngleByChordAndTangent } from "../Common/CurveUtils";
|
|
|
|
|
import { FixIndex } from "../Common/Utils";
|
|
|
|
|
import { Arc } from "../DatabaseServices/Arc";
|
|
|
|
|
import { Circle } from "../DatabaseServices/Circle";
|
|
|
|
|
import { Contour } from "../DatabaseServices/Contour";
|
|
|
|
@ -10,12 +11,12 @@ import { Polyline, PolylineProps } from '../DatabaseServices/Polyline';
|
|
|
|
|
import { equal, equaln } from "../Geometry/GeUtils";
|
|
|
|
|
import { isTargetCurInSourceCur, isTargetCurOutOrOnSourceCur } from "./BoolOperateUtils";
|
|
|
|
|
import { IntersectOption } from "./IntersectWith";
|
|
|
|
|
interface offestRes
|
|
|
|
|
interface offestRes2
|
|
|
|
|
{
|
|
|
|
|
index: number,
|
|
|
|
|
pl: Polyline
|
|
|
|
|
}
|
|
|
|
|
interface offestRes1
|
|
|
|
|
interface offestRes
|
|
|
|
|
{
|
|
|
|
|
index: number,
|
|
|
|
|
curve: Curve
|
|
|
|
@ -46,8 +47,8 @@ export class PolyOffestUtil
|
|
|
|
|
//偏移
|
|
|
|
|
GetOffsetCurves(): Curve[]
|
|
|
|
|
{
|
|
|
|
|
let plList1: offestRes[] = this.offestCurve(this.m_Polyline.Explode());
|
|
|
|
|
let plList2: offestRes[] = this.offestCurve(this.m_Polyline.Explode(), true);
|
|
|
|
|
let plList1: offestRes2[] = this.offestCurve(this.m_Polyline.Explode());
|
|
|
|
|
let plList2: offestRes2[] = this.offestCurve(this.m_Polyline.Explode(), true);
|
|
|
|
|
|
|
|
|
|
// //连接全部连接点
|
|
|
|
|
let newPlList: Array<Polyline> = this.trimAndJointOffestPolyline(plList1);
|
|
|
|
@ -72,9 +73,9 @@ export class PolyOffestUtil
|
|
|
|
|
|
|
|
|
|
return outputPls;
|
|
|
|
|
}
|
|
|
|
|
private offestCurve(pls: Curve[], isContrary: boolean = false): offestRes[]
|
|
|
|
|
private offestCurve(pls: Curve[], isContrary: boolean = false): offestRes2[]
|
|
|
|
|
{
|
|
|
|
|
let plList: offestRes[] = [];
|
|
|
|
|
let plList: offestRes2[] = [];
|
|
|
|
|
pls.forEach((cu, index) =>
|
|
|
|
|
{
|
|
|
|
|
let ocu = cu.GetOffsetCurves(isContrary ? -this.m_OffestDist : this.m_OffestDist)[0];
|
|
|
|
@ -102,7 +103,7 @@ export class PolyOffestUtil
|
|
|
|
|
* @returns
|
|
|
|
|
* @memberof Polyline
|
|
|
|
|
*/
|
|
|
|
|
private trimAndJointOffestPolyline(offResList: offestRes[])
|
|
|
|
|
private trimAndJointOffestPolyline(offResList: offestRes2[])
|
|
|
|
|
{
|
|
|
|
|
offResList = offResList.filter(r => r.pl)
|
|
|
|
|
if (offResList.length <= 1)
|
|
|
|
@ -610,8 +611,8 @@ export class PolyOffestUtil2
|
|
|
|
|
//偏移
|
|
|
|
|
GetOffsetCurves(): Curve[]
|
|
|
|
|
{
|
|
|
|
|
let plList1: offestRes[] = this.offestCurve(this.m_Polyline.Explode());
|
|
|
|
|
let plList2: offestRes[] = this.offestCurve(this.m_Polyline.Explode(), true);
|
|
|
|
|
let plList1: offestRes2[] = this.offestCurve(this.m_Polyline.Explode());
|
|
|
|
|
let plList2: offestRes2[] = this.offestCurve(this.m_Polyline.Explode(), true);
|
|
|
|
|
|
|
|
|
|
let contours: Contour[] = [];
|
|
|
|
|
for (let i = 0; i < plList1.length; i++)
|
|
|
|
@ -647,9 +648,9 @@ export class PolyOffestUtil2
|
|
|
|
|
return this.linkCurves(cus);
|
|
|
|
|
}
|
|
|
|
|
//偏移曲线
|
|
|
|
|
private offestCurve(pls: Curve[], isContrary: boolean = false): offestRes[]
|
|
|
|
|
private offestCurve(pls: Curve[], isContrary: boolean = false): offestRes2[]
|
|
|
|
|
{
|
|
|
|
|
let plList: offestRes[] = [];
|
|
|
|
|
let plList: offestRes2[] = [];
|
|
|
|
|
pls.forEach((cu, index) =>
|
|
|
|
|
{
|
|
|
|
|
let ocu = cu.GetOffsetCurves(isContrary ? -this.m_OffestDist : this.m_OffestDist)[0];
|
|
|
|
@ -686,7 +687,7 @@ export class PolyOffestUtil2
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 修剪连接相邻曲线
|
|
|
|
|
private trimAndJointOffestPolyline(offestPlList: offestRes[], originLine: Polyline)
|
|
|
|
|
private trimAndJointOffestPolyline(offestPlList: offestRes2[], originLine: Polyline)
|
|
|
|
|
{
|
|
|
|
|
offestPlList = offestPlList.filter(r => r.pl)
|
|
|
|
|
if (offestPlList.length === 0) return [];
|
|
|
|
@ -1055,7 +1056,7 @@ export class PolyOffestUtil3
|
|
|
|
|
private m_Polyline: Polyline;
|
|
|
|
|
private m_OffestDist: number;
|
|
|
|
|
private m_OffDir: number;
|
|
|
|
|
private IsKeepAllCurves = false;
|
|
|
|
|
private IsKeepAllCurves = false; //为true时 保留全部,不优化裁剪
|
|
|
|
|
constructor(pl: Polyline, offest: number)
|
|
|
|
|
{
|
|
|
|
|
this.m_Polyline = pl;
|
|
|
|
@ -1082,7 +1083,8 @@ export class PolyOffestUtil3
|
|
|
|
|
|
|
|
|
|
if (this.m_Polyline.IsClose && this.m_OffDir < 0)
|
|
|
|
|
{
|
|
|
|
|
cus = cus.filter(pl => isTargetCurInSourceCur(this.m_Polyline, pl))
|
|
|
|
|
//FIXME:
|
|
|
|
|
cus = cus.filter(pl => isTargetCurInSourceCur(this.m_Polyline, pl));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.IsKeepAllCurves)
|
|
|
|
@ -1094,14 +1096,18 @@ export class PolyOffestUtil3
|
|
|
|
|
// 先尝试把线段首尾相连成封闭区域
|
|
|
|
|
rets.forEach(cu =>
|
|
|
|
|
{
|
|
|
|
|
//不闭合 并且线段数大于等于3
|
|
|
|
|
//FIXME:
|
|
|
|
|
if (!cu.IsClose && cu.EndParam > 2)
|
|
|
|
|
{
|
|
|
|
|
let pts = cu.GetCurveAtParam(0).IntersectWith(cu.GetCurveAtParam(cu.EndParam), IntersectOption.OnBothOperands);
|
|
|
|
|
if (pts.length > 0)
|
|
|
|
|
if (pts.length === 1)
|
|
|
|
|
{
|
|
|
|
|
cu.StartPoint = pts[0];
|
|
|
|
|
cu.EndPoint = pts[0];
|
|
|
|
|
}
|
|
|
|
|
else if (pts.length > 1)
|
|
|
|
|
console.warn("未预料到的情况");
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
rets = rets.filter((cu, index) =>
|
|
|
|
@ -1127,7 +1133,7 @@ export class PolyOffestUtil3
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
//偏移曲线
|
|
|
|
|
private offestCurve(pls: Curve[], dis: number): offestRes1[]
|
|
|
|
|
private offestCurve(pls: Curve[], dis: number): offestRes[]
|
|
|
|
|
{
|
|
|
|
|
return pls.map((cu, index) =>
|
|
|
|
|
{
|
|
|
|
@ -1140,7 +1146,7 @@ export class PolyOffestUtil3
|
|
|
|
|
{
|
|
|
|
|
if (pl1 && pl2)
|
|
|
|
|
{
|
|
|
|
|
let dir = Math.sign(this.m_OffestDist)
|
|
|
|
|
let dir = Math.sign(this.m_OffestDist);
|
|
|
|
|
let arc1 = new Arc().ParseFromBul(pl1.StartPoint, pl2.StartPoint, -dir);
|
|
|
|
|
let arc2 = new Arc().ParseFromBul(pl1.EndPoint, pl2.EndPoint, dir);
|
|
|
|
|
return Contour.CreateContour([pl1.Clone() as Curve, pl2.Clone() as Curve, arc1, arc2]);
|
|
|
|
@ -1159,13 +1165,13 @@ export class PolyOffestUtil3
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 修剪连接相邻曲线
|
|
|
|
|
private trimAndJointOffestPolyline(offResList: offestRes1[], originLine: Polyline)
|
|
|
|
|
private trimAndJointOffestPolyline(offResList: offestRes[], originLine: Polyline)
|
|
|
|
|
{
|
|
|
|
|
offResList = offResList.filter(r => r.curve);
|
|
|
|
|
if (offResList.length <= 1)
|
|
|
|
|
return offResList.map(r => r.curve);
|
|
|
|
|
|
|
|
|
|
let newPlList: Array<Curve> = [];
|
|
|
|
|
let retPlList: Array<Curve> = [];
|
|
|
|
|
|
|
|
|
|
let nextPt: Vector3 = offResList[0].curve.StartPoint;
|
|
|
|
|
|
|
|
|
@ -1175,21 +1181,26 @@ export class PolyOffestUtil3
|
|
|
|
|
let frontLine = offResList[i].curve;
|
|
|
|
|
|
|
|
|
|
//后面线
|
|
|
|
|
let laterLine = i === offResList.length - 1 ? undefined : offResList[i + 1].curve;
|
|
|
|
|
let laterLine: Curve;
|
|
|
|
|
//如果是闭合的,继续循环,否则直接添加到新数组列表
|
|
|
|
|
if (i === offResList.length - 1)
|
|
|
|
|
{
|
|
|
|
|
if (retPlList.length === 0)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (this.m_Polyline.IsClose)
|
|
|
|
|
laterLine = newPlList[0];
|
|
|
|
|
laterLine = retPlList[0];
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
this.appendNewPllist(frontLine, nextPt, frontLine.EndPoint, newPlList);
|
|
|
|
|
this.appendNewPllist(frontLine, nextPt, frontLine.EndPoint, retPlList);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
laterLine = offResList[i + 1].curve;
|
|
|
|
|
|
|
|
|
|
//默认交点
|
|
|
|
|
let interPt = frontLine.EndPoint.clone();
|
|
|
|
|
let interPt = frontLine.EndPoint;
|
|
|
|
|
// 如果两线结合点不相等,调整交点位置
|
|
|
|
|
if (!equal(frontLine.EndPoint, laterLine.StartPoint))
|
|
|
|
|
{
|
|
|
|
@ -1200,39 +1211,43 @@ export class PolyOffestUtil3
|
|
|
|
|
if (interPts.length === 0)
|
|
|
|
|
{
|
|
|
|
|
//偏移线段对应的源线段,取其起始点作为圆心
|
|
|
|
|
let srcOffestRes = offResList[i + 1] ? offResList[i + 1] : offResList[0];
|
|
|
|
|
this.fillArc(offResList[i].index, srcOffestRes.index, nextPt, frontLine, laterLine, newPlList);
|
|
|
|
|
let srcOffestRes = offResList[FixIndex(i + 1, offResList)];
|
|
|
|
|
this.fillArc(offResList[i].index, srcOffestRes.index, nextPt, frontLine, laterLine, retPlList);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
let pts = frontLine.IntersectWith(laterLine, IntersectOption.OnBothOperands);
|
|
|
|
|
interPt = this.selectFitInterPt(pts.length ? pts : interPts, frontLine.EndPoint);
|
|
|
|
|
let pts = interPts.filter(p => frontLine.PtOnCurve(p) && laterLine.PtOnCurve(p));
|
|
|
|
|
interPt = this.selectFitInterPt(pts.length > 0 ? pts : interPts, frontLine.EndPoint);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
this.appendNewPllist(frontLine, nextPt, interPt, newPlList, laterLine);
|
|
|
|
|
this.appendNewPllist(frontLine, nextPt, interPt, retPlList, laterLine);
|
|
|
|
|
|
|
|
|
|
if (i === offResList.length - 1)
|
|
|
|
|
if (i === offResList.length - 1)//曲线闭合时,修改第一条线的起点
|
|
|
|
|
{
|
|
|
|
|
laterLine.StartPoint = nextPt;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return newPlList;
|
|
|
|
|
return retPlList;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//将线段拷贝并修改,加入到结果数组里面.
|
|
|
|
|
appendNewPllist(frontLine: Curve, nextPt: Vector3, interPt: Vector3, newPlList: Curve[], laterLine?: Curve, )
|
|
|
|
|
{
|
|
|
|
|
let newCu = frontLine.Clone() as Curve;
|
|
|
|
|
|
|
|
|
|
newCu.StartPoint = nextPt;
|
|
|
|
|
newCu.EndPoint = interPt;
|
|
|
|
|
|
|
|
|
|
nextPt.copy(interPt);
|
|
|
|
|
|
|
|
|
|
newCu.EndPoint = interPt;
|
|
|
|
|
if (this.isVail(frontLine, newCu))
|
|
|
|
|
{
|
|
|
|
|
newPlList.push(newCu);
|
|
|
|
|
}
|
|
|
|
|
else if (newPlList.length && laterLine)
|
|
|
|
|
else if (newPlList.length > 0 && laterLine)
|
|
|
|
|
{
|
|
|
|
|
//曲线校验补通过,尝试和前一条线段求交点.
|
|
|
|
|
let lastCu = arrayLast(newPlList);
|
|
|
|
|
let pts = lastCu.IntersectWith(laterLine, IntersectOption.ExtendBoth);
|
|
|
|
|
if (pts.length > 0)
|
|
|
|
@ -1251,16 +1266,30 @@ export class PolyOffestUtil3
|
|
|
|
|
} else
|
|
|
|
|
return oldCu.IsClockWise === newCu.IsClockWise
|
|
|
|
|
}
|
|
|
|
|
//补圆弧
|
|
|
|
|
fillArc(startIndex: number, endIndex: number, nextPt: Vector3, frontLine: Curve, laterLine: Curve, newPlList: Curve[])
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 补圆弧
|
|
|
|
|
*
|
|
|
|
|
* @param {number} startIndex 源线段索引
|
|
|
|
|
* @param {number} endIndex 源线段索引
|
|
|
|
|
* @param {Vector3} nextPt
|
|
|
|
|
* @param {Curve} frontLine
|
|
|
|
|
* @param {Curve} laterLine
|
|
|
|
|
* @param {Curve[]} retPlList
|
|
|
|
|
* @returns
|
|
|
|
|
* @memberof PolyOffestUtil3
|
|
|
|
|
*/
|
|
|
|
|
fillArc(startIndex: number, endIndex: number, nextPt: Vector3, frontLine: Curve, laterLine: Curve, retPlList: Curve[])
|
|
|
|
|
{
|
|
|
|
|
let centerPt = this.m_Polyline.GetPointAtParam(endIndex);
|
|
|
|
|
// 圆心到前面线end点距离
|
|
|
|
|
//圆心到前面线end点距离
|
|
|
|
|
let startDist = frontLine.EndPoint.distanceToSquared(centerPt);
|
|
|
|
|
// 圆心到后面线start点距离
|
|
|
|
|
//圆心到后面线start点距离
|
|
|
|
|
let endDist = laterLine.StartPoint.distanceToSquared(centerPt);
|
|
|
|
|
//补圆弧的起始交点
|
|
|
|
|
let intPt = frontLine.EndPoint;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
const buildArcJoinList = (cir1: Circle, intPt: Vector3) =>
|
|
|
|
|
{
|
|
|
|
|
let pars = [nextPt, intPt].map(p => cir1.GetParamAtPoint(p));
|
|
|
|
@ -1270,8 +1299,10 @@ export class PolyOffestUtil3
|
|
|
|
|
let cu = splitCus[0].Length < splitCus[1].Length ? splitCus[0] : splitCus[1];
|
|
|
|
|
|
|
|
|
|
//如果不是首尾相连,就反转后在存入数组
|
|
|
|
|
if (!equal(cu.StartPoint, arrayLast(newPlList).EndPoint)) cu.Reverse();
|
|
|
|
|
newPlList.push(cu);
|
|
|
|
|
if (!equal(cu.StartPoint, arrayLast(retPlList).EndPoint))
|
|
|
|
|
cu.Reverse();
|
|
|
|
|
|
|
|
|
|
retPlList.push(cu);
|
|
|
|
|
nextPt.copy(intPt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1287,7 +1318,7 @@ export class PolyOffestUtil3
|
|
|
|
|
{
|
|
|
|
|
//选取交点,如果有多个选离前面线start点近的
|
|
|
|
|
intPt = this.selectFitInterPt(pts, frontLine.StartPoint);
|
|
|
|
|
frontLine.EndPoint = intPt
|
|
|
|
|
frontLine.EndPoint = intPt;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
@ -1301,7 +1332,7 @@ export class PolyOffestUtil3
|
|
|
|
|
let pts = frontLine.IntersectWith(cirs[0], IntersectOption.OnBothOperands);
|
|
|
|
|
let inPt = this.selectFitInterPt(pts, frontLine.EndPoint);
|
|
|
|
|
|
|
|
|
|
this.appendNewPllist(frontLine, nextPt, inPt, newPlList);
|
|
|
|
|
this.appendNewPllist(frontLine, nextPt, inPt, retPlList);
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < cirs.length - 1; i++)
|
|
|
|
|
{
|
|
|
|
@ -1325,12 +1356,12 @@ export class PolyOffestUtil3
|
|
|
|
|
let tangent = laterLine.GetFistDeriv(0).negate().normalize();
|
|
|
|
|
let circleAngle = -getCirAngleByChordAndTangent(chord, tangent);
|
|
|
|
|
|
|
|
|
|
this.appendNewPllist(frontLine, nextPt, intPt, newPlList, laterLine);
|
|
|
|
|
this.appendNewPllist(frontLine, nextPt, intPt, retPlList, laterLine);
|
|
|
|
|
|
|
|
|
|
nextPt.copy(laterLine.StartPoint);
|
|
|
|
|
|
|
|
|
|
let arc = new Arc().ParseFromBul(intPt, laterLine.StartPoint, Math.tan(circleAngle / 4));
|
|
|
|
|
newPlList.push(arc);
|
|
|
|
|
retPlList.push(arc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 通过构建的轮廓对偏移曲线进行裁剪
|
|
|
|
@ -1343,9 +1374,10 @@ export class PolyOffestUtil3
|
|
|
|
|
|
|
|
|
|
needCutPls.forEach(l =>
|
|
|
|
|
{
|
|
|
|
|
//在上面或者在外面
|
|
|
|
|
if (isTargetCurOutOrOnSourceCur(outline, l))
|
|
|
|
|
{
|
|
|
|
|
tmpCus.push(l)
|
|
|
|
|
tmpCus.push(l);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
@ -1355,7 +1387,6 @@ export class PolyOffestUtil3
|
|
|
|
|
let par = pts.map(p => l.GetParamAtPoint(p));
|
|
|
|
|
let cus = l.GetSplitCurves(par);
|
|
|
|
|
tmpCus.push(...cus.filter(cu => !isTargetCurInSourceCur(outline, cu)));
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
@ -1371,7 +1402,7 @@ export class PolyOffestUtil3
|
|
|
|
|
* @returns
|
|
|
|
|
* @memberof PolyOffestUtil3
|
|
|
|
|
*/
|
|
|
|
|
private isSelfingCUs(cus: Curve[])
|
|
|
|
|
private isSelfingCus(cus: Curve[])
|
|
|
|
|
{
|
|
|
|
|
for (let i = 0; i < cus.length; i++)
|
|
|
|
|
{
|
|
|
|
@ -1424,8 +1455,8 @@ export class PolyOffestUtil3
|
|
|
|
|
*/
|
|
|
|
|
linkSelfingCurves(cus: Curve[])
|
|
|
|
|
{
|
|
|
|
|
let newPls: Polyline[] = [];
|
|
|
|
|
let isSelfing = this.isSelfingCUs(cus);
|
|
|
|
|
let retPls: Polyline[] = [];
|
|
|
|
|
let isSelfing = this.isSelfingCus(cus);
|
|
|
|
|
while (cus.length && isSelfing)
|
|
|
|
|
{
|
|
|
|
|
let pl = new Polyline();
|
|
|
|
@ -1493,12 +1524,12 @@ export class PolyOffestUtil3
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newPls.push(pl);
|
|
|
|
|
isSelfing = this.isSelfingCUs(cus);
|
|
|
|
|
retPls.push(pl);
|
|
|
|
|
isSelfing = this.isSelfingCus(cus);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
newPls.push(...this.linkCurves(cus));
|
|
|
|
|
return newPls;
|
|
|
|
|
retPls.push(...this.linkCurves(cus));
|
|
|
|
|
return retPls;
|
|
|
|
|
}
|
|
|
|
|
// 选择合适的交点
|
|
|
|
|
private selectFitInterPt(pts: Vector3[], refPt: Vector3)
|
|
|
|
|