// // (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.Windows.Forms; using System.Collections; using System.Xml; using Autodesk.Revit; using Autodesk.Revit.DB; using Autodesk.Revit.UI; namespace Revit.SDK.Samples.AllViews.CS { /// /// Implements the Revit add-in interface IExternalCommand /// [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)] [Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)] [Autodesk.Revit.Attributes.Journaling(Autodesk.Revit.Attributes.JournalingMode.NoCommandData)] public class Command : IExternalCommand { #region IExternalCommand Members Implementation /// /// Implement this method as an external command for Revit. /// /// An object that is passed to the external application /// which contains data related to the command, /// such as the application object and active view. /// A message that can be set by the external application /// which will be displayed if a failure or cancellation is returned by /// the external command. /// A set of elements to which the external application /// can add elements that are to be highlighted in case of failure or cancellation. /// Return the status of the external command. /// A result of Succeeded means that the API external method functioned as expected. /// Cancelled can be used to signify that the user cancelled the external operation /// at some point. Failure should be returned if the application is unable to proceed with /// the operation. public Autodesk.Revit.UI.Result Execute(Autodesk.Revit.UI.ExternalCommandData commandData, ref string message, Autodesk.Revit.DB.ElementSet elements) { Transaction newTran = null; try { if (null == commandData) { throw new ArgumentNullException("commandData"); } Document doc = commandData.Application.ActiveUIDocument.Document; ViewsMgr view = new ViewsMgr(doc); newTran = new Transaction(doc); newTran.Start("AllViews_Sample"); AllViewsForm dlg = new AllViewsForm(view); if (dlg.ShowDialog() == DialogResult.OK) { view.GenerateSheet(doc); } newTran.Commit(); return Autodesk.Revit.UI.Result.Succeeded; } catch (Exception e) { message = e.Message; if ((newTran != null) && newTran.HasStarted() && !newTran.HasEnded()) newTran.RollBack(); return Autodesk.Revit.UI.Result.Failed; } } #endregion IExternalCommand Members Implementation } /// /// Generating a new sheet that has all the selected views placed in. /// public class ViewsMgr { private TreeNode m_allViewsNames = new TreeNode("Views (all)"); private ViewSet m_allViews = new ViewSet(); private ViewSet m_selectedViews = new ViewSet(); private FamilySymbol m_titleBlock; private IList m_allTitleBlocks = new List(); private ArrayList m_allTitleBlocksNames = new ArrayList(); private string m_sheetName; private double m_rows; private double TITLEBAR = 0.2; private double GOLDENSECTION = 0.618; /// /// Tree node store all views' names. /// public TreeNode AllViewsNames { get { return m_allViewsNames; } } /// /// List of all title blocks' names. /// public ArrayList AllTitleBlocksNames { get { return m_allTitleBlocksNames; } } /// /// The selected sheet's name. /// public string SheetName { get { return m_sheetName; } set { m_sheetName = value; } } /// /// Constructor of views object. /// /// the active document public ViewsMgr(Document doc) { GetAllViews(doc); GetTitleBlocks(doc); } /// /// Finds all the views in the active document. /// /// the active document private void GetAllViews(Document doc) { FilteredElementCollector collector = new FilteredElementCollector(doc); FilteredElementIterator itor = collector.OfClass(typeof(Autodesk.Revit.DB.View)).GetElementIterator(); itor.Reset(); while (itor.MoveNext()) { Autodesk.Revit.DB.View view = itor.Current as Autodesk.Revit.DB.View; // skip view templates because they're invisible in project browser if (null == view || view.IsTemplate) { continue; } else { ElementType objType = doc.GetElement(view.GetTypeId()) as ElementType; if (null == objType || objType.Name.Equals("Schedule") || objType.Name.Equals("Drawing Sheet")) { continue; } else { m_allViews.Insert(view); AssortViews(view.Name, objType.Name); } } } } /// /// Assort all views for tree view displaying. /// /// The view assorting /// The type of view private void AssortViews(string view, string type) { foreach (TreeNode t in AllViewsNames.Nodes) { if (t.Tag.Equals(type)) { t.Nodes.Add(new TreeNode(view)); return; } } TreeNode categoryNode = new TreeNode(type); categoryNode.Tag = type; if (type.Equals("Building Elevation")) { categoryNode.Text = "Elevations [" + type + "]"; } else { categoryNode.Text = type + "s"; } categoryNode.Nodes.Add(new TreeNode(view)); AllViewsNames.Nodes.Add(categoryNode); } /// /// Retrieve the checked view from tree view. /// public void SelectViews() { ArrayList names = new ArrayList(); foreach (TreeNode t in AllViewsNames.Nodes) { foreach (TreeNode n in t.Nodes) { if (n.Checked && 0 == n.Nodes.Count) { names.Add(n.Text); } } } foreach (Autodesk.Revit.DB.View v in m_allViews) { foreach (string s in names) { if (s.Equals(v.Name)) { m_selectedViews.Insert(v); break; } } } } /// /// Generate sheet in active document. /// /// the currently active document public void GenerateSheet(Document doc) { if (null == doc) { throw new ArgumentNullException("doc"); } if (0 == m_selectedViews.Size) { throw new InvalidOperationException("No view be selected, generate sheet be canceled."); } ViewSheet sheet = ViewSheet.Create(doc, m_titleBlock.Id); sheet.Name = SheetName; PlaceViews(m_selectedViews, sheet); } /// /// Retrieve the title block to be generate by its name. /// /// The title block's name public void ChooseTitleBlock(string name) { if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); } foreach (FamilySymbol f in m_allTitleBlocks) { if (name.Equals(f.Family.Name + ":" + f.Name)) { m_titleBlock = f; return; } } } /// /// Retrieve all available title blocks in the currently active document. /// /// the currently active document private void GetTitleBlocks(Document doc) { FilteredElementCollector filteredElementCollector = new FilteredElementCollector(doc); filteredElementCollector.OfClass(typeof(FamilySymbol)); filteredElementCollector.OfCategory(BuiltInCategory.OST_TitleBlocks); m_allTitleBlocks = filteredElementCollector.ToElements(); if (0 == m_allTitleBlocks.Count) { throw new InvalidOperationException("There is no title block to generate sheet."); } foreach (Element element in m_allTitleBlocks) { FamilySymbol f = element as FamilySymbol; AllTitleBlocksNames.Add(f.Family.Name + ":" + f.Name); if (null == m_titleBlock) { m_titleBlock = f; } } } /// /// Place all selected views on this sheet's appropriate location. /// /// all selected views /// all views located sheet private void PlaceViews(ViewSet views, ViewSheet sheet) { double xDistance = 0; double yDistance = 0; CalculateDistance(sheet.Outline, views.Size, ref xDistance, ref yDistance); Autodesk.Revit.DB.UV origin = GetOffSet(sheet.Outline, xDistance, yDistance); //Autodesk.Revit.DB.UV temp = new Autodesk.Revit.DB.UV (origin.U, origin.V); double tempU = origin.U; double tempV = origin.V; int n = 1; foreach (Autodesk.Revit.DB.View v in views) { Autodesk.Revit.DB.UV location = new Autodesk.Revit.DB.UV(tempU, tempV); Autodesk.Revit.DB.View view = v; Rescale(view, xDistance, yDistance); try { //sheet.AddView(view, location); Viewport.Create(view.Document, sheet.Id, view.Id, new XYZ(location.U, location.V, 0)); } catch (ArgumentException /*ae*/) { throw new InvalidOperationException("The view '" + view.Name + "' can't be added, it may have already been placed in another sheet."); } if (0 != n++ % m_rows) { tempU = tempU + xDistance * (1 - TITLEBAR); } else { tempU = origin.U; tempV = tempV + yDistance; } } } /// /// Retrieve the appropriate origin. /// /// /// /// /// private Autodesk.Revit.DB.UV GetOffSet(BoundingBoxUV bBox, double x, double y) { return new Autodesk.Revit.DB.UV(bBox.Min.U + x * GOLDENSECTION, bBox.Min.V + y * GOLDENSECTION); } /// /// Calculate the appropriate distance between the views lay on the sheet. /// /// The outline of sheet. /// Amount of views. /// Distance in x axis between each view /// Distance in y axis between each view private void CalculateDistance(BoundingBoxUV bBox, int amount, ref double x, ref double y) { double xLength = (bBox.Max.U - bBox.Min.U) * (1 - TITLEBAR); double yLength = (bBox.Max.V - bBox.Min.V); //calculate appropriate rows numbers. double result = Math.Sqrt(amount); while (0 < (result - (int)result)) { amount = amount + 1; result = Math.Sqrt(amount); } m_rows = result; double area = xLength * yLength / amount; //calculate appropriate distance between the views. if (bBox.Max.U > bBox.Max.V) { x = Math.Sqrt(area / GOLDENSECTION); y = GOLDENSECTION * x; } else { y = Math.Sqrt(area / GOLDENSECTION); x = GOLDENSECTION * y; } } /// /// Rescale the view's Scale value for suitable. /// /// The view to be located on sheet. /// Distance in x axis between each view /// Distance in y axis between each view static private void Rescale(Autodesk.Revit.DB.View view, double x, double y) { double Rescale = 2; Autodesk.Revit.DB.UV outline = new Autodesk.Revit.DB.UV(view.Outline.Max.U - view.Outline.Min.U, view.Outline.Max.V - view.Outline.Min.V); if (outline.U > outline.V) { Rescale = outline.U / x * Rescale; } else { Rescale = outline.V / y * Rescale; } if (1 != view.Scale && 0 != Rescale) { view.Scale = (int)(view.Scale * Rescale); } } } }