From 2b0c2055ff5a79cf794926fd5946f8f2a69d1a9b Mon Sep 17 00:00:00 2001 From: DESKTOP-8BA9KEAgjm Date: Sat, 3 Oct 2026 22:20:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=AE=A1=E9=81=93ISO?= =?UTF-8?q?=E5=9B=BEPCF=E5=AF=BC=E5=87=BA(EW=5FPCF/EW=5FPCFSPLIT)=EF=BC=8C?= =?UTF-8?q?=E5=AE=8C=E5=96=84ITEM-CODE=E4=B8=8EWELD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CoreCommand 新增管é�“ ISO 图 PCF 导出功能: - EW_PCF:整个管é�“系统导出为å�•个 PCF 文件。 - EW_PCFSPLIT:按管é�“系统/连通å­�网拆分为多张 PCF。 内容完善: - 组件é½�全:直管ã€�管件(弯头/三通/å�˜å¾„/管帽等)ã€�法兰ã€�阀门ã€�设备ã€�支å�Šæž¶ã€‚ - ITEM-CODE:按 等级+管径(+类型/类别) 查规格库,写出 ITEM-CODE/ITEM-DESCRIPTION/PIPING-SPECï¼› 弯头按实测夹角区分 90°/45°,阀门按 VLVTYPE 映射类别过滤。 - WELD:两侧接å�£è¿žæŽ¥ç±»åž‹å�‡ä¸ºç„пޥ(0) 时生æˆ�焊å�£ï¼›æ³•兰螺栓é�¢ä¸�计焊å�£ã€‚ 构建:cmakelists.txt 加入 pcf.cppï¼›StdArx.h 声明 EW_PCF/EW_PCFSPLIT 命令。 --- CODEBUDDY.md | 150 + SourceCode/Code2026/CoreCommand/EarthWorm.cpp | 6 + SourceCode/Code2026/CoreCommand/StdArx.h | 2 + .../Code2026/CoreCommand/cmakelists.txt | 1 + SourceCode/Code2026/CoreCommand/pcf.cpp | 2800 +++++++++++++++-- SourceCode/Code2026/CoreCommand/pcf.h | 25 + iso需求讨论.txt | 6 + 7 files changed, 2734 insertions(+), 256 deletions(-) create mode 100644 CODEBUDDY.md create mode 100644 iso需求讨论.txt diff --git a/CODEBUDDY.md b/CODEBUDDY.md new file mode 100644 index 0000000..c0028fe --- /dev/null +++ b/CODEBUDDY.md @@ -0,0 +1,150 @@ +# CODEBUDDY.md + +This file provides guidance to CodeBuddy Code when working with code in this repository. + +> å�¦è§� `ai.memory/`:éš�仓库æ��交的跨机器项目记忆(概览 / 构建 / 模å�— / 工作日志 / 约定)。开始工作å‰�建议先阅读。本文件与其ä¿�æŒ�一致,冲çª�时以 `ai.memory/` 与当å‰�构建脚本为准。 + +## 项目概览 + +- **产å“�**:上海å�Žè½¯ **Envi3D 2026(环境设计)** —— CAD/BIM **机电(MEP)æ�’件套件**。 +- **å½¢æ€�**:ObjectARX / ZRX æ�’件(DLL,å�Žç¼€ `.arx` / `.zrx`),è¿�行在 CAD 宿主内,å�«å¤§é‡� MFC 界é�¢ä¸Žè‡ªå®šä¹‰å›¾å…ƒå®žä½“。 +- **CMake 项目å��**:`SHS_Code2026`(version 1.0.0)。 +- **主代ç �目录**:`SourceCode/Code2026/`(C++ 约 2888 `.cpp` + 3104 `.h`ï¼›å�¦æœ‰å¤©æ­£ `tg_shs/` 系列库)。 +- **远端**:`origin` = `ssh://gjm@47.93.46.28:1216/srv/git/new-start.git`,主分支 `main`。æ��交信æ�¯ç”¨ä¸­æ–‡ã€‚ + +目标平å�°ï¼ˆç”± preset 与编译å®�区分): + +| å¹³å�° | SDK | 版本 | 对应 CAD | +| --- | --- | --- | --- | +| AutoCAD | ObjectARX | R18 ~ R26 | CAD 2010 ~ 2027 | +| 中望CAD | ZRX | Z2023 ~ Z2026 | ZWCAD 2023 ~ 2026 | + +## 构建 + +**统一使用 CMake,ä¸�å†�使用 Visual Studio 工程文件(`.vcxproj` / `.sln` 已全部删除)。唯一例外:`SourceCode/Code2026/StartApp/StartApp.sln`(C# å�¯åŠ¨å™¨ï¼Œç‹¬ç«‹äºŽ CMake)。** + +所有构建命令å�‡åœ¨ `SourceCode/Code2026/` 目录下执行(preset 与 `cmakepresets.json` å�Œç›®å½•): + +```bash +cd SourceCode/Code2026 + +# é…�ç½® + 编译(示例:AutoCAD 2025-2026) +cmake --preset R250 +cmake --build --preset R250 + +# å�ªæž„建å�•个目标(例如æŸ�个模å�—) +cmake --build --preset R250 --target HvacCmd +``` + +- è¦�求 CMake ≥ 3.21;生æˆ�器固定 `Visual Studio 18 2026`,架构 `x64`。 +- 工具集(toolset)由 preset 指定,éš� CAD 版本å�˜åŒ–:`v143 / v142 / v141 / v140 / v110 / v100 / v90`。 +- C++ 标准自动切æ�¢ï¼šARX 26 → C++20ï¼›ARX 20~25 与 ZRX → C++14ï¼›ARX 20 → C++03;更è€� → C++98。 +- 输出目录:`bin/Code2026/{Debug|Release}-x64-<标签>` 与 `lib/Code2026/...`,标签形如 `R250` / `Z2026`。 +- Debug 构建会通过 post-build 调用 `copyarx.exe`,按 `sh_output_path.json`(ACAD)/ `zw_output_path.json`(中望)把产物部署到 `c:\ShangHuaSoft\Envi3D-2026-M`。 + +### 预设(`SourceCode/Code2026/cmakepresets.json`,共 13 套) + +| 分组 | preset | +| --- | --- | +| AutoCAD | `R180 R190 R200 R210 R220 R230 R240 R243 R250 R260` | +| 中望CAD | `Z2023 Z2024 Z2025 Z2026` | + +关键 cache å�˜é‡�:`CAD_SDK_ROOT`(`arx/` 或 `zrx/`)ã€�`DEP_LIB_ROOT`/`DEP_INC_ROOT`(`../dep_lib` / `../dep_inc`)ã€�`PRODUCT=ENV_2025_V6_S0`ã€�`TRIAL_YEAR=2026`ã€�`GENERATE_BIN_DIR`/`GENERATE_LIB_DIR`。 + +### 顶层è�šå�ˆç›®æ ‡ + +- `Build_TG` → `wfA wfB wfS wfAnotate wfoutdoor` +- `Build_SH_CORE` → `AecRxBase` + `CoreCommand_TRIAL_YEAR` + `CoreCommand_BAL_REMOTE` +- `Build_SH_GLOBAL` → `MFCCtrl sqliteserver AdsXRx ThunderProof` + +### 批é‡�编译与打包(`autoCompile/WF2026/`) + +- `batch_build.bat` → 调用 `cmake_batch_build.py` 批é‡�编译多个 preset。 +- 打包脚本:Inno Setup(`*.iss`)+ Python(`SHSCompile.py`)+ 多个 `.bat`,覆盖 ACAD/中望ã€�1 年期/加密版,以å�Šå®¢æˆ·ä¸“版(中广核ã€�国能集团等)。如 `环境设计-ACAD-加密自动打包.bat`ã€�`环境设计-中望-1年期自动打包.bat`。 + +### CMake 构建体系(`cmake/`) + +- `cmake/functions.cmake`:核心å°�装 + - `add_custom_module(dir folder)`:注册å­�模å�—(自动 `add_subdirectory` + 设 FOLDER);`add_custom_module_2(dir target folder)` 用于目录å��≠目标å��的情况。 + - `target_link_objectarx(target EXT)`:链接 CAD SDKã€�全局头 `ShsGlobalIncludes`ã€�定义 `CMAKE` 与 `ARX=<版本>`。 + - `simple_link_cad_sdk`:按 `IsZWCAD()` 自动选择 `ThirdParty::ARX` / `ThirdParty::ZRX`。 + - `set_encryption_definitions_and_output_path(target MODE)`:**授æ�ƒæ¨¡å¼�**,è§�下。 + - `set_debug_post_build`:调用 `copyarx.exe` 部署。 +- `cmake/ThirdPartyDeps.cmake`:定义 `ThirdParty::ARX` / `ZRX` / `SQLite3` / `cURL` / `TG` / `modernGlue` / `BitAnswer` 等接å�£ç›®æ ‡ï¼›æŒ‰ SDK 版本æ�¡ä»¶è¿½åŠ åº“ï¼ˆå¦‚ `acdrawbridge` 需 >19,`acpal`/`acgeoment` 需 >23)。 +- 顶层 `cmakelists.txt`:`add_custom_module` 注册全部模å�—并组织 `FOLDER`(`SH/Core`ã€�`SH/Pipe` …)。 + +## 授æ�ƒ / 加密 + +- `CoreCommand`ã€�`CoreLibrary` 通过 `get_encryption_modes()` ç”±**å�Œä¸€å¥—æº�ç �编译出两个目标**: + - `BAL_REMOTE`(网络é”� / æ­£å¼�版) + - `TRIAL_YEAR`(1 年期试用版,定义 `TRIAL_YEAR=<年份>`) +- ä¾�èµ– **BitAnswer**(加密狗库);加密表由 `utility/generateEncryptionTable` 生æˆ�。 + +## æž¶æž„ + +分三层: + +1. **实体层**:`CoreLibrary` 定义海é‡�自定义图元 `AecDbXxx`(继承 `AcDbEntity`),是数æ�®æ¨¡åž‹æ ¸å¿ƒï¼›å�Œæ—¶å�«ç»˜å›¾/分解/布尔等基础能力。 +2. **命令层**:å�„ `*Cmd` 模å�—实现 MFC 对è¯�框 + Jig 交互 + ARX 命令注册。 +3. **链接关系**:业务模å�— → `AecRxBase` / `CoreCommand` / `sqliteserver` / `MFCCtrl`。 + +模å�—在顶层 `cmakelists.txt` 中按 FOLDER 分组: + +| FOLDER | 模å�— | è�Œè´£ | +| --- | --- | --- | +| `SH/Global_Libraries` | `MFCCtrl`, `sqliteserver` | MFC 控件库;SQLite æ•°æ�®æœ�务 | +| `SH/ThunderProof` | `AdsXRx`, `ThunderProof` | 防雷接地设计 | +| `SH/Core` | `AecRxBase`, `CoreImplement`, `CoreLibrary`, `CoreCommand` | 核心基类ã€�自定义实体ã€�主命令 | +| `SH/Pipe` | `PipelineCmd`, `PipelineSpecCmd`, `PIDLineCmd`, `ISODraft`, `PipeHanger`, `PlumbingCmd`, `Pool3dCmd` | 管é�“/工艺/ISO 图/支å�Šæž¶/给排水/æ°´æ±  | +| `SH/Structures` | `ArchCmd`, `ElecCmd`, `HvacCmd`, `SPLDCmd` | 建筑/电气/暖通/é�“è·¯ | +| `SH/Other` | `shsTK`, `Dimension`, `EarthWormMain`, `EarthWormCmd` | 通用工具ã€�标注ã€�主程åº� | +| `TG/*` | `tg_shs/*` | 天正系列库 | + +关键模å�—: + +- **CoreLibrary**:数æ�®æ¨¡åž‹æ ¸å¿ƒï¼ˆè‡ªå®šä¹‰å®žä½“ `AecDbXxx`)。 +- **AecRxBase**:ARX 基类库(`AecDbEntityBase`ã€�`AecDbCurveBase`ã€�Gripã€�å�Œå‡»ç¼–辑等)。 +- **CoreCommand**:主命令集 + MFC 主界é�¢/é�¢æ�¿ï¼ˆBIM é�¢æ�¿ã€�AI 助手é�¢æ�¿ç­‰ï¼‰ï¼›**生æˆ�两ç§�加密版本**。 +- **CoreImplement**:仅在 Debug 下有效(自定义实体的实现层)。 +- **StartApp**:C# (.NET WinForms) å�¯åŠ¨å™¨ï¼Œä¸�èµ° CMake,ä¿�留独立 `StartApp.sln`。 +- **tg_shs/**:天正系列(`shs_kernal`/wfKã€�`shs_twtkernal`/wfKernalã€�`shs_GeLib`ã€�`shs_annotate`/wfAã€�`shs_twtanotate`/wfAnnotateã€�`shs_blklib`/wfBã€�`shs_siteplan`/wfSã€�`shs_pipewire`/wfpipewã€�`shs_outdoor`/wfoutdoorã€�`shs_ximage/*` 图åƒ�库ã€�`shs_dbf`ã€�`shs_sqlite` 等)。 + +## 目录结构 + +``` +envi-code/ +├── Arx/ # AutoCAD ObjectARX SDK(R19.0~R26.0,gitignore) +├── ZRX/ # 中望 ZRX SDK(Z2023~Z2026,gitignore) +├── SourceCode/ +│ ├── dep_inc/ # 第三方头:modernGlueã€�rapidjsonã€�curl +│ ├── dep_lib/ # 第三方库:modernGlueã€�pub(å�« sqlite3/BitAnswer) +│ └── Code2026/ # ★ 主代ç � + cmakelists.txt + cmakepresets.json + cmake/ +├── bin/, lib/ # 编译产物(按 SDK 版本分å­�目录,gitignore) +├── cmake_output/ # CMake 生æˆ�目录(gitignore) +├── autoCompile/ # 打包/加密/å�‘布脚本(.bat/.py/.iss) +├── utility/ # generateEncryptionTable(授æ�ƒåŠ å¯†è¡¨ç”Ÿæˆ�) +└── ai.memory/ # 跨机器项目记忆 +``` + +## 新增模å�—约定 + +在模å�—目录放 `CMakeLists.txt`,并在顶层 `SourceCode/Code2026/cmakelists.txt` 用 `add_custom_module(<相对目录> )` 注册。模å�— `CMakeLists.txt` å�‚考 `HvacCmd/CMakeLists.txt`: + +```cmake +add_library( SHARED ${SOURCES}) +add_def_file_name(SOURCES "") +target_set_name_and_suffix( "" ".arx") +target_link_objectarx( ) +set_debug_post_build( "" ".arx") +``` + +需è¦�授æ�ƒå�Œç‰ˆæœ¬æ—¶ï¼Œå�‚考 `CoreCommand/cmakelists.txt` çš„ `get_encryption_modes` + `foreach(MODE ...)` + `set_encryption_definitions_and_output_path` 写法。 + +## å¹³å�°å·®å¼‚与注æ„�事项 + +- 用 `IsZWCAD()` 判断目标平å�°ï¼›ZRX 产物å�Žç¼€è‡ªåЍå�˜ `.zrx`,链接 `ThirdParty::ZRX`ï¼›ARX 链接 `ThirdParty::ARX`。 +- 编译å®�:`ARX=<版本å�·>` 或 `ZWCAD`。 +- **æº�ç �ç¼–ç �为 GBK/ANSI(无 BOM)**:新增或修改的 `.cpp/.h` å¿…é¡»ä¿�存为 GBK。若存æˆ� UTF-8,MSVC 会按 GBK 误读其中的中文,导致 `C2001: newline in constant`(中文全角标点如 `。` 紧跟字符串结尾引å�·æ—¶å°¤å…¶å®¹æ˜“触å�‘)。æ��交å‰�å�¯ç”¨ `python -c "open('f.cpp','rb').read().decode('gbk')"` 校验。 +- 部分库仅在特定 SDK 版本å�¯ç”¨ï¼ˆå¦‚ `acdrawbridge` 需 >19,`acpal`/`acgeoment` 需 >23),已在 `ThirdPartyDeps.cmake` 处ç�†ã€‚ +- **ç¦�æ­¢**新增或ä¾�èµ– `.vcxproj` / `.sln`(`StartApp` 除外)。`cmake_output/` 下 CMake 生æˆ�的临时 `*.vcxproj` 是构建产物ã€�已被 gitignore,**ä¸�è¦�**误æ��交。 +- `.gitignore` 忽略:`Arx/`ã€�`cmake_output/`ã€�`bin/`ã€�`lib/`,以å�Š `*.obj/*.pdb/*.user/.vs/` ç­‰ VS 中间产物。 diff --git a/SourceCode/Code2026/CoreCommand/EarthWorm.cpp b/SourceCode/Code2026/CoreCommand/EarthWorm.cpp index 7849045..e156c99 100644 --- a/SourceCode/Code2026/CoreCommand/EarthWorm.cpp +++ b/SourceCode/Code2026/CoreCommand/EarthWorm.cpp @@ -722,6 +722,12 @@ void InitApplication() ADD_CMD(EW_DWGO, EW_PDWGOUTCmdFnc); ADD_CMD(EW_IGSO, EW_IGSOUTCmdFnc); + //ISOͼ: °´¹ÜÏߺŵ¼³ö PCF ÖмäÎļþ + ADD_CMD(EW_PCF, EW_PCFCmdFnc); + + //ISOͼ: ×Ô¶¯·Öͼ(°´¹ÜºÅ/Á¬Í¨ÐÔ/ͼ·ù°ÑÒ»¸ö¹ÜµÀϵͳ²ð³É¶àÕÅ PCF) + ADD_CMD(EW_PCFSPLIT, EW_PCFSPLITCmdFnc); + //¹ÜÀÈÂþÓÎ ADD_CMD(EW_GLMY, EW_GLMYCmdFnc); diff --git a/SourceCode/Code2026/CoreCommand/StdArx.h b/SourceCode/Code2026/CoreCommand/StdArx.h index d32e80b..9cddae7 100644 --- a/SourceCode/Code2026/CoreCommand/StdArx.h +++ b/SourceCode/Code2026/CoreCommand/StdArx.h @@ -128,6 +128,8 @@ void EW_STLOUTCmdFnc(); void EW_SALOUTCmdFnc(); void EW_PDWGOUTCmdFnc(); void EW_IGSOUTCmdFnc(); +void EW_PCFCmdFnc(); +void EW_PCFSPLITCmdFnc(); void EW_GLMYCmdFnc(); void EW_ENODECmdFnc(); void EW_CTRLVIEWCmdFnc(); diff --git a/SourceCode/Code2026/CoreCommand/cmakelists.txt b/SourceCode/Code2026/CoreCommand/cmakelists.txt index 90630b0..26941ed 100644 --- a/SourceCode/Code2026/CoreCommand/cmakelists.txt +++ b/SourceCode/Code2026/CoreCommand/cmakelists.txt @@ -99,6 +99,7 @@ set(SOURCES "aecuicontextmenu.cpp" "sortedmenuitemdlg.cpp" "collisiondetection.cpp" + "pcf.cpp" "EarthWorm.rc" # CoreCommand.def ) diff --git a/SourceCode/Code2026/CoreCommand/pcf.cpp b/SourceCode/Code2026/CoreCommand/pcf.cpp index 68d22f6..2bb9d46 100644 --- a/SourceCode/Code2026/CoreCommand/pcf.cpp +++ b/SourceCode/Code2026/CoreCommand/pcf.cpp @@ -7,9 +7,11 @@ #include "aecdbewfitting.h" #include "aecdbewequipment.h" #include "aecdbxequipment.h" +#include "aecdbpipehanger.h" #include #include #include +#include using namespace std; @@ -19,9 +21,9 @@ namespace typedef pair STR_PAIR; typedef map STR_MAP; - // 定义属性字符串,é�¿å…�直接输入造æˆ�笔误,用到那个,定义哪个 + // ¶¨ÒåÊôÐÔ×Ö·û´®£¬±ÜÃâÖ±½ÓÊäÈëÔì³É±ÊÎó£¬Óõ½ÄǸö£¬¶¨ÒåÄĸö // ========================================== - // 1. 基础å�•ä½� (Units) + // 1. »ù´¡µ¥Î» (Units) // ========================================== STR_PTR PCF_UNITS_MM = L"MM"; STR_PTR PCF_UNITS_METER = L"METER"; @@ -37,7 +39,7 @@ namespace STR_PTR PCF_UNITS_LBFT = L"LBFT"; // ========================================== - // 2. 全局头部属性 (Header Attributes) + // 2. È«¾ÖÍ·²¿ÊôÐÔ (Header Attributes) // ========================================== STR_PTR PCF_HEAD_ISOGEN_FILES = L"ISOGEN-FILES"; STR_PTR PCF_HEAD_UNITS_BORE = L"UNITS-BORE"; @@ -52,7 +54,7 @@ namespace STR_PTR PCF_HEAD_SYSTEM_IDENTIFIER = L"SYSTEM-IDENTIFIER"; // ========================================== - // 3. 组件主类型 (Component Types) - 增加å‰�ç¼€ COMP_ 以防命å��冲çª� + // 3. ×é¼þÖ÷ÀàÐÍ (Component Types) - Ôö¼Óǰ׺ COMP_ ÒÔ·ÀÃüÃû³åÍ» // ========================================== STR_PTR PCF_COMP_PIPE = L"PIPE"; STR_PTR PCF_COMP_ELBOW = L"ELBOW"; @@ -65,13 +67,39 @@ namespace STR_PTR PCF_COMP_BOLT = L"BOLT"; STR_PTR PCF_COMP_WELD = L"WELD"; STR_PTR PCF_COMP_CAP = L"CAP"; - STR_PTR PCF_COMP_BLIND_FLANGE = L"BLIND-FLANGE"; + STR_PTR PCF_COMP_BLIND_FLANGE = L"FLANGE-BLIND"; + STR_PTR PCF_COMP_REDUCER_CONC = L"REDUCER-CONCENTRIC"; + STR_PTR PCF_COMP_REDUCER_ECC = L"REDUCER-ECCENTRIC"; STR_PTR PCF_COMP_INSTRUMENT = L"INSTRUMENT"; STR_PTR PCF_COMP_SUPPORT = L"SUPPORT"; STR_PTR PCF_COMP_EQUIPMENT = L"EQUIPMENT"; + STR_PTR PCF_COMP_COUPLING = L"COUPLING"; + STR_PTR PCF_COMP_OLET = L"OLET"; + STR_PTR PCF_COMP_BEND = L"BEND"; + + // É豸(EQUIPMENT)¿é¹Ø¼ü×Ö + STR_PTR PCF_KW_REFERENCE = L"REFERENCE"; + STR_PTR PCF_KW_LOCATION = L"LOCATION"; + STR_PTR PCF_KW_ORIENTATION = L"ORIENTATION"; + STR_PTR PCF_KW_NOZZLE = L"NOZZLE"; + STR_PTR PCF_KW_DIRECTION = L"DIRECTION"; + STR_PTR PCF_KW_SHAPE = L"SHAPE"; + STR_PTR PCF_KW_CATEGORY = L"CATEGORY"; + + // Ö§µõ¼Ü(SUPPORT)¿é¹Ø¼ü×Ö / ȡֵ + STR_PTR PCF_ATTR_NAME = L"NAME"; + STR_PTR PCF_SKEY_SUPPORT_DEFAULT = L"01HG"; + STR_PTR PCF_CAT_ERECTION = L"ERECTION"; + STR_PTR PCF_ATTR_COMPONENT_ATTRIBUTE0 = L"COMPONENT-ATTRIBUTE0"; + STR_PTR PCF_KEY_SUPPORT_DN = L"DN"; // Ö§µõ¼ÜרҵÊý¾Ý¼ü(È¡×Ôͼ¼¯±íµÄÁÐÃû) + STR_PTR PCF_KEY_SUPPORT_MODE = L"MODE"; // Ö§µõ¼ÜÀàÐÍ 0~4 + + // º¸¿Ú(WELD)¿é¹Ø¼ü×Ö / ȡֵ + STR_PTR PCF_ATTR_SKEY_WELD = L"WW"; // Isogen º¸½Ó·ûºÅ¼ü + STR_PTR PCF_CAT_FABRICATION = L"FABRICATION"; // ========================================== - // 4. å��标与节点类型 (Point Types) + // 4. ×ø±êÓë½ÚµãÀàÐÍ (Point Types) // ========================================== STR_PTR PCF_PT_END_POINT = L"END-POINT"; STR_PTR PCF_PT_CENTRE_POINT = L"CENTRE-POINT"; @@ -80,7 +108,7 @@ namespace STR_PTR PCF_PT_CO_ORDS = L"CO-ORDS"; // ========================================== - // 5. 组件明细与业务属性 (Component Attributes) + // 5. ×é¼þÃ÷ϸÓëÒµÎñÊôÐÔ (Component Attributes) // ========================================== STR_PTR PCF_ATTR_SKEY = L"SKEY"; STR_PTR PCF_ATTR_ITEM_CODE = L"ITEM-CODE"; @@ -98,7 +126,7 @@ namespace { public: private: - ostream &m_out; // 统一使用窄字符æµ�基类ï¼� + ostream &m_out; // ͳһʹÓÃÕ­×Ö·ûÁ÷»ùÀ࣡ bool m_isFirstItem; public: @@ -110,7 +138,7 @@ namespace ~PcfRow() { m_out << "\n"; } - // 1. 基础类型模æ�¿ (如 int, double, AcGePoint3d) + // 1. »ù´¡ÀàÐÍÄ£°å (Èç int, double, AcGePoint3d) template PcfRow &operator<<(const T &value) { @@ -120,19 +148,19 @@ namespace return *this; } - // 3. 核心å�‡çº§ï¼šæ‹¦æˆª AutoCAD 宽字符 (处ç�†å¸¦ä¸­æ–‡çš„æ��è¿°ä¿¡æ�¯) + // 3. ºËÐÄÉý¼¶£ºÀ¹½Ø AutoCAD ¿í×Ö·û (´¦Àí´øÖÐÎĵÄÃèÊöÐÅÏ¢) PcfRow &operator<<(STR_PTR wValue) { if (!m_isFirstItem) m_out << " "; - // 自动转为 UTF-8 并推入底层字节æµ� + // ×Ô¶¯×ªÎª UTF-8 ²¢ÍÆÈëµ×²ã×Ö½ÚÁ÷ m_out << Base64::unicode2Ansii(wValue, CP_UTF8); m_isFirstItem = false; return *this; } - // 写一个属性 + // дһ¸öÊôÐÔ PcfRow &write_Attribute(STR_PTR attri, STR_PTR svalue) { if ((attri && svalue) @@ -146,15 +174,15 @@ namespace PcfRow &operator<<(PcfRow &row, const AcGePoint3d &pt) { - // 自动拆解并ä¿�æŒ�é—´è·� + // ×Ô¶¯²ð½â²¢±£³Ö¼ä¾à row << pt.x << pt.y << pt.z; return row; } void writePcfAttribute(ostream &out, int indent, STR_PTR attri, STR_PTR svalue) { - // å�ªæœ‰å½“属性å��和属性值都切实有效时,æ‰�实例化 PcfRow - if (!attri && !svalue && wcslen(attri) > 0 && wcslen(svalue) > 0) + // Ö»Óе±ÊôÐÔÃûºÍÊôÐÔÖµ¶¼ÇÐʵÓÐЧʱ£¬²ÅʵÀý»¯ PcfRow + if (attri && svalue && wcslen(attri) > 0 && wcslen(svalue) > 0) PcfRow(out, indent) << attri << svalue; } @@ -168,7 +196,8 @@ namespace { std::wstringstream wss; wss << fixed << setprecision(prec) << v; - return makePair(field, wss.str()); + // ÏÔʽ¹¹Ôì std::pair£¬±ÜÃâÔÙÆ¥Åäµ½±¾Ä£°åÔì³ÉÎÞÏ޵ݹé(C4717) + return std::make_pair(std::wstring(field), wss.str()); } wstring getValue(STR_MAP mm, STR_PTR key) @@ -179,53 +208,169 @@ namespace return L""; } - // level 等级 - // 通过 level在 AecSpecname 里é�¢æŸ¥è¯¢ 行业 - // 通过 等级ã€�行业在table内查询 fileds - bool getSpecFieldByLevel(CUIISQLiteServer *pDb - , STR_PTR table - , STR_PTR level - , const STR_MAP &filter - , STR_MAP &results) + // ============================ ¹æ¸ñ¿â(ÎïÁÏÂë)²éѯ ============================ + + // ºÏ·¨µÈ¼¶Ãû¼¯ºÏ(È¡×Ô AecSpecname)£¬ÓÃÓÚÔÚʵÌåרҵÊý¾ÝÀï·´²é"µÈ¼¶"¡£ + // ½ø³ÌÄÚÖ»¼ÓÔØÒ»´Î¡£ + const std::set &validLevels(CUIISQLiteServer *pDb) { - if (!pDb || !level || !table || !filter.empty()) return false; + static std::set s_levels; + static bool s_bLoaded = false; - std::wstringstream wss; - wss << L"SELECT *" - << L" FROM "<< table << L" t" - << L" INNER JOIN AecSpecname a" - << L" ON t.[项目å��ç§°] = a.[项目å��ç§°]" - << L" AND t.[等级å��ç§°] = a.[等级å��ç§°]" - << L" WHERE a.[等级å��ç§°] = '" << level << L"'"; - - STR_MAP::const_iterator itF(filter.begin()); - for (; itF != filter.end(); ++itF) + if (!s_bLoaded && pDb) { - wss << L" AND t.["<< itF->first << L"] = '" << itF->second << L"'"; + CStringArray ar; + if (pDb->GetSelData(_T("SELECT DISTINCT µÈ¼¶Ãû³Æ FROM AecSpecname"), ar) > 0) + { + for (int i = 0; i < ar.GetSize(); ++i) + { + CString s(ar[i]); + s.Trim(); + if (!s.IsEmpty()) s_levels.insert(s); + } + } + // ¼ÓÔØÊ§°Ü(¿âû´ò¿ªµÈ)ʱÏ´ÎÔÙÊÔ + s_bLoaded = !s_levels.empty(); } - - map res; - pDb->GetSelData(wss.str().c_str(), res); - - map::const_iterator itR(res.begin()); - for (; itR != res.end(); ++itR) - { - results.insert(make_pair(itR->first, itR->second)); - } - - return !results.empty(); + return s_levels; } /* - pcf 文件头 + ½âÎö×é¼þµÄ"µÈ¼¶"¡£ + ÏȶÁ PIPE_LEVEL("Level")£»Îª¿ÕʱɨÃèרҵÊý¾ÝÀïµÄÈ«²¿×Ö·û´®Öµ£¬ + ÃüÖÐ AecSpecname ÀïµÄºÏ·¨µÈ¼¶Ãû¼´²ÉÓᣠ+ + ʵ²âͼֽÀï PIPE_LEVEL ¾­³£Îª¿Õ(ÀýÈç²åÈë·§ÃÅʱ command.cpp:18836 »á°ÑËüÇå¿Õ)£¬ + µ«¹æ¸ñ¿âÀïµÄµÈ¼¶ÊÇÓÐЧµÄ£¬ËùÒÔ±ØÐë×öÕâ²ã¶µµ×£¬·ñÔò ITEM-CODE ÓÀÔ¶²é²»³öÀ´¡£ */ - bool pcf_begin(std::ostream &out, STR_PTR pipeline_reference - , STR_PTR spec + CString resolveLevel(AecDbObjXDataMap *pMap, CUIISQLiteServer *pDb) + { + if (!pMap) return _T(""); + + CString sLevel; + if (pMap->GetAt(PIPE_LEVEL, sLevel) && !sLevel.IsEmpty()) + { + sLevel.Trim(); + return sLevel; + } + + const std::set &levels = validLevels(pDb); + if (levels.empty()) return _T(""); + + // ÐèÒª·Ç const µü´úÆ÷²ÅÄܱéÀúרҵÊý¾Ý + for (AecDbObjXDataMap::It it = pMap->Begin(); it != pMap->End(); ++it) + { + const AecXData &xd = it->second; + if (xd.nVt == VT_BSTR && xd.pszVal) + { + CString s(xd.pszVal); + s.Trim(); + if (levels.find(s) != levels.end()) + return s; + } + } + return _T(""); + } + + // Æ´¹æ¸ñ²éѯ SQL£º°´ µÈ¼¶ + Èô¸ÉµÈÖµ¹ýÂËÁÐ + void buildSpecSql(CString &sql, LPCTSTR pszTable, const CString &sLevel + , const std::vector > &filters) + { + sql.Format(_T("SELECT * FROM %s t") + _T(" INNER JOIN AecSpecname a") + _T(" ON t.[ÏîÄ¿Ãû³Æ] = a.[ÏîÄ¿Ãû³Æ] AND t.[µÈ¼¶Ãû³Æ] = a.[µÈ¼¶Ãû³Æ]") + _T(" WHERE a.[µÈ¼¶Ãû³Æ] = '%s'"), pszTable, (LPCTSTR)sLevel); + + for (size_t k = 0; k < filters.size(); ++k) + { + sql += _T(" AND t.["); + sql += filters[k].first; + sql += _T("] = '"); + sql += filters[k].second; + sql += _T("'"); + } + } + + // °´ µÈ¼¶ + Èô¸ÉµÈÖµ¹ýÂËÁÐ ²é¹æ¸ñ¿â£¬·µ»ØËùÓÐÆ¥ÅäÐÐ(ÁÐÃû -> Öµ) + bool querySpecRows(CUIISQLiteServer *pDb, LPCTSTR pszTable, const CString &sLevel + , const std::vector > &filters + , std::vector > &rows) + { + rows.clear(); + if (!pDb || !pszTable || sLevel.IsEmpty()) return false; + + CString sql; + buildSpecSql(sql, pszTable, sLevel, filters); + return pDb->GetSelDataEx(sql, rows) > 0 && !rows.empty(); + } + + // °´ µÈ¼¶ + Èô¸ÉµÈÖµ¹ýÂËÁÐ ²é¹æ¸ñ¿â£¬·µ»ØµÚÒ»ÐС£²é²»µ½·µ»Ø false¡£ + bool querySpecRow(CUIISQLiteServer *pDb, LPCTSTR pszTable, const CString &sLevel + , const std::vector > &filters + , std::map &row) + { + std::vector > rows; + if (!querySpecRows(pDb, pszTable, sLevel, filters, rows) || rows.empty()) return false; + + row = rows[0]; + return true; + } + + // ´Ó¹æ¸ñÐÐÀïȡһÁÐ(´óСдÓëǰºó¿Õ¸ñ²»Ãô¸Ð) + CString specField(const std::map &row, LPCTSTR pszCol) + { + CString sWant(pszCol ? pszCol : _T("")); + sWant.Trim(); + + for (std::map::const_iterator it = row.begin(); it != row.end(); ++it) + { + CString sKey(it->first); + sKey.Trim(); + if (sKey.CompareNoCase(sWant) == 0) + { + CString sVal(it->second); + sVal.Trim(); + return sVal; + } + } + return _T(""); + } + + // Óùæ¸ñÐÐÌî³ä PCF µÄ ITEM-CODE / ITEM-DESCRIPTION / PIPING-SPEC¡£ + // pszDescOverride ·Ç¿ÕʱÓÃËüÌæ»»¹æ¸ñ¿âÀïµÄ"ÃèÊö"(·§ÃÅÓÃÐͺÅÃû±È"BB"ÕâÀàÀàÐÍÂë¸ü¿É¶Á)¡£ + bool writeSpecAttributes(std::ostream &out, const std::map &row + , LPCTSTR pszDescOverride = NULL) + { + const CString sCode = specField(row, _T("Ôª¼þ´úÂë")); + CString sDesc = specField(row, _T("ÃèÊö")); + if (pszDescOverride && *pszDescOverride) sDesc = pszDescOverride; + const CString sSpec = specField(row, _T("µÈ¼¶Ãû³Æ")); + if (sCode.IsEmpty() && sDesc.IsEmpty()) return false; + + writePcfAttribute(out, 4, PCF_ATTR_ITEM_CODE, (LPCTSTR)sCode); + writePcfAttribute(out, 4, PCF_ATTR_ITEM_DESCRIPTION, (LPCTSTR)sDesc); + writePcfAttribute(out, 4, PCF_HEAD_PIPING_SPEC, (LPCTSTR)sSpec); + return true; + } + + // ÊýÖµ -> ¹æ¸ñ¿âÀïµÄ"¹«³ÆÖ±¾¶"Îı¾(¿âÖÐÒÔÕûÊý×Ö·û´®´æ´¢£¬Èç "50") + CString dnText(const double &dn) + { + CString s; + s.Format(_T("%d"), (int)(dn + 0.5)); + return s; + } + + /* + pcf ÎļþÍ·(½öµ¥Î»²¿·Ö)¡£PIPELINE-REFERENCE ¼û pcf_pipeline_reference()£¬ + ÒòΪÉ豸(EQUIPMENT)¶¨Òå¿é±ØÐëдÔÚ PIPELINE-REFERENCE ֮ǰ¡£ + */ + bool pcf_begin(std::ostream &out , STR_PTR isogen_files = L"ISOGEN.FLS" , STR_PTR bore = PCF_UNITS_MM , STR_PTR co_ords = PCF_UNITS_MM , STR_PTR bolt_length = PCF_UNITS_MM - , STR_PTR bolt_dia= PCF_UNITS_MM + , STR_PTR bolt_dia = PCF_UNITS_MM , STR_PTR weight = PCF_UNITS_KGS ) { @@ -236,216 +381,765 @@ namespace PcfRow(out, 0) << PCF_HEAD_UNITS_BOLT_LENGTH << bolt_length; PcfRow(out, 0) << PCF_HEAD_UNITS_BOLT_DIA << bolt_dia; PcfRow(out, 0) << PCF_HEAD_UNITS_WEIGHT << weight; + return true; + } + + // ¹ÜÏßÒýÓÃ(·ÅÔÚÉ豸¶¨ÒåÖ®ºó) + bool pcf_pipeline_reference(std::ostream &out, STR_PTR pipeline_reference) + { + if (!out.good()) return false; PcfRow(out, 0) << PCF_HEAD_PIPELINE_REFERENCE << pipeline_reference; - PcfRow(out, 4) << PCF_HEAD_PIPING_SPEC << spec; return true; } + /* + ±éÀúÄ£ÐͿռ䣬ÊÕ¼¯ËùÓÐ ¹ÜµÀ/¹Ü¼þ/É豸 µÄ ObjectId ¼°Æä¹ÜµÀϵͳ(PIPE_SYS)¡£ + ¹ÜµÀϵͳ´æ·ÅÔÚʵÌåרҵÊý¾ÝÀ¼üΪ PIPE_SYS¡£ + */ + void collectComponents(std::vector &ids, std::vector &systems) + { + ids.clear(); + systems.clear(); + + AcDbDatabase *pDb = acdbHostApplicationServices()->workingDatabase(); + if (!pDb) return; + + AcDbBlockTable *pTbl = NULL; + if (Acad::eOk != pDb->getBlockTable(pTbl, AcDb::kForRead)) return; + + AcDbBlockTableRecord *pBTR = NULL; + if (Acad::eOk != pTbl->getAt(ACDB_MODEL_SPACE, pBTR, AcDb::kForRead)) + { + pTbl->close(); + return; + } + pTbl->close(); + + AcDbBlockTableRecordIterator *pIter = NULL; + if (Acad::eOk != pBTR->newIterator(pIter)) + { + pBTR->close(); + return; + } + + AcDbEntity *pEnt = NULL; + for (pIter->start(); !pIter->done(); pIter->step()) + { + if (Acad::eOk != pIter->getEntity(pEnt, AcDb::kForRead) || !pEnt) + continue; + + // ×¢Ò⣺AecDbEwPipe / AecDbXEquipment ÅÉÉú×Ô AecDbCurveBase(¡úAcDbCurve)£¬ + // Óë AecDbEntityBase(¡úAcDbEntity) ÊÇ¡°Ðֵܡ±À࣬²¢·ÇÆäÅÉÉúÀà¡£ + // Òò´Ë²»ÄÜÓà AecDbEntityBase::cast È¥¶Á¹ÜµÀµÄרҵÊý¾Ý(»á·µ»Ø NULL)£¬ + // ±ØÐë°´¾ßÌåÀàÐÍ·Ö±ðµ÷Óà GetAt£¬·ñÔò¹ÜµÀÈ¡²»µ½ PIPE_SYS ¶ø±»Â©µô¡£ + CString sSys; + bool bIsComponent = false; + + if (AecDbEwPipe *pPipe = AecDbEwPipe::cast(pEnt)) + { + pPipe->GetAt(PIPE_SYS, sSys); + bIsComponent = true; + } + else if (AecDbEwFitting *pFit = AecDbEwFitting::cast(pEnt)) + { + pFit->GetAt(PIPE_SYS, sSys); + bIsComponent = true; + } + else if (AecDbEwEquipment *pEqu = AecDbEwEquipment::cast(pEnt)) + { + pEqu->GetAt(PIPE_SYS, sSys); + bIsComponent = true; + } + else if (AecDbXEquipment *pXEqu = AecDbXEquipment::cast(pEnt)) + { + pXEqu->GetAt(PIPE_SYS, sSys); + bIsComponent = true; + } + + if (bIsComponent) + { + ids.push_back(pEnt->objectId()); + systems.push_back(sSys); + } + pEnt->close(); + } + + DELETE_PTR(pIter); + pBTR->close(); + } + + // ÊÕ¼¯Í¼Ö½ÖгöÏÖ¹ýµÄËùÓйܵÀϵͳ(È¥ÖØ£¬ºöÂÔ¿ÕÖµ) + void collectSystems(std::vector &out) + { + out.clear(); + + std::vector ids; + std::vector systems; + collectComponents(ids, systems); + + for (size_t k = 0; k < systems.size(); ++k) + { + if (systems[k].IsEmpty()) continue; + + bool bFound = false; + for (size_t m = 0; m < out.size(); ++m) + { + if (out[m] == systems[k]) { bFound = true; break; } + } + if (!bFound) out.push_back(systems[k]); + } + } + + // °´¹ÜµÀϵͳ(PIPE_SYS)ÊÕ¼¯ ¹ÜµÀ/¹Ü¼þ/É豸 + bool getComponentBySystem(LPCTSTR pszSys, AcDbObjectIdArray &ids) + { + if (!pszSys || _tcslen(pszSys) == 0) return false; + + std::vector allIds; + std::vector systems; + collectComponents(allIds, systems); + + for (size_t k = 0; k < allIds.size(); ++k) + { + if (systems[k] == pszSys) + ids.append(allIds[k]); + } + + return !ids.isEmpty(); + } + /* * ================================================================================= - * [PCF é™�级说明:无 ITEM-CODE æ—¶çš„ä¿�底策略] - * 适用组件:PIPE (直管) + * [PCF ½µ¼¶ËµÃ÷£ºÎÞ ITEM-CODE ʱµÄ±£µ×²ßÂÔ] + * ÊÊÓÃ×é¼þ£ºPIPE (Ö±¹Ü) * ================================================================================= - * 如果当å‰�管é�“没有物料ç � (ITEM-CODE),你至少需è¦�以下字段æ‰�能æ��述一段管é�“: - * * 1. 语法ç»�对必填字段(仅画几何骨架): - * - END-POINT (起点): 定义管é�“空间的起点三维å��æ ‡ (X, Y, Z) å�Š è¯¥ç«¯çš„å…¬ç§°ç›´å¾„ã€‚ - * - END-POINT (终点): 定义管é�“空间的终点三维å��æ ‡ (X, Y, Z) å�Š è¯¥ç«¯çš„å…¬ç§°ç›´å¾„ã€‚ - * *æ„�义:有了这两个端点,引擎就能在两点之间画出一æ�¡ä¸­å¿ƒçº¿ã€‚这是底线。* - * * 2. 工程强烈建议补充的字段(为了让下游软件ä¸�报错,且 BOM 表ä¸�为空): - * - ITEM-DESCRIPTION : æž�å…¶é‡�è¦�ï¼�物料的文本æ��述(如 L"é�žæ ‡å·¥è‰ºç›´ç®¡"),下游软件的 BOM 会直接打å�°è¿™å�¥è¯�。 - * - WALL-THICKNESS : å£�厚数值。部分查看器(如 Navisworks)ä¾�赖“管径+å£�厚â€�æ�¥æŽ¨ç®—真实的管é�“外径,ä¸�ä¼ å�¯èƒ½ä¼šç”»å‡ºæž�细的线。 - * - MATERIAL-IDENTIFIER : æ��质(如 L"CS" 或 L"碳钢"),辅助下游进行管é�“应力分æž�。 - * - FABRICATION-ITEM (或 ERECTION-ITEM) : 预制/现场安装标识。ä¸�带值(直接写属性å��),表示这是一根工厂预制管。 + * Èç¹ûµ±Ç°¹ÜµÀûÓÐÎïÁÏÂë (ITEM-CODE)£¬ÄãÖÁÉÙÐèÒªÒÔÏÂ×ֶβÅÄÜÃèÊöÒ»¶Î¹ÜµÀ£º + * * 1. Óï·¨¾ø¶Ô±ØÌî×ֶΣ¨½ö»­¼¸ºÎ¹Ç¼Ü£©£º + * - END-POINT (Æðµã): ¶¨Òå¹ÜµÀ¿Õ¼äµÄÆðµãÈýÎ¬×ø±ê (X, Y, Z) ¼° ¸Ã¶ËµÄ¹«³ÆÖ±¾¶¡£ + * - END-POINT (ÖÕµã): ¶¨Òå¹ÜµÀ¿Õ¼äµÄÖÕµãÈýÎ¬×ø±ê (X, Y, Z) ¼° ¸Ã¶ËµÄ¹«³ÆÖ±¾¶¡£ + * *ÒâÒ壺ÓÐÁËÕâÁ½¸ö¶Ëµã£¬ÒýÇæ¾ÍÄÜÔÚÁ½µãÖ®¼ä»­³öÒ»ÌõÖÐÐÄÏß¡£ÕâÊǵ×Ïß¡£* + * * 2. ¹¤³ÌÇ¿ÁÒ½¨Òé²¹³äµÄ×ֶΣ¨ÎªÁËÈÃÏÂÓÎÈí¼þ²»±¨´í£¬ÇÒ BOM ±í²»Îª¿Õ£©£º + * - ITEM-DESCRIPTION : ¼«ÆäÖØÒª£¡ÎïÁϵÄÎı¾ÃèÊö£¨Èç L"·Ç±ê¹¤ÒÕÖ±¹Ü"£©£¬ÏÂÓÎÈí¼þµÄ BOM »áÖ±½Ó´òÓ¡Õâ¾ä»°¡£ + * - WALL-THICKNESS : ±ÚºñÊýÖµ¡£²¿·Ö²é¿´Æ÷£¨Èç Navisworks£©ÒÀÀµ¡°¹Ü¾¶+±Úºñ¡±À´ÍÆËãÕæÊµµÄ¹ÜµÀÍâ¾¶£¬²»´«¿ÉÄܻử³ö¼«Ï¸µÄÏß¡£ + * - MATERIAL-IDENTIFIER : ²ÄÖÊ£¨Èç L"CS" »ò L"̼¸Ö"£©£¬¸¨ÖúÏÂÓνøÐйܵÀÓ¦Á¦·ÖÎö¡£ + * - FABRICATION-ITEM (»ò ERECTION-ITEM) : Ô¤ÖÆ/ÏÖ³¡°²×°±êʶ¡£²»´øÖµ£¨Ö±½ÓдÊôÐÔÃû£©£¬±íʾÕâÊÇÒ»¸ù¹¤³§Ô¤Öƹܡ£ * ================================================================================= */ - // 处ç�†æ™®é€šç®¡é�“,é�žæ³•兰管é�“ + // ´¦ÀíÆÕͨ¹ÜµÀ£¬·Ç·¨À¼¹ÜµÀ - wstring getItemCode(AecDbEwPipe *pPipe) + // Ö±¹Ü¹æ¸ñ²éѯ£º°´ µÈ¼¶ + ¹«³ÆÖ±¾¶ ÔÚ AecSpecPipe ÖвéÎïÁÏÂë/ÃèÊö/µÈ¼¶ + bool getPipeSpecRow(CUIISQLiteServer *pDb, const CString &sLevel, const double &dn + , std::map &row) { - return L""; + std::vector > filters; + filters.push_back(std::make_pair(CString(_T("¹«³ÆÖ±¾¶")), dnText(dn))); + return querySpecRow(pDb, _T("AecSpecPipe"), sLevel, filters, row); } - wstring getDescription(AecDbEwPipe *pPipe) + // ¶ÁÈ¡ÊýÖµÐÍרҵÊý¾Ý£¬¼æÈÝ´æÎª double / ×Ö·û´® / ÕûÊý ÈýÖÖÇé¿ö¡£ + // ʵ²â²¿·Öͼֽ°Ñ PIPE_DN / PIPE_THICK ´æ³É×Ö·û´®(Èç "450")£¬ + // ÈôÖ»Óà double ¶ÁÈ¡»áʧ°Ü£¬µ¼ÖÂÖ±¹Ü±»¾²Ä¬Ìø¹ý¡£ + template + bool getNumericValue(T *pEnt, LPCTSTR pszKey, double &dVal) { - return L""; + if (!pEnt) return false; + + if (pEnt->GetAt(pszKey, dVal)) return true; + + CString s; + if (pEnt->GetAt(pszKey, s) && !s.IsEmpty()) + { + dVal = _ttof(s); + return true; + } + + int n(0); + if (pEnt->GetAt(pszKey, n)) + { + dVal = (double)n; + return true; + } + return false; } - bool getPipeSpecInfo( CUIISQLiteServer *pDb - , STR_PTR level - , const double &dn - , STR_MAP &results) - { - map mm; - mm.insert(makePair(_T("公称直径"), dn)); - return getSpecFieldByLevel(pDb, L"aecspecpipe", level, mm, results); - } - - bool pcf_pipe_normal(CUIISQLiteServer *pDb, AecDbEwPipe *pPipe, std::ostream &out) + // pStart/pEnd ÓÃÓÚ"³¤Ö±¹ÜÖеãÇжÏ"£º°ÑÒ»¸ù¹Ü°´²ÎÊý¶Î²ð³É¶à¸ùÐéÄâ¹ÜÊä³ö£¬ + // ´« NULL ʱ°´¹Ü×Ó×ÔÉíµÄÆðÖ¹µãÊä³ö¡£ + bool pcf_pipe_normal(CUIISQLiteServer *pDb, AecDbEwPipe *pPipe, std::ostream &out + , const AcGePoint3d *pStart = NULL, const AcGePoint3d *pEnd = NULL) { if (!pPipe || !out.good()) return false; - AcGePoint3d ptStart = pPipe->StartPoint(); - AcGePoint3d ptEnd = pPipe->EndPoint(); + AcGePoint3d ptStart = pStart ? *pStart : pPipe->StartPoint(); + AcGePoint3d ptEnd = pEnd ? *pEnd : pPipe->EndPoint(); + // ¹«³ÆÖ±¾¶£ºÏȶÁרҵÊý¾Ý(¼æÈÝ×Ö·û´®)£¬ÔÙÍË»Ø PipeParam double bore(.0); - if (!pPipe->GetAt(PIPE_DN, bore)) return false; + if (!getNumericValue(pPipe, PIPE_DN, bore) || bore <= 0.0) + { + WPipe::PipeParam *pParam = pPipe->GetPipeParam(); + if (pParam) bore = pParam->m_dDN; + } + if (bore <= 0.0) return false; + // ±Úºñ£º¿ÉÑ¡£¬È±Ê§²»×è¶Ïµ¼³ö double thickness(.0); - if (!pPipe->GetAt(PIPE_THICK, thickness)) return false; + if (!getNumericValue(pPipe, PIPE_THICK, thickness) || thickness <= 0.0) + { + WPipe::PipeParam *pParam = pPipe->GetPipeParam(); + if (pParam) thickness = pParam->m_dThick; + } - CString level(_T("")); - pPipe->GetAt(PIPE_LEVEL, level); + // µÈ¼¶£ºÏȶÁ PIPE_LEVEL£¬Îª¿ÕʱÔÚרҵÊý¾ÝÀï·´²éºÏ·¨µÈ¼¶Ãû + AecDbObjXDataMap *pMap = pPipe->GetSpecialtyData(AcDb::kForRead); + const CString level = resolveLevel(pMap, pDb); - // 写入组件主类标 (顶格,无缩进) + // дÈë×é¼þÖ÷Àà±ê (¶¥¸ñ£¬ÎÞËõ½ø) PcfRow(out, 0) << PCF_COMP_PIPE; - // 写入起止å��标与管径 (必须紧跟在 PIPE å�Žé�¢ï¼Œç¼©è¿› 4 æ ¼) + // дÈëÆðÖ¹×ø±êÓë¹Ü¾¶ (±ØÐë½ô¸úÔÚ PIPE ºóÃæ£¬Ëõ½ø 4 ¸ñ) PcfRow(out, 4) << PCF_PT_END_POINT << ptStart << bore; PcfRow(out, 4) << PCF_PT_END_POINT << ptEnd << bore; - // 写入å£�厚,ä¿�è¯�在没有item-codeå’Œpiping-spec时能够正常显示 - PcfRow(out, 4) << PCF_ATTR_WALL_THICKNESS << thickness; + // дÈë±Úºñ£¬±£Ö¤ÔÚûÓÐitem-codeºÍpiping-specʱÄܹ»Õý³£ÏÔʾ + if (thickness > 0.0) + PcfRow(out, 4) << PCF_ATTR_WALL_THICKNESS << thickness; - // 等级管线 + // µÈ¼¶ -> ¹æ¸ñ¿â -> ÎïÁÏÂë / ÃèÊö / µÈ¼¶ if (!level.IsEmpty()) { - STR_MAP mm; - getPipeSpecInfo(pDb, level, bore, mm); - - // 物料ç � - writePcfAttribute(out, 4, PCF_ATTR_ITEM_CODE, getValue(mm, L"元件代ç �").c_str()); - - // 物料æ��è¿° - writePcfAttribute(out, 4, PCF_ATTR_ITEM_DESCRIPTION, getValue(mm, L"æ��è¿°").c_str()); - - // 等级信æ�¯ - writePcfAttribute(out, 4, PCF_HEAD_PIPING_SPEC, getValue(mm, L"等级å��ç§°").c_str()); - } - else - { - + std::map row; + if (getPipeSpecRow(pDb, level, bore, row)) + writeSpecAttributes(out, row); } - // 预制管件 + // Ô¤ÖÆ¹Ü¼þ PcfRow(out, 4) << PCF_ATTR_FABRICATION_ITEM; - out << L"\n"; + out << "\n"; return true; } - bool pcf_ewEquipment(CUIISQLiteServer *pDb, AecDbEwEquipment *pEqu, std::ostream &out) - { return false; } + // ============================ Phase 2: ¹Ü¼þµ¼³ö ============================ - bool pcf_xEquipment(CUIISQLiteServer *pDb, AecDbXEquipment *pXEqu, std::ostream &out) - { return false; } - - bool pcf_Elbow(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out) - {return false;} - - bool pcf_ReduceElbow(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out) - {return false;} - - bool pcf_Tee(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out) - {return false;} - - bool pcf_Cross(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out) - {return false;} - - bool pcf_Wye(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out) - {return false;} - - bool pcf_Reduce(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out) - {return false;} - - bool pcf_Lateral(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out) - {return false;} - - bool pcf_Flange(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out) - {return false;} - - bool pcf_Wcap(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out) - {return false;} - - bool pcf_FlxJoin(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out) - {return false;} - - bool pcf_Through(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out)//直通 - {return false;} - - bool pcf_UJoin(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out)//活接 - {return false;} - - bool pcf_RJoin(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out)//缩接 - {return false;} - - bool pcf_OJoin(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out) //外螺纹接头 - {return false;} - - bool pcf_IJoin(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out) //内螺纹接头 - {return false;} - - bool pcf_RP(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out)//补强圈 - {return false;} - - bool pcf_HP(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out)//å�Šç®¡æŽ¥å¤´ - {return false;} - - bool pcf_SPB(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out)//八字盲æ�¿ - {return false;} - - bool pcf_Gastket(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out) - {return false;} - - bool pcf_fitting(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out) + // ¶ÁÈ¡¹Ü¼þij½Ó¿ÚµÄ¹Ü¾¶£ºÓÅÏȽӿÚ×ÔÉí dSize1£¬È±Ê§Ê±Í˻عܼþ²ÎÊý + double fitInfBore(AecDbEwFitting *pFit, const AecInterface &inf, int nInf) { - if (!pFit || !pDb) return false; + double d = inf.dSize1; + if (d <= 0.0 && pFit) + { + WPipe::PipeParam *pParam = pFit->GetPipeParam(nInf); + if (pParam) d = pParam->m_dDN; + } + return d; + } - int nType(0); - if (!pFit->GetAt(KEY_RUNTIME, nType)) - return false; + // ¹Ü¼þ±Úºñ£ºÓÅÏÈרҵÊý¾Ý(¼æÈÝ×Ö·û´®)£¬ÔÙÍ˻عܼþ²ÎÊý + double fitThickness(AecDbEwFitting *pFit) + { + double t(0.0); + if (!getNumericValue(pFit, PIPE_THICK, t) || t <= 0.0) + { + WPipe::PipeParam *pParam = pFit ? pFit->GetPipeParam(0) : NULL; + if (pParam) t = pParam->m_dThick; + } + return t; + } + // ±ä¾¶ÀàÐÍ£º¼¯ÖÐʽ/Æ«ÐÄʽ£¬ÓÃÓÚÑ¡Ôñ PCF ×é¼þÃû + STR_PTR getReducerTypeName(AecDbEwFitting *pFit) + { + WPipe::PipeParam *pParam = pFit ? pFit->GetPipeParam(0) : NULL; + if (pParam && pParam->m_eRed != WPipe::eCen) + return PCF_COMP_REDUCER_ECC; + return PCF_COMP_REDUCER_CONC; + } + + // Íäͷʵ¼Ê¼Ð½Ç£ºÁ½½Ó¿Ú·½ÏòÏòÁ¿µÄ¼Ð½Ç(0~180¡ã)¡£ + // 90¡ã ÍäͷԼΪ 90¡ã£»45¡ã ÍäͷԼΪ 135¡ã(¼´×ªÍä 45¡ã)¡£È¡²»µ½·µ»Ø -1¡£ + double fitBendAngle(AecDbEwFitting *pFit) + { + if (!pFit) return -1.0; + AcArray arInfs; + if (!pFit->GetInterface(arInfs) || arInfs.length() < 2) return -1.0; + + AcGeVector3d u = arInfs.at(0).vtDir; + AcGeVector3d v = arInfs.at(1).vtDir; + if (u.length() < 1e-9 || v.length() < 1e-9) return -1.0; + u.normalize(); + v.normalize(); + + double c = u.dotProduct(v); + if (c > 1.0) c = 1.0; + if (c < -1.0) c = -1.0; + return acos(c) * 180.0 / 3.14159265358979323846; + } + + /* + ¹Ü¼þÔÚ¹æ¸ñ¿âÀïµÄ"ÀàÐÍ"ºòÑ¡Ãû(°´ÓÅÏȼ¶)¡£ + ʵ²â AecSpecFit.ÀàÐÍ Ö»ÓÐ: + ÍäÍ· / Èýͨ / °ë¹Ü½ÓÍ· / ²¹Ç¿È¦ / ±ä¾¶ / ¹Üñ / бÈýͨ / 90¶ÈÍäÍ· / 45¶ÈÍäÍ· / ͬÐı侶 / Æ«Ðı侶 + ¶ø AecSpecFlange.ÀàÐÍ Ö»ÓÐ PL¡£ + */ + void fitTypeCandidates(int nType, AecDbEwFitting *pFit, std::vector &names) + { + names.clear(); switch (nType) { case eElbow: - return pcf_Elbow(pDb, pFit, out); case eReduceElbow: - return pcf_ReduceElbow(pDb, pFit, out); - case eTee: - return pcf_Tee(pDb, pFit, out); - case eCross: - return pcf_Cross(pDb, pFit, out); - case eWye: - return pcf_Wye(pDb, pFit, out); + // ÍäÍ·µÄ 90/45 ¶ÈÔÚ getFitSpecRow Àﰴʵ²â¼Ð½Çµ¥¶ÀÌôÐУ¬ÕâÀïÖ»ÁкòÑ¡Ãû¡£ + names.push_back(_T("ÍäÍ·")); + names.push_back(_T("90¶ÈÍäÍ·")); + names.push_back(_T("45¶ÈÍäÍ·")); + break; case eReduce: - return pcf_Reduce(pDb, pFit, out); + if (pFit && wcscmp(getReducerTypeName(pFit), PCF_COMP_REDUCER_ECC) == 0) + names.push_back(_T("Æ«Ðı侶")); + else + names.push_back(_T("ͬÐı侶")); + names.push_back(_T("±ä¾¶")); + break; + case eTee: + names.push_back(_T("Èýͨ")); + break; + case eCross: + names.push_back(_T("ËÄͨ")); + names.push_back(_T("Èýͨ")); + break; case eLateral: - return pcf_Lateral(pDb, pFit, out); - case eFlange: - return pcf_Flange(pDb, pFit, out); + case eWye: + names.push_back(_T("бÈýͨ")); + names.push_back(_T("Èýͨ")); + break; case eWcap: - return pcf_Wcap(pDb, pFit, out); - case eFlxJoin: - return pcf_FlxJoin(pDb, pFit, out); - case eThrough://直通 - return pcf_Through(pDb, pFit, out); - case eUJoin://活接 - return pcf_UJoin(pDb, pFit, out); - case eRJoin://缩接 - return pcf_RJoin(pDb, pFit, out); - case eOJoin: //外螺纹接头 - return pcf_OJoin(pDb, pFit, out); - case eIJoin: //内螺纹接头 - return pcf_IJoin(pDb, pFit, out); - case eRP://补强圈 - return pcf_RP(pDb, pFit, out); - case eHP://å�Šç®¡æŽ¥å¤´ - return pcf_HP(pDb, pFit, out); - case eSPB://八字盲æ�¿ - return pcf_SPB(pDb, pFit, out); - case eGastket: - return pcf_Gastket(pDb, pFit, out); + names.push_back(_T("¹Üñ")); + break; + case eRP: + names.push_back(_T("²¹Ç¿È¦")); + break; + case eHP: + names.push_back(_T("°ë¹Ü½ÓÍ·")); + break; + case eFlange: + names.push_back(_T("PL")); + break; + } + } + + // ¹Ü¼þ¹æ¸ñ²éѯ£º·¨À¼×ß AecSpecFlange£¬ÆäÓà×ß AecSpecFit¡£ + // ÆÕͨ¹Ü¼þ°´ÀàÐͺòÑ¡ÃûÖð¸öÊÔ£¬×îºóÍË»¯Îª"Ö»°´¹Ü¾¶"¡£ + // ÍäÍ·ÌØÊâ´¦Àí£º90/45 ¶ÈÓÐʱдÔÚ"ÀàÐÍ"ÁС¢ÓÐʱֻÔÚ"ÃèÊö"ÀïÇø·Ö£¬ + // ÐèÈ¡»ØÈ«²¿ºòÑ¡Ðкó°´Êµ²â¼Ð½ÇÌôÑ¡¡£ + bool getFitSpecRow(CUIISQLiteServer *pDb, AecDbEwFitting *pFit + , const CString &sLevel, const double &dn, std::map &row) + { + if (!pFit || sLevel.IsEmpty() || dn <= 0.0) return false; + + const int nType = pFit->GetFittingType(); + const bool bFlange = (nType == eFlange); + LPCTSTR pszTable = bFlange ? _T("AecSpecFlange") : _T("AecSpecFit"); + + // ---- ÍäÍ·£º°´Êµ²â¼Ð½ÇÔÚ 90¶È/45¶È ÐÐÀïÌô ---- + if (nType == eElbow || nType == eReduceElbow) + { + std::vector > rows; + const LPCTSTR aNames[3] = { _T("ÍäÍ·"), _T("90¶ÈÍäÍ·"), _T("45¶ÈÍäÍ·") }; + for (int i = 0; i < 3; ++i) + { + std::vector > filters; + filters.push_back(std::make_pair(CString(_T("¹«³ÆÖ±¾¶")), dnText(dn))); + filters.push_back(std::make_pair(CString(_T("ÀàÐÍ")), CString(aNames[i]))); + std::vector > part; + if (querySpecRows(pDb, pszTable, sLevel, filters, part)) + rows.insert(rows.end(), part.begin(), part.end()); + } + if (rows.empty()) + { + std::vector > filters; + filters.push_back(std::make_pair(CString(_T("¹«³ÆÖ±¾¶")), dnText(dn))); + querySpecRows(pDb, pszTable, sLevel, filters, rows); + } + if (rows.empty()) return false; + + const double ang = fitBendAngle(pFit); + const bool bWant45 = (ang >= 112.5); // ¼Ð½ÇÔ¼ 135¡ã -> 45 ¶ÈÍäÍ· + + int nBest = -1; + for (size_t i = 0; i < rows.size(); ++i) + { + CString sAll = specField(rows[i], _T("ÀàÐÍ")) + specField(rows[i], _T("ÃèÊö")); + const bool bIs45 = (sAll.Find(_T("45¶È")) >= 0); + const bool bIs90 = (sAll.Find(_T("90¶È")) >= 0); + if (bWant45 && bIs45) { nBest = (int)i; break; } + if (!bWant45 && bIs90) { nBest = (int)i; break; } + } + if (nBest < 0) nBest = 0; + row = rows[nBest]; + return true; + } + + // ---- ÆäÓà¹Ü¼þ£º°´ÀàÐͺòÑ¡ÃûÖð¸öÊÔ ---- + std::vector names; + fitTypeCandidates(nType, pFit, names); + + for (size_t k = 0; k < names.size(); ++k) + { + std::vector > filters; + filters.push_back(std::make_pair(CString(_T("¹«³ÆÖ±¾¶")), dnText(dn))); + filters.push_back(std::make_pair(CString(_T("ÀàÐÍ")), names[k])); + if (querySpecRow(pDb, pszTable, sLevel, filters, row)) + return true; + } + + // ÔÙÍË»¯ÎªÖ»°´¹Ü¾¶(ÀàÐÍÃû¶Ô²»ÉÏʱµÄ¶µµ×) + { + std::vector > filters; + filters.push_back(std::make_pair(CString(_T("¹«³ÆÖ±¾¶")), dnText(dn))); + if (querySpecRow(pDb, pszTable, sLevel, filters, row)) + return true; + } + + // ·¨À¼±í²é²»µ½Ê±£¬Í˻عܼþ±íÔÙÊÔÒ»´Î + if (bFlange) + { + std::vector > filters; + filters.push_back(std::make_pair(CString(_T("¹«³ÆÖ±¾¶")), dnText(dn))); + if (querySpecRow(pDb, _T("AecSpecFit"), sLevel, filters, row)) + return true; + } + return false; + } + + // д³ö¹Ü¼þ¹«¹²ÊôÐÔ£º±Úºñ / ¹æ¸ñ¿â(ÎïÁÏÂë,ÃèÊö,µÈ¼¶) / Ô¤ÖÆ±ê¼Ç + void writeFittingCommon(CUIISQLiteServer *pDb, AecDbEwFitting *pFit + , const double &bore, std::ostream &out) + { + double thickness = fitThickness(pFit); + if (thickness > 0.0) + PcfRow(out, 4) << PCF_ATTR_WALL_THICKNESS << thickness; + + AecDbObjXDataMap *pMap = pFit->GetSpecialtyData(AcDb::kForRead); + const CString level = resolveLevel(pMap, pDb); + if (!level.IsEmpty() && pDb && bore > 0.0) + { + std::map row; + if (getFitSpecRow(pDb, pFit, level, bore, row)) + writeSpecAttributes(out, row); + } + + // Ô¤ÖÆ¹Ü¼þ + PcfRow(out, 4) << PCF_ATTR_FABRICATION_ITEM; + } + + // ÇóÁ½ÌõÉäÏß(µã+·½Ïò)ÔÚ¿Õ¼äÖеĽ»µã¡£ + // ÍäÍ·Á½¶Ë·½ÏòÒ»°ãÏཻ(Èç 90¡ã ÍäÍ·)£¬Ïཻʱ·µ»Ø½Çµã£»½Ó½üƽÐÐʱÍË»¯ÎªÁ½¶ËµãÖе㡣 + AcGePoint3d intersectRays(const AcGePoint3d &p0, const AcGeVector3d &d0 + , const AcGePoint3d &p1, const AcGeVector3d &d1) + { + AcGeVector3d u(d0), v(d1); + u.normalize(); + v.normalize(); + AcGeVector3d w(p0 - p1); + + const double a = u.dotProduct(u); + const double b = u.dotProduct(v); + const double c = v.dotProduct(v); + const double d = u.dotProduct(w); + const double e = v.dotProduct(w); + const double denom = a * c - b * b; + + if (fabs(denom) < 1e-9) + return AcGePoint3d((p0.x + p1.x) * 0.5, (p0.y + p1.y) * 0.5, (p0.z + p1.z) * 0.5); + + const double sc = (b * e - c * d) / denom; + return p0 + u * sc; + } + + // ·½ÏòÏòÁ¿ -> PCF ·½Î»(NORTH/SOUTH/EAST/WEST/UP/DOWN) + STR_PTR dirToOrientation(const AcGeVector3d &v) + { + const double ax = fabs(v.x), ay = fabs(v.y), az = fabs(v.z); + if (az >= ax && az >= ay) return (v.z >= 0.0) ? L"UP" : L"DOWN"; + if (ax >= ay) return (v.x >= 0.0) ? L"EAST" : L"WEST"; + return (v.y >= 0.0) ? L"NORTH" : L"SOUTH"; + } + + /* + * ͨÓãºÐ´³ö×é¼þÍ·Óëµãλ(²»º¬ÊôÐÔ)¡£ + * ²Î¿¼ PCF Reference Guide µÄµãλҪÇó£º + * 1 ¸ö½Ó¿Ú -> END-POINT + * 2 ¸ö½Ó¿Ú -> END-POINT x2 + * 2 ¸ö½Ó¿Ú + bCentre -> END-POINT x2 + CENTRE-POINT + * 3 ¸ö½Ó¿Ú -> END-POINT x2 + BRANCH1-POINT + * 4+ ¸ö½Ó¿Ú -> END-POINT x2 + BRANCH1/2-POINT + * ½Ó¿Ú°´ nLevel ÅÅÐò£º0/1=Ö÷¹ÜÁ½¶Ë£¬>=2=Ö§¹Ü¡£bores Óë arInfs Ò»Ò»¶ÔÓ¦¡£ + */ + bool writeComponentPoints(std::ostream &out, AcArray &arInfs + , const std::vector &bores, STR_PTR compType, bool bCentre, double &dBore) + { + if (!out.good() || arInfs.isEmpty()) return false; + + // °´ nLevel ÉýÐòÅÅÐò(²åÈëÅÅÐò£¬½Ó¿ÚÊýºÜÉÙ) + std::vector arOrder; + for (int i = 0; i < arInfs.length(); ++i) + { + int lv = arInfs.at(i).nLevel; + size_t nPos = arOrder.size(); + for (size_t k = 0; k < arOrder.size(); ++k) + { + if (lv < arInfs.at(arOrder[k]).nLevel) { nPos = k; break; } + } + arOrder.insert(arOrder.begin() + nPos, i); + } + + const int nCount = (int)arOrder.size(); + const int nMain = nCount >= 2 ? 2 : 1; + + PcfRow(out, 0) << compType; + + dBore = 0.0; + for (int i = 0; i < nMain; ++i) + { + const int idx = arOrder[i]; + double d = (idx < (int)bores.size()) ? bores[idx] : arInfs.at(idx).dSize1; + if (dBore <= 0.0) dBore = d; + PcfRow(out, 4) << PCF_PT_END_POINT << arInfs.at(idx).ptPos << d; + } + + if (bCentre && nCount >= 2) + { + const AecInterface &i0 = arInfs.at(arOrder[0]); + const AecInterface &i1 = arInfs.at(arOrder[1]); + PcfRow(out, 4) << PCF_PT_CENTRE_POINT + << intersectRays(i0.ptPos, i0.vtDir, i1.ptPos, i1.vtDir); + } + + for (int i = 2; i < nCount; ++i) + { + const int idx = arOrder[i]; + double d = (idx < (int)bores.size()) ? bores[idx] : arInfs.at(idx).dSize1; + STR_PTR ptType = (i == 2) ? PCF_PT_BRANCH1_POINT : PCF_PT_BRANCH2_POINT; + PcfRow(out, 4) << ptType << arInfs.at(idx).ptPos << d; + } + return true; + } + + // ¹Ü¼þ£º½Ó¿Ú¹Ü¾¶ÒѽâÎöºóдÈëµã룬ÔÙ²¹¹Ü¼þÊôÐÔ + bool pcf_genericFitting(CUIISQLiteServer *pDb, AecDbEwFitting *pFit + , STR_PTR compType, std::ostream &out, bool bCentre) + { + if (!pFit || !out.good()) return false; + + AcArray arInfs; + if (!pFit->GetInterface(arInfs) || arInfs.isEmpty()) return false; + + std::vector bores; + for (int i = 0; i < arInfs.length(); ++i) + bores.push_back(fitInfBore(pFit, arInfs.at(i), i)); + + double dBore = 0.0; + if (!writeComponentPoints(out, arInfs, bores, compType, bCentre, dBore)) + return false; + + writeFittingCommon(pDb, pFit, dBore, out); + out << "\n"; + return true; + } + + // ============================ Phase 3: É豸µ¼³ö ============================ + + // ·§ÃÅÀàÐÍö¾Ù(AecEqui::ValveType, EarThwormDef.h:2267) -> ¹æ¸ñ¿â AecSpecValve.[Àà±ð] Ãû³Æ¡£ + // Ãû³ÆÐëÓë g_vlvType[] (PipelineCmd/command.cpp:158) ¼° Plumbing.db µÄ [Àà±ð] ÖµÒ»Ö¡£ + LPCTSTR valveCategoryName(int nType) + { + switch (nType) + { + case 1: return _T("Õ¢·§"); + case 2: return _T("½ØÖ¹·§"); + case 3: return _T("Çò·§"); + case 4: return _T("Ö¹»Ø·§"); + case 5: return _T("µû·§"); + case 6: return _T("½Ç·§"); + case 7: return _T("°²È«·§"); + case 8: return _T("Èýͨ·§"); + case 9: return _T("ËÄͨ·§"); + case 10: return _T("µ÷½Ú·§"); + case 11: return _T("ÊèË®·§"); + case 12: return _T("ÐýÈû·§"); + case 13: return _T("¸ôĤ·§"); + case 14: return _T("¼õѹ·§"); + case 15: return _T("µç´Å·§"); + case 16: return _T("Ï𽺽ÓÍ·"); + case 17: return _T("ÅÅÆø·§"); + case 18: return _T("ÅÅÄà·§"); + case 19: return _T("½¬Òº·§"); + case 20: return _T("Õ¢ÃÅ"); + case 21: return _T("¿×°å"); + case 22: return _T("Ͱʽ¹ýÂËÆ÷"); + case 23: return _T("ÁÙʱ¹ýÂËÆ÷"); + case 24: return _T("TÐ͹ýÂËÆ÷"); + case 25: return _T("TÐ͹ýÂËÆ÷"); + case 26: return _T("ÊÓ¾µ"); + case 27: return _T("Á÷Á¿¼Æ"); + case 28: return _T("×è»ðÆ÷"); + case 31: return _T("ÉìËõ½ÓÍ·"); + case 32: return _T("´«Á¦½ÓÍ·"); + default: return _T(""); + } + } + + // д³ö·§ÃÅ/¹ÜµÀ¸½¼þÀàÉ豸µÄ¹«¹²ÊôÐÔ£º±Úºñ / Ãû³Æ / ·§ÃŹæ¸ñ¿â / Ô¤ÖÆ±ê¼Ç + void writeEquipmentCommon(CUIISQLiteServer *pDb, AecDbEwEquipment *pEqu + , const double &bore, std::ostream &out) + { + double thickness(0.0); + if (getNumericValue(pEqu, PIPE_THICK, thickness) && thickness > 0.0) + PcfRow(out, 4) << PCF_ATTR_WALL_THICKNESS << thickness; + + // Ãû³Æ£º·§ÃÅÐͺÅÃû(Èç D373H·¨À¼Ó²ÃÜ·âµû·§DN450)£¬±È¹æ¸ñ¿â"ÃèÊö"¸ü¾ß¿É¶ÁÐÔ£¬ÓÃ×÷ ITEM-DESCRIPTION + CString sName; + pEqu->GetAt(KEY_NAME, sName); + + // ·§ÃŹæ¸ñ¿â£º°´ µÈ¼¶ + Àà±ð(·§ÃÅÀàÐÍ) + ¹«³ÆÖ±¾¶ ÔÚ AecSpecValve ÖвéÎïÁÏÂë/ÃèÊö/µÈ¼¶¡£ + // ͬһµÈ¼¶+¹Ü¾¶ÏÂÕ¢·§/Ö¹»Ø·§/µû·§µÈ¶àÐв¢´æ£¬±ØÐëÔÙ°´"Àà±ð"¹ýÂË£¬·ñÔò»áÈ¡´íÐС£ + bool bSpec = false; + AecDbObjXDataMap *pMap = pEqu->GetSpecialtyData(AcDb::kForRead); + const CString level = resolveLevel(pMap, pDb); + if (!level.IsEmpty() && pDb && bore > 0.0) + { + int nVlvType = -1; + if (pMap) pMap->GetAt(PIPE_VALVE, nVlvType); + const LPCTSTR pszCat = valveCategoryName(nVlvType); + + // ±ØÐë°´ Àà±ð ¾«È·Æ¥Å䣺ͬһµÈ¼¶+¹Ü¾¶ÏÂÕ¢·§/Ö¹»Ø·§/µû·§µÈ²¢´æ£¬ + // Àà±ðδ֪»ò¿âÖÐÎÞ´ËÀà±ðʱÄþ¿É²»Ð´ÎïÁÏÂ룬Ҳ²»ÄÜÍË»¯Îª°´¹Ü¾¶È¡µ½±ðµÄ·§ÖÖ¡£ + std::map row; + bool bFound = false; + if (pszCat && *pszCat) + { + std::vector > filters; + filters.push_back(std::make_pair(CString(_T("¹«³ÆÖ±¾¶")), dnText(bore))); + filters.push_back(std::make_pair(CString(_T("Àà±ð")), CString(pszCat))); + bFound = querySpecRow(pDb, _T("AecSpecValve"), level, filters, row); + } + + if (bFound) + bSpec = writeSpecAttributes(out, row, (LPCTSTR)sName); + } + + if (!bSpec) + writePcfAttribute(out, 4, PCF_ATTR_ITEM_DESCRIPTION, (LPCTSTR)sName); + + PcfRow(out, 4) << PCF_ATTR_FABRICATION_ITEM; + } + + // ·§ÃÅ/¹ÜµÀ¸½¼þÀàÉ豸(AecDbEwEquipment)£º×÷Ϊ VALVE ×é¼þµ¼³ö + bool pcf_ewEquipment(CUIISQLiteServer *pDb, AecDbEwEquipment *pEqu, std::ostream &out) + { + if (!pEqu || !out.good()) return false; + + AcArray arInfs; + if (!pEqu->GetInterface(arInfs) || arInfs.isEmpty()) return false; + + std::vector bores; + for (int i = 0; i < arInfs.length(); ++i) + bores.push_back(arInfs.at(i).dSize1); + + double dBore = 0.0; + if (!writeComponentPoints(out, arInfs, bores, PCF_COMP_VALVE, true, dBore)) + return false; + + writeEquipmentCommon(pDb, pEqu, dBore, out); + out << "\n"; + return true; + } + + // ÈÝÆ÷/É豸Àà(AecDbXEquipment)£ºµ¼³öΪ EQUIPMENT ¶¨Òå¿é(º¬ NOZZLE)£¬Ðè·ÅÔÚ PIPELINE-REFERENCE ֮ǰ + bool pcf_xEquipment(CUIISQLiteServer *pDb, AecDbXEquipment *pXEqu, std::ostream &out) + { + if (!pXEqu || !out.good()) return false; + + AcGePoint3d ptIns; + AcGeVector3d vtDir; + pXEqu->GetInsert(ptIns, vtDir); + + // É豸Ãû£ºÓÅÏÈ NAME£¬Æä´ÎΨһÃû£¬×îºó¸ø¸ö¶µµ× + CString sName; + pXEqu->GetAt(KEY_NAME, sName); + if (sName.IsEmpty()) sName = pXEqu->getUniqueName(); + if (sName.IsEmpty()) sName = _T("EQUIPMENT"); + + PcfRow(out, 0) << PCF_COMP_EQUIPMENT; + PcfRow(out, 4) << PCF_KW_REFERENCE << (LPCTSTR)sName; + PcfRow(out, 4) << PCF_KW_LOCATION << ptIns; + PcfRow(out, 4) << PCF_KW_ORIENTATION << dirToOrientation(vtDir); + + // ¹Ü×ì + AcArray arInfs; + if (pXEqu->GetInterface(arInfs)) + { + for (int i = 0; i < arInfs.length(); ++i) + { + const AecInterface &inf = arInfs.at(i); + + CString sNoz; + sNoz.Format(_T("%sN%d"), (LPCTSTR)sName, i + 1); + + PcfRow(out, 4) << PCF_KW_NOZZLE; + PcfRow(out, 8) << PCF_KW_REFERENCE << (LPCTSTR)sNoz; + PcfRow(out, 8) << PCF_KW_DIRECTION << dirToOrientation(inf.vtDir); + PcfRow(out, 8) << PCF_PT_CO_ORDS << inf.ptPos << inf.dSize1; + } + } + + out << "\n"; + return true; + } + + // ¹Ü¼þ°´ EFittingType ·Ö·¢µ½Í¨Óõ¼³ö + bool pcf_fitting(CUIISQLiteServer *pDb, AecDbEwFitting *pFit, std::ostream &out) + { + if (!pFit) return false; + + switch (pFit->GetFittingType()) + { + case eElbow: + case eReduceElbow: + return pcf_genericFitting(pDb, pFit, PCF_COMP_ELBOW, out, true); + + case eReduce: + return pcf_genericFitting(pDb, pFit, getReducerTypeName(pFit), out, false); + + case eTee: + case eWye: + case eLateral: + return pcf_genericFitting(pDb, pFit, PCF_COMP_TEE, out, false); + + case eCross: + return pcf_genericFitting(pDb, pFit, PCF_COMP_CROSS, out, false); + + case eFlange: + return pcf_genericFitting(pDb, pFit, PCF_COMP_FLANGE, out, false); + + case eWcap: + return pcf_genericFitting(pDb, pFit, PCF_COMP_CAP, out, false); + + case eSPB://°Ë×Öä°å + return pcf_genericFitting(pDb, pFit, PCF_COMP_BLIND_FLANGE, out, false); + + case eGastket://µæÆ¬ + return pcf_genericFitting(pDb, pFit, PCF_COMP_GASKET, out, false); + + case eFlxJoin://¹¿ + case eThrough://ֱͨ + case eUJoin://»î½Ó + case eRJoin://Ëõ½Ó + case eOJoin://ÍâÂÝÎÆ½ÓÍ· + case eIJoin://ÄÚÂÝÎÆ½ÓÍ· + return pcf_genericFitting(pDb, pFit, PCF_COMP_COUPLING, out, false); + default: break; } @@ -453,76 +1147,1670 @@ namespace return false; } + // ============================ Phase 4: Ö§µõ¼Üµ¼³ö ============================ + + // µãµ½Ï߶εÄ×î¶Ì¾àÀë + double distPointSegment(const AcGePoint3d &p, const AcGePoint3d &a, const AcGePoint3d &b) + { + AcGeVector3d ab(b - a); + const double len2 = ab.lengthSqrd(); + if (len2 < 1e-12) return p.distanceTo(a); + + double t = AcGeVector3d(p - a).dotProduct(ab) / len2; + if (t < 0.0) t = 0.0; + else if (t > 1.0) t = 1.0; + return p.distanceTo(a + ab * t); + } + + // È¡×é¼þÖ÷ÖáÏß¶Î(Á½¸ö nLevel<2 µÄ½Ó¿Ú)£»½Ó¿Ú²»×ãÁ½¸öʱÍË»¯ÎªÒ»¸öµã + bool mainAxisSegment(AcArray &arInfs, AcGePoint3d &a, AcGePoint3d &b) + { + if (arInfs.isEmpty()) return false; + + std::vector arMain; + for (int i = 0; i < arInfs.length(); ++i) + { + if (arInfs.at(i).nLevel < 2) arMain.push_back(&arInfs.at(i)); + } + if (arMain.empty()) arMain.push_back(&arInfs.at(0)); + + a = arMain[0]->ptPos; + b = (arMain.size() >= 2) ? arMain[1]->ptPos : a; + return true; + } + + // Ö§µõ¼Ü¼ÈûÓÐ PIPE_SYS£¬Ò²Ã»ÓÐËÞÖ÷¹ÜµÀ¾ä±ú£¬Ö»Äܰ´¿Õ¼äλÖþͽü¹éÊôµ½×é¼þ£¬ + // ÔÙÈ¡¸Ã×é¼þµÄ¹ÜµÀϵͳ¡£ÕâÀï°Ñ×é¼þµÄÖÐÐÄÏß¶ÎÁ¬Í¬ÏµÍ³ÃûÊÕ¼¯ÆðÀ´±¸Óᣠ+ struct SupportTarget + { + CString sys; + AcGePoint3d a; + AcGePoint3d b; + }; + + void collectSupportTargets(std::vector &targets) + { + targets.clear(); + + AcDbDatabase *pDb = acdbHostApplicationServices()->workingDatabase(); + if (!pDb) return; + + AcDbBlockTable *pTbl = NULL; + if (Acad::eOk != pDb->getBlockTable(pTbl, AcDb::kForRead)) return; + + AcDbBlockTableRecord *pBTR = NULL; + if (Acad::eOk != pTbl->getAt(ACDB_MODEL_SPACE, pBTR, AcDb::kForRead)) + { + pTbl->close(); + return; + } + pTbl->close(); + + AcDbBlockTableRecordIterator *pIter = NULL; + if (Acad::eOk != pBTR->newIterator(pIter)) + { + pBTR->close(); + return; + } + + AcDbEntity *pEnt = NULL; + for (pIter->start(); !pIter->done(); pIter->step()) + { + if (Acad::eOk != pIter->getEntity(pEnt, AcDb::kForRead) || !pEnt) + continue; + + SupportTarget t; + bool bOk = false; + + if (AecDbEwPipe *pPipe = AecDbEwPipe::cast(pEnt)) + { + t.a = pPipe->StartPoint(); + t.b = pPipe->EndPoint(); + pPipe->GetAt(PIPE_SYS, t.sys); + bOk = true; + } + else if (AecDbEwFitting *pFit = AecDbEwFitting::cast(pEnt)) + { + AcArray arInfs; + if (pFit->GetInterface(arInfs) && mainAxisSegment(arInfs, t.a, t.b)) + { + pFit->GetAt(PIPE_SYS, t.sys); + bOk = true; + } + } + else if (AecDbEwEquipment *pEqu = AecDbEwEquipment::cast(pEnt)) + { + AcArray arInfs; + if (pEqu->GetInterface(arInfs) && mainAxisSegment(arInfs, t.a, t.b)) + { + pEqu->GetAt(PIPE_SYS, t.sys); + bOk = true; + } + } + else if (AecDbXEquipment *pXEqu = AecDbXEquipment::cast(pEnt)) + { + AcArray arInfs; + if (pXEqu->GetInterface(arInfs) && mainAxisSegment(arInfs, t.a, t.b)) + { + pXEqu->GetAt(PIPE_SYS, t.sys); + bOk = true; + } + } + + pEnt->close(); + + if (bOk && !t.sys.IsEmpty()) + targets.push_back(t); + } + + DELETE_PTR(pIter); + pBTR->close(); + } + + // Ö§µõ¼Ü(²åÈëµã pt)ÊÇ·ñÊôÓÚÖ¸¶¨¹ÜµÀϵͳ£ºÈ¡×î½ü×é¼þËùÊôµÄϵͳ + bool supportBelongsToSystem(const AcGePoint3d &pt, LPCTSTR pszSys + , const std::vector &targets) + { + double dMin = 0.0; + CString sBest; + for (size_t k = 0; k < targets.size(); ++k) + { + const double d = distPointSegment(pt, targets[k].a, targets[k].b); + if (sBest.IsEmpty() || d < dMin) + { + dMin = d; + sBest = targets[k].sys; + } + } + return (sBest == pszSys); + } + + // ÊÕ¼¯Í¼Ö½ÖÐËùÓÐÖ§µõ¼Ü(AecDbPipeHanger, DXF Ãû AEC_PIPEHNGR) + void collectPipeHangers(std::vector &ids) + { + ids.clear(); + + AcDbDatabase *pDb = acdbHostApplicationServices()->workingDatabase(); + if (!pDb) return; + + AcDbBlockTable *pTbl = NULL; + if (Acad::eOk != pDb->getBlockTable(pTbl, AcDb::kForRead)) return; + + AcDbBlockTableRecord *pBTR = NULL; + if (Acad::eOk != pTbl->getAt(ACDB_MODEL_SPACE, pBTR, AcDb::kForRead)) + { + pTbl->close(); + return; + } + pTbl->close(); + + AcDbBlockTableRecordIterator *pIter = NULL; + if (Acad::eOk != pBTR->newIterator(pIter)) + { + pBTR->close(); + return; + } + + AcDbEntity *pEnt = NULL; + for (pIter->start(); !pIter->done(); pIter->step()) + { + if (Acad::eOk != pIter->getEntity(pEnt, AcDb::kForRead) || !pEnt) + continue; + if (AecDbPipeHanger::cast(pEnt)) + ids.push_back(pEnt->objectId()); + pEnt->close(); + } + + DELETE_PTR(pIter); + pBTR->close(); + } + + /* + Ö§µõ¼Ü -> SUPPORT ×é¼þ¿é(µ¥×ø±ê)¡£ + ²Î¿¼ PCF Reference Guide£º + SUPPORT ±ØÌî CO-ORDS(º¬¹«³Æ³ß´ç) + SKEY£»Ä¬ÈÏ SKEY Ϊ 01HG(˫ƽÐÐÏßÖ§¼Ü·ûºÅ)£» + CATEGORY È¡ ERECTION(ÏÖ³¡°²×°)£»Ãû³Æ×ß NAME / ITEM-DESCRIPTION¡£ + Ö§¼ÜÀàÐÍ(0~4)²»ÊÇ PCF ±ê×¼ÊôÐÔ£¬½è COMPONENT-ATTRIBUTE0 ´ø³ö£¬·½±ãÏÂÓÎÖØÓ³Éä·ûºÅ¡£ + */ + bool pcf_support(AecDbPipeHanger *pHanger, std::ostream &out) + { + if (!pHanger || !out.good()) return false; + + const AcGePoint3d pt = pHanger->position(); + + double dn(0.0); + getNumericValue(pHanger, PCF_KEY_SUPPORT_DN, dn); + + PcfRow(out, 0) << PCF_COMP_SUPPORT; + if (dn > 0.0) + PcfRow(out, 4) << PCF_PT_CO_ORDS << pt << dn; + else + PcfRow(out, 4) << PCF_PT_CO_ORDS << pt; + + PcfRow(out, 4) << PCF_ATTR_SKEY << PCF_SKEY_SUPPORT_DEFAULT; + + CString sName; + pHanger->GetAt(KEY_NAME, sName); + writePcfAttribute(out, 4, PCF_ATTR_NAME, (LPCTSTR)sName); + writePcfAttribute(out, 4, PCF_ATTR_ITEM_DESCRIPTION, (LPCTSTR)sName); + + int nMode(-1); + if (pHanger->GetAt(PCF_KEY_SUPPORT_MODE, nMode)) + { + CString sMode; + sMode.Format(_T("%d"), nMode); + writePcfAttribute(out, 4, PCF_ATTR_COMPONENT_ATTRIBUTE0, (LPCTSTR)sMode); + } + + PcfRow(out, 4) << PCF_KW_CATEGORY << PCF_CAT_ERECTION; + out << "\n"; + return true; + } + + // ============================ Phase 5: ×Ô¶¯·Öͼ ============================ + + // ½Óͼ±êʶµÄ PCF ÊôÐÔÃû¡£Ð´ÔÚÏÂÓÎ×é¼þÊôÐÔÖ®ºó£¬Ëæ¸Ã×é¼þÒ»Æð±»Ê¶±ð¡£ + STR_PTR PCF_ATTR_CONTINUATION = L"MESSAGE-TEXT"; + + // ---- 5.1 ×é¼þͨÓöÁÈ¡ ---- + + // ºòÑ¡"¹ÜºÅ"¼ü£¬°´ÓÅÏȼ¶ÅÅÁС£ + // ×¢Ò⣺¹¤³ÌÀï"¹ÜºÅ"´æÔÚ PIPE_NO("No")£¬µ«"¸Ä¹Ü"·¾¶ + // (PipelineCmd\AecPipeLine.cpp:3647) »áÓÃ"˳ÐòºÅ"°Ñ PIPE_NO ¸²¸Çµô£¬ + // ËùÒÔ²»ÄÜÓ²±àÂ룬ÓÉ probeGroupKey() ʵ²âºóÌôÒ»¸ö¿ÉÓõļü¡£ + LPCTSTR g_pszNoKeys[] = + { + PIPE_NO, // "No" ¹ÜºÅ(¿ÉÄÜÒѱ»Ë³ÐòºÅ¸²¸Ç) + PIPE_LINENO, // "LineNo" ¹ÜÏߺÅ(PID Óã¬ÏÖ³¡³£Îª¿Õ) + PIPE_SPEC, // "Spec" ¹Ü×ÓÉϱê + KEY_NO, // "No." ˳ÐòºÅ + PIPE_UNITNO, // "UnitNo" µ¥ÔªºÅ + PIPE_ZONE, // "Zone" ÇøºÅ + }; + + template + bool readKeyString(T *pEnt, LPCTSTR pszKey, CString &s) + { + s.Empty(); + if (!pEnt || !pszKey) return false; + if (pEnt->GetAt(pszKey, s) && !s.IsEmpty()) return true; + s.Empty(); + return false; + } + + // ¹ÜµÀ/¹Ü¼þ/É豸ÊÇ"ÐÖµÜ"À࣬±ØÐë·Ö±ð cast ²ÅÄܶÁµ½×¨ÒµÊý¾Ý + bool readComponentKey(AcDbObject *pObj, LPCTSTR pszKey, CString &s) + { + s.Empty(); + if (!pObj) return false; + + if (AecDbEwPipe *pPipe = AecDbEwPipe::cast(pObj)) + return readKeyString(pPipe, pszKey, s); + if (AecDbEwFitting *pFit = AecDbEwFitting::cast(pObj)) + return readKeyString(pFit, pszKey, s); + if (AecDbEwEquipment *pEqu = AecDbEwEquipment::cast(pObj)) + return readKeyString(pEqu, pszKey, s); + if (AecDbXEquipment *pXEqu = AecDbXEquipment::cast(pObj)) + return readKeyString(pXEqu, pszKey, s); + return false; + } + + // ×é¼þµÄ EFittingType£»·Ç±¾²å¼þ×é¼þ·µ»Ø -1 + int getCompType(AcDbObject *pObj) + { + if (!pObj) return -1; + if (AecDbEwPipe::cast(pObj)) return ePipe; + if (AecDbEwFitting *pFit = AecDbEwFitting::cast(pObj)) return pFit->GetFittingType(); + if (AecDbEwEquipment::cast(pObj)) return eEquipment; + if (AecDbXEquipment::cast(pObj)) return eEquipment; + return -1; + } + + // ---- 5.3 ÍøÂçͼÓëÇеã ---- + + // ÍøÂçÀïµÄÒ»¸ö×é¼þ½Úµã(³¤Ö±¹Ü±»ÇжÏʱ£¬Í¬Ò»ÊµÌå¿É¶ÔÓ¦¶à¸ö½Úµã) + struct NetNode + { + AcDbObjectId id; + int nType; // EFITTINGTYPE + AcGePoint3d a, b; // ¸Ã½ÚµãÕ¼¾ÝµÄÖ÷ÖáÏß¶Î + AcArray infs; + int nSplitIdx; // ¶ÔÓ¦µÄ PipeSplit ϱê(ÓÃÓÚ°ÑÇжξ«È·Â䵽ͼÉÏ) + + NetNode() : nType(-1), nSplitIdx(-1) {} + }; + + // Ò»¸ö¿ÉÓÃÓÚÁ¬½ÓµÄ½Ó¿Úµã + struct ConnPt + { + AcGePoint3d pt; + int nConn; // AecInterface::nConnectType: 0º¸½Ó 1³Ð²å 2ÂÝÎÆ 3·¨À¼ 4¿¨¹¿ + double bore; // ½Ó¿Ú¹Ü¾¶ + ConnPt() : nConn(-1), bore(0.0) {} + }; + + // Á½¸ö×é¼þÖ®¼äµÄÁ¬½Ó ¡ª¡ª DZÔÚÇеã / º¸·ì + struct NetJoint + { + int nA, nB; // NetNode ϱê + AcGePoint3d pt; // ½Ó¿ÚλÖà + bool bFlange; // ÖÁÉÙÒ»¶ËÊÇ·¨À¼ -> ·¨À¼Ãæ + bool bWeld; // º¸½Ó½Ó¿Ú -> ÐèÒªÊä³ö WELD ¼Ç¼ + int nConnA, nConnB; // Á½²à½Ó¿ÚµÄÁ¬½ÓÀàÐÍ + double dBore; // ½Ó¿Ú¹Ü¾¶ + + NetJoint() : nA(-1), nB(-1), bFlange(false), bWeld(false) + , nConnA(-1), nConnB(-1), dBore(0.0) {} + }; + + // ÇеãÓÅÏȼ¶£º·¨À¼Ãæ(2) > ÏÖ³¡º¸·ì(1) > ÆÕͨ½Ó¿Ú(0) + int jointPriority(const NetJoint &j) + { + if (j.bFlange) return 2; + if (j.bWeld) return 1; + return 0; + } + + // Ö±¹Üij¶Ë(Æðµã/ÖÕµã)µÄ½Ó¿ÚÁ¬½ÓÀàÐÍ£»½Ó¿ÚÊý¾Ý²»×ãʱ·µ»Ø -1 + int pipeEndConnect(const NetNode &nd, const AcGePoint3d &pt) + { + int nBest = -1; + double dMin = 1e18; + for (int i = 0; i < nd.infs.length(); ++i) + { + const double d = nd.infs.at(i).ptPos.distanceTo(pt); + if (d < dMin) { dMin = d; nBest = nd.infs.at(i).nConnectType; } + } + return nBest; + } + + // Ö±¹Üij¶ËµÄ½Ó¿Ú¹Ü¾¶ + double pipeEndBore(const NetNode &nd, const AcGePoint3d &pt) + { + double dBore = 0.0; + double dMin = 1e18; + for (int i = 0; i < nd.infs.length(); ++i) + { + const double d = nd.infs.at(i).ptPos.distanceTo(pt); + if (d < dMin) { dMin = d; dBore = nd.infs.at(i).dSize1; } + } + return dBore; + } + + // ½ÚµãÉÏËùÓпÉÓÃÓÚÁ¬½ÓµÄ½Ó¿Ú(´øÁ¬½ÓÀàÐÍÓë¹Ü¾¶) + void nodeConnPoints(const NetNode &nd, std::vector &pts) + { + pts.clear(); + + if (nd.nType == ePipe) + { + ConnPt c0, c1; + c0.pt = nd.a; c0.nConn = pipeEndConnect(nd, nd.a); c0.bore = pipeEndBore(nd, nd.a); + c1.pt = nd.b; c1.nConn = pipeEndConnect(nd, nd.b); c1.bore = pipeEndBore(nd, nd.b); + pts.push_back(c0); + pts.push_back(c1); + return; + } + + for (int i = 0; i < nd.infs.length(); ++i) + { + ConnPt c; + c.pt = nd.infs.at(i).ptPos; + c.nConn = nd.infs.at(i).nConnectType; + c.bore = nd.infs.at(i).dSize1; + pts.push_back(c); + } + + if (pts.empty()) + { + ConnPt c0, c1; + c0.pt = nd.a; + pts.push_back(c0); + if (nd.a.distanceTo(nd.b) > 1e-9) { c1.pt = nd.b; pts.push_back(c1); } + } + } + + // ½Ó¿ÚÖØºÏÅж¨µÄÈݲî(ͼֽµ¥Î»)¡£±¾Í¼Ö½ÀïÏàÁÚ×é¼þµÄ½Ó¿ÚλÖÃÊÇÑϸñÖØºÏµÄ£¬ + // È¡ 0.01 ×ã¹»£»²»ÔÙ½èÓõײ㰴µæÆ¬³ß´ç(dGasket)·Å´óµÄÈݲ + double netTolerance() + { + double dUnit = 1.0; + struct resbuf rb; + if (acedGetVar(_T("INSUNITS"), &rb) == RTNORM && rb.resval.rint == AcDb::kUnitsMeters) + dUnit = 0.001; + return __max(0.01 * dUnit, 0.01); + } + + // ¶ÁÒ»¸öʵÌåµÄ½Ó¿ÚÓëÖ÷ÖáÏß¶Î(½Ó¿Ú²»×ãÁ½¸öʱÍË»¯Îªµã) + bool readAxisSegment(AcDbObject *pObj, AcArray &infs + , AcGePoint3d &a, AcGePoint3d &b) + { + if (AecDbEwPipe *pPipe = AecDbEwPipe::cast(pObj)) + { + a = pPipe->StartPoint(); + b = pPipe->EndPoint(); + pPipe->GetInterface(infs); + return true; + } + + if (AecDbEwFitting *pFit = AecDbEwFitting::cast(pObj)) + { + pFit->GetInterface(infs); + } + else if (AecDbEwEquipment *pEqu = AecDbEwEquipment::cast(pObj)) + { + pEqu->GetInterface(infs); + } + else if (AecDbXEquipment *pXEqu = AecDbXEquipment::cast(pObj)) + { + pXEqu->GetInterface(infs); + } + else + { + return false; + } + + if (!mainAxisSegment(infs, a, b)) + { + a = b = AcGePoint3d::kOrigin; + return false; + } + return true; + } + + /* + ×é×°ÍøÂçͼ¡£ + dSplitLen > 0 ʱ£¬³¤¶È³¬¹ý dSplitLen µÄÖ±¹Ü»á±»²ð³É¶à¶Î"ÐéÄâ½Úµã" + (°´ dSplitLen µÈ·Ö)£¬ÕâÑùºóÐø¼È¿ÉÒÔÔÚ½ÚµãÊýÉÏ¿ØÖÆÍ¼·ù£¬Ò²ÄÜÔÚ³¤Ö±¹Ü + µÄÖе㴦×ÔÈ»ÐγÉÇеã(·ûºÏ"³¤Ö±¹Ü¶ÎÖÐÐĵãÇжÏ"µÄÒªÇó)¡£ + pipeSplits »Ø´«Ã¿¸ö±»²ðÖ±¹ÜµÄÇжβÎÊý£¬¹©Ð´ PCF ʱÊä³ö¶à¸ùÐéÄâ¹Ü¡£ + */ + struct PipeSplit + { + AcDbObjectId id; + double t0, t1; // ÑØ¹Ü×ÓÆðµã->Öյ㷽ÏòµÄ¹éÒ»»¯²ÎÊý + }; + + void buildNetwork(const AcDbObjectIdArray &ids, double dSplitLen + , std::vector &nodes, std::vector &joints + , std::vector &pipeSplits) + { + nodes.clear(); + joints.clear(); + pipeSplits.clear(); + + for (int i = 0; i < ids.length(); ++i) + { + AcDbObjectPointer pObj(ids[i], AcDb::kForRead); + if (pObj.openStatus() != Acad::eOk) continue; + + const int nType = getCompType(pObj.object()); + if (nType < 0) continue; + + AcGePoint3d a, b; + AcArray infs; + if (!readAxisSegment(pObj.object(), infs, a, b)) continue; + + // ³¤Ö±¹Ü£º°´ dSplitLen µÈ·Ö£¬Öð¶Î½¨½Úµã + const double dLen = a.distanceTo(b); + if (dSplitLen > 0.0 && nType == ePipe && dLen > dSplitLen * 1.5) + { + const int nSeg = (int)(dLen / dSplitLen) + 1; + const AcGeVector3d vt(b - a); + + for (int k = 0; k < nSeg; ++k) + { + const double t0 = (double)k / nSeg; + const double t1 = (double)(k + 1) / nSeg; + + NetNode nd; + nd.id = ids[i]; + nd.nType = ePipe; + nd.a = a + vt * t0; + nd.b = a + vt * t1; + nd.infs = infs; // ±£Áô½Ó¿Ú£¬¹©Åж϶˲¿Á¬½ÓÀàÐÍ(º¸½Ó/·¨À¼) + nd.nSplitIdx = (int)pipeSplits.size(); + nodes.push_back(nd); + + PipeSplit sp; + sp.id = ids[i]; + sp.t0 = t0; + sp.t1 = t1; + pipeSplits.push_back(sp); + } + continue; + } + + NetNode nd; + nd.id = ids[i]; + nd.nType = nType; + nd.a = a; + nd.b = b; + nd.infs = infs; + nd.nSplitIdx = (int)pipeSplits.size(); + nodes.push_back(nd); + + PipeSplit sp; + sp.id = ids[i]; + sp.t0 = 0.0; + sp.t1 = 1.0; + pipeSplits.push_back(sp); + } + + // Á¬½Ó¹ØÏµ£º½Ó¿ÚλÖÃÖØºÏ¼´ÊÓΪÏà½Ó + const double dTol = netTolerance(); + + for (size_t i = 0; i < nodes.size(); ++i) + { + std::vector ptI; + nodeConnPoints(nodes[i], ptI); + + for (size_t k = i + 1; k < nodes.size(); ++k) + { + std::vector ptK; + nodeConnPoints(nodes[k], ptK); + + int nHitX = -1, nHitY = -1; + for (size_t x = 0; x < ptI.size() && nHitX < 0; ++x) + { + for (size_t y = 0; y < ptK.size() && nHitX < 0; ++y) + { + if (ptI[x].pt.distanceTo(ptK[y].pt) <= dTol) + { + nHitX = (int)x; + nHitY = (int)y; + } + } + } + if (nHitX < 0) continue; + + NetJoint jt; + jt.nA = (int)i; + jt.nB = (int)k; + jt.pt = ptI[nHitX].pt; + jt.nConnA = ptI[nHitX].nConn; + jt.nConnB = ptK[nHitY].nConn; + jt.dBore = (ptI[nHitX].bore > 0.0) ? ptI[nHitX].bore : ptK[nHitY].bore; + + // ·¨À¼Ã棺һ¶ËÊÇ·¨À¼¹Ü¼þ£¬»òijһ²à½Ó¿Ú±¾Éí¾ÍÊÇ·¨À¼Á¬½Ó(3) + jt.bFlange = (nodes[i].nType == eFlange) || (nodes[k].nType == eFlange) + || (jt.nConnA == 3) || (jt.nConnB == 3); + + /* + ÂÝ˨Á¬½ÓµÄ·¨À¼Ãæ²»Ë㺸¿Ú£º + - ÈÎÒ»½Ó¿ÚµÄÁ¬½ÓÀàÐÍÊÇ"·¨À¼(3)"£»»ò + - Ò»¶ËÊÇ·¨À¼¹Ü¼þ£¬ÁíÒ»¶ËÊÇ·§ÃÅ/É豸(¾ùÒÔ eEquipment ±íʾ)»òÁíһƬ·¨À¼¡£ + ×¢Ò⣺·¨À¼µÄÁíÒ»¶Ë(º¸¾±)ÓëÖ±¹Ü/¹Ü¼þÏà½ÓÈÔÊǺ¸¿Ú£¬¹Ê²»ÄÜ"·²·¨À¼¼´²»Ë㺸"¡£ + */ + bool bBoltedFace = (jt.nConnA == 3) || (jt.nConnB == 3); + if (!bBoltedFace && (nodes[i].nType == eFlange || nodes[k].nType == eFlange)) + { + const int nOther = (nodes[i].nType == eFlange) ? nodes[k].nType : nodes[i].nType; + if (nOther == eEquipment || nOther == eFlange) + bBoltedFace = true; + } + + // º¸½Ó½ÓÍ·£ºÁ½²à½Ó¿ÚµÄÁ¬½ÓÀàÐͶ¼ÊÇ"º¸½Ó(0)"£¬ÇÒ²»ÊÇÂÝ˨·¨À¼Ãæ¡£ + // Á¬½ÓÀàÐÍÈ¡²»µ½(-1£¬½Ó¿ÚÊý¾Ýȱʧ)ʱ£¬ÍË»Ø"·ÇÂÝË¨ÃæÇÒÖÁÉÙÒ»¶ËÊÇÖ±¹Ü"µÄ¾ÉÅоݡ£ + if (bBoltedFace) + jt.bWeld = false; + else if (jt.nConnA == 0 && jt.nConnB == 0) + jt.bWeld = true; + else if (jt.nConnA < 0 && jt.nConnB < 0) + jt.bWeld = (nodes[i].nType == ePipe || nodes[k].nType == ePipe); + + joints.push_back(jt); + } + } + } + + // ---- 5.3b Á¬Í¨×ÓÍø°þÀë ---- + + /* + °ÑÒ»×é×é¼þ°´"½Ó¿ÚÏà½Ó"µÄÁ¬Í¨ÐÔ²ð³ÉÈô¸ÉÁ¬Í¨×ÓÍø¡£ + Á¬Í¨ÐÔÍêÈ«ÒÔ±¾ÎļþµÄ½Ó¿ÚÖØºÏÅж¨Îª×¼(¼´ buildNetwork ½¨µÄͼ)£¬ÕâÑù + "²ð×ÓÍø"¡¢"Ñ¡Çеã"¡¢"¿çÍ¼Ðø½Ó±ê×¢"Èý´¦ÓõÄÊÇͬһÌ×¼¸ºÎ¹æÔò£¬½á¹û×ÔÇ¢¡£ + + ²»Óõײã GetPipeNetNodes£ºËüµÄÈݲîÈ¡µÄÊÇÄ¿±ê½Ó¿ÚµÄµæÆ¬³ß´ç(dGasket)£¬ + ÔÚ±¾Í¼Ö½ÉÏ»á°Ñ½Ó¿ÚλÖÃÍêÈ«ÖØºÏ(¾àÀë 0)µÄ·¨À¼Óë·§ÃÅÅгɲ»Á¬Í¨£¬µ¼Ö + Ò»¸öϵͳ±»ÇгÉÉϰٸöË鯬¡£ + */ + void splitNetByConnectivity(const AcDbObjectIdArray &ids, std::vector &nets) + { + nets.clear(); + if (ids.isEmpty()) return; + + std::vector nodes; + std::vector joints; + std::vector splits; + buildNetwork(ids, 0.0, nodes, joints, splits); + + const int n = (int)nodes.size(); + if (n <= 0) return; + + // ²¢²é¼¯£º½Ó¿ÚÖØºÏ¼´ÊÓΪͬһ×ÓÍø + std::vector par(n); + for (int i = 0; i < n; ++i) par[i] = i; + + for (size_t j = 0; j < joints.size(); ++j) + { + int a = joints[j].nA, b = joints[j].nB; + while (par[a] != a) { par[a] = par[par[a]]; a = par[a]; } + while (par[b] != b) { par[b] = par[par[b]]; b = par[b]; } + if (a != b) par[a] = b; + } + + // °´¸ù¾Û££»½Úµã˳ÐòÑØÓÃϵͳÄÚµÄ×é¼þ˳Ðò£¬±£Ö¤µ¼³ö˳ÐòÎȶ¨ + std::map rootToNet; + for (int i = 0; i < n; ++i) + { + int r = i; + while (par[r] != r) { par[r] = par[par[r]]; r = par[r]; } + + std::map::iterator it = rootToNet.find(r); + int idx; + if (it == rootToNet.end()) + { + idx = (int)nets.size(); + rootToNet.insert(std::make_pair(r, idx)); + nets.push_back(AcDbObjectIdArray()); + } + else + { + idx = it->second; + } + + if (nets[idx].find(nodes[i].id) == -1) + nets[idx].append(nodes[i].id); + } + + acutPrintf(_T("\nÁ¬Í¨×ÓÍø %d ¸ö¡£"), (int)nets.size()); + } + + // ¹ÜºÅÀï³£¼ûµÄռλֵ(¿Õ¡¢È«·Ö¸ô·û)ÊÓΪ"ûÌî" + bool isBlankKey(const CString &s) + { + if (s.IsEmpty()) return true; + for (int i = 0; i < s.GetLength(); ++i) + { + const TCHAR c = s[i]; + if (c != _T('-') && c != _T('_') && c != _T('.') && c != _T(' ') && c != _T('/')) + return false; + } + return true; + } + + /* + ȡһ¸öÁ¬Í¨×ÓÍøµÄ"¹ÜºÅ"£º×ÓÍøÄÚ³öÏÖ´ÎÊý×î¶àµÄ·Ç¿Õ¹ÜºÅ¡£ + ·§ÃÅ/¸½¼þÕâÀ಻´ø¹ÜºÅµÄ×é¼þÒò´Ë»á¸ú×ÅËüËùÔÚµÄÄÇÌõ¹ÜÏß×ߣ¬ + ¶ø²»ÊDZ»µ¥¶À·Ö³öÈ¥¡£È¡²»µ½Ê±ÍË»ØÏµÍ³Ãû¡£ + */ + CString dominantKey(const AcDbObjectIdArray &ids, LPCTSTR pszKey, LPCTSTR pszDefault) + { + CString sDefault(pszDefault ? pszDefault : _T("")); + if (!pszKey || _tcslen(pszKey) == 0) return sDefault; + + std::map hist; + for (int i = 0; i < ids.length(); ++i) + { + AcDbObjectPointer pObj(ids[i], AcDb::kForRead); + if (pObj.openStatus() != Acad::eOk) continue; + + CString s; + if (!readComponentKey(pObj.object(), pszKey, s) || isBlankKey(s)) continue; + hist[s]++; + } + + CString sBest; + int nBest = 0; + for (std::map::const_iterator it = hist.begin(); it != hist.end(); ++it) + { + if (it->second > nBest) { nBest = it->second; sBest = it->first; } + } + + return sBest.IsEmpty() ? sDefault : sBest; + } + + // ---- 5.4 ³ß´ç/Ãܶȶþ´ÎÇÐ·Ö ---- + + /* + Ò»ÕÅͼ·Å²»ÏÂʱ£¬ÑعÜÏß×ßÏò´ÓÒ»¶Ë¿ªÊ¼ÀÛ¼Ó×é¼þ£»Ò»µ©ÔټӾͻᳬ¹ý + nMaxNodes ¸ö×é¼þ»ò dMaxSpan µÄ¿ç¶È£¬¾Í»ØÍ˵½"×î½üµÄÓÅÏÈÇеã"ÔÙÇС£ + ÒòΪֻÔÚ×é¼þÖ®¼äµÄ½Ó¿Ú´¦ÇУ¬ËùÒÔ¾ø²»»áÇÐÔÚÍäÍ·/ÈýͨÄÚ²¿¡£ + */ + void splitBySize(const std::vector &nodes, const std::vector &joints + , int nMaxNodes, double dMaxSpan, std::vector > &sheets) + { + sheets.clear(); + + const int n = (int)nodes.size(); + if (n <= 0) return; + + // ÁÚ½Ó±í£ºnode -> (ÁÚ¾Ó, joint ϱê) + std::vector > > adj(n); + for (int j = 0; j < (int)joints.size(); ++j) + { + adj[joints[j].nA].push_back(std::make_pair(joints[j].nB, j)); + adj[joints[j].nB].push_back(std::make_pair(joints[j].nA, j)); + } + + std::vector used(n, 0); + + for (int s = 0; s < n; ++s) + { + if (used[s]) continue; + + // ÓÅÏÈ´Ó"¶Ëµã"(¶ÈΪ 1)Æð²½£¬·ûºÏ¹ÜÏß×ßÏò + int start = s; + for (int k = 0; k < n; ++k) + { + if (!used[k] && adj[k].size() <= 1) { start = k; break; } + } + + std::vector order; // ±éÀú˳Ðò + std::vector entry; // ½øÈë order[k] ËùÓÃµÄ joint£»order[0] = -1 + std::vector stack; + + order.push_back(start); + entry.push_back(-1); + used[start] = 1; + stack.push_back(start); + + AcGePoint3d ptMin, ptMax; + bool bBox = false; + + while (!stack.empty()) + { + const int u = stack.back(); + + int v = -1, je = -1; + for (size_t t = 0; t < adj[u].size(); ++t) + { + const int w = adj[u][t].first; + if (used[w]) continue; + v = w; + je = adj[u][t].second; + break; + } + if (v < 0) { stack.pop_back(); continue; } + + // ×é¼þÊýÉÏÏÞ + if (nMaxNodes > 0 && (int)order.size() >= nMaxNodes) + break; + + // ¿Õ¼ä¿ç¶ÈÉÏÏÞ + if (dMaxSpan > 0.0) + { + AcGePoint3d mn = nodes[v].a, mx = nodes[v].b; + if (mn.x > mx.x) { const double t = mn.x; mn.x = mx.x; mx.x = t; } + if (mn.y > mx.y) { const double t = mn.y; mn.y = mx.y; mx.y = t; } + if (mn.z > mx.z) { const double t = mn.z; mn.z = mx.z; mx.z = t; } + + AcGePoint3d tmn = mn, tmx = mx; + if (bBox) + { + if (ptMin.x < tmn.x) tmn.x = ptMin.x; + if (ptMin.y < tmn.y) tmn.y = ptMin.y; + if (ptMin.z < tmn.z) tmn.z = ptMin.z; + if (ptMax.x > tmx.x) tmx.x = ptMax.x; + if (ptMax.y > tmx.y) tmx.y = ptMax.y; + if (ptMax.z > tmx.z) tmx.z = ptMax.z; + } + + const double dx = tmx.x - tmn.x; + const double dy = tmx.y - tmn.y; + const double dz = tmx.z - tmn.z; + if (__max(dx, __max(dy, dz)) > dMaxSpan) + break; + + ptMin = tmn; + ptMax = tmx; + bBox = true; + } + + order.push_back(v); + entry.push_back(je); + used[v] = 1; + stack.push_back(v); + } + + int nKeep = (int)order.size(); + + // ÊÇ·ñ"Òò³¬ÏÞ±»½Ø¶Ï"(×îºóÒ»¸ö½Úµã»¹ÓÐûÓõ½µÄÁÚ¾Ó) + bool bTruncated = false; + { + const int last = order.back(); + for (size_t t = 0; t < adj[last].size(); ++t) + { + if (!used[adj[last][t].first]) { bTruncated = true; break; } + } + } + + // »ØÍ˵½×î½üµÄÓÅÏÈÇеã(·¨À¼Ãæ/ÏÖ³¡º¸·ì)£¬ÈÃÇеãÂäÔÚ¸ÃÂäµÄµØ·½ + if (bTruncated) + { + for (int k = nKeep - 1; k >= 1; --k) + { + if (jointPriority(joints[entry[k]]) >= 1) + { + // order[k..] ½»»¹¸øÏÂÒ»ÂÖ + for (int t = k; t < nKeep; ++t) used[order[t]] = 0; + nKeep = k; + break; + } + } + } + + sheets.push_back(std::vector(order.begin(), order.begin() + nKeep)); + } + } + + // ---- 5.5 ·Öͼµ¼³ö ---- + + // ÎļþÃû·Ç·¨×Ö·ûÌæ»» + CString sanitizeFileName(LPCTSTR psz) + { + CString s(psz ? psz : _T("")); + LPCTSTR pszBad = _T("\\/:*?\"<>|"); + for (int i = 0; i < (int)_tcslen(pszBad); ++i) + s.Replace(pszBad[i], _T('_')); + s.Trim(); + if (s.IsEmpty()) s = _T("PCF"); + return s; + } + + // Ò»¸öº¸¿Ú£ºÎ»Öà + ¹Ü¾¶ + Á½²à×é¼þ(ÓÃÓڰѺ¸¿Ú¹Òµ½×é¼þËùÔÚµÄÄÇÕÅͼÉÏ) + struct WeldRec + { + AcGePoint3d pt; + double bore; + AcDbObjectId idA, idB; + + WeldRec() : bore(0.0) {} + }; + + /* + º¸¿Ú(WELD)¡£PCF ²Î¿¼ÊÖ²áÀï WELD µÄ±ê׼д·¨£º + WELD + END-POINT x y z + END-POINT x y z + SKEY WW + CATEGORY FABRICATION + (Á½¸ö END-POINT ·Ö±ð´ú±íº¸·ìÁ½²à£»±¾Ä£ÐÍÀïÁ½²àλÖÃÖØºÏ£¬¹Ê×ø±êÏàͬ¡£) + */ + bool pcf_weld(const WeldRec &w, std::ostream &out) + { + if (!out.good()) return false; + + PcfRow(out, 0) << PCF_COMP_WELD; + if (w.bore > 0.0) + { + PcfRow(out, 4) << PCF_PT_END_POINT << w.pt << w.bore; + PcfRow(out, 4) << PCF_PT_END_POINT << w.pt << w.bore; + } + else + { + PcfRow(out, 4) << PCF_PT_CO_ORDS << w.pt; + } + PcfRow(out, 4) << PCF_ATTR_SKEY << PCF_ATTR_SKEY_WELD; + PcfRow(out, 4) << PCF_KW_CATEGORY << PCF_CAT_FABRICATION; + out << "\n"; + return true; + } + + // É豸(EQUIPMENT)¶¨Òå¿é£º±ØÐëдÔÚ PIPELINE-REFERENCE ֮ǰ + void writePcfEquipmentDefs(std::ostream &out, CUIISQLiteServer *pDb + , const AcDbObjectIdArray &ids, int &nDef, int &nDefOk) + { + nDef = nDefOk = 0; + for (int i(0); i < ids.length(); ++i) + { + AcDbObjectPointer pObj(ids[i], AcDb::kForRead); + if (pObj.openStatus() != Acad::eOk) continue; + if (pObj->isA() != AecDbXEquipment::desc()) continue; + + ++nDef; + AecDbXEquipment *pXEqu = AecDbXEquipment::cast(pObj.object()); + if (pcf_xEquipment(pDb, pXEqu, out)) ++nDefOk; + } + } + + // ¹ÜµÀ / ¹Ü¼þ / ·§ÃÅ(É豸) / º¸¿Ú + void writePcfComponents(std::ostream &out, CUIISQLiteServer *pDb + , const AcDbObjectIdArray &ids + , const std::vector *pSplits + , const std::vector > *pMsgs + , const std::vector *pWelds + , int &nPipe, int &nPipeOk, int &nFit, int &nFitOk, int &nEqu, int &nEquOk + , int &nWeld, int &nWeldOk) + { + nPipe = nPipeOk = nFit = nFitOk = nEqu = nEquOk = 0; + nWeld = nWeldOk = 0; + + // ͬһʵÌå±»²ð³É¶à¶Îʱ£¬ÏȰ´ÊµÌå¹é£ÇжβÎÊý + std::vector hit; + + for (int i(0); i < ids.length(); ++i) + { + const AcDbObjectId &id(ids[i]); + + AcDbObjectPointer pObj(id, AcDb::kForRead); + if (pObj.openStatus() != Acad::eOk) continue; + + bool bOk = false; + + if (pObj->isA() == AecDbEwPipe::desc()) + { + AecDbEwPipe *pPipe = AecDbEwPipe::cast(pObj.object()); + + // ÊÕ¼¯±¾ÊµÌå¶ÔÓ¦µÄÇжÎ(ͨ³£Ö»ÓÐÒ»¶Î) + hit.clear(); + if (pSplits) + { + for (size_t k = 0; k < pSplits->size(); ++k) + if ((*pSplits)[k].id == id) hit.push_back(k); + } + + if (!hit.empty()) + { + // ³¤Ö±¹Ü±»Çжϣº±¾Í¼Ö»Êä³öÂäÔÚ±¾Í¼ÉϵÄÄǼ¸¶ÎÐéÄâ¹Ü + const AcGePoint3d ptA = pPipe->StartPoint(); + const AcGeVector3d vt(pPipe->EndPoint() - ptA); + + nPipe += (int)hit.size(); + for (size_t k = 0; k < hit.size(); ++k) + { + const PipeSplit &sp = (*pSplits)[hit[k]]; + const AcGePoint3d ptS = ptA + vt * sp.t0; + const AcGePoint3d ptE = ptA + vt * sp.t1; + if (pcf_pipe_normal(pDb, pPipe, out, &ptS, &ptE)) ++nPipeOk; + } + bOk = true; + } + else + { + ++nPipe; + if (pcf_pipe_normal(pDb, pPipe, out)) { ++nPipeOk; bOk = true; } + } + } + else if (pObj->isA() == AecDbEwFitting::desc()) + { + ++nFit; + AecDbEwFitting *pFit = AecDbEwFitting::cast(pObj.object()); + if (pcf_fitting(pDb, pFit, out)) { ++nFitOk; bOk = true; } + } + else if (pObj->isA() == AecDbEwEquipment::desc()) + { + ++nEqu; + AecDbEwEquipment *pEqu = AecDbEwEquipment::cast(pObj.object()); + if (pcf_ewEquipment(pDb, pEqu, out)) { ++nEquOk; bOk = true; } + } + + // ½Óͼ±êʶ£º½ô¸úÔÚ±¾×é¼þÊôÐÔÖ®ºóд£¬Ëæ¸Ã×é¼þÒ»Æð±»ÏÂÓÎʶ±ð¡£ + // ͬһ¸ö×é¼þ¿ÉÄÜÊÇÁ½¸öÇзìµÄ¶Ëµã(ÀýÈçÈýͨµÄÁ½ÌõÖ§¹Ü¸÷È¥Á˲»Í¬µÄͼ)£¬ + // ËùÒÔÕâÀïÒª°Ñ¸Ã×é¼þµÄËùÓнÓͼ±êʶ¶¼Ð´³öÀ´£¬²»ÄÜ break¡£ + if (bOk && pMsgs) + { + for (size_t k = 0; k < pMsgs->size(); ++k) + { + if ((*pMsgs)[k].first == id) + writePcfAttribute(out, 4, PCF_ATTR_CONTINUATION, (LPCTSTR)(*pMsgs)[k].second); + } + } + + // º¸¿Ú£º¹ÒÔÚº¸·ì A ¶Ë×é¼þÖ®ºó£¬±£³ÖÓëÏàÁÚ×é¼þµÄǰºó¹ØÏµ + if (bOk && pWelds) + { + for (size_t k = 0; k < pWelds->size(); ++k) + { + if ((*pWelds)[k].idA != id) continue; + ++nWeld; + if (pcf_weld((*pWelds)[k], out)) ++nWeldOk; + } + } + } + } + + // Ö§µõ¼Ü£º±¾Éí²»´ø PIPE_SYS£¬Ò²Ã»ÓÐËÞÖ÷¹ÜµÀ¾ä±ú£¬°´¿Õ¼ä¾Í½ü¹éÊôµ½±¾¹ÜµÀϵͳ + void writePcfSupports(std::ostream &out, LPCTSTR pszSys + , const std::vector &hangers + , const std::vector &targets, int &nSup, int &nSupOk) + { + nSup = nSupOk = 0; + + for (size_t k(0); k < hangers.size(); ++k) + { + AcDbObjectPointer pObj(hangers[k], AcDb::kForRead); + if (pObj.openStatus() != Acad::eOk) continue; + + AecDbPipeHanger *pHanger = AecDbPipeHanger::cast(pObj.object()); + if (!pHanger) continue; + + if (!supportBelongsToSystem(pHanger->position(), pszSys, targets)) continue; + + ++nSup; + if (pcf_support(pHanger, out)) ++nSupOk; + } + } + + // Ò»ÕÅͼ(Ò»¸ö PCF Îļþ)µÄͳ¼Æ + struct PcfSheetCounts + { + int nPipe, nPipeOk, nFit, nFitOk, nEqu, nEquOk, nEquDef, nEquDefOk, nSup, nSupOk, nWeld, nWeldOk; + PcfSheetCounts() + : nPipe(0), nPipeOk(0), nFit(0), nFitOk(0), nEqu(0), nEquOk(0) + , nEquDef(0), nEquDefOk(0), nSup(0), nSupOk(0), nWeld(0), nWeldOk(0) {} + }; + + /* + дһÕÅͼµÄÍêÕû PCF ÄÚÈÝ(ÎļþÁ÷µÄ´ò¿ª/¹Ø±ÕÓɵ÷Ó÷½¸ºÔð)¡£ + pszPipelineRef : PIPELINE-REFERENCE ȡֵ(¹ÜºÅ£¬È¡²»µ½Ê±ÓÃϵͳÃû) + pSplits : ³¤Ö±¹ÜÇжÎ(¿É¿Õ) + pMsgs : ½Óͼ±êʶ(¿É¿Õ) + */ + void writePcfSheet(std::ostream &out, CUIISQLiteServer *pDb, LPCTSTR pszPipelineRef + , const AcDbObjectIdArray &ids + , const std::vector &targets + , const std::vector &hangers + , LPCTSTR pszSupportSys + , const std::vector *pSplits + , const std::vector > *pMsgs + , const std::vector *pWelds + , PcfSheetCounts &c) + { + pcf_begin(out); + + writePcfEquipmentDefs(out, pDb, ids, c.nEquDef, c.nEquDefOk); + + pcf_pipeline_reference(out, pszPipelineRef); + + writePcfComponents(out, pDb, ids, pSplits, pMsgs, pWelds + , c.nPipe, c.nPipeOk, c.nFit, c.nFitOk, c.nEqu, c.nEquOk, c.nWeld, c.nWeldOk); + + writePcfSupports(out, pszSupportSys, hangers, targets, c.nSup, c.nSupOk); + } + + // Ò»´Î±éÀúͬʱͳ¼ÆËùÓкòÑ¡¼üµÄȡֵ·Ö²¼(±ÜÃâ°´ 6 ¸ö¼ü·´¸´´ò¿ªÊµÌå) + void probeGroupKeys(const AcDbObjectIdArray &ids, std::vector > &hists) + { + const int nKeys = (int)(sizeof(g_pszNoKeys) / sizeof(g_pszNoKeys[0])); + hists.assign(nKeys, std::map()); + + for (int i = 0; i < ids.length(); ++i) + { + AcDbObjectPointer pObj(ids[i], AcDb::kForRead); + if (pObj.openStatus() != Acad::eOk) continue; + + for (int k = 0; k < nKeys; ++k) + { + CString s; + if (readComponentKey(pObj.object(), g_pszNoKeys[k], s) && !s.IsEmpty()) + hists[k][s]++; + } + } + } + + // ¿çͼÁ¬½ÓÅж¨ÓãºÒ»¸öÁ¬½Óµã¼°ÆäËùÊô×é¼þ + struct SheetPoint + { + AcGePoint3d pt; + AcDbObjectId id; + }; + + // ȡһ¸öʵÌåµÄ½ÚµãÐÅÏ¢(½Ó¿Ú + Ö÷Öá)£¬¶¨Òå¼ûÏ·½ + bool readNode(AcDbObjectId id, NetNode &nd); + + // Ô¤¼ÆËãÒ»ÕÅͼµÄÈ«²¿Á¬½Óµã£¬±ÜÃâ¿çͼÁ½Á½±È½Ïʱ·´¸´´ò¿ªÊµÌå + void collectSheetPoints(const AcDbObjectIdArray &ids, std::vector &pts) + { + pts.clear(); + + for (int i = 0; i < ids.length(); ++i) + { + NetNode nd; + if (!readNode(ids[i], nd)) continue; + + std::vector ar; + nodeConnPoints(nd, ar); + + for (size_t k = 0; k < ar.size(); ++k) + { + SheetPoint sp; + sp.pt = ar[k].pt; + sp.id = ids[i]; + pts.push_back(sp); + } + } + } + + // ȡһ¸öʵÌåµÄ½ÚµãÐÅÏ¢(½Ó¿Ú + Ö÷Öá)£¬¹©¿çͼÁ¬½ÓÅж¨Ê¹Óà + bool readNode(AcDbObjectId id, NetNode &nd) + { + AcDbObjectPointer pObj(id, AcDb::kForRead); + if (pObj.openStatus() != Acad::eOk) return false; + + const int nType = getCompType(pObj.object()); + if (nType < 0) return false; + + AcGePoint3d a, b; + AcArray infs; + if (!readAxisSegment(pObj.object(), infs, a, b)) return false; + + nd.id = id; + nd.nType = nType; + nd.a = a; + nd.b = b; + nd.infs = infs; + return true; + } + } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// 对外å�ªæš´éœ²è¿™ä¸€ä¸ªæŽ¥å�£ -// pszSystem代表管é�“系统,å�¯ä»¥é€šè¿‡è¿™ä¸ªå�‚数得到此系统下的所有管é�“ã€�管件ã€�设备,并输出到pcf +// ĬÈÏÊä³ö·¾¶(ʵÏÖÔÚÎļþĩβ) +static CString makeDefaultPcfPath(LPCTSTR pszSystem); + +// ¶ÔÍâÖ»±©Â¶ÕâÒ»¸ö½Ó¿Ú +// °´¹ÜµÀϵͳ(pszSystem)µÃµ½¸ÃϵͳϵÄËùÓÐ ¹ÜµÀ/¹Ü¼þ/É豸£¬²¢Êä³öµ½ pcf Îļþ bool PCF::makePCF(LPCTSTR pszFile, LPCTSTR pszSystem) { - CString dbPath(FilePath::GetSysDir() + _T("\\Plumbing.db")); + if (!pszFile || _tcslen(pszFile) == 0) + return false; + // δָ¶¨¹ÜµÀϵͳʱ£¬±éÀúͼֽÖгöÏÖµÄËùÓйܵÀϵͳ£¬È¡µÚÒ»¸ö + CString sSystem; + if (pszSystem && _tcslen(pszSystem) > 0) + { + sSystem = pszSystem; + } + else + { + std::vector systems; + collectSystems(systems); + if (systems.empty()) + { + acutPrintf(_T("\nͼֽÖÐδÕÒµ½ÈκιܵÀϵͳ(PIPE_PSYSTEM)!")); + return false; + } + sSystem = systems[0]; + } + + AcDbObjectIdArray ids; + if (!getComponentBySystem(sSystem, ids)) + { + acutPrintf(_T("\n¹ÜµÀϵͳ [%s] ÏÂûÓÐ ¹ÜµÀ/¹Ü¼þ/É豸¡£"), (LPCTSTR)sSystem); + return false; + } + + // ¹æ¸ñ¿â(ÎïÁÏÂë/ÃèÊö/µÈ¼¶)ÓÃÓÚÌî³ä PCF µÄ ITEM-CODE µÈÊôÐÔ£» + // ´ò²»¿ªÊ±½µ¼¶ÎªÖ»Êä³ö¼¸ºÎ¹Ç¼Ü£¬²»×è¶Ïµ¼³ö¡£ CUIISQLiteServer *pDb = new CUIISQLiteServer; - if (!pDb->InitADOServer(dbPath)) + if (!pDb->InitADOServer(FilePath::GetSysDir() + _T("\\Plumbing.db"))) + { + AfxMessageBox(_T("Êý¾Ý¿âÇý¶¯¼ÓÔØÊý¾Ý¿âPlumbing.dbʧ°Ü!½«Ö»µ¼³ö¼¸ºÎ¹Ç¼Ü¡£")); + DELETE_PTR(pDb); + pDb = NULL; + } + + std::ofstream out(pszFile, std::ios::binary); + if (!out.good()) { - AfxMessageBox(_T("æ•°æ�®åº“驱动加载数æ�®åº“Plumbing.db失败!")); DELETE_PTR(pDb); return false; } - AcDbObjectIdArray ids; - // 得到 pszSystem 的所有管é�“ã€�管件ã€�设备 - // GetComponentBySystem(pszSystem, ids); + // Ö§µõ¼Ü°´¿Õ¼ä¾Í½ü¹éÊô£¬Ïȱ¸ºÃ¹éÊôÓõÄ×é¼þÖ÷Öá±í + std::vector targets; + collectSupportTargets(targets); - if (ids.isEmpty()) return false; + std::vector hangers; + collectPipeHangers(hangers); -#ifdef NDEBUG - std::ofstream stream(pszFile, std::ios::binary); -#else - std::stringstream stream; -#endif - - pcf_begin(stream, L"P-1", L"sch40"); - - for (int i(0); i < ids.length(); ++i) + // º¸¿Ú£ºÕûϵͳ½¨Ò»´ÎÍøÂ磬ȡ³öËùÓк¸½Ó½ÓÍ·(Á½²à½Ó¿ÚÁ¬½ÓÀàÐͶ¼ÊÇ"º¸½Ó") + std::vector welds; { - AcDbObjectId &id(ids[i]); + std::vector nodes; + std::vector joints; + std::vector splits; + buildNetwork(ids, 0.0, nodes, joints, splits); - AcDbObjectPointer pObj(id, AcDb::kForRead); - if (pObj.openStatus() != Acad::eOk) continue; + for (size_t j = 0; j < joints.size(); ++j) + { + if (!joints[j].bWeld) continue; - if (pObj->isA() == AecDbEwPipe::desc()) - { - AecDbEwPipe *pPipe = AecDbEwPipe::cast(pObj.object()); - pcf_pipe_normal(pDb, pPipe, stream); - } - else if (pObj->isA() == AecDbEwFitting::desc()) - { - AecDbEwFitting *pFit = AecDbEwFitting::cast(pObj.object()); - pcf_fitting(pDb, pFit, stream); - } - else if (pObj->isA() == AecDbEwEquipment::desc()) - { - AecDbEwEquipment *pEqu = AecDbEwEquipment::cast(pObj.object()); - pcf_ewEquipment(pDb, pEqu, stream); - } - else if (pObj->isA() == AecDbXEquipment::desc()) - { - AecDbXEquipment *pXEqu = AecDbXEquipment::cast(pObj.object()); - pcf_xEquipment(pDb, pXEqu, stream); + WeldRec w; + w.pt = joints[j].pt; + w.bore = joints[j].dBore; + w.idA = nodes[joints[j].nA].id; + w.idB = nodes[joints[j].nB].id; + welds.push_back(w); } } -#ifndef NDEBUG - std::ofstream outFile(pszFile, std::ios::out | std::ios::binary); - if (outFile.is_open()) - { - outFile << stream.str(); - outFile.close(); - } -#endif + // Í·²¿(µ¥Î») + É豸¶¨Òå + ¹ÜÏßÒýÓà + ×é¼þ + º¸¿Ú + Ö§µõ¼Ü + PcfSheetCounts c; + writePcfSheet(out, pDb, (LPCTSTR)sSystem, ids, targets, hangers, (LPCTSTR)sSystem + , NULL, NULL, &welds, c); + + out.close(); + DELETE_PTR(pDb); + + acutPrintf(_T("\n¹ÜµÀϵͳ [%s]: Ö±¹Ü %d/%d, ¹Ü¼þ %d/%d, ·§ÃÅ/¸½¼þ %d/%d, É豸¶¨Òå %d/%d, º¸¿Ú %d/%d, Ö§µõ¼Ü %d/%d¡£") + , (LPCTSTR)sSystem, c.nPipeOk, c.nPipe, c.nFitOk, c.nFit, c.nEquOk, c.nEqu + , c.nEquDefOk, c.nEquDef, c.nWeldOk, c.nWeld, c.nSupOk, c.nSup); return true; } + +/* + ×Ô¶¯·Öͼ£º°ÑÒ»¸ö¹ÜµÀϵͳ²ð³É¶àÕÅ ISO ͼ£¬Ã¿ÕÅͼµ¼³öÒ»¸ö PCF Îļþ¡£ + ¼û pcf.h ÀïµÄ¹æÔò˵Ã÷¡£ +*/ +bool PCF::makePCFSplit(LPCTSTR pszDir, LPCTSTR pszSystem, int nMaxNodes, double dMaxSpan) +{ + // 1. ѡϵͳ + CString sSystem; + if (pszSystem && _tcslen(pszSystem) > 0) + { + sSystem = pszSystem; + } + else + { + std::vector systems; + collectSystems(systems); + if (systems.empty()) + { + acutPrintf(_T("\nͼֽÖÐδÕÒµ½ÈκιܵÀϵͳ(PIPE_PSYSTEM)!")); + return false; + } + sSystem = systems[0]; + } + + // 2. È¡¸ÃϵͳµÄÈ«²¿×é¼þ + AcDbObjectIdArray ids; + if (!getComponentBySystem(sSystem, ids)) + { + acutPrintf(_T("\n¹ÜµÀϵͳ [%s] ÏÂûÓÐ ¹ÜµÀ/¹Ü¼þ/É豸¡£"), (LPCTSTR)sSystem); + return false; + } + + // 3. ̽²â¿ÉÓõÄ"¹ÜºÅ"¼ü + acutPrintf(_T("\n---- ×Ô¶¯·Öͼ: ¹ÜµÀϵͳ [%s]£¬¹² %d ¸ö×é¼þ ----") + , (LPCTSTR)sSystem, ids.length()); + acutPrintf(_T("\nºòÑ¡¹ÜºÅ¼üµÄÌî³äÇé¿ö:")); + + std::vector > hists; + probeGroupKeys(ids, hists); + + LPCTSTR pszUseKey = NULL; + const int nKeys = (int)(sizeof(g_pszNoKeys) / sizeof(g_pszNoKeys[0])); + for (int k = 0; k < nKeys; ++k) + { + int nFilled = 0; + for (std::map::const_iterator it = hists[k].begin(); it != hists[k].end(); ++it) + nFilled += it->second; + + acutPrintf(_T("\n %-10s ÓÐÖµ %d/%d£¬È¡Öµ %d ÖÖ") + , g_pszNoKeys[k], nFilled, ids.length(), (int)hists[k].size()); + + // ¿ÉÓõķÖ×é¼ü£º¶àÊý×é¼þÓÐÖµ£¬ÇÒȡֵÊýÃ÷ÏÔÉÙÓÚ×é¼þÊý(·ñÔòµÈÓÚ°´Ã¿¸ù¹Ü·Ö×é) + if (!pszUseKey && nFilled * 2 >= ids.length() && !hists[k].empty() + && (int)hists[k].size() * 2 <= ids.length()) + pszUseKey = g_pszNoKeys[k]; + } + + if (pszUseKey) + acutPrintf(_T("\n²ÉÓ÷Ö×é¼ü: [%s]¡£"), pszUseKey); + else + acutPrintf(_T("\nδÕÒµ½¿ÉÓõĹܺżü(ȡֵ¹ýÓÚ·ÖÉ¢»òȫΪ¿Õ)£¬¸Ä°´Á¬Í¨×ÓÍø·Öͼ¡£")); + + // 4. ÏȰ´½Ó¿ÚÁ¬Í¨ÐÔ°ÑÕû¸öϵͳ²ð³ÉÁ¬Í¨×ÓÍø£¬ÔÙ°´×ÓÍøÄÚµÄ"¶àÊý¹ÜºÅ"¹é²¢³É¹ÜÏß×é¡£ + // ˳ÐòºÜÖØÒª£º·§ÃÅ/¸½¼þÕâÀ಻´ø¹ÜºÅµÄ×é¼þ±ØÐëÏÈ¿¿Á¬Í¨ÐԹ鵽ËüËùÔڵĹÜÏßÉÏ£¬ + // ·ñÔò»á±»µ¥¶À·Ö³öÈ¥(ʵ²â 97 ¸ö·§ÃÅ»á¸÷×Ô³ÉÒ»ÕÅͼ)¡£ + std::vector nets; + splitNetByConnectivity(ids, nets); + + std::map groups; + std::vector groupOrder; + for (size_t k = 0; k < nets.size(); ++k) + { + const CString sKey = dominantKey(nets[k], pszUseKey, (LPCTSTR)sSystem); + + if (groups.find(sKey) == groups.end()) + groupOrder.push_back(sKey); + + for (int i = 0; i < nets[k].length(); ++i) + groups[sKey].append(nets[k][i]); + } + + acutPrintf(_T("\n°´¹ÜºÅ¹é²¢Îª %d ¸ö¹ÜÏß×é¡£"), (int)groupOrder.size()); + + // 5. ×éÄÚ°´Í¼·ù¶þ´ÎÇзÖ(ͬһ¹ÜÏß×é¿ÉÄÜÓɶàÌõ»¥²»ÏàÁ¬µÄ×ÓÍø×é³É£¬¸÷×Ô³Éͼ) + struct SheetPlan + { + CString ref; // PIPELINE-REFERENCE(¹ÜºÅ) + AcDbObjectIdArray ids; + std::vector splits; + std::vector welds; + }; + std::vector plans; + + for (size_t gi = 0; gi < groupOrder.size(); ++gi) + { + const CString &sKey = groupOrder[gi]; + const AcDbObjectIdArray &groupIds = groups[sKey]; + + std::vector nodes; + std::vector joints; + std::vector splits; + + // ³¤Ö±¹Ü°´ dMaxSpan Ô¤ÇжΣ¬Ê¹"³¤Ö±¹ÜÖÐÐĵã"Ò²ÄܳÉΪÇеã + buildNetwork(groupIds, dMaxSpan, nodes, joints, splits); + + // µ¥ÕÅͼµÄÏÞÖÆ°´×é¼þ¸öÊý»»Ëãµ½½Úµã¸öÊý + const int nLimit = (nMaxNodes > 0) ? nMaxNodes : 0; + + std::vector > sheets; + splitBySize(nodes, joints, nLimit, dMaxSpan, sheets); + + // ½Úµã -> ͼºÅ + std::vector nodeSheet(nodes.size(), -1); + for (size_t s = 0; s < sheets.size(); ++s) + { + for (size_t t = 0; t < sheets[s].size(); ++t) + nodeSheet[sheets[s][t]] = (int)s; + } + + // º¸¿Ú°´ A ¶ËËùÔÚͼ¹éÊô(Á½¶Ë·ÖÊô²»Í¬Í¼Ê±¹é A ¶ËÄÇÕÅ£¬±£Ö¤È«ÏµÍ³Ö»³öÏÖÒ»´Î) + std::vector > sheetWelds(sheets.size()); + for (size_t j = 0; j < joints.size(); ++j) + { + if (!joints[j].bWeld) continue; + + int s = -1; + if (joints[j].nA >= 0 && joints[j].nA < (int)nodeSheet.size()) + s = nodeSheet[joints[j].nA]; + if (s < 0 && joints[j].nB >= 0 && joints[j].nB < (int)nodeSheet.size()) + s = nodeSheet[joints[j].nB]; + if (s < 0) continue; + + WeldRec w; + w.pt = joints[j].pt; + w.bore = joints[j].dBore; + w.idA = nodes[joints[j].nA].id; + w.idB = nodes[joints[j].nB].id; + sheetWelds[s].push_back(w); + } + + for (size_t s = 0; s < sheets.size(); ++s) + { + SheetPlan plan; + plan.ref = sKey; + plan.welds = sheetWelds[s]; + + // ½Úµã -> ×é¼þ(È¥ÖØ£¬±£³Ö˳Ðò) + for (size_t t = 0; t < sheets[s].size(); ++t) + { + const NetNode &nd = nodes[sheets[s][t]]; + if (plan.ids.find(nd.id) == -1) + plan.ids.append(nd.id); + } + + // Ö»±£Áô±¾Í¼Óõ½µÄÇжÎ(°´½Úµã¾«È·¶ÔÓ¦£¬±ÜÃâ°Ñ±ðÕÅͼµÄ¶Î´ø½øÀ´) + for (size_t t = 0; t < sheets[s].size(); ++t) + { + const int q = nodes[sheets[s][t]].nSplitIdx; + if (q < 0 || q >= (int)splits.size()) continue; + if (splits[q].t0 <= 0.0 && splits[q].t1 >= 1.0) continue; // δÇÐ + plan.splits.push_back(splits[q]); + } + + plans.push_back(plan); + } + } + + if (plans.empty()) + { + acutPrintf(_T("\nûÓпɵ¼³öµÄ·Öͼ¡£")); + return false; + } + + // 6. Éú³ÉͼºÅ²¢½¨Á¢"½Óͼֽ"Ó³É䣺 + // ÿ¸öÇеãÁ½²à¸÷дһÌõ"½Óͼֽ <¶Ô·½Í¼ºÅ>"£¬·½±ãÊ©¹¤Æ´Í¼¡£ + std::vector sheetCodes; + for (size_t s = 0; s < plans.size(); ++s) + { + CString sCode; + sCode.Format(_T("ISO-%03d"), (int)(s + 1)); + sheetCodes.push_back(sCode); + } + + // ͼºÅ -> ¸Ãͼ°üº¬µÄ×é¼þ + std::vector > sheetIds(plans.size()); + for (size_t s = 0; s < plans.size(); ++s) + { + for (int i = 0; i < plans[s].ids.length(); ++i) + sheetIds[s].push_back(plans[s].ids[i]); + } + + // Öð¶Ô¼ì²éÁ½ÕÅͼ֮¼äÊÇ·ñ´æÔÚ"¿çͼÁ¬½Ó"£ºA ͼij×é¼þµÄ½Ó¿ÚλÖÃÓë B ͼij×é¼þµÄ + // ½Ó¿ÚλÖÃÖØºÏ¼´ÈÏΪÕâÁ½ÕÅͼԭ±¾ÊǽÓÔÚÒ»ÆðµÄ£¬Á½²à»¥Ïàд"½Óͼֽ"±êʶ¡£ + // ÏȰѸ÷ͼµÄÁ¬½ÓµãËãºÃ£¬Ö®ºóÖ»ÊÇ´¿×ø±ê±È½Ï£¬²»ÔÙ·´¸´´ò¿ªÊµÌå¡£ + std::vector > sheetPts(plans.size()); + for (size_t s = 0; s < plans.size(); ++s) + collectSheetPoints(plans[s].ids, sheetPts[s]); + + std::vector > msgs; + { + const double dTol = netTolerance(); + + for (size_t a = 0; a < plans.size(); ++a) + { + for (size_t b = 0; b < plans.size(); ++b) + { + if (a == b) continue; + + CString sMsg; + sMsg.Format(_T("½Óͼֽ %s"), (LPCTSTR)sheetCodes[b]); + + // Ò»¶Ôͼ֮¼ä¿ÉÄÜÓкü¸´¦Çз죬Ö𴦶¼±ê£¬²»ÄÜÖ»±êµÚÒ»´¦ + std::vector hits; + for (size_t x = 0; x < sheetPts[a].size(); ++x) + { + for (size_t y = 0; y < sheetPts[b].size(); ++y) + { + if (sheetPts[a][x].pt.distanceTo(sheetPts[b][y].pt) > dTol) continue; + + const AcDbObjectId &idHit = sheetPts[a][x].id; + bool bDup = false; + for (size_t k = 0; k < hits.size(); ++k) + { + if (hits[k] == idHit) { bDup = true; break; } + } + if (!bDup) hits.push_back(idHit); + break; // ±¾Á¬½ÓµãÒÑÅäÉÏ£¬»»ÏÂÒ»¸ö + } + } + + for (size_t k = 0; k < hits.size(); ++k) + msgs.push_back(std::make_pair(hits[k], sMsg)); + } + } + } + + // 7. Êä³öĿ¼ + CString sDir = (pszDir && _tcslen(pszDir) > 0) ? pszDir : _T(""); + if (sDir.IsEmpty()) + { + CString sPath = makeDefaultPcfPath((LPCTSTR)sSystem); + const int nPos = sPath.ReverseFind(_T('\\')); + sDir = (nPos >= 0) ? sPath.Left(nPos) : _T(""); + } + if (!sDir.IsEmpty() && sDir[sDir.GetLength() - 1] != _T('\\')) + sDir += _T("\\"); + + // 8. Ö§µõ¼Ü(ȫͼÊÕ¼¯Ò»´Î£¬Öðͼ°´¿Õ¼ä¾Í½ü¹éÊô) + std::vector targets; + collectSupportTargets(targets); + + std::vector hangers; + collectPipeHangers(hangers); + + // 9. ÖðͼдÎļþ + CUIISQLiteServer *pDb = new CUIISQLiteServer; + if (!pDb->InitADOServer(FilePath::GetSysDir() + _T("\\Plumbing.db"))) + { + AfxMessageBox(_T("Êý¾Ý¿âÇý¶¯¼ÓÔØÊý¾Ý¿âPlumbing.dbʧ°Ü!½«Ö»µ¼³ö¼¸ºÎ¹Ç¼Ü¡£")); + DELETE_PTR(pDb); + pDb = NULL; + } + + int nOk = 0; + for (size_t s = 0; s < plans.size(); ++s) + { + CString sFile; + sFile.Format(_T("%s%s_%s.pcf") + , (LPCTSTR)sDir + , (LPCTSTR)sheetCodes[s] + , (LPCTSTR)sanitizeFileName(plans[s].ref)); + + std::ofstream out((LPCTSTR)sFile, std::ios::binary); + if (!out.good()) + { + acutPrintf(_T("\n·Öͼ %s ÎÞ·¨Ð´Èë: %s"), (LPCTSTR)sheetCodes[s], (LPCTSTR)sFile); + continue; + } + + // ±¾Í¼Ïà¹ØµÄ½Óͼ±êʶ + std::vector > sheetMsgs; + for (size_t m = 0; m < msgs.size(); ++m) + { + for (size_t i = 0; i < sheetIds[s].size(); ++i) + { + if (msgs[m].first == sheetIds[s][i]) + { + sheetMsgs.push_back(msgs[m]); + break; + } + } + } + + PcfSheetCounts c; + writePcfSheet(out, pDb, (LPCTSTR)plans[s].ref, plans[s].ids, targets, hangers + , (LPCTSTR)sSystem, &plans[s].splits, &sheetMsgs, &plans[s].welds, c); + out.close(); + + ++nOk; + acutPrintf(_T("\n %s -> %s (Ö±¹Ü %d, ¹Ü¼þ %d, ·§ÃÅ/¸½¼þ %d, É豸¶¨Òå %d, º¸¿Ú %d, Ö§µõ¼Ü %d)") + , (LPCTSTR)sheetCodes[s], (LPCTSTR)sFile + , c.nPipeOk, c.nFitOk, c.nEquOk, c.nEquDefOk, c.nWeldOk, c.nSupOk); + } + + DELETE_PTR(pDb); + + acutPrintf(_T("\n×Ô¶¯·ÖͼÍê³É: ϵͳ [%s] ¹²Êä³ö %d ÕÅͼ£¬Ä¿Â¼ %s") + , (LPCTSTR)sSystem, nOk, (LPCTSTR)sDir); + + return nOk > 0; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// ĬÈÏÊä³ö·¾¶£ºÍ¼Ö½ËùÔÚĿ¼\<ϵͳÃû>.pcf£»Í¼Ö½Î´±£´æÊ±ÍË»ØÏµÍ³Ä¿Â¼ +static CString makeDefaultPcfPath(LPCTSTR pszSystem) +{ + CString sSys = (pszSystem && _tcslen(pszSystem) > 0) ? pszSystem : _T("PCF"); + CString sPath; + + const TCHAR *pszDwg = NULL; + acdbCurDwg()->getFilename(pszDwg); + if (pszDwg && _tcslen(pszDwg) > 0) + { + sPath = pszDwg; + int nPos = sPath.ReverseFind(_T('\\')); + if (nPos < 0) nPos = sPath.ReverseFind(_T('/')); + sPath = (nPos >= 0) ? sPath.Left(nPos + 1) : _T(""); + } + + if (sPath.IsEmpty()) + sPath = FilePath::GetSysDir() + _T("\\"); + + sPath += sSys; + sPath += _T(".pcf"); + return sPath; +} + +// ÃüÁ°´¹ÜµÀϵͳµ¼³ö PCF ÖмäÎļþ +// ½»»¥Ó÷¨£ºEW_PCF -> Áгöϵͳ -> ÊäÈëϵͳ(¿É¿Õ=×Ô¶¯È¡µÚÒ»¸ö) -> ÊäÈëÊä³ö·¾¶(¿É¿Õ=²ÉÓÃĬÈÏ·¾¶) +// ·Ç½»»¥Ó÷¨£ºEW_PCF + Á½´Î»Ø³µ£¬¼´×Ô¶¯Ñ¡È¡µÚÒ»¸öϵͳ²¢µ¼³öµ½Ä¬ÈÏ·¾¶£¬²»»á¹ÒÆðµÈ´ýÊäÈë¡£ +void EW_PCFCmdFnc() +{ + // 1. ÁгöͼֽÖÐÏÖÓеĹܵÀϵͳ£¬·½±ãÑ¡Ôñ + std::vector systems; + collectSystems(systems); + if (!systems.empty()) + { + acutPrintf(_T("\nͼֽÖеĹܵÀϵͳ¹² %d ¸ö:"), (int)systems.size()); + for (size_t k = 0; k < systems.size(); ++k) + acutPrintf(_T("\n [%d] %s"), (int)(k + 1), (LPCTSTR)systems[k]); + } + else + { + acutPrintf(_T("\nδÕÒµ½¹ÜµÀϵͳ(PIPE_PSYSTEM)£¬½«ÎÞ·¨µ¼³ö¡£")); + } + + // 2. ÊäÈëϵͳ(¿É¿Õ=×Ô¶¯È¡µÚÒ»¸ö) + TCHAR szSys[256] = { 0 }; + if (acedGetString(FALSE, _T("\nÇëÊäÈë¹ÜµÀϵͳ<Ö±½Ó»Ø³µ=×Ô¶¯Ñ¡È¡µÚÒ»¸ö>: "), szSys) != RTNORM) + return; + CString sSystem = szSys; + + // Áô¿Õʱֱ½ÓÈ¡µÚÒ»¸öϵͳ£¬±ãÓÚĬÈÏÎļþÃû´øÉÏϵͳÃû + if (sSystem.IsEmpty() && !systems.empty()) + sSystem = systems[0]; + + // 3. Êä³ö·¾¶£ºÏÈËã³öĬÈÏÖµ²¢ÏÔʾ£¬Ö±½Ó»Ø³µ¼´²ÉÓÃĬÈÏ£¬±ÜÃâ·Ç½»»¥µ÷ÓÃʱ¹ÒÆðµÈ´ý + CString sDef = makeDefaultPcfPath(sSystem.IsEmpty() ? NULL : (LPCTSTR)sSystem); + CString sPrompt; + sPrompt.Format(_T("\nÇëÊäÈëÊä³öµÄPCFÎļþÍêÕû·¾¶<Ö±½Ó»Ø³µ²ÉÓÃĬÈÏ: %s>: "), (LPCTSTR)sDef); + + TCHAR szFile[512] = { 0 }; + if (acedGetString(FALSE, sPrompt, szFile) != RTNORM) + return; + CString sFile = szFile; + if (sFile.IsEmpty()) + sFile = sDef; + + // 4. µ¼³ö + LPCTSTR pszSys = sSystem.IsEmpty() ? NULL : (LPCTSTR)sSystem; + if (PCF::makePCF(sFile, pszSys)) + acutPrintf(_T("\nPCFµ¼³ö³É¹¦: %s"), (LPCTSTR)sFile); + else + acutPrintf(_T("\nPCFµ¼³öʧ°Ü!Çë¼ì²é¹ÜµÀϵͳÏÂÊÇ·ñ´æÔÚ ¹ÜµÀ/¹Ü¼þ/É豸¡£")); +} + +// ÃüÁ×Ô¶¯·Öͼ ¡ª¡ª °ÑÒ»¸ö¹ÜµÀϵͳ×Ô¶¯²ð³É¶àÕÅ ISO ͼ(ÿÕÅͼһ¸ö PCF Îļþ) +// ²ð·Ö¹æÔò¼û PCF::makePCFSplit()¡£È«²¿Ìáʾֱ½Ó»Ø³µ¼´²ÉÓÃĬÈÏÖµ£¬±ãÓڷǽ»»¥µ÷Óᣠ+void EW_PCFSPLITCmdFnc() +{ + // 1. ÁгöͼֽÖÐÏÖÓеĹܵÀϵͳ + std::vector systems; + collectSystems(systems); + if (!systems.empty()) + { + acutPrintf(_T("\nͼֽÖеĹܵÀϵͳ¹² %d ¸ö:"), (int)systems.size()); + for (size_t k = 0; k < systems.size(); ++k) + acutPrintf(_T("\n [%d] %s"), (int)(k + 1), (LPCTSTR)systems[k]); + } + else + { + acutPrintf(_T("\nδÕÒµ½¹ÜµÀϵͳ(PIPE_PSYSTEM)£¬½«ÎÞ·¨·Öͼ¡£")); + } + + // 2. ¹ÜµÀϵͳ + TCHAR szSys[256] = { 0 }; + if (acedGetString(FALSE, _T("\nÇëÊäÈëÒª·ÖͼµÄ¹ÜµÀϵͳ<Ö±½Ó»Ø³µ=×Ô¶¯Ñ¡È¡µÚÒ»¸ö>: "), szSys) != RTNORM) + return; + CString sSystem = szSys; + if (sSystem.IsEmpty() && !systems.empty()) + sSystem = systems[0]; + + // 3. µ¥ÕÅͼ×î´ó×é¼þÊý(³¬¹ýÔò¼ÌÐøÇзÖ) + TCHAR szNum[64] = { 0 }; + if (acedGetString(FALSE, _T("\nÇëÊäÈëµ¥ÕÅͼ×î´ó×é¼þÊý<Ö±½Ó»Ø³µ=60£¬0=²»ÏÞÖÆ>: "), szNum) != RTNORM) + return; + int nMaxNodes = 60; + if (_tcslen(szNum) > 0) nMaxNodes = _ttoi(szNum); + + // 4. µ¥ÕÅͼ×î´ó¿Õ¼ä¿ç¶È(³¬¹ýÔòÔÚ³¤Ö±¹ÜÖеã¼ÌÐøÇзÖ) + TCHAR szSpan[64] = { 0 }; + if (acedGetString(FALSE, _T("\nÇëÊäÈëµ¥ÕÅͼ×î´ó¿Õ¼ä¿ç¶È<Ö±½Ó»Ø³µ=0£¬±íʾ²»ÏÞÖÆ>: "), szSpan) != RTNORM) + return; + double dMaxSpan = 0.0; + if (_tcslen(szSpan) > 0) dMaxSpan = _ttof(szSpan); + + // 5. Êä³öĿ¼£ºÄ¬ÈÏȡͼֽËùÔÚĿ¼ + CString sDefDir; + { + CString sDef = makeDefaultPcfPath(sSystem.IsEmpty() ? NULL : (LPCTSTR)sSystem); + const int nPos = sDef.ReverseFind(_T('\\')); + sDefDir = (nPos >= 0) ? sDef.Left(nPos) : _T(""); + } + + CString sPrompt; + sPrompt.Format(_T("\nÇëÊäÈë·ÖͼÊä³öĿ¼<Ö±½Ó»Ø³µ=ͼֽËùÔÚĿ¼: %s>: "), (LPCTSTR)sDefDir); + TCHAR szDir[512] = { 0 }; + if (acedGetString(FALSE, sPrompt, szDir) != RTNORM) + return; + CString sDir = szDir; + if (sDir.IsEmpty()) sDir = sDefDir; + + // 6. ·Öͼµ¼³ö + LPCTSTR pszSys = sSystem.IsEmpty() ? NULL : (LPCTSTR)sSystem; + if (PCF::makePCFSplit(sDir, pszSys, nMaxNodes, dMaxSpan)) + acutPrintf(_T("\n×Ô¶¯·ÖͼÍê³É¡£")); + else + acutPrintf(_T("\n×Ô¶¯·Öͼʧ°Ü!Çë¼ì²é¹ÜµÀϵͳÏÂÊÇ·ñ´æÔÚ ¹ÜµÀ/¹Ü¼þ/É豸¡£")); +} diff --git a/SourceCode/Code2026/CoreCommand/pcf.h b/SourceCode/Code2026/CoreCommand/pcf.h index da49198..7e0edef 100644 --- a/SourceCode/Code2026/CoreCommand/pcf.h +++ b/SourceCode/Code2026/CoreCommand/pcf.h @@ -1,6 +1,31 @@ #pragma once +// PCF (Piping Component File) µ¼³ö¡£ +// µ±Ç°½×¶Î£º°´¡°¹ÜµÀϵͳ¡±ÊÕ¼¯ ¹ÜµÀ/¹Ü¼þ/É豸 ²¢Êä³ö PCF ÖмäÎļþ£¬ +// ¹© Isogen / ×ÔÑÐ isoAlgo / µÚÈý·½Èí¼þÉú³É ISO ͼʹÓᣠclass PCF { +public: + // °´¹ÜµÀϵͳ(PIPE_PSYSTEM)µ¼³ö PCF Îļþ¡£ + // pszFile : Êä³öµÄ .pcf ÎļþÍêÕû·¾¶ + // pszSystem : ¹ÜµÀϵͳÃû£¬¶ÔӦʵÌåרҵÊý¾ÝÀïµÄ PIPE_SYS£» + // ´«Èë¿Õ(NULL »ò¿Õ´®)ʱ×Ô¶¯Ñ¡È¡Í¼Ö½ÖеĵÚÒ»¸ö¹ÜµÀϵͳ¡£ static bool makePCF(LPCTSTR pszFile, LPCTSTR pszSystem); + + // ×Ô¶¯·Öͼ£º°ÑÒ»¸ö¹ÜµÀϵͳ²ð³É¶àÕÅ ISO ͼ£¬Ã¿ÕÅͼµ¼³öÒ»¸ö PCF Îļþ¡£ + // + // ²ð·Ö¹æÔò(°´×¨Òµ³öͼ¹ßÀý)£º + // 1) ÏȰ´"¹ÜºÅ"·Ö×飬ͬһ¹ÜºÅ¹éÒ»×é(¹ÜºÅÈ¡²»µ½Ê±Õûϵͳ×÷Ϊһ×é)£» + // 2) ×éÄÚ°´¹ÜµÀÁ¬Í¨ÐÔ(½Ó¿ÚÏà½Ó)ÔÙ²ð³ÉÈô¸ÉÁ¬Í¨×ÓÍø£» + // 3) ×ÓÍøÈôÈÔ³¬¹ý nMaxNodes ¸ö×é¼þ¡¢»ò¿Õ¼ä¿ç¶È³¬¹ý dMaxSpan£¬ + // ÑØ¹ÜÏß×ßÏòÀÛ¼Ó×é¼þ£¬³¬ÏÞʱ»ØÍ˵½×î½üµÄ"ÓÅÏÈÇеã"ÔÙÇУº + // ÓÅÏÈÇеã = ·¨À¼Ãæ(eFlange) > ÏÖ³¡º¸·ì(Á½¹Ü¼þº¸½ÓÏàÁ¬) > ÆÕͨ½Ó¿Ú + // Ö»ÔÚ×é¼þÖ®¼äµÄ½Ó¿Ú´¦ÇУ¬Òò´Ë¾ø²»»áÇÐÔÚÍäÍ·/ÈýͨÄÚ²¿£» + // 4) ÿ¸öÇеãÁ½²à»¥ÏàдÈë"½Óͼֽ <¶Ô·½Í¼ºÅ>"µÄ½ÓÐø±êʶ£¬±ãÓÚÊ©¹¤Æ´Í¼¡£ + // + // pszDir : Êä³öĿ¼£¬¿ÕʱÓÃͼֽËùÔÚĿ¼ + // pszSystem : ¹ÜµÀϵͳÃû£¬¿ÕʱȡͼֽÖеÚÒ»¸ö¹ÜµÀϵͳ + // nMaxNodes : µ¥ÕÅͼ×î´ó×é¼þÊý£¬<=0 ±íʾ²»ÏÞÖÆ + // dMaxSpan : µ¥ÕÅͼ×î´ó¿Õ¼ä¿ç¶È(ͼֽµ¥Î»)£¬<=0 ±íʾ²»ÏÞÖÆ + static bool makePCFSplit(LPCTSTR pszDir, LPCTSTR pszSystem, int nMaxNodes, double dMaxSpan); }; diff --git a/iso需求讨论.txt b/iso需求讨论.txt new file mode 100644 index 0000000..261c27d --- /dev/null +++ b/iso需求讨论.txt @@ -0,0 +1,6 @@ +现在需è¦�在corecommand工程添加一个新功能:管é�“çš„ISO图,具体你å�¯ä»¥å�‚考网络上的isogen软件. +这个功能最主è¦�的是实现isoAlgo (piping Isometric Algorithm) 算法. 现在国内的pipeCAD实现了一个 isoAlgo算法. +我现在有方案: +1.自己开å�‘isoalgo算法,结å�ˆçŽ°æœ‰çš„ç®¡é�“系统,实现iso图功能 +2.把管é�“,管件,设备数æ�®,ä¿�存为 pcf 文件,用 AutoCAD Plant 3D 内的 PNPIso.exe æ�¥ç”Ÿæˆ�.æ�®è¯´è¿™ä¸ªexeå�¯ä»¥å…�费用. +你的看法是什么? \ No newline at end of file