记录一下,写的比较简单 核心代码就这点。
没仔细测,反正目前检测的都是和rvt自带碰撞检测结果一样的。
List<ElementId> left;//要检测碰撞的元素id
List<ElementId> right;//要检测碰撞的元素id
string sResult="";
foreach(ElementId eid left)
{
Element elem = doc.GetElement(eid);
FilteredElementCollector collector = new FilteredElementCollector(doc,right);//创建收集器,指定收集范围
ElementIntersectsElementFilter filter = new ElementIntersectsElementFilter(elem);//用API过滤相交元素
List<Element> lstElem = collector.WherePasses(filter).ToElements().ToList();
if(lstElem.Count > 0)
{
foreach(Element collision_elem lstElem)
{
sInfo += elem.Name+" Id:"+elem.Id+" ----- "+collision_elem.Name+" Id:"+collision_elem.Id +"\n";
}
//处理两个集合具有相同id时,防止重复检测
if(right.Contains(eid))
right.Remove(eid);
}
}
TaskDialog.Show("result",sInfo);
纯手敲,可能有误,大家自行修改或回复。
-----------更新---------------
如果检测一个很大的模型,List<Element> lstElem = collector.WherePasses(filter).ToElements().ToList();
运行到这一句代码时会非常的耗时,出现界面假死的状态。想通过进度条显示检测进度,让界面变得更有好。
用这种方法就不行了,因为我获取不到检测的进度(不知道大家能获取到吗?)
网上查询发现也有遇到同样问题的,并且给出了解决方案:
1.用boundingboxIntersectFilter和boundingboxIsInsideFilter 快速过滤出碰撞元素(这两个都属于快速过滤器),但是过滤出来的元素会不准确,我们要把包含但不相交的元素从集合中删去。
2.用ElementIntersectsSolidFilter(慢速过滤器)进行确认是否真的碰撞
List<ElementId> left;
List<ElementId> right;
List<ElementId> realEids;//真实碰撞的id
//记录key 和哪些元素检测过
Dictionary<ElementId,List<ElementId>> m_dicCheck;
int iCount = 0;//快速过滤出的id总数
foreach(ElementId eid left)
{//此循环可以显示检测总进度
//防止重复检测
List<ElementId> temp = right;
if(m_dicCheck.Count > 0)
{
foreach(ElementId id in m_dicCheck.Keys)
{
if(m_dicCheck[id].Contains(eid))
temp.Remove(id);
}
m_dicCheck.Add(eid,temp);
}
else
{
m_dicCheck.Add(eid,temp);
}
Element elem = doc.GetElement(eid);
BoundingBoxXYZ boxXYZ = elem.get_BoundingBox(doc.ActiveView);
Outline ol = new Outline(boxXYZ.Min,boxXYZ.Max);
BoundingBoxIntersectsFilter boxIntersectsFilter = new BoundingBoxIntersectsFilter(ol);
BoundingBoxIsInsideFilter boxIsInsideFilter = new BoundingBoxIsInsideFilter(ol);
LogicalOrFilter filter = new LogicalOrFilter(boxIntersectsFilter,boxIsInsideFilter);
FilteredElememntCollector collector = new FilteredElememntCollector(doc,temp);
//用快速过滤器得到所有相交/包含的元素,并去掉集合中重复的id
List<ElementId> lstEid = collector.WherePasses(filter).ToElementIds().Distinct().ToList();
//去掉检测元素自身
lstEid = lstEid.Where(e=>e != eid).ToList();
iCount = lstEid.Count;
//得到当前检测元素的所有solid
List<Solid> lstSolid = GetElementSolid(elem);
if(lstSolid.Count == 0)
continue;
//然后就是循环判断是否真实碰撞
foreach(Solid solid lstSolid)
{//此循环可以显示单个元素检测进度
FilteredElementCollector collisionCollector = new FilteredElementCollector(doc,lstEid);
ElementIntersectsSolidFilter collisionFilter = new ElementIntersectsSolidFilter(solid);
List<ElementId> Ids = collisionCollector.WherePasses(collisionFilter).ToElementIds().ToList();
//释放过滤器和收集器,否则创建太多会内存溢出
collisionCollector.Dispose();
collisionFilter.Dispose();
if(Ids.Count > 0)
{
realEids.AddRange(Ids);
if(tempEids.Count == iCount)
break;
//将过滤出来的id从lstEid集合中删除,缩小检测范围
foreach(ElementId itemId Ids)
{
if(lstEid.Contains(itemId)) lstEid.Remove(itemId);
}
}
}
//
//真实碰撞的元素id在这里realEids, 在此执行对结果的操作
//
realEids.Clear();
}
获取Element的实体Solid
private List<Solid> GetElementSolid(Element elem)
{
List<Solid> lstSolid = new List<Solid>();
Options opt = new Option();
opt.ComputeReferences = true;
opt.IncludeNonVisbleObjects = true;
GeometryElement ge = element.get_Geomtry(opt);
if(ge != null)
lstSolid.AddRange(GetSolid(ge));
return lstSolid;
}
private List<Solid> GetSolid(GeometryElement ge)
{
List lstSolid = new List<Solid>();
foreach(GeomtryObject go in ge)
{
if(go is Solid)
{
Solid solid = go as Solid;
if(solid.SurfaceArea > 0 && solid.Volume > 0 && solid.Faces.Size > 1 && solid.Edges.Size > 1)
lstSolid.Add(solid);
}
else if(go is GeometryInstance)
{
GeomtryElement ge = (go as GeometryInstance).GetInstanceGeometry();
lstSolid.AddRange(GetSolid(ge));
}
}
return lstSolid;
}
手敲,有误自己改或回复。