Get Elevation From Selected Point Along a Pipe's Curve.

Get Elevation From Selected Point Along a Pipe's Curve.

Chris-VC_Studio
Advocate Advocate
1,080 Views
3 Replies
Message 1 of 4

Get Elevation From Selected Point Along a Pipe's Curve.

Chris-VC_Studio
Advocate
Advocate


Hey, Revit friends need some help with this one!
I've been building a plugin that will insert flow arrows onto piping by using the "Attached To" under the pipe accessories family type. So far, I can select the pipe and place the arrows on the pipe in the X&Y location along the pipe curve, but the Z elevation doesn't seem to be copying from the picked point location. I believe part of the problem is that I don't have a pipe connector on this family; the reason being is I don't want to cut the pipe into smaller segments as I plan on using this for fabrication parts too. I have seen many Revit hangar plugins from DeWalt, Super-hangers, and Victaulic where we are able to place a hanger along the curve of a pipe without breaking having to break the pipe segment. In Victaulic's case, they have their own shared parameter that appears to be copied from the picked pipe's "Z" elevation, which ends up being the center-line elevation parameter of their hangar, and I am looking to try something of the same by changing the Flow Arrows built-in Parameter "Elevation from Level." Can someone help me to identify how I can extract the Z from the picked section of my pipe and overwrite the "Elevation from Level" parameter?
For those who look at this later, I plan to parlay this into other pipe accessories like hangers, sleeves, pipe guilds, and pipe stands once I get this elevation thing out. Below is the code I have so so far.

 

Below is my code so far:

using System;

using System.Collections.Generic;

using System.Text;

using Autodesk.Revit.DB;

using Autodesk.Revit.UI;

using Autodesk.Revit.Attributes;

using Autodesk.Revit.UI.Selection;

using System.Linq;

using Autodesk.Revit.DB.Plumbing;

 

namespace myRevitCommands

{

    [Transaction(TransactionMode.Manual)]

    public class FlowArrows : IExternalCommand

    {

        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)

        {

            //Get Application ns document objects

            UIApplication uiApp = commandData.Application;

            UIDocument uiDoc = uiApp.ActiveUIDocument;

            Document doc = uiApp.ActiveUIDocument.Document;

 

            //HPSettings gpset = HPSetting.Default;

            ElementId activeviewId = doc.ActiveView.Id;

            Categories Cats = doc.Settings.Categories;

            Selection sel= uiApp.ActiveUIDocument.Selection;

 

            Transaction t = new Transaction(doc);

 

 

            FamilySymbol familyPart = new FilteredElementCollector(doc)

               .OfClass(typeof(FamilySymbol))

               .OfCategory(BuiltInCategory.OST_PipeAccessory)

               .Cast<FamilySymbol>()

               .Where<FamilySymbol>(fam => fam.Family.Name.Contains("Flow Arrow"))

               .FirstOrDefault<FamilySymbol>();

            try

            {

 

                Reference reference = sel.PickObject(ObjectType.Element);

                Pipe pipe = doc.GetElement(reference.ElementId) as Pipe;

                LocationCurve locCurve = pipe.Location as LocationCurve;

                Curve pipeCurve = locCurve.Curve;

                XYZ point = sel.PickPoint("Please pick a location along pipe place the Flow Arrow");

 

 

                Level level = doc.ActiveView.GenLevel;

                if (level == null)

                {

                    return Result.Failed;

                }

 

                t.Start("Flow Arrow");

 

                    if( !familyPart.IsActive)

                {

                    familyPart.Activate();

                    doc.Regenerate();

                }

                    

                    //Code to create flow arrow on the Curve of the pipe

                    doc.Create.NewFamilyInstance(point, familyPart, pipe, level, Autodesk.Revit.DB.Structure.StructuralType.NonStructural);

 

                    t.Commit();

                    

                //Ends Command if user Right clicks or presses Esc

            }

            catch (Autodesk.Revit.Exceptions.OperationCanceledException)

            {

 

                return Result.Cancelled;

            }

            //Catch all other exceptions errors

            catch (Exception ex)

            {

                message = ex.Message + " " + ex.StackTrace + " " + ex.Data + " " + ex.HResult;

                return Result.Failed;

            }

 

            return Result.Succeeded;

        }

    }

    public class MEPPickFilter : ISelectionFilter

    {

        public bool AllowElement(Element e)

        {

            bool IsMep = e.Category.Id.IntegerValue.Equals((int)BuiltInCategory.OST_PipeCurves) ||

                e.Category.Id.IntegerValue.Equals((int)BuiltInCategory.OST_DuctCurves);

                //e.Category.Id.IntegerValue.Equals((int)BuiltInCategory.OST_FabricationDuctwork);

                //e.Category.Id.IntegerValue.Equals((int)BuiltInCategory.OST_FabricationPipework);

            return IsMep;

        }

        public bool AllowReference(Reference r, XYZ p)

        {

            return false;

        }

    }

}

Accepted solutions (1)
1,081 Views
3 Replies
Replies (3)
Message 2 of 4

jeremy_tammik
Alumni
Alumni

Dear Chris,

  

