!20 实现直线倒角

Merge pull request !20 from ChenX/master_f
pull/650059/MERGE
ChenX 7 years ago
parent 5704c58c7e
commit 93f404be57

@ -1,5 +1,21 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`最近点 1`] = `
Vector3 {
"x": -2.5,
"y": -2.499999999999999,
"z": 0,
}
`;
exports[`最近点 2`] = `
Vector3 {
"x": 0,
"y": 0,
"z": 0,
}
`;
exports[`直线偏移 1`] = `
Vector3 {
"x": -6.123233995736766e-16,
@ -15,3 +31,67 @@ Vector3 {
"z": 0,
}
`;
exports[`直线偏移 3`] = `
Vector3 {
"x": -7.0710678118654755,
"y": 7.071067811865475,
"z": 0,
}
`;
exports[`直线偏移 4`] = `
Vector3 {
"x": -2.0710678118654755,
"y": 12.071067811865476,
"z": 0,
}
`;
exports[`直线偏移 5`] = `
Vector3 {
"x": 7.0710678118654755,
"y": -7.071067811865475,
"z": 0,
}
`;
exports[`直线偏移 6`] = `
Vector3 {
"x": 12.071067811865476,
"y": -2.0710678118654746,
"z": 0,
}
`;
exports[`直线偏移 7`] = `
Vector3 {
"x": -7.071067811865477,
"y": 7.071067811865475,
"z": 0,
}
`;
exports[`直线偏移 8`] = `
Vector3 {
"x": -12.071067811865477,
"y": 2.0710678118654746,
"z": 0,
}
`;
exports[`直线偏移 9`] = `
Vector3 {
"x": 7.071067811865477,
"y": -7.071067811865475,
"z": 0,
}
`;
exports[`直线偏移 10`] = `
Vector3 {
"x": 2.0710678118654773,
"y": -12.071067811865476,
"z": 0,
}
`;

@ -1,5 +1,6 @@
import { Line } from "../../src/DatabaseServices/Line";
import { Vector3 } from "three";
import { Vector3 } from 'three';
import { Line } from '../../src/DatabaseServices/Line';
test('直线参数', () =>
@ -91,4 +92,39 @@ test('直线偏移', () =>
let newLine = lines[0];
expect(newLine.StartPoint).toMatchSnapshot();
expect(newLine.EndPoint).toMatchSnapshot();
let l2 = new Line(new Vector3(0, 0, 0), new Vector3(5, 5, 0));
let lines2 = l2.GetOffsetCurves(-10)[0]; //?
lines2.StartPoint //?
lines2.EndPoint //?
expect(lines2.StartPoint).toMatchSnapshot();
expect(lines2.EndPoint).toMatchSnapshot();
lines2 = l2.GetOffsetCurves(10)[0]; //?
lines2.StartPoint //?
lines2.EndPoint //?
expect(lines2.StartPoint).toMatchSnapshot();
expect(lines2.EndPoint).toMatchSnapshot();
l2.EndPoint = l2.EndPoint.negate();
lines2 = l2.GetOffsetCurves(10)[0]; //?
lines2.StartPoint //?
lines2.EndPoint //?
expect(lines2.StartPoint).toMatchSnapshot();
expect(lines2.EndPoint).toMatchSnapshot();
lines2 = l2.GetOffsetCurves(-10)[0]; //?
lines2.StartPoint //?
lines2.EndPoint //?
expect(lines2.StartPoint).toMatchSnapshot();
expect(lines2.EndPoint).toMatchSnapshot();
});
test('最近点', () =>
{
let l = new Line(new Vector3(0, 0, 0), new Vector3(5, 5, 0));
expect(l.GetClosestPointTo(new Vector3(-5, 0, 0), true)/*?*/).toMatchSnapshot();//-5,0,0.
expect(l.GetClosestPointTo(new Vector3(-5, 0, 0), false)/*?*/).toMatchSnapshot();//0,0,0.
});

