Пример #1
0
        public Trampoline(Vector3 origin, Vector3 angle, int height) : base(BoxType.Trampline, origin, angle, 50)
        {
            Height      = height;
            Icon        = "cardicon_tictacboom";
            Shader      = Hud.CreateShader(origin, Icon);
            ObjectiveId = Hud.CreateObjective(origin, Icon);

            OnTriggerString += player =>
            {
                return("Press ^3[{+gostand}] ^7to boost jump.");
            };

            OnInterval(100, e =>
            {
                foreach (var player in Utility.Players)
                {
                    if (player.IsAlive && Origin.DistanceTo(player.Origin) <= Range && player.Call <int>("IsOnGround") == 1)
                    {
                        DoJump(player);
                    }
                }

                return(true);
            });
        }
Пример #2
0
        /// <summary>
        /// A method that parses a list of cities into properties used by the solver
        /// </summary>
        /// <param name="cities">The cities to be parsed</param>
        public void OrderData(List <City> cities)
        {
            // Clear any previous information
            Destinations.Clear();
            VisitedCities.Clear();
            DataCleared.Invoke(this, new EventArgs());

            // Set the first city as the start and end
            Origin = cities[0];
            VisitedCities.Add(Origin);
            CityAdded.Invoke(this, new CityAddedEventArgs(Origin, 0));
            VisitedCities.Add(Origin);
            CityAdded.Invoke(this, new CityAddedEventArgs(Origin, 1));

            // Set the next closest node as the second point
            SecondCity = cities[1];

            foreach (City city in cities.Skip(2))
            {
                if (Origin.DistanceTo(city) < Origin.DistanceTo(SecondCity))
                {
                    SecondCity = city;
                }
            }

            VisitedCities.Insert(1, SecondCity);
            CityAdded.Invoke(this, new CityAddedEventArgs(SecondCity, 1));

            // Add the rest of the cities to the destinations list
            Destinations = cities.Where(c => c != Origin && c != SecondCity).ToList();
        }
