大三土木程序员实习项目--暖通接天正

3,286 阅读11分钟

笔者是一名大三的土木工程专业的学生,自学编程一年半,今年寒假找了一份做CAD插件的实习,实习中第二个项目就是几乎是自己独立完成的项目.虽然项目不大,但是还是收获良多.

暖通接天正

项目背景

image.png 这是一个CAD设计图的一部分,这个图有点不清晰,我们找到其中一个代表图

image.png

先要用netload导入dll文件,然后输入THFPM即可调用生成风口和风阀程序

image.png 注意到右下角的是否生成天正构件的选框,这个选框原本是没有的,笔者后来在UI上面添加了,这里我们先不勾选进行操作

  1. 选中风机(风机具有不同的类型)不同的类型的生成逻辑还不一样
  2. 调整不同类型的风口
  3. 进行生成

image.png 这些构件是平面图形,而且位置是不对的,应该生成在风管里面才对

image.png

这里生成的构件是CAD构件,只是一个平面图形,实际上在生产应用中,设计图要是立体的才行,而且要可以有其他属性,所以我们引入了天正构件

我们对于选框进行勾选,从而生成天正构件,下面是效果图

image.png

代码逻辑

UI界面的设计

image.png 红色的选框是我添加的,使用了winform工具来生成UI,winform我用的并不熟悉,但是还是勉强可以做的. 然后在winform的代码中添加checkbox

 private System.Windows.Forms.CheckBox chk_generate_TCH;

这里有很多的UI的变量

image.png

这些变量都是要被初始化的

image.png

记录UI的值实际上用到了单例设计模式

 public ThHvacFpmCmd()
        {
            ActionName = "风平面";
            CommandName = "THFPM";
            cmdService = new ThHvacCmdService();
            if (singleInstance == null)
            {
                singleInstance = new PortParam();
                singleInstance.param = new ThMEPHVACParam(); ;
            }

        }

image.png

插入天正构件的逻辑

插入天正构件的逻辑其实并不算太复杂,但是对于当时的我还是有一定挑战的,简单的来说就是要构造出一个天正构件的对象,这个对象有充足的数据,将这些数据插入到和天正建筑软件链接的数据库,就可以实现插入天正构件

image.png

