Thursday, November 17, 2016

AU2016 SD20868

Autodesk University 2016 has come to a close for us now and it was very enlightening and entertaining. I enjoyed catching up with old friends and making a few new ones as well.

I taught a class entitled "SD20868 - Revit Usage and Model Data Reporting Simplified with C#"

It was a full solution style overview class showing how to get verb data out of Revit and into a graphical dashboard showing various Model and User metrics.

The purpose was to show and share how this can be done using ASP.NET coupled with a few other modern(ish) web development techniques. I want to thank the folks that provide the Gentelella web template and hope everyone enjoyed the class.



Tuesday, August 23, 2016

Revit Key Schedule Data Export

Have you ever had a need to export all of your key schedule data? The sample code provided below was built for Revit 2015 and should upgrade just fine to newer versions if need be.

Since you cannot transfer updates to existing Key Schedules from one project to another, I needed a way to export the data to a standardized key schedule definition so that I could easily import that updated definition information to a new or existing key schedule in an external project. This sample code is what I am using to export all of my key schedules including all of their row data to json file.

Sample data visualization thanks to our friends at http://jsonmate.com/



No I will not make a Dynamo definition for this :)

Enjoy...

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Newtonsoft.Json;
namespace Stg.ModelMonitor.Entry
{
[Transaction(TransactionMode.Manual)]
public class CmdKeySchedules : IExternalCommand
{
/// <summary>
/// This is the data we'll export
/// </summary>
public List<KeySchedule> Schedules { get; set; }
/// <summary>
/// Key Schedules
/// </summary>
/// <param name="commandData"></param>
/// <param name="msg"></param>
/// <param name="elements"></param>
/// <returns></returns>
public Result Execute(ExternalCommandData commandData, ref string msg, ElementSet elements)
{
try
{
Schedules = new List<KeySchedule>();
Document m_doc = commandData.Application.ActiveUIDocument.Document;
// Get the key schedules in the project
IEnumerable<ViewSchedule> m_ks = from e in new FilteredElementCollector(m_doc)
.OfClass(typeof(ViewSchedule))
let f = e as ViewSchedule
where f.Definition.IsKeySchedule
select f;
foreach (var x in m_ks.ToList())
{
Schedules.Add(new KeySchedule(x));
}
// Export to json
ExportJson(Schedules, "Key Schedules");
// Done
return Result.Succeeded;
} catch (Exception ex)
{
msg = ex.ToString();
return Result.Failed;
}
}
/// <summary>
/// Write an Object to Json
/// </summary>
/// <param name="sourceData">Top level object to write out to file</param>
/// <param name="objName">command kind to use in file name</param>
/// <returns>TRUE if file exists after main function</returns>
/// <remarks></remarks>
private void ExportJson(object sourceData, string objName)
{
try
{
// Export Path - change this path to suit your neeeds
string m_exportPath = @"c:\temp";
if (!Directory.Exists(m_exportPath)) return;
string m_fileName = string.Format("{0} {1}.json",
DateTime.Now.ToString("yyMMdd hhmmss"), objName);
string m_finalPath = Path.Combine(m_exportPath, m_fileName);
using (StreamWriter sw = new StreamWriter(m_finalPath, false))
{
sw.WriteLine(JsonConvert.SerializeObject(sourceData));
}
}
catch { }
}
}
/// <summary>
/// Key Schedule Object
/// </summary>
public class KeySchedule
{
public string Category { get; set; }
public string Name { get; set; }
public string KeyParameterName { get; set; }
public List<KeyScheduleRow> Rows { get; set; }
/// <summary>
/// Key Schedule
/// </summary>
/// <param name="v"></param>
public KeySchedule(ViewSchedule v)
{
Rows = new List<KeyScheduleRow>();
Name = v.Name;
foreach (Category x in v.Document.Settings.Categories)
{
if (x.Id.IntegerValue == v.Definition.CategoryId.IntegerValue)
{
Category = x.Name;
break;
}
}
KeyParameterName = v.KeyScheduleParameterName;
IEnumerable<Element> m_e = from e in new FilteredElementCollector(v.Document, v.Id) select e;
foreach (var elem in m_e)
{
Rows.Add(new KeyScheduleRow(elem));
}
}
}
/// <summary>
/// Key Schedule Row
/// Skips readonly parameters
/// </summary>
public class KeyScheduleRow
{
public string KeyName { get; set; }
public List<KeyScheduleRowParameter> Parameters { get; set; }
public KeyScheduleRow(Element e)
{
Parameters = new List<KeyScheduleRowParameter>();
KeyName = e.Name;
foreach (Parameter x in e.Parameters)
{
if (x.IsReadOnly) continue;
var m_name = x.Definition.Name.ToLower();
switch (m_name)
{
case "family name":
continue;
case "type name":
continue;
case "category":
continue;
case "design option":
continue;
}
Parameters.Add(new KeyScheduleRowParameter(x));
}
}
}
/// <summary>
/// Key Schedule Row Parameter
/// </summary>
public class KeyScheduleRowParameter
{
public string Name { get; set; }
public string Value { get; set; }
public KeyScheduleRowParameter(Parameter p)
{
Name = p.Definition.Name;
Value = GetValueString(p);
}
/// <summary>
/// Get a string parameter value as a string
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
private string GetValueString(Parameter p)
{
try
{
if (p != null)
{
if (p.StorageType == StorageType.None)
return "";
return p.StorageType == StorageType.String
? p.AsString()
: p.AsValueString();
}
}
catch { }
return "{error}";
}
}
}

