!2760 功能:侧面造型

Merge pull request !2760 from 林三/feat_side_hole
pull/2826/head^2
林三 3 months ago
parent 72f4d04b36
commit 63003a6f6e

@ -139,7 +139,7 @@ Array [
1, 1,
0, 0,
0, 0,
20, 21,
0, 0,
"晨丰顶板", "晨丰顶板",
"未命名", "未命名",
@ -193,6 +193,7 @@ Array [
0, 0,
"", "",
0, 0,
0,
] ]
`; `;
@ -359,7 +360,7 @@ Array [
0, 0,
0, 0,
0, 0,
20, 21,
0, 0,
"辅助条(上收口)", "辅助条(上收口)",
"", "",
@ -417,5 +418,6 @@ Array [
0, 0,
"", "",
0, 0,
0,
] ]
`; `;

@ -2,11 +2,11 @@
exports[`晨丰导入CAD解析 1`] = `"[12,103,1,2,1,0,0,1,\\"\\",2,2,0,0,3,\\"Board\\",10,2,100,0,1,2,0,[0,6.123233995736766e-17,1,0,0,-1,6.123233995736766e-17,0,1,0,0,0,20,0,0,1],0,0,1,[1,0,0,0,0,6.123233995736766e-17,1,0,0,-1,6.123233995736766e-17,0,20,0,0,1],0,0,1,3,100,80,18,true,\\"Polyline\\",10,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,2,4,[0,0],0,[0,100],0,[80,100],0,[80,0],0,true,1,3,20,10,1,true,\\"Polyline\\",10,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,2,4,[0,0],0,[0,20],0,[10,20],0,[10,0],0,true,0,3,0,0,0,0,0,[0,6.123233995736766e-17,1,0,0,-1,6.123233995736766e-17,0,1,0,0,0,20,6.123233995736766e-16,10,1],3,0,0,0,0,0,20,1,\\"层板\\",\\"板主卧\\",\\"板标准柜\\",\\"默认板材5厘\\",\\"生态板\\",\\"经典檀木\\",0,0,\\"不排\\",2,0,\\"1.5\\",\\"1.5\\",\\"1.5\\",\\"1.5\\",\\"\\",\\"\\",\\"\\",4,\\"三合一\\",\\"三合一\\",\\"三合一\\",\\"三合一\\",true,true,2,\\"备注1\\",\\"434\\",\\"备注2\\",\\"434\\",0,0,0,0,0,0,0,true,0,0,null,0,0,\\"\\",\\"\\",\\"\\",\\"\\",0,false,0,\\"\\",0,\\"HardwareCompositeEntity\\",1,10,2,101,0,1,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,1,\\"Board\\",10,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,3,30,50,60,true,\\"Polyline\\",10,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,2,4,[0,0],0,[50,0],0,[50,30],0,[0,30],0,true,0,3,0,0,0,0,0,20,null,\\"\\",\\"\\",\\"\\",\\"\\",\\"\\",\\"\\",0,0,\\"\\",2,0,\\"1\\",\\"1\\",\\"1\\",\\"1\\",\\"\\",\\"\\",\\"\\",4,\\"不排\\",\\"不排\\",\\"不排\\",\\"不排\\",true,true,0,0,0,0,0,0,0,0,true,0,0,null,0,0,\\"\\",\\"\\",\\"\\",\\"\\",0,false,0,\\"\\",0,5,\\"五金\\",false,false,\\"五金颜色\\",\\"五金材质\\",\\"五金\\",\\"五金主卧\\",\\"五金标准柜\\",\\"L*W*H*100\\",\\"L*W*H\\",\\"X-1\\",\\"厂家晨丰\\",\\"品牌晨丰\\",\\"{L*2}\\",\\"1\\",\\"五金备注\\",\\"个\\",0,true,0,0,0,\\"HardwareTopline\\",10,2,102,0,1,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,2,\\"\\",1,\\"\\",1,0,\\"0\\",\\"\\",\\"模板主卧\\",\\"模板标准柜\\",\\"\\",\\"\\",\\"\\",\\"\\",\\"\\",\\"\\",\\"\\",0,2,4,0,0,5,0,2,3,0,0,5,0,0,0,0,0,1,0,1,\\"CommandHistoryRecord\\",1,\\"\\",1,2,3,\\"HistorycRecord\\",2,\\"RemoveObjectData\\",1,0,\\"CreateObjectData\\",1,[],\\"HistorycRecord\\",2,\\"RemoveObjectData\\",1,1,\\"CreateObjectData\\",1,[],\\"HistorycRecord\\",2,\\"RemoveObjectData\\",1,2,\\"CreateObjectData\\",1,[],2,5,0,0,0,1,2,6,0,0,0,1,2,7,0,0,1,\\"\\",2,8,0,0,0,2,9,0,0,0,1,2,10,0,0,1,\\"\\",2,11,0,0,0,0,1,2,12,0,0,5,0,0,null,2,13,0,0,0]"`; exports[`晨丰导入CAD解析 1`] = `"[12,103,1,2,1,0,0,1,\\"\\",2,2,0,0,3,\\"Board\\",10,2,100,0,1,2,0,[0,6.123233995736766e-17,1,0,0,-1,6.123233995736766e-17,0,1,0,0,0,20,0,0,1],0,0,1,[1,0,0,0,0,6.123233995736766e-17,1,0,0,-1,6.123233995736766e-17,0,20,0,0,1],0,0,1,3,100,80,18,true,\\"Polyline\\",10,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,2,4,[0,0],0,[0,100],0,[80,100],0,[80,0],0,true,1,3,20,10,1,true,\\"Polyline\\",10,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,2,4,[0,0],0,[0,20],0,[10,20],0,[10,0],0,true,0,3,0,0,0,0,0,[0,6.123233995736766e-17,1,0,0,-1,6.123233995736766e-17,0,1,0,0,0,20,6.123233995736766e-16,10,1],3,0,0,0,0,0,20,1,\\"层板\\",\\"板主卧\\",\\"板标准柜\\",\\"默认板材5厘\\",\\"生态板\\",\\"经典檀木\\",0,0,\\"不排\\",2,0,\\"1.5\\",\\"1.5\\",\\"1.5\\",\\"1.5\\",\\"\\",\\"\\",\\"\\",4,\\"三合一\\",\\"三合一\\",\\"三合一\\",\\"三合一\\",true,true,2,\\"备注1\\",\\"434\\",\\"备注2\\",\\"434\\",0,0,0,0,0,0,0,true,0,0,null,0,0,\\"\\",\\"\\",\\"\\",\\"\\",0,false,0,\\"\\",0,\\"HardwareCompositeEntity\\",1,10,2,101,0,1,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,1,\\"Board\\",10,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,3,30,50,60,true,\\"Polyline\\",10,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,2,4,[0,0],0,[50,0],0,[50,30],0,[0,30],0,true,0,3,0,0,0,0,0,20,null,\\"\\",\\"\\",\\"\\",\\"\\",\\"\\",\\"\\",0,0,\\"\\",2,0,\\"1\\",\\"1\\",\\"1\\",\\"1\\",\\"\\",\\"\\",\\"\\",4,\\"不排\\",\\"不排\\",\\"不排\\",\\"不排\\",true,true,0,0,0,0,0,0,0,0,true,0,0,null,0,0,\\"\\",\\"\\",\\"\\",\\"\\",0,false,0,\\"\\",0,5,\\"五金\\",false,false,\\"五金颜色\\",\\"五金材质\\",\\"五金\\",\\"五金主卧\\",\\"五金标准柜\\",\\"L*W*H*100\\",\\"L*W*H\\",\\"X-1\\",\\"厂家晨丰\\",\\"品牌晨丰\\",\\"{L*2}\\",\\"1\\",\\"五金备注\\",\\"个\\",0,true,0,0,0,\\"HardwareTopline\\",10,2,102,0,1,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,2,\\"\\",1,\\"\\",1,0,\\"0\\",\\"\\",\\"模板主卧\\",\\"模板标准柜\\",\\"\\",\\"\\",\\"\\",\\"\\",\\"\\",\\"\\",\\"\\",0,2,4,0,0,5,0,2,3,0,0,5,0,0,0,0,0,1,0,1,\\"CommandHistoryRecord\\",1,\\"\\",1,2,3,\\"HistorycRecord\\",2,\\"RemoveObjectData\\",1,0,\\"CreateObjectData\\",1,[],\\"HistorycRecord\\",2,\\"RemoveObjectData\\",1,1,\\"CreateObjectData\\",1,[],\\"HistorycRecord\\",2,\\"RemoveObjectData\\",1,2,\\"CreateObjectData\\",1,[],2,5,0,0,0,1,2,6,0,0,0,1,2,7,0,0,1,\\"\\",2,8,0,0,0,2,9,0,0,0,1,2,10,0,0,1,\\"\\",2,11,0,0,0,0,1,2,12,0,0,5,0,0,null,2,13,0,0,0]"`;
exports[`晨丰导入五金解析 1`] = `"[1,11,2,100,0,1,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,0,1,\\"Board\\",11,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,0,3,30,50,60,true,\\"Polyline\\",11,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,0,2,4,[0,0],0,[50,0],0,[50,30],0,[0,30],0,true,0,3,0,0,0,0,0,20,null,\\"\\",\\"\\",\\"\\",\\"\\",\\"\\",\\"\\",0,0,\\"\\",2,0,\\"1\\",\\"1\\",\\"1\\",\\"1\\",\\"\\",\\"\\",\\"\\",4,\\"不排\\",\\"不排\\",\\"不排\\",\\"不排\\",true,true,0,0,0,0,0,0,0,0,true,0,0,null,0,0,\\"\\",\\"\\",\\"\\",\\"\\",0,false,0,\\"\\",0,5,\\"五金\\",false,false,\\"五金颜色\\",\\"五金材质\\",\\"五金\\",\\"五金主卧\\",\\"五金标准柜\\",\\"L*W*H*100\\",\\"L*W*H\\",\\"X-1\\",\\"厂家晨丰\\",\\"品牌晨丰\\",\\"{L*2}\\",\\"1\\",\\"五金备注\\",\\"个\\",0,true,0,0,0]"`; exports[`晨丰导入五金解析 1`] = `"[1,10,2,100,0,1,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,1,\\"Board\\",10,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,3,30,50,60,true,\\"Polyline\\",10,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,2,4,[0,0],0,[50,0],0,[50,30],0,[0,30],0,true,0,3,0,0,0,0,0,21,null,\\"\\",\\"\\",\\"\\",\\"\\",\\"\\",\\"\\",0,0,\\"\\",2,0,\\"1\\",\\"1\\",\\"1\\",\\"1\\",\\"\\",\\"\\",\\"\\",4,\\"不排\\",\\"不排\\",\\"不排\\",\\"不排\\",true,true,0,0,0,0,0,0,0,0,true,0,0,null,0,0,\\"\\",\\"\\",\\"\\",\\"\\",0,false,0,\\"\\",0,0,5,\\"五金\\",false,false,\\"五金颜色\\",\\"五金材质\\",\\"五金\\",\\"五金主卧\\",\\"五金标准柜\\",\\"L*W*H*100\\",\\"L*W*H\\",\\"X-1\\",\\"厂家晨丰\\",\\"品牌晨丰\\",\\"{L*2}\\",\\"1\\",\\"五金备注\\",\\"个\\",0,true,0,0,0]"`;
exports[`晨丰导入五金解析 2`] = `"[12,102,1,2,1,0,0,1,\\"\\",2,2,0,0,2,\\"HardwareCompositeEntity\\",1,10,2,100,0,1,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,1,\\"Board\\",10,2,101,0,1,2,0,[0,1,0,0,-1,0,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,3,100,100,100,true,\\"Polyline\\",10,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,2,4,[0,0],0,[100,0],0,[100,100],0,[0,100],0,true,0,3,0,0,0,0,0,20,0,\\"层板\\",\\"五金主卧\\",\\"五金标准柜\\",\\"\\",\\"\\",\\"\\",0,0,\\"不排\\",2,0,\\"1\\",\\"1\\",\\"1\\",\\"1\\",\\"\\",\\"\\",\\"\\",4,\\"不排\\",\\"不排\\",\\"不排\\",\\"不排\\",true,true,0,0,0,0,0,0,0,0,true,0,0,null,0,0,\\"\\",\\"\\",\\"\\",\\"\\",0,false,0,\\"\\",0,5,\\"五金\\",false,false,\\"五金颜色\\",\\"五金材质\\",\\"五金\\",\\"五金主卧\\",\\"五金标准柜\\",\\"L*W*H*100\\",\\"L*W*H\\",\\"X-1\\",\\"厂家晨丰\\",\\"品牌晨丰\\",\\"{L*2}\\",\\"1\\",\\"五金备注\\",\\"个\\",0,true,0,0,0,\\"Board\\",10,2,101,0,1,2,0,[0,1,0,0,-1,0,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,3,100,100,100,true,\\"Polyline\\",10,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,2,4,[0,0],0,[100,0],0,[100,100],0,[0,100],0,true,0,3,0,0,0,0,0,20,0,\\"层板\\",\\"五金主卧\\",\\"五金标准柜\\",\\"\\",\\"\\",\\"\\",0,0,\\"不排\\",2,0,\\"1\\",\\"1\\",\\"1\\",\\"1\\",\\"\\",\\"\\",\\"\\",4,\\"不排\\",\\"不排\\",\\"不排\\",\\"不排\\",true,true,0,0,0,0,0,0,0,0,true,0,0,null,0,0,\\"\\",\\"\\",\\"\\",\\"\\",0,false,0,\\"\\",0,2,4,0,0,5,0,2,3,0,0,5,0,0,0,0,0,1,0,1,\\"CommandHistoryRecord\\",1,\\"\\",1,2,2,\\"HistorycRecord\\",2,\\"RemoveObjectData\\",1,0,\\"CreateObjectData\\",1,[],\\"HistorycRecord\\",2,\\"RemoveObjectData\\",1,1,\\"CreateObjectData\\",1,[],2,5,0,0,0,1,2,6,0,0,0,1,2,7,0,0,1,\\"\\",2,8,0,0,0,2,9,0,0,0,1,2,10,0,0,1,\\"\\",2,11,0,0,0,0,1,2,12,0,0,5,0,0,null,2,13,0,0,0]"`; exports[`晨丰导入五金解析 2`] = `"[12,102,1,2,1,0,0,1,\\"\\",2,2,0,0,2,\\"HardwareCompositeEntity\\",1,10,2,100,0,1,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,1,\\"Board\\",10,2,101,0,1,2,0,[0,1,0,0,-1,0,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,3,100,100,100,true,\\"Polyline\\",10,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,2,4,[0,0],0,[100,0],0,[100,100],0,[0,100],0,true,0,3,0,0,0,0,0,20,0,\\"层板\\",\\"五金主卧\\",\\"五金标准柜\\",\\"\\",\\"\\",\\"\\",0,0,\\"不排\\",2,0,\\"1\\",\\"1\\",\\"1\\",\\"1\\",\\"\\",\\"\\",\\"\\",4,\\"不排\\",\\"不排\\",\\"不排\\",\\"不排\\",true,true,0,0,0,0,0,0,0,0,true,0,0,null,0,0,\\"\\",\\"\\",\\"\\",\\"\\",0,false,0,\\"\\",0,5,\\"五金\\",false,false,\\"五金颜色\\",\\"五金材质\\",\\"五金\\",\\"五金主卧\\",\\"五金标准柜\\",\\"L*W*H*100\\",\\"L*W*H\\",\\"X-1\\",\\"厂家晨丰\\",\\"品牌晨丰\\",\\"{L*2}\\",\\"1\\",\\"五金备注\\",\\"个\\",0,true,0,0,0,\\"Board\\",10,2,101,0,1,2,0,[0,1,0,0,-1,0,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,3,100,100,100,true,\\"Polyline\\",10,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,2,4,[0,0],0,[100,0],0,[100,100],0,[0,100],0,true,0,3,0,0,0,0,0,20,0,\\"层板\\",\\"五金主卧\\",\\"五金标准柜\\",\\"\\",\\"\\",\\"\\",0,0,\\"不排\\",2,0,\\"1\\",\\"1\\",\\"1\\",\\"1\\",\\"\\",\\"\\",\\"\\",4,\\"不排\\",\\"不排\\",\\"不排\\",\\"不排\\",true,true,0,0,0,0,0,0,0,0,true,0,0,null,0,0,\\"\\",\\"\\",\\"\\",\\"\\",0,false,0,\\"\\",0,2,4,0,0,5,0,2,3,0,0,5,0,0,0,0,0,1,0,1,\\"CommandHistoryRecord\\",1,\\"\\",1,2,2,\\"HistorycRecord\\",2,\\"RemoveObjectData\\",1,0,\\"CreateObjectData\\",1,[],\\"HistorycRecord\\",2,\\"RemoveObjectData\\",1,1,\\"CreateObjectData\\",1,[],2,5,0,0,0,1,2,6,0,0,0,1,2,7,0,0,1,\\"\\",2,8,0,0,0,2,9,0,0,0,1,2,10,0,0,1,\\"\\",2,11,0,0,0,0,1,2,12,0,0,5,0,0,null,2,13,0,0,0]"`;
exports[`晨丰导入板解析 1`] = `"[11,2,0,0,0,2,0,[0,6.123233995736766e-17,1,0,0,-1,6.123233995736766e-17,0,1,0,0,0,20,0,0,1],0,0,1,[1,0,0,0,0,6.123233995736766e-17,1,0,0,-1,6.123233995736766e-17,0,20,0,0,1],0,0,1,0,3,100,80,18,true,\\"Polyline\\",11,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,0,2,4,[0,0],0,[0,100],0,[80,100],0,[80,0],0,true,1,3,20,10,1,true,\\"Polyline\\",11,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,0,2,4,[0,0],0,[0,20],0,[10,20],0,[10,0],0,true,0,3,0,0,0,0,0,[0,6.123233995736766e-17,1,0,0,-1,6.123233995736766e-17,0,1,0,0,0,20,6.123233995736766e-16,10,1],3,0,0,0,0,0,20,1,\\"层板\\",\\"板主卧\\",\\"板标准柜\\",\\"默认板材5厘\\",\\"生态板\\",\\"经典檀木\\",0,0,\\"不排\\",2,0,\\"1.5\\",\\"1.5\\",\\"1.5\\",\\"1.5\\",\\"\\",\\"\\",\\"\\",4,\\"三合一\\",\\"三合一\\",\\"三合一\\",\\"三合一\\",true,true,2,\\"备注1\\",\\"434\\",\\"备注2\\",\\"434\\",0,0,0,0,0,0,0,true,0,0,null,0,0,\\"\\",\\"\\",\\"\\",\\"\\",0,false,0,\\"\\",0]"`; exports[`晨丰导入板解析 1`] = `"[10,2,0,0,0,2,0,[0,6.123233995736766e-17,1,0,0,-1,6.123233995736766e-17,0,1,0,0,0,20,0,0,1],0,0,1,[1,0,0,0,0,6.123233995736766e-17,1,0,0,-1,6.123233995736766e-17,0,20,0,0,1],0,0,1,3,100,80,18,true,\\"Polyline\\",10,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,2,4,[0,0],0,[0,100],0,[80,100],0,[80,0],0,true,1,3,20,10,1,true,\\"Polyline\\",10,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,2,4,[0,0],0,[0,20],0,[10,20],0,[10,0],0,true,0,3,0,0,0,0,0,[0,6.123233995736766e-17,1,0,0,-1,6.123233995736766e-17,0,1,0,0,0,20,6.123233995736766e-16,10,1],3,0,0,0,0,0,21,1,\\"层板\\",\\"板主卧\\",\\"板标准柜\\",\\"默认板材5厘\\",\\"生态板\\",\\"经典檀木\\",0,0,\\"不排\\",2,0,\\"1.5\\",\\"1.5\\",\\"1.5\\",\\"1.5\\",\\"\\",\\"\\",\\"\\",4,\\"三合一\\",\\"三合一\\",\\"三合一\\",\\"三合一\\",true,true,2,\\"备注1\\",\\"434\\",\\"备注2\\",\\"434\\",0,0,0,0,0,0,0,true,0,0,null,0,0,\\"\\",\\"\\",\\"\\",\\"\\",0,false,0,\\"\\",0,0]"`;
exports[`晨丰导入模板解析 1`] = `"[12,102,1,2,1,0,0,1,\\"\\",2,2,0,0,2,\\"HardwareCompositeEntity\\",1,10,2,100,0,1,7,0,[1,0,0,0,0,6.123233995736766e-17,1,0,0,-1,6.123233995736766e-17,0,400,0,0,1],0,0,1,[1,0,0,0,0,6.123233995736766e-17,1,0,0,-1,6.123233995736766e-17,0,400,0,0,1],0,0,1,1,\\"Board\\",10,2,101,0,1,2,0,[0,6.123233995736766e-17,1,0,-1,0,0,0,0,-1,6.123233995736766e-17,0,400,0,0,1],0,0,1,[1,0,0,0,0,6.123233995736766e-17,1,0,0,-1,6.123233995736766e-17,0,400,0,0,1],0,0,1,3,100,100,100,true,\\"Polyline\\",10,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,2,4,[0,0],0,[100,0],0,[100,100],0,[0,100],0,true,0,3,0,0,0,0,0,20,0,\\"层板\\",\\"模板主卧\\",\\"模板标准柜\\",\\"\\",\\"\\",\\"\\",0,0,\\"不排\\",2,0,\\"1\\",\\"1\\",\\"1\\",\\"1\\",\\"\\",\\"\\",\\"\\",4,\\"不排\\",\\"不排\\",\\"不排\\",\\"不排\\",true,true,0,0,0,0,0,0,0,0,true,0,0,null,0,0,\\"\\",\\"\\",\\"\\",\\"\\",0,false,0,\\"\\",0,5,\\"五金\\",false,false,\\"\\",\\"\\",\\"复合实体\\",\\"模板主卧\\",\\"模板标准柜\\",\\"L*W*H*100\\",\\"L*W*H*300\\",\\"X-1\\",\\"晨丰\\",\\"晨丰\\",\\"个\\",\\"1\\",\\"\\",\\"\\",0,true,0,0,0,\\"Board\\",10,2,101,0,1,2,0,[0,6.123233995736766e-17,1,0,-1,0,0,0,0,-1,6.123233995736766e-17,0,400,0,0,1],0,0,1,[1,0,0,0,0,6.123233995736766e-17,1,0,0,-1,6.123233995736766e-17,0,400,0,0,1],0,0,1,3,100,100,100,true,\\"Polyline\\",10,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,2,4,[0,0],0,[100,0],0,[100,100],0,[0,100],0,true,0,3,0,0,0,0,0,20,0,\\"层板\\",\\"模板主卧\\",\\"模板标准柜\\",\\"\\",\\"\\",\\"\\",0,0,\\"不排\\",2,0,\\"1\\",\\"1\\",\\"1\\",\\"1\\",\\"\\",\\"\\",\\"\\",4,\\"不排\\",\\"不排\\",\\"不排\\",\\"不排\\",true,true,0,0,0,0,0,0,0,0,true,0,0,null,0,0,\\"\\",\\"\\",\\"\\",\\"\\",0,false,0,\\"\\",0,2,4,0,0,5,0,2,3,0,0,5,0,0,0,0,0,1,0,1,\\"CommandHistoryRecord\\",1,\\"\\",1,2,2,\\"HistorycRecord\\",2,\\"RemoveObjectData\\",1,0,\\"CreateObjectData\\",1,[],\\"HistorycRecord\\",2,\\"RemoveObjectData\\",1,1,\\"CreateObjectData\\",1,[],2,5,0,0,0,1,2,6,0,0,0,1,2,7,0,0,1,\\"\\",2,8,0,0,0,2,9,0,0,0,1,2,10,0,0,1,\\"\\",2,11,0,0,0,0,1,2,12,0,0,5,0,0,null,2,13,0,0,0]"`; exports[`晨丰导入模板解析 1`] = `"[12,102,1,2,1,0,0,1,\\"\\",2,2,0,0,2,\\"HardwareCompositeEntity\\",1,10,2,100,0,1,7,0,[1,0,0,0,0,6.123233995736766e-17,1,0,0,-1,6.123233995736766e-17,0,400,0,0,1],0,0,1,[1,0,0,0,0,6.123233995736766e-17,1,0,0,-1,6.123233995736766e-17,0,400,0,0,1],0,0,1,1,\\"Board\\",10,2,101,0,1,2,0,[0,6.123233995736766e-17,1,0,-1,0,0,0,0,-1,6.123233995736766e-17,0,400,0,0,1],0,0,1,[1,0,0,0,0,6.123233995736766e-17,1,0,0,-1,6.123233995736766e-17,0,400,0,0,1],0,0,1,3,100,100,100,true,\\"Polyline\\",10,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,2,4,[0,0],0,[100,0],0,[100,100],0,[0,100],0,true,0,3,0,0,0,0,0,20,0,\\"层板\\",\\"模板主卧\\",\\"模板标准柜\\",\\"\\",\\"\\",\\"\\",0,0,\\"不排\\",2,0,\\"1\\",\\"1\\",\\"1\\",\\"1\\",\\"\\",\\"\\",\\"\\",4,\\"不排\\",\\"不排\\",\\"不排\\",\\"不排\\",true,true,0,0,0,0,0,0,0,0,true,0,0,null,0,0,\\"\\",\\"\\",\\"\\",\\"\\",0,false,0,\\"\\",0,5,\\"五金\\",false,false,\\"\\",\\"\\",\\"复合实体\\",\\"模板主卧\\",\\"模板标准柜\\",\\"L*W*H*100\\",\\"L*W*H*300\\",\\"X-1\\",\\"晨丰\\",\\"晨丰\\",\\"个\\",\\"1\\",\\"\\",\\"\\",0,true,0,0,0,\\"Board\\",10,2,101,0,1,2,0,[0,6.123233995736766e-17,1,0,-1,0,0,0,0,-1,6.123233995736766e-17,0,400,0,0,1],0,0,1,[1,0,0,0,0,6.123233995736766e-17,1,0,0,-1,6.123233995736766e-17,0,400,0,0,1],0,0,1,3,100,100,100,true,\\"Polyline\\",10,2,0,0,0,7,0,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0,0,1,2,4,[0,0],0,[100,0],0,[100,100],0,[0,100],0,true,0,3,0,0,0,0,0,20,0,\\"层板\\",\\"模板主卧\\",\\"模板标准柜\\",\\"\\",\\"\\",\\"\\",0,0,\\"不排\\",2,0,\\"1\\",\\"1\\",\\"1\\",\\"1\\",\\"\\",\\"\\",\\"\\",4,\\"不排\\",\\"不排\\",\\"不排\\",\\"不排\\",true,true,0,0,0,0,0,0,0,0,true,0,0,null,0,0,\\"\\",\\"\\",\\"\\",\\"\\",0,false,0,\\"\\",0,2,4,0,0,5,0,2,3,0,0,5,0,0,0,0,0,1,0,1,\\"CommandHistoryRecord\\",1,\\"\\",1,2,2,\\"HistorycRecord\\",2,\\"RemoveObjectData\\",1,0,\\"CreateObjectData\\",1,[],\\"HistorycRecord\\",2,\\"RemoveObjectData\\",1,1,\\"CreateObjectData\\",1,[],2,5,0,0,0,1,2,6,0,0,0,1,2,7,0,0,1,\\"\\",2,8,0,0,0,2,9,0,0,0,1,2,10,0,0,1,\\"\\",2,11,0,0,0,0,1,2,12,0,0,5,0,0,null,2,13,0,0,0]"`;