插入天正风口 这段代码的的业务逻辑也不算简单,依据生成的风管,读取风管的数据,还要读取要生成的风口的数据,而且最困难的是对于不同情况,数据要做不同的处理,其中还包含了一些几何变换等等,

 public void DrawVerticalPipePorts(EndlineSegInfo info,
                                          ThMEPHVACParam portParam,
                                          Vector3d orgDisVec,
                                          double portWidth,
                                          double portHeight,
                                          double avgAirVolume,
                                          out List<SegInfo> verticalPipes)
        {
            using (var db = Linq2Acad.AcadDatabase.Active())
            {
                var portRange = portParam.portRange;
                var dirVec = ThMEPHVACService.GetEdgeDirection(info.seg.l);
                double angle = ThMEPHVACService.GetPortRotateAngle(dirVec);
                double angleSub = angle - Math.PI * 0.5;
                double angleAdd = angle + Math.PI * 0.5;
                verticalPipes = new List<SegInfo>();
                // 立管长为风口长左右各加100
                var size = GetVerticalPipeHeight(avgAirVolume, portWidth + 200);
                var h = size.Item2;
                var vec = Vector3d.ZAxis * ((portHeight + 100) * 0.5);
                var portSelfEleVec = vec * 2;
                var mmElevation = portParam.elevation * 1000;
                var mainHeight = ThMEPHVACService.GetHeight(portParam.inDuctSize);
                var selfEleOftVec = Vector3d.ZAxis * (portParam.portBottomEle * 1000);
                foreach (var pos in info.portsInfo)
                {
                    var ductHeight = ThMEPHVACService.GetHeight(pos.ductSize);


                    GetSidePortInsertPosTCH(dirVec, pos.position, h, out Point3d pL, out Point3d pR);
                    var pLR = pL + selfEleOftVec + orgDisVec;
                    pLR = new Point3d(pLR.X, pLR.Y, portParam.portBottomEle * 1000 + 0.5 * portHeight);
                    var pRR = pR + selfEleOftVec + orgDisVec;
                    pRR = new Point3d(pRR.X, pRR.Y, portParam.portBottomEle * 1000 + 0.5 * portHeight);
                    //ThTCHService.GenerateTCHEle(portRange, pos, ref _blkId, ref _equipName, ref _type, ref _number, ref _subSysTableName, ref _subSysTableID, ref _isSide, ref _thick, _scenario);
                    var paramR = ThTCHService.GeneratePortExample(IDNumber++, pRR, angleAdd - (Math.PI * 0.5), portHeight, portWidth, avgAirVolume * 0.5, portRange, portParam.scenario);
                    var paramL = ThTCHService.GeneratePortExample(IDNumber++, pLR, angleSub - (Math.PI * 0.5), portHeight, portWidth, avgAirVolume * 0.5, portRange, portParam.scenario);
                    //var paramR = ThTCHService.GenerateParamExample(IDNumber++, _blkId,pRR, angleAdd - (Math.PI * 0.5), _equipName, portHeight, portWidth, _thick, avgAirVolume/2, _type, _number, _subSysTableID, _isSide,portRange);
                    //var paramL = ThTCHService.GenerateParamExample(IDNumber++, _blkId, pLR, angleSub - (Math.PI * 0.5), _equipName, portHeight, portWidth, _thick, avgAirVolume/2, _type, _number, _subSysTableID, _isSide,portRange);

                    string curDbPath = Path.GetTempPath() + "TG20.db";
                    var sqliteHelper = new THMEPSQLiteServices(curDbPath);
                    if (portParam.isCheckedGenerateTCH == true)
                    {
                        ThTCHService.RecordTCHPortInfo(sqliteHelper, new List<TCHPortParam> { paramR, paramL });
                        var t = Math.Max(portParam.portBottomEle * 1000 - mmElevation - mainHeight, 50);
                        var sp = pos.position + (mmElevation + mainHeight) * Vector3d.ZAxis;
                        var ep = sp + (portHeight + 50 + t) * Vector3d.ZAxis;
                        verticalPipes.Add(new SegInfo()
                        {
                            l = new Line(sp, ep),
                            horizontalVec = dirVec,
                            airVolume = avgAirVolume,
                            ductSize = (portWidth + 200).ToString() + "x" + h.ToString()
                        });
                    }
                    else
                    {
                        GetSidePortInsertPos(dirVec, pos.position, h, out Point3d pLNew, out Point3d pRNew);
                        InsertPort(pR + orgDisVec + selfEleOftVec, angle - Math.PI * 0.5, portWidth, portHeight, portRange, avgAirVolume * 0.5);
                        InsertPort(pL + orgDisVec + selfEleOftVec, angle + Math.PI * 0.5, portWidth, portHeight, portRange, avgAirVolume * 0.5);
                        var t = Math.Max(portParam.portBottomEle * 1000 - mmElevation - mainHeight, 50);
                        var sp = pos.position + (mmElevation + mainHeight) * Vector3d.ZAxis;
                        var ep = sp + (portHeight + 50 + t) * Vector3d.ZAxis;
                        verticalPipes.Add(new SegInfo()
                        {
                            l = new Line(sp, ep),
                            horizontalVec = dirVec,
                            airVolume = avgAirVolume,
                            ductSize = (portWidth + 200).ToString() + "x" + h.ToString()
                        });

                    }
                }
            }
        }
        
 public void DrawPorts(EndlineSegInfo info, ThMEPHVACParam portParam, Vector3d orgDisVec, double portWidth, double portHeight, double avgAirVolume)
        {
            using (var db = Linq2Acad.AcadDatabase.Active())
            {
                var portRange = portParam.portRange;
                var dirVec = ThMEPHVACService.GetEdgeDirection(info.seg.l);
                double angle = ThMEPHVACService.GetPortRotateAngle(dirVec);
                double angleAdd = angle + (Math.PI * 0.5);
                double angleSub = angle - (Math.PI * 0.5);//对于不同的风口还要有不同的旋转角度的计算
                var mmElevation = portParam.elevation * 1000;
                var mainHeight = ThMEPHVACService.GetHeight(portParam.inDuctSize);
                foreach (var pos in info.portsInfo)
                {
                    var ductHeight = ThMEPHVACService.GetHeight(pos.ductSize);
                    var selfEleOftVec = Vector3d.ZAxis * (mmElevation + mainHeight - ductHeight);//风口的高度也是一个麻烦的地方
                    var p = pos.position + orgDisVec;
                    string curDbPath = Path.GetTempPath() + "TG20.db";
                    var sqliteHelper = new THMEPSQLiteServices(curDbPath);
                    if (portParam.isCheckedGenerateTCH == true)
                    {
                        if (portRange.Contains("下") || portRange == "方形散流器" || portRange == "圆形风口")
                        {
                            var paramL = ThTCHService.GeneratePortExample(IDNumber++, p + selfEleOftVec, angleAdd, portWidth, portHeight, avgAirVolume, portRange, portParam.scenario);
                            ThTCHService.RecordTCHPortInfo(sqliteHelper, new List<TCHPortParam>() { paramL });
                        }
                        else
                        {
                            var curDuctW = ThMEPHVACService.GetWidth(pos.ductSize);
                            GetSidePortInsertPosTCH(dirVec, pos.position, curDuctW, out Point3d pL, out Point3d pR);
                            pL += orgDisVec;
                            pR += orgDisVec;
                            var pLR = pL + selfEleOftVec;
                            pLR = new Point3d(pLR.X, pLR.Y, portParam.portBottomEle * 1000 + 0.5 * portHeight);
                            var pRR = pR + selfEleOftVec;
                            pRR = new Point3d(pRR.X, pRR.Y, portParam.portBottomEle * 1000 + 0.5 * portHeight);
                            if (pos.haveRight)
                            {
                                if (portRange == "侧送风口" || portRange == "侧回风口")
                                {
                                    var paramL = ThTCHService.GeneratePortExample(IDNumber++, pLR, angleSub - (Math.PI * 0.5), portHeight, portWidth, avgAirVolume * 0.5, portRange, portParam.scenario);
                                    ThTCHService.RecordTCHPortInfo(sqliteHelper, new List<TCHPortParam>() { paramL });//这里便是插入风口的实现

                                }
                                else
                                {
                                    var paramL = ThTCHService.GeneratePortExample(IDNumber++, pLR, angleSub - (Math.PI * 0.5), portWidth, portHeight, avgAirVolume * 0.5, portRange, portParam.scenario);
                                    ThTCHService.RecordTCHPortInfo(sqliteHelper, new List<TCHPortParam>() { paramL });
                                }


                            }
                            if (pos.haveLeft)
                            {
                                if (portRange == "侧送风口" || portRange == "侧回风口")
                                {
                                    var paramR = ThTCHService.GeneratePortExample(IDNumber++, pRR, angleAdd - (Math.PI * 0.5), portHeight, portWidth, avgAirVolume * 0.5, portRange, portParam.scenario);
                                    ThTCHService.RecordTCHPortInfo(sqliteHelper, new List<TCHPortParam>() { paramR });
                                }
                                else
                                {
                                    var paramR = ThTCHService.GeneratePortExample(IDNumber++, pRR, angleAdd - (Math.PI * 0.5), portWidth, portHeight, avgAirVolume * 0.5, portRange, portParam.scenario);
                                    ThTCHService.RecordTCHPortInfo(sqliteHelper, new List<TCHPortParam>() { paramR });
                                }

                            }
                        }
                    }
                    else
                    {
                        if (portRange.Contains("下"))
                        {
                            InsertPort(p + selfEleOftVec, angle + (Math.PI * 0.5), portWidth, portHeight, portRange, avgAirVolume);
                        }
                        else
                        {
                            var curDuctW = ThMEPHVACService.GetWidth(pos.ductSize);
                            GetSidePortInsertPos(dirVec, pos.position, curDuctW, out Point3d pL, out Point3d pR);
                            pL += orgDisVec;
                            pR += orgDisVec;
                            if (pos.haveRight)
                                InsertPort(pR + selfEleOftVec, angle - Math.PI * 0.5, portWidth, portHeight, portRange, avgAirVolume * 0.5);
                            if (pos.haveLeft)
                                InsertPort(pL + selfEleOftVec, angle + Math.PI * 0.5, portWidth, portHeight, portRange, avgAirVolume * 0.5);
                        }

                    }

                }
            }
        }