@ -0,0 +1,194 @@
import { Vector3 } from 'three';
import { app } from '../ApplicationServices/Application';
import { Arc } from '../DatabaseServices/Arc';
import { Curve } from '../DatabaseServices/Curve';
import { Line } from '../DatabaseServices/Line';
import { Command } from '../Editor/CommandMachine';
import { PromptEntityResult, PromptStatus } from '../Editor/PromptResult';
import { angle, midPoint } from '../Geometry/GeUtils';
import { Intersect } from '../GraphicsSystem/IntersectWith';
enum FilletState { Invalid = -1, Normal, Parallel, RadiousInvalid }
export class CommandFillet implements Command
{
async exec()
{
//拾取曲线1.
let enRes = await this.SelectCurve([
{ msg: "放弃", key: "U" },
{ msg: "多段线", key: "P" },
{ msg: "半径", key: "R" },
{ msg: "修剪", key: "T" },
{ msg: "多个", key: "M" }]);
if (!enRes) return;
let cu1 = enRes.Entity as Curve;
//拾取曲线2
let enRes2 = await this.SelectCurve([{ msg: "放弃", key: "U" }, { msg: "半径", key: "R" }], cu1);
if (!enRes2) return;
let cu2 = enRes2.Entity as Curve;
//求交点
let in_pts = cu1.IntersectWith(cu2, Intersect.ExtendBoth);
if (in_pts.length === 0) return;
//裁剪. 尖角化
let new_cu1 = this.SplitCurve(cu1, in_pts, enRes.Point);
let new_cu2 = this.SplitCurve(cu2, in_pts, enRes2.Point);
//偏移
let off_cu1 = this.OffsetCurve(new_cu1, new_cu2, 3);
let off_cu2 = this.OffsetCurve(new_cu2, new_cu1, 3);
//圆心
let center = off_cu1.IntersectWith(off_cu2, Intersect.ExtendBoth)[0];
//圆弧点1
let arcP1 = new_cu1.GetClosestPointTo(center, true);
if (!new_cu1.PtOnCurve(arcP1))
{
app.m_Editor.m_CommandStore.Prompt("半径过大");
return;
}
//圆弧点2
let arcP2 = new_cu2.GetClosestPointTo(center, true);
if (!new_cu2.PtOnCurve(arcP2))
{
app.m_Editor.m_CommandStore.Prompt("半径过大");
return;
}
//时针校验
let v1 = arcP1.clone().sub(center);
let v2 = arcP2.clone().sub(center);
let [startAngle, endAngle] = [angle(v1), angle(v2)];
if (v1.cross(v2).z > 0)
[startAngle, endAngle] = [endAngle, startAngle];
//绘制圆弧
let arc = new Arc(center, 3, startAngle, endAngle);
app.m_Database.ModelSpace.Append(arc);
//延伸或者裁剪到圆弧点
this.ExtendPt(new_cu1 as Line, in_pts[0], arcP1);
this.ExtendPt(new_cu2 as Line, in_pts[0], arcP2);
cu1.CopyFrom(new_cu1);
cu2.CopyFrom(new_cu2);
app.m_Editor.UpdateScreen();
}
/**
* .
*
* @param {Line} cu
* @param {Vector3} insP
* @param {Vector3} newP
* @memberof CommandFillet
*/
ExtendPt(cu: Line, insP: Vector3, newP: Vector3)
{
if (cu.StartPoint.distanceToSquared(insP) < 1e-5)
cu.StartPoint = newP;
else
cu.EndPoint = newP;
}
/**
* 线,
*
* @param {Curve} cu 线
* @param {Array<Vector3>} pts
* @param {Vector3} pickPoint
* @returns {Curve} 线
* @memberof CommandFillet
*/
SplitCurve(cu: Curve, pts: Array<Vector3>, pickPoint: Vector3): Curve
{
let cp = cu.GetClosestPointTo(pickPoint, true);
let cus = cu.GetSplitCurves(pts.map(p => cu.GetParamAtPoint(p)))
if (cus.length === 0)
cus.push(cu.Clone() as Curve);
else
{
for (let cu of cus)
{
if (cu.PtOnCurve(cp))
return cu;
}
cus.sort((c1: Curve, c2: Curve) =>
{
return c1.GetClosestPointTo(cp, false).distanceTo(cp)
< c2.GetClosestPointTo(cp, false).distanceTo(cp) ? -1 : 1;
});
}
let newCu = cus[0];
newCu.Extend(newCu.GetParamAtPoint(pts[0]));//延伸到需要的长度
return cus[0];
}
/**
* 线(toCu).
*
* @param {Curve} thisCu
* @param {Curve} toCu
* @param {number} dis
* @returns {Curve}
* @memberof CommandFillet
*/
OffsetCurve(thisCu: Curve, toCu: Curve, dis: number): Curve
{
let minP = midPoint(toCu.StartPoint, toCu.EndPoint);
let cp = thisCu.GetClosestPointTo(minP, true);
let vec = minP.sub(cp).normalize().multiplyScalar(dis);
let newCu = thisCu.Clone() as Line;
newCu.StartPoint = thisCu.StartPoint.add(vec);
newCu.EndPoint = thisCu.EndPoint.add(vec);
return newCu;
}
/**
* 线
*
* @param {any} keyword
* @param {Curve} [oldCurve] 线
* @returns {Promise<PromptEntityResult>}
* @memberof CommandFillet
*/
async SelectCurve(keyword, oldCurve?: Curve): Promise<PromptEntityResult>
{
while (true)
{
let enRes = await app.m_Editor.GetEntity({
Msg: oldCurve ? "选择第二个对象:" : "选择第一个对象:",
KeyWordList: keyword,
});
switch (enRes.Status)
{
case PromptStatus.OK:
if (enRes.Entity === oldCurve)
{
app.m_Editor.m_CommandStore.Prompt("重复的对象!");
}
else if (enRes.Entity && enRes.Entity instanceof Curve)
{
return enRes;
}
break;
case PromptStatus.Cancel:
return undefined;
default:
break;
}
}
}
}

