// // (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.ComponentModel; using System.Data; using System.Linq; using System.Drawing; using System.Text; using System.Windows.Forms; using Autodesk.Revit; using System.Collections; using Autodesk.Revit.DB; using Autodesk.Revit.UI; using Autodesk.Revit.DB.Structure; using System.Drawing.Drawing2D; using System.Threading; namespace Revit.SDK.Samples.Truss.CS { /// /// window form contains one three picture box to show the /// profile of truss geometry and profile and tabControl. /// User can create truss, edit profile of truss and change type of truss members. /// public partial class TrussForm : System.Windows.Forms.Form { ExternalCommandData m_commandData; //object which contains reference of Revit Application ArrayList m_trussTypes; //stores all the truss types IEnumerable m_beamTypes; //stores all the beam types (FamilySymbol) IEnumerable m_views; //stores all the ViewPlan use to create truss TrussGeometry trussGeometry; //TrussGeometry object store geometry info of Truss TrussType m_selectedTrussType; //selected truss type Autodesk.Revit.DB.Structure.Truss m_truss; //store the truss created by this sample bool m_topChord = false; //allows to draw top chord when it's true, otherwise forbids to do it. bool m_bottomChord = false; //draw bottom chord when it's true, otherwise forbids to do it. int m_selectMemberIndex; //index of selected truss member Autodesk.Revit.DB.ViewPlan m_selectedView; //store the selected view FamilyInstance m_selecedtBeam; //store the selected beam FamilySymbol m_selectedBeamType; //store the selected beam type UIDocument m_activeDocument; //active document in Revit FamilyInstance column1; //one of 2 columns which truss build on FamilyInstance column2; //one of 2 columns which truss build on const String NoAssociatedLevel = ""; //when select truss doesn't have associate level /// /// constructor /// /// object which contains reference of Revit Application public TrussForm(ExternalCommandData commandData) { m_commandData = commandData; m_activeDocument = m_commandData.Application.ActiveUIDocument; InitializeComponent(); m_trussTypes = new ArrayList(); //Get user selection if (!GetSelectTrussOrColumns()) { TaskDialog.Show("Select", "Please select 1 existing truss or 2 columns before load this application."); this.Close(); } // get all the beam types, truss types and all the view plans from the active document DataInitialize(); } /// /// Get 1 truss or 2 columns from selection /// /// return false if selection incorrect private bool GetSelectTrussOrColumns() { if (m_activeDocument.Selection.GetElementIds().Count > 2 || 0 == m_activeDocument.Selection.GetElementIds().Count) { return false; } ElementSet es = new ElementSet(); foreach (ElementId elementId in m_activeDocument.Selection.GetElementIds()) { es.Insert(m_activeDocument.Document.GetElement(elementId)); } IEnumerator iter = es.GetEnumerator(); iter.Reset(); while (iter.MoveNext()) { if (iter.Current is Autodesk.Revit.DB.Structure.Truss) { if (null == m_truss) { m_truss = iter.Current as Autodesk.Revit.DB.Structure.Truss; } else { return false; } } else if (iter.Current is Autodesk.Revit.DB.FamilyInstance) { FamilyInstance familyInstance = iter.Current as FamilyInstance; if (StructuralType.Column == familyInstance.StructuralType) { if (null == column1) { column1 = familyInstance; } else { column2 = familyInstance; } } else { return false; } } else { return false; } } if (null == m_truss && (null == column1 || null == column2)) { return false; } return true; } /// /// get all the beam types, truss types and all the view plans from the active document /// public void DataInitialize() { // get all the beam types GetBeamTypes(); // get all the truss types // there's no truss type in the active document FilteredElementCollector filteredElementCollector = new FilteredElementCollector(m_activeDocument.Document); filteredElementCollector.OfClass(typeof(FamilySymbol)); filteredElementCollector.OfCategory(BuiltInCategory.OST_Truss); IList trussTypes = filteredElementCollector.Cast().ToList(); if (null == trussTypes || 0 == trussTypes.Count) { TaskDialog.Show("Load Truss Type", "Please load at least one truss type into your project."); this.Close(); } foreach (TrussType trussType in trussTypes) { if (null == trussType) { continue; } String trussTypeName = trussType.get_Parameter (BuiltInParameter.SYMBOL_FAMILY_AND_TYPE_NAMES_PARAM).AsString(); this.TrussTypeComboBox.Items.Add(trussTypeName); m_trussTypes.Add(trussType); } // get all the views // Skip view templates because they're behind-the-scene and invisible in project browser; also invalid for API..., etc. m_views = from elem in new FilteredElementCollector(m_activeDocument.Document).OfClass(typeof(ViewPlan)).ToElements() let viewPlan = elem as ViewPlan where viewPlan != null && !viewPlan.IsTemplate select viewPlan; foreach (Autodesk.Revit.DB.View view in m_views) { this.ViewComboBox.Items.Add(view.Name); } } /// /// get all the beam types /// private void GetBeamTypes() { m_beamTypes = from elem in new FilteredElementCollector(m_activeDocument.Document).OfClass( typeof(FamilySymbol)).OfCategory(Autodesk.Revit.DB.BuiltInCategory.OST_StructuralFraming) let type = elem as FamilySymbol select type; // can't obtain beam types from the active document if (null == m_beamTypes || 0 == m_beamTypes.Count()) { TaskDialog.Show("Load Structural Framing Family", "No Structural Framing Family loaded. Please load one of the Structure Framing Family."); this.Close(); } foreach (FamilySymbol familySymbol in m_beamTypes) { String beamTypeName = familySymbol.get_Parameter( BuiltInParameter.SYMBOL_FAMILY_AND_TYPE_NAMES_PARAM).AsString(); this.BeamTypeComboBox.Items.Add(beamTypeName); } } /// /// initialize the UI ComboBox's appearance /// /// object who sent this event /// event args private void TrussForm_Load(object sender, EventArgs e) { this.TrussTypeComboBox.SelectedIndex = 0; this.ViewComboBox.SelectedIndex = 0; //user pre-select a truss in Revit UI if (m_truss != null) { // show the truss type and level of pre-selected truss in the ComboBox String nameOfTrussType = m_truss.TrussType.get_Parameter (BuiltInParameter.SYMBOL_FAMILY_AND_TYPE_NAMES_PARAM).AsString(); this.TrussTypeComboBox.SelectedIndex = this.TrussTypeComboBox.Items.IndexOf(nameOfTrussType); Parameter viewName = m_truss.get_Parameter(BuiltInParameter.SKETCH_PLANE_PARAM); if (null == viewName || 0 == viewName.AsString().CompareTo(NoAssociatedLevel)) { this.ViewComboBox.Items.Add(NoAssociatedLevel); this.ViewComboBox.SelectedIndex = this.ViewComboBox.Items.IndexOf(NoAssociatedLevel); } else { String nameOfViewPlane = viewName.AsString().Substring(8); this.ViewComboBox.SelectedIndex = this.ViewComboBox.Items.IndexOf(nameOfViewPlane); } this.TrussTypeComboBox.Enabled = false; this.CreateButton.Enabled = false; this.ViewComboBox.Enabled = false; trussGeometry = new TrussGeometry(m_truss, m_commandData); this.TrussGraphicsTabControl.SelectedIndex = 1; } } /// /// get selected truss type, this data will be used in truss creation /// /// object who sent this event /// event args private void TrussTypeComboBox_SelectedIndexChanged(object sender, EventArgs e) { m_selectedTrussType = (TrussType)m_trussTypes[this.TrussTypeComboBox.SelectedIndex]; } /// /// create new truss /// /// object who sent this event /// event args private void CreateButton_Click(object sender, EventArgs e) { try { Transaction transaction = new Transaction(m_commandData.Application.ActiveUIDocument.Document, "CreateTruss"); transaction.Start(); // create the truss m_truss = CreateTruss(); m_truss.Location.Move(new Autodesk.Revit.DB.XYZ(0, 0, m_selectedView.GenLevel.Elevation)); transaction.Commit(); trussGeometry = new TrussGeometry(m_truss, m_commandData); this.TrussGraphicsTabControl.SelectedIndex = 1; } catch (Exception ex) { TaskDialog.Show("Exception", ex.Message); } this.TrussTypeComboBox.Enabled = false; this.CreateButton.Enabled = false; this.ViewComboBox.Enabled = false; } /// /// create truss in Revit /// /// new created truss public Autodesk.Revit.DB.Structure.Truss CreateTruss() { Autodesk.Revit.DB.Document document = m_commandData.Application.ActiveUIDocument.Document; Autodesk.Revit.Creation.Document createDoc = document.Create; Autodesk.Revit.Creation.Application createApp = m_commandData.Application.Application.Create; //sketchPlane Autodesk.Revit.DB.XYZ origin = new Autodesk.Revit.DB.XYZ(0, 0, 0); Autodesk.Revit.DB.XYZ xDirection = new Autodesk.Revit.DB.XYZ(1, 0, 0); Autodesk.Revit.DB.XYZ yDirection = new Autodesk.Revit.DB.XYZ(0, 1, 0); Plane plane = Plane.CreateByOriginAndBasis(xDirection, yDirection, origin); SketchPlane sketchPlane = SketchPlane.Create(document, plane); //new base Line AnalyticalModel frame1 = column1.GetAnalyticalModel(); Autodesk.Revit.DB.XYZ centerPoint1 = (frame1.GetCurve() as Line).GetEndPoint(0); AnalyticalModel frame2 = column2.GetAnalyticalModel(); Autodesk.Revit.DB.XYZ centerPoint2 = (frame2.GetCurve() as Line).GetEndPoint(0); Autodesk.Revit.DB.XYZ startPoint = new Autodesk.Revit.DB.XYZ(centerPoint1.X, centerPoint1.Y, 0); Autodesk.Revit.DB.XYZ endPoint = new Autodesk.Revit.DB.XYZ(centerPoint2.X, centerPoint2.Y, 0); Autodesk.Revit.DB.Line baseLine = null; try { baseLine = Line.CreateBound(startPoint, endPoint); } catch (System.ArgumentException) { TaskDialog.Show("Argument Exception", "Two column you selected are too close to create truss."); } return Autodesk.Revit.DB.Structure.Truss.Create(document, m_selectedTrussType.Id, sketchPlane.Id, baseLine); } /// /// draw profile, top chord and bottom of truss /// /// object who sent this event /// event args private void ProfileEditPictureBox_Paint(object sender, PaintEventArgs e) { e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; if (trussGeometry != null) { trussGeometry.Draw2D(e.Graphics, Pens.Blue); } Font font = new Font("Verdana", 10, FontStyle.Regular); string indicator = "Draw Top Chord and Bottom Chord here:"; e.Graphics.DrawString(indicator, font, Brushes.Blue, new PointF(20, 10)); } /// /// add point to top chord and bottom chord /// /// object who sent this event /// event args private void ProfileEditPictureBox_MouseClick(object sender, MouseEventArgs e) { // draw top chord line if (m_topChord) { trussGeometry.AddTopChordPoint(e.X, e.Y); } // draw bottom chord line else if (m_bottomChord) { trussGeometry.AddBottomChordPoint(e.X, e.Y); } this.ProfileEditPictureBox.Refresh(); } /// /// change move point of top chord lineTool and bottom chord lineTool /// /// object who sent this event /// event args private void ProfileEditPictureBox_MouseMove(object sender, MouseEventArgs e) { if (m_topChord) { trussGeometry.AddTopChordMovePoint(e.X, e.Y); } else if (m_bottomChord) { trussGeometry.AddBottomChordMovePoint(e.X, e.Y); } this.ProfileEditPictureBox.Refresh(); } /// /// begin to draw top chord /// /// object who sent this event /// event args private void TopChordButton_Click(object sender, EventArgs e) { m_topChord = true; m_bottomChord = false; this.ProfileEditPictureBox.Cursor = Cursors.Cross; this.ProfileEditPictureBox.Refresh(); } /// /// begin to draw bottom chord /// /// object who sent this event /// event args private void BottomChordButton_Click(object sender, EventArgs e) { m_topChord = false; m_bottomChord = true; this.ProfileEditPictureBox.Cursor = Cursors.Cross; this.ProfileEditPictureBox.Refresh(); } /// /// update the truss according to the top chord line and the bottom chord line /// /// object who sent this event /// event args private void UpdateButton_Click(object sender, EventArgs e) { Transaction transaction = new Transaction(m_activeDocument.Document, "SetProfile"); transaction.Start(); //update the truss trussGeometry.SetProfile(m_commandData); transaction.Commit(); this.ProfileEditPictureBox.Refresh(); } /// /// restore profile of truss /// /// object who sent this event /// event args private void RestoreButton_Click(object sender, EventArgs e) { Transaction transaction = new Transaction(m_activeDocument.Document, "RemoveProfile"); transaction.Start(); // restore the profile trussGeometry.RemoveProfile(); transaction.Commit(); this.ProfileEditPictureBox.Refresh(); } /// /// clear points of top and bottom chord line /// /// object who sent this event /// event args private void CleanChordbutton_Click(object sender, EventArgs e) { trussGeometry.ClearChords(); m_topChord = false; m_bottomChord = false; this.ProfileEditPictureBox.Cursor = Cursors.Default; this.ProfileEditPictureBox.Refresh(); } /// /// draw geometry of truss, and draw selected line red /// /// object who sent this event /// event args private void TrussGeometryPictureBox_Paint(object sender, PaintEventArgs e) { e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; if (trussGeometry != null) { trussGeometry.Draw2D(e.Graphics, Pens.Blue); } Font font = new Font("Verdana", 10, FontStyle.Regular); string indicator = "Select a beam from the truss:"; e.Graphics.DrawString(indicator, font, Brushes.Blue, new PointF(20, 10)); } /// /// get selected truss member (Beam) /// /// object who sent this event /// event args private void TrussGeometryPictureBox_MouseMove(object sender, MouseEventArgs e) { // indicates whether the mouse moves over or hovers on one beam // if true, paints the beam to red m_selectMemberIndex = trussGeometry.SelectTrussMember(e.X, e.Y); this.TrussMembersPictureBox.Refresh(); } /// /// select truss member (beam) /// /// object who sent this event /// event args private void TrussGeometryPictureBox_MouseClick(object sender, MouseEventArgs e) { // clicks in the canvas but doesn't select anything if (-1 == m_selectMemberIndex) { this.BeamTypeComboBox.Enabled = false; this.ChangeBeamTypeButton.Enabled = false; return; } // clicks in the canvas and selects a beam m_selecedtBeam = trussGeometry.GetSelectedBeam(m_commandData); if (null != m_selecedtBeam) { FamilySymbol symbol = m_selecedtBeam.Symbol; // get the type of the selected beam String nameOfSymbol = symbol.get_Parameter( BuiltInParameter.SYMBOL_FAMILY_AND_TYPE_NAMES_PARAM).AsString(); int index = this.BeamTypeComboBox.Items.IndexOf(nameOfSymbol); // show the beam type in the ComboBox this.BeamTypeComboBox.SelectedIndex = index; this.BeamTypeComboBox.Enabled = true; this.ChangeBeamTypeButton.Enabled = true; this.TrussMembersPictureBox.Refresh(); } } /// /// change selected beam type /// /// object who sent this event /// event args private void BeamTypeComboBox_SelectedIndexChanged(object sender, EventArgs e) { // choose a new beam type for the selected beam m_selectedBeamType = m_beamTypes.ElementAt(this.BeamTypeComboBox.SelectedIndex); } /// /// change type of selected beam /// /// object who sent this event /// event args private void ChangeBeamTypeButton_Click(object sender, EventArgs e) { // apply the beam type change Transaction transaction = new Transaction(m_activeDocument.Document, "ChangeSelectedBeamType"); transaction.Start(); if (null != m_selecedtBeam) { m_selecedtBeam.Symbol = m_selectedBeamType; } transaction.Commit(); } /// /// change selected ViewPlan /// /// object who sent this event /// event args private void ViewComboBox_SelectedIndexChanged(object sender, EventArgs e) { // choose another view for the truss creation if (this.ViewComboBox.SelectedIndex < m_views.Count()) { m_selectedView = m_views.ElementAt(this.ViewComboBox.SelectedIndex); } } /// /// quit the "top chord" or "bottom chord" drawing operation /// by pressing the "ESC" key /// /// /// private void TrussGraphicsTabControl_KeyPress(object sender, KeyPressEventArgs e) { // the "Profile Edit" tab page is active // and the user presses the "ESC" key (e.KeyChar == 27) if (TrussGraphicsTabControl.SelectedTab == ProfileEditTabPage && e.KeyChar == (char)27) { // quit the "chord" drawing and remove the move indicating line m_topChord = false; m_bottomChord = false; this.ProfileEditPictureBox.Cursor = Cursors.Default; trussGeometry.ClearMovePoint(); this.ProfileEditPictureBox.Refresh(); } } /// /// won't let open truss member tab until truss create successfully /// /// /// private void TrussGraphicsTabControl_Selecting(object sender, TabControlCancelEventArgs e) { // if no truss is created, locks the tab pages to the 1st tab page if (null == trussGeometry) { this.TrussGraphicsTabControl.SelectedIndex = 0; } else { trussGeometry.Reset(); m_selecedtBeam = null; } } /// /// Close dialogue box /// /// /// private void CloseButton_Click(object sender, EventArgs e) { this.Close(); } } }