优化:重新实现面域算法

pull/912/head
ChenX 5 years ago
parent 13a0a1be8d
commit 6081b35a9e

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

@ -1,240 +1,20 @@
import { Vector3 } from 'three'; import { LoadCurvesFromFileData } from "../Utils/LoadEntity.util";
import { Line } from '../../src/DatabaseServices/Entity/Line'; import { RegionParse } from "../../src/Geometry/RegionParse";
import { LoadCurvesFromFileData } from '../Utils/LoadEntity.util'; import { Polyline } from "../../src/DatabaseServices/Entity/Polyline";
import { RegionParse } from './../../src/Geometry/RegionParse'; import "../Utils/jest.util";
function expectReg(alg: RegionParse) test('面域分析测试', () =>
{ {
let data1 = alg.RegionsInternal.map(o => let cus = LoadCurvesFromFileData(require("./curves.json"));
{
let res = [];
o.forEach(r => { res.push(r.to.position.toArray()); });
return res;
});
let data2 = alg.RegionsOutline.map(o =>
{
let res = [];
o.forEach(r => { res.push(r.to.position.toArray()); });
return res;
});
expect(data1).toMatchSnapshot();
expect(data2).toMatchSnapshot();
}
test('两个相连的区域', () =>
{
let culist = [];
let l1 = new Line(new Vector3(0, 0, 0), new Vector3(5, 5, 0));
let l2 = new Line(new Vector3(0, 0, 0), new Vector3(3, 2, 0));
let l3 = new Line(new Vector3(5, 5, 0), new Vector3(5, 25, 0));
let l4 = new Line(new Vector3(5, 25, 0), new Vector3(0, 0, 0));
let l5 = new Line(new Vector3(3, 2, 0), new Vector3(4, 3, 0));
let l6 = new Line(new Vector3(4, 3, 0), new Vector3(20, 5, 0));
let l7 = new Line(new Vector3(20, 5, 0), new Vector3(3, 2, 0));
culist.push(l1, l2, l3, l4, l5, l6, l7);
let g = new RegionParse(culist);
g.RegionsOutline.length; //?
g.RegionsInternal.length; //?
expect(g.RegionsOutline.length).toBe(2);
expect(g.RegionsInternal.length).toBe(0);
expectReg(g);
});
test('区域内有分割-三角形', () =>
{
let culist = [];
let l1 = new Line(new Vector3(0, 0, 0), new Vector3(5, 0, 0));
let l2 = new Line(new Vector3(5, 0, 0), new Vector3(0, 5, 0));
let l3 = new Line(new Vector3(0, 5, 0), new Vector3(0, 0, 0));
let l4 = new Line(new Vector3(0, 0, 0), new Vector3(0, -5, 0));
let l5 = new Line(new Vector3(5, 0, 0), new Vector3(0, -5, 0));
culist.push(l1, l2, l3, l4, l5);
let g = new RegionParse(culist);
g.RegionsOutline.length; //?
g.RegionsInternal.length; //?
expect(g.RegionsOutline.length).toBe(1);
expect(g.RegionsInternal.length).toBe(2);
expectReg(g);
});
test('区域有延长线', () =>
{
let culist = [];
let l1 = new Line(new Vector3(0, 0, 0), new Vector3(5, 0, 0));
let l2 = new Line(new Vector3(5, 0, 0), new Vector3(0, 5, 0));
let l3 = new Line(new Vector3(0, 5, 0), new Vector3(0, 0, 0));
let l4 = new Line(new Vector3(0, 0, 0), new Vector3(0, -5, 0));
let l5 = new Line(new Vector3(5, 0, 0), new Vector3(0, -5, 0));
let l6 = new Line(new Vector3(5, 0, 0), new Vector3(7, 0, 0));
culist.push(l1, l2, l3, l4, l5, l6);
let g = new RegionParse(culist);
g.RegionsOutline.length; //?
g.RegionsInternal.length; //?
expect(g.RegionsOutline.length).toBe(1);
expect(g.RegionsInternal.length).toBe(2);
expectReg(g);
});
test('区域内多条线', () =>
{
let culist = [];
let l1 = new Line(new Vector3(0, 0, 0), new Vector3(5, 0, 0));
let l2 = new Line(new Vector3(5, 0, 0), new Vector3(0, 5, 0));
let l3 = new Line(new Vector3(0, 4, 0), new Vector3(0, 0, 0)); let reg = new RegionParse(cus);
let l4 = new Line(new Vector3(0, 0, 0), new Vector3(0, -5, 0));
let l5 = new Line(new Vector3(5, 0, 0), new Vector3(0, -5, 0)); expect(reg.RegionsOutline.length).toMatchSnapshot();
let l6 = new Line(new Vector3(0, 4, 0), new Vector3(5, 0, 0)); expect(reg.RegionsInternal.length).toMatchSnapshot();
let l7 = new Line(new Vector3(0, 4, 0), new Vector3(0, 5, 0));
culist.push(l1, l2, l3, l4, l5, l6, l7); for (let routes of [...reg.RegionsOutline, ...reg.RegionsInternal])
{
let g = new RegionParse(culist); let pl = Polyline.Combine(routes.map(r => r.curve), 1e-3);
g.RegionsOutline.length; //? expect(pl.Length).toMatchNumberSnapshot();
g.RegionsInternal.length; //? }
expect(g.RegionsOutline.length).toBe(1);
expect(g.RegionsInternal.length).toBe(3);
expectReg(g);
});
test('包含区域', () =>
{
let culist = [];
let l1 = new Line(new Vector3(0, 0, 0), new Vector3(5, 0, 0));
let l2 = new Line(new Vector3(5, 0, 0), new Vector3(5, 5, 0));
let l3 = new Line(new Vector3(5, 5, 0), new Vector3(0, 5, 0));
let l4 = new Line(new Vector3(0, 5, 0), new Vector3(0, 0, 0));
let l5 = new Line(new Vector3(1, 1, 0), new Vector3(2, 1, 0));
let l6 = new Line(new Vector3(2, 1, 0), new Vector3(2, 2, 0));
let l7 = new Line(new Vector3(2, 2, 0), new Vector3(1, 2, 0));
let l8 = new Line(new Vector3(1, 2, 0), new Vector3(1, 1, 0));
culist.push(l1, l2, l3, l4, l5, l6, l7, l8);
let g = new RegionParse(culist);
g.RegionsOutline.length; //?
g.RegionsInternal.length; //?
expect(g.RegionsOutline.length).toBe(2);
expect(g.RegionsInternal.length).toBe(0);
expectReg(g);
});
test('测试复杂形状', () =>
{
let culist = [
new Line(new Vector3().fromArray([3.9668615984405444, -1.042884990253411, 0]), new Vector3().fromArray([2.553606237816763, -2.3391812865497075, 0])),
new Line(new Vector3().fromArray([2.553606237816763, -2.3391812865497075, 0]), new Vector3().fromArray([4.912280701754386, -2.7777777777777777, 0])),
new Line(new Vector3().fromArray([4.912280701754386, -2.7777777777777777, 0]), new Vector3().fromArray([3.011695906432749, -3.469785575048733, 0])),
new Line(new Vector3().fromArray([3.011695906432749, -3.469785575048733, 0]), new Vector3().fromArray([1.306042884990254, -0.30214424951267027, 0])),
new Line(new Vector3().fromArray([2.348927875243664, -1.042884990253411, 0]), new Vector3().fromArray([2.553606237816763, -2.3391812865497075, 0])),
new Line(new Vector3().fromArray([2.553606237816763, -2.3391812865497075, 0]), new Vector3().fromArray([3.011695906432749, -3.469785575048733, 0])),
new Line(new Vector3().fromArray([3.011695906432749, -3.469785575048733, 0]), new Vector3().fromArray([4.844054580896684, -3.898635477582846, 0])),
new Line(new Vector3().fromArray([4.844054580896684, -3.898635477582846, 0]), new Vector3().fromArray([4.912280701754386, -2.7777777777777777, 0])),
new Line(new Vector3().fromArray([4.912280701754386, -2.7777777777777777, 0]), new Vector3().fromArray([3.9668615984405444, -1.042884990253411, 0])),
new Line(new Vector3().fromArray([2.465886939571151, 1.939571150097466, 0]), new Vector3().fromArray([1.306042884990254, -0.30214424951267027, 0])),
new Line(new Vector3().fromArray([1.306042884990254, -0.30214424951267027, 0]), new Vector3().fromArray([3.586744639376219, 0.253411306042885, 0])),
new Line(new Vector3().fromArray([3.586744639376219, 0.253411306042885, 0]), new Vector3().fromArray([2.348927875243664, -1.042884990253411, 0])),
new Line(new Vector3().fromArray([2.348927875243664, -1.042884990253411, 0]), new Vector3().fromArray([3.9668615984405444, -1.042884990253411, 0])),
new Line(new Vector3().fromArray([1.306042884990254, -0.30214424951267027, 0]), new Vector3().fromArray([2.348927875243664, -1.042884990253411, 0])),
new Line(new Vector3().fromArray([3.9668615984405444, -1.042884990253411, 0]), new Vector3().fromArray([3.586744639376219, 0.253411306042885, 0])),
new Line(new Vector3().fromArray([3.586744639376219, 0.253411306042885, 0]), new Vector3().fromArray([2.465886939571151, 1.939571150097466, 0])),
];
let g = new RegionParse(culist);
g.RegionsOutline.length; //?
g.RegionsInternal.length; //?
expect(g.RegionsOutline.length).toBe(1);
expect(g.RegionsInternal.length).toBe(8);
expectReg(g);
});
test('矩形套矩形', () =>
{
let culist = [
new Line(new Vector3().fromArray([12.781615108958839, -0.7407480871670697, 0]), new Vector3().fromArray([12.781615108958837, -5.947836900726392, 0])),
new Line(new Vector3().fromArray([12.781615108958837, -5.947836900726392, 0]), new Vector3().fromArray([19.5123215496368, -5.947836900726394, 0])),
new Line(new Vector3().fromArray([19.5123215496368, -5.947836900726394, 0]), new Vector3().fromArray([19.5123215496368, -0.7407480871670714, 0])),
new Line(new Vector3().fromArray([19.5123215496368, -0.7407480871670714, 0]), new Vector3().fromArray([12.781615108958839, -0.7407480871670697, 0])),
new Line(new Vector3().fromArray([12.781615108958839, -0.7407480871670697, 0]), new Vector3().fromArray([14.054086973365617, -2.0467060532687644, 0])),
new Line(new Vector3().fromArray([14.054086973365617, -2.0467060532687644, 0]), new Vector3().fromArray([18.54122460048426, -2.0467060532687653, 0])),
new Line(new Vector3().fromArray([18.54122460048426, -2.0467060532687653, 0]), new Vector3().fromArray([18.54122460048426, -5.026969104116222, 0])),
new Line(new Vector3().fromArray([18.54122460048426, -5.026969104116222, 0]), new Vector3().fromArray([14.054086973365617, -5.026969104116221, 0])),
new Line(new Vector3().fromArray([14.054086973365617, -5.026969104116221, 0]), new Vector3().fromArray([14.054086973365617, -2.0467060532687644, 0])),
new Line(new Vector3().fromArray([18.54122460048426, -5.026969104116222, 0]), new Vector3().fromArray([19.5123215496368, -5.947836900726394, 0])),
new Line(new Vector3().fromArray([14.054086973365617, -2.0467060532687644, 0]), new Vector3().fromArray([18.54122460048426, -5.026969104116222, 0]))
];
let g = new RegionParse(culist);
g.RegionsOutline.length; //?
g.RegionsInternal.length; //?
expect(g.RegionsOutline.length).toBe(1);
expect(g.RegionsInternal.length).toBe(4);
expectReg(g);
});
test('保护伞', () =>
{
let culist = [
new Line(new Vector3().fromArray([-2.0843672456575684, 1.9106699751861045, 0]), new Vector3().fromArray([-4.01985111662531, -0.7196029776674939, 0])),
new Line(new Vector3().fromArray([-4.01985111662531, -0.7196029776674939, 0]), new Vector3().fromArray([-1.4640198511166256, -0.7196029776674939, 0])),
new Line(new Vector3().fromArray([-1.4640198511166256, -0.7196029776674939, 0]), new Vector3().fromArray([-2.0843672456575684, 1.9106699751861045, 0])),
new Line(new Vector3().fromArray([-2.0843672456575684, 1.9106699751861045, 0]), new Vector3().fromArray([-4.156327543424318, 2.7171215880893302, 0])),
new Line(new Vector3().fromArray([-4.156327543424318, 2.7171215880893302, 0]), new Vector3().fromArray([-1.7121588089330027, 4.094292803970223, 0])),
new Line(new Vector3().fromArray([-1.7121588089330027, 4.094292803970223, 0]), new Vector3().fromArray([-2.0843672456575684, 1.9106699751861045, 0])),
new Line(new Vector3().fromArray([-2.0843672456575684, 1.9106699751861045, 0]), new Vector3().fromArray([-0.33498759305210907, 2.7543424317617866, 0])),
new Line(new Vector3().fromArray([-0.33498759305210907, 2.7543424317617866, 0]), new Vector3().fromArray([-0.33498759305210946, 0.5583126550868487, 0])),
new Line(new Vector3().fromArray([-0.33498759305210946, 0.5583126550868487, 0]), new Vector3().fromArray([-2.0843672456575684, 1.9106699751861045, 0])),
];
let g = new RegionParse(culist);
g.RegionsOutline.length; //?
g.RegionsInternal.length; //?
expect(g.RegionsOutline.length).toBe(3);
expect(g.RegionsInternal.length).toBe(0);
expectReg(g);
});
test('带圆弧的复杂图形测试', () =>
{
let cus = LoadCurvesFromFileData(
[23, "Line", 1, 1, -1, false, 0, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 1, [135.10332884629918, 7.41153204925861, 0], [141.2013396407662, -3.6141642356868466, 0], "Line", 1, 1, -1, false, 1, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 1, [141.2013396407662, -3.6141642356868466, 0], [129.0669141204631, -3.614164235686845, 0], "Line", 1, 1, -1, false, 2, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 1, [129.0669141204631, -3.614164235686845, 0], [118.90356279635137, 9.936970863128803, 0], "Line", 1, 1, -1, false, 3, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 1, [118.90356279635137, 9.936970863128803, 0], [129.25170232635605, 16.219769863488786, 0], "Line", 1, 1, -1, false, 4, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 1, [129.25170232635605, 16.219769863488786, 0], [131.77714114022623, 24.28885485414719, 0], "Line", 1, 1, -1, false, 5, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 1, [131.77714114022623, 24.28885485414719, 0], [121.09714288582433, 18.21968481731883, 0], "Line", 1, 1, -1, false, 6, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 1, [121.09714288582433, 18.21968481731883, 0], [115.57737509027845, 20.531494667657398, 0], "Line", 1, 1, -1, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 1, [115.57737509027845, 20.531494667657398, 0], [118.90356279635137, 9.936970863128803, 0], "Line", 1, 1, -1, false, 0, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 1, [129.25170232635605, 16.219769863488786, 0], [135.10332884629918, 7.41153204925861, 0], "Line", 1, 1, -1, false, 1, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 1, [135.10332884629918, 7.41153204925861, 0], [141.07814750350425, 7.411532049258609, 0], "Line", 1, 1, -1, false, 2, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 1, [141.07814750350425, 7.411532049258609, 0], [150.9951145530921, 6.9187635002107655, 0], "Line", 1, 1, -1, false, 3, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 1, [150.9951145530921, 6.9187635002107655, 0], [146.62179368029246, 22.625761001110725, 0], "Line", 1, 1, -1, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 1, [115.57737509027845, 20.531494667657398, 0], [122.16815443379333, 33.2818808742703, 0], "Line", 1, 1, -1, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 1, [122.16815443379333, 33.2818808742703, 0], [131.77714114022623, 24.28885485414719, 0], "Line", 1, 1, -1, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 1, [131.77714114022623, 24.28885485414719, 0], [140.3389946799325, 29.339732481887566, 0], "Line", 1, 1, -1, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 1, [140.3389946799325, 29.339732481887566, 0], [146.62179368029246, 22.625761001110725, 0], "Arc", 1, 1, -1, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 151.10541370131332, 26.821442121699068, 0, 1], 2, 6.14056907448819, 3.8938276244846772, 6.018122149019185, false, "Arc", 1, 1, -1, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 161.1393080144557, 24.097737845466003, 0, 1], 2, 4.256430496141867, 2.8765294954293896, 5.103001249079749, true, "Arc", 1, 1, -1, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 164.0426698023552, 17.04682100167833, 0, 1], 2, 3.368852318904628, 1.9614085954899536, 5.109952481560101, false, "Arc", 1, 1, -1, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 168.0577082733428, 7.485478534075631, 0, 1], 2, 7.001287685275334, 1.9683598279703076, 3.2491377039705007, true, "Arc", 1, 1, -1, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 156.0343039466818, 6.18741259702873, 0, 1], 2, 5.091984278064126, 0.10754505038070734, 2.997466317295445, false, "Arc", 1, 1, -1, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 146.05997836303806, 7.635012886374687, 0, 1], 2, 4.986840923627034, 6.139058970885238, 3.1864217771069283, true, "Arc", 1, 1, -1, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 138.09073817490173, 7.277519322534491, 0, 1], 2, 2.9904136682983347, 0.04482912351713572, 3.0967635300726575, false]
);
let g = new RegionParse(cus);
expect(g.RegionsInternal.length).toBe(7);
expect(g.RegionsOutline.length).toBe(1);
}); });

