BIMBase 二次开发 C++创建构件流程及遇到的问题和解决方案

参考了概要 (pkpm.cn),实现了圆柱的创建、布置、属性的显示和修改、夹点的拖拽。

1.Demo构建

以创建圆柱为例,首先添加圆柱的类,继承 BIMBase::Data::BPGraphicElement 私有属性:圆柱的底部圆心、半径和高度以及要存储的底部圆心坐标X、Y、X,获取和设置这些私有属性的get、set函数;重写读写数据和创建几何造型的函数。具体代码如下:

Demo.h

namespace DemoObject
{
	//定义智能指针、引用等
	class CylinderDemo;
	typedef CylinderDemo const& CylinderDemoCR;
	typedef CylinderDemo& CylinderDemoR;
	typedef CylinderDemo* CylinderDemoP;
	typedef RefCountedPtr<CylinderDemo> CylinderDemoPtr;
	class CylinderDemo : public BIMBase::Data::BPGraphicElement
	{
		DefineSuper(BPGraphicElement)
	public:
		CylinderDemo();
		~CylinderDemo();

		void   setBottomPoint(GePoint3d pt, bool is_change = false);
		GePoint3d getBottomPt()const;
		GePoint3d getBottomPoint(bool is_change = false)const;

		void setRadius(double dRadius);
		double getRadius()const;

		void setHeight(double dHeight);
		double getHeight()const;

		double getMiddlePt_x() const;
		void setptMiddlePt_x(double Pt_x);

		double getMiddlePt_y() const;
		void setptMiddlePt_y(double Pt_y);

		double getMiddlePt_z() const;
		void setptMiddlePt_z(double Pt_z);

project, BIMBase::PModelIdCR modelId);
	protected:
		virtual Utf8String	 _getSchemaName() const override { return PBM_SCHEMA_Demo; };
		virtual Utf8String	 _getClassName() const override { return PBM_CLASS_Cylinder_Demo; };

		//写数据
		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;

	private:
		GePoint3d m_ptBottom;//底圆心
		double m_dHeight;//高度
		double m_dR;//半径
		double m_ptMiddle_x;
		double m_ptMiddle_y;
		double m_ptMiddle_z;
		Demo_CREATE(CylinderDemo);
	};
	Demo_EXTENSION(CylinderDemo);
}

Demo.cpp

//这个宏是用来读写数据用的,后面字符串的和Schema表里面的Property字段要匹配
#define Property_Radius                          "Radius"
#define Property_Height                          "Height"
#define Property_BottomPoint                     "BottomPoint"
#define Property_pt_X                            "pt_X"
#define Property_pt_Y                            "pt_Y"
#define Property_pt_Z                            "pt_Z"

using namespace DemoObject;
DemoObject::CylinderDemo::CylinderDemo()
{
	//m_ptBottom = GePoint3d::create(0, 0, 0);//底圆心
	m_dHeight = 400;
	m_dR = 200;
	m_ptMiddle_x = 0.0;
	m_ptMiddle_y = 0.0;
	m_ptMiddle_z = 0.0;
	m_ptBottom = GePoint3d::create(m_ptMiddle_x, m_ptMiddle_y, m_ptMiddle_z);
}

DemoObject::CylinderDemo::~CylinderDemo()
{
}

void DemoObject::CylinderDemo::setBottomPoint(GePoint3d pt, bool is_change)
{
	m_ptBottom = pt;
}



GePoint3d DemoObject::CylinderDemo::getBottomPt()const
{
	return m_ptBottom;
}

GePoint3d DemoObject::CylinderDemo::getBottomPoint(bool is_change)const
{
	GePoint3d pt = GePoint3d::create(0, 0, 0);
	//圆柱局部坐标系转到世界坐标系下
	GeTransform trans = getPlacement().toTransform();
	trans.multiply(pt);

	return pt;
}

void DemoObject::CylinderDemo::setRadius(double dRadius)
{
	m_dR = dRadius;
}

double DemoObject::CylinderDemo::getRadius()const
{
	return m_dR;
}

void DemoObject::CylinderDemo::setHeight(double dHeight)
{
	m_dHeight = fabs(dHeight);
}

double DemoObject::CylinderDemo::getHeight() const
{
	return fabs(m_dHeight);
}

double DemoObject::CylinderDemo::getMiddlePt_x() const
{
	return m_ptMiddle_x;
}

