本节主要基于第3章创建的CubeTest对象,实现在立方体上开洞的效果。CubeTest 对象创建见3.1.5节示例代码3-6。

对象的创建主要分为三点:

一是创建一个洞口对象;

二是创建CubeTest 与洞口对象的关联关系;

三是在原CubeTest 对象上开洞,通过CubeTest 对象和洞口对象的布尔实现。

对象的布置中,需要在布置洞口时拾取CubeTest 对象,并在洞口对象布置后刷新CubeTest 对象。

9.2.1 创建洞口对象

3.1.5节中已经讲到,对象创建主要分为创建对象数据表、实现对象类、对象注册三个步骤,本节将不再赘述创建对象数据表和对象注册两部分,主要讲解洞口对象类的实现。

本节的洞口对象几何造型类似CubeTest的拉伸体造型,为了实现洞口效果,设置洞口几何图素的透明度为1。

[BPElementClassAttribute(schemaName = "DemoSchema", className = "OpenningDemo")]
public class OpenningDemo : BPGraphicElement
{
    int mWidth = 200;
    int mLength = 500;
    int mHeight = 500;
    int mColor = Color.Blue.ToArgb();
    public double mDTransparency = 1;

    [BPPropertyDefinitionAttribute(fieldName = "Length")]
    public int length
    {
        get { return mLength; }
        set { mLength = value; }
    }
    [BPPropertyDefinitionAttribute(fieldName = "width")]
    public int width
    {
        get { return mWidth; }
        set { mWidth = value; }
    }
    [BPPropertyDefinitionAttribute(fieldName = "Height")]
    public int height
    {
        get { return mHeight; }
        set { mHeight = value; }
    }
    protected override BIMBaseCS.Core.BPGraphics _createGraphics(BPModel model)
    {
        BIMBaseCS.Core.BPGraphics graphics = new BPGraphics(model);
        GePoint3d Point1 = new GePoint3d(length, 0, 0);
        GePoint3d Point2 = new GePoint3d(length, width, 0);
        GePoint3d Point3 = new GePoint3d(0, width, 0);
        GePoint3d Point4 = new GePoint3d(0, 0, 0);
        List<GePoint3d> listp = new List<GePoint3d>();
        listp.Add(Point1);
        listp.Add(Point2) ;
        listp.Add(Point3) ;
        listp.Add(Point4) ;
        BIMBaseCS.Geometry.GeCurveArray curve =
        GeCurveArray.createLinestringArray(listp,
        GeCurveArray.BoundaryType.Outer,false);
        GeExtrusionInfo info = new GeExtrusionInfo(curve,new GeVec3d(0, 0, height), true);
        IGeSolidBase solid = IGeSolidBase.createExtrusion(info);
        BIMBaseCS.Geometry.BPGeSymbology symb = new BPGeSymbology();
        symb.weight = 3;
        symb.color = Color.FromArgb(Color.White.ToArgb() );
        graphics.addSolid(solid, symb,mDTransparency) ;
        return graphics;
    }
}

代码9-1 洞口对象

从洞口对象源文件的_createPhysicalGraphics接口实现中我们可以发现,洞口对象几何构造基本和CubeTest对象相同,只在洞口对象需要将透明度设置为1。

9.2.2 创建立方体对象与洞口对象的关联关系

在实际应用场景中,存在许多构件联动的需求,比如墙与门窗的联动等,这些在BIMBase SDK中通过关联关系实现。

本章开洞范例中,需要将立方体与洞口对象进行关联,才能实现在洞口编辑时刷新立方体,或者立方体编辑时联动洞口。

关联关系的创建类似对象创建中数据表的创建,数据表中存在一种关联关系表,按照条件添加关系表(见附录2.3.3)后,可通过BPRelatedDataUtil中相关接口进行关联关系的创建、查找和删除。

9.2.3 在立方体对象中实现关联洞口开洞

示例代码3-6已经详细讲解了CubeTest对象的创建,本节将在其基础上进行补充,实现CubeDemo和洞口对象的布尔操作。

protected override BIMBaseCS.Core.BPGraphics _createGraphics(BPModel model)
{
    BIMBaseCS.Core.BPGraphics graphics = new BPGraphics(model);
    GePoint3d Point1 = new GePoint3d(length, 0, 0);
    GePoint3d Point2 = new GePoint3d(length, width, 0);
    GePoint3d Point3 = new GePoint3d(0, width, 0);
    GePoint3d Point4 = new GePoint3d(0, 0, 0);
    List<GePoint3d> listp = new List<GePoint3d>();
    listp.Add(Point1);
    listp.Add(Point2);
    listp.Add(Point3);
    listp.Add(Point4);
    BIMBaseCS.Geometry.GeCurveArray curve = GeCurveArray.createLinestringArray(listp, GeCurveArray.BoundaryType.Outer,false);
    GeExtrusionInfo info = new GeExtrusionInfo(curve,new GeVec3d(0,0, height), true);
    IGeSolidBase solid = IGeSolidBase.createExtrusion(info);
    BIMBaseCS.Geometry.BPGeSymbology symb = new BPGeSymbology();
    symb.weight = 3;
    symb.color = Color.FromArgb(color);
    graphics.addSolid(solid, symb, mDTransparency);

    //以下为创建洞口代码//查找关联关系
    BPDocument doc = BPApplication.singleton().activeDocument; BPDataKey keyCube = this.dataKey;
    if (keyCube == null) return graphics;
    List<BPDataKey> keyList = new List<BPDataKey>();
    BPRelatedDataUtil.getRelatedElements(keyList,doc,keyCube);
    if (keyList.Count == 0) return graphics;
    BPGraphics graphicBoolResult = new BPGraphics();

    foreach (BPDataKey key in keyList)
    {
        BPObject _object = BPObjectUtil.getObjFromData(doc,key);
        if (_object != null)
        {
            ApiTestOpenning Openning = _object as ApiTestOpenning;
            if (Openning == null) continue;
            //如果当前宽度不一致,修改洞口宽度
            if (Math.Abs(Openning.width - width) > 0.01)
            {
                Openning.width = width;
                Openning.replaceInDocument(doc);
            }
            BPGraphicElement graphicEle = _object as BPGraphicElement;
            if (graphicEle == null) continue;
            BPGraphics graphicOpenning = graphicEle.createGraphics(model);
            int tolerance = 0;
            BPBooleanUtils.getAngleTolerance(ref tolerance);
            BPBooleanUtils.setAngleTolerance(36);//防止面片变形
            //在 cube 的局部坐标系下进行布尔
            BPPlacement openningPlace = Openning.placement;
            GeTransform openningTrans = openningPlace.toTransform();
            BPPlacement cubeP1ace = this.placement;
            GeTransform cubeTrans = cubeP1ace.toTransform(); cubeTrans.setByInverse(cubeTrans);
            BPGraphicUtil.transformPhysicalGraphics(ref
            graphicOpenning, GeTransform.createByProduct(cubeTrans, openningTrans));
            BPStatus status = BPBooleanUtils.doBoolean(refgraphicBoolResult, graphics,graphicopenning, BPBooleanOp.Substract);
        }
    }
    return graphicBoolResult;
}