@ -225,7 +225,7 @@ test('矩形走刀 冗余1 优化走刀', () =>
let brs = LoadBoardsFromFileData(d); let brs = LoadBoardsFromFileData(d);
let { modeling, sideModeling } = Production.GetBoardModelingData(brs[0], new Vector3, 1, []); let { modeling } = Production.GetBoardModelingData(brs[0], new Vector3, 1, []);
for (let m of modeling) for (let m of modeling)
{ {

@ -29,7 +29,7 @@ export class FindModeingKnifeRadius implements Command
for (let board of boards) for (let board of boards)
{ {
let { sideModeling, modeling } = Production.GetOriginBoardModelingData(board); let { sideModeling, modeling } = Production.GetOriginBoardModelingData(board);
for (let m of [...sideModeling, ...modeling]) for (let m of [...sideModeling.sideModel, ...modeling])
{ {
let bs = knifeBoardMap.get(m.knifeRadius); let bs = knifeBoardMap.get(m.knifeRadius);
if (!bs) if (!bs)

@ -0,0 +1,225 @@
import { Matrix4, Vector3 } from "three";
import { arrayLast } from "../../Common/ArrayExt";
import { Board } from "../../DatabaseServices/Entity/Board";
import { Curve } from "../../DatabaseServices/Entity/Curve";
import { ExtrudeSolid } from "../../DatabaseServices/Entity/Extrude";
import { Line } from "../../DatabaseServices/Entity/Line";
import { Polyline } from "../../DatabaseServices/Entity/Polyline";
import { Box3Ext } from "../../Geometry/Box";
import { AsVector2, equaln } from "../../Geometry/GeUtils";
import { GetBoardSealingCurves, SubsectionCurvesOfHightSeal } from "../../GraphicsSystem/CalcEdgeSealing";
import { IntersectOption } from "../../GraphicsSystem/IntersectWith";
import { FixIndex } from "../../Nest/Common/Util";
import { SplitPolyline } from "./SplitPolyline";
//侧面造型分裂
export class SplitBoardSideModelUtil
{
//备份原始二维刀路在世界坐标系中
private OrgBoardOCS: Matrix4 = new Matrix4();
private CacheSideModel: Map<number, ExtrudeSolid[]> = new Map();
private OldSealCurves: Curve[] = [];
constructor(br: Board)
{
this.Init(br);
}
Init(br: Board, isSpecialShape = false)
{
this.OrgBoardOCS = br.OCS;
let curves = GetBoardSealingCurves(br);
//取消异型操作会提前令isSpecialShape = false
if (isSpecialShape)
SubsectionCurvesOfHightSeal(curves);
let oldSealCurves: Curve[] = [];
for (let c of curves)
if (c instanceof Polyline)
oldSealCurves.push(...c.Explode());
else
oldSealCurves.push(c);
this.OldSealCurves = oldSealCurves;
const sideModelMap: Map<number, ExtrudeSolid[]> = new Map();
for (let [num, soilds] of br.SideModelingMap)
sideModelMap.set(num, soilds);
this.CacheSideModel = sideModelMap;
}
CheckSideModel(): boolean
{
let maxSideIndex = 0;
for (let [num, soilds] of this.CacheSideModel)
maxSideIndex = Math.max(num, maxSideIndex);
return this.OldSealCurves.length >= maxSideIndex;
}
SetBoardSideModel(br: Board)
{
if (!this.CacheSideModel.size) return;
if (this.CheckSideModel())
{
this.SpiltSideModelOfBrContour(br);
}
}
//新轮廓切割原始轮廓
SpiltSideModelOfBrContour(br: Board)
{
let curves = GetBoardSealingCurves(br);
let newSealCurves: Curve[] = [];
for (let c of curves)
if (c instanceof Polyline)
newSealCurves.push(...c.Explode());
else
newSealCurves.push(c);
let sideMadelMap: Map<number, ExtrudeSolid[]> = new Map();
for (let [nmu, soilds] of this.CacheSideModel)
{
if (soilds?.length)
{
let oldCu = this.OldSealCurves[nmu]?.Clone();
if (!oldCu) continue;
oldCu.ApplyMatrix(this.OrgBoardOCS);
for (let i = 0; i < newSealCurves.length; i++)
{
let newCu = newSealCurves[i].Clone().ApplyMatrix(br.OCSNoClone) as Line;
let p = newCu.GetPointAtParam(newCu.EndParam * 0.5);
let spliteEnts: ExtrudeSolid[] = [];
if (oldCu.PtOnCurve(p))
{
let startX = oldCu.GetDistAtPoint(newCu.StartPoint);
let endX = oldCu.GetDistAtPoint(newCu.EndPoint);
let box = new Box3Ext(new Vector3(startX), new Vector3(endX, br.Thickness));
let knifePls: Polyline[] = [];
for (let soild of soilds)
{
if (soild.Thickness <= 0) continue;
let sCon = soild.ContourCurve.Clone().ApplyMatrix(soild.OCSNoClone) as Polyline;
let thickness = soild.Thickness;
let newNeighborCus: Curve[] = [];
newNeighborCus.push(newSealCurves[FixIndex(i - 1, newSealCurves)].Clone().ApplyMatrix(br.OCSNoClone));
newNeighborCus.push(newSealCurves[FixIndex(i + 1, newSealCurves)].Clone().ApplyMatrix(br.OCSNoClone));
const offsetCus = newCu.GetOffsetCurves(-thickness);
const xPtList: number[] = [startX, endX];
for (let cu of offsetCus)
{
for (let nbCu of newNeighborCus)
{
const intersectPts = cu.IntersectWith(nbCu, IntersectOption.ExtendThis);
for (let pt of intersectPts)
{
let { closestPt } = newCu.GetClosestAtPoint(pt, true);
let ptX = oldCu.GetDistAtPoint(closestPt);
xPtList.push(ptX);
}
}
}
xPtList.sort((a, b) => a - b);
for (let x of [xPtList[0], arrayLast(xPtList)])
knifePls.push(new Polyline([{ pt: AsVector2({ x, y: 0 }), bul: 0 }, { pt: AsVector2({ x, y: 1 }), bul: 0 }]));
let splitSideModelCons = SplitPolyline(sCon, knifePls);
if (!splitSideModelCons.length)
splitSideModelCons.push(sCon);
for (let j = 0; j < splitSideModelCons.length; j++)
{
let intersectBox = box.clone().intersect(splitSideModelCons[j].BoundingBox);
if (box.intersectsBox(splitSideModelCons[j].BoundingBox, 1) && !equaln(intersectBox.max.x, intersectBox.min.x))
{
let soildClone = soild.Clone();
soildClone.ContourCurve = splitSideModelCons[j].ApplyMatrix(soild.OCSInv);
soildClone.GrooveCheckAllAutoSplit();
soildClone.ApplyMatrix(new Matrix4().setPosition(-startX, 0, 0));
spliteEnts.push(soildClone);
}
}
}
if (spliteEnts.length)
sideMadelMap.set(i, spliteEnts);
}
}
}
}
br.SideModelingMap = sideMadelMap;
}
//修改板厚度时裁剪侧面造型
SpiltSideModelOfBrThickness(br: Board, thickness: number)
{
this.Init(br);
let sideMadelMap: Map<number, ExtrudeSolid[]> = new Map();
for (let [nmu, soilds] of this.CacheSideModel)
{
if (soilds?.length)
{
let cu = this.OldSealCurves[nmu]?.Clone();
if (!cu) continue;
cu.ApplyMatrix(this.OrgBoardOCS);
let spliteEnts: ExtrudeSolid[] = [];
let knifePls: Polyline[] = [];
let box = new Box3Ext(new Vector3(), new Vector3(cu.Length, thickness));
for (let soild of soilds)
{
if (soild.Thickness <= 0) continue;
let sCon = soild.ContourCurve.Clone().ApplyMatrix(soild.OCSNoClone) as Polyline;
knifePls.push(new Polyline([{ pt: AsVector2({ x: 0, y: 0 }), bul: 0 }, { pt: AsVector2({ x: 1, y: 0 }), bul: 0 }]));
knifePls.push(new Polyline([{ pt: AsVector2({ x: 0, y: thickness }), bul: 0 }, { pt: AsVector2({ x: 1, y: thickness }), bul: 0 }]));
let splitSideModelCons = SplitPolyline(sCon, knifePls);
if (!splitSideModelCons.length)
splitSideModelCons.push(sCon);
for (let con of splitSideModelCons)
{
let intersectBox = box.clone().intersect(con.BoundingBox);
if (box.intersectsBox(con.BoundingBox, 1) && !equaln(intersectBox.max.y, intersectBox.min.y))
{
let soildClone = soild.Clone();
soildClone.ContourCurve = con.ApplyMatrix(soild.OCSInv);
soildClone.GrooveCheckAllAutoSplit();
spliteEnts.push(soildClone);
}
}
}
if (spliteEnts.length)
sideMadelMap.set(nmu, spliteEnts);
}
}
br.SideModelingMap = sideMadelMap;
}
}

@ -2,6 +2,7 @@ import { Vector3 } from "three";
import { EBoardKeyList } from "../../Common/BoardKeyList"; import { EBoardKeyList } from "../../Common/BoardKeyList";
import { CADFiler } from "../../DatabaseServices/CADFiler"; import { CADFiler } from "../../DatabaseServices/CADFiler";
import { I2DModeling, I3DModeling, IPathItem } from "../../DatabaseServices/Entity/Board"; import { I2DModeling, I3DModeling, IPathItem } from "../../DatabaseServices/Entity/Board";
import { ExtrudeSolid } from "../../DatabaseServices/Entity/Extrude";
import { Polyline } from "../../DatabaseServices/Entity/Polyline"; import { Polyline } from "../../DatabaseServices/Entity/Polyline";
import { BoardProcessOption } from "../../UI/Store/OptionInterface/BoardProcessOption"; import { BoardProcessOption } from "../../UI/Store/OptionInterface/BoardProcessOption";
@ -203,3 +204,38 @@ export function DeserializationBoard3DModeingData(file: CADFiler, data: I3DModel
}); });
} }
} }
export function SerializeBoardSideModeingData(file: CADFiler, sideModelingMap: Map<number, ExtrudeSolid[]>)
{
file.Write(sideModelingMap.size);
for (let [index, sideModelingList] of sideModelingMap)
{
file.Write(index);
file.Write(sideModelingList.length);
for (let data of sideModelingList)
file.WriteObject(data);
}
}
export function DeserializationBoardSideModeingData(file: CADFiler, sideModelingMap: Map<number, ExtrudeSolid[]>)
{
sideModelingMap.clear();
const count = file.Read();
for (let i = 0; i < count; i++)
{
let index = file.Read();
let listCount = file.Read();
let sideModelingList: ExtrudeSolid[] = [];
for (let j = 0; j < listCount; j++)
{
let obj = file.ReadObject() as ExtrudeSolid;
sideModelingList.push(obj);
}
sideModelingMap.set(index, sideModelingList);
}
}

@ -186,7 +186,7 @@ export class BoardFindModify implements Command
for (let b of br.SplitBoards) for (let b of br.SplitBoards)
{ {
const { sideModeling, modeling } = Production.GetOriginBoardModelingData(b); const { sideModeling, modeling } = Production.GetOriginBoardModelingData(b);
for (let m of [...sideModeling, ...modeling]) for (let m of [...sideModeling.sideModel, ...modeling])
{ {
compareBrValue = m.knifeRadius; compareBrValue = m.knifeRadius;
isVail = this.FilterBrSize(compareBrValue, compareValue, torValue, option.compareType.knifeRadius); isVail = this.FilterBrSize(compareBrValue, compareValue, torValue, option.compareType.knifeRadius);

@ -41,6 +41,7 @@ export function ModelInspection(boards: Board[])
let errGrooves: ExtrudeSolid[] = []; let errGrooves: ExtrudeSolid[] = [];
let errHoles: ExtrudeHole[] = []; let errHoles: ExtrudeHole[] = [];
let errorSideModel: ExtrudeSolid[] = [];
for (let br of boards) for (let br of boards)
{ {
@ -51,9 +52,10 @@ export function ModelInspection(boards: Board[])
errGrooves.push(grooves[index]); errGrooves.push(grooves[index]);
} }
errHoles.push(...feedingTool.CheckCustomHole(br)); errHoles.push(...feedingTool.CheckCustomHole(br));
errorSideModel = feedingTool.CheckSideModeling(br);
} }
return [...errGrooves.map(g => [[g], "槽错误"]), ...errHoles.map(h => [[h], "孔错误"])]; return [...errGrooves.map(g => [[g], "槽错误"]), ...errorSideModel.map(g => [[g], "侧槽错误"]), ...errHoles.map(h => [[h], "孔错误"])];
} }
export function SpecialBoardContourInspection(boards: Board[]) export function SpecialBoardContourInspection(boards: Board[])

