Have you ever been frustrated by this error?
If so, I have good news for you!
That restriction does not apply to the Revit API, and the Dimension.ValueOverride property allows you to do great things like this:
Dimensions
Finding those constraining dimensions
Steve asks a lot of good questions and it is nice that the API is often able to help answer them. Recently he asked “Where are the Constraining Dimensions?
Here’s how to use the Dimension.IsLocked property to find those constraining dimensions:
For the entries where a segment of a multi-segment dimension is locked (such as #s 30, 31, 32), every reference of every segment is listed instead of just listing the two references related to the locked segment. This happens because while the Dimension class does has a References property, the DimensionSegement class has no such property. So the output is all references of the “parent” dimension instead of the two references of the relevant segment.
public void getConstraints()
{
Document doc = this.ActiveUIDocument.Document;
string data = "";
int ctr = 1;
foreach (Dimension d in new FilteredElementCollector(doc)
.OfClass(typeof(Dimension))
.Cast<Dimension>())
{
if (d.NumberOfSegments == 0 && d.IsLocked)
{
data += ctr + ": id = " + d.Id.IntegerValue + " " + getReferenceNames(doc, d.References) + Environment.NewLine;
ctr++;
}
else if (d.NumberOfSegments > 1)
{
foreach (DimensionSegment ds in d.Segments)
{
if (ds.IsLocked)
{
data += ctr + ": id = " + d.Id.IntegerValue + " " + getReferenceNames(doc, d.References) + " - segment" + Environment.NewLine;
ctr++;
}
}
}
}
if (data == "")
data = "No locked dimensions";
TaskDialog td = new TaskDialog("Locked Dimensions");
td.MainContent = data;
td.Show();
}
private string getReferenceNames(Document doc, ReferenceArray ra)
{
string ret = "";
foreach (Reference r in ra)
{
Element e = doc.GetElement(r);
if (e.Category != null)
ret += "(" + e.Category.Name + ") ";
ret += e.Name + " & ";
}
// trim trailing " & "
ret = ret.Remove(ret.Length - 3);
return ret;
}
#AU2013 Wish granted! Convert multiple dimensions into one
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.
public void 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 dimension
if (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 element
bool 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();
}
}
Setting door position relative to nearby walls
A reader sent the image on the right and asked: “can we make door with specific distance to face of wall like 20 cm without every time need to adjust distance in temporary dimension ?”
This seemed like a good excuse to stop writing code dealing with Family Parameters (I was getting tired of writing it, were you getting tired of reading about it?).
|
Scrubbing Out Dimension Styles
Over at AUGI a good question was asked about how to get undesired dimension styles out of a project.
Dimensions in sketches and unplaced groups are at least part of the problem because right-clicking on a dimension and choosing “Select All Instances – In Entire Project” doesn’t select them.
Here is a macro that handles both dimensions in sketches and dimensions in unplaced groups. The dimensions in sketches are found as part of a normal filter to find all dimensions in the project. Dimensions in unplaced groups needed to be treated specially because an instance of the group needs to be created before the dimension in the group can be changed.
public void DimensionSytleScrub()
{
Document doc = this.ActiveUIDocument.Document;
UIDocument uidoc = new UIDocument(doc);
// Prompt user to select a dimension with an unwanted style
Dimension selected = doc.GetElement(uidoc.Selection.PickObject(ObjectType.Element), "Select dimension with style to scrub.") as Dimension;
// Get name of the dimension style of this dimension
string toScrub = selected.DimensionType.Name;
// Find the dimension style named "Default" which will be used to replace the unwanted style
// There must be a style named "Default" for this command to work
DimensionType defaultType = (from v in new FilteredElementCollector(doc)
.OfClass(typeof(DimensionType))
.Cast<DimensionType>()
where v.Name == "Default" select v).First();
using (Transaction t = new Transaction(doc,"Change dimension style to default"))
{
t.Start();
// loop through all dimensions with the unwanted style
foreach (Dimension dimension in (from v in new FilteredElementCollector(doc).OfClass(typeof(Dimension)).Cast<Dimension>()
where v.DimensionType.Name == toScrub select v))
{
// change the dimension's style to the default style
dimension.DimensionType = defaultType;
}
t.Commit();
}
// Dimensions in unplaced groups will not be found by the code above.
// So we need to place an instance of each of these groups, find any dimensions in the group, and change their style if needed
foreach (GroupType groupType in new FilteredElementCollector(doc).OfClass(typeof(GroupType)))
{
// if there are already instances of the group then skip to the next group type
if (groupType.Groups.Size > 0)
continue;
using (Transaction t = new Transaction(doc,"Change dimension style in unplaced groups"))
{
// use this flag to track if any dimensions have been changed
bool flag = false;
t.Start();
// place an instance of the group
Group newGroup = doc.Create.PlaceGroup(XYZ.Zero, groupType);
// loop through all members in the group
foreach (ElementId id in newGroup.GetMemberIds())
{
// identify any dimensions in the group
Dimension dimension = doc.GetElement(id) as Dimension;
if (dimension != null)
{
// check if this dimension has the unwanted type
if (dimension.DimensionType.Name = toScrub)
{
// change the dimension type to the default type
dimension.DimensionType = defaultType;
flag = true;
}
}
}
doc.Delete(newGroup.Id); // delete the newly placed group
if (flag)
t.Commit(); // commit this transaction if any dimensions were changed
else
t.RollBack(); // no dimensions were changed, so throw away the entire transaction
}
}
}