其中比较重要的两个函数

  1. 数据的填充

  2. 向数据库进行插入

         public static TCHPortParam GeneratePortExample(ulong IDNumber, Point3d point, double angle,  double portWidth, double portHeight, double avgAirVolume,   string portRange, string _scenario)
     {
         var paramBlk = new TCHBlkParam()
         {
             BlkID = 0,
             type = "自定义设备",};
         var paramMaterial = new TCHMaterialParam()
         {
             maID = 3,
             maTablesname = "",
             maTablesremark = "暖通风系统"
         };
         var paramSubSysType = new TCHSubParam()
         { 
             subID = 2,
             subTablesname="排风加排烟",
             subTablesremark="暖通风系统"
         };
         
         var paramPorts = new TCHDuctPortParam()
         {
             ID = IDNumber,
             blkId = 0,
             subSystemTypeId = 2,
             materialId = 3,
             centerPoint = point,
             airWayVector = new Vector3d(0, 0, -1),
             mainVector = new Vector3d(Math.Cos(angle), Math.Sin(angle), 0),
             normalVector = new Vector3d(0, 0, -1),
             scaleVector = new Vector3d(0.0013, 0.004, 0.004),
             lablePoint = new Point3d(0, 0, 0),
             labelText = "",
             eqiupName = "",
             isSide = 0,
             sectType = 0,
             length = portWidth,
             width = portHeight,
             thick = 100,
             airLoad = avgAirVolume,
             areaRatio = 1,
             pScale = 100,
         };
         switch (_scenario)
         {
             case "消防加压送风":
                 paramPorts.subSystemTypeId = 1;
                 paramSubSysType.subID = 1;
                 paramSubSysType.subTablesname = "消防加压";
                 break;
             case "消防排烟":
                 paramPorts.subSystemTypeId = 2;
                 paramSubSysType.subID = 2;
                 paramSubSysType.subTablesname = "消防排烟";
                 break;
             case "消防补风":
                 paramPorts.subSystemTypeId = 3;
                 paramSubSysType.subID = 3;
                 paramSubSysType.subTablesname = "消防补风";
                 break;
             case "消防排烟兼平时排风":
                 paramPorts.subSystemTypeId = 4;
                 paramSubSysType.subID = 4;
                 paramSubSysType.subTablesname = "排风兼排烟";
    
                 break;
             case "消防补风兼平时送风":
                 paramPorts.subSystemTypeId = 5;
                 paramSubSysType.subID = 5;
                 paramSubSysType.subTablesname = "送风兼补风";
    
                 break;
             case "平时排风兼事故排风":
                 paramPorts.subSystemTypeId = 6;
                 paramSubSysType.subID = 6;
                 paramSubSysType.subTablesname = "排风";
    
                 break;
             case "平时排风":
                 paramPorts.subSystemTypeId = 6;
                 paramSubSysType.subID = 6;
                 paramSubSysType.subTablesname = "排风";
    
                 break;
             case "平时送风兼事故补风":
                 paramPorts.subSystemTypeId = 7;
                 paramSubSysType.subID = 7;
                 paramSubSysType.subTablesname = "送风";
    
                 break;
             case "平时送风":
                 paramPorts.subSystemTypeId = 7;
                 paramSubSysType.subID = 7;
                 paramSubSysType.subTablesname = "送风";
    
                 break;
             case "空调送风":
                 paramPorts.subSystemTypeId = 8;
                 paramSubSysType.subID = 8;
                 paramSubSysType.subTablesname = "空调送风";
                 break;
             case "空调回风":
                 paramPorts.subSystemTypeId = 9;
                 paramSubSysType.subID=9;
                 paramSubSysType.subTablesname = "空调回风";
                 break;
             case "空调新风":
                 paramPorts.subSystemTypeId = 10;
                 paramSubSysType.subID=10;
                 paramSubSysType.subTablesname = "空调新风";
                 break;
             case "厨房排油烟":
                 paramPorts.subSystemTypeId = 11;
                 paramSubSysType.subID=11;
                 paramSubSysType.subTablesname = "排油烟";
                 break;
             case "厨房排油烟补风":
                 paramPorts.subSystemTypeId = 12;
                 paramSubSysType.subID = 12;
                 paramSubSysType.subTablesname = "排油烟";
                 break;
             case "事故排风":
                 paramPorts.subSystemTypeId = 13;
                 paramSubSysType.subID = 13;
                 paramSubSysType.subTablesname = "事故排风";
                 break;
             case "事故补风":
                 paramPorts.subSystemTypeId = 13;
                 paramSubSysType.subID=13;
                 paramSubSysType.subTablesname = "事故补风";
                 break;
             default:
                 paramPorts.subSystemTypeId = 0;
                 
                 break;
    
         }
         switch (portRange)
         {
             case "下回风口":
    
                 paramPorts.blkId = 1;
                 paramPorts.eqiupName = "矩形风口";
                 paramPorts.airWayVector =new Vector3d(0, 0, 1);
                 paramPorts.normalVector= new Vector3d(0, 0, 1);
                 paramBlk.BlkID = 1;
                 paramBlk.type = "自定义设备";
                 paramBlk.number = "13151244";
                
                 break;
             case "侧回风口":
                 paramPorts.blkId = 2;
                 paramPorts.eqiupName = "侧回风口1";
                 paramPorts.airWayVector = new Vector3d(-Math.Cos(angle), -Math.Sin(angle), 0);
                 paramPorts.normalVector= new Vector3d(-Math.Cos(angle), -Math.Sin(angle), 0);
                 paramPorts.mainVector = new Vector3d(0, 0, 1);
                 paramPorts.scaleVector = new Vector3d(0.0025, 0.0025, 0.01);
                 paramBlk.BlkID = 2;
                 paramBlk.type = "风口";
                 paramBlk.number = "00000144";
                 paramPorts.isSide = 1;
                
    
                 break;
             case "下送风口":
                 paramPorts.blkId = 3;
                 paramPorts.eqiupName = "矩形风口";
                 paramBlk.BlkID = 3;
                 paramBlk.type = "自定义设备";
                 paramBlk.number = "13101702";
                
                 break;
             case "侧送风口":
                 paramPorts.blkId = 4;
                 paramPorts.eqiupName = "侧送风口1";
                 paramPorts.airWayVector = new Vector3d(Math.Cos(angle), Math.Sin(angle), 0);
                 paramPorts.normalVector = new Vector3d(Math.Cos(angle), Math.Sin(angle), 0);
                 paramPorts.mainVector = new Vector3d(0, 0, 1);
                 paramPorts.scaleVector = new Vector3d(0.0025, 0.0025, 0.01);
                 paramBlk.BlkID = 4;
                 paramBlk.type = "风口";
                 paramBlk.number = "00000098";
                 paramPorts.isSide = 1;
                
                 break;
             case "方形散流器":
                 paramPorts.blkId = 5;
                 paramPorts.airWayVector = new Vector3d(0, 0, 1);
                 paramPorts.normalVector = new Vector3d(0, 0, 1);
                 paramPorts.scaleVector = new Vector3d(0.0025, 0.0025, 0.01);
                 paramPorts.eqiupName = "方形散流器";
                 paramBlk.BlkID = 5;
                 paramBlk.type = "自定义设备";
                 paramBlk.number = "01162127";
                 
                 break;
             case "圆形风口":
                 paramPorts.blkId = 6;
                 paramPorts.airWayVector = new Vector3d(0, 0, 1);
                 paramPorts.normalVector = new Vector3d(0, 0, 1);
                 paramPorts.scaleVector = new Vector3d(0.004, 0.004, 0.004);
                 paramPorts.sectType = 1;
                 paramPorts.eqiupName = "圆形风口";
                 paramBlk.BlkID = 6;
                 paramBlk.type = "自定义设备";
                 paramBlk.number = "13145951";
                 break;
             case "外墙防雨百叶":
                 paramPorts.blkId = 7;
                 paramPorts.airWayVector=new Vector3d(0, -1, 0);
                 paramPorts.normalVector=new Vector3d(0,-1, 0);
                 paramPorts.scaleVector = new Vector3d(0.0025, 0.0017, 0.0050);
                 paramPorts.isSide = 1;
                 paramPorts.eqiupName = "单层防雨百叶";
                 paramBlk.BlkID = 7;
                 paramBlk.type = "风口";
                 paramBlk.number = "00000150";
                 
                 break;
             default:
                 paramPorts.blkId = 0;
                 paramBlk.type = "0";
                 paramBlk.number = "0";
                 paramPorts.eqiupName = "Unknown";
                 break;
    
    
         }
         var paramRes = new TCHPortParam()
         {
             tCHBlkParam = paramBlk,
             tCHMaterialParam = paramMaterial,
             tCHDuctPortParam = paramPorts,
             tCHSubSystemParam = paramSubSysType,
         };
         return paramRes;
    
     }
     
     
    
