|
|
|
@ -1,4 +1,4 @@
|
|
|
|
|
import { Vector3 } from "three";
|
|
|
|
|
import { Box3, Vector3 } from "three";
|
|
|
|
|
import { arrayLast, arrayRemoveIf, arraySortByNumber } from "../Common/ArrayExt";
|
|
|
|
|
import { curveLinkGroup } from "../Common/CurveUtils";
|
|
|
|
|
import { FixIndex } from "../Common/Utils";
|
|
|
|
@ -9,7 +9,7 @@ import { Curve } from "../DatabaseServices/Curve";
|
|
|
|
|
import { Line } from "../DatabaseServices/Line";
|
|
|
|
|
import { Polyline } from '../DatabaseServices/Polyline';
|
|
|
|
|
import { equal, equaln } from "../Geometry/GeUtils";
|
|
|
|
|
import { SortEntityByBox } from "../Geometry/SortEntityByBox";
|
|
|
|
|
import { EBox, SortEntityByBox } from "../Geometry/SortEntityByBox";
|
|
|
|
|
import { IsPtsAllOutOrOnReg } from "./BoolOperateUtils";
|
|
|
|
|
import { IntersectOption } from "./IntersectWith";
|
|
|
|
|
|
|
|
|
@ -31,6 +31,8 @@ export class PolyOffestUtil
|
|
|
|
|
private m_RetCurves: Curve[] = [];//第一步修剪的数组
|
|
|
|
|
private m_dist2: number;
|
|
|
|
|
private m_AbsDist: number;
|
|
|
|
|
private unNeedCutCus: Curve[] = [];
|
|
|
|
|
|
|
|
|
|
constructor(pl: Polyline, offest: number)
|
|
|
|
|
{
|
|
|
|
|
this.m_Polyline = pl;
|
|
|
|
@ -55,13 +57,14 @@ export class PolyOffestUtil
|
|
|
|
|
// console.time("join")
|
|
|
|
|
this.TrimAndBuildContour(offres);
|
|
|
|
|
// console.timeEnd("join")
|
|
|
|
|
// testContours(contours);
|
|
|
|
|
|
|
|
|
|
// testContours(this.m_Contours);
|
|
|
|
|
// return this.m_RetCurves;
|
|
|
|
|
//裁剪
|
|
|
|
|
let { boxCurves, outputCus } = this.trimByContours(this.m_RetCurves);
|
|
|
|
|
|
|
|
|
|
// 优化裁剪后的曲线
|
|
|
|
|
outputCus = this.optimizeCus(boxCurves, outputCus);
|
|
|
|
|
outputCus.push(...this.unNeedCutCus);
|
|
|
|
|
|
|
|
|
|
return this.linkCurves(outputCus);
|
|
|
|
|
}
|
|
|
|
@ -77,11 +80,11 @@ export class PolyOffestUtil
|
|
|
|
|
*/
|
|
|
|
|
private CheckPoint(pt: Vector3): boolean
|
|
|
|
|
{
|
|
|
|
|
let dis = this.m_Polyline.GetClosestPointTo(pt, false)
|
|
|
|
|
.distanceToSquared(pt);
|
|
|
|
|
let closePt = this.m_Polyline.GetClosestPointTo(pt, false);
|
|
|
|
|
let dis = closePt.distanceToSquared(pt);
|
|
|
|
|
return dis + 1e-2 > this.m_dist2;
|
|
|
|
|
}
|
|
|
|
|
private optimizeCus(boxCurves, outputCus)
|
|
|
|
|
private optimizeCus(boxCurves: Map<EBox, Box3>, outputCus: Curve[])
|
|
|
|
|
{
|
|
|
|
|
//过滤掉无效的线段
|
|
|
|
|
outputCus = outputCus.filter(c =>
|
|
|
|
@ -94,6 +97,8 @@ export class PolyOffestUtil
|
|
|
|
|
return this.CheckPoint(c.StartPoint) && this.CheckPoint(c.EndPoint);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
//处理在偏移反方向的曲线
|
|
|
|
|
|
|
|
|
|
//处理自交的线段
|
|
|
|
|
let count = outputCus.length;
|
|
|
|
|
for (let i = 0; i < count; i++)
|
|
|
|
@ -161,11 +166,29 @@ export class PolyOffestUtil
|
|
|
|
|
{
|
|
|
|
|
if (cu1 && cu2)
|
|
|
|
|
{
|
|
|
|
|
let l1 = new Line(cu1.StartPoint, cu2.StartPoint);
|
|
|
|
|
let l2 = new Line(cu1.EndPoint, cu2.EndPoint);
|
|
|
|
|
if (cu1 instanceof Arc && cu2 instanceof Arc)
|
|
|
|
|
{
|
|
|
|
|
let pts1 = l1.IntersectWith(cu2, 0);
|
|
|
|
|
if (pts1.length === 2)
|
|
|
|
|
{
|
|
|
|
|
let splitCus = cu2.GetSplitCurvesByPts(pts1);
|
|
|
|
|
this.unNeedCutCus.push(splitCus[0])
|
|
|
|
|
}
|
|
|
|
|
let pts2 = l2.IntersectWith(cu2, 0);
|
|
|
|
|
if (pts2.length === 2)
|
|
|
|
|
{
|
|
|
|
|
let splitCus = cu2.GetSplitCurvesByPts(pts2);
|
|
|
|
|
this.unNeedCutCus.push(splitCus[1])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return Contour.CreateContour([
|
|
|
|
|
cu1.Clone() as Curve,
|
|
|
|
|
cu2.Clone() as Curve,
|
|
|
|
|
new Line(cu1.StartPoint, cu2.StartPoint),
|
|
|
|
|
new Line(cu1.EndPoint, cu2.EndPoint)
|
|
|
|
|
l1,
|
|
|
|
|
l2
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
else if (cu1 || cu2)
|
|
|
|
@ -370,7 +393,6 @@ export class PolyOffestUtil
|
|
|
|
|
|
|
|
|
|
if (index === endIndex) break;
|
|
|
|
|
}
|
|
|
|
|
// testCurve(cirs);
|
|
|
|
|
|
|
|
|
|
//优先选择第一个后面的圆
|
|
|
|
|
let iPts: Vector3[];
|
|
|
|
@ -387,11 +409,10 @@ export class PolyOffestUtil
|
|
|
|
|
|
|
|
|
|
//#region 避免错误块
|
|
|
|
|
//假设我们认为连接一定能成功,那么下面的if不是必要的
|
|
|
|
|
// if (!iPts)
|
|
|
|
|
// {
|
|
|
|
|
// console.log("未预料到的情况");
|
|
|
|
|
// return;
|
|
|
|
|
// }
|
|
|
|
|
if (!iPts)
|
|
|
|
|
{
|
|
|
|
|
console.error("补圆失败,距离为", this.m_OffestDist);
|
|
|
|
|
}
|
|
|
|
|
//#endregion
|
|
|
|
|
|
|
|
|
|
let iPt = this.selectFitInterPt(iPts, frontLine.EndPoint);
|
|
|
|
@ -405,7 +426,12 @@ export class PolyOffestUtil
|
|
|
|
|
{
|
|
|
|
|
let c1 = cirs[index];//已经计算过的圆
|
|
|
|
|
|
|
|
|
|
let iPtsLater = c1.IntersectWith(laterLine, 0);
|
|
|
|
|
let iPtsLater: Vector3[];
|
|
|
|
|
if (index === cirs.length - 1)
|
|
|
|
|
iPtsLater = [laterLine.StartPoint];
|
|
|
|
|
else
|
|
|
|
|
iPtsLater = c1.IntersectWith(laterLine, 0);
|
|
|
|
|
|
|
|
|
|
if (iPtsLater.length > 0)//直接和最后一条连接
|
|
|
|
|
{
|
|
|
|
|
let iPt = this.selectFitInterPt(iPtsLater, nextPt);
|
|
|
|
@ -420,6 +446,7 @@ export class PolyOffestUtil
|
|
|
|
|
|
|
|
|
|
let iPts = c1.IntersectWith(c2, 0);
|
|
|
|
|
let iPt = this.selectFitInterPt(iPts, nextPt);
|
|
|
|
|
|
|
|
|
|
this.buildArcJoinList(c1, nextPt, iPt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -442,9 +469,24 @@ export class PolyOffestUtil
|
|
|
|
|
|
|
|
|
|
if (splitCus.length === 2) //2圆相交应该有2段,否则相切
|
|
|
|
|
{
|
|
|
|
|
let isNotInt = splitCus[0].IntersectWith(this.m_Polyline, IntersectOption.OnBothOperands).length === 0;
|
|
|
|
|
let tmpPts = cir.IntersectWith(this.m_Polyline, IntersectOption.OnBothOperands);
|
|
|
|
|
let onCu0Pts = tmpPts.filter(p => splitCus[0].PtOnCurve(p));
|
|
|
|
|
let onCu1Pts = tmpPts.filter(p => splitCus[1].PtOnCurve(p));
|
|
|
|
|
//选择和源线段不相交的那段圆弧
|
|
|
|
|
let cu = isNotInt ? splitCus[0] : splitCus[1];
|
|
|
|
|
let cu: Arc;
|
|
|
|
|
if (onCu0Pts.length === 0)
|
|
|
|
|
{
|
|
|
|
|
cu = splitCus[0];
|
|
|
|
|
}
|
|
|
|
|
else if (onCu1Pts.length === 0)
|
|
|
|
|
{
|
|
|
|
|
cu = splitCus[1]
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//TODO:先用第一段
|
|
|
|
|
cu = splitCus[0];
|
|
|
|
|
}
|
|
|
|
|
//防止加入0长度圆弧
|
|
|
|
|
if (equaln(cu.Length, 0, 1e-6))
|
|
|
|
|
return;
|
|
|
|
|