void DemoObject::CylinderDemo::setptMiddlePt_x(double Pt_x)
{
	m_ptMiddle_x = Pt_x;
	BPPlacement placement = getPlacement();
	GePoint3d ptOrigin = placement.getOrigin();
	ptOrigin.x = Pt_x;
	placement.setOrigin(ptOrigin);
	setPlacement(placement);
}

double DemoObject::CylinderDemo::getMiddlePt_y() const
{
	return m_ptMiddle_y;
}

void DemoObject::CylinderDemo::setptMiddlePt_y(double Pt_y)
{
	m_ptMiddle_y = Pt_y;
	BPPlacement placement = getPlacement();
	GePoint3d ptOrigin = placement.getOrigin();
	ptOrigin.y = Pt_y;
	placement.setOrigin(ptOrigin);
	setPlacement(placement);
}

double DemoObject::CylinderDemo::getMiddlePt_z() const
{
	return m_ptMiddle_z;
}

void DemoObject::CylinderDemo::setptMiddlePt_z(double Pt_z)
{
	m_ptMiddle_z = Pt_z;
	BPPlacement placement = getPlacement();
	GePoint3d ptOrigin = placement.getOrigin();
	ptOrigin.z = Pt_z;
	placement.setOrigin(ptOrigin);
	setPlacement(placement);
}

::p3d::P3DStatus DemoObject::CylinderDemo::_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_Radius, BPValue(this->getRadius()));
	if (P3DStatus::SUCCESS != status)
		return ERROR;

	status = instance.setValue(Property_Height, BPValue(this->getHeight()));
	if (P3DStatus::SUCCESS != status)
		return ERROR;

	status = instance.setValue(Property_pt_X, BPValue(this->getMiddlePt_x()));
	if (P3DStatus::SUCCESS != status)
		return ERROR;

	status = instance.setValue(Property_pt_Y, BPValue(this->getMiddlePt_y()));
	if (P3DStatus::SUCCESS != status)
		return ERROR;

	status = instance.setValue(Property_pt_Z, BPValue(this->getMiddlePt_z()));
	if (P3DStatus::SUCCESS != status)
		return ERROR;

	return SUCCESS;
}

::p3d::P3DStatus DemoObject::CylinderDemo::_initFromData(BIMBase::Core::BPDataCR instance)
{
	if (T_Super::_initFromData(instance) != P3DStatus::SUCCESS)
		return ERROR;

	BPValue value;
	P3DStatus status;

	status = instance.getValue(value, Property_Radius);
	if (P3DStatus::SUCCESS != status)
		return ERROR;
	setRadius(value.getDouble());

	status = instance.getValue(value, Property_Height);
	if (P3DStatus::SUCCESS != status)
		return ERROR;
	setHeight(value.getDouble());


	status = instance.getValue(value, Property_pt_X);
	if (P3DStatus::SUCCESS != status)
		return ERROR;
	setptMiddlePt_x(value.getDouble());

	status = instance.getValue(value, Property_pt_Y);
	if (P3DStatus::SUCCESS != status)
		return ERROR;
	setptMiddlePt_y(value.getDouble());

	status = instance.getValue(value, Property_pt_Z);
	if (P3DStatus::SUCCESS != status)
		return ERROR;
	setptMiddlePt_z(value.getDouble());

	return SUCCESS;
}

BIMBase::Core::BPGraphicsPtr DemoObject::CylinderDemo::_createPhysicalGraphics(BIMBase::Core::BPProjectR project, BIMBase::PModelIdCR modelId, bool bIsDynamics)
{
	BPModelPtr ptrModel = project.getModelById(modelId);
	if (ptrModel.isNull())
		return nullptr;

	BPGraphicsPtr ptrPhysicalGeometry = ptrModel->createPhysicalGraphics();
	if (ptrPhysicalGeometry.isNull())
		return nullptr;

	double dRadius = getRadius();
	double dHeight = getHeight();
	GePoint3d ptTopPoint = GePoint3d::create(0, 0, dHeight);//(getMiddlePt_x(), getMiddlePt_y(), getMiddlePt_z() + fabs(m_dHeight));
	GePoint3d ptBottomPoint = GePoint3d::create(0, 0, 0);//(getMiddlePt_x(), getMiddlePt_y(), getMiddlePt_z());
	GeConeInfo CylinderInfo(ptBottomPoint, ptTopPoint, m_dR, m_dR, true);
	IGeSolidBasePtr ptrCylinder = IGeSolidBase::createGeCone(CylinderInfo);
	ptrPhysicalGeometry->addGeSolidBase(*ptrCylinder);

	return ptrPhysicalGeometry;
}

