作者:张勇 中建八局装饰工程有限公司 【摘要】 本文讲述在AutoCAD二次开发平台基于C#编程求解复杂面域几何属性的方法,从只有一个连通域的面域到多个连通域的面域,由简单到复杂,逐步深入探究几何属性计算机求解的过程。 【关键词】复杂面域 面域几何属性 编程求解 【Abstract】 Complex Region Geometric Properties of An Area Programming Solution 【Key words】 This paper describes the method of solving the geometric attributes of complex regions based on C # programming, from regions with only one connected region to regions with multiple connected regions, from simple to complex, and gradually explores the process of computer solving geometric attributes. 在土木行业中,大型复杂结构计算一般采用专业的有限元软件,如YJK、PKPM、ANSYS、SAP2000、3D3S等,但一些简单结构,用静力学手册公式计算即可解决,这些结构的计算适用于开发简单的桌面应用程序,在工程设计应用中可大大提高工作效率。 幕墙的立柱和横梁就是这样的可自编公式计算的简单结构,但其铝合金型材截面通常比较复杂,在得到杆件内力后,计算复杂面域的几何属性是必不可少的,本文试图将这方面的知识作一简单阐述。 在AutoCAD二次开发平台,以C#编程语言为背景,分几个模块讲述其中的重要代码和编程思路: 1,从AutoCAD中获取曲线。 曲线种类以代码方式表示如下: RXClass.GetClass(typeof(Line)).DxfName; //直线 RXClass.GetClass(typeof(Polyline)).DxfName; //二维多段线 RXClass.GetClass(typeof(Circle)).DxfName; //圆 RXClass.GetClass(typeof(Arc)).DxfName; //圆弧 RXClass.GetClass(typeof(Spline)).DxfName; //样条曲线 RXClass.GetClass(typeof(Ellipse)).DxfName; //椭圆及椭圆弧 将上述类型定义为一个过滤器,在选择集中使用这个过滤器得到满足要求的曲线。 TypedValue[] values = { new TypedValue((int)DxfCode.Operator, '<or'), new TypedValue((int)DxfCode.Start, dxfnameLine), new TypedValue((int)DxfCode.Start, dxfnamePolyline), new TypedValue((int)DxfCode.Start, dxfnameCircle), new TypedValue((int)DxfCode.Start, dxfnameArc), new TypedValue((int)DxfCode.Start, dxfnameSpline), new TypedValue((int)DxfCode.Start, dxfnameEllipse), new TypedValue((int)DxfCode.Operator, 'or>') }; var filter = new SelectionFilter(values); var entSelected = ed.GetSelection(filter); if (entSelected.Status == PromptStatus.OK) { foreach (var id in entSelected.Value.GetObjectIds()) { Curve c = trans.GetObject(id, OpenMode.ForRead, false) as Curve; Curves.Add(c); } } 2,由曲线生成面域。 当曲线组成一个连通域时: 编程思路: 1)将每根平面闭合曲线生成面域; 2)将所有面域加入列表; 3)按面域面积大小排序; 4)将第一个面域减去其它所有面域,得到一个新的面域即为所求面域。 如下图,面域1面积最大,减去面域2和面域3即得到铝型材的截面面域。 当曲线组成多个连通域时: 编程思路: 1)将每根平面闭合曲线生成面域; 2)将所有面域加入列表; 3)按面域面积大小排序; 4)将第一个面域与其它所有面域相减,如果所得结果的面积没有变化,则被减面域与原面域不相交,新建一个面域列表装载这些面域,如果所得结果的面积减小,则被减面域与原面域相交,保存相减后的新面域。 5)将新建列表中的每个面域执行第4)步操作,得到一个新面域和一个新建面域列表。 6)循环执行第5)步操作直到无新建面域列表为止。 7)将每次得到的新面域组成一个集合,即为最终的型材截面。 如下图,面域1面积最大,减去面域2和面域3即得到一个新面域,因为每减一次面积比原来小,所以不会新建面域列表,当减去面域4时,面积没有变化,可知其与被减面域没有相交,故新建一个面域列表,再用面域4去减该列表中的面域,下图面域4中没有子面域,即退出方法,返回两个面域。 核心代码如下: List<Region> regionList = new List<Region>();//新建面域列表,存储创建的面域 //将可变数组转化为集合类,用于面域的创建 DBObjectCollection curveCollection = new DBObjectCollection(); foreach (Curve curve in curves)//遍历曲线 { curveCollection.Add(curve);//将曲线添加到集合中 } try { //根据曲线集合,在内存中创建面域对象集合 DBObjectCollection regionObjs = Region.CreateFromCurves(curveCollection);//此方法API自带 //将面域对象集合复制到面域列表 foreach (Region region in regionObjs) { regionList.Add(region); } //将所得面域按面积大小排序 List<Region> orderRegions = (from r in regionList orderby r.Area descending select r).ToList(); return orderRegions; } catch //如果面域创建失败,返回空值。 { regionList.Clear();//清空面域列表 return regionList;//返回空的面域列表 } for (int i = 0; i < RegionList.Count - 1; i++) { RegionList[0].BooleanOperation(BooleanOperationType.BoolSubtract, RegionList[i + 1]); } 3,由面域计算几何属性。 .NET库中尚未包含相应功能的函数,需要使用P/Invoke技术在.NET程序中调用C++函数,由面域返回几何属性的函数在Acdb**.dll文件(此文件是C++编写的)里。下面以AutoCAD2020为例,其它版本AutoCAD对应的Acdb**.dll文件如下:默认安装在C:\Program Files\Autodesk\AutoCAD 20**文件夹里。
核心代码如下: [DllImport('acdb23.dll', CallingConvention = CallingConvention.ThisCall, EntryPoint = //标识符,不随版本变化'?getAreaProp@AcDbRegion@@UEBA?AW4ErrorStatus@Acad@@AEBVAcGePoint3d@@AEBVAcGeVector3d@@1AEAN2AEAVAcGePoint2d@@QEAN24QEAVAcGeVector2d@@433@Z')] private static extern ErrorStatus getAreaProp18(IntPtr region, ref Point3d origin, //图形原点 ref Vector3d xAxis, //X主轴线 ref Vector3d yAxis, //X主轴线 out double perimeter, //周长 out double area, //面积 out Point2d centroid, //形心 double[] momInertia, //惯性矩 out double prodInertia, //惯性积 double[] prinMoments, //主惯性矩 Vector2d[] prinAxes, //主惯性轴 double[] radiiGyration, //回转半径 out Point2d extentsLow, //外包框最低点 out Point2d extentsHigh); //外包框最高点 //获取面域的形心。 public static Point2d GetCentroid(this Region region) { Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; CoordinateSystem3d coord = ed.CurrentUserCoordinateSystem.CoordinateSystem3d; Point3d origin = coord.Origin; Vector3d xAxis = coord.Xaxis; Vector3d yAxis = coord.Yaxis; getAreaProp(region.UnmanagedObject, ref origin, ref xAxis, ref yAxis, out perimeter, out area, out centroid,momInertia, out prodInertia, prinMoments, prinAxes, radiiGyration, out extentsLow, out extentsHigh); return centroid; } //获取面域的惯性矩。 public static double[] GetMomInertia(this Region region) { Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; CoordinateSystem3d coord = ed.CurrentUserCoordinateSystem.CoordinateSystem3d; Point3d origin = coord.Origin; Vector3d xAxis = coord.Xaxis; Vector3d yAxis = coord.Yaxis; getAreaProp (region.UnmanagedObject, ref origin, ref xAxis, ref yAxis, out perimeter, out area, out centroid, momInertia, out prodInertia, prinMoments, prinAxes, radiiGyration, out extentsLow, out extentsHigh); return momInertia; } //获取面域边界框的下限,其它特性相同。 public static Point2d GetExtentsLow(this Region region) { Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; CoordinateSystem3d coord =ed.CurrentUserCoordinateSystem.CoordinateSystem3d; Point3d origin = coord.Origin; Vector3d xAxis = coord.Xaxis; Vector3d yAxis = coord.Yaxis; getAreaProp(region.UnmanagedObject, ref origin, ref xAxis, ref yAxis, out perimeter, out area, out centroid, momInertia, out prodInertia, prinMoments, prinAxes, radiiGyration, out extentsLow, out extentsHigh); } return extentsLow; } 4,几何属性求解如下: 1)public double A { get; set; } //面积 由面域属性直接得出,代码:double A = Region.Area; 2)public double Ip { get; set; } //极惯性矩 由公式:Ip = Ix + Iy 3)public double Ix { get; set; } //X轴惯性矩 可由方法返回图形相对于模型空间X轴的惯性矩,再通过移轴公式移到面域形心处的惯性矩。 由公式:Ix = Ix0 + A * Ycent * Ycent 代码:double Ix = GetMomInertia(Region)[0] - A * Centroid.Y * Centroid.Y; 4)public double Iy { get; set; } //Y轴惯性矩 同 Ix,将X轴与Y轴参数对调 5)public double ix { get; set; } //X轴回转半径 由公式: 得出,代码: double ix = Math.Pow(Ix / A, 0.5) 6)public double iy { get; set; } //Y轴回转半径 同 ix,将X轴与Y轴参数对调 7)public double Wxup { get; set; } //X轴上部抗弯模量 由公式: 得出, 代码:double hy2 = Math.Abs(GetExtentsHigh(Region).Y - Centroid.Y) 8)public double Wxdown { get; set; } //X轴下部抗弯模量 同 Wxup,将Y轴上下参数对调 9)public double Wyleft { get; set; } //Y轴左侧抗弯模量 同 Wxup,将X轴与Y轴参数对调 10)public double Wyright { get; set; } //Y轴右侧抗弯模量 同 Wyleft,将X轴上下参数对调 11)public double Sx { get; set; } //X轴静矩 将面域沿过形心的X轴切开,得到上下两个面域,分别对这两个面域求面积A1,A2和形心坐标Y11,Y22,由新面域的形心坐标减去原面域的形心坐标Y11,Y22 得到距离 Y1,Y2(按绝对值计)。 由公式: 得出。(注:) 代码:double Sx = RgLastX.Area * Math.Abs(Region.GetCentroid().Y - Centroid.Y) 12)public double Sy { get; set; } //Y轴静矩 同 Sx,将Y轴上下参数对调 5,程序界面效果: 点击右侧的“梁截面”按扭,即隐藏主界面,提示用户选择AutoCAD曲线,获取曲线后,界面恢复显示,列表参数展示如下: 6,总结: 求面域的几何属性这样的功能,市面上有很多软件已经相当完善了,但其代码和编程思路并未公开,网上也很难找到这方面完备的参考资料,有鉴于此,作者在相关书籍的基础上通过编程实践,整理出来一套自已的思路和代码,以供行业同仁参考和切磋。 1.不足之处及有待改进的地方: A,不能动态调用Acdb**.dll(**与AutoCAD版本有关),而是要针对每个AutoCAD版本编译不同的程序。虽然作者采用了并行导入的方法,但是代码看起来比较冗繁,不利于维护。 B,对于不符合条件的曲线,比如Z轴坐标不为零、存在小缺口等,如何进行前期预处理,使曲线顺利生成正确的面域。 2.难点: A,面积矩S,既不能直接得出,也不能由现成参数量推导出来,需要切分原面域,再分别求形心,然后才能根据材料力学公式S = A * y计算。 B,多个连通域面域的识别和分类整理,这里用到的技术是面域相减结果与原面域比较的方法,如果不相交则相减后面积不变,从而进入新建列表,多个列表依次调用同一个方法。 参考文献: 【1】《AutoCAD VBA&;VB.NET开发基础与实例教程 (C#版)》 作者:曾洪飞 【2】《建筑结构静力计算实用手册(第四版)》 作者:姚谏 【3】《材料力学(第3版)》王晶,孙伟,王单,李栋栋,王社民 著 【4】《C#图解教程(第5版)》作者: [美] 丹尼尔·索利斯 / [美] 卡尔·施罗坦博尔 新书信息 图书信息: 书名:幕墙设计 实用软件案例解析 作者:章一峰 魏丽丽 谢容成 主编 |
|