作者:张勇 中建八局装饰工程有限公司
【摘要】 本文讲述在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**文件夹里。
AutoCAD2010 | Acdb18.dll |
AutoCAD2011 | Acdb18.dll |
AutoCAD2012 | Acdb18.dll |
AutoCAD2013 | Acdb19.dll |
AutoCAD2014 | Acdb19.dll |
AutoCAD2015 | Acdb20.dll |
AutoCAD2016 | Acdb20.dll |
AutoCAD2017 | Acdb21.dll |
AutoCAD2018 | Acdb22.dll |
AutoCAD2019 | Acdb23.dll |
AutoCAD2020 | Acdb23.dll |
核心代码如下:
[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版)》作者: [美] 丹尼尔·索利斯 / [美] 卡尔·施罗坦博尔
新书信息
图书信息:
书名:幕墙设计 实用软件案例解析
作者:章一峰 魏丽丽 谢容成 主编
联系客服