2.布置工具实现

在输入你的布置工具的命令后,开始跟随鼠标显示你将将要构造出来的图形,再次点击后,布置出该图形。继承于BPPrimitiveTool。主要的步骤是:布置后,把图形添加到工程的时候,把参数传给demo保存在Schema表里面,调用的是demo的_copyToData();显示的时候,调用demo的_initFromData()把数据读取出来。布置工具主要函数:向工程中增加圆柱体__addCylinder(),布置时创建立圆柱体数据(传递数据)__createOnePtData(),动态绘制函数_onDynamicFrame(),鼠标右键确定构建函数_onResetButton()具体代码如下:

Tool.h

class ToolLayoutCylinderDemo :public BIMBase::Core::BPPrimitiveTool
{
	DefineSuper(BPPrimitiveTool)
public:
	ToolLayoutCylinderDemo();
	~ToolLayoutCylinderDemo();

	//工具ID
	virtual Utf8CP _getToolName() const override { return "layoutCylinderDemo"; }
	//工具启动后响应函数
	virtual void _onPostInstall() override;
	//重启工具响应函数
	virtual void _onRestartTool() override;
	//点击鼠标左键响应函数
	virtual bool _onDataButton(BIMBase::Core::BPBaseButtonEventCP) override;
	//点击鼠标右键响应函数
	virtual bool _onResetButton(BIMBase::Core::BPBaseButtonEventCP) override;
	//动态函数
	virtual void _onDynamicFrame(BIMBase::Core::BPBaseButtonEventCP) override;
	//鼠标移动响应函数,决定是否开启动态函数
	virtual bool _onModelMotion(BIMBase::Core::BPBaseButtonEventCP ev) override;
	//键盘按键响应函数
	virtual bool _onKeyTransition(bool wentDown, ::p3d::platform::P3DVirtualKey key, bool shiftIsDown, bool ctrlIsDown) override;

private:
	//向工程中增加圆柱体
	void __addCylinder(PModelId modelId);
	//单点布置时创建立圆柱体数据
	void __createOnePtData(GePoint3d ptOri);

private:
	DemoObject::CylinderDemo m_Cylinder;
	GePoint3d m_ptBottom;//底圆心
	double m_dHeight;
	double m_dR;
}

 Tool.cpp

ToolLayoutCylinderDemo::ToolLayoutCylinderDemo()
{
	m_ptBottom = GePoint3d::create(0, 0, 0);//底圆心
	m_dHeight = 400;
	m_dR = 200;
	m_nStep = 0;
	m_nType = 0;
}

ToolLayoutCylinderDemo::~ToolLayoutCylinderDemo()
{
}

void ToolLayoutCylinderDemo::_onPostInstall()
{
	//调用基类
	T_Super::_onPostInstall();
	m_nType = 0;

	//打开捕捉
	BPSnap::getInstance().enableLocate(false);
	BPSnap::getInstance().enableSnap(true);
}

void ToolLayoutCylinderDemo::_onRestartTool()
{
	//重启工具
	ToolLayoutCylinderDemo* newTool = new ToolLayoutCylinderDemo();
	newTool->installTool();
}

bool ToolLayoutCylinderDemo::_onDataButton(BPBaseButtonEventCP ev)
{
	//获取鼠标屏幕点击的点
	GePoint3d ptCur = *ev->getPoint();

	//获取点击点所在的工程和模型ID
	::BIMBase::PModelId curModelId = ev->getViewport()->getTargetModel()->getModelId();

	//屏幕点击点Z向高度设置为楼层标高
	ptCur.z = 0;
	int nSize = 0;

	//单点布置
	__createOnePtData(ptCur);
	__addCylinder(curModelId);
	//获取当前视图,强制刷新界面
	BPViewportP pViewPort = BPViewManager::getInstance().getActivedViewport();
	if (NULL == pViewPort) return false;
	if (pViewPort)
	{
		pViewPort->updateView();
	}

	return true;
}

bool ToolLayoutCylinderDemo::_onResetButton(BIMBase::Core::BPBaseButtonEventCP)
{
	//点击右键退出工具
	_exitTool();
	return false;
}

