Hi all,
I have questions about bounding box. I tried to get outline of BoundingBox and retrieve elements inside it. But I've faced 3 cases:
1. My code works fine with horizontal BoundingBox (rorate = 0 deg).
2. BoundingBox still can get outline, but can not select all element inside. (rorate = 10 ~ 20 deg).
3. BoundingBox can't get outline(rorate > 45 deg) .Error message is "outline is an empty outline".See code below in red line
[Transaction(TransactionMode.Manual)] public class ElementInsideBoundingBox : IExternalCommand { public Result Execute( ExternalCommandData commandData, ref string message, ElementSet elements) { UIApplication uiapp = commandData.Application; UIDocument uidoc = uiapp.ActiveUIDocument; Application app = uiapp.Application; Document doc = uidoc.Document; View3D curView3d = doc.ActiveView as View3D; BoundingBoxXYZ box = curView3d.GetSectionBox(); Transform t = box.Transform; Outline o = new Outline(t.OfPoint(box.Min), t.OfPoint(box.Max)); FilteredElementCollector collector = new FilteredElementCollector(doc); BoundingBoxIsInsideFilter bbfilter = new BoundingBoxIsInsideFilter(o); IList<ElementId> insideList = collector .WhereElementIsNotElementType() .WherePasses(bbfilter) .Where(x => x.GetTypeId().IntegerValue != -1) .Where(x => x.IsPhysicalElement()) .Select(x => x.Id) .ToList(); uidoc.Selection.SetElementIds(insideList); return Result.Succeeded; } }
I attached revit file for example. Please tell me where I was wrong?
Thank you in advanced!
Solved! Go to Solution.
Solved by jeremytammik. Go to Solution.
Thank you for your query, good explanation and reproducible case.
I passed it on to the development team to ask what they can say off-hand.
Best regards,
Jeremy
I heard back from the development team on this. They say:
We struggled with a similar issue. My understanding is that an Outline is always axis aligned - you are rotating the min and max points of the bounding box, `new Outline(t.OfPoint(box.Min), t.OfPoint(box.Max));` this doesn't give the results you seem to be expecting (a rotated box). Instead, it creates an axis aligned outline, which won't have the same proportions as the original BB (the min and max were rotated). We solved this problem by doing the opposite, i.e., rotating the elements' outlines and not the BBox's outline (new outline from all rotated corners, so we loose some precision, but we didn't care). Perhaps there is another way but that is what we ended up doing and it worked pretty well.
I hope this helps.
Cheers,
Jeremy
I edited and cleaned up our discussion for posterity, plus adding another, new, suggestion to address your need using a solid intersection filter instead:
http://thebuildingcoder.typepad.com/blog/2018/04/bounding-box-filter-always-axis-aligned.html
Cheers,
Jeremy
So would I 🙂
Go ahead, try it out, and share the results.
Thank you!
Cheers,
jeremy
Hi Jeremy,
There are many categories that cannot get Solid out of geometry, i.e Lines, Planting,... That means I cannot use ElementIntersectsSolidFilter to retrieve them. Do you have any suggestions?
Yes.
Use a larger axis aligned bounding box filter to apply quick filtering.
In a second step, eliminate the elements that lie outside the enclosed rotated box that you are really interested in.
Cheers,
Jeremy
hi
you mentioned about this case as below.
ou can solve this problem by doing the opposite, i.e., rotating the elements' outlines and not the BBox's outline (new outline from all rotated corners, so you lose some precision).
We ended up doing that is one case and it worked pretty well.
please share the code in which you rotated the bounding box
Why in this line:
".Where(x => x.IsPhysicalElement())"
can't find "IsPhysicalElement()"(ps:even in the API Doc)?
Did you create a method?
Hi:
It's a method that not decleared in RevitAPI.
But I think it's name is quite easy to understand.
And also, you can try these lines:
internal static IEnumerable<Element> GetLocationElems(View v) { // Get elements that are visible in a View // And the elements must have a valid location (curve/point) var es = new FilteredElementCollector(v.Document, v.ID).ToElements(); return (from e in es where e != null && e.IsValidObject && e.Location != null where (e.Location is LocationCurve) || (e.Location is LocationPoint) select e).ToList(); }
I replaced some lines in the above codes. So if there is some little errors, I do believe it's also quite easy to work it out.