合并多段线偏移分支,重构多段线大部分方法. 重构修复arc的大部分方法. 重新编写测试代码

pull/44/head
ChenX 7 years ago
parent 53b15042b1
commit cfc224e660

@ -7,3 +7,75 @@ exports[`三点同一位置 2`] = `0`;
exports[`三点圆心 1`] = `3.141592653589793`;
exports[`三点圆心 2`] = `0`;
exports[`圆弧偏移 1`] = `
Vector3 {
"x": 5,
"y": 0,
"z": 0,
}
`;
exports[`圆弧偏移 2`] = `3.141592653589793`;
exports[`圆弧偏移 3`] = `0`;
exports[`圆弧偏移 4`] = `5`;
exports[`圆弧偏移 5`] = `
Vector3 {
"x": 5,
"y": 0,
"z": 0,
}
`;
exports[`圆弧偏移 6`] = `3.141592653589793`;
exports[`圆弧偏移 7`] = `0`;
exports[`圆弧偏移 8`] = `15`;
exports[`圆弧偏移 9`] = `
Vector3 {
"x": 5,
"y": 0,
"z": 0,
}
`;
exports[`圆弧偏移 10`] = `0`;
exports[`圆弧偏移 11`] = `3.141592653589793`;
exports[`圆弧偏移 12`] = `5`;
exports[`圆弧偏移 13`] = `
Vector3 {
"x": 5,
"y": 0,
"z": 0,
}
`;
exports[`圆弧偏移 14`] = `0`;
exports[`圆弧偏移 15`] = `3.141592653589793`;
exports[`圆弧偏移 16`] = `25`;
exports[`最近点 1`] = `
Vector3 {
"x": 0,
"y": 0,
"z": 0,
}
`;
exports[`最近点 2`] = `
Vector3 {
"x": 10,
"y": 0,
"z": 0,
}
`;

@ -0,0 +1,145 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`圆偏移 1`] = `
Vector3 {
"x": 2,
"y": 0,
"z": 0,
}
`;
exports[`圆偏移 2`] = `
Vector3 {
"x": 2,
"y": 0,
"z": 0,
}
`;
exports[`圆偏移 3`] = `
Vector3 {
"x": 5,
"y": 0,
"z": 0,
}
`;
exports[`圆偏移 4`] = `
Vector3 {
"x": 5,
"y": 0,
"z": 0,
}
`;
exports[`圆偏移 5`] = `
Vector3 {
"x": 20,
"y": 0,
"z": 0,
}
`;
exports[`圆偏移 6`] = `
Vector3 {
"x": 20,
"y": 0,
"z": 0,
}
`;
exports[`圆偏移 7`] = `
Vector3 {
"x": 20,
"y": 0,
"z": 0,
}
`;
exports[`圆偏移 8`] = `
Vector3 {
"x": 20,
"y": 0,
"z": 0,
}
`;
exports[`圆偏移 9`] = `
Vector3 {
"x": 5,
"y": 0,
"z": 0,
}
`;
exports[`圆偏移 10`] = `
Vector3 {
"x": 5,
"y": 0,
"z": 0,
}
`;
exports[`圆的切割2 1`] = `
Vector3 {
"x": 5,
"y": 5,
"z": 0,
}
`;
exports[`圆的切割2 2`] = `
Vector3 {
"x": 4.999999999999999,
"y": -5,
"z": 0,
}
`;
exports[`圆的切割2 3`] = `
Vector3 {
"x": 4.999999999999999,
"y": -5,
"z": 0,
}
`;
exports[`圆的切割2 4`] = `
Vector3 {
"x": 0,
"y": 6.123233995736766e-16,
"z": 0,
}
`;
exports[`圆的切割2 5`] = `
Vector3 {
"x": 0,
"y": 6.123233995736766e-16,
"z": 0,
}
`;
exports[`圆的切割2 6`] = `
Vector3 {
"x": 5,
"y": 5,
"z": 0,
}
`;
exports[`最近点 1`] = `
Vector3 {
"x": 0,
"y": 0,
"z": 0,
}
`;
exports[`最近点 2`] = `
Vector3 {
"x": 10,
"y": 0,
"z": 0,
}
`;

@ -8,7 +8,13 @@ Vector3 {
}
`;
exports[`相交测试 2`] = `undefined`;
exports[`相交测试 2`] = `
Vector3 {
"x": 2.5,
"y": 0,
"z": 0,
}
`;
exports[`相交测试 3`] = `
Vector3 {

@ -35,5 +35,5 @@ test('0向量', () =>
test('变量补全', () =>
{
let v = angleTo(new Vector3(1, 0, 0), new Vector3(0, 0, 1)) //?
expect(v).toEqual(0)
expect(v).toEqual(Math.PI * 0.5)
});

@ -4,6 +4,7 @@ import { app } from '../../src/ApplicationServices/Application';
import { Command } from '../../src/Editor/CommandMachine';
import { PromptStatus } from '../../src/Editor/PromptResult';
import { RenderType } from '../../src/GraphicsSystem/Enum';
import { equal, equaln } from '../../src/Geometry/GeUtils';
test("三点共线", () =>
{
@ -22,8 +23,6 @@ test("三点共线", () =>
expect(arc.Center.toArray()).toMatchObject([0, 0, 0]);
})
test("三点圆心", () =>
{
let arc = new Arc();
@ -53,9 +52,133 @@ test("三点同一位置", () =>
console.log(arc.StartAngle);
console.log(arc.EndAngle);
expect(arc.Center.toArray()).toMatchObject([0, 0, 0]);
expect(arc.Center.toArray()).toMatchObject([5, 5, 0]);
expect(arc.StartAngle).toMatchSnapshot();
expect(arc.EndAngle).toMatchSnapshot();
})
test('圆弧参数', () =>
{
let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0);
expect(arc.GetParamAtPoint(new Vector3(0, 0, 0))).toBe(0);
expect(equaln(arc.GetParamAtPoint(new Vector3(5, 5, 0)), 0.5)).toBeTruthy();
expect(equaln(arc.GetParamAtPoint(new Vector3(10, 0, 0)), 1)).toBeTruthy();
expect(equaln(arc.GetParamAtPoint(new Vector3(5, -5, 0)), 1.5)).toBeTruthy();
});
test('0长度圆弧,参数', () =>
{
let arc = new Arc(new Vector3(), 0, 0, 0);
expect(arc.GetParamAtPoint(new Vector3(0, 0, 0))).toBe(NaN);
});
test("圆弧的切割1", () =>
{
let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0);
expect(arc.GetSplitCurves(0.5)[0].EndPoint).toMatchObject({ 'x': 5, 'y': 5, 'z': 0 });
expect(arc.GetSplitCurves(0.5)[1].EndPoint).toMatchObject({ 'x': 10, 'y': 0, 'z': 0 });
});
test("圆弧的切割2", () =>
{
let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0);
expect(arc.GetSplitCurves([0.5, 0.8, 0.2])[0].StartPoint.distanceTo(new Vector3(0, 0, 0)) < 0.01).toBeTruthy();
expect(arc.GetSplitCurves([0.5, 0.2, 0.8])[1].EndPoint.distanceTo(new Vector3(5, 5, 0)) < 0.01).toBeTruthy();
expect(arc.GetSplitCurves([0.2, 0.5, 0.8]).length).toBe(4);
});
test("圆弧延伸-反向", () =>
{
let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0);
arc.Extend(-0.5);
expect(arc.StartPoint.distanceTo(new Vector3(5, -5, 0)) < 0.01).toBeTruthy();
});
test("圆弧延伸-正向", () =>
{
let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0);
arc.Extend(1.5);
expect(arc.EndPoint.distanceTo(new Vector3(5, -5, 0)) < 0.01).toBeTruthy();
});
test("由距离得到圆弧参数", () =>
{
let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0);
expect(equaln(arc.GetParamAtDist(0.25 * Math.PI * 5), 0.25)).toBeTruthy();
}
);
test("由距离得到对应点", () =>
{
let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0);
expect(equal(arc.GetPointAtDistance(0.5 * Math.PI * 5), new Vector3(5, 5, 0))).toBeTruthy();
}
);
test("由参数得到距离", () =>
{
let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0);
equaln(arc.GetDistAtParam(0.5), 0.5 * Math.PI * 5)
expect(equaln(arc.GetDistAtParam(0.5), 0.5 * Math.PI * 5)).toBeTruthy();
}
);
test("由点得到距离", () =>
{
let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0);
expect(equaln(arc.GetDistAtPoint(new Vector3(5, 5, 0)), 0.5 * Math.PI * 5)).toBeTruthy();
expect(arc.GetDistAtPoint(new Vector3(10, 0, 0))).toBe(Math.PI * 5);
}
);
test('圆弧偏移', () =>
{
let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0);
for (let d of [0, -10, 20])
{
let arcs = arc.GetOffsetCurves(d);
for (let a of arcs)
{
expect(a.Center).toMatchSnapshot();
expect(a.StartAngle).toMatchSnapshot();
expect(a.EndAngle).toMatchSnapshot();
expect(a.Radius).toMatchSnapshot();
}
}
arc.Reverse();
for (let d of [0, -10, 20])
{
let arcs = arc.GetOffsetCurves(d);
for (let a of arcs)
{
expect(a.Center).toMatchSnapshot();
expect(a.StartAngle).toMatchSnapshot();
expect(a.EndAngle).toMatchSnapshot();
expect(a.Radius).toMatchSnapshot();
}
}
});
test('最近点', () =>
{
let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0);
expect(arc.GetClosestPointTo(new Vector3(-5, 0, 0), true)/*?*/).toMatchSnapshot();//0,0,0.
expect(arc.GetClosestPointTo(new Vector3(8, 0, 0), true)/*?*/).toMatchSnapshot();//0,0,0.
});

@ -0,0 +1,131 @@
import { Circle } from '../../src/DatabaseServices/Circle';
import { Vector3, Vector2 } from 'three';
import { app } from '../../src/ApplicationServices/Application';
import { Command } from '../../src/Editor/CommandMachine';
import { PromptStatus } from '../../src/Editor/PromptResult';
import { RenderType } from '../../src/GraphicsSystem/Enum';
import { equal, equaln } from '../../src/Geometry/GeUtils';
test('圆参数', () =>
{
let circle = new Circle(new Vector3(5, 0, 0), 5);
circle.GetParamAtPoint(new Vector3(0, 0, 0))/*?*/
expect(equaln(circle.GetParamAtPoint(new Vector3(0, 0, 0))/*?*/, 0.5)).toBeTruthy();
expect(equaln(circle.GetParamAtPoint(new Vector3(5, 5, 0)), 0.25)).toBeTruthy();
expect(equaln(circle.GetParamAtPoint(new Vector3(10, 0, 0)), 0)).toBeTruthy();
expect(circle.GetParamAtPoint(new Vector3(-5, -5, 0))).toBe(NaN);
expect(circle.GetParamAtPoint(new Vector3(10, 0, 0))).toBe(0);
});
test('半径为0的圆,参数', () =>
{
let circle = new Circle(new Vector3(), 0);
expect(circle.GetParamAtPoint(new Vector3(0, 0, 0))).toBe(0);
});
test("圆的切割1", () =>
{
let circle = new Circle(new Vector3(5, 0, 0), 5);
let cs = circle.GetSplitCurves(0.5);
expect(cs.length).toBe(0);
});
test("圆的切割2", () =>
{
let circle = new Circle(new Vector3(5, 0, 0), 5);
let cs = circle.GetSplitCurves([0.5, 0.75, 0.25]);
for (let c of cs)
{
expect(c.StartPoint).toMatchSnapshot()
expect(c.EndPoint).toMatchSnapshot()
}
});
test("由距离得到圆参数", () =>
{
let circle = new Circle(new Vector3(5, 0, 0), 5);
expect(equaln(circle.GetParamAtDist(0.5 * Math.PI * 5), 0.25)).toBeTruthy();
}
);
test("由距离得到对应点", () =>
{
let circle = new Circle(new Vector3(5, 0, 0), 5);
expect(equal(circle.GetPointAtDistance(0.5 * Math.PI * 5), new Vector3(5, 5, 0))).toBeTruthy();
}
);
test("由参数得到距离", () =>
{
let circle = new Circle(new Vector3(5, 0, 0), 5);
expect(equaln(circle.GetDistAtParam(0.5), Math.PI * 5)).toBeTruthy();
}
);
test("由点得到距离", () =>
{
let circle = new Circle(new Vector3(5, 0, 0), 5);
expect(equaln(circle.GetDistAtPoint(new Vector3(5, 5, 0)), 0.5 * Math.PI * 5)).toBeTruthy();
expect(circle.GetDistAtPoint(new Vector3(10, 0, 0))).toBe(0);
}
);
test('圆偏移', () =>
{
let circle = new Circle(new Vector3(5, 0, 0), 5);
let arcs3 = circle.GetOffsetCurves(10);
let arcs = circle.GetOffsetCurves(-3);
arcs3[0].StartPoint //?
arcs3[0].EndPoint //?
arcs[0].StartPoint //?
arcs[0].EndPoint //?
// expect(arcs.length).toBe(1);
// expect(arcs.length).toBe(Math.PI * 2);
let newArc = arcs[0];
expect(newArc.StartPoint).toMatchSnapshot();
expect(newArc.EndPoint).toMatchSnapshot();
let circle2 = new Circle(new Vector3(10, 0, 0), 10);
let circles2 = circle2.GetOffsetCurves(-5)[0]; //?
circles2.StartPoint //?
circles2.EndPoint //?
expect(circles2.StartPoint).toMatchSnapshot();
expect(circles2.EndPoint).toMatchSnapshot();
circles2 = circle2.GetOffsetCurves(10)[0]; //?
circles2.StartPoint //?
circles2.EndPoint //?
expect(circles2.StartPoint).toMatchSnapshot();
expect(circles2.EndPoint).toMatchSnapshot();
expect(circles2.StartPoint).toMatchSnapshot();
expect(circles2.EndPoint).toMatchSnapshot();
circles2 = circle2.GetOffsetCurves(-5)[0]; //?
circles2.StartPoint //?
circles2.EndPoint //?
expect(circles2.StartPoint).toMatchSnapshot();
expect(circles2.EndPoint).toMatchSnapshot();
});
test('最近点', () =>
{
let circle = new Circle(new Vector3(5, 0, 0), 5);
expect(circle.GetClosestPointTo(new Vector3(-5, 0, 0), true)/*?*/).toMatchSnapshot();//0,0,0.
expect(circle.GetClosestPointTo(new Vector3(8, 0, 0), true)/*?*/).toMatchSnapshot();//10,0,0.
});