void ToolLayoutCylinderDemo::_onDynamicFrame(BPBaseButtonEventCP ev)
{
	if (NULL == ev)
		return;

	//获取鼠标屏幕点击的点
	GePoint3d ptDynamic = *ev->getPoint();

	//获取点击点所在的工程和模型ID
	BPProjectP pProject = ev->getViewport()->getTargetModel()->getBPProject();
	::BIMBase::PModelId curModelId = ev->getViewport()->getTargetModel()->getModelId();

	//屏幕点击点Z向高度设置为楼层标高
	ptDynamic.z = 0;
	int nSize = 0;

	__createOnePtData(ptDynamic);

	//根据构造的墙数据随着鼠标移动动态显示墙构件
	BPGraphicsPtr ptrGraphics;
	ptrGraphics = m_Cylinder.createPhysicalGraphics(*pProject, curModelId, true);

	if (!ptrGraphics.isValid())
		return;

	BPGraphicsUtils::transformPhysicalGraphics(*ptrGraphics, m_Cylinder.getPlacement().toTransform());
	ptrGraphics->finish();

	BPRedrawEntitys redrawElems;
	redrawElems.setDrawMode(BPDrawMode::enTempDraw);
	redrawElems.setDrawPurpose(BPDrawPurpose::enDynamics);
	redrawElems.setDynamicsViews(ev->getViewport());
	redrawElems.doRedraw(ptrGraphics->getEntityR());
}

bool ToolLayoutCylinderDemo::_onModelMotion(BIMBase::Core::BPBaseButtonEventCP ev)
{
	//如果动态没有开启则开启动态,这样才可以进入_OnDynamicFrame函数
	if (!getDynamicsStarted())
		_beginDynamics();
	return true;
}

bool ToolLayoutCylinderDemo::_onKeyTransition(bool wentDown, ::p3d::platform::P3DVirtualKey key, bool shiftIsDown, bool ctrlIsDown)
{
	return false;
}

void ToolLayoutCylinderDemo::__addCylinder(PModelId modelId)
{
	BPProjectP pProject = BPApplication::getInstance().getProjectManager()->getMainProject();
	if (pProject == nullptr)
		return;

	//增加构件到工程中
	if (SUCCESS != m_Cylinder.addToProject(*pProject, modelId))
	{
		AfxMessageBox(L"Can not add to project!");
		return;
	}
}

void ToolLayoutCylinderDemo::__createOnePtData(GePoint3d ptOri)
{
	//设置基本信息	
	m_Cylinder.setHeight(m_dHeight);
	m_Cylinder.setRadius(m_dR);
	m_Cylinder.setptMiddlePt_x(ptOri.x);
	m_Cylinder.setptMiddlePt_y(ptOri.y);
	m_Cylinder.setptMiddlePt_z(ptOri.z);
	m_Cylinder.setBottomPoint(ptOri);
}

//对工具进行注册
BPTool* CreateCylinderDemoTool()
{
	ToolLayoutCylinderDemo* tool = new ToolLayoutCylinderDemo();
	return tool;
}
AutoDoRegisterFunctionsBegin
BPToolsManager::registerTool("layoutCylinderDemo", &CreateCylinderDemoTool);
AutoDoRegisterFunctionsEnd

 3.右侧属性栏

在右侧显示圆柱的地面圆心、高度和半径。修改对应的数据,图形也会做出相应的变化。继承于IToolProperty。主要函数:获取属性并且在属性框显示OnPropertyGet(),设置属性框中的值OnPropertySet()

Property.h

class CylinderPropertyDemo : public IToolProperty
{
	enum CylinderPropName//判断你更改的属性是哪一个的时候调用
	{
		Middle_X,		//底面中心点X
		Middle_Y,		//底面中心点Y
		Middle_Z,		//底面中心点Z		
		Height,         //高度
		Radius,         //半径
		CylinderPropCount
	};

public:
	CylinderPropertyDemo();
	~CylinderPropertyDemo();
	bool is_0 = false;
	//获取属性并且在属性框显示
	virtual void OnPropertyGet(std::vector<BPEntityP> const& refps, PBBimUIProperyList& lst)  override;
	//设置属性框中的值
	virtual TIErrorStatus OnPropertySet(std::vector<BPEntityP> const& refps, int index, PBBimUIPropertyItem const& item) override;
};

 Property.cpp

using namespace DemoObject;
CylinderPropertyDemo::CylinderPropertyDemo()
{
}

CylinderPropertyDemo::~CylinderPropertyDemo()
{
}

