//
// (C) Copyright 2003-2010 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.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Reflection;
using Autodesk.Revit;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Panel = Autodesk.Revit.DB.Panel;
using Element = Autodesk.Revit.DB.Element;
using Instance = Autodesk.Revit.DB.Instance;
namespace Revit.SDK.Samples.MeasurePanelArea.CS
{
///
/// The window designed for interactive operations
///
public partial class frmPanelArea : System.Windows.Forms.Form
{
///
/// The revit application instance
///
Autodesk.Revit.UI.UIApplication m_uiApp;
///
/// The active Revit document
///
UIDocument m_uiDoc;
///
/// record the panel type specified by the user.
/// the panel with an area is greater than "m_maxValue" will be changed to this type
///
string m_maxType = "";
///
/// record the panel type specified by the user.
/// the panel with an area in the range [m_minValue, m_maxValue] will be changed to this type
///
string m_midType = "";
///
/// record the panel type specified by the user.
/// the panel with an area is smaller than "m_minValue" will be changed to this type
///
string m_minType = "";
///
/// Record the minimum value of the desired panel area
///
double m_minValue = 0;
///
/// Record the maximum value of the desired panel area
///
double m_maxValue = 0;
///
/// Record how many panels have an area larger than the maximum value
///
int m_maxCounter = 0;
///
/// Record how many panels have an area smaller than the minimum value
///
int m_minCounter = 0;
///
/// Record how many panels have an area in the range [m_minValue, m_maxValue]
///
int m_okCounter = 0;
///
/// Store all the divided surface selected by user or store all the divided surface in the document if user selects nothing
///
List m_dividedSurfaceList = new List();
///
/// A stream used to record the panel's element id and area to a text file
///
StreamWriter m_writeFile = null;
///
/// Constructor
///
///
/// An object that is passed to the external application
/// which contains data related to the command,
/// such as the application object and active view.
public frmPanelArea(ExternalCommandData commandData)
{
m_uiApp = commandData.Application;
m_uiDoc = m_uiApp.ActiveUIDocument;
InitializeComponent();
BuildPanelTypeList();
}
///
/// Handle the event triggered when user clicks the "Compute" button:
/// 1. compute all the panel areas;
/// 2. compare the areas with the range, mark the panels with different types;
/// 3. record the result to a text file
///
///
///
private void btnCompute_Click(object sender, EventArgs e)
{
m_minValue = Convert.ToDouble(txtMin.Text);
m_maxValue = Convert.ToDouble(txtMax.Text);
SetPanelTypesFromUI();
string assemblyName = Assembly.GetExecutingAssembly().Location;
string assemblyDirectory = Path.GetDirectoryName(assemblyName);
m_writeFile = new StreamWriter(assemblyDirectory + @"\" + "_PanelArea.txt");
m_writeFile.WriteLine("Panel Element ID : Area");
GetDividedSurfaces();
foreach (DividedSurface ds in m_dividedSurfaceList)
{
ExamineDividedSurface(ds);
}
m_writeFile.WriteLine(m_maxCounter + " panels larger than " + m_maxValue);
m_writeFile.WriteLine(m_minCounter + " panels smaller than " + m_minValue);
m_writeFile.WriteLine(m_okCounter + " panels within desired range");
m_writeFile.Close();
Close();
}
///
/// Get names of Panel families and populate drop-down lists in the UI
///
private void BuildPanelTypeList()
{
IList list = GetPanels();
if (list.Count == 0)
{
MessageBox.Show("There are no panel families loaded in your project");
btnCompute.Enabled = false;
Close();
return;
}
FamilySymbol fs = list[0].ObjectType as FamilySymbol;
string famDelimiter = ":";
foreach (Autodesk.Revit.DB.FamilySymbol famSymbol in fs.Family.Symbols)
{
cboxMax.Items.Add(fs.Family.Name + famDelimiter + famSymbol.Name);
cboxMin.Items.Add(fs.Family.Name + famDelimiter + famSymbol.Name);
cboxMid.Items.Add(fs.Family.Name + famDelimiter + famSymbol.Name);
}
cboxMax.SelectedIndex = 0;
cboxMin.SelectedIndex = 0;
cboxMid.SelectedIndex = 0;
}
///
/// Analyse the panel types set by UI operation
///
private void SetPanelTypesFromUI()
{
//Set the min, mid, and max panel types based on user selections in the UI
string minFamilyAndType = Convert.ToString(cboxMin.Text);
string maxFamilyAndType = Convert.ToString(cboxMax.Text);
string midFamilyAndType = Convert.ToString(cboxMid.Text);
string delimStr = ":";
char[] delimiter = delimStr.ToCharArray();
string[] split = minFamilyAndType.Split(delimiter);
m_minType = split[1];
split = maxFamilyAndType.Split(delimiter);
m_maxType = split[1];
split = midFamilyAndType.Split(delimiter);
m_midType = split[1];
}
///
/// Populate DividedSurfaceArray with the selected surfaces or all surfaces in the model
///
private void GetDividedSurfaces()
{
// want to compute all the divided surfaces
if (m_uiDoc.Selection.Elements.Size == 0)
{
m_dividedSurfaceList = GetElements();
return;
}
// user selects some divided surface
foreach (Element element in m_uiDoc.Selection.Elements)
{
DividedSurface ds = element as DividedSurface;
if (ds != null)
{
m_dividedSurfaceList.Add(ds);
}
}
}
///
/// Compute the area of the curtain panel instance
///
///
/// the curtain panel which needs to be computed
///
///
/// the area of the curtain panel
///
private double GetAreaOfTileInstance(FamilyInstance familyinstance)
{
double panelArea = 0d;
Autodesk.Revit.DB.Options opt = m_uiApp.Application.Create.NewGeometryOptions();
opt.ComputeReferences = true;
Autodesk.Revit.DB.GeometryElement geomElem = familyinstance.get_Geometry(opt);
foreach (GeometryObject geomObject1 in geomElem.Objects)
{
Solid solid = null;
// find area of partial border panels
if (geomObject1 is Solid)
{
solid = (Solid)geomObject1;
if (null == solid)
{
continue;
}
}
// find area of non-partial panels
else if (geomObject1 is GeometryInstance)
{
GeometryInstance geomInst = geomObject1 as GeometryInstance;
foreach (Object geomObj in geomInst.SymbolGeometry.Objects)
{
solid = geomObj as Solid;
if (solid != null)
break;
}
}
if (null == solid.Faces || 0 == solid.Faces.Size)
{
continue;
}
// get the area and write the data to a text file
foreach (Face face in solid.Faces)
{
panelArea = face.Area;
m_writeFile.WriteLine(familyinstance.Id.IntegerValue + " : " + panelArea);
}
}
return panelArea;
}
///
/// Check all the panels whose areas are below/above/within the range in the divided surface, mark them with different symbols
///
///
/// The divided surfaces created in the document, it contains the panels for checking
///
void ExamineDividedSurface(DividedSurface ds)
{
ElementType sym = ds.ObjectType;
FamilySymbol fs_min = null;
FamilySymbol fs_max = null;
FamilySymbol fs_mid = null;
// get the panel types which are used to identify the panels in the divided surface
FamilySymbol fs = sym as FamilySymbol;
foreach (FamilySymbol symbol in fs.Family.Symbols)
{
if (symbol.Name == m_maxType)
{
fs_max = symbol;
}
if (symbol.Name == m_minType)
{
fs_min = symbol;
}
if (symbol.Name == m_midType)
{
fs_mid = symbol;
}
}
// find all the panels areas and compare with the range
for (int u = 0; u < ds.NumberOfUGridlines; u++ )
{
for (int v = 0; v < ds.NumberOfVGridlines; v++ )
{
GridNode gn = new GridNode(u, v);
if (false == ds.IsSeedNode(gn))
{
continue;
}
FamilyInstance familyinstance = ds.GetTileFamilyInstance(gn, 0);
if (familyinstance != null)
{
double panelArea = GetAreaOfTileInstance(familyinstance);
// identify the panels drop in different ranges with different types
if (panelArea > m_maxValue)
{
familyinstance.Symbol = fs_max;
m_maxCounter++;
}
else if (panelArea < m_minValue)
{
familyinstance.Symbol = fs_min;
m_minCounter++;
}
else
{
familyinstance.Symbol = fs_mid;
m_okCounter++;
}
}
}
}
}
protected List GetElements() where T : Element
{
List returns = new List();
FilteredElementCollector collector = new FilteredElementCollector(m_uiDoc.Document);
ICollection founds = collector.OfClass(typeof(T)).ToElements();
foreach (Element elem in founds)
{
returns.Add(elem as T);
}
return returns;
}
protected IList GetPanels()
{
IList panels = null;
FilteredElementCollector collector = new FilteredElementCollector(m_uiDoc.Document);
collector.OfClass(typeof(FamilyInstance)).OfCategory(BuiltInCategory.OST_CurtainWallPanels);
panels = collector.ToElements();
return panels;
}
}
}