2021-04-20 11:36:21 +02:00
//
// (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.Text ;
using System.IO ;
using System.Diagnostics ;
using Autodesk.Revit ;
using Autodesk.Revit.ApplicationServices ;
using Autodesk.Revit.DB ;
using Autodesk.Revit.UI ;
using Autodesk.Revit.DB.Mechanical ;
using GXYZ = Autodesk . Revit . DB . XYZ ;
namespace Revit.SDK.Samples.AutoRoute.CS
{
/// <summary>
/// route a set of ducts and fittings between a base air supply equipment and 2 terminals.
/// </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
{
/// <summary>
/// The revit application
/// </summary>
private static Application m_application ;
/// <summary>
/// The current document of the application
/// </summary>
private static Document m_document ;
/// <summary>
/// The mechanical system that will be created
/// </summary>
private MechanicalSystem m_mechanicalSystem ;
/// <summary>
/// The type of the ducts in the system
/// </summary>
DuctType dtRectangle ;
/// <summary>
/// The type id of the duct
/// </summary>
2023-04-26 14:47:47 +02:00
Autodesk . Revit . DB . ElementId ductTypeId = new Autodesk . Revit . DB . ElementId ( 139191L ) ;
2021-04-20 11:36:21 +02:00
/// <summary>
/// The system type id of the duct
/// </summary>
ElementId systemTypeId = ElementId . InvalidElementId ;
/// <summary>
/// The level of the duct
/// </summary>
Level lvl = null ;
/// <summary>
/// Minimum length of a fitting
/// </summary>
private const double min1FittingLength = 1 ;
/// <summary>
/// Minimum length of a duct
/// </summary>
private const double minDuctLength = 0.5 ;
/// <summary>
/// The vertical offset of the highest connector to the trunk ducts
/// </summary>
private const double verticalTrunkOffset = 15 ;
/// <summary>
/// Optional distance from trunk to the boundary of system bounding box
/// used when failed to lay out ducts in the region of bounding box
/// </summary>
private const double horizontalOptionalTrunkOffset = 5 ;
/// <summary>
/// Minimum length of 2 fittings
/// </summary>
private const double min2FittingsLength = min1FittingLength * 2 ;
/// <summary>
/// The minimum length of 1 duct with 2 fittings
/// </summary>
private const double min1Duct2FittingsLength = min1FittingLength * 2 + minDuctLength ;
#region IExternalCommand Members
/// <summary>
/// Implement this method as an external command for Revit.
/// </summary>
/// <param name="commandData">An object that is passed to the external application
/// which contains data related to the command,
/// such as the application object and active view.</param>
/// <param name="message">A message that can be set by the external application
/// which will be displayed if a failure or cancellation is returned by
/// the external command.</param>
/// <param name="elements">A set of elements to which the external application
/// can add elements that are to be highlighted in case of failure or cancellation.</param>
/// <returns>Return the status of the external command.
/// A result of Succeeded means that the API external method functioned as expected.
/// Cancelled can be used to signify that the user cancelled the external operation
/// at some point. Failure should be returned if the application is unable to proceed with
/// the operation.</returns>
public Autodesk . Revit . UI . Result Execute ( ExternalCommandData commandData , ref string message ,
ElementSet elements )
{
// set out default result to Failed.
Autodesk . Revit . UI . Result retRes = Autodesk . Revit . UI . Result . Failed ;
m_application = commandData . Application . Application ;
m_document = commandData . Application . ActiveUIDocument . Document ;
Trace . Listeners . Clear ( ) ;
Trace . AutoFlush = true ;
//get the system type id of the duct
ElementClassFilter systemTypeFilter = new ElementClassFilter ( typeof ( MEPSystemType ) ) ;
FilteredElementCollector C = new FilteredElementCollector ( m_document ) ;
C . WherePasses ( systemTypeFilter ) ;
foreach ( MEPSystemType type in C )
{
if ( type . SystemClassification = = MEPSystemClassification . SupplyAir )
{
systemTypeId = type . Id ;
break ;
}
}
string outputFileName = Path . Combine ( Path . GetDirectoryName ( System . Reflection . Assembly . GetExecutingAssembly ( ) . Location ) , "AutoRoute.log" ) ;
if ( File . Exists ( outputFileName ) )
{
File . Delete ( outputFileName ) ;
}
TextWriterTraceListener listener = new TextWriterTraceListener ( outputFileName ) ;
Trace . Listeners . Add ( listener ) ;
Transaction transaction = new Transaction ( m_document , "Sample_AutoRoute" ) ;
try
{
transaction . Start ( ) ;
//set the level of the duct
lvl = Level . Create ( m_document , 0.0 ) ;
//Lists to temporarily record the created elements
List < Duct > ducts = new List < Duct > ( ) ;
List < GXYZ > points = new List < GXYZ > ( ) ;
List < Connector > connectors = new List < Connector > ( ) ;
List < Connector > baseConnectors = new List < Connector > ( ) ;
//Get the connectors and bounding boxes
List < Autodesk . Revit . DB . ElementId > ids = new List < ElementId > ( ) ;
2023-04-26 14:47:47 +02:00
ids . Add ( new ElementId ( 378728L ) ) ;
ids . Add ( new ElementId ( 378707L ) ) ;
ids . Add ( new ElementId ( 378716L ) ) ;
2021-04-20 11:36:21 +02:00
FamilyInstance [ ] instances = new FamilyInstance [ 3 ] ;
Autodesk . Revit . DB . BoundingBoxXYZ [ ] boxes = new Autodesk . Revit . DB . BoundingBoxXYZ [ 3 ] ;
Connector [ ] conns = new Connector [ 3 ] ;
ConnectorSetIterator csi = null ;
for ( int i = 0 ; i < ids . Count ; + + i )
{
Element element = m_document . GetElement ( ids [ i ] ) ;
if ( null = = element )
{
2022-04-07 09:12:58 +02:00
message = "Element " + ids [ i ] . ToString ( ) + " can't be found." ;
2021-04-20 11:36:21 +02:00
return Autodesk . Revit . UI . Result . Failed ;
}
instances [ i ] = element as FamilyInstance ;
2022-04-07 09:12:58 +02:00
csi = ConnectorInfo . GetConnectors ( ids [ i ] ) . ForwardIterator ( ) ;
2021-04-20 11:36:21 +02:00
csi . MoveNext ( ) ;
conns [ i ] = csi . Current as Connector ;
boxes [ i ] = instances [ i ] . get_BoundingBox ( m_document . ActiveView ) ;
}
//Find the "Out" and "SupplyAir" connector on the base equipment
2022-04-07 09:12:58 +02:00
csi = ConnectorInfo . GetConnectors ( ids [ 0 ] ) . ForwardIterator ( ) ;
2021-04-20 11:36:21 +02:00
while ( csi . MoveNext ( ) )
{
Connector conn = csi . Current as Connector ;
if ( conn . Direction = = FlowDirectionType . Out & & conn . DuctSystemType = = DuctSystemType . SupplyAir )
{
conns [ 0 ] = conn ;
}
}
//Create a mechanical system with a base air supply equipment and 2 terminals.
m_mechanicalSystem = CreateMechanicalSystem (
//[378728][SupplyAir][Out][RectProfile][OST_MechanicalEquipment]
2023-04-26 14:47:47 +02:00
new ConnectorInfo ( new ElementId ( 378728L ) , conns [ 0 ] . Origin . X , conns [ 0 ] . Origin . Y , conns [ 0 ] . Origin . Z ) ,
2021-04-20 11:36:21 +02:00
new ConnectorInfo [ ] {
//[378707][SupplyAir][In][RectProfile]
2023-04-26 14:47:47 +02:00
new ConnectorInfo ( new ElementId ( 378707L ) , conns [ 1 ] . Origin . X , conns [ 1 ] . Origin . Y , conns [ 1 ] . Origin . Z ) ,
2021-04-20 11:36:21 +02:00
//[378716][SupplyAir][In][RectProfile]
2023-04-26 14:47:47 +02:00
new ConnectorInfo ( new ElementId ( 378716L ) , conns [ 2 ] . Origin . X , conns [ 2 ] . Origin . Y , conns [ 2 ] . Origin . Z )
2021-04-20 11:36:21 +02:00
} ,
DuctSystemType . SupplyAir
) ;
//Get the boundary of the system
double minX = conns [ 0 ] . Origin . X ;
double minY = conns [ 0 ] . Origin . Y ;
double maxX = conns [ 0 ] . Origin . X ;
double maxY = conns [ 0 ] . Origin . Y ;
double maxZ = conns [ 0 ] . Origin . Z ;
for ( int i = 1 ; i < boxes . Length ; + + i )
{
if ( conns [ i ] . Origin . X < minX )
minX = conns [ i ] . Origin . X ;
if ( conns [ i ] . Origin . Y < minY )
minY = conns [ i ] . Origin . Y ;
if ( conns [ i ] . Origin . X > maxX )
maxX = conns [ i ] . Origin . X ;
if ( conns [ i ] . Origin . Y > maxY )
maxY = conns [ i ] . Origin . Y ;
if ( conns [ i ] . Origin . Z > maxZ )
maxZ = conns [ i ] . Origin . Z ;
}
//Calculate the optional values for the trunk ducts
double midX = ( minX + maxX ) / 2 ;
double midY = ( minY + maxY ) / 2 ;
double [ ] baseXValues = new double [ 3 ] { midX , ( minX + midX ) / 2 , ( maxX + midX ) / 2 } ;
double [ ] baseYValues = new double [ 3 ] { midY , ( minY + midY ) / 2 , ( maxY + midY ) / 2 } ;
//Get the duct type for the ducts to be created
dtRectangle = m_document . GetElement ( ductTypeId ) as DuctType ;
//Create the ducts and elbows that connect the base mechanical equipment
GXYZ connectorDirection = conns [ 0 ] . CoordinateSystem . BasisZ ;
if ( 0 = = connectorDirection . DistanceTo ( new GXYZ ( - 1 , 0 , 0 ) ) )
{
points . Add ( new GXYZ ( conns [ 0 ] . Origin . X - min1FittingLength , conns [ 0 ] . Origin . Y , conns [ 0 ] . Origin . Z ) ) ;
points . Add ( new GXYZ ( conns [ 0 ] . Origin . X - min2FittingsLength , conns [ 0 ] . Origin . Y , conns [ 0 ] . Origin . Z + min1FittingLength ) ) ;
points . Add ( new GXYZ ( conns [ 0 ] . Origin . X - min2FittingsLength , conns [ 0 ] . Origin . Y , maxZ + verticalTrunkOffset - min1FittingLength ) ) ;
}
else if ( 0 = = connectorDirection . DistanceTo ( new GXYZ ( 1 , 0 , 0 ) ) )
{
points . Add ( new GXYZ ( conns [ 0 ] . Origin . X + min1FittingLength , conns [ 0 ] . Origin . Y , conns [ 0 ] . Origin . Z ) ) ;
points . Add ( new GXYZ ( conns [ 0 ] . Origin . X + min2FittingsLength , conns [ 0 ] . Origin . Y , conns [ 0 ] . Origin . Z + min1FittingLength ) ) ;
points . Add ( new GXYZ ( conns [ 0 ] . Origin . X + min2FittingsLength , conns [ 0 ] . Origin . Y , maxZ + verticalTrunkOffset - min1FittingLength ) ) ;
}
else if ( 0 = = connectorDirection . DistanceTo ( new GXYZ ( 0 , - 1 , 0 ) ) )
{
points . Add ( new GXYZ ( conns [ 0 ] . Origin . X , conns [ 0 ] . Origin . Y - min1FittingLength , conns [ 0 ] . Origin . Z ) ) ;
points . Add ( new GXYZ ( conns [ 0 ] . Origin . X , conns [ 0 ] . Origin . Y - min2FittingsLength , conns [ 0 ] . Origin . Z + min1FittingLength ) ) ;
points . Add ( new GXYZ ( conns [ 0 ] . Origin . X , conns [ 0 ] . Origin . Y - min2FittingsLength , maxZ + verticalTrunkOffset - min1FittingLength ) ) ;
}
else if ( 0 = = connectorDirection . DistanceTo ( new GXYZ ( 0 , 1 , 0 ) ) )
{
points . Add ( new GXYZ ( conns [ 0 ] . Origin . X , conns [ 0 ] . Origin . Y + min1FittingLength , conns [ 0 ] . Origin . Z ) ) ;
points . Add ( new GXYZ ( conns [ 0 ] . Origin . X , conns [ 0 ] . Origin . Y + min2FittingsLength , conns [ 0 ] . Origin . Z + min1FittingLength ) ) ;
points . Add ( new GXYZ ( conns [ 0 ] . Origin . X , conns [ 0 ] . Origin . Y + min2FittingsLength , maxZ + verticalTrunkOffset - min1FittingLength ) ) ;
}
ducts . Add ( Duct . Create ( m_document , ductTypeId , lvl . Id , conns [ 0 ] , points [ 0 ] ) ) ;
ducts . Add ( Duct . Create ( m_document , systemTypeId , ductTypeId , lvl . Id , points [ 1 ] , points [ 2 ] ) ) ;
2022-04-07 09:12:58 +02:00
connectors . Add ( ConnectorInfo . GetConnector ( ducts [ 0 ] . Id , points [ 0 ] ) ) ;
connectors . Add ( ConnectorInfo . GetConnector ( ducts [ 1 ] . Id , points [ 1 ] ) ) ;
connectors . Add ( ConnectorInfo . GetConnector ( ducts [ 1 ] . Id , points [ 2 ] ) ) ;
2021-04-20 11:36:21 +02:00
connectors [ 0 ] . ConnectTo ( connectors [ 1 ] ) ;
m_document . Create . NewElbowFitting ( connectors [ 0 ] , connectors [ 1 ] ) ;
baseConnectors . Add ( connectors [ 2 ] ) ;
//Create the vertical ducts for terminals
points . Clear ( ) ;
ducts . Clear ( ) ;
points . Add ( new GXYZ ( conns [ 1 ] . Origin . X , conns [ 1 ] . Origin . Y , maxZ + verticalTrunkOffset - min1FittingLength ) ) ;
points . Add ( new GXYZ ( conns [ 2 ] . Origin . X , conns [ 2 ] . Origin . Y , maxZ + verticalTrunkOffset - min1FittingLength ) ) ;
ducts . Add ( Duct . Create ( m_document , ductTypeId , lvl . Id , conns [ 1 ] , points [ 0 ] ) ) ;
ducts . Add ( Duct . Create ( m_document , ductTypeId , lvl . Id , conns [ 2 ] , points [ 1 ] ) ) ;
2022-04-07 09:12:58 +02:00
baseConnectors . Add ( ConnectorInfo . GetConnector ( ducts [ 0 ] . Id , points [ 0 ] ) ) ;
baseConnectors . Add ( ConnectorInfo . GetConnector ( ducts [ 1 ] . Id , points [ 1 ] ) ) ;
2021-04-20 11:36:21 +02:00
//Connect the system by creating the trunk line of ducts and connect them to the base connectors
SortConnectorsByX ( baseConnectors ) ;
for ( int i = 0 ; i < baseYValues . Length ; + + i )
{
if ( ConnectSystemOnXAxis ( baseConnectors , baseYValues [ i ] ) )
{
LogUtility . WriteMechanicalSystem ( m_mechanicalSystem ) ;
return Autodesk . Revit . UI . Result . Succeeded ;
}
}
SortConnectorsByY ( baseConnectors ) ;
for ( int i = 0 ; i < baseXValues . Length ; + + i )
{
if ( ConnectSystemOnYAxis ( baseConnectors , baseXValues [ i ] ) )
{
LogUtility . WriteMechanicalSystem ( m_mechanicalSystem ) ;
return Autodesk . Revit . UI . Result . Succeeded ;
}
}
//If all the cases fail to route the system, try the trunks out of the bounding box
SortConnectorsByX ( baseConnectors ) ;
if ( ConnectSystemOnXAxis ( baseConnectors , maxY + horizontalOptionalTrunkOffset ) )
{
LogUtility . WriteMechanicalSystem ( m_mechanicalSystem ) ;
return Autodesk . Revit . UI . Result . Succeeded ;
}
SortConnectorsByY ( baseConnectors ) ;
if ( ConnectSystemOnYAxis ( baseConnectors , maxX + horizontalOptionalTrunkOffset ) )
{
LogUtility . WriteMechanicalSystem ( m_mechanicalSystem ) ;
return Autodesk . Revit . UI . Result . Succeeded ;
}
//If there's no path for the connection, choose one path and let Revit report the error
connectors . Clear ( ) ;
SortConnectorsByX ( baseConnectors ) ;
connectors . AddRange ( CreateDuct ( new GXYZ ( baseConnectors [ 0 ] . Origin . X + min1FittingLength , baseYValues [ 0 ] , maxZ + verticalTrunkOffset ) , new GXYZ ( baseConnectors [ 1 ] . Origin . X - min1FittingLength , baseYValues [ 0 ] , maxZ + verticalTrunkOffset ) ) ) ;
connectors . AddRange ( CreateDuct ( new GXYZ ( baseConnectors [ 1 ] . Origin . X + min1FittingLength , baseYValues [ 0 ] , maxZ + verticalTrunkOffset ) , new GXYZ ( baseConnectors [ 2 ] . Origin . X - min1FittingLength , baseYValues [ 0 ] , maxZ + verticalTrunkOffset ) ) ) ;
ConnectWithElbowFittingOnXAxis ( baseConnectors [ 0 ] , connectors [ 0 ] ) ;
ConnectWithElbowFittingOnXAxis ( baseConnectors [ 2 ] , connectors [ 3 ] ) ;
ConnectWithTeeFittingOnXAxis ( baseConnectors [ 1 ] , connectors [ 1 ] , connectors [ 2 ] , false ) ;
}
catch ( Exception ex )
{
Trace . WriteLine ( ex . ToString ( ) ) ;
message = ex . Message ;
retRes = Autodesk . Revit . UI . Result . Failed ;
}
finally
{
transaction . Commit ( ) ;
Trace . Flush ( ) ;
listener . Close ( ) ;
Trace . Close ( ) ;
Trace . Listeners . Remove ( listener ) ;
}
return retRes ;
}
#endregion
/// <summary>
/// Connect the system with a trunk line of ducts on X axis
/// </summary>
/// <param name="baseConnectors">the upper connectors of the vertical ducts that derived from the terminals and the base equipment</param>
/// <param name="baseY">the y value of the trunk line</param>
/// <returns>
/// true if the system can be connected
/// false if the system cannot be connected
/// </returns>
private bool ConnectSystemOnXAxis ( List < Connector > baseConnectors , double baseY )
{
//Check the count of the base connectors
if ( null = = baseConnectors | | 3 ! = baseConnectors . Count )
{
return false ;
}
for ( int i = 0 ; i < baseConnectors . Count ; + + i )
{
//Check the distance of the connector from the trunk
if ( baseConnectors [ i ] . Origin . Y ! = baseY & & Math . Abs ( baseConnectors [ i ] . Origin . Y - baseY ) < min1Duct2FittingsLength )
{
return false ;
}
//Check the distance of the connectors on X axis
for ( int j = i + 1 ; j < baseConnectors . Count ; + + j )
{
if ( baseConnectors [ j ] . Origin . X ! = baseConnectors [ i ] . Origin . X & & baseConnectors [ j ] . Origin . X - baseConnectors [ i ] . Origin . X < min2FittingsLength )
{
return false ;
}
}
}
try
{
double baseZ = baseConnectors [ 0 ] . Origin . Z + min1FittingLength ;
//Create the ducts and elbow fittings to connect the vertical ducts and the trunk ducts
List < Connector > connectors = new List < Connector > ( ) ;
if ( baseConnectors [ 0 ] . Origin . X = = baseConnectors [ 1 ] . Origin . X )
{
//All 3 connectors are with the same X value
if ( baseConnectors [ 1 ] . Origin . X = = baseConnectors [ 2 ] . Origin . X )
{
return false ;
}
else
{
//The 1st and 2nd base connectors are on the same side of the trunk
if ( Math . Sign ( baseConnectors [ 0 ] . Origin . Y - baseY ) * Math . Sign ( baseConnectors [ 1 ] . Origin . Y - baseY ) = = 1 )
{
return false ;
}
//Create the trunk
connectors = CreateDuct ( new GXYZ ( baseConnectors [ 0 ] . Origin . X + min1FittingLength , baseY , baseZ ) , new GXYZ ( baseConnectors [ 2 ] . Origin . X - min1FittingLength , baseY , baseZ ) ) ;
//Create a tee fitting connecting the 1st and 2nd base connectors to the trunk
ConnectWithTeeFittingOnXAxis ( baseConnectors [ 0 ] , baseConnectors [ 1 ] , connectors [ 0 ] , true ) ;
//Create an elbow fitting connection the 3rd base connector to the trunk
ConnectWithElbowFittingOnXAxis ( baseConnectors [ 2 ] , connectors [ 1 ] ) ;
}
}
else
{
//Create the segment of duct on the trunk to be connected to the 1st base connector
connectors = CreateDuct ( new GXYZ ( baseConnectors [ 0 ] . Origin . X + min1FittingLength , baseY , baseZ ) , new GXYZ ( baseConnectors [ 1 ] . Origin . X - min1FittingLength , baseY , baseZ ) ) ;
//Create an elbow fitting connection the 1st base connector with the trunk
ConnectWithElbowFittingOnXAxis ( baseConnectors [ 0 ] , connectors [ 0 ] ) ;
if ( baseConnectors [ 1 ] . Origin . X = = baseConnectors [ 2 ] . Origin . X )
{
//The 2nd and 3rd connectors are on the same side of the trunk
if ( Math . Sign ( baseConnectors [ 1 ] . Origin . Y - baseY ) * Math . Sign ( baseConnectors [ 2 ] . Origin . Y - baseY ) = = 1 )
{
return false ;
}
//Create a tee fitting connecting the 2nd and 3rd base connectors to the trunk
ConnectWithTeeFittingOnXAxis ( baseConnectors [ 1 ] , baseConnectors [ 2 ] , connectors [ 1 ] , true ) ;
}
else
{
connectors . AddRange ( CreateDuct ( new GXYZ ( baseConnectors [ 1 ] . Origin . X + min1FittingLength , baseY , baseZ ) , new GXYZ ( baseConnectors [ 2 ] . Origin . X - min1FittingLength , baseY , baseZ ) ) ) ;
//Create a tee fitting connecting the 2nd base connector to the trunk
ConnectWithTeeFittingOnXAxis ( baseConnectors [ 1 ] , connectors [ 1 ] , connectors [ 2 ] , false ) ;
//Create an elbow fitting connection the 3rd base connector to the trunk
ConnectWithElbowFittingOnXAxis ( baseConnectors [ 2 ] , connectors [ 3 ] ) ;
}
}
return true ;
}
catch
{
return false ;
}
}
/// <summary>
/// Connect a base connector to a connector on the trunk with an elbow fitting
/// </summary>
/// <param name="baseConn">the upper connector of the vertical duct that derived from a terminal or the base equipment</param>
/// <param name="conn">the connector of a duct on the trunk</param>
private void ConnectWithElbowFittingOnXAxis ( Connector baseConn , Connector conn )
{
double baseY = conn . Origin . Y ;
double baseZ = conn . Origin . Z ;
List < Connector > connectors = new List < Connector > ( ) ;
//If the distance of the two connectors on the Y axis is greater than 2, create a duct on the Y axis and then connect it to the 2 connectors with elbow fittings
if ( Math . Abs ( baseConn . Origin . Y - baseY ) > min1Duct2FittingsLength )
{
connectors . AddRange ( CreateDuct ( new GXYZ ( baseConn . Origin . X , baseConn . Origin . Y - Math . Sign ( baseConn . Origin . Y - baseY ) , baseZ ) , new GXYZ ( baseConn . Origin . X , baseY + Math . Sign ( baseConn . Origin . Y - baseY ) , baseZ ) ) ) ;
connectors [ 0 ] . ConnectTo ( baseConn ) ;
m_document . Create . NewElbowFitting ( connectors [ 0 ] , baseConn ) ;
connectors [ 1 ] . ConnectTo ( conn ) ;
m_document . Create . NewElbowFitting ( connectors [ 1 ] , conn ) ;
}
//If the distance of the two connectors on the Y axis is less than 2, connect them with an elbow fitting
else
{
baseConn . ConnectTo ( conn ) ;
m_document . Create . NewElbowFitting ( baseConn , conn ) ;
}
}
/// <summary>
/// Connect 3 connectors on the trunk with a tee fitting
/// </summary>
/// <param name="conn1">the first connector</param>
/// <param name="conn2">the second connector</param>
/// <param name="conn3">the third connector</param>
/// <param name="flag">a flag to indicate whether there are 2 base connectors or 1 base connector</param>
private void ConnectWithTeeFittingOnXAxis ( Connector conn1 , Connector conn2 , Connector conn3 , bool flag )
{
double baseY = conn3 . Origin . Y ;
double baseZ = conn3 . Origin . Z ;
List < GXYZ > points = new List < GXYZ > ( ) ;
List < Duct > ducts = new List < Duct > ( ) ;
List < Connector > connectors = new List < Connector > ( ) ;
//Connect two base connectors to a connector on the trunk
if ( true = = flag )
{
Connector baseConn1 = conn1 ;
Connector baseConn2 = conn2 ;
Connector conn = conn3 ;
connectors . AddRange ( CreateDuct ( new GXYZ ( baseConn1 . Origin . X , baseConn1 . Origin . Y - Math . Sign ( baseConn1 . Origin . Y - baseY ) , baseZ ) , new GXYZ ( baseConn1 . Origin . X , baseY + Math . Sign ( baseConn1 . Origin . Y - baseY ) , baseZ ) ) ) ;
connectors . AddRange ( CreateDuct ( new GXYZ ( baseConn2 . Origin . X , baseConn2 . Origin . Y - Math . Sign ( baseConn2 . Origin . Y - baseY ) , baseZ ) , new GXYZ ( baseConn2 . Origin . X , baseY + Math . Sign ( baseConn2 . Origin . Y - baseY ) , baseZ ) ) ) ;
connectors [ 0 ] . ConnectTo ( baseConn1 ) ;
connectors [ 2 ] . ConnectTo ( baseConn2 ) ;
m_document . Create . NewElbowFitting ( connectors [ 0 ] , baseConn1 ) ;
m_document . Create . NewElbowFitting ( connectors [ 2 ] , baseConn2 ) ;
connectors [ 1 ] . ConnectTo ( connectors [ 3 ] ) ;
connectors [ 1 ] . ConnectTo ( conn ) ;
connectors [ 3 ] . ConnectTo ( conn ) ;
m_document . Create . NewTeeFitting ( connectors [ 1 ] , connectors [ 3 ] , conn ) ;
}
//Connect a base connector to two connectors on the trunk
else
{
Connector baseConn = conn1 ;
if ( Math . Abs ( baseConn . Origin . Y - baseY ) > min1Duct2FittingsLength )
{
connectors . AddRange ( CreateDuct ( new GXYZ ( baseConn . Origin . X , baseConn . Origin . Y - Math . Sign ( baseConn . Origin . Y - baseY ) , baseZ ) , new GXYZ ( baseConn . Origin . X , baseY + Math . Sign ( baseConn . Origin . Y - baseY ) , baseZ ) ) ) ;
baseConn . ConnectTo ( connectors [ 0 ] ) ;
m_document . Create . NewElbowFitting ( connectors [ 0 ] , baseConn ) ;
connectors [ 1 ] . ConnectTo ( conn2 ) ;
connectors [ 1 ] . ConnectTo ( conn3 ) ;
conn2 . ConnectTo ( conn3 ) ;
m_document . Create . NewTeeFitting ( conn2 , conn3 , connectors [ 1 ] ) ;
}
else
{
baseConn . ConnectTo ( conn2 ) ;
baseConn . ConnectTo ( conn3 ) ;
conn2 . ConnectTo ( conn3 ) ;
m_document . Create . NewTeeFitting ( conn2 , conn3 , baseConn ) ;
}
}
}
/// <summary>
/// Sort the base connectors by their x values
/// </summary>
/// <param name="connectors">the connectors to be sorted</param>
private void SortConnectorsByX ( List < Connector > connectors )
{
for ( int i = 0 ; i < connectors . Count ; + + i )
{
double min = connectors [ i ] . Origin . X ;
int minIndex = i ;
for ( int j = i ; j < connectors . Count ; + + j )
{
if ( connectors [ j ] . Origin . X < min )
{
min = connectors [ j ] . Origin . X ;
minIndex = j ;
}
}
Connector t = connectors [ i ] ;
connectors [ i ] = connectors [ minIndex ] ;
connectors [ minIndex ] = t ;
}
}
/// <summary>
/// Connect the system with a trunk line of ducts on Y axis
/// </summary>
/// <param name="baseConnectors">the upper connectors of the vertical ducts that derived from the terminals and the base equipment</param>
/// <param name="baseX">the x value of the trunk line</param>
/// <returns>
/// true if the system can be connected
/// false if the system cannot be connected
/// </returns>
private bool ConnectSystemOnYAxis ( List < Connector > baseConnectors , double baseX )
{
//Check the count of the base connectors
if ( null = = baseConnectors | | 3 ! = baseConnectors . Count )
{
return false ;
}
for ( int i = 0 ; i < baseConnectors . Count ; + + i )
{
//Check the distance of the connector from the trunk
if ( baseConnectors [ i ] . Origin . X ! = baseX & & Math . Abs ( baseConnectors [ i ] . Origin . X - baseX ) < min1Duct2FittingsLength )
{
return false ;
}
//Check the distance of the connectors on Y axis
for ( int j = i + 1 ; j < baseConnectors . Count ; + + j )
{
if ( baseConnectors [ j ] . Origin . Y ! = baseConnectors [ i ] . Origin . Y & & baseConnectors [ j ] . Origin . Y - baseConnectors [ i ] . Origin . Y < min2FittingsLength )
{
return false ;
}
}
}
try
{
double baseZ = baseConnectors [ 0 ] . Origin . Z + min1FittingLength ;
//Create the ducts and elbow fittings to connect the vertical ducts and the trunk ducts
List < Connector > connectors = new List < Connector > ( ) ;
if ( baseConnectors [ 0 ] . Origin . Y = = baseConnectors [ 1 ] . Origin . Y )
{
//All 3 connectors are with the same Y value
if ( baseConnectors [ 1 ] . Origin . Y = = baseConnectors [ 2 ] . Origin . Y )
{
return false ;
}
else
{
//The 1st and 2nd base connectors are on the same side of the trunk
if ( Math . Sign ( baseConnectors [ 0 ] . Origin . X - baseX ) * Math . Sign ( baseConnectors [ 1 ] . Origin . X - baseX ) = = 1 )
{
return false ;
}
//Create the trunk
connectors = CreateDuct ( new GXYZ ( baseX , baseConnectors [ 0 ] . Origin . Y + min1FittingLength , baseZ ) , new GXYZ ( baseX , baseConnectors [ 2 ] . Origin . Y - min1FittingLength , baseZ ) ) ;
//Create a tee fitting connecting the 1st and 2nd base connectors to the trunk
ConnectWithTeeFittingOnYAxis ( baseConnectors [ 0 ] , baseConnectors [ 1 ] , connectors [ 0 ] , true ) ;
//Create an elbow fitting connection the 3rd base connector to the trunk
ConnectWithElbowFittingOnYAxis ( baseConnectors [ 2 ] , connectors [ 1 ] ) ;
}
}
else
{
//Create the segment of duct on the trunk to be connected to the 1st base connector
connectors = CreateDuct ( new GXYZ ( baseX , baseConnectors [ 0 ] . Origin . Y + min1FittingLength , baseZ ) , new GXYZ ( baseX , baseConnectors [ 1 ] . Origin . Y - min1FittingLength , baseZ ) ) ;
//Create an elbow fitting connection the 1st base connector with the trunk
ConnectWithElbowFittingOnYAxis ( baseConnectors [ 0 ] , connectors [ 0 ] ) ;
if ( baseConnectors [ 1 ] . Origin . Y = = baseConnectors [ 2 ] . Origin . Y )
{
//The 2nd and 3rd connectors are on the same side of the trunk
if ( Math . Sign ( baseConnectors [ 1 ] . Origin . X - baseX ) * Math . Sign ( baseConnectors [ 2 ] . Origin . X - baseX ) = = 1 )
{
return false ;
}
//Create a tee fitting connecting the 2nd and 3rd base connectors to the trunk
ConnectWithTeeFittingOnYAxis ( baseConnectors [ 1 ] , baseConnectors [ 2 ] , connectors [ 1 ] , true ) ;
}
else
{
connectors . AddRange ( CreateDuct ( new GXYZ ( baseX , baseConnectors [ 1 ] . Origin . Y + min1FittingLength , baseZ ) , new GXYZ ( baseX , baseConnectors [ 2 ] . Origin . Y - min1FittingLength , baseZ ) ) ) ;
//Create a tee fitting connecting the 2nd base connector to the trunk
ConnectWithTeeFittingOnYAxis ( baseConnectors [ 1 ] , connectors [ 1 ] , connectors [ 2 ] , false ) ;
//Create an elbow fitting connection the 3rd base connector to the trunk
ConnectWithElbowFittingOnYAxis ( baseConnectors [ 2 ] , connectors [ 3 ] ) ;
}
}
return true ;
}
catch
{
return false ;
}
}
/// <summary>
/// Connect a base connector to a connector on the trunk with an elbow fitting
/// </summary>
/// <param name="baseConn">the upper connector of the vertical duct that derived from a terminal or the base equipment</param>
/// <param name="conn">the connector of a duct on the trunk</param>
private void ConnectWithElbowFittingOnYAxis ( Connector baseConn , Connector conn )
{
double baseX = conn . Origin . X ;
double baseZ = conn . Origin . Z ;
List < Connector > connectors = new List < Connector > ( ) ;
//If the distance of the two connectors on the X axis is greater than 2, create a duct on the X axis and then connect it to the 2 connectors with elbow fittings
if ( Math . Abs ( baseConn . Origin . X - baseX ) > min1Duct2FittingsLength )
{
connectors . AddRange ( CreateDuct ( new GXYZ ( baseConn . Origin . X - Math . Sign ( baseConn . Origin . X - baseX ) , baseConn . Origin . Y , baseZ ) , new GXYZ ( baseX + Math . Sign ( baseConn . Origin . X - baseX ) , baseConn . Origin . Y , baseZ ) ) ) ;
connectors [ 0 ] . ConnectTo ( baseConn ) ;
m_document . Create . NewElbowFitting ( connectors [ 0 ] , baseConn ) ;
connectors [ 1 ] . ConnectTo ( conn ) ;
m_document . Create . NewElbowFitting ( connectors [ 1 ] , conn ) ;
}
//If the distance of the two connectors on the X axis is less than 2, connect them with an elbow fitting
else
{
baseConn . ConnectTo ( conn ) ;
m_document . Create . NewElbowFitting ( baseConn , conn ) ;
}
}
/// <summary>
/// Connect 3 connectors on the trunk with a tee fitting
/// </summary>
/// <param name="conn1">the first connector</param>
/// <param name="conn2">the second connector</param>
/// <param name="conn3">the third connector</param>
/// <param name="flag">a flag to indicate whether there are 2 base connectors or 1 base connector</param>
private void ConnectWithTeeFittingOnYAxis ( Connector conn1 , Connector conn2 , Connector conn3 , bool flag )
{
double baseX = conn3 . Origin . X ;
double baseZ = conn3 . Origin . Z ;
List < GXYZ > points = new List < GXYZ > ( ) ;
List < Duct > ducts = new List < Duct > ( ) ;
List < Connector > connectors = new List < Connector > ( ) ;
//Connect two base connectors to a connector on the trunk
if ( true = = flag )
{
Connector baseConn1 = conn1 ;
Connector baseConn2 = conn2 ;
Connector conn = conn3 ;
connectors . AddRange ( CreateDuct ( new GXYZ ( baseConn1 . Origin . X - Math . Sign ( baseConn1 . Origin . X - baseX ) , baseConn1 . Origin . Y , baseZ ) , new GXYZ ( baseX + Math . Sign ( baseConn1 . Origin . X - baseX ) , baseConn1 . Origin . Y , baseZ ) ) ) ;
connectors . AddRange ( CreateDuct ( new GXYZ ( baseConn2 . Origin . X - Math . Sign ( baseConn2 . Origin . X - baseX ) , baseConn2 . Origin . Y , baseZ ) , new GXYZ ( baseX + Math . Sign ( baseConn2 . Origin . X - baseX ) , baseConn2 . Origin . Y , baseZ ) ) ) ;
connectors [ 0 ] . ConnectTo ( baseConn1 ) ;
connectors [ 2 ] . ConnectTo ( baseConn2 ) ;
m_document . Create . NewElbowFitting ( connectors [ 0 ] , baseConn1 ) ;
m_document . Create . NewElbowFitting ( connectors [ 2 ] , baseConn2 ) ;
connectors [ 1 ] . ConnectTo ( connectors [ 3 ] ) ;
connectors [ 1 ] . ConnectTo ( conn ) ;
connectors [ 3 ] . ConnectTo ( conn ) ;
m_document . Create . NewTeeFitting ( connectors [ 1 ] , connectors [ 3 ] , conn ) ;
}
//Connect a base connector to two connectors on the trunk
else
{
Connector baseConn = conn1 ;
if ( Math . Abs ( baseConn . Origin . X - baseX ) > min1Duct2FittingsLength )
{
connectors . AddRange ( CreateDuct ( new GXYZ ( baseConn . Origin . X - Math . Sign ( baseConn . Origin . X - baseX ) , baseConn . Origin . Y , baseZ ) , new GXYZ ( baseX + Math . Sign ( baseConn . Origin . X - baseX ) , baseConn . Origin . Y , baseZ ) ) ) ;
baseConn . ConnectTo ( connectors [ 0 ] ) ;
m_document . Create . NewElbowFitting ( connectors [ 0 ] , baseConn ) ;
connectors [ 1 ] . ConnectTo ( conn2 ) ;
connectors [ 1 ] . ConnectTo ( conn3 ) ;
conn2 . ConnectTo ( conn3 ) ;
m_document . Create . NewTeeFitting ( conn2 , conn3 , connectors [ 1 ] ) ;
}
else
{
baseConn . ConnectTo ( conn2 ) ;
baseConn . ConnectTo ( conn3 ) ;
conn2 . ConnectTo ( conn3 ) ;
m_document . Create . NewTeeFitting ( conn2 , conn3 , baseConn ) ;
}
}
}
/// <summary>
/// Sort the base connectors by their y values
/// </summary>
/// <param name="connectors">the connectors to be sorted</param>
private void SortConnectorsByY ( List < Connector > connectors )
{
for ( int i = 0 ; i < connectors . Count ; + + i )
{
double min = connectors [ i ] . Origin . Y ;
int minIndex = i ;
for ( int j = i ; j < connectors . Count ; + + j )
{
if ( connectors [ j ] . Origin . Y < min )
{
min = connectors [ j ] . Origin . Y ;
minIndex = j ;
}
}
Connector t = connectors [ i ] ;
connectors [ i ] = connectors [ minIndex ] ;
connectors [ minIndex ] = t ;
}
}
/// <summary>
/// Create a duct with two points
/// </summary>
/// <param name="point1">the first point</param>
/// <param name="point2">the second point</param>
/// <returns></returns>
private List < Connector > CreateDuct ( GXYZ point1 , GXYZ point2 )
{
List < Connector > connectors = new List < Connector > ( ) ;
Duct duct = Duct . Create ( m_document , systemTypeId , ductTypeId , lvl . Id , point1 , point2 ) ;
2022-04-07 09:12:58 +02:00
connectors . Add ( ConnectorInfo . GetConnector ( duct . Id , point1 ) ) ;
connectors . Add ( ConnectorInfo . GetConnector ( duct . Id , point2 ) ) ;
2021-04-20 11:36:21 +02:00
return connectors ;
}
/// <summary>
/// Create a mechanical system
/// </summary>
/// <param name="baseConnector">the base connector of the mechanical system</param>
/// <param name="connectors">the connectors of the mechanical system</param>
/// <param name="systemType">the system type of the mechanical system</param>
/// <returns>the created mechanical system</returns>
private MechanicalSystem CreateMechanicalSystem ( ConnectorInfo baseConnector , ConnectorInfo [ ] connectors , DuctSystemType systemType )
{
ConnectorSet cset = null ;
if ( connectors ! = null )
{
cset = new ConnectorSet ( ) ;
foreach ( ConnectorInfo ci in connectors )
{
cset . Insert ( ci . Connector ) ;
}
}
MechanicalSystem mechanicalSystem = m_document . Create . NewMechanicalSystem ( baseConnector = = null ? null : baseConnector . Connector , cset , systemType ) ;
return mechanicalSystem ;
}
/// <summary>
/// information of a connector
/// </summary>
public class ConnectorInfo
{
/// <summary>
/// The owner's element ID
/// </summary>
2022-04-07 09:12:58 +02:00
ElementId m_ownerId ;
2021-04-20 11:36:21 +02:00
/// <summary>
/// The origin of the connector
/// </summary>
GXYZ m_origin ;
/// <summary>
/// The Connector object
/// </summary>
Connector m_connector ;
/// <summary>
/// The connector this object represents
/// </summary>
public Connector Connector
{
get { return m_connector ; }
set { m_connector = value ; }
}
/// <summary>
/// The owner ID of the connector
/// </summary>
2022-04-07 09:12:58 +02:00
public ElementId OwnerId
2021-04-20 11:36:21 +02:00
{
get { return m_ownerId ; }
set { m_ownerId = value ; }
}
/// <summary>
/// The origin of the connector
/// </summary>
public GXYZ Origin
{
get { return m_origin ; }
set { m_origin = value ; }
}
/// <summary>
/// The constructor that finds the connector with the owner ID and origin
/// </summary>
/// <param name="ownerId">the ownerID of the connector</param>
/// <param name="origin">the origin of the connector</param>
2022-04-07 09:12:58 +02:00
public ConnectorInfo ( ElementId ownerId , GXYZ origin )
2021-04-20 11:36:21 +02:00
{
m_ownerId = ownerId ;
m_origin = origin ;
m_connector = ConnectorInfo . GetConnector ( m_ownerId , origin ) ;
}
/// <summary>
/// The constructor that finds the connector with the owner ID and the values of the origin
/// </summary>
/// <param name="ownerId">the ownerID of the connector</param>
/// <param name="x">the X value of the connector</param>
/// <param name="y">the Y value of the connector</param>
/// <param name="z">the Z value of the connector</param>
2022-04-07 09:12:58 +02:00
public ConnectorInfo ( ElementId ownerId , double x , double y , double z )
2021-04-20 11:36:21 +02:00
: this ( ownerId , new GXYZ ( x , y , z ) )
{
}
/// <summary>
/// Get the connector of the owner at the specific origin
/// </summary>
/// <param name="ownerId">the owner ID of the connector</param>
/// <param name="connectorOrigin">the origin of the connector</param>
/// <returns>if found, return the connector, or else return null</returns>
2022-04-07 09:12:58 +02:00
public static Connector GetConnector ( ElementId ownerId , GXYZ connectorOrigin )
2021-04-20 11:36:21 +02:00
{
ConnectorSet connectors = GetConnectors ( ownerId ) ;
foreach ( Connector conn in connectors )
{
if ( conn . ConnectorType = = ConnectorType . Logical )
continue ;
if ( conn . Origin . IsAlmostEqualTo ( connectorOrigin ) )
return conn ;
}
return null ;
}
/// <summary>
/// Get all the connectors of an element with a specific ID
/// </summary>
/// <param name="ownerId">the owner ID of the connector</param>
/// <returns>the connector set which includes all the connectors found</returns>
2022-04-07 09:12:58 +02:00
public static ConnectorSet GetConnectors ( ElementId ownerId )
2021-04-20 11:36:21 +02:00
{
2022-04-07 09:12:58 +02:00
Element element = m_document . GetElement ( ownerId ) ;
2021-04-20 11:36:21 +02:00
return GetConnectors ( element ) ;
}
/// <summary>
/// Get all the connectors of a specific element
/// </summary>
/// <param name="element">the owner of the connector</param>
/// <returns>if found, return all the connectors found, or else return null</returns>
public static ConnectorSet GetConnectors ( Autodesk . Revit . DB . Element element )
{
if ( element = = null ) return null ;
FamilyInstance fi = element as FamilyInstance ;
if ( fi ! = null & & fi . MEPModel ! = null )
{
return fi . MEPModel . ConnectorManager . Connectors ;
}
MEPSystem system = element as MEPSystem ;
if ( system ! = null )
{
return system . ConnectorManager . Connectors ;
}
MEPCurve duct = element as MEPCurve ;
if ( duct ! = null )
{
return duct . ConnectorManager . Connectors ;
}
return null ;
}
/// <summary>
/// Find the two connectors of the specific ConnectorManager at the two locations
/// </summary>
/// <param name="connMgr">The ConnectorManager of the connectors to be found</param>
/// <param name="ptn1">the location of the first connector</param>
/// <param name="ptn2">the location of the second connector</param>
/// <returns>The two connectors found</returns>
public static Connector [ ] FindConnectors ( ConnectorManager connMgr , GXYZ pnt1 , GXYZ pnt2 )
{
Connector [ ] result = new Connector [ 2 ] ;
ConnectorSet conns = connMgr . Connectors ;
foreach ( Connector conn in conns )
{
if ( conn . Origin . IsAlmostEqualTo ( pnt1 ) )
{
result [ 0 ] = conn ;
}
else if ( conn . Origin . IsAlmostEqualTo ( pnt2 ) )
{
result [ 1 ] = conn ;
}
}
return result ;
}
} ;
}
public class LogUtility
{
/// <summary>
/// Invalid string.
/// </summary>
public const string InvalidString = "[!]" ;
/// <summary>
/// Write the information of an element to the log file
/// </summary>
/// <param name="element">the element whose information is to be written</param>
public static void WriteElement ( Element element )
{
WriteElement ( element , true ) ;
}
/// <summary>
/// Write the information of an element to the log file
/// </summary>
/// <param name="element">the element whose information is to be written</param>
/// <param name="writeId">whether the id will be outputted</param>
public static void WriteElement ( Element element , bool writeId )
{
if ( element = = null )
{
Trace . WriteLine ( "null" ) ; return ;
}
2022-04-07 09:12:58 +02:00
ElementId elementId = element . Id ;
ElementId familyId = element . get_Parameter ( BuiltInParameter . ELEM_FAMILY_PARAM ) . AsElementId ( ) ;
2021-04-20 11:36:21 +02:00
string familyName = LogUtility . InvalidString ;
Element objectType = GetElement < Element > ( element . Document , familyId ) ;
string elementName = LogUtility . InvalidString ;
try { elementName = element . Name ; }
catch { }
if ( objectType ! = null )
{
Parameter familyNameParameter = objectType . get_Parameter ( BuiltInParameter . ALL_MODEL_FAMILY_NAME ) ;
if ( familyNameParameter ! = null )
familyName = familyNameParameter . AsString ( ) ;
}
2022-04-07 09:12:58 +02:00
BuiltInCategory category = element . Category . BuiltInCategory ;
2021-04-20 11:36:21 +02:00
Trace . WriteLine ( "Type: " + element . GetType ( ) . FullName ) ;
Trace . WriteLine ( "Name: " + familyName + ":" + elementName ) ;
2022-04-07 09:12:58 +02:00
if ( writeId ) Trace . WriteLine ( "Id: " + elementId . ToString ( ) ) ;
2021-04-20 11:36:21 +02:00
Trace . WriteLine ( "Category: " + category ) ;
2022-04-07 09:12:58 +02:00
Trace . WriteLine ( "FamilyId: " + familyId . ToString ( ) ) ;
2021-04-20 11:36:21 +02:00
}
/// <summary>
/// Write the information of a mechanical system to the log file
/// </summary>
/// <param name="system">the mechanical system whose information is to be written</param>
public static void WriteMechanicalSystem ( MechanicalSystem system )
{
string flow = InvalidString ;
try { flow = system . GetFlow ( ) . ToString ( ) ; }
catch ( Exception ) { }
Trace . WriteLine ( "Flow: " + flow ) ;
Trace . WriteLine ( "IsWellConnected: " + system . IsWellConnected ) ;
Trace . WriteLine ( "SystemType: " + system . SystemType ) ;
Trace . WriteLine ( "+DuctNetwork" ) ;
Trace . Indent ( ) ;
foreach ( Element element in system . DuctNetwork )
{
LogUtility . WriteElement ( element , false ) ;
Trace . WriteLine ( "" ) ;
}
Trace . Unindent ( ) ;
WriteMEPSystem ( system ) ;
}
/// <summary>
/// Get element by its id and cast it to the specified type
/// </summary>
/// <param name="document">the owner document of the element</param>
/// <param name="eid">the id of the element</param>
/// <returns>the element of the specified type</returns>
2022-04-07 09:12:58 +02:00
public static T GetElement < T > ( Document document , ElementId eid ) where T : Autodesk . Revit . DB . Element
2021-04-20 11:36:21 +02:00
{
2022-04-07 09:12:58 +02:00
return document . GetElement ( eid ) as T ;
2021-04-20 11:36:21 +02:00
}
/// <summary>
/// Write the information of a MEPSystem to the log file.
/// </summary>
/// <param name="system">the MEP system whose information is to be written</param>
public static void WriteMEPSystem ( MEPSystem system )
{
WriteElement ( system . BaseEquipment ) ;
Trace . Unindent ( ) ;
Trace . WriteLine ( "+BaseEquipmentConnector" ) ;
Trace . Indent ( ) ;
WriteConnector ( system . BaseEquipmentConnector ) ;
Trace . Unindent ( ) ;
Trace . WriteLine ( "+Elements" ) ;
Trace . Indent ( ) ;
foreach ( Element element in system . Elements )
{
WriteElement ( element ) ;
Trace . WriteLine ( "" ) ;
}
Trace . Unindent ( ) ;
Trace . WriteLine ( "+ConnectorManager" ) ;
Trace . Indent ( ) ;
WriteConnectorManager ( system . ConnectorManager ) ;
Trace . Unindent ( ) ;
}
/// <summary>
/// Write the information of a connector to the log file
/// </summary>
/// <param name="connector">the connector whose information is to be written</param>
public static void WriteConnector ( Connector connector )
{
if ( connector = = null )
{
Trace . WriteLine ( "null" ) ; return ;
}
object connType = InvalidString ;
object connDirection = InvalidString ;
object connShape = InvalidString ;
try { connShape = connector . Shape ; }
catch { }
object connSize = InvalidString ;
try { connSize = GetShapeInfo ( connector ) ; }
catch { }
object connLocation = GetLocation ( connector ) ;
object connAType = connector . ConnectorType ;
object connIsConnected = InvalidString ;
switch ( connector . Domain )
{
case Domain . DomainElectrical :
connType = connector . ElectricalSystemType ;
break ;
case Domain . DomainHvac :
connType = connector . DuctSystemType ;
connDirection = connector . Direction ;
connIsConnected = connector . IsConnected ;
break ;
case Domain . DomainPiping :
connType = connector . PipeSystemType ;
connDirection = connector . Direction ;
connIsConnected = connector . IsConnected ;
break ;
case Domain . DomainUndefined :
default :
connType = Domain . DomainUndefined ;
break ;
}
Trace . WriteLine ( "Type: " + connAType ) ;
Trace . WriteLine ( "SystemType: " + connType ) ;
Trace . WriteLine ( "Direction: " + connDirection ) ;
Trace . WriteLine ( "Shape: " + connShape ) ;
Trace . WriteLine ( "Size: " + connSize ) ;
Trace . WriteLine ( "Location: " + connLocation ) ;
Trace . WriteLine ( "IsConnected: " + connIsConnected ) ;
}
/// <summary>
/// Write the information of a ConnectorManager to the log file
/// </summary>
/// <param name="connectorManager">the ConnectorManager whose information is to be written</param>
public static void WriteConnectorManager ( ConnectorManager connectorManager )
{
Trace . WriteLine ( "+Connectors" ) ;
Trace . Indent ( ) ;
WriteConnectorSet2 ( connectorManager . Connectors ) ;
Trace . Unindent ( ) ;
Trace . WriteLine ( "+UnusedConnectors" ) ;
Trace . Indent ( ) ;
WriteConnectorSet2 ( connectorManager . UnusedConnectors ) ;
Trace . Unindent ( ) ;
}
/// <summary>
/// Get the information string of a connector
/// </summary>
/// <param name="connector">the connector to be read</param>
/// <returns>the information string of the connector</returns>
public static string GetConnectorId ( Connector connector )
{
if ( connector = = null )
{
return "null" ;
}
2022-04-07 09:12:58 +02:00
ElementId ownerId = connector . Owner . Id ;
2021-04-20 11:36:21 +02:00
string systemId = InvalidString ;
2022-04-07 09:12:58 +02:00
try { systemId = connector . MEPSystem . Id . ToString ( ) ; }
2021-04-20 11:36:21 +02:00
catch { }
object connType = InvalidString ;
object connDirection = InvalidString ;
object connShape = InvalidString ;
try { connShape = connector . Shape ; }
catch { }
object connSize = InvalidString ;
try { connSize = GetShapeInfo ( connector ) ; }
catch { }
object connLocation = GetLocation ( connector ) ;
object connAType = connector . ConnectorType ;
object connIsConnected = InvalidString ;
switch ( connector . Domain )
{
case Domain . DomainElectrical :
connType = connector . ElectricalSystemType ;
break ;
case Domain . DomainHvac :
connType = connector . DuctSystemType ;
connDirection = connector . Direction ;
connIsConnected = connector . IsConnected ;
break ;
case Domain . DomainPiping :
connType = connector . PipeSystemType ;
connDirection = connector . Direction ;
connIsConnected = connector . IsConnected ;
break ;
case Domain . DomainUndefined :
default :
connType = Domain . DomainUndefined ;
break ;
}
return string . Format ( "[{0}]\t[{1}]\t[{2}]\t[{3}]\t[{4}]\t[{5}]\t[{6}]\t[{7}]\t[{8}]\t" ,
2022-04-07 09:12:58 +02:00
ownerId . ToString ( ) , connType , connDirection , connShape , connSize , connLocation ,
2021-04-20 11:36:21 +02:00
connAType , connIsConnected , systemId ) ;
}
/// <summary>
/// Get the shape information string of a connector
/// </summary>
/// <param name="conn">the element to be read</param>
/// <returns>the shape information string of the connector</returns>
private static string GetShapeInfo ( Connector conn )
{
switch ( conn . Shape )
{
case ConnectorProfileType . Invalid :
break ;
case ConnectorProfileType . Oval :
break ;
case ConnectorProfileType . Rectangular :
return string . Format ( "{0}\" x {1}\"" , conn . Width , conn . Height ) ;
case ConnectorProfileType . Round :
return string . Format ( "{0}\"" , conn . Radius ) ;
default :
break ;
}
return InvalidString ;
}
/// <summary>
/// Get the location string of a connector
/// </summary>
/// <param name="conn">the connector to be read</param>
/// <returns>the location information string of the connector</returns>
private static object GetLocation ( Connector conn )
{
if ( conn . ConnectorType = = ConnectorType . Logical )
{
return InvalidString ;
}
Autodesk . Revit . DB . XYZ origin = conn . Origin ;
return string . Format ( "{0},{1},{2}" , origin . X , origin . Y , origin . Z ) ;
}
/// <summary>
/// Write the information of a ConnectorSet to the log file.
/// </summary>
/// <param name="connectorSet">the ConnectorSet whose information is to be written</param>
private static void WriteConnectorSet2 ( ConnectorSet connectorSet )
{
SortedDictionary < string , List < Connector > > connectors = new SortedDictionary < string , List < Connector > > ( ) ;
foreach ( Connector conn in connectorSet )
{
string connId = GetConnectorId ( conn ) ;
if ( conn . ConnectorType = = ConnectorType . Logical )
{
foreach ( Connector logLinkConn in conn . AllRefs )
{
connId + = GetConnectorId ( logLinkConn ) ;
}
}
if ( ! connectors . ContainsKey ( connId ) )
{
connectors . Add ( connId , new List < Connector > ( ) ) ;
}
connectors [ connId ] . Add ( conn ) ;
}
foreach ( string key in connectors . Keys )
{
foreach ( Connector conn in connectors [ key ] )
{
WriteConnector ( conn ) ;
Trace . WriteLine ( "+AllRefs" ) ;
Trace . Indent ( ) ;
WriteConnectorSet ( conn . AllRefs ) ;
Trace . Unindent ( ) ;
Trace . WriteLine ( "" ) ;
}
}
}
/// <summary>
/// Write the information of a ConnectorSet to the log file.
/// </summary>
/// <param name="connectorSet">the mechanical system whose information is to be written</param>
private static void WriteConnectorSet ( ConnectorSet connectorSet )
{
SortedDictionary < string , List < Connector > > connectors = new SortedDictionary < string , List < Connector > > ( ) ;
foreach ( Connector conn in connectorSet )
{
string connId = GetConnectorId ( conn ) ;
if ( conn . ConnectorType = = ConnectorType . Logical )
{
foreach ( Connector logLinkConn in conn . AllRefs )
{
connId + = GetConnectorId ( logLinkConn ) ;
}
}
if ( ! connectors . ContainsKey ( connId ) )
{
connectors . Add ( connId , new List < Connector > ( ) ) ;
}
connectors [ connId ] . Add ( conn ) ;
}
foreach ( string key in connectors . Keys )
{
foreach ( Connector conn in connectors [ key ] )
{
WriteConnector ( conn ) ;
Trace . WriteLine ( "" ) ;
}
}
}
}
}