void CylinderPropertyDemo::OnPropertyGet(std::vector<BPEntityP> const& refps, PBBimUIProperyList& lst)
{
	//选择集中的对象的个数
	if (refps.size() == 0)
		return;

	BPEntityId eleId;
	std::vector<IBPObjectPtr> pbObjs;
	BPProjectP pProject = nullptr;

	for (auto elementRef : refps)
	{
		if (NULL == pProject)
		{
			pProject = elementRef->getBPProject();
			if (pProject == NULL)
				continue;
		}
		IBPObjectPtr ptrPbObj = BPObjectExtensionManager::getInstance().getBPObject(*elementRef);
		if (!ptrPbObj.isValid())
			continue;

		pbObjs.push_back(ptrPbObj);
	}

	if (pbObjs.size() < 1)
		return;

	PBBimUIPropertyItem properties[CylinderPropName::CylinderPropCount];
	for (int i = 0; i < pbObjs.size(); ++i)
	{
		IBPObjectPtr ptrObject = pbObjs.at(i);
		CylinderDemo* pCylinder = dynamic_cast<CylinderDemo*>(ptrObject.get());
		//pCylinder->setMiddlePoint(GePoint3d::create(pCylinder->getMiddlePt_x(), pCylinder->getMiddlePt_y(), pCylinder->getMiddlePt_z()));
		if (NULL == pCylinder)
			continue;

		// ---------------------------------------中心点--------------------------------------
		{
			if (0 == i)
			{
				PBBimUIPropertyItem item_X(L"底面中心点X", pCylinder->getMiddlePt_x());
				PBBimUIPropertyItem item_Y(L"底面中心点Y", pCylinder->getMiddlePt_y());
				PBBimUIPropertyItem item_Z(L"底面中心点Z", pCylinder->getMiddlePt_z());
				properties[CylinderPropName::Middle_X].swap(item_X);
				properties[CylinderPropName::Middle_Y].swap(item_Y);
				properties[CylinderPropName::Middle_Z].swap(item_Z);
			}

			else
			{
				PBBimUIPropertyItem* oldItem_X = &properties[CylinderPropName::Middle_X];
				if (!oldItem_X->multiValue())     // 比较判断是否为多值
				{
					PBBimUIPropertyItem::ListValue oldType;
					double oldValu;
					oldItem_X->getValue(oldValu);
					if (fabs(oldValu - pCylinder->getBottomPt().x) > 1e-15)
						properties[CylinderPropName::Middle_X].setMultiValue(true);
				}

				PBBimUIPropertyItem* oldItem_Y = &properties[CylinderPropName::Middle_Y];
				if (!oldItem_Y->multiValue())     // 比较判断是否为多值
				{
					PBBimUIPropertyItem::ListValue oldType;
					double oldValu;
					oldItem_Y->getValue(oldValu);
					if (fabs(oldValu - pCylinder->getBottomPt().y) > 1e-15)
						properties[CylinderPropName::Middle_Y].setMultiValue(true);
				}

				PBBimUIPropertyItem* oldItem_Z = &properties[CylinderPropName::Middle_Z];
				if (!oldItem_Z->multiValue())     // 比较判断是否为多值
				{
					PBBimUIPropertyItem::ListValue oldType;
					double oldValu;
					oldItem_Z->getValue(oldValu);
					if (fabs(oldValu - pCylinder->getBottomPt().z) > 1e-15)
						properties[CylinderPropName::Middle_Z].setMultiValue(true);
				}

			}
		}

		// ----------------------------------------高度---------------------------------------
		{
			double nHeight = pCylinder->getHeight();
			if (0 == i)
			{	
				PBBimUIPropertyItem item(L"高度", nHeight);
				properties[CylinderPropName::Height].swap(item);
			}
			else
			{
				PBBimUIPropertyItem* oldItem = &properties[CylinderPropName::Height];
				if (!oldItem->multiValue())     // 比较判断是否为多值
				{
					PBBimUIPropertyItem::ListValue oldType;
					double nNoldHeight;
					oldItem->getValue(nNoldHeight);
					if (fabs(nNoldHeight - nHeight) > 1e-15)
						properties[CylinderPropName::Height].setMultiValue(true);
				}
			}
		}

		// ----------------------------------------半径---------------------------------------
		{
			double nLength = pCylinder->getRadius();
			if (0 == i)
			{
				PBBimUIPropertyItem item(L"半径", nLength);
				properties[CylinderPropName::Radius].swap(item);
			}
			else
			{
				PBBimUIPropertyItem* oldItem = &properties[CylinderPropName::Radius];
				if (!oldItem->multiValue())     // 比较判断是否为多值
				{
					PBBimUIPropertyItem::ListValue oldType;
					double oldLength;
					oldItem->getValue(oldLength);
					if (fabs(oldLength - nLength) > 1e-15)
						properties[CylinderPropName::Radius].setMultiValue(true);
				}
			}
		}
	}

	lst.AppendGroup(L"构件属性");
	int nIndex = 0;

	for (int i = 0; i < CylinderPropName::CylinderPropCount; ++i)
	{
		lst.Append(nIndex++, properties[i]);
	}
}

