#include "StdAfx.h" #include "pcf.h" #include "uiiado.h" #include "base64.h" #include "coretools.h" #include "aecdbewpipe.h" #include "aecdbewfitting.h" #include "aecdbewequipment.h" #include "aecdbxequipment.h" #include #include #include using namespace std; namespace { typedef const wchar_t *STR_PTR; typedef pair STR_PAIR; typedef map STR_MAP; // 定义属性字符串,避免直接输入造成笔误,用到那个,定义哪个 // ========================================== // 1. 基础单位 (Units) // ========================================== STR_PTR PCF_UNITS_MM = L"MM"; STR_PTR PCF_UNITS_METER = L"METER"; STR_PTR PCF_UNITS_INCH = L"INCH"; STR_PTR PCF_UNITS_FEET = L"FEET"; STR_PTR PCF_UNITS_INCH_SIXTEENTH = L"INCH-SIXTEENTH"; STR_PTR PCF_UNITS_MM_HUNDREDTHS = L"MM-HUNDREDTHS"; STR_PTR PCF_UNITS_DEGREES = L"DEGREES"; STR_PTR PCF_UNITS_RADIANS = L"RADIANS"; STR_PTR PCF_UNITS_KGS = L"KGS"; STR_PTR PCF_UNITS_LBS = L"LBS"; STR_PTR PCF_UNITS_NM = L"NM"; STR_PTR PCF_UNITS_LBFT = L"LBFT"; // ========================================== // 2. 全局头部属性 (Header Attributes) // ========================================== STR_PTR PCF_HEAD_ISOGEN_FILES = L"ISOGEN-FILES"; STR_PTR PCF_HEAD_UNITS_BORE = L"UNITS-BORE"; STR_PTR PCF_HEAD_UNITS_CO_ORDS = L"UNITS-CO-ORDS"; STR_PTR PCF_HEAD_UNITS_BOLT_DIA = L"UNITS-BOLT-DIA"; STR_PTR PCF_HEAD_UNITS_BOLT_LENGTH = L"UNITS-BOLT-LENGTH"; STR_PTR PCF_HEAD_UNITS_WEIGHT = L"UNITS-WEIGHT"; STR_PTR PCF_HEAD_PIPELINE_REFERENCE = L"PIPELINE-REFERENCE"; STR_PTR PCF_HEAD_PIPING_SPEC = L"PIPING-SPEC"; STR_PTR PCF_HEAD_REVISION = L"REVISION"; STR_PTR PCF_HEAD_PROJECT_IDENTIFIER = L"PROJECT-IDENTIFIER"; STR_PTR PCF_HEAD_SYSTEM_IDENTIFIER = L"SYSTEM-IDENTIFIER"; // ========================================== // 3. 组件主类型 (Component Types) - 增加前缀 COMP_ 以防命名冲突 // ========================================== STR_PTR PCF_COMP_PIPE = L"PIPE"; STR_PTR PCF_COMP_ELBOW = L"ELBOW"; STR_PTR PCF_COMP_TEE = L"TEE"; STR_PTR PCF_COMP_CROSS = L"CROSS"; STR_PTR PCF_COMP_REDUCER = L"REDUCER"; STR_PTR PCF_COMP_VALVE = L"VALVE"; STR_PTR PCF_COMP_FLANGE = L"FLANGE"; STR_PTR PCF_COMP_GASKET = L"GASKET"; 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_INSTRUMENT = L"INSTRUMENT"; STR_PTR PCF_COMP_SUPPORT = L"SUPPORT"; STR_PTR PCF_COMP_EQUIPMENT = L"EQUIPMENT"; // ========================================== // 4. 坐标与节点类型 (Point Types) // ========================================== STR_PTR PCF_PT_END_POINT = L"END-POINT"; STR_PTR PCF_PT_CENTRE_POINT = L"CENTRE-POINT"; STR_PTR PCF_PT_BRANCH1_POINT = L"BRANCH1-POINT"; STR_PTR PCF_PT_BRANCH2_POINT = L"BRANCH2-POINT"; STR_PTR PCF_PT_CO_ORDS = L"CO-ORDS"; // ========================================== // 5. 组件明细与业务属性 (Component Attributes) // ========================================== STR_PTR PCF_ATTR_SKEY = L"SKEY"; STR_PTR PCF_ATTR_ITEM_CODE = L"ITEM-CODE"; STR_PTR PCF_ATTR_ITEM_DESCRIPTION = L"ITEM-DESCRIPTION"; STR_PTR PCF_ATTR_MATERIAL_IDENTIFIER = L"MATERIAL-IDENTIFIER"; STR_PTR PCF_ATTR_WEIGHT = L"WEIGHT"; STR_PTR PCF_ATTR_WALL_THICKNESS = L"WALL-THICKNESS"; STR_PTR PCF_ATTR_RATING = L"RATING"; STR_PTR PCF_ATTR_FABRICATION_ITEM = L"FABRICATION-ITEM"; STR_PTR PCF_ATTR_ERECTION_ITEM = L"ERECTION-ITEM"; STR_PTR PCF_ATTR_SPINDLE_DIRECTION = L"SPINDLE-DIRECTION"; STR_PTR PCF_ATTR_MESSAGE_TEXT = L"MESSAGE-TEXT"; class PcfRow { public: private: ostream &m_out; // 统一使用窄字符流基类! bool m_isFirstItem; public: PcfRow(ostream &outStream, int numOfSpace) : m_out(outStream), m_isFirstItem(true) { for (int i = 0; i < numOfSpace; ++i) m_out << " "; } ~PcfRow() { m_out << "\n"; } // 1. 基础类型模板 (如 int, double, AcGePoint3d) template PcfRow &operator<<(const T &value) { if (!m_isFirstItem) m_out << " "; m_out << fixed << setprecision(4) << value; m_isFirstItem = false; return *this; } // 3. 核心升级:拦截 AutoCAD 宽字符 (处理带中文的描述信息) PcfRow &operator<<(STR_PTR wValue) { if (!m_isFirstItem) m_out << " "; // 自动转为 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) && (wcslen(attri) > 0 && wcslen(svalue) > 0)) { *this<< attri << svalue; } return *this; } }; 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(out, indent) << attri << svalue; } STR_PAIR makePair(STR_PTR field, STR_PTR v) { return make_pair(field, v); } template STR_PAIR makePair(STR_PTR field, T &v, const int &prec = 0) { std::wstringstream wss; wss << fixed << setprecision(prec) << v; return makePair(field, wss.str()); } wstring getValue(STR_MAP mm, STR_PTR key) { STR_MAP::const_iterator it(mm.find(key)); if (it != mm.end()) return it->second; return L""; } // level 等级 // 通过 level在 AecSpecname 里面查询 行业 // 通过 等级、行业在table内查询 fileds bool getSpecFieldByLevel(CUIISQLiteServer *pDb , STR_PTR table , STR_PTR level , const STR_MAP &filter , STR_MAP &results) { if (!pDb || !level || !table || !filter.empty()) return 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) { wss << L" AND t.["<< itF->first << L"] = '" << itF->second << L"'"; } 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(); } /* pcf 文件头 */ bool pcf_begin(std::ostream &out, STR_PTR pipeline_reference , STR_PTR spec , 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 weight = PCF_UNITS_KGS ) { if (!out.good()) return false; PcfRow(out, 0) << PCF_HEAD_ISOGEN_FILES << isogen_files; PcfRow(out, 0) << PCF_HEAD_UNITS_BORE << bore; PcfRow(out, 0) << PCF_HEAD_UNITS_CO_ORDS << co_ords; 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; PcfRow(out, 0) << PCF_HEAD_PIPELINE_REFERENCE << pipeline_reference; PcfRow(out, 4) << PCF_HEAD_PIPING_SPEC << spec; return true; } /* * ================================================================================= * [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) : 预制/现场安装标识。不带值(直接写属性名),表示这是一根工厂预制管。 * ================================================================================= */ // 处理普通管道,非法兰管道 wstring getItemCode(AecDbEwPipe *pPipe) { return L""; } wstring getDescription(AecDbEwPipe *pPipe) { return L""; } 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) { if (!pPipe || !out.good()) return false; AcGePoint3d ptStart = pPipe->StartPoint(); AcGePoint3d ptEnd = pPipe->EndPoint(); double bore(.0); if (!pPipe->GetAt(PIPE_DN, bore)) return false; double thickness(.0); if (!pPipe->GetAt(PIPE_THICK, thickness)) return false; CString level(_T("")); pPipe->GetAt(PIPE_LEVEL, level); // 写入组件主类标 (顶格,无缩进) PcfRow(out, 0) << PCF_COMP_PIPE; // 写入起止坐标与管径 (必须紧跟在 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; // 等级管线 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 { } // 预制管件 PcfRow(out, 4) << PCF_ATTR_FABRICATION_ITEM; out << L"\n"; return true; } bool pcf_ewEquipment(CUIISQLiteServer *pDb, AecDbEwEquipment *pEqu, std::ostream &out) { return false; } 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) { if (!pFit || !pDb) return false; int nType(0); if (!pFit->GetAt(KEY_RUNTIME, nType)) return false; 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); case eReduce: return pcf_Reduce(pDb, pFit, out); case eLateral: return pcf_Lateral(pDb, pFit, out); case eFlange: return pcf_Flange(pDb, pFit, out); 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); default: break; } return false; } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 对外只暴露这一个接口 // pszSystem代表管道系统,可以通过这个参数得到此系统下的所有管道、管件、设备,并输出到pcf bool PCF::makePCF(LPCTSTR pszFile, LPCTSTR pszSystem) { CString dbPath(FilePath::GetSysDir() + _T("\\Plumbing.db")); CUIISQLiteServer *pDb = new CUIISQLiteServer; if (!pDb->InitADOServer(dbPath)) { AfxMessageBox(_T("数据库驱动加载数据库Plumbing.db失败!")); DELETE_PTR(pDb); return false; } AcDbObjectIdArray ids; // 得到 pszSystem 的所有管道、管件、设备 // GetComponentBySystem(pszSystem, ids); if (ids.isEmpty()) return false; #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) { AcDbObjectId &id(ids[i]); AcDbObjectPointer pObj(id, AcDb::kForRead); if (pObj.openStatus() != Acad::eOk) 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); } } #ifndef NDEBUG std::ofstream outFile(pszFile, std::ios::out | std::ios::binary); if (outFile.is_open()) { outFile << stream.str(); outFile.close(); } #endif return true; }