Revit二次开发小技巧(十四)封闭墙体最大外轮廓

前言:当前方法使用在既定的情况下,选择闭合的墙体,然后找到对应的外轮廓,并不支持存在开口的情况,仅提供一种思路。Revit版本为2019

代码:

using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace RevitTest
{
    [Transaction(TransactionMode.Manual)]
    public class AlgorithmCmd : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            UIDocument uidoc = commandData.Application.ActiveUIDocument;
            Document doc = uidoc.Document;

            List<Reference> selRefList = new List<Reference>();
            try
            {
                selRefList = uidoc.Selection.PickObjects(ObjectType.Element, new OnlySelectWall(), "选择墙体").ToList();
            }
            catch (Exception)
            {
                return Result.Succeeded;
            }
            //提取实体
            List<Solid> selectWallSolidList = selRefList.Select(x => GetUnionSolid(GetSolids(doc.GetElement(x)), BooleanOperationsType.Union)).ToList();
            //提取顶面
            List<CurveLoop> topCLList = selectWallSolidList.SelectMany(x => GetDirectionOriginCurveLoop(x, XYZ.BasisZ)).ToList();
            List<Line> maxOuterLineList = GetMaximumOuterContour(doc, topCLList.SelectMany(x => x).OfType<Line>().ToList());
            Transaction trans = new Transaction(doc, "測試");
            trans.Start();
            maxOuterLineList.ForEach(x => LineTest(doc, x));
            trans.Commit();
            return Result.Succeeded;
        }
        /// <summary>
        /// 计算最大外轮廓
        /// </summary>
        /// <param name="lineList"></param>
        /// <returns></returns>
        public List<Line> GetMaximumOuterContour(Document doc, List<Line> lineList)
        {
            List<Line> result = new List<Line>();
            //先得到线段中x轴最小的点
            XYZ targetPoint = lineList.SelectMany(x =>
            {
                return new List<XYZ>() { x.GetEndPoint(0), x.GetEndPoint(1) };
            }).OrderBy(x => x.X).ThenBy(x => x.Y).FirstOrDefault();
            XYZ startPoint = targetPoint;
            XYZ lastPoint = null;
            while (true)
            {
                List<Line> lines = lineList.FindAll(x => GetHorizontalDistance(x.GetEndPoint(0), startPoint) < 1 / 304.8 || GetHorizontalDistance(x.GetEndPoint(1), startPoint) < 1 / 304.8).Select(x =>
                {
                    if (GetHorizontalDistance(x.GetEndPoint(1), startPoint) < 1 / 304.8) return x.CreateReversed() as Line;
                    else return x;
                }).ToList();
                //如果线只有一个的时候,说明断开了
                if (lineList.Count == 0) break;
                if (lastPoint == null)
                {
                    lastPoint = startPoint.Add(-XYZ.BasisY * 10);
                }
                //确定一开始的方向
                XYZ direction = (lastPoint - startPoint).Normalize();
                Line nextLine = null;

                if (GetHorizontalDistance(startPoint, targetPoint) < 1 / 304.8)
                    nextLine = lines.OrderBy(x => direction.AngleOnPlaneTo(x.Direction, XYZ.BasisZ)).FirstOrDefault();
                else
                    nextLine = lines.Where(x => !IsParallel(x.Direction, direction, true)).OrderBy(x => direction.AngleOnPlaneTo(x.Direction, XYZ.BasisZ)).FirstOrDefault();
                result.Add(nextLine);
                if (nextLine.GetEndPoint(1).DistanceTo(targetPoint) < 1 / 304.8) break;
                startPoint = nextLine.GetEndPoint(1);
                lastPoint = nextLine.GetEndPoint(0);
            }
            return result;
        }
        /// <summary>
        /// 计算两点平面上的巨鹿
        /// </summary>
        /// <param name="onePoint"></param>
        /// <param name="twoPoint"></param>
        /// <returns></returns>
        public double GetHorizontalDistance(XYZ onePoint, XYZ twoPoint)
        {
            return Math.Pow(Math.Pow(onePoint.X - twoPoint.X, 2) + Math.Pow(onePoint.Y - twoPoint.Y, 2), 0.5);
        }

        /// <summary>
        /// 生成直线
        /// </summary>
        /// <param name="doc"></param>
        /// <param name="l"></param>
        /// <returns></returns>
        public ModelCurve LineTest(Document doc, Line l)
        {
            XYZ basicZ = XYZ.BasisZ;
            if (l.Direction.AngleTo(XYZ.BasisZ) < 0.0001 || l.Direction.AngleTo(-XYZ.BasisZ) < 0.0001)
                basicZ = XYZ.BasisY;
            XYZ normal = basicZ.CrossProduct(l.Direction).Normalize();

            Plane plane = Plane.CreateByNormalAndOrigin(normal, l.GetEndPoint(0));

            Transaction transCreate = null;
            if (!doc.IsModifiable)
                transCreate = new Transaction(doc, "模型线测试");
            transCreate?.Start();
            SketchPlane sktpl = SketchPlane.Create(doc, plane);
            ModelCurve mc = doc.IsFamilyDocument ? doc.FamilyCreate.NewModelCurve(l, sktpl) : doc.Create.NewModelCurve(l, sktpl);
            transCreate?.Commit();
            return mc;
        }
        /// <summary>
        /// 拿到对应构件的Solid集合
        /// </summary>
        /// <param name="elem"></param>
        /// <param name="vdtLevel"></param>
        /// <returns></returns>
        public List<Solid> GetSolids(Element elem, ViewDetailLevel vdtLevel = ViewDetailLevel.Fine)
        {
            if (elem == null)
            {
                return new List<Solid>();
            }
            GeometryElement geometryElement = elem.get_Geometry(new Options
            {
                ComputeReferences = true,
                DetailLevel = vdtLevel,
                IncludeNonVisibleObjects = false,
            });
            return GetSolids(geometryElement);
        }
        /// <summary>
        /// 获取所有的Solid
        /// </summary>
        /// <param name="geometryElement"></param>
        /// <returns></returns>
        public List<Solid> GetSolids(GeometryElement geometryElement)
        {
            List<Solid> result = new List<Solid>();
            foreach (GeometryObject geomObj in geometryElement)
            {
                Solid solid = geomObj as Solid;
                if (null != solid)
                {
                    result.Add(solid);
                    continue;
                }
                //If this GeometryObject is Instance, call AddCurvesAndSolids
                GeometryInstance geomInst = geomObj as GeometryInstance;
                if (null != geomInst)
                {
                    GeometryElement transformedGeomElem = geomInst.GetInstanceGeometry(Transform.Identity);
                    result.AddRange(GetSolids(transformedGeomElem));
                }
            }
            return result;
        }
        /// <summary>
        /// 得到实体指定方向的一开始的面(取该方向上最里面的面)
        /// </summary>
        /// <param name="targetSolid"></param>
        /// <returns></returns>
        public List<CurveLoop> GetDirectionOriginCurveLoop(Solid targetSolid, XYZ direction)
        {
            List<CurveLoop> result = new List<CurveLoop>();
            List<PlanarFace> topFaceList = new List<PlanarFace>();
            foreach (Face geoFace in targetSolid.Faces)
            {
                PlanarFace temFace = geoFace as PlanarFace;
                if (temFace == null) continue;
                if (IsParallel(temFace.FaceNormal, direction))
                {
                    topFaceList.Add(temFace);
                }
            }
            var topFace = topFaceList.OrderBy(x => x.Origin.DotProduct(direction)).FirstOrDefault();
            var curveLoopList = topFace.GetEdgesAsCurveLoops().ToList();
            result.AddRange(curveLoopList);
            return result;
        }
        /// <summary>
        /// 向量是否平行
        /// </summary>
        /// <param name="vector1"></param>
        /// <param name="vector2"></param>
        /// <param name="v">true为同向平行,false为反向平行,null为平行</param>
        /// <param name="tolerance">允许误差的角度</param>
        /// <returns></returns>
        public bool IsParallel(XYZ vector1, XYZ vector2, bool? v = null, double tolerance = 0.1)
        {
            var angle = vector1.AngleTo(vector2) / Math.PI * 180;
            if (v == null)
            {
                return angle >= 180 - tolerance || angle <= tolerance;
            }
            else if (v == true)
            {
                return angle <= tolerance;
            }
            else
            {
                return angle >= 180 - tolerance;
            }
        }
        /// <summary>
        /// 传入集合的集合体,批量操作
        /// </summary>
        /// <param name="solids"></param>
        /// <param name="booleanOperationsType"></param>
        /// <returns></returns>
        public Solid GetUnionSolid(List<Solid> solids, BooleanOperationsType booleanOperationsType)
        {
            Solid firstSolid = solids[0];
            solids.RemoveAt(0);
            //对所有的几何体进行融合
            foreach (var oneSoild in solids)
            {
                try
                {
                    firstSolid = SolidBooleanOperation(firstSolid, oneSoild, booleanOperationsType);
                }
                catch
                {

                }

            }
            return firstSolid;
        }
        /// <summary>
        /// Solid布尔操作
        /// </summary>
        /// <param name="solidA"></param>
        /// <param name="solidB"></param>
        /// <param name="booleanOperationsType"></param>
        /// <returns></returns>
        public Solid SolidBooleanOperation(Solid solidA, Solid solidB, BooleanOperationsType booleanOperationsType)
        {
            Solid result = null;
            try
            {
                result = BooleanOperationsUtils.ExecuteBooleanOperation(solidA, solidB, booleanOperationsType);
            }
            catch (Exception ex)
            {
                result = BooleanOperationsUtils.ExecuteBooleanOperation(solidB, solidA, booleanOperationsType);
            }
            return result;
        }
    }
    public class OnlySelectWall : ISelectionFilter
    {
        public bool AllowElement(Element elem)
        {
            if (elem is Wall) return true;
            return false;
        }

        public bool AllowReference(Reference reference, XYZ position)
        {
            return true;
        }
    }
}

