From 9a75fbbe7705d59babd36d1c8b01492857916ab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E8=AF=97=E6=B4=A5?= <2723065175@qq.com> Date: Mon, 4 Mar 2024 03:30:40 +0000 Subject: [PATCH] =?UTF-8?q?!2522=20=E5=8A=9F=E8=83=BD:=E6=99=A8=E4=B8=B0?= =?UTF-8?q?=E5=BC=80=E6=94=BE=E5=AF=BC=E5=85=A5=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __test__/CFImport/CFDoc.json | 246 +++++++++++ __test__/CFImport/CFImport.test.ts | 314 +++++++++++++ .../__snapshots__/CFImport.test.ts.snap | 15 + .../Import/BoardMaterialLoader.ts} | 2 +- src/Add-on/CF/Import/CFImport.ts | 117 +++++ src/Add-on/CF/Import/CFInterface.ts | 206 +++++++++ src/Add-on/CF/Parse/ParseBoard.ts | 217 +++++++++ src/Add-on/CF/Parse/ParseCurve.ts | 44 ++ src/Add-on/CF/Parse/ParseEntityTree.ts | 89 ++++ .../CF/Parse/ParseHardwareAndTemplate.ts | 118 +++++ .../CF/Parse/ParseHardwareAndTemplateInfo.ts | 181 ++++++++ src/Add-on/CF/doc.md | 414 ++++++++++++++++++ src/Add-on/JiaJu/Import/JiaJuImport.ts | 4 +- src/Common/CommandNames.ts | 1 + src/Editor/CommandRegister.ts | 4 + src/UI/Components/CommandPanel/CommandList.ts | 9 + src/UI/Components/Template/ToplineList.tsx | 18 +- 17 files changed, 1995 insertions(+), 4 deletions(-) create mode 100644 __test__/CFImport/CFDoc.json create mode 100644 __test__/CFImport/CFImport.test.ts create mode 100644 __test__/CFImport/__snapshots__/CFImport.test.ts.snap rename src/Add-on/{JiaJu/Import/JiaJuLoader.ts => CF/Import/BoardMaterialLoader.ts} (98%) create mode 100644 src/Add-on/CF/Import/CFImport.ts create mode 100644 src/Add-on/CF/Import/CFInterface.ts create mode 100644 src/Add-on/CF/Parse/ParseBoard.ts create mode 100644 src/Add-on/CF/Parse/ParseCurve.ts create mode 100644 src/Add-on/CF/Parse/ParseEntityTree.ts create mode 100644 src/Add-on/CF/Parse/ParseHardwareAndTemplate.ts create mode 100644 src/Add-on/CF/Parse/ParseHardwareAndTemplateInfo.ts create mode 100644 src/Add-on/CF/doc.md diff --git a/__test__/CFImport/CFDoc.json b/__test__/CFImport/CFDoc.json new file mode 100644 index 000000000..c9f55c0f7 --- /dev/null +++ b/__test__/CFImport/CFDoc.json @@ -0,0 +1,246 @@ +{ + "ModelSpace": [ + { + "Name": "层板", + "Type": "Board", + "ColorIndex": 2, + "RoomName": "板主卧", + "CabinetName": "板标准柜", + "Rot": [ + 90, + 0, + 0 + ], + "Pos": [ + 20, + 0, + 0 + ], + "ContourCurve": [ + { + "pt": [ + 0, + 0 + ], + "bul": 0 + }, + { + "pt": [ + 0, + 100 + ], + "bul": 0 + }, + { + "pt": [ + 80, + 100 + ], + "bul": 0 + }, + { + "pt": [ + 80, + 0 + ], + "bul": 0 + }, + { + "pt": [ + 0, + 0 + ], + "bul": 0 + } + ], + "Thickness": 18, + "BrMatName": "默认板材5厘", + "Matrial": "生态板", + "Color": "经典檀木", + "BrType": 1, + "PositionType": 0, + "OpenDir": 0, + "Lines": 0, + "BigHole": 0, + "ComposingFace": 2, + "UpSealed": "1.5", + "DownSealed": "1.5", + "LeftSealed": "1.5", + "RightSealed": "1.5", + "EachEdgeDrills": [ + "三合一", + "三合一", + "三合一", + "三合一" + ], + "Remarks": [ + [ + "备注1", + "434" + ], + [ + "备注2", + "434" + ] + ], + "Holes": [ + { + "Type": "ExtrudeSolid", + "ColorIndex": 2, + "Pos": [ + 10, + 0, + 0 + ], + "ContourCurve": [ + { + "pt": [ + 0, + 0 + ], + "bul": 0 + }, + { + "pt": [ + 0, + 20 + ], + "bul": 0 + }, + { + "pt": [ + 10, + 20 + ], + "bul": 0 + }, + { + "pt": [ + 10, + 0 + ], + "bul": 0 + } + ] + } + ], + "GroovesAddLength": 0, + "GroovesAddWidth": 0, + "GroovesAddDepth": 0, + "KnifeRadius": 3 + }, + { + "Type": "Hardware", + "BoxSize": [ + 50, + 30, + 60 + ], + "RoomName": "五金主卧", + "CabinetName": "五金标准柜", + "Name": "五金", + "Unit": "个", + "ActualExpr": "L*W*H", + "Model": "X-1", + "Factory": "厂家晨丰", + "Brand": "品牌晨丰", + "Spec": "{L*2}", + "Comments": "五金备注", + "IsHole": true, + "Material": "五金材质", + "Color": "五金颜色" + }, + { + "Type": "Topline", + "BoxSize": [ + 50, + 30, + 60 + ], + "RoomName": "顶线主卧", + "CabinetName": "顶线标准柜", + "Name": "顶线", + "Unit": "个", + "ActualExpr": "L*W*H", + "Model": "X-1", + "Factory": "厂家晨丰", + "Brand": "品牌晨丰", + "Spec": "{L*2}", + "Comments": "顶线备注", + "Contour": [ + { + "pt": [ + 0, + 0 + ], + "bul": 0 + }, + { + "pt": [ + 0, + 20 + ], + "bul": 0 + }, + { + "pt": [ + 20, + 20 + ], + "bul": 0 + }, + { + "pt": [ + 20, + 0 + ], + "bul": 0 + }, + { + "pt": [ + 0, + 0 + ], + "bul": 0 + } + ], + "PathCurve": [ + { + "pt": [ + 0, + 0 + ], + "bul": 0 + }, + { + "pt": [ + 0, + 100 + ], + "bul": 0 + }, + { + "pt": [ + 100, + 100 + ], + "bul": 0 + }, + { + "pt": [ + 100, + 0 + ], + "bul": 0 + }, + { + "pt": [ + 0, + 0 + ], + "bul": 0 + } + ] + } + ] +} diff --git a/__test__/CFImport/CFImport.test.ts b/__test__/CFImport/CFImport.test.ts new file mode 100644 index 000000000..17a79d745 --- /dev/null +++ b/__test__/CFImport/CFImport.test.ts @@ -0,0 +1,314 @@ +import { ParseCFDoc } from "../../src/Add-on/CF/Import/CFImport"; +import { CFBoard, CFDoc, CFEntityTree, CFHardware, CFTemplate, CFTopline } from "../../src/Add-on/CF/Import/CFInterface"; +import { ParseBoard } from "../../src/Add-on/CF/Parse/ParseBoard"; +import { ParseAddEntity, ParseEntityTree } from "../../src/Add-on/CF/Parse/ParseEntityTree"; +import { ParseTemplate } from "../../src/Add-on/CF/Parse/ParseHardwareAndTemplate"; +import { ParseHardwareInfo, ParseTemplateInfo, ParseToplineInfo } from "../../src/Add-on/CF/Parse/ParseHardwareAndTemplateInfo"; +import { CADFiler } from "../../src/DatabaseServices/CADFiler"; +import { Database } from "../../src/DatabaseServices/Database"; +import { Board } from "../../src/DatabaseServices/Entity/Board"; +import { BoardType } from "../../src/DatabaseServices/Entity/BoardInterface"; +import { Entity } from "../../src/DatabaseServices/Entity/Entity"; +import { Polyline } from "../../src/DatabaseServices/Entity/Polyline"; +import { HardwareCompositeEntity } from "../../src/DatabaseServices/Hardware/HardwareCompositeEntity"; +import { HardwareTopline } from "../../src/DatabaseServices/Hardware/HardwareTopline"; +import { TemplateRecord } from "../../src/DatabaseServices/Template/TemplateRecord"; + +const testBr: CFBoard = { + Name: "层板", + Type: "Board", + ColorIndex: 2, + RoomName: "板主卧", + CabinetName: "板标准柜", + Rot: [90, 0, 0], + Pos: [20, 0, 0], + ContourCurve: [ + { pt: [0, 0], bul: 0 }, + { pt: [0, 100], bul: 0 }, + { pt: [80, 100], bul: 0 }, + { pt: [80, 0], bul: 0 }, + { pt: [0, 0], bul: 0 } + ], + Thickness: 18, + BrMatName: "默认板材5厘", + Matrial: "生态板", + Color: "经典檀木", + BrType: 1, + PositionType: 0, + OpenDir: 0, + Lines: 0, + BigHole: 0, + ComposingFace: 2, + UpSealed: "1.5", + DownSealed: "1.5", + LeftSealed: "1.5", + RightSealed: "1.5", + EachEdgeDrills: ["三合一", "三合一", "三合一", "三合一"], + Remarks: [["备注1", "434"], ["备注2", "434"]], + Holes: [ + { + Type: "ExtrudeSolid", + ColorIndex: 2, + Pos: [10, 0, 0], + ContourCurve: [ + { pt: [0, 0], bul: 0 }, + { pt: [0, 20], bul: 0 }, + { pt: [10, 20], bul: 0 }, + { pt: [10, 0], bul: 0 }, + ] + }], + GroovesAddLength: 0, + GroovesAddWidth: 0, + GroovesAddDepth: 0, + KnifeRadius: 3, +}; + +const testBr2 = Object.assign({}, testBr); +testBr2.Pos = [150, 0, 0]; + +const testBr3 = Object.assign({}, testBr); +testBr2.Pos = [300, 0, 0]; + +const entityTree2: CFEntityTree = { + Type: "EntityTree", + Name: "实体2", + Entitys: [ + testBr3 + ], +}; + +const entityTree: CFEntityTree = { + Type: "EntityTree", + Name: "实体1", + Childen: [ + entityTree2, + ], + Entitys: [ + testBr2 + ] +}; + +const testTemp: CFTemplate = { + Type: "Template", + TempalteId: "88888888", + BoxSize: [300, 100, 500], + RoomName: "模板主卧", + CabinetName: "模板标准柜", + Rot: [90, 0, 0], + Pos: [400, 0, 0], + ParamMap: [ + { + name: "CZ", + value: "1137" + }, + { + name: "QT", + value: "123" + } + ] +}; + +const testHardware: CFHardware = { + Type: "Hardware", + BoxSize: [50, 30, 60], + RoomName: "五金主卧", + CabinetName: "五金标准柜", + Name: "五金", + Unit: "个", + ActualExpr: "L*W*H", + Model: "X-1", + Factory: "厂家晨丰", + Brand: "品牌晨丰", + Spec: "{L*2}", + Comments: "五金备注", + IsHole: true, + Material: "五金材质", + Color: "五金颜色", +}; + +const testHardware2 = Object.assign({}, testHardware); +testHardware2.HardwarerId = "1111111"; + +const testTopline: CFTopline = { + Type: "Topline", + BoxSize: [50, 30, 60], + RoomName: "顶线主卧", + CabinetName: "顶线标准柜", + Name: "顶线", + Unit: "个", + ActualExpr: "L*W*H", + Model: "X-1", + Factory: "厂家晨丰", + Brand: "品牌晨丰", + Spec: "{L*2}", + Comments: "顶线备注", + Contour: [ + { pt: [0, 0], bul: 0 }, + { pt: [0, 20], bul: 0 }, + { pt: [20, 20], bul: 0 }, + { pt: [20, 0], bul: 0 }, + { pt: [0, 0], bul: 0 }, + ], + PathCurve: [ + { pt: [0, 0], bul: 0 }, + { pt: [0, 100], bul: 0 }, + { pt: [100, 100], bul: 0 }, + { pt: [100, 0], bul: 0 }, + { pt: [0, 0], bul: 0 }, + ], +}; + +const testTopline2 = Object.assign({}, testTopline); +testTopline2.ToplineId = "222222"; + +jest.mock("../../src/Add-on/CF/Parse/ParseHardwareAndTemplate", () => +{ + return { + __esModule: true, + ParseTemplate: async (testTemp: CFTemplate, cuDb: Database) => + { + const newTemp = TestTemplate(cuDb); + await ParseTemplateInfo(newTemp, testTemp, cuDb); + return newTemp; + }, + ParseHardware: async (testHardware: CFHardware, cuDb: Database) => + { + let newTemp: TemplateRecord; + if (testHardware.HardwarerId) + { + newTemp = TestTemplate(cuDb); + await ParseTemplateInfo(newTemp, testTemp, cuDb); + } + + const hardware = await ParseHardwareInfo(newTemp, testHardware, cuDb); + return hardware; + }, + ParseTopline: async (testTopline: CFTopline, cuDb: Database) => + { + let contour: Polyline; + if (testTopline.ToplineId) + { + contour = new Polyline().Rectangle(10, 10); + } + const topline = await ParseToplineInfo(contour, testTemp, cuDb); + return topline; + } + }; +}); + +jest.mock("../../src/Add-on/CF/Import/CFImport", () => +{ + return { + __esModule: true, + async ParseCFDoc(document: CFDoc, cuDb: Database) + { + for (const model of document.ModelSpace) + { + if (model.Type === "EntityTree") + { + await ParseEntityTree(model as CFEntityTree, cuDb); + } + else + { + await ParseAddEntity(model, cuDb); + } + } + } + }; +}); + +test('晨丰导入板解析', () => +{ + const br = ParseBoard(testBr); + + expect(br).toBeInstanceOf(Board); + + const file = EntitysOut(br); + expect(file).toMatchSnapshot(); +}); + +test('晨丰导入模板解析', async () => +{ + const cuDb = new Database(); + + const newTemp = await ParseTemplate(testTemp, cuDb); + expect(newTemp).toBeInstanceOf(TemplateRecord); + + const data = cuDb.FileWrite().ToString(); + expect(data).toMatchSnapshot(); +}); + +test('晨丰导入五金解析', async () => +{ + const cuDb = new Database(); + let newTemp: TemplateRecord; + const hardware = await ParseHardwareInfo(newTemp, testHardware, cuDb) as HardwareCompositeEntity; + expect(hardware).toBeInstanceOf(HardwareCompositeEntity); + const data = EntitysOut(hardware); + expect(data).toMatchSnapshot(); + + const cuDb2 = new Database(); + let newTemp2: TemplateRecord = TestTemplate(cuDb2); + const hardware2 = await ParseHardwareInfo(newTemp2, testHardware2, cuDb2) as TemplateRecord; + expect(hardware2).toBeInstanceOf(TemplateRecord); + const data2 = cuDb2.FileWrite().ToString(); + expect(data2).toMatchSnapshot(); +}); + +test('晨丰导入顶线解析', async () => +{ + const cuDb = new Database(); + let contour: Polyline; + const topline = await ParseToplineInfo(contour, testTopline, cuDb); + expect(topline).toBeInstanceOf(HardwareTopline); + const data = EntitysOut(topline); + expect(data).toMatchSnapshot(); + + let contour2 = new Polyline().Rectangle(10, 10); + const topline2 = await ParseToplineInfo(contour2, testTopline2, cuDb); + expect(topline2).toBeInstanceOf(HardwareTopline); + const data2 = EntitysOut(topline2); + expect(data2).toMatchSnapshot(); +}); + +test('晨丰导入实体树解析', async () => +{ + const cuDb = new Database(); + const temp = await ParseEntityTree(entityTree, cuDb) as TemplateRecord; + + expect(cuDb.TemplateTable.Objects.length).toBe(2); + expect(temp).toBeInstanceOf(TemplateRecord); + expect((temp.Children[0].Object as TemplateRecord).Name).toBe(entityTree.Childen[0].Name); +}); + +test('晨丰导入CAD解析', async () => +{ + const cuDb = new Database(); + let cfDoc = require("./CFDoc.json"); + await ParseCFDoc(cfDoc, cuDb); + + const data = cuDb.FileWrite().ToString(); + expect(data).toMatchSnapshot(); +}); + +function TestTemplate(cuDb: Database): TemplateRecord +{ + const newTemp = new TemplateRecord().InitBaseParams(); + const board = Board.CreateBoard(100, 100, 100, BoardType.Layer); + const hardware = new HardwareCompositeEntity(); + hardware.Entitys.push(board); + cuDb.ModelSpace.Append(hardware); + cuDb.ModelSpace.Append(board); + newTemp.Objects.push(board.Id, hardware.Id); + newTemp.SetParamExpr("CZ", "1137"); + newTemp.SetParamExpr("QT", "123"); + newTemp.UpdateTemplateTree(); + return newTemp; +} + +export function EntitysOut(en: Entity, callback?: (en) => void) +{ + let vf = new CADFiler(); + en.WriteFile(vf); + return JSON.stringify(vf.Data); +} diff --git a/__test__/CFImport/__snapshots__/CFImport.test.ts.snap b/__test__/CFImport/__snapshots__/CFImport.test.ts.snap new file mode 100644 index 000000000..b2e714681 --- /dev/null +++ b/__test__/CFImport/__snapshots__/CFImport.test.ts.snap @@ -0,0 +1,15 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`晨丰导入CAD解析 1`] = `"[11,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,13,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,\\"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,13,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,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]"`; + +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,13,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,5,\\"五金\\",false,false,\\"五金颜色\\",\\"五金材质\\",\\"五金\\",\\"五金主卧\\",\\"五金标准柜\\",\\"L*W*H*100\\",\\"L*W*H\\",\\"X-1\\",\\"厂家晨丰\\",\\"品牌晨丰\\",\\"{L*2}\\",\\"1\\",\\"五金备注\\",\\"个\\",0,true,0,0,0]"`; + +exports[`晨丰导入五金解析 2`] = `"[11,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,13,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,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,13,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,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]"`; + +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,13,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]"`; + +exports[`晨丰导入模板解析 1`] = `"[11,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,13,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,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,13,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,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]"`; + +exports[`晨丰导入顶线解析 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,2,\\"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,5,[0,0],0,[0,20],0,[20,20],0,[20,0],0,[0,0],0,false,1,\\"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,5,[0,0],0,[0,100],0,[100,100],0,[100,0],0,[0,0],0,true,1,0,\\"0\\",\\"顶线\\",\\"顶线主卧\\",\\"顶线标准柜\\",\\"\\",\\"L*W*H\\",\\"X-1\\",\\"厂家晨丰\\",\\"品牌晨丰\\",\\"{L*2}\\",\\"顶线备注\\",0]"`; + +exports[`晨丰导入顶线解析 2`] = `"[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,2,\\"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,[10,0],0,[10,10],0,[0,10],0,true,1,\\"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,5,[0,0],0,[0,100],0,[100,100],0,[100,0],0,[0,0],0,true,1,0,\\"0\\",\\"顶线\\",\\"顶线主卧\\",\\"顶线标准柜\\",\\"\\",\\"L*W*H\\",\\"X-1\\",\\"厂家晨丰\\",\\"品牌晨丰\\",\\"{L*2}\\",\\"顶线备注\\",0]"`; diff --git a/src/Add-on/JiaJu/Import/JiaJuLoader.ts b/src/Add-on/CF/Import/BoardMaterialLoader.ts similarity index 98% rename from src/Add-on/JiaJu/Import/JiaJuLoader.ts rename to src/Add-on/CF/Import/BoardMaterialLoader.ts index 647a24cbb..3c0b13642 100644 --- a/src/Add-on/JiaJu/Import/JiaJuLoader.ts +++ b/src/Add-on/CF/Import/BoardMaterialLoader.ts @@ -7,7 +7,7 @@ export interface MaterialInfo material: string; color: string; } -export class JiaJuLoader +export class BoardMaterialLoader { constructor() { } diff --git a/src/Add-on/CF/Import/CFImport.ts b/src/Add-on/CF/Import/CFImport.ts new file mode 100644 index 000000000..aacd7ac71 --- /dev/null +++ b/src/Add-on/CF/Import/CFImport.ts @@ -0,0 +1,117 @@ +import { Intent } from "@blueprintjs/core"; +import { Box3 } from "three"; +import { app } from "../../../ApplicationServices/Application"; +import { FS } from "../../../Common/FileSystem"; +import { JigMoveEntity } from "../../../Common/JigMove"; +import { Database } from "../../../DatabaseServices/Database"; +import { Board } from "../../../DatabaseServices/Entity/Board"; +import { Entity } from "../../../DatabaseServices/Entity/Entity"; +import { HardwareCompositeEntity } from "../../../DatabaseServices/Hardware/HardwareCompositeEntity"; +import { Command, CommandWrap } from "../../../Editor/CommandMachine"; +import { AppToaster } from "../../../UI/Components/Toaster"; +import { CuttingBoardByBoard } from "../../BoardCutting/CuttingUtils2"; +import { ParseAddEntity, ParseEntityTree } from "../Parse/ParseEntityTree"; +import { BoardMaterialLoader } from "./BoardMaterialLoader"; +import { CFDoc, CFEntityTree } from "./CFInterface"; + +export class ImportCFData implements Command +{ + exec() + { + FS.ChooseFile({ + filter: ".json", multiple: false, callback: async (files) => + { + for (let i = 0; i < files.length; i++) + { + let file = files.item(i); + let data = await file.text(); + try + { + let doc = JSON.parse(data); + if (doc.ModelSpace) + { + await ParseCFDoc(doc, app.Database); + } + else + { + AppToaster.show({ + message: `${file.name}不是有效的晨丰JSON文件!`, + timeout: 5000, + intent: Intent.WARNING, + }); + } + } + catch (error) + { + AppToaster.show({ + message: `${file.name}导入失败!`, + timeout: 5000, + intent: Intent.WARNING, + }); + } + } + } + }); + } +} + +export async function ParseCFDoc(document: CFDoc, cuDb: Database) +{ + await CommandWrap(async () => + { + const brMatLoader = new BoardMaterialLoader(); + await brMatLoader.LoaderMaterialInfo(); + const boardMaterialMap = brMatLoader.Code_MaterialInfo; + + for (const model of document.ModelSpace) + { + if (model.Type === "EntityTree") + { + await ParseEntityTree(model as CFEntityTree, cuDb, boardMaterialMap); + } + else + { + await ParseAddEntity(model, cuDb, boardMaterialMap); + } + } + + let ents = app.CommandReactor._createObejcts.filter(obj => obj instanceof Entity) as Entity[]; + + let brs = ents.filter(en => en instanceof Board) as Board[]; + let hws = ents.filter(en => en instanceof HardwareCompositeEntity).filter(hw => (hw as HardwareCompositeEntity).HardwareOption.isHole) as HardwareCompositeEntity[]; + + if (ents.length === 0) + return true; + + let box = new Box3; + for (let en of ents) + box.union(en.BoundingBox); + + app.Editor.GetPointServices.snapServices.FilterEntitys = new Set(ents); + let ok = await JigMoveEntity(ents, box.isEmpty() ? undefined : box.min); + app.Editor.GetPointServices.snapServices.FilterEntitys = undefined; + + if (ok) + { + if (brs.length !== 0) + { + app.Editor.Prompt("开始计算薄背板拉槽!"); + let bbrs: Board[] = []; + let allBrs: Board[] = []; + for (let br of brs) + { + if (br.IsKnife)//br.BoardType === BoardType.Behind + bbrs.push(br); + else + allBrs.push(br); + } + + CuttingBoardByBoard(allBrs, bbrs); + } + + //直接调用五金挖孔 + await app._hardwareCuttingReactor.StartReactor(hws, new Set); + } + return !ok; + }, "晨丰导入"); +} diff --git a/src/Add-on/CF/Import/CFInterface.ts b/src/Add-on/CF/Import/CFInterface.ts new file mode 100644 index 000000000..93c8c41e7 --- /dev/null +++ b/src/Add-on/CF/Import/CFInterface.ts @@ -0,0 +1,206 @@ +//通用类型定义 +type CurverType = "Curve" | "Polyline" | "Rect" | "Line" | "Arc" | "Circle"; +type EntityType = "Entity" | "ExtrudeSolid" | "Board" | "Template" | "EntityTree" | "Hardware" | "Topline"; + +// ContourCurve 定义轮廓曲线,每个点的坐标和弯曲度, +// pt为点坐标,bul为弯曲度(区间-1~1),俗称弓弦比 +// bul为0时为直线,bul为0.5时为半圆,正负为上下弯曲的方向 +// bul值为(弧线两点直线的中点到弧线中点的距离)除以(弧线两点直线的中点到弧线起点的距离) +export type PolylineContour = { pt: [number, number], bul: 0; }[]; //多段线轮廓 +export type CircleContour = { Radius: number, Center: [number, number, number]; }; //圆形轮廓 + +type ExtrudeContour = PolylineContour | CircleContour; +//图纸(文档) +export interface CFDoc +{ + //定义模型空间,包含所有实体类 + ModelSpace: CFEntity[]; //模型空间 + + // ProcessGroup: any; +} + +// 定义实体类,包含所有实体通用属性 +export interface CFEntity +{ + Type: EntityType | CurverType; //实体类型 + Id?: number; //自定义id,加工组使用 + ColorIndex?: number; //颜色索引 值区间0-255 + + // 定位方式选择 OCS 或 pos(位置) + rot(旋转) 或 pos(位置) + Qua(四元数) + OCS?: number[]; //OCS矩阵 长度16的数组 + + //定位方式 pos(位置) rot(旋转) + Pos?: [number, number, number]; //位置 + + Rot?: [number, number, number]; //欧拉旋转角 + // Or + Qua?: [number, number, number, number]; //四元数旋转角 +} + +export interface CFExtrudeSolid extends CFEntity +{ + // Type: "ExtrudeSolid" //类型拉伸实体(必填) + + Width?: number; //宽 + Height?: number; //高 + // Or + ContourCurve?: ExtrudeContour; //轮廓曲线 + + Thickness?: number; //厚度 + GroovesAddLength?: number; //槽加长 + GroovesAddWidth?: number; //槽加宽 + GroovesAddDepth?: number; //槽加深 + KnifeRadius?: number; //刀半径 + + //孔洞本质上也是拉伸实体,一般孔洞只需要提供位置,轮廓曲线和厚度即可 + Holes?: CFExtrudeSolid[]; //孔洞 +} + +export interface CFBoard extends CFExtrudeSolid +{ + // Type: "Board"; //类型板(必填) + + Name?: string; //板名称 + BrType?: number; //板类型(选填) 0:层板,1:立板,2:背板 + + //定位类型0-3 + PositionType?: number; //定位类型(选填) 0:晨丰基点(默认),1:基于板盒子最小点,2:基于板盒子中心点 + + OpenDir?: number; //打开方向(选填) 0:非门板(默认),1:左开门板,2:右开门板,3:上开门板,4:下开门板, + + //纹路0-2 + Lines?: number; //纹路(选填) 0:正纹(默认),1:反,2:可翻转 + BigHole?: number; //大孔面(选填) 0:正(默认),1:反 + ComposingFace?: number; //排版面(选填) 0:正面,1:背面,2:随意面(默认) + + RoomName?: string; //房名 + CabinetName?: string; //柜名 + + BrMatName?: string; //板材名 + Matrial?: string; //材料 + Color?: string; //颜色 + + //板材信息可以自定义写入,也可以通过材质编码ID获取对应的值 + BoardMaterialId?: string; //板材信息Id + + UpSealed?: string; //封边上下左右 + DownSealed?: string; + LeftSealed?: string; + RightSealed?: string; + + // 封边信息 + // 普通板时使用 UpSealed,DownSealed,LeftSealed,RightSealed 表示上下左右封边的值 + // 异形板时使用 EachSealeds 数组表示每个边的封边数据,size表示封边的厚度 + EachSealeds?: { size: number; }[]; //每个边的封边数据 + + EachEdgeDrills?: string[]; //每个边的排钻数据 + + FrontDrill?: boolean; //正排孔面 + BackDrill?: boolean; //反排孔面 + Remarks?: [string, string][]; //备注 +} + +export interface CFEntityTree extends CFEntity +{ + // Type: "EntityTree"; //类型实体树(必填) + Name?: string; //模板空间名称 + Entitys?: CFEntity[]; //实体数组 + Childen?: CFEntityTree[]; //子模板数组 +} + +//模块 +export interface CFTemplate extends CFEntity +{ + // Type: "Template"; //类型模板(必填) + TempalteId?: string; //模板ID + Name?: string; //模板名称 + + //模块参数 + Lenght?: number; //长度 + Width?: number; //宽度 + Height?: number; //高度 + // Or + BoxSize?: [number, number, number]; //盒子尺寸 + + ParamMap?: { name: string, value: string; }[]; //模块参数 + + RoomName?: string; //房名 + CabinetName?: string; //柜名 +} + +export interface CFHardware extends CFTemplate +{ + // Type: "Hardware"; //类型五金(必填) + Name?: string; //五金名称 + HardwarerId?: string; //五金模板ID + + Unit?: string; //单位 + ActualExpr?: string; //价格表达式 + Model?: string; //型号 + Factory?: string; //厂家 + Brand?: string; //品牌 + Spec?: string; //规格 + Comments?: string; //备注 + IsHole?: boolean; //是否挖孔 + Material?: string; //材质 + Color?: string; //颜色 +} + +export interface CFTopline extends CFTemplate +{ + // Type: "Topline"; //类型顶线(必填) + Name?: string; //顶线名称 + ToplineId?: string; //顶线横截面轮廓模板ID + + Unit?: string; //单位 + ActualExpr?: string; //价格表达式 + Model?: string; //型号 + Factory?: string; //厂家 + Brand?: string; //品牌 + Spec?: string; //规格 + Comments?: string; //备注 + + Contour?: { pt: [number, number], bul: 0; }[]; //横截面轮廓曲线 + PathCurve?: ExtrudeContour; //绘制路径曲线 +} + + +export interface CFCurve extends CFEntity +{ + // Type: "Curve"; //类型曲线(必填) + +} + +export interface CFLine extends CFCurve +{ + // Type: "Line"; //类型直线(必填) + StartPoint: [number, number, number]; //起点 + EndPoint: [number, number, number]; //终点 +} + +export interface CFPolyline extends CFCurve +{ + // Type: "Polyline"; //类型多段线(必填) + ContourCurve?: { pt: [number, number], bul: 0; }[]; //轮廓曲线 +} + +export interface CFRect extends CFCurve +{ + // Type: "Rect"; //类型矩形(必填) + Width: number; //宽度 + Height: number; //高度 +} + +export interface CFCircle extends CFCurve +{ + // Type: "Circle"; //类型圆形(必填) + Radius: number; //半径 + Center: [number, number, number]; //中心点 +} + + +// interface CFPRocessGroup +// { +// name: string; +// entitys: [1, 2, 3, 4, 5, 6, 7, 8, 9]; +// } diff --git a/src/Add-on/CF/Parse/ParseBoard.ts b/src/Add-on/CF/Parse/ParseBoard.ts new file mode 100644 index 000000000..5f004ec95 --- /dev/null +++ b/src/Add-on/CF/Parse/ParseBoard.ts @@ -0,0 +1,217 @@ +import { Intent, Position, Toaster } from "@blueprintjs/core"; +import { Euler, Matrix4, Quaternion, Vector3 } from "three"; +import { Log, LogType } from "../../../Common/Log"; +import { Board } from "../../../DatabaseServices/Entity/Board"; +import { BoardOpenDir, ComposingType, LinesType } from "../../../DatabaseServices/Entity/BoardInterface"; +import { ExtrudeContourCurve, ExtrudeSolid } from "../../../DatabaseServices/Entity/Extrude"; +import { Polyline } from "../../../DatabaseServices/Entity/Polyline"; +import { userConfig } from "../../../Editor/UserConfig"; +import { DrillType, FaceDirection } from "../../DrawDrilling/DrillType"; +import { BoardType } from "../../Erp/Models/CadBlock"; +import { MaterialInfo } from "../Import/BoardMaterialLoader"; +import { CFBoard, CircleContour } from "../Import/CFInterface"; +import { ParseCurve } from "./ParseCurve"; + +export function ParseBoard(el: CFBoard, boardMaterialMap?: Map) +{ + const br = new Board(); + br.Name = el.Name ?? ""; + br.OpenDir = el.OpenDir ?? BoardOpenDir.None; + + const parseCurve = new ParseCurve(); + let pl: ExtrudeContourCurve; + if (el.ContourCurve) + { + if ((el.ContourCurve as CircleContour).Center !== undefined) + { + const { Center, Radius } = el.ContourCurve as CircleContour; + pl = parseCurve.ParseCircle(Radius, Center); + } + else + pl = parseCurve.ParsePolyline(el.ContourCurve, true); + } + else if (el.Height && el.Width) + { + pl = parseCurve.ParseRect(el.Height, el.Width); + } + else + { + Toaster.create({ + className: "recipe-toaster", + position: Position.TOP, + canEscapeKeyClear: false, + }).show({ + message: `无法绘制板${br.Name}轮廓`, + timeout: 5000, + intent: Intent.DANGER, + }); + return; + } + + br.ContourCurve = pl; + br.Thickness = el.Thickness ?? 1; + + if (el.Holes) + { + for (const hole of el.Holes) + { + let pl: Polyline; + if (hole.ContourCurve) + { + pl = parseCurve.ParsePolyline(hole.ContourCurve, true); + } + else if (hole.Height && hole.Width) + { + pl = parseCurve.ParseRect(hole.Height, hole.Width); + } + else + { + Toaster.create({ + className: "recipe-toaster", + position: Position.TOP, + canEscapeKeyClear: false, + }).show({ + message: `板${br.Name}的造型轮廓错误`, + timeout: 5000, + intent: Intent.DANGER, + }); + continue; + } + + let extrude = new ExtrudeSolid(); + extrude.ContourCurve = pl; + extrude.Thickness = hole.Thickness ?? 1; + if (hole.Pos) + extrude.Move(new Vector3(...hole.Pos)); + br.Grooves.push(extrude); + } + } + br.GroovesAddLength = el.GroovesAddLength ?? 0; + br.GroovesAddWidth = el.GroovesAddWidth ?? 0; + br.GroovesAddDepth = el.GroovesAddDepth ?? 0; + br.KnifeRadius = el.KnifeRadius ?? 3; + + if (el.BrType !== undefined) //默认位置 + { + if (el.BrType === BoardType.Layer) + { + br.BoardType = BoardType.Layer; + br.ColorIndex = 2; + } + else if (el.BrType === BoardType.Vertical) + { + br.BoardType = BoardType.Vertical; + br.ColorIndex = 11; + } + else + { + br.BoardType = BoardType.Behind; + br.ColorIndex = 3; + } + } + + if (el.PositionType !== undefined) + { + if (el.PositionType === 1) //基于盒子最左下角点 + { + if (el.BrType === BoardType.Layer) + br.Move(new Vector3(br.Height, 0, 0)); + else if (el.BrType === BoardType.Behind) + br.Move(new Vector3(0, br.Thickness, 0)); + } + else if (el.PositionType === 2) //基于盒子中心点 + { + if (el.BrType === BoardType.Layer) + br.Move(new Vector3(br.Height / 2, -br.Width / 2, -br.Thickness / 2)); + else if (el.BrType === BoardType.Vertical) + br.Move(new Vector3(-br.Thickness / 2, -br.Width / 2, - br.Height / 2)); + else + br.Move(new Vector3(-br.Width / 2, br.Thickness / 2, -br.Height / 2)); + } + } + + if (el.ColorIndex) + br.ColorIndex = el.ColorIndex; + + let mtx = new Matrix4(); + if (el.OCS) + { + if (el.OCS.length != 16) + Log("OCS数组错误!", LogType.Error); + else + mtx = new Matrix4().fromArray(el.OCS); + } + else + { + const angle = Math.PI / 180; + if (el.Rot) + { + mtx.makeRotationFromEuler(new Euler(el.Rot[0] * angle, el.Rot[1] * angle, el.Rot[2] * angle, "ZYX")); + } + else if (el.Qua) + { + const quaternion = new Quaternion(); + quaternion.setFromAxisAngle(new Vector3(el.Qua[0], el.Qua[1], el.Qua[2]), el.Qua[3]); + mtx.makeRotationFromQuaternion(quaternion); + } + if (el.Pos) + { + mtx.setPosition(el.Pos[0], el.Pos[1], el.Pos[2]); + } + } + br.ApplyMatrix(mtx); + + const process = br.BoardProcessOption; + + process.roomName = el.RoomName ?? ""; + process.cabinetName = el.CabinetName ?? ""; + + process.boardName = el.BrMatName ?? ""; + process.material = el.Matrial ?? ""; + process.color = el.Color ?? ""; + + if (el.BoardMaterialId && boardMaterialMap?.size) + { + const materialParam = boardMaterialMap.get(el.BoardMaterialId); + if (materialParam) + { + process.boardName = materialParam.brName; + process.material = materialParam.material; + process.color = materialParam.color; + } + } + + process.lines = el.Lines ?? LinesType.CanReversal; + process.bigHoleDir = el.BigHole ?? FaceDirection.Front; + process.composingFace = el.ComposingFace ?? ComposingType.Arbitrary; + process.sealedUp = el.UpSealed ?? ""; + process.sealedDown = el.DownSealed ?? ""; + process.sealedLeft = el.LeftSealed ?? ""; + process.sealedRight = el.RightSealed ?? ""; + process.frontDrill = el.FrontDrill ?? true; + process.backDrill = el.BackDrill ?? true; + + if (el.EachEdgeDrills) + { + process.highDrill = el.EachEdgeDrills; + + let types = ["不排", ...userConfig.DrillConfigs.keys()]; + let set = new Set(process.highDrill); + if (set.size > 1) + process.drillType = DrillType.More; + else if (set.size === 1) + process.drillType = (process.highDrill[0] === "不排" ? process.highDrill[0] : types[1]) ?? "不排"; + else + process.drillType = DrillType.Invail; + } + else + Log(`板:${br.Name}没有提供排钻信息!`, LogType.Warning, [br]); + + if (el.EachSealeds) + process.highSealed = el.EachSealeds; + + if (el.Remarks) + process.remarks = el.Remarks; + + return br; +} diff --git a/src/Add-on/CF/Parse/ParseCurve.ts b/src/Add-on/CF/Parse/ParseCurve.ts new file mode 100644 index 000000000..ad0e6c8f1 --- /dev/null +++ b/src/Add-on/CF/Parse/ParseCurve.ts @@ -0,0 +1,44 @@ +import { Vector2, Vector3 } from "three"; +import { Circle } from "../../../DatabaseServices/Entity/Circle"; +import { Line } from "../../../DatabaseServices/Entity/Line"; +import { Polyline, PolylineProps } from "../../../DatabaseServices/Entity/Polyline"; + +export class ParseCurve +{ + ParseLine(StartPoint: [number, number, number], EndPoint: [number, number, number]) + { + const startPoint = new Vector3().fromArray(StartPoint); + const endPoint = new Vector3().fromArray(EndPoint); + const line = new Line(startPoint, endPoint); + return line; + } + + ParsePolyline(ContourCurve, isColosed: boolean = false) + { + const pl = new Polyline(); + const paths: PolylineProps[] = ContourCurve.map((path) => + { + return { + pt: new Vector2().fromArray(path.pt), + bul: path.bul + }; + }); + pl.LineData = paths; + pl.CloseMark = isColosed; + return pl; + } + + ParseRect(Width: number, Height: number) + { + const pl = new Polyline(); + pl.Rectangle(Width, Height); + return pl; + } + + ParseCircle(Radius: number, Center: [number, number, number]) + { + const conter = new Vector3().fromArray(Center); + const cir = new Circle(conter, Radius); + return cir; + } +} diff --git a/src/Add-on/CF/Parse/ParseEntityTree.ts b/src/Add-on/CF/Parse/ParseEntityTree.ts new file mode 100644 index 000000000..4ef445b9f --- /dev/null +++ b/src/Add-on/CF/Parse/ParseEntityTree.ts @@ -0,0 +1,89 @@ +import { Database } from "../../../DatabaseServices/Database"; +import { Entity } from "../../../DatabaseServices/Entity/Entity"; +import { TemplateRecord } from "../../../DatabaseServices/Template/TemplateRecord"; +import { MaterialInfo } from "../Import/BoardMaterialLoader"; +import { CFEntity, CFEntityTree } from "../Import/CFInterface"; +import { ParseBoard } from "./ParseBoard"; +import { ParseHardware, ParseTemplate, ParseTopline } from "./ParseHardwareAndTemplate"; + +export async function ParseEntityTree(model: CFEntityTree, cuDb: Database, boardMaterialMap?: Map): Promise +{ + let entitys: Entity[] = []; + let templates: TemplateRecord[] = []; + if (model.Entitys?.length) + { + for (const entInfo of model.Entitys) + { + let en = await ParseAddEntity(entInfo, cuDb); + if (en) + { + if (en instanceof Entity) + { + entitys.push(en); + } + else if (en instanceof TemplateRecord) + { + templates.push(en); + } + } + } + } + + if (model.Childen?.length) + { + for (const m of model.Childen) + { + let temp = await ParseEntityTree(m, cuDb, boardMaterialMap); + if (temp && temp instanceof TemplateRecord) + templates.push(temp); + } + } + + if (templates.length > 0 || entitys.length > 0) + { + let template = new TemplateRecord().InitBaseParams(); + template.Name = model.Name; + cuDb.TemplateTable.Add(template); + if (entitys.length > 0) + template.Objects.push(...entitys.map(en => en.Id)); + if (templates.length > 0) + template.Children.push(...templates.map(t => t.Id)); + return template; + } +} + + +export async function ParseAddEntity(model: CFEntity, cuDb: Database, boardMaterialMap?: Map) +{ + let en: Entity | TemplateRecord | undefined; + switch (model.Type) + { + case "Board": + en = await ParseBoard(model, boardMaterialMap); + break; + case "Template": + en = await ParseTemplate(model, cuDb); + break; + case "Hardware": + en = await ParseHardware(model, cuDb); + break; + case "Topline": + en = await ParseTopline(model, cuDb); + break; + default: + break; + } + + if (en) + { + if (en instanceof Entity) + { + cuDb.ModelSpace.Add(en); + } + else if (en instanceof TemplateRecord) + { + cuDb.TemplateTable.Add(en); + } + } + return en; +} diff --git a/src/Add-on/CF/Parse/ParseHardwareAndTemplate.ts b/src/Add-on/CF/Parse/ParseHardwareAndTemplate.ts new file mode 100644 index 000000000..66cb06438 --- /dev/null +++ b/src/Add-on/CF/Parse/ParseHardwareAndTemplate.ts @@ -0,0 +1,118 @@ +import { Intent } from "@blueprintjs/core"; +import { MaterialUrls, ToplineUrls } from "../../../Common/HostUrl"; +import { PostJson, RequestStatus } from "../../../Common/Request"; +import { MaterialIn, toplineFileIn } from "../../../Common/SerializeMaterial"; +import { DuplicateRecordCloning } from "../../../Common/Status"; +import { inflateBase64 } from "../../../Common/inflate"; +import { Database } from "../../../DatabaseServices/Database"; +import { Polyline } from "../../../DatabaseServices/Entity/Polyline"; +import { PhysicalMaterialRecord } from "../../../DatabaseServices/PhysicalMaterialRecord"; +import { TemplateParamType } from "../../../DatabaseServices/Template/Param/TemplateParamType"; +import { GetOnlineTemplate } from "../../../DatabaseServices/Template/TempateUtils"; +import { TemplateRecord } from "../../../DatabaseServices/Template/TemplateRecord"; +import { AppToaster } from "../../../UI/Components/Toaster"; +import { CFHardware, CFTemplate, CFTopline } from "../Import/CFInterface"; +import { ParseHardwareInfo, ParseTemplateInfo, ParseToplineInfo } from "./ParseHardwareAndTemplateInfo"; + +export async function ParseTemplate(temp: CFTemplate, cuDb: Database) +{ + const newTemp = await GetTemplate(temp, cuDb); + if (temp.ParamMap) + { + for (const mk of temp.ParamMap) + { + const param = newTemp.GetParam(mk.name); + if (param && param.type === TemplateParamType.Material) + { + const mat = await LoadMaterial(mk.value.toString(), cuDb); + if (mat) + param.MaterialValue = mat; + } + } + } + + await ParseTemplateInfo(newTemp, temp, cuDb); + return newTemp; +} + +export async function GetTemplate(temp: CFTemplate, cuDb: Database) +{ + let newTemp: TemplateRecord; + if (temp.TempalteId) + { + const template = await GetOnlineTemplate(temp.TempalteId.toString()); + if (template) + { + newTemp = cuDb.WblockCloneObejcts([template], cuDb.TemplateTable, new Map(), DuplicateRecordCloning.Ignore)[0] as TemplateRecord; + } + } + return newTemp; +} + +export async function ParseHardware(el: CFHardware, cuDb: Database) +{ + let newTemp: TemplateRecord; + if (el.HardwarerId) + { + newTemp = await ParseTemplate(el, cuDb); + } + + const hardware = await ParseHardwareInfo(newTemp, el, cuDb); + return hardware; +} + +export async function ParseTopline(el: CFTopline, cuDb: Database) +{ + let contour: Polyline; + if (el.ToplineId) + { + const data = await PostJson(ToplineUrls.detail, { topline_id: el.ToplineId }); + if (data.err_code === RequestStatus.Ok) + { + const file = inflateBase64(data.toplines.file); + contour = toplineFileIn(file); + } + } + + const topline = await ParseToplineInfo(contour, el, cuDb); + return topline; +} + + +async function LoadMaterial(fetchMaterialId: string, cuDb: Database): Promise +{ + let mtl: PhysicalMaterialRecord; + + let data = await PostJson(MaterialUrls.detail, { material_id: fetchMaterialId }); + if (data.err_code !== RequestStatus.Ok) + { + AppToaster.show({ + message: `错误:无法从远程获取到材质数据!id:${fetchMaterialId}`, + timeout: 5000, + intent: Intent.DANGER, + }, "no_mtl_data"); + return; + } + + try + { + let jsonData = JSON.parse(inflateBase64(data.materials.file)); + let mtlOut = MaterialIn(jsonData) as PhysicalMaterialRecord; + mtl = cuDb.WblockCloneObejcts( + [mtlOut], + cuDb.MaterialTable, + new Map(), + DuplicateRecordCloning.Ignore + )[0] as PhysicalMaterialRecord; + + return mtl; + } + catch (error) + { + AppToaster.show({ + message: `加载材质失败! id:${fetchMaterialId}`, + timeout: 5000, + intent: Intent.WARNING, + }); + } +} diff --git a/src/Add-on/CF/Parse/ParseHardwareAndTemplateInfo.ts b/src/Add-on/CF/Parse/ParseHardwareAndTemplateInfo.ts new file mode 100644 index 000000000..aacdc2570 --- /dev/null +++ b/src/Add-on/CF/Parse/ParseHardwareAndTemplateInfo.ts @@ -0,0 +1,181 @@ +import { Euler, Matrix4, Quaternion, Vector3 } from "three"; +import { EBoardKeyList } from "../../../Common/BoardKeyList"; +import { Log, LogType } from "../../../Common/Log"; +import { Database } from "../../../DatabaseServices/Database"; +import { Board } from "../../../DatabaseServices/Entity/Board"; +import { Curve } from "../../../DatabaseServices/Entity/Curve"; +import { Entity } from "../../../DatabaseServices/Entity/Entity"; +import { Polyline } from "../../../DatabaseServices/Entity/Polyline"; +import { HardwareCompositeEntity } from "../../../DatabaseServices/Hardware/HardwareCompositeEntity"; +import { HardwareTopline } from "../../../DatabaseServices/Hardware/HardwareTopline"; +import { TemplateParamType } from "../../../DatabaseServices/Template/Param/TemplateParamType"; +import { TemplateRecord } from "../../../DatabaseServices/Template/TemplateRecord"; +import { CFHardware, CFTemplate, CFTopline, CircleContour } from "../Import/CFInterface"; +import { ParseCurve } from "./ParseCurve"; + +export async function ParseTemplateInfo(newTemp: TemplateRecord, tempInfo: CFTemplate, cuDb: Database) +{ + if (newTemp) + { + newTemp.Name = tempInfo.Name; + let mtx = new Matrix4(); + if (tempInfo.OCS) + { + if (tempInfo.OCS.length != 16) + Log("OCS数组错误!", LogType.Error); + else + mtx = new Matrix4().fromArray(tempInfo.OCS); + } + else + { + const angle = Math.PI / 180; + if (tempInfo.Rot) + { + mtx.makeRotationFromEuler(new Euler(tempInfo.Rot[0] * angle, tempInfo.Rot[1] * angle, tempInfo.Rot[2] * angle, "ZYX")); + } + else if (tempInfo.Qua) + { + const quaternion = new Quaternion(); + quaternion.setFromAxisAngle(new Vector3(tempInfo.Qua[0], tempInfo.Qua[1], tempInfo.Qua[2]), tempInfo.Qua[3]); + mtx.makeRotationFromQuaternion(quaternion); + } + if (tempInfo.Pos) + { + mtx.setPosition(...tempInfo.Pos); + } + } + + const size = new Vector3().fromArray(tempInfo.BoxSize ? tempInfo.BoxSize : [tempInfo.Lenght, tempInfo.Width, tempInfo.Height]); + + newTemp.SetParamExpr("L", size.x); + newTemp.SetParamExpr("W", size.y); + newTemp.SetParamExpr("H", size.z); + + if (tempInfo.ParamMap) + { + for (const mk of tempInfo.ParamMap) + { + const param = newTemp.GetParam(mk.name); + if (param && param.type === TemplateParamType.Float) + { + param.expr = mk.value; + } + } + } + + await newTemp.UpdateTemplateTree(); + + let ens = newTemp.AllEntitys as Entity[]; + for (const en of ens) + { + if (en instanceof Board) + { + en.BoardProcessOption[EBoardKeyList.RoomName] = tempInfo.RoomName; + en.BoardProcessOption[EBoardKeyList.CabinetName] = tempInfo.CabinetName; + } + else if (en instanceof HardwareCompositeEntity) + { + en.HardwareOption[EBoardKeyList.RoomName] = tempInfo.RoomName; + en.HardwareOption[EBoardKeyList.CabinetName] = tempInfo.CabinetName; + } + en.ApplyMatrix(new Matrix4().premultiply(mtx)); + } + + } + return newTemp; +} + +export async function ParseHardwareInfo(newTemp: TemplateRecord, el: CFHardware, cuDb: Database) +{ + const ParseHardwareParam = (en: HardwareCompositeEntity, el: CFHardware) => + { + const option = en.HardwareOption; + + option.name = el.Name ?? ""; + option.unit = el.Unit ?? "个"; + option.actualExpr = el.ActualExpr ?? ""; + option.model = el.Model ?? ""; + option.factory = el.Factory ?? ""; + option.brand = el.Brand ?? ""; + option.spec = el.Spec ?? ""; + option.comments = el.Comments ?? ""; + option.isHole = el.IsHole ?? false; + option.material = el.Material ?? ""; + option.color = el.Color ?? ""; + }; + + if (newTemp) + { + let ens = newTemp.AllEntitys as Entity[]; + for (const en of ens) + { + if (en instanceof Board) + { + en.BoardProcessOption[EBoardKeyList.RoomName] = el.RoomName; + en.BoardProcessOption[EBoardKeyList.CabinetName] = el.CabinetName; + } + else if (en instanceof HardwareCompositeEntity) + { + en.HardwareOption[EBoardKeyList.RoomName] = el.RoomName; + en.HardwareOption[EBoardKeyList.CabinetName] = el.CabinetName; + ParseHardwareParam(en, el); + } + } + return newTemp; + } + + let hw = new HardwareCompositeEntity(); + let en = new Board(); + + const boxSize = new Vector3().fromArray(el.BoxSize ? el.BoxSize : [el.Lenght, el.Width, el.Height]); + [en.Width, en.Height, en.Thickness] = [boxSize.x, boxSize.y, boxSize.z]; + + hw.Entitys.push(en); + hw.HardwareOption[EBoardKeyList.RoomName] = el.RoomName; + hw.HardwareOption[EBoardKeyList.CabinetName] = el.CabinetName; + ParseHardwareParam(hw, el); + cuDb.ModelSpace.Append(hw); + return hw; +} + +export async function ParseToplineInfo(contour: Polyline, el: CFTopline, cuDb: Database) +{ + const ParseHardwareParam = (en: HardwareTopline | HardwareCompositeEntity, el: CFTopline) => + { + const option = en.HardwareOption; + option.name = el.Name ?? ""; + option.unit = el.Unit ?? "毫米"; + option.actualExpr = el.ActualExpr ?? ""; + option.model = el.Model ?? ""; + option.factory = el.Factory ?? ""; + option.brand = el.Brand ?? ""; + option.spec = el.Spec ?? ""; + option.comments = el.Comments ?? ""; + }; + + const parseCurve = new ParseCurve(); + + if (!contour && el.Contour) + { + contour = parseCurve.ParsePolyline(el.Contour); + } + + let pathCurve: Curve; + if (el.PathCurve) + { + if ((el.PathCurve as CircleContour).Center !== undefined) + { + const { Center, Radius } = el.PathCurve as CircleContour; + pathCurve = parseCurve.ParseCircle(Radius, Center); + } + else + pathCurve = parseCurve.ParsePolyline(el.PathCurve, true); + } + const topline = new HardwareTopline(contour, pathCurve); + + topline.HardwareOption[EBoardKeyList.RoomName] = el.RoomName; + topline.HardwareOption[EBoardKeyList.CabinetName] = el.CabinetName; + ParseHardwareParam(topline, el); + cuDb.ModelSpace.Append(topline); + return topline; +} diff --git a/src/Add-on/CF/doc.md b/src/Add-on/CF/doc.md new file mode 100644 index 000000000..ac777bdbf --- /dev/null +++ b/src/Add-on/CF/doc.md @@ -0,0 +1,414 @@ +晨丰导入 + +//通用类型定义 +type CurverType = "Curve" | "Polyline" | "Rect" | "Line" | "Arc" | "Circle"; +type EntityType = "Entity" | "ExtrudeSolid" | "Board" | "Template" | "EntityTree" | "Hardware" | "Topline"; + +// ContourCurve 定义轮廓曲线,每个点的坐标和弯曲度, +// pt为点坐标,bul为弯曲度(区间-1~1),俗称弓弦比 +// bul为0时为直线,bul为0.5时为半圆,正负为上下弯曲的方向 +// bul值为(弧线两点直线的中点到弧线中点的距离)除以(弧线两点直线的中点到弧线起点的距离) +type PolylineContour = { pt: [number, number], bul: 0; }[]; //多段线轮廓 +type CircleContour = { Radius: number, Center: [number, number, number]; }; //圆形轮廓 + +type ExtrudeContour = PolylineContour | CircleContour; +图纸结构 + +1.模型空间 ModelSpace 结构 + 定义模型空间,包含所有实体类 + ModelSpace [ + Board, //板类 + Temple, //模板类 + Entity, //其他实体类 + EntityTree, //实体模板树类 + ] + + 模型中所有实体遵循自身坐标系定位 + + +2.实体基类 CFEntity 结构 + 定义实体类,包含所有实体通用属性 + export interface CFEntity + { + Type: EntityType | CurverType; //实体类型 + Id?: number; //自定义id,加工组使用 + ColorIndex?: number; //颜色索引 值区间0-255 + + // 定位方式选择 OCS 或 pos(位置) + rot(旋转) 或 pos(位置) + Qua(四元数) + OCS?: number[]; //OCS矩阵 长度16的数组 + + //定位方式 pos(位置) rot(旋转) + Pos?: [number, number, number]; //位置 + + Rot?: [number, number, number]; //欧拉旋转角 + // Or + Qua?: [number, number, number, number]; //四元数旋转角 + } + + 实体类型判断 Type 字段(必填) + Type: "Curve" | "Line" | "Point" | "Circle" | "Entity" | "ExtrudeSolid" | "Board" | "Template" | "EntityTree" + + 定位方式选择 OCS 或 pos(位置) + rot(旋转) 或 pos(位置) + Qua(四元数) + + 例: + { + Type:"Entity", //类型实体 + colorIndex:0, //颜色索引(选填),默认值7白色 + + OCS: [1,0,0,0,0,0,1,0,0,-1,0,0,0,0,100,1], //x轴旋转90度,z轴向上平移100 + 或 + pos: [0, 0, 100], + rot: [90, 0, 0], + 或 + pos: [0, 0, 100], + Qua: [0.7071, 0, 0, 0.7071, 0, 0, 0] + } + +3.拉伸实体类 继承 CFEntity + 定义拉伸实体类通用属性 + export interface CFExtrudeSolid extends CFEntity + { + // Type: "ExtrudeSolid" //类型拉伸实体(必填) + + Width?: number; //宽 + Height?: number; //高 + // Or + ContourCurve?: ExtrudeContour; //轮廓曲线 + + Thickness?: number; //厚度 + GroovesAddLength?: number; //槽加长 + GroovesAddWidth?: number; //槽加宽 + GroovesAddDepth?: number; //槽加深 + KnifeRadius?: number; //刀半径 + + //孔洞本质上也是拉伸实体,一般孔洞只需要提供位置,轮廓曲线和厚度即可 + Holes?: CFExtrudeSolid[]; //孔洞 + } + + 例: + { + Type:"ExtrudeSolid", + ...实体类属性 + + Width:100, + Height:200, + //或 + ContourCurve:[{pt: [0,0], bul: 0;},{pt: [100,0], bul: 0;},{pt: [100,200], bul: 0;},{pt: [0,200], bul: 0;},{pt: [0,0], bul: 0;}] + + thickness:18, + GroovesAddLength:0, + GroovesAddWidth:0, + GroovesAddDepth:0, + KnifeRadius:3, + + Holes:[] + } + + Holes 孔洞本质上也是拉伸实体,一般孔洞只需要提供位置,轮廓曲线和厚度即可 + 例: + { + Type:"ExtrudeSolid", + ...拉伸实体类属性 + + Width:100, + Height:200, + //或 + ContourCurve:[{pt: [0,0], bul: 0;},{pt: [10,0], bul: 0;},{pt: [10,20], bul: 0;},{pt: [0,20], bul: 0;}] + + thickness:10, + } + + + +4.画板类 CFBoard 继承 CFExtrudeSolid + 定义板类通用属性 + export interface CFBoard extends CFExtrudeSolid + { + // Type: "Board"; //类型板(必填) + + Name?: string; //板名称 + BrType?: number; //板类型(选填) 0:层板,1:立板,2:背板 + + //定位类型0-3 + PositionType?: number; //定位类型(选填) 0:晨丰基点(默认),1:基于板盒子最小点,2:基于板盒子中心点 + + OpenDir?: number; //打开方向(选填) 0:非门板(默认),1:左开门板,2:右开门板,3:上开门板,4:下开门板, + + //纹路0-2 + Lines?: number; //纹路(选填) 0:正纹(默认),1:反,2:可翻转 + BigHole?: number; //大孔面(选填) 0:正(默认),1:反 + ComposingFace?: number; //排版面(选填) 0:正面,1:背面,2:随意面(默认) + + RoomName?: string; //房名 + CabinetName?: string; //柜名 + + BrMatName?: string; //板材名 + Matrial?: string; //材料 + Color?: string; //颜色 + + //板材信息可以自定义写入,也可以通过材质编码ID获取对应的值 + BoardMaterialId?: string; //板材信息Id + + UpSealed?: string; //封边上下左右 + DownSealed?: string; + LeftSealed?: string; + RightSealed?: string; + + // 封边信息 + // 普通板时使用 UpSealed,DownSealed,LeftSealed,RightSealed 表示上下左右封边的值 + // 异形板时使用 EachSealeds 数组表示每个边的封边数据,size表示封边的厚度 + EachSealeds?: { size: number; }[]; //每个边的封边数据 + + EachEdgeDrills?: string[]; //每个边的排钻数据 + + FrontDrill?: boolean; //正排孔面 + BackDrill?: boolean; //反排孔面 + Remarks?: [string, string][]; //备注 + } + + 例: + { + Type: "Board", + ...拉伸实体类属性 + ContourCurve: [{ pt: [0, 0], bul: 0 },{ pt: [0, 200], bul: 0 },{ pt: [100, 200], bul: 0 },{ pt: [100, 0], bul: 0 }], + Thickness: 18, + ColorIndex: 2, + Rot: [90, 0, 0], + Pos: [-200, 0, 0], + + Name: "层板", + RoomName:"房名", + CabinetName:"柜名", + + BrType: 0, + PositionType: 0, + OpenDir: 0, + Lines:0, + BigHole:0, + ComposingFace:2, + + BrMatName: "默认板材5厘", + Matrial:"生态板", + Color:"经典檀木", + //或 + BoardMaterialId:"SP202104121", + + UpSealed: "1", + DownSealed: "1", + LeftSealed: "1", + RightSealed: "1", + //或 + EachSealeds: [{ size: 1 }, { size: ,1 }, { size: 1 }, { size: 1 }, { size: 1 }], + + EachEdgeDrills: ["不排", "不排", "不排", "不排"], + FrontDrill:true, + BackDrill:true, + + Remarks: [["备注", "层板"],["备注2", "层板2"]], + } + + 板材信息可以自定义写入,也可以通过材质编码ID获取对应的值 + + 封边信息 + 普通板时使用 UpSealed,DownSealed,LeftSealed,RightSealed 表示上下左右封边的值 + 异形板时使用 EachSealeds 数组表示每个边的封边数据,size表示封边的厚度 + + +5.模板类 CFTemplate 继承 CFEntity + export interface CFTemplate extends CFEntity + { + // Type: "Template"; //类型模板(必填) + TempalteId?: string; //模板ID + Name?: string; //模板名称 + + //模块参数 + Lenght?: number; //长度 + Width?: number; //宽度 + Height?: number; //高度 + // Or + BoxSize?: [number, number, number]; //盒子尺寸 + + ParamMap?: { name: string, value: string; }[]; //模块参数 + + RoomName?: string; //房名 + CabinetName?: string; //柜名 + } + + 例: + { + Type: "Template", + TempalteId: "1923", + Name: "模板1", + Lenght: 100, + Width: 100, + Height: 100, + //Or + BoxSize: [100, 100, 100], + RoomName: "模板主卧", + CabinetName: "模板标准柜", + Rot: [90, 0, 0], + Pos: [400, 0, 0], + ParamMap: + [ + { + name: "CZ", + value: "1137" + }, + { + name: "QT", + value: "123" + } + ] + } + +6.实体树类 CFEntityTree 结构 继承 CFEntity + 定义实体树类 + export interface CFEntityTree extends CFEntity + { + // Type: "EntityTree"; //类型实体树(必填) + Name?: string; //模板空间名称 + Entitys?: CFEntity[]; //实体数组 + Childen?: CFEntityTree[]; //子模板数组 + } + + 例: + { + Type:"EntityTree", + Name:"模板1", + Children:[ + { + Type:"EntityTree", + Name:"模板2", + Entitys:[ + { + Type:"Entity", + Name:"实体1", + }, + { + Type:"Entity", + Name:"实体2", + } + ] + } + ] + } + + 实体树中的实体位置由实体自身的位置决定 + +7.五金实体类 CFHardware 继承 CFTemplate + 定义五金实体类 + export interface CFHardware extends CFTemplate + { + // Type: "Hardware"; //类型五金(必填) + Name?: string; //五金名称 + HardwarerId?: string; //五金模板ID + + Unit?: string; //单位 + ActualExpr?: string; //价格表达式 + Model?: string; //型号 + Factory?: string; //厂家 + Brand?: string; //品牌 + Spec?: string; //规格 + Comments?: string; //备注 + IsHole?: boolean; //是否挖孔 + Material?: string; //材质 + Color?: string; //颜色 + } + + 例: + { + Type: "Hardware", + ...模板属性 + + HardwarerId: "44444444", + Name: "五金", + Unit: "个", + ActualExpr: "L*W*H", + Model: "X-1", + Factory: "厂家晨丰", + Brand: "品牌晨丰", + Spec: "{L*2}", + Comments: "五金备注", + IsHole: true, + Material: "五金材质", + Color: "五金颜色", + } + + 当提供HardwareId时,五金实体会根据ID获取返回一个五金模板, + 没有提供HardwareId时,返回一个虚拟五金实体 + +8.顶线实体类 CFTopLine 继承 CFTemplate + 定义顶线实体类 + export interface CFTopline extends CFTemplate + { + // Type: "Topline"; //类型顶线(必填) + Name?: string; //顶线名称 + ToplineId?: string; //顶线横截面轮廓模板ID + + Unit?: string; //单位 + ActualExpr?: string; //价格表达式 + Model?: string; //型号 + Factory?: string; //厂家 + Brand?: string; //品牌 + Spec?: string; //规格 + Comments?: string; //备注 + + Contour?: { pt: [number, number], bul: 0; }[]; //横截面轮廓曲线 + PathCurve?: ExtrudeContour; //绘制路径曲线 + } + + 例1: + { + Type: "Topline", + ...模板属性 + + ToplineId: "55555555", + Name: "顶线", + Unit: "个", + ActualExpr: "L*W*H", + Model: "X-1", + Factory: "厂家晨丰", + Brand: "品牌晨丰", + Spec: "{L*2}", + Comments: "顶线备注", + PathCurve: [ + { pt: [0, 0], bul: 0 }, + { pt: [100, 0], bul: 0 }, + { pt: [100, 200], bul: 0 }, + { pt: [0, 200], bul: 0 }, + { pt: [0, 0], bul: 0 } + ], + } + + 例2: + { + Type: "Topline", + ...模板属性 + + Name: "顶线", + Unit: "个", + ActualExpr: "L*W*H", + Model: "X-1", + Factory: "厂家晨丰", + Brand: "品牌晨丰", + Spec: "{L*2}", + Comments: "顶线备注", + Contour: [ + { pt: [0, 0], bul: 0 }, + { pt: [0, 10], bul: 0 }, + { pt: [10, 10], bul: 0 }, + { pt: [10, 0], bul: 0 } + { pt: [0, 0], bul: 0 }, + ], + PathCurve: [ + { pt: [0, 0], bul: 0 }, + { pt: [100, 0], bul: 0 }, + { pt: [100, 200], bul: 0 }, + { pt: [0, 200], bul: 0 }, + { pt: [0, 0], bul: 0 } + ], + } + + 当提供ToplineId时,顶线实体会根据ID获取顶线模板的横截面轮廓,通过绘制路径轮廓进行绘制顶线 + + 没有提供ToplineId时,顶线会根据提供的横截面轮廓,通过绘制路径轮廓进行绘制顶线 diff --git a/src/Add-on/JiaJu/Import/JiaJuImport.ts b/src/Add-on/JiaJu/Import/JiaJuImport.ts index f1167e8c7..d768f66e2 100644 --- a/src/Add-on/JiaJu/Import/JiaJuImport.ts +++ b/src/Add-on/JiaJu/Import/JiaJuImport.ts @@ -34,9 +34,9 @@ import { XAxis, YAxis, ZAxis, ZeroVec, equaln } from "../../../Geometry/GeUtils" import { GetSealedBoardContour } from "../../../GraphicsSystem/CalcEdgeSealing"; import { AppToaster } from "../../../UI/Components/Toaster"; import { CuttingBoardByBoard } from "../../BoardCutting/CuttingUtils2"; +import { BoardMaterialLoader, MaterialInfo } from "../../CF/Import/BoardMaterialLoader"; import { FaceDirection } from "../../DrawDrilling/DrillType"; import { IBoardRectHoleType, SetBrHighHoleTypeFromRectHoleType } from "../../DrawDrilling/HoleUtils"; -import { JiaJuLoader, MaterialInfo } from "./JiaJuLoader"; let _xmlParse: DOMParser; @@ -171,7 +171,7 @@ class JiaJuParse async Do() { this.ParseRoomNameMap(); - const jiaJuLoader = new JiaJuLoader(); + const jiaJuLoader = new BoardMaterialLoader(); await jiaJuLoader.LoaderMaterialInfo(); this.Code_MaterialInfo = jiaJuLoader.Code_MaterialInfo; for (let ps of this.bom.Products[0].Product) diff --git a/src/Common/CommandNames.ts b/src/Common/CommandNames.ts index fe8ad5706..69f565d4d 100644 --- a/src/Common/CommandNames.ts +++ b/src/Common/CommandNames.ts @@ -7,6 +7,7 @@ export enum CommandNames KJLMaterialMap = "KJLMATERIALMAP", Clearkjltoken = "CLEARKJLTOKEN", JiaJuImport = "JIAJUIMPORT", + CFImport = "CFIMPORT", Group = "GROUP", DXFImport = "DXF", DWGImport = "DWG", diff --git a/src/Editor/CommandRegister.ts b/src/Editor/CommandRegister.ts index d92daefe9..d561fbdc4 100644 --- a/src/Editor/CommandRegister.ts +++ b/src/Editor/CommandRegister.ts @@ -211,6 +211,7 @@ import { Command_GroovesModify } from "../Add-on/showModal/GroovesModify"; import { ShowEditorBBS } from "../Add-on/showModal/ShowModal"; // import { DrawFloor } from '../Add-on/DrawFloor'; // import { RevTarget, SaveTarget } from '../Add-on/RenderTarget'; +import { ImportCFData } from "../Add-on/CF/Import/CFImport"; import { ChangeColorByRoomCabinet } from "../Add-on/ChangeColorByRoomOrCabinet/ChangeColorByRoomOrCabinet"; import { Command_RemovePolylineRepeatPos } from "../Add-on/Cmd_RemovePolylineRepeatPos"; import { Command_Modeling } from "../Add-on/Command_Modeling"; @@ -317,6 +318,9 @@ export function registerCommand() //嘉居 commandMachine.RegisterCommand(CommandNames.JiaJuImport, new Command_JiaJuImport()); + //晨丰导入 + commandMachine.RegisterCommand(CommandNames.CFImport, new ImportCFData()); + //编组 commandMachine.RegisterCommand(CommandNames.Group, new Command_Group()); commandMachine.RegisterCommand(CommandNames.UnGroup, new Command_UnGroup()); diff --git a/src/UI/Components/CommandPanel/CommandList.ts b/src/UI/Components/CommandPanel/CommandList.ts index b18d1fcc8..3818ec910 100644 --- a/src/UI/Components/CommandPanel/CommandList.ts +++ b/src/UI/Components/CommandPanel/CommandList.ts @@ -2246,6 +2246,15 @@ export const CommandList: ICommand[] = [ chName: "嘉居导入", chDes: "从嘉居导入数据", }, + { + typeId: "util", + link: `#`, + defaultCustom: "CF", + command: CommandNames.CFImport, + type: "工具", + chName: "晨丰导入", + chDes: "晨丰文档导入数据", + }, { typeId: "util", link: `#`, diff --git a/src/UI/Components/Template/ToplineList.tsx b/src/UI/Components/Template/ToplineList.tsx index f1776b134..8cb2a64c4 100644 --- a/src/UI/Components/Template/ToplineList.tsx +++ b/src/UI/Components/Template/ToplineList.tsx @@ -4,9 +4,10 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { app } from '../../../ApplicationServices/Application'; import { ToplineUrls } from '../../../Common/HostUrl'; -import { inflateBase64 } from "../../../Common/inflate"; import { PostJson, RequestStatus } from '../../../Common/Request'; import { deflate, getPolylineSVG, toplineFileIn } from '../../../Common/SerializeMaterial'; +import { copyTextToClipboard } from '../../../Common/Utils'; +import { inflateBase64 } from "../../../Common/inflate"; import { CADFiler } from '../../../DatabaseServices/CADFiler'; import { Polyline } from '../../../DatabaseServices/Entity/Polyline'; import { CommandWrap } from '../../../Editor/CommandMachine'; @@ -174,6 +175,11 @@ export class ToplineList extends React.Component this.props.updata("", null, this.props.getData)} /> + this.copyId(tpline.topline_id)} + /> + { + copyTextToClipboard(toplineId); + AppToaster.show({ + message: "ID复制成功", + intent: Intent.SUCCESS + }); + }; public render() { return (