1. 约束标注图像
有约束,就要把约束显示出来,创建一个继承于BPGraphicElement类的类作为约束标注类。对于不同的约束,也要有不同的显示形式,水平距离和垂直距离用标尺的方式标注,既显示标注,又显示约束的水平距离值和垂直距离值(如下,分别为水平距离约束和垂直距离约束)。
保持水平或保持垂直的约束,就不需要距离,那么就创建为一个平行于被约对象的线段(如下,分别为保持水平约束和保持垂直约束)。
对于共点约束,在共点处标记出来较为合理(如下图)。
代码如下:
ConstraintDimension.h
class ConstraintDimension : public BIMBase::Data::BPGraphicElement
{
DefineSuper(BPGraphicElement)
public:
ConstraintDimension();
~ConstraintDimension();
virtual Utf8String _getSchemaName() const override { return PBM_SCHEMA_Demo; };
virtual Utf8String _getClassName() const override { return PBM_CLASS_Dim_Demo; };
//创建线性标注
CString* CreateDimension(BIMBase::Core::BPProjectR project, GePoint3d ptStart, GePoint3d ptEnd, int nType, double dConValue, BPEntityPtr entptr);
//写数据
virtual ::p3d::P3DStatus _copyToData(BIMBase::Core::BPDataR instance, BIMBase::Core::BPProject& project) const override;
//读数据
virtual ::p3d::P3DStatus _initFromData(BIMBase::Core::BPDataCR instance) override;
//创建几何造型
virtual BIMBase::Core::BPGraphicsPtr _createPhysicalGraphics(BIMBase::Core::BPProjectR project, BIMBase::PModelIdCR modelId, bool bIsDynamics) override;
public:
GePoint3d m_ptStart;
GePoint3d m_ptEnd;
int m_nGraphicElementID;//被约束的图形的ID
int m_nConstraintType;//约束类型
double m_dDimensionValue;//约束值
CString m_strClassName; //被约束的图形的ClassName
int m_nConstraintNum;//约束所在序列
int m_nPtOnNum;//共点约束在对象上点的序列(Line:起0 终1; PolyGon:在点容器序列)
bool m_bIsCreate = true;
bool m_bIsShow = true;//约束是否显示(后续在显示或者隐藏约束时用)
Demo_CREATE(ConstraintDimension);
};
Demo_EXTENSION(ConstraintDimension);
ConstraintDimension.cpp
#include "ConstraintDimension.h"
#define Property_StartPoint "ptStart"
#define Property_EndPoint "ptEnd"
#define Property_ConstraintValue "ConstraintValue"
#define Property_ConstraintType "ConstraintType"
#define Property_ClassName "ClassName"
#define Property_GraphicElementID "GraphicElementID"
#define Property_ConstraintNum "ConstraintNum"
#define Property_PtOnNum "PtOnNum"
#define Property_isShow "isShow"
#define PI 3.1415926
ConstraintDimension::ConstraintDimension()
{
}
ConstraintDimension::~ConstraintDimension()
{
//m_Dimension->~BPDimensionLinear();
}
CString* ConstraintDimension::CreateDimension(BIMBase::Core::BPProjectR project, GePoint3d ptStart, GePoint3d ptEnd, int nType, double dConValue, BPEntityPtr entptr)
{
return nullptr;
}
::p3d::P3DStatus ConstraintDimension::_copyToData(BIMBase::Core::BPDataR instance, BIMBase::Core::BPProject& project) const
{
if (T_Super::_copyToData(instance, project) != P3DStatus::SUCCESS)
return ERROR;
P3DStatus status;
status = instance.setValue(Property_StartPoint, BPValue(this->m_ptStart));
if (P3DStatus::SUCCESS != status)
return ERROR;
status = instance.setValue(Property_EndPoint, BPValue(this->m_ptEnd));
if (P3DStatus::SUCCESS != status)
return ERROR;
status = instance.setValue(Property_ConstraintValue, BPValue(this->m_dDimensionValue));
if (P3DStatus::SUCCESS != status)
return ERROR;
status = instance.setValue(Property_ConstraintType, BPValue(this->m_nConstraintType));
if (P3DStatus::SUCCESS != status)
return ERROR;
status = instance.setValue(Property_ClassName, BPValue(this->m_strClassName));
if (P3DStatus::SUCCESS != status)
return ERROR;
status = instance.setValue(Property_GraphicElementID, BPValue(this->m_nGraphicElementID));
if (P3DStatus::SUCCESS != status)
return ERROR;
status = instance.setValue(Property_ConstraintNum, BPValue(this->m_nConstraintNum));
if (P3DStatus::SUCCESS != status)
return ERROR;
status = instance.setValue(Property_PtOnNum, BPValue(this->m_nPtOnNum));
if (P3DStatus::SUCCESS != status)
return ERROR;
status = instance.setValue(Property_isShow, BPValue(this->m_bIsShow));
if (P3DStatus::SUCCESS != status)
return ERROR;
return SUCCESS;
}
::p3d::P3DStatus ConstraintDimension::_initFromData(BIMBase::Core::BPDataCR instance)
{
if (T_Super::_initFromData(instance) != P3DStatus::SUCCESS)
return ERROR;
BPValue value;
P3DStatus status;
status = instance.getValue(value, Property_StartPoint);
if (P3DStatus::SUCCESS != status)
return ERROR;
m_ptStart = value.getPoint3D();
status = instance.getValue(value, Property_EndPoint);
if (P3DStatus::SUCCESS != status)
return ERROR;
m_ptEnd = value.getPoint3D();
status = instance.getValue(value, Property_ConstraintValue);
if (P3DStatus::SUCCESS != status)
return ERROR;
m_dDimensionValue = value.getDouble();
status = instance.getValue(value, Property_ConstraintType);
if (P3DStatus::SUCCESS != status)
return ERROR;
m_nConstraintType = value.getInteger();
status = instance.getValue(value, Property_ClassName);
if (P3DStatus::SUCCESS != status)
return ERROR;
m_strClassName = value.getString().c_str();
status = instance.getValue(value, Property_GraphicElementID);
if (P3DStatus::SUCCESS != status)
return ERROR;
m_nGraphicElementID = value.getInteger();
status = instance.getValue(value, Property_ConstraintNum);
if (P3DStatus::SUCCESS != status)
return ERROR;
m_nConstraintNum = value.getInteger();
status = instance.getValue(value, Property_PtOnNum);
if (P3DStatus::SUCCESS != status)
return ERROR;
m_nPtOnNum = value.getInteger();
status = instance.getValue(value, Property_isShow);
if (P3DStatus::SUCCESS != status)
return ERROR;
m_bIsShow = value.getBoolean();
return SUCCESS;
}
BIMBase::Core::BPGraphicsPtr ConstraintDimension::_createPhysicalGraphics(BIMBase::Core::BPProjectR project, BIMBase::PModelIdCR modelId, bool bIsDynamics)
{
if (!m_bIsCreate)
{
return nullptr;
}
BPGraphicsPtr ptrGraphics;
if (m_nConstraintType == 1 || m_nConstraintType == 2)//水平垂直距离
{
if (m_nConstraintType == 1)
{
if (m_ptStart.y > m_ptEnd.y)
m_ptEnd.y = m_ptStart.y;
else
m_ptStart.y = m_ptEnd.y;
}
else if (m_nConstraintType == 2)
{
if (m_ptStart.x > m_ptEnd.x)
m_ptStart.x = m_ptEnd.x;
else
m_ptEnd.x = m_ptStart.x;
}
//标注样式
BIMBase::Core::BPDimensionStylePtr ptrDimensionStyle = BIMBase::Core::BPDimensionStyle::create(L"线性标注样式范例", project);
if (ptrDimensionStyle.isNull())
return NULL;
ptrDimensionStyle->setDimtad(0);
ptrDimensionStyle->setDimse1(true);
ptrDimensionStyle->setDimse2(true);
ptrDimensionStyle->setDimdec(0);
ptrDimensionStyle->setDimrnd(0);
ptrDimensionStyle->setDimscale(1);
ptrDimensionStyle->setDimtxt(m_dDimensionValue / 10);
ptrDimensionStyle->setDimasz(m_dDimensionValue / 10);
BIMBase::BPColorDef colorDef;
colorDef.m_rgba.red = 255;
colorDef.m_rgba.green = 0;
colorDef.m_rgba.blue = 0;
UInt32 colorInt = BPColorUtil::getEntityColor(colorDef, project, true);
ptrDimensionStyle->setDimclrd(colorInt);
ptrDimensionStyle->setDimclre(colorInt);
ptrDimensionStyle->setDimclrt(colorInt);
ptrDimensionStyle->replace(L"线性标注样式范例", &project);
//绘制选中对象的标注
BIMBase::Data::BPPlacement dimPlace;
GePoint3d xLine1Point = m_ptStart;
GePoint3d xLine2Point = m_ptEnd;
GeVec3d dirVec = GeVec3d::createByStartEndNormalize(xLine1Point, xLine2Point);
double ang = GeVec3d::create(1., 0., 0.).angleTo2D(dirVec);
GeVec3d vOffset = dirVec;
vOffset.rotate2D(PI / 2);
vOffset = vOffset * (m_dDimensionValue / 10);
GePoint3d textPoint = xLine1Point;
dirVec = dirVec * 0.5;
textPoint = textPoint + vOffset;
CString str;
str.Format(_T("%.2lf"), m_dDimensionValue);
PString pstr = str;
//根据计算信息构造直线标注,第6个参数传入不为空时,标注上显示传入的值
BIMBase::Data::BPDimensionLinear linearDim(dimPlace, textPoint, xLine1Point, xLine2Point, textPoint, pstr, ang);
linearDim.setDimstyle(L"线性标注样式范例");
ptrGraphics = linearDim.createPhysicalGraphics(project, project.getActiveModel()->getModelId(), true);
return ptrGraphics;
}
else if (m_nConstraintType == 3 || m_nConstraintType == 4)//水平垂直
{
BPModelPtr ptrModel = project.getModelById(modelId);
if (ptrModel.isNull())
return nullptr;
ptrGraphics = ptrModel->createPhysicalGraphics();
if (ptrGraphics.isNull())
return nullptr;
if (m_nConstraintType == 3)
{
double dDistance = (m_ptEnd.x - m_ptStart.x) / 5;
if (m_ptStart.y > m_ptEnd.y)
m_ptEnd.y = m_ptStart.y;
else
m_ptStart.y = m_ptEnd.y;
m_ptStart.x = m_ptStart.x + dDistance * 2;
m_ptEnd.x = m_ptStart.x + dDistance;
GeSegment3d seg1;
seg1.point[0].set(m_ptStart.x, m_ptStart.y - dDistance, m_ptStart.z);
seg1.point[1].set(m_ptEnd.x, m_ptEnd.y - dDistance, m_ptEnd.z);
IGeCurveBasePtr Line = IGeCurveBase::createSegment(seg1);
BIMBase::BPSymbology type;
type.color = 10;
type.style = 0;
type.weight = 1;
ptrGraphics->addGeCurve(*Line, type, 0);
ptrGraphics->finish();
return ptrGraphics;
}
else if (m_nConstraintType == 4)
{
double dDistance = (m_ptEnd.y - m_ptStart.y) / 5;
if (m_ptStart.x > m_ptEnd.x)
m_ptStart.x = m_ptEnd.x;
else
m_ptEnd.x = m_ptStart.x;
m_ptStart.y = m_ptStart.y + dDistance * 2;
m_ptEnd.y = m_ptStart.y + dDistance;
GeSegment3d seg1;
seg1.point[0].set(m_ptStart.x - dDistance, m_ptStart.y, m_ptStart.z);
seg1.point[1].set(m_ptEnd.x - dDistance, m_ptEnd.y, m_ptEnd.z);
IGeCurveBasePtr Line = IGeCurveBase::createSegment(seg1);
BIMBase::BPSymbology type;
type.color = 10;
type.style = 0;
type.weight = 1;
ptrGraphics->addGeCurve(*Line, type, 0);
ptrGraphics->finish();
return ptrGraphics;
}
}
else if (m_nConstraintType == 5)//共点
{
BPModelPtr ptrModel = project.getModelById(modelId);
if (ptrModel.isNull())
return nullptr;
ptrGraphics = ptrModel->createPhysicalGraphics();
if (ptrGraphics.isNull())
return nullptr;
double dDistance = fabs(m_ptStart.distance(m_ptEnd) / 15);
GePoint3d ptO;
if (m_nPtOnNum == 0)
ptO = m_ptStart;
else if(m_nPtOnNum == 1)
ptO = m_ptEnd;
GeEllipse3d cirlceOuter = GeEllipse3d::createByCircle(ptO, GeVec3d::create(0, 0, 1), dDistance);
IGeCurveBasePtr ptrCir = IGeCurveBase::createEllipse(cirlceOuter);
BIMBase::BPSymbology type;
type.color = 10;
type.style = 0;
type.weight = 1;
ptrGraphics->addGeCurve(*ptrCir, type, 0);
ptrGraphics->finish();
return ptrGraphics;
}
}
2. 添加约束并写入.ini文件
添加约束时,提前把要约束得对象选择放在 BPSelectionSetManager 里(一般建议一次性选一个被约束几何对象),然后反序列化拾取的实体指针,需要约束值的就计算该对象的起点到终点的距离(水平距离或垂直距离就计算对应坐标的差值)。然后再构造一个约束图像,把对应的值赋给该约束对象,并保存到项目中。
2.1 添加约束
以添加水平距离代码为例,具体如下:
//根据实例初始化
LineDemo pbLine;
pbLine.initFromData(*ptrData);
pbLine.setLineId(ptrEntity->getEntityId().m_entityId);
pbLine.replaceInProject(*pProject);
//约束值
double dValue = pbLine.getEndPoint().x - pbLine.getStartPoint().x;
//获取模型空间
BPModelBaseP pModle = ptrEntity->getBPModel();
if (pModle == nullptr)
return;
PModelId modelidd = pModle->getModelId();
//添加约束图像
ConstraintDimensionP Dim = new ConstraintDimension();
Dim->m_ptStart = pbLine.getStartPoint();
Dim->m_ptEnd = pbLine.getEndPoint();
Dim->m_dDimensionValue = dValue;
Dim->m_nConstraintType = 1;
strAppName.Format(_T("%s_Id=%d"), strClassName.c_str(), pbLine.m_nLineId);
int nConstraintCount = GetPrivateProfileInt(strAppName, _T("ConstraintCount"), 0, PBM_Constraint_INIFile_Path);
Dim->m_nConstraintNum = nConstraintCount + 1;
Dim->m_strClassName = strClassName.c_str();
Dim->m_nGraphicElementID = ptrEntity->getEntityId().m_entityId;
p3d::P3DStatus stu = Dim->addToProject(*pProject, modelidd);
int dataID = Dim->getDataKey().getDataId().getValue();
int ClassID = Dim->getDataKey().getClassId();
//ini文件写入约束
Dim->m_nConstraintNum = WriteConstraint(1, strAppName, PBM_Constraint_INIFile_Path, dValue, dataID, ClassID);
Dim->replaceInProject(*pProject);
2.2 约束写入.ini文件
以被约束对象的ClassNam+BPEntityId作为节名(Section),关键信息+约束序列号为key,构建.ini文件,具体例子如下:
[ATDLine_Id=1331]
ConstraintCount=3
Constrain_1=5
Constrain_Value_1=0.000000
Constrain_DataID_1=67
Constrain_ClassID_1=1558
Constrain_LineNum_1=1
Constrain_NextDataID_1=66
Constrain_NextClassID_1=1560
Constrain_NextGraphicElementID_1=1333
Constrain_NextLineNum_1=0
Constrain_NextOnNum_1=1
Constrain_2=1
Constrain_Value_2=649.784248
Constrain_DataID_2=68
Constrain_ClassID_2=1558
Constrain_3=2
Constrain_Value_3=880.864008
Constrain_DataID_3=69
Constrain_ClassID_3=1558
该函数返回的就是写入的约束所在序列,写入.ini文件的集体实现如下:
int WriteConstraint(int nConstraintType, CString strAppName, CString csIniFile, double dConstraintValue, int nDataID, int nClassID, int nDemoDataID = 0, int nDemoClassID = 0, int nGraphicElementID = 0, int nLineNum = -1,int nNextNum = -1)
{
CString strKey, strValue;
int nConstraintCount = GetPrivateProfileInt(strAppName, _T("ConstraintCount"), 0, csIniFile);
//写入约束个数
nConstraintCount += 1;
strValue.Format(_T("%d"), nConstraintCount);
::WritePrivateProfileString(strAppName, L"ConstraintCount", strValue, csIniFile);
//约束序列 例:有Constrain_2,但是没有Constrain_1,那当前写入的序列就写Constrain_1
int ConstraintNum = -1;
for (int i = 1;; i++)
{
strKey.Format(_T("Constrain_%d"), i);
if (::GetPrivateProfileInt(strAppName, strKey, -1, csIniFile) == -1)
{
ConstraintNum = i;
break;
}
}
//写入约束
strKey.Format(_T("Constrain_%d"), ConstraintNum);
strValue.Format(_T("%d"), nConstraintType);
::WritePrivateProfileString(strAppName, strKey, strValue, csIniFile);
//写入约束值
strKey.Format(_T("Constrain_Value_%d"), ConstraintNum);
strValue.Format(_T("%lf"), dConstraintValue);
::WritePrivateProfileString(strAppName, strKey, strValue, csIniFile);
//写入约束图像的DataKey->DataID
strKey.Format(_T("Constrain_DataID_%d"), ConstraintNum);
strValue.Format(_T("%d"), nDataID);
::WritePrivateProfileString(strAppName, strKey, strValue, csIniFile);
//写入约束图像的DataKey->DataID
strKey.Format(_T("Constrain_ClassID_%d"), ConstraintNum);
strValue.Format(_T("%d"), nClassID);
::WritePrivateProfileString(strAppName, strKey, strValue, csIniFile);
if (nConstraintType == 5)
{
//写入共点约束的点是起点还是终点
strKey.Format(_T("Constrain_LineNum_%d"), ConstraintNum);
strValue.Format(_T("%d"), nLineNum);
::WritePrivateProfileString(strAppName, strKey, strValue, csIniFile);
//写入其他对象的DataKey->DataID
strKey.Format(_T("Constrain_NextDataID_%d"), ConstraintNum);
strValue.Format(_T("%d"), nDemoDataID);
::WritePrivateProfileString(strAppName, strKey, strValue, csIniFile);
//写入其他对象的DataKey->DataID
strKey.Format(_T("Constrain_NextClassID_%d"), ConstraintNum);
strValue.Format(_T("%d"), nDemoClassID);
::WritePrivateProfileString(strAppName, strKey, strValue, csIniFile);
//写入其他对象的GraphicElementID
strKey.Format(_T("Constrain_NextGraphicElementID_%d"), ConstraintNum);
strValue.Format(_T("%d"), nGraphicElementID);
::WritePrivateProfileString(strAppName, strKey, strValue, csIniFile);
//写入其他对象的共点约束的点是起点还是终点
strKey.Format(_T("Constrain_NextLineNum_%d"), ConstraintNum);
strValue.Format(_T("%d"), nNextNum);
::WritePrivateProfileString(strAppName, strKey, strValue, csIniFile);
//写入其他对象的共点约束的序列号(暂时写入一个值,后续在共点函数里有更改)
strKey.Format(_T("Constrain_NextOnNum_%d"), ConstraintNum);
strValue.Format(_T("%d"), ConstraintNum);
::WritePrivateProfileString(strAppName, strKey, strValue, csIniFile);
}
return ConstraintNum;
}
3. 约束求解
显示约束的约束标注图像只是为了把约束可视化,真正的核心是约束求解。当存在约束时。移动一条直线的起点或终点是,另一个点也跟着做出正确的变化,这就是约束求解的结果(个人理解)。把所有和约束相关的东西都存储在Schema表既不方便,也很冗杂,还不方便。可以存储为.ini文件,这样读写就很方便,能存储的信息类别也更多,不受Schema表的约束(Schema读写个人觉得很烦)。在ini文件可以存成下面这样的。
[ATDLine_Id=1331]
ConstraintCount=3
Constrain_1=5
Constrain_Value_1=0.000000
Constrain_DataID_1=67
Constrain_ClassID_1=1558
Constrain_LineNum_1=1
Constrain_NextDataID_1=66
Constrain_NextClassID_1=1560
Constrain_NextGraphicElementID_1=1333
Constrain_NextLineNum_1=0
Constrain_NextOnNum_1=1
Constrain_2=1
Constrain_Value_2=649.784248
Constrain_DataID_2=68
Constrain_ClassID_2=1558
Constrain_3=2
Constrain_Value_3=880.864008
Constrain_DataID_3=69
Constrain_ClassID_3=1558
3.1 水平距离约束
如下图,在一条直线存在水平距离约束时,移动该直线的一个夹点(ptFirst)到当前光标的过程中,另一个夹点(pSecond)也会在保持与被移动夹点的水平距离的前提下,做相应的变化,即:
pSecond.x = ptFirst.x+dConstrainValue;
而y坐标保持不变,即可完成约束变化。
3.2 垂直距离约束
同理,在一条直线存在垂直距离约束时,移动该直线的一个夹点(ptFirst)到当前光标的过程中,另一个夹点(pSecond)也会在保持与被移动夹点的垂直距离的前提下,做相应的变化,即:
pSecond.y = ptFirst.y+dConstrainValue;
而x坐标保持不变,即可完成约束变化。
而当同时存在水平和垂直距离约束时,直线的两个端点就保持相对静止,整体一起移动。如下图所示:
3.3 保持水平约束
与上面两个相对比,保持水平约束就不存在距离,只要两点的y相同即可,x值同样保持不变即可。即:
pSecond.y = ptFirst.y;
3.4 保持垂直约束
直线存在保持垂直约束时,只要两个点的x坐标值相同,y坐标保持原来的即可。即:
pSecond.x = ptFirst.x;
3.5 共点约束
共点约束约束的两条直线,当移动第一个对象时,线处理第一个对象的自身约束,然后再处理共点约束的另一个对象的自身约束。但是如果两个对象都只有该共点约束时,只要不是移动的不是共点的点,则不做多于变化;如果移动的是共点的点,那么也只要把令爱一个对象的共点的点移动到当前光标处即可。
如上图,每条直线除了共点约束以外,都有约束自身的其他约束,在移动夹点时,就先处理约束自身的约束,然后再处理共点对象的约束,最后再处理约束图像,这样就能昨晚一次完整的夹点移动变化。
3.6 约束求解函数
关于约束的求解函数如下,相当简单(后续写完直线和圆相切,圆和圆相切,两条直线保持水平和垂直,约束一条直线的长度,约束圆的半径,点对称约束,两直线的夹角约束等继续来更新)。重难点是何时调用这个约束求解函数。
/**
@brief 约束求解
@param[in] type:约束类型
@param[in] ptFirst:起点
@param[in] pSecond:终点
@param[in] dConstrainValue:约束值
@return 满足约束的另一个点
*/
GePoint3d Distance(int type, GePoint3d ptFirst, GePoint3d pSecond, double dConstrainValue);
GePoint3d ATiDeConstraint::Distance(int ntype, GePoint3d ptFirst, GePoint3d pSecond, double dConstrainValue)
{
switch (ntype)
{
case ConstraintType::None:
{
AfxMessageBox(L"当前没有约束!");
//return NULL;
}
break;
case ConstraintType::DistanceX:
{
pSecond.x = ptFirst.x + dConstrainValue;
return pSecond;
}
break;
case ConstraintType::DistanceY:
{
pSecond.y = ptFirst.y + dConstrainValue;
return pSecond;
}
break;
case ConstraintType::Level:
{
pSecond.y = ptFirst.y;
return pSecond;
}
break;
case ConstraintType::vertical:
{
pSecond.x = ptFirst.x;
return pSecond;
}
case ConstraintType::PtOnPt:
{
pSecond = ptFirst;
}
break;
default:
break;
}
}
4.被约束对象的图像处理和约束标注图形的处理
当被约束对象的夹点移动时,就会处理该对象已有的约束,就会调用约束求解函数,先把自身的约束处理完,变化为正确的图像以后,再处理共点约束(涉及其他对象),同理,在处理其他共点约束对象时,也是先处理约束自身的约束,自身做出正确的变化后,再依次处理其他共点的对象。下面代码为直线的夹点移动的代码,除了夹点处理外,核心就是调用了处理直线的约束的函数(DealConstrain_Line)和处理约束图像的函数(DealDimGraphics)。
StatusInt LineDragManipulatorDemo::_doDragControls(BPEntityR elHandle, BPBaseButtonEventCR ev, bool isDynamics)
{
::BIMBase::PModelId curModelId = ev.getViewport()->getTargetModel()->getModelId();
BIMBase::Core::IBPProjectManagerP pProjectManager = BIMBase::Core::BPApplication::getInstance().getProjectManager();
if (pProjectManager == nullptr)
return ERROR;
BPProjectP pProject = pProjectManager->getMainProject();
if (pProject == nullptr)
return ERROR;
BPDataPtr ptrData = BPDataUtil::getDataOnEntity(elHandle);
if (!ptrData.isValid())
return false;
//根据实例初始化
LineDemoP pbNextLine = new LineDemo();
LineDemo pbLine;
pbLine.initFromData(*ptrData);
//获取点击夹点后⿏标点
GePoint3d cursorPt = GePoint3d::create(0, 0, 0);
_getAdjustedPoint(cursorPt, ev);
//获取点击夹点的编号,编号根据加⼊夹点的顺序确定
GePoint3d m_orginPt;
SIZE_T index = -1;
for (SIZE_T i = 0; i < m_controls.m_locations.size(); i++)
{
if (CONTROL_STATE_Flashed == m_controls.m_locations[i]->m_state)
{
m_orginPt = m_controls.m_locations[i]->m_point;
index = i;
break;
}
}
if (index < 0)
return ERROR;
cursorPt.z = m_orginPt.z;
//通过转换矩阵获取原点及坐标信息
GeTransform curTm = pbLine.getPlacement().toTransform();
GePoint3d ptOri;
GeVec3d vecX, vecY, vecZ;
curTm.getOriginAndVectors(ptOri, vecX, vecY, vecZ);
GeVec3d vecXNew = vecX;
GePoint3d ptOriNew = ptOri;
GeVec3d vecYNew = vecZ ^ vecXNew;
//根据新计算的坐标及原点得到转换矩阵
GeTransform transNew = GeTransform::createByOriginAndVectors(ptOriNew, vecXNew, vecYNew, vecZ);
BPPlacement placNew;
placNew.fromTransform(transNew);
//设置新的转换矩阵,转换到新的位置
pbLine.setPlacement(placNew);
//transNew.multiply(cursorPt);
CString strAppName, strKey, strValue;
strAppName.Format(_T("%s_Id=%d"), L"ATDLine", pbLine.getLineId());
int nConstraintcount = GetPrivateProfileInt(strAppName, _T("ConstraintCount"), 0, PBM_Constraint_INIFile_Path);
int nLineNum = GetPrivateProfileInt(strAppName, _T("Constrain_LineNum"), 0, PBM_Constraint_INIFile_Path);
map<int,ConstraintDimension*> Dim;
int nConstraintType = 0;
map<int, int> mapAlreDealPOPCntDataID;
vector<LineDemoP> vecLine;
if (index == 0)//起点
{
pbLine.setStartPoint(cursorPt);
if (nConstraintcount > 0)
pbLine.setEndPoint(ATiDeConstraint::DealConstrain_Line(ptrData, index, cursorPt, pProject, mapAlreDealPOPCntDataID));
}
else if (index == 1)//终点
{
pbLine.setEndPoint(cursorPt);
if (nConstraintcount > 0)
pbLine.setStartPoint(ATiDeConstraint::DealConstrain_Line(ptrData, index, cursorPt, pProject, mapAlreDealPOPCntDataID));
}
for (auto iter_mapLine : mapAlreDealPOPCntDataID)//处理共点对象的约束图像
{
if (iter_mapLine.second == pbLine.getDataKey().getClassId())
{
BPDataKey datakey_Line(iter_mapLine.second, BPDataId(iter_mapLine.first));
BPDataPtr ptrNextLineData = BPDataUtil::getDataByKey(datakey_Line, *pProject);
pbNextLine->initFromData(*ptrNextLineData);
CString strNextAppName, strNextKey;
strNextAppName.Format(_T("%s_Id=%d"), L"ATDLine", pbNextLine->getLineId());
int nNextConstraintcount = GetPrivateProfileInt(strNextAppName, _T("ConstraintCount"), 0, PBM_Constraint_INIFile_Path);
ATiDeConstraint::DealDimGraphics(strNextAppName, nNextConstraintcount, pProject, curModelId, pbNextLine->getStartPoint(), pbNextLine->getEndPoint(), Dim);
}
}
if (nConstraintcount != 0)//处理自己的约束图像
{
strAppName.Format(_T("%s_Id=%d"), L"ATDLine", pbLine.getLineId());
ATiDeConstraint::DealDimGraphics(strAppName, nConstraintcount, pProject, curModelId, pbLine.getStartPoint(), pbLine.getEndPoint(), Dim);
}
if (isDynamics)
{//动态显示
BPGraphicsPtr ptrGraphics = pbLine.createPhysicalGraphics(*pProject, curModelId, true);
GeTransform trans = pbLine.getPlacement().toTransform();
BPGraphicsUtils::transformPhysicalGraphics(*ptrGraphics, trans);
if (ptrGraphics.isValid())
{
elHandle = ptrGraphics->getEntityR();
}
}
else
{//最终点击后Replace
::p3d::P3DStatus stu;
for (auto iter : Dim)//把标注逐个跟着直线移动
{
stu = iter.second->replaceInProject(*pProject);
if (iter.second->m_bIsShow == false)
{
vector<BPEntityPtr> vcEEH;
BPEntityPtr ptrEnt;
iter.second->getData(*pProject)->getPrimaryEntity(ptrEnt);
if (ptrEnt.isValid())
{
vcEEH.push_back(ptrEnt);
ATDFun::ATDHideEntitiy(vcEEH);
}
}
}
for (auto iter_mapLine : mapAlreDealPOPCntDataID)//共点图像刷新过来
{
BPDataKey datakey_Line(iter_mapLine.second, BPDataId(iter_mapLine.first));
BPDataPtr ptrNextLineData = BPDataUtil::getDataByKey(datakey_Line, *pProject);
if (iter_mapLine.second == pbLine.getDataKey().getClassId())
{
pbNextLine->initFromData(*ptrNextLineData);
if (pbNextLine->isValidDataKey())
stu = pbNextLine->replaceInProject(*pProject);
}
}
stu = pbLine.replaceInProject(*pProject);
return stu;
}
return SUCCESS;
}
4.1 处理直线约束
直线约束分两大类,一类是约束自身的约束,例如:水平距离、垂直距离、保持水平和保持垂直这四个,另一类是跨对象约束,例如共点约束,这类约束,就是一个点的位置要在一起。而在处理直线的约束时,就是先处理约束自身的约束,再处理跨对象的约束。跨对象的约束(共点约束)处理起来,也是先处理跨对象的自身的约束,再处理其他约束,这样就形成了一个递归链。首先把约束分类,两类约束各自装在一个容器内,然后先自身,后跨对象。体代码实现按如下:
/**
@brief 处理直线的约束(内含递归调用,涉及到的对象和约束越多,内存开销越大)
@param[in] ptrData:直线的反序列化的BPData
@param[in] ptIndex:当前被拾取的点(起点 0, 终点 1)
@param[in] pProject:当前所在项目
@param[in] vecAlreDealPOPCntDataID:已处理共点对象的DataID
@return 处理完约束后满足的点
*/
GePoint3d DealConstrain_Line(BPDataPtr ptrData, int ptIndex, GePoint3d inPoint, BPProjectP pProject, map<int, int>& mapAlreDealPOPCntDataID);
GePoint3d ATiDeConstraint::DealConstrain_Line(BPDataPtr ptrData, int ptIndex, GePoint3d inPoint, BPProjectP pProject, map<int, int>& mapAlreDealPOPCntDataID)
{
if (!ptrData.isValid())
return GePoint3d::create(0, 0, 0);
GePoint3d retPoint(GePoint3d::create(0, 0, 0));
LineDemo pbLine;
pbLine.initFromData(*ptrData);
if (ptIndex == 0)
{
pbLine.setStartPoint(inPoint);
retPoint = pbLine.getEndPoint();
}
else if (ptIndex == 1)
{
pbLine.setEndPoint(inPoint);
retPoint = pbLine.getStartPoint();
}
CString strAppName, strKey, strValue;
double dConstrainValue = 0.0;
strAppName.Format(_T("%s_Id=%d"), L"ATDLine", pbLine.getLineId());
int nConstraintcount = GetPrivateProfileInt(strAppName, _T("ConstraintCount"), 0, PBM_Constraint_INIFile_Path);
if (nConstraintcount <= 0)
return retPoint;
int nConstraintType = 0;
int j = 0;
::p3d::P3DStatus stu;
//分离约束
map<int,int> mapConstrain_NOon;
vector<int> vecConstrain_On;//目前涉及其他对象的约束只有共点,存的全是5
for (int i = 1; ; i++)//后续读取的约束达到 nConstraintcount 后,有break
{
strAppName.Format(_T("%s_Id=%d"), L"ATDLine", pbLine.getLineId());//下面递归调用导致strAppName变为递归调用内pbNextLine的m_nLineId,导致死循环卡死
strKey.Format(_T("Constrain_%d"), i);
nConstraintType = GetPrivateProfileInt(strAppName, strKey, 0, PBM_Constraint_INIFile_Path);
if (nConstraintType == 0)//当前约束不存在(有可能被删除)
continue;
j++;
//判断当前约束类型是不是共点约束
if (nConstraintType != 5)
mapConstrain_NOon.insert(pair<int,int>(i,nConstraintType));//else if (nConstraintType == 5) vecConstrain_On.push_back(nConstraintType);
if (nConstraintType == 5)
vecConstrain_On.push_back(i);
if (j >= nConstraintcount)
break;
}
//处理不跨对象的约束
for (auto iter_vecConstrain : mapConstrain_NOon)
{
if (iter_vecConstrain.second < 1 || iter_vecConstrain.second > 4)
return retPoint;
//读取约束值
TCHAR szValue[MAX_PATH + 1] = _T("");
strKey.Format(_T("Constrain_Value_%d"), iter_vecConstrain.first);
::GetPrivateProfileString(strAppName, strKey, _T("0"), szValue, MAX_PATH, PBM_Constraint_INIFile_Path);
strValue.Format(_T("%s"), szValue);
dConstrainValue = _wtof(strValue.GetBuffer());
if (ptIndex == 0)
{
retPoint = ATiDeConstraint::Distance(iter_vecConstrain.second, pbLine.getStartPoint(), pbLine.getEndPoint(), dConstrainValue);
pbLine.setEndPoint(retPoint);
}
else if (ptIndex == 1)
{
retPoint = ATiDeConstraint::Distance(iter_vecConstrain.second, pbLine.getEndPoint(), pbLine.getStartPoint(), dConstrainValue - 2 * dConstrainValue);
pbLine.setStartPoint(retPoint);
}
}
//处理跨对象的约束
strAppName.Format(_T("%s_Id=%d"), L"ATDLine", pbLine.getLineId());
for (auto iter_vecConstrain_On : vecConstrain_On)
{
strAppName.Format(_T("ATDLine_Id=%d"), pbLine.getLineId());//下面递归调用导致strAppName变为递归调用内pbNextLine的m_nLineId,导致bug
strKey.Format(_T("Constrain_LineNum_%d"), iter_vecConstrain_On);
int nLineNum = GetPrivateProfileInt(strAppName, strKey, -1, PBM_Constraint_INIFile_Path);//共点约束判断约束的是起点还是终点
strKey.Format(_T("Constrain_DataID_%d"), iter_vecConstrain_On);
int nCntDim_DataID = GetPrivateProfileInt(strAppName, strKey, 0, PBM_Constraint_INIFile_Path);
strKey.Format(_T("Constrain_ClassID_%d"), iter_vecConstrain_On);
int nConstrain_ClassID = GetPrivateProfileInt(strAppName, strKey, 0, PBM_Constraint_INIFile_Path);
bool isBreak = false;
for (auto iter_map : mapAlreDealPOPCntDataID)
{
if (iter_map.first == nCntDim_DataID)
{
isBreak = true;
break;
}
}
if (isBreak)
continue;
int nNextLineNum = 0;//当前共点约束的另一个对象所在点的序列
//根据实例初始化
LineDemoP pbNextLine = new LineDemo();
//NextLine.BPDataKey.DataId
strKey.Format(_T("Constrain_NextDataID_%d"), iter_vecConstrain_On);
int nNextDataID = GetPrivateProfileInt(strAppName, strKey, 0, PBM_Constraint_INIFile_Path);
//NextLine.BPDataKey.ClassID
strKey.Format(_T("Constrain_NextClassID_%d"), iter_vecConstrain_On);
int nNextClassID = GetPrivateProfileInt(strAppName, strKey, 0, PBM_Constraint_INIFile_Path);
if (nNextDataID != 0 && nNextClassID != 0)
{
BPDataKey datakey(nNextClassID, BPDataId(nNextDataID));
BPDataPtr ptrNextLineData = BPDataUtil::getDataByKey(datakey, *pProject);
pbNextLine->initFromData(*ptrNextLineData);
int nNextGraphicElementID = pbNextLine->getLineId();
strAppName.Format(_T("ATDLine_Id=%d"), nNextGraphicElementID);
int nNextConstraintCount = GetPrivateProfileInt(strAppName, L"ConstraintCount", -1, PBM_Constraint_INIFile_Path);
int nCntNum = -1;
for (int i_next = 1; i_next <= nNextConstraintCount; i_next++)
{
strKey.Format(_T("Constrain_NextGraphicElementID_%d"), i_next);
int nNextGraphicElementID = GetPrivateProfileInt(strAppName, strKey, 0, PBM_Constraint_INIFile_Path);
if (nNextGraphicElementID == pbLine.m_nLineId)
{
nCntNum = i_next;
break;
}
}
strKey.Format(_T("Constrain_LineNum_%d"), nCntNum);
nNextLineNum = GetPrivateProfileInt(strAppName, strKey, -1, PBM_Constraint_INIFile_Path);
if (ptIndex == 0)
{
//retPoint = pbLine.getEndPoint();
if (nLineNum == 0)//当前移动的夹点是共点
{
if (nNextLineNum == 0)//处理NextLine的约束
{
pbNextLine->setStartPoint(inPoint);
mapAlreDealPOPCntDataID.insert(pair<int, int>(nCntDim_DataID, nConstrain_ClassID));
stu = pbNextLine->replaceData(*pProject);
pbNextLine->setEndPoint(DealConstrain_Line(ptrNextLineData, nNextLineNum, inPoint, pProject, mapAlreDealPOPCntDataID));
}
else if (nNextLineNum == 1)
{
pbNextLine->setEndPoint(inPoint);
mapAlreDealPOPCntDataID.insert(pair<int, int>(nCntDim_DataID, nConstrain_ClassID));
stu = pbNextLine->replaceData(*pProject);
pbNextLine->setStartPoint(DealConstrain_Line(ptrNextLineData, nNextLineNum, inPoint, pProject, mapAlreDealPOPCntDataID));
}
}
else if (nLineNum == 1)
{
if (nNextLineNum == 0)//处理NextLine的约束
{
pbNextLine->setStartPoint(retPoint);
mapAlreDealPOPCntDataID.insert(pair<int, int>(nCntDim_DataID, nConstrain_ClassID));
stu = pbNextLine->replaceData(*pProject);
pbNextLine->setEndPoint(DealConstrain_Line(ptrNextLineData, nNextLineNum, retPoint, pProject, mapAlreDealPOPCntDataID));
}
else if (nNextLineNum == 1)
{
pbNextLine->setEndPoint(retPoint);
mapAlreDealPOPCntDataID.insert(pair<int, int>(nCntDim_DataID, nConstrain_ClassID));
stu = pbNextLine->replaceData(*pProject);
pbNextLine->setStartPoint(DealConstrain_Line(ptrNextLineData, nNextLineNum, retPoint, pProject, mapAlreDealPOPCntDataID));
}
}
}
else if (ptIndex == 1)
{
//retPoint = inPoint;
if (nLineNum == 0)//当前移动的夹点不是共点
{
if (nNextLineNum == 0)//处理NextLine的约束
{
pbNextLine->setStartPoint(retPoint);
mapAlreDealPOPCntDataID.insert(pair<int, int>(nCntDim_DataID, nConstrain_ClassID));
stu = pbNextLine->replaceData(*pProject);
pbNextLine->setEndPoint(DealConstrain_Line(ptrNextLineData, nNextLineNum, retPoint, pProject, mapAlreDealPOPCntDataID));
}
else if (nNextLineNum == 1)
{
pbNextLine->setEndPoint(retPoint);
mapAlreDealPOPCntDataID.insert(pair<int, int>(nCntDim_DataID, nConstrain_ClassID));
stu = pbNextLine->replaceData(*pProject);
pbNextLine->setStartPoint(DealConstrain_Line(ptrNextLineData, nNextLineNum, retPoint, pProject, mapAlreDealPOPCntDataID));
}
}
else if (nLineNum == 1)//当前移动的夹点是共点
{
if (nNextLineNum == 0)//处理NextLine的约束
{
pbNextLine->setStartPoint(inPoint);
mapAlreDealPOPCntDataID.insert(pair<int, int>(nCntDim_DataID, nConstrain_ClassID));
stu = pbNextLine->replaceData(*pProject);
pbNextLine->setEndPoint(DealConstrain_Line(ptrNextLineData, nNextLineNum, inPoint, pProject, mapAlreDealPOPCntDataID));
}
else if (nNextLineNum == 1)
{
pbNextLine->setEndPoint(inPoint);
mapAlreDealPOPCntDataID.insert(pair<int, int>(nCntDim_DataID, nConstrain_ClassID));
stu = pbNextLine->replaceData(*pProject);
pbNextLine->setStartPoint(DealConstrain_Line(ptrNextLineData, nNextLineNum, inPoint, pProject, mapAlreDealPOPCntDataID));
}
}
}
}
}
pbLine.replaceData(*pProject);
int dataID = pbLine.getDataKey().getDataId().getValue();
int ClassID = pbLine.getDataKey().getClassId();
mapAlreDealPOPCntDataID.insert(pair<int, int>(dataID, ClassID));
return retPoint;
}
4.2 处理约束图像
/**
@brief 处理约束约束图像
@param[in] nConstraintcount:当前对象的约束个数
@param[in] pProject:当前对象所在工程
@param[in] curModelId:当前对象所在模型空间
@param[in] nLineNum:共点约束判断约束的是起点还是终点
@param[in] ptStart,ptEnd:当前对象的起始点
@param[out] Dim:约束图像对象容器
*/
void ATiDeConstraint::DealDimGraphics(CString strAppName,int nConstraintcount, BPProjectP pProject, ::BIMBase::PModelId curModelId, GePoint3d ptStart, GePoint3d ptEnd, std::map<int, ConstraintDimension*>& Dim)
{
CString strKey, strValue;
double dConstrainValue = 0.0;
int j = 0;
for (int i = 1; ; i++)
{
strKey.Format(_T("Constrain_DataID_%d"), i);
int nDataID = GetPrivateProfileInt(strAppName, strKey, 0, PBM_Constraint_INIFile_Path);
if (nDataID == 0)
continue;
j++;
strKey.Format(_T("Constrain_ClassID_%d"), i);
int nClassID = GetPrivateProfileInt(strAppName, strKey, 0, PBM_Constraint_INIFile_Path);
BPDataKey datakey(nClassID, BPDataId(nDataID));
BPDataPtr ptrDimData = BPDataUtil::getDataByKey(datakey, *pProject);
if (ptrDimData == NULL)
continue;
//读取约束值
TCHAR szValue[MAX_PATH + 1] = _T("");
strKey.Format(_T("Constrain_Value_%d"), i);
::GetPrivateProfileString(strAppName, strKey, _T("0"), szValue, MAX_PATH, PBM_Constraint_INIFile_Path);
strValue.Format(_T("%s"), szValue);
dConstrainValue = _wtof(strValue.GetBuffer());
//根据实例初始化
ConstraintDimensionP CTDim = new ConstraintDimension();
CTDim->initFromData(*ptrDimData);
strKey.Format(_T("Constrain_Origin_%d"), i);
int nConstrain_Origin = GetPrivateProfileInt(strAppName, strKey, -1, PBM_Constraint_INIFile_Path);
GePoint3d ptOrigin = GePoint3d::create(0,0,0);
if (nConstrain_Origin == 0)
{
CTDim->m_ptStart = ptStart;
CTDim->m_ptEnd = ptOrigin;
}
else if (nConstrain_Origin == 1)
{
CTDim->m_ptStart = ptOrigin;
CTDim->m_ptEnd = ptEnd;
}
else
{
CTDim->m_ptStart = ptStart;
CTDim->m_ptEnd = ptEnd;
}
CTDim->m_dDimensionValue = dConstrainValue;
BPGraphicsPtr ptrDimGraphics = CTDim->createPhysicalGraphics(*pProject, curModelId, true);
GeTransform trans = CTDim->getPlacement().toTransform();
BPGraphicsUtils::transformPhysicalGraphics(*ptrDimGraphics, trans);
Dim.insert(pair<int, ConstraintDimension*>(nDataID, CTDim));
if (j >= nConstraintcount)
break;
}
}
未完待续,如有问题,欢迎私聊指正!