@ -1,7 +1,6 @@
import * as THREE from 'three';
import { Intersect } from '../../src/Geometry/GeUtils';
import { IntersectLAndL } from '../../src/GraphicsSystem/IntersectWith';
test('相交测试', () =>
{
@ -13,14 +12,13 @@ test('相交测试', () =>
let p5 = new THREE.Vector3(3, 0, 0);
let p6 = new THREE.Vector3(6, 0, 0);
let res = Intersect(p1, p2, p3, p4);/*?*/
let res = IntersectLAndL(p1, p2, p3, p4);/*?*/
expect(res).toMatchSnapshot();
res = Intersect(p1, p2, p5, p6);/*?*/
res = IntersectLAndL(p1, p2, p5, p6);/*?*/
expect(res).toMatchSnapshot();
let ins = Intersect(
let ins = IntersectLAndL(
new THREE.Vector3(0, 5),
new THREE.Vector3(5, 5),
new THREE.Vector3(0.5, 1),

@ -19,9 +19,9 @@ test('直线相交,共线', () =>
expect(pts.length).toBe(0);
pts = IntersectLineAndLine(l1, l2, IntersectOption.ExtendArg);
expect(pts.length).toBe(1);
expect(pts.length).toBe(0);
pts = IntersectLineAndLine(l1, l2, IntersectOption.ExtendBoth);
pts = IntersectLineAndLine(l1, l2, IntersectOption.ExtendBoth);//?
expect(pts.length).toBe(1);
});

@ -0,0 +1,118 @@
import { Polyline } from "../../src/DatabaseServices/Polyline";
import { Vector2, Vector3 } from "three";
import { IntersectOption } from "../../src/GraphicsSystem/IntersectWith";
describe("相交", () =>
{
test("不相交曲线", () =>
{
let pl = new Polyline([
{
pt: new Vector2(37, 5),
bul: -1.63
},
{
pt: new Vector2(26.7, -4),
bul: 0.32
},
])
let p2 = new Polyline([
{
pt: new Vector2(26, -3),
bul: 0.32
},
{
pt: new Vector2(9.5, -8.2),
bul: 2.01
},
])
let pts = pl.IntersectWith(p2, IntersectOption.OnBothOperands);
expect(pts.length).toBe(0);
let pts1 = pl.IntersectWith(p2, IntersectOption.ExtendBoth);
expect(pts1.length).toBe(2);
let pts2 = pl.IntersectWith(p2, IntersectOption.ExtendThis);
expect(pts2.length).toBe(0);
let pts3 = pl.IntersectWith(p2, IntersectOption.ExtendArg);
expect(pts3.length).toBe(1);
})
test("相交曲线", () =>
{
let pl = new Polyline([
{
pt: new Vector2(0, 0),
bul: 1
},
{
pt: new Vector2(0, 5),
bul: 0.32
},
])
let p2 = new Polyline([
{
pt: new Vector2(-1, 0),
bul: -1
},
{
pt: new Vector2(4, 0),
bul: 0
},
])
let p3 = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(3, 3),
bul: 0
},
])
let p4 = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(1, 1),
bul: 0
},
])
let p5 = new Polyline([
{
pt: new Vector2(1, 0),
bul: 0
},
{
pt: new Vector2(1, 0.5),
bul: 0
},
])
let p6 = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(3, 3),
bul: 0
},
])
let pts = pl.IntersectWith(p2, IntersectOption.OnBothOperands);
expect(pts.length).toBe(1);
let pts1 = pl.IntersectWith(p2, IntersectOption.ExtendBoth);
expect(pts1.length).toBe(2);
let pts2 = pl.IntersectWith(p2, IntersectOption.ExtendThis);
expect(pts2.length).toBe(2);
let pts3 = pl.IntersectWith(p2, IntersectOption.ExtendArg);
expect(pts3.length).toBe(1);
let pts4 = pl.IntersectWith(p3, IntersectOption.OnBothOperands);
expect(pts4[0]).toEqual(new Vector3(2.5, 2.5, 0))
expect(pts4.length).toBe(2);
let pts5 = pl.IntersectWith(p4, IntersectOption.OnBothOperands);
expect(pts5.length).toBe(1);
let pts6 = pl.IntersectWith(p4, IntersectOption.ExtendArg);
expect(pts6.length).toBe(2);
let pts7 = p5.IntersectWith(p6, IntersectOption.ExtendThis);
expect(pts7.length).toBe(1);
})
})

@ -0,0 +1,85 @@
import { Vector2 } from "three";
import { Polyline } from "../../src/DatabaseServices/Polyline";
import { equaln } from "../../src/Geometry/GeUtils";
test('获得点,来自参数', () =>
{
let pl = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(5, 0),
bul: 1
},
{
pt: new Vector2(5, 5),
bul: -1
},
{
pt: new Vector2(5, 10),
bul: 0
},
{
pt: new Vector2(0, 10),
bul: 0
},
{
pt: new Vector2(0, 0),
bul: 0
}
]);
//不闭合时
pl.CloseMark = false;
for (let p = -2; p < 7; p += 0.2)
{
let pt = pl.GetPointAtParam(p);
//反向测试
if (pt)
{
let pn = pl.GetParamAtPoint(pt);
if (equaln(pn, 0))
{
expect(equaln(p, 0) || equaln(p, pl.EndParam)).toBeTruthy();
}
else
{
expect(equaln(p, pn)).toBeTruthy();
}
}
//测试一阶导数
let deriv = pl.GetFistDeriv(p);
expect(deriv).toMatchSnapshot();
expect(pt).toMatchSnapshot();
}
//闭合时
pl.CloseMark = true;
for (let p = -2; p < 7; p += 0.3)
{
let pt = pl.GetPointAtParam(p);
//反向测试
if (pt)
{
let pn = pl.GetParamAtPoint(pt);
if (equaln(pn, 0))
{
expect(equaln(pn, 0) || equaln(p, pl.EndParam)).toBeTruthy();
}
else
{
expect(equaln(p, pn)).toBeTruthy();
}
}
//测试一阶导数
let deriv = pl.GetFistDeriv(p);
expect(deriv).toMatchSnapshot();
expect(pt).toMatchSnapshot();
}
});

File diff suppressed because it is too large Load Diff

@ -0,0 +1,472 @@
import { Vector2, Vector3 } from 'three';
import { Polyline } from '../../src/DatabaseServices/Polyline';
import { equal, equaln } from '../../src/Geometry/GeUtils';
test("多段线点获取参数", () =>
{
let pl = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(5, 0),
bul: 1
},
{
pt: new Vector2(5, 5),
bul: -1
},
{
pt: new Vector2(5, 10),
bul: 0
},
{
pt: new Vector2(0, 10),
bul: 0
},
{
pt: new Vector2(0, 0),
bul: 0
}
])
expect(pl.GetParamAtPoint(new Vector3(5, 0, 0))).toBe(1);
expect(pl.GetParamAtPoint(new Vector3(6, 0, 0)) /*?*/).toBe(NaN);
expect(pl.GetParamAtPoint(new Vector3(-2.5, 0, 0))/*?*/).toBe(-0.5);
expect(pl.GetParamAtPoint(new Vector3(7.5, 2.5, 0))).toBe(1.5);
expect(pl.GetParamAtPoint(new Vector3(5, 5, 0))).toBe(2);
expect(pl.GetParamAtPoint(pl.GetPointAtParam(1.25)) /*?*/).toBe(1.25);
expect(equaln(pl.GetParamAtPoint(new Vector3(0, 5, 0)), 4.5)).toBeTruthy();
expect(pl.GetParamAtPoint(new Vector3(0, -5, 0))).toBe(5.5);
expect(pl.GetParamAtPoint(new Vector3(0, 10, 0))).toBe(4);
let pl2 = new Polyline([
{
pt: new Vector2(1.5, 8.5),
bul: 0
},
{
pt: new Vector2(1.5, 1.5),
bul: 0
}
])
expect(pl2.GetParamAtPoint(new Vector3(1.5, 5))).toBe(0.5)
})
describe('多段线', () =>
{
test("多段线参数获取点", () =>
{
let pl = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(5, 0),
bul: 1
},
{
pt: new Vector2(5, 5),
bul: -1
},
{
pt: new Vector2(5, 10),
bul: 0
},
{
pt: new Vector2(0, 10),
bul: 0
},
{
pt: new Vector2(0, 0),
bul: 0
}
])
expect(equal(pl.GetPointAtParam(1), new Vector3(5, 0, 0))).toBeTruthy();
expect(equal(pl.GetPointAtParam(0.5), new Vector3(2.5, 0, 0))).toBeTruthy();
expect(equal(pl.GetPointAtParam(-0.5), new Vector3(-2.5, 0, 0))).toBeTruthy();
expect(equal(pl.GetPointAtParam(4.5), new Vector3(0, 5, 0))).toBeTruthy();
expect(equal(pl.GetPointAtParam(5), new Vector3(0, 0, 0))).toBeTruthy();
expect(equal(pl.GetPointAtParam(5.5), new Vector3(0, -5, 0))).toBeTruthy();
})
test("多段线参数获取弧长", () =>
{
let pl = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(5, 0),
bul: 1
},
{
pt: new Vector2(5, 5),
bul: -1
},
{
pt: new Vector2(5, 10),
bul: 0
},
{
pt: new Vector2(0, 10),
bul: 0
},
{
pt: new Vector2(0, 0),
bul: 0
}
])
expect(pl.GetDistAtParam(1)).toBe(5);
expect(pl.GetDistAtParam(2)).toBe(5 + Math.PI * 2.5);
expect(pl.GetDistAtParam(1.5)).toBe(5 + Math.PI * 2.5 / 2);
expect(pl.GetDistAtParam(3)).toBe(5 + Math.PI * 5);
expect(pl.GetDistAtParam(4)).toBe(5 + Math.PI * 5 + 5);
expect(pl.GetDistAtParam(3.5)).toBe(5 + Math.PI * 5 + 2.5);
})
test("多段线弧长获取点", () =>
{
let pl = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(5, 0),
bul: 1
},
{
pt: new Vector2(5, 5),
bul: -1
},
{
pt: new Vector2(5, 10),
bul: 0
},
{
pt: new Vector2(0, 10),
bul: 0
},
{
pt: new Vector2(0, 0),
bul: 0
}
])
expect(equal(pl.GetPointAtDistance(5), new Vector3(5, 0, 0))).toBeTruthy();
expect(equal(pl.GetPointAtDistance(2.5), new Vector3(2.5, 0, 0))).toBeTruthy();
expect(equal(pl.GetPointAtDistance(5 + Math.PI * 2.5), new Vector3(5, 5, 0))).toBeTruthy();
expect(equal(pl.GetPointAtDistance(5 + Math.PI * 2.5 * 2), new Vector3(5, 10, 0))).toBeTruthy();
expect(equal(pl.GetPointAtDistance(0), new Vector3(0, 0, 0))).toBeTruthy();
})
test("多段线距离获取参数", () =>
{
let pl = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(5, 0),
bul: 1
},
{
pt: new Vector2(5, 5),
bul: -1
},
{
pt: new Vector2(5, 10),
bul: 0
},
{
pt: new Vector2(0, 10),
bul: 0
},
{
pt: new Vector2(0, 0),
bul: 0
}
])
expect(pl.GetParamAtDist(5)).toBe(1);
expect(pl.GetParamAtDist(5 + Math.PI * 2.5)).toBe(2);
expect(pl.GetParamAtDist(5 + Math.PI * 2.5 / 2)).toBe(1.5);
})
test("多段线点获取弧长", () =>
{
let pl = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(5, 0),
bul: 1
},
{
pt: new Vector2(5, 5),
bul: -1
},
{
pt: new Vector2(5, 10),
bul: 0
},
{
pt: new Vector2(0, 10),
bul: 0
},
{
pt: new Vector2(0, 0),
bul: 0
}
])
expect(pl.GetDistAtPoint(new Vector3(0, 0, 0))).toBe(0);
expect(pl.GetDistAtPoint(new Vector3(5, 0, 0))).toBe(5);
expect(pl.GetDistAtPoint(new Vector3(7.5, 2.5, 0))).toBe(5 + Math.PI / 2 * 2.5);
expect(pl.GetDistAtPoint(new Vector3(7.5, 2.5, 0))).toBe(5 + Math.PI / 2 * 2.5);
expect(equaln(pl.Length, 20 + 2 * Math.PI * 2.5)).toBeTruthy();
})
test("多段线延伸,不闭合", () =>
{
let pl = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(5, 0),
bul: 1
},
{
pt: new Vector2(5, 5),
bul: -1
},
{
pt: new Vector2(5, 10),
bul: 0
},
{
pt: new Vector2(0, 10),
bul: 0
},
{
pt: new Vector2(0, 0),
bul: 0
}
])
let pl2 = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(5, 0),
bul: 1
},
{
pt: new Vector2(5, 5),
bul: -1
},
{
pt: new Vector2(5, 10),
bul: 0
},
{
pt: new Vector2(0, 10),
bul: 0
}
])
expect(pl.IsClose).toBeTruthy();
pl.Extend(5.5);
expect(pl.EndPoint).toEqual(new Vector3(0, -5, 0));
expect(pl.LineData.length).toEqual(6);
expect(pl.GetPointAtParam(5)).toEqual(new Vector3(0, -5, 0));
pl.Extend(-0.5);
expect(pl.StartPoint).toEqual(new Vector3(-2.5, 0, 0));
expect(pl.IsClose).toBeFalsy();
pl2.Extend(4.5)
expect(pl2.EndPoint).toEqual(new Vector3(-2.5, 10, 0));
pl2.Extend(-0.5)
expect(pl2.EndPoint).toEqual(new Vector3(-2.5, 10, 0));
expect(pl2.StartPoint).toEqual(new Vector3(-2.5, 0, 0));
let pl3 = new Polyline([
{
pt: new Vector2(0, 0),
bul: 1
},
{
pt: new Vector2(0, 5),
bul: 0
}
])
pl3.Extend(1.5);
expect(equal(pl3.EndPoint, new Vector3(-2.5, 2.5, 0))).toBeTruthy();
pl3.Extend(1 + 1 / 3);
// expect(pl3.EndPoint).toEqual(new Vector3(0, 0, 0));
expect(equal(pl3.EndPoint /*?*/, new Vector3(0, 0, 0))).toBeTruthy();
})
test("多段线延伸,闭合", () =>
{
let pl = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(5, 0),
bul: 1
},
{
pt: new Vector2(5, 5),
bul: -1
},
{
pt: new Vector2(5, 10),
bul: 0
},
{
pt: new Vector2(0, 10),
bul: 0
},
{
pt: new Vector2(0, 0),
bul: 0
}
])
pl.CloseMark = true;
pl.Extend(5.5);
expect(pl.EndPoint).toEqual(new Vector3());
})
test("多段线点在线上", () =>
{
let pl = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(5, 0),
bul: 1
},
{
pt: new Vector2(5, 5),
bul: -1
},
{
pt: new Vector2(5, 10),
bul: 0
},
{
pt: new Vector2(0, 10),
bul: 0
},
{
pt: new Vector2(0, 0),
bul: 0
}
])
expect(pl.GetParamAtPoint(new Vector3())).toBe(0);
expect(pl.PtOnCurve(new Vector3(0, 0, 0))).toBeTruthy();
expect(pl.PtOnCurve(new Vector3(5, 0, 0))).toBeTruthy();
expect(pl.PtOnCurve(new Vector3(7.5, 2.5, 0))).toBeTruthy();
expect(pl.PtOnCurve(new Vector3(7.5, 3.5, 0))).toBeFalsy();
})
test("多段线最近点", () =>
{
let pl = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(5, 0),
bul: 1
},
{
pt: new Vector2(5, 5),
bul: -1
},
{
pt: new Vector2(5, 10),
bul: 0
},
{
pt: new Vector2(0, 10),
bul: 0
},
{
pt: new Vector2(0, 0),
bul: 0
}
])
expect(pl.GetClosestPointTo(new Vector3(), true)).toEqual(new Vector3());
expect(pl.GetClosestPointTo(new Vector3(3.5, 2.5), true)).toEqual(new Vector3(3.5, 0, 0));
expect(pl.GetClosestPointTo(new Vector3(1.5, 3.5), true)).toEqual(new Vector3(0, 3.5, 0));
expect(equal(pl.GetClosestPointTo(new Vector3(1.5, 3.5), true), new Vector3(0, 3.5, 0))).toBeTruthy();
expect(equal(pl.GetClosestPointTo(new Vector3(-0.5, -1), true), new Vector3(0, -1, 0))).toBeTruthy();
})
test("多段线包围盒", () =>
{
let pl = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(5, 0),
bul: 1
},
{
pt: new Vector2(5, 5),
bul: -1
},
{
pt: new Vector2(5, 10),
bul: 0
},
{
pt: new Vector2(0, 10),
bul: 0
},
{
pt: new Vector2(0, 0),
bul: 0
}
])
expect(pl.BoundingBox.getSize()).toEqual(new Vector3(7.5, 10, 0))
})
test("多段线反转", () =>
{
let pl = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(5, 0),
bul: 1
},
{
pt: new Vector2(5, 5),
bul: -1
},
{
pt: new Vector2(5, 10),
bul: 0
},
{
pt: new Vector2(0, 10),
bul: 0
}
])
pl.Reverse();
expect(pl.StartPoint).toEqual(new Vector3(0, 10, 0))
})
})

