pull/300/MERGE
ChenX 5 years ago
parent 33c0828b92
commit fe231128f9

@ -0,0 +1,316 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`完整椭圆 GetClosestPointTo 1`] = `
Vector3 {
"x": 161.75177046648375,
"y": 76.24839906616579,
"z": 0,
}
`;
exports[`完整椭圆 GetClosestPointTo 2`] = `
Vector3 {
"x": -133.46958799601072,
"y": -84.55612959938519,
"z": 0,
}
`;
exports[`完整椭圆 offset 1`] = `
Array [
Vector3 {
"x": 250,
"y": 0,
"z": 0,
},
Vector3 {
"x": -250,
"y": 0,
"z": 0,
},
Vector3 {
"x": 0,
"y": 100,
"z": 0,
},
Vector3 {
"x": 0,
"y": -100,
"z": 0,
},
Vector3 {
"x": 250,
"y": 0,
"z": 0,
},
Vector3 {
"x": 0,
"y": 0,
"z": 0,
},
]
`;
exports[`完整椭圆 offset 2`] = `
Array [
Vector3 {
"x": 200,
"y": 0,
"z": 0,
},
Vector3 {
"x": -200,
"y": 0,
"z": 0,
},
Vector3 {
"x": 0,
"y": 50,
"z": 0,
},
Vector3 {
"x": 0,
"y": -50,
"z": 0,
},
Vector3 {
"x": 200,
"y": 0,
"z": 0,
},
Vector3 {
"x": 0,
"y": 0,
"z": 0,
},
]
`;
exports[`完整椭圆 offset 3`] = `
Array [
Vector3 {
"x": 450,
"y": 0,
"z": 0,
},
Vector3 {
"x": -450,
"y": 0,
"z": 0,
},
Vector3 {
"x": 0,
"y": 300,
"z": 0,
},
Vector3 {
"x": 0,
"y": -300,
"z": 0,
},
Vector3 {
"x": 450,
"y": 0,
"z": 0,
},
Vector3 {
"x": 0,
"y": 0,
"z": 0,
},
]
`;
exports[`完整椭圆 几何数据 1`] = `1150.6559640322623`;
exports[`完整椭圆 几何数据 2`] = `78539.81633974482`;
exports[`非完整椭圆 GetParamAtDist 1`] = `242.30725311615984`;
exports[`非完整椭圆 GetParamAtDist 2`] = `605.7681327903996`;
exports[`非完整椭圆 GetParamAtDist 3`] = `969.2290124646394`;
exports[`非完整椭圆 GetPointAtParam 1`] = `
Vector3 {
"x": -128.24678398779253,
"y": 479.9479365060514,
"z": 0,
}
`;
exports[`非完整椭圆 GetPointAtParam 2`] = `
Vector3 {
"x": 239.42920866477306,
"y": 323.0232500594477,
"z": 0,
}
`;
exports[`非完整椭圆 offset 1`] = `
Array [
Vector3 {
"x": 350.2058941499969,
"y": 373.22534255869425,
"z": 0,
},
Vector3 {
"x": -290.9818601387027,
"y": 910.1549254183373,
"z": 0,
},
Vector3 {
"x": 174.41678315228742,
"y": 814.612330454892,
"z": 0,
},
Vector3 {
"x": -115.19274914099324,
"y": 468.7679375221395,
"z": 0,
},
Vector3 {
"x": -298.4690575735684,
"y": 706.7486518071757,
"z": 0,
},
Vector3 {
"x": 245.79986047889065,
"y": 746.5732067866242,
"z": 0,
},
Vector3 {
"x": 29.61201700564709,
"y": 641.6901339885158,
"z": 0,
},
]
`;
exports[`非完整椭圆 offset 2`] = `
Array [
Vector3 {
"x": 311.87157824105714,
"y": 405.3264363686194,
"z": 0,
},
Vector3 {
"x": -252.64754422976296,
"y": 878.0538316084121,
"z": 0,
},
Vector3 {
"x": 142.3156893423623,
"y": 776.2780145459523,
"z": 0,
},
Vector3 {
"x": -83.09165533106811,
"y": 507.10225343107925,
"z": 0,
},
Vector3 {
"x": -248.70057555417316,
"y": 711.5547102218358,
"z": 0,
},
Vector3 {
"x": 205.57861428580685,
"y": 716.8704905021605,
"z": 0,
},
Vector3 {
"x": 29.61201700564709,
"y": 641.6901339885158,
"z": 0,
},
]
`;
exports[`非完整椭圆 offset 3`] = `
Array [
Vector3 {
"x": 273.5372623321175,
"y": 437.42753017854454,
"z": 0,
},
Vector3 {
"x": -214.3132283208233,
"y": 845.952737798487,
"z": 0,
},
Vector3 {
"x": 110.21459553243717,
"y": 737.9436986370126,
"z": 0,
},
Vector3 {
"x": -50.99056152114299,
"y": 545.4365693400189,
"z": 0,
},
Vector3 {
"x": -198.93209353477783,
"y": 716.3607686364959,
"z": 0,
},
Vector3 {
"x": 165.35736809272308,
"y": 687.1677742176968,
"z": 0,
},
Vector3 {
"x": 29.61201700564709,
"y": 641.6901339885158,
"z": 0,
},
]
`;
exports[`非完整椭圆 offset 4`] = `
Array [
Vector3 {
"x": 503.54315778575557,
"y": 244.82096731899384,
"z": 0,
},
Vector3 {
"x": -444.3191237744614,
"y": 1038.5593006580377,
"z": 0,
},
Vector3 {
"x": 302.8211583919879,
"y": 967.9495940906507,
"z": 0,
},
Vector3 {
"x": -243.59712438069374,
"y": 315.43067388638076,
"z": 0,
},
Vector3 {
"x": -497.5429856511497,
"y": 687.5244181485352,
"z": 0,
},
Vector3 {
"x": 406.6848452512257,
"y": 865.3840719244788,
"z": 0,
},
Vector3 {
"x": 29.61201700564709,
"y": 641.6901339885158,
"z": 0,
},
]
`;
exports[`非完整椭圆 几何参数 1`] = `885.1880105792319`;
exports[`非完整椭圆 几何参数 2`] = `72828.18768552072`;
exports[`非完整椭圆 几何参数 3`] = `1211.5362655807992`;
exports[`非完整椭圆 几何参数 4`] = `72828.18768552072`;