@ -34,6 +34,7 @@ export class CheckModeling implements Command
let errGrooves: ExtrudeSolid[] = []; let errGrooves: ExtrudeSolid[] = [];
let errHoles: ExtrudeHole[] = []; let errHoles: ExtrudeHole[] = [];
let errorSideModel: ExtrudeSolid[] = [];
for (let br of brs) for (let br of brs)
{ {
@ -44,17 +45,21 @@ export class CheckModeling implements Command
errGrooves.push(grooves[index]); errGrooves.push(grooves[index]);
} }
errHoles.push(...feedingTool.CheckCustomHole(br)); errHoles.push(...feedingTool.CheckCustomHole(br));
errorSideModel = feedingTool.CheckSideModeling(br);
} }
if (errGrooves.length > 0 || errHoles.length > 0) if (errGrooves.length > 0 || errorSideModel.length || errHoles.length > 0)
app.Editor.Prompt(`检测到${errGrooves.length}个无法加工的造型和${errHoles.length}个无法加工的自定义排钻!旋转视图可以隐藏板件查看造型位置!`, LogType.Warning, [...errHoles, ...errGrooves]); app.Editor.Prompt(`检测到${errGrooves.length + errorSideModel.length}个无法加工的造型和${errHoles.length}个无法加工的自定义排钻!旋转视图可以隐藏板件查看造型位置!`,
LogType.Warning, [...errHoles, ...errGrooves, ...errorSideModel]);
else else
app.Editor.Prompt(`未检测到无法加工的造型!`, LogType.Info); app.Editor.Prompt(`未检测到无法加工的造型!`, LogType.Info);
if (errGrooves.length > 0 || errHoles.length > 0) if (errGrooves.length > 0 || errorSideModel.length > 0 || errHoles.length > 0)
{ {
app.Viewer.OutlinePass.selectedObjects = [...errHoles.map(h => h.DrawObject), app.Viewer.OutlinePass.selectedObjects = [...errHoles.map(h => h.DrawObject),
...errGrooves.map(g => JigUtils.Draw(g.Clone()).DrawObject)]; ...errGrooves.map(g => JigUtils.Draw(g.Clone()).DrawObject),
...errorSideModel.map(soild => JigUtils.Draw(soild.Clone()).DrawObject)];
app.Editor.UpdateScreen(); app.Editor.UpdateScreen();
AppToaster.show({ AppToaster.show({

@ -24,6 +24,7 @@ export class Command_ClearCDBrHoleModeling implements Command
br.ClearAllDrillList(); br.ClearAllDrillList();
br.ClearLayerNails(); br.ClearLayerNails();
br.ClearRelevance(); br.ClearRelevance();
br.ClearSideModeling();
} }
} }
else else
@ -34,6 +35,7 @@ export class Command_ClearCDBrHoleModeling implements Command
br.ClearBoardModeling(); br.ClearBoardModeling();
br.ClearLayerNails(); br.ClearLayerNails();
br.ClearRelevance(); br.ClearRelevance();
br.ClearSideModeling();
} }
} }
} }

@ -5,14 +5,17 @@ import { Intent } from "../Common/Toaster";
import { DimStyleKeyCode } from "../DatabaseServices/DimStyle/DimstyleKeyCodeEnum"; import { DimStyleKeyCode } from "../DatabaseServices/DimStyle/DimstyleKeyCodeEnum";
import { Board } from "../DatabaseServices/Entity/Board"; import { Board } from "../DatabaseServices/Entity/Board";
import { Circle } from "../DatabaseServices/Entity/Circle"; import { Circle } from "../DatabaseServices/Entity/Circle";
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 { Text, TextAligen } from "../DatabaseServices/Text/Text"; import { Text, TextAligen } from "../DatabaseServices/Text/Text";
import { Command } from "../Editor/CommandMachine"; import { Command } from "../Editor/CommandMachine";
import { PromptStatus } from "../Editor/PromptResult"; import { PromptStatus } from "../Editor/PromptResult";
import { userConfig } from "../Editor/UserConfig"; import { userConfig } from "../Editor/UserConfig";
import { GetSideCuFaceMtx } from "../Geometry/Board2DModelCSG/BoardSideModelCSGBuilder";
import { MoveMatrix, ZAxis, rotatePoint } from "../Geometry/GeUtils"; import { MoveMatrix, ZAxis, rotatePoint } from "../Geometry/GeUtils";
import { IContourData } from "../Production/Convert2PtsBul"; import { IContourData } from "../Production/Convert2PtsBul";
import { IBoardHoleInfo, IModelingData, ISpliteOrderData, Production } from "../Production/Product"; import { IBoardHoleInfo, IModelingData, IOriginSideModelingData, ISpliteOrderData, ModelType, Production } from "../Production/Product";
import { AppToaster } from "../UI/Components/Toaster"; import { AppToaster } from "../UI/Components/Toaster";
import { FaceDirection } from "./DrawDrilling/DrillType"; import { FaceDirection } from "./DrawDrilling/DrillType";
import { DrawHoleDim } from "./DrawHoleDimUtil"; import { DrawHoleDim } from "./DrawHoleDimUtil";
@ -118,8 +121,12 @@ export class FeedingCommand implements Command
let tMtx = MoveMatrix(pos); let tMtx = MoveMatrix(pos);
let contouLines = this.ParseContourData(info.originOutlin);//线段形式返回封边轮廓拆成多个线段主要运用在3个点形成的平面 let contouLines = this.ParseContourData(info.originOutlin);//线段形式返回封边轮廓拆成多个线段主要运用在3个点形成的平面
let originContour = Production.Data2Polyline(info.originOutlin);
let sealingContour = Production.Data2Polyline(info.outline);
this.DrawHole(info.holes, tMtx, info.offsetTanslation); this.DrawHole(info.holes, tMtx, info.offsetTanslation);
//侧面非圆排钻孔
this.DrawSideHole(info.sideModeling, originContour, tMtx, info.offsetTanslation);
const DimStyle: Map<DimStyleKeyCode, any> = new Map(); const DimStyle: Map<DimStyleKeyCode, any> = new Map();
DimStyle.set(DimStyleKeyCode.DIMASZ, 2); //箭头尺寸 DimStyle.set(DimStyleKeyCode.DIMASZ, 2); //箭头尺寸
@ -132,9 +139,6 @@ export class FeedingCommand implements Command
//占位空间box //占位空间box
let box = new Box3(); let box = new Box3();
let originContour = Production.Data2Polyline(info.originOutlin);
let sealingContour = Production.Data2Polyline(info.outline);
if (drawHoleDim) if (drawHoleDim)
await DrawHoleDim(info, tMtx, contouLines, DimStyle, box, originContour.BoundingBox); await DrawHoleDim(info, tMtx, contouLines, DimStyle, box, originContour.BoundingBox);
@ -163,7 +167,7 @@ export class FeedingCommand implements Command
this.DrawOriginModeling(brs[i], tMtx, info); this.DrawOriginModeling(brs[i], tMtx, info);
this.TestModeling(info.modeling, tMtx); this.TestModeling(info.modeling, tMtx);
this.TestModeling(info.sideModeling, tMtx); // this.TestModeling(info.sideModeling, tMtx);
let size = originContour.BoundingBox.getSize(new Vector3); let size = originContour.BoundingBox.getSize(new Vector3);
this.DateText(info, tMtx, size.x, box, pos.y); this.DateText(info, tMtx, size.x, box, pos.y);
@ -205,6 +209,41 @@ export class FeedingCommand implements Command
app.Database.ModelSpace.Append(c); app.Database.ModelSpace.Append(c);
} }
} }
private DrawSideHole(sideHoleInfo: IOriginSideModelingData[], sealingContour: Polyline, tMtx: Matrix4, offset: Vector3)
{
let cus = sealingContour.Explode() as Curve[];
const inverseZ = sealingContour.Area2 < 0;
const mt4Cache: Map<number, Matrix4> = new Map();
let offsetPs = offset.clone().multiplyScalar(-1);
for (let info of sideHoleInfo)
{
if (info.modelType !== ModelType.drill) continue;
let cu = cus[info.dir];
if (!cu) continue;
let mt4 = mt4Cache.get(info.dir);
if (!mt4)
{
mt4 = GetSideCuFaceMtx(cu, inverseZ);
mt4Cache.set(info.dir, mt4);
}
let holeOutline = Production.Data2Polyline(info.outline);
holeOutline.ApplyMatrix(mt4);
holeOutline.Move(offsetPs);
holeOutline.ApplyMatrix(tMtx);
app.Database.ModelSpace.Append(holeOutline);
let pos = holeOutline.BoundingBox.getCenter(new Vector3);
let l = new Line(pos, pos.clone().sub(holeOutline.Normal.multiplyScalar(info.thickness)));
l.ColorIndex = 3;
app.Database.ModelSpace.Append(l);
}
}
private TestModeling(datalist: IModelingData[], tMtx: Matrix4) private TestModeling(datalist: IModelingData[], tMtx: Matrix4)
{ {
for (let data of datalist) for (let data of datalist)

@ -0,0 +1,101 @@
import { Matrix4, Vector3 } from "three";
import { app } from "../ApplicationServices/Application";
import { Intent, Toaster } from "../Common/Toaster";
import { Board } from "../DatabaseServices/Entity/Board";
import { Entity } from "../DatabaseServices/Entity/Entity";
import { Polyline } from "../DatabaseServices/Entity/Polyline";
import { Text, TextAligen } from "../DatabaseServices/Text/Text";
import { Command } from "../Editor/CommandMachine";
import { PromptStatus } from "../Editor/PromptResult";
import { ParseBoardSideFace } from "../Geometry/DrillParse/ParseBoardSideFace";
import { MoveMatrix } from "../Geometry/GeUtils";
import { FeedingToolPath } from "../GraphicsSystem/ToolPath/FeedingToolPath";
export class SideModelFeedingCommand implements Command
{
async exec()
{
let enRes = await app.Editor.GetEntity({ Filter: { filterTypes: [Entity] } });
if (enRes.Status !== PromptStatus.OK) return;
let br = enRes.Entity as Board;
if (!br.SideModelingMap?.size) return;
const tool = FeedingToolPath.GetInstance();
let faces = new ParseBoardSideFace(br);
let ptRes = await app.Editor.GetPoint({ Msg: "点取位置" });
if (ptRes.Status === PromptStatus.OK)
{
let pos = ptRes.Point;;
let width = 0;
let sideModelList = Array.from(br.SideModelingMap);
sideModelList.sort((a, b) => a[0] - b[0]);
for (let [n, soilds] of sideModelList)
{
let tMtx = MoveMatrix(pos);
let faceContour = faces.Faces[n].Region.ShapeManager.ShapeList[0].Outline.Curve as Polyline;
for (let soild of soilds)
{
let con = soild.ContourCurve.Clone().ApplyMatrix(soild.OCSNoClone).ApplyMatrix(tMtx);
con.ColorIndex = 8;
app.Database.ModelSpace.Append(con);
let paths = tool.GetSideModelFeedPath(soild, faceContour);//走刀路径
if (paths.length)
for (let pl of paths)
{
pl.ApplyMatrix(tMtx);
pl.ColorIndex = 1;
app.Database.ModelSpace.Append(pl);
}
else
{
Toaster({
message: "板件有侧面造型无法加工,请运行造型检测命令<checkmodeing>确认",
timeout: 5000,
intent: Intent.DANGER,
key: "造型加工错误"
});
}
for (let hole of soild.Shape.Holes)
{
let cu = hole.Curve.ApplyMatrix(soild.OCSNoClone).ApplyMatrix(tMtx);
cu.ColorIndex = 8;
app.Database.ModelSpace.Append(cu);
}
}
faceContour.ApplyMatrix(tMtx);
faceContour.ColorIndex = 3;
app.Database.ModelSpace.Append(faceContour);
width = faces.Faces[n].Length;
this.OrderText((n + 1).toString(), tMtx, width);
pos.add(new Vector3(width + 100));
}
}
}
private OrderText(order: string, tMtx: Matrix4, width: number)
{
//文本上下间隔 i
let i = -100;
let text = new Text(new Vector3, order);
text.Height = 60;
text.TextAligen = TextAligen.Mid;
text.ApplyMatrix(tMtx);
text.Position = text.Position.add(new Vector3(width * 0.5, i));
app.Database.ModelSpace.Append(text);
}
}

@ -13,7 +13,7 @@ import { TemplateRecord } from "../../DatabaseServices/Template/TemplateRecord";
import { CoordinateSystem } from "../../Geometry/CoordinateSystem"; import { CoordinateSystem } from "../../Geometry/CoordinateSystem";
import { GetBoxArr, IdentityMtx4, equalv2 } from "../../Geometry/GeUtils"; import { GetBoxArr, IdentityMtx4, equalv2 } from "../../Geometry/GeUtils";
import { IContourData } from "../../Production/Convert2PtsBul"; import { IContourData } from "../../Production/Convert2PtsBul";
import { I2DModeling, I3DContourData, I3DModeling, IDrillingOption, IHardwareType, IModelingData, ISpliteHardwareData, ISpliteOrderData, Production } from '../../Production/Product'; import { I2DModeling, I3DContourData, I3DModeling, IDrillingOption, IHardwareType, IModelingData, IOriginModelingData, ISpliteHardwareData, ISpliteOrderData, Production } from '../../Production/Product';
import { EMetalsType } from "../../UI/Components/RightPanel/RightPanelInterface"; import { EMetalsType } from "../../UI/Components/RightPanel/RightPanelInterface";
import { ISealingData } from "../../UI/Store/OptionInterface/IHighSealedItem"; import { ISealingData } from "../../UI/Store/OptionInterface/IHighSealedItem";
import { FaceDirection } from "../DrawDrilling/DrillType"; import { FaceDirection } from "../DrawDrilling/DrillType";
@ -390,7 +390,8 @@ export class ErpParseData
} }
return pointList; return pointList;
} }
//获取造型数据
//获取正反面造型数据
GetModelDetail(DataArray: IModelingData[], frontOrSide: FrontOrSide, isRect: Boolean = false, add: number = 0): CadBlockModel[] GetModelDetail(DataArray: IModelingData[], frontOrSide: FrontOrSide, isRect: Boolean = false, add: number = 0): CadBlockModel[]
{ {
if (DataArray == null) return []; if (DataArray == null) return [];
@ -428,6 +429,32 @@ export class ErpParseData
return modelList; return modelList;
} }
//获取侧面造型数据
GetSideModelDetail(DataArray: IOriginModelingData[]): CadBlockModel[]
{
if (DataArray == null) return [];
let sideModelList: CadBlockModel[] = [];
let modelID: number = 1;
for (let i = 0; i < DataArray.length; i++)
{
if (DataArray[i].outline)
{
let newModel = new CadBlockModel();
newModel.ModelID = modelID;
newModel.LineID = 1;
newModel.Face = DataArray[i].dir;
newModel.KnifeName = "";
newModel.KnifeRadius = DataArray[i].knifeRadius;
newModel.Depth = DataArray[i].thickness;
newModel.OriginModeling = DataArray[i];
sideModelList.push(newModel);
modelID++;
}
}
return sideModelList;
}
GetModelPointDetail(feeding: IContourData, lineID: number, deep: number): CadBlockModelPoint[] GetModelPointDetail(feeding: IContourData, lineID: number, deep: number): CadBlockModelPoint[]
{ {
if (feeding == null) return []; if (feeding == null) return [];
@ -651,7 +678,7 @@ export class ErpParseData
frontModelDetail.push(...this.GetOffSetModelDetail(board.modeling2D, maxID)); frontModelDetail.push(...this.GetOffSetModelDetail(board.modeling2D, maxID));
maxID = frontModelDetail.length + 1; maxID = frontModelDetail.length + 1;
frontModelDetail.push(...this.Get3DModelDetail(board.modeling3D, maxID)); frontModelDetail.push(...this.Get3DModelDetail(board.modeling3D, maxID));
let sideModelDetail = this.GetModelDetail(board.sideModeling, FrontOrSide., board.info.isRect, add); let sideModelDetail = this.GetSideModelDetail(board.sideModeling);
let frontHoleDetail = this.GetHolesDetail(board.holes.frontBackHoles, FrontOrSide.); let frontHoleDetail = this.GetHolesDetail(board.holes.frontBackHoles, FrontOrSide.);
let sideHoleDetail = this.GetHolesDetail(board.holes.sideHoles, FrontOrSide., board.info.isRect, add); let sideHoleDetail = this.GetHolesDetail(board.holes.sideHoles, FrontOrSide., board.info.isRect, add);
let result = new CadBlockInfo(); let result = new CadBlockInfo();

@ -15,10 +15,12 @@ import { Curve } from "../DatabaseServices/Entity/Curve";
import { Entity } from "../DatabaseServices/Entity/Entity"; import { Entity } from "../DatabaseServices/Entity/Entity";
import { EntityFbx } from "../DatabaseServices/Entity/EntityFbx"; import { EntityFbx } from "../DatabaseServices/Entity/EntityFbx";
import { EntityRef } from "../DatabaseServices/Entity/EntityRef"; import { EntityRef } from "../DatabaseServices/Entity/EntityRef";
import { ExtrudeSolid } from "../DatabaseServices/Entity/Extrude";
import { HardwareCompositeEntity } from "../DatabaseServices/Hardware/HardwareCompositeEntity"; import { HardwareCompositeEntity } from "../DatabaseServices/Hardware/HardwareCompositeEntity";
import { Command } from "../Editor/CommandMachine"; import { Command } from "../Editor/CommandMachine";
import { JigUtils } from "../Editor/JigUtils"; import { JigUtils } from "../Editor/JigUtils";
import { PromptStatus } from "../Editor/PromptResult"; import { PromptStatus } from "../Editor/PromptResult";
import { GetBoardContour } from "../GraphicsSystem/CalcEdgeSealing";
import { AppToaster } from "../UI/Components/Toaster"; import { AppToaster } from "../UI/Components/Toaster";
import { UpdateEntityDrawTask } from "./UpdateEntityDrawTask"; import { UpdateEntityDrawTask } from "./UpdateEntityDrawTask";
@ -139,6 +141,10 @@ export class MirrorCommand implements Command
for (let en of ens) for (let en of ens)
{ {
en.ApplyMatrix(mtx); en.ApplyMatrix(mtx);
if (en instanceof Board && en.HasSideModel)
this.MirrorSideModel(en);
if (NEED_ENTITY.some(T => en instanceof T)) if (NEED_ENTITY.some(T => en instanceof T))
en.DeferUpdate();//立即更新 en.DeferUpdate();//立即更新
} }
@ -149,4 +155,32 @@ export class MirrorCommand implements Command
//延迟更新 //延迟更新
this.UpdateTask = new UpdateEntityDrawTask(ens); this.UpdateTask = new UpdateEntityDrawTask(ens);
} }
//侧面造型镜像
MirrorSideModel(br: Board)
{
let newSideModelMap: Map<number, ExtrudeSolid[]> = new Map();
let con = GetBoardContour(br);
let cus = con.Explode() as Curve[];
for (let [num, soilds] of br.SideModelingMap)
{
let index = cus.length - num - 1;
newSideModelMap.set(index, soilds);
const mirrorMtxX = MakeMirrorMtx(new Vector3(1));
for (let so of soilds)
{
const sign = Math.sign(new Vector3().setFromMatrixColumn(so.OCSNoClone, 0).x);
let x = sign * (cus[index].Length - so.Position.x * 2);
so.OCSNoClone.multiply(mirrorMtxX.setPosition(x, 0, 0));
for (let groove of so.Grooves)
groove.OCSNoClone.multiply(mirrorMtxX.setPosition(sign * (cus[index].Length - groove.Position.x * 2), 0, 0));
}
}
br.SideModelingMap = newSideModelMap;
}
} }

@ -0,0 +1,16 @@
import { Matrix4, Vector3 } from "three";
import { Line } from "../../DatabaseServices/Entity/Line";
import { Point } from "../../DatabaseServices/Entity/Point";
import { TestDraw } from "../test/TestUtil";
export async function TestDrawUCS(mat4: Matrix4)
{
let pt = new Vector3().applyMatrix4(mat4);
let l1 = new Line(pt, pt.clone().add(new Vector3().setFromMatrixColumn(mat4, 0).normalize().multiplyScalar(100)));
let l2 = new Line(pt, pt.clone().add(new Vector3().setFromMatrixColumn(mat4, 1).normalize().multiplyScalar(100)));
let l3 = new Line(pt, pt.clone().add(new Vector3().setFromMatrixColumn(mat4, 2).normalize().multiplyScalar(100)));
TestDraw(new Point(pt));
TestDraw(l1, 1);
TestDraw(l2, 3);
TestDraw(l3, 5);
}

@ -141,7 +141,7 @@ export enum CommandNames
FZWL = "FZWL", FZWL = "FZWL",
ActicityLayerBoard = "ACTICITYLAYERBOARD", ActicityLayerBoard = "ACTICITYLAYERBOARD",
TestFb = "TESTFENGBIAN", TestFb = "TESTFENGBIAN",
TestModeling = "TESTMODELING", TestSideModeling = "TESTSIDEMODELING",
Mirror = "MIRROR", Mirror = "MIRROR",
Topline = "TOPLINE", Topline = "TOPLINE",
Winerack = "WINERACK", Winerack = "WINERACK",