@ -0,0 +1,111 @@
import { Polyline } from "../../src/DatabaseServices/Polyline";
import { Vector2 } from "three";
//构造测试的多段线
function createTestPolyline(): Polyline
{
return new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(5, 0),
bul: 1
},
{
pt: new Vector2(5, 5),
bul: -1
},
{
pt: new Vector2(5, 10),
bul: 0
},
{
pt: new Vector2(0, 10),
bul: 0
},
{
pt: new Vector2(0, 0),
bul: 0
}
]);
}
//切割测试
{
let pl = createTestPolyline();
test('多切刀', () =>
{
//不闭合标志
pl.CloseMark = false;
//不包括0
let cus = pl.GetSplitCurves([1.5, 2.5, 2.8, 2.8, 1.2, 2, 1.8, 1, 2.2]);//
for (let cu of cus)
{
expect(cu.LineData).toMatchSnapshot();
}
//包括0
let cus2 = pl.GetSplitCurves([1.5, 2.5, 2.8, 2.8, 1.2, 2, 1.8, 1, 2.2, 0]);//
for (let cu of cus)
{
expect(cu.LineData).toMatchSnapshot();
}
});
test('多切刀闭合', () =>
{
//闭合标志
pl.CloseMark = true;
//不包括0
let cus = pl.GetSplitCurves([1.5, 2.5, 2.8, 2.8, 1.2, 2, 1.8, 1, 2.2]);//
for (let cu of cus)
{
expect(cu.LineData).toMatchSnapshot();
}
//包括0
let cus2 = pl.GetSplitCurves([1.5, 2.5, 2.8, 2.8, 1.2, 2, 1.8, 1, 2.2, 0]);//
for (let cu of cus)
{
expect(cu.LineData).toMatchSnapshot();
}
});
test('单刀', () =>
{
for (let p of [0, 1.5, 2, 2.5, 3])
{
let cus = pl.GetSplitCurves(p);
for (let cu of cus)
{
//该测试用于数值精度的问题经常造成测试失败.请刷新测试.
expect(cu.LineData).toMatchSnapshot();
}
}
});
test('单刀闭合', () =>
{
pl.CloseMark = true;
for (let p of [0, 1.5, 2, 2.5, 3])
{
let cus = pl.GetSplitCurves(p);
for (let cu of cus)
{
expect(cu.LineData).toMatchSnapshot();
}
}
});
}

@ -1,9 +1,9 @@
import { Vector3 } from 'three';
import { app } from '../ApplicationServices/Application';
import { getCircleAngle, rotateLine, Vec2DTo3D, Vec3DTo2D } from '../Common/CurveUtils';
import { getArcAngle, rotateLine, Vec2DTo3D, Vec3DTo2D } from '../Common/CurveUtils';
import { Line } from '../DatabaseServices/Line';
import { Polyline, PolylineData } from '../DatabaseServices/Polyline';
import { Polyline, PolylineProps } from '../DatabaseServices/Polyline';
import { Command } from '../Editor/CommandMachine';
import { PromptStatus } from '../Editor/PromptResult';
@ -27,18 +27,18 @@ export class DrawPolyline implements Command
this.m_Model = PolylineModel.Line;
let p1 = ptRes.Value;
let basePt = ptRes.Value;
//存储基点
let BasePts = [p1];
let BasePts = [basePt];
//多段线最终点
let data: PolylineData = {
pt: Vec3DTo2D(p1),
let data: PolylineProps = {
pt: Vec3DTo2D(basePt),
bul: 0
}
//储存多段线数据
let lineData = [data]
let lineProps = [data]
let polyline = new Polyline(lineData);
let polyline = new Polyline(lineProps);
app.m_Database.ModelSpace.Append(polyline);
// 切线
@ -54,37 +54,37 @@ export class DrawPolyline implements Command
//返回一步
let restore = () =>
{
lineData.pop();
polyline.LineData = lineData;
lineProps.pop();
polyline.LineData = lineProps;
}
// 更新多段线凸度
let updateBul = (v, p1) =>
let updateBul = (endPt: Vector3, startPt: Vector3) =>
{
// 弦长矢量
chord = v.clone().sub(p1);
cirAng = getCircleAngle(chord, tangentLine);
chord = endPt.clone().sub(startPt);
cirAng = getArcAngle(chord, tangentLine);
if (cirAng)
{
//凸度
let bul = Math.tan(cirAng / 4);
lineData[lineData.length - 2].bul = bul
lineProps[lineProps.length - 2].bul = bul
}
}
while (true)
{
data = {
pt: Vec3DTo2D(p1),
pt: Vec3DTo2D(basePt),
bul: 0
}
if (lineData.length === 2)
if (lineProps.length === 2)
{
KeyWordList.push({ msg: "闭合", key: "C" })
}
lineData.push(data);
lineProps.push(data);
app.m_Editor.m_CommandStore.Prompt("请输入点2:");
ptRes = await app.m_Editor.GetPoint({
Msg: "请输入点2:",
BasePoint: p1,
BasePoint: basePt,
AllowDrawRubberBand: true,
KeyWordList,
Callback: (v) =>
@ -93,8 +93,8 @@ export class DrawPolyline implements Command
{
if (!tangentLine) tangentLine = new Vector3(1, 0, 0);
data.pt.set(v.x, v.y);
updateBul(v, p1);
polyline.LineData = lineData;
updateBul(v, basePt);
polyline.LineData = lineProps;
}
}
});
@ -105,17 +105,17 @@ export class DrawPolyline implements Command
if (this.m_Model === 1)
{
//切线
tangentLine = ptRes.Value.clone().sub(p1).normalize();
tangentLine = ptRes.Value.clone().sub(basePt).normalize();
}
else
{
updateBul(ptRes.Value, p1);
updateBul(ptRes.Value, basePt);
tangentLine = rotateLine(tangentLine, cirAng)
}
polyline.LineData = lineData;
BasePts.push(p1);
p1 = ptRes.Value;
polyline.LineData = lineProps;
BasePts.push(basePt);
basePt = ptRes.Value;
continue;
}
@ -124,26 +124,26 @@ export class DrawPolyline implements Command
//是否闭合曲线
if (ptRes.StringResult == "C")
{
data.pt = lineData[0].pt;
data.pt = lineProps[0].pt;
let endPt = Vec2DTo3D(data.pt);
if (this.m_Model === PolylineModel.Arc)
{
polyline.CloseMark = true;
updateBul(endPt, p1);
updateBul(endPt, basePt);
}
polyline.LineData = lineData;
polyline.LineData = lineProps;
break;
}
if (ptRes.StringResult == "U")
{
p1 = BasePts.pop();
lineData.pop();
basePt = BasePts.pop();
lineProps.pop();
if (this.m_Model === 1)
tangentLine = p1.clone().sub(BasePts[BasePts.length - 1]).normalize();
tangentLine = basePt.clone().sub(BasePts[BasePts.length - 1]).normalize();
else
{
data = lineData[lineData.length - 2];
data = lineProps[lineProps.length - 2];
cirAng = Math.atan(data.bul) * 4;
tangentLine = rotateLine(tangentLine, -cirAng)
}
@ -154,7 +154,7 @@ export class DrawPolyline implements Command
}
else if (ptRes.StringResult == "L")
{
lineData[lineData.length - 2].bul = 0;
lineProps[lineProps.length - 2].bul = 0;
this.m_Model = PolylineModel.Line;
}
restore();

@ -0,0 +1,31 @@
import { Command } from "../Editor/CommandMachine";
import { SelectSet } from "../Editor/SelectSet";
import { PromptStatus } from "../Editor/PromptResult";
import { app } from "../ApplicationServices/Application";
export class Command_Export implements Command
{
async exec(ss: SelectSet)
{
if (ss.SelectEntityList.length === 0)
{
let ssRes = await app.m_Editor.GetSelection({ Msg: "请选择需要拷贝的实体:" });
if (ssRes.Status != PromptStatus.OK)
return;
ss = ssRes.SelectSet;
}
for (let en of ss.SelectEntityList)
{
let ens = en.Export();
en.Erase();
for (let e of ens)
{
app.m_Database.ModelSpace.Append(e);
}
}
}
}

@ -7,39 +7,80 @@ export class Command_Offset implements Command
{
async exec()
{
let dis = await app.m_Editor.GetDistance({
Msg: "指定偏移距离:"
});
if (dis.Status == PromptStatus.OK)
if (dis.Status != PromptStatus.OK) return;
while (true)
{
let enRes = await app.m_Editor.GetEntity({
Msg: "选择要偏移的对象:"
});
if (enRes.Status != PromptStatus.OK)
break;
let pt = await app.m_Editor.GetPoint({
Msg: "指定要偏移的那一侧的点"
});
if (enRes.Status === PromptStatus.OK)
let cu = enRes.Entity;
if (cu instanceof Curve)
{
let ptClose = cu.GetClosestPointTo(pt.Value, false);
let toPtVec = pt.Value.clone().sub(ptClose); //点击处向量
let d = cu.GetFistDeriv(cu.GetParamAtPoint(ptClose));//切线。
let pt = await app.m_Editor.GetPoint({
Msg: "指定要偏移的那一侧的点"
});
let c = toPtVec.cross(d);
let cur = enRes.Entity;
// if (cur instanceof Line || cur instanceof Arc || cur instanceof Circle)
if (cur instanceof Curve)
let offCurs = cu.GetOffsetCurves(dis.Value * Math.sign(c.z));
offCurs.forEach((offCur) =>
{
let ptClose = cur.GetClosestPointTo(pt.Value, true);
let toPtVec = pt.Value.clone().sub(ptClose); //点击处向量
let d = cur.GetFistDeriv(cur.GetParamAtPoint(ptClose));//切线。
app.m_Database.ModelSpace.Append(offCur);
})
app.m_Viewer.m_bNeedUpdate = true;
}
}
}
}
let c = toPtVec.cross(d);
let offCur = cur.GetOffsetCurves(dis.Value * Math.sign(c.z))[0];
export class Command_TestOffset implements Command
{
async exec()
{
//禁用捕捉服务
app.m_Editor.m_GetpointServices.snapServices.m_Disabled = true;
while (true)
{
let enRes = await app.m_Editor.GetEntity({
Msg: "选择要偏移的对象:"
});
if (enRes.Status != PromptStatus.OK)
break;
let cu = enRes.Entity as Curve;
app.m_Database.ModelSpace.Append(offCur);
let lastpls: Curve[];
await app.m_Editor.GetPoint({
Msg: "指定要偏移的那一侧的点",
Callback: (p) =>
{
if (lastpls) lastpls.forEach(cu => cu.Erase());
let ptClose = cu.GetClosestPointTo(p, false);
let toPtVec = p.clone().sub(ptClose); //点击处向量
let d = cu.GetFistDeriv(cu.GetParamAtPoint(ptClose));//切线。
let c = toPtVec.cross(d);
lastpls = cu.GetOffsetCurves(p.distanceTo(cu.GetClosestPointTo(p, true)) * Math.sign(c.z));
lastpls.forEach((offCur) =>
{
app.m_Database.ModelSpace.Append(offCur);
})
app.m_Viewer.m_bNeedUpdate = true;
}
}
});
}
}
}

@ -2,22 +2,21 @@ import { Command } from '../Editor/CommandMachine';
import { SelectSet } from '../Editor/SelectSet';
import { Polyline } from '../DatabaseServices/Polyline';
import { app } from '../ApplicationServices/Application';
import { Curve } from '../DatabaseServices/Curve';
export class Command_RevPl implements Command
{
async exec(ss: SelectSet)
{
let pls: Polyline[] = [];
for (let en of ss.SelectEntityList)
{
if (en instanceof Polyline)
if (en instanceof Curve)
{
pls.push(en);
en.Reverse();
app.m_Editor.m_CommandStore.Prompt("成功翻转曲线");
}
}
app.m_Editor.UpdateScreen();
}
}

@ -13,7 +13,7 @@ export class Save implements Command
let store = await IndexedDbStore.CADStore();
let fileId = store.m_CurrentFileId;
app.m_Viewer.Render();
let url = app.m_Viewer.m_Render.domElement.toDataURL()
let url = app.m_Viewer.m_Render.domElement.toDataURL("image/png", 1)
let fileInfo: FileInfo;
if (!fileId)