@ -0,0 +1,358 @@
import { Vector3 } from "three";
import { Ellipse } from "../../src/DatabaseServices/Ellipse";
import { equalv3 } from "../../src/Geometry/GeUtils";
import { Status } from "../../src/Common/Status";
import { Line } from "../../src/DatabaseServices/Line";
import { Arc } from "../../src/DatabaseServices/Arc";
import { Circle } from "../../src/DatabaseServices/Circle";
import { LoadCurvesFromFileData } from "../Utils/LoadEntity.util";
import { Polyline } from "../../src/DatabaseServices/Polyline";
import { Curve } from "../../src/DatabaseServices/Curve";
describe('完整椭圆', () =>
{
let el = new Ellipse(new Vector3(), 250, 100, 0);
let p1 = el.GetPointAtParam(0);
let p2 = el.GetPointAtParam(0.1);
let p3 = el.GetPointAtParam(0.25);
let p4 = el.GetPointAtParam(0.5);
let p5 = el.GetPointAtParam(0.6);
let p6 = el.GetPointAtParam(0.75);
let p7 = el.GetPointAtParam(0.8);
test("几何数据", () =>
{
expect(el.Length).toMatchSnapshot();
expect(el.Length).toBeCloseTo(1150.66);
expect(el.Area).toMatchSnapshot();
expect(el.Area).toBeCloseTo(78539.82);
})
test("PtOnCurve", () =>
{
let pt = new Vector3(160.20983328761838, 76.76750283077186);
[pt, new Vector3(250), new Vector3(0, -100)].forEach(p =>
{
expect(el.PtOnCurve(p)).toBeTruthy();
})
});
test("GetPointAtParam", () =>
{
expect(equalv3(p1, new Vector3(250))).toBeTruthy();
expect(equalv3(p2, new Vector3(202.25424859373686, 58.778525229247315))).toBeTruthy();
expect(equalv3(p3, new Vector3(0, 100))).toBeTruthy();
expect(equalv3(p4, new Vector3(-250))).toBeTruthy();
});
test("GetParamAtPoint", () =>
{
expect(el.GetParamAtPoint(p1)).toBeCloseTo(0);
expect(el.GetParamAtPoint(p2)).toBeCloseTo(0.1);
expect(el.GetParamAtPoint(p3)).toBeCloseTo(0.25);
expect(el.GetParamAtPoint(p5)).toBeCloseTo(0.6);
expect(el.GetParamAtPoint(p7)).toBeCloseTo(0.8);
});
test("GetDistAtParam", () =>
{
expect(el.GetDistAtParam(0.5)).toBeCloseTo(el.Length * 0.5);
});
test("GetParamAtDist", () =>
{
expect(el.GetParamAtDist(el.Length * 0.5)).toBeCloseTo(0.5);
});
test("GetFistDeriv", () =>
{
expect(equalv3(el.GetFistDeriv(0), new Vector3(0, 1))).toBeTruthy();
expect(equalv3(el.GetFistDeriv(0.5), new Vector3(0, -1))).toBeTruthy();
expect(equalv3(el.GetFistDeriv(0.25), new Vector3(-1))).toBeTruthy();
expect(equalv3(el.GetFistDeriv(0.75), new Vector3(1))).toBeTruthy();
expect(equalv3(el.GetFistDeriv(0.1), new Vector3(-1, 0.5505527681884694))).toBeTruthy();
expect(equalv3(el.GetFistDeriv(0.3), new Vector3(-1, -0.1299678784931625))).toBeTruthy();
expect(equalv3(el.GetFistDeriv(0.6), new Vector3(1, -0.5505527681884692))).toBeTruthy();
expect(equalv3(el.GetFistDeriv(0.8), new Vector3(1, 0.12996787849316255))).toBeTruthy();
});
test("GetClosestPointTo", () =>
{
expect(el.GetClosestPointTo(new Vector3(180, 130), true)).toMatchSnapshot();
expect(el.GetClosestPointTo(new Vector3(-150, -150), true)).toMatchSnapshot();
expect(equalv3(el.GetClosestPointTo(new Vector3(), true), new Vector3(250))).toBeTruthy();
});
test('offset', () =>
{
for (let d of [0, -50, -100, 200])
{
let els = el.GetOffsetCurves(d);
for (let e of els)
{
expect(e.GetGripPoints()).toMatchSnapshot();
}
}
});
test("join", () =>
{
let el1 = el.Clone();
el1.StartAngle = Math.PI * 0.2;
el1.EndAngle = Math.PI * 0.5;
let el2 = el.Clone();
el2.StartAngle = Math.PI * 0.5;
el2.EndAngle = Math.PI * 0.2;
expect(el1.Join(el2)).toBe(Status.True);
expect(el1.IsClose).toBeTruthy();
});
test("GetSplitCurves", () =>
{
let els = el.GetSplitCurves([0, 0.1, 0.5, 0.75]);
expect(els.length).toBe(4);
let len = 0;
els.forEach(l => len += l.Length);
expect(len).toBeCloseTo(el.Length);
});
test("椭圆和直线相交", () =>
{
let l = new Line(new Vector3(250), new Vector3(250, 300));
let pts = el.IntersectWith(l, 0);
expect(pts.length).toBe(1);
l = new Line(new Vector3(250), new Vector3(-200, 200));
pts = el.IntersectWith(l, 0);
expect(pts.length).toBe(2);
l = new Line(new Vector3(130, 50), new Vector3(-200, 200));
pts = el.IntersectWith(l, 0);
expect(pts.length).toBe(1);
l = new Line(new Vector3(200, -300), new Vector3(200, 300));
pts = el.IntersectWith(l, 0);
expect(pts.length).toBe(2);
});
test("椭圆和圆弧相交", () =>
{
let l = new Arc(new Vector3(200, 90), 120, 1.2667, 4.204);
let pts = el.IntersectWith(l, 0);
expect(pts.length).toBe(1);
pts = el.IntersectWith(l, 3);
expect(pts.length).toBe(2);
let cir = new Circle(new Vector3(), 100);
pts = el.IntersectWith(cir, 0);
expect(pts.length).toBe(2);
cir = new Circle(new Vector3(), 250);
pts = el.IntersectWith(cir, 0);
expect(pts.length).toBe(2);
cir = new Circle(new Vector3(), 200);
pts = el.IntersectWith(cir, 0);
expect(pts.length).toBe(4);
cir = new Circle(new Vector3(0, 100), 100);
pts = el.IntersectWith(cir, 0);
expect(pts.length).toBe(2);
cir = new Circle(new Vector3(400), 100);
pts = el.IntersectWith(cir, 0);
expect(pts.length).toBe(0);
let data =
{ "file": [2, "Ellipse", 3, 2, 833, false, 0, 7, 0, [1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 11102.861204896697, 0, 2032.2646535460103, 1], 1, 3731.0773801284895, 1822.1540693650747, -0.7853981633972875, 0, 6.283185307179586, "Circle", 3, 2, 842, false, 1, 7, 0, [1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 11102.861204896697, 0, 2032.2646535460103, 1], 1, 3001.2505191312093], "basePt": { "x": 20324.11883779178, "y": 0, "z": 2875.7945530299553 } }
let cus = LoadCurvesFromFileData(data) as Curve[];
pts = cus[0].IntersectWith(cus[1], 0);
expect(pts.length).toBe(4);
});
test("椭圆和多段线相交", () =>
{
let data = { "file": [1, "Polyline", 3, 2, 112, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 4, [-335.6038995638465, -82.43257813770273], 0, [-106.1153157638372, -6.7633694252672285], 0, [12.970652045897396, -45.21821319716078], 0, [117.1708738794153, 118.52499254122434], 0, false], "basePt": { "x": 55.14693231184518, "y": 32.93195317797762, "z": 0 } };
let pl = LoadCurvesFromFileData(data)[0];
let pts = el.IntersectWith(pl, 0);
expect(pts.length).toBe(2);
data = { "file": [1, "Polyline", 3, 2, 113, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 5, [-410.1219439207879, -125.67070828328724], 0, [-173.79584080236958, -1.6724443014010655], 0.2825944770646096, [-68.76201719418361, 174.84273148457797], -2.140757839596393, [63.989065421717896, 66.8913016650536], 0, [441.8190697900534, -102.32985859257917], 0, false], "basePt": { "x": 435.98385736737646, "y": -78.98900890187124, "z": 0 } }
pl = LoadCurvesFromFileData(data)[0];
pts = el.IntersectWith(pl, 0);
expect(pts.length).toBe(4);
});
test("椭圆椭圆相交", () =>
{
let pts = el.IntersectWith(el.Clone(), 0);
expect(pts.length).toBe(0);
let el2 = el.Clone();
el2.Center = new Vector3(250);
pts = el.IntersectWith(el2, 0);
expect(pts.length).toBe(2);
let data = { "file": [1, "Ellipse", 3, 2, 115, false, 1, 7, 0, [-0.4190581774617472, -0.9079593845004515, 0, 0, 0.9079593845004515, -0.4190581774617472, 0, 0, 0, 0, 1, 0, 20.59763950762874, 46.6612008780327, 0, 1], 1, 250, 100, 0, 0, 6.283185307179586], "basePt": { "x": 735.3489273304585, "y": 121.3525062483825, "z": 0 } };
let el3 = LoadCurvesFromFileData(data)[0];
pts = el.IntersectWith(el3, 0);
expect(pts.length).toBe(4);
data = { "file": [1, "Ellipse", 3, 2, 115, false, 1, 7, 0, [-0.4190581774617472, -0.9079593845004515, 0, 0, 0.9079593845004515, -0.4190581774617472, 0, 0, 0, 0, 1, 0, 187.7445845668207, 364.27473348939463, 0, 1], 1, 250, 100, 0, 0, 6.283185307179586], "basePt": { "x": 317.9344290644616, "y": 379.38531948896275, "z": 0 } }
el3 = LoadCurvesFromFileData(data)[0];
pts = el.IntersectWith(el3, 0);
expect(pts.length).toBe(0);
})
});
describe("非完整椭圆", () =>
{
let data = { "file": [1, "Ellipse", 3, 2, 121, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 1, 250, 100, 0, 3.2624068331327574, 1.8128125175408325], "basePt": { "x": 948.626520974941, "y": -75.40395225389025, "z": 0 } };
let el = LoadCurvesFromFileData(data)[0] as Ellipse;
data = { "file": [1, "Ellipse", 3, 2, 124, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 29.61201700564709, 641.6901339885158, 0, 1], 1, 418.15520838547974, 225.54490978414745, -0.69713252541264, 3.934994981148553, 1.3332220725861395], "basePt": { "x": 334.56716843563856, "y": 365.4059797015151, "z": 0 } }
let el2 = LoadCurvesFromFileData(data)[0] as Ellipse;
test("几何参数", () =>
{
expect(el.Length).toMatchSnapshot();
expect(el.Area).toMatchSnapshot();
expect(el2.Length).toMatchSnapshot();
expect(el.Area).toMatchSnapshot();
});
test("PtOnCurve", () =>
{
let p = new Vector3(-283.26124450979813, 673.4306820783466);
let data = { "file": [1, "Ellipse", 3, 2, 124, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 29.61201700564709, 641.6901339885158, 0, 1], 1, 418.15520838547974, 225.54490978414745, -0.69713252541264, 3.934994981148553, 1.3332220725861395], "basePt": { "x": 2681.2570394768845, "y": -1593.4506532289088, "z": 0 } }
let l = LoadCurvesFromFileData(data)[0] as Ellipse;
expect(l.PtOnCurve(p)).toBeTruthy();
p = new Vector3(2397.1610323469677, 85.35748381925586);
data = { "file": [1, "Ellipse", 3, 2, 444, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2079.1139796352218, 127.64566779152159, 0, 1], 1, 225.54490978414742, 418.1552083854798, -2.2679288522075365, 5.505791307943451, 2.904018399381034], "basePt": { "x": 3700.685116502911, "y": -68.9791965641534, "z": 0 } }
l = LoadCurvesFromFileData(data)[0] as Ellipse;
expect(l.PtOnCurve(p)).toBeTruthy();
});
test("GetPointAtParam", () =>
{
expect(el2.GetPointAtParam(0.2)).toMatchSnapshot();
expect(el2.GetPointAtParam(0.5)).toMatchSnapshot();
});
test("GetParamAtPoint", () =>
{
let data = { "file": [1, "Ellipse", 3, 2, 124, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 29.61201700564709, 641.6901339885158, 0, 1], 1, 418.15520838547974, 225.54490978414745, -0.69713252541264, 3.934994981148553, 1.3332220725861395], "basePt": { "x": 2681.2570394768845, "y": -1593.4506532289088, "z": 0 } }
let l = LoadCurvesFromFileData(data)[0] as Ellipse;
let p = new Vector3(246.01582144145584, 746.3383795723034);
expect(l.GetParamAtPoint(p)).toBeCloseTo(1);
p = new Vector3(73.23667922398035, 886.2085173816399);
expect(l.GetParamAtPoint(p)).toBeGreaterThan(1);
p = new Vector3(-317.46308327988817, 769.1547312689645);
expect(l.GetParamAtPoint(p)).toBeLessThan(1);
expect(l.GetParamAtPoint(l.GetPointAtParam(0.2))).toBeCloseTo(0.2);
expect(l.GetParamAtPoint(l.GetPointAtParam(0.5))).toBeCloseTo(0.5);
expect(l.GetParamAtPoint(l.GetPointAtParam(0.8))).toBeCloseTo(0.8);
});
test("GetDistAtParam", () =>
{
expect(el2.GetParamAtDist(el2.GetDistAtParam(0.2))).toBeCloseTo(0.2);
expect(el2.GetParamAtDist(el2.GetDistAtParam(0.5))).toBeCloseTo(0.5);
expect(el2.GetParamAtDist(el2.GetDistAtParam(0.8))).toBeCloseTo(0.8);
});
test("GetParamAtDist", () =>
{
expect(el2.GetDistAtParam(0.2)).toMatchSnapshot();
expect(el2.GetDistAtParam(0.5)).toMatchSnapshot();
expect(el2.GetDistAtParam(0.8)).toMatchSnapshot();
});
test("GetFistDeriv", () =>
{
let p = new Vector3(3245.070906808509, -20.406490193093504);
let data = { "file": [1, "Ellipse", 3, 2, 131, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2910.330625096328, 62.245373351688414, 0, 1], 1, 418.15520838547974, 225.54490978414745, -0.69713252541264, 3.934994981148553, 1.3332220725861395], "basePt": { "x": 3893.631897322025, "y": -235.90267753572692, "z": 0 } }
let el = LoadCurvesFromFileData(data)[0] as Ellipse;
let derv = el.GetFistDeriv(p);
expect(derv.x < 0).toBeTruthy();
expect(derv.y > 0).toBeTruthy();
derv = el.GetFistDeriv(0.2)
expect(derv.x > 0).toBeTruthy();
expect(derv.y < 0).toBeTruthy();
derv = el.GetFistDeriv(0.5)
expect(derv.x > 0).toBeTruthy();
expect(derv.y > 0).toBeTruthy();
});
test("GetClosestPointTo", () =>
{
let p = new Vector3(-485.6180207115862, 791.5205029837365);
let data = { "file": [1, "Ellipse", 3, 2, 124, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 29.61201700564709, 641.6901339885158, 0, 1], 1, 418.15520838547974, 225.54490978414745, -0.69713252541264, 3.934994981148553, 1.3332220725861395], "basePt": { "x": 1514.970345140928, "y": 460.6123732805639, "z": 0 } };
let l = LoadCurvesFromFileData(data)[0] as Ellipse;
let closePt = l.GetClosestPointTo(p, false);
expect(equalv3(closePt, l.StartPoint)).toBeTruthy();
p = new Vector3(255.02021875477413, 873.0660067450125);
closePt = l.GetClosestPointTo(p, false);
expect(equalv3(closePt, l.EndPoint)).toBeTruthy();
p = new Vector3(-301.20629379808594, 636.6952439507315);
closePt = l.GetClosestPointTo(p, false);
expect(l.PtOnCurve(closePt)).toBeTruthy();
});
test('offset', () =>
{
for (let d of [0, -50, -100, 200])
{
let els = el2.GetOffsetCurves(d);
for (let e of els)
{
expect(e.GetGripPoints()).toMatchSnapshot();
}
}
});
test("join", () =>
{
expect(el.Join(el2)).toBeFalsy();
let data = { "file": [2, "Ellipse", 3, 2, 834, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2910.330625096328, 62.245373351688414, 0, 1], 1, 418.15520838547974, 225.54490978414745, -0.69713252541264, 6.343188564109003, 7.616407379765725, "Ellipse", 3, 2, 833, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2910.330625096327, 62.24537335168705, 0, 1], 1, 418.15520838547974, 225.54490978414745, -0.69713252541264, 3.934994981148553, 6.34318856410901], "basePt": { "x": 3070.6075022402556, "y": -251.35268998703185, "z": 0 } }
let els = LoadCurvesFromFileData(data) as Ellipse[];
expect(els[0].Join(els[1])).toBeTruthy();
expect(els[0].StartAngle).toBeCloseTo(el2.StartAngle);
expect(els[0].EndAngle).toBeCloseTo(el2.EndAngle);
});
test("GetSplitCurves", () =>
{
let cus = el2.GetSplitCurves(0.2);
expect(cus.length).toBe(2);
cus = el2.GetSplitCurves([0, 1]);
expect(cus.length).toBe(1);
expect(cus[0].Length).toBeCloseTo(el2.Length);
});
test("椭圆和直线相交", () =>
{
let data = { "file": [1, "Line", 3, 2, 835, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 1, [40.99635967060419, 828.344303500637, 0], [419.2963252629038, 79.65300513942876, 0]], "basePt": { "x": 1547.6371722986987, "y": 505.9487058831845, "z": 0 } }
let l = LoadCurvesFromFileData(data)[0] as Line;
let intPts = el2.IntersectWith(l, 0);
expect(intPts.length).toBe(1);
data = { "file": [1, "Line", 3, 2, 836, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 1, [-508.03376696505734, 378.26728108419354, 0], [1506.1407092390264, 857.0726240804099, 0]], "basePt": { "x": 819.8530509444495, "y": 697.4708430816711, "z": 0 } }
l = LoadCurvesFromFileData(data)[0] as Line;
intPts = el2.IntersectWith(l, 0);
expect(intPts.length).toBe(2);
});
test("椭圆和圆弧相交", () =>
{
let data = { "file": [1, "Circle", 3, 2, 837, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 29.61201700564709, 641.6901339885158, 0, 1], 1, 240.28658436372382], "basePt": { "x": 1747.976477968104, "y": 478.1948499374774, "z": 0 } }
let cir = LoadCurvesFromFileData(data)[0] as Circle;
let intPts = el2.IntersectWith(cir, 0);
expect(intPts.length).toBe(3);
let cus = el2.GetSplitCurvesByPts(intPts);
expect(cus.length).toBe(3);
data = { "file": [1, "Circle", 3, 2, 829, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 187.80449653238327, 687.2252854417625, 0, 1], 1, 142.38840109430407], "basePt": { "x": 230.04137781057622, "y": 568.9620178628227, "z": 0 } }
cir = LoadCurvesFromFileData(data)[0] as Circle;
intPts = el2.IntersectWith(cir, 0);
expect(intPts.length).toBe(1);
data = { "file": [1, "Arc", 3, 2, 830, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 23.981256652944406, 734.2425700250855, 0, 1], 2, 380.9050292698399, 3.8973798333988365, 0.296805111427033, false], "basePt": { "x": 676.8826456844006, "y": 686.8100446096855, "z": 0 } }
let arc = LoadCurvesFromFileData(data)[0] as Arc;
intPts = el2.IntersectWith(arc, 0);
expect(intPts.length).toBe(2);
});
test("椭圆和多段线相交", () =>
{
let data =
{ "file": [1, "Polyline", 3, 2, 831, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 4, [-199.7615585356133, 411.90419659644084], 0, [67.50801592170811, 509.64849811226117], 0, [316.4505338448129, 443.97654553131935], 0, [316.4505338448129, 828.844732749862], 0, false], "basePt": { "x": 1289.3117848694626, "y": 358.45028170497653, "z": 0 } }
let l = LoadCurvesFromFileData(data)[0] as Polyline;
let pts = el2.IntersectWith(l, 0);
expect(pts.length).toBe(2);
});
test("椭圆椭圆相交", () =>
{
let data =
{ "file": [1, "Ellipse", 3, 2, 121, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 280.916829323563, 321.0478049412151, 0, 1], 1, 250, 100, 0, 3.2624068331327574, 1.8128125175408325], "basePt": { "x": 217.06597636418695, "y": 243.35797242008385, "z": 0 } }
let l = LoadCurvesFromFileData(data)[0] as Ellipse;
let pts = el2.IntersectWith(l, 0);
expect(pts.length).toBe(1);
})
})

