Files
RevitSdkSamples/SDK/Samples/DoorSwing/CS/DoorSwingData.cs
T
2019-09-11 14:43:53 +02:00

532 lines
21 KiB
C#

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using Autodesk.Revit;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System.Windows.Forms;
namespace Revit.SDK.Samples.DoorSwing.CS
{
/// <summary>
/// Stores all the needed data and operates RevitAPI.
/// </summary>
public class DoorSwingData
{
#region "Memebers"
// store door-opening types: user to decide how he wants to identify
// the Left, Right or others information.
public static List<String> OpeningTypes = new List<string>();
// store current project's door families.
List<DoorFamily> m_doorFamilies = new List<DoorFamily>();
Autodesk.Revit.UI.UIApplication m_app;
#endregion
#region "Properties"
// retrieves door families.
public List<DoorFamily> DoorFamilies
{
get
{
return m_doorFamilies;
}
}
#endregion
#region "Methods"
/// <summary>
/// fill OpeningTypes static member variable.
/// </summary>
static DoorSwingData()
{
// fill door's opening types. User can modify the DoorSwingResource according to
// how he wants to identify the Left, Right or others opening information.
OpeningTypes.Clear();
// Undefined means this door family is insensible of door opening feature.
// User didn't add the relevant parameters or just gave an invalid value.
OpeningTypes.Add(DoorSwingResource.Undefined);
OpeningTypes.Add(DoorSwingResource.LeftDoor);
OpeningTypes.Add(DoorSwingResource.RightDoor);
OpeningTypes.Add(DoorSwingResource.TwoLeaf);
OpeningTypes.Add(DoorSwingResource.TwoLeafActiveLeafLeft);
OpeningTypes.Add(DoorSwingResource.TwoLeafActiveLeafRight);
}
/// <summary>
/// constructor.
/// </summary>
/// <param name="app"> Revit application</param>
public DoorSwingData(Autodesk.Revit.UI.UIApplication app)
{
m_app = app;
// store door families in m_doorFamilies.
PrepareDoorFamilies();
// add needed shared parameters
// if the parameters already added will not add again.
DoorSharedParameters.AddSharedParameters(app);
}
/// <summary>
/// update door instances information: Left/Right information, related rooms information.
/// </summary>
/// <param name="creFilter">One element filter utility object.</param>
/// <param name="doc">Revit project.</param>
/// <param name="onlyUpdateSelect">
/// true means only update selected doors' information otherwise false.
/// </param>
/// <param name="showUpdateResultMessage">
/// this parameter is used for invoking this method in Application's events (document save and document saveAs).
/// update door infos in Application level events should not show unnecessary messageBox.
/// </param>
public static Autodesk.Revit.UI.Result UpdateDoorsInfo(Document doc, bool onlyUpdateSelect,
bool showUpdateResultMessage, ref string message)
{
if ((!AssignedAllRooms(doc)) && showUpdateResultMessage)
{
TaskDialogResult dialogResult = TaskDialog.Show("Door Swing", "One or more eligible areas of this level " +
"have no assigned room(s). Doors bounding these areas " +
"will be designated as external doors. Proceed anyway?",
TaskDialogCommonButtons.Yes | TaskDialogCommonButtons.No);
if (TaskDialogResult.No == dialogResult)
{
message = "Update cancelled. Please assign rooms for all eligible areas first.";
return Autodesk.Revit.UI.Result.Cancelled;
}
}
// begin update door parameters.
IEnumerator iter;
int doorCount = 0;
bool checkSharedParameters = false;
if (onlyUpdateSelect) // update doors in select elements
{
UIDocument newUIdoc = new UIDocument(doc);
ElementSet es = new ElementSet();
foreach (ElementId elementId in newUIdoc.Selection.GetElementIds())
{
es.Insert(newUIdoc.Document.GetElement(elementId));
}
iter = es.GetEnumerator();
}
else // update all doors in current Revit project.
{
ElementClassFilter familyInstanceFilter = new ElementClassFilter(typeof(FamilyInstance));
ElementCategoryFilter doorsCategoryfilter = new ElementCategoryFilter(BuiltInCategory.OST_Doors);
LogicalAndFilter doorInstancesFilter = new LogicalAndFilter(familyInstanceFilter, doorsCategoryfilter);
iter = new FilteredElementCollector(doc).WherePasses(doorInstancesFilter).GetElementIterator();
}
iter.Reset();
while (iter.MoveNext())
{
// find door instance
FamilyInstance door = iter.Current as FamilyInstance;
if (onlyUpdateSelect)
{
if (null == door)
{
continue;
}
if (null == door.Category)
{
continue;
}
if (!door.Category.Name.Equals("Doors"))
{
continue;
}
}
// check if has needed parameters.
if (!checkSharedParameters)
{
checkSharedParameters = true;
if (!(door.Symbol.ParametersMap.Contains("BasalOpening") &&
door.ParametersMap.Contains("InstanceOpening") &&
door.ParametersMap.Contains("Internal Door")))
{
message = "Cannot update door parameters. Please customize door opening expression first.";
return Autodesk.Revit.UI.Result.Failed;
}
}
// get one door.
doorCount++;
// update one door's Opening parameter value.
if (UpdateOpeningFeatureOfOneDoor(door) == Autodesk.Revit.UI.Result.Failed)
{
message = "Cannot update door parameters. Please customize door opening expression first.";
return Autodesk.Revit.UI.Result.Failed;
}
// update one door's from/to room.
UpdateFromToRoomofOneDoor(door, false);
// update one door's internalDoor flag
UpdateInternalDoorFlagFeatureofOneDoor(door);
}
if (showUpdateResultMessage)
{
if (onlyUpdateSelect)
{
Autodesk.Revit.UI.TaskDialog.Show("Door Swing", "Updated all selected doors of " + doc.Title +
" (" + doorCount + " doors).\r\n (Selection may " +
"include miscellaneous elements.)");
}
else
{
Autodesk.Revit.UI.TaskDialog.Show("Door Swing", "Updated all doors of " + doc.Title + " (" +
doorCount + " doors).");
}
}
return Autodesk.Revit.UI.Result.Succeeded;
}
/// <summary>
/// Doors related rooms: update doors' geometry according to its To/From room information.
/// </summary>
/// <param name="creFilter">One element filter utility object.</param>
/// <param name="doc">Revit project.</param>
/// <param name="onlyUpdateSelect">
/// true means only update selected doors' information else false.
/// </param>
public static void UpdateDoorsGeometry(Document doc, bool onlyUpdateSelect)
{
IEnumerator iter;
int doorCount = 0;
if (onlyUpdateSelect) // update doors in select elements
{
UIDocument newUIdoc = new UIDocument(doc);
ElementSet es = new ElementSet();
foreach (ElementId elementId in newUIdoc.Selection.GetElementIds())
{
es.Insert(newUIdoc.Document.GetElement(elementId));
}
iter = es.GetEnumerator();
}
else // update all doors in current Revit document
{
ElementClassFilter familyInstanceFilter = new ElementClassFilter(typeof(FamilyInstance));
ElementCategoryFilter doorsCategoryfilter = new ElementCategoryFilter(BuiltInCategory.OST_Doors);
LogicalAndFilter doorInstancesFilter = new LogicalAndFilter(familyInstanceFilter, doorsCategoryfilter);
iter = new FilteredElementCollector(doc).WherePasses(doorInstancesFilter).GetElementIterator();
}
iter.Reset();
while (iter.MoveNext())
{
// find door instance
FamilyInstance door = iter.Current as FamilyInstance;
if (onlyUpdateSelect)
{
if (null == door)
{
continue;
}
if (null == door.Category)
{
continue;
}
if (!door.Category.Name.Equals("Doors"))
{
continue;
}
}
// find one door.
doorCount++;
// update one door.
UpdateFromToRoomofOneDoor(door, true);
doc.Regenerate();
}
if (onlyUpdateSelect)
{
Autodesk.Revit.UI.TaskDialog.Show("Door Swing", "Updated all selected doors (" + doorCount +
" doors).\r\n (Selection may include miscellaneous elements.)");
}
else
{
Autodesk.Revit.UI.TaskDialog.Show("Door Swing", "Updated all doors of this project (" +
doorCount + " doors).");
}
}
/// <summary>
/// Update doors' Left/Right information.
/// </summary>
/// <param name="door">one door instance.</param>
private static Autodesk.Revit.UI.Result UpdateOpeningFeatureOfOneDoor(FamilyInstance door)
{
// flag whether the opening value should switch from its corresponding family's basic opening value.
bool switchesOpeningValueFlag = false;
// When the door is being mirrored once, the door switches its direction;
// When the door is being flipped once, the door switches its direction.
// When the door is being mirrored and flipped, the door's direction remains the same.
if (door.FacingFlipped ^ door.HandFlipped)
{
switchesOpeningValueFlag = true;
}
// get door's Opening parameter which indicates whether the door is Left or Right.
Parameter openingParam = door.ParametersMap.get_Item("InstanceOpening");
// country's standard Left/Right opening for this door type.
String basalOpeningValue = door.Symbol.ParametersMap.get_Item("BasalOpening").AsString();
string rightOpeningValue; // actual opening value of the door.
if (switchesOpeningValueFlag)
{
if (DoorSwingResource.LeftDoor.Equals(basalOpeningValue))
{
rightOpeningValue = DoorSwingResource.RightDoor;
}
else if (DoorSwingResource.RightDoor.Equals(basalOpeningValue))
{
rightOpeningValue = DoorSwingResource.LeftDoor;
}
else if (DoorSwingResource.TwoLeafActiveLeafLeft.Equals(basalOpeningValue))
{
rightOpeningValue = DoorSwingResource.TwoLeafActiveLeafRight;
}
else if (DoorSwingResource.TwoLeafActiveLeafRight.Equals(basalOpeningValue))
{
rightOpeningValue = DoorSwingResource.TwoLeafActiveLeafLeft;
}
else if (DoorSwingResource.TwoLeaf.Equals(basalOpeningValue))
{
rightOpeningValue = DoorSwingResource.TwoLeaf;
}
else if (DoorSwingResource.Undefined.Equals(basalOpeningValue))
{
rightOpeningValue = DoorSwingResource.Undefined;
}
else
{
return Autodesk.Revit.UI.Result.Failed;
}
}
else
{
if (OpeningTypes.Contains(basalOpeningValue))
{
rightOpeningValue = basalOpeningValue;
}
else
{
return Autodesk.Revit.UI.Result.Failed;
}
}
// update door's Opening param.
openingParam.Set(rightOpeningValue);
return Autodesk.Revit.UI.Result.Succeeded;
}
/// <summary>
/// Update one door's internalDoor flag which indicates the door is internal door or external door.
/// </summary>
/// <param name="door">one door instance.</param>
private static void UpdateInternalDoorFlagFeatureofOneDoor(FamilyInstance door)
{
// get the "Internal Door" shared parameter.
Parameter internalDoorFlagParam = door.ParametersMap.get_Item("Internal Door");
// "Internal Door" is decided based on whether door's ToRoom and FromRoom properties both have values.
// 1 means internal door, 0 means external door.
if (null != door.ToRoom && null != door.FromRoom) // considered as internal door.
{
internalDoorFlagParam.Set(1);
}
else
{
internalDoorFlagParam.Set(0); // considered as external door.
}
}
/// <summary>
/// Doors related rooms: update one door's To/From room information or geometry.
/// </summary>
/// <param name="door">one door instance.</param>
/// <param name="updateGeo">
/// true means update geometry else update To/From room information.
/// </param>
private static void UpdateFromToRoomofOneDoor(FamilyInstance door, bool updateGeo)
{
if (null == door.ToRoom && null == door.FromRoom)
{
return;
}
// update the door's geometry according to door's To/From room info.
// standard: door.ToRoom should keep consistent with door.Room else need update.
if ((null == door.Room) && (null == door.FromRoom))
{
// only external door may have this status.
// door.Room are consistent with door.FromRoom, so need update.
if (updateGeo) // update geometry
{
door.flipHand();
door.flipFacing();
}
else // update To/From Room.
{
door.FlipFromToRoom();
}
}
else if ((null != door.Room) && (null != door.FromRoom))
{
// door.Room are consistent with door.FromRoom, so need update.
if (door.Room.Id.IntegerValue.Equals(door.FromRoom.Id.IntegerValue))
{
if (updateGeo) // update geometry
{
door.flipHand();
door.flipFacing();
}
else // update To/From Room.
{
door.FlipFromToRoom();
}
}
}
}
/// <summary>
/// Iterate through plan topology to determine if all plan circuits have assigned rooms.
/// </summary>
/// <param name="doc">Revit project.</param>
/// <returns> true means all plan circuits have assigned rooms else not.</returns>
private static bool AssignedAllRooms(Document doc)
{
PlanTopologySet planTopologies = doc.PlanTopologies;
// Iterate plan topology for each level.
foreach (PlanTopology planTopology in planTopologies)
{
PlanCircuitSet circuits = planTopology.Circuits;
// Iterate each circuit in this plan topology.
foreach (PlanCircuit circuit in circuits)
{
bool locatedRoom = circuit.IsRoomLocated;
if (!locatedRoom)
{
// If any circuit isn't assigned room, then method return false.
return locatedRoom;
}
}
}
return true;
}
/// <summary>
/// Do Door symbols' Opening set based on family's basic geometry and country's standard.
/// </summary>
public void UpdateDoorFamiliesOpeningFeature()
{
for (int i = 0; i < m_doorFamilies.Count; i++)
{
m_doorFamilies[i].UpdateOpeningFeature();
}
}
/// <summary>
/// Delete temporarily created door instances which are used to retrieve geometry. Retrieved
/// geometry will shown to users. So they can initialize door opening parameter more visually.
/// </summary>
public void DeleteTempDoorInstances()
{
for (int i = 0; i < m_doorFamilies.Count; i++)
{
m_doorFamilies[i].DeleteTempDoorInstance();
}
}
/// <summary>
/// get all the door families in the project.
/// And store them in two lists separately based on opening parameter.
/// </summary>
private void PrepareDoorFamilies()
{
// prepare DoorFamilies
FilteredElementIterator familyIter = new FilteredElementCollector(m_app.ActiveUIDocument.Document).OfClass(typeof(Family)).GetElementIterator();
while (familyIter.MoveNext())
{
Family doorFamily = familyIter.Current as Family;
if (null == doorFamily.FamilyCategory) // some family.FamilyCategory is null
{
continue;
}
if (doorFamily.FamilyCategory.Name !=
m_app.ActiveUIDocument.Document.Settings.Categories.get_Item(BuiltInCategory.OST_Doors).Name) // FamilyCategory.Name is not 'Doors'
{
continue;
}
// create one instance of self class DoorFamily.
DoorFamily tempDoorFamily = new DoorFamily(doorFamily, m_app);
// store the created DoorFamily instance
m_doorFamilies.Add(tempDoorFamily);
}
}
#endregion
}
}