@ -0,0 +1,24 @@
import { Command } from "../Editor/CommandMachine";
import { app } from "../ApplicationServices/Application";
import { PromptStatus } from "../Editor/PromptResult";
import { Line } from "../DatabaseServices/Line";
export class Command_TestBox implements Command
{
async exec()
{
let ss = await app.m_Editor.GetSelection();
if (ss.Status != PromptStatus.OK)
return;
for (let en of ss.SelectSet.SelectEntityList)
{
let box = en.BoundingBox;
let line = new Line(box.min, box.max);
app.m_Database.ModelSpace.Append(line);
}
}
}

@ -90,6 +90,13 @@ export class Command_Trim implements Command
cu.Erase();
continue;
}
else
{
// for (let cu of splitCus)
// {
// app.m_Database.ModelSpace.Append(cu)
// }
}
if (s instanceof SelectPick)
{

@ -0,0 +1,46 @@
import { Command } from "../Editor/CommandMachine";
import { app } from "../ApplicationServices/Application";
import { Line } from "../DatabaseServices/Line";
import { Curve, ExtendType } from "../DatabaseServices/Curve";
import { PromptStatus } from "../Editor/PromptResult";
import { Polyline } from "../DatabaseServices/Polyline";
export class Command_ClosePt implements Command
{
async exec()
{
let cuRes = await app.m_Editor.GetEntity();
if (cuRes.Entity instanceof Curve)
{
let cu = cuRes.Entity as Curve;
let line = new Line();
app.m_Database.ModelSpace.Append(line);
let extend = false;
while (true)
{
app.m_Editor.AddNoSnapEntity(line);
let p = await app.m_Editor.GetPoint({
KeyWordList: [{ key: "C", msg: (extend ? "不" : "") + "延伸" }],
Callback: p =>
{
line.StartPoint = p;
line.EndPoint = cu.GetClosestPointTo(p, extend);
}
})
if (p.Status === PromptStatus.Keyword)
{
extend = !extend;
}
if (p.Status === PromptStatus.Cancel)
return;
}
}
}
}

@ -0,0 +1,40 @@
import { app } from '../ApplicationServices/Application';
import { Circle } from '../DatabaseServices/Circle';
import { Curve } from '../DatabaseServices/Curve';
import { Command } from '../Editor/CommandMachine';
import { PromptStatus } from '../Editor/PromptResult';
import { IntersectOption } from '../GraphicsSystem/IntersectWith';
export class Command_INsTest implements Command
{
async exec()
{
let ss = await app.m_Editor.GetSelection();
if (ss.Status != PromptStatus.OK)
return;
let cus = ss.SelectSet.SelectEntityList.filter(e => e instanceof Curve);
for (let i = 0; i < cus.length; i++)
{
let cu = cus[i];
for (let j = i + 1; j < cus.length; j++)
{
let cu2 = cus[j];
let ins = cu.IntersectWith(cu2, IntersectOption.OnBothOperands);
for (let p of ins)
{
let c = new Circle(p, 0.1);
app.m_Database.ModelSpace.Append(c);
}
}
}
app.m_Editor.UpdateScreen();
}
}

@ -0,0 +1,270 @@
import { Command } from "../Editor/CommandMachine";
import { Polyline } from "../DatabaseServices/Polyline";
import { Vector2, Vector3 } from "three";
import { app } from "../ApplicationServices/Application";
import { Circle } from "../DatabaseServices/Circle";
import { Arc } from "../DatabaseServices/Arc";
import { Move, polar } from "../Geometry/GeUtils";
import { IntersectOption } from "../GraphicsSystem/IntersectWith";
import { Line } from "../DatabaseServices/Line";
import { ExtendType } from "../DatabaseServices/Curve";
export class Command_PLTest implements Command
{
async exec()
{
//this.intersect();
// this.splitPolyline();
this.splitPolyline();
// this.testGetPointAtParam();
}
createPolyline()
{
}
testClosePoint()
{
let pl = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(5, 0),
bul: 1
},
{
pt: new Vector2(5, 5),
bul: -1
},
{
pt: new Vector2(5, 10),
bul: 0
},
// {
// pt: new Vector2(0, 10),
// bul: 0
// },
// {
// pt: new Vector2(0, 0),
// bul: 0
// }
]);
// pl.CloseMark = true;
app.m_Database.ModelSpace.Append(pl);
let lines: Line[] = [];
let a = Math.PI / 180;
let center = new Vector3(2.5, 2.5)
for (let i = 0; i < 1; i++)
{
let p = polar(center.clone(), a * i, 3) as Vector3;
let pc = pl.GetClosestPointTo(p, true);
let line = new Line(p, pc);
app.m_Database.ModelSpace.Append(line);
lines.push(line);
}
app.m_Editor.GetPoint({
Callback: center =>
{
for (let i = 0; i < 1; i++)
{
let p = polar(center.clone(), a * i, 0) as Vector3;
lines[i].StartPoint = p;
lines[i].EndPoint = pl.GetClosestPointTo2(p, ExtendType.Back);
}
}
})
}
//TODO:[]多段线切割导致的数据错误,数据重用.
splitPolyline()
{
let pl = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(5, 0),
bul: 1
},
{
pt: new Vector2(5, 5),
bul: -1
},
{
pt: new Vector2(5, 10),
bul: 0
},
{
pt: new Vector2(0, 10),
bul: 0
},
{
pt: new Vector2(0, 0),
bul: 0
}
]);
pl.CloseMark = true;
let c = 0;
for (let p of [7])
// for (let p = -3; p < 7; p += 0.2)
{
// let pt = pl.GetPointAtParam(p);
// if (!pt) continue;
// let cir = new Circle(pt, 0.1);
// c++;
// cir.ColorIndex = c % 7 + 1;
// app.m_Database.ModelSpace.Append(cir);
// let d = pl.GetFistDeriv(p);
// let line = new Line(pt, pt.clone().add(d));
// line.ColorIndex = c % 7 + 1;
// app.m_Database.ModelSpace.Append(line);
for (let cu of pl.GetOffsetCurves(p))
{
app.m_Database.ModelSpace.Append(cu);
}
}
app.m_Database.ModelSpace.Append(pl);
}
testGetPointAtParam()
{
let pl = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(5, 0),
bul: 1
},
{
pt: new Vector2(5, 5),
bul: -1
},
{
pt: new Vector2(5, 10),
bul: 0
},
{
pt: new Vector2(0, 10),
bul: 0
},
{
pt: new Vector2(0, 0),
bul: 0
}
]);
pl.CloseMark = true;
console.log(pl.EndPoint);
let c = 0;
let v = pl.GetFistDeriv(7);
console.log(v);
let pt = app.m_Editor.GetPoint({
Callback: (pt) =>
{
}
})
// for (let p of [1.5, 2.5, 2.8, 2.8, 1.2, 2, 1.8, 1, 2.2, 0])
for (let p = -3; p < 7; p += 0.2)
{
let pt = pl.GetPointAtParam(p);
if (!pt) continue;
let cir = new Circle(pt, 0.1);
c++;
cir.ColorIndex = c % 7 + 1;
app.m_Database.ModelSpace.Append(cir);
let d = pl.GetFistDeriv(p);
let line = new Line(pt, pt.clone().add(d));
if (line.Length == 0)
{
console.log(1);
}
line.ColorIndex = c % 7 + 1;
app.m_Database.ModelSpace.Append(line);
}
app.m_Database.ModelSpace.Append(pl);
}
intersect()
{
let pl = new Polyline([
{
pt: new Vector2(0, 0),
bul: 1
},
{
pt: new Vector2(0, 5),
bul: 0.32
},
])
let p2 = new Polyline([
{
pt: new Vector2(-1, 0),
bul: -1
},
{
pt: new Vector2(4, 0),
bul: 0
},
])
let p3 = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(3, 3),
bul: 0
},
])
let p4 = new Polyline([
{
pt: new Vector2(0, 0),
bul: 0
},
{
pt: new Vector2(1, 1),
bul: 0
},
])
app.m_Database.ModelSpace.Append(pl);
app.m_Database.ModelSpace.Append(p4);
console.log(pl.IntersectWith(p4, IntersectOption.ExtendArg));
}
}