public static void RecordTCHPortInfo(THMEPSQLiteServices sqliteHelper, List<TCHPortParam> interfaces)
        {
            foreach (var p in interfaces)
            {
                string recordTCHInfo = $"INSERT INTO " + ThTCHCommonTables.ductPortTableName +
                    " VALUES ('" + p.tCHDuctPortParam.ID.ToString() + "'," +
                    "'" + p.tCHDuctPortParam.blkId.ToString() + "'," +
                    "'" + p.tCHDuctPortParam.subSystemTypeId.ToString() + "'," +
                    "'" + p.tCHDuctPortParam.materialId.ToString() + "'," +
                    "'" + CovertPoint(p.tCHDuctPortParam.centerPoint) + "'," +
                    "'" + CovertVector(p.tCHDuctPortParam.airWayVector) + "'," +
                    "'" + CovertVector(p.tCHDuctPortParam.mainVector) + "'," +
                    "'" + CovertVector(p.tCHDuctPortParam.normalVector) + "'," +
                    "'" + CovertVector(p.tCHDuctPortParam.scaleVector) + "'," +
                    "'" + CovertPoint(p.tCHDuctPortParam.lablePoint) + "'," +
                    "'" + p.tCHDuctPortParam.labelText.ToString() + "'," +
                    "'" + p.tCHDuctPortParam.eqiupName.ToString() + "'," +
                    "'" + p.tCHDuctPortParam.isSide.ToString() + "'," +
                    "'" + p.tCHDuctPortParam.sectType.ToString() + "'," +
                    "'" + p.tCHDuctPortParam.length.ToString() + "'," +
                    "'" + p.tCHDuctPortParam.width.ToString() + "'," +
                    "'" + p.tCHDuctPortParam.thick.ToString() + "'," +
                    "'" + p.tCHDuctPortParam.airLoad.ToString() + "'," +
                    "'" + p.tCHDuctPortParam.areaRatio.ToString() + "'," +
                    "'" + p.tCHDuctPortParam.pScale.ToString() + "')";
                string recordDWBBlocks = $"INSERT INTO " + ThTCHCommonTables.DWBBlocksTableName +
                    " VALUES ('" + p.tCHBlkParam.BlkID.ToString() + "'," +
                      "'" + p.tCHBlkParam.type.ToString() + "'," +
                        "'" + p.tCHBlkParam.number.ToString() + "')";
                string recordMaterials = $"INSERT INTO " + ThTCHCommonTables.materialsTableName +
                      " VALUES ('" + p.tCHMaterialParam.maID.ToString() + "'," +
                      "'" + p.tCHMaterialParam.maTablesname.ToString() + "'," +
                        "'" + p.tCHMaterialParam.maTablesremark.ToString() + "')";

                sqliteHelper.ExecuteNonQuery(recordTCHInfo);
                sqliteHelper.ExecuteNonQuery(recordDWBBlocks);
                sqliteHelper.ExecuteNonQuery(recordMaterials);
                
            }
        }

