#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();
    }
}

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s