Wednesday, April 27, 2016

Delete Empty Elevation Marker Tags

It is pretty common for a model to end up with a bunch of abandoned elevation marker tags. There are a bunch of ways that this can happen and depending on how you have your elevation tag symbols defined can be difficult to find visually for removal.



One of the supreme beings that I used to work with at CASE built a means of doing this in Dynamo.

This is a simple routine that finds these and eradicates them from your model...


[Transaction(TransactionMode.Manual)]
public class CmdMain : IExternalCommand
{
/// <summary>
/// Command
/// </summary>
/// <param name="commandData"></param>
/// <param name="message"></param>
/// <param name="elements"></param>
/// <returns></returns>
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
try
{
Document m_doc = commandData.Application.ActiveUIDocument.Document;
int m_cnt = 0;
IEnumerable<ElevationMarker> m_elem = from e in new FilteredElementCollector(m_doc)
.WhereElementIsNotElementType().OfClass(typeof (ElevationMarker))
let em = e as ElevationMarker
where em.HasElevations() == false
select em;
using (Transaction t = new Transaction(m_doc))
{
if (t.Start("Delete Empty Elevation Marker Tags") == TransactionStatus.Started)
{
foreach (var x in m_elem.ToList())
{
m_doc.Delete(x.Id);
m_cnt++;
}
t.Commit();
}
}
// Results
clsUtility.ShowTaskDialog(
"Results",
"Deleted Elevation Markers",
string.Format("Removed {0} Empty Elevation Marker Tags", m_cnt));
return Result.Succeeded;
}
catch (Exception ex)
{
clsUtility.ShowTaskDialog(
"Failure",
"Deleting Elevation Markers",
string.Format("Failed: \n{0}", ex));
return Result.Cancelled;
}
}
}
/// <summary>
/// Quick basic task dialog
/// </summary>
/// <param name="titleText"></param>
/// <param name="largeText"></param>
/// <param name="smallText"></param>
internal static void ShowTaskDialog(string titleText, string largeText, string smallText)
{
using (TaskDialog td = new TaskDialog(titleText))
{
td.CommonButtons = TaskDialogCommonButtons.Ok;
td.DefaultButton = TaskDialogResult.Ok;
td.TitleAutoPrefix = false;
td.MainInstruction = largeText;
td.MainContent = smallText;
td.Show();
}
}

Friday, April 1, 2016

Getting Families to Display in RCP if Below View Cut Plane

I haven't posted anything in quite a while and plan to start posting more often again. I've got loads of new code related ideas that I will be posting in the not so distant future, but for now, we're going to show a popular family editing trick to get elements to display in RCP views when their base geometry might dictate otherwise.

Plan regions are not necessary to solve this issue...

This trick is also handy for furniture elements (tables, etc.) that you wish to be visible in RCP views even though they don't contain any visible geometry above the RCP view range cut plane.

Open your family in the editor and add a new model line to the top of your family so that the top of this line will always extend just beyond your view range cut plane in the project environment. Be sure to set this model line to invisible so that you don't see it anywhere in the project environment.



Your element will not be visible in an RCP view with a cut plane higher than the top of your geometry since the model line passes through it in the project environment. Revit will display the whole family for you.