@ -12,6 +12,9 @@ Factory(Board);
export function LoadEntityFromFileData(data)
{
if (!Array.isArray(data))
data = data.file;
let file = new CADFiler();
file.Data = data;
let ens: Entity[] = [];

@ -3,7 +3,6 @@ import { app } from '../ApplicationServices/Application';
import { arrayLast, arrayRemove } from '../Common/ArrayExt';
import { Status } from '../Common/Status';
import { Arc } from '../DatabaseServices/Arc';
import { Circle } from '../DatabaseServices/Circle';
import { Curve } from '../DatabaseServices/Curve';
import { Line } from '../DatabaseServices/Line';
import { Polyline } from '../DatabaseServices/Polyline';
@ -110,7 +109,7 @@ export class Command_Trim implements Command
let newCus: Curve[] = [];
if (cu instanceof Polyline && (kniefCus.includes(cu) || kniefCus.length === 0))
newCus = this.TrimPolyline(cu, kniefCus, s);
else if (cu instanceof Circle || cu instanceof Arc || cu instanceof Line || cu instanceof Polyline)
else
newCus = this.TrimCurve(cu, kniefCus, s);
resCus.set(cu, newCus);
@ -141,7 +140,7 @@ export class Command_Trim implements Command
* @param selBox
* @param [isSelect]
*/
TrimCurve(curve: Line | Circle | Arc | Polyline, kniefCus: Curve[], selBox: SelectBox, thisCurve: Curve = curve, insSelfPts: Vector3[] = []): Curve[]
TrimCurve(curve: Curve, kniefCus: Curve[], selBox: SelectBox, thisCurve: Curve = curve, insSelfPts: Vector3[] = []): Curve[]
{
//求交
let intPts = this.GetIntersetPoints(kniefCus, curve, thisCurve);

@ -46,7 +46,7 @@ export class Command_ClosePt implements Command
line.EndPoint = cu.GetClosestPointTo(p, extend);
derLine.StartPoint = line.EndPoint;
derLine.EndPoint = line.EndPoint.add(cu.GetFistDeriv(line.EndPoint));
derLine.EndPoint = line.EndPoint.add(cu.GetFistDeriv(line.EndPoint).multiplyScalar(100));
if (cu instanceof Arc)
{

@ -13,6 +13,7 @@ import { FixIndex } from './Utils';
import { PlaneExt } from '../Geometry/Plane';
import { IntersectOption } from '../GraphicsSystem/IntersectWith';
import { arrayLast, changeArrayStartIndex, equalArray } from './ArrayExt';
import { Ellipse } from '../DatabaseServices/Ellipse';
//3点获取圆心
export function getCircleCenter(pt1: Vector3, pt2: Vector3, pt3: Vector3)
@ -256,6 +257,13 @@ export function equalCurve(cu1: Curve, cu2: Curve)
&& equaln(cu1.StartAngle, cu2.StartAngle)
&& equaln(cu1.EndAngle, cu2.EndAngle);
}
else if (cu1 instanceof Ellipse && cu2 instanceof Ellipse)
{
return equalv3(cu1.Center, cu2.Center)
&& equaln(cu1.RadX, cu2.RadX)
&& equaln(cu1.RadY, cu2.RadY)
&& equalv3(cu1.StartPoint, cu2.StartPoint);
}
return false;
}
@ -546,7 +554,7 @@ export function CircleOuterTangentLines(circle0: Circle, circle1: Circle): Line[
}
}
export function getArcOrCirNearPts(cu: Circle | Arc, pickPoint: Vector3, viewXform: Matrix3)
export function getArcOrCirNearPts(cu: Circle | Arc | Ellipse, pickPoint: Vector3, viewXform: Matrix3)
{
//@ts-ignore
let viewNormal = new Vector3().fromArray(viewXform.elements, 2 * 3);
@ -579,3 +587,8 @@ export function getArcOrCirNearPts(cu: Circle | Arc, pickPoint: Vector3, viewXfo
return cu.IntersectWith(lz, IntersectOption.ExtendBoth);
}
}
export function getTanPtsOnEllipse(cu: Ellipse, lastPoint: Vector3)
{
return [];
}