@ -1,6 +1,9 @@
import { data } from '../../Add-on/data';
import * as THREE from 'three';
import { data } from '../../Add-on/data';
import { polar } from '../../Geometry/GeUtils';
import { RotateUVs } from '../../Geometry/RotateUV';
export namespace CreateBoardUtil
{
//解析二维圆弧类.
@ -28,8 +31,8 @@ export namespace CreateBoardUtil
this.m_Center = p1.clone().add(p2);
this.m_Center.multiplyScalar(0.5);
this.m_Center.x += Math.cos(an) * toDis;
this.m_Center.y += Math.sin(an) * toDis;
polar(this.m_Center, an, toDis);
this.m_StartAn = p1.clone().sub(this.m_Center).angle();
this.m_EndAn = p2.clone().sub(this.m_Center).angle();
@ -46,9 +49,9 @@ export namespace CreateBoardUtil
//创建轮廓 通过点表和凸度
export function createPath(pts: THREE.Vector2[], buls: number[], shapeOut?: THREE.Shape): THREE.Shape
{
var shape = shapeOut || new THREE.Shape();
let shape = shapeOut || new THREE.Shape();
let firstPt = pts[0];
shape.moveTo(firstPt.x, firstPt.y);
for (let i = 0; i < pts.length - 1; i++)
{
@ -59,12 +62,12 @@ export namespace CreateBoardUtil
}
else
{
var pt = pts[i];
let pt = pts[i];
//参考
//http://www.dorodnic.com/blog/tag/three-js/ 绘制一个齿轮
//https://www.kirupa.com/html5/drawing_circles_canvas.htm //html5
var arc2 = new Arc2d(pt, nextPt, buls[i]);
var cen = arc2.m_Center;
let arc2 = new Arc2d(pt, nextPt, buls[i]);
let cen = arc2.m_Center;
shape.absarc(cen.x, cen.y, arc2.m_Radius, arc2.m_StartAn, arc2.m_EndAn, buls[i] < 0);
}
}

@ -2,8 +2,14 @@ import { Vector2, Vector3 } from 'three';
import * as THREE from 'three';
import { CreateBoardUtil } from '../ApplicationServices/mesh/createBoard';
import { angleTo } from '../Geometry/GeUtils';
import { angleTo, equaln, equal } from '../Geometry/GeUtils';
export enum ExtendDir
{
Front = 0,
Later = 1,
Both = 2
}
// 旋转矢量
export function rotateLine(l: Vector3, ang: number)
{
@ -14,7 +20,7 @@ export function rotateLine(l: Vector3, ang: number)
//2点加凸度获取圆弧面积
export function getArcArea(startV: THREE.Vector2, endV: THREE.Vector2, bul: number)
{
let arcData = getArcData(startV, endV, bul);
let arcData = getArcProps(startV, endV, bul);
//圆心角
let circleAng = Math.atan(bul) * 4;
//扇形面积
@ -29,11 +35,11 @@ export function getArcArea(startV: THREE.Vector2, endV: THREE.Vector2, bul: numb
}
}
//2点加凸度获取圆弧半径圆心,起始线,终止线
export function getArcData(startV: THREE.Vector2, endV: THREE.Vector2, bul: number)
export function getArcProps(startV: THREE.Vector2, endV: THREE.Vector2, bul: number)
{
let arc2d = new CreateBoardUtil.Arc2d(startV, endV, bul);
let centerPt = arc2d.m_Center;
let rad = arc2d.m_Radius;
let rad = Math.abs(arc2d.m_Radius);
//起始矢量
let startVec = startV.clone().sub(centerPt);
//终止矢量
@ -73,8 +79,10 @@ export function getCircleCenter(pt1: Vector3, pt2: Vector3, pt3: Vector3)
return center;
}
//3点获取凸度
export function getArcAngle(startPt: Vector3, midPt: Vector3, endPt: Vector3)
/**
*
*/
export function getArcAngleBy3Pt(startPt: Vector3, midPt: Vector3, endPt: Vector3)
{
// 圆心
let center = getCircleCenter(startPt, midPt, endPt);
@ -99,7 +107,7 @@ export function getArcAngle(startPt: Vector3, midPt: Vector3, endPt: Vector3)
return circleAng *= (-dir.z);
}
// 弦长+切线获取圆心角
export function getCircleAngle(chord: Vector3, tangentLine: Vector3)
export function getArcAngle(chord: Vector3, tangentLine: Vector3)
{
let dir = tangentLine.clone().cross(chord).normalize();
@ -120,7 +128,7 @@ export function getDeterminant(v1: Vector2, v2: Vector2): number
return v1.x * v2.y - v1.y * v2.x;
}
// 获取曲线指定位置的点
export function getPointAtParam(startPt: Vector2, endPt: Vector2, bul: number, segment: number)
export function getPtAtCurveParam(startPt: Vector2, endPt: Vector2, bul: number, segment: number)
{
let pt = new Vector3();
if (bul === 0)
@ -129,18 +137,15 @@ export function getPointAtParam(startPt: Vector2, endPt: Vector2, bul: number, s
}
else
{
let arc2d = new CreateBoardUtil.Arc2d(startPt, endPt, bul);
let circlePt = arc2d.m_Center;
//起始矢量
let startVec = startPt.clone().sub(circlePt);
// 将起始线终止线转3维
let startLine = Vec2DTo3D(startVec);
let arcData = getArcProps(startPt, endPt, bul);
// 起始线
let startLine = Vec2DTo3D(arcData.startVec);
//圆心角
let circleAng = Math.atan(bul) * 4 * segment;
if (Math.abs(circleAng) > 2 * Math.PI)
circleAng = 2 * Math.PI * (bul > 0 ? 1 : -1);
circleAng = 2 * Math.PI * Math.sign(bul);
startLine = rotateLine(startLine, circleAng)
pt = Vec2DTo3D(circlePt);
pt = Vec2DTo3D(arcData.centerPt);
pt.add(startLine);
}
return pt;
@ -157,7 +162,7 @@ export function getCurveLength(startPt: Vector2, endPt: Vector2, bul: number)
}
else
{
let arcData = getArcData(startPt, endPt, bul);
let arcData = getArcProps(startPt, endPt, bul);
// 圆心角
let cirAng = Math.atan(bul) * 4;
dist = Math.abs(arcData.rad) * Math.abs(cirAng);
@ -165,50 +170,51 @@ export function getCurveLength(startPt: Vector2, endPt: Vector2, bul: number)
return dist;
}
//点是否在圆弧上
export function isAtArc(startPt: Vector2, endPt: Vector2, bul: number, pt: Vector3)
export function isPtOnArc(startPt: Vector2, endPt: Vector2, bul: number, pt: Vector3, isExt = false)
{
let arcData = getArcData(startPt, endPt, bul);
let arcData = getArcProps(startPt, endPt, bul);
let rad = Math.abs(arcData.rad);
//圆心到输入点连线
let ptLine = pt.clone().sub(Vec2DTo3D(arcData.centerPt));
if (Math.abs(ptLine.length() - rad) <= 0.000001)
if (equaln(ptLine.length(), rad, 1e-7))
{
if (isExt) return true;
let startLine = Vec2DTo3D(arcData.startVec);
let endLine = Vec2DTo3D(arcData.endVec);
let oldCircleAngle = Math.abs(Math.atan(bul) * 4);
if (startLine.equals(ptLine) || endLine.equals(ptLine))
if (equal(startLine, ptLine) || equal(endLine, ptLine))
return true;
let cirAng = getCirLineAngle(startLine, ptLine, bul);
let cirAng = getArcLineAngle(startLine, ptLine, bul);
if (Math.abs(cirAng) < oldCircleAngle)
return true;
}
return false;
}
// 获得圆弧指定点的弧长
export function getArcPtLenAngle(startPt: Vector2, endPt: Vector2, bul: number, pt: Vector3)
// 获得圆弧指定点的弧长和角度
export function getArcPtLenAndAngle(startPt: Vector2, endPt: Vector2, bul: number, pt: Vector3)
{
let arcData = getArcData(startPt, endPt, bul);
let arcData = getArcProps(startPt, endPt, bul);
let rad = Math.abs(arcData.rad);
//圆心到输入点连线
let ptLine = pt.clone().sub(Vec2DTo3D(arcData.centerPt));
let startLine = Vec2DTo3D(arcData.startVec);
let cirAng = getCirLineAngle(startLine, ptLine, bul);
let cirAng = getArcLineAngle(startLine, ptLine, bul);
return {
len: Math.abs(cirAng) * rad,
angle: cirAng
}
}
// 求圆弧上任一条线的圆心角
export function getCirLineAngle(startLine: Vector3, ptLine: Vector3, bul: number)
export function getArcLineAngle(startLine: Vector3, ptLine: Vector3, bul: number)
{
let cirAng = angleTo(startLine, ptLine);
if (cirAng * bul < 0)
{
cirAng = (Math.PI * 2 - Math.abs(cirAng)) * (bul > 0 ? 1 : -1);
cirAng = (Math.PI * 2 - Math.abs(cirAng)) * Math.sign(bul);
}
return cirAng;
@ -223,7 +229,7 @@ export function Vec3DTo2D(pt: Vector3)
return new Vector2(pt.x, pt.y);
}
//点到曲线上的最近点
export function getClosestPt(startPt: Vector2, endPt: Vector2, bul: number, pt: Vector3, isExt: boolean = false)
export function getClosestPt(startPt: Vector2, endPt: Vector2, bul: number, pt: Vector3, isExt: boolean = false, extendDir: ExtendDir = ExtendDir.Both)
{
let closestPt: Vector3;
let closestLen: number;
@ -249,17 +255,16 @@ export function getClosestPt(startPt: Vector2, endPt: Vector2, bul: number, pt:
}
else
{
let arcData = getArcPtLenAngle(startPt, endPt, bul, pt);
let arcData = getArcPtLenAndAngle(startPt, endPt, bul, pt);
let angle = arcData.angle
if (Math.abs(angle) > Math.PI) angle -= (Math.PI * bul / Math.abs(bul));
segment = angle / (Math.atan(bul) * 4);
}
if (segment > 1 || (segment < 0 && !isExt))
{
return;
}
closestPt = getPointAtParam(startPt, endPt, bul, segment);
if (((segment > 1 || segment < -1e-7) && !isExt) ||
(segment > 1 && isExt && extendDir === ExtendDir.Later) ||
(segment < -1e-7 && isExt && extendDir === ExtendDir.Front)) return;
closestPt = getPtAtCurveParam(startPt, endPt, bul, segment);
closestLen = closestPt.distanceTo(pt);
return { closestPt, closestLen }
}

@ -158,6 +158,7 @@ export enum KeyBoard
NumpadEqual = 12,
NumpadMultiply = 106,
NumpadSubtract = 109,
NumpadDot = 110
NumpadDot = 110,
NumpadDot1 = 190
}

@ -28,6 +28,11 @@ export function ArrayRemove(arr: Array<any>, el: any)
arr.splice(index, 1)
}
export function Last(arr: Array<any>)
{
return arr[arr.length - 1];
}
export function clamp(value, min, max)
{
@ -76,3 +81,8 @@ export function isBetweenNums(v1, v2, v)
{
return v === v1 || v === v2 || (Math.max(v1, v2, v) !== v && Math.min(v1, v2, v) !== v);
}
//深复制对象数组
export function sliceDeep(arr: object[], start?: number, end?: number): object[]
{
return arr.slice(start, end).map((obj) => Object.assign({}, obj));
}

@ -1,16 +1,30 @@
import * as THREE from 'three';
import { Box3, Matrix4, ShapeGeometry, Vector3, Object3D } from 'three';
import { Box3, Matrix4, ShapeGeometry, Vector3, Object3D, Vector2 } from 'three';
import { ColorMaterial } from '../Common/ColorPalette';
import { getArcAngle, isAtArc, rotateLine, Vec3DTo2D } from '../Common/CurveUtils';
import { equal, equaln, polar, angle } from '../Geometry/GeUtils';
import { getArcAngleBy3Pt, isPtOnArc, rotateLine, Vec3DTo2D, Vec2DTo3D } from '../Common/CurveUtils';
import { equal, equaln, polar, angle, midPoint, angleTo2Pi } from '../Geometry/GeUtils';
import { RenderType } from '../GraphicsSystem/Enum';
import { IntersectOption, IntersectArcAndArc, IntersectCircleAndArc, IntersectLineAndArc } from '../GraphicsSystem/IntersectWith';
import { IntersectOption, IntersectArcAndArc, IntersectCircleAndArc, IntersectLineAndArc, reverseIntersectOption, IntersectPolylineAndCurve } from '../GraphicsSystem/IntersectWith';
import { Factory } from './CADFactory';
import { CADFile } from './CADFile';
import { Circle } from './Circle';
import { Curve } from './Curve';
import { Line } from './Line';
import { getCircleCenter } from './../Common/CurveUtils';
import { Polyline } from './Polyline';
/**
*
* ACAD,,.
*
* :
* 0-2PI.().
* . .
* .
*
* @export
* @class Arc
* @extends {Curve}
*/
@Factory
export class Arc extends Curve
{
@ -20,15 +34,22 @@ export class Arc extends Curve
center && this.m_Center.copy(center);
normal && this.m_Normal.copy(normal);
this.m_Radius = radius || 0;
this.m_StartAngle = startAngle || 0;
this.m_EndAngle = endAngle || 0;
if (startAngle) this.m_StartAngle = angleTo2Pi(startAngle);
if (endAngle) this.m_EndAngle = angleTo2Pi(endAngle);
}
private m_Center = new Vector3(0, 0, 0);
private m_Radius: number = 0;
private m_StartAngle: number;
private m_EndAngle: number;
private m_StartAngle: number = 0;
private m_EndAngle: number = 0;
private m_Normal = new Vector3(0, 0, 1);
private m_Clockwise = true;//顺时针
/**
* 线
*
* @private
* @memberof Arc
*/
private m_Clockwise = true;
get Center()
{
@ -52,6 +73,21 @@ export class Arc extends Curve
this.Update();
}
get Area(): number
{
return 0.5 * this.AllAngle * this.Radius * this.Radius;
}
//获得曲线的面积,逆时针为正,顺时针为负.
get Area2(): number
{
let clockwise = this.m_Clockwise ? -1 : 1;
return 0.5 * this.AllAngle * this.Radius * this.Radius * clockwise;
}
get IsClose(): boolean
{
return false;
}
get BoundingBox(): Box3
{
let pts = [this.StartPoint, this.EndPoint];
@ -94,7 +130,7 @@ export class Arc extends Curve
set StartAngle(v: number)
{
this.WriteAllObjectRecord();
this.m_StartAngle = v <= 0 ? 1e-19 : v;
this.m_StartAngle = v;
this.Update();
}
@ -105,179 +141,158 @@ export class Arc extends Curve
set EndAngle(v: number)
{
this.WriteAllObjectRecord();
this.m_EndAngle = v <= 0 ? 1e-19 : v;
this.m_EndAngle = v;
this.Update();
}
//******************** Curve function start*****************//
get StartPoint()
{
let startPt = new Vector3();
polar(startPt, this.m_StartAngle, this.m_Radius);
startPt = this.m_Center.clone().add(startPt);
return startPt;
return polar(this.Center, this.StartAngle, this.m_Radius) as Vector3;
}
get EndPoint()
{
let endtPt = new Vector3();
polar(endtPt, this.m_EndAngle, this.m_Radius);
endtPt = this.m_Center.clone().add(endtPt);
return endtPt;
return polar(this.Center, this.m_EndAngle, this.m_Radius) as Vector3;
}
get StartParam()
{
let startPm: number = 0.0;
return startPm;
return 0;
}
get EndParam()
{
let endPm: number = 1.0;
return endPm;
return 1;
}
get Length()
{
return this.AllAngle * this.m_Radius;
}
GetPointAtParam(param: number)
{
if (0 <= param && param <= 1)
{
param = 1 - param;
let ptAtpm = new Vector3();
let angle = this.GetParamAngle(param);
polar(ptAtpm, this.GetParamAngle(param), this.m_Radius);
ptAtpm = this.m_Center.clone().add(ptAtpm);
console.log(ptAtpm);
return ptAtpm;
}
let an = this.GetAngleAtParam(param);
return polar(this.Center, an, this.m_Radius) as Vector3;
}
GetPointAtDistance(distance: number)
{
if (distance <= (Math.abs(this.getArcBul()) * this.m_Radius))//长度不能超过总弧长
{
let ptAtDist = new Vector3();
let propor = distance / this.getArcBul();
polar(ptAtDist, Math.abs(this.getArcBul(propor)), this.m_Radius);
ptAtDist = this.m_Center.clone().add(ptAtDist);
return ptAtDist;
}
let len = this.Length;
if (len == 0) return;
return this.GetPointAtParam(distance / len);
}
GetDistAtParam(param: number)
{
if (0 <= param && param <= 1)
{
let distAtPm: number = 0;
distAtPm = Math.abs(this.getArcBul(param)) * this.m_Radius;
return distAtPm;
}
return Math.abs(param * this.Length);
}
GetDistAtPoint(pt?: Vector3)
GetDistAtPoint(pt: Vector3)
{
if (!pt)
{
return;
}
let dist: number = 0;
//求出点1和点2的中点
let midpt = new Vector3(0, 0, 0);
let startPt = new Vector3(0, 0, 0);
polar(startPt, this.m_StartAngle, this.m_Radius);
startPt = this.m_Center.clone().add(startPt);
midpt.x = (pt.x + startPt.x) / 2;
midpt.y = (pt.y + startPt.y) / 2;
let length = this.m_Center.distanceTo(midpt);
if (length)
{
dist = Math.acos(length / this.m_Radius) * 2 * this.m_Radius;
if (Math.abs(this.getArcBul()) > Math.PI)
dist = 2 * Math.PI * this.m_Radius - dist;
}
else
{
dist = Math.PI * this.m_Radius;
}
return dist;
let param = this.GetParamAtPoint(pt);
return this.GetDistAtParam(param);
}
GetParamAtPoint(pt: Vector3)
{
if (!this.PtOnCurve(pt))
{
if (this.m_Radius == 0 ||
this.AllAngle == 0 ||
!equaln(pt.distanceToSquared(this.m_Center), this.m_Radius * this.m_Radius, 1e-6))
return NaN;
//角度
let an = angle(pt.clone().sub(this.m_Center));
return this.GetParamAtAngle(an);
}
/**
* .
* ,0-1
* ,
*
* @param {number} an
* @returns
* @memberof Arc
*/
GetParamAtAngle(an: number)
{
//如果以pt为终点,那么所有的角度为
let ptAllAn = this.ComputeAnlge(an);
let allAn = this.AllAngle;
//减去圆弧角度,剩余角度的一半
let surplusAngleHalf = Math.PI - allAn / 2;
if (ptAllAn > allAn + surplusAngleHalf)//返回负数
{
return ((ptAllAn - allAn) - (surplusAngleHalf * 2)) / allAn;
}
let pmAtPt: number = 0;
let length = this.GetDistAtPoint(pt);
pmAtPt = this.GetParamAtDist(length);
return pmAtPt;
else//返回正数
return ptAllAn / allAn;
}
GetSplitCurves(param: number[] | number)
GetAngleAtParam(param: number)
{
let anglelist = new Array<number>();
let curvelist = new Array<Arc>();
anglelist.push(this.m_StartAngle);
return this.m_StartAngle + param * this.AllAngle * (this.m_Clockwise ? -1 : 1);
}
GetSplitCurves(param: number[] | number): Arc[]
{
//切割参数列表
let params: number[];
if (param instanceof Array)
{
for (let pm of param)
{
anglelist.push(this.GetParamAngle(1 - pm));
}
params = param.filter(param => !isNaN(param) && (param > 0 && param < 1));
params.push(0, 1);
params.sort();
}
else
{
anglelist.push(this.GetParamAngle(1 - param));
params = [0, param, 1];
}
anglelist.push(this.m_EndAngle);
for (let i = 0; i < anglelist.length - 1; i++)
//角度列表
let ans = params.map(p => this.GetAngleAtParam(p));
//返回圆弧表
let arcs: Arc[] = [];
for (let i = 0; i < ans.length - 1; i++)
{
if (!equaln(anglelist[i], anglelist[i + 1]))
if (!equaln(ans[i], ans[i + 1]))
{
let arc = new Arc(this.m_Center, this.m_Radius, anglelist[i], anglelist[i + 1], this.m_Normal);
curvelist.push(arc);
let arc = this.Clone() as Arc;
arc.StartAngle = ans[i];
arc.EndAngle = ans[i + 1];
arcs.push(arc);
}
}
return curvelist;
return arcs;
}
PtOnCurve(pt: Vector3)
PtOnCurve(pt: Vector3): boolean
{
let isOnArc = false;
let startPoint = new Vector3();
let endPoint = new Vector3();
polar(startPoint, this.m_StartAngle, this.m_Radius);
polar(endPoint, this.m_EndAngle, this.m_Radius);
startPoint = this.m_Center.clone().add(startPoint);
endPoint = this.m_Center.clone().add(endPoint);
if (equal(startPoint, pt) || equal(endPoint, pt))//如果是是起始点和终止点
{
isOnArc = true;
return isOnArc;
}
isOnArc = isAtArc(Vec3DTo2D(startPoint), Vec3DTo2D(endPoint), Math.tan(this.getArcBul() / 4), pt);
return isOnArc;
let param = this.GetParamAtPoint(pt);
return !isNaN(param) && param >= 0 && param <= 1;
}
GetOffsetCurves(offsetDist: number)
{
let arcArr = new Array<Curve>();
if (this.m_Clockwise) offsetDist *= -1;
if ((offsetDist + this.m_Radius) > 0)
{
let arc = new Arc(this.m_Center, this.m_Radius + offsetDist, this.m_StartAngle, this.m_EndAngle, this.m_Normal);
arcArr.push(arc);
let arc = this.Clone() as Arc;
arc.Radius = offsetDist + this.m_Radius;
return [arc];
}
return arcArr;
return [];
}
Extend(newParam: number)
{
if (0 > newParam || newParam > 1)
this.WriteAllObjectRecord();
if (newParam < 0)
{
if (newParam > 1)
{
newParam -= 1;
}
let allAngle = Math.abs(this.getArcBul(newParam));
if (allAngle + Math.abs(this.getArcBul()) < (2 * Math.PI))//原弧长+延伸<圆
{
this.SetExtendPointAngle(newParam, allAngle);
}
this.m_StartAngle = this.GetAngleAtParam(newParam);
}
else if (newParam > 1)
{
this.m_EndAngle = this.GetAngleAtParam(newParam);
}
this.Update();
}
Reverse()
@ -295,92 +310,105 @@ export class Arc extends Curve
}
if (curve instanceof Line)
{
return IntersectLineAndArc(curve, this, intType);
return IntersectLineAndArc(curve, this, reverseIntersectOption(intType));
}
if (curve instanceof Circle)
{
return IntersectCircleAndArc(curve, this, intType);
return IntersectCircleAndArc(curve, this, reverseIntersectOption(intType));
}
if (curve instanceof Polyline)
return IntersectPolylineAndCurve(curve, this, reverseIntersectOption(intType))
return [];
}
//******************** Curve function end*****************//
SetExtendPointAngle(newParam: number, allAngle: number)
/**
*
*
* @readonly
* @type {number}
* @memberof Arc
*/
get AllAngle(): number
{
let pmXAngle: number = 0;
if (0 > newParam)
return this.ComputeAnlge(this.m_EndAngle);
}
/**
*
*
* @private
* @param {number} endAngle
* @returns
* @memberof Arc
*/
private ComputeAnlge(endAngle: number)
{
//顺时针
if (this.m_Clockwise)
{
if (this.m_StartAngle + allAngle > 2 * Math.PI)
this.m_StartAngle = this.m_StartAngle + allAngle - 2 * Math.PI;
else
this.m_StartAngle = this.m_StartAngle + allAngle;
if (this.m_StartAngle > endAngle)
return this.StartAngle - endAngle;
else //越过0点绘制圆弧
return (Math.PI * 2) - (endAngle - this.m_StartAngle);
}
else
{
if (this.m_EndAngle - allAngle >= 0)
this.m_EndAngle = this.m_EndAngle - allAngle;
if (endAngle > this.m_StartAngle)
return endAngle - this.m_StartAngle;
else
this.m_EndAngle = this.m_EndAngle - allAngle + 2 * Math.PI;
return (Math.PI * 2) - (this.m_StartAngle - endAngle);
}
}
getArcBul(param: number = 1)//圆心角
/**
*
*
* @param {THREE.Vector2} p1
* @param {THREE.Vector2} p2
* @param {number} bul ,cad, <()>
* @memberof Arc
*/
ParseFromBul(p1: Vector3 | Vector2, p2: Vector3 | Vector2, bul: number): Arc
{
let ptArr = this.GetStretchPoints();
return getArcAngle(ptArr[0], ptArr[1], ptArr[2]) * param;
}
if (p1 instanceof Vector2)
p1 = Vec2DTo3D(p1);
if (p2 instanceof Vector2)
p2 = Vec2DTo3D(p2);
GetParamAngle(param: number)//返回相对于x轴正方向所形成的角度
{
let pmAngle = 0;
if (this.m_EndAngle < this.m_StartAngle)
{
pmAngle = (this.m_StartAngle - this.m_EndAngle) * param + this.m_EndAngle;
}
else
{
pmAngle = (this.m_EndAngle - this.m_StartAngle) * param + this.m_StartAngle + Math.PI;
}
return pmAngle;
//弦向量
let chordV = p2.clone().sub(p1);
//弦角度
let chordAn = angle(chordV);
//弦长度/2
let chordLengthHalf = chordV.length() / 2;
let allAngle = Math.atan(bul) * 4;
let HalfAngle = allAngle * 0.5;
//半径
this.m_Radius = chordLengthHalf / Math.sin(HalfAngle);
//指向圆心的角度
let toCenterAn = chordAn + Math.PI * 0.5;//弦角度转90
//圆心
this.m_Center = midPoint(p1, p2);
polar(this.m_Center, toCenterAn, this.m_Radius - (bul * chordLengthHalf));
this.m_Radius = Math.abs(this.m_Radius);
this.m_StartAngle = angle(p1.clone().sub(this.m_Center));
this.m_EndAngle = angle(p2.clone().sub(this.m_Center));
this.m_Clockwise = bul < 0;
return this;
}
FromThreePoint(pt1: Vector3, pt2: Vector3, pt3: Vector3)
{
if (!(pt1 && pt2 && pt3))
return;
// 通过三个点到圆心距离相等建立方程:
// (2 * pt2.x - 2 * pt1.x) * center.x + (2 * pt1.y - 2 * pt2.y) * center.y=pt1.y2+pt2.x2-pt1.x2-pt2.y2
// (2 * pt3.x - 2 * pt2.x) * center.x + (2 * pt2.y - 2 * pt3.y) * center.y=pt2.y2+pt3.x2-pt2.x2-pt3.y2
// 令:
// a1 = 2 * pt2.x - 2 * pt1.x b1 = 2 * pt1.y - 2 * pt2.y c1 = pt1.y2+pt2.x2-pt1.x2-pt2.y2
// a2 = 2 * pt3.x - 2 * pt2.x b2 = 2 * pt2.y - 2 * pt3.y c2 = pt2.y2+pt3.x2-pt2.x2-pt3.y2
// 则上述方程组变成一下形式:
// a1 * center.x + b1 * center.y=c1
// a2 * center.x + b2 * center.y=c2
// 联立以上方程组可以求出:
// center.x = (c1 * b2 - c2 * b1) / a1 * b2 - a2 * b1;
// center.y = (a1 * c2 - a2 * c1) / a1 * b2 - a2 * b1;
let a1 = pt1.x - pt2.x;
let b1 = pt1.y - pt2.y;
let c1 = (Math.pow(pt1.x, 2) - Math.pow(pt2.x, 2) + Math.pow(pt1.y, 2) - Math.pow(pt2.y, 2)) / 2;
let a2 = pt3.x - pt2.x;
let b2 = pt3.y - pt2.y;
let c2 = (Math.pow(pt3.x, 2) - Math.pow(pt2.x, 2) + Math.pow(pt3.y, 2) - Math.pow(pt2.y, 2)) / 2;
//令temp = A1*B2 - A2*B1
let temp = a1 * b2 - a2 * b1;
//判断三点是否共线
if (temp === 0)
{
return;
}
else
{
//不共线则求出圆心:
this.m_Center.x = (c1 * b2 - c2 * b1) / temp;
this.m_Center.y = (a1 * c2 - a2 * c1) / temp;
}
this.m_Center = getCircleCenter(pt1, pt2, pt3);
//用圆心和其中一个点求距离得到半径:
this.m_Radius = this.m_Center.distanceTo(pt1);
//起始角度 端点角度
@ -395,7 +423,7 @@ export class Arc extends Curve
p2.y = pt3.y - pt1.y;
//叉积
//this.m_Normal = p1.clone().cross(p2).normalize();
let normal = Math.tan(getArcAngle(pt1, pt2, pt3) * 0.25);
let normal = Math.tan(getArcAngleBy3Pt(pt1, pt2, pt3) * 0.25);
if (normal > 0)
{
let startAngle = this.m_StartAngle;
@ -452,18 +480,10 @@ export class Arc extends Curve
}
GetStretchPoints(): Array<Vector3>
{
//用角度求出三个点位置
let startPoint = new Vector3();
let endPoint = new Vector3();
let midPoint = new Vector3();
polar(startPoint, this.m_StartAngle, this.m_Radius);
polar(endPoint, this.m_EndAngle, this.m_Radius);
polar(midPoint, this.GetParamAngle(0.5), this.m_Radius);
return [
this.m_Center.clone().add(startPoint),
this.m_Center.clone().add(midPoint),
this.m_Center.clone().add(endPoint),
this.StartPoint,
this.GetPointAtParam(0.5),
this.EndPoint,
this.m_Center.clone(),
]
}
@ -493,47 +513,28 @@ export class Arc extends Curve
GetParamAtDist(d: number)
{
let pmAtDist: number = 0;
pmAtDist = d / this.GetDistAtParam(1);
return pmAtDist;
return d / this.Length;
}
GetFistDeriv(pt: number | Vector3)
{
let an: number;
if (typeof pt === "number")
{
pt = this.GetPointAtParam(pt);
an = this.GetAngleAtParam(pt);
}
else
pt = pt.clone();
an = angle(pt.sub(this.m_Center));
let an = angle(pt.sub(this.Center)) + Math.PI * 0.5;
let d = new Vector3();
polar(d, an, 1);
return d;
an += Math.PI * 0.5 * (this.m_Clockwise ? -1 : 1);
return polar(new Vector3(), an, this.m_Radius) as Vector3;
}
GetClosestPointTo(pt: Vector3, extend: boolean): Vector3
{
let l = new Line(this.Center, pt);
if (extend)
{
let pts = l.IntersectWith(this, IntersectOption.ExtendBoth);
return pt.distanceTo(pts[0]) < pt.distanceTo(pts[1]) ? pts[0] : pts[1];
}
//单向延伸可能有两个一个和0个交点
let pts = l.IntersectWith(this, IntersectOption.ExtendThis);
switch (pts.length)
{
case 0:
return pt.distanceTo(this.StartPoint) < pt.distanceTo(this.EndPoint) ? this.StartPoint : this.EndPoint;
case 1:
return pts[0];
case 2:
return pt.distanceTo(pts[0]) < pt.distanceTo(pts[1]) ? pts[0] : pts[1];
default:
return;
}
let inPts: Vector3[] = this.IntersectWith(l, extend ? IntersectOption.ExtendBoth : IntersectOption.ExtendArg);
if (inPts.length < 2)
inPts.push(this.StartPoint, this.EndPoint);
return inPts.reduce((p1, p2) => p1.distanceToSquared(pt) < p2.distanceToSquared(pt) ? p1 : p2);
}
//#region -------------------------File-------------------------
//对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化

@ -4,7 +4,7 @@ import { Box3, EllipseCurve, Geometry, Matrix4, Vector3, Object3D } from 'three'
import { ColorMaterial } from '../Common/ColorPalette';
import { rotateLine } from '../Common/CurveUtils';
import { Arc } from '../DatabaseServices/Arc';
import { angle, angleTo, equaln, polar } from '../Geometry/GeUtils';
import { angle, angleTo, equaln, polar, angleTo2Pi } from '../Geometry/GeUtils';
import { RenderType } from '../GraphicsSystem/Enum';
import
{
@ -12,11 +12,14 @@ import
IntersectCircleAndArc,
IntersectCircleAndCircle,
IntersectLineAndCircle,
reverseIntersectOption,
IntersectPolylineAndCurve,
} from '../GraphicsSystem/IntersectWith';
import { Factory } from './CADFactory';
import { CADFile } from './CADFile';
import { Curve } from './Curve';
import { Line } from './Line';
import { Polyline } from './Polyline';
@Factory
export class Circle extends Curve
@ -51,6 +54,27 @@ export class Circle extends Curve
}
//******************** Curve function start*****************//
get StartPoint(): Vector3
{
let startPt = new Vector3(this.m_Radius, 0, 0);
this.m_Center.clone().add(startPt);
return startPt;
}
get StartParam(): number
{
return 0;
}
get EndPoint(): Vector3
{
let endPt = new Vector3(this.m_Radius, 0, 0);
this.m_Center.clone().add(endPt);
return endPt;
}
get EndParam(): number
{
return 1;
}
get Area()
{
return Math.PI * Math.pow(this.m_Radius, 2);
@ -60,6 +84,11 @@ export class Circle extends Curve
return Math.PI * 2 * this.m_Radius;
}
get IsClose(): boolean
{
return true;
}
GetPointAtParam(param: number)
{
let ptAtPm = new Vector3();
@ -100,56 +129,42 @@ export class Circle extends Curve
GetSplitCurves(param: number[] | number)
{
let anglelist = new Array<number>();
let curvelist = new Array<Arc>();
let anglelist: number[];
if (param instanceof Array)
{
for (let pm of param)
if (param.length < 2) return [];
param.sort();
anglelist = [];
for (let p of param)
{
anglelist.push(2 * Math.PI * pm);
if (!isNaN(p) && p >= 0 && p <= 1)
anglelist.push(Math.PI * 2 * p);
}
anglelist.push(anglelist[0]);
anglelist.reverse();
}
else
{
anglelist.push(2 * Math.PI * param);
return [];
}
let curvelist = new Array<Arc>();
for (let i = 0; i < anglelist.length - 1; i++)
{
let arc = new Arc(this.m_Center, this.m_Radius, anglelist[i], anglelist[i + 1]);
curvelist.push(arc);
}
let arc = new Arc(this.m_Center, this.m_Radius, anglelist[anglelist.length - 1], anglelist[0]);
curvelist.push(arc);
return curvelist;
}
GetParamAtPoint(pt?: Vector3)
{
if (!pt)
if (!this.PtOnCurve(pt))
{
return;
return NaN;
}
let pmAtPt: number = 0;
let startPt = new Vector3(0, 0, 0);
polar(startPt, 0, this.m_Radius);
startPt = this.m_Center.clone().add(startPt);
//求出向量
let p1 = new Vector3(0, 0, 0);
p1.x = pt.x - this.m_Center.x;
p1.y = pt.y - this.m_Center.y;
let p2 = new Vector3(0, 0, 0);
p2.x = startPt.x - this.m_Center.x;
p2.y = startPt.y - this.m_Center.y;
pmAtPt = angleTo(p2, p1);
if (pmAtPt < 0)
{
pmAtPt = 2 * Math.PI + pmAtPt;
}
pmAtPt = pmAtPt / (2 * Math.PI);
return pmAtPt;
return angle(pt.clone().sub(this.m_Center)) / (Math.PI * 2);
}
PtOnCurve(pt: Vector3)
@ -181,15 +196,16 @@ export class Circle extends Curve
}
if (curve instanceof Line)
{
return IntersectLineAndCircle(curve, this, intType);
return IntersectLineAndCircle(curve, this, reverseIntersectOption(intType));
}
if (curve instanceof Circle)
{
return IntersectCircleAndCircle(this, curve, intType);
return IntersectCircleAndCircle(this, curve);
}
if (curve instanceof Polyline)
return IntersectPolylineAndCurve(curve, this, reverseIntersectOption(intType))
return [];
}
//******************** Curve function end*****************//
get BoundingBox(): Box3
@ -292,9 +308,7 @@ export class Circle extends Curve
let l = new Line(this.Center, pt);
let pts = l.IntersectWith(this, IntersectOption.ExtendBoth);
let ptIns = pt.distanceTo(pts[0]) < pt.distanceTo(pts[1]) ? pts[0] : pts[1];
return ptIns;
}
//#region -------------------------File-------------------------
//对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化

