faceobject.Intersects(faceobject) giving obscure results.

faceobject.Intersects(faceobject) giving obscure results.

sahin.ikbal
Advocate Advocate
510 Views
6 Replies
Message 1 of 7

faceobject.Intersects(faceobject) giving obscure results.

sahin.ikbal
Advocate
Advocate

I was trying to generate a list of all walls that intersects mep objects(i.e., pipe,ducts)
Below is the code that I have written but its retuning clash for every Elements, also I have checked by drawing lines in from the intersecting curves and its returning obscure lines.

 

Any Idea why? or am I doing something wrong here?

 

 

 private IEnumerable<WallPipe> WallMEPfromFace(List<Element> mepElements, List<Element> walls)
        {


            var allWallFaces = walls.Select(x => new ElemSolidFace()
            {
                faceList = x.get_Geometry(new Options() { DetailLevel = ViewDetailLevel.Fine }).Cast<Solid>().SelectMany(z => z.Faces.Cast<Face>()),
                Elem = x
            });
            var allMEPFaces = mepElements.Select(x => new ElemSolidFace()
            {
                faceList = x.get_Geometry(new Options() { DetailLevel = ViewDetailLevel.Fine }).Cast<Solid>().SelectMany(z => z.Faces.Cast<Face>()),
                Elem = x
            });



            return allWallFaces.SelectMany(x =>
             {
                 return allMEPFaces.Select(y =>
                 {
                     var MEPfaces = y.faceList;
                     var WallFaces = x.faceList;
                     var state = MEPfaces.Any(mf => WallFaces.Any(wf =>
                     {
                         Curve curve = null;
                         var check = wf.Intersect(mf) == FaceIntersectionFaceResult.Intersecting;
                         var check1 = wf.Intersect(mf, out curve);
                         if (curve is Line)
                         {
                             SMethodsBeta.TransDrawLine(curve as Line, document);
                         }


                         return wf.Intersect(mf) == FaceIntersectionFaceResult.Intersecting;
                     }));

                     var statetool = MEPfaces.Where(mf => WallFaces.Any(wf => mf.Intersect(wf) == FaceIntersectionFaceResult.Intersecting));

                     if (state)
                     {
                         return new WallPipe() { mepElement = y.Elem, wall = x.Elem };
                     }
                     else
                     {
                         return null;
                     }
                 }).Where(it => it != null);
             }).Where(x => x != null);

 

 

 

 

WallMEP.png

Lines.png

0 Likes
511 Views
6 Replies
Replies (6)
Message 2 of 7

RPTHOMAS108
Mentor
Mentor

The planes are treated as infinite:

 

Re: Face Class, Intersect() method problem - Autodesk Community - Revit Products

 

There are pros and cons about this behaviour i.e.

(A) Sometimes you want to find actual intersections between elements

(B) Sometimes you want to project edges onto other surfaces. 

 

For (A) you can always rule out erroneous points by checking Face.IsInside

However for (B) you can't do anything if no projected intersections are found.

 

Perhaps there should be an option but the behaviour as current is justified for me.

Message 3 of 7

sahin.ikbal
Advocate
Advocate

@RPTHOMAS108 
How do you Find out for two classes(eg. wall & pipe), where they are clashing?

As I only can do that through SlowFilters like ElementIntersectsElement (or Solid), combined with some QuickFilter like boundingbox inside and intersects, but thats coming very slow. Also ElementFilter gets side effected after using WherePasses function and I again have to create new ones inside loop which seems very ineficient.

0 Likes
Message 4 of 7

RPTHOMAS108
Mentor
Mentor

If you know you are dealing with pipes and walls you can also use Category/Class filters.

 

The slowness may be related to how you go about the task (loop structure and variable scope) rather than specific filters used. That is hard to comment on without code example.

 

There is also the option of ReferenceIntersector e.g. with rays cast along pipe lengths but I don't imagine that would be quicker and you would still have to deal with bends separately.

Message 5 of 7

sahin.ikbal
Advocate
Advocate

This is how I am detecting clashes now, it's still slower than I would like it to be.

Is there anything I could introduce or change to make it faster?

 

 

private IEnumerable<WallPipe> WallMEPIntersects()
        {


            var Walls = new FilteredElementCollector(document).OfClass(typeof(Wall)).ToElements();
            int count = 0;

            var view3d = new FilteredElementCollector(document).OfClass(typeof(View3D)).FirstOrDefault(x => !(x as View3D).IsTemplate) as View3D;


            return Walls.SelectMany(x =>
             {
                 var mepFilter = new FilteredElementCollector(document).OfClass(typeof(Pipe)).
                UnionWith(new FilteredElementCollector(document).OfClass(typeof(Duct))).
                UnionWith(new FilteredElementCollector(document).OfClass(typeof(Conduit)));
                 count++;
                 var bbx = x.get_BoundingBox(view3d);
                 var outline = new Outline(bbx.Min, bbx.Max);
                 var orFilter = new LogicalOrFilter(new BoundingBoxIntersectsFilter(outline), new BoundingBoxIsInsideFilter(outline));
                 var clashedMep = mepFilter.WherePasses(orFilter).WherePasses(new ElementIntersectsElementFilter(x)).ToElements();
                 return clashedMep.Select(y => new WallPipe() { mepElement = y, wall = x });
             });

        }

 

@RPTHOMAS108 

 

0 Likes
Message 6 of 7

RPTHOMAS108
Mentor
Mentor

You have to consider that the select many clause is executing on each element in the entire set. The items that remain the same should therefore be declared outside of this or you are asking Revit to look for the same things multiple times. The 'union' LINQ extension method is something executed outside of Revit so perhaps slower than asking Revit to find such things with ElementMultiClassFilter.

 

Not sure you need the BoundingBoxIsInsideFilter unless you are checking for pipes entirely within walls. A pipe has to exit a wall at some point. So the only pipes you'll likely find with this are stray vertical segments.

 

I've replaced your return type for an anonymous type since I didn't have WallPipe class. Unless WallPipe includes some ctor logic (adding a clash id etc.) it isn't required.

 

Perhaps the below can be cleaned up some more I wouldn't typically include so much logic in a LINQ extension lambda. It may be better to conduct the check separately for each class i.e. find bounding box clashes globally then cut this out of the lambda.

 

 

public IEnumerable<object> WallMEPIntersects(Document document)
		{

			var Walls = new FilteredElementCollector(document).OfClass(typeof(Wall)).ToElements();
			int count = 0;

			var view3d = new FilteredElementCollector(document).OfClass(typeof(View3D)).FirstOrDefault(x => !(x as View3D).IsTemplate) as View3D;

			var mepFilter1 = new ElementMulticlassFilter(new List<Type>(2) { typeof(Pipe), typeof(Duct), typeof(Conduit) });
			var mepFilter = new FilteredElementCollector(document).WherePasses(mepFilter1).ToElementIds();


			return Walls.SelectMany(x =>
			{
		
				count++;
				var bbx = x.get_BoundingBox(view3d);
				var outline = new Outline(bbx.Min, bbx.Max);
				var orFilter = new LogicalOrFilter(new BoundingBoxIntersectsFilter(outline), new BoundingBoxIsInsideFilter(outline));
				var clashedMep = new FilteredElementCollector(document, mepFilter).WherePasses(orFilter).WherePasses(new ElementIntersectsElementFilter(x)).ToElements();
				return clashedMep.Select(y => new  { mepElement = y, wall = x });
			});

		}

 

 

Message 7 of 7

sahin.ikbal
Advocate
Advocate

@RPTHOMAS108 

Thank you very much for your suggestions.
I found using anonymous types a really good idea instead of container classes where not needed.

And ElementMultiClassFilter might be faster as I am only getting from unique document instance so Union can be omitted there.

//Not sure you need the BoundingBoxIsInsideFilter unless you are checking for pipes entirely within walls. A pipe has to exit a wall at some point. So the only pipes you'll likely find with this are stray vertical segments//

-Actually I will do some operations between the wall and mep elements which are clashing with it or even inside small part so, I'm recording them.

-BoundingBoxInside filter is used for where the wall is in angle and the boundingbox of it might contain the whole mep element also walls are not always straight they can be generated from other than line curves.

 

0 Likes