@ -8,13 +8,14 @@ import { ObjectSnapMode } from '../Editor/ObjectSnapMode';
import { BufferGeometryUtils } from '../Geometry/BufferGeometryUtils';
import { angle, angleTo2Pi, equaln, equalv3, midPoint, MoveMatrix, polar } from '../Geometry/GeUtils';
import { RenderType } from '../GraphicsSystem/RenderType';
import { IntersectArcAndArc, IntersectCircleAndArc, IntersectLineAndArc, IntersectOption, IntersectPolylineAndCurve, reverseIntersectOption } from '../GraphicsSystem/IntersectWith';
import { IntersectArcAndArc, IntersectCircleAndArc, IntersectLineAndArc, IntersectOption, IntersectPolylineAndCurve, reverseIntersectOption, IntersectEllipseAndCircleOrArc } from '../GraphicsSystem/IntersectWith';
import { Factory } from './CADFactory';
import { CADFiler } from './CADFiler';
import { Circle } from './Circle';
import { Curve } from './Curve';
import { Line } from './Line';
import { Polyline } from './Polyline';
import { Ellipse } from './Ellipse';
/**
*
* ACAD,,.
@ -456,7 +457,10 @@ export class Arc extends Curve
return IntersectCircleAndArc(curve, this, reverseIntersectOption(intType));
}
if (curve instanceof Polyline)
return IntersectPolylineAndCurve(curve, this, reverseIntersectOption(intType))
return IntersectPolylineAndCurve(curve, this, reverseIntersectOption(intType));
if (curve instanceof Ellipse)
return IntersectEllipseAndCircleOrArc(curve, this, intType);
return [];
}

@ -8,7 +8,7 @@ import { clamp } from '../Common/Utils';
import { ObjectSnapMode } from '../Editor/ObjectSnapMode';
import { BufferGeometryUtils } from '../Geometry/BufferGeometryUtils';
import { angle, equaln, MoveMatrix, polar } from '../Geometry/GeUtils';
import { IntersectCircleAndArc, IntersectCircleAndCircle, IntersectLineAndCircle, IntersectOption, IntersectPolylineAndCurve, reverseIntersectOption } from '../GraphicsSystem/IntersectWith';
import { IntersectCircleAndArc, IntersectCircleAndCircle, IntersectLineAndCircle, IntersectOption, IntersectPolylineAndCurve, reverseIntersectOption, IntersectEllipseAndCircleOrArc } from '../GraphicsSystem/IntersectWith';
import { RenderType } from '../GraphicsSystem/RenderType';
import { Arc } from './Arc';
import { Factory } from './CADFactory';
@ -16,6 +16,7 @@ import { CADFiler } from './CADFiler';
import { Curve } from './Curve';
import { Line } from './Line';
import { Polyline } from './Polyline';
import { Ellipse } from './Ellipse';
let circleGeometry: BufferGeometry;
function GetCircleGeometry()
@ -216,6 +217,10 @@ export class Circle extends Curve
{
return IntersectCircleAndCircle(this, curve);
}
if (curve instanceof Ellipse)
{
return IntersectEllipseAndCircleOrArc(curve, this, intType);
}
if (curve instanceof Polyline)
return IntersectPolylineAndCurve(curve, this, reverseIntersectOption(intType))
return [];

@ -155,7 +155,7 @@ export abstract class Curve extends Entity
* @returns {Vector3[]}
* @memberof Curve
*/
IntersectWith(curve: Curve, intType: IntersectOption): Vector3[] { return; }
IntersectWith(curve: Curve, intType: IntersectOption): Vector3[] { return []; }
//------------------绘制相关------------------
GetDrawObjectFromRenderType(renderType: RenderType = RenderType.Wireframe): Object3D

