From ecf4449962e43848762f66b08c6a0229a921d503 Mon Sep 17 00:00:00 2001 From: Zoe Date: Mon, 11 Jun 2018 16:05:30 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=B8=85=E7=90=86=E4=BC=98?= =?UTF-8?q?=E5=8C=96=EF=BC=8Cbug=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Common/ArrayExt.ts | 19 + src/Common/CurveUtils.ts | 3 +- src/DatabaseServices/Polyline.ts | 4 +- src/GraphicsSystem/OffestPolyline.ts | 770 ++------------------------- 4 files changed, 68 insertions(+), 728 deletions(-) diff --git a/src/Common/ArrayExt.ts b/src/Common/ArrayExt.ts index 6db4cc15f..2684abf22 100644 --- a/src/Common/ArrayExt.ts +++ b/src/Common/ArrayExt.ts @@ -56,6 +56,25 @@ export function arrayRemoveIf(arr: Array, checkFuntion: (e: T) => boolean) return arr; } +export function arrayRemoveIf2(arr: Array, checkFuntion: (e: T) => boolean): Array +{ + let j = 0; + let removeArr = []; + for (let i = 0, l = arr.length; i < l; i++) + { + if (!checkFuntion(arr[i])) + { + arr[j++] = arr[i]; + } + else + { + removeArr.push(arr[i]); + } + } + arr.length = j; + + return removeArr; +} export function arrayFirst(arr: Array): T { diff --git a/src/Common/CurveUtils.ts b/src/Common/CurveUtils.ts index 7534ead2b..293c2be23 100644 --- a/src/Common/CurveUtils.ts +++ b/src/Common/CurveUtils.ts @@ -103,10 +103,9 @@ export function curveLinkGroup(cus: Curve[]): Array> let isClose = c.IsClose; if (isClose) groupCus.push([c]); - return !isClose; }); - + if (cus.length === 0) return groupCus; //曲线节点图 let cuMap = new CurveMap(); cus.forEach(c => cuMap.addCurveToMap(c)); diff --git a/src/DatabaseServices/Polyline.ts b/src/DatabaseServices/Polyline.ts index e96851329..dc81cf619 100644 --- a/src/DatabaseServices/Polyline.ts +++ b/src/DatabaseServices/Polyline.ts @@ -9,7 +9,7 @@ import { FixIndex } from '../Common/Utils'; import { equal, equaln, rotatePoint, updateGeometry } from '../Geometry/GeUtils'; import { RenderType } from '../GraphicsSystem/Enum'; import { IntersectOption, IntersectPolylineAndCurve } from '../GraphicsSystem/IntersectWith'; -import { PolyOffestUtil, PolyOffestUtil1 } from '../GraphicsSystem/OffestPolyline'; +import { PolyOffestUtil } from '../GraphicsSystem/OffestPolyline'; import { Arc } from './Arc'; import { Factory } from './CADFactory'; import { CADFile } from './CADFile'; @@ -746,7 +746,7 @@ export class Polyline extends Curve //偏移 GetOffsetCurves(offsetDist: number): Array { - let polyOffestUtil = new PolyOffestUtil1(this, offsetDist); + let polyOffestUtil = new PolyOffestUtil(this, offsetDist); return polyOffestUtil.GetOffsetCurves(); } /** diff --git a/src/GraphicsSystem/OffestPolyline.ts b/src/GraphicsSystem/OffestPolyline.ts index 2402d8d46..a7568e6b5 100644 --- a/src/GraphicsSystem/OffestPolyline.ts +++ b/src/GraphicsSystem/OffestPolyline.ts @@ -1,6 +1,6 @@ import { Box3, Vector3 } from "three"; import { arrayLast, arrayRemoveIf } from "../Common/ArrayExt"; -import { curveLinkGroup, getCirAngleByChordAndTangent, Vec2DTo3D, Vec3DTo2D } from "../Common/CurveUtils"; +import { curveLinkGroup, getCirAngleByChordAndTangent, Vec2DTo3D } from "../Common/CurveUtils"; import { FixIndex } from "../Common/Utils"; import { Arc } from "../DatabaseServices/Arc"; import { Circle } from "../DatabaseServices/Circle"; @@ -9,723 +9,56 @@ import { Curve } from "../DatabaseServices/Curve"; import { Line } from "../DatabaseServices/Line"; import { Polyline } from '../DatabaseServices/Polyline'; import { equal, equaln } from "../Geometry/GeUtils"; -import { IsPtsAllOutOrOnReg, isTargetCurInOrOnSourceCur, isTargetCurOutOrOnSourceCur } from "./BoolOperateUtils"; +import { IsPtsAllOutOrOnReg } from "./BoolOperateUtils"; import { IntersectOption } from "./IntersectWith"; -import { LinkSelf } from "./LinkSelft"; -import { ptInRectOrCircle } from "../DatabaseServices/PointInPolyline"; interface offestRes { index: number, curve: Curve } +//FIXME:1当轮廓自交时,会丢失自交的线段 +//FIXME:2往内偏移到极限位置,会有多余线段 +//FIXME:3线段共线时,有时造成线段不连续 export class PolyOffestUtil { private m_Polyline: Polyline; private m_OffestDist: number; - // private m_OffDir: number; - private IsKeepAllCurves = false; //为true时 保留全部,不优化裁剪 constructor(pl: Polyline, offest: number) { this.m_Polyline = pl; this.m_OffestDist = offest; - // this.m_OffDir = Math.sign(this.m_OffestDist) * Math.sign(this.m_Polyline.Area2); } //偏移 GetOffsetCurves(): Curve[] { let expCus = this.m_Polyline.Explode(); let offres1 = this.offestCurve(expCus, this.m_OffestDist); - let offres2 = this.offestCurve(expCus, -this.m_OffestDist); let contours: Contour[] = []; - for (let i = 0; i < offres1.length; i++) - { - let cu1 = offres1[i].curve; - let cu2 = offres2[i].curve; - let con = this.buildContourByTwoSideOfest(cu1, cu2); - con && contours.push(con); - - //加入每个顶点的圆 - let originCu = this.m_Polyline.GetCurveAtIndex(i); - if (i === 0 && !this.m_Polyline.IsClose) - contours.push(Contour.CreateContour([new Circle(originCu.StartPoint, Math.abs(this.m_OffestDist))])); - contours.push(Contour.CreateContour([new Circle(originCu.EndPoint, Math.abs(this.m_OffestDist))])); - } - // contours.forEach(c => - // { - // c.Outline.ColorIndex = 2; - // app.m_Database.ModelSpace.Append(c.Outline); - // }) - // console.time("trim"); - let newPls = this.trimAndJointOffestPolyline(offres1); - console.timeEnd("trim"); - console.time("con"); - let cus = this.trimByContours(newPls, contours); - // console.timeEnd("con"); - - // console.time("link"); - let rets = this.linkSelfingCurves2(cus); - // console.timeEnd('link'); - - if (!this.IsKeepAllCurves) - { - // console.time('k'); - rets = this.optimizeCus(rets); - // console.timeEnd('k'); - } - return rets; - // return []; - } - /** - * 过滤优化曲线数组 - * 先将曲线闭合,在排除和第一段有交点且不闭合的曲线 - * @param {Polyline[]} rets - * @returns - * @memberof PolyOffestUtil - */ - optimizeCus(rets: Polyline[]) - { - if (this.m_Polyline.IsClose) - { - return rets.map(l => this.closePolyline(l)).filter(l => l.IsClose) - } - else - { - if (rets.length <= 1) return rets; - let deleteCus: Set = new Set(); - - for (let i = 0; i < rets.length; i++) - { - let cu1 = rets[0]; - if (cu1.IsClose) continue; - for (let j = i + 1; j < rets.length; j++) - { - let cu2 = rets[j]; - if (cu2.IsClose) continue; - - let [tmpCu1, tmpCu2] = cu1.Length > cu2.Length ? [cu1, cu2] : [cu2, cu1]; - if (!this.compareCus(tmpCu1, tmpCu2)) - { - deleteCus.add(tmpCu2); - } - } - } - rets = rets.filter(cu => !deleteCus.has(cu)); - } - return rets; - } - compareCus(srcLine: Polyline, tarLine: Polyline) - { - let pts = tarLine.PtsBuls.pts; - return pts.some(p => - { - let p1 = Vec2DTo3D(p); - let closePt = srcLine.GetClosestPointTo(p1, false); - let dist = closePt.distanceToSquared(p1); - return dist > Math.pow(this.m_OffestDist, 2); - }) - } - //偏移曲线 - private offestCurve(pls: Curve[], dis: number): offestRes[] - { - return pls.map((cu, index) => - { - let curve = cu.GetOffsetCurves(dis)[0]; - return { curve, index }; - }); - } - //通过2侧偏移曲线构建封闭轮廓,由于是双向偏移,所以不可能出现2个曲线都为空的情况 - private buildContourByTwoSideOfest(pl1: Curve, pl2: Curve) - { - if (pl1 && pl2) - { - // 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]); - return Contour.CreateContour([pl1.Clone() as Curve, pl2.Clone() as Curve, new Line(pl1.StartPoint, pl2.StartPoint), new Line(pl1.EndPoint, pl2.EndPoint)]); - } - else if (pl1 || pl2) - { - let arc = pl1 ? pl1.Clone() as Arc : pl2.Clone() as Arc; - let l1 = new Line(arc.Center, arc.StartPoint); - let l2 = new Line(arc.Center, arc.EndPoint); - return Contour.CreateContour([arc, l1, l2]); - } - else - { - console.error("错误,2曲线为未定义"); - return undefined; - } - } - // 修剪连接相邻曲线 - private trimAndJointOffestPolyline(offResList: offestRes[]) - { - offResList = offResList.filter(r => r.curve && !equaln(r.curve.Length, 0, 1e-6)); - if (offResList.length <= 1) - return offResList.map(r => r.curve); - - let retPlList: Array = []; - - let nextPt: Vector3 = offResList[0].curve.StartPoint; - - for (let i = 0; i < offResList.length; i++) - { - //前面线 - let frontLine = offResList[i].curve; - - //后面线 - let laterLine: Curve; - //如果是闭合的,继续循环,否则直接添加到新数组列表 - if (i === offResList.length - 1) - { - if (retPlList.length === 0) - break; - - if (this.m_Polyline.IsClose) - laterLine = retPlList[0]; - else - { - this.appendNewPllist(frontLine, nextPt, frontLine.EndPoint, retPlList); - break; - } - } - else - laterLine = offResList[i + 1].curve; - - //默认交点 - let interPt = frontLine.EndPoint; - // 如果两线结合点不相等,调整交点位置 - if (!equal(frontLine.EndPoint, laterLine.StartPoint)) - { - // 源线段对应索引 - let startIndex = offResList[i].index; - let endIndex = offResList[FixIndex(i + 1, offResList)].index; - let isFillArc = endIndex - startIndex !== 1; - if (endIndex === 0) - { - endIndex = this.m_Polyline.EndParam - 1; - isFillArc = this.m_Polyline.EndParam - 1 !== startIndex; - endIndex = isFillArc ? endIndex : 0; - } - // 多段线交点数组 - let interPts = frontLine.IntersectWith(laterLine, IntersectOption.ExtendBoth); - - //如果有圆弧丢失或者没有交点,则用圆弧连接 - if (isFillArc || interPts.length === 0) - { - //偏移线段对应的源线段,取其起始点作为圆心 - this.fillArc(startIndex, endIndex, nextPt, frontLine, laterLine, retPlList); - continue; - } - else - { - let pts = interPts.filter(p => frontLine.PtOnCurve(p) && laterLine.PtOnCurve(p)); - interPt = this.selectFitInterPt(pts.length ? pts : interPts, frontLine.EndPoint); - if (pts.length > 0) - { - this.appendNewPllist(frontLine, nextPt, interPt, retPlList); - } - else - { - this.checkCuAndAppendList(frontLine, laterLine, interPt, nextPt, retPlList, endIndex); - } - - } - } - else - this.appendNewPllist(frontLine, nextPt, frontLine.EndPoint, retPlList); - - if (i === offResList.length - 1)//曲线闭合时,修改第一条线的起点 - { - laterLine.StartPoint = nextPt; - } - } - 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); - newPlList.push(newCu); - } - /** - * 检测偏移线段是否有效并加入结果曲线数组 - * - * @private - * @param {Curve} frontLine - * @param {Curve} laterLine - * @param {Vector3} intPt - * @param {Vector3} nextPt - * @param {Curve[]} newPlList - * @param {number} endIndex - * @memberof PolyOffestUtil - */ - private checkCuAndAppendList(frontLine: Curve, laterLine: Curve, intPt: Vector3, nextPt: Vector3, newPlList: Curve[], endIndex: number) - { - let par1 = frontLine.GetParamAtPoint(intPt); - - if (frontLine instanceof Arc && laterLine instanceof Arc) - { - let isOnFline = frontLine.PtOnCurve(intPt); - let isOnLline = laterLine.PtOnCurve(intPt); - if ((!isOnFline && !isOnLline)) - { - this.appendNewPllist(frontLine, nextPt, intPt, newPlList); - } - else - { - this.fillArc(endIndex - 1, endIndex, nextPt, frontLine, laterLine, newPlList); - } - } - else - { - let par2 = laterLine.GetParamAtPoint(intPt); - if (par1 > 1) - { - this.appendNewPllist(frontLine, nextPt, intPt, newPlList); - } - else if (par1 < 0 && par2 < 0 && frontLine instanceof Arc) - { - this.fillArc(endIndex - 1, endIndex, nextPt, frontLine, laterLine, newPlList); - } - else - { - this.appendNewPllist(frontLine, nextPt, frontLine.EndPoint, newPlList); - newPlList.push(new Line(frontLine.EndPoint, laterLine.StartPoint)); - nextPt.copy(laterLine.StartPoint); - } - } - } - /** - * 补圆弧 - * - * @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点距离 - let startDist = frontLine.EndPoint.distanceToSquared(centerPt); - //圆心到后面线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)); - let splitCus = cir1.GetSplitCurves(pars); - if (splitCus.length === 2) - { - let cu = splitCus[0].Length < splitCus[1].Length ? splitCus[0] : splitCus[1]; - let lastCu = arrayLast(retPlList); - //如果不是首尾相连,就反转后在存入数组 - if (!equal(cu.StartPoint, lastCu.EndPoint)) - cu.Reverse(); - - nextPt.copy(intPt); - if (equaln(cu.Length, 0, 1e-6)) - { - return; - } - retPlList.push(cu); - } else nextPt.copy(intPt); - } - - if (!equaln(startDist, endDist)) - { - let rad = Math.abs(this.m_OffestDist); - // 以centerPt为圆心,偏移距离为为半径画圆 - let tmpCir = new Circle(centerPt, rad); - //只会和前面线相交,因为圆心选取是根据后面线startPoint偏移距离处的点,只会与后面线相切,允许前面线延伸 - let pts = tmpCir.IntersectWith(frontLine, IntersectOption.OnBothOperands); - if (pts.length > 0) - { - //选取交点,如果有多个选离前面线start点近的 - intPt = this.selectFitInterPt(pts, frontLine.StartPoint); - frontLine.EndPoint = intPt; - } - else - { - let cirs: Circle[] = []; - for (let i = startIndex + 1; i <= endIndex; i++) - { - let center = this.m_Polyline.GetPointAtParam(i); - cirs.push(new Circle(center, rad)); - } - - let pts = frontLine.IntersectWith(cirs[0], IntersectOption.OnBothOperands); - let inPt = this.selectFitInterPt(pts, frontLine.EndPoint); - if (!inPt) - { - console.log(this.m_OffestDist); - } - this.appendNewPllist(frontLine, nextPt, inPt, retPlList); - - for (let i = 0; i < cirs.length - 1; i++) - { - let cir1 = cirs[i]; - let cir2 = cirs[i + 1]; - let pts = cir1.IntersectWith(cir2, IntersectOption.OnBothOperands); - let intPt = this.selectFitInterPt(pts, nextPt); - buildArcJoinList(cir1, intPt); - - if (i === cirs.length - 2) - { - buildArcJoinList(cir2, laterLine.StartPoint); - } - } - // 补完圆弧直接退出函数 - return; - } - } - //改用根据laterline切线和弦判断圆心角及方向 - let chord = intPt.clone().sub(laterLine.StartPoint); - let tangent = laterLine.GetFistDeriv(0).negate().normalize(); - let circleAngle = -getCirAngleByChordAndTangent(chord, tangent); - - this.appendNewPllist(frontLine, nextPt, intPt, retPlList, laterLine); - - nextPt.copy(laterLine.StartPoint); - - let arc = new Arc().ParseFromBul(intPt, laterLine.StartPoint, Math.tan(circleAngle / 4)); - retPlList.push(arc); - - } - - // 通过构建的轮廓对偏移曲线进行裁剪 - private trimByContours(needCutCus: Curve[], cons: Contour[]): Curve[] - { - cons.forEach(c => - { - let tmpCus: Curve[] = []; - let outline = c.Outline; - for (let l of needCutCus) - { - // let posSrcForTar = TargetCurPosForSourceCur(outline, l as Arc | Line); - // if (posSrcForTar.onSrc || posSrcForTar.outSrc) - // { - // tmpCus.push(l); - // } - // else if (posSrcForTar.throughSrc) - // { - // let par = posSrcForTar.pts.map(p => l.GetParamAtPoint(p)); - // let cus = l.GetSplitCurves(par); - // if (cus.length === 0) - // { - // tmpCus.push(l); - // } - // else - // { - // tmpCus.push(...cus.filter(cu => !equaln(cu.Length, 0, 1e-6) && isTargetCurOutOrOnSourceCur(outline, cu))); - // } - // } - // else - // { - // l instanceof Arc && tmpCus.push(l); - // } - - // 在上面或者在外面 - if (isTargetCurOutOrOnSourceCur(outline, l)) - { - tmpCus.push(l); - } - else if (!isTargetCurInOrOnSourceCur(outline, l)) - { - let pts = l.IntersectWith(outline, IntersectOption.OnBothOperands); - if (pts.length > 0) - { - let par = pts.map(p => l.GetParamAtPoint(p)); - let cus = l.GetSplitCurves(par); - - if (cus.length > 0) - tmpCus.push(...cus.filter(cu => !equaln(cu.Length, 0, 1e-6) && !isTargetCurInOrOnSourceCur(outline, cu))); - else - { - tmpCus.push(l); - } - } - } - else - { - // l instanceof Arc && tmpCus.push(l); - } - } - needCutCus = tmpCus; - }) - return needCutCus; - } - /** - * 判断曲线是否自交 - * - * @private - * @param {Curve[]} cus - * @returns - * @memberof PolyOffestUtil3 - */ - private isSelfingCus(cus: Curve[]): boolean - { - if (cus.length <= 1) return false; - for (let i = 0; i < cus.length; i++) - { - let frontLine = cus[i]; - for (let j = cus.length - 1; j > i; j--) - { - let laterLine = cus[j]; - let pts = frontLine.IntersectWith(laterLine, IntersectOption.OnBothOperands); - pts = pts.filter(p => - { - return !(equal(p, frontLine.StartPoint) && equal(p, laterLine.EndPoint) || (equal(frontLine.EndPoint, p) && equal(laterLine.StartPoint, p))) - }); - if (pts.length) return true; - } - } - return false; - } - //连接最终曲线 - private linkCurves(cus: Curve[]): Polyline[] - { - let groups = curveLinkGroup(cus); - let resultPls: Polyline[] = []; - for (let g of groups) - { - let pl = new Polyline(); - for (let cu of g) - { - pl.Join(cu); - } - resultPls.push(pl) - } - return resultPls; - } - private linkCurves2(cus: Curve[] | Set): Polyline - { - let pl = new Polyline(); - for (let cu of cus) - { - pl.Join(cu); - } - return pl; - } - /** - *连接自交曲线数组 - * - * @param {Curve[]} cus - * @returns - * @memberof PolyOffestUtil3 - */ - linkSelfingCurves(cus: Curve[]): Polyline[] - { - let retPls: Polyline[] = []; - let isSelfing = this.isSelfingCus(cus); - while (cus.length && isSelfing) - { - let pl = new Polyline(); - let frontLine = cus.shift(); - - let end = 0; - - for (let j = cus.length - 1; j >= end; j--) - { - let laterLine = cus[j]; - let pts = frontLine.IntersectWith(laterLine, IntersectOption.OnBothOperands); - if (pts.length === 2) - { - pts = pts.filter(p => - { - return !(equal(frontLine.EndPoint, p) && equal(laterLine.StartPoint, p)) - }); - } - pts = pts.filter(p => - { - return !(equal(frontLine.StartPoint, p) && equal(laterLine.EndPoint, p)) - }); - if (pts.length) - { - //TODO:判断0~j之间的曲线是否自交,不自觉直接按顺序连接起来 - let parForFront = frontLine.GetParamAtPoint(pts[0]); - let parForLater = laterLine.GetParamAtPoint(pts[0]); - - if (equaln(parForLater, 1)) - { - continue; - } - - if (equaln(parForFront, 0, 1e-6)) - { - //理论应该把该段移除出来 - continue; - } - else if (equaln(parForFront, 1, 1e-6)) - { - pl.Join(frontLine); - } - else - { - let spliteCusForFront = frontLine.GetSplitCurves(parForFront); - pl.Join(spliteCusForFront[0]); - cus.unshift(spliteCusForFront[1]); - j++; - } - if (equaln(parForLater, 0, 1e-6)) - frontLine = cus.splice(j, 1)[0]; - else - { - let splitCus = laterLine.GetSplitCurves(parForLater); - cus[j].EndPoint = pts[0]; - frontLine = splitCus[1]; - } - end = j; - j = cus.length; - } - - //搜索到尽头,先直接join,先不判断 - if (end >= j) - { - pl.Join(frontLine); - break; - } - } - - retPls.push(pl); - isSelfing = this.isSelfingCus(cus); - - } - retPls.push(...this.linkCurves(cus)); - return retPls; - } - // - linkSelfingCurves2(cus: Curve[]): Polyline[] - { - let retPls: Polyline[] = []; - let retsCus = new LinkSelf(cus); - let noSealCus = retsCus.noSealCus.map(cs => - { - return this.linkCurves2(cs); - }) - let sealCus = retsCus.sealCus.map(s => - { - return this.linkCurves2(s); - }) - // let firstLine = noSealCus[0]; - // noSealCus.sort((a, b) => b.Length - a.Length); - // if (firstLine !== noSealCus[0]) - // { - // retPls.push(noSealCus[0]); - // } - // firstLine && retPls.push(firstLine); - retPls.push(...noSealCus); - retPls.push(...sealCus); - return retPls; - } - closePolyline(pl: Polyline) - { - //闭合或者只有一条线段或者2条线段都是直线的,直接返回 - if (pl.IsClose || pl.EndParam < 2 || ((pl.EndParam === 2 && pl.GetBuilgeAt(0) == 0 && pl.GetBuilgeAt(1) == 0))) - return pl; - - for (let i = 0; i < pl.EndParam; i++) - { - let frontCu = pl.GetCurveAtIndex(i); - for (let j = pl.EndParam - 1; j > i; j--) - { - let lastCu = pl.GetCurveAtIndex(j); - let pts = frontCu.IntersectWith(lastCu, IntersectOption.OnBothOperands); - - - pts = pts.filter(p => - { - return !(equal(p, frontCu.EndPoint) && equal(p, lastCu.StartPoint)) && !(equal(p, frontCu.StartPoint) && equal(p, lastCu.EndPoint)) - }) - - if (pts.length == 1) - { - let polyProps = pl.LineData.slice(i, j + 2); - polyProps[0].pt = Vec3DTo2D(pts[0]); - if (frontCu instanceof Arc) - { - frontCu.StartPoint = pts[0]; - polyProps[0].bul = Math.tan(frontCu.AllAngle / 4) * Math.sign(polyProps[0].bul); - } - arrayLast(polyProps).pt = Vec3DTo2D(pts[0]); - return new Polyline(polyProps); - - } - else if (pts.length > 1) - { - console.warn("未知情况"); - } - } - } - return pl; - } - // 选择合适的交点 - private selectFitInterPt(pts: Vector3[], refPt: Vector3) - { - let pt = pts[0]; - if (pts.length > 1) - { - let dist1 = refPt.distanceToSquared(pts[0]); - let dist2 = refPt.distanceToSquared(pts[1]); - pt = dist1 <= dist2 ? pts[0] : pts[1]; - } - return pt; - } -} -export class PolyOffestUtil1 -{ - private m_Polyline: Polyline; - private m_OffestDist: number; - constructor(pl: Polyline, offest: number) - { - this.m_Polyline = pl; - this.m_OffestDist = offest; - } - //偏移 - GetOffsetCurves(): Curve[] - { - let expCus = this.m_Polyline.Explode(); - let offres1 = this.offestCurve(expCus, this.m_OffestDist); - - let contours: Contour[] = []; - let rad = Math.abs(this.m_OffestDist) + let rad = Math.abs(this.m_OffestDist); this.m_Polyline.PtsBuls.pts.forEach(p => { let cir = new Circle(Vec2DTo3D(p).applyMatrix4(this.m_Polyline.OCS), rad); contours.push(Contour.CreateContour([cir])) }) - console.time("join") + // console.time("join") let cus = this.trimAndJointOffestPolyline(offres1, contours); - console.timeEnd("join") + // console.timeEnd("join") // testContours(contours); - console.time("trim") + // console.time("trim") cus = this.trimByContours(cus, contours).filter(c => { if (c.IntersectWith(this.m_Polyline, IntersectOption.OnBothOperands).length !== 0) return false; + let rad2 = Math.pow(this.m_OffestDist, 2); let dist1 = this.m_Polyline.GetClosestPointTo(c.StartPoint, false).distanceToSquared(c.StartPoint); + if (dist1 - rad2 < -1e-3) return false; let dist2 = this.m_Polyline.GetClosestPointTo(c.EndPoint, false).distanceToSquared(c.EndPoint); - let rad2 = Math.pow(this.m_OffestDist, 2); - return (dist1 - rad2 >= -1e-3 || dist2 - rad2 >= -1e-3); + return dist2 - rad2 >= -1e-3; }); - console.timeEnd("trim") - + // console.timeEnd("trim") return this.linkCurves(cus); } //偏移曲线 @@ -767,7 +100,7 @@ export class PolyOffestUtil1 let rets: Array = []; - let nextPt: Vector3 = offResList[0].curve.StartPoint; + let nextStartPt: Vector3 = offResList[0].curve.StartPoint; for (let i = 0; i < offResList.length; i++) { @@ -787,7 +120,7 @@ export class PolyOffestUtil1 laterLine = rets[0]; else { - this.appendNewPllist(frontLine, nextPt, frontLine.EndPoint, rets, startIndex, cons); + this.appendNewCuAndContour(frontLine, nextStartPt, frontLine.EndPoint, rets, startIndex, cons); break; } } @@ -799,59 +132,60 @@ export class PolyOffestUtil1 // 如果两线结合点不相等,调整交点位置 if (!equal(frontLine.EndPoint, laterLine.StartPoint)) { + // 后面线对应源线段索引 let endIndex = offResList[FixIndex(i + 1, offResList)].index; + //是否补圆弧,如果中间缺线段就补,如果最后一段不是源线段最大索引,也补圆弧 let isFillArc = endIndex - startIndex !== 1; if (endIndex === 0) { endIndex = this.m_Polyline.EndParam - 1; - isFillArc = this.m_Polyline.EndParam - 1 !== startIndex; + isFillArc = endIndex !== startIndex; endIndex = isFillArc ? endIndex : 0; } // 多段线交点数组 let interPts = frontLine.IntersectWith(laterLine, IntersectOption.ExtendBoth); + let pts = interPts.filter(p => frontLine.PtOnCurve(p) && laterLine.PtOnCurve(p)); - //如果有圆弧丢失或者没有交点,则用圆弧连接 - if (isFillArc || interPts.length === 0) + //如果有圆弧丢失或者没有交点,则用圆弧连接,如果有交点同时存在2线段,则直接连接(与AutoCad一致) + if ((isFillArc && pts.length === 0) || interPts.length === 0) { //偏移线段对应的源线段,取其起始点作为圆心 - this.fillArc(startIndex, endIndex, nextPt, frontLine, laterLine, rets, cons); + this.fillArc(startIndex, endIndex, nextStartPt, frontLine, laterLine, rets, cons); continue; } else { - let pts = interPts.filter(p => frontLine.PtOnCurve(p) && laterLine.PtOnCurve(p)); - interPt = this.selectFitInterPt1(pts.length ? pts : interPts); + interPt = this.selectFitInterPt(pts.length ? pts : interPts, frontLine.EndPoint); if (pts.length > 0) { - this.appendNewPllist(frontLine, nextPt, interPt, rets, startIndex, cons); + this.appendNewCuAndContour(frontLine, nextStartPt, interPt, rets, startIndex, cons); } else { - this.checkCuAndAppendList(frontLine, laterLine, interPt, nextPt, rets, startIndex, endIndex, cons); + this.checkCuAndAppendList(frontLine, laterLine, interPt, nextStartPt, rets, startIndex, endIndex, cons); } - } } else - this.appendNewPllist(frontLine, nextPt, frontLine.EndPoint, rets, startIndex, cons); + this.appendNewCuAndContour(frontLine, nextStartPt, frontLine.EndPoint, rets, startIndex, cons); if (i === offResList.length - 1)//曲线闭合时,修改第一条线的起点 { - laterLine.StartPoint = nextPt; + laterLine.StartPoint = nextStartPt; } } return rets; } - //将线段拷贝并修改,加入到结果数组里面. - appendNewPllist(frontLine: Curve, nextPt: Vector3, interPt: Vector3, newPlList: Curve[], index: number, cons: Contour[]) + //将线段拷贝并修改,加入到结果数组里面,构建轮廓加入轮廓数组. + appendNewCuAndContour(frontLine: Curve, nextStartPt: Vector3, interPt: Vector3, newCuList: Curve[], index: number, cons: Contour[]) { + //复制一条新曲线,修改起始点和终止点,并修改下一段的起始点 let newCu = frontLine.Clone() as Curve; - - newCu.StartPoint = nextPt; + newCu.StartPoint = nextStartPt; newCu.EndPoint = interPt; - nextPt.copy(interPt); - newPlList.push(newCu); + nextStartPt.copy(interPt); + newCuList.push(newCu); let originCu = this.m_Polyline.GetCurveAtParam(index); cons.push(this.buildContourByTwoSideOfest(originCu, newCu)); } @@ -875,9 +209,9 @@ export class PolyOffestUtil1 { let isOnFline = frontLine.PtOnCurve(intPt); let isOnLline = laterLine.PtOnCurve(intPt); - if ((!isOnFline && !isOnLline)) + if (!isOnFline && !isOnLline) { - this.appendNewPllist(frontLine, nextPt, intPt, newPlList, startIndex, cons); + this.appendNewCuAndContour(frontLine, nextPt, intPt, newPlList, startIndex, cons); } else { @@ -889,7 +223,7 @@ export class PolyOffestUtil1 let par2 = laterLine.GetParamAtPoint(intPt); if (par1 > 1) { - this.appendNewPllist(frontLine, nextPt, intPt, newPlList, startIndex, cons); + this.appendNewCuAndContour(frontLine, nextPt, intPt, newPlList, startIndex, cons); } else if (par1 < 0 && par2 < 0 && frontLine instanceof Arc) { @@ -897,7 +231,7 @@ export class PolyOffestUtil1 } else { - this.appendNewPllist(frontLine, nextPt, frontLine.EndPoint, newPlList, startIndex, cons); + this.appendNewCuAndContour(frontLine, nextPt, frontLine.EndPoint, newPlList, startIndex, cons); newPlList.push(new Line(frontLine.EndPoint, laterLine.StartPoint)); nextPt.copy(laterLine.StartPoint); } @@ -957,7 +291,7 @@ export class PolyOffestUtil1 if (pts.length > 0) { //选取交点,如果有多个选离前面线start点近的 - intPt = this.selectFitInterPt1(pts); + intPt = this.selectFitInterPt(pts, frontLine.StartPoint); frontLine.EndPoint = intPt; } else @@ -979,20 +313,20 @@ export class PolyOffestUtil1 cirs.shift(); } - let inPt = this.selectFitInterPt1(pts); + let inPt = this.selectFitInterPt(pts, frontLine.EndPoint); if (!inPt) { console.log(this.m_OffestDist); } - this.appendNewPllist(frontLine, nextPt, inPt, retPlList, startIndex, cons); + this.appendNewCuAndContour(frontLine, nextPt, inPt, retPlList, startIndex, cons); for (let i = 0; i < cirs.length - 1; i++) { let cir1 = cirs[i]; let cir2 = cirs[i + 1]; let pts = cir1.IntersectWith(cir2, IntersectOption.OnBothOperands); - let intPt = this.selectFitInterPt1(pts); + let intPt = this.selectFitInterPt(pts, nextPt); buildArcJoinList(cir1, intPt); if (i === cirs.length - 2) @@ -1009,7 +343,7 @@ export class PolyOffestUtil1 let tangent = laterLine.GetFistDeriv(0).negate().normalize(); let circleAngle = -getCirAngleByChordAndTangent(chord, tangent); - this.appendNewPllist(frontLine, nextPt, intPt, retPlList, startIndex, cons); + this.appendNewCuAndContour(frontLine, nextPt, intPt, retPlList, startIndex, cons); nextPt.copy(laterLine.StartPoint); @@ -1093,26 +427,14 @@ export class PolyOffestUtil1 return resultPls; } // 选择合适的交点 - private selectFitInterPt1(pts: Vector3[]) + private selectFitInterPt(pts: Vector3[], refPt: Vector3) { let pt = pts[0]; if (pts.length > 1) { - let dist1 = this.m_Polyline.GetClosestPointTo(pts[0], false).distanceToSquared(pts[0]); - let dist2 = this.m_Polyline.GetClosestPointTo(pts[1], false).distanceToSquared(pts[1]); - let rad2 = Math.pow(this.m_OffestDist, 2); - if (equaln(dist1, rad2)) - { - pt = pts[0] - } - else if (equaln(dist2, rad2)) - { - pt = pts[1]; - } - else - { - pt = dist1 <= dist2 ? pts[0] : pts[1]; - } + let dist1 = refPt.distanceToSquared(pts[0]); + let dist2 = refPt.distanceToSquared(pts[1]); + pt = dist1 <= dist2 ? pts[0] : pts[1]; } return pt; }