代码9-2 CubeTest(源文件部分代码)

示例代码9-2为立方体的造型代码,前半部分为原有造型代码,即通过拉伸体造型创建立方体;增加的代码中,通过关联关系获取到与立方体关联的洞口对象,再获取洞口对象的几何图素,分别与立方体进行布尔操作,最终得到一个带洞的立方体。

9.2.4 布置洞口对象

本节通过2.3.2中所讲的IBPPointCommand工具实现洞口对象的布置。与普通布置工具不同的是,布置洞口时需要拾取CubeTest 对象,在洞口对象布置后需添加CubeTest与洞口对象的关联关系并刷新CubeTest对象。

[BPExternalCommandAttribute(name = "ExLayoutOpenningDemo")]
public class ExLayoutOpenning : IBPPointCommand
{
    OpenningDemo mOpenning;
    CubeDemo mCube;
    public ExLayoutOpenning()
    {
        mOpenning = new OpenningDemo();
        mCube = new CubeDemo();
    }
    public override bool onLeftClick(BPCommandContext context)
    {
        BPDocument doc = BPApplication.singleton().activeDocument;
        BPModel model = doc.modelManager.activeModel;
        //确保洞口是开在立方体上的
        if (mCube == null) return false;
        if (mCube.dataKey == null) return false;
        if (mOpenning == null) return false;
        mOpenning.addToDocument(model);
        BPRelatedDataUtil.addRelationship(doc, mCube.dataKey, mOpenning.dataKey, "TestSchema", "CubeWithOpenning");
        mCube.replaceInDocument(doc);
        BPViewport view = doc.viewManager.getActivedViewport();
        view.forceHealImmediate();
        return true;
    }
    public override bool onRightClick(BPCommandContext context)
    {
        callExitTool();
        return true;
    }
    public override void onDynamicDraw(BPCommandContext context)
    {
        BPDocument doc = BPApplication.singleton().activeDocument;
        BPModel model = doc.modelManager.activeModel;
        BPViewport view = doc.viewManager.getActivedViewport();
        ApiTestOpenning openning = new ApiTestOpenning();
        string str = "";

        int erroCode = 0;
        BPGraphics graphics =
        BPElementLocateManager.doLocatePickData(ref erroCode, str, true, context.mousePoint, doc.viewManager.getActivedViewport(), true);
        if (graphics == null) return;
        BPObject _object = BPObjectUtil.getObjFromData(doc, graphics.getGraphicElement());
        mCube = _object as ApiTestCube; if (mCube == null) return;

        // 获取 Cube对象端点,将鼠标点投影到cube基线上
        double AngleRadians = mCube.placement.getAngles().getYaw().getRadians();
        GePoint3d ptCubeS = mCube.placement.getOrigin();
        GePoint3d ptCubeE = ptCubeS + new GeVec3d(mCube.length * Math.Cos(AngleRadians), mCube.length * Math.Sin(AngleRadians), 0);
        ptCubeS.z = 0;
        ptCubeE.z = 0;
        GePoint3d ptEvOnCube = GePoint3d.createByZero();
        double ptX = (ptCubeS.x + ptCubeE.x) * 0.5;
        double ptY = (ptCubeS.y + ptCubeE.y) * 0.5;
        GePlane3d planeP = new GePlane3d(ptCubeS, ptCubeE, new GePoint3d(ptX, ptY, mCube.height));
        planeP.projectPointToPlane(ref ptEvOnCube, context.mousePoint);
        ptEvOnCube.z = 0;

        // 获取 cube对象的方向使洞口与cube 宽度一致
        GePoint3d ori = ptEvOnCube;
        GeYPRAngles angel = mCube.placement.getAngles();
        BPPlacement openningPlace = new BPPlacement(ori, angel);
        mOpenning.width = mCube.width;
        mOpenning.placement = openningPlace;
        BPGraphics graphic = mOpenning.createGraphics(model);
        BPGraphicUtil.transformPhysicalGraphics(ref graphic, mOpenning.placement.toTransform());
        view.dynamicDraw(graphic);
    }
}

代码2-1

下图为立方体开洞效果。

图9-1 立方体开洞