修改补圆弧圆心角方向,添加注释

pull/68/head
Zoe 6 years ago
parent 095d4ecb02
commit 23374071e2

@ -277,131 +277,6 @@ Array [
]
`;
exports[`单刀 6`] = `
Array [
Object {
"bul": 0,
"pt": Vector2 {
"x": 0,
"y": 0,
},
},
Object {
"bul": 1,
"pt": Vector2 {
"x": 5,
"y": 0,
},
},
Object {
"bul": -0.41421356237309503,
"pt": Vector2 {
"x": 5,
"y": 5,
},
},
Object {
"bul": 0,
"pt": Vector2 {
"x": 2.5,
"y": 7.5,
},
},
]
`;
exports[`单刀 7`] = `
Array [
Object {
"bul": -0.41421356237309503,
"pt": Vector2 {
"x": 2.5,
"y": 7.5,
},
},
Object {
"bul": 0,
"pt": Vector2 {
"x": 5,
"y": 10,
},
},
Object {
"bul": 0,
"pt": Vector2 {
"x": 0,
"y": 10,
},
},
Object {
"bul": 0,
"pt": Vector2 {
"x": 0,
"y": 0,
},
},
]
`;
exports[`单刀 8`] = `
Array [
Object {
"bul": 0,
"pt": Vector2 {
"x": 0,
"y": 0,
},
},
Object {
"bul": 1,
"pt": Vector2 {
"x": 5,
"y": 0,
},
},
Object {
"bul": -1,
"pt": Vector2 {
"x": 5,
"y": 5,
},
},
Object {
"bul": 0,
"pt": Vector2 {
"x": 5,
"y": 10,
},
},
]
`;
exports[`单刀 9`] = `
Array [
Object {
"bul": 0,
"pt": Vector2 {
"x": 5,
"y": 10,
},
},
Object {
"bul": 0,
"pt": Vector2 {
"x": 0,
"y": 10,
},
},
Object {
"bul": 0,
"pt": Vector2 {
"x": 0,
"y": 0,
},
},
]
`;
exports[`单刀闭合 1`] = `
Array [
Object {

@ -49,8 +49,9 @@ export class DrawPolyline implements Command
let dir: Vector3;
let KeyWordList = [{ msg: "圆弧", key: "A" }, { msg: "直线", key: "L" }, { msg: "放弃", key: "U" }];
//返回一步
let restore = () =>
//弹出循环开始就添加的线段点
let popLineProps = () =>
{
lineProps.pop();
polyline.LineData = lineProps;
@ -109,7 +110,6 @@ export class DrawPolyline implements Command
{
updateBul(ptRes.Value, basePt);
tangentLine = rotateLine(tangentLine, cirAng)
}
polyline.LineData = lineProps;
BasePts.push(basePt);
@ -155,11 +155,11 @@ export class DrawPolyline implements Command
lineProps[lineProps.length - 2].bul = 0;
this.m_Model = PolylineModel.Line;
}
restore();
popLineProps();
}
else
{
restore();
popLineProps();
break;
}
}