实现的效果图

目标墙实体轮廓

在这里插入图片描述

提取出来的线轮廓

在这里插入图片描述

最终计算得到的轮廓线

在这里插入图片描述

思路写在最后

(1)第一个点我找的是x和y轴都最小的点,默认的方向为指向下。
在这里插入图片描述
(2)找到起终点在第一个点上的线段,然后重构成以第一个点为起点的线。
在这里插入图片描述
(3)然后找与第一个方向单位向量,逆时针夹角最小的那一个方向的线,就是我们需要的线。然后再以这根线的终点作为找下一根线的起点,线的终点指向起点的方向为新起点方向。继续上面的循环通过找最小的夹角来确定需要的线。

在这里插入图片描述
(4)结束的点在,找到的终点就是我们一开始的点,就是循环的结束。希望能给你带来帮助

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Revit 楼板轮廓二次开发是指在Revit软件中对楼板轮廓进行定制化的开发和设计。 Revit软件是一种专业的建筑信息模型(BIM)软件,具有丰富的建筑元素库和强大的建模功能。在Revit中,楼板是建筑模型中一个重要的组成部分,其轮廓形状直接影响建筑的观和功能。 对于Revit楼板轮廓的二次开发,我们可以通过以下方式进行: 1. 参数化设计:使用Revit的参数化建模工具,可以轻松地调整和修改楼板的轮廓形状。通过定义参数并与轮廓形状相关联,可以快速实现设计变更,提高设计效率。 2. 自定义轮廓Revit提供了丰富的编辑工具,可以根据具体需求自定义楼板轮廓。可以使用编辑边界、剪切轮廓、绘制新的边界等方法进行二次开发,使楼板的轮廓与设计要求完全匹配。 3. 创新设计:通过二次开发,可以实现一些创新的楼板轮廓设计。可以自定义不规则形状的楼板轮廓,创造出独特的建筑形象。此,还可以结合其他建模工具,如梁、柱等,实现更复杂的建筑设计。 4. 自动化工具:通过编程开发,可以创建自动化工具来帮助简化楼板轮廓的设计。可以使用Revit API进行编程,定制符合特定需求的楼板轮廓生成工具,提高设计流程的效率和准确性。 总之,Revit 楼板轮廓的二次开发提供了丰富的设计和定制化的可能性。通过合理的应用,可以有效地优化建筑设计流程,提高设计效率和质量。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

baobao熊

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

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

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

打赏作者

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

抵扣说明:

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

余额充值