在BIMBase中,对象的编辑有以下几种方法:

  • 右键菜单及编辑菜单栏中的移动、复制、镜像、删除功能。对于用户自建对象,需用户代码实现移动、复制、镜像、删除功能;
  • 夹点拖拽功能,用户自建对象需代码实现;
  • 属性编辑功能,用户自建对象需代码实现;

3.2.1 移动

对于自建对象,需实现自己的复制功能,可通过重写IToolMove类实现,IToolMove类提供的接口如表3-1所示。

表3-1 IToolMove类接口

方法 描述
ElementsSelected(vector&) 过滤选择对象接口
Dynamic(vector&,GeTransform,BPRedrawEntitys) 动态预览接口
Move(vector&, GeTransform, unsigned int) 实现移动效果接口
CacheDynamic() 是否使用默认动态效果
class ToolCubeMoveDemo:public IToolMove
{
public:
    ToolCubeMoveDemo();
    ~ToolCubeMoveDemo();

    //选中需要移动的构件后响应
    virtual void ElementsSelected(vector<BPEntityPtr> & refps) override;
    //如果返回false则会调用自定义Dynamic函数,调自定义函数时最好不要是
    //计算密集型操作
    virtual bool CacheDynamic() override { return true; }
    //动态移动物体时响应函数,需要CacheDynamic为false时函数启动
    virtual void Dynamic(std::vector<BPEntityPtr> const & refps, GeTransformCR transform, BPRedrawEntitys& redrawElems) override;
    //移动完构件点击布置时响应函数
    virtual void Move(std::vector<BPEntityPtr> const & refps, GeTransformCR transform) override;
};

代码3-9:立方体移动(头文件)

#include "pch.h"
#include "ToolCubeMoveDemo.h"
#include "CubeDemo.h"

ToolCubeMoveDemo::ToolCubeMoveDemo()
{}
ToolCubeMoveDemo::~ToolCubeMoveDemo()
{}
void ToolCubeMoveDemo::Dynamic(std::vector<BPEntityPtr> const & refps, GeTransformCR transform, BPRedrawEntitys& redrawElems){}

void ToolCubeMoveDemo::Move(std::vector<BPEntityPtr> const & refps, GeTransformCR transform)
{
    for (BPEntityPtr refP : refps)
    {
        if (refP.isNull())
            continue;
            //根据传入的BPEntity信息获取对象实例
        BPDataPtr ptrData = BPDataUtil::getDataOnEntity(*refP);
        if (!ptrData.isValid())
        continue;

        DemoObject::CubeDemo pbCube;
        pbCube.initFromData(*ptrData);

        //选中的墙乘以移动的转换矩阵,移动到点击的位置
        pbCube.onTransform(transform);

        //新位置的替换旧位置的
        pbCube.replaceInProject(*refP->getBPProject());
    }
}
void ToolCubeMoveDemo::ElementsSelected(std::vector<BPEntityPtr> & refps)
{}

//注册移动
class CubeMoveDemoFactory :public IToolInterfaceFactory
{
public:
    virtual IToolInterface* CreateInterface() override
    {
        ToolCubeMoveDemo *p = new ToolCubeMoveDemo();
        p->AddRef();
        return p;
    }
};
static CubeMoveDemoFactory s_CubeMoveDemoFactory;

AutoDoRegisterFunctionsBegin
PBBimToolsInterfaceManager::RegisterFactory("CubeDemo",IToolNameMove,&s_CubeMoveDemoFactory);
AutoDoRegisterFunctionsEnd

代码3-10:立方体移动(源文件)

示例代码3-9,3-10展示了Cube移动实现的部分代码,主要通过重写Move接口实现Cube的移动。对象移动类采用工厂模式进行管理,需要将当前对象的移动工厂利用PBBimToolsInterfaceManager类进行注册。

3.2.2 复制

复制功能同移动功能,可重写类IToolCopy实现。

3.2.3 镜像

镜像功能同移动功能,可重写类IToolMirror实现。

3.2.4 删除

删除功能同移动功能,可重写类IToolDelete实现。

3.2.5 夹点

夹点功能可实现构件的自由拖拽,如图3-5所示,拖拽选中构件后显示的夹点,可自由编辑构件。



图3-5 CubeTest夹点

对于用户自建对象,可按需要实现夹点功能。实现夹点功能步骤如下:

  • 在插件加载入口DllMain函数中注册对象的夹点,详见代码3-11;
  • 继承类BPPointDragManipulator并重写_onCreateControls_doDragControls接口可实现增加夹点及夹点拖拽效果的实现,详见代码3-12,3-13;
  • 继承类IBPDragManipulatorExtension,注册夹点实现类,需重写_getIDragManipulator接口,返回上一步骤实现的类,详见代码3-14。
//注册造型夹点
std::wstring classname = std::wstring(L"DemoSchema").append(L":").append(L"CubeDemo");
BPManipulatorExtensionManager::registerDragManipulatorExtension(classname.c_str(), new MyCubeDragManipulatorDemoExtension());

