参考了概要 (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)。