@ -11,7 +11,7 @@
"build": "webpack --config ./config/webpack.prod.ts && ts-node ./utils/log.ts && ts-node ./utils/publish.ts", "build": "webpack --config ./config/webpack.prod.ts && ts-node ./utils/log.ts && ts-node ./utils/publish.ts",
"test": "jest", "test": "jest",
"testu": "jest -u", "testu": "jest -u",
"testw": "jest --watch", "testw": "jest --watchAll",
"ser": "node ./utils/server.js", "ser": "node ./utils/server.js",
"type": "ts-node ./utils/copy_type.ts", "type": "ts-node ./utils/copy_type.ts",
"publish": "ts-node ./utils/publish.ts" "publish": "ts-node ./utils/publish.ts"

@ -7,7 +7,8 @@ import { Region } from '../DatabaseServices/Entity/Region';
import { Spline } from '../DatabaseServices/Spline'; import { Spline } from '../DatabaseServices/Spline';
import { Command } from '../Editor/CommandMachine'; import { Command } from '../Editor/CommandMachine';
import { PromptStatus } from '../Editor/PromptResult'; import { PromptStatus } from '../Editor/PromptResult';
import { RegionParse, Route } from '../Geometry/RegionParse'; import { Route } from '../Geometry/CurveMap';
import { RegionParse } from '../Geometry/RegionParse';
export class DrawRegion implements Command export class DrawRegion implements Command
{ {
@ -79,11 +80,9 @@ export class DrawRegion implements Command
} }
} }
} }
DrawRegion(routeS: Set<Route>) DrawRegion(routeS: Array<Route>)
{ {
let cus: Curve[] = []; let cus: Curve[] = routeS.map(r => r.curve);
for (let r of routeS)
cus.push(r.curve);
let reg = Region.CreateFromCurves(cus); let reg = Region.CreateFromCurves(cus);
if (reg) if (reg)
{ {

@ -6,7 +6,8 @@ import { Line } from '../DatabaseServices/Entity/Line';
import { Region } from '../DatabaseServices/Entity/Region'; import { Region } from '../DatabaseServices/Entity/Region';
import { Command } from '../Editor/CommandMachine'; import { Command } from '../Editor/CommandMachine';
import { MoveMatrix } from '../Geometry/GeUtils'; import { MoveMatrix } from '../Geometry/GeUtils';
import { RegionParse, Route } from '../Geometry/RegionParse'; import { RegionParse } from '../Geometry/RegionParse';
import { Route } from '../Geometry/CurveMap';
export class DrawRegTest implements Command export class DrawRegTest implements Command
{ {
@ -203,10 +204,9 @@ export class DrawRegTest implements Command
// } // }
} }
} }
function createReg(r: Set<Route>) function createReg(routes: Array<Route>)
{ {
let cus: Curve[] = []; let cus: Curve[] = routes.map(r => r.curve);
r.forEach(route => cus.push(route.curve.Clone() as Curve));
let re = Region.CreateFromCurves(cus); let re = Region.CreateFromCurves(cus);
app.Database.ModelSpace.Append(re); app.Database.ModelSpace.Append(re);
} }

@ -4,9 +4,10 @@ import { app } from "../ApplicationServices/Application";
import { Vector3, Object3D } from "three"; import { Vector3, Object3D } from "three";
import { Board } from "../DatabaseServices/Entity/Board"; import { Board } from "../DatabaseServices/Entity/Board";
import { PromptStatus } from "../Editor/PromptResult"; import { PromptStatus } from "../Editor/PromptResult";
import { Entity } from "../DatabaseServices/Entity/Entity";
const MOVEDIS = 10; const MOVEDIS = 10;
const MOVECOUNT = 70; const MOVECOUNT = 300;
const STOPCOUNT = MOVECOUNT * 2 + 1; const STOPCOUNT = MOVECOUNT * 2 + 1;
export class Command_ExplosionMap implements Command export class Command_ExplosionMap implements Command
@ -35,7 +36,7 @@ export class Command_ExplosionMap implements Command
UseSelect: true, UseSelect: true,
Msg: "请选择需要展示爆炸图的板件", Msg: "请选择需要展示爆炸图的板件",
Filter: { Filter: {
filterTypes: [Board], filterTypes: [Entity],
}, },
AllowNone: false, AllowNone: false,
}); });
@ -46,7 +47,7 @@ export class Command_ExplosionMap implements Command
let cen = box.getCenter(new Vector3()); let cen = box.getCenter(new Vector3());
for (let obj of brs.SelectSet.SelectObjectList) for (let obj of brs.SelectSet.SelectObjectList)
{ {
if (obj.userData && obj.userData.Entity instanceof Board) if (obj.userData && obj.userData.Entity)
{ {
let objCen = GetBox(obj).getCenter(new Vector3()); let objCen = GetBox(obj).getCenter(new Vector3());
let v = objCen.clone().sub(cen); let v = objCen.clone().sub(cen);

@ -7,11 +7,10 @@ import { Line } from '../DatabaseServices/Entity/Line';
import { Polyline } from '../DatabaseServices/Entity/Polyline'; import { Polyline } from '../DatabaseServices/Entity/Polyline';
import { IsPointInBowArc } from '../DatabaseServices/PointInPolyline'; import { IsPointInBowArc } from '../DatabaseServices/PointInPolyline';
import { Count } from '../Geometry/Count'; import { Count } from '../Geometry/Count';
import { CurveMap } from '../Geometry/CurveMap'; import { CurveMap, Vertice } from '../Geometry/CurveMap';
import { AsVector2, AsVector3, equaln, equalv2, equalv3, isParallelTo, ZeroVec } from '../Geometry/GeUtils'; import { AsVector2, AsVector3, equaln, equalv2, equalv3, isParallelTo, ZeroVec } from '../Geometry/GeUtils';
import { Orbit } from '../Geometry/Orbit'; import { Orbit } from '../Geometry/Orbit';
import { PlaneExt } from '../Geometry/Plane'; import { PlaneExt } from '../Geometry/Plane';
import { Stand } from '../Geometry/RegionParse';
import { IntersectOption, IntersectResult } from '../GraphicsSystem/IntersectWith'; import { IntersectOption, IntersectResult } from '../GraphicsSystem/IntersectWith';
import { OffsetPolyline } from '../GraphicsSystem/OffsetPolyline'; import { OffsetPolyline } from '../GraphicsSystem/OffsetPolyline';
import { arrayLast, changeArrayStartIndex, equalArray } from './ArrayExt'; import { arrayLast, changeArrayStartIndex, equalArray } from './ArrayExt';
@ -115,12 +114,11 @@ export function curveLinkGroup(cus: Curve[]): Array<Array<Curve>>
/** /**
* 线,线. * 线,线.
* *
* @param {Stand} stand
* @param {Curve[]} cus 线 * @param {Curve[]} cus 线
* @param {boolean} isEndSeach true:,false: * @param {boolean} isEndSeach true:,false:
* @returns {Stand} 线,,undefined * @returns {Stand} 线,,undefined
*/ */
function linkCurve(stand: Stand, cus: Curve[], isEndSeach: boolean): Stand | undefined function linkCurve(stand: Vertice, cus: Curve[], isEndSeach: boolean): Vertice | undefined
{ {
for (let route of stand.routes) for (let route of stand.routes)
{ {

@ -3,8 +3,9 @@ import { arrayLast, arrayRemoveDuplicateBySort } from "../Common/ArrayExt";
import { curveLinkGroup, equalCurve } from "../Common/CurveUtils"; import { curveLinkGroup, equalCurve } from "../Common/CurveUtils";
import { Status } from "../Common/Status"; import { Status } from "../Common/Status";
import { FixIndex } from "../Common/Utils"; import { FixIndex } from "../Common/Utils";
import { Route } from "../Geometry/CurveMap";
import { equaln, equalv3 } from "../Geometry/GeUtils"; import { equaln, equalv3 } from "../Geometry/GeUtils";
import { RegionParse, Route } from "../Geometry/RegionParse"; import { RegionParse } from "../Geometry/RegionParse";
import { isTargetCurInOrOnSourceCur } from "../GraphicsSystem/BoolOperateUtils"; import { isTargetCurInOrOnSourceCur } from "../GraphicsSystem/BoolOperateUtils";
import { IntersectOption } from "../GraphicsSystem/IntersectWith"; import { IntersectOption } from "../GraphicsSystem/IntersectWith";
import { Arc } from "./Entity/Arc"; import { Arc } from "./Entity/Arc";
@ -162,13 +163,11 @@ export class Contour
let contours: Contour[] = []; let contours: Contour[] = [];
//分析封闭包围区域 //分析封闭包围区域
const parseRoute = (routeSet: Set<Route>[]) => const parseRoute = (routeSet: Array<Route>[]) =>
{ {
for (let routes of routeSet) for (let routes of routeSet)
{ {
let cs: Curve[] = []; let cs: Curve[] = routes.map(r => r.curve);
for (let r of routes)
cs.push(r.curve);
let c = Contour.CreateContour(cs, false); let c = Contour.CreateContour(cs, false);
if (c if (c
&& !equalCurve(c.Curve, this.Curve) && !equalCurve(c.Curve, this.Curve)
@ -270,7 +269,7 @@ export class Contour
} }
return { intersectionList, unionList }; return { intersectionList, unionList };
} }
GetSubtractList(target: Contour) GetSubtractList(target: Contour): Polyline[]
{ {
let sourceOutline = this._Curve as Polyline; let sourceOutline = this._Curve as Polyline;
let targetOutline = target.Curve as Polyline; let targetOutline = target.Curve as Polyline;
@ -292,32 +291,29 @@ export class Contour
} }
//相交 //相交
let subtractList: Curve[] = []; let subtractList: Polyline[] = [];
let sourceCus = sourceOutline.GetSplitCurves(interPts.map(r => r.thisParam)) as Polyline[]; let sourceCus = sourceOutline.GetSplitCurves(interPts.map(r => r.thisParam)) as Polyline[];
let targetCus = targetOutline.GetSplitCurves(interPts.map(r => r.argParam)) as Polyline[]; let targetCus = targetOutline.GetSplitCurves(interPts.map(r => r.argParam)) as Polyline[];
for (let pl of sourceCus) for (let pl of sourceCus)
{ {
let hasEqualCus = false; let plMidParam = pl.MidParam;
for (let i = 0; i < targetCus.length; i++) let plDir = pl.GetFistDeriv(plMidParam).normalize();
{
let cu = targetCus[i]; let index = targetCus.findIndex(cu => fastEqualCurve(cu, pl));
hasEqualCus = fastEqualCurve(cu, pl); if (index !== -1)
if (hasEqualCus &&
(!equalv3(cu.GetFistDeriv(cu.EndParam * 0.5).normalize(), pl.GetFistDeriv(pl.EndParam * 0.5).normalize(), 1e-3))
=== isEqualNormal)
{ {
let cu = targetCus[index];
let cuMidParam = cu.MidParam;
let cuDir = cu.GetFistDeriv(cuMidParam).normalize();
if (isEqualNormal === !equalv3(cuDir, plDir, 1e-3))//不同向
subtractList.push(pl); subtractList.push(pl);
targetCus.splice(i, 1);
}
if (hasEqualCus) targetCus.splice(index, 1);
break;
}
if (hasEqualCus)
continue; continue;
}
if (!fastCurveInCurve(targetOutline, pl)) if (!fastCurveInCurve(targetOutline, pl))
subtractList.push(pl); subtractList.push(pl);
} }

@ -52,7 +52,19 @@ export abstract class Curve extends Entity
set EndPoint(v: Vector3) { return; } set EndPoint(v: Vector3) { return; }
/** 曲线中点 */ /** 曲线中点 */
get Midpoint() { return this.GetPointAtParam(0.5); } get Midpoint()
{
return this.GetPointAtParam(this.MidParam);
}
get MidParam()
{
if (this.EndParam === 1)
return 0.5;
else
return this.GetParamAtDist(this.Length * 0.5);
}
get EndParam(): number { return; } get EndParam(): number { return; }
get Area(): number { return 0; } get Area(): number { return 0; }
/** /**

@ -350,13 +350,6 @@ export class Polyline extends Curve
this.SetPointAt(this.EndParam, AsVector2(p)); this.SetPointAt(this.EndParam, AsVector2(p));
} }
get Midpoint()
{
if (this.EndParam === 1)
return this.GetPointAtParam(0.5);
return this.GetPointAtDistance(this.Length * 0.5);
}
get CurveCount(): number get CurveCount(): number
{ {
return this.EndParam; return this.EndParam;
@ -420,7 +413,7 @@ export class Polyline extends Curve
//曲线是否闭合 //曲线是否闭合
get IsClose(): boolean get IsClose(): boolean
{ {
return this.CloseMark || (equalv3(this.StartPoint, this.EndPoint, 1e-4)) && this.EndParam > 1; return this.CloseMark || (this.EndParam > 1 && (equalv3(this.StartPoint, this.EndPoint, 1e-4)));
} }
set CloseMark(v: boolean) set CloseMark(v: boolean)
{ {

@ -1,94 +1,152 @@
import { Vector3 } from "three"; import { Vector3 } from "three";
import { ToFixed } from "../Common/Utils"; import { Arc } from "../DatabaseServices/Entity/Arc";
import { Curve } from "../DatabaseServices/Entity/Curve"; import { Curve } from "../DatabaseServices/Entity/Curve";
import { angle, equalv3 } from "./GeUtils"; import { angle, clampRad, equalv3 } from "./GeUtils";
import { Route, Stand } from "./RegionParse";
//顶点
export interface Vertice
{
//位置
position: Vector3;
//路径
routes: Route[];
}
//路线
export interface Route
{
curve: Curve; //路线的曲线
from: Vertice;
to: Vertice; //终点的点
length: number;
isReverse: boolean;
an?: number; //角度
s: Vector3;
e: Vector3;
}
/** /**
* 线,使. * 线,使.
*/ */
export class CurveMap export class CurveMap
{ {
constructor(public fractionDigits = 4) constructor(
{ public numdimensions = 4,
public _RemoveSortLine = false,
} private multiplier = 10 ^ numdimensions,
) { }
/* /*
. .
线. 线.
使,使x. 使,使x.
*/ */
m_NodeMap = new Map<Vector3, Stand>(); _NodeMap = new Map<Vector3, Vertice>();
/** /**
* *
* @type {Stand[]}
*/ */
get Stands(): Stand[] get Stands(): Vertice[]
{ {
let stands = []; let stands: Vertice[] = [];
this.m_NodeMap.forEach(s => stands.push(s)); this._NodeMap.forEach(s => stands.push(s));
return stands; return stands;
} }
AddCurveToMap(cu: Curve) AddCurveToMap(curve: Curve, isArc: boolean = curve instanceof Arc, removeDuplicate: boolean = false)
{ {
cu.TempData = 0; let sp = curve.StartPoint;
let sp = cu.StartPoint; let ep = curve.EndPoint;
let ep = cu.EndPoint;
let startS = this.GetStand(sp); let startS = this.GetStand(sp);
let endS = this.GetStand(ep); let endS = this.GetStand(ep);
let routeS2E: Route = { curve: cu, to: endS, s: sp, e: ep };
CalcRouteAngle(routeS2E, startS.position); //在面域分析中,路线指向同一个顶点已经没有意义了
let routeE2S: Route = { curve: cu, to: startS, s: ep, e: sp }; if (this._RemoveSortLine && startS === endS)
CalcRouteAngle(routeE2S, endS.position); return;
if (removeDuplicate)//删除重复
{
let index = startS.routes.findIndex(r =>
{
if (r.to === endS && r.curve.constructor.name === curve.constructor.name)
{
if (isArc)
return equalv3(curve.GetPointAtParam(0.5), r.curve.GetPointAtParam(0.5));
return true;
}
});
if (index !== -1) return;
}
let length = curve.Length;
curve.TempData = 0;
let routeS2E: Route = { curve, isReverse: false, length, from: startS, to: endS, s: sp, e: ep };
let routeE2S: Route = { curve, isReverse: true, length, from: endS, to: startS, e: sp, s: ep };
if (!isArc)
{
let an = angle(ep.clone().sub(sp));
routeS2E.an = an;
routeE2S.an = clampRad(an + Math.PI);
}
startS.routes.push(routeS2E); startS.routes.push(routeS2E);
endS.routes.push(routeE2S); endS.routes.push(routeE2S);
} }
/** /**
* . *
*
* @private
* @param {Vector3} p
* @returns {Stand}
* @memberof RegionAlg
*/ */
GetStand(p: Vector3): Stand GetStand(p: Vector3): Vertice
{ {
let gp = this.GenerateP(p); let gp = this.GenerateP(p);
if (this.m_NodeMap.has(gp)) if (this._NodeMap.has(gp))
return this.m_NodeMap.get(gp); return this._NodeMap.get(gp);
let stand = { position: gp, routes: [] }; let stand = { position: gp, routes: [] };
this.m_NodeMap.set(p, stand); this._NodeMap.set(p, stand);
return stand; return stand;
} }
private m_vecMap = new Map<string, Vector3>(); _LookupTable: { [key: string]: Vector3; } = {};
/** /**
* . * .
*
* @param {Vector3} v
* @returns {Vector3}
* @memberof RegionAlg
*/ */
private GenerateP(v: Vector3): Vector3 GenerateP(v: Vector3): Vector3
{ {
let str = v.toArray().map(v => ToFixed(v, this.fractionDigits)).join(","); let key = "";
if (this.m_vecMap.has(str)) let els = v.toArray();
return this.m_vecMap.get(str); for (let n of els)
this.m_vecMap.set(str, v); {
return v; let valueQuantized = Math.round(n * this.multiplier);
key += valueQuantized + '/';
} }
}
function CalcRouteAngle(r: Route, standPoint: Vector3) if (key in this._LookupTable)
{ return this._LookupTable[key];
if (equalv3(r.curve.StartPoint, standPoint))
r.an = angle(r.curve.GetFistDeriv(0)); let hashparts = els.map((el) =>
else {
r.an = angle(r.curve.GetFistDeriv(r.curve.EndParam).negate()); let q0 = Math.floor(el * this.multiplier);
let q1 = q0 + 1;
return ['' + q0 + '/', '' + q1 + '/'];
});
let numelements = els.length;
let numhashes = 1 << numelements;
for (let hashmask = 0; hashmask < numhashes; ++hashmask)
{
let hashmaskShifted = hashmask;
key = '';
hashparts.forEach(function (hashpart)
{
key += hashpart[hashmaskShifted & 1];
hashmaskShifted >>= 1;
});
this._LookupTable[key] = v;
}
return v;
}
} }

@ -1,34 +1,14 @@
import { Vector3 } from 'three'; import { Vector3 } from "three";
import { arrayRemoveDuplicateBySort, arrayRemoveIf } from '../Common/ArrayExt'; import { arrayLast, arrayRemove, arrayRemoveIf } from "../Common/ArrayExt";
import { Arc } from '../DatabaseServices/Entity/Arc'; import { Arc } from "../DatabaseServices/Entity/Arc";
import { Curve } from '../DatabaseServices/Entity/Curve'; import { Curve } from "../DatabaseServices/Entity/Curve";
import { Polyline } from '../DatabaseServices/Entity/Polyline'; import { Polyline } from "../DatabaseServices/Entity/Polyline";
import { equaln } from '../Nest/Util'; import { FixIndex } from "../Nest/Util";
import { CurveMap } from './CurveMap'; import { CurveMap, Route, Vertice } from "./CurveMap";
import { equalv3 } from './GeUtils'; import { angle } from "./GeUtils";
//路线
export interface Route
{
curve: Curve; //路线的曲线
to: Stand; //终点的点
s: Vector3;
e: Vector3;
an?: number;
}
//站台
export interface Stand
{
//位置
position: Vector3;
//路径
routes: Array<Route>;
}
//区域的路线表 表示了一个区域 //区域的路线表 表示了一个区域
type RegionRouteS = Array<Set<Route>>; type RegionRouteS = Route[][];
//区域搜索算法 //区域搜索算法
export class RegionParse export class RegionParse
@ -41,152 +21,126 @@ export class RegionParse
//碎线 曲线进入到这里会被炸开. //碎线 曲线进入到这里会被炸开.
ExpLineMap: Map<Curve, Curve[]> = new Map(); ExpLineMap: Map<Curve, Curve[]> = new Map();
private _CurveCount: number;
/** /**
* @param {Curve[]} cuList . * @param {Curve[]} cuList .
*/ */
constructor(cuList: Curve[], public fractionDigits = 3) constructor(cuList: Curve[], public numDimensions = 3, private removeDuplicate = true)
{ {
//需要搜索的站 //需要搜索的站
let needFinds = this.GenerateNodeMap(cuList); let vertices = this.GenerateNodeMap(cuList);
//搜索大轮廓. //移除细丝
while (needFinds.size > 0) while (true)
{ {
//找到最小的站. let v = vertices.find(v => v.routes.length < 2);
let lowerLeftStand = this.FindLowerLeftStand(needFinds); if (v) vertices = this.RemoveFilamentAt(v, vertices);
needFinds.delete(lowerLeftStand); else break;
//逆时针+逆时针
for (let i = lowerLeftStand.routes.length; i--;)
{
let wayS = new Set<Stand>();
let routeS = new Set<Route>();
let isFind = this.FindRegion(lowerLeftStand, lowerLeftStand, undefined, wayS, routeS, 1);
if (isFind)
{
this.RegionsOutline.push(routeS);
//计数增加
for (let route of routeS)
route.curve.TempData += 1;
this.FindInternalRegion(wayS);
}
}
}
} }
let lowerVertice: Vertice;
while (vertices.length > 0)
{
lowerVertice = lowerVertice?.routes.length > 1 ? lowerVertice : this.FindLowerLeftStand(vertices);
let minWalk = ClosedWalkFrom(lowerVertice, this._CurveCount, WalkType.Min);
let maxWalk = ClosedWalkFrom(lowerVertice, this._CurveCount, WalkType.Max);
/** this.RemoveEdge(minWalk[0]);
* 线使 vertices = this.RemoveFilamentAt(minWalk[0].from, vertices);
* @param cu vertices = this.RemoveFilamentAt(minWalk[0].to, vertices);
* @returns true if cueve used
*/ minWalk = ReduceWalk(minWalk);
GetCueveUsed(cu: Curve): boolean maxWalk = ReduceWalk(maxWalk);
if (maxWalk.length > 1)
{ {
if (this.ExpLineMap.has(cu)) this.RegionsOutline.push(maxWalk);
if (minWalk.length === maxWalk.length && minWalk.every((w1, index) => w1 === maxWalk[index]))//大小重叠
{ {
let use = this.ExpLineMap.get(cu).some(c => c.TempData > 0); //直接remove,不用计算引用个数
if (!use) for (let w of minWalk)
this.ExpLineMap.delete(cu); {
return use; this.RemoveEdge(w);
this.RemoveFilamentAt(w.from, vertices);
this.RemoveFilamentAt(w.to, vertices);
}
continue;//继续循环
} }
else else
return cu.TempData > 0; for (let w of maxWalk)
w.curve.TempData = 1;
} }
/** if (minWalk.length > 1)// && minWalk.every(w => <number>(w.curve.TempData) < 2) 没有重复线应该不会被用2次
* 使,,.
* .
* @param {Set<Stand>} standS
*/
FindInternalRegion(standS: Set<Stand>)
{ {
//需要搜索的. this.RegionsInternal.push(minWalk);
let needFinds = new Set<Stand>(); for (let w of minWalk)
standS.forEach(w => needFinds.add(w));
//已经走过的
let passingStands = new Set<Stand>();
let regs: RegionRouteS = [];
while (needFinds.size > 0)
{ {
//找到最下方最左边的站点yx w.curve.TempData++;
let lowerLeftStand = this.FindLowerLeftStand(needFinds); if (w.curve.TempData === 2)
//添加为已经计算
passingStands.add(lowerLeftStand);
needFinds.delete(lowerLeftStand);
//顺时针搜索
for (let j = lowerLeftStand.routes.length; j--;)
{ {
let route = lowerLeftStand.routes[j]; this.RemoveEdge(w);
this.RemoveFilamentAt(w.from, vertices);
if (!needFinds.has(route.to)) this.RemoveFilamentAt(w.to, vertices);
continue; }
}
if (route.curve.TempData === 2) }
continue; }
}
let wayS = new Set<Stand>();
let routeS = new Set<Route>();
routeS.add(route);
wayS.add(route.to);
let isFindMin = this.FindRegion(lowerLeftStand, route.to, route.curve, wayS, routeS, 2); RemoveFilamentAt(v: Vertice, vertices: Vertice[])
if (isFindMin)
{ {
regs.push(routeS); let current = v;
while (current && current.routes.length < 2)
wayS.forEach(w =>
{ {
//站点拓展,如果该地点没有被走过,那么加入到需要搜寻的站点表 vertices = arrayRemove(vertices, current);
if (!passingStands.has(w)) let r = current.routes[0];
needFinds.add(w); if (r)
}); {
this.RemoveEdge(r);
for (let route of routeS) current = r.to;
route.curve.TempData += 1;
} }
else
current = undefined;
} }
return vertices;
} }
if (regs.length > 1) RemoveEdge(r: Route)
this.RegionsInternal.push(...regs); {
let index = r.from.routes.findIndex(rr => rr.curve === r.curve);
if (index !== -1)
r.from.routes.splice(index, 1);
index = r.to.routes.findIndex(rr => rr.curve === r.curve);
if (index !== -1)
r.to.routes.splice(index, 1);
} }
/** /**
* yx * yx
* @param {Set<Stand>} standS
*/ */
private FindLowerLeftStand(standS: Set<Stand>): Stand private FindLowerLeftStand(vertices: Vertice[]): Vertice
{ {
let minStand: Stand; return vertices.reduce((m, v) =>
for (let stand of standS)
{ {
if (!minStand) let dy = v.position.y - m.position.y;
{ if (dy < 0) return v;
minStand = stand; if (dy > 0) return m;
continue; return v.position.x - m.position.x < 0 ? v : m;
} });
if (minStand.position.y > stand.position.y)
minStand = stand;
else if (minStand.position.y === stand.position.y && minStand.position.x > stand.position.x)
minStand = stand;
}
return minStand;
} }
/** /**
* 线. 线. 使,使x. * 线. 线. 使,使x.
* @param {Curve[]} cuList * @returns
* @returns {Set<Stand>}
*/ */
private GenerateNodeMap(cuList: Curve[]): Set<Stand> private GenerateNodeMap(curveList: Curve[]): Array<Vertice>
{ {
let curveMap = new CurveMap(this.fractionDigits); let curveMap = new CurveMap(this.numDimensions, true);
//将多段线炸开 //将多段线炸开
let plcus: Curve[] = []; let plcus: Curve[] = [];
arrayRemoveIf(cuList, c => arrayRemoveIf(curveList, c =>
{ {
if (c instanceof Polyline) if (c instanceof Polyline)
{ {
@ -216,9 +170,11 @@ export class RegionParse
} }
return false; return false;
}); });
cuList.push(...plcus); curveList.push(...plcus);
for (let cu of cuList) this._CurveCount = curveList.length;
for (let cu of curveList)
{ {
//由于圆弧可能导致最低点计算错误的问题. //由于圆弧可能导致最低点计算错误的问题.
if (cu instanceof Arc) if (cu instanceof Arc)
@ -226,36 +182,35 @@ export class RegionParse
let arcs = this.BreakArc(cu); let arcs = this.BreakArc(cu);
if (arcs.length > 1) if (arcs.length > 1)
{ {
arcs.forEach(a => curveMap.AddCurveToMap(a)); arcs.forEach(a => curveMap.AddCurveToMap(a, true, this.removeDuplicate));
this.ExpLineMap.set(cu, arcs); this.ExpLineMap.set(cu, arcs);
continue; continue;
} }
else
curveMap.AddCurveToMap(cu, true, this.removeDuplicate);
} }
curveMap.AddCurveToMap(cu); else
curveMap.AddCurveToMap(cu, false, this.removeDuplicate);
} }
//排序,根据角度逆时针排序. //排序,根据角度逆时针排序.
curveMap.m_NodeMap.forEach(s => curveMap._NodeMap.forEach(s =>
{
s.routes.sort((r1, r2) =>
{ {
return r1.an - r2.an; let minLength = Infinity;
}); for (let r of s.routes)
//移除重复的线
arrayRemoveDuplicateBySort(s.routes, (r1, r2) =>
{ {
let isEqual = r1.to === r2.to && r1.curve.constructor.name === r2.curve.constructor.name; if (r.length < minLength)
if (isEqual && r1.curve instanceof Arc) minLength = r.length;
return equalv3(r1.curve.GetPointAtParam(0.5), r2.curve.GetPointAtParam(0.5)); }
return isEqual; for (let r of s.routes)
}); CalcRouteAngle(r, minLength * 0.2);
s.routes.sort((r1, r2) => r1.an - r2.an);
}); });
return new Set(curveMap.Stands); return curveMap.Stands;
} }
private BreakArc(arc: Arc) private BreakArc(arc: Arc): Arc[]
{ {
let underPt = arc.Center.add(new Vector3(0, -arc.Radius)); let underPt = arc.Center.add(new Vector3(0, -arc.Radius));
let param = arc.GetParamAtPoint(underPt); let param = arc.GetParamAtPoint(underPt);
@ -265,73 +220,98 @@ export class RegionParse
return [arc]; return [arc];
} }
//寻找闭合轮廓,下一站总是使用逆时针规划. /**
private FindRegion(firstS: Stand, //起点 * 线使
nowStand: Stand, //当前站 * @param cu
lastCurve: Curve, //上一条线索引 * @returns true if cueve used
wayStands: Set<Stand>, //走过的站 */
routeS: Set<Route>, //走过的路 GetCueveUsed(cu: Curve): boolean
cuMaximumCount: number, //允许最大的行走次数
)
{
let routeCount = nowStand.routes.length;
//查找上一条线的索引.
let lastIndex = -1;
if (lastCurve)
{
for (let i = routeCount; i--;)//顺时针搜索.
{ {
if (nowStand.routes[i].curve === lastCurve) if (this.ExpLineMap.has(cu))
{ {
lastIndex = i; let use = this.ExpLineMap.get(cu).some(c => c.TempData > 0);
break; if (!use)
} this.ExpLineMap.delete(cu);
return use;
} }
else
return cu.TempData > 0;
} }
}
for (let i = 0; i < routeCount - 1; i++) function CalcRouteAngle(r: Route, length: number)
{ {
let index = lastIndex + i + 1;//转弯,逆时针 if (r.an !== undefined) return;
if (index >= routeCount) index -= routeCount; let cu = r.curve;
let p = r.isReverse ?
//下一站 cu.GetPointAtParam(cu.GetParamAtDist(r.length - length))
let route = nowStand.routes[index]; : cu.GetPointAtParam(cu.GetParamAtDist(length));
r.an = angle(p.sub(r.from.position));
}
let usedCount = route.curve.TempData; enum WalkType
if (usedCount >= cuMaximumCount) {
continue; Min = 1,
Max = -1,
}
//如果发现这条路已经走回去,中途回路 function ClosedWalkFrom(startVertice: Vertice, maxRoute: number, type = WalkType.Min): Route[]
if (wayStands.has(route.to)) {
{ let walk: Route[] = [];
return false; let curVertice: Vertice = startVertice;
// for (let stand of wayStands) let preRoute: Route;
// { // console.log("start", type, startVertice.position.toArray());
// if (stand === route.to) do
// break; {
// wayStands.delete(stand);//删除不是回路的部分 let route = GetNextRoute(curVertice, preRoute, type);
// } if (type === WalkType.Max && route.curve.TempData > 0)
// return true; return [];
// console.log(route.to.position.toArray());
walk.push(route);
[curVertice, preRoute] = [route.to, route];
if (walk.length > maxRoute * 2)
throw "超过计算次数限制";
} }
while (curVertice !== startVertice);
//加入到已经走过的道路. return walk;
wayStands.add(route.to); }
routeS.add(route);
//已经回原地,此处不验证该轮廓的正确性. /**
if (route.to === firstS) *
return true; */
function ReduceWalk(w: Route[]): Route[]
{
if (w.length === 0) return w;
//未构成回路,直接回家
if (w[0].curve === arrayLast(w).curve) return [];
//在下个路口试着往前走 for (let i = 0; i < w.length; i++)
let isFind = this.FindRegion(firstS, route.to, route.curve, wayStands, routeS, cuMaximumCount);
if (isFind)
return true;
else
{ {
wayStands.delete(route.to);//不走这条路 let r1 = w[i];
routeS.delete(route); for (let j = w.length; j--;)
{
if (i === j) break;
let r2 = w[j];
if (r1.to === r2.to)
{
if (j > i)
w.splice(i + 1, j - i);
break;
} }
} }
return false;
} }
return w;
}
function GetNextRoute(v: Vertice, prev?: Route, type: WalkType = WalkType.Min): Route
{
if (!prev)
return arrayLast(v.routes); //顺时针 cw \|/ 从左往右
//逆时针 ccw 往左
let index = v.routes.findIndex(r => r.curve === prev.curve);
let newIndex = FixIndex(index + 1 * type, v.routes);
return v.routes[newIndex];
} }

@ -1,9 +1,8 @@
import { Vector3 } from "three"; import { Vector3 } from "three";
import { Curve } from "../DatabaseServices/Entity/Curve"; import { Curve } from "../DatabaseServices/Entity/Curve";
import { CurveIntersection } from "../Geometry/CurveIntersection"; import { CurveIntersection } from "../Geometry/CurveIntersection";
import { CurveMap } from "../Geometry/CurveMap"; import { CurveMap, Vertice } from "../Geometry/CurveMap";
import { equalv3, equaln } from "../Geometry/GeUtils"; import { equaln, equalv3 } from "../Geometry/GeUtils";
import { Stand } from "../Geometry/RegionParse";
export class LinkSelf export class LinkSelf
{ {
@ -92,7 +91,7 @@ export class LinkSelf
for (let route of stand.routes) for (let route of stand.routes)
{ {
//缓存走过的节点 //缓存走过的节点
let ways: Stand[] = []; let ways: Vertice[] = [];
ways.push(cuMap.GetStand(cu.StartPoint)); ways.push(cuMap.GetStand(cu.StartPoint));
if (equalv3(route.curve.EndPoint, stand.position)) if (equalv3(route.curve.EndPoint, stand.position))
@ -187,7 +186,7 @@ export class LinkSelf
} }
} }
//寻找最小索引的路线 //寻找最小索引的路线
private FindMinRoute(nowStand: Stand, nowIndex: number, cs: Curve[], routes: Curve[]): { minIndex: number, routes: Curve[]; } private FindMinRoute(nowStand: Vertice, nowIndex: number, cs: Curve[], routes: Curve[]): { minIndex: number, routes: Curve[]; }
{ {
//和当前索引一样的 搜索结果 //和当前索引一样的 搜索结果
let curIndex: { minIndex: number, routes: Curve[]; } = undefined; let curIndex: { minIndex: number, routes: Curve[]; } = undefined;
@ -238,7 +237,7 @@ export class LinkSelf
} }
//搜索闭合的区域 //搜索闭合的区域
private FindCloseCurve(nowStand: Stand, cuIndex: number, ways: Stand[], routes: Set<Curve>, cuMap: CurveMap) private FindCloseCurve(nowStand: Vertice, cuIndex: number, ways: Vertice[], routes: Set<Curve>, cuMap: CurveMap)
{ {
for (let route of nowStand.routes) for (let route of nowStand.routes)
{ {
@ -281,7 +280,7 @@ export class LinkSelf
let cuMap = new CurveMap(); let cuMap = new CurveMap();
breakCus.forEach(c => cuMap.AddCurveToMap(c)); breakCus.forEach(c => cuMap.AddCurveToMap(c));
//所有的站点 逆序排序. //所有的站点 逆序排序.
for (let [, stand] of cuMap.m_NodeMap) for (let [, stand] of cuMap._NodeMap)
{ {
stand.routes.sort((r1, r2) => stand.routes.sort((r1, r2) =>
{ {

@ -10,9 +10,8 @@ import { Curve } from "../DatabaseServices/Entity/Curve";
import { Line } from "../DatabaseServices/Entity/Line"; import { Line } from "../DatabaseServices/Entity/Line";
import { Polyline } from "../DatabaseServices/Entity/Polyline"; import { Polyline } from "../DatabaseServices/Entity/Polyline";
import { IntersectsBox } from "../Geometry/Box"; import { IntersectsBox } from "../Geometry/Box";
import { CurveMap } from "../Geometry/CurveMap"; import { CurveMap, Vertice, Route } from "../Geometry/CurveMap";
import { angle, equaln, equalv2, equalv3, IdentityMtx4, SelectNearP } from "../Geometry/GeUtils"; import { angle, equaln, equalv2, equalv3, IdentityMtx4, SelectNearP } from "../Geometry/GeUtils";
import { Route, Stand } from "../Geometry/RegionParse";
import { SortEntityByBox } from "../Geometry/SortEntityByBox"; import { SortEntityByBox } from "../Geometry/SortEntityByBox";
import { IntersectOption } from "../GraphicsSystem/IntersectWith"; import { IntersectOption } from "../GraphicsSystem/IntersectWith";
@ -611,7 +610,7 @@ export class OffsetPolyline
let preP: Vector3; let preP: Vector3;
let searchNext = (s: Stand, pl: Polyline): Stand => let searchNext = (s: Vertice, pl: Polyline): Vertice =>
{ {
let minDist = Infinity; let minDist = Infinity;
let minR: Route; let minR: Route;
@ -651,10 +650,10 @@ export class OffsetPolyline
preP = undefined; preP = undefined;
let pl = new Polyline(); let pl = new Polyline();
let ss = s; let ss = s;
while (ss) while (ss && !pl.IsClose)
ss = searchNext(ss, pl); ss = searchNext(ss, pl);
ss = s; ss = s;
while (ss) while (ss && !pl.IsClose)
ss = searchNext(ss, pl); ss = searchNext(ss, pl);
if (pl.NumberOfVertices > 0) if (pl.NumberOfVertices > 0)

@ -1,24 +1,25 @@
import { Matrix4, Vector3 } from "three"; import { Matrix4, Vector3 } from "three";
import { equalCurve, IsRect } from "../../Common/CurveUtils"; import { equalCurve, IsRect } from "../../Common/CurveUtils";
import { Singleton } from "../../Common/Singleton"; import { Singleton } from "../../Common/Singleton";
import { ExtrudeHole } from "../../DatabaseServices/3DSolid/ExtrudeHole";
import { Contour } from "../../DatabaseServices/Contour"; import { Contour } from "../../DatabaseServices/Contour";
import { Board, IModeling } from "../../DatabaseServices/Entity/Board"; import { Board, IModeling } from "../../DatabaseServices/Entity/Board";
import { Circle } from "../../DatabaseServices/Entity/Circle"; import { Circle } from "../../DatabaseServices/Entity/Circle";
import { Curve } from "../../DatabaseServices/Entity/Curve"; import { Curve } from "../../DatabaseServices/Entity/Curve";
import { Line } from "../../DatabaseServices/Entity/Line"; import { Line } from "../../DatabaseServices/Entity/Line";
import { Polyline } from "../../DatabaseServices/Entity/Polyline"; import { Polyline } from "../../DatabaseServices/Entity/Polyline";
import { HardwareCompositeEntity } from '../../DatabaseServices/Hardware/HardwareCompositeEntity';
import { Shape } from "../../DatabaseServices/Shape"; import { Shape } from "../../DatabaseServices/Shape";
import { ShapeManager } from "../../DatabaseServices/ShapeManager"; import { ShapeManager } from "../../DatabaseServices/ShapeManager";
import { Route } from "../../Geometry/CurveMap";
import { GetSideFaceMtx } from "../../Geometry/DrillParse/BoardGetFace"; import { GetSideFaceMtx } from "../../Geometry/DrillParse/BoardGetFace";
import { isParallelTo, angleTo, XAxis, MoveMatrix } from "../../Geometry/GeUtils"; import { angleTo, isParallelTo, MoveMatrix, XAxis } from "../../Geometry/GeUtils";
import { RegionParse, Route } from "../../Geometry/RegionParse"; import { RegionParse } from "../../Geometry/RegionParse";
import { Production } from "../../Production/Product";
import { FaceDirection } from "../../UI/Store/BoardInterface"; import { FaceDirection } from "../../UI/Store/BoardInterface";
import { BoolOpeartionType, isTargetCurInOrOnSourceCur } from "../BoolOperateUtils"; import { BoolOpeartionType, isTargetCurInOrOnSourceCur } from "../BoolOperateUtils";
import { OptimizeToolPath, GetCurveToInDir, GetOffsetCurves } from "./OptimizeToolPath";
import { ExtrudeHole } from "../../DatabaseServices/3DSolid/ExtrudeHole";
import { Production } from "../../Production/Product";
import { HardwareCompositeEntity } from '../../DatabaseServices/Hardware/HardwareCompositeEntity';
import { GetSealedBoardContour } from "../CalcEdgeSealing"; import { GetSealedBoardContour } from "../CalcEdgeSealing";
import { GetCurveToInDir, GetOffsetCurves, OptimizeToolPath } from "./OptimizeToolPath";
/** /**
* *
@ -292,13 +293,11 @@ export class FeedingToolPath extends Singleton
let regParse = new RegionParse(expCus); let regParse = new RegionParse(expCus);
//分析封闭包围区域 //分析封闭包围区域
const parseRoute = (routeSet: Set<Route>[]) => const parseRoute = (routeSet: Array<Route>[]) =>
{ {
for (let routes of routeSet) for (let routes of routeSet)
{ {
let cs: Curve[] = []; let cs: Curve[] = routes.map(r => r.curve);
for (let r of routes)
cs.push(r.curve);
let c = Contour.CreateContour(cs, false); let c = Contour.CreateContour(cs, false);
if (c && c.Area > 1e-3) if (c && c.Area > 1e-3)
cons.push(c); cons.push(c);

Loading…
Cancel
Save