本节主要基于第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 立方体开洞