Files
envi-code/SourceCode/Code2026/CoreCommand/pcf.cpp
T
2026-09-28 15:28:50 +08:00

529 lines
16 KiB
C++

#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 <ostream>
#include <string>
#include <iomanip>
using namespace std;
namespace
{
typedef const wchar_t *STR_PTR;
typedef pair<wstring, wstring> STR_PAIR;
typedef map<wstring, wstring> 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 <typename T>
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 <typename T>
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<CString, CString> res;
pDb->GetSelData(wss.str().c_str(), res);
map<CString, CString>::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<wstring, wstring> 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<AcDbObject> 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;
}