#RTCEUR Wish 2: Pipe Split and Hanger Creation

Brian wished for “splitting MEP Pipework at certain distances on the horizontals with Revit MEP Hangers”. Here’s a look at how the API can be used to create a new set of pipes of a specified length to replace one long pipe. Hangers are placed at the start and end of each new pipe.

One opportunity for improvement would be to do something more sophisticated at the end of the original pipe. If your pipe comes in standard lengths, you may not want to end up with a 1′ piece of pipe at the end if you need 37′ total feet of pipe and your standard length is 6′. If that sounds like an interesting problem to solve, send me a tweet and maybe I’ll post the solution tomorrow. But now its time to find out more about the PORT in Porto.

public void SplitPipe()
{
    UIDocument uidoc = this.ActiveUIDocument;
    Document doc = uidoc.Document;
    Pipe pipe = doc.GetElement(uidoc.Selection.PickObject(ObjectType.Element)) as Pipe;
    ElementId levelId = pipe.get_Parameter(BuiltInParameter.RBS_START_LEVEL_PARAM).AsElementId();

    Line pipeLine = ((LocationCurve)pipe.Location).Curve as Line;
    double segmentLength = 6;
    List<Line> newLines = new List<Line>();
    double i = 0;
    for (i=0; i <= pipeLine.Length - segmentLength; i = i + segmentLength)
    {
        XYZ end0 = pipeLine.Evaluate(i, false);
        XYZ end1 = pipeLine.Evaluate(i + segmentLength, false);
        newLines.Add(Line.CreateBound(end0, end1));
    }
    newLines.Add(Line.CreateBound(pipeLine.Evaluate(i, false), pipeLine.Evaluate(1, true)));
    
    FamilySymbol hangerSymbol = new FilteredElementCollector(doc)
        .OfClass(typeof(FamilySymbol))
        .Cast<FamilySymbol>()
        .FirstOrDefault(q => q.Family.Name == "Hanger" &&
                        q.Family.FamilyCategory.Id.IntegerValue == (int)BuiltInCategory.OST_PipeAccessory);
    
    using (Transaction t = new Transaction(doc, "Split Pipe"))
    {
        t.Start();
        View3D view3d = View3D.CreateIsometric(doc, new FilteredElementCollector(doc)
                                               .OfClass(typeof(ViewFamilyType))
                                               .Cast<ViewFamilyType>()
                                               .FirstOrDefault(q => q.ViewFamily == ViewFamily.ThreeDimensional).Id);
        
        List<Tuple<FamilyInstance, double>> hangers = new List<Tuple<FamilyInstance, double>>();
        for (int lineCtr = 0; lineCtr < newLines.Count; lineCtr++)
        {
            Pipe newPipe = Pipe.Create(doc, pipe.MEPSystem.GetTypeId(), pipe.PipeType.Id, levelId, newLines[lineCtr].GetEndPoint(0), newLines[lineCtr].GetEndPoint(1));
            ReferenceIntersector ri = new ReferenceIntersector(new ElementClassFilter(typeof(Ceiling)), FindReferenceTarget.Face, view3d);
            ReferenceWithContext rwc = ri.FindNearest(newLines[lineCtr].GetEndPoint(1), XYZ.BasisZ);
            if (rwc != null)
            {
                Reference r = rwc.GetReference();
                Ceiling ceiling = doc.GetElement(r) as Ceiling;
                Options opt = new Options();
                opt.ComputeReferences = true;
                PlanarFace ceilingBottomFace = null;
                Solid s = ceiling.get_Geometry(opt).Cast<GeometryObject>().FirstOrDefault(q => q is Solid) as Solid;
                foreach (Face face in s.Faces)
                {
                    if (face is PlanarFace)
                    {
                        PlanarFace pf = face as PlanarFace;
                        if (pf.FaceNormal.IsAlmostEqualTo(XYZ.BasisZ.Negate()))
                        {
                            
                            ceilingBottomFace = pf;
                            break;
                        }
                    }
                }
                if (ceilingBottomFace != null)
                {
                    FamilyInstance fiHanger = doc.Create.NewFamilyInstance(ceilingBottomFace, newLines[lineCtr].GetEndPoint(1), pipeLine.Direction.CrossProduct(XYZ.BasisZ), hangerSymbol);
                    hangers.Add(new Tuple<FamilyInstance, double>(fiHanger, rwc.Proximity));
                    if (lineCtr == 0)
                    {
                        fiHanger = doc.Create.NewFamilyInstance(ceilingBottomFace, newLines[lineCtr].GetEndPoint(0), pipeLine.Direction.CrossProduct(XYZ.BasisZ), hangerSymbol);    
                        hangers.Add(new Tuple<FamilyInstance, double>(fiHanger, rwc.Proximity));
                    }
                }
            }
        }
        
        foreach (Tuple<FamilyInstance, double> tup in hangers)
        {
            tup.Item1.Parameters.Cast<Parameter>().FirstOrDefault(q => q.Definition.Name == "Distance from Ceiling to Pipe Center").Set(tup.Item2);
        }
        
        doc.Delete(pipe.Id);
        doc.Delete(view3d.Id);
        t.Commit();
    }
}
Advertisements

2 thoughts on “#RTCEUR Wish 2: Pipe Split and Hanger Creation

  1. Thank you so much. I have few questions as listed below

    a. Where i can find hanger family?
    b. Is that a ceiling or floor?
    c. Which code needs to be removed if I don’t want to split pipes but need hangers placed at the distance provided?

    I am just learning your revit API. so its bit confusing to me.

    Thanks again for your help.

    • Hi,

      Glad you find this interesting. if you are new to the Revit API and would like to learn more, I highly recommend my top-rated video course at http://bit.ly/revitapi. Hundreds of people have used it to go from beginner to advanced.

      I don’t have the hanger family handy, but you can use any ceiling hosted family. Name it Hanger.rfa and assign it to the Pipe Accessories category.
      if you don’t want to split the pipes, the code to remove would include
      Pipe newPipe = Pipe.Create(doc, pipe.MEPSystem.GetTypeId(), pipe.PipeType.Id, levelId, newLines[lineCtr].GetEndPoint(0), newLines[lineCtr].GetEndPoint(1));
      doc.Delete(pipe.Id);

      Regards
      Harry

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s