@ -1,18 +1,29 @@
import * as THREE from 'three';
import { Geometry, Object3D, Shape, Vector3 } from 'three';
import { Box3, BufferGeometry, Matrix3, Matrix4, Object3D, Shape, Vector3 } from 'three';
import { arrayLast, arrayRemoveDuplicateBySort } from '../Common/ArrayExt';
import { ColorMaterial } from '../Common/ColorPalette';
import { MoveMatrix, rotatePoint } from '../Geometry/GeUtils';
import { getDeterminantFor2V, Vec3DTo2D, getArcOrCirNearPts, getTanPtsOnEllipse } from '../Common/CurveUtils';
import { Status } from '../Common/Status';
import { ObjectSnapMode } from '../Editor/ObjectSnapMode';
import { angle, equaln, equalv3, MoveMatrix, rotatePoint, angleTo } from '../Geometry/GeUtils';
import { IntersectEllipse, IntersectEllipseAndCircleOrArc, IntersectEllipseAndLine, IntersectOption, IntersectPolylineAndCurve, reverseIntersectOption } from '../GraphicsSystem/IntersectWith';
import { RenderType } from '../GraphicsSystem/RenderType';
import { Arc } from './Arc';
import { Factory } from './CADFactory';
import { CADFiler } from './CADFiler';
import { Circle } from './Circle';
import { Curve } from './Curve';
import { Line } from './Line';
import { Polyline } from './Polyline';
@Factory
export class Ellipse extends Curve
{
private m_RadX: number;
private m_RadY: number;
private m_Angle: number;
private _radX: number;
private _radY: number;
private _rotate: number;
private _startAngle = 0;
private _endAngle = Math.PI * 2;
constructor(
center?: Vector3,
radX: number = 1e-3,
@ -21,20 +32,35 @@ export class Ellipse extends Curve
{
super();
center && this.m_Matrix.setPosition(center);
this.m_RadX = radX;
this.m_RadY = radY;
this.m_Angle = angle;
this._radX = radX;
this._radY = radY;
this._rotate = angle;
}
get StartParam(): number
{
return 0;
}
get EndParam(): number
{
return 1;
}
get StartPoint()
{
return this.GetPointAtParam(0);
}
get EndPoint()
{
return this.GetPointAtParam(1);
}
get Shape(): Shape
{
let sp = new Shape();
sp.ellipse(0, 0, this.m_RadX, this.m_RadY, 0, 2 * Math.PI, false, this.m_Angle);
sp.ellipse(0, 0, this._radX, this._radY, this._startAngle, this._endAngle, false, this._rotate);
return sp;
}
get IsClose(): boolean
get IsClose(): boolean
{
return true;
return equaln(this.TotalAngle, Math.PI * 2);
}
get Center()
{
@ -48,58 +74,423 @@ export class Ellipse extends Curve
}
get RadX()
{
return this.m_RadX;
return this._radX;
}
set RadX(v: number)
{
this.WriteAllObjectRecord();
this.m_RadX = v;
this._radX = v;
this.Update();
}
get RadY()
{
return this.m_RadY;
return this._radY;
}
set RadY(v: number)
{
this.WriteAllObjectRecord();
this.m_RadY = v;
this._radY = v;
this.Update();
}
get Rotation()
{
return this._rotate;
}
set Rotation(v: number)
{
this.WriteAllObjectRecord();
this._rotate = v;
this.Update();
}
get Angle()
get StartAngle()
{
return this._startAngle;
}
get EndAngle()
{
return this._startAngle;
}
set StartAngle(v: number)
{
return this.m_Angle;
this.WriteAllObjectRecord();
this._startAngle = v;
this.Update();
}
set Angle(v: number)
set EndAngle(v: number)
{
this.WriteAllObjectRecord();
this.m_Angle = v;
this._endAngle = v;
this.Update();
}
get Length()
{
let q = this._radX + this._radY;
let h = ((this._radX - this._radY) / (this._radX + this._radY)) ** 2;
let m = 22 / 7 * Math.PI - 1;
let n = Math.pow(((this._radX - this._radY) / this._radX), 33.697);
let len = Math.PI * q * (1 + 3 * h / (10 + Math.sqrt(4 - 3 * h))) * (1 + m * n);
return len * this.TotalAngle / Math.PI * 0.5;
}
get Area()
{
let area = Math.PI * this._radX * this._radY;
let an = this._endAngle - this._startAngle;
if (an < 0)
an = Math.PI * 2 + an;
area *= an / Math.PI * 0.5;
let area2 = Math.abs(
getDeterminantFor2V(
Vec3DTo2D(this.StartPoint.sub(this.Center)),
Vec3DTo2D(this.EndPoint.sub(this.Center)))
) / 2;
if (an < Math.PI)
area -= area2;
else
area += area2;
return area;
}
get TotalAngle()
{
let totolAngle = this._endAngle - this._startAngle;
if (totolAngle < 0)
totolAngle = Math.PI * 2 + totolAngle;
return totolAngle;
}
get BoundingBox(): Box3
{
return new Box3().setFromPoints(this.GetGripPoints());
}
PtInCurve(pt: Vector3)
{
let p = rotatePoint(pt.clone().sub(this.Center), -this.Angle);
let p = rotatePoint(pt.clone().sub(this.Center), -this.Rotation);
return p.x ** 2 / this.RadX ** 2 + p.y ** 2 / this.RadY ** 2 < 1;
}
PtOnCurve(pt: Vector3)
{
if (this.PtOnEllipse(pt))
{
let a = this.GetCircleAngleAtPoint(pt);
return a <= this.TotalAngle + 1e-6;
}
return false;
}
PtOnEllipse(pt: Vector3)
{
let p = rotatePoint(pt.clone().applyMatrix4(this.OCSInv), -this.Rotation);
return equaln(p.x ** 2 / this.RadX ** 2 + p.y ** 2 / this.RadY ** 2, 1, 1e-3);
}
GetPointAtParam(param: number)
{
let an = this.TotalAngle * param + this._startAngle;
if (an > Math.PI)
an -= 2 * Math.PI;
let a = this.RadX;
let b = this.RadY;
let pt = new Vector3(a * Math.cos(an), b * Math.sin(an), 0);
pt.applyMatrix4(new Matrix4().makeRotationZ(this._rotate));
return pt.applyMatrix4(this.OCS);
}
GetParamAtPoint(pt?: Vector3)
{
if (!this.PtOnEllipse(pt))
{
return NaN;
}
let an = this.GetCircleAngleAtPoint(pt);
let par = an / this.TotalAngle;
if (this.IsClose || par < 1 + 1e-6)
return par;
else
{
let diffPar = Math.PI * 2 / this.TotalAngle - 1;
if (par - 1 < diffPar / 2)
return par;
else
return par - 1 - diffPar;
}
}
GetPointAtDistance(distance: number)
{
let param = distance / this.Length;
return this.GetPointAtParam(param);
}
GetDistAtParam(param: number)
{
return this.Length * param;
}
GetDistAtPoint(pt: Vector3)
{
let param = this.GetParamAtPoint(pt);
return this.GetDistAtParam(param);
}
GetParamAtDist(d: number)
{
return d / this.Length;
}
GetAngleAtParam(par: number)
{
let pt = this.GetPointAtParam(par).applyMatrix4(this.OCSInv).applyMatrix4(new Matrix4().makeRotationZ(-this.Rotation));
return angle(pt) + this._startAngle;
}
GetCircleAngleAtPoint(pt: Vector3)
{
pt = pt.clone().applyMatrix4(this.OCSInv);
let an = angle(pt) - this._rotate;
if (an < 0)
an = Math.PI * 2 - an;
if (an > Math.PI * 2)
an -= Math.PI * 2;
let dist = pt.length();
let k = dist * Math.cos(an) / this._radX;
if (Math.abs(k) > 1)
k = Math.floor(Math.abs(k)) * Math.sign(k);
if (Math.abs(an) <= Math.PI)
an = Math.acos(k);
else
an = Math.PI * 2 - Math.acos(k);
an -= this._startAngle;
if (an < 0)
an = Math.PI * 2 + an;
return an;
}
GetFistDeriv(pt: number | Vector3)
{
if (typeof pt === "number")
pt = this.GetPointAtParam(pt);
else
pt = pt.clone();
let refPts = this.GetGripPoints();
let p = pt.clone().applyMatrix4(this.OCSInv).applyMatrix4(new Matrix4().makeRotationZ(-this._rotate));
let vec = new Vector3();
if (equalv3(pt, refPts[0]))
vec.set(0, 1, 0);
else if (equalv3(pt, refPts[1]))
{
vec.set(0, -1, 0);
}
else if (p.y > 0)
{
let k = -(this._radY ** 2 * p.x) / (this._radX ** 2 * p.y);
vec.set(-1, -k, 0);
}
else
{
let k = -(this._radY ** 2 * p.x) / (this._radX ** 2 * p.y);
vec.set(1, k, 0);
}
vec.applyMatrix4(new Matrix4().makeRotationZ(this._rotate));
return vec.applyMatrix4(new Matrix4().extractRotation(this.OCS));
}
GetClosestPointTo(p: Vector3, extend: boolean): Vector3
{
//参考:https://wet-robots.ghost.io/simple-method-for-distance-to-ellipse/
let ro = new Matrix4().makeRotationZ(this._rotate);
let roInv = new Matrix4().getInverse(ro);
let pt = p.clone().applyMatrix4(this.OCSInv).setZ(0).applyMatrix4(roInv);
let px = pt.x;
let py = pt.y;
let t = angle(pt);
let a = this._radX;
let b = this._radY;
let x: number, y: number;
for (let i = 0; i < 3; i++)
{
x = a * Math.cos(t);
y = b * Math.sin(t);
let ex = (a ** 2 - b ** 2) * Math.cos(t) ** 3 / a;
let ey = (b * b - a * a) * Math.sin(t) ** 3 / b;
let rx = x - ex;
let ry = y - ey;
let qx = px - ex;
let qy = py - ey;
let r = Math.sqrt(ry ** 2 + rx ** 2);
let q = Math.sqrt(qy ** 2 + qx ** 2);
let dc = r * Math.asin((rx * qy - ry * qx) / (r * q));
let dt = dc / Math.sqrt(a * a + b * b - x * x - y * y);
t += dt;
}
let retPt = new Vector3(x, y).applyMatrix4(ro).applyMatrix4(this.OCS);
if (this.IsClose || extend)
{
return retPt;
}
else if (this.PtOnCurve(retPt))
{
return retPt
}
else
{
let d1 = p.distanceToSquared(this.StartPoint);
let d2 = p.distanceToSquared(this.EndPoint);
return d1 < d2 ? this.StartPoint : this.EndPoint;
}
}
GetOffsetCurves(offsetDist: number)
{
if ((offsetDist + Math.min(this._radX, this._radY)) > 0)
{
let el = this.Clone();
el.RadX = this._radX + offsetDist;
el.RadY = this._radY + offsetDist;
return [el];
}
return []
}
GetSplitCurves(param: number[] | number)
{
let params: number[];
if (param instanceof Array)
{
params = param.filter(p => this.ParamOnCurve(p));
params.sort((a1, a2) => a2 - a1);//从大到小
}
else
params = [param];
//补上最后一个到第一个的弧
if (this.IsClose)
params.unshift(arrayLast(params));
else
{
params.unshift(1);
params.push(0);
}
arrayRemoveDuplicateBySort(params);
let anglelist = params.map(param => this.TotalAngle * param + this._startAngle);
let elllist: this[] = [];
for (let i = 0; i < anglelist.length - 1; i++)
{
let sa = anglelist[i];
let ea = anglelist[i + 1];
let el = this.Clone();
if (!equaln(sa, ea, 1e-6))
{
el.StartAngle = ea;
el.EndAngle = equaln(sa, 0) ? Math.PI * 2 : sa;
elllist.push(el);
}
}
return elllist;
}
Join(el: Ellipse)
{
if (this.IsClose || el.IsClose || !this.IsCoplaneTo(el) || !equalv3(el.Center, this.Center))
return Status.False;
let status = Status.False;
if (equaln(this._endAngle, this._startAngle))
{
this.EndAngle = this._endAngle;
status = Status.True;
}
else if (equaln(this._startAngle, el._endAngle))
{
this.StartAngle = el._startAngle;
status = Status.True;
}
if (status === Status.True && !this.IsClose && equaln(this._startAngle, this._endAngle))
{
this.StartAngle = 0;
this.EndAngle = Math.PI * 2;
}
return status;
}
GetObjectSnapPoints(
snapMode: ObjectSnapMode,
pickPoint: Vector3,
lastPoint: Vector3,
viewXform?: Matrix3
): Vector3[]
{
switch (snapMode)
{
case ObjectSnapMode.End:
{
let pts = this.GetGripPoints();
return pts;
}
case ObjectSnapMode.Cen:
return [this.Center];
case ObjectSnapMode.Nea:
{
return getArcOrCirNearPts(this, pickPoint, viewXform);
}
case ObjectSnapMode.Per:
if (lastPoint)
{
if (equaln(lastPoint.distanceToSquared(this.Center), 0, 1e-10))
return [];
return [this.GetClosestPointTo(lastPoint, false)];
}
case ObjectSnapMode.Tan:
{
//TODO:过某点获取椭圆全部切点
if (lastPoint)
{
return getTanPtsOnEllipse(this, lastPoint);
}
}
default:
return [];
}
}
IntersectWith(curve: Curve, intType: IntersectOption): Vector3[]
{
//TODO:优化椭圆和椭圆,椭圆和圆相交
if (curve instanceof Line)
{
return IntersectEllipseAndLine(curve, this, reverseIntersectOption(intType));
}
else if (curve instanceof Circle || curve instanceof Arc)
{
return IntersectEllipseAndCircleOrArc(this, curve, intType);
}
else if (curve instanceof Polyline)
{
return IntersectPolylineAndCurve(curve, this, intType);
}
else if (curve instanceof Ellipse)
{
return IntersectEllipse(this, curve, intType);
}
else
return [];
}
InitDrawObject(renderType: RenderType = RenderType.Wireframe): Object3D
{
let geometry = new Geometry();
this.UpdateGeometry(geometry);
let ellipseObj = new THREE.Line(geometry, ColorMaterial.GetLineMaterial(this.m_Color));
return ellipseObj;
let line = new THREE.Line(this.UpdateGeometry(), ColorMaterial.GetLineMaterial(this.m_Color));
this.UpdateDrawObject(renderType, line);
return line;
}
UpdateDrawObject(type: RenderType, en: Object3D)
UpdateDrawObject(type: RenderType, obj: Object3D)
{
let geo = (en as THREE.Line).geometry as Geometry;
let geo = (obj as THREE.Line).geometry as BufferGeometry;
this.UpdateGeometry(geo);
}
//更新Geometry
private UpdateGeometry(geo: THREE.Geometry)
private UpdateGeometry(geo?: BufferGeometry)
{
if (!geo)
geo = new BufferGeometry();
let curve = this.Shape;
geo.setFromPoints(curve.getPoints(60));
geo.verticesNeedUpdate = true;
return geo;
}
GetStretchPoints(): Array<Vector3>
{
@ -107,15 +498,21 @@ export class Ellipse extends Curve
}
GetGripPoints(): Array<Vector3>
{
let tmpMat4 = new THREE.Matrix4().makeRotationZ(this.Angle);
let tmpMat4 = new THREE.Matrix4().makeRotationZ(this.Rotation);
let pts = [
new Vector3(this.m_RadX, 0),
new Vector3(-this.m_RadX, 0),
new Vector3(0, -this.m_RadY),
new Vector3(0, this.m_RadY),
new Vector3(),
]
return pts.map(p => p.applyMatrix4(tmpMat4).applyMatrix4(this.OCS));
new Vector3(this._radX, 0),
new Vector3(-this._radX, 0),
new Vector3(0, this._radY),
new Vector3(0, -this._radY)
].map(p => p.applyMatrix4(tmpMat4).applyMatrix4(this.OCS))
if (!equaln(0, this._startAngle))
pts.push(this.StartPoint);
if (!equaln(0, this._endAngle))
pts.push(this.EndPoint);
pts.push(this.Center);
return pts;
}
MoveStretchPoints(indexList: Array<number>, vec: Vector3)
{
@ -127,24 +524,46 @@ export class Ellipse extends Curve
if (indexList.length > 0)
{
let p = pts[indexList[0]];
let p = pts[indexList[0]].clone();
p.add(vec);
if (indexList[0] === 0 || indexList[0] === 1)
if (indexList[0] <= 1)
this.RadX = p.distanceTo(this.Center);
else if (indexList[0] === 2 || indexList[0] === 3)
else if (indexList[0] <= 3)
this.RadY = p.distanceTo(this.Center);
else
this.Center = p;
{
let p1 = pts[indexList[0]];
//TODO:跟cad不一致待优化
if (equalv3(p1, this.StartPoint))
{
let v1 = p1.clone().sub(this.Center);
let v2 = p.clone().sub(this.Center);
let an = angleTo(v1, v2);
this.StartAngle = this.StartAngle + an;
}
else if (equalv3(p1, this.EndPoint))
{
let v1 = p1.clone().sub(this.Center);
let v2 = p.clone().sub(this.Center);
let an = angleTo(v2, v1);
this.EndAngle = this.EndAngle + an;
}
else
this.Center = p;
}
}
}
protected _ReadFile(file: CADFiler)
{
super._ReadFile(file);
let ver = file.Read();
this.RadX = file.Read();
this.RadY = file.Read();
this.Angle = file.Read();
this._radX = file.Read();
this._radY = file.Read();
this._rotate = file.Read();
this._startAngle = file.Read();
this._endAngle = file.Read();
this.Update();
}
//对象将自身数据写入到文件.
WriteFile(file: CADFiler)
@ -153,7 +572,9 @@ export class Ellipse extends Curve
file.Write(1);
file.Write(this.RadX);
file.Write(this.RadY);
file.Write(this.Angle);
file.Write(this.Rotation);
file.Write(this._startAngle);
file.Write(this._endAngle);
}
}

