Shortest Path Analysis using Revit API’s PathOfTravel()

Shortest Path Analysis using Revit API’s PathOfTravel()

The newly introduced Route Analysis function in Revit 2020 provides us a really handy tool to perform the shortest path analysis. And what makes it even better, is its ease of access through the Revit API.

Before we jump into coding, there are some information about this function that we should know. Since most of the information are well documented by Autodesk, I’ll highlight the few which, in my opinion, are more critical.

  1. Shortest path assessed based on the A* algorithm.
  2. The “nodes” or “grids” assessed by the algorithm are fixed at 200mm by 200mm, which affects the amount of allowance between paths.
  3. You can define obstacles by Revit Categories through the User Interface and/ or the API (Doors are not regarded as obstacles by default).

The code that follows gets the user to select 2 elements manually, and finds the shortest path between them. (Don’t forget the Autodesk.Revit.DB.Analysis Namespace !) While this is similar to the manual button that can be found in your User Interface, you can imagine developing your own set of rules to select XYZ points computationally.

using Autodesk.Revit.DB.Analysis;
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
    UIDocument uidoc = commandData.Application.ActiveUIDocument;
    Document doc = commandData.Application.ActiveUIDocument.Document;
            
    //Select first room
    Reference selection = uidoc.Selection.PickObject( ObjectType.Element);      //Select Element 1
    ElementId eleId = selection.ElementId;
    LocationPoint eleLocPt = doc.GetElement(eleId).Location as LocationPoint;
    XYZ roomXyzPoint1 = eleLocPt.Point;
 
    //Select second room
    Reference selection2 = uidoc.Selection.PickObject( ObjectType.Element);     //Select Element 2
    ElementId eleId2 = selection2.ElementId;
    LocationPoint eleLocPt2 = doc.GetElement(eleId2).Location as LocationPoint;
    XYZ roomXyzPoint2 = eleLocPt2.Point;
 
    //Find shortest Path
    using (Transaction tx = new Transaction(doc))
    {
        tx.Start("Find shortest Path !");
 
        PathOfTravel route = PathOfTravel.Create( doc.ActiveView, roomXyzPoint1, roomXyzPoint2);
                
        tx.Commit();
    }
            
    return Result.Succeeded;
}

You can see the results by selecting 2 different room elements.

We can also perform multiple path analysis using handy methods provided off the shelf, i.e. CreateMapped() and CreateMultiple() methods.

The following snippet demonstrates the implementation of the CreateMapped() method with a single XYZ input in the first list and 8 XYZ inputs in the second list.

public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
    UIDocument uidoc = commandData.Application.ActiveUIDocument;
    Document doc = commandData.Application.ActiveUIDocument.Document;
 
    IList<Reference> selection1 = uidoc.Selection.PickObjects(ObjectType.Element);      //Select 1st list
    IList<XYZ> roomsXyz1 = selection1                                                   //Room 7 only
        .Select(r => doc.GetElement(r.ElementId).Location)
        .Cast<LocationPoint>()
        .Select(locPoint => locPoint.Point)
        .ToList();
 
    IList<Reference> selection2 = uidoc.Selection.PickObjects( ObjectType.Element );    //Select 2nd list
    IList<XYZ> roomsXyz2 = selection2                                                   //Room 1 thru 9 except 7
        .Select(r => doc.GetElement(r.ElementId).Location)                              
        .Cast<LocationPoint>()
        .Select(locPoint => locPoint.Point)
        .ToList();
 
    using (Transaction tx = new Transaction(doc))
    {
        tx.Start("Find shortest Path !");
 
        IList<PathOfTravel> routeMap = PathOfTravel.CreateMapped(doc.ActiveView, roomsXyz1, roomsXyz2);
 
        tx.Commit();
    }
            
    return Result.Succeeded;
}

Below yields the results by the CreateMapped() method.

The following snippet demonstrates the implementation of the CreateMultiple() method which requires the same amount of inputs in both lists.

public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
    UIDocument uidoc = commandData.Application.ActiveUIDocument;
    Document doc = commandData.Application.ActiveUIDocument.Document;
 
    IList<Reference> selection1 = uidoc.Selection.PickObjects(ObjectType.Element);      //Select 1st list
    IList<XYZ> roomsXyz1 = selection1                                                   //Room 1,2 & 3
        .Select(r => doc.GetElement(r.ElementId).Location)
        .Cast<LocationPoint>()
        .Select(locPoint => locPoint.Point)
        .ToList();
 
    IList<Reference> selection2 = uidoc.Selection.PickObjects( ObjectType.Element );    //Select 2nd list
    IList<XYZ> roomsXyz2 = selection2                                                   //Room 4,6 & 8
        .Select(r => doc.GetElement(r.ElementId).Location)                              
        .Cast<LocationPoint>()
        .Select(locPoint => locPoint.Point)
        .ToList();
 
    using (Transaction tx = new Transaction(doc))
    {
        tx.Start("Find shortest Path !");
 
        //IList<PathOfTravel> routeMap = PathOfTravel.CreateMapped(doc.ActiveView, roomsXyz1, roomsXyz2);
        IList<PathOfTravel> routeMultiple = PathOfTravel.CreateMultiple(doc.ActiveView, roomsXyz1, roomsXyz2);
 
        tx.Commit();
    }
            
    return Result.Succeeded;
}

Below yields the results by the CreateMultiple() method.

As always, you can find the source code for the full implementation HERE for Single elements and HERE for multiple elements! Happy coding!

Leave a Reply

Close Menu