From d120d83062ad556773b29163c742041bf02de81e Mon Sep 17 00:00:00 2001 From: Zoe Date: Tue, 5 Jun 2018 15:00:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A8=E6=80=81=E8=BF=9E=E6=8E=A5=E6=9B=B2?= =?UTF-8?q?=E7=BA=BF=E6=95=B0=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__snapshots__/circle.test.ts.snap | 8 + src/GraphicsSystem/LinkSelft.ts | 126 +++++++++------ src/GraphicsSystem/OffestPolyline.ts | 147 ++++++++++++++---- 3 files changed, 199 insertions(+), 82 deletions(-) diff --git a/__test__/Geometry/__snapshots__/circle.test.ts.snap b/__test__/Geometry/__snapshots__/circle.test.ts.snap index ba912f250..18dfeb2b1 100644 --- a/__test__/Geometry/__snapshots__/circle.test.ts.snap +++ b/__test__/Geometry/__snapshots__/circle.test.ts.snap @@ -143,3 +143,11 @@ Vector3 { "z": 0, } `; + +exports[`最近点2 1`] = ` +Vector3 { + "x": 10, + "y": 0, + "z": 0, +} +`; diff --git a/src/GraphicsSystem/LinkSelft.ts b/src/GraphicsSystem/LinkSelft.ts index 970291e5c..36c555bca 100644 --- a/src/GraphicsSystem/LinkSelft.ts +++ b/src/GraphicsSystem/LinkSelft.ts @@ -3,29 +3,29 @@ import { Curve } from "../DatabaseServices/Curve"; import { CurveIntersection } from "../Geometry/CurveIntersection"; import { CurveMap } from "../Geometry/CurveMap"; import { equal } from "../Geometry/GeUtils"; -import { Route, Stand } from "../Geometry/RegionParse"; +import { Stand } from "../Geometry/RegionParse"; export class LinkSelf { private curveUseData: WeakMap = new WeakMap(); private curveIndexData: WeakMap = new WeakMap(); + sealCus: Set[] = []; + noSealCus: Curve[][] = []; + private cuMap: CurveMap; constructor(cus: Curve[]) { - //打断曲线 let breakCus: Curve[] = this.BreakCurve(cus); //曲线图 用来快速搜索求交 - let cuMap = this.GenerateCurveMap(breakCus); + this.cuMap = this.GenerateCurveMap(breakCus); //自交曲线表 - let selfRoutes = this.CalCloseCurve(breakCus, cuMap); - console.log('自交列表: ', selfRoutes); + this.CalCloseCurve(breakCus, this.cuMap); //非自交曲线连接表 - let css = this.CalOrderLink(breakCus, cuMap); - console.log("没有自交的列表:", css); + this.CalOrderLink(breakCus, this.cuMap); } @@ -109,82 +109,110 @@ export class LinkSelf { this.SetCurveUse(c); } - selfRoutes.push(routeCus); + this.sealCus.push(routeCus); } } } - return selfRoutes; } //顺序连接. private CalOrderLink(breakCus: Curve[], cuMap: CurveMap) { - //没有自交的线段表 二维数组 - let css = []; - let breakCount = breakCus.length; //剩下没有被自交 for (let i = 0; i < breakCount; i++) { let cu = breakCus[i]; if (this.GetCurveUse(cu)) continue; - let cuIndex = this.GetCurveIndex(cu); + // let cuIndex = this.GetCurveIndex(cu); this.SetCurveUse(cu); let cs = [cu]; - - while (true) + //顺序连接 + this.linkCurve(cu, cuMap, cs); + //拿出第一条进行倒序连接 + cu = cs[0]; + this.linkCurve(cu, cuMap, cs, true); + } + } + linkCurve(originCu: Curve, cuMap: CurveMap, cs: Curve[], isInv: boolean = false) + { + let cuIndex = this.GetCurveIndex(originCu); + while (true) + { + let oldCount = cs.length; + let routes = cuMap.GetStand(isInv ? originCu.StartPoint : originCu.EndPoint).routes; + for (let j = routes.length; j--;) //按照索引从小到大搜索 { - let oldCount = cs.length; - let routes = cuMap.GetStand(cu.EndPoint).routes; - for (let j = routes.length; j--;) //按照索引从小到大搜索 + let cu2 = routes[j].curve; + let cu2Index = this.GetCurveIndex(cu2); + if (this.GetCurveUse(cu2)) continue; + if (cuIndex === cu2Index) { - let cu2 = routes[j].curve; - let cu2Index = this.GetCurveIndex(cu2); - if (this.GetCurveUse(cu2)) continue; - if (cuIndex === cu2Index) continue; - - if (cu2Index < cuIndex) - { - if (cs.findIndex((c) => - { - return this.GetCurveIndex(c) === cu2Index; - }) === -1) - { - continue; - } - } - //能够连接 - if (equal(cu2.StartPoint, cu.EndPoint)) - { - this.SetCurveUse(cu2); - cs.push(cu2); - cu = cu2; - cuIndex = this.GetCurveIndex(cu2); - break; - } + continue;//如果和自身的线连接,则需要判断这条路线是否合理 } - - //如果没找到 则退出循环 - if (oldCount === cs.length) + //能够连接 + let isLink = isInv ? equal(cu2.EndPoint, originCu.StartPoint) : equal(cu2.StartPoint, originCu.EndPoint); + if (isLink) { - css.push(cs); + this.SetCurveUse(cu2); + isInv ? cs.unshift(cu2) : cs.push(cu2); + originCu = cu2; + cuIndex = this.GetCurveIndex(cu2); break; } } + + //如果没找到 则退出循环 + if (oldCount === cs.length) + { + this.noSealCus.push(cs); + break; + } + } + } + //寻找最小索引的路线 + private FindMinRoute(nowStand: Stand, nowIndex: number, cs: Curve[], routes: Curve[]): { minIndex: number, routes: Curve[] } + { + //和当前索引一样的 搜索结果 + let curIndex: { minIndex: number, routes: Curve[] } = undefined; + for (let j = nowStand.routes.length; j--;) //按照索引从小到大搜索 + { + let cu = nowStand.routes[j].curve; + let cuIndex = this.GetCurveIndex(cu); + if (this.GetCurveUse(cu)) continue; + if (!equal(cu.StartPoint, nowStand.position)) continue; + if (nowIndex === cuIndex) + { + let routes2 = routes.concat();//复制数组保证函数有唯一结果 + routes2.push(cu); + curIndex = this.FindMinRoute(this.cuMap.GetStand(cu.EndPoint), nowIndex, cs, routes2); + continue; + } + + if (cuIndex < nowIndex) //小于 回归自身 + if (cs.findIndex((c) => this.GetCurveIndex(c) === cuIndex) === -1) + continue; + + if (curIndex && curIndex.minIndex < cuIndex) + return curIndex; + + //这里不复制数组,因为数组不会再被改变 + routes.push(cu); + return { minIndex: cuIndex, routes }; } - return css; + return { minIndex: Infinity, routes }; } GetCurveUse(curve: Curve): boolean { return this.curveUseData.get(curve); } - SetCurveUse(curve: Curve) + SetCurveUse(curve: Curve, use: boolean = true) { - this.curveUseData.set(curve, true); + this.curveUseData.set(curve, use); } GetCurveIndex(curve: Curve): number { diff --git a/src/GraphicsSystem/OffestPolyline.ts b/src/GraphicsSystem/OffestPolyline.ts index ecfcbf1dc..2256cb177 100644 --- a/src/GraphicsSystem/OffestPolyline.ts +++ b/src/GraphicsSystem/OffestPolyline.ts @@ -1,6 +1,6 @@ import { Vector3 } from "three"; import { arrayLast } from "../Common/ArrayExt"; -import { Vec3DTo2D, curveLinkGroup, getCirAngleByChordAndTangent, Vec2DTo3D } from "../Common/CurveUtils"; +import { Vec2DTo3D, Vec3DTo2D, curveLinkGroup, getCirAngleByChordAndTangent } from "../Common/CurveUtils"; import { FixIndex } from "../Common/Utils"; import { Arc } from "../DatabaseServices/Arc"; import { Circle } from "../DatabaseServices/Circle"; @@ -8,10 +8,10 @@ import { Contour } from "../DatabaseServices/Contour"; import { Curve } from "../DatabaseServices/Curve"; import { Line } from "../DatabaseServices/Line"; import { Polyline } from '../DatabaseServices/Polyline'; -import { equal, equaln, midPoint } from "../Geometry/GeUtils"; +import { equal, equaln } from "../Geometry/GeUtils"; import { isTargetCurInSourceCur, isTargetCurOutOrOnSourceCur } from "./BoolOperateUtils"; import { IntersectOption } from "./IntersectWith"; -import { app } from "../ApplicationServices/Application"; +import { LinkSelf } from "./LinkSelft"; interface offestRes { index: number, @@ -22,13 +22,13 @@ export class PolyOffestUtil { private m_Polyline: Polyline; private m_OffestDist: number; - private m_OffDir: 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); + // this.m_OffDir = Math.sign(this.m_OffestDist) * Math.sign(this.m_Polyline.Area2); } //偏移 GetOffsetCurves(): Curve[] @@ -61,43 +61,87 @@ export class PolyOffestUtil let newPls = this.trimAndJointOffestPolyline(offres1, this.m_Polyline); let cus = this.trimByContours(newPls, contours); - let rets = this.linkSelfingCurves(cus); + let rets = this.linkSelfingCurves2(cus); if (!this.IsKeepAllCurves) { - // 先尝试把线段相连成封闭区域 - rets = rets.map(cu => this.closePolyline(cu)).filter((l, i) => + // rets = this.optimizeCus(rets); + } + return rets; + } + /** + * 过滤优化曲线数组 + * 先将曲线闭合,在排除和第一段有交点且不闭合的曲线 + * @param {Polyline[]} rets + * @returns + * @memberof PolyOffestUtil + */ + optimizeCus(rets: Polyline[]) + { + if (rets.length <= 1) return rets; + + if (this.m_Polyline.IsClose) + { + return rets.filter(l => l.IsClose) + } + else + { + let baseline = rets[0]; + + if (!baseline.IsClose) { - if (i === 0) return true; - else + let longestCu = baseline; + for (let i = 1; i < rets.length; i++) { - return l.IsClose || l.IntersectWith(rets[0], IntersectOption.OnBothOperands).length === 0; + if (rets[i].Length > longestCu.Length) + { + longestCu = rets[i]; + } } - }); - if (this.m_Polyline.IsClose) - rets = rets.filter(l => l.IsClose); - else - rets = rets.sort((l1, l2) => l2.Length - l1.Length) - .filter((l, i) => + + if (baseline !== longestCu) + { + let isVail = this.compareCus(longestCu, baseline); + if (!isVail) { - if (i == 0) return true; - else - { - if (l.IsClose) - { - let pts = l.PtsBuls.pts; - return pts.some(p => - { - let p1 = Vec2DTo3D(p); - let closePt = rets[0].GetClosestPointTo(p1, false); - let dist = closePt.distanceToSquared(p1); - return dist > Math.pow(this.m_OffestDist, 2); - }) - } else return false; - } - }); + rets.shift(); + baseline = rets[0]; + } + } + } + rets = rets.filter((l, i) => + { + if (i === 0) return true; + else return (l.IsClose || l.IntersectWith(baseline, IntersectOption.OnBothOperands).length === 0) && this.compareCus(baseline, l); + }) + for (let i = 1; i < rets.length - 1; i++) + { + let isvail1 = this.compareCus(rets[i], rets[i + 1]); + let isvail2 = this.compareCus(rets[i + 1], rets[i]); + if (!isvail1) + { + rets.splice(i + 1, 1); + i--; + } + else if (!isvail2 && !rets[i].IsClose) + { + rets.splice(i, 1); + i--; + } + } } 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[] { @@ -417,6 +461,7 @@ export class PolyOffestUtil */ private isSelfingCus(cus: Curve[]): boolean { + if (cus.length <= 1) return false; for (let i = 0; i < cus.length; i++) { let frontLine = cus[i]; @@ -493,6 +538,7 @@ export class PolyOffestUtil }); if (pts.length) { + //TODO:判断0~j之间的曲线是否自交,不自觉直接按顺序连接起来 let parForFront = frontLine.GetParamAtPoint(pts[0]); let parForLater = laterLine.GetParamAtPoint(pts[0]); @@ -544,6 +590,41 @@ export class PolyOffestUtil retPls.push(...this.linkCurves(cus)); return retPls; } + + // + linkSelfingCurves2(cus: Curve[]): Polyline[] + { + let retPls: Polyline[] = []; + let retsCus = new LinkSelf(cus); + + retsCus.noSealCus.forEach(cs => + { + let pl = new Polyline(); + cs.forEach(c => + { + pl.Join(c) + }) + retPls.push(pl); + }) + // let seals: Polyline[] = []; + retsCus.sealCus.forEach(s => + { + let pl = new Polyline(); + s.forEach(c => + { + pl.Join(c) + }) + + retPls.push(pl); + }) + // retPls = retPls.filter((l, i) => + // { + // if (i === 0) return true; + // return seals.every(l1 => l1.IntersectWith(l, IntersectOption.OnBothOperands).length === 0) + // }) + // retPls.push(...seals); + return retPls; + } closePolyline(pl: Polyline) { //闭合或者只有一条线段或者2条线段都是直线的,直接返回