启明办公

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 96|回复: 0

在AutoCAD上开发盾构隧道管片设计程序

[复制链接]

2

主题

7

帖子

10

积分

新手上路

Rank: 1

积分
10
发表于 2022-12-13 04:51:01 | 显示全部楼层 |阅读模式
盾构隧道是用管片拼装而成的。管片拼装就位以后,在土压力的作用下会形成结构受力性能非常好的圆形隧道。



广州地铁盾构隧道洞口



某核电排水隧洞管片模型

由于管片外形规则,具备参数化设计可能性,因此在设计过程中可以编写程序自动生成管片模型。但在轨道交通工程领域这一需求并不强烈,因为列车限界统一,因此轨道交通工程领域管片尺寸高度统一。然而在水电工程领域各型机组需水量变化大,隧洞直径变化多样。
此种需求近期在某核电排水隧洞初步设计中达到顶峰,该项目采用了两机一洞、一机一洞两种隧洞,因此有两种不同直径的隧洞,因此尝试编制一个管片生成器,方便设计工作的开展。



管片生成器程序界面

首先寻找开发平台。事实上在开展本项工作之前就已经在AutoCAD VBA平台上编制过类似的软件,但这次编制再用VBA明显对事后发布不利,因此曾经尝试在Python上寻找开发平台,很可惜经过接近一周的寻找与大量测试代码的编写,发现除了令计算机多了一堆臃肿程序外,并没有多大进展,过程记录如下:

  • pyautocad:俄罗斯人编写的开源接口,pyautocad,功能尚可,但看到此包从2015年至今未有更新,便感觉其前景岌岌可危。
  • ezdxf:直接对dxf文件进行操作,ezdxf,很不错的接口,更新也快,更重要的是它让我看到摆脱AutoCAD平台的可能,但花了点时间阅读资料后发现由于三维实体涉及专利授权,因此它全部是对二维图元的操作。
  • freeCAD:可以代替AutoCAD的开放平台,freeCAD,强大到被制裁的俄罗斯人把他当作AutoCAD的替代品,但光是建立运行环境就让人望而生畏,资料又少。正准备咬牙强行学习其文档时猛然想到,如果为了运行一个小程序而要同事下载个五六百兆的程序,别人会怎么想?
来到这一步时,甚至在想不如还是用pyANSYS吧,APDL我在行,可是ANSYS的科学安装更复杂……
于是退回到AutoCAD平台,面前至少放着四种二次开发模式:VBA、ObjectARX、ObjectARX .Net Wrapper和AutoLisp。当然是挑熟悉的来做,那么只剩下VBA和ObjectARX .Net Wrapper,前者封装似乎很麻烦,于是就选择后者。
再者,.Net平台的GUI编写实在太舒服,所见即所得,至于python的tkinter之流,我呸……而且AutoCAD的资料很丰富AutoCAD开发者文档,相对而言找资料比较容易。果然免费的是最贵的。
由于在VBA上写的程序,最后遇到的问题是无法对实体边缘进行倒角,因此花了不少时间找资料,最后利用Brep解决了这个问题,如何在AutoCAD.NET中对Solid3d对象进行倒角(ChamferEdges),但此举对自己后面的编程思路构成了误导,令我哭笑不得。原因是如果我想不计后果的获得一个Solid3d的每一条边的几何数据,我可以很简单的Clone一个,然后循环Explode它,Explode到只剩下简单直线、圆弧这种简单对象,再去读它的几何数据。我竟然忘记了这种简单的方法,苦苦用奇怪的Brep去求边界,真的……无语。
而且更悲哀的是,用了三四天东拼西凑想出来的ChamferEdges方法,竟然在程序里面完全用不上!后面用Solid3d.BooleanOperation顺带着就实现了ChamferEdges的效果。
扯远了,回到程序本身,先谈GUI。GUI最大的问题就是需要面对管片大量的参数,输入界面需要具备动态调整的可能,于是简单的用DataSet和DataGridView空间快速实现了这一目标。首先添加一个DataSetSegment.xsd,添加一个Parameter数据表,添加下面的结构并设置Name为主键。



Parameter数据表结构

然后添加一个DataGridView控件,简单设置一下列名。



DataGridView控件