Пример #3
0
        public static Result CreatePipeFromConnector(UIApplication uiApp)
        {
            Document doc = uiApp.ActiveUIDocument.Document;

            bool ctrl = false;

            if ((int)Keyboard.Modifiers == 2)
            {
                ctrl = true;
            }

            string pipeTypeName = MEPUtils.Properties.Settings.Default.PipeCreator_SelectedPipeTypeName;

            //If the name of pipeType is null or empty for some reason -- reinitialize
            if (string.IsNullOrEmpty(pipeTypeName))
            {
                ctrl = true;
            }

            if (ctrl)
            {
                FilteredElementCollector colPipeTypes = new FilteredElementCollector(doc);
                var pipeTypes = colPipeTypes.OfClass(typeof(PipeType)).ToElements();

                var pipeTypeNames = colPipeTypes.Select(x => x.Name).ToList();

                int count = pipeTypeNames.Count;

                var pc = new PipeTypeSelector(uiApp, pipeTypeNames);
                pc.ShowDialog();

                pipeTypeName = pc.pipeTypeName;
            }

            try
            {
                //One element selected, creates pipe at random connector
                //Or an elbow for pipe
                //Two elements selected: Creates pipe between them
                //NOTE: the connectors must be aligned
                Selection selection           = uiApp.ActiveUIDocument.Selection;
                ICollection <ElementId> elIds = selection.GetElementIds();
                if (elIds.Count == 2)
                {
                    Element firstEl  = doc.GetElement(elIds.First());
                    Element secondEl = doc.GetElement(elIds.Last());

                    HashSet <Connector> firstCons  = mp.GetALLConnectorsFromElements(firstEl);
                    HashSet <Connector> secondCons = mp.GetALLConnectorsFromElements(secondEl);

                    var listToCompare = new List <(Connector firstCon, Connector secondCon, double Distance)>();

                    foreach (Connector c1 in firstCons)
                    {
                        foreach (Connector c2 in secondCons)
                        {
                            listToCompare.Add((c1, c2, c1.Origin.DistanceTo(c2.Origin)));
                        }
                    }

                    var(firstCon, secondCon, Distance) = listToCompare.MinBy(x => x.Distance).FirstOrDefault();

                    using (Transaction tx = new Transaction(doc))
                    {
                        //Get the typeId of the selected or read PipeType
                        var filter = fi.ParameterValueGenericFilter(doc, pipeTypeName, BuiltInParameter.ALL_MODEL_TYPE_NAME);
                        FilteredElementCollector col = new FilteredElementCollector(doc);
                        var pipeType = col.OfClass(typeof(PipeType)).WherePasses(filter).ToElements().FirstOrDefault();
                        if (pipeType == null)
                        {
                            throw new Exception("Collection of PipeType failed!");
                        }

                        //LevelId can be null -> work around
                        ElementId levelId;

                        if (firstEl.LevelId.IntegerValue == -1)
                        {
                            FilteredElementCollector lcol = new FilteredElementCollector(doc);
                            var randomLvl = lcol.OfClass(typeof(Level)).ToElements().LastOrDefault(); //Select random levelid
                            levelId = randomLvl.Id;
                        }
                        else
                        {
                            levelId = firstEl.LevelId;
                        }

                        tx.Start("Create pipe!");
                        Pipe.Create(doc, pipeType.Id, levelId, firstCon, secondCon);
                        tx.Commit();
                    }
                }
                else
                {
                    //if (elIds.Count == 0 || elIds.Count > 1) throw new Exception("Only works on single element! No or multiple elements selected!");
                    ElementId id = elIds.FirstOrDefault();
                    if (id == null)
                    {
                        throw new Exception("Getting element from selection failed!");
                    }
                    Element element = doc.GetElement(id);
                    var     cons    = mp.GetALLConnectorsFromElements(element);

                    //Get the typeId of the selected or read PipeType
                    var filter = fi.ParameterValueGenericFilter(doc, pipeTypeName, BuiltInParameter.ALL_MODEL_TYPE_NAME);
                    FilteredElementCollector col = new FilteredElementCollector(doc);
                    var pipeType = col.OfClass(typeof(PipeType)).WherePasses(filter).ToElements().FirstOrDefault();
                    if (pipeType == null)
                    {
                        throw new Exception("Collection of PipeType failed!");
                    }

                    //LevelId can be null -> work around
                    ElementId levelId;

                    if (element.LevelId.IntegerValue == -1)
                    {
                        FilteredElementCollector lcol = new FilteredElementCollector(doc);
                        var randomLvl = lcol.OfClass(typeof(Level)).ToElements().LastOrDefault(); //Select random levelid
                        levelId = randomLvl.Id;
                    }
                    else
                    {
                        levelId = element.LevelId;
                    }

                    Connector con = (from Connector c in cons where c.IsConnected == false select c).FirstOrDefault();
                    if (con == null)
                    {
                        throw new Exception("No not connected connectors in element!");
                    }

                    //If the element is a Pipe -> Create a bend in a specified direction
                    if (element is Pipe selectedPipe)
                    {
                        string bendDir;

                        //Get Pipe Size
                        double pipeSize = selectedPipe.Diameter;

                        //Select the direction to create in
                        BaseFormTableLayoutPanel_Basic ds = new BaseFormTableLayoutPanel_Basic(
                            System.Windows.Forms.Cursor.Position.X, System.Windows.Forms.Cursor.Position.Y, lad.Directions());
                        ds.ShowDialog();
                        bendDir = ds.strTR;

                        ElementId curPipingSysTypeId = selectedPipe.MEPSystem.GetTypeId();
                        ElementId curPipeTypeId      = selectedPipe.PipeType.Id;

                        XYZ iP       = con.Origin;
                        XYZ dirPoint = null;
                        //Create direction point
                        switch (bendDir)
                        {
                        case "Top":
                            dirPoint = new XYZ(iP.X, iP.Y, iP.Z + 5);
                            break;

                        case "Bottom":
                            dirPoint = new XYZ(iP.X, iP.Y, iP.Z - 5);
                            break;

                        case "Front":
                            dirPoint = new XYZ(iP.X, iP.Y - 5, iP.Z);
                            break;

                        case "Back":
                            dirPoint = new XYZ(iP.X, iP.Y + 5, iP.Z);
                            break;

                        case "Left":
                            dirPoint = new XYZ(iP.X - 5, iP.Y, iP.Z);
                            break;

                        case "Right":
                            dirPoint = new XYZ(iP.X + 5, iP.Y, iP.Z);
                            break;

                        default:
                            break;
                        }

                        using (TransactionGroup txGp = new TransactionGroup(doc))
                        {
                            txGp.Start("Create new elbow and pipe!");

                            Pipe newPipe;

                            using (Transaction tx1 = new Transaction(doc))
                            {
                                tx1.Start("Create new pipe!");

                                newPipe = Pipe.Create(doc, curPipingSysTypeId, curPipeTypeId, levelId, iP, dirPoint);

                                //Change size of the pipe
                                Parameter par = newPipe.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM);
                                par.Set(pipeSize);

                                tx1.Commit();
                            }

                            //Find the connector from the dummy pipe at intersection
                            var       newCons = mp.GetALLConnectorsFromElements(newPipe);
                            Connector newCon  = newCons.Where(c => c.Equalz(con, Extensions._1mmTol)).FirstOrDefault();

                            using (Transaction tx2 = new Transaction(doc))
                            {
                                tx2.Start("Create new bend!");

                                doc.Create.NewElbowFitting(con, newCon);

                                tx2.Commit();
                            }

                            txGp.Assimilate();
                        }
                    }
                    else //if element is anything other than a Pipe -> Create a pipe from random connector
                    {
                        //Create a point in space to connect the pipe
                        XYZ direction    = con.CoordinateSystem.BasisZ.Multiply(2);
                        XYZ origin       = con.Origin;
                        XYZ pointInSpace = origin.Add(direction);

                        //Transaction that creates the pipe
                        Transaction tx = new Transaction(doc);
                        tx.Start("Create pipe!");
                        //Create the pipe
                        Pipe.Create(doc, pipeType.Id, levelId, con, pointInSpace);
                        tx.Commit();
                    }
                }
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }

            return(Result.Succeeded);
        }
        public static Result ValidateConnectorsSpatially(ExternalCommandData cData)
        {
            bool ctrl = false;

            //bool shft = false;
            if ((int)Keyboard.Modifiers == 2)
            {
                ctrl = true;
            }
            //if ((int)Keyboard.Modifiers == 4) shft = true;

            UIApplication uiApp = cData.Application;
            Document      doc   = cData.Application.ActiveUIDocument.Document;
            UIDocument    uidoc = uiApp.ActiveUIDocument;

            //Gather all connectors from the document
            //Filter also out all "Curve" connectors, which are olet ends at pipe cntr.
            HashSet <Connector> AllCons = mp.GetALLConnectorsInDocument(doc).ExceptWhere(c => c.ConnectorType == ConnectorType.Curve).ToHashSet();

            //if (ctrl)
            AllCons = AllCons.ExceptWhere(c => c.MEPSystemAbbreviation(doc, true) == "ARGD").ToHashSet();

            //Create collection with distinct connectors with a set tolerance
            double Tol          = 3.0.MmToFt();
            var    DistinctCons = AllCons.ToHashSet(new ConnectorXyzComparer(Tol));

            List <connectorSpatialGroup> csgList = new List <connectorSpatialGroup>();

            foreach (Connector distinctCon in DistinctCons)
            {
                csgList.Add(new connectorSpatialGroup(AllCons.Where(x => distinctCon.Equalz(x, Tol))));
                AllCons = AllCons.ExceptWhere(x => distinctCon.Equalz(x, Tol)).ToHashSet();
            }

            foreach (var g in csgList)
            {
                g.pairs = g.Connectors
                          .SelectMany((fst, i) => g.Connectors.Skip(i + 1)
                                      .Select(snd => (fst, snd, fst.Origin.DistanceTo(snd.Origin))))
                          .ToList();
                g.longestPair = g.pairs.MaxBy(x => x.dist).FirstOrDefault();

                g.longestDist = g.longestPair.dist.FtToMm().Round(4);
            }

            csgList.Sort((y, x) => x.longestDist.CompareTo(y.longestDist));

            List <string> results = new List <string>();

            foreach (var g in csgList)
            {
                if (g.longestDist > 0.001)
                {
                    //Element owner1 = g.longestPair.c1.Owner;
                    //Element owner2 = g.longestPair.c2.Owner;
                    //string intermediateResult = $"{owner1.Name}: {owner1.Id} - {owner2.Name}: {owner2.Id} => {g.longestDist} mm\n";
                    //results.Add(intermediateResult);

                    //This check (if(), s1, s2) is to detect wether the coordinates will display differently in exported (ntr, pcf) text which causes problems
                    //The goal is to have all geometric coordinates have same string value
                    //If the distance between connectors too small to register in the string value -> we don't care (i think)
                    bool coordinatesDiffer = false;

                    foreach (var pair in g.pairs)
                    {
                        string s1 = PointStringMm(pair.c1.Origin, precision);
                        string s2 = PointStringMm(pair.c2.Origin, precision);
                        if (s1 != s2)
                        {
                            coordinatesDiffer = true;
                        }
                    }
                    if (coordinatesDiffer)
                    {
                        results.Add($"{g.longestDist}\n");
                        foreach (var c in g.Connectors)
                        {
                            string s = PointStringMm(c.Origin, precision);
                            results.Add($"{s} {c.Owner.Id.ToString()}\n");
                        }
                        results.Add("\n");
                    }
                }
            }

            Shared.BuildingCoder.BuildingCoderUtilities.InfoMsg(string.Join(string.Empty, results));

            return(Result.Succeeded);
        }
