// // (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.Collections; using System.Drawing; using Autodesk.Revit; using Autodesk.Revit.DB; using Autodesk.Revit.UI; namespace Revit.SDK.Samples.GenerateFloor.CS { /// /// obtain all data for this sample. /// all possible types for floor /// the level that walls based /// public class Data { private Hashtable m_floorTypes; private List m_floorTypesName; private FloorType m_floorType; private Level m_level; private CurveArray m_profile; private bool m_structural; private System.Drawing.PointF[] m_points; private double m_maxLength; private const double PRECISION = 0.00000001; private Autodesk.Revit.Creation.Application m_creApp; private Document m_document; /// /// A floor type to be used by the new floor instead of the default type. /// public FloorType FloorType { get { return m_floorType; } set { m_floorType = value; } } /// /// The level on which the floor is to be placed. /// public Level Level { get { return m_level; } set { m_level = value; } } /// /// A array of planar lines and arcs that represent the horizontal profile of the floor. /// public CurveArray Profile { get { return m_profile; } set { m_profile = value; } } /// /// If set, specifies that the floor is structural in nature. /// public bool Structural { get { return m_structural; } set { m_structural = value; } } /// /// Points to be draw. /// public System.Drawing.PointF[] Points { get { return m_points; } set { m_points = value; } } /// /// the graphics' max length /// public double MaxLength { get { return m_maxLength; } set { m_maxLength = value; } } /// /// List of all floor types name could be used by the floor. /// public List FloorTypesName { get { return m_floorTypesName; } set { m_floorTypesName = value; } } /// /// Obtain all data which is necessary for generate floor. /// /// 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 void ObtainData(ExternalCommandData commandData) { if (null == commandData) { throw new ArgumentNullException("commandData"); } UIDocument doc = commandData.Application.ActiveUIDocument; m_document = doc.Document; ElementSet es = new ElementSet(); foreach (ElementId elementId in doc.Selection.GetElementIds()) { es.Insert(doc.Document.GetElement(elementId)); } ElementSet walls = WallFilter(es); m_creApp = commandData.Application.Application.Create; Profile = m_creApp.NewCurveArray(); FilteredElementIterator iter = (new FilteredElementCollector(doc.Document)).OfClass(typeof(FloorType)).GetElementIterator(); ObtainFloorTypes(iter); ObtainProfile(walls); ObtainLevel(walls); Generate2D(); Structural = true; } /// /// Set the floor type to generate by its name. /// /// the floor type's name public void ChooseFloorType(string typeName) { FloorType = m_floorTypes[typeName] as FloorType; } /// /// Obtain all types are available for floor. /// /// all elements within the Document. private void ObtainFloorTypes(FilteredElementIterator elements) { m_floorTypes = new Hashtable(); FloorTypesName = new List(); elements.Reset(); while (elements.MoveNext()) { Autodesk.Revit.DB.FloorType ft = elements.Current as Autodesk.Revit.DB.FloorType; if (null == ft || null == ft.Category || !ft.Category.Name.Equals("Floors")) { continue; } m_floorTypes.Add(ft.Name, ft); FloorTypesName.Add(ft.Name); FloorType = ft; } } /// /// Obtain the wall's level /// /// the selection of walls that make a closed outline private void ObtainLevel(ElementSet walls) { Autodesk.Revit.DB.Level temp = null; foreach (Wall w in walls) { if (null == temp) { temp = m_document.GetElement(w.LevelId) as Level; Level = temp; } if (Level.Elevation != (m_document.GetElement(w.LevelId) as Level).Elevation) { throw new InvalidOperationException("All walls should base the same level."); } } } /// /// Obtain a profile to generate floor. /// /// the selection of walls that make a closed outline private void ObtainProfile(ElementSet walls) { CurveArray temp = new CurveArray(); foreach (Wall w in walls) { LocationCurve curve = w.Location as LocationCurve; temp.Append(curve.Curve); } SortCurves(temp); } /// /// Generate 2D data for preview pane. /// private void Generate2D() { ArrayList tempArray = new ArrayList(); double xMin = 0; double xMax = 0; double yMin = 0; double yMax = 0; foreach (Curve c in Profile) { List xyzArray = c.Tessellate() as List; foreach (Autodesk.Revit.DB.XYZ xyz in xyzArray) { Autodesk.Revit.DB.XYZ temp = new Autodesk.Revit.DB.XYZ(xyz.X, -xyz.Y, xyz.Z); FindMinMax(temp, ref xMin, ref xMax, ref yMin, ref yMax); tempArray.Add(temp); } } MaxLength = ((xMax - xMin) > (yMax - yMin)) ? (xMax - xMin) : (yMax - yMin); Points = new PointF[tempArray.Count / 2 + 1]; for (int i = 0; i < tempArray.Count; i = i + 2) { Autodesk.Revit.DB.XYZ point = (Autodesk.Revit.DB.XYZ)tempArray[i]; Points.SetValue(new PointF((float)(point.X - xMin), (float)(point.Y - yMin)), i / 2); } PointF end = (PointF)Points.GetValue(0); Points.SetValue(end, tempArray.Count / 2); } /// /// Estimate the current point is left_bottom or right_up. /// /// current point /// left /// right /// bottom /// up static private void FindMinMax(Autodesk.Revit.DB.XYZ point, ref double xMin, ref double xMax, ref double yMin, ref double yMax) { if (point.X < xMin) { xMin = point.X; } if (point.X > xMax) { xMax = point.X; } if (point.Y < yMin) { yMin = point.Y; } if (point.Y > yMax) { yMax = point.Y; } } /// /// Filter none-wall elements. /// /// The currently selected Elements in Autodesk Revit /// static private ElementSet WallFilter(ElementSet miscellanea) { ElementSet walls = new ElementSet(); foreach (Autodesk.Revit.DB.Element e in miscellanea) { Wall w = e as Wall; if (null != w) { walls.Insert(w); } } if (0 == walls.Size) { throw new InvalidOperationException("Please select wall first."); } return walls; } /// /// Chaining the profile. /// /// none-chained profile private void SortCurves(CurveArray lines) { Autodesk.Revit.DB.XYZ temp = lines.get_Item(0).GetEndPoint(1); Curve temCurve = lines.get_Item(0); Profile.Append(temCurve); while (Profile.Size != lines.Size) { temCurve = GetNext(lines, temp, temCurve); if (Math.Abs(temp.X - temCurve.GetEndPoint(0).X) < PRECISION && Math.Abs(temp.Y - temCurve.GetEndPoint(0).Y) < PRECISION) { temp = temCurve.GetEndPoint(1); } else { temp = temCurve.GetEndPoint(0); } Profile.Append(temCurve); } if (Math.Abs(temp.X - lines.get_Item(0).GetEndPoint(0).X) > PRECISION || Math.Abs(temp.Y - lines.get_Item(0).GetEndPoint(0).Y) > PRECISION || Math.Abs(temp.Z - lines.get_Item(0).GetEndPoint(0).Z) > PRECISION) { throw new InvalidOperationException("The selected walls should be closed."); } } /// /// Get the connected curve for current curve /// /// a closed outline made by the selection of walls /// current curve's end point /// current curve /// a appropriate curve for generate floor private Curve GetNext(CurveArray profile, Autodesk.Revit.DB.XYZ connected, Curve line) { foreach (Curve c in profile) { if (c.Equals(line)) { continue; } if ((Math.Abs(c.GetEndPoint(0).X - line.GetEndPoint(1).X) < PRECISION && Math.Abs(c.GetEndPoint(0).Y - line.GetEndPoint(1).Y) < PRECISION && Math.Abs(c.GetEndPoint(0).Z - line.GetEndPoint(1).Z) < PRECISION) && (Math.Abs(c.GetEndPoint(1).X - line.GetEndPoint(0).X) < PRECISION && Math.Abs(c.GetEndPoint(1).Y - line.GetEndPoint(0).Y) < PRECISION && Math.Abs(c.GetEndPoint(1).Z - line.GetEndPoint(0).Z) < PRECISION) && 2 != profile.Size) { continue; } if (Math.Abs(c.GetEndPoint(0).X - connected.X) < PRECISION && Math.Abs(c.GetEndPoint(0).Y - connected.Y) < PRECISION && Math.Abs(c.GetEndPoint(0).Z - connected.Z) < PRECISION) { return c; } else if (Math.Abs(c.GetEndPoint(1).X - connected.X) < PRECISION && Math.Abs(c.GetEndPoint(1).Y - connected.Y) < PRECISION && Math.Abs(c.GetEndPoint(1).Z - connected.Z) < PRECISION) { if (c.GetType().Name.Equals("Line")) { Autodesk.Revit.DB.XYZ start = c.GetEndPoint(1); Autodesk.Revit.DB.XYZ end = c.GetEndPoint(0); return Line.CreateBound(start, end); } else if (c.GetType().Name.Equals("Arc")) { int size = c.Tessellate().Count; Autodesk.Revit.DB.XYZ start = c.Tessellate()[0]; Autodesk.Revit.DB.XYZ middle = c.Tessellate()[size / 2]; Autodesk.Revit.DB.XYZ end = c.Tessellate()[size]; return Arc.Create(start, end, middle); } } } throw new InvalidOperationException("The selected walls should be closed."); } } }