@ -57,7 +57,7 @@ export async function TemplateOut(template: TemplateRecord, tempDb = new Databas
if (idMapRev.has(ent.Id)) if (idMapRev.has(ent.Id))
{ {
let oldEnt = idMapRev.get(ent.Id).Object as Entity; let oldEnt = idMapRev.get(ent.Id).Object as Entity;
if (oldEnt instanceof Board && oldEnt.Async2DPathing) if (oldEnt instanceof Board && oldEnt.Async2DPathing && oldEnt.AsyncSideModeling)
{ {
async2DPathingPromis.push( async2DPathingPromis.push(
oldEnt.Load2DPathIng().then((res) => oldEnt.Load2DPathIng().then((res) =>

@ -2,8 +2,9 @@ import Geom3 from '@jscad/modeling/src/geometries/geom3/type';
import { BufferAttribute, BufferGeometry, Euler, FrontSide, Frustum, Geometry, LineSegments, Matrix3, Matrix4, Mesh, Object3D, ShapeGeometry, Line as TLine, UVGenerator, Vector2, Vector3 } from 'three'; import { BufferAttribute, BufferGeometry, Euler, FrontSide, Frustum, Geometry, LineSegments, Matrix3, Matrix4, Mesh, Object3D, ShapeGeometry, Line as TLine, UVGenerator, Vector2, Vector3 } from 'three';
import { ArcBoardBuild } from '../../Add-on/ArcBoard/ArcBoardBuild'; import { ArcBoardBuild } from '../../Add-on/ArcBoard/ArcBoardBuild';
import { ArcBoardOptions, ParseBoardArcFeed, defultArcBoardOption } from '../../Add-on/ArcBoard/ArcBoardFeeding'; import { ArcBoardOptions, ParseBoardArcFeed, defultArcBoardOption } from '../../Add-on/ArcBoard/ArcBoardFeeding';
import { SplitBoardSideModelUtil } from '../../Add-on/BoardCutting/SplitBoardSideModel';
import { Board2Regions } from '../../Add-on/BoardEditor/Board2Regions'; import { Board2Regions } from '../../Add-on/BoardEditor/Board2Regions';
import { DeserializationBoard2DModeingData, DeserializationBoard3DModeingData, SerializeBoard2DModeingData, SerializeBoard3DModeingData, deserializationBoardData, serializeBoardData } from '../../Add-on/BoardEditor/SerializeBoardData'; import { DeserializationBoard2DModeingData, DeserializationBoard3DModeingData, DeserializationBoardSideModeingData, SerializeBoard2DModeingData, SerializeBoard3DModeingData, SerializeBoardSideModeingData, deserializationBoardData, serializeBoardData } from '../../Add-on/BoardEditor/SerializeBoardData';
import { DrillType, FaceDirection } from "../../Add-on/DrawDrilling/DrillType"; import { DrillType, FaceDirection } from "../../Add-on/DrawDrilling/DrillType";
import { CyHoleInBoard, IBoardRectHoleType, ParseBoardRectHoleType, SetBrHighHoleTypeFromRectHoleType } from '../../Add-on/DrawDrilling/HoleUtils'; import { CyHoleInBoard, IBoardRectHoleType, ParseBoardRectHoleType, SetBrHighHoleTypeFromRectHoleType } from '../../Add-on/DrawDrilling/HoleUtils';
import { HostApplicationServices } from '../../ApplicationServices/HostApplicationServices'; import { HostApplicationServices } from '../../ApplicationServices/HostApplicationServices';
@ -14,13 +15,14 @@ import { Geom3Res } from '../../Common/CSGIntersect';
import { ColorMaterial } from '../../Common/ColorPalette'; import { ColorMaterial } from '../../Common/ColorPalette';
import { DisposeThreeObj, Object3DRemoveAll } from '../../Common/Dispose'; import { DisposeThreeObj, Object3DRemoveAll } from '../../Common/Dispose';
import { Log, LogType } from '../../Common/Log'; import { Log, LogType } from '../../Common/Log';
import { TransformVector, tempMatrix1 } from '../../Common/Matrix4Utils'; import { MakeMirrorMtx, TransformVector, tempMatrix1 } from '../../Common/Matrix4Utils';
import { UpdateDraw } from '../../Common/Status'; import { UpdateDraw } from '../../Common/Status';
import { FixedNotZero } from '../../Common/Utils'; import { FixedNotZero } from '../../Common/Utils';
import { safeEval } from '../../Common/eval'; import { safeEval } from '../../Common/eval';
import { ObjectSnapMode } from '../../Editor/ObjectSnapMode'; import { ObjectSnapMode } from '../../Editor/ObjectSnapMode';
import { SelectPick } from '../../Editor/SelectPick'; import { SelectPick } from '../../Editor/SelectPick';
import { Board2DModelCSGBuilder } from '../../Geometry/Board2DModelCSG/Board2DModelCSGBuilder'; import { Board2DModelCSGBuilder } from '../../Geometry/Board2DModelCSG/Board2DModelCSGBuilder';
import { BoardSideModelCSGBuilder, GetSideCuFaceMtx } from '../../Geometry/Board2DModelCSG/BoardSideModelCSGBuilder';
import { boardUVGenerator, boardUVGenerator2 } from '../../Geometry/BoardUVGenerator'; import { boardUVGenerator, boardUVGenerator2 } from '../../Geometry/BoardUVGenerator';
import { Box3Ext } from '../../Geometry/Box'; import { Box3Ext } from '../../Geometry/Box';
import { BufferGeometryUtils } from '../../Geometry/BufferGeometryUtils'; import { BufferGeometryUtils } from '../../Geometry/BufferGeometryUtils';
@ -28,7 +30,7 @@ import { AddCSGSubtractTask, CSGTask, TerminateCSGTask } from '../../Geometry/CS
import { EdgesGeometry } from '../../Geometry/EdgeGeometry'; import { EdgesGeometry } from '../../Geometry/EdgeGeometry';
import { AsVector2, AsVector3, IdentityMtx4, XAxis, XAxisN, YAxis, YAxisN, ZAxis, ZeroVec, equaln, equalv3 } from '../../Geometry/GeUtils'; import { AsVector2, AsVector3, IdentityMtx4, XAxis, XAxisN, YAxis, YAxisN, ZAxis, ZeroVec, equaln, equalv3 } from '../../Geometry/GeUtils';
import { PointShapeUtils } from '../../Geometry/PointShapeUtils'; import { PointShapeUtils } from '../../Geometry/PointShapeUtils';
import { GetBoardHighSeal, GetBoardSealingCurves, GetHighBoardEdgeRemark, SetBoardEdgeRemarkData, SetBoardTopDownLeftRightSealData } from '../../GraphicsSystem/CalcEdgeSealing'; import { GetBoardContour, GetBoardHighSeal, GetBoardSealingCurves, GetHighBoardEdgeRemark, SetBoardEdgeRemarkData, SetBoardTopDownLeftRightSealData } from '../../GraphicsSystem/CalcEdgeSealing';
import { RenderType } from '../../GraphicsSystem/RenderType'; import { RenderType } from '../../GraphicsSystem/RenderType';
import { BoardProcessOption } from "../../UI/Store/OptionInterface/BoardProcessOption"; import { BoardProcessOption } from "../../UI/Store/OptionInterface/BoardProcessOption";
import { CSG2Geometry2, Geometry2CSG2 } from '../../csg/core/Geometry2CSG'; import { CSG2Geometry2, Geometry2CSG2 } from '../../csg/core/Geometry2CSG';
@ -130,6 +132,8 @@ export class Board extends ExtrudeSolid
private _IsChaiDan: boolean = true; private _IsChaiDan: boolean = true;
private _2DModelingList: I2DModeling[] = []; private _2DModelingList: I2DModeling[] = [];
private _3DModelingList: I3DModeling[] = []; private _3DModelingList: I3DModeling[] = [];
//侧面造型
private _SideModelingMap: Map<number, ExtrudeSolid[]> = new Map();
private _CustomNumber: number = null;//自定义编号 private _CustomNumber: number = null;//自定义编号
private _DrillLock = false; //排钻独立锁 private _DrillLock = false; //排钻独立锁
private _DrillAssociationLock = new Set<ObjectId>(); //排钻关联锁 private _DrillAssociationLock = new Set<ObjectId>(); //排钻关联锁
@ -956,6 +960,30 @@ export class Board extends ExtrudeSolid
this.Update(UpdateDraw.Geometry); this.Update(UpdateDraw.Geometry);
} }
//侧面造型
get SideModelingMap()
{
return this._SideModelingMap;
}
set SideModelingMap(sideModelingMap: Map<number, ExtrudeSolid[]>)
{
this.WriteAllObjectRecord();
this.ClearSideModelingCache();
this._SideModelingMap = sideModelingMap;
this.Update(UpdateDraw.Geometry);
}
ClearSideModeling()
{
if (!this._SideModelingMap.size) return;
this.WriteAllObjectRecord();
this.ClearSideModelingCache();
this._SideModelingMap.clear();
this.Update(UpdateDraw.Geometry);
}
ClearModeling2DList() ClearModeling2DList()
{ {
if (this._2DModelingList.length === 0) return; if (this._2DModelingList.length === 0) return;
@ -1135,6 +1163,9 @@ export class Board extends ExtrudeSolid
if (this._SweepPath && !this._FixContourByArcSweepPath_Ing) if (this._SweepPath && !this._FixContourByArcSweepPath_Ing)
this.FixArcSweepPathLength(); this.FixArcSweepPathLength();
if (this.HasSideModel)
this.SplitBoardSideModelUtil.SpiltSideModelOfBrContour(this);
this.Update(); this.Update();
} }
} }
@ -1163,6 +1194,9 @@ export class Board extends ExtrudeSolid
if (this._SweepPath && !this._FixContourByArcSweepPath_Ing) if (this._SweepPath && !this._FixContourByArcSweepPath_Ing)
this.FixArcSweepPathLength(); this.FixArcSweepPathLength();
if (this.HasSideModel)
this.SplitBoardSideModelUtil.SpiltSideModelOfBrContour(this);
this.Update(); this.Update();
} }
} }
@ -1173,6 +1207,9 @@ export class Board extends ExtrudeSolid
{ {
if (!equaln(thickness, this.thickness, 1e-4))//避免18.0009 无法改成 18 if (!equaln(thickness, this.thickness, 1e-4))//避免18.0009 无法改成 18
{ {
if (this.HasSideModel)
this.SplitBoardSideModelUtil.SpiltSideModelOfBrThickness(this, thickness);
super.Thickness = thickness; super.Thickness = thickness;
if (this._SweepPath && !this._FixContourByArcSweepPath_Ing) if (this._SweepPath && !this._FixContourByArcSweepPath_Ing)
this.FixContourByArcSweepPath(); this.FixContourByArcSweepPath();
@ -1256,6 +1293,31 @@ export class Board extends ExtrudeSolid
this._Name = n; this._Name = n;
} }
private UpdateSplitBoardSideModelUtil = true;
private _SplitBoardSideModelUtil: SplitBoardSideModelUtil;
get SplitBoardSideModelUtil(): SplitBoardSideModelUtil
{
if (!this._SplitBoardSideModelUtil)
this._SplitBoardSideModelUtil = new SplitBoardSideModelUtil(this);
return this._SplitBoardSideModelUtil;
}
override GeneralRectContour()
{
//取消异型时,强制使用矩形轮廓 导致原始轮廓数据丢失
if (this.HasSideModel)
{
this.UpdateSplitBoardSideModelUtil = false;
this.SplitBoardSideModelUtil.Init(this, true);
super.GeneralRectContour();
this.UpdateSplitBoardSideModelUtil = true;
}
else
super.GeneralRectContour();
}
/** /**
* ,. * ,.
*/ */
@ -1284,6 +1346,18 @@ export class Board extends ExtrudeSolid
let oldHightSealDatas = GetBoardHighSeal(this, oldHightSealCurves);//旧的封边数据 let oldHightSealDatas = GetBoardHighSeal(this, oldHightSealCurves);//旧的封边数据
let oldHighBoardEdgeRemarkDatas = GetHighBoardEdgeRemark(this, oldHightSealCurves);//旧的封边数据 let oldHighBoardEdgeRemarkDatas = GetHighBoardEdgeRemark(this, oldHightSealCurves);//旧的封边数据
let splitSideModel = false;
if (this.UpdateSplitBoardSideModelUtil && this.HasSideModel)
{
this.SplitBoardSideModelUtil.Init(this); //旧的侧面造型
//记录侧面造型后清空 防止在分裂侧面造型时带入更新mesh
this.WriteAllObjectRecord();
this._SideModelingMap.clear();
splitSideModel = true;
}
let oldContour = this.ContourCurve;//旧的轮廓 let oldContour = this.ContourCurve;//旧的轮廓
let defaultDrillType = this._BoardProcessOption.drillType; let defaultDrillType = this._BoardProcessOption.drillType;
@ -1357,6 +1431,10 @@ export class Board extends ExtrudeSolid
this._BoardProcessOption.highBoardEdgeRemark.push(oldHighBoardEdgeRemarkDatas[closesIndex]); this._BoardProcessOption.highBoardEdgeRemark.push(oldHighBoardEdgeRemarkDatas[closesIndex]);
} }
} }
//分裂侧面造型
if (splitSideModel || this.HasSideModel)
this.SplitBoardSideModelUtil.SetBoardSideModel(this);
} }
Explode() Explode()
@ -1791,9 +1869,38 @@ export class Board extends ExtrudeSolid
} }
//#endregion //#endregion
//#region 侧面造型
_SideModeingCsgs: Geom3[];
private GetSideModeingCsgs(): Geom3[]
{
if (this._SideModeingCsgs)
return this._SideModeingCsgs;
this._SideModeingCsgs = [];
if (!this._SideModelingMap.size)
return this._SideModeingCsgs;
this._SideModeingCsgs = BoardSideModelCSGBuilder(this);
return this._SideModeingCsgs;
}
//清除侧面造型Csgs的缓存
ClearSideModelingCache()
{
this._SideModeingCsgs = undefined;
}
//#endregion 侧面造型
get HasSideModel() { return this._SideModelingMap.size > 0; }
private _asyncSideModelIng = false;
get AsyncSideModeling() { return this._asyncSideModelIng; }
protected get Has2DPath() { return this._2DModelingList.length > 0; } protected get Has2DPath() { return this._2DModelingList.length > 0; }
private _workerCalcedGeom: Geom3 = null;//worker计算后,暂时存入到这里 private _workerCalcedGeom: Geom3 = null;//worker计算后,暂时存入到这里
private _async2DPathIng = false; private _async2DPathIng = false;
get Async2DPathing() { return this._async2DPathIng; } get Async2DPathing() { return this._async2DPathIng; }
override GoodBye(): void override GoodBye(): void
{ {
@ -1815,8 +1922,25 @@ export class Board extends ExtrudeSolid
{ {
if (!this._workerCalcedGeom) if (!this._workerCalcedGeom)
{ {
let path2dCsgs = this.Get2DPathCsgs(); const AllSubtractCSGs: Geom3[] = [];
if (!path2dCsgs.length || !HostApplicationServices.show2DPathObject)
this._async2DPathIng = false;
this._asyncSideModelIng = false;
if (HostApplicationServices.show2DPathObject)
for (let csg of this.Get2DPathCsgs())
{
AllSubtractCSGs.push(csg);
this._async2DPathIng = true;
}
for (let csg of this.GetSideModeingCsgs())
{
AllSubtractCSGs.push(csg);
this._asyncSideModelIng = true;
}
if (!AllSubtractCSGs.length)
{ {
if (geo instanceof Geometry) if (geo instanceof Geometry)
return new BufferGeometry().fromGeometry(geo); return new BufferGeometry().fromGeometry(geo);
@ -1824,18 +1948,18 @@ export class Board extends ExtrudeSolid
} }
let geom = Geometry2CSG2(geo); let geom = Geometry2CSG2(geo);
this._async2DPathIng = true;
// 使用线程池 // 使用线程池
const task: CSGTask = { const task: CSGTask = {
key: this, key: this,
data: [path2dCsgs, geom], data: [AllSubtractCSGs, geom],
then: (e) => then: (e) =>
{ {
let data = e.data as { status: number, geom: Geom3; }; let data = e.data as { status: number, geom: Geom3; };
if (data.status || !data.geom.polygons) if (data.status || !data.geom.polygons)
{ {
this._AsyncIngTextEntity.TextString = "二维刀路建模失败"; this._AsyncIngTextEntity.TextString = "二维刀路或侧面造型建模失败";
Log(`板:${this.Name}二维刀路建模失败!`, LogType.Error, [this]); Log(`板:${this.Name}二维刀路或侧面造型建模失败!`, LogType.Error, [this]);
return; return;
} }
@ -1864,6 +1988,7 @@ export class Board extends ExtrudeSolid
} }
this._async2DPathIng = false; this._async2DPathIng = false;
this._asyncSideModelIng = false;
const newGeom = this._workerCalcedGeom; const newGeom = this._workerCalcedGeom;
this._workerCalcedGeom = undefined;//保护 this._workerCalcedGeom = undefined;//保护
@ -2167,7 +2292,7 @@ export class Board extends ExtrudeSolid
private DrawAsyncText(obj: Object3D) private DrawAsyncText(obj: Object3D)
{ {
if (this._async2DPathIng) if (this._async2DPathIng || this._asyncSideModelIng)
{ {
//#region 添加文字 //#region 添加文字
if (!this._AsyncIngTextEntity) if (!this._AsyncIngTextEntity)
@ -2185,7 +2310,10 @@ export class Board extends ExtrudeSolid
else else
this._AsyncIngTextEntity.OCSNoClone.identity().setPosition(this.width * 0.5, this.height * 0.5, this.thickness * 0.5); this._AsyncIngTextEntity.OCSNoClone.identity().setPosition(this.width * 0.5, this.height * 0.5, this.thickness * 0.5);
this._AsyncIngTextEntity.TextString = "二维刀路建模中!"; if (this._async2DPathIng)
this._AsyncIngTextEntity.TextString = "二维刀路建模中!";
else if (this._asyncSideModelIng)
this._AsyncIngTextEntity.TextString = "侧面造型建模中!";
let o = this._AsyncIngTextEntity.GetDrawObjectFromRenderType(RenderType.Conceptual); let o = this._AsyncIngTextEntity.GetDrawObjectFromRenderType(RenderType.Conceptual);
if (o) if (o)
@ -2289,6 +2417,8 @@ export class Board extends ExtrudeSolid
else else
obj.add(path2d); obj.add(path2d);
} }
this.GetSideModeingCsgs();
} }
} }
@ -2337,6 +2467,51 @@ export class Board extends ExtrudeSolid
} }
} }
private AddSideModelGripPoints(pts: Vector3[], dragPointType: DragPointType)
{
let con = GetBoardContour(this);
let inverseZ = con.Area2 < 0;
let cus = con.Explode() as Curve[];
for (let [index, soilds] of this.SideModelingMap)
{
let cu = cus[index];
if (!cu) continue;
let mt4 = GetSideCuFaceMtx(cus[index], inverseZ);
for (let soild of soilds)
{
const MirrorMtxZ = MakeMirrorMtx(ZAxis);
let s = soild.Clone();
s.ApplyMatrix(MirrorMtxZ);
s.ApplyMatrix(mt4);
s.ApplyMatrix(this.OCSNoClone);
pts.push(...s.GetGripOrStretchPoints(dragPointType));
}
}
}
override GetStrectchPointCountList(dragType: DragPointType): number[]
{
let counts = super.GetStrectchPointCountList(dragType);
if (this.HasSideModel)
{
for (let [num, soilds] of this.SideModelingMap)
{
for (let soild of soilds)
{
let c = soild.ContourCurve.GetDragPointCount(dragType) * 2;
for (let g of soild.Grooves)
c += g.ContourCurve.GetDragPointCount(dragType) * 2;
counts.push(c);
}
}
}
return counts;
}
//因为圆弧板 我们重载了它 //因为圆弧板 我们重载了它
override GetGripPoints(): Vector3[] override GetGripPoints(): Vector3[]
{ {
@ -2387,8 +2562,13 @@ export class Board extends ExtrudeSolid
p.applyMatrix4(mtx); p.applyMatrix4(mtx);
} }
} }
if (this.HasSideModel)
this.AddSideModelGripPoints(pts, DragPointType.Grip);
return pts; return pts;
} }
override MoveGripPoints(indexList: number[], vec: Vector3): void override MoveGripPoints(indexList: number[], vec: Vector3): void
{ {
if (indexList.length === 0) return; if (indexList.length === 0) return;
@ -2429,6 +2609,7 @@ export class Board extends ExtrudeSolid
} }
} }
this.ClearSideModelingCache();
super.MoveGripPoints(indexList, vec); super.MoveGripPoints(indexList, vec);
} }
@ -2482,6 +2663,10 @@ export class Board extends ExtrudeSolid
{ {
pts.push(...m.path.GetStretchPoints().map(p => p.add(new Vector3(0, 0, m.dir === FaceDirection.Front ? this.thickness : 0)).applyMatrix4(this.OCSNoClone))); pts.push(...m.path.GetStretchPoints().map(p => p.add(new Vector3(0, 0, m.dir === FaceDirection.Front ? this.thickness : 0)).applyMatrix4(this.OCSNoClone)));
} }
if (this.HasSideModel)
this.AddSideModelGripPoints(pts, DragPointType.Stretch);
return pts; return pts;
} }
@ -2682,6 +2867,7 @@ export class Board extends ExtrudeSolid
this.Clear2DPathCache(); this.Clear2DPathCache();
this.Clear3DPathCache(); this.Clear3DPathCache();
this.ClearSideModelingCache();
this.Update(UpdateDraw.Geometry); this.Update(UpdateDraw.Geometry);
} }
@ -2996,12 +3182,16 @@ export class Board extends ExtrudeSolid
if (ver > 19) if (ver > 19)
this.AlignLineObject = file.ReadHardObjectId(); this.AlignLineObject = file.ReadHardObjectId();
if (ver > 20)
DeserializationBoardSideModeingData(file, this._SideModelingMap);
this.ClearSideModelingCache();
} }
WriteFile(file: CADFiler) WriteFile(file: CADFiler)
{ {
super.WriteFile(file); super.WriteFile(file);
file.Write(20); file.Write(21);
// file.Write(this._SpaceOCS.toArray()); ver < 6 // file.Write(this._SpaceOCS.toArray()); ver < 6
file.Write(this._BoardType); file.Write(this._BoardType);
file.Write(this._Name); file.Write(this._Name);
@ -3098,6 +3288,9 @@ export class Board extends ExtrudeSolid
//ver 20 //ver 20
file.WriteHardObjectId(this.AlignLineObject); file.WriteHardObjectId(this.AlignLineObject);
//ver 21
SerializeBoardSideModeingData(file, this._SideModelingMap);
} }
} }

