CreateModelCurve() public method

public CreateModelCurve ( Curve curve ) : ModelCurve
curve Curve
return ModelCurve
        static Transform _t = Transform.CreateTranslation(_offset); // 2014

        public Result Execute(
            ExternalCommandData commandData,
            ref string message,
            ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
            UIDocument    uidoc = uiapp.ActiveUIDocument;
            Application   app   = uiapp.Application;
            Document      doc   = uidoc.Document;

            List <Element> walls = new List <Element>();

            if (!Util.GetSelectedElementsOrAll(
                    walls, uidoc, typeof(Wall)))
            {
                Selection sel = uidoc.Selection;
                //message = ( 0 < sel.Elements.Size ) // 2014
                message = (0 < sel.GetElementIds().Count) // 2015
          ? "Please select some wall elements."
          : "No wall elements found.";
                return(Result.Failed);
            }

            using (Transaction tx = new Transaction(doc))
            {
                tx.Start("Create model curve copies of analytical model curves");

                Creator creator = new Creator(doc);

                foreach (Wall wall in walls)
                {
                    AnalyticalModel am = wall.GetAnalyticalModel();

                    foreach (AnalyticalCurveType ct in _curveTypes)
                    {
                        IList <Curve> curves = am.GetCurves(ct);

                        int n = curves.Count;

                        Debug.Print("{0} {1} curve{2}.",
                                    n, ct, Util.PluralSuffix(n));

                        foreach (Curve curve in curves)
                        {
                            //creator.CreateModelCurve( curve.get_Transformed( _t ) ); // 2013

                            creator.CreateModelCurve(curve.CreateTransformed(_t)); // 2014
                        }
                    }
                }
                tx.Commit();
            }
            return(Result.Succeeded);
        }
        public Result Execute(
            ExternalCommandData commandData,
            ref string message,
            ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
            UIDocument    uidoc = uiapp.ActiveUIDocument;
            Application   app   = uiapp.Application;
            Document      doc   = uidoc.Document;

            //// Select all pipes in the entire model.

            //List<Pipe> pipes = new List<Pipe>(
            //  new FilteredElementCollector( doc )
            //    .OfClass( typeof( Pipe ) )
            //    .ToElements()
            //    .Cast<Pipe>() );

            //int n = pipes.Count;

            //// If there are less than two,
            //// there is nothing we can do.

            //if( 2 > n )
            //{
            //  message = _prompt;
            //  return Result.Failed;
            //}

            //// If there are exactly two, pick those.

            //if( 2 < n )
            //{
            //  // Else, check for a pre-selection.

            //  pipes.Clear();

            //  Selection sel = uidoc.Selection;

            //  //n = sel.Elements.Size; // 2014

            //  ICollection<ElementId> ids
            //    = sel.GetElementIds(); // 2015

            //  n = ids.Count; // 2015

            //  Debug.Print( "{0} pre-selected elements.",
            //    n );

            //  // If two or more model pipes were pre-
            //  // selected, use the first two encountered.

            //  if( 1 < n )
            //  {
            //    //foreach( Element e in sel.Elements ) // 2014

            //    foreach( ElementId id in ids ) // 2015
            //    {
            //      Pipe c = doc.GetElement( id ) as Pipe;

            //      if( null != c )
            //      {
            //        pipes.Add( c );

            //        if( 2 == pipes.Count )
            //        {
            //          Debug.Print( "Found two model pipes, "
            //            + "ignoring everything else." );

            //          break;
            //        }
            //      }
            //    }
            //  }

            //  // Else, prompt for an
            //  // interactive post-selection.

            //  if( 2 != pipes.Count )
            //  {
            //    pipes.Clear();

            //    try
            //    {
            //      Reference r = sel.PickObject(
            //        ObjectType.Element,
            //        new PipeElementSelectionFilter(),
            //        "Please pick first pipe." );

            //      pipes.Add( doc.GetElement( r.ElementId )
            //        as Pipe );
            //    }
            //    catch( Autodesk.Revit.Exceptions
            //      .OperationCanceledException )
            //    {
            //      return Result.Cancelled;
            //    }

            //    try
            //    {
            //      Reference r = sel.PickObject(
            //        ObjectType.Element,
            //        new PipeElementSelectionFilter(),
            //        "Please pick second pipe." );

            //      pipes.Add( doc.GetElement( r.ElementId )
            //        as Pipe );
            //    }
            //    catch( Autodesk.Revit.Exceptions
            //      .OperationCanceledException )
            //    {
            //      return Result.Cancelled;
            //    }
            //  }
            //}

            JtPairPicker <Pipe> picker
                = new JtPairPicker <Pipe>(uidoc);

            Result rc = picker.Pick();

            if (Result.Failed == rc)
            {
                message = _prompt;
            }

            if (Result.Succeeded != rc)
            {
                return(rc);
            }

            IList <Pipe> pipes = picker.Selected;

            // Check for same pipe system type.

            ElementId systemTypeId
                = pipes[0].MEPSystem.GetTypeId();

            Debug.Assert(pipes[1].MEPSystem.GetTypeId()
                         .IntegerValue.Equals(
                             systemTypeId.IntegerValue),
                         "expected two similar pipes");

            // Check for same pipe level.

            ElementId levelId = pipes[0].LevelId;

            Debug.Assert(
                pipes[1].LevelId.IntegerValue.Equals(
                    levelId.IntegerValue),
                "expected two pipes on same level");

            // Extract data from the two selected pipes.

            double wall_thickness = GetWallThickness(pipes[0]);

            Debug.Print("{0} has wall thickness {1}",
                        Util.ElementDescription(pipes[0]),
                        Util.RealString(wall_thickness));

            Curve c0 = pipes[0].GetCurve();
            Curve c1 = pipes[1].GetCurve();

            if (!(c0 is Line) || !(c1 is Line))
            {
                message = _prompt
                          + " Expected straight pipes.";

                return(Result.Failed);
            }

            XYZ p00 = c0.GetEndPoint(0);
            XYZ p01 = c0.GetEndPoint(1);

            XYZ p10 = c1.GetEndPoint(0);
            XYZ p11 = c1.GetEndPoint(1);

            XYZ v0 = p01 - p00;
            XYZ v1 = p11 - p10;

            if (!Util.IsParallel(v0, v1))
            {
                message = _prompt
                          + " Expected parallel pipes.";

                return(Result.Failed);
            }

            // Select the two pipe endpoints
            // that are farthest apart.

            XYZ p0 = p00.DistanceTo(p10) > p01.DistanceTo(p10)
        ? p00
        : p01;

            XYZ p1 = p10.DistanceTo(p0) > p11.DistanceTo(p0)
        ? p10
        : p11;

            XYZ pm = 0.5 * (p0 + p1);

            XYZ v = p1 - p0;

            if (Util.IsParallel(v, v0))
            {
                message = "The selected pipes are colinear.";
                return(Result.Failed);
            }

            // Normal vector of the plane defined by the
            // two parallel and offset pipes, which is
            // the plane hosting the rolling offset

            XYZ z = v.CrossProduct(v1);

            // Vector perpendicular to v0 and v0 and
            // z, i.e. vector pointing from the first pipe
            // to the second in the cross sectional view.

            XYZ w = z.CrossProduct(v1).Normalize();

            // Offset distance perpendicular to pipe direction

            double distanceAcross = Math.Abs(
                v.DotProduct(w));

            // Distance between endpoints parallel
            // to pipe direction

            double distanceAlong = Math.Abs(
                v.DotProduct(v1.Normalize()));

            Debug.Assert(Util.IsEqual(v.GetLength(),
                                      Math.Sqrt(distanceAcross * distanceAcross
                                                + distanceAlong * distanceAlong)),
                         "expected Pythagorean equality here");

            // The required offset pipe angle.

            double angle = 45 * Math.PI / 180.0;

            // The angle on the other side.

            double angle2 = 0.5 * Math.PI - angle;

            double length = distanceAcross * Math.Tan(angle2);

            double halfLength = 0.5 * length;

            // How long should the pipe stubs become?

            double remainingPipeLength
                = 0.5 * (distanceAlong - length);

            if (0 > v1.DotProduct(v))
            {
                v1.Negate();
            }

            v1 = v1.Normalize();

            XYZ q0 = p0 + remainingPipeLength * v1;

            XYZ q1 = p1 - remainingPipeLength * v1;

            using (Transaction tx = new Transaction(doc))
            {
                // Determine pipe diameter for creating
                // matching pipes and fittings

                Pipe pipe = pipes[0];

                double diameter = pipe
                                  .get_Parameter(bipDiameter) // "Diameter"
                                  .AsDouble();

                // Pipe type for calls to doc.Create.NewPipe

                PipeType pipe_type_standard
                    = new FilteredElementCollector(doc)
                      .OfClass(typeof(PipeType))
                      .Cast <PipeType>()
                      .Where <PipeType>(e
                                        => e.Name.Equals("Standard"))
                      .FirstOrDefault <PipeType>();

                Debug.Assert(
                    pipe_type_standard.Id.IntegerValue.Equals(
                        pipe.PipeType.Id.IntegerValue),
                    "expected all pipes in this simple "
                    + "model to use the same pipe type");

                tx.Start("Rolling Offset");

                if (_place_model_line)
                {
                    // Trim or extend existing pipes

                    (pipes[0].Location as LocationCurve).Curve
                        = Line.CreateBound(p0, q0);

                    (pipes[1].Location as LocationCurve).Curve
                        = Line.CreateBound(p1, q1);

                    // Add a model line for the rolling offset pipe

                    Creator creator = new Creator(doc);

                    Line line = Line.CreateBound(q0, q1);

                    creator.CreateModelCurve(line);

                    pipe = null;
                }
                else if (_place_fittings)
                {
                    // Set active work plane to the rolling
                    // offset plane... removed again, since
                    // this has no effect at all on the
                    // fitting placement or rotation.
                    //
                    //Plane plane = new Plane( z, q0 );
                    //
                    //SketchPlane sp = SketchPlane.Create(
                    //  doc, plane );
                    //
                    //uidoc.ActiveView.SketchPlane = sp;
                    //uidoc.ActiveView.ShowActiveWorkPlane();

                    FamilySymbol symbol
                        = new FilteredElementCollector(doc)
                          .OfClass(typeof(FamilySymbol))
                          .OfCategory(BuiltInCategory.OST_PipeFitting)
                          .Cast <FamilySymbol>()
                          .Where <FamilySymbol>(e
                                                => e.Family.Name.Contains("Elbow - Generic"))
                          .FirstOrDefault <FamilySymbol>();

                    // Set up first 45 degree elbow fitting

                    FamilyInstance fitting0 = doc.Create
                                              .NewFamilyInstance(q0, symbol,
                                                                 StructuralType.NonStructural);

                    fitting0.LookupParameter("Angle").Set(
                        45.0 * Math.PI / 180.0);

                    //fitting0.get_Parameter( bipDiameter ) // does not exist
                    //  .Set( diameter );

                    fitting0.LookupParameter("Nominal Radius")
                    .Set(0.5 * diameter);

                    Line axis = Line.CreateBound(p0, q0);
                    angle = z.AngleTo(XYZ.BasisZ);

                    ElementTransformUtils.RotateElement(
                        doc, fitting0.Id, axis, Math.PI - angle);

                    Connector con0 = Util.GetConnectorClosestTo(
                        fitting0, p0);

                    // Trim or extend existing pipe

                    (pipes[0].Location as LocationCurve).Curve
                        = Line.CreateBound(p0, con0.Origin);

                    // Connect pipe to fitting

                    Util.Connect(con0.Origin, pipe, fitting0);

                    // Set up second 45 degree elbow fitting

                    FamilyInstance fitting1 = doc.Create
                                              .NewFamilyInstance(q1, symbol,
                                                                 StructuralType.NonStructural);

                    //fitting1.get_Parameter( "Angle" ).Set( 45.0 * Math.PI / 180.0 ); // 2014
                    //fitting1.get_Parameter( "Nominal Radius" ).Set( 0.5 * diameter ); // 2014

                    fitting1.LookupParameter("Angle").Set(45.0 * Math.PI / 180.0);  // 2015
                    fitting1.LookupParameter("Nominal Radius").Set(0.5 * diameter); // 2015

                    axis = Line.CreateBound(
                        q1, q1 + XYZ.BasisZ);

                    ElementTransformUtils.RotateElement(
                        doc, fitting1.Id, axis, Math.PI);

                    axis = Line.CreateBound(q1, p1);

                    ElementTransformUtils.RotateElement(
                        doc, fitting1.Id, axis, Math.PI - angle);

                    Connector con1 = Util.GetConnectorClosestTo(
                        fitting1, p1);

                    (pipes[1].Location as LocationCurve).Curve
                        = Line.CreateBound(con1.Origin, p1);

                    Util.Connect(con1.Origin, fitting1, pipes[1]);

                    con0 = Util.GetConnectorClosestTo(
                        fitting0, pm);

                    con1 = Util.GetConnectorClosestTo(
                        fitting1, pm);

                    // Connecting one fitting to the other does
                    // not insert a pipe in between. If the
                    // system is edited later, however, the two
                    // fittings snap together.
                    //
                    //con0.ConnectTo( con1 );

                    // Create rolling offset pipe segment

                    //pipe = doc.Create.NewPipe( con0.Origin, // 2014
                    //  con1.Origin, pipe_type_standard );

                    pipe = Pipe.Create(doc,
                                       pipe_type_standard.Id, levelId, con0, con1); // 2015

                    pipe.get_Parameter(bipDiameter)
                    .Set(diameter);

                    // Connect rolling offset pipe segment
                    // with elbow fittings at each end

                    Util.Connect(con0.Origin, fitting0, pipe);
                    Util.Connect(con1.Origin, pipe, fitting1);
                }
                else
                {
                    if (_use_static_pipe_create)
                    {
                        // Element id arguments to Pipe.Create.

                        ElementId idSystem;
                        ElementId idType;
                        ElementId idLevel;

                        // All these values are invalid for idSystem:

                        ElementId idSystem1 = pipe.MEPSystem.Id;
                        ElementId idSystem2 = ElementId.InvalidElementId;
                        ElementId idSystem3 = PipingSystem.Create(
                            doc, pipe.MEPSystem.GetTypeId(), "Tbc")
                                              .Id;

                        // This throws an argument exception saying
                        // The systemTypeId is not valid piping system type.
                        // Parameter name: systemTypeId

                        //pipe = Pipe.Create( doc, idSystem,
                        //  idType, idLevel, q0, q1 );

                        // Retrieve pipe system type, e.g.
                        // hydronic supply.

                        PipingSystemType pipingSystemType
                            = new FilteredElementCollector(doc)
                              .OfClass(typeof(PipingSystemType))
                              .OfType <PipingSystemType>()
                              .FirstOrDefault(st
                                              => st.SystemClassification
                                              == MEPSystemClassification
                                              .SupplyHydronic);

                        if (null == pipingSystemType)
                        {
                            message = "Could not find hydronic supply piping system type";
                            return(Result.Failed);
                        }

                        idSystem = pipingSystemType.Id;

                        Debug.Assert(pipe.get_Parameter(
                                         BuiltInParameter.RBS_PIPING_SYSTEM_TYPE_PARAM)
                                     .AsElementId().IntegerValue.Equals(
                                         idSystem.IntegerValue),
                                     "expected same piping system element id");

                        // Retrieve the PipeType.

                        PipeType pipeType =
                            new FilteredElementCollector(doc)
                            .OfClass(typeof(PipeType))
                            .OfType <PipeType>()
                            .FirstOrDefault();

                        if (null == pipeType)
                        {
                            message = "Could not find pipe type";
                            return(Result.Failed);
                        }

                        idType = pipeType.Id;

                        Debug.Assert(pipe.get_Parameter(
                                         BuiltInParameter.ELEM_TYPE_PARAM)
                                     .AsElementId().IntegerValue.Equals(
                                         idType.IntegerValue),
                                     "expected same pipe type element id");

                        Debug.Assert(pipe.PipeType.Id.IntegerValue
                                     .Equals(idType.IntegerValue),
                                     "expected same pipe type element id");

                        // Retrieve the reference level.
                        // pipe.LevelId is not the correct source!

                        idLevel = pipe.get_Parameter(
                            BuiltInParameter.RBS_START_LEVEL_PARAM)
                                  .AsElementId();

                        // Create the rolling offset pipe.

                        pipe = Pipe.Create(doc,
                                           idSystem, idType, idLevel, q0, q1);
                    }
                    else
                    {
                        //pipe = doc.Create.NewPipe( q0, q1, pipe_type_standard ); // 2014

                        pipe = Pipe.Create(doc, systemTypeId,
                                           pipe_type_standard.Id, levelId, q0, q1); // 2015
                    }

                    pipe.get_Parameter(bipDiameter)
                    .Set(diameter);

                    // Connect rolling offset pipe segment
                    // directly with the neighbouring original
                    // pipes
                    //
                    //Util.Connect( q0, pipes[0], pipe );
                    //Util.Connect( q1, pipe, pipes[1] );

                    // NewElbowFitting performs the following:
                    // - select appropriate fitting family and type
                    // - place and orient a family instance
                    // - set its parameters appropriately
                    // - connect it with its neighbours

                    Connector con0 = Util.GetConnectorClosestTo(
                        pipes[0], q0);

                    Connector con = Util.GetConnectorClosestTo(
                        pipe, q0);

                    doc.Create.NewElbowFitting(con0, con);

                    Connector con1 = Util.GetConnectorClosestTo(
                        pipes[1], q1);

                    con = Util.GetConnectorClosestTo(
                        pipe, q1);

                    doc.Create.NewElbowFitting(con, con1);
                }

                tx.Commit();
            }
            return(Result.Succeeded);
        }
        public Result Execute(
            ExternalCommandData commandData,
            ref string message,
            ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
            UIDocument    uidoc = uiapp.ActiveUIDocument;
            Application   app   = uiapp.Application;
            Document      doc   = uidoc.Document;

            Wall wall = Util.SelectSingleElementOfType(
                uidoc, typeof(Wall), "a curtain wall", false)
                        as Wall;

            if (null == wall)
            {
                message = "Please select a single "
                          + "curtain wall element.";

                return(Result.Failed);
            }
            else
            {
                LocationCurve locationcurve
                    = wall.Location as LocationCurve;

                Curve curve = locationcurve.Curve;

                // move whole geometry over by length of wall:

                XYZ p = curve.GetEndPoint(0);
                XYZ q = curve.GetEndPoint(1);
                XYZ v = q - p;

                Transform tv = Transform.CreateTranslation(v);

                //curve = curve.get_Transformed( tv ); // 2013
                curve = curve.CreateTransformed(tv); // 2014

                Creator creator = new Creator(doc);
                creator.CreateModelCurve(curve);

                Options opt = app.Create.NewGeometryOptions();
                opt.IncludeNonVisibleObjects = true;

                GeometryElement e = wall.get_Geometry(opt);

                foreach (GeometryObject obj in e)
                {
                    curve = obj as Curve;

                    if (null != curve)
                    {
                        //curve = curve.get_Transformed( tv ); // 2013
                        curve = curve.CreateTransformed(tv); // 2014
                        creator.CreateModelCurve(curve);
                    }
                }
                return(Result.Succeeded);
            }
        }
        public Result Execute(
            ExternalCommandData commandData,
            ref string message,
            ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
              UIDocument uidoc = uiapp.ActiveUIDocument;
              Application app = uiapp.Application;
              Document doc = uidoc.Document;

              // Select all pipes in the entire model.

              List<Pipe> pipes = new List<Pipe>(
            new FilteredElementCollector( doc )
              .OfClass( typeof( Pipe ) )
              .ToElements()
              .Cast<Pipe>() );

              int n = pipes.Count;

              // If there are less than two,
              // there is nothing we can do.

              if( 2 > n )
              {
            message = _prompt;
            return Result.Failed;
              }

              // If there are exactly two, pick those.

              if( 2 < n )
              {
            // Else, check for a pre-selection.

            pipes.Clear();

            Selection sel = uidoc.Selection;

            n = sel.Elements.Size;

            Debug.Print( "{0} pre-selected elements.",
              n );

            // If two or more model pipes were pre-
            // selected, use the first two encountered.

            if( 1 < n )
            {
              foreach( Element e in sel.Elements )
              {
            Pipe c = e as Pipe;

            if( null != c )
            {
              pipes.Add( c );

              if( 2 == pipes.Count )
              {
                Debug.Print( "Found two model pipes, "
                  + "ignoring everything else." );

                break;
              }
            }
              }
            }

            // Else, prompt for an
            // interactive post-selection.

            if( 2 != pipes.Count )
            {
              pipes.Clear();

              try
              {
            Reference r = sel.PickObject(
              ObjectType.Element,
              new PipeElementSelectionFilter(),
              "Please pick first pipe." );

            pipes.Add( doc.GetElement( r.ElementId )
              as Pipe );
              }
              catch( Autodesk.Revit.Exceptions
            .OperationCanceledException )
              {
            return Result.Cancelled;
              }

              try
              {
            Reference r = sel.PickObject(
              ObjectType.Element,
              new PipeElementSelectionFilter(),
              "Please pick second pipe." );

            pipes.Add( doc.GetElement( r.ElementId )
              as Pipe );
              }
              catch( Autodesk.Revit.Exceptions
            .OperationCanceledException )
              {
            return Result.Cancelled;
              }
            }
              }

              // Extract data from the two selected pipes.

              Curve c0 = ( pipes[0].Location as LocationCurve ).Curve;
              Curve c1 = ( pipes[1].Location as LocationCurve ).Curve;

              if( !( c0 is Line ) || !( c1 is Line ) )
              {
            message = _prompt
              + " Expected straight pipes.";

            return Result.Failed;
              }

              XYZ p00 = c0.GetEndPoint( 0 );
              XYZ p01 = c0.GetEndPoint( 1 );

              XYZ p10 = c1.GetEndPoint( 0 );
              XYZ p11 = c1.GetEndPoint( 1 );

              XYZ v0 = p01 - p00;
              XYZ v1 = p11 - p10;

              if( !Util.IsParallel( v0, v1 ) )
              {
            message = _prompt
              + " Expected parallel pipes.";

            return Result.Failed;
              }

              // Select the two pipe endpoints
              // that are farthest apart.

              XYZ p0 = p00.DistanceTo( p10 ) > p01.DistanceTo( p10 )
            ? p00
            : p01;

              XYZ p1 = p10.DistanceTo( p0 ) > p11.DistanceTo( p0 )
            ? p10
            : p11;

              XYZ pm = 0.5 * ( p0 + p1 );

              XYZ v = p1 - p0;

              if( Util.IsParallel( v, v0 ) )
              {
            message = "The selected pipes are colinear.";
            return Result.Failed;
              }

              // Normal vector of the plane defined by the
              // two parallel and offset pipes, which is
              // the plane hosting the rolling offset

              XYZ z = v.CrossProduct( v1 );

              // Vector perpendicular to v0 and v0 and
              // z, i.e. vector pointing from the first pipe
              // to the second in the cross sectional view.

              XYZ w = z.CrossProduct( v1 ).Normalize();

              // Offset distance perpendicular to pipe direction

              double distanceAcross = Math.Abs(
            v.DotProduct( w ) );

              // Distance between endpoints parallel
              // to pipe direction

              double distanceAlong = Math.Abs(
            v.DotProduct( v1.Normalize() ) );

              Debug.Assert( Util.IsEqual( v.GetLength(),
            Math.Sqrt( distanceAcross * distanceAcross
              + distanceAlong * distanceAlong ) ),
            "expected Pythagorean equality here" );

              // The required offset pipe angle.

              double angle = 45 * Math.PI / 180.0;

              // The angle on the other side.

              double angle2 = 0.5 * Math.PI - angle;

              double length = distanceAcross * Math.Tan( angle2 );

              double halfLength = 0.5 * length;

              // How long should the pipe stubs become?

              double remainingPipeLength
            = 0.5 * ( distanceAlong - length );

              if( 0 > v1.DotProduct( v ) )
              {
            v1.Negate();
              }

              v1 = v1.Normalize();

              XYZ q0 = p0 + remainingPipeLength * v1;

              XYZ q1 = p1 - remainingPipeLength * v1;

              using( Transaction tx = new Transaction( doc ) )
              {
            // Determine pipe diameter for creating
            // matching pipes and fittings

            Pipe pipe = pipes[0];

            double diameter = pipe
              .get_Parameter( bipDiameter ) // "Diameter"
              .AsDouble();

            // Pipe type for calls to doc.Create.NewPipe

            PipeType pipe_type_standard
              = new FilteredElementCollector( doc )
            .OfClass( typeof( PipeType ) )
            .Cast<PipeType>()
            .Where<PipeType>( e
              => e.Name.Equals( "Standard" ) )
            .FirstOrDefault<PipeType>();

            Debug.Assert(
              pipe_type_standard.Id.IntegerValue.Equals(
            pipe.PipeType.Id.IntegerValue ),
              "expected all pipes in this simple "
              + "model to use the same pipe type" );

            tx.Start( "Rolling Offset" );

            if( _place_model_line )
            {
              // Trim or extend existing pipes

              ( pipes[0].Location as LocationCurve ).Curve
            = Line.CreateBound( p0, q0 );

              ( pipes[1].Location as LocationCurve ).Curve
            = Line.CreateBound( p1, q1 );

              // Add a model line for the rolling offset pipe

              Creator creator = new Creator( doc );

              Line line = Line.CreateBound( q0, q1 );

              creator.CreateModelCurve( line );

              pipe = null;
            }
            else if( _place_fittings )
            {
              // Set active work plane to the rolling
              // offset plane... removed again, since
              // this has no effect at all on the
              // fitting placement or rotation.
              //
              //Plane plane = new Plane( z, q0 );
              //
              //SketchPlane sp = SketchPlane.Create(
              //  doc, plane );
              //
              //uidoc.ActiveView.SketchPlane = sp;
              //uidoc.ActiveView.ShowActiveWorkPlane();

              FamilySymbol symbol
            = new FilteredElementCollector( doc )
              .OfClass( typeof( FamilySymbol ) )
              .OfCategory( BuiltInCategory.OST_PipeFitting )
              .Cast<FamilySymbol>()
              .Where<FamilySymbol>( e
                => e.Family.Name.Contains( "Elbow - Generic" ) )
              .FirstOrDefault<FamilySymbol>();

              // Set up first 45 degree elbow fitting

              FamilyInstance fitting0 = doc.Create
            .NewFamilyInstance( q0, symbol,
              StructuralType.NonStructural );

              fitting0.get_Parameter( "Angle" ).Set(
            45.0 * Math.PI / 180.0 );

              //fitting0.get_Parameter( bipDiameter ) // does not exist
              //  .Set( diameter );

              fitting0.get_Parameter( "Nominal Radius" )
            .Set( 0.5 * diameter );

              Line axis = Line.CreateBound( p0, q0 );
              angle = z.AngleTo( XYZ.BasisZ );

              ElementTransformUtils.RotateElement(
            doc, fitting0.Id, axis, Math.PI - angle );

              Connector con0 = Util.GetConnectorClosestTo(
            fitting0, p0 );

              // Trim or extend existing pipe

              ( pipes[0].Location as LocationCurve ).Curve
            = Line.CreateBound( p0, con0.Origin );

              // Connect pipe to fitting

              Util.Connect( con0.Origin, pipe, fitting0 );

              // Set up second 45 degree elbow fitting

              FamilyInstance fitting1 = doc.Create
            .NewFamilyInstance( q1, symbol,
              StructuralType.NonStructural );

              fitting1.get_Parameter( "Angle" ).Set(
            45.0 * Math.PI / 180.0 );

              fitting1.get_Parameter( "Nominal Radius" )
            .Set( 0.5 * diameter );

              axis = Line.CreateBound(
            q1, q1 + XYZ.BasisZ );

              ElementTransformUtils.RotateElement(
            doc, fitting1.Id, axis, Math.PI );

              axis = Line.CreateBound( q1, p1 );

              ElementTransformUtils.RotateElement(
            doc, fitting1.Id, axis, Math.PI - angle );

              Connector con1 = Util.GetConnectorClosestTo(
            fitting1, p1 );

              ( pipes[1].Location as LocationCurve ).Curve
            = Line.CreateBound( con1.Origin, p1 );

              Util.Connect( con1.Origin, fitting1, pipes[1] );

              con0 = Util.GetConnectorClosestTo(
            fitting0, pm );

              con1 = Util.GetConnectorClosestTo(
            fitting1, pm );

              // Connecting one fitting to the other does
              // not insert a pipe in between. If the
              // system is edited later, however, the two
              // fittings snap together.
              //
              //con0.ConnectTo( con1 );

              // Create rolling offset pipe segment

              pipe = doc.Create.NewPipe( con0.Origin,
            con1.Origin, pipe_type_standard );

              pipe.get_Parameter( bipDiameter )
            .Set( diameter );

              // Connect rolling offset pipe segment
              // with elbow fittings at each end

              Util.Connect( con0.Origin, fitting0, pipe );
              Util.Connect( con1.Origin, pipe, fitting1 );
            }
            else
            {
              if( _use_static_pipe_create )
              {
            // Element id arguments to Pipe.Create.

            ElementId idSystem;
            ElementId idType;
            ElementId idLevel;

            // All these values are invalid for idSystem:

            ElementId idSystem1 = pipe.MEPSystem.Id;
            ElementId idSystem2 = ElementId.InvalidElementId;
            ElementId idSystem3 = PipingSystem.Create(
              doc, pipe.MEPSystem.GetTypeId(), "Tbc" )
                .Id;

            // This throws an argument exception saying
            // The systemTypeId is not valid piping system type.
            // Parameter name: systemTypeId

            //pipe = Pipe.Create( doc, idSystem,
            //  idType, idLevel, q0, q1 );

            // Retrieve pipe system type, e.g.
            // hydronic supply.

            PipingSystemType pipingSystemType
              = new FilteredElementCollector( doc )
                .OfClass( typeof( PipingSystemType ) )
                .OfType<PipingSystemType>()
                .FirstOrDefault( st
                  => st.SystemClassification
                    == MEPSystemClassification
                      .SupplyHydronic );

            if( null == pipingSystemType )
            {
              message = "Could not find hydronic supply piping system type";
              return Result.Failed;
            }

            idSystem = pipingSystemType.Id;

            Debug.Assert( pipe.get_Parameter(
              BuiltInParameter.RBS_PIPING_SYSTEM_TYPE_PARAM )
                .AsElementId().IntegerValue.Equals(
                  idSystem.IntegerValue ),
                "expected same piping system element id" );

            // Retrieve the PipeType.

            PipeType pipeType =
              new FilteredElementCollector( doc )
                .OfClass( typeof( PipeType ) )
                .OfType<PipeType>()
                .FirstOrDefault();

            if( null == pipeType )
            {
              message = "Could not find pipe type";
              return Result.Failed;
            }

            idType = pipeType.Id;

            Debug.Assert( pipe.get_Parameter(
              BuiltInParameter.ELEM_TYPE_PARAM )
                .AsElementId().IntegerValue.Equals(
                  idType.IntegerValue ),
              "expected same pipe type element id" );

            Debug.Assert( pipe.PipeType.Id.IntegerValue
              .Equals( idType.IntegerValue ),
              "expected same pipe type element id" );

            // Retrieve the reference level.
            // pipe.LevelId is not the correct source!

            idLevel = pipe.get_Parameter(
              BuiltInParameter.RBS_START_LEVEL_PARAM )
                .AsElementId();

            // Create the rolling offset pipe.

            pipe = Pipe.Create( doc,
              idSystem, idType, idLevel, q0, q1 );
              }
              else
              {
            pipe = doc.Create.NewPipe( q0, q1,
              pipe_type_standard );
              }

              pipe.get_Parameter( bipDiameter )
            .Set( diameter );

              // Connect rolling offset pipe segment
              // directly with the neighbouring original
              // pipes
              //
              //Util.Connect( q0, pipes[0], pipe );
              //Util.Connect( q1, pipe, pipes[1] );

              // NewElbowFitting performs the following:
              // - select appropriate fitting family and type
              // - place and orient a family instance
              // - set its parameters appropriately
              // - connect it with its neighbours

              Connector con0 = Util.GetConnectorClosestTo(
            pipes[0], q0 );

              Connector con = Util.GetConnectorClosestTo(
            pipe, q0 );

              doc.Create.NewElbowFitting( con0, con );

              Connector con1 = Util.GetConnectorClosestTo(
            pipes[1], q1 );

              con = Util.GetConnectorClosestTo(
            pipe, q1 );

              doc.Create.NewElbowFitting( con, con1 );
            }

            tx.Commit();
              }
              return Result.Succeeded;
        }
        ///// <summary>
        ///// Allow selection of curve elements only.
        ///// </summary>
        //class CurveElementSelectionFilter : ISelectionFilter
        //{
        //  public bool AllowElement( Element e )
        //  {
        //    return e is CurveElement;
        //  }
        //  public bool AllowReference( Reference r, XYZ p )
        //  {
        //    return true;
        //  }
        //}
        public Result Execute(
            ExternalCommandData commandData,
            ref string message,
            ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
              UIDocument uidoc = uiapp.ActiveUIDocument;
              Application app = uiapp.Application;
              Document doc = uidoc.Document;

              // Select all model curves in the entire model.

              List<CurveElement> curves = new List<CurveElement>(
            new FilteredElementCollector( doc )
              .OfClass( typeof( CurveElement ) )
              .ToElements()
              .Cast<CurveElement>() );

              int n = curves.Count;

              // If there are less than two,
              // there is nothing we can do.

              if( 2 > n )
              {
            message = _prompt;
            return Result.Failed;
              }

              // If there are exactly two, pick those.

              if( 2 < n )
              {
            // Else, check for a pre-selection.

            curves.Clear();

            Selection sel = uidoc.Selection;
            ICollection<ElementId> ids = sel.GetElementIds();
            n = ids.Count;

            Debug.Print( "{0} pre-selected elements.",
              n );

            // If two or more model curves were pre-
            // selected, use the first two encountered.

            if( 1 < n )
            {
              foreach( ElementId id in ids )
              {
            CurveElement c = doc.GetElement( id )
              as CurveElement;

            if( null != c )
            {
              curves.Add( c );

              if( 2 == curves.Count )
              {
                Debug.Print( "Found two model curves, "
                  + "ignoring everything else." );

                break;
              }
            }
              }
            }

            // Else, prompt for an
            // interactive post-selection.

            if( 2 != curves.Count )
            {
              curves.Clear();

              ISelectionFilter f
            = new JtElementsOfClassSelectionFilter<CurveElement>();

              try
              {
            Reference r = sel.PickObject(
              ObjectType.Element, f,
              "Please pick first model curve." );

            curves.Add( doc.GetElement( r.ElementId )
              as CurveElement );
              }
              catch( Autodesk.Revit.Exceptions
            .OperationCanceledException )
              {
            return Result.Cancelled;
              }

              try
              {
            Reference r = sel.PickObject(
              ObjectType.Element, f,
              "Please pick second model curve." );

            curves.Add( doc.GetElement( r.ElementId )
              as CurveElement );
              }
              catch( Autodesk.Revit.Exceptions
            .OperationCanceledException )
              {
            return Result.Cancelled;
              }
            }
              }

              // Extract data from the two selected curves.

              Curve c0 = curves[0].GeometryCurve;
              Curve c1 = curves[1].GeometryCurve;

              double sp0 = c0.GetEndParameter( 0 );
              double ep0 = c0.GetEndParameter( 1 );
              double step0 = ( ep0 - sp0 ) / _nSegments;

              double sp1 = c1.GetEndParameter( 0 );
              double ep1 = c1.GetEndParameter( 1 );
              double step1 = ( ep1 - sp1 ) / _nSegments;

              Debug.Print( "Two curves' step size [start, end]:"
            + " {0} [{1},{2}] -- {3} [{4},{5}]",
            Util.RealString( step0 ),
            Util.RealString( sp0 ),
            Util.RealString( ep0 ),
            Util.RealString( step1 ),
            Util.RealString( sp1 ),
            Util.RealString( ep1 ) );

              // Modify document within a transaction.

              using( Transaction tx = new Transaction( doc ) )
              {
            Creator creator = new Creator( doc );

            tx.Start( "MidCurve" );

            // Current segment start points.

            double t0 = sp0;
            double t1 = sp1;

            XYZ p0 = c0.GetEndPoint( 0 );
            XYZ p1 = c1.GetEndPoint( 0 );
            XYZ p = Util.Midpoint( p0, p1 );

            Debug.Assert(
              p0.IsAlmostEqualTo( c0.Evaluate( t0, false ) ),
              "expected equal start points" );

            Debug.Assert(
              p1.IsAlmostEqualTo( c1.Evaluate( t1, false ) ),
              "expected equal start points" );

            // Current segment end points.

            t0 += step0;
            t1 += step1;

            XYZ q0, q1, q;
            Line line;

            for( int i = 0; i < _nSegments; ++i, t0 += step0, t1 += step1 )
            {
              q0 = c0.Evaluate( t0, false );
              q1 = c1.Evaluate( t1, false );
              q = Util.Midpoint( q0, q1 );

              Debug.Print(
            "{0} {1} {2} {3}-{4} {5}-{6} {7}-{8}",
            i,
            Util.RealString( t0 ),
            Util.RealString( t1 ),
            Util.PointString( p0 ),
            Util.PointString( q0 ),
            Util.PointString( p1 ),
            Util.PointString( q1 ),
            Util.PointString( p ),
            Util.PointString( q ) );

              // Create approximating curve segment.

              line = Line.CreateBound( p, q );
              creator.CreateModelCurve( line );

              p0 = q0;
              p1 = q1;
              p = q;
            }
            tx.Commit();
              }
              return Result.Succeeded;
        }
        static Transform _t = Transform.CreateTranslation( _offset ); // 2014

        #endregion Fields

        #region Methods

        public Result Execute(
            ExternalCommandData commandData,
            ref string message,
            ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
              UIDocument uidoc = uiapp.ActiveUIDocument;
              Application app = uiapp.Application;
              Document doc = uidoc.Document;

              List<Element> walls = new List<Element>();

              //XYZ p;
              //List<XYZ> wall_start_points
              //  = walls.Select<Element, XYZ>( e => {
              //    Util.GetElementLocation( out p, e );
              //      return p; } )
              //        .ToList<XYZ>();

              if( !Util.GetSelectedElementsOrAll(
            walls, uidoc, typeof( Wall ) ) )
              {
            Selection sel = uidoc.Selection;
            //message = ( 0 < sel.Elements.Size ) // 2014
            message = ( 0 < sel.GetElementIds().Count ) // 2015
              ? "Please select some wall elements."
              : "No wall elements found.";
            return Result.Failed;
              }

              using( Transaction tx = new Transaction( doc ) )
              {
            tx.Start( "Create model curve copies of analytical model curves" );

            Creator creator = new Creator( doc );

            foreach( Wall wall in walls )
            {
              AnalyticalModel am = wall.GetAnalyticalModel();

              foreach( AnalyticalCurveType ct in _curveTypes )
              {
            IList<Curve> curves = am.GetCurves( ct );

            int n = curves.Count;

            Debug.Print( "{0} {1} curve{2}.",
              n, ct, Util.PluralSuffix( n ) );

            foreach( Curve curve in curves )
            {
              //creator.CreateModelCurve( curve.get_Transformed( _t ) ); // 2013

              creator.CreateModelCurve( curve.CreateTransformed( _t ) ); // 2014
            }
              }
            }
            tx.Commit();
              }
              return Result.Succeeded;
        }
            Transform.CreateTranslation(_offset); // 2014