Пример #5
0
        public static Result Move(UIApplication uiApp)
        {
            Document   doc   = uiApp.ActiveUIDocument.Document;
            UIDocument uidoc = uiApp.ActiveUIDocument;

            try
            {
                using (TransactionGroup txGp = new TransactionGroup(doc))
                {
                    txGp.Start("Move elements to distance!");

                    Selection selection = uidoc.Selection;
                    var       selIds    = selection.GetElementIds();
                    if (selIds.Count == 0)
                    {
                        throw new Exception("Empty selection: must select element(s) to move first!");
                    }

                    HashSet <Element> elsToMove = selIds.Select(x => doc.GetElement(x)).ToHashSet();

                    var     elId     = uidoc.Selection.PickObject(ObjectType.Element, "Select element to move to!");
                    Element MoveToEl = doc.GetElement(elId);
                    double  distanceToKeep;

                    //Ask for a length input
                    InputBoxBasic ds = new InputBoxBasic();
                    ds.ShowDialog();
                    distanceToKeep = double.Parse(ds.DistanceToKeep).MmToFt();

                    //Business logic to move but keep desired distance
                    HashSet <Connector> toMoveCons = SpecialGetAllConnectors(elsToMove);

                    HashSet <Connector> moveToCons = SpecialGetAllConnectors(new HashSet <Element> {
                        MoveToEl
                    });

                    var listToCompare = new List <(Connector toMoveCon, Connector MoveToCon, double Distance)>();

                    foreach (Connector c1 in toMoveCons)
                    {
                        foreach (Connector c2 in moveToCons)
                        {
                            listToCompare.Add((c1, c2, c1.Origin.DistanceTo(c2.Origin)));
                        }
                    }

                    var(toMoveCon, MoveToCon, Distance) = listToCompare.MinBy(x => x.Distance).FirstOrDefault();

                    XYZ moveVector = (MoveToCon.Origin - toMoveCon.Origin) * (1 - distanceToKeep / Distance);

                    using (Transaction trans3 = new Transaction(doc))
                    {
                        trans3.Start("Move Element!");
                        {
                            if (elsToMove.Count > 1)
                            {
                                ElementTransformUtils.MoveElements(doc, selIds, moveVector);
                            }
                            else
                            {
                                foreach (Element elToMove in elsToMove)
                                {
                                    ElementTransformUtils.MoveElement(doc, elToMove.Id, moveVector);
                                }
                            }
                        }
                        trans3.Commit();
                    }

                    txGp.Assimilate();
                }

                return(Result.Succeeded);
            }

            catch (Autodesk.Revit.Exceptions.OperationCanceledException) { return(Result.Cancelled); }

            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
Пример #6
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="source"></param>
        /// <param name="direction"></param>
        /// <returns></returns>
        private Line GetRayGeometry(Point source, Vector direction)
        {
            double size = Origin.DistanceTo(source) * 100;

            return(Line.ByStartPointDirectionLength(source, direction, size));
        }
Пример #7
0
        internal Result ExecuteMyCommand(UIApplication uiApp, ref string msg)
        {
            // UIApplication uiApp = commandData.Application;
            //Test comment
            Document   doc   = uiApp.ActiveUIDocument.Document;
            UIDocument uidoc = uiApp.ActiveUIDocument;

            try
            {
                #region Declaration of variables
                // Instance a collector
                FilteredElementCollector collector = new FilteredElementCollector(doc);
                //FilteredElementCollector pipeTypeCollector = new FilteredElementCollector(doc); //Obsolete???

                // Define a Filter instance to filter by System Abbreviation
                ElementParameterFilter sysAbbr = Shared.Filter.ParameterValueGenericFilter(doc, InputVars.SysAbbr, InputVars.SysAbbrParam);

                // Declare pipeline grouping object
                IEnumerable <IGrouping <string, Element> > pipelineGroups;

                //Declare an object to hold collected elements from collector
                HashSet <Element> colElements = new HashSet <Element>();

                // Instance a collecting stringbuilder
                StringBuilder sbCollect = new StringBuilder();
                #endregion

                #region Compose preamble
                //Compose preamble
                Composer composer = new Composer();

                StringBuilder sbPreamble = composer.PreambleComposer();

                //Append preamble
                sbCollect.Append(sbPreamble);
                #endregion

                #region Element collectors
                //If user chooses to export a single pipeline get only elements in that pipeline and create grouping.
                //Grouping is necessary even tho theres only one group to be able to process by the same code as the all pipelines case

                //If user chooses to export all pipelines get all elements and create grouping
                if (InputVars.ExportAllOneFile)
                {
                    //Define a collector (Pipe OR FamInst) AND (Fitting OR Accessory OR Pipe).
                    //This is to eliminate FamilySymbols from collector which would throw an exception later on.
                    collector.WherePasses(new LogicalAndFilter(new List <ElementFilter>
                    {
                        new LogicalOrFilter(new List <ElementFilter>
                        {
                            new ElementCategoryFilter(BuiltInCategory.OST_PipeFitting),
                            new ElementCategoryFilter(BuiltInCategory.OST_PipeAccessory),
                            new ElementClassFilter(typeof(Pipe))
                        }),
                        new LogicalOrFilter(new List <ElementFilter>
                        {
                            new ElementClassFilter(typeof(Pipe)),
                            new ElementClassFilter(typeof(FamilyInstance))
                        })
                    }));

                    colElements = collector.ToElements().ToHashSet();
                }

                else if (InputVars.ExportAllSepFiles || InputVars.ExportSpecificPipeLine)
                {
                    //Define a collector with multiple filters to collect PipeFittings OR PipeAccessories OR Pipes + filter by System Abbreviation
                    //System Abbreviation filter also filters FamilySymbols out.
                    collector.WherePasses(
                        new LogicalOrFilter(
                            new List <ElementFilter>
                    {
                        new ElementCategoryFilter(BuiltInCategory.OST_PipeFitting),
                        new ElementCategoryFilter(BuiltInCategory.OST_PipeAccessory),
                        new ElementClassFilter(typeof(Pipe))
                    })).WherePasses(sysAbbr);
                    colElements = collector.ToElements().ToHashSet();
                }

                else if (InputVars.ExportSelection)
                {
                    ICollection <ElementId> selection = uiApp.ActiveUIDocument.Selection.GetElementIds();
                    colElements = selection.Select(s => doc.GetElement(s)).ToHashSet();
                }


                #region Sub: Filtering
                HashSet <Element> elements;
                try
                {
                    //DiameterLimit filter applied to ALL elements.
                    var filtering = from element in colElements where Filters.FilterDL(element) select element;

                    //Filter out EXCLUDED elements -> 0 means no checkmark
                    filtering = from element in filtering
                                where element.get_Parameter(new plst().PCF_ELEM_EXCL.Guid).AsInteger() == 0
                                select element;

                    //Filter out EXCLUDED pipelines -> 0 means no checkmark
                    filtering = filtering.Where(x => x.PipingSystemAllowed(doc) == true);

                    //Remove instrument pipes
                    filtering = filtering.ExceptWhere(x => x.get_Parameter(BuiltInParameter.RBS_DUCT_PIPE_SYSTEM_ABBREVIATION_PARAM)
                                                      .AsString() == "INSTR");

                    //Filter out elements with specified PCF_ELEM_SPEC string
                    if (InputVars.PCF_ELEM_SPEC_FILTER.IsNullOrEmpty() == false)
                    {
                        filtering = filtering.ExceptWhere(x => x.get_Parameter(new plst().PCF_ELEM_SPEC.Guid).AsString() == InputVars.PCF_ELEM_SPEC_FILTER);
                    }

                    //If exporting to ISO, remove some not needed elements
                    if (InputVars.ExportToIsogen)
                    {
                        //When exporting to Plant3D ISO creation, remove the group with the Piping System: Analysis Rigids (ARGD)
                        filtering = filtering
                                    .Where(x => !(x.get_Parameter(BuiltInParameter.RBS_DUCT_PIPE_SYSTEM_ABBREVIATION_PARAM).AsString() == "ARGD"));

                        ////Also remove anchor symbols -> not needed for ISO
                        ////Currently not removed -> used for floor symbols
                        //filtering = filtering.ExceptWhere(x => x
                        //    .get_Parameter(BuiltInParameter.ELEM_FAMILY_AND_TYPE_PARAM)
                        //    .AsValueString() == "Support Symbolic: ANC");
                    }

                    //Create a grouping of elements based on the Pipeline identifier (System Abbreviation)
                    pipelineGroups = from e in filtering
                                     group e by e.get_Parameter(BuiltInParameter.RBS_DUCT_PIPE_SYSTEM_ABBREVIATION_PARAM).AsString();

                    elements = filtering.ToHashSet();
                }
                catch (Exception ex)
                {
                    throw new Exception("Filtering in Main threw an exception:\n" + ex.Message +
                                        "\nTo fix:\n" +
                                        "1. See if parameter PCF_ELEM_EXCL exists, if not, rerun parameter import.");
                }
                #endregion
                #endregion

                #region Initialize Material Data
                //TEST: Do not write material data to elements with EXISTING-INCLUDE spec
                //HashSet<Element> existInclElements = elements.Where(x =>
                //    x.get_Parameter(new plst().PCF_ELEM_SPEC.Guid).AsString() == "EXISTING-INCLUDE").ToHashSet();
                ////Remember the clearing of previous run data in transaction below

                //elements = elements.ExceptWhere(x =>
                //    x.get_Parameter(new plst().PCF_ELEM_SPEC.Guid).AsString() == "EXISTING-INCLUDE").ToHashSet();

                //Set the start number to count the COMPID instances and MAT groups.
                int elementIdentificationNumber = 0;
                int materialGroupIdentifier     = 0;

                //Make sure that every element has PCF_MAT_DESCR filled out.
                foreach (Element e in elements)
                {
                    if (string.IsNullOrEmpty(e.get_Parameter(new plst().PCF_MAT_DESCR.Guid).AsString()))
                    {
                        uidoc.Selection.SetElementIds(new List <ElementId>(1)
                        {
                            e.Id
                        });
                        BuildingCoderUtilities.ErrorMsg("PCF_MAT_DESCR is empty for element " + e.Id + "! Please, correct this issue before exporting again.");
                        throw new Exception("PCF_MAT_DESCR is empty for element " + e.Id + "! Please, correct this issue before exporting again.");
                    }
                }

                //Initialize material group numbers on the elements
                IEnumerable <IGrouping <string, Element> > materialGroups = from e in elements group e by e.get_Parameter(new plst().PCF_MAT_DESCR.Guid).AsString();

                using (Transaction trans = new Transaction(doc, "Set PCF_ELEM_COMPID and PCF_MAT_ID"))
                {
                    trans.Start();
                    //Clear MTL data from previous runs for elements with EXISTING-INCLUDE spec
                    //foreach (Element e in existInclElements)
                    //{
                    //    e.get_Parameter(new plst().PCF_ELEM_COMPID.Guid).Set("");
                    //    e.get_Parameter(new plst().PCF_MAT_ID.Guid).Set("");
                    //}

                    //Access groups
                    foreach (IEnumerable <Element> group in materialGroups)
                    {
                        materialGroupIdentifier++;
                        //Access parameters
                        foreach (Element element in group)
                        {
                            elementIdentificationNumber++;
                            element.get_Parameter(new plst().PCF_ELEM_COMPID.Guid).Set(elementIdentificationNumber.ToString());
                            element.get_Parameter(new plst().PCF_MAT_ID.Guid).Set(materialGroupIdentifier.ToString());
                        }
                    }
                    trans.Commit();
                }

                //If turned on, write wall thickness of all components
                if (InputVars.WriteWallThickness)
                {
                    //Assign correct wall thickness to elements.
                    using (Transaction trans1 = new Transaction(doc))
                    {
                        trans1.Start("Set wall thickness for pipes!");
                        ParameterDataWriter.SetWallThicknessPipes(elements);
                        trans1.Commit();
                    }
                }

                #endregion

                using (TransactionGroup txGp = new TransactionGroup(doc))
                {
                    txGp.Start("Bogus transactionGroup for the break in hangers");
                    #region Pipeline management
                    foreach (IGrouping <string, Element> gp in pipelineGroups)
                    {
                        HashSet <Element> pipeList = (from element in gp
                                                      where element.Category.Id.IntegerValue == (int)BuiltInCategory.OST_PipeCurves
                                                      select element).ToHashSet();
                        HashSet <Element> fittingList = (from element in gp
                                                         where element.Category.Id.IntegerValue == (int)BuiltInCategory.OST_PipeFitting
                                                         select element).ToHashSet();
                        HashSet <Element> accessoryList = (from element in gp
                                                           where element.Category.Id.IntegerValue == (int)BuiltInCategory.OST_PipeAccessory
                                                           select element).ToHashSet();

                        StringBuilder sbPipeline           = new PCF_Pipeline.PCF_Pipeline_Export().Export(gp.Key, doc);
                        StringBuilder sbFilename           = PCF_Pipeline.Filename.BuildAndWriteFilename(doc);
                        StringBuilder sbEndsAndConnections = PCF_Pipeline.EndsAndConnections
                                                             .DetectAndWriteEndsAndConnections(gp.Key, pipeList, fittingList, accessoryList, doc);

                        #region BrokenPipes

                        //Here be code to handle break in accessories that act as supports
                        //Find the supports in current acessoryList and add to supportList
                        //Instantiate a brokenPipesGroup class

                        //Collect all Connectors from brokenPipesList and find the longest distance
                        //Create a temporary pipe from the Connectors with longest distance
                        //Copy PCF_ELEM parameter values to the temporary pipe
                        //Add the temporary pipe to the pipeList
                        //Roll back the TransactionGroup after the elements are sent to Export class' Export methods.

                        List <BrokenPipesGroup> bpgList = new List <BrokenPipesGroup>();

                        List <Element> supportsList = accessoryList.Where(x => x.ComponentClass1(doc) == "Pipe Support").ToList();

                        while (supportsList.Count > 0)
                        {
                            //Get an element to start traversing
                            Element seedElement = supportsList.FirstOrDefault();
                            if (seedElement == null)
                            {
                                throw new Exception("BrokenPipes: Seed element returned null! supportsList.Count is " + supportsList.Count);
                            }

                            //Instantiate the BrokenPipesGroup
                            BrokenPipesGroup bpg = new BrokenPipesGroup(seedElement, gp.Key);

                            //Traverse system
                            bpg.Traverse(doc);

                            //Remove the support Elements from the collection to keep track of the while loop
                            foreach (Element support in bpg.SupportsOnPipe)
                            {
                                supportsList = supportsList.ExceptWhere(x => x.Id.IntegerValue == support.Id.IntegerValue).ToList();
                            }

                            bpgList.Add(bpg);
                        }

                        using (Transaction tx = new Transaction(doc))
                        {
                            tx.Start("Create healed pipes");
                            foreach (BrokenPipesGroup bpg in bpgList)
                            {
                                //Remove the broken pipes from the pipeList
                                //If there's only one broken pipe, then there's no need to do anything
                                //If there's no broken pipes, then there's no need to do anything either
                                if (bpg.BrokenPipes.Count != 0 && bpg.BrokenPipes.Count != 1)
                                {
                                    foreach (Element pipe in bpg.BrokenPipes)
                                    {
                                        pipeList = pipeList.ExceptWhere(x => x.Id.IntegerValue == pipe.Id.IntegerValue).ToHashSet();
                                    }

                                    //Using the new IEqualityComparer for Connectors to get distinct connectors in the collection
                                    var brokenCons = MepUtils.GetALLConnectorsFromElements(bpg.BrokenPipes.ToHashSet(), new ConnectorXyzComparer(2.0.MmToFt()));
                                    //Create distinct pair combinations with distance from all broken connectors
                                    //https://stackoverflow.com/a/47003122/6073998
                                    List <(Connector c1, Connector c2, double dist)> pairs = brokenCons
                                                                                             .SelectMany
                                                                                             (
                                        (fst, i) => brokenCons.Skip(i + 1).Select(snd => (fst, snd, fst.Origin.DistanceTo(snd.Origin)))
                                                                                             )
                                                                                             .ToList();
                                    var  longest = pairs.MaxBy(x => x.dist).FirstOrDefault();
                                    Pipe dPipe   = (Pipe)longest.c1.Owner;
                                    bpg.HealedPipe = Pipe.Create(doc, dPipe.MEPSystem.GetTypeId(), dPipe.GetTypeId(),
                                                                 dPipe.ReferenceLevel.Id, longest.c1.Origin, longest.c2.Origin);

                                    Pipe donorPipe = (Pipe)bpg.BrokenPipes.FirstOrDefault();
                                    bpg.HealedPipe.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM).Set(donorPipe.Diameter);

                                    //Add the healed pipe to the pipeList for processing
                                    pipeList.Add(bpg.HealedPipe);
                                }
                            }
                            tx.Commit();
                        }

                        //Now the healed pipe must be populated by the parameters from a donorPipe
                        using (Transaction tx = new Transaction(doc))
                        {
                            //Gather all relevant parameter definitions
                            List <pdef> plist = new plst().LPAll.Where(x => x.Domain == "ELEM" && x.Usage == "U").ToList();
                            plist.Add(new plst().PCF_MAT_ID);

                            tx.Start("Populate the HealedPipe parameters!");
                            foreach (BrokenPipesGroup bpg in bpgList)
                            {
                                //Skip iteration if there's only 1 or no broken pipes
                                if (bpg.BrokenPipes.Count == 0 || bpg.BrokenPipes.Count == 1)
                                {
                                    continue;
                                }
                                Element donorPipe = bpg.BrokenPipes.FirstOrDefault();

                                foreach (pdef p in plist)
                                {
                                    Parameter donorParameter = donorPipe.get_Parameter(p.Guid);
                                    if (donorParameter == null)
                                    {
                                        continue;
                                    }
                                    switch (donorParameter.StorageType)
                                    {
                                    case StorageType.None:
                                        continue;

                                    case StorageType.Integer:
                                        int donorInt = donorParameter.AsInteger();
                                        if (donorInt == 0)
                                        {
                                            continue;
                                        }
                                        Parameter targetParInt = bpg.HealedPipe.get_Parameter(p.Guid);
                                        targetParInt.Set(donorInt);
                                        break;

                                    case StorageType.Double:
                                        continue;

                                    case StorageType.String:
                                        string donorStr = donorParameter.AsString();
                                        if (donorStr.IsNullOrEmpty())
                                        {
                                            continue;
                                        }
                                        Parameter targetParStr = bpg.HealedPipe.get_Parameter(p.Guid);
                                        targetParStr.Set(donorStr);
                                        break;

                                    case StorageType.ElementId:
                                        continue;

                                    default:
                                        continue;
                                    }
                                }
                            }
                            tx.Commit();
                        }

                        #endregion

                        StringBuilder sbPipes       = new PCF_Pipes.PCF_Pipes_Export().Export(gp.Key, pipeList, doc);
                        StringBuilder sbFittings    = new PCF_Fittings.PCF_Fittings_Export().Export(gp.Key, fittingList, doc);
                        StringBuilder sbAccessories = new PCF_Accessories.PCF_Accessories_Export().Export(gp.Key, accessoryList, doc);

                        sbCollect.Append(sbPipeline); sbCollect.Append(sbFilename); sbCollect.Append(sbEndsAndConnections);
                        sbCollect.Append(sbPipes); sbCollect.Append(sbFittings); sbCollect.Append(sbAccessories);
                    }
                    #endregion

                    txGp.RollBack(); //RollBack the temporary created elements
                }

                #region Materials
                StringBuilder sbMaterials = composer.MaterialsSection(materialGroups);
                sbCollect.Append(sbMaterials);
                #endregion

                #region Output
                // Output the processed data
                PCF_Output.Output output = new PCF_Output.Output();
                output.OutputWriter(sbCollect);
                #endregion
            }

            catch (Autodesk.Revit.Exceptions.OperationCanceledException)
            {
                return(Result.Cancelled);
            }

            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }

            return(Result.Succeeded);
        }