@ -13,6 +13,7 @@ import { MakeMirrorMtx, TransformVector, Vector2ApplyMatrix4, reviseMirrorMatrix
import { Status, UpdateDraw } from "../../Common/Status"; import { Status, UpdateDraw } from "../../Common/Status";
import { ObjectSnapMode } from "../../Editor/ObjectSnapMode"; import { ObjectSnapMode } from "../../Editor/ObjectSnapMode";
import { BSPGroupParse } from '../../Geometry/BSPGroupParse'; import { BSPGroupParse } from '../../Geometry/BSPGroupParse';
import { GetSideCuFaceMtx } from '../../Geometry/Board2DModelCSG/BoardSideModelCSGBuilder';
import { boardUVGenerator } from "../../Geometry/BoardUVGenerator"; import { boardUVGenerator } from "../../Geometry/BoardUVGenerator";
import { Box3Ext } from "../../Geometry/Box"; import { Box3Ext } from "../../Geometry/Box";
import { BufferGeometryUtils } from "../../Geometry/BufferGeometryUtils"; import { BufferGeometryUtils } from "../../Geometry/BufferGeometryUtils";
@ -22,6 +23,7 @@ import { ExtrudeGeometryBuilder } from "../../Geometry/ExtrudeMeshGeomBuilder/Ex
import { AsVector2, IdentityMtx4, MoveMatrix, XAxis, YAxis, ZAxis, ZeroVec, equaln, equalv2, equalv3, isIntersect, isParallelTo, isPerpendicularityTo } from "../../Geometry/GeUtils"; import { AsVector2, IdentityMtx4, MoveMatrix, XAxis, YAxis, ZAxis, ZeroVec, equaln, equalv2, equalv3, isIntersect, isParallelTo, isPerpendicularityTo } from "../../Geometry/GeUtils";
import { OBB } from "../../Geometry/OBB/obb"; import { OBB } from "../../Geometry/OBB/obb";
import { ScaleUV, ScaleUV2 } from "../../Geometry/UVUtils"; import { ScaleUV, ScaleUV2 } from "../../Geometry/UVUtils";
import { GetBoardContour } from '../../GraphicsSystem/CalcEdgeSealing';
import { RenderType } from "../../GraphicsSystem/RenderType"; import { RenderType } from "../../GraphicsSystem/RenderType";
import { Geometry2CSG2 } from "../../csg/core/Geometry2CSG"; import { Geometry2CSG2 } from "../../csg/core/Geometry2CSG";
import { BlockTableRecord } from "../BlockTableRecord"; import { BlockTableRecord } from "../BlockTableRecord";
@ -35,6 +37,7 @@ import { ShapeManager } from "../ShapeManager";
import { Spline } from "../Spline"; import { Spline } from "../Spline";
import { Board } from "./Board"; import { Board } from "./Board";
import { Circle } from "./Circle"; import { Circle } from "./Circle";
import { Curve } from './Curve';
import { DragPointType } from "./DragPointType"; import { DragPointType } from "./DragPointType";
import { Ellipse } from "./Ellipse"; import { Ellipse } from "./Ellipse";
import { Entity } from "./Entity"; import { Entity } from "./Entity";
@ -371,6 +374,12 @@ export class ExtrudeSolid extends Entity
return this.grooves; return this.grooves;
} }
//侧面造型
get SideModelingMap(): Map<any, any>
{
return undefined;
}
/** /**
* 线 * 线
*/ */
@ -886,7 +895,9 @@ export class ExtrudeSolid extends Entity
this.WriteAllObjectRecord(); this.WriteAllObjectRecord();
let counts = this.GetStrectchPointCountList(dragType); let counts = this.GetStrectchPointCountList(dragType);
if (dragType === DragPointType.Stretch && indexList.length === arraySum(counts)) const isGrip = dragType === DragPointType.Grip;
if (!isGrip && indexList.length === arraySum(counts))
{ {
this.Position = this.Position.add(vec); this.Position = this.Position.add(vec);
return; return;
@ -897,7 +908,7 @@ export class ExtrudeSolid extends Entity
let updateBak = this.AutoUpdate; let updateBak = this.AutoUpdate;
this.AutoUpdate = false; this.AutoUpdate = false;
if (this.grooves.length === 0) if (!this.grooves.length && !this.HasSideModel)
{ {
this.MoveGripOrStretchPointsOnly(indexList, vec, dragType); this.MoveGripOrStretchPointsOnly(indexList, vec, dragType);
} }
@ -908,6 +919,34 @@ export class ExtrudeSolid extends Entity
let offset = 0; let offset = 0;
let grooveIndex = -1; let grooveIndex = -1;
let sideModelIndex = -1;
let cus: Curve[];
let baseIndexList: Set<number> = new Set();
let sideModelSealCurveMtxCache: Map<number, Matrix4> = new Map();
//获取侧面的OCS
const GetSideModelSealCurveMtx = (num: number): Matrix4 =>
{
if (!cus) cus = GetBoardContour(this as unknown as Board)?.Explode() as Curve[];
let mtx = sideModelSealCurveMtxCache.get(num);
if (!mtx && cus?.length)
{
let cu = cus[num];
if (!cu) return new Matrix4;
let x = cu.GetFirstDeriv(0).normalize().applyMatrix4(this.OCS.setPosition(0, 0, 0));
let y = this.Normal;
let z = x.clone().cross(y);
mtx = new Matrix4().getInverse(new Matrix4().makeBasis(x, y, z));
sideModelSealCurveMtxCache.set(num, mtx);
}
return mtx ?? new Matrix4;
};
for (let count of counts) for (let count of counts)
{ {
offset += count; offset += count;
@ -923,11 +962,145 @@ export class ExtrudeSolid extends Entity
if (ilist.length > 0) if (ilist.length > 0)
{ {
if (grooveIndex === -1) if (grooveIndex === -1)
{
let orgCus = GetBoardContour(this as unknown as Board).Explode() as Curve[];
this.MoveGripOrStretchPointsOnly(ilist, vec, dragType); this.MoveGripOrStretchPointsOnly(ilist, vec, dragType);
else
if (this.HasSideModel)
{
//修正点的索引 判断侧面造型的起点是否被移动
let stretchCount = this.ContourCurve.GetDragPointCount(dragType);
for (let num of ilist)
{
if (num < stretchCount)
baseIndexList.add(num);
else
baseIndexList.add(num - stretchCount);
}
let isChangeThiness = this.IsStretchThickness(Array.from(baseIndexList));
//起点被拉伸时反向移动 达到相对静止状态
const sideModelingMap: Map<number, ExtrudeSolid[]> = this.SideModelingMap;
for (let [num, soilds] of sideModelingMap)
{
let firstIndex = num;
let secondIndex = (num + 1) === stretchCount ? 0 : num + 1;
if (isGrip)
{
firstIndex = num * 2;
//拉取中点时
secondIndex = (firstIndex - 1) < 0 ? (stretchCount - 1) : (firstIndex - 1);
}
//Grip的时候点选中点时两边相连的 也反向移动 firstIndex - 1
if (
!isGrip && (baseIndexList.has(firstIndex) && !baseIndexList.has(secondIndex)) ||
isGrip && (baseIndexList.has(firstIndex) || baseIndexList.has(secondIndex)) ||
isChangeThiness && ilist[0] < stretchCount
)
{
for (let s of soilds)
{
let mtx = GetSideModelSealCurveMtx(num);
let v = vec.clone().applyMatrix4(mtx).setZ(0);
if (isChangeThiness)
{
v.setX(0);
}
else
{
if (cus?.length && cus[num])
v = new Vector3(orgCus[num].Length - cus[num].Length);
else
v.setY(0);
}
s.ApplyMatrix(new Matrix4().setPosition(v.clone().multiplyScalar(-1)));
}
}
}
}
}
else if (grooveIndex < this.grooves.length)
this.grooves[grooveIndex].MoveGripOrStretchPoints(ilist, vec, dragType); this.grooves[grooveIndex].MoveGripOrStretchPoints(ilist, vec, dragType);
else
{
//侧面造型拉伸
const sideModelingMap: Map<number, ExtrudeSolid[]> = this.SideModelingMap;
let soildCount = 0;
const isMainChangeThiness = this.IsStretchThickness(Array.from(baseIndexList));
for (let [num, soilds] of sideModelingMap)
{
soildCount += soilds.length;
if (sideModelIndex < soildCount)
{
let mtx = GetSideModelSealCurveMtx(num);
let v = vec.clone().applyMatrix4(mtx);
if (isMainChangeThiness) v.setX(0);
let soild = soilds[soilds.length - (soildCount - sideModelIndex)];
const stretchPtLength = soild.ContourCurve.GetStretchPoints().length;
const firstIndex = num;
const secondIndex = (num + 1) === stretchPtLength ? 0 : num + 1;
const mainSoildIList: number[] = [];
const grooveSoildIList: number[] = [];
for (let k of ilist)
{
if (k < stretchPtLength * 2)
mainSoildIList.push(k);
else
grooveSoildIList.push(k);
}
//改变侧面造型厚度
if (soild.IsStretchThickness(mainSoildIList))
{
if (mainSoildIList.every(i => i >= stretchPtLength))
{
//造型 底边
v.setZ(-v.z);
}
else if ((baseIndexList.has(firstIndex) && baseIndexList.has(secondIndex)))
{
//造型见光面 和侧面一起移动
ilist = [];
for (let k = 0; k < stretchPtLength; k++)
ilist.push(k + stretchPtLength);
//有选中子槽端点 默认一起改变
if (grooveSoildIList.length)
{
const grooveStretchPtLength = soild.grooves[0].ContourCurve.GetStretchPoints().length;
for (let k = 0; k < grooveStretchPtLength; k++)
ilist.push(k + grooveStretchPtLength + stretchPtLength * 2);
}
}
else
break;
}
else if (!isMainChangeThiness && baseIndexList.has(firstIndex) && baseIndexList.has(secondIndex))
break;
else
v.setZ(0);
soild.MoveGripOrStretchPoints(ilist, v, dragType);
break;
}
}
}
} }
grooveIndex++; grooveIndex++;
if (grooveIndex >= this.grooves.length)
sideModelIndex++;
} }
} }
@ -937,6 +1110,14 @@ export class ExtrudeSolid extends Entity
let splitEntitys: this[] = []; let splitEntitys: this[] = [];
this.GrooveCheckAll(splitEntitys); this.GrooveCheckAll(splitEntitys);
if (this.HasSideModel)
{
let board = (this as unknown as Board);
board.SplitBoardSideModelUtil.Init(board);
board.SplitBoardSideModelUtil.SpiltSideModelOfBrContour(board);
board.SplitBoardSideModelUtil.SpiltSideModelOfBrThickness(board, board.Thickness);
}
if (splitEntitys.length > 0 && this.Owner) if (splitEntitys.length > 0 && this.Owner)
{ {
let ms = this.Owner.Object as BlockTableRecord; let ms = this.Owner.Object as BlockTableRecord;
@ -2012,7 +2193,7 @@ export class ExtrudeSolid extends Entity
} }
protected get Has2DPath() { return false; } protected get Has2DPath() { return false; }
protected get HasSideModel() { return false; }
protected _EdgeGeometry: EdgesGeometry | BufferGeometry; protected _EdgeGeometry: EdgesGeometry | BufferGeometry;
get EdgeGeometry() get EdgeGeometry()
{ {
@ -2026,7 +2207,7 @@ export class ExtrudeSolid extends Entity
return this._EdgeGeometry; return this._EdgeGeometry;
//这里我们超过100就用这个,为了性能 和MaxDrawGrooveCount不一致 //这里我们超过100就用这个,为了性能 和MaxDrawGrooveCount不一致
if (this.grooves.length > 100 || (!this.Has2DPath && (this.grooves.length === 0 || this.grooves.every(g => equaln(g.thickness, this.thickness)))) if (this.grooves.length > 100 || (!this.Has2DPath && !this.HasSideModel && (this.grooves.length === 0 || this.grooves.every(g => equaln(g.thickness, this.thickness))))
) )
{ {
let coords = FastExtrudeEdgeGeometry(this, this.DrawColorIndex, 12, true); let coords = FastExtrudeEdgeGeometry(this, this.DrawColorIndex, 12, true);
@ -2141,6 +2322,11 @@ export class ExtrudeSolid extends Entity
new LineSegments(this.EdgeGeometry, ColorMaterial.GetConceptualEdgeMaterial()) new LineSegments(this.EdgeGeometry, ColorMaterial.GetConceptualEdgeMaterial())
); );
obj.add(this.GetModelGroove()); obj.add(this.GetModelGroove());
if (this.SideModelingMap?.size)
{
obj.add(this.GetSideModelGroove());
}
} }
else if (renderType === RenderType.Physical) else if (renderType === RenderType.Physical)
{ {
@ -2175,6 +2361,7 @@ export class ExtrudeSolid extends Entity
); );
} }
} }
UpdateDrawObjectMaterial(renderType: RenderType, obj: Object3D) UpdateDrawObjectMaterial(renderType: RenderType, obj: Object3D)
{ {
if (renderType === RenderType.Wireframe) if (renderType === RenderType.Wireframe)
@ -2230,11 +2417,47 @@ export class ExtrudeSolid extends Entity
const meshGeo = grooveClone.MeshGeometry; const meshGeo = grooveClone.MeshGeometry;
meshGeo.applyMatrix4(mtx); meshGeo.applyMatrix4(mtx);
const mesh = new Mesh(meshGeo, ColorMaterial.GetConceptualMaterial(1, 0.6)); const mesh = new Mesh(meshGeo, ColorMaterial.GetBasicMaterialTransparent2(1, 0.6));
group.add(mesh, line); group.add(mesh, line);
} }
return group; return group;
} }
private GetSideModelGroove()
{
let board = this as unknown as Board;
const group = new Group();
let con = GetBoardContour(board);
let inverseZ = con.Area2 < 0;
let cus = con.Explode() as Curve[];
const mirrorMtxZ = MakeMirrorMtx(ZAxis);
for (let [index, soilds] of board.SideModelingMap)
{
let cu = cus[index];
if (!cu) continue;
let mt4 = GetSideCuFaceMtx(cus[index], inverseZ);
for (let soild of soilds)
{
const edgeGeo = soild.EdgeGeometry;
const line = new LineSegments(edgeGeo, ColorMaterial.GetLineMaterial(1, this.Freeze));
line.applyMatrix4(mirrorMtxZ);
line.applyMatrix4(mt4.clone().multiply(soild.OCS));
const meshGeo = soild.MeshGeometry;
const mesh = new Mesh(meshGeo, ColorMaterial.GetBasicMaterialTransparent2(1, 0.6));
mesh.applyMatrix4(mirrorMtxZ);
mesh.applyMatrix4(mt4.clone().multiply(soild.OCS));
group.add(mesh, line);
}
}
return group;
}
UpdateJigMaterial(color = 8) UpdateJigMaterial(color = 8)
{ {

@ -218,6 +218,7 @@ import { ImportCFData } from "../Add-on/CF/Import/CFImport";
import { ChangeColorByRoomCabinet } from "../Add-on/ChangeColorByRoomOrCabinet/ChangeColorByRoomOrCabinet"; import { ChangeColorByRoomCabinet } from "../Add-on/ChangeColorByRoomOrCabinet/ChangeColorByRoomOrCabinet";
import { Command_ClearCDBrHoleModeling } from "../Add-on/ClearCDBrHoleModeling"; import { Command_ClearCDBrHoleModeling } from "../Add-on/ClearCDBrHoleModeling";
import { Command_RemovePolylineRepeatPos } from "../Add-on/Cmd_RemovePolylineRepeatPos"; import { Command_RemovePolylineRepeatPos } from "../Add-on/Cmd_RemovePolylineRepeatPos";
import { SideModelFeedingCommand } from "../Add-on/CommandSideModelFeediing";
import { Command_Modeling } from "../Add-on/Command_Modeling"; import { Command_Modeling } from "../Add-on/Command_Modeling";
import { Command_PickUp2DModelCsgs } from "../Add-on/Command_PickUp2DModelCsgs"; import { Command_PickUp2DModelCsgs } from "../Add-on/Command_PickUp2DModelCsgs";
import { Command_TemplateGroup } from "../Add-on/Command_TemplateGroup"; import { Command_TemplateGroup } from "../Add-on/Command_TemplateGroup";
@ -580,6 +581,8 @@ export function registerCommand()
for (let i = 0; i <= 255; i++) commandMachine.RegisterCommand(i.toString(), new ChangeColor(i)); for (let i = 0; i <= 255; i++) commandMachine.RegisterCommand(i.toString(), new ChangeColor(i));
commandMachine.RegisterCommand(CommandNames.TestM, new FeedingCommand()); //模拟走刀 commandMachine.RegisterCommand(CommandNames.TestM, new FeedingCommand()); //模拟走刀
commandMachine.RegisterCommand(CommandNames.TestSideModeling, new SideModelFeedingCommand()); //模拟侧面造型走刀
commandMachine.RegisterCommand(CommandNames.TestFb, new TestFb()); //模拟封边 commandMachine.RegisterCommand(CommandNames.TestFb, new TestFb()); //模拟封边
commandMachine.RegisterCommand(CommandNames.Mirror, new MirrorCommand()); commandMachine.RegisterCommand(CommandNames.Mirror, new MirrorCommand());

@ -0,0 +1,52 @@
import { Geom3, transform } from "@jscad/modeling/src/geometries/geom3";
import { Mat4 } from "@jscad/modeling/src/maths/mat4";
import { Matrix4 } from "three";
import { MakeMirrorMtx } from "../../Common/Matrix4Utils";
import { Board } from "../../DatabaseServices/Entity/Board";
import { Curve } from "../../DatabaseServices/Entity/Curve";
import { GetBoardContour } from "../../GraphicsSystem/CalcEdgeSealing";
import { Geometry2CSG2 } from "../../csg/core/Geometry2CSG";
import { ZAxis } from "../GeUtils";
export function BoardSideModelCSGBuilder(board: Board): Geom3[]
{
const sideModeingCsgs: Geom3[] = [];
if (!board.SideModelingMap.size)
return sideModeingCsgs;
let con = GetBoardContour(board);
let inverseZ = con.Area2 < 0;
let cus = con.Explode() as Curve[];
const mirrorMtxZ = MakeMirrorMtx(ZAxis);
for (let [index, soilds] of board.SideModelingMap)
{
let cu = cus[index];
if (!cu) continue;
let mt4 = GetSideCuFaceMtx(cus[index], inverseZ);
for (let soild of soilds)
{
let s = soild.Clone();
let geom3 = Geometry2CSG2(s.MeshGeometry);
geom3 = transform(mirrorMtxZ.elements as Mat4, geom3);
geom3 = transform(mt4.clone().multiply(soild.OCS).elements as Mat4, geom3);
sideModeingCsgs.push(geom3);
}
}
return sideModeingCsgs;
}
export function GetSideCuFaceMtx(cu: Curve, inverseZ = false): Matrix4
{
let x = cu.GetFirstDeriv(0).normalize();
let y = ZAxis;
let z = x.clone().cross(y);
if (inverseZ) z.negate();
let basePt = cu.StartPoint;
return new Matrix4().makeBasis(x, y, z).setPosition(basePt);
}

@ -1,6 +1,7 @@
import { BufferGeometry, Float32BufferAttribute, Geometry, Line, LineBasicMaterial, LineSegments, Matrix4, Object3D, Vector3 } from "three"; import { BufferGeometry, Float32BufferAttribute, Geometry, Line, LineBasicMaterial, LineSegments, Matrix4, Object3D, Vector3 } from "three";
import { FaceDirection } from "../Add-on/DrawDrilling/DrillType"; import { FaceDirection } from "../Add-on/DrawDrilling/DrillType";
import { ColorMaterial } from "../Common/ColorPalette"; import { ColorMaterial } from "../Common/ColorPalette";
import { MakeMirrorMtx } from "../Common/Matrix4Utils";
import { FixIndex } from "../Common/Utils"; import { FixIndex } from "../Common/Utils";
import { ExtrudeHole } from "../DatabaseServices/3DSolid/ExtrudeHole"; import { ExtrudeHole } from "../DatabaseServices/3DSolid/ExtrudeHole";
import { Contour } from "../DatabaseServices/Contour"; import { Contour } from "../DatabaseServices/Contour";
@ -9,7 +10,9 @@ import { Curve } from "../DatabaseServices/Entity/Curve";
import { ExtrudeSolid } from "../DatabaseServices/Entity/Extrude"; import { ExtrudeSolid } from "../DatabaseServices/Entity/Extrude";
import { Shape } from "../DatabaseServices/Shape"; import { Shape } from "../DatabaseServices/Shape";
import { Shape2 } from "../DatabaseServices/Shape2"; import { Shape2 } from "../DatabaseServices/Shape2";
import { MatrixIsIdentityCS, MoveMatrix } from "./GeUtils"; import { GetBoardContour } from "../GraphicsSystem/CalcEdgeSealing";
import { GetSideCuFaceMtx } from "./Board2DModelCSG/BoardSideModelCSGBuilder";
import { MatrixIsIdentityCS, MoveMatrix, ZAxis } from "./GeUtils";
//FIXME: #IWBPB 性能缺陷和BUG. 等待废弃或者改进 //FIXME: #IWBPB 性能缺陷和BUG. 等待废弃或者改进
export function CreateWireframe(en3D: Board | ExtrudeSolid) export function CreateWireframe(en3D: Board | ExtrudeSolid)
@ -144,6 +147,36 @@ export function FastWireframe(br: ExtrudeSolid, color = 0, divCount = 6, optArc
} }
} }
if (br instanceof Board && br.HasSideModel)
{
let con = GetBoardContour(br);
if (con)
{
let inverseZ = con.Area2 < 0;
let cus = con.Explode() as Curve[];
const mirrorMtxZ = MakeMirrorMtx(ZAxis);
for (let [index, soilds] of br.SideModelingMap)
{
let cu = cus[index];
if (!cu) continue;
let mt4 = GetSideCuFaceMtx(cus[index], inverseZ);
for (let soild of soilds)
{
let lines = FastWireframe(soild, color, 3, false);
for (let line of lines)
{
line.applyMatrix4(mirrorMtxZ);
line.applyMatrix4(soild.OCSNoClone);
line.applyMatrix4(mt4);
result.push(line);
}
}
}
}
}
return result; return result;
} }

