Selecting elements between two points

Selecting elements between two points

Kevin.Bell
Advisor Advisor
1,170 Views
2 Replies
Message 1 of 3

Selecting elements between two points

Kevin.Bell
Advisor
Advisor

Hi,

 

I'm looking to write a c# routine which will process elements selected by the user which are between two points.

 

Kinda like the how you can use a 'fence' selection in AutoCAD.

 

i.e. the user picks one point, then another and any objects which cross an imaginary line between the two points would be returned.

 

 

The only way I can think of doing this is that the routine would use coordinates of the two points to calculator a 'thin rectangle', say 100mm wide, the length of which would be the distance between the two points. I could then use BoundingBoxIntersectsFilter as a filter to a FilteredElementCollector to find the elements.

 

Is this a good way to do this? Or is there a simpler method using the API?

 

Thanks.

0 Likes
1,171 Views
2 Replies
Replies (2)
Message 2 of 3

RPTHOMAS108
Mentor
Mentor

Similar to below perhaps:

 

Create DirectShape along path of picked points then use ElementIntersectsElement filter to get the elements. Rollback the transaction to remove the added shapes.

 

Things to consider:

  1. Tested for view plans only
  2. Should create DirectShape element whose vertical extent matches the view range (so that height of elements in view vs height of fence doesn't give unexpected results).
  3. Not verified the accuracy of the ElementIntersectsElement filter results.

 

VB.Net

    Private Function TObj17(ByVal commandData As Autodesk.Revit.UI.ExternalCommandData, _
                ByRef message As String, ByVal elements As Autodesk.Revit.DB.ElementSet) As Result

        Dim IntApp As UIApplication = commandData.Application
        Dim UIDoc As UIDocument = IntApp.ActiveUIDocument
        If UIDoc Is Nothing Then Return Result.Cancelled Else 
        Dim IntDoc As Document = UIDoc.Document

        Dim Mls As New List(Of Element)
        Dim LastEp As XYZ = Nothing
        Dim Selection As New List(Of ElementId)

        Dim GetPipeShp = Function(Pt1 As XYZ, Pt2 As XYZ) As DirectShape
                             Const Rad As Double = 50 / 304.8 '50mm

                             Dim LN As Line = Line.CreateBound(Pt1, Pt2)
                             Dim T As Transform = LN.ComputeDerivatives(0, True)

                             Dim P As Plane = Plane.CreateByNormalAndOrigin(T.BasisX.Normalize, LN.GetEndPoint(0))
                             Dim a1 As Arc = Arc.Create(P, Rad, 0, Math.PI)
                             Dim a2 As Arc = Arc.Create(P, Rad, Math.PI, Math.PI * 2)

                             Dim CL As List(Of CurveLoop) = New CurveLoop(0) {CurveLoop.Create(New Curve(1) {a1, a2}.ToList)}.ToList
                             Dim CL_P As CurveLoop = CurveLoop.Create(New Curve(0) {LN}.ToList)

                             Dim S As Solid = GeometryCreationUtilities.CreateSweptGeometry(CL_P, 0, LN.GetEndParameter(0), CL)

                             Dim Out As DirectShape = Nothing
                             Using Tx As New SubTransaction(IntDoc)
                                 If Tx.Start = TransactionStatus.Started Then
                                     Out = DirectShape.CreateElement(IntDoc, New ElementId(BuiltInCategory.OST_GenericModel))
                                     Out.AppendShape(New GeometryObject(0) {S})
                                     Tx.Commit()
                                 End If
                             End Using
                             Return Out
                         End Function

        Using Tx As New Transaction(IntDoc, "Fence")
            If Tx.Start = TransactionStatus.Started Then

                Using ST As New SubTransaction(IntDoc)
                    If ST.Start = TransactionStatus.Started Then
                        Dim Plane As Plane = Plane.CreateByNormalAndOrigin(IntDoc.ActiveView.ViewDirection, IntDoc.ActiveView.Origin)
                        IntDoc.ActiveView.SketchPlane = SketchPlane.Create(IntDoc, Plane)
                        ST.Commit()
                    End If
                End Using
               
                While True
                    Try
                        Dim XYZ As XYZ = UIDoc.Selection.PickPoint("Pick points then press escape to cause an exception ahem...exit selection")
                        If LastEp Is Nothing Then
                            LastEp = XYZ
                        Else
                            Dim Dist As Double = LastEp.DistanceTo(XYZ)
                            If Dist <= IntApp.Application.ShortCurveTolerance Then
                                Continue While
                            End If
                            Dim El As Element = GetPipeShp(LastEp, XYZ)
                            If El Is Nothing = False Then
                                Mls.Add(El)
                            End If

                            IntDoc.Regenerate()
                            LastEp = XYZ
                        End If
                    Catch ex As Exception
                        Exit While
                    End Try
                End While
            End If
            If Mls.Count > 0 Then
                Dim FEC As New FilteredElementCollector(IntDoc, IntDoc.ActiveView.Id)
                Dim EF As ElementFilter = Nothing

                If Mls.Count = 1 Then
                    EF = New ElementIntersectsElementFilter(Mls(0))
                Else
                    Dim Filts As New List(Of ElementFilter)
                    For Each item As Element In Mls
                        Dim EIE As New ElementIntersectsElementFilter(item)
                        Filts.Add(EIE)
                    Next
                    EF = New LogicalOrFilter(Filts)
                End If

                Selection = FEC.WherePasses(EF).ToElementIds
            End If
            Tx.RollBack()
        End Using
        TaskDialog.Show("Count", CStr(Selection.Count))


        Return Result.Succeeded

    End Function

C#

 

 public Result TObj17(Autodesk.Revit.UI.ExternalCommandData commandData, ref string message, Autodesk.Revit.DB.ElementSet elements)
        {

            UIApplication IntApp = commandData.Application;
            UIDocument UIDoc = IntApp.ActiveUIDocument;
            if (UIDoc == null)
                return Result.Cancelled;
            Document IntDoc = UIDoc.Document;

            List<Element> Mls = new List<Element>();
            XYZ LastEp = null;
            ICollection<ElementId> Selection = new List<ElementId>();


            Func<XYZ,XYZ,Element> GetPipeShp;
            GetPipeShp = (XYZ Pt1, XYZ Pt2) =>
            {
                const double Rad = 50 / 304.8;
                //50mm

                Line LN = Line.CreateBound(Pt1, Pt2);
                Transform T = LN.ComputeDerivatives(0, true);

                Plane P = Plane.CreateByNormalAndOrigin(T.BasisX.Normalize(), LN.GetEndPoint(0));
                Arc a1 = Arc.Create(P, Rad, 0, Math.PI);
                Arc a2 = Arc.Create(P, Rad, Math.PI, Math.PI * 2);

                List<CurveLoop> CL = new CurveLoop[1] { CurveLoop.Create(new Curve[2] {
				a1,
				a2
			}.ToList()) }.ToList();
                CurveLoop CL_P = CurveLoop.Create(new Curve[1] { LN }.ToList());

                Solid S = GeometryCreationUtilities.CreateSweptGeometry(CL_P, 0, LN.GetEndParameter(0), CL);

                DirectShape Out = null;
                using (SubTransaction Tx = new SubTransaction(IntDoc))
                {
                    if (Tx.Start() == TransactionStatus.Started)
                    {
                        Out = DirectShape.CreateElement(IntDoc, new ElementId(BuiltInCategory.OST_GenericModel));
                        Out.AppendShape(new GeometryObject[1] { S });
                        Tx.Commit();
                    }
                }
                return Out;
            };

            using (Transaction Tx = new Transaction(IntDoc, "Fence"))
            {

                if (Tx.Start() == TransactionStatus.Started)
                {
                    using (SubTransaction ST = new SubTransaction(IntDoc))
                    {
                        if (ST.Start() == TransactionStatus.Started)
                        {
                            Plane Plane = Plane.CreateByNormalAndOrigin(IntDoc.ActiveView.ViewDirection, IntDoc.ActiveView.Origin);
                            IntDoc.ActiveView.SketchPlane = SketchPlane.Create(IntDoc, Plane);
                            ST.Commit();
                        }
                    }
                    Boolean EndWhile = false;

                    while (EndWhile == false)
                    {
                        try
                        {
                            XYZ XYZ = UIDoc.Selection.PickPoint("Pick points then press escape to cause an exception ahem...exit selection");
                            if (LastEp == null)
                            {
                                LastEp = XYZ;
                            }
                            else
                            {
                                double Dist = LastEp.DistanceTo(XYZ);
                                if (Dist <= IntApp.Application.ShortCurveTolerance)
                                {
                                    continue;
                                }
                                Element El = GetPipeShp(LastEp, XYZ);
                                if (El == null == false)
                                {
                                    Mls.Add(El);
                                }

                                IntDoc.Regenerate();
                                LastEp = XYZ;
                            }
                        }
                        catch
                        {
                            EndWhile = true;
                            break; // TODO: might not be correct. Was : Exit While
                        }
                    }
                }
                if (Mls.Count > 0)
                {
                    FilteredElementCollector FEC = new FilteredElementCollector(IntDoc, IntDoc.ActiveView.Id);
                    ElementFilter EF = null;

                    if (Mls.Count == 1)
                    {

                       EF = new ElementIntersectsElementFilter(Mls.First());
                    }
                    else
                    {
                        List<ElementFilter> Filts = new List<ElementFilter>();
                        foreach (Element item in Mls)
                        {
                            ElementIntersectsElementFilter EIE = new ElementIntersectsElementFilter(item);
                            Filts.Add(EIE);
                        }
                        EF = new LogicalOrFilter(Filts);
                    }

                    Selection = FEC.WherePasses(EF).ToElementIds();
                }
                Tx.RollBack();
            }
            TaskDialog.Show("Count", Convert.ToString(Selection.Count));

            return Result.Succeeded;

        }
0 Likes
Message 3 of 3

Kevin.Bell
Advisor
Advisor

Thats great, I've not used DirectShapes before (or heard of them...), but it sounds like a plan.

 

I'll give it a try. Thanks for your help.

 

 

0 Likes