@ -1,5 +1,5 @@
import { Vector2, Vector3 } from "three";
import { Vec2DTo3D, Vec3DTo2D, isTargetCurInSourceCur, rotateLine } from "../Common/CurveUtils";
import { Vec2DTo3D, Vec3DTo2D, getCirAngleByChordAndTangent, rotateLine } from "../Common/CurveUtils";
import { sliceDeep } from "../Common/Utils";
import { Arc } from "../DatabaseServices/Arc";
import { Circle } from "../DatabaseServices/Circle";
@ -7,8 +7,8 @@ import { Curve } from "../DatabaseServices/Curve";
import { Line } from "../DatabaseServices/Line";
import { Polyline, PolylineProps } from "../DatabaseServices/Polyline";
import { MoveMatrix, angleTo, equal, equaln } from "../Geometry/GeUtils";
import { isTargetCurInSourceCur } from "./BoolOperateUtils";
import { IntersectOption } from "./IntersectWith";
import { app } from "../ApplicationServices/Application";
interface offestRes
{
index: number,
@ -22,6 +22,8 @@ interface offestRes
* 线
* 线
*
* 线
* //TODO:尝试先通过自交点把偏移后曲线数组打散,然后进行曲线切割(用源线段点和线段到源线段的最近点)
* @export
* @class PolyOffestUtil
*/
@ -40,16 +42,16 @@ export class PolyOffestUtil
let plList: offestRes[] = this.offestCurve(this.m_Polyline.Explode());
//连接全部连接点
let newPlList: Array<Polyline> = this.trimAndJointOffestPolyline(plList);
// //分离出自交的线
// // //分离出自交的线
let outputPls = this.removeSelfIntersect(newPlList);
this.linkPLine(newPlList);
this.cuttingPolyLine(newPlList);
//如果曲线闭合并且向内偏移,曲线应都在闭合曲线内
if (this.m_Polyline.IsClose)
{
//FIXME:没想好确定偏移方向
}
// //如果曲线闭合并且向内偏移,曲线应都在闭合曲线内
// if (this.m_Polyline.IsClose)
// {
// }
outputPls.push(...this.arrangePlineList(newPlList));
return outputPls;
}
@ -158,21 +160,18 @@ export class PolyOffestUtil
//如果没有交点,则用圆弧连接
if (interPts.length === 0)
{
let srcLine = offResList[i + 1] ? offResList[i + 1] : offResList[0];
let centerPt = this.m_Polyline.GetCurveAtIndex(srcLine.index).StartPoint;
// 圆心到前面线end点向量
let startLine = frontLine.EndPoint.clone().sub(centerPt);
// 圆心到后面线start点向量
let endLine = laterLine.StartPoint.clone().sub(centerPt);
let circleAngle;
//偏移线段对应的源线段,取其起始点作为圆心
let srcOffestRes = offResList[i + 1] ? offResList[i + 1] : offResList[0];
let centerPt = this.m_Polyline.GetCurveAtIndex(srcOffestRes.index).StartPoint;
// 圆心到前面线end点距离
let startDist = frontLine.EndPoint.distanceToSquared(centerPt);
// 圆心到后面线start点距离
let endDist = laterLine.StartPoint.distanceToSquared(centerPt);
//补圆弧的起始交点
let intPt = Vec2DTo3D(frontLine.LineData[1].pt);
// 如果起始向量和终止向量相等,则都为半径
if (equaln(startLine.lengthSq(), endLine.lengthSq()))
{
circleAngle = angleTo(startLine, endLine);
}
else
if (!equaln(startDist, endDist))
{
// 以centerPt为圆心偏移距离为为半径画圆
let tmpCir = new Circle(centerPt, Math.abs(this.m_OffestDist));
@ -183,12 +182,11 @@ export class PolyOffestUtil
//选取交点,如果有多个选离前面线start点近的
intPt = this.selectPlInterPt(pts, frontLine.StartPoint);
let insLine = intPt.clone().sub(centerPt);
circleAngle = angleTo(insLine, endLine);
this.adjustFrontLine(startV, frontLine.LineData[1], intPt);
}
else
{
// 与补线圆无交点,放弃补圆弧
//TODO: 与补线圆无交点,放弃补圆弧,若按CAD可以补
newPlList.push(new Polyline([
startV, this.clonePlData(frontLine.LineData[1])
]))
@ -196,6 +194,11 @@ export class PolyOffestUtil
continue;
}
}
//改用根据laterline切线和弦判断圆心角及方向
let chord = intPt.clone().sub(laterLine.StartPoint);
let tangent = laterLine.GetFistDeriv(0).negate().normalize();
let circleAngle = -getCirAngleByChordAndTangent(chord, tangent);
let tmpPlData = {
pt: Vec3DTo2D(intPt),
bul: Math.tan(circleAngle / 4)
@ -343,6 +346,23 @@ export class PolyOffestUtil
}
return plLists;
}
//根据自交点分离多段线
private spliteOffestPolyline(plList: Polyline[])
{
for (let i = 0; i < plList.length - 1; i++)
{
//前一根线
let frontLine = plList[i];
let insertPt = new Vector3();
for (let j = i + 1; j < plList.length; j++)
{
// 后一根线
let laterLine = plList[j];
let intPts = frontLine.IntersectWith(laterLine, IntersectOption.OnBothOperands);
}
}
}
//处理分离出的多段线,把相交的部分提取出来
private handleRemoveLine(plList: Polyline[])
{
@ -1060,449 +1080,3 @@ export class PolyOffestUtil2
}
}
}
//合并前2个偏移算法,未完善
export class PolyOffestUtil3
{
private m_Polyline: Polyline;
private m_OffestDist: number
constructor(pl: Polyline, offest: number)
{
this.m_Polyline = pl;
this.m_OffestDist = offest;
}
//偏移
GetOffsetCurves(): Curve[]
{
//预处理源线段自交线段
let handledPl = this.handleIntersectToSelf();
let pls = handledPl.Explode();
let plList1: offestRes[] = this.offestCurve(pls, this.m_OffestDist);
let plList2: offestRes[] = this.offestCurve(pls, -this.m_OffestDist);
let l = plList1.map(l => l.pl).filter(l => l !== undefined);
let newPls = this.trimAndJointOffestPolyline(plList1, handledPl);
let refPls = this.trimAndJointOffestPolyline(plList2, handledPl);
newPls = this.arrangePlineList(newPls);
// console.log('newPls: ', newPls);
refPls = this.arrangePlineList(refPls);
return [...newPls, ...refPls]
// console.log('refPls: ', refPls);
// let outputPls: Polyline[] = [];
// for (let newPl of newPls)
// {
// for (let refPl of refPls)
// {
// outputPls.push(...this.clipOffestPolyline(handledPl, newPl, refPl));
// }
// }
// return outputPls;
// return newPls;
}
//偏移曲线
private offestCurve(pls: Curve[], dist: number): offestRes[]
{
let plList: offestRes[] = [];
pls.forEach((pl, index) =>
{
let l1 = pl.GetOffsetCurves(dist)[0];
let offPl: Polyline;
if (l1 instanceof Line)
{
offPl = new Polyline([{
pt: Vec3DTo2D(l1.StartPoint),
bul: 0
}, {
pt: Vec3DTo2D(l1.EndPoint),
bul: 0
}]);
}
else if (l1 instanceof Arc)
{
offPl = new Polyline([{
pt: Vec3DTo2D(l1.StartPoint),
bul: Math.tan(l1.AllAngle / 4) * (l1.IsClockWise ? -1 : 1)
}, {
pt: Vec3DTo2D(l1.EndPoint),
bul: 0
}]);
}
offPl && plList.push({
index, pl: offPl
})
})
return plList;
}
/**
* 线线
* @private
* @memberof PolyOffestUtil2
*/
private handleIntersectToSelf()
{
let newPlProps = sliceDeep(this.m_Polyline.LineData) as PolylineProps[];
//处理相邻线段自交
for (let i = 0; i < this.m_Polyline.EndParam - 1; i++)
{
let frontLine = this.m_Polyline.GetCurveAtIndex(i);
let laterLine = this.m_Polyline.GetCurveAtIndex(i + 1);
let interPts = frontLine.IntersectWith(laterLine, IntersectOption.OnBothOperands).filter(p =>
{
return !equal(p, frontLine.EndPoint);
});
let newProp: PolylineProps;
if (interPts.length > 0)
{
newProp = {
pt: Vec3DTo2D(interPts[0]),
bul: 0
}
if (frontLine instanceof Arc)
{
let startV = this.m_Polyline.LineData[i];
this.adjustFrontLine(startV, newPlProps[i + 1], interPts[0]);
frontLine.StartPoint = interPts[0];
newProp.bul = Math.tan(frontLine.AllAngle * 0.25) * Math.sign(startV.bul);
}
newPlProps.splice(i + 1, 0, newProp);
i++;
}
}
return new Polyline(newPlProps)
}
private getSelfInterPts(pl: Polyline)
{
let interPts: Vector3[] = [];
for (let i = 0; i < pl.EndParam; i++)
{
let frontLine = pl.GetCurveAtIndex(i);
for (let j = i + 1; j < pl.EndParam; j++)
{
let laterLine = pl.GetCurveAtIndex(j);
let tmpPts = frontLine.IntersectWith(laterLine, IntersectOption.OnBothOperands).filter(p =>
{
return !equal(p, frontLine.EndPoint);
});
interPts.push(...tmpPts);
}
}
return interPts;
}
// 修剪连接相邻曲线
private trimAndJointOffestPolyline(offsetRes: offestRes[], originLine: Polyline)
{
if (offsetRes.length <= 1)
{
return offsetRes[0] ? [offsetRes[0].pl] : [];
}
let newPlList: Array<Polyline> = [];
let startV = this.clonePlData(offsetRes[0].pl.LineData[0]);
let isStillClose = this.m_Polyline.IsClose;
for (let i = 0; i < offsetRes.length; i++)
{
//前面线
let frontLine = offsetRes[i].pl;
let laterLine = i === offsetRes.length - 1 ? undefined : offsetRes[i + 1].pl;
if (i === offsetRes.length - 1)
{
if (this.m_Polyline.IsClose && isStillClose)
laterLine = newPlList[0];
else break;
}
if (!laterLine) return []; //终点data
let endV = i === offsetRes.length - 1 ? laterLine.LineData[0] : this.clonePlData(laterLine.LineData[0]);
//交点
let interPt = Vec2DTo3D(endV.pt);
// 如果两线结合点不相等
if (!equal(frontLine.EndPoint, laterLine.StartPoint))
{
// 多段线交点数组
let interPts = frontLine.IntersectWith(laterLine, IntersectOption.ExtendBoth);
//如果没有交点,则用圆弧连接
if (interPts.length === 0)
{
let centerPt = this.m_Polyline.GetCurveAtIndex(offsetRes[i + 1].index).StartPoint;
// 圆心到前面线end点向量
let startLine = frontLine.EndPoint.clone().sub(centerPt);
// 圆心到后面线start点向量
let endLine = laterLine.StartPoint.clone().sub(centerPt);
let circleAngle;
//补圆弧的起始交点
let intPt = Vec2DTo3D(frontLine.LineData[1].pt);
// 如果起始向量和终止向量相等,则都为半径
if (equaln(startLine.lengthSq(), endLine.lengthSq()))
{
circleAngle = angleTo(startLine, endLine);
}
else
{
// 以centerPt为圆心偏移距离为为半径画圆
let tmpCir = new Circle(centerPt, Math.abs(this.m_OffestDist));
//只会和前面线相交,因为圆心选取是根据后面线startPoint偏移距离处的点,只会与后面线相切,允许前面线延伸
let pts = tmpCir.IntersectWith(frontLine, IntersectOption.OnBothOperands);
if (pts.length > 0)
{
//选取交点,如果有多个选离前面线start点近的
intPt = this.selectFitInterPt(pts, frontLine.StartPoint);
let insLine = intPt.clone().sub(centerPt);
circleAngle = angleTo(insLine, endLine);
this.adjustFrontLine(startV, frontLine.LineData[1], intPt);
}
else
{
// 与补线圆无交点,放弃补圆弧
newPlList.push(new Polyline([
startV, this.clonePlData(frontLine.LineData[1])
]))
startV = this.clonePlData(laterLine.LineData[0]);
continue;
}
}
let tmpPlData = {
pt: Vec3DTo2D(intPt),
bul: Math.tan(circleAngle / 4)
};
newPlList.push(new Polyline([
startV, tmpPlData
]))
startV = this.clonePlData(tmpPlData);
}
else
{
let pts = frontLine.IntersectWith(laterLine, IntersectOption.OnBothOperands);
interPt = this.selectFitInterPt(pts.length ? pts : interPts, laterLine.StartPoint)
this.adjustFrontLine(startV, frontLine.LineData[1], interPt);
if (i === offsetRes.length - 1)
{
let tmpPar = laterLine.GetParamAtPoint(interPt);
tmpPar > 1 && newPlList.splice(0, 1);
}
this.adjustLaterLine(endV, laterLine.LineData[1], interPt);
}
}
let pl = new Polyline([startV, endV]);
let tmpPar = frontLine.GetParamAtPoint(Vec2DTo3D(startV.pt));
let tmpCur = frontLine.GetCurveAtIndex(0) as Line | Arc;
if (tmpPar > 0) tmpCur.EndPoint = Vec2DTo3D(startV.pt);
else tmpCur.StartPoint = Vec2DTo3D(startV.pt);
let par = tmpCur.GetParamAtPoint(interPt);
// newSlope = pl.GetFistDeriv(0);
startV = this.clonePlData(endV);
if (equal(pl.StartPoint, pl.EndPoint) || par < 0)
{
if (isStillClose)
{
isStillClose = !(offsetRes[i].index === 0 || offsetRes[i].index === originLine.EndParam);
}
continue;
}
newPlList.push(pl);
}
if (!this.m_Polyline.IsClose)
{
let frontLine = offsetRes[offsetRes.length - 1].pl;
let endV = this.clonePlData(frontLine.LineData[1]);
let tmpPar = frontLine.GetParamAtPoint(Vec2DTo3D(startV.pt));
if (tmpPar < 1)
{
if (offsetRes.length >= 3)
{
let laterLine = newPlList[0];
let pts = frontLine.IntersectWith(laterLine, IntersectOption.OnBothOperands);
if (pts.length === 1)
{
this.adjustFrontLine(startV, endV, pts[0]);
endV.pt = Vec3DTo2D(pts[0]);
if (newPlList.length > 0)
{
this.adjustLaterLine(laterLine.LineData[0], laterLine.LineData[1], pts[0]);
}
}
}
let pl = new Polyline([startV, endV]);
let par = frontLine.GetParamAtPoint(Vec2DTo3D(endV.pt));
par > 0 && newPlList.push(pl);
}
}
return newPlList;
}
/**
* 线
* 2线线,
* @private
* @param {Polyline} origin
* @param {Polyline} newPl
* @param {Polyline} refPl
* @memberof PolyOffestUtil2
*/
private clipOffestPolyline(origin: Polyline, newPl: Polyline, refPl: Polyline)
{
//结果曲线与参考曲线的交点
let interPts = newPl.IntersectWith(refPl, IntersectOption.OnBothOperands);
// 结果曲线自交点
let selfInterPts = this.getSelfInterPts(newPl);
//临时多段线数组
let tmpPlList: Polyline[] = [];
if (!interPts.length && !selfInterPts.length)
{
tmpPlList.push(newPl);
}
else
{
//根据交点顺序分割偏移线段
let params = [...interPts].map(pt => newPl.GetParamAtPoint(pt));
[...selfInterPts].forEach(pt =>
{
params.push(...this.getParsByPt(newPl, pt));
})
//分割的线段
let tmpPls = newPl.GetSplitCurves(params);
tmpPls.forEach(pl =>
{
let tmpInterPts = pl.IntersectWith(origin, IntersectOption.OnBothOperands);
if (tmpInterPts.length === 0)
tmpPlList.push(pl)
else
{
let tmpPt = tmpInterPts.filter(pt => equal(pt, origin.StartPoint) || equal(pt, origin.EndPoint));
if (tmpPt.length > 0)
{
//切割该分段
let tmpCir = new Circle(tmpPt[0], Math.abs(this.m_OffestDist));
tmpPlList.push(...this.cuttingPolyline(pl, tmpPt[0]))
}
}
})
}
//用小于偏移距离最近点对结果多段线数组进行切割
// this.cuttingOffestPlByClosePt(origin, tmpPlList);
return tmpPlList.filter(pl => !equaln(pl.Length, 0));
}
private getParsByPt(pl: Polyline, pt: Vector3)
{
let pars: number[] = [];
let cus = pl.Explode();
for (let i = 0; i < cus.length; i++)
{
let cu = cus[i];
let param = cu.GetParamAtPoint(pt);
if (cu.ParamOnCurve(param))
pars.push(i + param); //返回点在曲线内部的参数
}
return pars;
}
private cuttingOffestPlByClosePt(origin: Polyline, pllist: Polyline[])
{
for (let i = 0; i < pllist.length; i++)
{
let pl = pllist[i];
for (let j = 0; j < pl.EndParam + 1; j++)
{
let pt = pl.GetPointAtParam(j);
let center = origin.GetClosestPointTo(pt, false);
let dist = center.distanceToSquared(pt);
if (dist - Math.pow(this.m_OffestDist, 2) < -1e-4)
{
let cutedPls = this.cuttingPolyline(pl, center).filter(l => !equaln(l.Length, 0, 0.1));
pllist.splice(i, 1, ...cutedPls);
i -= (cutedPls.length ? cutedPls.length : 1);
break;
}
}
}
}
private cuttingPolyline(pl: Polyline, centerPt: Vector3)
{
let rad = Math.abs(this.m_OffestDist);
let circle = new Circle(centerPt, rad);
let pts = pl.IntersectWith(circle, IntersectOption.OnBothOperands);
let params = pts.map(p => pl.GetParamAtPoint(p));
let cutedPls = pl.GetSplitCurves(params).filter(l => !isTargetCurInSourceCur(circle, l));
return cutedPls;
}
// 根据交点调整前面线段的凸度
private adjustFrontLine(startV: PolylineProps, endV: PolylineProps, insertPt: Vector3)
{
if (startV.bul !== 0)
{
let arc = new Arc().ParseFromBul(startV.pt, endV.pt, startV.bul);
arc.EndPoint = insertPt;
//前面线的凸度调整
startV.bul = Math.tan(arc.AllAngle / 4) * Math.sign(startV.bul);
}
}
// 根据交点调整后面线段的凸度和起始点
private adjustLaterLine(startV: PolylineProps, endV: PolylineProps, interPt: Vector3)
{
let bul = 0;
if (startV.bul !== 0)
{
let arc = new Arc().ParseFromBul(startV.pt, endV.pt, startV.bul);
arc.StartPoint = interPt;
bul = Math.tan(arc.AllAngle * 0.25) * Math.sign(startV.bul);
}
// 调整后面线起始点和凸度
startV.pt = Vec3DTo2D(interPt);
startV.bul = bul;
}
// 选择合适的交点
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;
}
private clonePlData(pl: PolylineProps)
{
return {
pt: pl.pt,
bul: pl.bul
}
}
//整理多段线数组,把相连的组合成多段线,返回多段线数组
private arrangePlineList(pls: Array<Polyline>)
{
if (pls.length === 0) return [];
let plDataList: PolylineProps[] = [];
let plList: Polyline[] = [];
plDataList.push(pls[0].LineData[0]);
for (let i = 0; i < pls.length - 1; i++)
{
let frontLine = pls[i];
let laterLine = pls[i + 1];
if (equal(frontLine.EndPoint, laterLine.StartPoint))
{
plDataList.push(laterLine.LineData[0]);
}
else
{
plDataList.push(frontLine.LineData[1]);
plList.push(new Polyline(plDataList));
plDataList = [laterLine.LineData[0]];
}
}
plDataList.push(pls[pls.length - 1].LineData[1]);
plList.push(new Polyline(plDataList));
return plList;
}
}

Loading…
Cancel
Save