风口表的对应关系

分别是三张表

  1. DuctAirLets
  2. DwbBlocks
  3. Materials 这三张表的数据是相互关联的,因为产品经理也不知道,经过很多核对,终于发现要插入的是这三张表,当时给我带来了很大困扰

image.png

插入风阀

插入风阀总体来说和插入风口的逻辑相似,但是它的难点在于天正阀门和CAD阀门的定位点是不一样的,所以插入位置会有很大偏差,不仅如此,各个阀门的方向还不一样,这就给获取合适的定位点带来了挑战,这里我的解决方式是构造两个互相垂直的向量,在两个互相垂直的向量上移动相应的距离,从而获取正确的位置

 public void InsertValves(Point3d srtPoint, List<EndlineInfo> endlines, string visibility, ThMEPHVACParam portParam)
        {

            if (endlines.Count == 1)// 只有一条endline的情况不插阀
                return;
            var mmElevation = portParam.elevation * 1000;
            var mainHeight = ThMEPHVACService.GetHeight(portParam.inDuctSize);
            using (var db = Linq2Acad.AcadDatabase.Active())
            {

                foreach (var endline in endlines)
                {
                    var rootSeg = endline.endlines.Values.LastOrDefault();
                    var width = ThMEPHVACService.GetWidth(rootSeg.seg.ductSize);
                    var dirVec = ThMEPHVACService.GetEdgeDirection(rootSeg.seg.l);
                    var verticalR = ThMEPHVACService.GetRightVerticalVec(dirVec);
                    var angle = dirVec.GetAngleTo(Vector3d.XAxis);
                    var thick = ThMEPHVACService.GetHeight(rootSeg.seg.ductSize);
                    var selfEleOftVec = Vector3d.ZAxis * (mmElevation + mainHeight-0.5*thick );
                    if (Vector3d.XAxis.CrossProduct(dirVec).Z < 0)
                        angle = 2 * Math.PI - angle;
                    angle += 0.5 * Math.PI;
                    var textAngle = (angle >= Math.PI * 0.5) ? Math.PI * 0.5 : 0;
                    var p = rootSeg.seg.l.StartPoint + (dirVec * rootSeg.seg.srcShrink);
                    var insertP = p + verticalR * width * 0.5 + srtPoint.GetAsVector();
                    var mainVector = new Vector3d(Math.Cos(angle + Math.PI / 2), Math.Sin(angle + Math.PI / 2), 0);
                    var Aimpoint = new Point3d(insertP.X - 0.5 * 300 * mainVector.X, insertP.Y - 0.5 * 300 * mainVector.Y, 0);
                    var newMainVector = ThTCHService.GenerateVerticalVector(mainVector, Math.PI / 2);//逆时针旋转90度的向量
                    Aimpoint = new Point3d(Aimpoint.X - 0.5 * width * newMainVector.X, Aimpoint.Y - 0.5 * width * newMainVector.Y, selfEleOftVec.Z);
                    var Aimpointp = new Point3d(Aimpoint.X - 300 * mainVector.X, Aimpoint.Y - 300 * mainVector.Y, selfEleOftVec.Z);
                    string curDbPath = Path.GetTempPath() + "TG20.db";
                    var sqliteHelper = new THMEPSQLiteServices(curDbPath);
                    if (portParam.isCheckedGenerateTCH == true)
                    {
                        int _blkId = 0;
                        Point3d _lablePoint = new Point3d(insertP.X, insertP.Y, 0);
                        Point3d _dimPoint = new Point3d(insertP.X, insertP.Y - 705, 0);
                        Point3d _lablePoint1 = new Point3d(Aimpoint.X, Aimpoint.Y - 600, 0);
                        Point3d _lablePoint2 = new Point3d(Aimpointp.X, Aimpointp.Y + 600, 0);
                        Point3d _codePoint = new Point3d(insertP.X + 200, insertP.Y + 625, 0);
                        double _length = 300;
                        double _width = width;
                        double _thick = thick;
                        var param = ThTCHService.GenerateValvesExample(valveVisibility, ID++, _blkId, Aimpoint, _lablePoint1, _dimPoint, _codePoint, _length, _width, _thick, angle, portParam.scenario);
                        var paramp = ThTCHService.GenerateValvesExample(visibility, ID++, _blkId, Aimpointp, _lablePoint2, _dimPoint, _codePoint, _length, _width, _thick, angle, portParam.scenario);
                        ThTCHService.RecordTCHValve(sqliteHelper, new List<TCHValvesParam> { param, paramp });
                        
                    }
                    else
                    {
                        InsertValve(insertP, width, angle, textAngle);//150
                        insertP += (dirVec * 320);// 320是默认阀宽
                        InsertValve(insertP, width, angle, textAngle, visibility);//BEC
                    }

                }
            }
        }
