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 two walls and the dimension line point:

              Selection sel = uidoc.Selection;
              ReferenceArray refs = new ReferenceArray();

              try
              {
            ISelectionFilter f
              = new JtElementsOfClassSelectionFilter<Wall>();

            refs.Append( sel.PickObject(
              ObjectType.Element, f,
              "Please select first wall" ) );

            refs.Append( sel.PickObject(
              ObjectType.Element, f,
              "Please pick dimension line "
              + "point on second wall" ) );

            //rFace = sel.PickObject( ObjectType.Face,
            //  "Please select face on second wall at dimension line point" );
            //
            //rPoint = sel.PickObject( ObjectType.PointOnElement,
            //  "Please select point on first wall" );
              }
              catch( Autodesk.Revit.Exceptions.OperationCanceledException )
              {
            message = "No two walls selected";
            return Result.Failed;
              }

              // Ensure the two selected walls are straight and
              // parallel; determine their mutual normal vector
              // and a point on each wall for distance
              // calculations:

              Wall[] walls = new Wall[2];
              List<int> ids = new List<int>( 2 );
              XYZ[] pts = new XYZ[2];
              Line[] lines = new Line[2];
              IntersectionResult ir;
              XYZ normal = null;
              int i = 0;

              foreach( Reference r in refs )
              {
            // 'Autodesk.Revit.DB.Reference.Element' is
            // obsolete: Property will be removed. Use
            // Document.GetElement(Reference) instead.
            //Wall wall = r.Element as Wall; // 2011

            Wall wall = doc.GetElement( r ) as Wall; // 2012

            walls[i] = wall;
            ids.Add( wall.Id.IntegerValue );

            // Obtain location curve and
            // check that it is straight:

            LocationCurve lc = wall.Location
              as LocationCurve;

            Curve curve = lc.Curve;
            lines[i] = curve as Line;

            if( null == lines[i] )
            {
              message = _prompt;
              return Result.Failed;
            }

            // Obtain normal vectors
            // and ensure that they are equal,
            // i.e. walls are parallel:

            if( null == normal )
            {
              normal = Util.Normal( lines[i] );
            }
            else
            {
              if( !Util.IsParallel( normal,
            Util.Normal( lines[i] ) ) )
              {
            message = _prompt;
            return Result.Failed;
              }
            }

            // Obtain pick points and project
            // onto wall location lines:

            XYZ p = r.GlobalPoint;
            ir = lines[i].Project( p );

            if( null == ir )
            {
              message = string.Format(
            "Unable to project pick point {0} "
            + "onto wall location line.",
            i );

              return Result.Failed;
            }

            pts[i] = ir.XYZPoint;

            Debug.Print(
              "Wall {0} id {1} at {2}, {3} --> point {4}",
              i, wall.Id.IntegerValue,
              Util.PointString( lines[i].GetEndPoint( 0 ) ),
              Util.PointString( lines[i].GetEndPoint( 1 ) ),
              Util.PointString( pts[i] ) );

            if( 0 < i )
            {
              // Project dimension point selected on second wall
              // back onto first wall, and ensure that normal
              // points from second wall to first:

              ir = lines[0].Project( pts[1] );
              if( null == ir )
              {
            message = string.Format(
              "Unable to project selected dimension "
              + "line point {0} on second wall onto "
              + "first wall's location line.",
              Util.PointString( pts[1] ) );

            return Result.Failed;
              }
              pts[0] = ir.XYZPoint;
            }

            ++i;
              }

              XYZ v = pts[0] - pts[1];
              if( 0 > v.DotProduct( normal ) )
              {
            normal = -normal;
              }

              // Shoot a ray back from the second
              // picked wall towards first:

              Debug.Print(
            "Shooting ray from {0} in direction {1}",
            Util.PointString( pts[1] ),
            Util.PointString( normal ) );

              View3D view = Get3DView( doc );

              if( null == view )
              {
            message = "No 3D view named '{3D}' found; "
              + "run the View > 3D View command once "
              + "to generate it.";

            return Result.Failed;
              }

              //refs = doc.FindReferencesByDirection(
              //  pts[1], normal, view ); // 2011

              //IList<ReferenceWithContext> refs2
              //  = doc.FindReferencesWithContextByDirection(
              //    pts[1], normal, view ); // 2012

              // In the Revit 2014 API, the call to
              // FindReferencesWithContextByDirection causes a
              // warning saying:
              // "FindReferencesWithContextByDirection is obsolete:
              // This method is deprecated in Revit 2014.
              // Use the ReferenceIntersector class instead."

              ReferenceIntersector ri
            = new ReferenceIntersector(
              walls[0].Id, FindReferenceTarget.Element, view );

              ReferenceWithContext ref2
            = ri.FindNearest( pts[1], normal );

              if( null == ref2 )
              {
            message = "ReferenceIntersector.FindNearest"
              + " returned null!";

            return Result.Failed;
              }

              #region Obsolete code to determine the closest reference
            #if NEED_TO_DETERMINE_CLOSEST_REFERENCE
              // Store the references to the wall surfaces:

              Reference[] surfrefs = new Reference[2] {
            null, null };

              // Find the two closest intersection
              // points on each of the two walls:

              double[] minDistance = new double[2] {
            double.MaxValue,
            double.MaxValue };

              //foreach( Reference r in refs )
              foreach( ReferenceWithContext rc in refs2 )
              {
            // 'Autodesk.Revit.DB.Reference.Element' is
            // obsolete: Property will be removed. Use
            // Document.GetElement(Reference) instead.
            //Element e = r.Element; // 2011

            Reference r = rc.GetReference();
            Element e = doc.GetElement( r ); // 2012

            if( e is Wall )
            {
              i = ids.IndexOf( e.Id.IntegerValue );

              if( -1 < i
            && ElementReferenceType.REFERENCE_TYPE_SURFACE
              == r.ElementReferenceType )
              {
            //GeometryObject g = r.GeometryObject; // 2011
            GeometryObject g = e.GetGeometryObjectFromReference( r ); // 2012

            if( g is PlanarFace )
            {
              PlanarFace face = g as PlanarFace;

              Line line = ( e.Location as LocationCurve )
            .Curve as Line;

              Debug.Print(
            "Wall {0} at {1}, {2} surface {3} "
            + "normal {4} proximity {5}",
            e.Id.IntegerValue,
            Util.PointString( line.GetEndPoint( 0 ) ),
            Util.PointString( line.GetEndPoint( 1 ) ),
            Util.PointString( face.Origin ),
            Util.PointString( face.Normal ),
            rc.Proximity );

              // First reference: assert it is a face on this wall
              // and the distance is half the wall thickness.
              // Second reference: the first reference on the other
              // wall; assert the distance between the two references
              // equals the distance between the wall location lines
              // minus half of the sum of the two wall thicknesses.

              if( rc.Proximity < minDistance[i] )
              {
            surfrefs[i] = r;
            minDistance[i] = rc.Proximity;
              }
            }
              }
            }
              }

              if( null == surfrefs[0] )
              {
            message = "No suitable face intersection "
              + "points found on first wall.";

            return Result.Failed;
              }

              if( null == surfrefs[1] )
              {
            message = "No suitable face intersection "
              + "points found on second wall.";

            return Result.Failed;
              }

              CmdDimensionWallsIterateFaces
            .CreateDimensionElement( doc.ActiveView,
            pts[0], surfrefs[0], pts[1], surfrefs[1] );
            #endif // NEED_TO_DETERMINE_CLOSEST_REFERENCE
              #endregion // Obsolete code to determine the closest reference

              CmdDimensionWallsIterateFaces
            .CreateDimensionElement( doc.ActiveView,
            pts[0], ref2.GetReference(), pts[1], refs.get_Item( 1 ) );

              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;
        }