@ -0,0 +1,47 @@
import { Matrix4 } from "three";
import { Arc } from "../../DatabaseServices/Entity/Arc";
import { Board } from "../../DatabaseServices/Entity/Board";
import { Curve } from "../../DatabaseServices/Entity/Curve";
import { GetBoardContour } from "../../GraphicsSystem/CalcEdgeSealing";
import { GetSideCuFaceMtx } from "../Board2DModelCSG/BoardSideModelCSGBuilder";
import { equaln } from "../GeUtils";
import { BoardFaceType, BoardGetFace } from "./BoardGetFace";
import { Face } from "./Face";
export class ParseBoardSideFace extends BoardGetFace
{
constructor(public Board: Board)
{
super(Board);
}
ParseFaces()
{
this.GetSideFaces();
}
GetSideFaces()
{
let con = GetBoardContour(this.Board);
let inverseZ = con.Area2 < 0;
let cus = con.Explode() as Curve[];
for (let cu of cus)
{
let type = BoardFaceType.Side;
let length = cu.Length;
if (equaln(length, 0) || cu instanceof Arc)
type = BoardFaceType.NoSide;
let mtx = GetSideCuFaceMtx(cu, inverseZ);
let face = new Face({
type,
localBoard: this.Board,
matrix4: new Matrix4().multiplyMatrices(this.Board.OCS.clone(), mtx),
length,
width: this.Board.Thickness,
});
this.Faces.push(face);
}
}
}

@ -76,6 +76,10 @@ export class CameraUpdate
} }
get Target() { return this._Target; } get Target() { return this._Target; }
set Target(value: Vector3)
{
this._Target = value;
}
get Camera(): Camera get Camera(): Camera
{ {

@ -4,24 +4,28 @@ import { HostApplicationServices } from "../../ApplicationServices/HostApplicati
import { arrayRemoveIf } from "../../Common/ArrayExt"; import { arrayRemoveIf } from "../../Common/ArrayExt";
import { ConverCircleToPolyline, IsRect, MergeCurvelist, equalCurve } from "../../Common/CurveUtils"; import { ConverCircleToPolyline, IsRect, MergeCurvelist, equalCurve } from "../../Common/CurveUtils";
import { LogEnable } from "../../Common/Log"; import { LogEnable } from "../../Common/Log";
import { MakeMirrorMtx } from "../../Common/Matrix4Utils";
import { Singleton } from "../../Common/Singleton"; import { Singleton } from "../../Common/Singleton";
import { ExtrudeHole } from "../../DatabaseServices/3DSolid/ExtrudeHole"; 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 { ExtrudeContourCurve } from "../../DatabaseServices/Entity/Extrude"; import { ExtrudeContourCurve, ExtrudeSolid } from "../../DatabaseServices/Entity/Extrude";
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 { Shape } from "../../DatabaseServices/Shape"; import { Shape } from "../../DatabaseServices/Shape";
import { ShapeManager } from "../../DatabaseServices/ShapeManager"; import { ShapeManager } from "../../DatabaseServices/ShapeManager";
import { GetSideCuFaceMtx } from "../../Geometry/Board2DModelCSG/BoardSideModelCSGBuilder";
import { Box3Ext } from "../../Geometry/Box"; import { Box3Ext } from "../../Geometry/Box";
import { Route } from "../../Geometry/CurveMap"; import { Route } from "../../Geometry/CurveMap";
import { CanDrawHoleFuzz } from "../../Geometry/DrillParse/CanDrawHoleFuzz"; import { CanDrawHoleFuzz } from "../../Geometry/DrillParse/CanDrawHoleFuzz";
import { AsVector2, equaln, isParallelTo } from "../../Geometry/GeUtils"; import { ParseBoardSideFace } from "../../Geometry/DrillParse/ParseBoardSideFace";
import { AsVector2, ZAxis, equaln, isParallelTo } from "../../Geometry/GeUtils";
import { RegionParse } from "../../Geometry/RegionParse"; import { RegionParse } from "../../Geometry/RegionParse";
import { FixIndex } from "../../Nest/Common/Util"; import { FixIndex } from "../../Nest/Common/Util";
import { ParseArcBoardHoles } from "../../Production/Product"; import { ConverToPtsBul } from "../../Production/Convert2PtsBul";
import { IOriginSideModelingData, ModelType, ParseArcBoardHoles } from "../../Production/Product";
import { BoolOpeartionType, isTargetCurInOrOnSourceCur } from "../BoolOperateUtils"; import { BoolOpeartionType, isTargetCurInOrOnSourceCur } from "../BoolOperateUtils";
import { GetBoardContour } from "../CalcEdgeSealing"; import { GetBoardContour } from "../CalcEdgeSealing";
import { GetCurveToInDir, GetOffsetCurves, OptimizeToolPath } from "./OptimizeToolPath"; import { GetCurveToInDir, GetOffsetCurves, OptimizeToolPath } from "./OptimizeToolPath";
@ -211,8 +215,8 @@ export class FeedingToolPath extends Singleton
TestCalcPath(br: Board, isCd = false, rk = 0) TestCalcPath(br: Board, isCd = false, rk = 0)
{ {
let modelings = br.BoardModeling; let modelings = br.BoardModeling;
let allModeling = GetModelingFromCustomDrill(br); let { modeling } = GetModelingFromCustomDrill(br);
modelings.push(...allModeling.modeling); modelings.push(...modeling);
if (isCd && HostApplicationServices.chaidanOption.useDefaultRad) if (isCd && HostApplicationServices.chaidanOption.useDefaultRad)
modelings.forEach(m => m.knifeRadius = HostApplicationServices.chaidanOption.radius); modelings.forEach(m => m.knifeRadius = HostApplicationServices.chaidanOption.radius);
if (isCd) if (isCd)
@ -287,6 +291,46 @@ export class FeedingToolPath extends Singleton
} }
return cus; return cus;
} }
//获取侧面造型走刀
GetSideModelFeedPath(solid: ExtrudeSolid, faceContour: Polyline, redundancyKnif = 0): Curve[]
{
let cus: Curve[] = [];//返回走刀路径
let shape = solid.Shape;
let thickness = solid.Thickness;
let knifeRadius = solid.KnifeRadius;
let addLen = solid.GroovesAddLength;
let addDepth = solid.GroovesAddDepth;
let addWidth = solid.GroovesAddWidth;
if (!knifeRadius) knifeRadius = 3;
if (addDepth)
thickness += addDepth;
if (thickness < 1e-5) return cus;
shape = shape.Clone().ApplyMatrix(solid.OCSNoClone);
shape.Z0();
this.GrooveAddSize(shape, addLen, addWidth);
this.HandleThoughGroove(faceContour, shape, knifeRadius);
//造型半径和刀半径相等,返回重合点的线
let outline = shape.Outline.Curve;
if (outline instanceof Circle && equaln(outline.Radius, knifeRadius))
return [new Polyline([{ pt: AsVector2(outline.Center), bul: 0 }, { pt: AsVector2(outline.Center), bul: 0 }])];
// {
// todo 全深槽
// }
let offsetCus = this.HandleShape(shape, knifeRadius, true, redundancyKnif);
if (offsetCus.length > 1)
cus.push(...OptimizeToolPath(offsetCus, shape, knifeRadius));
return cus;
}
private GrooveAddSize(shape: Shape, addLen: number, addWidth: number) private GrooveAddSize(shape: Shape, addLen: number, addWidth: number)
{ {
shape.Outline.Curve.Position = shape.Outline.Curve.Position.setZ(0); shape.Outline.Curve.Position = shape.Outline.Curve.Position.setZ(0);
@ -359,6 +403,7 @@ export class FeedingToolPath extends Singleton
return cons; return cons;
} }
//检查正反面造型
CheckModeling(br: Board) CheckModeling(br: Board)
{ {
let errorIndexs: number[] = []; let errorIndexs: number[] = [];
@ -377,13 +422,54 @@ export class FeedingToolPath extends Singleton
} }
return errorIndexs; return errorIndexs;
} }
//检查侧面造型
CheckSideModeling(br: Board)
{
if (!br.SideModelingMap.size) return [];
let errorSideModel: ExtrudeSolid[] = [];
let faces = new ParseBoardSideFace(br);
let con = GetBoardContour(br);
let inverseZ = con.Area2 < 0;
let cus = con.Explode() as Curve[];
const mirrorMtxZ = MakeMirrorMtx(ZAxis);
for (let [n, solids] of br.SideModelingMap)
{
let faceContour = faces.Faces[n].Region.ShapeManager.ShapeList[0].Outline.Curve as Polyline;
let mt4 = GetSideCuFaceMtx(cus[n], inverseZ);
for (let solid of solids)
{
// 圆造型拆成孔
// let cu = solid.Shape.Outline.Curve;
// if (!solid.Shape.Holes.length && cu instanceof Circle && cu.Radius < HostApplicationServices.chaidanOption.modeling2HoleRad + 1e-6)
// continue;
let paths = this.GetSideModelFeedPath(solid, faceContour);//走刀路径
if (!paths.length)
{
let s = solid.Clone();
s.ApplyMatrix(mirrorMtxZ);
s.ApplyMatrix(mt4);
s.ApplyMatrix(br.OCS);
errorSideModel.push(s);
}
}
}
return errorSideModel;
}
CheckCustomHole(br: Board) CheckCustomHole(br: Board)
{ {
let { modeling, sideModeling } = GetModelingFromCustomDrill(br); let { modeling } = GetModelingFromCustomDrill(br);
let errHoles: ExtrudeHole[] = []; let errHoles: ExtrudeHole[] = [];
for (let m of [...modeling, ...sideModeling]) for (let m of modeling)
{ {
let cu = m.shape.Outline.Curve; let cu = m.shape.Outline.Curve;
if (m.shape.Holes.length === 0 && cu instanceof Circle && cu.Radius < HostApplicationServices.chaidanOption.modeling2HoleRad + 1e-6) if (m.shape.Holes.length === 0 && cu instanceof Circle && cu.Radius < HostApplicationServices.chaidanOption.modeling2HoleRad + 1e-6)
@ -539,10 +625,11 @@ export function GetModelingFromCustomDrill(br: Board)
{ {
let normal = br.Normal; let normal = br.Normal;
let brInv = br.OCSInv; let brInv = br.OCSInv;
let outline = GetBoardContour(br); let originOutline = GetBoardContour(br) as Polyline;
let outline = originOutline;
let modeling: (IModeling & { originEn: ExtrudeHole; })[] = []; let modeling: (IModeling & { originEn: ExtrudeHole; })[] = [];
let sideModeling: (IModeling & { originEn: ExtrudeHole; })[] = []; let sideModeling: IOriginSideModelingData[] = [];
const holes: ExtrudeHole[] = []; const holes: ExtrudeHole[] = [];
let bbox = br.BoundingBoxInOCS; let bbox = br.BoundingBoxInOCS;
@ -632,11 +719,10 @@ export function GetModelingFromCustomDrill(br: Board)
let boxSize = faceRegionsBox.getSize(new Vector3); let boxSize = faceRegionsBox.getSize(new Vector3);
let extrude = Board.CreateBoard(boxSize.y, boxSize.x, 1); let extrude = Board.CreateBoard(boxSize.y, boxSize.x, 1);
outline = extrude.ContourCurve; outline = extrude.ContourCurve as Polyline;
} }
} }
let diff = brInv.clone().multiply(hole.OCS); let diff = brInv.clone().multiply(hole.OCS);
shape.ApplyMatrix(diff); shape.ApplyMatrix(diff);
let thickness: number; let thickness: number;
@ -686,48 +772,68 @@ export function GetModelingFromCustomDrill(br: Board)
} }
else else
{ {
//侧面非圆造型 if (min.z <= 0 || max.z >= br.Thickness) continue;
//TODO: 拆成侧面造型孔 let spt = hole.Position.applyMatrix4(brInv).setZ(0);
// 有可能Z向量朝向轮廓内部
// if (outline.PtOnCurve(spt)) continue;
// if (min.z <= 0 || max.z >= br.Thickness) continue; let line = new Line(spt, hole.Position.add(hole.Normal.multiplyScalar(hole.Height)).applyMatrix4(brInv).setZ(0));
// let spt = hole.Position.applyMatrix4(brInv).setZ(0); let pt = outline.IntersectWith(line, 0)[0];
if (!pt) continue;
// if (outline.PtOnCurve(spt)) continue; let thickness = 0;
// let line = new Line(spt, hole.Position.add(hole.Normal.multiplyScalar(hole.Height)).applyMatrix4(brInv).setZ(0)); for (let p of [line.StartPoint, line.EndPoint])
// let pt = outline.IntersectWith(line, 0)[0]; {
// if (!pt) continue; if (outline.PtInCurve(p))
{
// let index = Math.floor(outline.GetParamAtPoint(pt)); thickness = p.distanceTo(pt);
// let thickness = line.StartPoint.distanceTo(pt); break;
}
// let shape = hole.Shape.ApplyMatrix(hole.OCS).ApplyMatrix(brInv); }
// let vec = line.GetFirstDeriv(0).normalize().multiplyScalar(thickness);
// shape.Position = shape.Position.add(vec); let index = Math.floor(outline.GetParamAtPoint(pt));
// //侧面造型仅在多段线直线上 let vec = line.GetFirstDeriv(0).normalize().multiplyScalar(thickness);
// let cu = (outline as Polyline).GetCurveAtIndex(index); shape.Position = shape.Position.add(vec);
// shape.ApplyMatrix(new Matrix4().getInverse(GetSideFaceMtx(cu)));
if (br.IsArcBoard)
// if (br.IsArcBoard) {
// { //弧形板需要单独增加差值
// //弧形板需要单独增加差值 shape.Position = shape.Position.add(addPos);
// shape.Position = shape.Position.add(addPos);
if (br.SweepAngle)
// if (br.SweepAngle) {
// { let ocsInv = new Matrix4().getInverse(br.ArcBuild.OCS2RotateMtx);
// let ocsInv = new Matrix4().getInverse(br.ArcBuild.Rotate2OCSMtx); pt.applyMatrix4(ocsInv);
// shape.ApplyMatrix(ocsInv); shape.ApplyMatrix(ocsInv);
// } }
// } }
// sideModeling.push({ if (br.IsArcBoard)
// shape, {
// thickness, //侧面造型仅在多段线直线上
// dir: index, //因为侧面造型起点特殊性 要处理一下
// knifeRadius: hole.KnifeRadius, index = Math.floor(originOutline.GetParamAtPoint(pt));
// addLen: 0, let cu = originOutline.GetCurveAtIndex(index);
// originEn: hole, shape.ApplyMatrix(new Matrix4().getInverse(GetSideCuFaceMtx(cu)));
// }); }
else
{
let cu = outline.GetCurveAtIndex(index);
shape.ApplyMatrix(new Matrix4().getInverse(GetSideCuFaceMtx(cu)));
}
sideModeling.push({
outline: ConverToPtsBul(shape.Outline.Curve, false),
holes: shape.Holes.map((cu) => ConverToPtsBul(cu.Curve, false)),
thickness,
dir: index,
knifeRadius: hole.KnifeRadius,
addLen: 0,
addDepth: 0,
addWidth: 0,
modelType: ModelType.drill
});
} }
} }

