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