@ -7,6 +7,27 @@ import { Factory } from './CADFactory';
import { Entity } from './Entity';
export enum ExtendType
{
/**
*
*/
None = 0,
/**
*
*/
Front = 1,
/**
*
*/
Back = 2,
/**
*
*/
Both = 3,
}
/**
* 线,.
*
@ -67,7 +88,11 @@ export abstract class Curve extends Entity
//翻转曲线.首尾调换.
Reverse() { };
PtOnCurve(pt: Vector3): boolean { return; }
//点在曲线内部
PtOnCurve(pt: Vector3): boolean { return false; }
//参数在曲线内部
ParamOnCurve(param: number): boolean { return !isNaN(param) && param >= 0 && param <= this.EndParam; }
GetOffsetCurves(offsetDist: number): Array<Curve> { return; }
GetClosestPointTo(pt: Vector3, extend: boolean): Vector3 { return; }

@ -1,11 +1,10 @@
import { Factory } from "./CADFactory";
import { Entity } from "./Entity";
import { Vector3, Geometry, Matrix4 } from "three";
import { RenderType } from "../GraphicsSystem/Enum";
import { ColorMaterial } from "../Common/ColorPalette";
import * as THREE from "three";
import { cZAxis } from "../Geometry/GeUtils";
import { CADFile } from "./CADFile";
import { Geometry, Matrix4, Object3D, Vector3 } from 'three';
import * as THREE from 'three';
import { ColorMaterial } from '../Common/ColorPalette';
import { RenderType } from '../GraphicsSystem/Enum';
import { Factory } from './CADFactory';
import { CADFile } from './CADFile';
import { Curve } from './Curve';
@Factory
@ -79,33 +78,25 @@ export class Ellipse extends Curve
this.m_Center.applyMatrix4(m);
this.Update();
}
Draw(renderType: RenderType): THREE.Object3D
{
let obj = super.Draw(renderType);
if (obj) return obj;
let curve = this.createCurve();
let geometry = new Geometry().setFromPoints(curve.getPoints(60));
InitDrawObject(renderType: RenderType = RenderType.Wireframe): Object3D
{
let geometry = new Geometry();
this.UpdateGeometry(geometry);
let ellipseObj = new THREE.Line(geometry, ColorMaterial.GetLineMaterial(this.m_Color));
this.m_DrawEntity.set(renderType, ellipseObj);
ellipseObj.userData = this;
return ellipseObj;
}
Update()
UpdateDrawObject(type: RenderType, en: Object3D)
{
for (let [, obj] of this.m_DrawEntity)
{
let geo = obj["geometry"] as Geometry;
let curve = this.createCurve();
geo.setFromPoints(curve.getPoints(60));
geo.verticesNeedUpdate = true;
geo.computeBoundingSphere();
}
let geo = en["geometry"] as Geometry;
this.UpdateGeometry(geo);
}
//更新Geometry
private UpdateGeometry(geo: THREE.Geometry)
{
let curve = this.createCurve();
geo.setFromPoints(curve.getPoints(60));
geo.verticesNeedUpdate = true;
}
GetStretchPoints(): Array<Vector3>
{

@ -40,6 +40,14 @@ export class Entity extends CADObject
return this.m_Color;
}
/**
*
*
* @returns {Entity[]}
* @memberof Entity
*/
Export(): Entity[] { return [] }
/**
* .
*

@ -1,16 +1,23 @@
//直线对象
import { Geometry, Matrix4, Object3D, Vector3 } from 'three';
import * as THREE from 'three';
import { Geometry, Matrix4, Object3D, Vector3, Box3 } from 'three';
import { ColorMaterial } from '../Common/ColorPalette';
import { equal, polar } from '../Geometry/GeUtils';
import { RenderType } from '../GraphicsSystem/Enum';
import { IntersectOption, IntersectLineAndArc, IntersectLineAndLine, IntersectLineAndCircle } from '../GraphicsSystem/IntersectWith';
import
{
IntersectLineAndArc,
IntersectLineAndCircle,
IntersectLineAndLine,
IntersectOption,
reverseIntersectOption,
} from '../GraphicsSystem/IntersectWith';
import { Arc } from './Arc';
import { Factory } from './CADFactory';
import { CADFile } from './CADFile';
import { Curve } from './Curve';
import { Circle } from './Circle';
import { Curve } from './Curve';
@Factory
export class Line extends Curve
@ -185,7 +192,7 @@ export class Line extends Curve
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 line = new Line(pt, polar(pt.clone(), an, 1) as Vector3);
//交点
let pt_int = this.IntersectWith(line, IntersectOption.ExtendBoth)[0];
if (extend) return pt_int;
@ -219,10 +226,18 @@ export class Line extends Curve
{
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);
newLine.StartPoint = polar(this.StartPoint, an, offsetDist) as Vector3;
newLine.EndPoint = polar(this.EndPoint, an, offsetDist) as Vector3;
return [newLine];
}
get BoundingBox(): Box3
{
let pts = [
this.m_StartPoint,
this.m_EndPoint
];
return new Box3().setFromPoints(pts);
}
get StartParam()
{

File diff suppressed because it is too large Load Diff

@ -1,10 +1,12 @@
import { DrawAxis } from '../Add-on/AddAxis';
import { Command_ClosePt } from '../Add-on/closetest';
import { Command_Copy } from '../Add-on/Copy';
import { CustomUcs } from '../Add-on/CostumUCS';
import { Union } from '../Add-on/CSGUnion';
import { DrawArc } from '../Add-on/DrawArc';
import { Command_DrawBoard } from '../Add-on/DrawBoard';
import { DrawAlignedDimension } from '../Add-on/DrawDim/DrawAlignedDimension';
import { DrawLinearDimension } from '../Add-on/DrawDim/DrawLinearDimension';
import { DrawEllipse } from '../Add-on/DrawEllipse';
import { DrawFloor } from '../Add-on/DrawFloor';
import { DrawGripStretch } from '../Add-on/DrawGripStretch';
@ -17,13 +19,16 @@ import { DrawRegTest } from '../Add-on/DrawTestReg';
import { DrawCircle0 } from '../Add-on/DrawZeroCircle';
import { Entsel } from '../Add-on/Entsel';
import { Command_Erase } from '../Add-on/Erase';
import { Command_Export } from '../Add-on/Export';
import { Command_Extend } from '../Add-on/Extends';
import { CommandFillet } from '../Add-on/Fillet';
import { Command_INsTest } from '../Add-on/instest';
import { Fbx } from '../Add-on/loadfbx';
import { LoadImg } from '../Add-on/LoadImg';
import { Command_Move } from '../Add-on/Move';
import { Command_Offset } from '../Add-on/Offset';
import { Command_Offset, Command_TestOffset } from '../Add-on/Offset';
import { Open } from '../Add-on/Open';
import { Command_PLTest } from '../Add-on/polytest';
import { Command_RevPl } from '../Add-on/RevPl';
import { Command_Rotate } from '../Add-on/Rotate';
import { Save } from '../Add-on/Save';
@ -32,6 +37,7 @@ import { Stretch } from '../Add-on/Stretch';
import { Command_SwitchCamera } from '../Add-on/SwitchCamera';
import { Command_SwitchPass } from '../Add-on/SwitchPass';
import { Test } from '../Add-on/test';
import { Command_TestBox } from '../Add-on/TestBox';
import { Command_DrawBoard2 } from '../Add-on/TestDrawBoard';
import { TestDrawDirectionalLight } from '../Add-on/TestDrawDirectionalLight';
import { TestDrawPointLight } from '../Add-on/TestDrawPointLight';
@ -40,7 +46,7 @@ import { Command_Trim } from '../Add-on/Trim';
import { Redo, Undo } from '../Add-on/Undo';
import { ViewToFront, ViewToRight, ViewToTop } from '../Add-on/ViewChange';
import { commandMachine } from './CommandMachine';
import { DrawLinearDimension } from '../Add-on/DrawDim/DrawLinearDimension';
// import { DrawFloor } from '../Add-on/DrawFloor';
// import { RevTarget, SaveTarget } from '../Add-on/RenderTarget';
export function registerCommand()
@ -132,6 +138,22 @@ export function registerCommand()
commandMachine.RegisterCommand("dal", new DrawAlignedDimension());
commandMachine.RegisterCommand("dli", new DrawLinearDimension());
commandMachine.RegisterCommand("tt", new Command_PLTest());
commandMachine.RegisterCommand("tt2", new Command_INsTest());
commandMachine.RegisterCommand("x", new Command_Export());
commandMachine.RegisterCommand("close", new Command_ClosePt());
//用于测试包围盒
commandMachine.RegisterCommand("box", new Command_TestBox());
commandMachine.RegisterCommand("testoffset", new Command_TestOffset());
// commandMachine.RegisterCommand("st", new SaveTarget())
// commandMachine.RegisterCommand("rt", new RevTarget())
}

@ -4,7 +4,8 @@ import { app } from '../ApplicationServices/Application';
import { ColorMaterial } from '../Common/ColorPalette';
import { GetPointPrompt } from '../Common/InputState';
import { Entity } from '../DatabaseServices/Entity';
import { equaln, fixAngle, Intersect, polar } from '../Geometry/GeUtils';
import { equaln, fixAngle, polar } from '../Geometry/GeUtils';
import { IntersectLAndL } from '../GraphicsSystem/IntersectWith';
import { PreViewer } from '../GraphicsSystem/PreViewer';
@ -27,6 +28,7 @@ interface SnapIntersect
//提供点捕捉的服务.
export class SnapServices
{
m_Disabled: boolean = false;//禁用捕捉
private preLines: THREE.Line[] = []; //前视图绘制的线表
notSnapEntity = new Set<THREE.Object3D>();//不参与捕捉的实体列表,这个属性由开发人员维护.
private snapPoints: THREE.Vector3[] = [];//捕捉的点列表
@ -102,7 +104,7 @@ export class SnapServices
for (let j = i + 1; j < snapAxisList.length; j++)
{
let axis2 = snapAxisList[j];
let insP = Intersect(axis1.BasePoint, axis1.SnapPoint, axis2.BasePoint, axis2.SnapPoint);
let insP = IntersectLAndL(axis1.BasePoint, axis1.SnapPoint, axis2.BasePoint, axis2.SnapPoint);
if (insP)
axisIntersectList.push({
IntersectPoint: insP,
@ -145,10 +147,11 @@ export class SnapServices
//计算图形的捕捉点 如果有 则返回.
private GetEntitySnapPoint()
{
if (this.m_Disabled) return;
let vcsP = app.m_Editor.m_MouseCtrl.m_CurMousePointVCS;
for (let obj of app.m_Viewer.Scene.children)
{
if (!this.notSnapEntity.has(obj) && obj.userData && obj.userData instanceof Entity)
if (!this.notSnapEntity.has(obj.userData) && obj.userData && obj.userData instanceof Entity)
{
for (let p of obj.userData.GetSnapPoints())
{

@ -1,8 +1,7 @@
import { Matrix4, Vector3 } from 'three';
import { Matrix4, Vector2, Vector3 } from 'three';
import * as THREE from 'three';
import { CreateBoardUtil } from '../ApplicationServices/mesh/createBoard';
import { rotateLine } from './../Common/CurveUtils';
import { rotateLine } from '../Common/CurveUtils';
export const cZeroVec = new THREE.Vector3();
export const cXAxis = new THREE.Vector3(1, 0, 0);
@ -15,7 +14,7 @@ export function equaln(v1: number, v2: number, fuzz = 1e-3)
}
export function equal(v1: THREE.Vector3, v2: THREE.Vector3)
{
return v1.manhattanDistanceTo(v2) < 1e-8;
return v1.distanceToSquared(v2) < 1e-12;
}
export function fixAngle(an: number, fixAngle: number, fuzz: number = 0.1)
@ -36,16 +35,18 @@ export function fixAngle(an: number, fixAngle: number, fuzz: number = 0.1)
}
//改变向量v 不拷贝新向量 返回自身
export function polar(v: THREE.Vector3, an: number, dis: number)
export function polar(v: Vector3 | Vector2, an: number, dis: number): Vector3 | Vector2
{
v.x += Math.cos(an) * dis;
v.y += Math.sin(an) * dis;
return v;
}
export function angle(v: THREE.Vector3)
export function angle(v: Vector3 | Vector2)
{
return Math.atan2(v.y, v.x);
let angle = Math.atan2(v.y, v.x);
if (angle < 0) angle += Math.PI * 2;
return angle;
}
/**
@ -74,7 +75,7 @@ export function angleTo(v1: THREE.Vector3, v2: THREE.Vector3, ref: THREE.Vector3
if (v1.equals(cZeroVec) || v2.equals(cZeroVec))
return 0;
let cv = new Vector3().crossVectors(v1, v2).normalize();
return cv.z * v1.angleTo(v2);
return cv.z === 0 ? v1.angleTo(v2) : v1.angleTo(v2) * cv.z;
}
export function getLoocAtUpVec(dir: THREE.Vector3): THREE.Vector3
@ -128,6 +129,11 @@ export function midPoint(v1: THREE.Vector3, v2: THREE.Vector3): THREE.Vector3
{
return v1.clone().add(v2).multiplyScalar(0.5);
}
export function midPoint2(v1: THREE.Vector2, v2: THREE.Vector2): THREE.Vector2
{
return v1.clone().add(v2).multiplyScalar(0.5);
}
export function midPtCir(v1: THREE.Vector3, v2: THREE.Vector3)
{
let baseline = new Vector3(1, 0, 0);
@ -191,37 +197,6 @@ export function MoveMatrix(v: THREE.Vector3): THREE.Matrix4
return mat;
}
export function Intersect(p1: THREE.Vector3, p2: THREE.Vector3, p3: THREE.Vector3, p4: THREE.Vector3): THREE.Vector3
{
let dx1 = p1.x - p2.x;
let dx2 = p3.x - p4.x;
let dx3 = p4.x - p2.x;
let dy1 = p1.y - p2.y;
let dy2 = p3.y - p4.y;
let dy3 = p4.y - p2.y;
let det = (dx2 * dy1) - (dy2 * dx1);
let pt = new THREE.Vector3(0, 0, 0);
if (equaln(det, 0.0, 1e-5))
{
if (equaln(dx2 * dy3, dy2 * dx3, 1e-5))
{
if (p3.distanceTo(p2) < 1e-3)
{
return p2;
}
}
return;
}
let ratio = ((dx1 * dy3) - (dy1 * dx3)) / det;
pt.x = (ratio * dx2) + p4.x;
pt.y = (ratio * dy2) + p4.y;
return pt;
}
export function getProjectDist(v1: Vector3, v2: Vector3)
{
let ang = v1.angleTo(v2);
@ -231,3 +206,16 @@ export function getProjectDist(v1: Vector3, v2: Vector3)
v: dist * Math.sin(ang)
}
}
/**
* 0-2pi
*
* @export
* @param {number} an
*/
export function angleTo2Pi(an: number)
{
an = an % (Math.PI * 2);
if (an < 0) an += Math.PI * 2
return an;
}

