Revit二次开发---墙体开洞

此功能要实现 管线与构筑物(墙、梁、楼板、天花板、屋顶)交点开洞,并且要把管线与洞口关联起来。

首先是开洞,以墙为例

大致思路:1、得到墙体的水平面

                  2、得到管线与墙面相交的两点,并计算出中点

                  3、在中点创建洞口族并执行剪切

private void OpeningHole(Element wall,Curve line)
{
    //得到墙的面
    List<Face> lstFace = Get_ElementFace(wall);
    //得到管线与墙的交点
    List<XYZ> lstIntersection = Get_Intersection(line, lstFace);
    //计算中心点
    XYZ ptIntersection = (lstIntersection[0] + lstIntersection[1]) / 2
    Transaction trans = new Transaction(doc, "opening");
    trans.Start();
    try
    {
        //创建洞口
        FamilyInstance instance = doc.Create.NewFamilyInstance(ptIntersection, fs, StructuralType.NonStructural);
        //执行剪切
        InstanceVoidCutUtils.AddInstanceVoidCut(doc, wall, instance);
        trans.Commit();
    }
    catch
    {
        trans.RollBack();
    }
}
        /// <summary>
        /// 找到宿主的面
        /// </summary>
        public static List<Face> Get_ElementFace(Element element)
        {
            Options opt = new Options();
            opt.ComputeReferences = true;
            opt.DetailLevel = ViewDetailLevel.Fine;
            GeometryElement geometryElement = element.get_Geometry(opt);
            Face normalFace = null;
            List<Face> lstFace = new List<Face>();
            foreach (var go in geometryElement)
            {
                if(go is Solid)
                {
                    Solid solid = go as Solid;
                    if (solid != null && solid.Faces.Size > 0)
                    {
                        foreach (Face face in solid.Faces)
                        {
                            PlanarFace planarFace = face as PlanarFace;
                            if (planarFace != null)
                            {
                                lstFace.Add(face);
                            }
                        }
                    }
                }
                else if(go is GeometryInstance)
                {
                    GeometryInstance gins = goas GeometryInstance;
                    if (gins != null)
                    {
                        GeometryElement ge = gins.GetInstanceGeometry();
                        foreach (GeometryObject go in ge)
                        {
                            Solid solid = go as Solid;
                            if (solid != null && solid.Faces.Size > 0)
                            {
                                foreach (Face face in solid.Faces)
                                {
                                    PlanarFace planarFace = face as PlanarFace;
                                    if (planarFace != null)
                                    {
                                        lstFace.Add(face);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return lstFace;
        }
        /// <summary>
        /// 获取线与构筑物面的焦点
        /// </summary>
        public static List<XYZ> Get_Intersection(Curve pipeLine, List<Face> lstFace)
        {
            List<XYZ> lstIntersection = new List<XYZ>();
            foreach (Face item in lstFace)
            {
                XYZ ptJd = CaculateIntersection(item, pipeLine);
                if (ptJd != null)
                {
                    lstIntersection.Add(ptJd);
                }
            }
            return lstIntersection;
        }
        /// <summary>
        /// 求面和线的交点
        /// </summary>
        public XYZ CaculateIntersection(Face face, Curve curve)
        {
            XYZ intersection = null;
            try
            {
                IntersectionResultArray resultArray = new IntersectionResultArray();
                SetComparisonResult setComparisonResult = face.Intersect(curve, out resultArray);
                if (SetComparisonResult.Disjoint != setComparisonResult && resultArray != null)
                {
                    if (!resultArray.IsEmpty)
                    {
                        intersection = resultArray.get_Item(0).XYZPoint;
                    }
                }
            }
            catch (Exception ex)
            { }
            return intersection;
        }

然后是管线和洞口/套管关联,

大致思路:1、统计需要用到的数据;比如 洞口id,墙体id等等 

                  2、开洞的同时把数据写入管线扩展属性中

                  3、利用“IUpdater”接口,用户更改模型时会触发,触发后:

                        ①获取记录的数据,并得到洞口和墙体实例  ②计算管线与墙体新交点,并设置给洞口(还有管线的长/宽/半径)

这样就实现了洞口与管线相关联的功能。

//key:洞口id,value:所在墙体id
Dictionary<string,string> dicData = new Dictionary<string,string>();

private void OpeningHole(Element wall,Element duct)
{
    //得到风管中心线
    LocationCurve lc = duct.Location as LocationCurve;
    Curve curve = lc.Curve;
    //得到墙的面
    List<Face> lstFace = Get_ElementFace(wall);
    //得到管线与墙的交点
    List<XYZ> lstIntersection = Get_Intersection(curve, lstFace);
    //计算中心点
    XYZ ptIntersection = (lstIntersection[0] + lstIntersection[1]) / 2
    Transaction trans = new Transaction(doc, "opening");
    trans.Start();
    try
    {
        //创建洞口
        FamilyInstance instance = doc.Create.NewFamilyInstance(ptIntersection, fs, StructuralType.NonStructural);
        //执行剪切
        InstanceVoidCutUtils.AddInstanceVoidCut(doc, wall, instance);
        dicData.Add(instance.Id,wall.Id);
        //数据加到扩展属性
        Add_Data(duct,dicData);
        trans.Commit();
    }
    catch
    {
        trans.RollBack();
    }
}

注册更新

public class OpeningApplication : IExternalApplication
    {
        ElementUpdate Updater;
        /// <summary>
        /// 注册更新
        /// </summary>
        /// <param name="addInId"></param>
        private void Init(AddInId addInId)
        {
            try
            {
                //设置触发元素类型
                ElementFilter pipe = new ElementCategoryFilter(BuiltInCategory.OST_PipeCurves);
                ElementFilter duct = new ElementCategoryFilter(BuiltInCategory.OST_DuctCurves);
                List<ElementFilter> lstFilters = new List<ElementFilter>();
                lstFilters.Add(pipe);
                lstFilters.Add(duct);
                //注册更新
                Updater = new ElementUpdate(addInId);
                UpdaterRegistry.RegisterUpdater(Updater);
                LogicalOrFilter filter = new LogicalOrFilter(lstFilters);
                UpdaterRegistry.AddTrigger(Updater.GetUpdaterId(), filter, Element.GetChangeTypeAny());
            }
            catch(Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message);
            }
        }
        public Result OnShutdown(UIControlledApplication application)
        {
            if(Updater != null)
            {
                //注销更新
                UpdaterRegistry.UnregisterUpdater(Updater.GetUpdaterId());
            }
            return Result.Succeeded;
        }

        public Result OnStartup(UIControlledApplication application)
        {
            Init(application.ActiveAddInId); 
            return Result.Succeeded;
        }
    }

实现IUpdater接口

public class ElementUpdate : IUpdater
{
    private AddInId addInId = null;
    Guid guid = new Guid("FBFBF6B2-4C06-42d4-97C1-D1B4EB593EFF");
    public ElementUpdate(AddInId addin)
    {
        this.addInId = addin;
    }
    public void Execute(UpdaterData data)
    {
        Document doc = data.GetDocument();
        List<ElementId> lstModefieIds = data.GetModifiedElementIds().ToList();
        //更新元素,此接口内不可以开启事务,因为触发这个接口时文档中的修改还未提交
        foreach(ElementId eid in lstModefieIds)
        {
            Element duct = doc.GetElement(eid);
            LocationCurve lc = duct.Location as LocationCurve;
            Curve curve = lc.Curve;
            Dictionary<string,string> dicData = Get_ExtendedData(duct);
            foreach(string cid in dicData)
            {
                FamilyInstance cave = doc.GetElement(new ElementId(Convert.ToInt32(cid))) as FamilyInstance;
                Element wall = doc.GetElement(new ElementId(Convert.ToInt32(dicData[cid])));
                //得到墙的面
                List<Face> lstFace = Get_ElementFace(wall);
                //得到管线与墙的交点
                List<XYZ> lstIntersection = Get_Intersection(curve, lstFace);
                //计算中心点
                XYZ ptIntersection = (lstIntersection[0] + lstIntersection[1]) / 2;
                LocationPoint lp = cave.Location as LocationPoint;
                lp.Point = ptIntersection;
            }
        }
    }

    public string GetAdditionalInformation()
    {
        return "add";
    }
    public ChangePriority GetChangePriority()
    {
        return ChangePriority.FloorsRoofsStructuralWalls;
    }
    public UpdaterId GetUpdaterId()
    {
        return new UpdaterId(addInId, guid);
    }
    public string GetUpdaterName()
    {
        return "update";
    }
}

操作扩展属性的方法

        /// <summary>
        /// 获取指定元素扩展属性数据
        /// </summary>
        public static Dictionary<string, string> Get_ExtendedData(Element elem)
        {
            Dictionary<string, string> dicData = new Dictionary<string, string>();
            IList<Guid> listGuid = elem.GetEntitySchemaGuids();
            if (listGuid.Count == 0)
                return dicData;
            Schema sa = Schema.Lookup(listGuid[0]);
            Entity entity = elem.GetEntity(sa);
            IDictionary<string, string> dicMap = entity.Get<IDictionary<string, string>>(sa.GetField("管件集合"));
            for (int i = 0; i < dicMap.Count; i++)
            {
                dicData.Add(dicMap.Keys.ElementAt(i), dicMap.Values.ElementAt(i));
            }
            return dicData;
        }
        
        /// <summary>
        /// 覆盖原有扩展属性
        /// </summary>
        private static void Cover_Data(Element elem, string guid, string name, IDictionary<string, string> data)
        {
            if (GbvSchema == null)
            {
                //设置Schema的数据结构框架
                SchemaBuilder schemaBuilder = new SchemaBuilder(new Guid(guid));
                //设置这个结构框架的可读性和可写性
                schemaBuilder.SetReadAccessLevel(AccessLevel.Public);
                schemaBuilder.SetWriteAccessLevel(AccessLevel.Public);
                //设置这个框架的总名称
                schemaBuilder.SetSchemaName(name);
                //设置这个框架的类型和数据的名字
                schemaBuilder.AddMapField(name, typeof(string), typeof(string));
                //把数据结构框架添加到Schema中
                GbvSchema = schemaBuilder.Finish();
            }
            //创建一个新的数据对象
            Entity entity = new Entity(GbvSchema);
            //得到Revit中对应名字的数据对象
            Field field = GbvSchema.GetField(name);
            //然后给数据对象entity赋值
            entity.Set(field, data);
            //最后给墙添加数据
            elem.SetEntity(entity);
        }
        /// <summary>
        /// 添加扩展属性
        /// </summary>
        public static void Add_Data(Element elem, IDictionary<string, string> data)
        {
            Dictionary<string, string> tempData = Get_ExtendedData(elem);
            if (tempData.Count > 0)
            {
                foreach (string item in tempData.Keys)
                {
                    if (data.Keys.Contains(item))
                        continue;
                    data.Add(item, tempData[item]);
                }
            }
            if (data.Count > 0)
            {
                Cover_Data(elem, "f0c28996-670d-438f-a2be-b81b14aeb8dd", "管件集合", data);
            }
        }

大概就这些,代码都是删减简化后的,没有运行过  给个参考而已。

有问题可留言。

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嘿呦嘿呦嘿呦嘿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值