public void InsertValve(Point3d srtPoint, List<EndlineInfo> endlines, ThMEPHVACParam portParam)
        {

            Point3d pos = endlines.First().endlines.First().Value.portsInfo.First().position;
            var ductHeight = ThMEPHVACService.GetHeight(endlines.First().endlines.First().Value.portsInfo.First().ductSize);
            var Z = pos.Z;
            if (endlines.Count == 1)// 只有一条endline的情况不插阀
                return;
            using (var db = Linq2Acad.AcadDatabase.Active())
            {

                var mmElevation = portParam.elevation * 1000;
                var mainHeight = ThMEPHVACService.GetHeight(portParam.inDuctSize);
               
                foreach (var endline in endlines)
                {

                    var rootSeg = endline.endlines.Values.LastOrDefault();
                    var width = ThMEPHVACService.GetWidth(rootSeg.seg.ductSize);
                    var thick = ThMEPHVACService.GetHeight(rootSeg.seg.ductSize);
                    var dirVec = ThMEPHVACService.GetEdgeDirection(rootSeg.seg.l);
                    var verticalR = ThMEPHVACService.GetRightVerticalVec(dirVec);
                    var angle = dirVec.GetAngleTo(Vector3d.XAxis);
                    var selfEleOftVec = Vector3d.ZAxis * (mmElevation + mainHeight-0.5*thick );
                    if (Vector3d.XAxis.CrossProduct(dirVec).Z < 0)
                        angle = 2 * Math.PI - angle;
                    angle += 0.5 * Math.PI;
                    var textAngle = (angle >= Math.PI * 0.5) ? Math.PI * 0.5 : 0;
                    var p = rootSeg.seg.l.StartPoint + (dirVec * rootSeg.seg.srcShrink);
                    var insertP = p + verticalR * width * 0.5 + srtPoint.GetAsVector();
                    var mainVector = new Vector3d(Math.Cos(angle + Math.PI / 2), Math.Sin(angle + Math.PI / 2), 0);
                    var Aimpoint = new Point3d(insertP.X - 0.5 * 300 * mainVector.X, insertP.Y - 0.5 * 300 * mainVector.Y, 0);
                    var newMainVector = ThTCHService.GenerateVerticalVector(mainVector, Math.PI / 2);
                      Aimpoint = new Point3d(Aimpoint.X - 0.5 * width * newMainVector.X, Aimpoint.Y - 0.5 * width * newMainVector.Y , selfEleOftVec.Z);
                    if (portParam.isCheckedGenerateTCH == true)
                    {

                        int _blkId = 0;
                        Point3d _lablePoint = new Point3d(insertP.X, insertP.Y, 0);
                        Point3d _dimPoint = new Point3d(insertP.X, insertP.Y - 705, 0);//???
                        Point3d _codePoint = new Point3d(insertP.X + 200, insertP.Y + 625, 0);//???
                        double _length = 300;
                        double _width = width;
                        double _thick = thick;
                        var param = ThTCHService.GenerateValvesExample(valveVisibility, ID++, _blkId, Aimpoint, _lablePoint, _dimPoint, _codePoint, _length, _width, _thick, angle, portParam.scenario);
                        string curDbPath = Path.GetTempPath() + "TG20.db";
                        var sqliteHelper = new THMEPSQLiteServices(curDbPath);
                        ThTCHService.RecordTCHValve(sqliteHelper, new List<TCHValvesParam> { param });

                    }
                    else
                        InsertValve(insertP, width, angle, textAngle);
                }
            }
        }

