Files
2024-12-12 09:51:40 +01:00

948 lines
40 KiB
C#

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Plumbing;
using System.Xml.Linq;
using System.IO;
using System.Xml;
using System.Diagnostics;
namespace Revit.SDK.Samples.RoutingPreferenceTools.CS
{
/// <summary>
/// Class to read and write XML and routing preference data
/// </summary>
public class RoutingPreferenceBuilder
{
#region Data
private IEnumerable<Segment> m_segments;
private IEnumerable<FamilySymbol> m_fittings;
private IEnumerable<Material> m_materials;
private IEnumerable<PipeScheduleType> m_pipeSchedules;
private IEnumerable<PipeType> m_pipeTypes;
private Autodesk.Revit.DB.Document m_document;
#endregion
#region Public interface
/// <summary>
/// Create an instance of the class and initialize lists of all segments, fittings, materials, schedules, and pipe types in the document.
/// </summary>
public RoutingPreferenceBuilder(Document document)
{
m_document = document;
m_segments = GetAllPipeSegments(m_document);
m_fittings = GetAllFittings(m_document);
m_materials = GetAllMaterials(m_document);
m_pipeSchedules = GetAllPipeScheduleTypes(m_document);
m_pipeTypes = GetAllPipeTypes(m_document);
}
/// <summary>
/// Reads data from an Xml source and loads pipe fitting families, creates segments, sizes, schedules, and routing preference rules from the xml data.
/// </summary>
/// <param name="xDoc">The Xml data source to read from</param>
public void ParseAllPipingPoliciesFromXml(XDocument xDoc)
{
if (m_pipeTypes.Count() == 0)
throw new RoutingPreferenceDataException("No pipe pipes defined in this project. At least one must be defined.");
FormatOptions formatOptionPipeSize = m_document.GetUnits().GetFormatOptions(SpecTypeId.PipeSize);
string docPipeSizeUnit = formatOptionPipeSize.GetUnitTypeId().TypeId;
string xmlPipeSizeUnit = xDoc.Root.Attribute("pipeSizeUnits").Value;
if (docPipeSizeUnit != xmlPipeSizeUnit)
throw new RoutingPreferenceDataException("Units from XML do not match current pipe size units.");
FormatOptions formatOptionRoughness = m_document.GetUnits().GetFormatOptions(SpecTypeId.PipingRoughness);
string docRoughnessUnit = formatOptionRoughness.GetUnitTypeId().TypeId;
string xmlRoughnessUnit = xDoc.Root.Attribute("pipeRoughnessUnits").Value;
if (docRoughnessUnit != xmlRoughnessUnit)
throw new RoutingPreferenceDataException("Units from XML do not match current pipe roughness units.");
Transaction loadFamilies = new Transaction(m_document, "Load Families");
loadFamilies.Start();
IEnumerable<XElement> families = xDoc.Root.Elements("Family");
FindFolderUtility findFolderUtility = new FindFolderUtility(m_document.Application);
foreach (XElement xfamily in families)
try
{
ParseFamilyFromXml(xfamily, findFolderUtility); //Load families.
}
catch (Exception)
{
loadFamilies.RollBack();
throw;
}
loadFamilies.Commit();
Transaction addPipeTypes = new Transaction(m_document, "Add PipeTypes");
addPipeTypes.Start();
IEnumerable<XElement> pipeTypes = xDoc.Root.Elements("PipeType");
foreach (XElement xpipeType in pipeTypes)
try
{
ParsePipeTypeFromXml(xpipeType); //Define new pipe types.
}
catch (Exception)
{
addPipeTypes.RollBack();
throw;
}
addPipeTypes.Commit();
Transaction addPipeSchedules = new Transaction(m_document, "Add Pipe Schedule Types");
addPipeSchedules.Start();
IEnumerable<XElement> pipeScheduleTypes = xDoc.Root.Elements("PipeScheduleType");
foreach (XElement xpipeScheduleType in pipeScheduleTypes)
try
{
ParsePipeScheduleTypeFromXml(xpipeScheduleType); //Define new pipe schedule types.
}
catch (Exception)
{
addPipeSchedules.RollBack();
throw;
}
addPipeSchedules.Commit();
//The code above have added some new pipe types, schedules, or fittings, so update the lists of all of these.
UpdatePipeTypesList();
UpdatePipeTypeSchedulesList();
UpdateFittingsList();
Transaction addPipeSegments = new Transaction(m_document, "Add Pipe Segments");
addPipeSchedules.Start();
IEnumerable<XElement> pipeSegments = xDoc.Root.Elements("PipeSegment"); //Define new segments.
foreach (XElement xpipeSegment in pipeSegments)
try
{
ParsePipeSegmentFromXML(xpipeSegment);
}
catch (Exception)
{
addPipeSchedules.RollBack();
throw;
}
addPipeSchedules.Commit();
UpdateSegmentsList(); //More segments may have been created, so update the segment list.
//Now that all of the various types that routing preferences use have been created or loaded, add all the routing preferences.
Transaction addRoutingPreferences = new Transaction(m_document, "Add Routing Preferences");
addRoutingPreferences.Start();
IEnumerable<XElement> routingPreferenceManagers = xDoc.Root.Elements("RoutingPreferenceManager");
foreach (XElement xroutingPreferenceManager in routingPreferenceManagers)
try
{
ParseRoutingPreferenceManagerFromXML(xroutingPreferenceManager);
}
catch (Exception)
{
addRoutingPreferences.RollBack();
throw;
}
addRoutingPreferences.Commit();
}
/// <summary>
/// Reads pipe fitting family, segment, size, schedule, and routing preference data from a document and summarizes it in Xml.
/// </summary>
/// <returns>An XDocument containing an Xml summary of routing preference information</returns>
public XDocument CreateXmlFromAllPipingPolicies(ref bool pathsNotFound)
{
//To export the full path name of all .rfa family files, use the FindFolderUtility class.
FindFolderUtility findFolderUtility = new FindFolderUtility(m_document.Application);
XDocument routingPreferenceBuilderDoc = new XDocument();
XElement xroot = new XElement(XName.Get("RoutingPreferenceBuilder"));
FormatOptions formatOptionPipeSize = m_document.GetUnits().GetFormatOptions(SpecTypeId.PipeSize);
string unitStringPipeSize = formatOptionPipeSize.GetUnitTypeId().TypeId;
xroot.Add(new XAttribute(XName.Get("pipeSizeUnits"), unitStringPipeSize));
FormatOptions formatOptionRoughness = m_document.GetUnits().GetFormatOptions(SpecTypeId.PipingRoughness);
string unitStringRoughness = formatOptionRoughness.GetUnitTypeId().TypeId;
xroot.Add(new XAttribute(XName.Get("pipeRoughnessUnits"), unitStringRoughness));
foreach (FamilySymbol familySymbol in this.m_fittings)
{
xroot.Add(CreateXmlFromFamily(familySymbol, findFolderUtility, ref pathsNotFound));
}
foreach (PipeType pipeType in m_pipeTypes)
{
xroot.Add(CreateXmlFromPipeType(pipeType));
}
foreach (PipeScheduleType pipeScheduleType in m_pipeSchedules)
{
xroot.Add(CreateXmlFromPipeScheduleType(pipeScheduleType));
}
foreach (PipeSegment pipeSegment in m_segments)
{
xroot.Add(CreateXmlFromPipeSegment(pipeSegment));
}
foreach (PipeType pipeType in m_pipeTypes)
{
xroot.Add(CreateXmlFromRoutingPreferenceManager(pipeType.RoutingPreferenceManager));
}
routingPreferenceBuilderDoc.Add(xroot);
return routingPreferenceBuilderDoc;
}
#endregion
#region XML parsing and generation
/// <summary>
/// Load a family from xml
/// </summary>
/// <param name="familyXElement"></param>
/// <param name="findFolderUtility"></param>
private void ParseFamilyFromXml(XElement familyXElement, FindFolderUtility findFolderUtility)
{
XAttribute xafilename = familyXElement.Attribute(XName.Get("filename"));
string familyPath = xafilename.Value;
if (!System.IO.File.Exists(familyPath))
{
string filename = System.IO.Path.GetFileName(familyPath);
familyPath = findFolderUtility.FindFileFolder(filename);
if (!System.IO.File.Exists(familyPath))
throw new RoutingPreferenceDataException("Cannot find family file: " + xafilename.Value);
}
if (string.Compare(System.IO.Path.GetExtension(familyPath), ".rfa", true) != 0)
throw new RoutingPreferenceDataException(familyPath + " is not a family file.");
try
{
if (!m_document.LoadFamily(familyPath))
return; //returns false if already loaded.
}
catch (System.Exception ex)
{
throw new RoutingPreferenceDataException("Cannot load family: " + xafilename.Value + ": " + ex.ToString());
}
}
/// <summary>
/// Create xml from a family
/// </summary>
/// <param name="pipeFitting"></param>
/// <param name="findFolderUtility"></param>
/// <param name="pathNotFound"></param>
/// <returns></returns>
private static XElement CreateXmlFromFamily(FamilySymbol pipeFitting, FindFolderUtility findFolderUtility, ref bool pathNotFound)
{
//Try to find the path of the .rfa file.
string path = findFolderUtility.FindFileFolder(pipeFitting.Family.Name + ".rfa");
string pathToWrite;
if (path == "")
{
pathNotFound = true;
pathToWrite = pipeFitting.Family.Name + ".rfa";
}
else
pathToWrite = path;
XElement xFamilySymbol = new XElement(XName.Get("Family"));
xFamilySymbol.Add(new XAttribute(XName.Get("filename"), pathToWrite));
return xFamilySymbol;
}
/// <summary>
/// Greate a PipeType from xml
/// </summary>
/// <param name="pipetypeXElement"></param>
private void ParsePipeTypeFromXml(XElement pipetypeXElement)
{
XAttribute xaName = pipetypeXElement.Attribute(XName.Get("name"));
ElementId pipeTypeId = GetPipeTypeByName(xaName.Value);
if (pipeTypeId == ElementId.InvalidElementId) //If the pipe type does not exist, create it.
{
PipeType newPipeType = m_pipeTypes.First().Duplicate(xaName.Value) as PipeType;
ClearRoutingPreferenceRules(newPipeType);
}
}
/// <summary>
/// Clear all routing preferences in a PipeType
/// </summary>
/// <param name="pipeType"></param>
private static void ClearRoutingPreferenceRules(PipeType pipeType)
{
foreach ( RoutingPreferenceRuleGroupType group in System.Enum.GetValues(typeof(RoutingPreferenceRuleGroupType)))
{
int ruleCount = pipeType.RoutingPreferenceManager.GetNumberOfRules(group);
for (int index = 0; index != ruleCount; ++index)
{
pipeType.RoutingPreferenceManager.RemoveRule(group, 0);
}
}
}
/// <summary>
/// Create Xml from a PipeType
/// </summary>
/// <param name="pipeType"></param>
/// <returns></returns>
private static XElement CreateXmlFromPipeType(PipeType pipeType)
{
XElement xPipeType = new XElement(XName.Get("PipeType"));
xPipeType.Add(new XAttribute(XName.Get("name"), pipeType.Name));
return xPipeType;
}
private void ParsePipeScheduleTypeFromXml(XElement pipeScheduleTypeXElement)
{
XAttribute xaName = pipeScheduleTypeXElement.Attribute(XName.Get("name"));
ElementId pipeScheduleTypeId = GetPipeScheduleTypeByName(xaName.Value);
if (pipeScheduleTypeId == ElementId.InvalidElementId) //If the pipe schedule type does not exist, create it.
m_pipeSchedules.First().Duplicate(xaName.Value);
}
/// <summary>
/// Create Xml from a PipeScheduleType
/// </summary>
/// <param name="pipeScheduleType"></param>
/// <returns></returns>
private static XElement CreateXmlFromPipeScheduleType(PipeScheduleType pipeScheduleType)
{
XElement xPipeSchedule = new XElement(XName.Get("PipeScheduleType"));
xPipeSchedule.Add(new XAttribute(XName.Get("name"), pipeScheduleType.Name));
return xPipeSchedule;
}
/// <summary>
/// Create a PipeSegment from XML
/// </summary>
/// <param name="segmentXElement"></param>
private void ParsePipeSegmentFromXML(XElement segmentXElement)
{
XAttribute xaMaterial = segmentXElement.Attribute(XName.Get("materialName"));
XAttribute xaSchedule = segmentXElement.Attribute(XName.Get("pipeScheduleTypeName"));
XAttribute xaRoughness = segmentXElement.Attribute(XName.Get("roughness"));
ElementId materialId = GetMaterialByName(xaMaterial.Value); //There is nothing in the xml schema for creating new materials -- any material specified must already exist in the document.
if (materialId == ElementId.InvalidElementId)
{
throw new RoutingPreferenceDataException("Cannot find Material: " + xaMaterial.Value + " in: " + segmentXElement.ToString());
}
ElementId scheduleId = GetPipeScheduleTypeByName(xaSchedule.Value);
double roughness;
bool r1 = double.TryParse(xaRoughness.Value, out roughness);
if (!r1)
throw new RoutingPreferenceDataException("Invalid roughness value: " + xaRoughness.Value + " in: " + segmentXElement.ToString());
if (roughness <= 0)
throw new RoutingPreferenceDataException("Invalid roughness value: " + xaRoughness.Value + " in: " + segmentXElement.ToString());
if (scheduleId == ElementId.InvalidElementId)
{
throw new RoutingPreferenceDataException("Cannot find Schedule: " + xaSchedule.Value + " in: " + segmentXElement.ToString()); //we will not create new schedules.
}
ElementId existingPipeSegmentId = GetSegmentByIds(materialId, scheduleId);
if (existingPipeSegmentId != ElementId.InvalidElementId)
return; //Segment found, no need to create.
ICollection<MEPSize> sizes = new List<MEPSize>();
foreach (XNode sizeNode in segmentXElement.Nodes())
{
if (sizeNode is XElement)
{
MEPSize newSize = ParseMEPSizeFromXml(sizeNode as XElement, m_document);
sizes.Add(newSize);
}
}
PipeSegment pipeSegment = PipeSegment.Create(m_document, materialId, scheduleId, sizes);
pipeSegment.Roughness = Convert.ConvertValueToFeet(roughness, m_document);
return;
}
/// <summary>
/// Create Xml from a PipeSegment
/// </summary>
/// <param name="pipeSegment"></param>
/// <returns></returns>
private XElement CreateXmlFromPipeSegment(PipeSegment pipeSegment)
{
XElement xPipeSegment = new XElement(XName.Get("PipeSegment"));
string segmentName = pipeSegment.Name;
xPipeSegment.Add(new XAttribute(XName.Get("pipeScheduleTypeName"), GetPipeScheduleTypeNamebyId(pipeSegment.ScheduleTypeId)));
xPipeSegment.Add(new XAttribute(XName.Get("materialName"), GetMaterialNameById(pipeSegment.MaterialId)));
double roughnessInDocumentUnits = Convert.ConvertValueDocumentUnits(pipeSegment.Roughness, m_document);
xPipeSegment.Add(new XAttribute(XName.Get("roughness"), roughnessInDocumentUnits.ToString("r") ));
foreach (MEPSize size in pipeSegment.GetSizes())
xPipeSegment.Add(CreateXmlFromMEPSize(size, m_document));
return xPipeSegment;
}
/// <summary>
/// Create an MEPSize from Xml
/// </summary>
/// <param name="sizeXElement"></param>
/// <param name="document"></param>
/// <returns></returns>
private static MEPSize ParseMEPSizeFromXml(XElement sizeXElement, Autodesk.Revit.DB.Document document)
{
XAttribute xaNominal = sizeXElement.Attribute(XName.Get("nominalDiameter"));
XAttribute xaInner = sizeXElement.Attribute(XName.Get("innerDiameter"));
XAttribute xaOuter = sizeXElement.Attribute(XName.Get("outerDiameter"));
XAttribute xaUsedInSizeLists = sizeXElement.Attribute(XName.Get("usedInSizeLists"));
XAttribute xaUsedInSizing = sizeXElement.Attribute(XName.Get("usedInSizing"));
double nominal, inner, outer;
bool usedInSizeLists, usedInSizing;
bool r1 = double.TryParse(xaNominal.Value, out nominal);
bool r2 = double.TryParse(xaInner.Value, out inner);
bool r3 = double.TryParse(xaOuter.Value, out outer);
bool r4 = bool.TryParse(xaUsedInSizeLists.Value, out usedInSizeLists);
bool r5 = bool.TryParse(xaUsedInSizing.Value, out usedInSizing);
if (!r1 || !r2 || !r3 || !r4 || !r5)
throw new RoutingPreferenceDataException("Cannot parse MEPSize attributes:" + xaNominal.Value + ", " + xaInner.Value + ", " + xaOuter.Value + ", " + xaUsedInSizeLists.Value + ", " + xaUsedInSizing.Value);
MEPSize newSize = null;
try
{
newSize = new MEPSize(Convert.ConvertValueToFeet(nominal, document), Convert.ConvertValueToFeet(inner, document), Convert.ConvertValueToFeet(outer, document), usedInSizeLists, usedInSizing);
}
catch (Exception)
{
throw new RoutingPreferenceDataException("Invalid MEPSize values: " + nominal.ToString() + ", " + inner.ToString() + ", " + outer.ToString());
}
return newSize;
}
/// <summary>
/// Create Xml from an MEPSize
/// </summary>
/// <param name="size"></param>
/// <param name="document"></param>
/// <returns></returns>
private static XElement CreateXmlFromMEPSize(MEPSize size, Autodesk.Revit.DB.Document document)
{
XElement xMEPSize = new XElement(XName.Get("MEPSize"));
xMEPSize.Add(new XAttribute(XName.Get("innerDiameter"), (Convert.ConvertValueDocumentUnits(size.InnerDiameter, document) ).ToString()));
xMEPSize.Add(new XAttribute(XName.Get("nominalDiameter"), (Convert.ConvertValueDocumentUnits(size.NominalDiameter, document) ).ToString()));
xMEPSize.Add(new XAttribute(XName.Get("outerDiameter"), (Convert.ConvertValueDocumentUnits(size.OuterDiameter, document) ).ToString()));
xMEPSize.Add(new XAttribute(XName.Get("usedInSizeLists"), size.UsedInSizeLists));
xMEPSize.Add(new XAttribute(XName.Get("usedInSizing"), size.UsedInSizing));
return xMEPSize;
}
/// <summary>
/// Populate a routing preference manager from Xml
/// </summary>
/// <param name="routingPreferenceManagerXElement"></param>
private void ParseRoutingPreferenceManagerFromXML(XElement routingPreferenceManagerXElement)
{
XAttribute xaPipeTypeName = routingPreferenceManagerXElement.Attribute(XName.Get("pipeTypeName"));
XAttribute xaPreferredJunctionType = routingPreferenceManagerXElement.Attribute(XName.Get("preferredJunctionType"));
PreferredJunctionType preferredJunctionType;
bool r1 = Enum.TryParse<PreferredJunctionType>(xaPreferredJunctionType.Value, out preferredJunctionType);
if (!r1)
throw new RoutingPreferenceDataException("Invalid Preferred Junction Type in: " + routingPreferenceManagerXElement.ToString());
ElementId pipeTypeId = GetPipeTypeByName(xaPipeTypeName.Value);
if (pipeTypeId == ElementId.InvalidElementId)
throw new RoutingPreferenceDataException("Could not find pipe type element in: " + routingPreferenceManagerXElement.ToString());
PipeType pipeType = m_document.GetElement(pipeTypeId) as PipeType;
RoutingPreferenceManager routingPreferenceManager = pipeType.RoutingPreferenceManager;
routingPreferenceManager.PreferredJunctionType = preferredJunctionType;
foreach (XNode xRule in routingPreferenceManagerXElement.Nodes())
{
if (xRule is XElement)
{
RoutingPreferenceRuleGroupType groupType;
RoutingPreferenceRule rule = ParseRoutingPreferenceRuleFromXML(xRule as XElement, out groupType);
routingPreferenceManager.AddRule(groupType, rule);
}
}
}
/// <summary>
/// Create Xml from a RoutingPreferenceManager
/// </summary>
/// <param name="routingPreferenceManager"></param>
/// <returns></returns>
private XElement CreateXmlFromRoutingPreferenceManager(RoutingPreferenceManager routingPreferenceManager)
{
XElement xRoutingPreferenceManager = new XElement(XName.Get("RoutingPreferenceManager"));
xRoutingPreferenceManager.Add(new XAttribute(XName.Get("pipeTypeName"), GetPipeTypeNameById(routingPreferenceManager.OwnerId)));
xRoutingPreferenceManager.Add(new XAttribute(XName.Get("preferredJunctionType"), routingPreferenceManager.PreferredJunctionType.ToString()));
for (int indexCrosses = 0; indexCrosses != routingPreferenceManager.GetNumberOfRules(RoutingPreferenceRuleGroupType.Crosses); indexCrosses++)
{
xRoutingPreferenceManager.Add(createXmlFromRoutingPreferenceRule(routingPreferenceManager.GetRule(RoutingPreferenceRuleGroupType.Crosses, indexCrosses), RoutingPreferenceRuleGroupType.Crosses));
}
for (int indexElbows = 0; indexElbows != routingPreferenceManager.GetNumberOfRules(RoutingPreferenceRuleGroupType.Elbows); indexElbows++)
{
xRoutingPreferenceManager.Add(createXmlFromRoutingPreferenceRule(routingPreferenceManager.GetRule(RoutingPreferenceRuleGroupType.Elbows, indexElbows), RoutingPreferenceRuleGroupType.Elbows));
}
for (int indexSegments = 0; indexSegments != routingPreferenceManager.GetNumberOfRules(RoutingPreferenceRuleGroupType.Segments); indexSegments++)
{
xRoutingPreferenceManager.Add(createXmlFromRoutingPreferenceRule(routingPreferenceManager.GetRule(RoutingPreferenceRuleGroupType.Segments, indexSegments), RoutingPreferenceRuleGroupType.Segments));
}
for (int indexJunctions = 0; indexJunctions != routingPreferenceManager.GetNumberOfRules(RoutingPreferenceRuleGroupType.Junctions); indexJunctions++)
{
xRoutingPreferenceManager.Add(createXmlFromRoutingPreferenceRule(routingPreferenceManager.GetRule(RoutingPreferenceRuleGroupType.Junctions, indexJunctions), RoutingPreferenceRuleGroupType.Junctions));
}
for (int indexTransitions = 0; indexTransitions != routingPreferenceManager.GetNumberOfRules(RoutingPreferenceRuleGroupType.Transitions); indexTransitions++)
{
xRoutingPreferenceManager.Add(createXmlFromRoutingPreferenceRule(routingPreferenceManager.GetRule(RoutingPreferenceRuleGroupType.Transitions, indexTransitions), RoutingPreferenceRuleGroupType.Transitions));
}
for (int indexUnions = 0; indexUnions != routingPreferenceManager.GetNumberOfRules(RoutingPreferenceRuleGroupType.Unions); indexUnions++)
{
xRoutingPreferenceManager.Add(createXmlFromRoutingPreferenceRule(routingPreferenceManager.GetRule(RoutingPreferenceRuleGroupType.Unions, indexUnions), RoutingPreferenceRuleGroupType.Unions));
}
for (int indexMechanicalJoints = 0; indexMechanicalJoints != routingPreferenceManager.GetNumberOfRules(RoutingPreferenceRuleGroupType.MechanicalJoints); indexMechanicalJoints++)
{
xRoutingPreferenceManager.Add(createXmlFromRoutingPreferenceRule(routingPreferenceManager.GetRule(RoutingPreferenceRuleGroupType.MechanicalJoints, indexMechanicalJoints), RoutingPreferenceRuleGroupType.MechanicalJoints));
}
return xRoutingPreferenceManager;
}
/// <summary>
/// Create a RoutingPreferenceRule from Xml
/// </summary>
/// <param name="ruleXElement"></param>
/// <param name="groupType"></param>
/// <returns></returns>
private RoutingPreferenceRule ParseRoutingPreferenceRuleFromXML(XElement ruleXElement, out RoutingPreferenceRuleGroupType groupType)
{
XAttribute xaDescription = null;
XAttribute xaPartName = null;
XAttribute xaMinSize = null;
XAttribute xaMaxSize = null;
XAttribute xaGroup = null;
xaDescription = ruleXElement.Attribute(XName.Get("description"));
xaPartName = ruleXElement.Attribute(XName.Get("partName"));
xaGroup = ruleXElement.Attribute(XName.Get("ruleGroup"));
xaMinSize = ruleXElement.Attribute(XName.Get("minimumSize"));
ElementId partId;
bool r3 = Enum.TryParse<RoutingPreferenceRuleGroupType>(xaGroup.Value, out groupType);
if (!r3)
throw new RoutingPreferenceDataException("Could not parse rule group type: " + xaGroup.Value);
string description = xaDescription.Value;
if (groupType == RoutingPreferenceRuleGroupType.Segments)
partId = GetSegmentByName(xaPartName.Value);
else
partId = GetFittingByName(xaPartName.Value);
if (partId == ElementId.InvalidElementId)
throw new RoutingPreferenceDataException("Could not find MEP Part: " + xaPartName.Value + ". Is this the correct family name, and is the correct family loaded?");
RoutingPreferenceRule rule = new RoutingPreferenceRule(partId, description);
PrimarySizeCriterion sizeCriterion;
if (string.Compare(xaMinSize.Value, "All", true) == 0) //If "All" or "None" are specified, set min and max values to documented "Max" values.
{
sizeCriterion = PrimarySizeCriterion.All();
}
else if (string.Compare(xaMinSize.Value, "None", true) == 0)
{
sizeCriterion = PrimarySizeCriterion.None();
}
else // "maximumSize" attribute is only needed if not specifying "All" or "None."
{
try
{
xaMaxSize = ruleXElement.Attribute(XName.Get("maximumSize"));
}
catch (System.Exception)
{
throw new RoutingPreferenceDataException("Cannot get maximumSize attribute in: " + ruleXElement.ToString());
}
double min, max;
bool r1 = double.TryParse(xaMinSize.Value, out min);
bool r2 = double.TryParse(xaMaxSize.Value, out max);
if (!r1 || !r2)
throw new RoutingPreferenceDataException("Could not parse size values: " + xaMinSize.Value + ", " + xaMaxSize.Value);
if (min > max)
throw new RoutingPreferenceDataException("Invalid size range.");
min = Convert.ConvertValueToFeet(min, m_document);
max = Convert.ConvertValueToFeet(max, m_document);
sizeCriterion = new PrimarySizeCriterion(min, max);
}
rule.AddCriterion(sizeCriterion);
return rule;
}
/// <summary>
/// Create Xml from a RoutingPreferenceRule
/// </summary>
/// <param name="rule"></param>
/// <param name="groupType"></param>
/// <returns></returns>
private XElement createXmlFromRoutingPreferenceRule(RoutingPreferenceRule rule, RoutingPreferenceRuleGroupType groupType)
{
XElement xRoutingPreferenceRule = new XElement(XName.Get("RoutingPreferenceRule"));
xRoutingPreferenceRule.Add(new XAttribute(XName.Get("description"), rule.Description));
xRoutingPreferenceRule.Add(new XAttribute(XName.Get("ruleGroup"), groupType.ToString()));
if (rule.NumberOfCriteria >= 1)
{
PrimarySizeCriterion psc = rule.GetCriterion(0) as PrimarySizeCriterion;
if (psc.IsEqual(PrimarySizeCriterion.All()))
{
xRoutingPreferenceRule.Add(new XAttribute(XName.Get("minimumSize"), "All"));
}
else
if (psc.IsEqual(PrimarySizeCriterion.None()))
{
xRoutingPreferenceRule.Add(new XAttribute(XName.Get("minimumSize"), "None"));
}
else //Only specify "maximumSize" if not specifying "All" or "None" for minimum size, just like in the UI.
{
xRoutingPreferenceRule.Add(new XAttribute(XName.Get("minimumSize"), (Convert.ConvertValueDocumentUnits(psc.MinimumSize, m_document)).ToString()));
xRoutingPreferenceRule.Add(new XAttribute(XName.Get("maximumSize"), (Convert.ConvertValueDocumentUnits(psc.MaximumSize, m_document)).ToString()));
}
}
else
{
xRoutingPreferenceRule.Add(new XAttribute(XName.Get("minimumSize"), "All"));
}
if (groupType == RoutingPreferenceRuleGroupType.Segments)
{
xRoutingPreferenceRule.Add(new XAttribute(XName.Get("partName"), GetSegmentNameById(rule.MEPPartId)));
}
else
xRoutingPreferenceRule.Add(new XAttribute(XName.Get("partName"), GetFittingNameById(rule.MEPPartId)));
return xRoutingPreferenceRule;
}
#endregion
#region Accessors and finders
/// <summary>
/// Get PipeScheduleTypeName by Id
/// </summary>
/// <param name="pipescheduleTypeId"></param>
/// <returns></returns>
private string GetPipeScheduleTypeNamebyId(ElementId pipescheduleTypeId)
{
return m_document.GetElement(pipescheduleTypeId).Name;
}
/// <summary>
/// Get material name by Id
/// </summary>
/// <param name="materialId"></param>
/// <returns></returns>
private string GetMaterialNameById(ElementId materialId)
{
return m_document.GetElement(materialId).Name;
}
/// <summary>
/// Get segment name by Id
/// </summary>
/// <param name="segmentId"></param>
/// <returns></returns>
private string GetSegmentNameById(ElementId segmentId)
{
return m_document.GetElement(segmentId).Name;
}
/// <summary>
/// Get fitting name by Id
/// </summary>
/// <param name="fittingId"></param>
/// <returns></returns>
private string GetFittingNameById(ElementId fittingId)
{
FamilySymbol fs = m_document.GetElement(fittingId) as FamilySymbol;
return fs.Family.Name + " " + fs.Name;
}
/// <summary>
/// Get segment by Ids
/// </summary>
/// <param name="materialId"></param>
/// <param name="pipeScheduleTypeId"></param>
/// <returns></returns>
private ElementId GetSegmentByIds(ElementId materialId, ElementId pipeScheduleTypeId)
{
if ((materialId == ElementId.InvalidElementId) || (pipeScheduleTypeId == ElementId.InvalidElementId))
return ElementId.InvalidElementId;
Element material = m_document.GetElement(materialId);
Element pipeScheduleType = m_document.GetElement(pipeScheduleTypeId);
string segmentName = material.Name + " - " + pipeScheduleType.Name;
return GetSegmentByName(segmentName);
}
/// <summary>
/// Get pipe type name by Id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
private string GetPipeTypeNameById(ElementId id)
{
return m_document.GetElement(id).Name;
}
/// <summary>
/// Get segment by name
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
private ElementId GetSegmentByName(string name)
{
foreach (Segment segment in m_segments)
if (segment.Name == name)
return segment.Id;
return ElementId.InvalidElementId;
}
/// <summary>
/// Get fitting by name
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
private ElementId GetFittingByName(string name)
{
foreach (FamilySymbol fitting in m_fittings)
if ((fitting.Family.Name + " " + fitting.Name) == name)
return fitting.Id;
return ElementId.InvalidElementId;
}
/// <summary>
/// Get material by name
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
private ElementId GetMaterialByName(string name)
{
foreach (Material material in m_materials)
if (material.Name == name)
return material.Id;
return ElementId.InvalidElementId;
}
/// <summary>
/// Get pipe schedule type by name
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
private ElementId GetPipeScheduleTypeByName(string name)
{
foreach (PipeScheduleType pipeScheduleType in m_pipeSchedules)
if (pipeScheduleType.Name == name)
return pipeScheduleType.Id;
return ElementId.InvalidElementId;
}
/// <summary>
/// Get pipe type by name
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
private ElementId GetPipeTypeByName(string name)
{
foreach (PipeType pipeType in m_pipeTypes)
if (pipeType.Name == name)
return pipeType.Id;
return ElementId.InvalidElementId;
}
/// <summary>
/// Update fittings list
/// </summary>
private void UpdateFittingsList()
{
m_fittings = GetAllFittings(m_document);
}
/// <summary>
/// Update segments list
/// </summary>
private void UpdateSegmentsList()
{
m_segments = GetAllPipeSegments(m_document);
}
/// <summary>
/// Update pipe types list
/// </summary>
private void UpdatePipeTypesList()
{
m_pipeTypes = GetAllPipeTypes(m_document);
}
/// <summary>
/// Update pipe type schedules list
/// </summary>
private void UpdatePipeTypeSchedulesList()
{
m_pipeSchedules = GetAllPipeScheduleTypes(m_document);
}
/// <summary>
/// Update materials list
/// </summary>
private void UpdateMaterialsList()
{
m_materials = GetAllMaterials(m_document);
}
/// <summary>
/// Get all pipe segments
/// </summary>
/// <param name="document"></param>
/// <returns></returns>
public IEnumerable<PipeSegment> GetAllPipeSegments(Document document)
{
FilteredElementCollector fec = new FilteredElementCollector(document);
fec.OfClass(typeof(PipeSegment));
IEnumerable<PipeSegment> segments = fec.ToElements().Cast<PipeSegment>();
return segments;
}
/// <summary>
/// Get all fittings
/// </summary>
/// <param name="document"></param>
/// <returns></returns>
public IEnumerable<FamilySymbol> GetAllFittings(Document document)
{
FilteredElementCollector fec = new FilteredElementCollector(document);
fec.OfClass(typeof(FamilySymbol));
fec.OfCategory(BuiltInCategory.OST_PipeFitting);
IEnumerable<FamilySymbol> fittings = fec.ToElements().Cast<FamilySymbol>();
return fittings;
}
/// <summary>
/// Get all materials
/// </summary>
/// <param name="document"></param>
/// <returns></returns>
private IEnumerable<Material> GetAllMaterials(Document document)
{
FilteredElementCollector fec = new FilteredElementCollector(document);
fec.OfClass(typeof(Material));
IEnumerable<Material> materials = fec.ToElements().Cast<Material>();
return materials;
}
/// <summary>
/// Get all pipe schedule types
/// </summary>
/// <param name="document"></param>
/// <returns></returns>
public IEnumerable<PipeScheduleType> GetAllPipeScheduleTypes(Document document)
{
FilteredElementCollector fec = new FilteredElementCollector(document);
fec.OfClass(typeof(Autodesk.Revit.DB.Plumbing.PipeScheduleType));
IEnumerable<Autodesk.Revit.DB.Plumbing.PipeScheduleType> pipeScheduleTypes = fec.ToElements().Cast<Autodesk.Revit.DB.Plumbing.PipeScheduleType>();
return pipeScheduleTypes;
}
/// <summary>
/// Get all pipe types
/// </summary>
/// <param name="document"></param>
/// <returns></returns>
public IEnumerable<PipeType> GetAllPipeTypes(Document document)
{
ElementClassFilter ecf = new ElementClassFilter(typeof(PipeType));
FilteredElementCollector fec = new FilteredElementCollector(document);
fec.WherePasses(ecf);
IEnumerable<PipeType> pipeTypes = fec.ToElements().Cast<PipeType>();
return pipeTypes;
}
#endregion
}
}