TIErrorStatus CylinderPropertyDemo::OnPropertySet(std::vector<BPEntityP> const& refps, int index, PBBimUIPropertyItem const& item)
{
	P3DStatus stu;
	BPProjectP pProject = NULL;
	std::vector<IBPObjectPtr> pbObjs;
	for (auto elementRef : refps)
	{
		if (NULL == pProject)
		{
			pProject = elementRef->getBPProject();
			if (pProject == NULL)
				continue;
		}
		IBPObjectPtr ptrPbObj = BPObjectExtensionManager::getInstance().getBPObject(*elementRef);
		if (!ptrPbObj.isValid())
			continue;
		pbObjs.push_back(ptrPbObj);
	}

	if (pbObjs.size() < 1)
		return TIErrorStatus::failed;

	for (int indexGj = 0; indexGj < pbObjs.size(); ++indexGj)
	{
		IBPObjectPtr ptrObject = pbObjs.at(indexGj);
		CylinderDemo* pCylinder = dynamic_cast<CylinderDemo*>(ptrObject.get());
		if (pCylinder == nullptr)
			continue;
		GePoint3d ptBottom = pCylinder->getBottomPoint();
		switch (index)
		{
		case CylinderPropName::Middle_X:
		{
			double dx = 0.0;
			item.getValue(dx);
			pCylinder->setptMiddlePt_x(dx);
		}
		break;
		case CylinderPropName::Middle_Y:
		{
			double dy = 0.0;
			item.getValue(dy);
			pCylinder->setptMiddlePt_y(dy);
		}
		break;
		case CylinderPropName::Middle_Z:
		{
			double dz = 0.0;
			item.getValue(dz);
			pCylinder->setptMiddlePt_z(dz);
		}
		break;
		case CylinderPropName::Height:
		{
			double nHeight = 0.0;
			item.getValue(nHeight);
			if (nHeight < (1e-15))
			{
				AfxMessageBox(L"请输入大于0的数");
				return TIErrorStatus::failed;
			}
			pCylinder->setHeight(nHeight);
			pCylinder->setBottomPoint(ptBottom);
		}
		break;
		case CylinderPropName::Radius:
		{
			double nRadius = 0.0;
			item.getValue(nRadius);
			if (nRadius < (1e-15))
			{
				AfxMessageBox(L"请输入大于0的数");
				return TIErrorStatus::failed;
			}
			pCylinder->setRadius(nRadius);
		}
		break;

		default:
			break;

		}
		stu = pCylinder->replaceInProject(*pProject);
	}
	return TIErrorStatus::succeed;
}

//属性工厂注册
class CylinderPropertyFactoryDemo :public IToolInterfaceFactory
{
public:
	virtual IToolInterface* CreateInterface() override
	{
		CylinderPropertyDemo* p = new CylinderPropertyDemo();
		p->AddRef();
		return p;
	}
};
static CylinderPropertyFactoryDemo s_CylinderPropertyFactory;
AutoDoRegisterFunctionsBegin
PBBimToolsInterfaceManager::RegisterFactory(PBM_CLASS_Cylinder_Demo, IToolNameProperty, &s_CylinderPropertyFactory);
AutoDoRegisterFunctionsEnd

4.夹点

在底部圆心加了一个夹点,用来移动图形。这里需要调用Demo里面的getBottomPoint()const ,把该点设为夹点。在最后鼠标确定的时候,用新图形覆盖就图形,并把当前的刚体变换坐标传递给Demo保存在Schema表里,右侧的属性栏在夹点移动后,也能正确显示底部圆心坐标。

DragManipulator.h

