copied Revit 2024 SDK

This commit is contained in:
Jeremy Tammik
2023-04-26 14:47:47 +02:00
parent 2ca39e38fd
commit 4d69f3eea5
425 changed files with 344414 additions and 2296 deletions
@@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Analysis;
namespace Revit.SDK.Samples.NetworkPressureLossReport
{
public class AVFViewer
{
private bool? m_isItemzied;
private View m_view;
private SpatialFieldManager m_sfm;
private int m_schemaIdx;
private XYZ m_maxCorner;
const string DisplayStyleName = "NetworkFlowDisplayStyle";
const String SchemaName = "NetworkFlowSchema";
public AVFViewer(View view, bool? isItemized)
{
m_view = view;
m_isItemzied = isItemized;
m_sfm = SpatialFieldManager.GetSpatialFieldManager(view);
if (m_sfm == null)
{
m_sfm = SpatialFieldManager.CreateSpatialFieldManager(view, 1);
}
m_sfm.Clear();
m_maxCorner = new XYZ(-Double.MaxValue, -Double.MaxValue, -Double.MaxValue);
}
public Document Document
{
get { return m_view.Document; }
}
public double Scale
{
get { return m_view.Scale; }
}
public bool IsItemized
{
get { return m_isItemzied == true; }
}
public void InitAVF()
{
m_view.EnableTemporaryViewPropertiesMode(m_view.Id);
m_view.TemporaryViewModes.RemoveCustomization();
m_view.TemporaryViewModes.CustomTitle = "Network Flow Analysis";
AnalysisResultSchema resultSchema = new AnalysisResultSchema(SchemaName, "");
m_sfm.SetMeasurementNames(new List<string>() { SchemaName });
m_schemaIdx = m_sfm.RegisterResult(resultSchema);
}
public int AddData(List<XYZ> points, List<VectorAtPoint> valList)
{
int idx = m_sfm.AddSpatialFieldPrimitive();
FieldDomainPointsByXYZ pnts = new FieldDomainPointsByXYZ(points);
FieldValues vals = new FieldValues(valList);
m_sfm.UpdateSpatialFieldPrimitive(idx, pnts, vals, m_schemaIdx);
return idx;
}
public void AddCorner(double maxX, double maxY, double maxZ)
{
double xx = Math.Max(m_maxCorner.X, maxX);
double yy = Math.Max(m_maxCorner.Y, maxY);
double zz = Math.Max(m_maxCorner.Z, maxZ);
m_maxCorner = new XYZ(xx, yy, zz);
}
private AnalysisDisplayStyle getStyleByName(string name)
{
FilteredElementCollector collector = new FilteredElementCollector(Document);
ICollection<Element> collection = collector.OfClass(typeof(AnalysisDisplayStyle)).ToElements();
var displayStyle = from element in collection
where element.Name == name
select element;
AnalysisDisplayStyle analysisDisplayStyle = null;
if (displayStyle.Count() != 0)
analysisDisplayStyle = displayStyle.Cast<AnalysisDisplayStyle>().ElementAt<AnalysisDisplayStyle>(0);
return analysisDisplayStyle;
}
public void FinishDisplayStyle()
{
// set the legend to the top right corner so it is close to the AVF display
m_sfm.LegendPosition = m_maxCorner;
AnalysisDisplayStyle analysisDisplayStyle = getStyleByName(DisplayStyleName);
// If display style does not already exist in the document, create it
AnalysisDisplayColorSettings colorSettings = new AnalysisDisplayColorSettings();
if (analysisDisplayStyle == null)
{
colorSettings.MaxColor = new Color(255, 0, 0);
colorSettings.MinColor = new Color(0, 255, 0);
AnalysisDisplayVectorSettings vectorSettings = new AnalysisDisplayVectorSettings();
vectorSettings.VectorOrientation = AnalysisDisplayStyleVectorOrientation.Linear;
vectorSettings.ArrowheadScale = AnalysisDisplayStyleVectorArrowheadScale.NoScaling;
vectorSettings.ArrowLineWeight = 4;
vectorSettings.VectorTextType = AnalysisDisplayStyleVectorTextType.ShowNone;
AnalysisDisplayLegendSettings legendSettings = new AnalysisDisplayLegendSettings();
legendSettings.ShowLegend = false;
analysisDisplayStyle = AnalysisDisplayStyle.CreateAnalysisDisplayStyle(Document, DisplayStyleName, vectorSettings, colorSettings, legendSettings);
}
m_view.AnalysisDisplayStyleId = analysisDisplayStyle.Id;
m_view.TemporaryViewModes.CustomColor = analysisDisplayStyle.GetColorSettings().MaxColor;
// Transparent everything so we can see the flow vector.
ElementId rasterId = new ElementId(BuiltInCategory.OST_RasterImages);
foreach (Category c in m_view.Document.Settings.Categories)
{
if (!m_view.GetCategoryHidden(c.Id))
{
if (c.Id != rasterId && m_view.IsCategoryOverridable(c.Id))
{
OverrideGraphicSettings ogs = m_view.GetCategoryOverrides(c.Id);
if (!ogs.Halftone)
{
m_view.SetCategoryOverrides(c.Id, ogs.SetHalftone(true));
m_view.SetCategoryOverrides(c.Id, ogs.SetSurfaceTransparency(50));
}
}
}
}
}
}
}
@@ -0,0 +1,190 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Autodesk.Revit.DB;
namespace Revit.SDK.Samples.NetworkPressureLossReport
{
public class CSVExporter : IDisposable
{
private Document m_doc;
private bool? m_isItemized;
private ConnectorDomainType m_connType;
private StreamWriter m_streamWriter;
public StreamWriter Writer
{
get { return m_streamWriter; }
}
public bool? IsItemized
{
get { return m_isItemized; }
}
public Document Document
{
set { m_doc = value; }
}
public ConnectorDomainType DomainType
{
set { m_connType = value; }
}
public CSVExporter(string csvFilePath, bool? isItemized)
{
if(!string.IsNullOrEmpty(csvFilePath))
{
m_streamWriter = new StreamWriter(csvFilePath, false, System.Text.Encoding.Unicode);
}
m_isItemized = isItemized;
}
~CSVExporter() => Dispose(false);
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if(m_streamWriter != null)
{
// Dispose/Close the stream writer.
m_streamWriter.Dispose();
m_streamWriter = null;
}
}
private string SafeGetUnitLabel(FormatOptions opt)
{
string msg = null;
string unitLabel = null;
try
{
unitLabel = LabelUtils.GetLabelForSymbol(opt.GetSymbolTypeId());
}
catch (Autodesk.Revit.Exceptions.ArgumentException ex)
{
// The unit symbol is None.
msg = ex.Message;
}
if(string.IsNullOrEmpty(unitLabel))
{
try
{
unitLabel = LabelUtils.GetLabelForUnit(opt.GetUnitTypeId());
}
catch (Autodesk.Revit.Exceptions.ArgumentException ex)
{
// The unit symbol is None.
msg = ex.Message;
}
}
return unitLabel;
}
private ForgeTypeId GetFlowTypeId()
{
ForgeTypeId typeId = null;
if (m_connType == ConnectorDomainType.Piping)
typeId = SpecTypeId.Flow;
else if (m_connType == ConnectorDomainType.Hvac)
typeId = SpecTypeId.AirFlow;
return typeId;
}
public double ConvertFromInternalFlow(double flow)
{
FormatOptions formatOption = m_doc.GetUnits().GetFormatOptions(GetFlowTypeId());
return UnitUtils.ConvertFromInternalUnits(flow, formatOption.GetUnitTypeId());
}
public string GetFlowUnitSymbol()
{
FormatOptions formatOption = m_doc.GetUnits().GetFormatOptions(GetFlowTypeId());
return SafeGetUnitLabel(formatOption);
}
private ForgeTypeId GetSizeTypeId()
{
ForgeTypeId typeId = null;
if (m_connType == ConnectorDomainType.Piping)
typeId = SpecTypeId.PipeSize;
else if (m_connType == ConnectorDomainType.Hvac)
typeId = SpecTypeId.DuctSize;
return typeId;
}
public double ConvertFromInternalSize(double value)
{
FormatOptions formatOption = m_doc.GetUnits().GetFormatOptions(GetSizeTypeId());
return UnitUtils.ConvertFromInternalUnits(value, formatOption.GetUnitTypeId());
}
public string GetSizeUnitSymbol()
{
FormatOptions formatOption = m_doc.GetUnits().GetFormatOptions(GetSizeTypeId());
return SafeGetUnitLabel(formatOption);
}
private ForgeTypeId GetVelocityTypeId()
{
ForgeTypeId typeId = null;
if (m_connType == ConnectorDomainType.Piping)
typeId = SpecTypeId.PipingVelocity;
else if (m_connType == ConnectorDomainType.Hvac)
typeId = SpecTypeId.HvacVelocity;
return typeId;
}
public double ConvertFromInternalVelocity(double value)
{
FormatOptions formatOption = m_doc.GetUnits().GetFormatOptions(GetVelocityTypeId());
return UnitUtils.ConvertFromInternalUnits(value, formatOption.GetUnitTypeId());
}
public string GetVelocityUnitSymbol()
{
FormatOptions formatOption = m_doc.GetUnits().GetFormatOptions(GetVelocityTypeId());
return SafeGetUnitLabel(formatOption);
}
private ForgeTypeId GetPressureTypeId()
{
ForgeTypeId typeId = null;
if (m_connType == ConnectorDomainType.Piping)
typeId = SpecTypeId.PipingPressure;
else if (m_connType == ConnectorDomainType.Hvac)
typeId = SpecTypeId.HvacPressure;
return typeId;
}
public double ConvertFromInternalPressure(double value)
{
FormatOptions formatOption = m_doc.GetUnits().GetFormatOptions(GetPressureTypeId());
return UnitUtils.ConvertFromInternalUnits(value, formatOption.GetUnitTypeId());
}
public string GetPressureUnitSymbol()
{
FormatOptions formatOption = m_doc.GetUnits().GetFormatOptions(GetPressureTypeId());
return SafeGetUnitLabel(formatOption);
}
private ForgeTypeId GetFrictionTypeId()
{
ForgeTypeId typeId = null;
if (m_connType == ConnectorDomainType.Piping)
typeId = SpecTypeId.PipingFriction;
else if (m_connType == ConnectorDomainType.Hvac)
typeId = SpecTypeId.HvacFriction;
return typeId;
}
public double ConvertFromInternalFriction(double value)
{
FormatOptions formatOption = m_doc.GetUnits().GetFormatOptions(GetFrictionTypeId());
return UnitUtils.ConvertFromInternalUnits(value, formatOption.GetUnitTypeId());
}
public string GetFrictionUnitSymbol()
{
FormatOptions formatOption = m_doc.GetUnits().GetFormatOptions(GetFrictionTypeId());
return SafeGetUnitLabel(formatOption);
}
public double ConvertFromInternalLength(double value)
{
FormatOptions formatOption = m_doc.GetUnits().GetFormatOptions(SpecTypeId.Length);
return UnitUtils.ConvertFromInternalUnits(value, formatOption.GetUnitTypeId());
}
public string GetLengthUnitSymbol()
{
FormatOptions formatOption = m_doc.GetUnits().GetFormatOptions(SpecTypeId.Length);
return SafeGetUnitLabel(formatOption);
}
}
}
@@ -0,0 +1,52 @@
//
// (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.Collections.Generic;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
namespace Revit.SDK.Samples.NetworkPressureLossReport
{
/// <summary>
/// Demonstrate how to find all networks available in the active document.
/// </summary>
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
[Autodesk.Revit.Attributes.Journaling(Autodesk.Revit.Attributes.JournalingMode.NoCommandData)]
public class Command : IExternalCommand
{
#region IExternalCommand Members
public Autodesk.Revit.UI.Result Execute(ExternalCommandData commandData, ref string message, Autodesk.Revit.DB.ElementSet elements)
{
// Get the application and document from external command data.
Document activeDoc = commandData.Application.ActiveUIDocument.Document;
NetworkDialog dlg = new NetworkDialog(activeDoc);
dlg.ShowDialog();
return Autodesk.Revit.UI.Result.Succeeded;
}
#endregion
}
}
@@ -0,0 +1,46 @@
<Window x:Class="Revit.SDK.Samples.NetworkPressureLossReport.NetworkDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Revit.SDK.Samples.NetworkPressureLossReport"
Title="Network Flow and Pressure Loss Report"
mc:Ignorable="d"
Height="450"
Width="600"
MinHeight="250"
MinWidth="400">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Grid.Row="0" Content="Networks:" Margin="7,5" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<ListView Grid.Column="0"
Grid.Row="1"
Margin="7,0,0,7"
SelectionMode="Multiple"
x:Name="NetworkList" >
<ListView.View>
<GridView AllowsColumnReorder="true" ColumnHeaderToolTip="Network Information">
<GridViewColumn DisplayMemberBinding="{Binding Path=Name}" Header="Name" Width="300"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=NumberOfSections}" Header="Sections" Width="60"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=FlowDisplay}" Header="Flow" Width="Auto"/>
</GridView>
</ListView.View>
</ListView>
<StackPanel Grid.Column="1" Grid.Row="1">
<CheckBox Content="Itemized" x:Name="ChxItemized" HorizontalAlignment="Left" Margin='16,10, 14,20' VerticalAlignment="Top" Height="Auto" Width="110" />
<Button Content="Export..." HorizontalAlignment="Left" Margin='16,0, 14,10' VerticalAlignment="Top" Height="35" Width="110" IsDefault="True" Click="Report_Click"/>
<Button Content="View" HorizontalAlignment="Left" Margin='16,12, 14,10' VerticalAlignment="Top" Height="35" Width="110" Click="View_Click"/>
<Button Content="Cancel" HorizontalAlignment="Left" Margin='16,12, 14,5' VerticalAlignment="Top" Height="35" Width="110" Click="Cancel_Click" IsCancel="True"/>
</StackPanel>
</Grid>
</Window>
@@ -0,0 +1,92 @@
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Forms;
using Autodesk.Revit.DB;
namespace Revit.SDK.Samples.NetworkPressureLossReport
{
/// <summary>
/// Interaction logic for NetworkDialog.xaml
/// </summary>
public partial class NetworkDialog : Window
{
private Document m_doc;
private IList<NetworkInfo> m_networks;
public NetworkDialog(Document doc)
{
m_doc = doc;
InitializeComponent();
refreshNetworkList();
}
private void refreshNetworkList()
{
m_networks = NetworkInfo.FindValidNetworks(m_doc);
NetworkList.ItemsSource = m_networks;
if(m_networks.Count > 0)
{
NetworkList.SelectedIndex = 0;
}
}
public void Cancel_Click(object sender, RoutedEventArgs e)
{
Close();
}
public void View_Click(object sender, RoutedEventArgs e)
{
if (NetworkList.SelectedItems.Count <= 0)
return;
using (Transaction tran = new Transaction(m_doc))
{
tran.Start("Create Analysis View");
AVFViewer viewer = new AVFViewer(m_doc.ActiveView, ChxItemized.IsChecked);
viewer.InitAVF();
foreach (var item in NetworkList.SelectedItems)
{
NetworkInfo net = item as NetworkInfo;
if (net != null)
{
net.UpdateView(viewer);
}
}
viewer.FinishDisplayStyle();
tran.Commit();
}
Close();
}
public void Report_Click(object sender, RoutedEventArgs e)
{
int idx = NetworkList.SelectedIndex;
if (idx < 0 || m_networks.Count <= 0)
return;
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.FileName = "PressureReport.csv";
saveFileDialog1.Filter = "CSV Files | *.csv";
saveFileDialog1.DefaultExt = "csv";
saveFileDialog1.FilterIndex = 2;
saveFileDialog1.RestoreDirectory = true;
if(saveFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
using (CSVExporter ex = new CSVExporter(saveFileDialog1.FileName, ChxItemized.IsChecked))
{
// Pass over the document and domain type to the exporter.
NetworkInfo netInfo = m_networks[idx];
ex.Document = netInfo.Document;
ex.DomainType = netInfo.DomainType;
netInfo.ExportCSV(ex);
}
}
}
}
}
@@ -0,0 +1,270 @@
using System;
using System.Collections.Generic;
using System.IO;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Analysis;
namespace Revit.SDK.Samples.NetworkPressureLossReport
{
public class NetworkInfo
{
private Document m_doc;
private string m_name; // A recognizable name from design system or fabrication service.
private double m_maxFlow; // The maximum flow value of any segment on the entire network.
private string m_flow;
private ConnectorDomainType m_domainType;
private IDictionary<int, SectionInfo> m_sections;
public NetworkInfo(Document doc)
{
m_doc = doc;
m_maxFlow = 0.0;
m_flow = null;
m_domainType = ConnectorDomainType.Undefined;
m_sections = new SortedDictionary<int, SectionInfo>();
}
public int NumberOfSections
{
get { return m_sections.Count; }
}
public Document Document
{
get { return m_doc; }
}
public string Name
{
get { return m_name; }
set { m_name = value; }
}
public string FlowDisplay
{
get { return m_flow; }
}
public ConnectorDomainType DomainType
{
get { return m_domainType; }
set { m_domainType = value; }
}
public static IList<NetworkInfo> FindValidNetworks(Document doc)
{
IList<NetworkInfo> validNetworks = new List<NetworkInfo>();
HashSet<MEPNetworkSegmentId> visitedSegments = new HashSet<MEPNetworkSegmentId>(new CompareNetworkSegmentId());
// Find all elements that may drive the pipe or duct flow calculations.
List<BuiltInCategory> categories = new List<BuiltInCategory>();
categories.Add(BuiltInCategory.OST_MechanicalEquipment);
categories.Add(BuiltInCategory.OST_PlumbingEquipment);
categories.Add(BuiltInCategory.OST_DuctTerminal);
ElementMulticategoryFilter multiCatFilter = new ElementMulticategoryFilter(categories);
FilteredElementCollector elemCollector = new FilteredElementCollector(doc).WherePasses(multiCatFilter).WhereElementIsNotElementType();
foreach (Element elem in elemCollector.ToElements())
{
MEPAnalyticalModelData data = MEPAnalyticalModelData.GetMEPAnalyticalModelData(elem);
if (data == null)
continue;
int nSeg = data.GetNumberOfSegments();
for (int ii = 0; ii < nSeg; ii++)
{
MEPAnalyticalSegment seg = data.GetSegmentByIndex(ii);
MEPNetworkSegmentId idSegment = new MEPNetworkSegmentId(elem.Id, seg.Id);
if (visitedSegments.Contains(idSegment))
continue;
// Start from this analytical segment to traverse the entire network.
NetworkInfo newNetwork = new NetworkInfo(doc);
newNetwork.DomainType = seg.DomainType;
// First start from the side of the start node.
MEPAnalyticalNode startNode = data.GetNodeById(seg.StartNode);
MEPNetworkIterator iter = new MEPNetworkIterator(doc, startNode, seg);
for (iter.Start(); !iter.End(); iter.Next())
{
MEPAnalyticalSegment currentSegment = iter.GetAnalyticalSegment();
if (currentSegment == null)
continue;
MEPAnalyticalModelData currentModelData = iter.GetAnalyticalModelData();
if (currentModelData == null)
continue;
// Mark this segment so not to create the duplicate network.
MEPNetworkSegmentId currentSegmentId = new MEPNetworkSegmentId(currentSegment.RevitElementId, currentSegment.Id);
visitedSegments.Add(currentSegmentId);
MEPNetworkSegmentData segFlowData = currentModelData.GetSegmentData(currentSegment.Id);
// Grow the network information by filling in one segment.
newNetwork.AddSegment(currentSegment, segFlowData);
// Refine the network name based on the straight segments.
if (currentSegment.SegmentType == MEPAnalyticalSegmentType.Segment)
newNetwork.RefineName(currentSegment.RevitElementId);
}
// If this is not a close loop, we must include the other side as well!
MEPAnalyticalNode endNode = data.GetNodeById(seg.EndNode);
iter = new MEPNetworkIterator(doc, endNode, seg);
for (iter.Start(); !iter.End(); iter.Next())
{
MEPAnalyticalSegment currentSegment = iter.GetAnalyticalSegment();
if (currentSegment == null)
continue;
MEPNetworkSegmentId currentSegmentId = new MEPNetworkSegmentId(currentSegment.RevitElementId, currentSegment.Id);
// Check if the segment was already visited.
if (visitedSegments.Contains(currentSegmentId))
continue;
visitedSegments.Add(currentSegmentId);
MEPAnalyticalModelData currentModelData = iter.GetAnalyticalModelData();
if (currentModelData == null)
continue;
MEPNetworkSegmentData segFlowData = currentModelData.GetSegmentData(currentSegment.Id);
newNetwork.AddSegment(currentSegment, segFlowData);
if (currentSegment.SegmentType == MEPAnalyticalSegmentType.Segment)
newNetwork.RefineName(currentSegment.RevitElementId);
}
// Collect this new network
if (newNetwork.NumberOfSections > 0)
{
newNetwork.ResetFlowDisplay();
validNetworks.Add(newNetwork);
}
}
}
return validNetworks;
}
public void AddSegment(MEPAnalyticalSegment segment, MEPNetworkSegmentData segmentData)
{
int sectionNumber = segmentData.SectionNumber;
// The equipment segment may not belong to any section. Skip those?!
if (sectionNumber < 0)
return;
double segmentFlow = Math.Abs(segmentData.Flow);
if (segmentFlow > m_maxFlow)
m_maxFlow = segmentFlow;
if (!m_sections.ContainsKey(sectionNumber))
{
m_sections.Add(sectionNumber, new SectionInfo());
}
SegmentInfo newSegmentInfo = m_sections[sectionNumber].AddSegment(m_doc, segment, segmentData);
}
private void RefineName(ElementId idElem)
{
Element elem = m_doc.GetElement(idElem);
MEPCurve aCurve = elem as MEPCurve;
if (aCurve != null)
{
MEPSystem sys = aCurve.MEPSystem;
if (sys != null)
{
AppendName(sys.Name);
}
}
else
{
FabricationPart aPart = elem as FabricationPart;
if (aPart != null)
{
string serviceName = aPart.ServiceName;
// Get the full name of fabrication service by its id.
FabricationConfiguration fabConfig = FabricationConfiguration.GetFabricationConfiguration(m_doc);
if (fabConfig != null)
{
FabricationService fabService = fabConfig.GetService(aPart.ServiceId);
if (fabService != null)
{
serviceName = fabService.Name;
}
}
AppendName(serviceName);
}
}
}
private void AppendName(string name)
{
if (string.IsNullOrEmpty(m_name))
{
m_name = name;
}
else
{
if (!m_name.Contains(name))
{
m_name += " + " + name;
}
}
}
private void ResetFlowDisplay()
{
ForgeTypeId specId = SpecTypeId.Flow;
if (DomainType == ConnectorDomainType.Hvac)
specId = SpecTypeId.AirFlow;
// Reset the flow display value based on the maximum number after adding all segments.
m_flow = UnitFormatUtils.Format(m_doc.GetUnits(), specId, m_maxFlow, false);
}
public void ExportCSV(CSVExporter ex)
{
// Export the header line.
string str = string.Format("Section, Type/No, Element, Flow ({0}), Size/Hydraulic Diameter ({1}), Velocity ({2}), Velocity Pressure ({3}), Length ({4}), Coefficients, Friction ({5}), Pressure Loss ({3}), Section Pressure Loss ({3})",
ex.GetFlowUnitSymbol(), ex.GetSizeUnitSymbol(), ex.GetVelocityUnitSymbol(), ex.GetPressureUnitSymbol(), ex.GetLengthUnitSymbol(), ex.GetFrictionUnitSymbol());
ex.Writer.WriteLine(str);
foreach (var item in m_sections)
{
item.Value.ExportCSV(ex, item.Key);
}
// Critical path if available
double dCriticalLoss = 0.0;
string path = null;
foreach(var item in m_sections)
{
if(item.Value.IsCriticalPath)
{
dCriticalLoss += item.Value.TotalPressureLoss;
if(string.IsNullOrEmpty(path))
{
path = item.Key.ToString();
}
else
{
path += @" - " + item.Key.ToString();
}
}
}
ex.Writer.WriteLine(string.Format("Critical Pressure Loss: {0}, {1}", path, dCriticalLoss));
}
public void UpdateView(AVFViewer viewer)
{
List<XYZ> points = new List<XYZ>();
List<VectorAtPoint> valList = new List<VectorAtPoint>();
// Safety check.
if (m_maxFlow < 0.0000001)
return;
foreach (var item in m_sections)
{
int sectionNum = item.Key;
item.Value.UpdateView(viewer, points, valList, m_maxFlow);
}
if(points.Count > 0)
{
viewer.AddData(points, valList);
}
}
}
}
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<RevitAddIns>
<AddIn Type="Command">
<Assembly>D:\git\revit\RevitAdditions\RevitSDK\Software Development Kit\Samples\NetworkPressureLossReport\CS\bin\Debug\NetworkPressureLossReport.dll</Assembly>
<ClientId>a000b64b-a718-48e7-bf5c-7f1f7452490b</ClientId>
<FullClassName>Revit.SDK.Samples.NetworkPressureLossReport.Command</FullClassName>
<Text>Pressure Loss Report</Text>
<Description>Report the pressure loss for the network flow calculation.</Description>
<VisibilityMode>AlwaysVisible</VisibilityMode>
<VendorId>ADSK</VendorId>
<VendorDescription>Autodesk, www.autodesk.com</VendorDescription>
</AddIn>
</RevitAddIns>
@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{D9F2AB5B-1348-421A-9B08-9B4ED74A82CE}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Revit.SDK.Samples.NetworkPressureLossReport.CS</RootNamespace>
<AssemblyName>NetworkPressureLossReport</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup>
<RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
</PropertyGroup>
<ItemGroup>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xaml" />
<Reference Include="System.Xml" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="AVFViewer.cs" />
<Compile Include="Command.cs" />
<Compile Include="CSVExporter.cs" />
<Compile Include="NetworkInfo.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SectionInfo.cs" />
<Compile Include="SegmentInfo.cs" />
<Compile Include="NetworkDialog.xaml.cs">
<DependentUpon>NetworkDialog.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Page Include="NetworkDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<Import Project="$(SolutionDir)VSProps\SDKSamples.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<PropertyGroup>
<PostBuildEvent>set FILEFORSAMPLEREG="$(SolutionDir)..\..\..\..\Regression\API\SDKSamples\UpdateSampleDllForRegression.py"
if exist %25FILEFORSAMPLEREG%25 py -3 %25FILEFORSAMPLEREG%25 "$(ProjectPath)" "$(TargetPath)" "$(SolutionDir)"</PostBuildEvent>
</PropertyGroup>
<PropertyGroup>
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
</PropertyGroup>
</Project>
@@ -0,0 +1,58 @@
//
// (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.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("NetworkPressureLossReport")]
[assembly: AssemblyDescription("Report the pressure loss in the network flow calculation")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Autodesk")]
[assembly: AssemblyProduct("NetworkPressureLossReport")]
[assembly: AssemblyCopyright("Copyright © Autodesk, Inc. 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("72ce761f-210a-40ce-ae47-e75e1356af1f")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,169 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Analysis;
namespace Revit.SDK.Samples.NetworkPressureLossReport
{
internal class SectionInfo
{
private double m_totalLoss;
private IList<SegmentInfo> m_segments;
const double Epsilon = 0.0001; // The small tolerance within which two flow values may be considered equal.
public SectionInfo()
{
m_totalLoss = 0.0;
m_segments = new List<SegmentInfo>();
}
public double TotalPressureLoss
{
get { return m_totalLoss; }
set { m_totalLoss = value; }
}
public int NumberOfSegments
{
get { return m_segments.Count; }
}
public int NumberOfStraights
{
get { return m_segments.Count(x => x.SegmentType == MEPAnalyticalSegmentType.Segment); }
}
public int NumberOfFittingsOrAccessories
{
get { return m_segments.Count(x => x.SegmentType == MEPAnalyticalSegmentType.Fitting); }
}
public double Flow
{
get { return m_segments.FirstOrDefault().Flow; }
}
public double Size
{
get { return m_segments.FirstOrDefault().Size; }
}
public double Velocity
{
get { return m_segments.FirstOrDefault().Velocity; }
}
public double VelocityPressure
{
get { return m_segments.FirstOrDefault().VelocityPressure; }
}
public double Friction
{
get { return m_segments.FirstOrDefault().Friction; }
}
public bool IsCriticalPath
{
get { return m_segments.FirstOrDefault().IsCriticalPath; }
}
public SegmentInfo AddSegment(Document doc, MEPAnalyticalSegment segment, MEPNetworkSegmentData segmentData)
{
SegmentInfo newSegmentInfo = new SegmentInfo(doc, segment, segmentData);
m_segments.Add(newSegmentInfo);
return newSegmentInfo;
}
public void ExportCSV(CSVExporter ex, int sectionNumber)
{
// "Section, Type/No, Element, Flow, Size, Velocity, Velocity Pressure, Length, Coefficients, Friction, Pressure Loss, Section Pressure Loss");
string sNull = null;
int straightCount = 0, fittingCount = 0;
double totalStraightLength = 0.0;
double totalFittingCoeff = 0.0;
double totalStraightLoss = 0.0;
double totalFittingLoss = 0.0;
foreach (SegmentInfo segInfo in m_segments)
{
if (ex.IsItemized == true)
{
ex.Writer.WriteLine(string.Format("{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}",
sectionNumber, segInfo.SegmentType, segInfo.Id, ex.ConvertFromInternalFlow(segInfo.Flow), ex.ConvertFromInternalSize(segInfo.Size),
ex.ConvertFromInternalVelocity(segInfo.Velocity), ex.ConvertFromInternalPressure(segInfo.VelocityPressure), ex.ConvertFromInternalLength(segInfo.Length),
segInfo.Coefficients, ex.ConvertFromInternalFriction(segInfo.Friction), ex.ConvertFromInternalPressure(segInfo.PressureDrop), sNull));
}
if (segInfo.SegmentType == MEPAnalyticalSegmentType.Segment)
{
straightCount++;
totalStraightLength += segInfo.Length;
totalStraightLoss += segInfo.PressureDrop;
}
else if (segInfo.SegmentType == MEPAnalyticalSegmentType.Fitting)
{
fittingCount++;
totalFittingCoeff += segInfo.Coefficients;
totalFittingLoss = segInfo.PressureDrop;
}
}
TotalPressureLoss = totalStraightLoss + totalFittingLoss;
// "Section, Type/No, Element, Flow, Size, Velocity, Velocity Pressure, Length, Coefficients, Friction, Pressure Loss, Section Pressure Loss");
ex.Writer.WriteLine(string.Format("{0}, {1}, Straights, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}",
sectionNumber, straightCount, ex.ConvertFromInternalFlow(Flow), ex.ConvertFromInternalSize(Size),
ex.ConvertFromInternalVelocity(Velocity), sNull, ex.ConvertFromInternalLength(totalStraightLength), sNull,
ex.ConvertFromInternalFriction(Friction), ex.ConvertFromInternalPressure(totalStraightLoss), sNull));
ex.Writer.WriteLine(string.Format("{0}, {1}, Fittings, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}",
sectionNumber, fittingCount, ex.ConvertFromInternalFlow(Flow), ex.ConvertFromInternalSize(Size),
ex.ConvertFromInternalVelocity(Velocity), ex.ConvertFromInternalPressure(VelocityPressure), sNull,
totalFittingCoeff, sNull, ex.ConvertFromInternalPressure(totalFittingLoss), ex.ConvertFromInternalPressure(TotalPressureLoss)));
}
public void UpdateView(AVFViewer viewer, List<XYZ> points, List<VectorAtPoint> valList, double maxFlow)
{
double coeff = viewer.Scale / 12.0;
double maxX = -Double.MaxValue;
double maxY = -Double.MaxValue;
double maxZ = -Double.MaxValue;
foreach (SegmentInfo seg in m_segments)
{
// With the flow value being the scaled vector length, the fittings typically get much longer vector than its actual length.
// As such, we skip the fitting flow display.
if (seg.SegmentType != MEPAnalyticalSegmentType.Segment)
continue;
// Skip the zero flow segments.
if (seg.Flow < 0.0000001)
continue;
XYZ p0 = seg.Start;
XYZ p1 = seg.End;
maxX = Math.Max(Math.Max(maxX, p0.X), p1.X);
maxY = Math.Max(Math.Max(maxY, p0.Y), p1.Y);
maxZ = Math.Max(Math.Max(maxZ, p0.Z), p1.Z);
points.Add(p1);
List<XYZ> xyzList = new List<XYZ>();
XYZ vec = (p1 - p0) / coeff; // This is the exact segment length at the current view scale.
// Convert the vector length to the flow value in scale.
vec = vec.Normalize();
vec *= seg.Flow / maxFlow;
xyzList.Add(vec) ;
valList.Add(new VectorAtPoint(xyzList));
if (points.Count >= 1000) // 1000 is the limit on the number of points for one spatial field primitive
viewer.AddData(points, valList);
// Only display the first segment in the section unless checked "Itemized", since the flow value and direction are the same in one section.
if (!viewer.IsItemized)
break;
}
viewer.AddCorner(maxX, maxY, maxZ);
}
}
}
@@ -0,0 +1,136 @@
using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Analysis;
namespace Revit.SDK.Samples.NetworkPressureLossReport
{
internal class SegmentInfo
{
private MEPNetworkSegmentId m_id;
private MEPAnalyticalSegmentType m_segmentType;
private bool m_isCriticalPath;
private double m_length;
private double m_size;
private double m_flow;
private double m_velocity;
private double m_velocityPressure;
private double m_coefficients;
private double m_pressureDrop;
private double m_reynolds;
private XYZ m_startPt;
private XYZ m_endPt;
const double Tolerance = 0.0000001;
public double Flow
{
get { return m_flow; }
}
public double PressureDrop
{
get { return m_pressureDrop; }
}
public MEPAnalyticalSegmentType SegmentType
{
get { return m_segmentType; }
}
public bool IsCriticalPath
{
get { return m_isCriticalPath; }
}
public string Id
{
get { return m_id.ElementId.ToString() + @"_" + m_id.SegmentId.ToString(); }
}
public ElementId RevitElementId
{
get { return m_id.ElementId; }
}
public double Length
{
get { return m_length; }
}
public double Size
{
get { return m_size; }
}
public double Velocity
{
get { return m_velocity; }
}
public double VelocityPressure
{
get { return m_velocityPressure; }
}
public double Coefficients
{
get { return m_coefficients; }
}
public double Friction
{
get { return m_length < Tolerance ? 0.0 : m_pressureDrop / m_length; }
}
public double ReynoldsNumber
{
get { return m_reynolds; }
}
public XYZ Start
{
get { return m_startPt; }
}
public XYZ End
{
get { return m_endPt; }
}
public SegmentInfo(Document doc, MEPAnalyticalSegment seg, MEPNetworkSegmentData data)
{
m_id = new MEPNetworkSegmentId(seg.RevitElementId, seg.Id);
// Be aware that the flow and pressure may be negative.
// It means the flow is from the end node to the start node.
m_segmentType = seg.SegmentType;
m_size = seg.InnerDiameter; // Hydraulic diameter for rectangular or oval profile.
m_flow = Math.Abs(data.Flow);
m_pressureDrop = data.Flow > 0 ? data.PressureDrop : -1 * data.PressureDrop;
m_velocity = Math.Abs(data.Velocity);
m_velocityPressure = Math.Abs(data.VelocityPressure);
m_coefficients = data.Coefficient;
m_isCriticalPath = data.IsCriticalPath;
m_reynolds = data.ReynoldsNumber;
m_length = 0.0;
Element thisElem = doc.GetElement(seg.RevitElementId);
if (thisElem != null)
{
MEPAnalyticalModelData thisModel = MEPAnalyticalModelData.GetMEPAnalyticalModelData(thisElem);
MEPAnalyticalNode start = thisModel.GetNodeById(seg.StartNode);
MEPAnalyticalNode end = thisModel.GetNodeById(seg.EndNode);
if (start != null && end != null)
{
m_startPt = data.Flow > 0 ? start.Location : end.Location;
m_endPt = data.Flow > 0 ? end.Location : start.Location;
m_length = m_startPt.DistanceTo(m_endPt);
}
}
}
}
internal class CompareNetworkSegmentId : IEqualityComparer<MEPNetworkSegmentId>
{
public bool Equals(MEPNetworkSegmentId left, MEPNetworkSegmentId right)
{
return left.ElementId == right.ElementId
&& left.SegmentId == right.SegmentId;
}
public int GetHashCode(MEPNetworkSegmentId idSeg)
{
// A simple way to combine the element id and segment id into one hash code.
int hash = 17;
hash = hash * 31 + idSeg.ElementId.GetHashCode();
hash = hash * 31 + idSeg.SegmentId.GetHashCode();
return hash;
}
}
}