Files
2024-12-12 09:51:40 +01:00

536 lines
19 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.
//
namespace Revit.SDK.Samples.FrameBuilder.CS
{
using System;
using System.Text;
using System.Collections.Generic;
using Autodesk.Revit;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using UV = Autodesk.Revit.DB.UV;
/// <summary>
/// data class contains information to create framing
/// </summary>
public class FrameData
{
const int XNumberMaxValue = 50; // maximum number of Columns in the X Direction
const int XNumberMinValue = 2; // minimum number of Columns in the X Direction
const int XNumberDefault = 3; // default number of Columns in the X Direction
const int YNumberMaxValue = 50; // maximum number of Columns in the Y Direction
const int YNumberMinValue = 2; // minimum number of Columns in the Y Direction
const int YNumberDefault = 3; // default number of Columns in the Y Direction
const int TotalMaxValue = 200; // maximum total number of Columns to create
const int FloorNumberMinValue = 1; // minimum number of floors
const int FloorNumberMaxValue = 200; // maximum number of floors
const double DistanceMaxValue = 3000; // maxinum distance between 2 adjoining columns
const double DistanceMinValue = 1; // mininum distance between 2 adjoining columns
const double DistanceDefault = 5; // default distance between 2 adjoining columns
const double LevelHeightMaxValue = 100; // maximum height between 2 new levels
const double LevelHeightMinValue = 1; // minimum height between 2 new levels
const int DigitPrecision = 4; // the number of significant digits(precision)
int m_xNumber = XNumberDefault; // number of Columns in the X Direction
int m_yNumber = XNumberDefault; // number of Columns in the Y Direction
double m_distance = DistanceDefault; // distance between 2 adjoining columns
int m_floorNumber; // number of floors
double m_levelHeight; // increaced height of autogenerated levels
Autodesk.Revit.DB.UV m_frameOrigin = new Autodesk.Revit.DB.UV(0.0, 0.0); // bottom left point of the frame
double m_frameOriginAngle = 0.0; // the angle to rotate around bottom left point
int m_originalLevelSize; // the number of levels before invoke external command
FamilySymbol m_columnSymbol; // column's type
FamilySymbol m_beamSymbol; // beam's type
FamilySymbol m_braceSymbol; // brace's type
ExternalCommandData m_commandData;
FrameTypesMgr m_columnSymbolsMgr; // object manage all column types
FrameTypesMgr m_beambracesSymbolsMgr; // object manage all beam types
SortedList<double, Level> m_levels; // list of all levels in the order of Elevation
/// <summary>
/// command data pass from entry point
/// </summary>
public ExternalCommandData CommandData
{
get
{
return m_commandData;
}
}
/// <summary>
/// object manage all column types
/// </summary>
public FrameTypesMgr ColumnSymbolsMgr
{
get
{
return m_columnSymbolsMgr;
}
}
/// <summary>
/// object manage all beam types
/// </summary>
public FrameTypesMgr BeamSymbolsMgr
{
get
{
return m_beambracesSymbolsMgr;
}
}
/// <summary>
/// object manage all brace types
/// </summary>
public FrameTypesMgr BraceSymbolsMgr
{
get
{
return m_beambracesSymbolsMgr;
}
}
/// <summary>
/// number of Columns in the Y Direction
/// </summary>
public int YNumber
{
get
{
return m_yNumber;
}
set
{
if (value < YNumberMinValue || value > YNumberMaxValue)
{
string message = "Number of Columns in the Y Direction should no less than "
+ YNumberMinValue.ToString() + " and no more than "
+ YNumberMaxValue.ToString();
throw new ErrorMessageException(message);
}
CheckTotalNumber(value * XNumber * (m_floorNumber - 1));
m_yNumber = value;
}
}
/// <summary>
/// number of Columns in the X Direction
/// </summary>
public int XNumber
{
get
{
return m_xNumber;
}
set
{
if (value < XNumberMinValue || value > XNumberMaxValue)
{
string message = "Number of Columns in the X Direction should no less than "
+ XNumberMinValue.ToString() + " and no more than "
+ XNumberMaxValue.ToString();
throw new ErrorMessageException(message);
}
CheckTotalNumber(value * YNumber * (m_floorNumber - 1));
m_xNumber = value;
}
}
/// <summary>
/// distance between 2 adjoining columns
/// </summary>
public double Distance
{
get
{
return m_distance;
}
set
{
if (value < DistanceMinValue || value > DistanceMaxValue)
{
string message = "The distance between columns shoule no less than "
+ DistanceMinValue.ToString() + "and no more than "
+ DistanceMaxValue.ToString();
throw new ErrorMessageException(message);
}
m_distance = value;
}
}
/// <summary>
/// number of floors
/// </summary>
public int FloorNumber
{
get
{
return m_floorNumber;
}
set
{
if (value < FloorNumberMinValue || value > FloorNumberMaxValue)
{
string message = "Number of floors should no less than "
+ FloorNumberMinValue.ToString() + " and no more than "
+ FloorNumberMaxValue.ToString();
throw new ErrorMessageException(message);
}
CheckTotalNumber(XNumber * YNumber * (value - 1));
m_floorNumber = value;
}
}
/// <summary>
/// increased height of autogenerated levels
/// </summary>
public double LevelHeight
{
get
{
return Math.Round(m_levelHeight, DigitPrecision);
}
set
{
if (value < LevelHeightMinValue || value > LevelHeightMaxValue)
{
string message = "The distance between columns shoule no less than "
+ LevelHeightMinValue.ToString() + "and no more than "
+ LevelHeightMaxValue.ToString();
throw new ErrorMessageException(message);
}
m_distance = value;
}
}
/// <summary>
/// bottom left point of the frame
/// </summary>
public Autodesk.Revit.DB.UV FrameOrigin
{
get
{
return m_frameOrigin;
}
set
{
m_frameOrigin = value;
}
}
/// <summary>
/// the angle to rotate around bottom left point
/// </summary>
public double FrameOriginAngle
{
get
{
return m_frameOriginAngle;
}
set
{
m_frameOriginAngle = value;
}
}
/// <summary>
/// column's type
/// </summary>
public FamilySymbol ColumnSymbol
{
get
{
return m_columnSymbol;
}
}
/// <summary>
/// beam's type
/// </summary>
public FamilySymbol BeamSymbol
{
get
{
return m_beamSymbol;
}
}
/// <summary>
/// brace's type
/// </summary>
public FamilySymbol BraceSymbol
{
get
{
return m_braceSymbol;
}
}
/// <summary>
/// list of all levels in the ordr of Elevation
/// </summary>
public SortedList<double, Level> Levels
{
get
{
return m_levels;
}
}
/// <summary>
/// the number of levels before invoke external command
/// </summary>
public int OriginalLevelSize
{
get
{
return m_originalLevelSize;
}
}
/// <summary>
/// create FramingData object. applicationException will throw out,
/// if current Revit document doesn't satisfy the condition to create framing
/// </summary>
/// <param name="commandData"></param>
/// <returns></returns>
public static FrameData CreateInstance(ExternalCommandData commandData)
{
FrameData data = new FrameData(commandData);
data.Initialize();
data.Validate();
// initialize members after checking precondition
data.m_floorNumber = (data.m_levels.Count - 1) > 0 ? (data.m_levels.Count - 1) : 1;
data.m_columnSymbol = data.m_columnSymbolsMgr.FramingSymbols[0];
data.m_beamSymbol = data.m_beambracesSymbolsMgr.FramingSymbols[0];
data.m_braceSymbol = data.m_beambracesSymbolsMgr.FramingSymbols[0];
data.m_levelHeight = data.m_levels.Values[data.m_levels.Count - 1].Elevation
- data.m_levels.Values[data.m_levels.Count - 2].Elevation;
return data;
}
/// <summary>
/// cast object to FamilySymbol and set as column's type
/// </summary>
/// <param name="obj">FamilySymbol object</param>
/// <returns>failed to cast and set</returns>
public bool SetColumnSymbol(object obj)
{
FamilySymbol symbol = obj as FamilySymbol;
if (null == symbol)
{
return false;
}
m_columnSymbol = symbol;
return true;
}
/// <summary>
/// cast object to FamilySymbol and set as beam's type
/// </summary>
/// <param name="obj">FamilySymbol object</param>
/// <returns>failed to cast and set</returns>
public bool SetBeamSymbol(object obj)
{
FamilySymbol symbol = obj as FamilySymbol;
if (null == symbol)
{
return false;
}
m_beamSymbol = symbol;
return true;
}
/// <summary>
/// cast object to FamilySymbol and set as brace's type
/// </summary>
/// <param name="obj">FamilySymbol object</param>
/// <returns>failed to cast and set</returns>
public bool SetBraceSymbol(object obj)
{
FamilySymbol symbol = obj as FamilySymbol;
if (null == symbol)
{
return false;
}
m_braceSymbol = symbol;
return true;
}
/// <summary>
/// add more levels so that level number can meet floor number
/// </summary>
public void UpdateLevels()
{
double baseElevation = m_levels.Values[m_levels.Count - 1].Elevation;
Autodesk.Revit.Creation.Document createDoc = m_commandData.Application.ActiveUIDocument.Document.Create;
Autodesk.Revit.DB.Document m_Doc = m_commandData.Application.ActiveUIDocument.Document;
FilteredElementCollector collector = new FilteredElementCollector(m_Doc);
IList<Element> viewFamilyTypes = collector.OfClass(typeof(ViewFamilyType)).ToElements();
ElementId floorPlanId = new ElementId(-1);
foreach (Element e in viewFamilyTypes)
{
ViewFamilyType v = e as ViewFamilyType;
if (v != null && v.ViewFamily == ViewFamily.FloorPlan)
{
floorPlanId = e.Id;
break;
}
}
int newLevelSize = (m_floorNumber + 1) - m_levels.Count;
if (newLevelSize == 0)
{
return;
}
for (int ii = 0; ii < newLevelSize; ii++)
{
double elevation = baseElevation + m_levelHeight * (ii + 1);
Level newLevel = Level.Create(m_commandData.Application.ActiveUIDocument.Document, elevation);
//createDoc.NewViewPlan(newLevel.Name, newLevel, Autodesk.Revit.DB.ViewPlanType.FloorPlan);
ViewPlan viewPlan = ViewPlan.Create(m_Doc, floorPlanId, newLevel.Id);
viewPlan.Name = newLevel.Name;
m_levels.Add(elevation, newLevel);
}
m_originalLevelSize = m_levels.Count;
}
/// <summary>
/// it is only used for object factory method
/// </summary>
/// <param name="commandData"></param>
private FrameData(ExternalCommandData commandData)
{
// initialize members
m_commandData = commandData;
m_columnSymbolsMgr = new FrameTypesMgr(commandData);
m_beambracesSymbolsMgr = new FrameTypesMgr(commandData);
m_levels = new SortedList<double, Level>();
m_originalLevelSize = m_levels.Count;
m_yNumber = YNumberDefault;
m_xNumber = XNumberDefault;
m_distance = DistanceDefault;
}
/// <summary>
/// check the total number of columns to create less than certain value
/// </summary>
/// <param name="number"></param>
/// <returns></returns>
private static void CheckTotalNumber(int number)
{
if (number > TotalMaxValue)
{
string message = "The total number of columns should less than "
+ TotalMaxValue.ToString();
throw new ErrorMessageException(message);
}
}
/// <summary>
/// initialize list of column, beam and brace's type;
/// initialize list of level
/// </summary>
private void Initialize()
{
Application app = m_commandData.Application.Application;
Document doc = m_commandData.Application.ActiveUIDocument.Document;
FilteredElementCollector collector1 = new FilteredElementCollector(doc);
IList<Autodesk.Revit.DB.Element> a1 = collector1.OfClass(typeof(Level)).ToElements();
foreach (Level lev in a1)
{
m_levels.Add(lev.Elevation, lev);
}
a1.Clear();
Categories categories = doc.Settings.Categories;
BuiltInCategory bipColumn = BuiltInCategory.OST_StructuralColumns;
BuiltInCategory bipFraming = BuiltInCategory.OST_StructuralFraming;
Autodesk.Revit.DB.ElementId idColumn = categories.get_Item(bipColumn).Id;
Autodesk.Revit.DB.ElementId idFraming = categories.get_Item(bipFraming).Id;
ElementCategoryFilter filterColumn = new ElementCategoryFilter(bipColumn);
ElementCategoryFilter filterFraming = new ElementCategoryFilter(bipFraming);
LogicalOrFilter orFilter = new LogicalOrFilter(filterColumn, filterFraming);
ElementClassFilter filterSymbol = new ElementClassFilter(typeof(FamilySymbol));
LogicalAndFilter andFilter = new LogicalAndFilter(orFilter, filterSymbol);
//
// without filtering for the structural categories,
// our sample project was returning over 500 family symbols;
// adding the category filters reduced this number to 40:
//
FilteredElementCollector collector2 = new FilteredElementCollector(doc);
IList<Element> a2 = collector2.WherePasses(andFilter).ToElements();
foreach (FamilySymbol symbol in a2)
{
Autodesk.Revit.DB.ElementId categoryId = symbol.Category.Id;
if (idFraming.Equals(categoryId))
{
m_beambracesSymbolsMgr.AddSymbol(symbol);
}
else if (idColumn.Equals(categoryId))
{
m_columnSymbolsMgr.AddSymbol(symbol);
}
}
}
/// <summary>
/// validate the precondition to create framing
/// </summary>
private void Validate()
{
// level shouldn't less than 2
if (m_levels.Count < 2)
{
throw new ErrorMessageException("The level's number in active document is less than 2.");
}
// no Structural Column family is loaded in current document
if (m_columnSymbolsMgr.Size == 0)
{
throw new ErrorMessageException("No Structural Column family is loaded in current project.");
}
// no Structural Beam family is loaded in current document
if (m_beambracesSymbolsMgr.Size == 0)
{
throw new ErrorMessageException("No Structural Beam family is loaded in current project.");
}
}
}
}