class CylinderDragManipulatorDemo : public BPPointDragManipulator
{
	DefineSuper(BPPointDragManipulator)
public:
	static CylinderDragManipulatorDemo* Create();
protected:
	CylinderDragManipulatorDemo();
	~CylinderDragManipulatorDemo();
protected:
	//增加夹点控制点
	virtual bool _onCreateControls(::BIMBase::Core::BPEntityCR) override;
	//实现拖拽夹点构件变化效果
	virtual StatusInt _doDragControls(BPEntityR elHandle, BPBaseButtonEventCR ev, bool isDynamics) override;
};

//注册夹点实现类
class CylinderDragManipulatorDemoExtension : public ::BIMBase::Data::IBPDragManipulatorExtension
{
protected:
	virtual BPIDragManipulatorP _getIDragManipulator(::BIMBase::Core::BPEntityCR elHandle, ::BIMBase::Core::BPPickDataCP path) override;
};

 DragManipulator.cpp

CylinderDragManipulatorDemo::CylinderDragManipulatorDemo()
{
}

CylinderDragManipulatorDemo::~CylinderDragManipulatorDemo()
{
}

bool CylinderDragManipulatorDemo::_onCreateControls(::BIMBase::Core::BPEntityCR eh)
{
	//根据传⼊的BPEntity信息获取对象实例
	BIMBase::Core::BPDataPtr ptrData = BPDataUtil::getDataOnEntity(eh);
	if (!ptrData.isValid())
		return false;

	//根据根据实例初始化
	DemoObject::CylinderDemo pbCylinder;
	pbCylinder.initFromData(*ptrData);
	GePoint3d midPt = pbCylinder.getBottomPoint();

	addControlPoint(midPt);
	return true;
}

StatusInt CylinderDragManipulatorDemo::_doDragControls(BPEntityR elHandle, BPBaseButtonEventCR ev, bool isDynamics)
{
	//根据传⼊的BPEntity信息获取对象实例
	BPDataPtr ptrData = BPDataUtil::getDataOnEntity(elHandle);
	if (!ptrData.isValid())
		return false;
	//根据实例初始化
	CylinderDemo pbCylinder;
	pbCylinder.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;
	//根据⿏标移动点与原始点求转换矩阵
	GePoint3d offset = { cursorPt.x - m_orginPt.x, cursorPt.y - m_orginPt.y, cursorPt.z - m_orginPt.z };
	GeTransform tm = GeTransform::create(offset);
	pbCylinder.onTransform(tm);

	::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;
	if (isDynamics)
	{//动态显⽰
		BPGraphicsPtr ptrGraphics = pbCylinder.createPhysicalGraphics(*pProject, curModelId, true);
		GeTransform trans = pbCylinder.getPlacement().toTransform();
		BPGraphicsUtils::transformPhysicalGraphics(*ptrGraphics, trans);
		if (ptrGraphics.isValid())
		{
			elHandle = ptrGraphics->getEntityR();
		}
	}
	else
	{//最终点击后Replacex
		BPPlacement placement = pbCylinder.getPlacement();
		GePoint3d ptOrigin = placement.getOrigin();
		pbCylinder.setptMiddlePt_x(ptOrigin.x);
		pbCylinder.setptMiddlePt_y(ptOrigin.y);
		pbCylinder.setptMiddlePt_z(ptOrigin.z);
		return pbCylinder.replaceInProject(*pProject);
	}
	return SUCCESS;
}

CylinderDragManipulatorDemo* CylinderDragManipulatorDemo::Create()
{
	return new CylinderDragManipulatorDemo();
}

BPIDragManipulatorP CylinderDragManipulatorDemoExtension::_getIDragManipulator(::BIMBase::Core::BPEntityCR elHandle, ::BIMBase::Core::BPPickDataCP path)
{
	return CylinderDragManipulatorDemo::Create();
}

5.相关配置

1.添加schema表名的宏和圆柱在schema表里面的类名

//schema
#define PBM_SCHEMA_Demo_W            L"TemSchema_wMElik"
#define PBM_SCHEMA_Demo              "TemSchema_wMElik"

//Cylinder
#define PBM_CLASS_Cylinder_Demo_W            L"ATDCylinder"
#define PBM_CLASS_Cylinder_Demo              "ATDCylinder"

2.在DllMain.cpp里面添加 注册运行时类型判断 和 注册造型夹点。

//注册造型夹点
classname = std::wstring(PBM_SCHEMA_Demo_W).append(L":").append(PBM_CLASS_Cylinder_Demo_W);
		BPManipulatorExtensionManager::registerDragManipulatorExtension(classname.c_str(), new CylinderDragManipulatorDemoExtension());