@ -25,6 +25,7 @@ import { HardwareCompositeEntity } from "../DatabaseServices/Hardware/HardwareCo
import { HardwareTopline } from "../DatabaseServices/Hardware/HardwareTopline"; import { HardwareTopline } from "../DatabaseServices/Hardware/HardwareTopline";
import { Shape } from "../DatabaseServices/Shape"; import { Shape } from "../DatabaseServices/Shape";
import { CanDrawHoleFuzz } from "../Geometry/DrillParse/CanDrawHoleFuzz"; import { CanDrawHoleFuzz } from "../Geometry/DrillParse/CanDrawHoleFuzz";
import { ParseBoardSideFace } from "../Geometry/DrillParse/ParseBoardSideFace";
import { AsVector2, IsBetweenA2B, MoveMatrix, XAxis, angle, angleTo, equaln, equalv2, equalv3, isIntersect2, isParallelTo, isPerpendicularityTo } from "../Geometry/GeUtils"; import { AsVector2, IsBetweenA2B, MoveMatrix, XAxis, angle, angleTo, equaln, equalv2, equalv3, isIntersect2, isParallelTo, isPerpendicularityTo } from "../Geometry/GeUtils";
import { BrSealedData, GetSealedBoardContour } from "../GraphicsSystem/CalcEdgeSealing"; import { BrSealedData, GetSealedBoardContour } from "../GraphicsSystem/CalcEdgeSealing";
import { FeedingToolPath, GetModelingFromCustomDrill } from "../GraphicsSystem/ToolPath/FeedingToolPath"; import { FeedingToolPath, GetModelingFromCustomDrill } from "../GraphicsSystem/ToolPath/FeedingToolPath";
@ -115,7 +116,7 @@ export interface ISpliteOrderData
modeling: IModelingData[]; //造型信息 modeling: IModelingData[]; //造型信息
curveBoardModeling: IModeling[]; curveBoardModeling: IModeling[];
holes: IBoardHoleInfo; //孔信息 holes: IBoardHoleInfo; //孔信息
sideModeling: IModelingData[]; //侧面造型信息 sideModeling: IOriginSideModelingData[]; //侧面造型信息
offsetTanslation: Vector3; offsetTanslation: Vector3;
originOutlin: IContourData; //不扣封边拆单原始轮廓 originOutlin: IContourData; //不扣封边拆单原始轮廓
metalsData?: { metals: number, comp: number; }; //板件五金 metalsData?: { metals: number, comp: number; }; //板件五金
@ -151,6 +152,20 @@ export interface IOriginModelingData
addDepth?: number; addDepth?: number;
} }
export interface IOriginSideModelingData extends IOriginModelingData
{
chaiDanName?: string;
modelType: ModelType;
}
export enum ModelType
{
frontBackModel = 0, //正反面造型槽
sideModel = 1,//绘制的侧槽造型
drill = 2, //自定义排钻生成的非圆侧孔
sideHoleModel = 3,//绘制的圆侧槽
}
interface IChaiDanFeedingData extends IOriginModelingData interface IChaiDanFeedingData extends IOriginModelingData
{ {
boardContour: IContourData; boardContour: IContourData;
@ -190,7 +205,11 @@ export namespace Production
const curveBoardModeling = br.ArcBoardModeling; const curveBoardModeling = br.ArcBoardModeling;
//正反面造型 自定义不规则排钻孔
let { modeling, sideModeling } = GetBoardModelingData(br, offsetTanslation, redundancyKnif, curveBoardModeling); let { modeling, sideModeling } = GetBoardModelingData(br, offsetTanslation, redundancyKnif, curveBoardModeling);
//侧面造型
let { sideModel, sideHole } = GetBoardSideModelingData(br, true);
sideModeling.push(...sideModel);
let boardContour: IContourData; let boardContour: IContourData;
if (GetSpiteSize(br)) if (GetSpiteSize(br))
@ -209,6 +228,9 @@ export namespace Production
orgContour.Reverse(); orgContour.Reverse();
} }
let holes = GetBoardHolesData(br, offsetTanslation, orgContour);
holes.sideHoles.push(...sideHole);
return { return {
info: GetBoardInfo(br, size), info: GetBoardInfo(br, size),
originOutlin: originOutlinePtsBul,//拼错了 未扣封边的点表 originOutlin: originOutlinePtsBul,//拼错了 未扣封边的点表
@ -217,7 +239,7 @@ export namespace Production
boardEdgeRemark: perBoardEdgeRemarkData, //每段曲线的板边备注信息 boardEdgeRemark: perBoardEdgeRemarkData, //每段曲线的板边备注信息
modeling, modeling,
curveBoardModeling, curveBoardModeling,
holes: GetBoardHolesData(br, offsetTanslation, orgContour), holes,
sideModeling, sideModeling,
offsetTanslation, offsetTanslation,
metalsData: GetBoardMetals(br), metalsData: GetBoardMetals(br),
@ -385,10 +407,8 @@ export namespace Production
}; };
let allModeling = GetModelingFromCustomDrill(br); let allModeling = GetModelingFromCustomDrill(br);
let modeling = getModelings([...br.BoardModeling, ...allModeling.modeling]); let modeling = getModelings([...br.BoardModeling, ...allModeling.modeling]);
let sideModeling = GetBoardSideModelingData(br);
let sideModeling = getModelings(allModeling.sideModeling);
return { modeling, sideModeling }; return { modeling, sideModeling };
} }
@ -402,7 +422,7 @@ export namespace Production
{ {
const tool = FeedingToolPath.GetInstance(); const tool = FeedingToolPath.GetInstance();
const tMtx = MoveMatrix(offsetTanslation.clone().negate()); const tMtx = MoveMatrix(offsetTanslation.clone().negate());
const getModelings = (ms: IModeling[], isSide: boolean): IModelingData[] => const getModelings = (ms: IModeling[]): IModelingData[] =>
{ {
let data: IModelingData[] = []; let data: IModelingData[] = [];
@ -414,8 +434,7 @@ export namespace Production
if (HostApplicationServices.chaidanOption.useDefaultRad) if (HostApplicationServices.chaidanOption.useDefaultRad)
m.knifeRadius = HostApplicationServices.chaidanOption.radius; m.knifeRadius = HostApplicationServices.chaidanOption.radius;
let paths = tool.GetModelFeedPath(br, m, redundancyKnif);//走刀路径 let paths = tool.GetModelFeedPath(br, m, redundancyKnif);//走刀路径
if (!isSide) paths.forEach(path => path.ApplyMatrix(tMtx));
paths.forEach(path => path.ApplyMatrix(tMtx));
//走刀的ptsbuls //走刀的ptsbuls
let feeding = paths.map((c: ExtrudeContourCurve) => ConverToPtsBul(c, false)); let feeding = paths.map((c: ExtrudeContourCurve) => ConverToPtsBul(c, false));
@ -448,17 +467,91 @@ export namespace Production
let allModeling = GetModelingFromCustomDrill(br); let allModeling = GetModelingFromCustomDrill(br);
let modeling = getModelings([...br.BoardModeling, ...allModeling.modeling, ...curveBoardModeling], false).filter(f => f.feeding.length > 0); let modeling = getModelings([...br.BoardModeling, ...allModeling.modeling, ...curveBoardModeling]).filter(f => f.feeding.length > 0);
return { modeling, sideModeling: allModeling.sideModeling };
}
let sideModeling = getModelings(allModeling.sideModeling, true).filter(f => f.feeding.length > 0); export function GetBoardSideModelingData(br: Board, toaster = false)
{
let sideModel: IOriginSideModelingData[] = [];
let sideHole: IDrillingOption[] = [];
return { modeling, sideModeling }; if (!br.SideModelingMap.size) return { sideModel, sideHole };
const tool = FeedingToolPath.GetInstance();
let faces = new ParseBoardSideFace(br);
for (let [num, solids] of br.SideModelingMap)
{
let faceContour = faces.Faces[num].Region.ShapeManager.ShapeList[0].Outline.Curve as Polyline;
for (let solid of solids)
{
let cu = solid.Shape.Outline.Curve.Clone().ApplyMatrix(solid.OCSNoClone);
let modelType = ModelType.sideModel;
// 圆造型拆成孔类型
if (!solid.Shape.Holes.length && cu instanceof Circle && cu.Radius < HostApplicationServices.chaidanOption.modeling2HoleRad + 1e-6)
{
let mtx = br.OCSInv.multiply(faces.Faces[num].OCS);
let position = cu.Position.clone().applyMatrix4(mtx);
let endPt = cu.Position.clone().setZ(-solid.Thickness).applyMatrix4(mtx);
// cu.ApplyMatrix(mtx);
// TestDraw(cu);
// TestDraw(new Point(position));
// TestDraw(new Point(endPt));
sideHole.push({
position, //排钻开始位置
endPt, //排钻结束的位置(在板的坐标系)
radius: cu.Radius, //排钻半径
depth: solid.Thickness, //排钻的插入深度
face: num, //板在哪个边上
name: "",
type: null
});
continue;
}
let knifeRadius = solid.KnifeRadius;
if (HostApplicationServices.chaidanOption.useDefaultRad)
knifeRadius = HostApplicationServices.chaidanOption.radius;
let paths = tool.GetSideModelFeedPath(solid, faceContour);//走刀路径
if (paths.length)
{
sideModel.push({
thickness: solid.Thickness + (solid.GroovesAddDepth ?? 0),
dir: num,
knifeRadius,
outline: ConverToPtsBul(cu, false),
holes: solid.Shape.Holes.map((cu) => ConverToPtsBul(cu.Curve.Clone().ApplyMatrix(solid.OCSNoClone), false)),
addLen: solid.GroovesAddLength,
addWidth: solid.GroovesAddWidth,
addDepth: solid.GroovesAddDepth,
modelType
});
}
else if (toaster)
{
Toaster({
message: "板件有侧面造型或者自定义排钻无法加工,请运行造型检测命令<checkmodeing>确认",
timeout: 5000,
intent: Intent.DANGER,
key: "侧面造型加工错误"
});
}
}
}
return { sideModel, sideHole };
} }
//获得拆单尺寸 //获得拆单尺寸
export function GetSpiteSize(br: Board) export function GetSpiteSize(br: Board)
{ {
let [spHeight, spWidth, spThickness] = [br.BoardProcessOption.spliteHeight, br.BoardProcessOption.spliteWidth, br.BoardProcessOption.spliteThickness]; let [spHeight, spWidth, spThickness] = [br.BoardProcessOption?.spliteHeight, br.BoardProcessOption?.spliteWidth, br.BoardProcessOption?.spliteThickness];
const isEffect = HostApplicationServices.chaidanOption.partialSplitValueCanTakesEffect; const isEffect = HostApplicationServices.chaidanOption.partialSplitValueCanTakesEffect;
const param = { L: br.Height, W: br.Width, H: br.Thickness }; const param = { L: br.Height, W: br.Width, H: br.Thickness };

@ -52,6 +52,7 @@ import { BoardOpenDirSelect, BoardTypeComponent, ItemName, SetBoardDataBlock, Se
import { BoardModalType } from "./BoardModalType"; import { BoardModalType } from "./BoardModalType";
import { BoardOptionModal } from "./BoardOptionModal"; import { BoardOptionModal } from "./BoardOptionModal";
import { LastExtractBoardContour } from "./LastExtractBoardContour"; import { LastExtractBoardContour } from "./LastExtractBoardContour";
import { SideModelingEditor } from "./SideModelingEditor";
import { DialogUserConfig } from "./UserConfigComponent"; import { DialogUserConfig } from "./UserConfigComponent";
interface BoardConfigProps interface BoardConfigProps
@ -61,6 +62,7 @@ interface BoardConfigProps
br: Board; br: Board;
canDrawSpeical: IObservableValue<boolean>; canDrawSpeical: IObservableValue<boolean>;
canModeling: IObservableValue<boolean>; canModeling: IObservableValue<boolean>;
canSideModeling: IObservableValue<boolean>;
canCurve: IObservableValue<boolean>; canCurve: IObservableValue<boolean>;
grooveOption: IGrooveOption; grooveOption: IGrooveOption;
uiBoardConfig: IUiOption<BoardConfigOption>; uiBoardConfig: IUiOption<BoardConfigOption>;
@ -105,6 +107,7 @@ export class BoardConfigModal extends React.Component<BoardConfigProps, {}>
grooveOption, grooveOption,
canDrawSpeical, canDrawSpeical,
canModeling, canModeling,
canSideModeling,
canCurve, canCurve,
arcBoardOptions, arcBoardOptions,
arcBoardConfig, arcBoardConfig,
@ -166,18 +169,13 @@ export class BoardConfigModal extends React.Component<BoardConfigProps, {}>
/> />
<div> <div>
<Checkbox <Checkbox
style={{ style={{ marginRight: 6 }}
marginRight: 7
}}
checked={canDrawSpeical.get()} checked={canDrawSpeical.get()}
label="异形" label="异形"
inline={true} inline={true}
onChange={() => canDrawSpeical.set(!canDrawSpeical.get())} onChange={() => canDrawSpeical.set(!canDrawSpeical.get())}
/> />
<Checkbox <Checkbox
style={{
marginRight: 7
}}
checked={canModeling.get()} checked={canModeling.get()}
label="造型" label="造型"
inline={true} inline={true}
@ -190,11 +188,28 @@ export class BoardConfigModal extends React.Component<BoardConfigProps, {}>
/> />
<Button <Button
intent={Intent.PRIMARY} intent={Intent.PRIMARY}
style={{ marginLeft: 5 }}
onClick={this.ChangeModeling} onClick={this.ChangeModeling}
text="修改" /> text="修改" />
</div> </div>
<div className="flex"> <div className="flex">
<div style={{ marginRight: 10 }}> <Checkbox
style={{ marginTop: 6 }}
checked={canSideModeling.get()}
label="侧面造型"
inline={true}
onChange={() => canSideModeling.set(!canSideModeling.get())}
/>
<div style={{ marginLeft: 4 }}>
<Button
intent={Intent.PRIMARY}
text="编辑"
onClick={this.EditorSideModeling}
/>
</div>
</div>
<div className="flex">
<div style={{ marginRight: 22 }}>
<Button <Button
intent={Intent.PRIMARY} intent={Intent.PRIMARY}
text="二维刀路" text="二维刀路"
@ -208,14 +223,12 @@ export class BoardConfigModal extends React.Component<BoardConfigProps, {}>
onClick={this.PickUpModelingOutline3} onClick={this.PickUpModelingOutline3}
/> />
<Button <Button
style={{ marginLeft: 5 }}
intent={Intent.PRIMARY} intent={Intent.PRIMARY}
onClick={this.ChangeModeling3} onClick={this.ChangeModeling3}
text="修改" /> text="修改" />
</div> </div>
</div> </div>
<div style={{ fontWeight: "bold" }}>
:!
</div>
{ {
this.isCurveBoard && this.isCurveBoard &&
<> <>
@ -1168,4 +1181,37 @@ export class BoardConfigModal extends React.Component<BoardConfigProps, {}>
this.props.br.Modeling3D = modelingList; this.props.br.Modeling3D = modelingList;
}, "修改三维刀路"); }, "修改三维刀路");
}; };
//编辑侧面造型
private EditorSideModeling = async () =>
{
let br = this.props.br;
if ((br.BoardProcessOption.spliteHeight ||
br.BoardProcessOption.spliteHeight ||
br.BoardProcessOption.spliteHeight) && !br.IsRect
)
{
AppToaster.show({
message: "板件有拆单值且是异形板不支持绘制侧面造型!",
timeout: 5000,
intent: Intent.WARNING,
});
return;
}
const rightStore = RightPanelStore.GetInstance();
rightStore.m_IsShow = true;
rightStore.modelingStore.isNotUpdateStore = true;
let config = new DialogUserConfig(rightStore.modelingStore, BoardModalType.Zx);
await config.LoadAndInitConfig();
rightStore.m_TabId = RightTabId.Model;
setTimeout(async () =>//当前命令结束后在进入编辑
{
let Editor = new SideModelingEditor(this.props.br);
await Editor.StartEditor();
rightStore.modelingStore.isNotUpdateStore = false;
}, 0);
};
} }

@ -123,6 +123,7 @@ class BoardOptionCom extends React.Component<ICommonOptionProps, {}>
br={this.props._CurrentBoard.get()} br={this.props._CurrentBoard.get()}
canDrawSpeical={this.props.canDrawSpecial} canDrawSpeical={this.props.canDrawSpecial}
canModeling={this.props.canModeling} canModeling={this.props.canModeling}
canSideModeling={this.props.canSideModeling}
canCurve={this.props.canCurve} canCurve={this.props.canCurve}
grooveOption={this.props._GrooveOption} grooveOption={this.props._GrooveOption}
uiBoardConfig={this.props.uiConfigOption} uiBoardConfig={this.props.uiConfigOption}

@ -33,6 +33,7 @@ export interface ICommonOptionProps
drillsOption?: IBoardRectHoleType; drillsOption?: IBoardRectHoleType;
canDrawSpecial?: IObservableValue<boolean>; canDrawSpecial?: IObservableValue<boolean>;
canModeling?: IObservableValue<boolean>; canModeling?: IObservableValue<boolean>;
canSideModeling?: IObservableValue<boolean>;
canCurve: IObservableValue<boolean>; canCurve: IObservableValue<boolean>;
_IsSpecialBoard?: IObservableValue<boolean>; _IsSpecialBoard?: IObservableValue<boolean>;
otherBoardData: { [key: string]: any; }; otherBoardData: { [key: string]: any; };
@ -70,6 +71,7 @@ export function AddCommonBoardProps(Com: React.ComponentType<ICommonOptionProps>
public _IsSpecialBoard = observable.box(false); public _IsSpecialBoard = observable.box(false);
public canDrawSpecial = observable.box(true); public canDrawSpecial = observable.box(true);
public canModeling = observable.box(true); public canModeling = observable.box(true);
public canSideModeling = observable.box(true);
public canCurve = observable.box(true); public canCurve = observable.box(true);
public arcBoardOptions = observable.map(new Map()); public arcBoardOptions = observable.map(new Map());
public remarks: [string, string][] = observable(Array.from({ length: 12 }, () => ["", ""]) as [string, string][]); public remarks: [string, string][] = observable(Array.from({ length: 12 }, () => ["", ""]) as [string, string][]);
@ -106,6 +108,7 @@ export function AddCommonBoardProps(Com: React.ComponentType<ICommonOptionProps>
drillsOption={this.drillsOption} drillsOption={this.drillsOption}
canDrawSpecial={this.canDrawSpecial} canDrawSpecial={this.canDrawSpecial}
canModeling={this.canModeling} canModeling={this.canModeling}
canSideModeling={this.canSideModeling}
canCurve={this.canCurve} canCurve={this.canCurve}
_IsSpecialBoard={this._IsSpecialBoard} _IsSpecialBoard={this._IsSpecialBoard}
otherBoardData={this.otherBoardData} otherBoardData={this.otherBoardData}
@ -123,6 +126,7 @@ export function AddCommonBoardProps(Com: React.ComponentType<ICommonOptionProps>
this._IsSpecialBoard.set(this.CurrentBoard.IsSpecialShape); this._IsSpecialBoard.set(this.CurrentBoard.IsSpecialShape);
this.canDrawSpecial.set(this.CurrentBoard.IsSpecialShape); this.canDrawSpecial.set(this.CurrentBoard.IsSpecialShape);
this.canModeling.set(this.CurrentBoard.HasGroove); this.canModeling.set(this.CurrentBoard.HasGroove);
this.canSideModeling.set(this.CurrentBoard.HasSideModel);
this.canCurve.set(this.CurrentBoard.IsArcBoard); this.canCurve.set(this.CurrentBoard.IsArcBoard);
let ro = this.CurrentBoard.Rotation; let ro = this.CurrentBoard.Rotation;
@ -318,6 +322,10 @@ export function AddCommonBoardProps(Com: React.ComponentType<ICommonOptionProps>
if (!this.canModeling.get() && board.HasGroove) if (!this.canModeling.get() && board.HasGroove)
board.ClearBoardModeling(); board.ClearBoardModeling();
//取消勾选侧面造型,清除侧面造型
if (!this.canSideModeling.get() && board.HasSideModel)
board.ClearSideModeling();
//取消勾选异形,板件回复正常形状 //取消勾选异形,板件回复正常形状
if (!this.canDrawSpecial.get() && !isRect) if (!this.canDrawSpecial.get() && !isRect)
board.ConverToRectSolid(); board.ConverToRectSolid();
@ -380,6 +388,7 @@ export function AddCommonBoardProps(Com: React.ComponentType<ICommonOptionProps>
board.ClearBoardModeling(); board.ClearBoardModeling();
board.ClearLayerNails(); board.ClearLayerNails();
board.ClearRelevance(); board.ClearRelevance();
board.ClearSideModeling();
} }
} }
else else
@ -392,6 +401,7 @@ export function AddCommonBoardProps(Com: React.ComponentType<ICommonOptionProps>
board.ClearBoardModeling(); board.ClearBoardModeling();
board.ClearLayerNails(); board.ClearLayerNails();
board.ClearRelevance(); board.ClearRelevance();
board.ClearSideModeling();
} }
} }
} }