代码3-11:立方体夹点注册

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

代码3-12:立方体夹点实现(头文件)

#include "pch.h"
#include "MyCubeDragManipulatorDemo.h"
#include "CubeDemo.h"
using namespace DemoObject;
MyCubeDragManipulatorDemo::MyCubeDragManipulatorDemo()
{}
MyCubeDragManipulatorDemo::~MyCubeDragManipulatorDemo()
{}
bool MyCubeDragManipulatorDemo::_onCreateControls (::BIMBase::Core::BPEntityCR eh)
{
    //根据传入的BPEntity信息获取对象实例
    BIMBase::Core::BPDataPtr ptrData = BPDataUtil::getDataOnEntity(eh);
    if (!ptrData.isValid())
        return false;

    //根据根据实例初始化
    DemoObject::CubeDemo pbCube;
    pbCube.initFromData(*ptrData);
    GePoint3d startPt, endPt, midPt;
    startPt = pbCube.getStartPoint();
    endPt = pbCube.getEndPoint();
    midPt = pbCube.getMiddlePoint();

    // 基础数据
    double height = pbCube.getHeight();
    addControlPoint(startPt);
    addControlPoint(endPt);
    addControlPoint(midPt);
    return true;
}

StatusInt MyCubeDragManipulatorDemo::_doDragControls(BPEntityR elHandle,BPBaseButtonEventCR ev, bool isDynamics)
{
    //根据传入的BPEntity信息获取对象实例
    BPDataPtr ptrData = BPDataUtil::getDataOnEntity(elHandle);
    if (!ptrData.isValid())
        return false;
    //根据实例初始化
    CubeDemo pbCube;
    pbCube.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;
    //长度方向中点设置为移动点,端点设置为拖拽点
    if (index != 2)
    {
        //通过转换矩阵获取原点及坐标信息
        GeTransform curTm = pbCube.getPlacement().toTransform();
        GePoint3d ptOri;
        GeVec3d vecX, vecY, vecZ;
        curTm.getOriginAndVectors(ptOri, vecX, vecY, vecZ);

        double dLenNew = pbCube.getLength();
        GeVec3d vecXNew = vecX;
        GePoint3d ptOriNew = ptOri;
        if (index == 0)
        {//起点
        //根据新起点重新计算墙长度及坐标系
            GePoint3d ptEnd = pbCube.getEndPoint();
            dLenNew = cursorPt.distance(ptEnd);
            vecXNew = GeVec3d::createByStartEndNormalize(cursorPt, ptEnd);
            ptOriNew = cursorPt;
    }
    else
    {//终点
    //根据新的终点重新计算长度及坐标系
        dLenNew = cursorPt.distance(ptOri);
        vecXNew = GeVec3d::createByStartEndNormalize(ptOri, cursorPt);
    }

    GeVec3d vecYNew = vecZ^vecXNew;
    //根据新计算的坐标及原点得到转换矩阵
    GeTransform transNew = GeTransform::createByOriginAndVectors(ptOriNew, vecXNew, vecYNew, vecZ);

    BPPlacement placNew;
    placNew.fromTransform(transNew);
    //墙设置新的转换矩阵,转换到新的位置
    pbCube.setPlacement(placNew);
    pbCube.setLength(dLenNew);
    }
    else
    {
    //根据鼠标移动点与原始点求转换矩阵
    GePoint3d offset = { cursorPt.x - m_orginPt.x, cursorPt.y - m_orginPt.y, cursorPt.z - m_orginPt.z };
    GeTransform tm = GeTransform::create(offset);
    pbCube.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= pbCube.createPhysicalGraphics(*pProject, curModelId, true);
        GeTransform trans = pbCube.getPlacement().toTransform();
        BPGraphicsUtils::transformPhysicalGraphics(*ptrGraphics, trans);
        if (ptrGraphics.isValid())
        {
            elHandle = ptrGraphics->getEntityR();
        }
    }
    else
    {//最终点击后Replace
        return pbCube.replaceInProject(*pProject);
    }
    return SUCCESS;
}
MyCubeDragManipulatorDemo* MyCubeDragManipulatorDemo::Create()
{
    return new MyCubeDragManipulatorDemo();
}

代码3-13:立方体夹点实现(源文件)

class MyCubeDragManipulatorDemoExtension : public ::BIMBase::Data::IBPDragManipulatorExtension
{
protected:
    virtual BPIDragManipulatorP _getIDragManipulator (::BIMBase::Core::BPEntityCR elHandle, ::BIMBase::Core::BPPickDataCP path) override
    {
    //返回自己的夹点类
        return MyCubeDragManipulatorDemo::Create();
    }
};

代码3-14:注册夹点实现类

需要指出,运行当前夹点功能,需要对CubeDemo文件进行修改,主要是对获取立方体的起点、中点、终点进行了封装,获取的是世界坐标系下的点。修改代码如下:

