It is possible to automate the creation of dimensions in Revit. This process is highly customisable, but for the sake of argument, let's say we want to dimension the horizontal extents of a series of walls (to learn how to dimension room separation lines, click here).
To do this, we'll be using the NewDimension() method, which takes four arguments:
- View. In this case, we'll be using the doc.ActiveView, but you can specify any view you'd like.
- A line. This line will form the dimension. We will create this line before creating the dimension.
- A reference array. We need to tell the dimension which wall planes to base itself on. That way, if the wall moves, the dimension moves too.
- Dimension type. This input is optional. To keep this tutorial as simple as possible, we'll ignore this for now.
Before we begin, let's set up a simple rounding function (to deal with tiny imprecisions in our model), and an instance of Options(), which we'll need to access our wall geometry later.
| def r2(num): |
| return round(num, 2) |
| |
| wall_options = Options() |
| wall_options.ComputeReferences = True |
Next, we'll collect our vertical walls.
| doc = DocumentManager.Instance.CurrentDBDocument |
| walls = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls).WhereElementIsNotElementType().ToElements() |
| |
| vertical_walls = [] |
| for wall in walls: |
| if r2(wall.Orientation.X) != 0: |
| vertical_walls.append(wall) |
In our case, vertical_walls contains three walls. We'll now iterate through these to find the leftmost and rightmost faces.
| leftmost_x = float("inf") |
| rightmost_x = 0 |
| |
| for wall in vertical_walls: |
| geometry = wall.get_Geometry(wall_options) |
| for obj in geometry: |
| if isinstance(obj, Solid): |
| for face in obj.Faces: |
| face_orientation = face.FaceNormal |
| face_origin = face.Origin |
| if r2(face_orientation.X) != 0: |
| if face_origin.X < leftmost_x: |
| leftmost_x = face_origin.X |
| leftmost_face = face |
| if face_origin.X > rightmost_x: |
| rightmost_x = face_origin.X |
| rightmost_face = face |
Now, we need to create a line so we can our script where to draw our dimension. For the sake of argument, let's say we want our line precisely one foot (304.8mm) above our model.
To do this, we'll find the top point of the model, add a foot to it, create two points (one for each end of the line), then draw a line between our points.
| top_point = 0 |
| for wall in walls: |
| bounding_box = wall.get_BoundingBox(doc.ActiveView) |
| max_y = bounding_box.Max.Y |
| if max_y > top_point: |
| top_point = max_y |
| dimension_y = top_point+1 |
| |
| dimension_left_point = XYZ(leftmost_x, dimension_y, 0) |
| dimension_right_point = XYZ(rightmost_x, dimension_y, 0) |
| |
| dimension_line = Line.CreateBound(dimension_left_point, dimension_right_point) |
Now, all we need to do is extract our References from our two wall faces, pack them into a reference array, and then create our dimension.
| refArray = ReferenceArray() |
| refArray.Append(leftmost_face.Reference) |
| refArray.Append(rightmost_face.Reference) |
| |
| TransactionManager.Instance.EnsureInTransaction(doc) |
| new_dim = doc.Create.NewDimension(doc.ActiveView, dimension_line, refArray) |
| TransactionManager.Instance.TransactionTaskDone() |
Our dimension should now have been created.
Naturally, a real-world project would look a little more complex. But the code above should give you a solid base on which to add error handling, more dimension lines, and more references per dimension line, in whichever configuration you'd like.
Comments
Post a Comment