@ -0,0 +1,622 @@
import { Button, Intent } from "@blueprintjs/core";
import React from "react";
import { Box3, LineSegments, Matrix4, Mesh, Object3D, Vector3 } from "three";
import { FaceDirection } from "../../../Add-on/DrawDrilling/DrillType";
import { app } from "../../../ApplicationServices/Application";
import { ColorMaterial } from "../../../Common/ColorPalette";
import { curveLinkGroup } from "../../../Common/CurveUtils";
import { GroupEntitysByBox } from "../../../Common/GroupEntitysByBox";
import { Log } from "../../../Common/Log";
import { MakeMirrorMtx } from "../../../Common/Matrix4Utils";
import { UpdateDraw } from "../../../Common/Status";
import { GetEntity } from "../../../Common/Utils";
import { CADFiler } from "../../../DatabaseServices/CADFiler";
import { Contour } from "../../../DatabaseServices/Contour";
import { Board, IModeling } from "../../../DatabaseServices/Entity/Board";
import { Curve } from "../../../DatabaseServices/Entity/Curve";
import { Ellipse } from "../../../DatabaseServices/Entity/Ellipse";
import { ExtrudeSolid } from "../../../DatabaseServices/Entity/Extrude";
import { Polyline } from "../../../DatabaseServices/Entity/Polyline";
import { Region } from "../../../DatabaseServices/Entity/Region";
import { Spline } from "../../../DatabaseServices/Spline";
import { CommandWrap } from "../../../Editor/CommandMachine";
import { PromptStatus } from "../../../Editor/PromptResult";
import { TempEditor } from "../../../Editor/TempEditor";
import { userConfig } from "../../../Editor/UserConfig";
import { CreateContours } from "../../../Geometry/CreateContour2";
import { BoardFaceType } from "../../../Geometry/DrillParse/BoardGetFace";
import { Face } from "../../../Geometry/DrillParse/Face";
import { ParseBoardSideFace } from "../../../Geometry/DrillParse/ParseBoardSideFace";
import { ContourTreeNode } from "../../../Geometry/ExtrudeMeshGeomBuilder/ExtrudeEdgeGeometry2";
import { ZAxis, angleTo, equalv3 } from "../../../Geometry/GeUtils";
import { CameraUpdate } from "../../../GraphicsSystem/CameraUpdate";
import { RenderType } from "../../../GraphicsSystem/RenderType";
import { Board_Editor_Key } from "../../Store/RightPanelStore/BoardEdgesEditor";
import { RightPanelStore } from "../../Store/RightPanelStore/RightPanelStore";
import { AppConfirm } from "../Common/Confirm";
import { AppToaster } from "../Toaster";
export class SideModelingEditor
{
private Board: Board;
private SideFaces: Face[] = [];
private AroundBoardMesh: Object3D[] = []; //周围板件
private SideModelEdgeGeom: Object3D[] = []; //已存在侧面造型边线
private CurrentFace: Face; //选择编辑的侧面
private CurrentFaceIndex: number;
private CurrentFaceOCS: Matrix4;
private CurrentFaceOCSInv: Matrix4;
private CurrentSideContour: Polyline; //选择编辑的侧面轮廓
private Editoring = false;
private CameraFiler: CADFiler;
private OpacityBak: number;
private BackUCSMatrix: Matrix4;
private BackVisibleUCS: boolean;
private RenderTypeBak: RenderType;
private ShowSaveCancleButton: boolean = false;
constructor(br: Board)
{
this.Board = br;
}
StartEditor = async () =>
{
if (this.Editoring)
throw "重复进入编辑模式!";
this.Editoring = true;
this.Init();
this.ShowToaster(); //保存或取消
this.Start();
await this.SelectSideFace(); //选择侧面
if (this.Editoring)
this.AddModelingCurve(); //添加自身已存在的测槽
};
AddModelingCurve()
{
CommandWrap(async () =>
{
for (const face of this.SideFaces)
{
let region = face.Region;
region.Erase();
}
//添加最外圈轮廓
this.CurrentSideContour = this.CurrentFace.Region.ShapeManager.ShapeList[0].Outline.Curve as Polyline;
app.Database.ModelSpace.Append(this.CurrentSideContour);
//添加该面已有造型轮廓
const SideModelingList = this.Board.SideModelingMap.get(this.CurrentFaceIndex);
if (SideModelingList?.length)
{
const rightPanelStore = RightPanelStore.GetInstance();
let dataColorMap = new Map<string, number>();//data->color
let canUseColor: number[] = [];//可使用的颜色(无高度)
let onUseColor: number[] = [];//已经使用的颜色
let colorIndex = 1;
for (let item of rightPanelStore.modelingStore.modelingItems)
{
let str = [item.height, item.knifeRad, item.addLen, item.addWidth, item.addDepth].join("-");
if (dataColorMap.has(str) || item.height === 0)//重复的相同设定一样没有意义,所以可以覆盖
canUseColor.push(item.color);//可以被覆盖
else
dataColorMap.set(str, item.color);//记录颜色
}
for (let solid of SideModelingList)
{
let str = [solid.Thickness, solid.KnifeRadius, solid.GroovesAddLength, solid.GroovesAddWidth, solid.GroovesAddDepth].join("-");
let color: number;
if (dataColorMap.has(str))
color = dataColorMap.get(str);
else
{
color = canUseColor[0];
if (!color)
{
while (colorIndex < 24)
{
if (!onUseColor.includes(colorIndex)) break;
colorIndex++;
}
color = colorIndex;
}
canUseColor.shift();
dataColorMap.set(str, color);
const data: IModeling = {
shape: undefined,
thickness: solid.Thickness,
dir: FaceDirection.Front,
knifeRadius: solid.KnifeRadius,
addLen: solid.GroovesAddLength,
addWidth: solid.GroovesAddWidth,
addDepth: solid.GroovesAddDepth
};
rightPanelStore.modelingStore.ChangeModelingValue(color - 1, data);
}
onUseColor.push(color);
let cu = solid.ContourCurve.Clone().ApplyMatrix(new Matrix4().multiplyMatrices(this.CurrentFace.OCS, solid.OCS));
cu.ColorIndex = color;
app.Database.ModelSpace.Append(cu);
//添加子集
for (let c of solid.Shape.Holes)
{
cu = c.Curve.Clone().ApplyMatrix(new Matrix4().multiplyMatrices(this.CurrentFace.OCS, solid.OCS));
cu.ColorIndex = color;
app.Database.ModelSpace.Append(cu);
}
}
}
}, "选择侧面");
}
private Init()
{
let br = this.Board;
if (
this.Board.BoardProcessOption.spliteHeight ||
this.Board.BoardProcessOption.spliteWidth ||
this.Board.BoardProcessOption.spliteThickness
)
{
br = br.Clone();
br.BoardProcessOption.spliteHeight = "";
br.BoardProcessOption.spliteWidth = "";
br.BoardProcessOption.spliteThickness = "";
}
let bgf = new ParseBoardSideFace(br);
this.SideFaces = bgf.Faces;
}
private ShowToaster()
{
AppToaster.show({
message: this.RenderToasterMessage(),
intent: Intent.PRIMARY,
timeout: 0,
onDismiss: () => this.EndEditor()
}, Board_Editor_Key);
}
private RenderToasterMessage = () =>
{
return (
<div className="flex-between toaster-message">
<span></span>
{
<div>
<Button text="保存" minimal onClick={async () => { await this.ParseCurveLinkGroup(); }} />
<Button text="取消" minimal onClick={() => { AppToaster.dismiss(Board_Editor_Key); }} />
</div>
}
</div>
);
};
//分析绘画造型曲线轮廓
private async ParseCurveLinkGroup()
{
if (!this.ShowSaveCancleButton) return;
let contourMap = new Map<number, Contour[]>();
let hasDrawNoHeight = false;
await CommandWrap(async () =>
{
const Curves: Set<Curve> = new Set();
for (let obj of app.Viewer.Scene.children)
{
if (obj.visible)
{
let ent = GetEntity(obj);
if (ent && ent.Id?.Object && ent.Visible && !ent.IsErase && ent instanceof Curve)
{
if (ent instanceof Ellipse || ent instanceof Spline)
{
let temp = ent.Convert2Polyline();
temp.__CachePolyline__ = ent;
Curves.add(temp);
}
else if (ent !== this.CurrentSideContour)
Curves.add(ent);
}
}
}
const curGroups = curveLinkGroup(Array.from(Curves));
const rightStore = RightPanelStore.GetInstance();
if (curGroups.length)
{
let box = this.CurrentSideContour.BoundingBox;
for (let g of curGroups)
{
for (let c of g)
{
let cd = rightStore.modelingStore.modelingItems[c.ColorIndex - 1];
if (!cd || cd.height <= 0)
{
hasDrawNoHeight = true;
break;
}
if (box.intersectsBox(c.BoundingBox))
{
//在创建内部造型时,如果存在封闭的轮廓或者圆,那么自动分裂将失效(需要用户自己裂开)
let contours = CreateContours(g);
if (!contourMap.has(c.ColorIndex))
contourMap.set(c.ColorIndex, contours);
else
contourMap.get(c.ColorIndex).push(...contours);
break;
}
}
}
}
}, "解析侧面造型");
if (hasDrawNoHeight)
{
let status = await AppConfirm.show({
message: "检查到部分造型轮廓未设置高度,是否继续?",
confirmButtonText: "确定",
intent: Intent.WARNING
});
if (!status)
return;
}
AppToaster.dismiss(Board_Editor_Key);
await this.AddModeling(contourMap);
}
private async AddModeling(contourMap: Map<number, Contour[]>)
{
const rightStore = RightPanelStore.GetInstance();
const SideModelingSolidList: ExtrudeSolid[] = [];
for (let [color, contours] of contourMap)
{
for (let con of contours)
con.Curve.ApplyMatrix(this.CurrentFaceOCSInv);
let cd = rightStore.modelingStore.modelingItems[color - 1];
//分析包含关系
let contourNodes = contours.map(contour => new ContourTreeNode(contour));
ContourTreeNode.ParseContourTree(contourNodes);
for (let contourNode of contourNodes)
{
if (contourNode.IsHole) continue;
let solid = new ExtrudeSolid();
solid.Thickness = cd.height;
solid.ContourCurve = contourNode.contour.Curve;
solid.KnifeRadius = cd.knifeRad;
solid.GroovesAddLength = cd.addLen;
solid.GroovesAddWidth = cd.addWidth;
solid.GroovesAddDepth = cd.addDepth;
for (let hole of contourNode.children)
{
let holeSolid = new ExtrudeSolid();
holeSolid.Thickness = cd.height;
holeSolid.ContourCurve = hole.contour.Curve;
solid.AppendGroove(holeSolid);
}
SideModelingSolidList.push(solid);
}
}
CommandWrap(() =>
{
this.Board.WriteAllObjectRecord();
if (SideModelingSolidList.length)
this.Board.SideModelingMap.set(this.CurrentFaceIndex, SideModelingSolidList);
else
this.Board.SideModelingMap.delete(this.CurrentFaceIndex);
this.Board.ClearSideModelingCache();
this.Board.Update(UpdateDraw.Geometry);
}, "应用侧面造型");
}
private async Start()
{
app.Editor.ModalManage.ToggleShow();
app.Editor.MaskManage.Clear();
TempEditor.Start();
//记录初始
this.BackUCSMatrix = app.Editor.UCSMatrix;
this.BackVisibleUCS = app.Editor.UcsServices.Visible;
this.OpacityBak = userConfig.ConceptualOpacity;
this.RenderTypeBak = userConfig.RenderType;
this.CameraFiler = new CADFiler;
app.Viewer.CameraCtrl.WriteFile(this.CameraFiler);
//初始视角 俯视图
// app.Viewer.CameraCtrl.LookAt(ZAxisN);
// app.Viewer.CameraCtrl.ZoomExtentsBox3(this.Board.BoundingBoxInOCS);
// app.Viewer.CameraCtrl.Zoom(1.3);
// app.Editor.UcsServices.Visible = false;
userConfig.RenderType = RenderType.Conceptual;
//获取周围板件
let aroundBoard = app.Database.ModelSpace.Entitys.filter((ent) => ent && ent.IsVisible && ent instanceof Board) as Board[];
let groupEntMap = GroupEntitysByBox(aroundBoard);
CommandWrap(() =>
{
const MirrorMtxZ = MakeMirrorMtx(ZAxis);
let b = new Board();
b.Thickness = this.Board.Thickness;
b.ContourCurve = this.Board.ContourCurve;
let cloneBrMesh = new Mesh(b.MeshGeometry, ColorMaterial.GetBasicMaterialTransparent(this.Board.ColorIndex, 0.3));
cloneBrMesh["freeze"] = true;
cloneBrMesh.applyMatrix4(this.Board.OCSNoClone);
TempEditor.editorScene.add(cloneBrMesh);
this.AroundBoardMesh.push(cloneBrMesh);
for (let [index, soilds] of this.Board.SideModelingMap)
{
let face = this.SideFaces[index];
if (!face) continue;
for (let soild of soilds)
{
//添加原板件网格
let line = new LineSegments(soild.EdgeGeometry, ColorMaterial.GetConceptualEdgeMaterial());
line.applyMatrix4(MirrorMtxZ);
line.applyMatrix4(soild.OCS);
line.applyMatrix4(face.OCS);
TempEditor.editorScene.add(line);
this.SideModelEdgeGeom.push(line);
}
}
for (let [box, brs] of groupEntMap)
{
if (brs.find((br) => br === this.Board))
{
for (let br of brs)
{
if (br === this.Board) continue;
let geo = br.MeshGeometry;
let aroundMesh = new Mesh(geo, ColorMaterial.GetBasicMaterialTransparent(br.ColorIndex, 0.1));
aroundMesh["freeze"] = true;
aroundMesh.applyMatrix4(br.OCSNoClone);
TempEditor.editorScene.add(aroundMesh);
this.AroundBoardMesh.push(aroundMesh);
}
break;
}
}
//侧面面域
for (let face of this.SideFaces)
{
if (face.type === BoardFaceType.Side)
{
let region = face.Region;
region.ShapeApplyMatrix(face.OCS);
region.ColorIndex = this.Board.ColorIndex;
app.Database.ModelSpace.Append(region);
}
}
}, "编辑侧面造型");
app.Database.hm.lockIndex++;//禁止初始化动作被撤销
}
private async EndEditor()
{
if (!this.Editoring) return;
//马上标记为否,避免重入
this.Editoring = false;
await app.Editor.ModalManage.EndExecingCmd();
app.Editor.UcsServices.Visible = this.BackVisibleUCS;
app.Editor.UCSMatrix = this.BackUCSMatrix;
userConfig.ConceptualOpacity = this.OpacityBak;
app.Viewer.CameraCtrl.ReadFile(this.CameraFiler);
userConfig.RenderType = this.RenderTypeBak;
TempEditor.End();
app.Editor.Cancel();
this.SideFaces = [];
this.AroundBoardMesh = [];
this.SideModelEdgeGeom = [];
this.CurrentSideContour = undefined;
this.CameraFiler = undefined;
this.BackUCSMatrix = undefined;
this.ShowSaveCancleButton = false;
app.Editor.ModalManage.ToggleShow();
app.Editor.MaskManage.OnFocusEvent();
}
private SelectSideFace = async () =>
{
let enRes = await app.Editor.GetEntity({
Msg: "选择该板件的一个侧面:",
Filter: { filterTypes: [Region] },
NotNone: true,
Callback: (res) =>
{
if (res.Status === PromptStatus.OK)
{
if (app.Viewer.OutlinePass.selectedObjects[0] !== res.Entity.DrawObject)
{
app.Viewer.OutlinePass.selectedObjects = [res.Entity.DrawObject];
app.Viewer.UpdateRender();
}
}
else
{
app.Viewer.OutlinePass.selectedObjects = [];
app.Viewer.UpdateRender();
}
}
});
if (enRes.Status !== PromptStatus.OK)
{
AppToaster.dismiss(Board_Editor_Key);
return;
};
app.Editor.SelectCtrl.Cancel();
const firstMesh = this.AroundBoardMesh.shift();
for (const Mesh of this.AroundBoardMesh)
TempEditor.editorScene.remove(Mesh);
let index = this.SideFaces.findIndex((face) => face.Region === enRes.Entity);
if (index === -1)
{
Log("出错了,找不到选择面位置");
return;
}
this.CurrentFaceIndex = index;
this.CurrentFace = this.SideFaces[index];
this.CurrentFaceOCS = this.CurrentFace.OCS;
this.CurrentFaceOCSInv = new Matrix4().getInverse(this.CurrentFaceOCS);
this.ShowSaveCancleButton = true;
const CameraUpDir = new Vector3().setFromMatrixColumn(this.CurrentFaceOCS, 2).normalize().multiplyScalar(-1);
//旋转至选择面
await RotateCamera(this.Board.OCS, this.Board.BoundingBox, CameraUpDir, 70, this.Board.Normal);
//设置世界坐标系
app.Editor.SetUCSLookAt(CameraUpDir);
app.Editor.UCSMatrix = this.CurrentFaceOCS;
TempEditor.editorScene.remove(firstMesh);
for (const obj of this.SideModelEdgeGeom)
TempEditor.editorScene.remove(obj);
};
}
//旋转至面视角
export async function RotateCamera(UCSMatrix: Matrix4, box: Box3, lookAtDir: Vector3, totalSegments: number = 100, cameraUpDir = new Vector3(0, 0, 1)): Promise<void>
{
return new Promise<void>((res) =>
{
const cameraControl = app.Viewer.CameraControl;
const currentCameraUp = cameraControl.Camera.up;
const currentDir = app.Viewer.CameraControl.Direction;
const currentViewHeight = app.Viewer.CameraControl.ViewHeight;
//最终观察视角
const cameraControlClone = new CameraUpdate();
cameraControlClone.SetSize(cameraControl.Width, cameraControl.Height);
cameraControlClone.LookAt(lookAtDir);
cameraControlClone.ZoomExtentsBox3(box.clone());
cameraControlClone.Zoom(1.2);
const EndViewHeight = cameraControlClone.ViewHeight;
// ----获取相机曲线控制点 begin------
let controlMidPt = lookAtDir.clone();
const OCS = UCSMatrix.clone();
let norZ = new Vector3().setFromMatrixColumn(OCS, 2);
controlMidPt = currentDir.clone().sub(norZ.clone().multiplyScalar(currentDir.dot(norZ)));
let an = angleTo(controlMidPt, lookAtDir, norZ);
let normalV = controlMidPt.clone().normalize();
if (!normalV.length())
{
controlMidPt = new Vector3(0, 1).applyMatrix4(app.Editor.UCSMatrix).add(lookAtDir).multiplyScalar(0.5);
if (equalv3(controlMidPt, new Vector3))
an = Math.PI / 2;
}
//相机朝向角度较大时 使用中点过渡
if (Math.abs(an) >= Math.PI / 2)
controlMidPt = lookAtDir.clone().applyMatrix4(new Matrix4().makeRotationAxis(norZ, Math.sign(-an) * Math.PI / 2));
else
controlMidPt = currentDir.clone().add(lookAtDir).multiplyScalar(0.5);
const ControlPoints = [
currentDir, // 起始点
controlMidPt, // 控制中点
lookAtDir // 结束点
];
// ----获取相机曲线控制点 end------
let index = 0;
let time = setInterval(() =>
{
// 当前分段参数
const totalSeg = index / totalSegments;
// 计算贝塞尔曲线上对应 t 值的点
const dirPt = EvaluateBezierCurve(ControlPoints, totalSeg);
// 相机的上方向向量
const cameraUp = new Vector3().lerpVectors(currentCameraUp, cameraUpDir, totalSeg);
const traget = box.getCenter(new Vector3);
cameraControl.LookAt(dirPt);
cameraControl.Camera.up = cameraUp;
cameraControl.Target = traget;
cameraControl.ViewHeight = currentViewHeight - (currentViewHeight - EndViewHeight) * totalSeg;
cameraControl.Update();
app.Viewer.UpdateRender();
if (index === totalSegments)
{
clearInterval(time);
return res();
}
index++;
}, 10);
});
}
// 贝塞尔曲线求值函数
function EvaluateBezierCurve(controlPoints: Vector3[], t: number): Vector3
{
let n = controlPoints.length - 1;
let result = new Vector3(0, 0, 0);
for (let i = 0; i <= n; i++)
{
let binomialCoefficient = BinomialCoefficient(n, i);
let powerTerm = Math.pow(1 - t, n - i) * Math.pow(t, i);
result.addScaledVector(controlPoints[i], binomialCoefficient * powerTerm);
}
return result;
}
// 计算二项式系数
function BinomialCoefficient(n: number, k: number): number
{
let result = 1;
for (let i = 1; i <= k; i++)
{
result *= (n - i + 1) / i;
}
return result;
}

@ -948,6 +948,15 @@ export const CommandList: ICommand[] = [
chName: "模拟造型走刀+排钻+封边", chName: "模拟造型走刀+排钻+封边",
chDes: "", chDes: "",
}, },
{
typeId: "bjbj",
link: `#`,
defaultCustom: CommandNames.TestSideModeling,
command: CommandNames.TestSideModeling,
type: "模拟侧面造型加工结果",
chName: "模拟侧面造型走刀",
chDes: "",
},
{ {
typeId: "bjbj", typeId: "bjbj",
defaultCustom: "BBB", defaultCustom: "BBB",

@ -85,6 +85,7 @@ class BoardPropsCom extends React.Component<ICommonOptionProps, {}>
br={this.props._CurrentBoard.get()} br={this.props._CurrentBoard.get()}
canDrawSpeical={this.props.canDrawSpecial} canDrawSpeical={this.props.canDrawSpecial}
canModeling={this.props.canModeling} canModeling={this.props.canModeling}
canSideModeling={this.props.canSideModeling}
canCurve={this.props.canCurve} canCurve={this.props.canCurve}
grooveOption={this.props._GrooveOption} grooveOption={this.props._GrooveOption}
uiBoardConfig={this.props.uiConfigOption} uiBoardConfig={this.props.uiConfigOption}

@ -1,7 +1,7 @@
import { FuzzyFactory } from "./FuzzyFactory"; import { FuzzyFactory } from "./FuzzyFactory";
import { EPS } from "./constants"; import { EPS } from "./constants";
import { Polygon } from "./math/Polygon3";
import { Plane } from "./math/Plane"; import { Plane } from "./math/Plane";
import { Polygon } from "./math/Polygon3";
import { Vertex3D } from "./math/Vertex3"; import { Vertex3D } from "./math/Vertex3";
export class FuzzyCSGFactory export class FuzzyCSGFactory

Loading…
Cancel
Save