@ -121,6 +121,7 @@ export abstract class CADObject
//从一个实体拷贝数据,实体类型必须相同.
CopyFrom(obj: CADObject)
{
this.WriteAllObjectRecord();
let f = new CADFile();
obj.WriteFile(f);
this.ReadFile(f);

@ -46,6 +46,11 @@ export abstract class Curve extends Entity
* @memberof Curve
*/
GetFistDeriv(param: number | Vector3): Vector3 { return; }
GetFistDerivAngle(param: number | Vector3): number
{
let d = this.GetFistDeriv(param);
return Math.atan2(d.y, d.x);
}
GetSplitCurves(param: number[] | number): Array<Curve> { return; }
Extend(newParam: number) { }

@ -116,6 +116,13 @@ export class Entity extends CADObject
super.ApplyPartialUndo(undoData);
this.Update();
}
CopyFrom(obj: CADObject)
{
super.CopyFrom(obj);
this.Update();
}
//#endregion
}

@ -189,6 +189,22 @@ export class Line extends Curve
}
return ret;
}
GetClosestPointTo(pt: Vector3, extend: boolean): Vector3
{
let an = this.GetFistDerivAngle(0) + Math.PI * 0.5;
let line = new Line(pt, polar(pt.clone(), an, 1));
//交点
let pt_int = this.IntersectWith(line, Intersect.ExtendBoth)[0];
if (extend) return pt_int;
//参数
let param = this.GetParamAtPoint(pt_int);
if (param >= 0 && param <= 1) return pt_int;
if (param < 0) return this.StartPoint;
if (param > 0) return this.EndPoint;
return;
}
Extend(newParam: number)
{
if (newParam < this.StartParam)
@ -203,7 +219,7 @@ export class Line extends Curve
GetOffsetCurves(offsetDist: number): Array<Curve>
{
let an = this.GetFistDeriv(0).angleTo(new Vector3(1, 0, 0)) - Math.PI * 0.5;
let an = this.GetFistDerivAngle(0) - Math.PI * 0.5;
let newLine = this.Clone() as Line;
newLine.StartPoint = polar(this.StartPoint, an, offsetDist);
newLine.EndPoint = polar(this.EndPoint, an, offsetDist);

@ -34,6 +34,7 @@ import { Redo, Undo } from '../Add-on/Undo';
import { ViewToFront, ViewToTop } from '../Add-on/ViewChange';
import { commandMachine } from './CommandMachine';
import { Command_Ssget } from '../Add-on/ssget';
import { CommandFillet } from '../Add-on/Fillet';
// import { RevTarget, SaveTarget } from '../Add-on/RenderTarget';
export function registerCommand()
@ -108,6 +109,8 @@ export function registerCommand()
commandMachine.RegisterCommand("ss", new Command_Ssget());
commandMachine.RegisterCommand("f", new CommandFillet());
// commandMachine.RegisterCommand("st", new SaveTarget())
// commandMachine.RegisterCommand("rt", new RevTarget())
}

@ -42,6 +42,11 @@ export function polar(v: THREE.Vector3, an: number, dis: number)
return v;
}
export function angle(v: THREE.Vector3)
{
return Math.atan2(v.y, v.x);
}
/**
* ,,
*

Loading…
Cancel
Save