Sorry, TLDR... I can just try to answer the question in your title, how to get elevation of a selected point along a pipe's curve: The pipe curve is generally just a straight line somewhere in 3D space. You can determine its start and end points; they are the pipe principal and secondary connectors. You can determine their elevations; basically, they are simply the end point Z coordinates. For any point in between the two end points, you can extrapolate between the start and end elevation to determine the intermediate value.

  

Cheers,

  

Jeremy

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 3 of 4

Chris-VC_Studio
Advocate
Advocate

So here's an update to my code so far, and now I can place a FlowArrow at any point on the pipe on the first floor by

rewriting a lot of the code and using the  .GlobalPoint (xyzReference).

 

Reference reference = uiDocument.Selection.PickObject(ObjectType.PointOnElement);
Pipe pipe = document.GetElement(reference) as Pipe;

XYZ point = reference.GlobalPoint;

 

Now I have two issues:

  1. I can't see any of my FlowArrow (newFamilyInstance) in a 3d view, but it works mostly works in a plan view.
  2. Next, on every level above level 1, the FlowArrows come in at the picked pipe elevation plus the datum above the level, meaning if my pipe elevation on level is 9' and the second floor is 10' above the first level the FlowArrow comes in at 19' above the floor. 9' (pipe) + 10 (floor elevation datum) = 19'

So I tried adding the following code to offset the FlowArrow down by subtracting the two Z differences, but my FlowArrows don't appear in the model when placed on the pipe at any level. Any advice on how to solve these two issues would be greatly appreciated.

document.Regenerate();
XYZ arrowOrigin = reference.GlobalPoint;
XYZ differencePoint = new XYZ(point.X - arrowOrigin.X, point.Y - arrowOrigin.Y, point.Z - arrowOrigin.Z);
flowArrow.Location.Move(new XYZ(differencePoint.X, differencePoint.Y, differencePoint.Z));

 

Below is my complete code so far, (if any ones want to use my code to place FlowArrows, all you have to do is "comment out" the elevation difference code above, and all the arrows will come in at the correct elevation on level 1 but on the floors above you will to manually adjust the arrows down to the pipe).

using System;
using System.Linq;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.UI;

namespace FlowArrows
{

[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class FlowArrows : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)

{
//Get Application as document objects
UIApplication uiApplication = commandData.Application;
Application application = uiApplication.Application;
UIDocument uiDocument = uiApplication.ActiveUIDocument;
Document document = uiApplication.ActiveUIDocument.Document;

Transaction transaction = new Transaction(document);

// Select the Flow Arrow to be used flowArrow
FamilySymbol flowArrow = new FilteredElementCollector(document)
.OfClass(typeof(FamilySymbol))
.OfCategory(BuiltInCategory.OST_PipeAccessory)
.Cast<FamilySymbol>()
.FirstOrDefault(fam => fam.Family.Name.Contains("Flow Arrow"));

 

Reference reference = uiDocument.Selection.PickObject(ObjectType.PointOnElement);
Pipe pipe = document.GetElement(reference) as Pipe;
ElementId levelId = pipe.LevelId;
XYZ point = reference.GlobalPoint;
Level level = document.ActiveView.GenLevel;
if (level == null)
{
return Result.Failed;
}
try
{
transaction.Start("Flow Arrow");

if (!flowArrow.IsActive)
{
flowArrow.Activate();
document.Regenerate();
}

//Code to create flow arrow on the Curve of the pipe

document.Create.NewFamilyInstance(point, flowArrow, document.GetElement(levelId) as Level, StructuralType.NonStructural);

document.Regenerate();
XYZ arrowOrigin = reference.GlobalPoint;
XYZ differencePoint = new XYZ(point.X - arrowOrigin.X, point.Y - arrowOrigin.Y, point.Z - arrowOrigin.Z);
flowArrow.Location.Move(new XYZ(differencePoint.X, differencePoint.Y, differencePoint.Z));


transaction.Commit();

}
//Ends Command if user Right clicks or presses Esc
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
{
return Result.Cancelled;
}
//Catch all other exceptions errors
catch (Exception ex)
{
message = ex.Message + " " + ex.StackTrace + " " + ex.Data + " " + ex.HResult;
return Result.Failed;
}
return Result.Succeeded;
}
}
}

0 Likes
Message 4 of 4

Chris-VC_Studio
Advocate
Advocate
Accepted solution

SUCCESS (well mostly),

I still can't place a flow arrow in a 3d or section view but I was able to correctly elevate the FlowArrows to match the pipe center line no matter what level they are located on.

I did this by adding the following code to get "LocationPoint" of the pipe and subtracting it from the current location of the placed arrow after the NewFamilyInstance Method

 

                document.Regenerate();

                LocationPoint arrowLocationPoint = placedArrow.Location as LocationPoint;

                XYZ location = arrowLocationPoint.Point;

                XYZ differencePoint = new XYZ(point.X - location.X, point.Y - location.Y, point.Z - location.Z);

                placedArrow.Location.Move(new XYZ(differencePoint.X, differencePoint.Y, differencePoint.Z));

 

here is the link to my code on github

https://github.com/cabowker/FlowArrows