Files
envi-code/SourceCode/Code2026/Pool3dCmd/paraDesignDlg.cpp
T
company-desktop d6614a44d5 feat: 阀门插入——参数化阀门 + 定制阀门(两种都做成 MCP 工具)
一、参数化阀门(P3_CR* 19 个命令)
命令链:P3_CRZF -> initParamPipeValveJsonData("闸阀") -> PL_wValveEx("闸阀",…,false)
-> startForPipeValve(...) -> 里面 dlg.DoModal()(弹"参数化设计"对话框)-> start2Ptr。
产品自己是 LoadLibrary + GetProcAddress 调 pool3dcmd.arx 导出的 startForPipeValve,
所以我们也照做,但用新增的无界面版 startForPipeValveNoUI(不 DoModal)。

Pool3dCmd 里两处小改造(不改原命令行为):
1. 把 startForPipeValve 里"DoModal 之前"的准备逻辑抽成 PreparePipeValveDlg(..., bSilent),
   有界面/无界面共用;bSilent=true 时不弹 AfxMessageBox(MCP 里弹框会卡死调用方)。
2. 把"点确定"里填 m_datas/m_Bims 的那段抽成 CParaDesignDlg::BuildDatas(),
   无界面版在 start2Ptr 之前也调一次 —— VALVE::start2Ptr 里 getDatasByDlg 读的就是 m_datas,
   不填直接返回 NULL(这是第一版失败的真因)。

二、定制阀门(PL_CR* 20+ 命令)
不搬代码:照命令的做法查 sys/Aec3DMep.db -> aec_class(类别) -> aec_package(name like %DN<n>%)
-> select package 的 blob 落成临时 .equ -> AecDbEwEquipment::ReadFromFile。
注意 Aec_Class.Class 存的是多级路径(如 "管路附件\闸阀"),要用
class='<类别>' or class like '%\<类别>' 匹配末级,用等号查不到(第一版就栽在这)。

三、共同部分
SetInsert(pt, vtDir)(给 pipe 时位置投影到管轴、朝向取管轴)+ 图层 LAY_PIPE_OUTSIDE
+ 专业数据记 KEY_ASSOIC(所在管线) 与 PIPE_SYS(跟管线)。

工程改动:cad_mcp_aec 的 cmakelists 补链 sqliteserver(CUIISQLiteServer 要用,
CoreCommand 链了但不传递);源文件里先 #include "uiiado.h" 定义 TGADOSRV_API。

实测(R230 Debug,空图,DN100 给水管):
- 参数化闸阀 -> 31F
- 定制闸阀 -> 320,库里取到 Z45X(RVHX)弹性座封楔式闸阀DN100
工具总数 95 -> 97(本插件 67 -> 69),R230/Z2026 都编过。

限制:还没做插入时的"断管+法兰对接"(命令里的 InsertValAtInfPos 约 150 行),
阀门只是摆在管线上的位置与方向,管段不会自动断开。
2026-10-31 12:54:13 +08:00

