//
// (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.ObjectModel;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Linq;
using Autodesk.Revit;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Creation = Autodesk.Revit.Creation;
namespace Revit.SDK.Samples.Journaling.CS
{
public class Journaling
{
///
/// Define a comparer which compare WallType by name property
///
class WallTypeComparer : IComparer
{
int IComparer.Compare(WallType first, WallType second)
{
return String.Compare(first.Name, second.Name);
}
}
// Private members
ExternalCommandData m_commandData; // Store the reference of command data
bool m_canReadData; // Indicate whether has journal data
Autodesk.Revit.DB.XYZ m_startPoint; // Store the start point of the created wall
Autodesk.Revit.DB.XYZ m_endPoint; // Store the end point of the created wall
Level m_createlevel; // Store the level which the created wall on
WallType m_createType; // Store the type of the created wall
List m_levelList; // Store all levels in revit
List m_wallTypeList; // Store all wall types in revit
// Properties
///
/// Give all levels in revit, and this information can be showed in UI
///
public ReadOnlyCollection Levels
{
get
{
return new ReadOnlyCollection(m_levelList);
}
}
///
/// Give all wall types in revit, and this information can be showed in UI
///
public ReadOnlyCollection WallTypes
{
get
{
return new ReadOnlyCollection(m_wallTypeList);
}
}
// Methods
///
/// The default constructor
///
/// the external command data which revit give RevitAPI
public Journaling(ExternalCommandData commandData)
{
// Initialize the data members
m_commandData = commandData;
m_canReadData = (0 < commandData.JournalData.Count) ? true : false;
// Initialize the two list data members
m_levelList = new List();
m_wallTypeList = new List();
InitializeListData();
}
///
/// This is the main deal method in this sample.
/// It invoke methods to read and write journal data and create a wall using these data
///
public void Run()
{
// According to it has journal data or not, this sample create wall in two ways
if (m_canReadData) // if it has journal data
{
ReadJournalData(); // read the journal data
CreateWall(); // create a wall using the data
}
else // if it doesn't have journal data
{
if (!DisplayUI()) // display a form to collect some necessary data
{
return; // if the user cancels the form, only return
}
CreateWall(); // create a wall using the collected data
WriteJournalData(); // write the journal data
}
}
///
/// Set the necessary data which support the wall creation
///
/// the start point of the wall
/// the end point of the wall
/// the level which the wall base on
/// the type of the wall
public void SetNecessaryData(Autodesk.Revit.DB.XYZ startPoint, Autodesk.Revit.DB.XYZ endPoint, Level level, WallType type)
{
m_startPoint = startPoint; // start point
m_endPoint = endPoint; // end point
m_createlevel = level; // the level information
m_createType = type; // the wall type
}
///
/// Get the levels and wall types from revit and insert into the lists
///
private void InitializeListData()
{
// Assert the lists have been constructed
if (null == m_wallTypeList || null == m_levelList)
{
throw new Exception("necessary data members don't initialize.");
}
// Get all wall types from revit
Document document = m_commandData.Application.ActiveUIDocument.Document;
FilteredElementCollector filteredElementCollector = new FilteredElementCollector(document);
filteredElementCollector.OfClass(typeof(WallType));
m_wallTypeList = filteredElementCollector.Cast().ToList();
// Sort the wall type list by the name property
WallTypeComparer comparer = new WallTypeComparer();
m_wallTypeList.Sort(comparer);
// Get all levels from revit
FilteredElementIterator iter = (new FilteredElementCollector(document)).OfClass(typeof(Level)).GetElementIterator();
iter.Reset();
while (iter.MoveNext())
{
Level level = iter.Current as Level;
if (null == level)
{
continue;
}
m_levelList.Add(level);
}
}
///
/// Read the journal data from the journal.
/// All journal data is stored in commandData.Data.
///
private void ReadJournalData()
{
// Get the journal data map from API
Document doc = m_commandData.Application.ActiveUIDocument.Document;
IDictionary dataMap = m_commandData.JournalData;
String dataValue = null; // store the journal data value temporarily
// Get the wall type from the journal
dataValue = GetSpecialData(dataMap, "Wall Type Name"); // get wall type name
foreach (WallType type in m_wallTypeList) // get the wall type by the name
{
if (dataValue == type.Name)
{
m_createType = type;
break;
}
}
if (null == m_createType) // assert the wall type is exist
{
throw new InvalidDataException("Can't find the wall type from the journal.");
}
// Get the level information from the journal
dataValue = GetSpecialData(dataMap, "Level Id"); // get the level id
Autodesk.Revit.DB.ElementId id = new Autodesk.Revit.DB.ElementId(Convert.ToInt32(dataValue)); // get the level by its id
m_createlevel = doc.GetElement(id) as Level;
if (null == m_createlevel) // assert the level is exist
{
throw new InvalidDataException("Can't find the level from the journal.");
}
// Get the start point information from the journal
dataValue = GetSpecialData(dataMap, "Start Point");
m_startPoint = StirngToXYZ(dataValue);
// Get the end point information from the journal
dataValue = GetSpecialData(dataMap, "End Point");
m_endPoint = StirngToXYZ(dataValue);
// Create wall don't allow the start point equals end point
if (m_startPoint.Equals(m_endPoint))
{
throw new InvalidDataException("Start point is equal to end point.");
}
}
///
/// Display the UI form to collect some necessary information for create wall.
/// The information will be write into the journal
///
///
private bool DisplayUI()
{
// Display the form and allow the user to input some information for wall creation
using (JournalingForm displayForm = new JournalingForm(this))
{
displayForm.ShowDialog();
if (DialogResult.OK != displayForm.DialogResult)
{
return false;
}
}
return true;
}
///
/// Create a wall with the collected data or the data read from journal
///
private void CreateWall()
{
// Get the create classes.
Creation.Application createApp = m_commandData.Application.Application.Create;
Creation.Document createDoc = m_commandData.Application.ActiveUIDocument.Document.Create;
// Create geometry line(curve)
Line geometryLine = Line.CreateBound(m_startPoint, m_endPoint);
if (null == geometryLine) // assert the creation is successful
{
throw new Exception("Create the geometry line failed.");
}
// Create the wall using the wall type, level and created geometry line
Wall createdWall = Wall.Create(m_commandData.Application.ActiveUIDocument.Document, geometryLine, m_createType.Id, m_createlevel.Id,
15, m_startPoint.Z + m_createlevel.Elevation, true, true);
if (null == createdWall) // assert the creation is successful
{
throw new Exception("Create the wall failed.");
}
}
///
/// Write the support data into the journal
///
private void WriteJournalData()
{
// Get the StringStringMap class which can write support into.
IDictionary dataMap = m_commandData.JournalData;
dataMap.Clear();
// Begin to add the support data
dataMap.Add("Wall Type Name", m_createType.Name); // add wall type name
dataMap.Add("Level Id", m_createlevel.Id.IntegerValue.ToString()); // add level id
dataMap.Add("Start Point", XYZToString(m_startPoint)); // add start point
dataMap.Add("End Point", XYZToString(m_endPoint)); // add end point
}
///
/// The helper function which convert a format string to a Autodesk.Revit.DB.XYZ point
///
/// a format string
/// the converted Autodesk.Revit.DB.XYZ point
private static Autodesk.Revit.DB.XYZ StirngToXYZ(String pointString)
{
// Define some temporary data
double x = 0; // Store the temporary x coordinate
double y = 0; // Store the temporary y coordinate
double z = 0; // Store the temporary z coordinate
String subString; // A part of the format string
// Get the data string from the format string
subString = pointString.TrimStart('(');
subString = subString.TrimEnd(')');
String[] coordinateString = subString.Split(',');
if (3 != coordinateString.Length)
{
throw new InvalidDataException("The point information in journal is incorrect");
}
// Return a Autodesk.Revit.DB.XYZ point using the collected data
try
{
x = Convert.ToDouble(coordinateString[0]);
y = Convert.ToDouble(coordinateString[1]);
z = Convert.ToDouble(coordinateString[2]);
}
catch (Exception)
{
throw new InvalidDataException("The point information in journal is incorrect");
}
return new Autodesk.Revit.DB.XYZ(x, y, z);
}
///
/// The helper function which convert a Autodesk.Revit.DB.XYZ point to a format string
///
/// A Autodesk.Revit.DB.XYZ point
/// The format string which store the information of the point
private static String XYZToString(Autodesk.Revit.DB.XYZ point)
{
String pointString = "(" + point.X.ToString() + "," + point.Y.ToString() + ","
+ point.Z.ToString() + ")";
return pointString;
}
///
/// Get the data which is related to a special key in journal
///
/// the map which store the journal data
/// a key which indicate which data to get
/// The gotten data in string format
private static String GetSpecialData(IDictionary dataMap, String key)
{
String dataValue = dataMap[key];
if (String.IsNullOrEmpty(dataValue))
{
throw new Exception(key + "information is not exist in journal.");
}
return dataValue;
}
}
}