I made an API tool to help place Spot Coordinates at the end of Conduits. If you have lots of conduit this can be tedious to do manually. It can be even more annoying to do manually if the conduit is overlapping so that, like in this example, in looks like in the plan view that there is only one conduit.
Leave a comment or send me an email if this would be useful to you.
The boundaries of Revit toposurfaces are not edges. Among other things, this means that topo boundaries can’t be used to create model lines, don’t work with linework, and can’t be selected to define the path of a sweep.
A reader asked if there is a good way to use the API to generate 3D reference lines from a toposurface that could be used as the path for sweeps to represent curbs and gutters for roads, parking lots and driveways. I wrote this bit of code to create model lines from the boundary points of a selected toposurface, but the result is not great, because many small lines are created where a single arc or spline would be preferable and these model lines will not automatically update when the toposurface changes.
Do any of the Revit Site experts out there have ideas about what a more complete solution might be?
Brok asked “Can you via #Revit API combine individual dims into a single string and remove the old dims?”
Yes!
The tricky part was figuring out how to avoid creating zero-length dimension segments between the references used by adjacent dimensions.
publicvoid dimensionConsolidation()
{
Document doc = this.ActiveUIDocument.Document;
Application app = this.Application;
UIDocument uidoc = new UIDocument(doc);
IList<ElementId> idsToDelete = new List<ElementId>();
ReferenceArray dimensionRefsForNewDimension = new ReferenceArray();
// list of element ids and geometry objects used to weed out duplicate references
IList<Tuple<ElementId,GeometryObject>> geomObjList = new List<Tuple<ElementId,GeometryObject>>();
Line line = null;
DimensionType dimType = null;
IList<Element> elementList = uidoc.Selection.PickElementsByRectangle();
if (elementList.Count == 0)
return;
foreach (Element selectedElement in elementList)
{
Dimension d = selectedElement as Dimension;
idsToDelete.Add(d.Id);
// take the dimension line & dimension type from the first dimensionif (line == null)
{
line = d.Curve as Line;
dimType = d.DimensionType;
}
foreach (Reference dr in d.References)
{
Element thisElement = doc.GetElement(dr);
GeometryObject thisGeomObj = thisElement.GetGeometryObjectFromReference(dr);
// do not add references to the array if the array already contains a reference// to the same geometry element in the same elementbool duplicate = false;
foreach (Tuple<ElementId,GeometryObject> myTuple in geomObjList)
{
ElementId idInList = myTuple.Item1;
GeometryObject geomObjInList = myTuple.Item2;
if (thisElement.Id == idInList && thisGeomObj == geomObjInList)
{
duplicate = true;
break;
}
}
if (!duplicate)
{
dimensionRefsForNewDimension.Append(dr);
geomObjList.Add(new Tuple<ElementId, GeometryObject>(thisElement.Id, thisGeomObj));
}
}
}
using (Transaction t = new Transaction(doc, "Dimension Consolidation"))
{
t.Start();
Dimension newDim = doc.Create.NewDimension(doc.ActiveView, line, dimensionRefsForNewDimension, dimType);
doc.Delete(idsToDelete);
t.Commit();
}
}
This macro opens every view in the RVT, does some zoom in/zoom out, and iterates through all display styles. With the Revit 2014 rac_basic_sample_project.rvt, how long does it take to run on your machine?
Sean asked “Question for you: Is it possible to replace the #Revit Recent Files page with custom HTML, either local file or online?”
There is no straightforward way to replace the Recent Files page (it is built at run-time by Revit). But here are two ways to show a web browser as part of the Revit session.
A modeless, independent dialog with a web browser is showed when Revit starts
A dockable web browser is created after the first Revit file is opened
Nancy asked for “auto duplicating and placing views through Design Option set creation”
Here is a macro that creates new views and sheets, with a new view for each design option. Each duplicated view is set to display a different design option and is placed on a sheet in the same location as on the sheet hosting the main model viewport.
publicvoid ViewDuplicateOptions()
{
Document doc = this.ActiveUIDocument.Document;
UIDocument uidoc = this.ActiveUIDocument;
IEnumerable<DesignOption> designOptions = new FilteredElementCollector(doc).OfClass(typeof(DesignOption)).Cast<DesignOption>().Where(q => !q.IsPrimary);
if (designOptions.Count() == 1)
{
TaskDialog.Show("Error","Only one design option exists. No views duplicated.");
return;
}
IList<ViewSheet> newSheets = new List<ViewSheet>();
IList<ViewSheet> viewSheets = new FilteredElementCollector(doc).OfClass(typeof(ViewSheet)).Cast<ViewSheet>().ToList();
using (Transaction t = new Transaction(doc,"Duplicate Views by Option"))
{
t.Start();
foreach (ViewSheet vs in viewSheets)
{
IEnumerable<Viewport> viewportsOnSheet = new FilteredElementCollector(doc).OfClass(typeof(Viewport)).Cast<Viewport>().Where(q => q.SheetId == vs.Id);
if (viewportsOnSheet.Count() == 0)
continue;
FamilyInstance titleblock = new FilteredElementCollector(doc).OfClass(typeof(FamilyInstance)).OfCategory(BuiltInCategory.OST_TitleBlocks).Cast<FamilyInstance>().First(q => q.OwnerViewId == vs.Id);
foreach (DesignOption dOpt in designOptions)
{
ViewSheet newSheet = ViewSheet.Create(doc, titleblock.GetTypeId());
newSheet.Name = vs.Name + " - " + dOpt.Name;
newSheets.Add(newSheet);
foreach (Viewport vp in viewportsOnSheet)
{
View view = doc.GetElement(vp.ViewId) as View;
XYZ vpCenter = vp.GetBoxCenter();
View newView = doc.GetElement(view.Duplicate(ViewDuplicateOption.WithDetailing)) as View;
newView.Name = view.Name.Replace("{","").Replace("}","") + " - " + dOpt.Name;
newView.get_Parameter("Visible In Option").Set(dOpt.Id);
Viewport newVp = Viewport.Create(doc, newSheet.Id, newView.Id, vpCenter);
}
}
}
t.Commit();
}
foreach(ViewSheet v in newSheets)
{
uidoc.ActiveView = v;
}
}
Matt asked to “duplicate scope box across models”. Open the source file (in this case named “scope boxes.rvt”), then activate the target document and run the macro.
publicvoid CopyScopeBoxBtwDoc()
{
Document doc = this.ActiveUIDocument.Document;
Application app = this.Application;
string filename = "scope boxes.rvt";
Document sourceDoc = app.Documents.Cast<Document>().FirstOrDefault(q => q.PathName.EndsWith(filename));
if (sourceDoc == null)
{
TaskDialog.Show("Error", "No open document named " + filename);
return;
}
ICollection<ElementId> elementsToCopy = new FilteredElementCollector(sourceDoc).OfCategory(BuiltInCategory.OST_VolumeOfInterest).ToElementIds();
using (Transaction t = new Transaction(doc,"Copy Scope Box from " + filename))
{
t.Start();
ElementTransformUtils.CopyElements(sourceDoc, elementsToCopy, doc, Transform.Identity, new CopyPasteOptions());
t.Commit();
}
}
Here is the coding challenge for the AU BIM Hackathon. What would you like to see automated?
Code Challenge: Automate Your Industry
Designers, engineers, and builders are constantly confronted by redundant, time consuming tasks that could easily be mitigated with some expertly applied automation. This coding challenge asks participants to define an automation problem in the AECO industry and develop a working prototype.
Requirements…
Your solution must be coded or scripted (any language is acceptable)
Your solution must address an AECO industry automation problem
Any software is allowed.
Hypotheticals….
Can you speed up model production?
Can you enable better data integrations between project collaborators?
Can you streamline the feedback loop between design and analysis?