这里在生成阀门的时候要分成两种情况

image.png 生成阀门需要的数据库表

image.png

是否消防加压送风也要分成两种情况

public override void SubExecute()
        {
            string curDbPath = Path.GetTempPath() + "TG20.db";
            string templateDbPath = ThCADCommon.TCHHVACDBPath();
            ulong gId = 0;
            ThHvacCmdService.InitTables(curDbPath, templateDbPath, ref gId);
            var status = GetFanParam(out bool isSelectFan,
                                     out Point3d startPoint,
                                     out PortParam portParam,
                                     out DBObjectCollection connNotRoomLines,
                                     out Dictionary<string, FanParam> dicFans,
                                     out Dictionary<string, ThDbModelFan> dicModels,
                                     out Dictionary<Polyline, ObjectId> allFansDic);
            if (portParam.param == null)
                return;
            DrawBrokenLines(portParam, out ObjectIdList brokenLineIds);
            if (!status)
                return;
            if (isSelectFan)
            {
                var knife = new ThSepereateFansDuct(startPoint, connNotRoomLines, dicFans);
                var anay = new ThFansMainDuctAnalysis(knife.mainDucts, knife.dicLineParam);
                var fanParam = GetInfo(dicFans);
                var flag = dicFans.Count > 1;
                if (flag)
                {
                    ThNotRoomStartComp.DrawEndLineEndComp(ref anay.fanDucts, startPoint, portParam);// 先插入comp
                    DrawMultiFanMainDuct(ref gId, anay, startPoint, fanParam, curDbPath, portParam);// 会改变线信息
                }
                var mat = Matrix3d.Displacement(-portParam.srtPoint.GetAsVector());
                var wallIndex = ThMEPHVACService.CreateRoomOutlineIndex(portParam.srtPoint);
                foreach (var key in dicFans.Keys)
                {
                    var fan = dicFans[key];
                    var model = dicModels[key];
                    var p = model.FanInletBasePoint.TransformBy(mat);
                    var wallLines = GetWalls(p, wallIndex);
                    portParam.param.inDuctSize = fan.roomDuctSize;
                    if (model.scenario == "消防加压送风")//??
                        cmdService.PressurizedAirSupply(ref gId, curDbPath, fan, model, wallLines, portParam, flag, allFansDic, brokenLineIds);
                    else
                        cmdService.NotPressurizedAirSupply(ref gId, curDbPath, fan, model, wallLines, portParam, flag, allFansDic, brokenLineIds);
                }
            }
            else
            {
                var ductPort = new ThHvacDuctPortsCmd(curDbPath, portParam, allFansDic);            //所有操作的service都是在这里先初始化
                ductPort.Execute(ref gId, brokenLineIds);
            }
            ThDuctPortsDrawService.ClearGraphs(brokenLineIds);
#if ACAD_ABOVE_2014
            Active.Editor.Command("TIMPORTTG20HVAC", curDbPath, " ");
#else
            ResultBuffer args = new ResultBuffer(
               new TypedValue((int)LispDataType.Text, "_.TIMPORTTG20HVAC"),
               new TypedValue((int)LispDataType.Text, curDbPath),
               new TypedValue((int)LispDataType.Text, " "));
            Active.Editor.AcedCmd(args);
#endif
        }