@ -7,7 +7,7 @@ import { ObjectSnapMode } from '../Editor/ObjectSnapMode';
import { BufferGeometryUtils } from '../Geometry/BufferGeometryUtils';
import { equaln, equalv3, isParallelTo, MoveMatrix } from '../Geometry/GeUtils';
import { PlaneExt } from '../Geometry/Plane';
import { IntersectLineAndArc, IntersectLineAndCircle, IntersectLineAndLine, IntersectOption, IntersectPolylineAndCurve, reverseIntersectOption } from '../GraphicsSystem/IntersectWith';
import { IntersectLineAndArc, IntersectLineAndCircle, IntersectLineAndLine, IntersectOption, IntersectPolylineAndCurve, reverseIntersectOption, IntersectEllipseAndLine } from '../GraphicsSystem/IntersectWith';
import { RenderType } from '../GraphicsSystem/RenderType';
import { Arc } from './Arc';
import { Factory } from './CADFactory';
@ -15,6 +15,7 @@ import { CADFiler } from './CADFiler';
import { Circle } from './Circle';
import { Curve } from './Curve';
import { Polyline } from './Polyline';
import { Ellipse } from './Ellipse';
@Factory
export class Line extends Curve
@ -174,6 +175,10 @@ export class Line extends Curve
{
return IntersectPolylineAndCurve(curve, this, reverseIntersectOption(intType));
}
if (curve instanceof Ellipse)
return IntersectEllipseAndLine(this, curve, intType);
//其他的尚未实现.
return [];
}

