// 用于处理门窗检查 #pragma once #include "BayWindow.h" namespace NDoorWinCheck { // 洞分类: // 门, 门连窗,子母门, 组合门窗, 窗, 弧窗, 凸窗, 转角窗, 带形窗, 老虎窗, 洞口 enum EEntType{eM = 0, eMLC, eZMM, eZHMC, eC, eHC, eTC, eZJC, eDXC, eLHC, eDK, eDoorTypeNum}; enum EShowItem { eTypeProp = 0x1, // 类型 eWidProp = 0x2, // 长度 eHeiProp = 0x4, // 高度 eEle = 0x8, // 底高 eGeoTypeProp = 0x10, // 型式 eChutiaoProp = 0x20, // 出挑长 eTixingkuanProp = 0x40, // 梯形宽 eNewLabelProp = 0x80, // 新编号 eLabelProp = 0x100,// 编号 // 下边是类型的索引,可以实现两者的转化 eLabelIndex = 0, eNewLabelIndex , eTypeIndex, eWidIndex, eHeiIndex, eEleIndex, eGeoTypeIndex, eChutiaoIndex, eTixingkuanIndex, eDoorWinParmNum }; #define IsCADClosed() (curDoc() == NULL) // ShowItemIndex ==> ShowItemProp EShowItem GetShowItem(EShowItem eShowIndex); // ShowItemProp ==>ShowItemIndex; EShowItem ShowItem2Index(EShowItem eShowItem); // 属性类型 ==> 字符串名称 CString ParamTypeToString(EShowItem type); // 检测是否是文本具有的属性,文本只具有宽度,高度和新编号属性 BOOL IsTextShowItem(EShowItem eItem); // 更新显示,不管ID对应的是普通实体,块参照实体,或者外部参照实体 void UpdateGraphicAny(const TDPtrList &ss); // 锁定文档防止切换 void LockDocumentChange(); // 解除文档切换锁定。 void UnLockDocumentChange(); // 判断一个类型是否需要显示门窗样式 BOOL IsSlideType(EEntType eEntType); #define IsCheckText() (CSetDlg::CheckText() ? true : false) #define IsCheckDWG() (CSetDlg::CheckCurrDWG() ? true : false) #define IsCheckProj() (CSetDlg::CheckCurrProj() ? true : false) #define IsCheckBlock() (CSetDlg::CheckBlock() ? true : false) struct CItem; struct CWidItem; typedef CArray AryEShowItem; typedef CArray AryEtype; typedef CArray AryItemPtr; typedef CArray AryWidItemPtr; // 当前工程是否为空。 BOOL IsEmptyProject(); // 工程名字 CString ProjectName(); // 工程全路径名称 CString ProjectFullName(); // 得到洞分类的名称 例如:eM ==> “门” CString Type2Name(EEntType type); // 门窗类型返回对应的类型名字 CString EntTypeToString(EEntType eEntType); // 检测某eEntType类型数据是否具有该属性 // BOOL TestHasProp(EEntType eEntType, EShowItem eShowItem); // 检测id对应实体的属性跟sValue是否相等 BOOL IsPropModify(AcDbObjectId id, EShowItem eShowItem, CString sValue); // 从数组中查找同名的widItem; CWidItem* FindWidItem(const AryWidItemPtr &aryWidItem, CString strLabel); // 向widItem数组中添加pItem void AddItemToWidItemAry(AryWidItemPtr &aryWidItem, CItem *pItem); // 清空,并且释放pWidItem对应的内存 void ClearAryWidItemPtr(AryWidItemPtr &aryWidItemPtr); // AryItemPtr ==> AryWidItemPtr; 本函数直接将每个item ==> widItem.并不执行同名合并。 void ItemPtrAry2Wid(const AryItemPtr &aryItemPtr, AryWidItemPtr &aryWidItem); // 将当前的属性数据覆盖DWG图纸中的数据 void UpdateProp2DWG(AcDbEntity* pEnt, EEntType eEntType, AryEShowItem &aryEShowItem, CStringArray &aryProp); // 修改类门窗样式 void UpdateEntStyle(TDbEntity *pEnt, EEntType eEntType, CString strStyle, bool b2dOr3d); // 鉴别编号是否按照尺寸编号,还是按照顺序编号,不是按照尺寸编号就认为是按照顺序编号,没有其他情况 // ret: TRUE:尺寸编号;FALSE:顺序编号 BOOL CheckName(const CString &strName); // 获取尺寸编号的尺寸 BOOL GetSize(const CString &strName, CString &strHead, CString &strHei, CString &strWid); BOOL GetSize(const CString &strName, CString &strHead, double &dHei, double &dWid); // 根据编号判断对应的类型;该函数一般用于检测文字对应的类型,而不检测普通门窗的编号 EEntType TextLabelType(const CString &strLabelHead); BOOL TestItemEmpty(const AryItemPtr &aryItemPtr, BOOL bText, BOOL bBlock); BOOL TestItemEmpty(const AryWidItemPtr &aryItemPtr, BOOL bText, BOOL bBlock); // 洞口属性 struct SOpeningProp { SOpeningProp() : pItem(NULL), bText(false), bBlock(false), bExternBlock(false) {}; CString strLabel; // 编号 int nHei; //高度 int nWid; // 宽度 int nEle; // 底高,老虎窗没有该值 CString strType; // 类型,并非所有的洞都有这个参数 XBayWindow::XBayWinStyle eProWinGeo; // 型式,凸窗属性 int nChuTiaoChang; // 凸窗,和转角窗会有这两个属性 int nTixingkuan; // 只有凸窗才有这两个属性 CString str3DShowStyle; // 门窗显示的三维样式 CString str2DShowStyle; // 门窗显示的二维样式 bool bZJCTuChuang; // 转角凸窗, bool bText;// 是否文字对象。 bool bBlock; // 是不是属于块内对象(外部参照) bool bExternBlock; // 是否为 外部参考 CItem *pItem; // 所属的item; }; // 根据id,获取对应的soprop; BOOL GetDoorWinProp(AcDbObjectId &id, SOpeningProp &soprop, EEntType &eOpType); // 获取门窗的按照宽高属性的编号。 CString GetDoorWinSizeLabel(EEntType eEntType, const SOpeningProp &sProp); // 凸窗型式 ==> 字符串名字 CString GeoType2String(XBayWindow::XBayWinStyle style); // 字符串名字 ==> 凸窗型式 XBayWindow::XBayWinStyle GeoType2Style(CString &strGeoType); // 设置属性: void SetPropData(SOpeningProp &sProp, EShowItem eShowItem, CString strData); // 将prop相应属性转换为字符串。 CString PropToString(const SOpeningProp &prop, EShowItem eShowItem); // 测试是否冲突,文字不参与冲突测试。 BOOL TestConflict(EEntType type, const SOpeningProp &sprop1, const SOpeningProp &sprop2); BOOL TestConflict(CItem *pItem); // 检测该数据内部是否冲突 BOOL TestConflict(CItem *pItem1, CItem *pItem2); // 分别从aryWidItem 和 pWidItem中找到对应的类型、widItem必须是同类型的才能编号。 int FindEType(AryWidItemPtr &aryWidItem, AryEtype &aryEtype); int FindEType(CWidItem *pWidItem, AryEtype &aryEtype); typedef CArray AryOpeningProp; class CGroup; class CDataTable; // 每一个共名字的ID -->同楼层的,或者都是没有楼层的 struct CItem { AcDbObjectIdArray aryId; // 该组中的ID们,该ID如果是本土所对应的ID,则一直有效,否则,ID并非一直有效。 AryOpeningProp aryProp; // 该组中的prop们 CString strLabel; // 本组的名字,如果为空,则使用尺寸编号。 EEntType eDoorWinType; // 类型。 CGroup *pGroup; // 所属的group; BOOL bConflict; // 根据检测范围不同在变的冲突 // 处理sLable == sLabel[X]; // bTextTest:是否检测文字。 CString GetItemName(bool bCheckText, bool bBlock) const; // 非文字的个数。 int NoTextDataNum() const; // 根据是否检测文字 int ItemNum(bool bText, bool bBlock) const ; bool HasItem(bool bText, bool bBlock) const; // 添加属性,并且检测是否冲突。 void AddProp(SOpeningProp &prop); // 检测某个block是不是重复的 bool TestRepeatBlock(int index) const; // }; // 对CItem的包装,用于提取信息,不用于数据存储 struct CWidItem { CWidItem() : strLabel(_T("")){} CWidItem(CItem* pItem) { AddItem(pItem); } // 所有的item AryItemPtr aryItem; // 所包含的aryItem; CString strLabel; // 对应的编号 // BOOL bConflict; // 是否冲突 void CopyFrom(const CWidItem &widItem); int GetEntNum(bool bCheckText, bool bBlock) const; // 会设置bConflict; void AddItem(CItem* pItem); // 处理sLable == sLabel[X]; CString GetItemName(bool bCheckText, bool bBlock) const; CString StyleString(BOOL is2D) const; // 返回3D门窗样式,如果冲突则返回空 // 检测某个block是不是重复的,检测之前是不是已经存在了。 bool TestRepeatBlock(int nItem, int index) const; void GetIdAry(TDPtrList &idLst); }; // 一组数据,包含所有类型,用来代表一个楼层 class CGroup { public: CGroup(); ~CGroup(); void Clear(); // 按照类型添加门窗,返回门窗对应的check指针 // 同名,同类型,放在同一个下边,注意监测冲突标记 CItem* AddOpening(AcDbObjectId &id, SOpeningProp &prop, EEntType eEntType); // 获取、设置楼层名字 CString GetFloorName() const; void SetFloorName(CString strName); // 是否当前文档 BOOL IsCurrDoc() const; // 根据类型获取CheckItem; const AryItemPtr& GetItemAry(EEntType eEntType)const; // 本楼层包含的对象类型 int FindEType(AryEtype &aryEType) const; // 过滤ID void FilterId(AcDbObjectIdArray &idArray); private: CString m_strFloor; // 楼层名字 public: AryItemPtr m_doors[eDoorTypeNum]; BOOL m_bCurrDoc; // 是否当前图 CDataTable *m_pDataTable; }; typedef CArray AryAllData; // 保存工程数据,用以检测工程是否发生改变 struct SProjectInfo { struct _SFloorInfo { CString strfloorNo; CString strFloorDoc; XPoint ptMin; XPoint ptMax; bool bInFrame; }; CString strProjectName; CString strProjectFullName; CArray<_SFloorInfo, _SFloorInfo> aryFloorInfo; // DList lstFloorData; void Clear(); void Init(); void AddFloorInfoByDoc(CString _strFloorNo, CString _strFloorDoc); void AddFloorByRange(CString _strFloorNo, CString _strFloorDoc, XPoint _ptMin, XPoint _ptMax); // 比较,没有差异的话,返回true.否则返回false; bool Compare(const SProjectInfo &sProjectInfo) const; void ReadProjInfo(); }; // 门窗检查数据结构 class CDataTable { struct _DataStruct { AcDbObjectId id; SOpeningProp *prop; EEntType eEntType; }; typedef CArray<_DataStruct, _DataStruct&> _AryDataStruct; public: CDataTable(); virtual ~CDataTable(); void Clear(); // 是否空工程。 BOOL IsEmptyTable() const; BOOL IsProjChange() const; // 检测当前工程是否发生改变; BOOL IsDocChange() const; // 检测当前工程是否发生改变; bool IsCurrDocNotInProj() const; // 根据楼层添加ID。nFloor是GetFloorTable()中的索引顺序,并非真正的楼层编号 void AddIdByFloor(AcDbObjectIdArray &idAry, int nFloor, CString &floorName, BOOL bCurrDoc = FALSE, AcDbObjectIdArray *pAryIdBlock = NULL); // 添加不属于工程的数据,只有当前图才考虑添加不属于工程的数据 void AddIdNoProject(AcDbObjectIdArray &idAry, AcDbObjectIdArray *pAryIdBlock = NULL); void SetFloorNum(int n); // 设置楼层的个数 // 框选标记设置,标记当前结果是框选结果。 bool IsSelData() const {return m_bSelBox;} void SetSelFlag(bool bSel) {m_bSelBox = bSel;} // 获取楼层数 int GetFloorNum() const; // 获取楼层 CGroup* GetFloor(int nFloor) const; // 工程名、工程全名、当前文档名的设置和读取。 void SetProjName(CString sProjName) {m_projectInfo.strProjectName = sProjName;} CString GetProjName() const {return m_projectInfo.strProjectName;} void SetProjFullName(CString sProjFullName) {m_projectInfo.strProjectFullName = sProjFullName;} CString GetProjFullName() const {return m_projectInfo.strProjectFullName;} void SetDocName(CString sDoc) {m_strCurrDoc = sDoc;} CString GetDocName() const {return m_strCurrDoc;} ////////////////////////////////////////////////////////////////////////// // 属性表格绘制 // 本工程的数据包含的所有的门窗类型,工程内 int FindETypeProj(AryEtype &aryEType) const; // 本工程,本图内的数据包含的所有的门窗类型 int FindETypeDwg(AryEtype &aryEtype) const; // 本工程,本图内的数据包含的所有的门窗类型 int FindETypeNoProj(AryEtype &aryEtype) const; static int FindEType(AryWidItemPtr widItemPtr[eDoorTypeNum], AryEtype &aryEtype); // 判断有没有未创建工程的数据 BOOL HasNoProjData() const; // 本工程内的所有的数据,不分楼层。 void GetDataPNf(AryWidItemPtr doors[eDoorTypeNum]) const; // void GetNoFloorCurrProj(AryWidItemPtr widItem[eDoorTypeNum]) const; // ???????本工程的所有数据,分楼层 void GetDataPF(AryAllData &data) const; // ???????本工程的冲突数据, void GetConflictProj(AryWidItemPtr widItem[eDoorTypeNum]) const; // ????????工程内本图的数据,分楼层 void GetDataDPF(AryAllData &data) const; // ????????工程内本图的数据,不分楼层 void GetCurrDPNf(AryWidItemPtr widItem[eDoorTypeNum]) const; // ????????工程内本图的冲突数据,不分楼层 void GetConflictDP(AryWidItemPtr widItem[eDoorTypeNum]) const; // ????????全部本图的数据,不分楼层 void GetDataDNpNf(AryAllData &data) const; void GetDataDNpNf(AryWidItemPtr widItem[eDoorTypeNum]) const; // ????????全部本图的冲突数据 void GetConflictDNp(AryWidItemPtr widItem[eDoorTypeNum]) const; // ????????工程外的数据 const CGroup* GetDataNp() const {return &m_dataNoProject;} void GetDataNp(AryWidItemPtr widItem[eDoorTypeNum]) const; // ????????工程外的冲突数据 void GetConflictNoProj(AryWidItemPtr widItem[eDoorTypeNum]) const; // 根据当前的形式计算冲突数据,在CItem中设置标记 void CalcConflictData(); // 属性表格绘制 ////////////////////////////////////////////////////////////////////////// // 数据更新检测: enum EDataChange {eProjChange = 0x01, eDocChange = 0x02, eLabelChange = 0x04, eIdAdd = 0x8, eIdDel = 0x10, ePropChange = 0x20}; DWORD Compare(const CDataTable &dataTable) const; // 检测数据的改变,标签改变,id添加,id删除,属性改变 DWORD DataCompare(const CDataTable &dataTable, bool bOnlyDWG, bool bOnlyProj, bool bNeedText, bool bNeedBlock) const; static BOOL TestDataChange(const DWORD dwFlag, EDataChange eChange); static void SetDataChange(DWORD &dwFlag, EDataChange eChange, BOOL bSet); // 更新属性:更新属性中除了编号之外的其他内容,只更新当前文档 void UpdateProp(const CDataTable &dataTable); // 筛选,筛选出处于ss中的数据,其他数据删除,该函数用于框选 void FilterId(AcDbObjectIdArray &idArray); // 查找未编号门窗的个数 int GetNoNameLabeNum(bool bOnlyDWG, bool bOnlyProj, bool bNeedText, bool bNeedBlock) const; // 检测数据是否为空。 // true:不空,false:空 bool TestHasData(bool bOnlyDWG, bool bOnlyProj, bool bNeedText, bool bNeedBlock) const; // 是否定义楼层:true:有楼层,False没有楼层 bool HasFloor() const; // 检测是否有未创建工程的数据。 bool TestHasNoProjData(bool bNeedText, bool bNeedBlock) const; // 再更新了原图数据之后,现在保存的数据即变成了老数据,如果重新提取图形,一定要把老数据更新掉, void MakeDataOld() {m_bOldData = true;} bool IsOldData() const {return m_bOldData;} void SetFileInfo(); void ClearNullFloor(); void AddFloorInfo(CString strFloorNo, CString strFloorDoc, bool bInFrame, const XPoint &ptMin, const XPoint &ptMax); protected: // 清空aryData的内容,包括内部的释放内存 static void ClearFloorDataAry(AryAllData &aryData); static SOpeningProp* GetProp(_AryDataStruct &_aryDataStruct, const AcDbObjectId &id); // dataStruct根据编号的比较函数。 static int Cmp_DataStruct(const void *ds1, const void *ds2); void GetAryDataStruct(_AryDataStruct &aryDataStruct, bool bOnLyDWG, bool bOnLyProj, bool bNeedText, bool bNeedBlock)const; private: AryAllData m_aryDataAll; // 已创建工程数据 CGroup m_dataNoProject; // 本图未创建工程数据,或者没有工程的时候 // CString m_strProjName; // 工程名称,纯工程名字。没有后缀 // CString m_strProjFullName; // 工程全路径名称,// 防止切换 CString m_strCurrDoc; // 当前图纸全路径名称,防止切换了原图 bool m_bSelBox; // 框选结果 bool m_bOldData; // 老数据标志,如果数据被更新到原图之后,当前数据已经过期,如果发生提取图纸命令,则重新提取数据 SProjectInfo m_projectInfo; // 工程信息,需要检测工程是否发生改变,如果需要发生改变,则需要重新显示数据 }; // 获取门窗列表 void FilterDoorWinText(DList &lstId); void GetOpeningIdListNew(DList &dbList, DList &idList); void GetCurrProjAndDoc(CString &strCurrProj, CString &strCurrDoc, CString &strCurrProjFullName); // 读取本土中的门窗ID。 // lstIdAll:所有的ID。aryIdBlock:块表中的ID void GetDoorWinIds(DList &lstIdAll, AcDbObjectIdArray &aryIdBlock); void GetOpeningDataTable(CDataTable &dataTable); template BOOL IsEmpty(const T &ary) { return (ary.GetSize() == 0); } template BOOL IsEmptyAcAry(const T &ary) { return (ary.length() == 0); } }; // 附带冲突检测的逻辑: // 根据当前显示范围的不同,以及显示的属性的不同,冲突检测的结果不同。 // 冲突检测执行以下逻辑: // 每次重新生成的时候,根据当前属性,执行检测设置冲突标记。 // 绘制的时候,直接检测冲突标记是否设置。