//注册运行时类型判断
BPObjectExtensionManager::getInstance().registerBPObjectExtension(PBM_SCHEMA_Demo, PBM_CLASS_Cylinder_Demo, new CylinderDemoExtension());

3.Schema表

用Schema编辑器打开你自己的Schema表,然单击你自己那个表的Classes节点选择 增加Classes,然后在右侧配置该类。

配置完后点击属性,去添加你要存储的Demo的关键信息,例如圆柱的底圆坐标和半径、高, 确定了这三个数据就能确定该圆柱。添加完数据以后,就可以保存了(注意该文件的路径)。

剩下的项目配置就不做多余陈述,应该没啥问题的,有问题请参考第1章 Hello BIMBase (pkpm.cn)进行配置。

6.出现的错误及解决方法

1.布置时预显的图形不跟着鼠标走,图形距离坐标原点的距离 等于 鼠标指针到原点的距离的2倍

问题出现的原因及解决办法:布置工具的__createOnePtData() 传递基本数据的时候,设置了刚体的变换数据,即:

    BPPlacement newPlacement  = m_Cylinder.getPlacement();	
	newPlacement.setOrigin(ptOri);
	m_Cylinder.setPlacement(newPlacement);

2.布置时,确定布置时弹出 不能添加到工程

问题出现的原因及解决办法:有很多原因会导致这个问题,有:

1.Schema文件配置不对,表里面的属性数据类型和你存进去的数据类型不对。这个主要去调试Demo的_copyToData() 、_initFromData()这两个函数;

2.Dllmain.cpp里面没有注册,直接去该文件去注册就行;

3.坐标问题

这个问题有很多问题会导致,主要就是刚体变化结构参数的设置,局部坐标和全局坐标没有设置正确。在Demo的_createPhysicalGraphics()函数里面,构造Info时,用的局部坐标,建议直接把图形中心设为坐标原点。在gset这个中心坐标时,都去变化一下刚体变化参数就行,最后在夹点移动后,用旧图形替代新图形的时候,把中心坐标赋值保存(详见DragManipulator.cpp)。

  • 39
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在C++ ObjectARX中进行二次开发创建自定义实体并将其添加到图层,可以按照以下步骤进行: 1. 在Visual Studio中创建一个新的ObjectARX项目,并将其设置为使用AutoCAD应用程序类型。 2. 在项目中包含需要的头文件,例如“aced.h”、“dbents.h”、“dbmain.h”以及“dbapserv.h”。 3. 创建一个新的实体类,该类继承自AcDbEntity类,并实现必要的函数,例如“dwgInFields”、“dwgOutFields”、“cloneMe”等。 4. 在类中添加成员变量,以存储实体的属性信息。 5. 实现一个新的命令函数,该函数将创建新的实体,并将其添加到指定的图层中。在命令函数中,可以使用AcDbBlockTable、AcDbBlockTableRecord和AcDbEntityTable等类来操作AutoCAD数据库。 下面是一个示例代码,演示如何在C++ ObjectARX中创建自定义实体并添加到图层: ```cpp void createCustomEntity() { // 获取当前文档的数据库 AcDbDatabase* pDatabase = acdbHostApplicationServices()->workingDatabase(); // 获取当前文档的图层表 AcDbLayerTable* pLayerTable; pDatabase->getLayerTable(pLayerTable, AcDb::kForRead); // 获取指定图层的ObjectId AcDbObjectId layerId; pLayerTable->getAt("MyLayer", layerId, Adesk::kTrue); pLayerTable->close(); // 创建一个新的实体 MyEntity* pEntity = new MyEntity; // 设置实体的属性 pEntity->setColorIndex(1); pEntity->setLayer(layerId); // 将实体添加到数据库中 AcDbBlockTable* pBlockTable; pDatabase->getBlockTable(pBlockTable, AcDb::kForRead); AcDbBlockTableRecord* pBlockTableRecord; pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord, AcDb::kForWrite); pBlockTable->close(); AcDbObjectId entityId; pBlockTableRecord->appendAcDbEntity(entityId, pEntity); pBlockTableRecord->close(); acutPrintf("New entity created with ID: %lx", entityId.asOldId()); } ``` 在上面的代码中,我们首先获取当前文档的数据库和图层表。然后,我们获取名为“MyLayer”的图层的ObjectId。接下来,我们创建一个新的自定义实体,并将其属性设置为颜色索引为1,图层为“MyLayer”。最后,我们将实体添加到数据库中,并在命令行上显示其ObjectId。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值