这里面最令人头痛的莫过于要额外插入电动阀门,这个插入电动阀门的的位置是很难获取的,因为它和上面获取位置的逻辑又不太一样,而且电动阀门的长宽也要重新寻找

image.png

image.png

image.png

插入两种电动阀门的寻找位置的逻辑完全不同,产品经理也没给我具体的方法,只能硬着头皮去前任程序员写的代码一点点去找线索.

改BUG

前任程序员在生成CAD构件的时候出现了一个bug,就是生成构件的标高居然是负的,而且负的没有规律,然后我也按照他的逻辑去生成构件,结果产品经理告诉我是错的,那没办法,只能我一个实习生去给他擦屁股了. 费了我一个下午的时间,终于把问题找到了,原来是前任程序员在进行位置变换的时候出现了一个低级的错误,我在他的基础上把错误进行修正,但是要修改的地方实在是很多,费了我很多精力,终于算是解决了.

 public void DrawVTDuct(List<SegInfo> segInfos, Matrix3d mat, bool isTextSide, ThMEPHVACParam param, ref ulong gId)
        {
            var gap = ThTCHCommonTables.flgThickness * 0.5;
            foreach (var seg in segInfos)
            {
                var l = seg.GetShrinkedLine();
                l.StartPoint = new Point3d(l.StartPoint.X, l.StartPoint.Y, l.StartPoint.Z - mat.CoordinateSystem3d.Origin.Z);
                l.EndPoint = new Point3d(l.EndPoint.X, l.EndPoint.Y, l.EndPoint.Z - mat.CoordinateSystem3d.Origin.Z);
                //改bug的地方

                if (l.Length < lineLimition)
                    continue;
                RecordDuctInfo(seg.airVolume, ref gId);
                RecordDuctDimContents(ref gId);
                RecordDuctDimensions(mat, seg, param, isTextSide, ref gId);
                GetWidthAndHeight(seg.ductSize, out double width, out double height);
                var dirVec = (l.EndPoint - l.StartPoint).GetNormal();
                var sEndParam = new TCHInterfaceParam()
                {
                    ID = ductParam.startFaceID,
                    sectionType = ductParam.sectionType,
                    height = height,
                    width = width,
                    normalVector = dirVec,
                    heighVector = new Vector3d(0, 0, 1),
                    centerPoint = (l.StartPoint.TransformBy(mat) + (gap * dirVec)),
                };
                var eEndParam = new TCHInterfaceParam()
                {
                    ID = ductParam.endFaceID,
                    sectionType = ductParam.sectionType,
                    height = height,
                    width = width,
                    normalVector = -dirVec,
                    heighVector = new Vector3d(0, 0, 1),
                    centerPoint = (l.EndPoint.TransformBy(mat) - (gap * dirVec))
                };
                ThTCHService.RecordPortInfo(sqliteHelper, new List<TCHInterfaceParam>() { sEndParam, eEndParam });
            }
            sqliteHelper.CloseConnect();
        }

整个项目做完还是很有收获的,掌握了很多调试技巧,提升了很多分析代码和写代码的能力,转码路漫漫,感觉做什么都不容易,继续加油吧.