Revit开发__任意点地面投影点查找

概述

    在一些设计场景中,用户需要贴着地面生成某些构件,或者将已有的构件移到地形表面。这时,就需要一个标高查找的功能,即用户输入一个点,就返回该点在地面的铅锤投影点。

原理

    Revit中的地形由一个个三角形组成的三角网构成。要获得输入点的铅锤投影点,先要查找与投影线相交的三角形,再通过线面相交获取交点。另外,当项目存在多个地面时,对每个地面去获取三角形再对每个三角形逐个判断是否相交效率很低,单个点可能几秒钟甚至几十秒才能找出交点。为了提高查找效率,可以对主体地形和它的子面域一起查找,同时只对与输入点平面距离最近的三个点相关的三角形查找交点,同时还可以对循环次数比较多的操作采取并行的方式。这样,每次查找消耗时间可以控制在0.5秒内。当找到交点时,返回交点坐标;未找到交点时,返回null。

代码实现

     完整的查找方法如下:

public static XYZ GetIntersectPointOnTopographySurface(TopographySurface typography, XYZ inputPoint)
{
    var document = typography.Document;
    var targetTypography = !typography.IsSiteSubRegion ? typography : document.GetElement(typography.AsSiteSubRegion().HostId) as TopographySurface;
    var typographyList = new List<TopographySurface>();
    var meshs = new List<Mesh>();
    var meshTriangles = new List<MeshTriangle>();
    var points = new List<XYZ>();
    typographyList.Add(targetTypography);
    var subRegionIds = targetTypography.GetHostedSubRegionIds();
    if (subRegionIds != null) typographyList.AddRange(subRegionIds.Select(x => document.GetElement(x) as TopographySurface));
    typographyList.ForEach(x => meshs.AddRange(GetMeshs(x.get_Geometry(new Options { DetailLevel = ViewDetailLevel.Fine }))));
    meshs.ForEach(x => { points.AddRange(x.Vertices); });
    points.Sort((x, y) => (x - XYZ.BasisZ * y.Z).DistanceTo(inputPoint) <= (y - XYZ.BasisZ * y.Z).DistanceTo(inputPoint) ? -1 : 1);
    var firstThreePoints = points.GetRange(0, 3);
    Parallel.ForEach(meshs, (mesh) =>
     {
         for (var i = 0; i < mesh.NumTriangles; i++)
         {
             var meshTriangle = mesh.get_Triangle(i);
             for (var j = 0; j < 3; j++)
             {
                 if (firstThreePoints.Any(y => meshTriangle.get_Vertex(j).IsAlmostEqualTo(y)))
                 {
                     meshTriangles.Add(meshTriangle);
                     break;
                 }
             }
         }
     });

   foreach (var meshTriangle in meshTriangles)
   { 
     try
      {
          var profile = new CurveLoop();
           for (var j = 0; j < 3; j++)
           {
               profile.Append(Line.CreateBound(meshTriangle.get_Vertex(j), meshTriangle.get_Vertex((j + 1) % 3)));
           }
           var intersectPoint = GetIntersectPointOnCurveloop(new List<CurveLoop> { profile }, inputPoint);
           if (intersectPoint == null) continue;
           return intersectPoint;
       }
       catch { }
   }
   return null;
}

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值