|
|
@ -13,16 +13,16 @@ import { EBox, SortEntityByBox } from "../Geometry/SortEntityByBox";
|
|
|
|
import { IsPtsAllOutOrOnReg } from "./BoolOperateUtils";
|
|
|
|
import { IsPtsAllOutOrOnReg } from "./BoolOperateUtils";
|
|
|
|
import { IntersectOption } from "./IntersectWith";
|
|
|
|
import { IntersectOption } from "./IntersectWith";
|
|
|
|
|
|
|
|
|
|
|
|
interface offestRes
|
|
|
|
interface offsetRes
|
|
|
|
{
|
|
|
|
{
|
|
|
|
index: number;
|
|
|
|
index: number;
|
|
|
|
curve: Curve;
|
|
|
|
curve: Curve;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export class PolyOffestUtil
|
|
|
|
export class PolyOffsetUtil
|
|
|
|
{
|
|
|
|
{
|
|
|
|
private m_Polyline: Polyline;
|
|
|
|
private m_Polyline: Polyline;
|
|
|
|
private m_OffestDist: number;
|
|
|
|
private m_OffsetDist: number;
|
|
|
|
private m_Contours: Contour[] = [];//构建的轮廓
|
|
|
|
private m_Contours: Contour[] = [];//构建的轮廓
|
|
|
|
private m_RetCurves: Curve[] = [];//第一步修剪的数组
|
|
|
|
private m_RetCurves: Curve[] = [];//第一步修剪的数组
|
|
|
|
//偏移距离平方值
|
|
|
|
//偏移距离平方值
|
|
|
@ -34,12 +34,12 @@ export class PolyOffestUtil
|
|
|
|
//源线段点数量
|
|
|
|
//源线段点数量
|
|
|
|
private m_PtCount: number;
|
|
|
|
private m_PtCount: number;
|
|
|
|
|
|
|
|
|
|
|
|
constructor(pl: Polyline, offest: number)
|
|
|
|
constructor(pl: Polyline, offset: number)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
this.m_Polyline = pl;
|
|
|
|
this.m_Polyline = pl;
|
|
|
|
this.m_OffestDist = offest;
|
|
|
|
this.m_OffsetDist = offset;
|
|
|
|
this.m_dist2 = Math.pow(offest, 2);
|
|
|
|
this.m_dist2 = Math.pow(offset, 2);
|
|
|
|
this.m_AbsDist = Math.abs(this.m_OffestDist);
|
|
|
|
this.m_AbsDist = Math.abs(this.m_OffsetDist);
|
|
|
|
this.m_PtCount = pl.EndParam;
|
|
|
|
this.m_PtCount = pl.EndParam;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
GetOffsetCurves(): Curve[]
|
|
|
|
GetOffsetCurves(): Curve[]
|
|
|
@ -61,6 +61,7 @@ export class PolyOffestUtil
|
|
|
|
|
|
|
|
|
|
|
|
// 裁剪并优化的曲线
|
|
|
|
// 裁剪并优化的曲线
|
|
|
|
let { boxCurves, outputCus } = this.trimByContours(this.m_RetCurves);
|
|
|
|
let { boxCurves, outputCus } = this.trimByContours(this.m_RetCurves);
|
|
|
|
|
|
|
|
|
|
|
|
this.m_RetCurves = this.optimizeCus(boxCurves, outputCus);
|
|
|
|
this.m_RetCurves = this.optimizeCus(boxCurves, outputCus);
|
|
|
|
|
|
|
|
|
|
|
|
this.m_RetCurves.push(...this.unNeedCutCus);
|
|
|
|
this.m_RetCurves.push(...this.unNeedCutCus);
|
|
|
@ -76,7 +77,7 @@ export class PolyOffestUtil
|
|
|
|
private CheckPointDir(pt: Vector3)
|
|
|
|
private CheckPointDir(pt: Vector3)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
let dir = GetPointAtCurveDir(this.m_Polyline, pt) ? 1 : -1;
|
|
|
|
let dir = GetPointAtCurveDir(this.m_Polyline, pt) ? 1 : -1;
|
|
|
|
return dir === Math.sign(this.m_OffestDist);
|
|
|
|
return dir === Math.sign(this.m_OffsetDist);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -90,7 +91,6 @@ export class PolyOffestUtil
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
private optimizeCus(boxCurves: Map<EBox, Box3>, outputCus: Curve[])
|
|
|
|
private optimizeCus(boxCurves: Map<EBox, Box3>, outputCus: Curve[])
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
//过滤掉无效的线段
|
|
|
|
//过滤掉无效的线段
|
|
|
|
outputCus = outputCus.filter(c =>
|
|
|
|
outputCus = outputCus.filter(c =>
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -123,7 +123,6 @@ export class PolyOffestUtil
|
|
|
|
for (let j = i + 1; j < outputCus.length; j++)
|
|
|
|
for (let j = i + 1; j < outputCus.length; j++)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
let c2 = outputCus[j];
|
|
|
|
let c2 = outputCus[j];
|
|
|
|
|
|
|
|
|
|
|
|
let c2b = boxCurves.get(c2);
|
|
|
|
let c2b = boxCurves.get(c2);
|
|
|
|
|
|
|
|
|
|
|
|
//过滤掉不需要计算的曲线
|
|
|
|
//过滤掉不需要计算的曲线
|
|
|
@ -132,17 +131,22 @@ export class PolyOffestUtil
|
|
|
|
if (c2b.min.y > c1b.max.y)
|
|
|
|
if (c2b.min.y > c1b.max.y)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let c1StartPt = c1.StartPoint;
|
|
|
|
|
|
|
|
let c1EndPt = c1.EndPoint;
|
|
|
|
|
|
|
|
let c2StartPt = c2.StartPoint;
|
|
|
|
|
|
|
|
let c2EndPt = c2.EndPoint;
|
|
|
|
|
|
|
|
|
|
|
|
//被包含的直线删掉
|
|
|
|
//被包含的直线删掉
|
|
|
|
if (c1 instanceof Line && c2 instanceof Line)
|
|
|
|
if (c1 instanceof Line && c2 instanceof Line)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
//c1完全在c2内
|
|
|
|
//c1完全在c2内
|
|
|
|
if (c2.PtOnCurve(c1.StartPoint) && c2.PtOnCurve(c1.EndPoint))
|
|
|
|
if (c2.PtOnCurve(c1StartPt) && c2.PtOnCurve(c1EndPt))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
outputCus.splice(i, 1);
|
|
|
|
outputCus.splice(i, 1);
|
|
|
|
i--;
|
|
|
|
i--;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (c1.PtOnCurve(c2.StartPoint) && c1.PtOnCurve(c2.EndPoint))
|
|
|
|
else if (c1.PtOnCurve(c2StartPt) && c1.PtOnCurve(c2EndPt))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// c2完全在c1内
|
|
|
|
// c2完全在c1内
|
|
|
|
outputCus.splice(j, 1);
|
|
|
|
outputCus.splice(j, 1);
|
|
|
@ -152,21 +156,20 @@ export class PolyOffestUtil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//如果线段端点相连,跳过
|
|
|
|
//如果线段端点相连,跳过
|
|
|
|
let isLink = [c1.StartPoint, c1.EndPoint].some(p => equal(p, c2.StartPoint) || equal(p, c2.EndPoint));
|
|
|
|
let isLink = [c1StartPt, c1EndPt].some(p => equal(p, c2StartPt) || equal(p, c2EndPt));
|
|
|
|
if (isLink) continue;
|
|
|
|
if (isLink) continue;
|
|
|
|
|
|
|
|
|
|
|
|
let pts = c1.IntersectWith(c2, IntersectOption.OnBothOperands);
|
|
|
|
let pts = c1.IntersectWith(c2, IntersectOption.OnBothOperands);
|
|
|
|
if (pts.length > 0)
|
|
|
|
if (pts.length > 0)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
//按照从左到右,从上到下,分别取前后部分,即去掉中间部分
|
|
|
|
//按照从左到右,从上到下,分别取前后部分,即去掉中间部分
|
|
|
|
|
|
|
|
|
|
|
|
[c1, c2].forEach((c, index) =>
|
|
|
|
[c1, c2].forEach((c, index) =>
|
|
|
|
{
|
|
|
|
{
|
|
|
|
let cs = c.GetSplitCurvesByPts(pts);
|
|
|
|
let cs = c.GetSplitCurvesByPts(pts);
|
|
|
|
if (cs.length === 2)
|
|
|
|
if (cs.length === 2)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
let box = SortEntityByBox(cs, true);
|
|
|
|
let box = SortEntityByBox(cs, true);
|
|
|
|
index === 0 ? outputCus[i] = cs[index] : outputCus[j] = cs[index];
|
|
|
|
outputCus[index === 0 ? i : j] = cs[index]
|
|
|
|
boxCurves.set(cs[index], box.get(cs[index]));
|
|
|
|
boxCurves.set(cs[index], box.get(cs[index]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
@ -177,11 +180,11 @@ export class PolyOffestUtil
|
|
|
|
return outputCus;
|
|
|
|
return outputCus;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//偏移曲线
|
|
|
|
//偏移曲线
|
|
|
|
private OffestCurve(pls: Curve[]): offestRes[]
|
|
|
|
private OffestCurve(pls: Curve[]): offsetRes[]
|
|
|
|
{
|
|
|
|
{
|
|
|
|
return pls.map((cu, index) =>
|
|
|
|
return pls.map((cu, index) =>
|
|
|
|
{
|
|
|
|
{
|
|
|
|
let curve = cu.GetOffsetCurves(this.m_OffestDist)[0];
|
|
|
|
let curve = cu.GetOffsetCurves(this.m_OffsetDist)[0];
|
|
|
|
return { curve, index };
|
|
|
|
return { curve, index };
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -262,10 +265,10 @@ export class PolyOffestUtil
|
|
|
|
* 连接修剪相邻曲线,并构造修剪轮廓
|
|
|
|
* 连接修剪相邻曲线,并构造修剪轮廓
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @private
|
|
|
|
* @param {offestRes[]} offResList
|
|
|
|
* @param {offsetRes[]} offResList
|
|
|
|
* @memberof PolyOffestUtil
|
|
|
|
* @memberof PolyOffestUtil
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
private TrimAndBuildContour(offResList: offestRes[])
|
|
|
|
private TrimAndBuildContour(offResList: offsetRes[])
|
|
|
|
{
|
|
|
|
{
|
|
|
|
arrayRemoveIf(offResList, r => !r.curve || equaln(r.curve.Length, 0, 1e-6));
|
|
|
|
arrayRemoveIf(offResList, r => !r.curve || equaln(r.curve.Length, 0, 1e-6));
|
|
|
|
|
|
|
|
|
|
|
@ -561,6 +564,7 @@ export class PolyOffestUtil
|
|
|
|
* @param {Circle} cir 补圆
|
|
|
|
* @param {Circle} cir 补圆
|
|
|
|
* @param {Vector3} startPt 补圆的切割点1
|
|
|
|
* @param {Vector3} startPt 补圆的切割点1
|
|
|
|
* @param {Vector3} endPt 补圆的切割点2
|
|
|
|
* @param {Vector3} endPt 补圆的切割点2
|
|
|
|
|
|
|
|
* @param {boolean} isbuildCir 是否构建圆轮廓
|
|
|
|
* @returns
|
|
|
|
* @returns
|
|
|
|
* @memberof PolyOffestUtil
|
|
|
|
* @memberof PolyOffestUtil
|
|
|
|
*/
|
|
|
|
*/
|
|
|
@ -574,15 +578,19 @@ export class PolyOffestUtil
|
|
|
|
{
|
|
|
|
{
|
|
|
|
let arc1 = splitCus[0] as Arc;
|
|
|
|
let arc1 = splitCus[0] as Arc;
|
|
|
|
let arc2 = splitCus[1] as Arc;
|
|
|
|
let arc2 = splitCus[1] as Arc;
|
|
|
|
|
|
|
|
|
|
|
|
let tmpPts = cir.IntersectWith(this.m_Polyline, IntersectOption.OnBothOperands);
|
|
|
|
let tmpPts = cir.IntersectWith(this.m_Polyline, IntersectOption.OnBothOperands);
|
|
|
|
let onCu0Pts = tmpPts.filter(p => arc1.PtOnCurve(p));
|
|
|
|
let onCu0Pts = tmpPts.filter(p => arc1.PtOnCurve(p));
|
|
|
|
let onCu1Pts = tmpPts.filter(p => arc2.PtOnCurve(p));
|
|
|
|
let onCu1Pts = tmpPts.filter(p => arc2.PtOnCurve(p));
|
|
|
|
|
|
|
|
|
|
|
|
let lastCu = arrayLast(this.m_RetCurves);
|
|
|
|
let lastCu = arrayLast(this.m_RetCurves);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//让圆弧保持和最后一段首尾相连
|
|
|
|
if (!equal(arc1.StartPoint, lastCu.EndPoint))
|
|
|
|
if (!equal(arc1.StartPoint, lastCu.EndPoint))
|
|
|
|
arc1.Reverse();
|
|
|
|
arc1.Reverse();
|
|
|
|
if (!equal(arc2.StartPoint, lastCu.EndPoint))
|
|
|
|
if (!equal(arc2.StartPoint, lastCu.EndPoint))
|
|
|
|
arc2.Reverse();
|
|
|
|
arc2.Reverse();
|
|
|
|
|
|
|
|
|
|
|
|
//优先选择和源线段不想交的圆弧,如果都相交或者都不相交,选择和最后一段切线接近的圆弧
|
|
|
|
//优先选择和源线段不想交的圆弧,如果都相交或者都不相交,选择和最后一段切线接近的圆弧
|
|
|
|
let cu: Arc;
|
|
|
|
let cu: Arc;
|
|
|
|
if (onCu0Pts.length === onCu1Pts.length)
|
|
|
|
if (onCu0Pts.length === onCu1Pts.length)
|
|
|
@ -652,7 +660,8 @@ export class PolyOffestUtil
|
|
|
|
let cus = l.GetSplitCurves(iParams);
|
|
|
|
let cus = l.GetSplitCurves(iParams);
|
|
|
|
|
|
|
|
|
|
|
|
//移除0长度线和在轮廓内的线.
|
|
|
|
//移除0长度线和在轮廓内的线.
|
|
|
|
arrayRemoveIf(cus, cu => equaln(cu.Length, 0, 1e-6)
|
|
|
|
arrayRemoveIf(cus, cu =>
|
|
|
|
|
|
|
|
equaln(cu.Length, 0, 1e-6)
|
|
|
|
|| outline.PtInCurve(cu.GetPointAtParam(0.5))
|
|
|
|
|| outline.PtInCurve(cu.GetPointAtParam(0.5))
|
|
|
|
);
|
|
|
|
);
|
|
|
|
cus.forEach(c => boxCurves.set(c, c.BoundingBox))
|
|
|
|
cus.forEach(c => boxCurves.set(c, c.BoundingBox))
|
|
|
@ -701,7 +710,7 @@ export class PolyOffestUtil
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (pts.length > 1)
|
|
|
|
if (pts.length > 1)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
let rad2 = Math.pow(this.m_OffestDist, 2);
|
|
|
|
let rad2 = Math.pow(this.m_OffsetDist, 2);
|
|
|
|
|
|
|
|
|
|
|
|
//计算到曲线的距离大于偏移距离
|
|
|
|
//计算到曲线的距离大于偏移距离
|
|
|
|
let [ptGtRad1, ptGtRad2] = pts.map(p =>
|
|
|
|
let [ptGtRad1, ptGtRad2] = pts.map(p =>
|
|
|
|