public StringBuilder Export(string pipeLineAbbreviation, HashSet <Element> elements, Document document) { Document doc = document; string key = pipeLineAbbreviation; plst pList = new plst(); //paramList = new plst(); //The list of fittings, sorted by TYPE then SKEY IList <Element> accessoriesList = elements. OrderBy(e => e.get_Parameter(pList.PCF_ELEM_TYPE.Guid).AsString()). ThenBy(e => e.get_Parameter(pList.PCF_ELEM_SKEY.Guid).AsString()).ToList(); StringBuilder sbAccessories = new StringBuilder(); //This is a workaround to try to determine what element caused an exception Element element = null; try { foreach (Element Element in accessoriesList) { //This is a workaround to try to determine what element caused an exception element = Element; sbAccessories.AppendLine(element.get_Parameter(new plst().PCF_ELEM_TYPE.Guid).AsString()); sbAccessories.AppendLine(" COMPONENT-IDENTIFIER " + element.get_Parameter(new plst().PCF_ELEM_COMPID.Guid).AsString()); if (element.get_Parameter(new plst().PCF_ELEM_SPEC.Guid).AsString() == "EXISTING-INCLUDE") { sbAccessories.AppendLine(" STATUS DOTTED-UNDIMENSIONED"); sbAccessories.AppendLine(" MATERIAL-LIST EXCLUDE"); } //Write Plant3DIso entries if turned on if (InputVars.ExportToIsogen) { sbAccessories.Append(Composer.Plant3DIsoWriter(element, doc)); } //Cast the elements gathered by the collector to FamilyInstances FamilyInstance familyInstance = (FamilyInstance)element; Options options = new Options(); //Gather connectors of the element var cons = mp.GetConnectors(element); //Switch to different element type configurations switch (element.get_Parameter(pList.PCF_ELEM_TYPE.Guid).AsString()) { case ("FILTER"): //Process endpoints of the component sbAccessories.Append(EndWriter.WriteEP1(element, cons.Primary)); sbAccessories.Append(EndWriter.WriteEP2(element, cons.Secondary)); sbAccessories.Append(pdw.ParameterValue("TAG", new[] { "TAG 1", "TAG 2", "TAG 3" }, element)); break; case ("INSTRUMENT"): //Process endpoints of the component sbAccessories.Append(EndWriter.WriteEP1(element, cons.Primary)); sbAccessories.Append(EndWriter.WriteEP2(element, cons.Secondary)); sbAccessories.Append(EndWriter.WriteCP(familyInstance)); sbAccessories.Append(pdw.ParameterValue("TAG", new[] { "TAG 1", "TAG 2", "TAG 3" }, element)); break; case ("VALVE"): goto case ("INSTRUMENT"); case ("VALVE-ANGLE"): //Process endpoints of the component sbAccessories.Append(EndWriter.WriteEP1(element, cons.Primary)); sbAccessories.Append(EndWriter.WriteEP2(element, cons.Secondary)); //The centre point is obtained by creating an bound line from primary connector and projecting the secondary point on the line. XYZ reverseConnectorVector = -cons.Primary.CoordinateSystem.BasisZ; Line primaryLine = Line.CreateBound(cons.Primary.Origin, cons.Primary.Origin + reverseConnectorVector * 10); XYZ centrePoint = primaryLine.Project(cons.Secondary.Origin).XYZPoint; sbAccessories.Append(EndWriter.WriteCP(centrePoint)); sbAccessories.Append(pdw.ParameterValue("TAG", new[] { "TAG 1", "TAG 2", "TAG 3" }, element)); break; case ("INSTRUMENT-DIAL"): //Connector information extraction sbAccessories.Append(EndWriter.WriteEP1(element, cons.Primary)); XYZ primConOrigin = cons.Primary.Origin; //Analyses the geometry to obtain a point opposite the main connector. //Extraction of the direction of the connector and reversing it reverseConnectorVector = -cons.Primary.CoordinateSystem.BasisZ; Line detectorLine = Line.CreateBound(primConOrigin, primConOrigin + reverseConnectorVector * 10); //Begin geometry analysis GeometryElement geometryElement = familyInstance.get_Geometry(options); //Prepare resulting point XYZ endPointAnalyzed = null; foreach (GeometryObject geometry in geometryElement) { GeometryInstance instance = geometry as GeometryInstance; if (null == instance) { continue; } foreach (GeometryObject instObj in instance.GetInstanceGeometry()) { Solid solid = instObj as Solid; if (null == solid || 0 == solid.Faces.Size || 0 == solid.Edges.Size) { continue; } foreach (Face face in solid.Faces) { IntersectionResultArray results = null; XYZ intersection = null; try { SetComparisonResult result = face.Intersect(detectorLine, out results); if (result != SetComparisonResult.Overlap) { continue; } intersection = results.get_Item(0).XYZPoint; if (intersection.IsAlmostEqualTo(primConOrigin) == false) { endPointAnalyzed = intersection; } } catch (Exception) { continue; } } } } //If the point is still null after geometry intersection, it means the analysis failed //Create an artificial point if (endPointAnalyzed == null) { endPointAnalyzed = cons.Primary.Origin + reverseConnectorVector * 2; } sbAccessories.Append(EndWriter.WriteCO(endPointAnalyzed)); sbAccessories.Append(pdw.ParameterValue("TAG", new[] { "TAG 1", "TAG 2", "TAG 3" }, element)); break; case "SUPPORT": sbAccessories.Append(EndWriter.WriteCO(familyInstance, cons.Primary)); sbAccessories.Append(pdw.ParameterValue("TAG", new[] { "TAG 1", "TAG 2", "TAG 3" }, element)); break; case "FLOOR-SYMBOL": sbAccessories.Append(EndWriter.WriteCO(familyInstance)); break; case "INSTRUMENT-3WAY": //Process endpoints of the component sbAccessories.Append(EndWriter.WriteEP1(element, cons.Primary)); sbAccessories.Append(EndWriter.WriteEP2(element, cons.Secondary)); sbAccessories.Append(EndWriter.WriteEP3(element, cons.Tertiary)); sbAccessories.Append(EndWriter.WriteCP(familyInstance)); break; } Composer elemParameterComposer = new Composer(); sbAccessories.Append(elemParameterComposer.ElemParameterWriter(element)); #region CII export if (InputVars.ExportToCII && !string.Equals(element.get_Parameter(pList.PCF_ELEM_TYPE.Guid).AsString(), "SUPPORT")) { sbAccessories.Append(Composer.CIIWriter(doc, key)); } #endregion sbAccessories.Append(" UNIQUE-COMPONENT-IDENTIFIER "); sbAccessories.Append(element.UniqueId); sbAccessories.AppendLine(); //Process tap entries of the element if any //Diameter Limit nullifies the tapsWriter output if the tap diameter is less than the limit so it doesn't get exported if (string.IsNullOrEmpty(element.LookupParameter("PCF_ELEM_TAP1").AsString()) == false) { TapsWriter tapsWriter = new TapsWriter(element, "PCF_ELEM_TAP1", doc); sbAccessories.Append(tapsWriter.tapsWriter); } if (string.IsNullOrEmpty(element.LookupParameter("PCF_ELEM_TAP2").AsString()) == false) { TapsWriter tapsWriter = new TapsWriter(element, "PCF_ELEM_TAP2", doc); sbAccessories.Append(tapsWriter.tapsWriter); } if (string.IsNullOrEmpty(element.LookupParameter("PCF_ELEM_TAP3").AsString()) == false) { TapsWriter tapsWriter = new TapsWriter(element, "PCF_ELEM_TAP3", doc); sbAccessories.Append(tapsWriter.tapsWriter); } } } catch (Exception e) { throw new Exception("Element " + element.Id.IntegerValue.ToString() + " caused an exception: " + e.Message); } //// Clear the output file //System.IO.File.WriteAllBytes(InputVars.OutputDirectoryFilePath + "Accessories.pcf", new byte[0]); //// Write to output file //using (StreamWriter w = File.AppendText(InputVars.OutputDirectoryFilePath + "Accessories.pcf")) //{ // w.Write(sbAccessories); // w.Close(); //} return(sbAccessories); }
public StringBuilder Export(string pipeLineAbbreviation, HashSet <Element> elements, Document document) { Document doc = document; string key = pipeLineAbbreviation; plst pList = new plst(); //paramList = new plst(); //The list of fittings, sorted by TYPE then SKEY IList <Element> accessoriesList = elements. OrderBy(e => e.get_Parameter(pList.PCF_ELEM_TYPE.Guid).AsString()). ThenBy(e => e.get_Parameter(pList.PCF_ELEM_SKEY.Guid).AsString()).ToList(); StringBuilder sbAccessories = new StringBuilder(); //This is a workaround to try to determine what element caused an exception Element element = null; try { foreach (Element Element in accessoriesList) { //This is a workaround to try to determine what element caused an exception element = Element; //If the Element Type field is empty -> ignore the component if (string.IsNullOrEmpty(element.get_Parameter(pList.PCF_ELEM_TYPE.Guid).AsString())) { continue; } sbAccessories.AppendLine(element.get_Parameter(new plst().PCF_ELEM_TYPE.Guid).AsString()); sbAccessories.AppendLine(" COMPONENT-IDENTIFIER " + element.get_Parameter(new plst().PCF_ELEM_COMPID.Guid).AsInteger()); //Write Plant3DIso entries if turned on if (InputVars.ExportToPlant3DIso) { sbAccessories.Append(Composer.Plant3DIsoWriter(element, doc)); } //Cast the elements gathered by the collector to FamilyInstances FamilyInstance familyInstance = (FamilyInstance)element; Options options = new Options(); //MEPModel of the elements is accessed MEPModel mepmodel = familyInstance.MEPModel; //Get connector set for the element ConnectorSet connectorSet = mepmodel.ConnectorManager.Connectors; //Switch to different element type configurations switch (element.get_Parameter(pList.PCF_ELEM_TYPE.Guid).AsString()) { case ("FILTER"): //Process endpoints of the component Connector primaryConnector = null; Connector secondaryConnector = null; foreach (Connector connector in connectorSet) { if (connector.GetMEPConnectorInfo().IsPrimary) { primaryConnector = connector; } if (connector.GetMEPConnectorInfo().IsSecondary) { secondaryConnector = connector; } } //Process endpoints of the component sbAccessories.Append(EndWriter.WriteEP1(element, primaryConnector)); sbAccessories.Append(EndWriter.WriteEP2(element, secondaryConnector)); break; case ("INSTRUMENT"): //Process endpoints of the component primaryConnector = null; secondaryConnector = null; foreach (Connector connector in connectorSet) { if (connector.GetMEPConnectorInfo().IsPrimary) { primaryConnector = connector; } if (connector.GetMEPConnectorInfo().IsSecondary) { secondaryConnector = connector; } } //Process endpoints of the component sbAccessories.Append(EndWriter.WriteEP1(element, primaryConnector)); sbAccessories.Append(EndWriter.WriteEP2(element, secondaryConnector)); sbAccessories.Append(EndWriter.WriteCP(familyInstance)); break; case ("VALVE"): goto case ("INSTRUMENT"); case ("VALVE-ANGLE"): //Process endpoints of the component primaryConnector = null; secondaryConnector = null; foreach (Connector connector in connectorSet) { if (connector.GetMEPConnectorInfo().IsPrimary) { primaryConnector = connector; } if (connector.GetMEPConnectorInfo().IsSecondary) { secondaryConnector = connector; } } //Process endpoints of the component sbAccessories.Append(EndWriter.WriteEP1(element, primaryConnector)); sbAccessories.Append(EndWriter.WriteEP2(element, secondaryConnector)); //The centre point is obtained by creating an unbound line from primary connector and projecting the secondary point on the line. XYZ reverseConnectorVector = -primaryConnector.CoordinateSystem.BasisZ; Line primaryLine = Line.CreateUnbound(primaryConnector.Origin, reverseConnectorVector); XYZ centrePoint = primaryLine.Project(secondaryConnector.Origin).XYZPoint; sbAccessories.Append(EndWriter.WriteCP(centrePoint)); break; case ("INSTRUMENT-DIAL"): ////Process endpoints of the component //primaryConnector = null; //foreach (Connector connector in connectorSet) primaryConnector = connector; ////Process endpoints of the component //sbAccessories.Append(EndWriter.WriteEP1(element, primaryConnector)); ////The co-ords point is obtained by creating an unbound line from primary connector and taking an arbitrary point a long the line. //reverseConnectorVector = -primaryConnector.CoordinateSystem.BasisZ.Multiply(0.656167979); //XYZ coOrdsPoint = primaryConnector.Origin; //Transform pointTranslation; //pointTranslation = Transform.CreateTranslation(reverseConnectorVector); //coOrdsPoint = pointTranslation.OfPoint(coOrdsPoint); primaryConnector = null; foreach (Connector connector in connectorSet) { primaryConnector = connector; } //Connector information extraction sbAccessories.Append(EndWriter.WriteEP1(element, primaryConnector)); XYZ primConOrigin = primaryConnector.Origin; //Analyses the geometry to obtain a point opposite the main connector. //Extraction of the direction of the connector and reversing it reverseConnectorVector = -primaryConnector.CoordinateSystem.BasisZ; Line detectorLine = Line.CreateUnbound(primConOrigin, reverseConnectorVector); //Begin geometry analysis GeometryElement geometryElement = familyInstance.get_Geometry(options); //Prepare resulting point XYZ endPointAnalyzed = null; foreach (GeometryObject geometry in geometryElement) { GeometryInstance instance = geometry as GeometryInstance; if (null == instance) { continue; } foreach (GeometryObject instObj in instance.GetInstanceGeometry()) { Solid solid = instObj as Solid; if (null == solid || 0 == solid.Faces.Size || 0 == solid.Edges.Size) { continue; } foreach (Face face in solid.Faces) { IntersectionResultArray results = null; XYZ intersection = null; SetComparisonResult result = face.Intersect(detectorLine, out results); if (result != SetComparisonResult.Overlap) { continue; } intersection = results.get_Item(0).XYZPoint; if (intersection.IsAlmostEqualTo(primConOrigin) == false) { endPointAnalyzed = intersection; } } } } sbAccessories.Append(EndWriter.WriteCO(endPointAnalyzed)); break; case "SUPPORT": primaryConnector = (from Connector c in connectorSet where c.GetMEPConnectorInfo().IsPrimary select c).FirstOrDefault(); sbAccessories.Append(EndWriter.WriteCO(familyInstance, primaryConnector)); break; case "INSTRUMENT-3WAY": //Sort connectors to primary, secondary and none primaryConnector = null; secondaryConnector = null; Connector tertiaryConnector = null; foreach (Connector connector in connectorSet) { if (connector.GetMEPConnectorInfo().IsPrimary) { primaryConnector = connector; } if (connector.GetMEPConnectorInfo().IsSecondary) { secondaryConnector = connector; } if ((connector.GetMEPConnectorInfo().IsPrimary == false) && (connector.GetMEPConnectorInfo().IsSecondary == false)) { tertiaryConnector = connector; } } //Process endpoints of the component sbAccessories.Append(EndWriter.WriteEP1(element, primaryConnector)); sbAccessories.Append(EndWriter.WriteEP2(element, secondaryConnector)); sbAccessories.Append(EndWriter.WriteEP3(element, tertiaryConnector)); sbAccessories.Append(EndWriter.WriteCP(familyInstance)); break; } Composer elemParameterComposer = new Composer(); sbAccessories.Append(elemParameterComposer.ElemParameterWriter(element)); #region CII export if (InputVars.ExportToCII && !string.Equals(element.get_Parameter(pList.PCF_ELEM_TYPE.Guid).AsString(), "SUPPORT")) { sbAccessories.Append(Composer.CIIWriter(doc, key)); } #endregion sbAccessories.Append(" UNIQUE-COMPONENT-IDENTIFIER "); sbAccessories.Append(element.UniqueId); sbAccessories.AppendLine(); //Process tap entries of the element if any //Diameter Limit nullifies the tapsWriter output if the tap diameter is less than the limit so it doesn't get exported if (string.IsNullOrEmpty(element.LookupParameter("PCF_ELEM_TAP1").AsString()) == false) { TapsWriter tapsWriter = new TapsWriter(element, "PCF_ELEM_TAP1", doc); sbAccessories.Append(tapsWriter.tapsWriter); } if (string.IsNullOrEmpty(element.LookupParameter("PCF_ELEM_TAP2").AsString()) == false) { TapsWriter tapsWriter = new TapsWriter(element, "PCF_ELEM_TAP2", doc); sbAccessories.Append(tapsWriter.tapsWriter); } if (string.IsNullOrEmpty(element.LookupParameter("PCF_ELEM_TAP3").AsString()) == false) { TapsWriter tapsWriter = new TapsWriter(element, "PCF_ELEM_TAP3", doc); sbAccessories.Append(tapsWriter.tapsWriter); } } } catch (Exception e) { throw new Exception("Element " + element.Id.IntegerValue.ToString() + " caused an exception: " + e.Message); } //// Clear the output file //System.IO.File.WriteAllBytes(InputVars.OutputDirectoryFilePath + "Accessories.pcf", new byte[0]); //// Write to output file //using (StreamWriter w = File.AppendText(InputVars.OutputDirectoryFilePath + "Accessories.pcf")) //{ // w.Write(sbAccessories); // w.Close(); //} return(sbAccessories); }
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); }