@ -110,6 +110,7 @@ import { DrawLattice } from '../Add-on/LatticeDrawer/DrawLatticeDrawer';
import { TestFb } from '../Add-on/TestFb';
import { DeleteDrill } from '../Add-on/DrawDrilling/DeleteDrill';
import { DownLoadDrillConfig, UpLoadDrillConfig } from '../Add-on/LoadConfig';
import { DrawEllipse } from '../Add-on/DrawEllipse';
export function registerCommand()
@ -124,7 +125,7 @@ export function registerCommand()
commandMachine.RegisterCommand("ze", new ZoomE())
commandMachine.RegisterCommand("RECTANG", new DrawRect())
commandMachine.RegisterCommand("c", new DrawCircle())
// commandMachine.RegisterCommand("el", new DrawEllipse())
commandMachine.RegisterCommand("el", new DrawEllipse())
commandMachine.RegisterCommand("spl", new DrawSpline())
commandMachine.RegisterCommand("pl", new DrawPolyline())
commandMachine.RegisterCommand("sc", new Command_Scale())

@ -1,8 +1,9 @@
import { Vector3 } from 'three';
import { Matrix4, Vector3 } from 'three';
import { arrayRemoveDuplicateBySort } from '../Common/ArrayExt';
import { Arc } from '../DatabaseServices/Arc';
import { Circle } from '../DatabaseServices/Circle';
import { Curve } from '../DatabaseServices/Curve';
import { Ellipse } from '../DatabaseServices/Ellipse';
import { Line } from '../DatabaseServices/Line';
import { Polyline } from '../DatabaseServices/Polyline';
import { comparePoint, equaln, equalv3 } from '../Geometry/GeUtils';
@ -139,6 +140,12 @@ export function IntersectArcAndArc(arc1: Arc, arc2: Arc, extType: IntersectOptio
return CheckPointOnCurve(pts, arc1, arc2, extType);
}
export function IntersectEllipseAndLine(l: Line, el: Ellipse, extType: IntersectOption)
{
let pts = IntersectLineAndEllipseFor2D(l, el);
return CheckPointOnCurve(pts, l, el, extType);
}
/**
* :线,
*
@ -383,3 +390,177 @@ export function IntersectPolylineAndCurve(pl: Polyline, cu: Curve, extType: Inte
arrayRemoveDuplicateBySort(pts, equalv3);
return pts;
}
export function IntersectLineAndEllipseFor2D(l: Line, el: Ellipse)
{
if (!l.IsCoplaneTo(el)) return [];
let mat = new Matrix4().makeRotationZ(-el.Rotation).multiply(el.OCSInv);
let a = el.RadX;
let b = el.RadY;
let sp = l.StartPoint.applyMatrix4(mat);
let ep = l.EndPoint.applyMatrix4(mat);
let pts: Vector3[] = [];
if (equaln(sp.x, ep.x))
{
let c = sp.x;
let j = (b ** 2) * (1 - (c ** 2) / (a ** 2));
if (equaln(j, 0))
{
pts = [new Vector3(sp.x, 0)];
}
else if (j < 0)
return [];
else
{
let y1 = Math.sqrt(j);
let y2 = -Math.sqrt(j);
pts = [
new Vector3(c, y1),
new Vector3(c, y2)
]
}
}
else
{
let k = (sp.y - ep.y) / (sp.x - ep.x);
let c = sp.y - sp.x * k;
let j = (2 * a * a * k * c) * (2 * a * a * k * c) - 4 * (b * b + a * a * k * k) * a * a * (c * c - b * b);
if (equaln(j, 0))
{
let x1 = -2 * k * c * a * a / (2 * (b * b + a * a * k * k));
let y1 = k * x1 + c;
pts = [new Vector3(x1, y1)];
}
else if (j < 0)
return [];
else
{
let x1 = (-2 * k * c * a * a + Math.sqrt(j)) / (2 * (b * b + a * a * k * k));
let y1 = k * x1 + c;
let x2 = (-2 * k * c * a * a - Math.sqrt(j)) / (2 * (b * b + a * a * k * k));
let y2 = k * x2 + c;
pts = [
new Vector3(x1, y1),
new Vector3(x2, y2)
]
}
}
let matInv = new Matrix4().getInverse(mat);
return pts.map(p => p.applyMatrix4(matInv));
}
export function IntersectEllipseAndCircleOrArc(el: Ellipse, cir: Circle | Arc, type: IntersectOption)
{
if (!el.IsCoplaneTo(cir)) return [];
let a = Math.max(el.RadX, el.RadY);
let dist = el.Center.distanceTo(cir.Center);
let disVail = dist > (a + cir.Radius)
if (disVail)
return [];
if (equalv3(el.Center, cir.Center))
{
let a = el.RadX;
let b = el.RadY;
let r = cir.Radius;
let j = ((a * b) ** 2 - (b * r) ** 2) / (a ** 2 - b ** 2);
let pts: Vector3[] = [];
if (equaln(j, 0) || equaln(j, r ** 2))
{
if (equaln(j, 0))
pts = [
new Vector3(a, 0),
new Vector3(-a, 0)
]
else
pts = [
new Vector3(0, r),
new Vector3(0, -r)
]
}
else if (j < 0)
return [];
else
{
let y1 = Math.sqrt(j);
let y2 = - Math.sqrt(j);
let n = r ** 2 - j;
let x1 = Math.sqrt(n);
let x2 = - Math.sqrt(n);
pts = [
new Vector3(x1, y1),
new Vector3(x1, y2),
new Vector3(x2, y1),
new Vector3(x2, y2),
]
}
let ro = new Matrix4().makeRotationZ(el.Rotation);
pts = pts.map(p => p.applyMatrix4(ro).applyMatrix4(el.OCS));
return CheckPointOnCurve(pts, el, cir, type);
}
else
{
let pts = el.Shape.getPoints(60);
let lineData = pts.map(p =>
{
return { pt: p, bul: 0 }
});
let pl = new Polyline(lineData);
let cirClone = cir.Clone().ApplyMatrix(el.OCSInv);
if (type === IntersectOption.ExtendBoth)
type = IntersectOption.ExtendArg;
else if (type !== IntersectOption.ExtendArg)
type = IntersectOption.OnBothOperands;
let intPts = IntersectPolylineAndCurve(pl, cirClone, type);
return intPts.map(p => p.applyMatrix4(el.OCS));
}
}
export function IntersectEllipse(el1: Ellipse, el2: Ellipse, type: IntersectOption)
{
if (!el1.IsCoplaneTo(el2)) return [];
let isEqul = equalv3(el1.Center, el2.Center)
&& equaln(el1.RadX, el2.RadX)
&& equaln(el1.RadY, el2.RadY)
&& equalv3(el1.StartPoint, el2.StartPoint);
if (isEqul)
return [];
let a1 = Math.max(el1.RadX, el1.RadY);
let a2 = Math.max(el2.RadX, el2.RadY);
let dist = el1.Center.distanceToSquared(el2.Center);
if (dist > (a1 + a2) ** 2)
{
return [];
}
if (!el1.BoundingBox.intersectsBox(el2.BoundingBox))
return [];
let diffMat = el1.OCSInv.multiply(el2.OCS);
let pts1 = el1.Shape.getPoints(60);
let pts2 = el2.Shape.getPoints(60);
let lineData1 = pts1.map(p =>
{
return { pt: p, bul: 0 }
});
let lineData2 = pts2.map(p =>
{
return { pt: p, bul: 0 }
});
let pl1 = new Polyline(lineData1);
let pl2 = new Polyline(lineData2).ApplyMatrix(diffMat);
let intPts = pl1.IntersectWith(pl2, 0);
return intPts.map(p => p.applyMatrix4(el1.OCS));
}

@ -21,7 +21,7 @@ export class EntityModal extends React.Component<{ store?: EntityStore }, {}> {
{
if (e.keyCode === KeyBoard.Escape)
app.m_Editor.m_ModalManage.Clear();
}))
}));
}
componentWillUnmount()
{
@ -45,6 +45,7 @@ export class EntityModal extends React.Component<{ store?: EntityStore }, {}> {
{
options.unshift({ label: "全部" + count.toString(), value: "all" });
}
let ents = this.props.store.GetEntitys();
return (
<div id="entityModal" className={Classes.CARD} >
@ -62,6 +63,18 @@ export class EntityModal extends React.Component<{ store?: EntityStore }, {}> {
<li>
<ColorModal store={this.props.store} />
</li>
{
ents.length > 0 && this.props.store.GetEntitys()[0]['Length'] !== undefined &&
<>
<li>
: {this.props.store.GetEntitys()[0]['Length'].toFixed(2)}
</li>
<li>
: {this.props.store.GetEntitys()[0]['Area'].toFixed(2)}
</li>
</>
}
</ul>
</div >
);

@ -6,6 +6,7 @@ import { Entity } from "../../DatabaseServices/Entity";
import { Line } from "../../DatabaseServices/Line";
import { Polyline } from "../../DatabaseServices/Polyline";
import { Region } from "../../DatabaseServices/Region";
import { Ellipse } from "../../DatabaseServices/Ellipse";
export class EntityStore extends Singleton
{
@ -43,6 +44,8 @@ export class EntityStore extends Singleton
addEnToMap("圆", en);
else if (en instanceof Arc)
addEnToMap("圆弧", en);
else if (en instanceof Ellipse)
addEnToMap("椭圆", en);
else
addEnToMap("三维实体", en);

Loading…
Cancel
Save