/// <summary>
            /// Add new profile to the sketch.
            /// </summary>
            public void MakeHole(Document doc)
            {
                FilteredElementCollector floorCollector
                    = new FilteredElementCollector(doc)
                      .WhereElementIsNotElementType()
                      .OfCategory(BuiltInCategory.OST_Floors)
                      .OfClass(typeof(Floor));

                Floor floor = floorCollector.FirstOrDefault() as Floor;

                if (floor == null)
                {
                    TaskDialog.Show("Error", "Document does not contain a floor.");
                    return;
                }

                Sketch sketch = doc.GetElement(floor.SketchId) as Sketch;
                // Create a circle inside the floor
                // Start a sketch edit scope
                SketchEditScope sketchEditScope = new SketchEditScope(doc,
                                                                      "Add profile to the sketch");

                sketchEditScope.Start(sketch.Id);

                using (Transaction transaction = new Transaction(doc,
                                                                 "Make a hole"))
                {
                    transaction.Start();
                    // Create and add an ellipse
                    Curve circle = Ellipse.CreateCurve(new XYZ(50, 50, 0),
                                                       10, 10, XYZ.BasisX, XYZ.BasisY, 0, 2 * Math.PI);

                    // Model curve creation automatically puts the curve
                    // into the sketch, if sketch edit scope is running.

                    doc.Create.NewModelCurve(circle, sketch.SketchPlane);
                    transaction.Commit();
                }
                sketchEditScope.Commit(new FailuresPreprocessor());
            }
        /// <summary>
        /// Implement this method as an external command for Revit.
        /// </summary>
        /// <param name="commandData">An object that is passed to the external application
        /// which contains data related to the command,
        /// such as the application object and active view.</param>
        /// <param name="message">A message that can be set by the external application
        /// which will be displayed if a failure or cancellation is returned by
        /// the external command.</param>
        /// <param name="elements">A set of elements to which the external application
        /// can add elements that are to be highlighted in case of failure or cancellation.</param>
        /// <returns>Return the status of the external command.
        /// A result of Succeeded means that the API external method functioned as expected.
        /// Cancelled can be used to signify that the user cancelled the external operation
        /// at some point. Failure should be returned if the application is unable to proceed with
        /// the operation.</returns>
        public virtual Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            try
            {
                Document document = commandData.Application.ActiveUIDocument.Document;

                //create analytical panel
                AnalyticalPanel analyticalPanel = CreateAnalyticalPanel.CreateAMPanel(document);
                if (analyticalPanel != null)
                {
                    // Start a sketch edit scope
                    SketchEditScope sketchEditScope = new SketchEditScope(document, "Replace line with an arc");
                    sketchEditScope.StartWithNewSketch(analyticalPanel.Id);

                    using (Transaction transaction = new Transaction(document, "Modify sketch"))
                    {
                        transaction.Start();

                        //replace a boundary line with an arc
                        Line   line   = null;
                        Sketch sketch = document.GetElement(analyticalPanel.SketchId) as Sketch;
                        if (sketch != null)
                        {
                            foreach (CurveArray curveArray in sketch.Profile)
                            {
                                foreach (Curve curve in curveArray)
                                {
                                    line = curve as Line;
                                    if (line != null)
                                    {
                                        break;
                                    }
                                }
                                if (line != null)
                                {
                                    break;
                                }
                            }
                        }

                        // Create arc
                        XYZ   normal = line.Direction.CrossProduct(XYZ.BasisZ).Normalize().Negate();
                        XYZ   middle = line.GetEndPoint(0).Add(line.Direction.Multiply(line.Length / 2));
                        Curve arc    = Arc.Create(line.GetEndPoint(0), line.GetEndPoint(1), middle.Add(normal.Multiply(20)));

                        // Remove element referenced by the found line.
                        document.Delete(line.Reference.ElementId);

                        // Model curve creation automatically puts the curve into the sketch, if sketch edit scope is running.
                        document.Create.NewModelCurve(arc, sketch.SketchPlane);

                        transaction.Commit();
                    }

                    sketchEditScope.Commit(new FailurePreproccessor());
                }

                return(Result.Succeeded);
            }
            catch (Exception ex)
            {
                message = ex.Message;
                return(Result.Failed);
            }
        }
        /// <summary>
        /// Implement this method as an external command for Revit.
        /// </summary>
        /// <param name="commandData">An object that is passed to the external application
        /// which contains data related to the command,
        /// such as the application object and active view.</param>
        /// <param name="message">A message that can be set by the external application
        /// which will be displayed if a failure or cancellation is returned by
        /// the external command.</param>
        /// <param name="elements">A set of elements to which the external application
        /// can add elements that are to be highlighted in case of failure or cancellation.</param>
        /// <returns>Return the status of the external command.
        /// A result of Succeeded means that the API external method functioned as expected.
        /// Cancelled can be used to signify that the user cancelled the external operation
        /// at some point. Failure should be returned if the application is unable to proceed with
        /// the operation.</returns>
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            //Expected results: the Analytical Panel has been moved and the connection with the Analytical Member has been broken
            try
            {
                //Get the Document
                Document document = commandData.Application.ActiveUIDocument.Document;

                // Create Analytical Panel
                AnalyticalPanel analyticalPanel = CreateAnalyticalPanel.CreateAMPanel(document);

                // Create an Analytical Member connected with the Analytical Panel above
                AnalyticalMember analyticalMember = CreateAnalyticalMember.CreateMember(document);

                // Move the Analytical Panel using SketchEditScope
                SketchEditScope sketchEditScope = new SketchEditScope(document, "Move panel with SketchEditScope");
                sketchEditScope.StartWithNewSketch(analyticalPanel.Id);

                // Start transaction
                using (Transaction transaction = new Transaction(document, "Offset panel"))
                {
                    transaction.Start();

                    // Get Sketch
                    if (document.GetElement(analyticalPanel.SketchId) is Sketch sketch)
                    {
                        foreach (CurveArray curveArray in sketch.Profile)
                        {
                            // Iterate through the Curves forming the Analytical Panel and
                            // create new ones with a slight offset from the original ones before deleting them
                            foreach (Curve curve in curveArray)
                            {
                                Line line = curve as Line;
                                if (line != null)
                                {
                                    // Create new offseted Start and End points from the original line coordinates
                                    double offset       = 5.0;
                                    XYZ    newLineStart = new XYZ(line.GetEndPoint(0).X + offset, line.GetEndPoint(0).Y + offset, 0);
                                    XYZ    newLineEnd   = new XYZ(line.GetEndPoint(1).X + offset, line.GetEndPoint(1).Y + offset, 0);

                                    // Define the new line with offseted coordinates
                                    Curve offsetedLine = Line.CreateBound(newLineStart, newLineEnd);

                                    // Remove the old line
                                    document.Delete(line.Reference.ElementId);

                                    // Create the new line
                                    document.Create.NewModelCurve(offsetedLine, sketch.SketchPlane);
                                }
                            }
                        }
                    }
                    transaction.Commit();
                }
                sketchEditScope.Commit(new FailurePreproccessor());

                return(Result.Succeeded);
            }
            catch (Exception ex)
            {
                message = ex.Message;
                return(Result.Failed);
            }
        }
            // Find a line in a sketch, delete it and create an arc in its place.
            public void ReplaceBoundaryLine(Document doc)
            {
                FilteredElementCollector floorCollector
                    = new FilteredElementCollector(doc)
                      .WhereElementIsNotElementType()
                      .OfCategory(BuiltInCategory.OST_Floors)
                      .OfClass(typeof(Floor));

                Floor floor = floorCollector.FirstOrDefault() as Floor;

                if (floor == null)
                {
                    TaskDialog.Show("Error", "doc does not contain a floor.");
                    return;
                }

                Sketch sketch = doc.GetElement(floor.SketchId) as Sketch;
                Line   line   = null;

                foreach (CurveArray curveArray in sketch.Profile)
                {
                    foreach (Curve curve in curveArray)
                    {
                        line = curve as Line;
                        if (line != null)
                        {
                            break;
                        }
                    }
                    if (line != null)
                    {
                        break;
                    }
                }

                if (line == null)
                {
                    TaskDialog.Show("Error",
                                    "Sketch does not contain a straight line.");
                    return;
                }

                // Start a sketch edit scope
                SketchEditScope sketchEditScope = new SketchEditScope(doc,
                                                                      "Replace line with an arc");

                sketchEditScope.Start(sketch.Id);

                using (Transaction transaction = new Transaction(doc,
                                                                 "Modify sketch"))
                {
                    transaction.Start();

                    // Create arc
                    XYZ   normal = line.Direction.CrossProduct(XYZ.BasisZ).Normalize().Negate();
                    XYZ   middle = line.GetEndPoint(0).Add(line.Direction.Multiply(line.Length / 2));
                    Curve arc    = Arc.Create(line.GetEndPoint(0), line.GetEndPoint(1),
                                              middle.Add(normal.Multiply(20)));

                    // Remove element referenced by the found line.
                    doc.Delete(line.Reference.ElementId);

                    // Model curve creation automatically puts the curve
                    // into the sketch, if sketch edit scope is running.

                    doc.Create.NewModelCurve(arc, sketch.SketchPlane);

                    transaction.Commit();
                }
                sketchEditScope.Commit(new FailuresPreprocessor());
            }