1191 lines
29 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "stdafx.h"
#include "compare_double.h"
#include "io.h"
#include "AecDbParamEquipment.h"
#include "AecDbXEquipment.h"
#include "AecDbEwEquipment.h"
#include "paraDesignDlg.h"
#include "CoreTools.h"
#include "KTCADUtilityEx.h"
#include "KTCADUtility.h"
#include "AecDbEwPipe.h"
#include <math.h>
#include "aecdbrivergroove.h"
#include "AecDbFlume.h"
#include "AecDbWeir.h"
#include "EquInsDirJig.h"
#include "AecDbXBG.h"
#include "ParamEquJson.h"
#include "AecDbMultiPartEntity.h"
#pragma warning(disable:4005)
#define JSON_FILE _T("\\paraDesign.json")
#define VALVE_JSON_PATH _T("\\valveSize.json")
namespace
{
bool checkValue(const CEquJsonObject::Param &para, LPCTSTR value, CString &errMsg)
{
if (!value) return false;
CString v(value);
if (para._type == _T("float"))
{
if (!CoreTools::isDigitString<double>(v))
{
errMsg.Format(_T("请输入一个数字!"), para._min, para._max);
return false;
}
double d(TypeConvert::s2f(v));
if (COMPARE_DOUBLE::upequal(d, para._max) || COMPARE_DOUBLE::downequal(d, para._min))
{
errMsg.Format(_T("数值不符合要求!应大于%.3f小于%.3f。"), para._min, para._max);
return false;
}
return true;
}
return true;
}
CEquJsonObject* getJsonObjByEnt(AcDbObjectId &id)
{
CEquJsonObject *pObj(NULL);
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDbEntity, pEnt)
{
if (!pEnt) return pObj;
AecDbParamEquipment *pEqu(AecDbParamEquipment::cast(pEnt));
AecDbWeir *pFlume(AecDbWeir::cast(pEnt));
AecDbRiverGroove *pRG(AecDbRiverGroove::cast(pEnt));
AecDbXEquipment *pXEqu(AecDbXEquipment::cast(pEnt));
AecDbEwEquipment *pEwEqu(AecDbEwEquipment::cast(pEnt));
AecDbXBG *pXBG(AecDbXBG::cast(pEnt));
AecDbMultiPartEntity *pMulEnt(AecDbMultiPartEntity::cast(pEnt));
CString json;
if (pEqu) pEqu->GetSrcString(json);
else if (pFlume) pFlume->GetSrcString(json);
else if (pRG) pRG->GetSrcString(json);
else if (pXEqu) pXEqu->GetSrcString(json);
else if (pXBG) pXBG->GetSrcString(json);
else if (pEwEqu)
{
pEwEqu->GetSpecialtyData()->GetAt(_T("_SRC_STRING_"), json);
}
else if (pMulEnt)
{
pMulEnt->GetAt(_T("_SRC_STRING_"), json);
}
else return pObj;
if (json.IsEmpty()) return pObj;
CString type, subtype;
WDocument doc;
SHJson::string2Json(json, doc);
MCIt it1 = doc.MemberBegin();
if (it1 == doc.MemberEnd()) return pObj;
type = it1->name.GetString();
MCIt it2 = it1->value.MemberBegin();
if (it2 == it1->value.MemberEnd()) return pObj;
subtype = it2->name.GetString();
pObj = CEquJsonObject::createParamEqu(type, subtype);
if (!pObj) return pObj;
ParseJson::readObject(it2->value, *pObj);
pObj->_bInplace = true;
}
OPENOBJ_END()
return pObj;
}
bool GetValveInsSizeByLevel(LPCTSTR pszName
, double dn
, const AecDbObjXDataMap *pSrcData
, std::map<CString, CString> &data)
{
typedef bool(_cdecl *func_GetValveInsSizeByLevel)(
LPCTSTR
, double
, const AecDbObjXDataMap*
, std::map<CString, CString>&);
#ifndef ZWCAD
HINSTANCE hmod = ::LoadLibrary(FilePath::GetArxDir() + _T("\\pipelinecmd.arx"));
#else
HINSTANCE hmod = ::LoadLibrary(FilePath::GetArxDir() + _T("\\pipelinecmd.zrx"));
#endif
if (!hmod) return NULL;
func_GetValveInsSizeByLevel proc = (func_GetValveInsSizeByLevel)::GetProcAddress(hmod, "GetValveInsSizeByLevel");
if (!proc)
{
::FreeLibrary(hmod);
return NULL;
}
bool bRel = proc(pszName, dn, pSrcData, data);
::FreeLibrary(hmod);
return bRel;
}
}
IMPLEMENT_DYNAMIC(CParaDesignDlg, CDialog)
CParaDesignDlg::CParaDesignDlg(LPCTSTR pszType, LPCTSTR pszName, const int &idx, CWnd* pParent)
: CDialog(IDD_DLG_CU_GESHAN_I, pParent)
, m_iFstObj(idx)
, m_equType(_T(""))
, m_sErr(_T(""))
, m_objType(pszType)
, m_objName(pszName)
, m_bShowPIC(true)
, m_hBitmap(NULL)
, m_pCurObj(NULL)
, m_bInplace(false)
{
ParseJson::readObjects(FilePath::GetSysDir() + JSON_FILE, m_objType, m_objs);
}
CParaDesignDlg::CParaDesignDlg(CEquJsonObject *pObj, CWnd * pParent)
:CDialog(IDD_DLG_CU_GESHAN_I, pParent)
, m_iFstObj(0)
, m_equType(_T(""))
, m_sErr(_T(""))
, m_objType(pObj->_type.c_str())
, m_objName(_T("参数化设备在位编辑"))
, m_bShowPIC(true)
, m_hBitmap(NULL)
, m_pCurObj(NULL)
, m_bInplace(true)
{
// 参数化阀门的阀体长度不能修改
if (pObj->_class_type == _T("VALVE"))
{
if (pObj->_params.size() >= 6)
pObj->_params[5]._readOnly = true;
}
if (pObj->_class_type == _T("HVAC_VALVE"))
{
if (pObj->_params.size() >= 9)
pObj->_params[8]._readOnly = true;
}
m_objs.push_back(std::make_pair(pObj->_subtype.c_str(), pObj));
}
CParaDesignDlg::~CParaDesignDlg()
{
if (m_hBitmap)
::DeleteObject(m_hBitmap);
for (size_t i = 0; i < m_strArrs.size(); ++i)
DELETE_PTR(m_strArrs[i]);
Objects::const_iterator it(m_objs.begin());
for (; it != m_objs.end(); ++it)
{
Object *p(it->second);
DELETE_PTR(p);
}
m_fontBtn.DeleteObject();
m_fontList.DeleteObject();
}
void CParaDesignDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_LIST1, m_wndListCtrl);
DDX_CBString(pDX, IDC_COMBO1, m_equType);
DDX_Control(pDX, IDC_STA_PIC, m_wndPIC);
DDX_Control(pDX, IDC_BUTTON1, m_btnShowPIC);
DDX_Control(pDX, IDC_COMBO1, m_wndComboType);
DDX_Control(pDX, IDC_BUTTON2, m_btnAdd);
DDX_Control(pDX, IDC_BUTTON3, m_btnModify);
DDX_Control(pDX, IDC_BUTTON4, m_btnDel);
DDX_Text(pDX, IDC_STA_ERR, m_sErr);
}
BOOL CParaDesignDlg::OnInitDialog()
{
CDialog::OnInitDialog();
m_btnShowPIC.SetWindowText(m_bShowPIC ? _T("<<") : _T(">>"));
initCtrls();
SetWindowText(m_objName);
UpdateData(FALSE);
return TRUE;
}
void CParaDesignDlg::initCtrls()
{
m_wndListCtrl.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT | LVS_EX_SINGLEROW);
m_wndListCtrl.EnableToolTips(TRUE);
m_wndListCtrl.InsertColumn(0, _T("参数名称"), LVCFMT_LEFT, 187);
m_wndListCtrl.InsertColumn(1, _T("数值"), LVCFMT_LEFT, 180);
int idx(0);
m_wndComboType.Clear();
Objects::const_iterator it(m_objs.begin());
for (; it != m_objs.end(); ++it)
{
const Object &obj(*it->second);
idx = m_wndComboType.AddString(obj._name.c_str());
m_wndComboType.SetItemDataPtr(idx, (void*)&obj);
}
if (m_wndComboType.GetCount() == 0) return;
if (m_wndComboType.GetCount() > m_iFstObj)
m_wndComboType.SetCurSel(m_iFstObj);
else
m_wndComboType.SetCurSel(0);
OnCbnSelchangeType();
LOGFONT lf;
::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT), sizeof(lf), &lf);
CClientDC dc(this);
_tcscpy(lf.lfFaceName, _T("Arial Unicode Ms"));
lf.lfHeight = -MulDiv(13, GetDeviceCaps(dc.m_hDC, LOGPIXELSY), 72);
m_fontBtn.CreateFontIndirect(&lf);
_tcscpy(lf.lfFaceName, _T("微软雅黑"));
lf.lfHeight = -MulDiv(11, GetDeviceCaps(dc.m_hDC, LOGPIXELSY), 72);
m_fontList.CreateFontIndirect(&lf);
m_btnAdd.SetFont(&m_fontBtn);
m_btnModify.SetFont(&m_fontBtn);
m_btnDel.SetFont(&m_fontBtn);
m_btnAdd.SetWindowText(_T("✙"));
m_btnModify.SetWindowText(_T("✎"));
m_btnDel.SetWindowText(_T("✖"));
m_wndListCtrl.SetFont(&m_fontList);
m_wndComboType.SetFont(&m_fontList);
}
bool CParaDesignDlg::getParamByKey(LPCTSTR psz, double &v)
{
if (!psz) return false;
CString xx;
v = .0;
if (getParamByKey(psz, xx))
{
v = TypeConvert::s2f(xx);
return true;
}
acutPrintf(_T("\n参数%s获取失败!"), psz);
return false;
}
bool CParaDesignDlg::getParamByKey(LPCTSTR psz, int & n)
{
if (!psz) return false;
CString xx;
n = .0;
if (getParamByKey(psz, xx))
{
n = TypeConvert::s2i(xx);
return true;
}
acutPrintf(_T("\n参数%s获取失败!"), psz);
return false;
}
bool CParaDesignDlg::getParamByKey(LPCTSTR psz, CString & v)
{
std::map<CString, CString>::const_iterator it = m_datas.find(psz);
if (it != m_datas.end())
v = it->second;
else
{
acutPrintf(_T("\n参数%s获取失败!"), psz);
return false;
}
return true;
}
bool CParaDesignDlg::getCombolIdx(LPCTSTR psz, int &n)
{
if (!psz) return false;
if (!m_pCurObj) return false;
for (size_t i = 0; i < m_pCurObj->_params.size(); ++i)
{
Param &pa = m_pCurObj->_params[i];
if (pa._key == psz)
{
// 非下选择框模式
if (!pa._data.empty())
{
int idx = _ttoi(pa._value.c_str());
if (idx < 0 || idx >= pa._data.size())
return false;
n = idx;
return true;
}
}
}
acutPrintf(_T("\n参数%s获取失败!"), psz);
return false;
}
int CParaDesignDlg::getColor()
{
int clr(256);
CString s(_T("256"));
if (getParamByKey(_T("color"), s))
clr = TypeConvert::s2i(s);
return clr;
}
CString CParaDesignDlg::getEquDesc()
{
return m_equType;
}
void CParaDesignDlg::modifyParams(const int & idx, LPCTSTR key, LPCTSTR v)
{
if (idx < 0 || idx >= m_objs.size()) return;
if (!key || !v) return;
Object *pObj = m_objs[idx].second;
if (!pObj) return;
for (size_t i = 0; i < pObj->_params.size(); ++i)
{
Param &pa = pObj->_params[i];
if (pa._key == key)
{
pa._value = v;
return;
}
}
}
void CParaDesignDlg::modifyParams(const int &idx, std::map<CString, CString> &kv)
{
std::map<CString, CString>::const_iterator it = kv.begin();
for (; it != kv.end(); ++it)
{
modifyParams(idx, it->first, it->second);
}
}
void CParaDesignDlg::modifyParams(const std::map<CString, CString>& kv)
{
for (size_t i = 0; i < m_objs.size(); ++i)
{
std::map<CString, CString>::const_iterator it = kv.begin();
for (; it != kv.end(); ++it)
{
modifyParams(i, it->first, it->second);
}
}
}
void CParaDesignDlg::hideParam(const int &idx, LPCTSTR key, const bool &bHide)
{
if (idx < 0 || idx >= m_objs.size()) return;
if (!key) return;
Object *pObj = m_objs[idx].second;
if (!pObj) return;
for (size_t i = 0; i < pObj->_params.size(); ++i)
{
Param &pa = pObj->_params[i];
if (pa._key == key)
{
pa._show = bHide;
return;
}
}
}
CString CParaDesignDlg::getCurrentObjValve(LPCTSTR key)
{
if (!m_pCurObj) return _T("");
for (size_t i = 0; i < m_pCurObj->_params.size(); ++i)
{
Param &pa = m_pCurObj->_params[i];
if (pa._key == key)
{
// 非下选择框模式
if (pa._data.empty())
return pa._value.c_str();
else
{
int idx = _ttoi(pa._value.c_str());
if (idx < 0 || idx >= pa._data.size())
return _T("");
return pa._data[idx].c_str();
}
}
}
return _T("");
}
BEGIN_MESSAGE_MAP(CParaDesignDlg, CDialog)
ON_WM_PAINT()
ON_WM_ERASEBKGND()
ON_BN_CLICKED(IDOK, &CParaDesignDlg::OnBnClickedOk)
ON_BN_CLICKED(IDC_BUTTON1, &CParaDesignDlg::OnBnClickedButton1)
ON_CBN_SELCHANGE(IDC_COMBO1, &CParaDesignDlg::OnCbnSelchangeType)
ON_BN_CLICKED(IDC_BUTTON2, &CParaDesignDlg::OnBnClickedButton2)
ON_BN_CLICKED(IDC_BUTTON3, &CParaDesignDlg::OnBnClickedButton3)
ON_BN_CLICKED(IDC_BUTTON4, &CParaDesignDlg::OnBnClickedButton4)
ON_REGISTERED_MESSAGE(WM_XLISTCTRL_COMBO_SELECTION, &CParaDesignDlg::OnComboSelection)
ON_REGISTERED_MESSAGE(WM_XLISTCTRL_EDIT_END, &CParaDesignDlg::OnEditEnd)
ON_NOTIFY(NM_CLICK, IDC_LIST1, &CParaDesignDlg::OnNMClkList1)
END_MESSAGE_MAP()
BOOL CParaDesignDlg::OnEraseBkgnd(CDC * pDC)
{
return CDialog::OnEraseBkgnd(pDC);
}
void CParaDesignDlg::OnPaint()
{
CRect rect;
m_wndPIC.GetWindowRect(&rect);
ScreenToClient(&rect);
CPaintDC dc(this);
CBitmap bitmap;
bitmap.Attach(m_hBitmap);
if (!bitmap.m_hObject)
return;
CDC memDC;
memDC.CreateCompatibleDC(&dc);
BITMAP bm;
bitmap.GetBitmap(&bm);
CBitmap *pOld = memDC.SelectObject(&bitmap);
// 计算等比缩放
double sx = (double)rect.Width() / bm.bmWidth;
double sy = (double)rect.Height() / bm.bmHeight;
double scale = min(sx, sy);
int drawW = (int)(bm.bmWidth * scale);
int drawH = (int)(bm.bmHeight * scale);
int x = rect.left + (rect.Width() - drawW) / 2;
int y = rect.top + (rect.Height() - drawH) / 2;
dc.SetStretchBltMode(HALFTONE);
dc.StretchBlt(
x, y, drawW, drawH,
&memDC,
0, 0,
bm.bmWidth, bm.bmHeight,
SRCCOPY
);
memDC.SelectObject(pOld);
bitmap.Detach();
}
// 把当前对象的参数摊成 m_datas(绘制时按 key 取值)与 m_Bims(BIM 数据)。
// 原来这段只写在"确定"按钮里,无界面建模(startForPipeValveNoUI)也要用,所以抽出来。
void CParaDesignDlg::BuildDatas()
{
m_datas.clear();
m_Bims.clear();
if (!m_pCurObj) return;
int idx(0);
for (size_t i = 0; i < m_pCurObj->_params.size(); ++i)
{
Param &param(m_pCurObj->_params[i]);
if (!param._key.empty())
{
if (!param._data.empty())
{
idx = TypeConvert::s2i(param._value.c_str());
if (idx >= param._data.size() || idx < 0) idx = 0;
m_datas.insert(std::make_pair(param._key.c_str(), param._data[idx].c_str()));
}
else
m_datas.insert(std::make_pair(param._key.c_str(), param._value.c_str()));
}
if (param._data.empty())
m_Bims.push_back(std::make_pair(param._name.c_str(), param._value.c_str()));
else
m_Bims.push_back(std::make_pair(param._name.c_str(), param.getCombo2String().c_str()));
}
}
void CParaDesignDlg::OnBnClickedOk()
{
if (!UpdateData(TRUE)) return;
BuildDatas();
//int row = m_wndListCtrl.GetItemCount();
//int col = m_wndListCtrl.GetColumns();
//CString s0(_T("")), s1(_T(""));
//for (size_t i = 0; i < row; ++i)
//{
// s0 = m_wndListCtrl.GetItemText(i, 0);
// s1 = m_wndListCtrl.GetItemText(i, 1);
// m_Bims.push_back(std::make_pair(s0, s1));
//}
ParseJson::writeObjects(FilePath::getProgramDataFolder() + JSON_FILE, *m_pCurObj);
CDialog::OnOK();
}
void CParaDesignDlg::OnBnClickedButton1()
{
double dScale(CoreTools::GetDPIScale());
m_bShowPIC = !m_bShowPIC;
m_btnShowPIC.SetWindowText(m_bShowPIC ? _T("<<") : _T(">>"));
CRect rcDlg, rcPic;
GetWindowRect(rcDlg);
m_wndPIC.GetClientRect(rcPic);
int w(rcPic.Width() + 10 * dScale);
if (m_bShowPIC)
{
rcDlg.right += w;
//m_wndPIC.ShowWindow(SW_SHOW);
}
else
{
rcDlg.right -= w;
//m_wndPIC.ShowWindow(SW_HIDE);
}
CWnd *pBtnOK(GetDlgItem(IDOK));
CWnd *pBtnCancel(GetDlgItem(IDCANCEL));
if (pBtnOK && pBtnCancel)
{
CRect rcOK, rcCancel;
CSize szOK, szCancel;
pBtnOK->GetWindowRect(rcOK);
pBtnCancel->GetWindowRect(rcCancel);
ScreenToClient(rcOK);
ScreenToClient(rcCancel);
szOK = rcOK.Size();
szCancel = rcCancel.Size();
rcOK.left = (int)((rcDlg.Width() - rcOK.Width()) * .5);
rcOK.right = rcOK.left + szOK.cx;
rcCancel.left = rcDlg.Width() - rcCancel.Width() - 28 * dScale;
rcCancel.right = rcCancel.left + szCancel.cx;
pBtnOK->MoveWindow(rcOK);
pBtnCancel->MoveWindow(rcCancel);
}
MoveWindow(rcDlg);
Invalidate(TRUE);
}
void CParaDesignDlg::OnCbnSelchangeType()
{
int idx = m_wndComboType.GetCurSel();
if (idx == -1) return;
if (idx >= m_objs.size()) return;
m_pCurObj = ((Object*)m_wndComboType.GetItemDataPtr(idx));
if (!m_pCurObj) return;
Object &obj(*m_pCurObj);
obj.initParams();
if (!obj._pic.empty())
{
CString sPicPath(FilePath::GetSysDir() + _T("\\ExamplePIC\\") + obj._pic.c_str());
if (_taccess(sPicPath, 0x0) == 0x0)
{
if (m_hBitmap) ::DeleteObject(m_hBitmap);
m_hBitmap = (HBITMAP)::LoadImage(0, sPicPath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
//m_wndPIC.SetBitmap(m_hBitmap);
m_btnShowPIC.EnableWindow(true);
}
else
{
if (m_bShowPIC)
CParaDesignDlg::OnBnClickedButton1();
m_btnShowPIC.EnableWindow(false);
}
}
else
{
if (m_bShowPIC)
{
CParaDesignDlg::OnBnClickedButton1();
m_btnShowPIC.EnableWindow(false);
}
}
refreshListCtrl(obj);
Invalidate();
}
void CParaDesignDlg::OnBnClickedButton2() // 添加
{
if (!m_pCurObj) return;
CString sName(_T("名称"));
if (!CoreTools::getNameByDialog(_T("添加参数"), _T("参数名称:"), sName)) return;
Object &obj(*m_pCurObj);
for (size_t i = 0; i < obj._params.size(); ++i)
{
const std::wstring &n(obj._params[i]._name);
if (sName.Compare(n.c_str()) == 0)
{
AfxMessageBox(_T("新参数名称与现有参数重名,请重新输入!"));
return;
}
}
Param para;
para.clear();
para._name = sName;
para._canModify = true;
para._type = _T("string");
para._value = _T("");
para._key = _T("other");
obj._params.push_back(para);
OnCbnSelchangeType();
}
void CParaDesignDlg::OnBnClickedButton3() // 修改
{
if (!m_pCurObj) return;
Object &obj(*m_pCurObj);
int idxUI = m_wndListCtrl.GetSelectionMark();
if (idxUI >= obj._params.size())
{
AfxMessageBox(_T("请选择一个参数!"));
return;
}
int idxJson = m_wndListCtrl.GetItemData(idxUI);
Param &param(obj._params[idxJson]);
if (!param._canModify)
{
AfxMessageBox(_T("请选择一个新添加的参数!"));
}
CString sName = m_wndListCtrl.GetItemText(idxUI, 0);
if (!CoreTools::getNameByDialog(_T("修改参数名称"), _T("参数名称"), sName)) return;
param._name = sName;
OnCbnSelchangeType();
}
void CParaDesignDlg::OnBnClickedButton4() // 删除
{
if (!m_pCurObj) return;
Object &obj(*m_pCurObj);
int idxUI = m_wndListCtrl.GetSelectionMark();
if (idxUI >= obj._params.size())
{
AfxMessageBox(_T("请选择一个参数!"));
return;
}
int idxJson = m_wndListCtrl.GetItemData(idxUI);
Param &param(obj._params[idxJson]);
if (!param._canModify)
{
AfxMessageBox(_T("请选择一个新添加的参数!"));
}
Params::iterator it(obj._params.begin());
std::advance(it, idxJson);
obj._params.erase(it);
OnCbnSelchangeType();
}
LRESULT CParaDesignDlg::OnComboSelection(WPARAM nItem, LPARAM nSubItem)
{
if (!m_pCurObj) return 0;
Object &obj(*m_pCurObj);
int idx = (int)m_wndListCtrl.GetItemData(nItem);
if (idx >= obj._params.size() || idx < 0) return 0;
if (idx >= obj._params.size() || idx < 0) return 0;
Param &para(obj._params[idx]);
if (para._data.empty()) return 0;
CString sItem = m_wndListCtrl.GetItemText(nItem, nSubItem);
std::vector<std::wstring>::iterator it = std::find(para._data.begin(), para._data.end(), (LPCTSTR)sItem);
if (it == para._data.end()) return 0;
int dis = std::distance(para._data.begin(), it);
CString errMsg;
if (!obj.checkParams(idx, TypeConvert::i2s(dis), errMsg))
{
m_sErr = errMsg;
UpdateData(FALSE);
m_wndListCtrl.SetItemText(nItem, nSubItem, para.getCombo2String().c_str());
return 0;
}
else
{
m_sErr.Empty();
UpdateData(FALSE);
}
para._value = TypeConvert::i2s(dis);
if (obj.modifyParams(idx))
OnCbnSelchangeType();
return 0L;
}
LRESULT CParaDesignDlg::OnEditEnd(WPARAM nItem, LPARAM nSubItem)
{
if (!m_pCurObj) return 0;
Object &obj(*m_pCurObj);
int idx = (int)m_wndListCtrl.GetItemData(nItem);
if (idx >= obj._params.size() || idx < 0) return 0;
Param &param(obj._params[idx]);
CString sItem = m_wndListCtrl.GetItemText(nItem, nSubItem);
CString errMsg(_T(""));
if (param._type == _T("string"))
{
if (param._key != _T("2D"))
param._value = sItem;
return 0;
}
if (!checkValue(param, sItem, errMsg))
{
AfxMessageBox(errMsg);
m_wndListCtrl.SetItemText(nItem, nSubItem, param._value.c_str());
return 0;
}
if (!obj.checkParams(idx, sItem, errMsg))
{
m_sErr = errMsg;
UpdateData(FALSE);
m_wndListCtrl.SetItemText(nItem, nSubItem, param._value.c_str());
return 0;
}
else
{
m_sErr.Empty();
UpdateData(FALSE);
}
param._value = sItem;
if (obj.modifyParams(idx))
OnCbnSelchangeType();
return 0;
}
void CParaDesignDlg::OnNMClkList1(NMHDR * pNMHDR, LRESULT * pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
*pResult = 0;
if (pNMItemActivate->hdr.code != NM_CLICK) return;
int idx = pNMItemActivate->iItem;
if (idx < 0) return;
if (pNMItemActivate->iSubItem != 1) return;
int idxRec = m_wndListCtrl.GetItemData(idx);
Object &obj(*m_pCurObj);
obj.onSigleClickItem(idxRec);
refreshListCtrl(obj);
return;
}
void CParaDesignDlg::refreshListCtrl(Object &obj)
{
m_wndListCtrl.DeleteAllItems();
int idx(-1);
for (size_t i = 0; i < obj._params.size(); ++i)
{
Param &param(obj._params[i]);
if (!param._show) continue;
idx = m_wndListCtrl.InsertItem(i, param._name.c_str());
// 由于json中有隐藏的行,所以这里保存数组索引,供双击时使用
m_wndListCtrl.SetItemData(idx, i);
if (!param._canModify)
{
m_wndListCtrl.SetItemColors(idx, 0, RGB(0, 0, 0), RGB(220, 220, 220));
if (param._readOnly)
m_wndListCtrl.SetItemColors(idx, 1, RGB(0, 0, 0), RGB(220, 220, 220));
}
obj.setItemText(m_wndListCtrl, idx, i);
}
}
void CParaDesignDlg::start(LPCTSTR objType, LPCTSTR objName, const int &idx)
{
CAcModuleResourceOverride myResources;
if (objType && objName)
{
CParaDesignDlg dlg(objType, objName, idx);
if (dlg.DoModal() != IDOK) return;
if (!dlg.m_pCurObj) return;
dlg.m_pCurObj->start(dlg);
}
}
#define _SET_MAP_(key1, key2)if (data.find(##key1) != data.end()) kv.insert(std::make_pair(L#key2, data[##key1]));;
// ---------------------------------------------------------------------------
// 把 startForPipeValve 里"DoModal 之前"的准备逻辑抽出来,
// 供 startForPipeValve(有界面)与 startForPipeValveNoUI(无界面,给 MCP 用)共用。
// bSilent = true 时失败不弹 AfxMessageBox(MCP 里弹框会把调用方卡住)。
// ---------------------------------------------------------------------------
static bool PreparePipeValveDlg(CParaDesignDlg& dlg
, LPCTSTR objType
, const double &dDN
, const double &dPN
, const AecDbObjXDataMap *pSrcData
, bool &bHasFlange
, bool bSilent)
{
// 首先检查一下有没有 objType 数据
CString sSizePath = FilePath::GetSysDir() + VALVE_JSON_PATH;
WDocument doc;
if (!file2Json(sSizePath, doc))
{
if (!bSilent) AfxMessageBox(_T("打开valvesize.josn文件失败。"));
return false;
}
MIt it = doc.FindMember(_T("Pipe"));
if (it == doc.MemberEnd())
{
if (!bSilent) AfxMessageBox(_T("未找到当前阀门类型。"));
return false;
}
it = it->value.FindMember(objType);
if (it == doc.MemberEnd())
{
if (!bSilent) AfxMessageBox(_T("未找到当前阀门类型。"));
return false;
}
if (it->value.MemberCount() == 0 && !bSilent)
{
AfxMessageBox(_T("当前阀门类型没有数据。请自行输入尺寸数据。"));
}
// 向 json 参数里注入 DN、PN 等
std::map<CString, CString> kv, data;
auto &objs = dlg.getObjects();
for (size_t i(0); i < objs.size(); ++i)
{
GetValveInsSizeByLevel(objs[i].first.c_str(), dDN, pSrcData, data);
kv.clear();
kv.insert(std::make_pair(_T("DN"), TypeConvert::convert<std::wstring, double>(dDN).c_str()));
_SET_MAP_(PID_PIPE_DPRESS, PN);
_SET_MAP_(PIPE_LEVEL, LEVEL);
_SET_MAP_(DOC_PROJECT, PROJ);
_SET_MAP_(DOC_TRADE, TRADE);
_SET_MAP_(_T("阀长"), L);
_SET_MAP_(_T("手轮高度"), H);
_SET_MAP_(_T("手轮直径"), W);
_SET_MAP_(_T("端面"), R);
dlg.modifyParams(i, kv);
dlg.modifyParams(i, _T("F"), bHasFlange ? _T("0") : _T("1"));
}
return !dlg.getObjects().empty();
}
AcDbEntity * CParaDesignDlg::startForPipeValve(LPCTSTR objType
, LPCTSTR objName
, const double &dDN
, const double &dPN
, bool &bHasFlange
, const int & idx
, const AecDbObjXDataMap *pSrcData)
{
CAcModuleResourceOverride myResources;
if (objType && objName)
{
CParaDesignDlg dlg(objType, objName, idx);
if (!PreparePipeValveDlg(dlg, objType, dDN, dPN, pSrcData, bHasFlange, false))
return NULL;
if (dlg.DoModal() != IDOK) return NULL;
if (!dlg.m_pCurObj) return NULL;
CString ss = dlg.getCurrentObjValve(_T("F"));
bHasFlange = ss == _T("是");
return dlg.m_pCurObj->start2Ptr(dlg);
}
return NULL;
}
AcDbEntity *CParaDesignDlg::startForHvacValve(LPCTSTR objType
, LPCTSTR objName
, const int &nShape
, const double &dDN
, const double &dW
, const double &dH
, const double &dFlT
, const double &dFlE
, bool &bHasFlange
, const int &idx)
{
CAcModuleResourceOverride myResources;
if (objType && objName)
{
// 首先检查一下有没有 objType 数据
CString sSizePath = FilePath::GetSysDir() + VALVE_JSON_PATH;
WDocument doc;
if (!file2Json(sSizePath, doc))
{
AfxMessageBox(_T("打开valvesize.josn文件失败。"));
return NULL;
}
MIt it = doc.FindMember(_T("Hvac"));
if (it == doc.MemberEnd())
{
AfxMessageBox(_T("未找到当前阀门类型。"));
return NULL;
}
it = it->value.FindMember(objType);
if (it == it->value.MemberEnd())
{
AfxMessageBox(_T("未找到当前阀门类型。"));
return NULL;
}
if (it->value.MemberCount() == 0)
{
AfxMessageBox(_T("当前阀门类型没有数据。请自行输入尺寸数据。"));
}
// 在这之前,向 json 文件中注入DN,PN两个参数
CParaDesignDlg dlg(objType, objName, idx);
std::map<CString, CString> kv;
kv.insert(std::make_pair(_T("shape"), TypeConvert::convert<std::wstring, int>(nShape).c_str()));
kv.insert(std::make_pair(_T("DN"), TypeConvert::convert<std::wstring, double>(dDN).c_str()));
kv.insert(std::make_pair(_T("W"), TypeConvert::convert<std::wstring, double>(dW).c_str()));
kv.insert(std::make_pair(_T("H"), TypeConvert::convert<std::wstring, double>(dH).c_str()));
kv.insert(std::make_pair(_T("FlT"), TypeConvert::convert<std::wstring, double>(dFlT).c_str()));
kv.insert(std::make_pair(_T("FlE"), TypeConvert::convert<std::wstring, double>(dFlE).c_str()));
dlg.modifyParams(kv);
if (dlg.DoModal() != IDOK) return NULL;
if (!dlg.m_pCurObj) return NULL;
CString ss = dlg.getCurrentObjValve(_T("Flange"));
bHasFlange = ss == _T("是");
return dlg.m_pCurObj->start2Ptr(dlg);
}
return NULL;
}
void CParaDesignDlg::inplace(AcDbObjectId &id, AcDbObjectIdArray &ar)
{
CEquJsonObject *pObj(getJsonObjByEnt(id)); // 传入CParaDesignDlg并在其内部释放
if (pObj)
{
CAcModuleResourceOverride myResources;
CParaDesignDlg dlg(pObj);
if (dlg.DoModal() != IDOK) return;
if (!dlg.m_pCurObj) return;
dlg.m_pCurObj->inplace(ar, dlg);
}
}
namespace
{
void checkParams(CEquJsonObject *pObj, bool bValve)
{
// 只向下兼容,即 新软件打开旧图纸
using namespace SHJson;
CString jsFile = FilePath::getProgramDataFolder() + JSON_FILE;
if (_taccess(jsFile, 0x0) != 0x0) return;
WDocument doc;
if (!file2Json(jsFile, doc)) return;
CString path(_T(""));
if (bValve)
path = _T("/PIPE_VALVE/SUB_VALVE/param");
else
path = CString(_T("/")) + pObj->_type.c_str() + _T("/") + pObj->_subtype.c_str() + _T("/param");
WCValue *pParam = WPointer(path).Get(doc);
if (!pParam || !pParam->IsArray()) return;
CArr arr = pParam->GetArray();
int count(0);
if (arr.Size() <= pObj->_params.size())
count = arr.Size();
else
count = pObj->_params.size();
// 两个数据集合,相同的索引的key应该相同
std::wstring sKey;
for (int i(0); i < count; ++i)
{
sKey = _T("");
MCIt it = arr[i].FindMember(_T("key"));
if (it != arr[i].MemberEnd())
sKey = it->value.GetString();
// 不相同,重新读取json文件内的默认数据
if (sKey != pObj->_params[i]._key)
{
ParseJson::readParam(arr[i], pObj->_params[i]);
continue;
}
}
// pObj->_params 的数量少,则从arr里挑出没有的参数加入其中
for (int i(pObj->_params.size()); i < arr.Size(); ++i)
{
pObj->_params.push_back(CEquJsonObject::Param());
ParseJson::readParam(arr[i], *pObj->_params.rbegin());
}
}
bool isValveEnt(AcDbObjectId &id)
{
AcDbObjectPointer<AecDbEwEquipment> entPtr(id, AcDb::kForRead);
if (entPtr.openStatus() != Acad::eOk) return false;
int nVal;
if (entPtr->GetAt(PIPE_VALVE, nVal))
return true;
return false;
}
}
void CParaDesignDlg::inplace(AcDbObjectId &id)
{
CEquJsonObject *pObj(getJsonObjByEnt(id)); // 传入CParaDesignDlg并在其内部释放
if (pObj)
{
// 由于参数设备的参数数量经常改变
// 检查一下参数的个数与json模板文件里是否一致?
checkParams(pObj, isValveEnt(id));
CAcModuleResourceOverride myResources;
CParaDesignDlg dlg(pObj);
if (dlg.DoModal() != IDOK) return;
if (!dlg.m_pCurObj) return;
dlg.m_pCurObj->inplace(id, dlg);
}
}
// 下面导出函数为其它工程所用
extern "C" __declspec(dllexport) AcDbEntity* startForPipeValve(LPCTSTR objType
, LPCTSTR objName
, const double &dDN
, const double &dPN
, bool &bHasFlange
, const int & idx
, const AecDbObjXDataMap *pSrcData = NULL )
{
return CParaDesignDlg::startForPipeValve(objType, objName, dDN, dPN, bHasFlange, idx, pSrcData);
}
// 无界面版:不弹"参数化设计"对话框,按 DN/PN 与 idx 直接取第 idx 个规格建模。
// 给 MCP(cad_mcp_aec)用 —— 有界面的那条路在 MCP 里会卡在模态框上。
// 失败返回 NULL(不弹 AfxMessageBox)。
extern "C" __declspec(dllexport) AcDbEntity* startForPipeValveNoUI(LPCTSTR objType
, LPCTSTR objName
, const double &dDN
, const double &dPN
, bool &bHasFlange
, const int & idx
, const AecDbObjXDataMap *pSrcData = NULL)
{
CAcModuleResourceOverride myResources;
if (!objType) return NULL;
CParaDesignDlg dlg(objType, objName ? objName : objType, idx);
if (!PreparePipeValveDlg(dlg, objType, dDN, dPN, pSrcData, bHasFlange, true))
return NULL;
auto &objs = dlg.getObjects();
int n = (idx >= 0 && idx < (int)objs.size()) ? idx : 0;
dlg.m_pCurObj = objs[n].second;
if (!dlg.m_pCurObj) return NULL;
dlg.BuildDatas(); // 原来只有点"确定"时才填 m_datas / m_Bims,start2Ptr 依赖它
CString ss = dlg.getCurrentObjValve(_T("F"));
bHasFlange = ss == _T("是");
return dlg.m_pCurObj->start2Ptr(dlg);
}
extern "C" __declspec(dllexport) void inplaceForValve(AcDbObjectId &id)
{
CParaDesignDlg::inplace(id);
}
extern "C" __declspec(dllexport) AcDbEntity* startForHvacValve(LPCTSTR objType
, LPCTSTR objName
, const int &nShape // 风管形状
, const double &dDN // nShape = 1,公称,nShape = 0,无效
, const double &dW // nShape = 0,风管长,nShape = 1,无效
, const double &dH // nShape = 0,风管宽,nShape = 1,无效
, const double &dFlT // 法兰厚
, const double &dFlE // 法兰卷边
, bool &bHasFlange // 风管插入阀门带法兰
, const int &idx)
{
return CParaDesignDlg::startForHvacValve(objType, objName, nShape
, dDN, dW, dH, dFlT, dFlE, bHasFlange, idx);
}