Joe Stott recently posted about using Ceilings to model floor finishes in Revit, because the Automatic Ceiling tool finds the ceiling boundaries, er, automatically.
But it would be better BIM if the floor finishes were modelled as Floors. And I’ve always though there should be some way of connecting a Room’s Floor Finish property with the modelled floor finish.
So, as a proof of concept, here is a VSTA macro for R2012: MakeFloorsForSelectedRooms.
For each Room you’ve selected, it makes a new floor the same shape as the Room. The floor type is taken from the Room’s Floor Finish property:
- If there’s a Floor Type with a matching name, the new floor will be of that type.
- If there isn’t a matching Floor Type, a new Type is created.
- If the Floor Finish property is blank, the new Floor will be a new default type.
As a proof of concept, it’s still a bit rough around the edges. And there are lots of ways in which it could be extended. As usual, the code comes with no warranties: Experiment at your own risk.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Autodesk.Revit.DB;
using DBArch = Autodesk.Revit.DB.Architecture;
namespace RoomFloors
{
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
[Autodesk.Revit.VSTA.AddInId("039bfb1c-5582-4afc-ab85-491abcf2484a")]
public partial class ThisApplication
{
#region Fields
public int MakeOpeningExceptionCount { get; set; }
public int MakeFloorExceptionCount { get; set; }
private FloorType defaultFloorType;
#endregion
#region Startup and Shutdown
private void Module_Startup(object sender, EventArgs e)
{
}
private void Module_Shutdown(object sender, EventArgs e)
{
}
#endregion
#region VSTA generated code
private void InternalStartup()
{
this.Startup += new System.EventHandler(Module_Startup);
this.Shutdown += new System.EventHandler(Module_Shutdown);
}
#endregion
public void MakeFloorsForSelectedRooms()
{
Transaction transaction = new Transaction(ActiveUIDocument.Document);
if (transaction.Start("Create new floors") == TransactionStatus.Started)
{
defaultFloorType = GetDefaultFloorType();
Autodesk.Revit.UI.Selection.SelElementSet collection = ActiveUIDocument.Selection.Elements;
foreach (Autodesk.Revit.DB.Element element in collection)
{
if (element is DBArch.Room)
{
MakeFloorForRoom(element as DBArch.Room);
}
}
transaction.Commit();
}
}
#region Floor Making
private void MakeFloorForRoom(DBArch.Room room)
{
SpatialElementBoundaryOptions options = new SpatialElementBoundaryOptions();
IList<IList<BoundarySegment>> bounds = room.GetBoundarySegments(options);
CurveArrArray boundsArray = new CurveArrArray();
Floor floor = null;
bool outerLoop = true;
foreach (IList<BoundarySegment> loop in bounds)
{
CurveArray profile = new CurveArray();
foreach (BoundarySegment segment in loop)
{
Curve curve = segment.Curve;
profile.Append(curve);
}
if (outerLoop)
{
FloorType newFloorType;
string newFloorTypeName = GetFloorTypeName(room);
if ("" == newFloorTypeName)
{ newFloorType = defaultFloorType; }
else { newFloorType = GetOrMakeFloorType(newFloorTypeName); }
floor = MakeAFloor(profile, room.Level, room.BaseOffset, newFloorType);
outerLoop = false;
}
else
{
if (null != floor) { MakeAnOpening(floor, profile); }
}
}
}
private string GetFloorTypeName(DBArch.Room room)
{
string newFloorTypeName = GetProperty(room, BuiltInParameter.ROOM_FINISH_FLOOR);
if (null == newFloorTypeName) { newFloorTypeName = ""; }
return newFloorTypeName;
}
private Floor MakeAFloor(CurveArray loop, Level level, double offset, FloorType newFloorType)
{
Floor newFloor = null;
try
{
newFloor = ActiveUIDocument.Document.Create.NewFloor(loop, newFloorType, level, false);
}
catch (Exception ex)
{
MakeFloorExceptionCount++;
Debug.WriteLine("Exception: " + ex.Message);
//throw;
}
if (null != newFloor)
{
BuiltInParameter paraIndex = BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM;
Parameter parameter = newFloor.get_Parameter(paraIndex);
parameter.Set(offset + GetFloorThickness(defaultFloorType));
}
return newFloor;
}
private void MakeAnOpening(Floor floor, CurveArray loop)
{
try
{
Opening newOpening = ActiveUIDocument.Document.Create.NewOpening(floor, loop, true);
}
catch (Exception ex)
{
MakeOpeningExceptionCount++;
Debug.WriteLine("Exception: " + ex.Message);
//throw;
}
}
#endregion
#region Floor Types
private FloorType GetDefaultFloorType()
{
string newFloorTypeName = GetUniqueFloorTypeName();
return MakeNewFloorType(newFloorTypeName);
}
private FloorType MakeNewFloorType(string newFloorTypeName)
{
FloorType newFloortype = (FloorType)GetFloorType().Duplicate(newFloorTypeName);
return newFloortype;
}
private string GetUniqueFloorTypeName()
{
int index = 0;
string proposedFloorTypeName;
do
{
index++;
proposedFloorTypeName = "DefaultFloorType" + index.ToString();
} while (!IsUniqueName(proposedFloorTypeName));
return proposedFloorTypeName;
}
private bool IsUniqueName(string proposedFloorTypeName)
{
FloorTypeSet floorTypes = ActiveUIDocument.Document.FloorTypes;
bool isUniqueName = true;
foreach (FloorType floorType in floorTypes)
{
if (floorType.Name == proposedFloorTypeName) { isUniqueName = false; }
}
return isUniqueName;
}
private FloorType GetFloorType()
{
FloorType myFloorType = null;
FloorTypeSet floorTypes = ActiveUIDocument.Document.FloorTypes;
foreach (FloorType floorType in floorTypes)
{
myFloorType = floorType;
}
if (null == myFloorType)
{ throw new Exception("No FloorTypes in Document"); }
return myFloorType;
}
private FloorType GetOrMakeFloorType(string floorTypeName)
{
FloorType myFloorType = null;
FloorTypeSet floorTypes = ActiveUIDocument.Document.FloorTypes;
foreach (FloorType floorType in floorTypes)
{
if (floorTypeName == floorType.Name)
{ myFloorType = floorType; }
}
if (null == myFloorType)
{ myFloorType = MakeNewFloorType(floorTypeName); }
return myFloorType;
}
private double GetFloorThickness(FloorType floorType)
{
//return 1; //in feet;
double floorThickness = 0;
CompoundStructure comStruct = floorType.GetCompoundStructure();
foreach (CompoundStructureLayer structLayer in comStruct.GetLayers())
{ floorThickness += structLayer.Width; }
return floorThickness;
}
#endregion
#region Utility
public String GetProperty(DBArch.Room room, BuiltInParameter paramEnum)
{
String propertyValue = null; //the value of parameter
//get the parameter via the parameterId
Parameter param = room.get_Parameter(paramEnum);
//get the parameter's storage type
StorageType storageType = param.StorageType;
switch (storageType)
{
case StorageType.Integer:
int iVal = param.AsInteger();
propertyValue = iVal.ToString();
break;
case StorageType.String:
String stringVal = param.AsString();
propertyValue = stringVal;
break;
case StorageType.Double:
Double dVal = param.AsDouble();
dVal = Math.Round(dVal, 2);
propertyValue = dVal.ToString();
break;
default:
break;
}
return propertyValue;
}
#endregion
}
}