//获取起点
GePoint3d    getStartPoint() const;
//获取中点
GePoint3d    getMiddlePoint() const;
//获取终点
GePoint3d    getEndPoint() const;

代码3-15:CubeDemo头文件补充

GePoint3d DemoObject::CubeDemo::getStartPoint() const
{
    //通过转换矩阵获取原点
    return getPlacement().getOrigin();
}

GePoint3d DemoObject::CubeDemo::getMiddlePoint() const
{
    GePoint3d ptMiddle = GePoint3d::create(getLength() / 2.0, 0, 0);
    //墙局部坐标系转到世界坐标系下
    GeTransform trans = getPlacement().toTransform();
    trans.multiply(ptMiddle);
    return ptMiddle;
}

GePoint3d DemoObject::CubeDemo::getEndPoint() const
{
    GePoint3d ptEnd = GePoint3d::create(getLength(), 0, 0);
    //墙局部坐标系转到世界坐标系下
    GeTransform trans = getPlacement().toTransform();
    trans.multiply(ptEnd);
    return ptEnd;
}

代码3-16:CubeDemo源文件补充

3.2.6 属性

对于自建对象,用户可通过重写IToolProperty类实现自建对象的属性功能,如图3-6所示,在属性栏显示Cube的属性长度、宽度、高度,并可通过修改属性值驱动对象变化。



图3-6 CubeDemo属性展示

示例代码3-15,3-16展示了Cube属性实现的部分代码,其中OnPropertyGet中实现从对象获取属性显示在属性栏的功能,OnPropertySet实现在属性栏修改属性,驱动对象修改的功能。属性类采用工厂模式进行管理,需要将当前对象的属性工厂利用PBBimToolsInterfaceManager类进行注册。

若属性代码实现后没有调出属性功能,可参见示例代码3-7对象的注册,查看是否对自己的构件实现了注册。

class MyCubePropertyDemo :public IToolProperty
{
    enum CubePropName
    {
    Length,         //长度
    Height,         //高度
    Width,          //宽度
    CubePropCount
    };
public:
    MyCubePropertyDemo();
    ~MyCubePropertyDemo();

    //获取属性并且在属性框显示
    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;
};

代码3-17:立方体属性(头文件)

#include "pch.h"
#include "MyCubePropertyDemo.h"
#include "CubeDemo.h"
MyCubePropertyDemo::MyCubePropertyDemo()
{}
MyCubePropertyDemo::~MyCubePropertyDemo()
{}
void MyCubePropertyDemo::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[CubePropName::CubePropCount];
    for (int i = 0; i < pbObjs.size(); ++i)
    {
        IBPObjectPtr ptrObj= pbObjs.at(i);
        DemoObject::CubeDemoP pCube = dynamic_cast< DemoObject::CubeDemoP>(ptrObj.get());
        if (NULL == pCube)
            continue;

        // -----------------长度--------------------
        {
            int nLength = pCube->getLength();
            if (0 == i)
            {
                PBBimUIPropertyItem item(L"长度", nLength);
                properties[CubePropName::Length].swap(item);
            }
            else
            {
                PBBimUIPropertyItem *oldItem = &properties[CubePropName::Length];
                if (!oldItem->multiValue())
                {
                    PBBimUIPropertyItem::ListValue oldType;
                    int oldLength;
                    oldItem->getValue(oldLength);
                    if (oldLength != nLength)
                        properties[CubePropName::Length].setMultiValue(true);
                }
            }
        }
    }


    lst.AppendGroup(L"构件属性");
    for (int i = 0; i < CubePropName::CubePropCount; ++i)
    {
        lst.Append(i+1, properties[i]);
    }
}

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

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

    for (int indexGj = 0; indexGj < pbObjs.size(); ++indexGj)
    {
        IBPObjectPtr ptrObj= pbObjs.at(indexGj);
        DemoObject::CubeDemoP pCube = dynamic_cast< DemoObject::CubeDemo*>(ptrObj.get());
        if (pCube == nullptr)
            continue;
        switch (index-1)
        {
            case CubePropName::Length:
            {
                int nLen = 0;
                item.getValue(nLen);
                pCube->setLength(nLen);
            }
            break;
            default:
            break;
        }
        pCube->replaceInProject(*pProject);
    }
    return TIErrorStatus::succeed;
}
class CubePropertyFactoryDemo :public IToolInterfaceFactory
{
public:
    virtual IToolInterface* CreateInterface() override
    {
        MyCubePropertyDemo *p = new MyCubePropertyDemo();
        p->AddRef();
        return p;
    }
};
static CubePropertyFactoryDemo s_CubePropertyFactory;

AutoDoRegisterFunctionsBegin
PBBimToolsInterfaceManager::RegisterFactory("CubeDemo", IToolNameProperty,&s_CubePropertyFactory);
AutoDoRegisterFunctionsEnd

代码3-18:立方体属性(源文件部分代码)