@ -1,10 +1,12 @@
import { Vector3 } from 'three';
import { getClosestPt, Vec3DTo2D } from '../Common/CurveUtils';
import { Arc } from '../DatabaseServices/Arc';
import { Circle } from '../DatabaseServices/Circle';
import { Curve } from '../DatabaseServices/Curve';
import { Line } from '../DatabaseServices/Line';
import { equal, equaln } from '../Geometry/GeUtils';
import { Circle } from '../DatabaseServices/Circle';
import { getClosestPt, Vec3DTo2D } from '../Common/CurveUtils';
import { Polyline } from '../DatabaseServices/Polyline';
import { equal, equaln, midPoint } from '../Geometry/GeUtils';
/**
* .
@ -31,29 +33,48 @@ export enum IntersectOption
*/
ExtendBoth = 3,
}
//延伸自身还是参数反转
export function reverseIntersectOption(intType: IntersectOption)
{
if (intType === IntersectOption.ExtendThis)
intType = IntersectOption.ExtendArg;
else if (intType === IntersectOption.ExtendArg)
intType = IntersectOption.ExtendThis;
return intType;
}
/**
*
* 线,
*
* @param {Vector3[]} intPts .线
* @param {Curve} c1 线1
* @param {Curve} c2 线2
* @param {Intersect} intType .
* @returns {Array<Vector3>}
* @param {Curve} c1 线1 this
* @param {Curve} c2 线2 arg
* @param {Intersect} extType .
* @returns {Array<Vector3>}
*/
function CheckPointOnCurve(intPts: Vector3[], c1: Curve, c2: Curve, intType: IntersectOption): Array<Vector3>
function CheckPointOnCurve(intPts: Vector3[], c1: Curve, c2: Curve, extType: IntersectOption): Array<Vector3>
{
return intPts.filter(p =>
{
return (intType & IntersectOption.ExtendThis || c1.PtOnCurve(p)) && (intType & IntersectOption.ExtendArg || c2.PtOnCurve(p))
return (extType & IntersectOption.ExtendThis || c1.PtOnCurve(p)) && (extType & IntersectOption.ExtendArg || c2.PtOnCurve(p))
})
}
//圆和圆(传入圆心和半径)
export function IntersectCircleAndCircleOrArc(center1?: Vector3, radius1?: number, center2?: Vector3, radius2?: number)
/**
* ,,.
*
* @export
* @param {(Circle | Arc)} c1
* @param {(Circle | Arc)} c2
* @returns
*/
export function IntersectCircleAndCircle(c1: Circle | Arc, c2: Circle | Arc)
{
let center1 = c1.Center;
let center2 = c2.Center;
let radius1 = c1.Radius;
let radius2 = c2.Radius;
let pts: Vector3[] = [];
let dist = center2.distanceTo(center1);
@ -92,33 +113,56 @@ export function IntersectCircleAndCircleOrArc(center1?: Vector3, radius1?: numbe
return pts;
}
//圆与圆
export function IntersectCircleAndCircle(circle1: Circle, circle2: Circle, intType: IntersectOption)
{
return this.IntersectCircleAndCircleOrArc(circle1.Center, circle1.Radius, circle2.Center, circle2.Radius);
}
//圆与圆弧
export function IntersectCircleAndArc(circle: Circle, arc2: Arc, intType: IntersectOption)
/**
* .
*
* @export
* @param {Circle} circle
* @param {Arc} arc
* @param {IntersectOption} extType
* @returns
*/
export function IntersectCircleAndArc(circle: Circle, arc: Arc, extType: IntersectOption)
{
let ptArr = this.IntersectCircleAndCircleOrArc(circle.Center, circle.Radius, arc2.Center, arc2.Radius);
return CheckPointOnCurve(ptArr, circle, arc2, intType | IntersectOption.ExtendThis);
let pts = IntersectCircleAndCircle(circle, arc);
return CheckPointOnCurve(pts, circle, arc, extType | IntersectOption.ExtendThis);
}
//圆弧与圆弧
export function IntersectArcAndArc(arc1: Arc, arc2: Arc, intType: IntersectOption)
/**
*
*
* @export
* @param {Arc} arc1
* @param {Arc} arc2
* @param {IntersectOption} extType
* @returns
*/
export function IntersectArcAndArc(arc1: Arc, arc2: Arc, extType: IntersectOption)
{
let ptArr = this.IntersectCircleAndCircleOrArc(arc1.Center, arc1.Radius, arc2.Center, arc2.Radius);
return CheckPointOnCurve(ptArr, arc1, arc2, intType);
let pts = IntersectCircleAndCircle(arc1, arc2);
return CheckPointOnCurve(pts, arc1, arc2, extType);
}
//直线和圆(传入圆心和半径)
export function IntersectLineAndCircleOrArc(line: Line, center?: Vector3, radius?: number)
/**
* :线,
*
* @export
* @param {Line} line 线
* @param {(Circle | Arc)} circle
* @returns
*/
function IntersectLineAndCircleOrArc(line: Line, circle: Circle | Arc)
{
let startPoint = line.StartPoint;
let endPoint = line.EndPoint;
let center = circle.Center;
let radius = circle.Radius;
let pts: Vector3[] = [];
if (equaln(line.EndPoint.x, line.StartPoint.x))
if (equaln(endPoint.x, startPoint.x, 1e-7))
{
if (line.PtOnCurve(center))
if (equaln(startPoint.x, center.x, 1e-7))
{
let pt1 = new Vector3(0, radius);
let pt2 = new Vector3(0, -radius);
@ -126,24 +170,24 @@ export function IntersectLineAndCircleOrArc(line: Line, center?: Vector3, radius
pts.push(center.clone().add(pt2));
return pts;
}
let closestArr = getClosestPt(Vec3DTo2D(line.StartPoint), Vec3DTo2D(line.EndPoint), 0, center);
let closestArr = getClosestPt(Vec3DTo2D(startPoint), Vec3DTo2D(endPoint), 0, center, true);
if (closestArr.closestLen === radius)
{
pts.push(center.clone().add(closestArr.closestPt));
}
if (closestArr.closestLen < radius)
else if (closestArr.closestLen < radius)
{
let y = Math.sqrt(Math.pow(radius, 2) - Math.pow(closestArr.closestLen, 2));
let pt1 = new Vector3(closestArr.closestPt.x, y);
let pt2 = new Vector3(closestArr.closestPt.x, -y);
pts.push(center.clone().add(pt1));
pts.push(center.clone().add(pt2));
let closePt = closestArr.closestPt;
let pt1 = closePt.clone().setY(closePt.y + y)
let pt2 = closePt.clone().setY(closePt.y - y)
pts.push(pt1, pt2);
}
}
else
{
let k = (line.EndPoint.y - line.StartPoint.y) / (line.EndPoint.x - line.StartPoint.x);
let b = line.EndPoint.y - k * line.EndPoint.x;
let k = (endPoint.y - startPoint.y) / (endPoint.x - startPoint.x);
let b = endPoint.y - k * endPoint.x;
//列方程
let x1 = 0, y1 = 0, x2 = 0, y2 = 0;
let c = Math.pow(center.x, 2) + Math.pow(b - center.y, 2) - Math.pow(radius, 2);
@ -168,26 +212,20 @@ export function IntersectLineAndCircleOrArc(line: Line, center?: Vector3, radius
}
//直线和圆
export function IntersectLineAndCircle(line: Line, circle: Circle, intType: IntersectOption)
export function IntersectLineAndCircle(line: Line, circle: Circle, extType: IntersectOption)
{
let ptArr = this.IntersectLineAndCircleOrArc(line, circle.Center, circle.Radius);
return CheckPointOnCurve(ptArr, line, circle, intType | IntersectOption.ExtendArg);
let ptArr = IntersectLineAndCircleOrArc(line, circle);
return CheckPointOnCurve(ptArr, line, circle, extType | IntersectOption.ExtendArg);
}
//直线和圆弧
export function IntersectLineAndArc(line: Line, arc: Arc, intType: IntersectOption)
export function IntersectLineAndArc(line: Line, arc: Arc, extType: IntersectOption)
{
let ptArr = this.IntersectLineAndCircleOrArc(line, arc.Center, arc.Radius);
return CheckPointOnCurve(ptArr, line, arc, intType);
let ptArr = IntersectLineAndCircleOrArc(line, arc);
return CheckPointOnCurve(ptArr, line, arc, extType);
}
//直线和直线
export function IntersectLineAndLine(l1: Line, l2: Line, intType: IntersectOption)
export function IntersectLAndL(p1: Vector3, p2: Vector3, p3: Vector3, p4: Vector3): Vector3
{
let p1 = l1.StartPoint;
let p2 = l1.EndPoint;
let p3 = l2.StartPoint;
let p4 = l2.EndPoint;
let dx1 = p1.x - p2.x;
let dx2 = p3.x - p4.x;
let dx3 = p4.x - p2.x;
@ -197,28 +235,100 @@ export function IntersectLineAndLine(l1: Line, l2: Line, intType: IntersectOptio
let det = (dx2 * dy1) - (dy2 * dx1);
let res = [];
//直线平行
if (equaln(det, 0, 1e-6))
let pt = new Vector3(0, 0, 0);
if (equaln(det, 0.0, 1e-5))
{
//直线共线
if (equaln(dx2 * dy3, dy2 * dx3, 1e-5))
{
res.push(p2);
return midPoint(midPoint(p1, p2), midPoint(p3, p4));
}
return;
}
let ratio = ((dx1 * dy3) - (dy1 * dx3)) / det;
pt.x = (ratio * dx2) + p4.x;
pt.y = (ratio * dy2) + p4.y;
return pt;
}
//直线和直线
export function IntersectLineAndLine(l1: Line, l2: Line, extType: IntersectOption)
{
let pt = IntersectLAndL(l1.StartPoint, l1.EndPoint, l2.StartPoint, l2.EndPoint);
return pt ? CheckPointOnCurve([pt], l1, l2, extType) : [];
}
export function IntersectPolylineAndCurve(pl: Polyline, cu: Curve, extType: IntersectOption): Vector3[]
{
let cus: Curve[] = pl.Export();
let cus2: Curve[];
if (cu instanceof Polyline)
cus2 = cu.Export()
else
cus2 = [cu];
let pts: Vector3[] = [];
for (let i = 0; i < cus.length; i++)
{
let ratio = ((dx1 * dy3) - (dy1 * dx3)) / det;
res.push(
new Vector3(
(ratio * dx2) + p4.x,
(ratio * dy2) + p4.y,
0
));
let cu1 = cus[i];
for (let j = 0; j < cus2.length; j++)
{
let cu2 = cus2[j];
let ext = extType;
let isStart = i === 0;
let isEnd = i === cus.length - 1;
let isStart2 = j === 0;
let isEnd2 = j === cus2.length - 1;
//当曲线闭合时,或者当前的子曲线不是起始和不是结束,那么不延伸曲线.
if (pl.CloseMark || !(isStart || isEnd))
ext = ext & ~IntersectOption.ExtendThis;
if ((cu instanceof Polyline && cu.CloseMark) || !(isStart2 || isEnd2))
ext = ext & ~IntersectOption.ExtendArg;
let ipts = cu1.IntersectWith(cu2, ext);
//校验延伸
if (IntersectOption.ExtendThis & ext)
{
//如果曲线是起始又是结束,那么不校验.
if (isStart && isEnd)
{
}
else if (isStart)
{
ipts = ipts.filter(p => cu1.GetParamAtPoint(p) <= 1);
}
else if (isEnd)
{
ipts = ipts.filter(p => cu1.GetParamAtPoint(p) >= 0);
}
}
if (IntersectOption.ExtendArg & ext)
{
//如果曲线是起始又是结束,那么不校验.
if (isStart2 && isEnd2)
{
}
else if (isStart2)
{
ipts = ipts.filter(p => cu2.GetParamAtPoint(p) <= cu2.EndParam);
}
else if (isEnd2)
{
ipts = ipts.filter(p => cu2.GetParamAtPoint(p) >= 0);
}
}
pts.push(...ipts);
}
}
return CheckPointOnCurve(res, l1, l2, intType);
return pts;
}

@ -126,9 +126,6 @@ export class Viewer
this.m_Composer.addPass(this.m_effectFXAA);
this.onSize();
}
onSize = (width?, height?) =>

@ -65,6 +65,7 @@ export class ModalManage
//底部面板高度
let downHeight = document.getElementById("DownPanel").offsetHeight;
let dragArea = document.getElementById("dragArea");
if (!dragArea) return;
dragArea.onmousedown = (e) =>
{
//命令栏高度

@ -38,16 +38,14 @@ export class FileItem extends React.Component<FileItemProps, FileItemState>{
fontWeight: "bold"
}
const imgStyle: React.CSSProperties = {
transform: "scale(10)",
width: "40px",
height: "40px"
filter: "invert(91%) grayscale(93%) sepia(50%)"
}
return (
<li
className="pt-card pt-elevation-0"
style={{
display: "flex",
width: "100 %",
width: "100%",
padding: "10px"
}}
>
@ -56,7 +54,9 @@ export class FileItem extends React.Component<FileItemProps, FileItemState>{
style={{
width: 120,
height: 120,
overflow: "hidden"
overflow: "hidden",
padding: "8px",
background: "#444444"
}}
>
<img src={fileInfo.pic} style={imgStyle} />

Loading…
Cancel
Save