//
// (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;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using Autodesk.Revit;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.UI.Selection;
namespace Revit.SDK.Samples.PowerCircuit.CS
{
///
/// Data class which stores the information of electrical circuit operation
///
public class CircuitOperationData
{
#region Fields
///
/// Active document of Revit
///
UIDocument m_revitDoc;
///
/// Selection of active document
///
Selection m_selection;
///
/// Operation on selected elements
///
private Operation m_operation;
///
/// Option of editing circuit
///
private EditOption m_editOption;
///
/// Whether new circuit can be created with selected elements
///
private bool m_canCreateCircuit;
///
/// Whether there is a circuit in selected elements
///
private bool m_hasCircuit;
///
/// Whether the circuit in selected elements has panel
///
private bool m_hasPanel;
///
/// All electrical systems contain selected element
///
private ElectricalSystemSet m_electricalSystemSet;
///
/// All electrical system items which will be displayed in circuit selecting form
///
private List m_electricalSystemItems;
///
/// The electrical system chosen to operate
///
private ElectricalSystem m_selectedElectricalSystem;
#endregion
#region Properties
///
/// Operation type
///
public Operation Operation
{
get
{
return m_operation;
}
set
{
m_operation = value;
}
}
///
/// Get the information whether new circuit can be created
///
public bool CanCreateCircuit
{
get
{
return m_canCreateCircuit;
}
}
///
/// Get the value of whether there are circuits in selected elements
///
public bool HasCircuit
{
get
{
return m_hasCircuit;
}
}
///
/// Get the information whether the circuit in selected elements has panel
///
public bool HasPanel
{
get
{
return m_hasPanel;
}
}
///
/// Edit options
///
public EditOption EditOption
{
get
{
return m_editOption;
}
set
{
m_editOption = value;
}
}
///
/// All electrical system items which will be displayed in circuit selecting form
///
public ReadOnlyCollection ElectricalSystemItems
{
get
{
foreach (ElectricalSystem es in m_electricalSystemSet)
{
ElectricalSystemItem esi = new ElectricalSystemItem(es);
m_electricalSystemItems.Add(esi);
}
return new ReadOnlyCollection(m_electricalSystemItems);
}
}
///
/// Number of electrical systems contain selected elements
///
public int ElectricalSystemCount
{
get
{
return m_electricalSystemSet.Size;
}
}
#endregion
#region Methods
///
/// Constructor
///
/// Revit's external commandData
public CircuitOperationData(ExternalCommandData commandData)
{
m_revitDoc = commandData.Application.ActiveUIDocument;
m_selection = m_revitDoc.Selection;
m_electricalSystemSet = new ElectricalSystemSet();
m_electricalSystemItems = new List();
CollectConnectorInfo();
CollectCircuitInfo();
}
///
/// Verify if all selected elements have unused connectors
///
private void CollectConnectorInfo()
{
m_canCreateCircuit = true;
// Flag to check if all selected elements are lighting devices
bool allLightingDevices = true;
foreach (ElementId elementId in m_selection.GetElementIds())
{
Element element = m_revitDoc.Document.GetElement(elementId);
FamilyInstance fi = element as FamilyInstance;
if (null == fi)
{
m_canCreateCircuit = false;
return;
}
if (!String.Equals(fi.Category.Name, "Lighting Devices"))
{
allLightingDevices = false;
}
// Verify if the family instance has usable connectors
if (!VerifyUnusedConnectors(fi))
{
m_canCreateCircuit = false;
return;
}
}
if (allLightingDevices)
{
m_canCreateCircuit = false;
}
}
///
/// Verify if the family instance has usable connectors
///
/// The family instance to be verified
/// True if the family instance has usable connecotors,
/// otherwise false
static private bool VerifyUnusedConnectors(FamilyInstance fi)
{
bool hasUnusedElectricalConnector = false;
try
{
MEPModel mepModel = fi.MEPModel;
if (null == mepModel)
{
return hasUnusedElectricalConnector;
}
ConnectorManager cm = mepModel.ConnectorManager;
ConnectorSet unusedConnectors = cm.UnusedConnectors;
if (null == unusedConnectors || unusedConnectors.IsEmpty)
{
return hasUnusedElectricalConnector;
}
foreach (Connector connector in unusedConnectors)
{
if (connector.Domain == Domain.DomainElectrical)
{
hasUnusedElectricalConnector = true;
break;
}
}
}
catch (Exception)
{
return hasUnusedElectricalConnector;
}
return hasUnusedElectricalConnector;
}
///
/// Get common circuits contain all selected elements
///
private void CollectCircuitInfo()
{
//bool isElectricalSystem = false;
bool bInitilzedElectricalSystemSet = false;
//
// Get common circuits of selected elements
//
ElectricalSystem tempElectricalSystem = null;
foreach (ElementId elementId in m_selection.GetElementIds())
{
Element element = m_revitDoc.Document.GetElement(elementId);
FamilyInstance fi = element as FamilyInstance;
MEPModel mepModel;
ElectricalSystemSet ess;
if (fi != null && (mepModel = fi.MEPModel) != null)
{
//
// If the element is a family instance and its MEP model is not null,
// retrieve its circuits
// Then compare the circuits with circuits of other selected elements
// to get the common ones
//
// Get all electrical systems
ess = mepModel.ElectricalSystems;
if (null == ess)
{
m_hasCircuit = false;
m_hasPanel = false;
return;
}
// Remove systems which are not power circuits
foreach (ElectricalSystem es in ess)
{
if (es.SystemType != ElectricalSystemType.PowerCircuit)
{
ess.Erase(es);
}
}
if (ess.IsEmpty)
{
m_hasCircuit = false;
m_hasPanel = false;
return;
}
// If m_electricalSystemSet is not set before, set it
// otherwise compare the circuits with circuits of other selected elements
// to get the common ones
if (!bInitilzedElectricalSystemSet)
{
m_electricalSystemSet = ess;
bInitilzedElectricalSystemSet = true;
continue;
}
else
{
foreach (ElectricalSystem es in m_electricalSystemSet)
{
if (!ess.Contains(es))
{
m_electricalSystemSet.Erase(es);
}
}
if (m_electricalSystemSet.IsEmpty)
{
m_hasCircuit = false;
m_hasPanel = false;
return;
}
}
}
else if ((tempElectricalSystem = element as ElectricalSystem) != null)
{
//
// If the element is an electrical system, verify if it is a power circuit
// If not, compare with circuits of other selected elements
// to get the common ones
//
//verify if it is a power circuit
if (tempElectricalSystem.SystemType != ElectricalSystemType.PowerCircuit)
{
m_hasCircuit = false;
m_hasPanel = false;
return;
}
// If m_electricalSystemSet is not set before, set it
// otherwise compare with circuits of other selected elements
// to get the common ones
if (!bInitilzedElectricalSystemSet)
{
m_electricalSystemSet.Insert(tempElectricalSystem);
bInitilzedElectricalSystemSet = true;
continue;
}
if (!m_electricalSystemSet.Contains(tempElectricalSystem))
{
m_hasCircuit = false;
m_hasPanel = false;
return;
}
m_electricalSystemSet.Clear();
m_electricalSystemSet.Insert(tempElectricalSystem);
}
else
{
m_hasCircuit = false;
m_hasPanel = false;
return;
}
}
// Verify if there is any common power circuit
if (!m_electricalSystemSet.IsEmpty)
{
m_hasCircuit = true;
if (m_electricalSystemSet.Size == 1)
{
foreach (ElectricalSystem es in m_electricalSystemSet)
{
m_selectedElectricalSystem = es;
break;
}
}
foreach (ElectricalSystem es in m_electricalSystemSet)
{
if (!String.IsNullOrEmpty(es.PanelName))
{
m_hasPanel = true;
break;
}
}
}
}
///
/// Dispatch operations
///
public void Operate()
{
Transaction transaction = new Transaction(m_revitDoc.Document, m_operation.ToString());
transaction.Start();
switch (m_operation)
{
case Operation.CreateCircuit:
CreatePowerCircuit();
break;
case Operation.EditCircuit:
EditCircuit();
break;
case Operation.SelectPanel:
SelectPanel();
break;
case Operation.DisconnectPanel:
DisconnectPanel();
break;
default:
break;
}
transaction.Commit();
// Select the modified circuit
if (m_operation != Operation.CreateCircuit)
{
SelectCurrentCircuit();
}
}
///
/// Create a power circuit with selected elements
///
public void CreatePowerCircuit()
{
List selectionElementId = new List();
ElementSet elements = new ElementSet();
foreach (ElementId elementId in m_selection.GetElementIds())
{
elements.Insert(m_revitDoc.Document.GetElement(elementId));
}
foreach (Element e in elements)
{
selectionElementId.Add(e.Id);
}
try
{
// Creation
ElectricalSystem es = ElectricalSystem.Create(m_revitDoc.Document, selectionElementId, ElectricalSystemType.PowerCircuit);
// Select the newly created power system
m_selection.GetElementIds().Clear();
m_selection.GetElementIds().Add(es.Id);
}
catch (Exception)
{
ShowErrorMessage("FailedToCreateCircuit");
}
}
///
/// Dispatch operations of editing circuit
///
public void EditCircuit()
{
switch (m_editOption)
{
case EditOption.Add:
AddElementToCircuit();
break;
case EditOption.Remove:
RemoveElementFromCircuit();
break;
case EditOption.SelectPanel:
SelectPanel();
break;
default:
break;
}
}
///
/// Add an element to circuit
///
public void AddElementToCircuit()
{
// Clear selection before selecting the panel
m_selection.GetElementIds().Clear();
// Interact with UI to select a panel
if (m_revitDoc.Selection.PickObject(ObjectType.Element) == null)
{
return;
}
//
// Verify if the selected element can be added to the circuit
//
// Get selected element
Element selectedElement = null;
foreach (ElementId elementId in m_selection.GetElementIds())
{
Element element = m_revitDoc.Document.GetElement(elementId);
selectedElement = element;
}
// Get the MEP model of selected element
MEPModel mepModel = null;
FamilyInstance fi = selectedElement as FamilyInstance;
if (null == fi || null == (mepModel = fi.MEPModel))
{
ShowErrorMessage("SelectElectricalComponent");
return;
}
// Verify if the element has usable connector
if (!VerifyUnusedConnectors(fi))
{
ShowErrorMessage("NoUsableConnector");
return;
}
if (IsElementBelongsToCircuit(mepModel, m_selectedElectricalSystem))
{
ShowErrorMessage("ElementInCircuit");
return;
}
try
{
ElementSet es = new ElementSet();
foreach (ElementId elementId in m_selection.GetElementIds())
{
es.Insert(m_revitDoc.Document.GetElement(elementId));
}
if (!m_selectedElectricalSystem.AddToCircuit(es))
{
ShowErrorMessage("FailedToAddElement");
return;
}
}
catch (Exception)
{
ShowErrorMessage("FailedToAddElement");
}
}
///
/// Remove an element from selected circuit
///
public void RemoveElementFromCircuit()
{
// Clear selection before selecting the panel
m_selection.GetElementIds().Clear();
// Interact with UI to select a panel
if (m_revitDoc.Selection.PickObject(ObjectType.Element) == null)
{
return;
}
// Get the selected element
Element selectedElement = null;
foreach (ElementId elementId in m_revitDoc.Selection.GetElementIds())
{
Element element = m_revitDoc.Document.GetElement(elementId);
selectedElement = element;
}
// Get the MEP model of selected element
MEPModel mepModel = null;
FamilyInstance fi = selectedElement as FamilyInstance;
if (null == fi || null == (mepModel = fi.MEPModel))
{
ShowErrorMessage("SelectElectricalComponent");
return;
}
// Check whether the selected element belongs to the circuit
if (!IsElementBelongsToCircuit(mepModel, m_selectedElectricalSystem))
{
ShowErrorMessage("ElementNotInCircuit");
return;
}
try
{
// Remove the selected element from circuit
ElementSet es = new ElementSet();
foreach (ElementId elementId in m_revitDoc.Selection.GetElementIds())
{
es.Insert(m_revitDoc.Document.GetElement(elementId));
}
m_selectedElectricalSystem.RemoveFromCircuit(es);
}
catch (Exception)
{
ShowErrorMessage("FailedToRemoveElement");
}
}
static private bool IsElementBelongsToCircuit(MEPModel mepModel,
ElectricalSystem selectedElectricalSystem)
{
ElectricalSystemSet ess = mepModel.ElectricalSystems;
if (null == ess || !ess.Contains(selectedElectricalSystem))
{
return false;
}
return true;
}
///
/// Select a panel for selected circuit
///
public void SelectPanel()
{
// Clear selection before selecting the panel
m_selection.GetElementIds().Clear();
// Interact with UI to select a panel
if (m_revitDoc.Selection.PickObject(ObjectType.Element) == null)
{
return;
}
try
{
FamilyInstance fi;
foreach (ElementId elementId in m_selection.GetElementIds())
{
Element element = m_revitDoc.Document.GetElement(elementId);
fi = element as FamilyInstance;
if (fi != null)
{
m_selectedElectricalSystem.SelectPanel(fi);
}
}
}
catch (Exception)
{
ShowErrorMessage("FailedToSelectPanel");
}
}
///
/// Disconnect panel for selected circuit
///
public void DisconnectPanel()
{
try
{
m_selectedElectricalSystem.DisconnectPanel();
}
catch (Exception)
{
ShowErrorMessage("FailedToDisconnectPanel");
}
}
///
/// Get selected index from circuit selecting form and locate expected circuit
///
/// Index of selected item in circuit selecting form
public void SelectCircuit(int index)
{
// Locate ElectricalSystemItem by index
ElectricalSystemItem esi = m_electricalSystemItems[index] as ElectricalSystemItem;
Autodesk.Revit.DB.ElementId ei = esi.Id;
// Locate expected electrical system
m_selectedElectricalSystem = m_revitDoc.Document.GetElement(ei) as ElectricalSystem;
// Select the electrical system
SelectCurrentCircuit();
}
///
/// Select created/modified/selected electrical system
///
public void SelectCurrentCircuit()
{
m_selection.GetElementIds().Clear();
m_selection.GetElementIds().Add(m_selectedElectricalSystem.Id);
}
///
/// Get selected index from circuit selecting form and show the circuit in the center of
/// screen by moving the view.
///
/// Index of selected item in circuit selecting form
public void ShowCircuit(int index)
{
ElectricalSystemItem esi = m_electricalSystemItems[index] as ElectricalSystemItem;
Autodesk.Revit.DB.ElementId ei = esi.Id;
m_revitDoc.ShowElements(ei);
}
///
/// Show message box with specified string
///
/// specified string to show
static private void ShowErrorMessage(String message)
{
TaskDialog.Show(Properties.Resources.ResourceManager.GetString("OperationFailed"), Properties.Resources.ResourceManager.GetString(message), TaskDialogCommonButtons.Ok);
}
#endregion
}
}