然后用下面代码生成默认的管片几何参数:
segment.Parameter.AddParameterRow("segment_project_name", "项目名称", "TW7、8号机组排水隧洞工程", "", "");
segment.Parameter.AddParameterRow("segment_assembly_type", "管片拼装类型", "A", "型", "A型为标准环模式,B型为左中右环模式");
segment.Parameter.AddParameterRow("tunnel_radius_outer", "隧道外部半径", "3850", "mm", "");
segment.Parameter.AddParameterRow("tunnel_radius_inner", "隧道内部半径", "3400", "mm", "");
segment.Parameter.AddParameterRow("segment_wedge", "楔形量尺寸", "40", "mm", "只考虑双面楔");
segment.Parameter.AddParameterRow("segment_width", "管片宽度尺寸", "1500", "mm", "");
segment.Parameter.AddParameterRow("segment_chamfer", "管片边缘倒角尺寸", "5", "mm", "");
segment.Parameter.AddParameterRow("groove_up_positions", "管片上端槽角点坐标数据", "0,0,2,2,2,12,12,16,12,56,2,60,2,95,12,105,0,105", "mm", "以最下侧角点为原点,逆时针排序,注意以半角逗号隔开");
segment.Parameter.AddParameterRow("groove_up_radius", "管片上端槽角点1所在半径", "3750", "mm", "以最下侧角点所在半径定位");
segment.Parameter.AddParameterRow("groove_low_positions", "管片下端槽角点坐标数据", "0,0,0,-55,14,-55,4,-45,4,-28,2,-25,2,-2", "mm", "以最上侧角点为原点,逆时针排序,注意以半角逗号隔开");
segment.Parameter.AddParameterRow("groove_low_radius", "管片下端槽角点1所在半径", "3450", "mm", "以最上侧角点所在半径定位");
segment.Parameter.AddParameterRow("circular_tenon_positions", "管片环向卡榫凸榫角点坐标数据", "0,0,20,15,20,150,0,165", "mm", "以最下侧角点为原点,逆时针排序,注意以半角逗号隔开");
segment.Parameter.AddParameterRow("circular_tenon_radius", "管片环向卡榫凸榫角点1所在半径", "3517", "mm", "以最下侧角点所在半径定位");
segment.Parameter.AddParameterRow("circular_groove_positions", "管片环向卡榫凹槽角点坐标数据", "0,0,20,15,20,158,0,173", "mm", "以最下侧角点为原点,逆时针排序,注意以半角逗号隔开");
segment.Parameter.AddParameterRow("circular_groove_radius", "管片环向卡榫凹槽角点1所在半径", "3513", "mm", "以最下侧角点所在半径定位");
segment.Parameter.AddParameterRow("segment_number", "管片分块数量", "6", "块", "只考虑1K+2L+nB的管片分块组合");
segment.Parameter.AddParameterRow("k_angle_front", "K块前端角度", "22", "°", "");
segment.Parameter.AddParameterRow("k_angle_back", "K块后端角度", "18", "°", "管片后端外侧左右侧控制点与圆心连线所形成的夹角");
segment.Parameter.AddParameterRow("b_angle", "B块角度", "67.5", "°", "");
segment.Parameter.AddParameterRow("guide_rob_radius", "导向棒半径", "26", "mm", "");
segment.Parameter.AddParameterRow("guide_rob_location_radius", "导向棒所在半径", "3625", "mm", "");
segment.Parameter.AddParameterRow("guide_rob_triangle_width", "导向棒三角区宽度", "14", "mm", "");
segment.Parameter.AddParameterRow("guide_rob_triangle_height", "导向棒三角区高度", "2", "mm", "");
segment.Parameter.AddParameterRow("guide_rob_length", "导向棒长度", "600", "mm", "");
segment.Parameter.AddParameterRow("bolt_type", "螺栓类型", "A", "型", "A为弯螺栓,B为直螺栓");
segment.Parameter.AddParameterRow("bolt_hole_radius", "螺栓开孔半径", "25", "mm", "注意是螺栓开孔半径,需要在螺栓半径的基础上考虑适当裕量");
segment.Parameter.AddParameterRow("bolt_hole_arc_angle", "螺栓孔弧夹角", "90", "°", "");
segment.Parameter.AddParameterRow("bolt_hole_arc_radius", "螺栓孔弧半径", "380", "mm", "");
segment.Parameter.AddParameterRow("hand_hole_radius", "手孔半径", "60", "mm", "");
segment.Parameter.AddParameterRow("hand_hole_angle", "手孔夹角", "36", "°", "");
segment.Parameter.AddParameterRow("bolt_position_radius", "螺栓定位半径", "3580", "mm", "");
segment.Parameter.AddParameterRow("bolt_position_angle", "螺栓定位角度", "0", "°", "第一枚纵向螺栓与3点方向的夹角,一般设置为0°");
segment.Parameter.AddParameterRow("tunnel_direction_bolt_number", "纵向螺栓数量", "16", "枚", "");
segment.Parameter.AddParameterRow("circle_direction_bolt_distance", "两枚环向螺栓的距离", "800", "mm", "");
segment.Parameter.AddParameterRow("grouting_hole_positions", "注浆孔截面角点坐标数据", "0,0,50,0,45,10,40,10,40,80,30,80,30,300,0,300", "mm", "以最左下侧角点为原点,逆时针排序,注意以半角逗号隔开");
segment.Parameter.AddParameterRow("grouting_hole_placement", "注浆孔布置数据", "3395,0,0,3395,45,0,3395,112.5,0,3395,180,0,3395,247.5,0,3395,315,0", "mm,°,mm", "柱坐标,中轴为原点,3点方向为0°,数据格式(radius,angle,z),注意以半角逗号隔开");
于是很容易的就获得了一个能够编辑、输入输出数据的程序界面:



默认管片几何参数界面

然后利用ReadXml与WriteXml,读写数据简直不要太容易:
dsSegment.ReadXml(ofdMain.FileName);
dsSegment.WriteXml(sfdMain.FileName,System.Data.XmlWriteMode.WriteSchema);
至此,还在python里面玩pd.read_csv?我呸……
然后我们开始切管片吧,不过要先跟AutoCAD建立会话,方法如下:
// 获取当前文档并建立会话
Document acDoc = Application.DocumentManager.MdiActiveDocument;
Database acCurDb = acDoc.Database;

// 锁定文档、建立会话,开始建模
using (DocumentLock docLock = acDoc.LockDocument())
{
    using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
    {
        // 绘制几何模型

        // 向会话提交数据变更
        acTrans.Commit();
    }
}
不知道什么版本开始突然AutoCAD .Net接口要求DocumentLock docLock = acDoc.LockDocument()才能正常工作,而且还不声不响,比如官网Create Solids (.NET)就没提到这个要求。
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
[CommandMethod("CreateWedge")]
public static void CreateWedge()
{
    // Get the current document and database, and start a transaction
    Document acDoc = Application.DocumentManager.MdiActiveDocument;
    Database acCurDb = acDoc.Database;
    using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
    {
        // Open the Block table record for read
        BlockTable acBlkTbl;
        acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead) as BlockTable;
        // Open the Block table record Model space for write
        BlockTableRecord acBlkTblRec;
        acBlkTblRec = acTrans.GetObject(acBlkTbl[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
        // Create a 3D solid wedge
        using (Solid3d acSol3D = new Solid3d())
        {
            acSol3D.CreateWedge(10, 15, 20);
            // Position the center of the 3D solid at (5,5,0)
            acSol3D.TransformBy(Matrix3d.Displacement(new Point3d(5, 5, 0) -Point3d.Origin));
            // Add the new object to the block table record and the transaction
            acBlkTblRec.AppendEntity(acSol3D);
            acTrans.AddNewlyCreatedDBObject(acSol3D, true);
        }
        // Open the active viewport
        ViewportTableRecord acVportTblRec;
        acVportTblRec = acTrans.GetObject(acDoc.Editor.ActiveViewportId, OpenMode.ForWrite) as ViewportTableRecord;
        // Rotate the view direction of the current viewport
        acVportTblRec.ViewDirection = new Vector3d(-1, -1, 1);
        acDoc.Editor.UpdateTiledViewportsFromDatabase();
        // Save the new objects to the database
        acTrans.Commit();
    }
}
没关系,坑这种东西趟多了,我们就变成SUV了。搞管片大概分8步(与手绘过程基本一致):

  • 生成一条管
  • 按楔形量切出粗胚
  • 在环面切出环向止水槽、凹凸榫
  • 将管切分为若干管片
  • 在每一管片上切出纵向止水槽、凹凸榫
  • 在每一管片上切出纵向螺栓
  • 在每一管片上切出环向螺栓
  • 在每一管片上切出注浆吊装孔
在这里面的关键问题,其实能手绘出来,程序实现就很容,稍微有点难度的只不过是:

  • 利用空间椭圆线作为Path,利用Solid3d.CreateSweptSolid生成止水槽Cutter
  • 利用Matrix3d.AlignCoordinateSystem,实现Align三点对齐的方法(需了解向量叉乘)
  • 利用Solid3d.TransformBy,实现实体的空间移动、旋转等操作
  • 利用Entity.Explode,求取特殊控制点
如果大学高等数学学得好,上面的操作会相当简单,只不过是不同操作的复杂叠加。大致就是这样了。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|天恒办公

Copyright © 2001-2013 Comsenz Inc.Template by Comsenz Inc.All Rights Reserved.

Powered by Discuz!X3.4

快速回复 返回顶部 返回列表