BMBase二次开发 C++ 创建直线约束求解器

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;
	}

}

未完待续,如有问题,欢迎私聊指正!

  • 11
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值