#endif // CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES

        public Result Execute(
            ExternalCommandData commandData,
            ref string message,
            ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
            UIDocument    uidoc = uiapp.ActiveUIDocument;
            Application   app   = uiapp.Application;
            Document      doc   = uidoc.Document;

            Options opt = app.Create.NewGeometryOptions();

            XyzEqualityComparer comparer
                = new XyzEqualityComparer(1e-6);

#if CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES
            Creator creator = new Creator(doc);

            Transaction t = new Transaction(doc);

            t.Start("Create model curve copies of top face edges");
#endif // CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES

            IList <Face> topFaces = new List <Face>();

            int n;
            int nWalls = 0;

            //foreach( Element e in uidoc.Selection.Elements ) // 2014

            foreach (ElementId id in uidoc.Selection.GetElementIds()) // 2015
            {
                Element e = doc.GetElement(id);

                Wall wall = e as Wall;

                if (null == wall)
                {
                    Debug.Print("Skipped "
                                + Util.ElementDescription(e));
                    continue;
                }

                // Get the side faces

                IList <Reference> sideFaces
                    = HostObjectUtils.GetSideFaces(wall,
                                                   ShellLayerType.Exterior);

                // Access the first side face

                Element e2 = doc.GetElement(sideFaces[0]);

                Debug.Assert(e2.Id.Equals(e.Id),
                             "expected side face element to be the wall itself");

                Face face = e2.GetGeometryObjectFromReference(
                    sideFaces[0]) as Face;

                if (null == face)
                {
                    Debug.Print("No side face found for "
                                + Util.ElementDescription(e));
                    continue;
                }

                // When there are opening such as doors or
                // windows in the wall, we need to find the
                // outer loop.
                // For one possible approach to extract the
                // outermost loop, please refer to
                // http://thebuildingcoder.typepad.com/blog/2008/12/2d-polygon-areas-and-outer-loop.html

                // Determine the outer loop of the side face
                // by finding the polygon with the largest area

                XYZ       normal;
                double    area, dist, maxArea = 0;
                EdgeArray outerLoop = null;

                foreach (EdgeArray ea in face.EdgeLoops)
                {
                    if (CmdWallProfileArea.GetPolygonPlane(
                            ea.GetPolygon(), out normal, out dist, out area) &&
                        Math.Abs(area) > Math.Abs(maxArea))
                    {
                        maxArea   = area;
                        outerLoop = ea;
                    }
                }

                n = 0;

#if GET_FACES_FROM_OUTER_LOOP
                // With the outermost loop, calculate the top faces

                foreach (Edge edge in outerLoop)
                {
                    // For each edge, get the neighbouring
                    // face and check its normal

                    for (int i = 0; i < 2; ++i)
                    {
                        PlanarFace pf = edge.get_Face(i)
                                        as PlanarFace;

                        if (null == pf)
                        {
                            Debug.Print("Skipped non-planar face on "
                                        + Util.ElementDescription(e));
                            continue;
                        }

                        if (Util.PointsUpwards(pf.Normal, 0.9))
                        {
                            if (topFaces.Contains(pf))
                            {
                                Debug.Print("Duplicate face on "
                                            + Util.ElementDescription(e));
                            }
                            else
                            {
                                topFaces.Add(pf);
                                ++n;
                            }
                        }
                    }
                }
#endif // GET_FACES_FROM_OUTER_LOOP

                List <XYZ> sideVertices = outerLoop.GetPolygon();

                // Go over all the faces of the wall and
                // determine which ones fulfill the following
                // two criteria: (i) planar face pointing
                // upwards, and (ii) neighbour of the side
                // face outer loop.

                Solid solid = wall.get_Geometry(opt)
                              .OfType <Solid>()
                              .First <Solid>(sol => null != sol);

                foreach (Face f in solid.Faces)
                {
                    if (IsTopFace(f))
                    {
                        IList <XYZ> faceVertices
                            = f.Triangulate().Vertices;

                        //if( sideVertices.Exists( v
                        //  => faceVertices.Contains<XYZ>( v, comparer ) ) )
                        //{
                        //  topFaces.Add( f );
                        //  ++n;
                        //}

                        foreach (XYZ v in faceVertices)
                        {
                            if (sideVertices.Contains <XYZ>(
                                    v, comparer))
                            {
                                topFaces.Add(f);
                                ++n;

#if CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES
                                // Display face for debugging purposes

                                foreach (EdgeArray ea in f.EdgeLoops)
                                {
                                    IEnumerable <Curve> curves
                                        = ea.Cast <Edge>()
                                          .Select <Edge, Curve>(
                                              x => x.AsCurve());

                                    foreach (Curve curve in curves)
                                    {
                                        //creator.CreateModelCurve( curve.get_Transformed( _t ) ); // 2013
                                        creator.CreateModelCurve(curve.CreateTransformed(_t)); // 2014
                                    }
                                }
#endif // CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES

                                break;
                            }
                        }
                    }
                }

                Debug.Print(string.Format(
                                "{0} top face{1} found on {2} ({3})",
                                n, Util.PluralSuffix(n),
                                Util.ElementDescription(e)),
                            nWalls++);
            }

#if CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES
            t.Commit();
#endif // CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES

            string s = string.Format(
                "{0} wall{1} successfully processed",
                nWalls, Util.PluralSuffix(nWalls));

            n = topFaces.Count;

            TaskDialog.Show("Wall Top Faces",
                            string.Format(
                                "{0} with {1} top face{2}.",
                                s, n, Util.PluralSuffix(n)));

            return(Result.Succeeded);
        }
        ///// <summary>
        ///// Allow selection of curve elements only.
        ///// </summary>
        //class CurveElementSelectionFilter : ISelectionFilter
        //{
        //  public bool AllowElement( Element e )
        //  {
        //    return e is CurveElement;
        //  }

        //  public bool AllowReference( Reference r, XYZ p )
        //  {
        //    return true;
        //  }
        //}

        public Result Execute(
            ExternalCommandData commandData,
            ref string message,
            ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
            UIDocument    uidoc = uiapp.ActiveUIDocument;
            Application   app   = uiapp.Application;
            Document      doc   = uidoc.Document;

            // Select all model curves in the entire model.

            List <CurveElement> curves = new List <CurveElement>(
                new FilteredElementCollector(doc)
                .OfClass(typeof(CurveElement))
                .ToElements()
                .Cast <CurveElement>());

            int n = curves.Count;

            // If there are less than two,
            // there is nothing we can do.

            if (2 > n)
            {
                message = _prompt;
                return(Result.Failed);
            }

            // If there are exactly two, pick those.

            if (2 < n)
            {
                // Else, check for a pre-selection.

                curves.Clear();

                Selection sel = uidoc.Selection;
                ICollection <ElementId> ids = sel.GetElementIds();
                n = ids.Count;

                Debug.Print("{0} pre-selected elements.",
                            n);

                // If two or more model curves were pre-
                // selected, use the first two encountered.

                if (1 < n)
                {
                    foreach (ElementId id in ids)
                    {
                        CurveElement c = doc.GetElement(id)
                                         as CurveElement;

                        if (null != c)
                        {
                            curves.Add(c);

                            if (2 == curves.Count)
                            {
                                Debug.Print("Found two model curves, "
                                            + "ignoring everything else.");

                                break;
                            }
                        }
                    }
                }

                // Else, prompt for an
                // interactive post-selection.

                if (2 != curves.Count)
                {
                    curves.Clear();

                    ISelectionFilter f
                        = new JtElementsOfClassSelectionFilter <CurveElement>();

                    try
                    {
                        Reference r = sel.PickObject(
                            ObjectType.Element, f,
                            "Please pick first model curve.");

                        curves.Add(doc.GetElement(r.ElementId)
                                   as CurveElement);
                    }
                    catch (Autodesk.Revit.Exceptions
                           .OperationCanceledException)
                    {
                        return(Result.Cancelled);
                    }

                    try
                    {
                        Reference r = sel.PickObject(
                            ObjectType.Element, f,
                            "Please pick second model curve.");

                        curves.Add(doc.GetElement(r.ElementId)
                                   as CurveElement);
                    }
                    catch (Autodesk.Revit.Exceptions
                           .OperationCanceledException)
                    {
                        return(Result.Cancelled);
                    }
                }
            }

            // Extract data from the two selected curves.

            Curve c0 = curves[0].GeometryCurve;
            Curve c1 = curves[1].GeometryCurve;

            double sp0   = c0.GetEndParameter(0);
            double ep0   = c0.GetEndParameter(1);
            double step0 = (ep0 - sp0) / _nSegments;

            double sp1   = c1.GetEndParameter(0);
            double ep1   = c1.GetEndParameter(1);
            double step1 = (ep1 - sp1) / _nSegments;

            Debug.Print("Two curves' step size [start, end]:"
                        + " {0} [{1},{2}] -- {3} [{4},{5}]",
                        Util.RealString(step0),
                        Util.RealString(sp0),
                        Util.RealString(ep0),
                        Util.RealString(step1),
                        Util.RealString(sp1),
                        Util.RealString(ep1));

            // Modify document within a transaction.

            using (Transaction tx = new Transaction(doc))
            {
                Creator creator = new Creator(doc);

                tx.Start("MidCurve");

                // Current segment start points.

                double t0 = sp0;
                double t1 = sp1;

                XYZ p0 = c0.GetEndPoint(0);
                XYZ p1 = c1.GetEndPoint(0);
                XYZ p  = Util.Midpoint(p0, p1);

                Debug.Assert(
                    p0.IsAlmostEqualTo(c0.Evaluate(t0, false)),
                    "expected equal start points");

                Debug.Assert(
                    p1.IsAlmostEqualTo(c1.Evaluate(t1, false)),
                    "expected equal start points");

                // Current segment end points.

                t0 += step0;
                t1 += step1;

                XYZ  q0, q1, q;
                Line line;

                for (int i = 0; i < _nSegments; ++i, t0 += step0, t1 += step1)
                {
                    q0 = c0.Evaluate(t0, false);
                    q1 = c1.Evaluate(t1, false);
                    q  = Util.Midpoint(q0, q1);

                    Debug.Print(
                        "{0} {1} {2} {3}-{4} {5}-{6} {7}-{8}",
                        i,
                        Util.RealString(t0),
                        Util.RealString(t1),
                        Util.PointString(p0),
                        Util.PointString(q0),
                        Util.PointString(p1),
                        Util.PointString(q1),
                        Util.PointString(p),
                        Util.PointString(q));

                    // Create approximating curve segment.

                    line = Line.CreateBound(p, q);
                    creator.CreateModelCurve(line);

                    p0 = q0;
                    p1 = q1;
                    p  = q;
                }
                tx.Commit();
            }
            return(Result.Succeeded);
        }
        public Result Execute(
            ExternalCommandData commandData,
            ref string message,
            ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
              UIDocument uidoc = uiapp.ActiveUIDocument;
              Application app = uiapp.Application;
              Document doc = uidoc.Document;

              Wall wall = Util.SelectSingleElementOfType(
            uidoc, typeof( Wall ), "a curtain wall", false )
            as Wall;

              if( null == wall )
              {
            message = "Please select a single "
              + "curtain wall element.";

            return Result.Failed;
              }
              else
              {
            LocationCurve locationcurve
              = wall.Location as LocationCurve;

            Curve curve = locationcurve.Curve;

            // move whole geometry over by length of wall:

            XYZ p = curve.GetEndPoint( 0 );
            XYZ q = curve.GetEndPoint( 1 );
            XYZ v = q - p;

            Transform tv = Transform.CreateTranslation( v );

            //curve = curve.get_Transformed( tv ); // 2013
            curve = curve.CreateTransformed( tv ); // 2014

            Creator creator = new Creator( doc );
            creator.CreateModelCurve( curve );

            Options opt = app.Create.NewGeometryOptions();
            opt.IncludeNonVisibleObjects = true;

            GeometryElement e = wall.get_Geometry( opt );

            foreach( GeometryObject obj in e )
            {
              curve = obj as Curve;

              if( null != curve )
              {
            //curve = curve.get_Transformed( tv ); // 2013
            curve = curve.CreateTransformed( tv ); // 2014
            creator.CreateModelCurve( curve );
              }
            }
            return Result.Succeeded;
              }
        }