lisa-marie mueller

lisa-marie mueller

bullet pont

filtering with Revit parameters (python for Dynamo) link

May 22, 2020

laptop with title, cloud shaped balloons, rocket shaped balloon, orange and green When I first started my blog, my original intent was to cover equal parts Dynamo content and Revit API content. Due to numerous circumstances, I dove headfirst into developing plug-ins for Revit and haven’t spent much time in Dynamo since August of last year. Every time I did go in to write a script, I also encountered some of the same frustrations. Don’t get me wrong, I think Dynamo is invaluable, but if you don’t utilize the Revit API, there are limitations. Recently, I’ve been spending more time in Dynamo and am going to start interjecting some Dynamo posts on my blog. Of course anything you can do in Dynamo you can due purely in Python or C#, but I see value in creating graphs including ease of use and speed. I think there is a benefit to using Dynamo nodes but also to utilizing opportunities to make your graphs more efficient. Currently, I’m trying to collect Python snippets that you can use in a Python node in Dynamo to make your workflow faster and easier.

A minor note on terminology, when I am discussing parameters for elements in Revit I will do my best to always refer to them as Revit parameters to avoid confusion with method parameters.

collecting elements that have a specific Revit parameter:

Personally, one of my least favorite things to do in Dynamo is filter lists. I find filtering with nodes unnecessarily complicated and often I need so many nodes to filter out what I want. One of these examples is filtering for Revit parameters. Last week, for example, I wanted a Dynamo script to turn off the visibility setting of a certain instance Revit parameter in all the title blocks in a project. I wrote two helpful nodes that are super simple but save you so much time.

The first challenge I ran into is we had planning packages and construction document sheets set up and not all of them contained the Revit visibility parameter I wanted to toggle. So the first Python node finds all elements that have a certain Revit parameter.

The node has two inputs. The input at index 0 is a list of elements and the input at index 1 is a list of the element’s Revit parameters. You can get these inputs with Dynamo nodes (see graph at the end of this post). After creating a new empty list, the node then looks at each element and that element’s Revit parameters. If the element has a Revit parameter with the name “Consultant Stamp” it adds it to our new list. You can copy and paste the code below into a Python node in your own Dynamo script and change the p.Name from “Consultant Stamp” to the Revit parameter relevant to you. Please note when comparing strings, the name needs to be an exact match including spaces and capitalizations. The block then returns a list of elements that have a Revit parameter equal to the p.Name you specified.

filter list based on Revit parameter value

After I found all the title blocks that had the Consultant Stamp Revit parameter, I wanted to hide it if it was visible so I had to filter the list one more time. This time, I needed to filter by the Revit parameter value. This node will only have one input and that will be the list of Revit parameters of the elements we filtered with the previous Python node.

Because the Consultant Stamp Revit parameter is a visibility Revit parameter, a value of 0 means it is hidden and a value of 1 means it is visible. I want to check if p.Name is equal to “Consultant Stamp” and p.Value is equal to 1. In other words, I want to select all the elements with the Revit parameter “Consultant Stamp” equal to 1 which means it is visible. Then we can add the element to our new list. The output will be a list of the Revit parameters that we need to hide. We can do this using the Revit Parameter.SetValue node and simply set the value to 0. Remember to also update the p.Name in this node.

And this is what the graph looks like in use:

dynamo graph with collect elements with parameter node and filter list based on parameter value node

summary

And now when we connect our Python nodes with the other nodes, we can easily change the value of a Revit parameter. These nodes can be reused to filter for a number of Revit parameters for different types of elements, not just title blocks. I hope this gives you a few tools that you can use and modify to make your Dynamo workflow more efficient. Happy scripting!

resources

If you want to learn to code and don’t know where to start check out my posts about Steps to Learn to Code [for architects and designers] Part 1 and Part 2.

Revit API Docs

bullet pont

tracking ROI link

May 15, 2020

ipad with title, large neon star, movie reel, marker, purple Happy Friday! Today I wanted to walk through an option for tracking ROI. It’s much easier to make the business case for the work you do if you understand how it’s impacting people’s every day process. Thankfully, you can log just a few pieces of information and receive a lot of insight!

platform

There are three main parts to tracking ROI data: the platform to track the data, the configuration file with the link, and the data you are tracking. There are multiple options for platforms to track this data. One option is Slack. You will want to create a web hook with Slack or your chosen platform. As always, before implementing processes with 3rd party applications, read and follow the license agreements.

config file

You may want to create a configuration file for your project so you don’t hard-code API keys or credentials. I would recommend building projects without the keys entered into the configuration files and then copy and pasting this information when you deploy it. This is more secure. Of course, it is important to know that the configuration file with this information will need to be on the computers of everyone who is using your plug-in and sending telemetry. Anyone with the credentials can send information to that channel. If your project is exclusively internal, this is an acceptable set-up, just know that this is how it works.

Once you have the configuration file you will need to add a method to read it. Our method is a public method and returns the Configuration. We need the location of the file as well as the tag we used. In my case, I called the URL “telemetryURL”. We can simply search through each of the elements in our config file and if the element has a tag “telemetryURL” we want to assign this value to the Configuration.

data

Then you can consider what data you would like to collect. Some options include the file name, date and time, and the name of the plug-in that was run. These are general pieces of information that can be included in our SendTelemetryData method. The ROI calculation is plug-in specific and can be added in the Execute method within the plug-in. Because I want to add plug-in specific information I have a parameter called “message” that allows me to also send any additional information that I want.

We can then format the information so it is easier to read and add any required description. I collect the username, date and time, and plug-in and format it into an easy to read string. Then I place the message on the next line. This is a utility method that I added to my Utility file so I can use it for all plug-ins.

ROI

The ROI calculation is entered as the message parameter in the above described method. This allows me to customize the information for each plug-in and still send the data I need. There may be slight differences in calculating ROI depending on the plug-in. Generally, I actually take the stop watch feature on my phone and time myself completing the tasks that the plug-in automates. I record it at least a few times to make sure there aren’t any outliers. Then, I find the appropriate relatable metric and multiply to get the total time saved.

For example, for the Automate Interior Elevations Plug-In, I timed myself creating elevations, renaming them, adjusting the crop, adding the view template, and adding the masking region for one room. In my ROI calculation, I take this time and multiply it by the number of rooms that the program goes through to get my total time saved.

I send data both when the plug-in started running and then ROI data when it has completed. This way I also know if people are canceling after opening it. When the plug-in is started, I read the config file and then simply send the message “Started”. This code lives in the Execute method of the plug-in.

When a plug-in finishes running successfully, I record the ROI information. For interior elevations, I calculated an approximate time savings of 8 minutes per room. I multiply this by the number of rooms in the project and return the time saved in hours and minutes.

summary

And these are the steps to start tracking the ROI of the plug-ins you make. I hope this will be helpful in understanding how your work impacts the time spent on projects.


Disclaimer: This post is intended to explain how to collect data relevant to tracking and understanding ROI. Please review any relevant privacy and protection policies before collecting data.

resources

If you want to learn to code and don’t know where to start check out my posts about Steps to Learn to Code [for architects and designers] Part 1 and Part 2.

Revit API Docs

bullet pont

user wall selection link

May 1, 2020

ipad with title, large neon star, movie reel, marker, purple Happy Friday! As you know, I am tackling placing exterior elevations based on selected walls. This week we can add in the final piece: allowing users to select the wall.

goals and considerations

  • create an elevation marker for exterior walls by having the user select the walls
  • place the marker and elevation offset from the wall so it is legible
  • correctly phase the elevation markers
  • accommodate curved and angled walls

if you missed it:

Part 1: elevation by wall

Part 2: phases

Part 3: rotating elevation markers

Part 4: align ViewSection CropBox to Wall CropBox

Part 5: finding the wall normal for curved walls

Part 6: align elevation markers to curved walls

windows presentation foundation (WPF)

I’m starting to learn WPF so for this plug-in I made a very simple user interface with the instructions for using the plug-in. I’m just beginning to learn so it’s nothing complicated. I won’t walk through this portion because I have done a couple posts on user interfaces and there are a lot of WPF resources out there. In our execute method, we need to first create a new instance of our form. Our form needs the active document which we had previously assigned to a variable called UIdoc. In the WPF code, depending on if the user clicked cancel or accept, it will return false or true for the dialog result. If the user pressed the cancel button, we want to stop our application.

WPF form with instructions for exterior elevations

user wall selection

If the user did not cancel, then they are going to select the walls. We can use the PickObjects method for this selection. One thing to note, is that the user will be able to select things other than walls with this method. One way to filter the user’s selection is to use the method that allows you to enter an ISelectionFilter as an input parameter. You can also filter for it in your code. Since we know all of our elements need to be walls specifically, we can just take our list of user elements and see if they are walls and if they are not, we don’t add them to our list. Finally, we just assign our list of user selected walls to our variable for the list of walls that we use for our program.

summary

And those few steps are all it takes to add user selection to our plug-in. This wraps up the create exterior elevations plug-in. You can access the code on my GitHub account and complied DLL is there to download as well. I’m taking a pause next week and will return the week after with a new plug-in. See you May 15th!

resources

If you want to learn to code and don’t know where to start check out my posts about Steps to Learn to Code [for architects and designers] Part 1 and Part 2.

Revit API Docs

bullet pont

align elevation markers for curved walls link

April 24, 2020

ipad with title, large neon star, movie reel, marker, green Happy Friday! For me, this marks the end of week 7 of quarantine here in the Bay Area. We’ve been trying to keep ourselves busy. One of the things my husband and I started doing is having Skype game nights with friends. We found some board games that work pretty well and we also purchased some computer games that are good for groups. I hope you are all staying healthy and sane.

As you know, I am tackling placing exterior elevations based on selected walls. Last week, we found the normal of curved walls so we could properly locate our elevation marker. This week we are going to offset our elevation marker so it correctly aligns with the curved wall.

I would like to add one note about a challenge that I found with the wall's normal. When I was testing this plug-in I had always created new curved walls to try it and had placed them where I wanted to test them. It wasn’t until I accidentally copied and pasted walls and then rotated them when I realized an interesting feature. The endpoints of a wall’s LocationCurve stay the same when you rotate walls. But the x and y direction parameter changes. This means that the walls are first created in the model coordinate space but when you rotate them they will be in a transformed space. The methods we used to find the wall's normal won't work if a curved wall was rotated after it was placed. I believe that this will apply to a small number of cases so I won’t be addressing it in this series. I did want to point it out so you are aware and can adjust your code to accommodate. I do have it on my list to address in the future.

goals and considerations

  • create an elevation marker for exterior walls by having the user select the walls
  • place the marker and elevation offset from the wall so it is legible
  • correctly phase the elevation markers
  • accommodate curved and angled walls

if you missed it:

Part 1: elevation by wall

Part 2: phases

Part 3: rotating elevation markers

Part 4: align ViewSection CropBox to Wall CropBox

Part 5: finding the wall normal for curved walls

orientation of curved walls

We will be adding a GetElevationMarkerPosition method which we will call within out PlaceMarker method that we wrote in Part 1. This will find the offset center for both curved walls and straight walls. Within our method, we add an if statement to separate our curved walls. We can do the same test for our if statement that we have done in the past. We try to cast the wall’s LocationCurve as an Arc and if that works then we know our wall is curved. After the last post Part 5, I have pullout out the code for finding the normal of a wall into its own method. This way we can use it again. I called it NormalofCurvedWall and output not only the angle of the normal, I also output a boolean parameter so we know if the wall is concave or convex. 

Within our if statement, we declare a few of our variables, call the NormalofCurvedWall method, and get the endpoints for our curve. This then allows us to get the angle that the curved wall’s orientation is at. This is the angle of the line that connects the two endpoints of the wall’s location curve. When we find the normal angle of the wall, that angle is relative to the model’s coordinate space, however, we need to find the angle between the wall’s normal and the wall’s orientation. So we update the wNormalAngle to be the wNormalAngle minus the angleLine EP1EP2. We add a negative because the axis of rotation for the marker is inverted. 

concave walls

Adjusting the normal is necessary for all curved walls. If a wall is concave, we want the wall center to be in between the two endpoints of the curve. That way, we can offset the marker’s location from this center by 5 feet and it will have the same offset as our straight walls. Our wall's normal is in radians and we need to find the vector for that angle so we can offset our elevation marker in the correct direction. To do that, we can use a rotation matrix and rotate our wall’s Orientation, which is the vector between the wall’s endpoints, and rotate it by the angle of our wall’s normal to get the wall’s normal as a vector. We also need to find the center which, for concave walls, we want to have as the center between the two endpoints.

convex walls

If a wall is convex, we still want to find the wall’s normal as a vector just as we did for concave walls. However, we need to use the negative of the wall’s normal as an angle. This is because a rotation matrix rotates the coordinate counter-clockwise when it is rotated about the Z-axis, but when rotating elevation markers around the Z-axis, it rotates clockwise. To accommodate for that, we use the negative of the angle. Our wall center for convex walls will be the center, plus the offset of the radius, times the wall’s normal. This will place it at the center of the rounded part of the curve, or the peak.

straight walls

This covers when our wall is curved, we also need our else statement for finding the center and the normal for a straight line.

offset

And finally, regardless of what type of wall it is, we can offset the center by 5 feet in the direction of the normal of the wall. This offset makes sure that the marker does not overlap with the wall. Since it is the same offset for curved and straight walls, we can do this at the end of our method and then return this offset center so we can use it in our PlaceElevations method.

summary

And that wraps up the adjustments we have to make to correctly place the marker for curved walls. The last item we want to update is adding the user selection for the walls so you can select the walls through Revit by clicking on them.

For reference, the NormalofCurveWall method. We put together the steps in Part 5, but I pulled it out into a separate method so we can use it again.

resources

If you want to learn to code and don’t know where to start check out my posts about Steps to Learn to Code [for architects and designers] Part 1 and Part 2.

Revit API Docs

bullet pont

finding the wall normal for curved walls link

April 17, 2020

ipad with title, large neon star, movie reel, marker, light blue Happy Friday! I hope you had an egg-cellent easter if you celebrate or otherwise a good week.

As you know, I am tackling placing exterior elevations based on selected walls. One of our goals was to accommodate curved and angled walls. Our plug-in already accommodates walls at any angle. Now, we need to make a few adjustments to accommodate curved walls. This involves finding the normal for curved walls.

goals and considerations

  • create an elevation marker for exterior walls by having the user select the walls
  • place the marker and elevation offset from the wall so it is legible
  • correctly phase the elevation markers
  • accommodate curved and angled walls

if you missed it:

Part 1: elevation by wall

Part 2: phases

Part 3: rotating elevation markers

Part 4: align ViewSection CropBox to Wall CropBox

orientation of curved walls

When we test our plug-in with curved walls, we immediately notice that the elevation markers do not face the correct direction. Using RevitLookUp we can see that the Orientation of the wall does not face away or towards the curve, but instead is the vector between the wall’s endpoints.

Curved walls fall into two categories:
category A: concave when looking at the wall from the outside
category B: convex when looking at the wall from the outside

Additionally, you can draw walls two different ways, from left to right and from right to left. Wherever you click first, that is the endpoint that is stored in the first index when you retrieve the endpoints of the location curve. We will call these type 1 and type 2. I diagramed these four instances in the image below.

When looking at the Orientation property for the wall, it is possible to notice a pattern. For walls A1 and A2, the Orientation of the wall is the unit vector from endpoint(0) to endpoint(1). The Orientation flips if you draw the curve from right to left instead of from left to right. We will come back to this in a moment.

diagram of curved wall category A and category B with both variations

LocationCurve

For now, we are going to make the adjustment to accommodate curved walls in our GetAngleViewtoWall method which we had created in Part 3 rotating elevation markers. Originally, we had used the wall’s Orientation property which is the wall’s normal for a straight wall. As we realized above, the Orientation of curved walls is not equal to the wall normal. When you have a curved wall, the LocationCurve is an Arc instead of a Curve. We can use this to filter our if statement so the part of the code we are about to write only executes if the wall is curved. If the wall is not an arc, the variable wallCurveAsArc will return null.

Since the variable wallCurveAsArc tells us if the wall is curved, we can use an if statement that checks if the variable wallCurveAsArc is not equal to null. From there we can first get the curve’s endpoints. We also want to get the angle between the endpoints using ArcTan and declare our curveNormal variable which we will use later.

category A or B

We also need to figure out if a wall falls into category A: concave when looking at it from the outside or category B: convex when looking at it from the outside. We know that the Orientation of the walls that fall into category A is the unit vector from endpoint(0) to endpoint(1). This means that if the unit vector from endpoint(0) to endpoint(1) is equal to the Orientation, then it falls into category A. If they are not equal, it falls into category B. To simplify this comparison, we compare the signs for the X and Y value of the vectors to the signs of the X and Y values of the Orientation. This prevents any rounding errors that may happen if we were to compare the actual values.

First, we set up our Boolean variables.

Then we can use an if statement to find the correct curveNormal based on if the wall is in category A or category B. If the wall is in category A, the X and Y values of the unit vector from endpoint(0) to endpoint(1) is equal to the X and Y values of the Orientation. We simplified this comparison by only comparing the signs as described above. If the wall is in Category A1 then the curveNormal will equal the angle between the endpoints plus 90 degrees. If the wall is in Category A2 the curveNormal will equal the angle between the endpoints minus 90 degrees. To adjust if you add or subtract, we are multiplying it by the YDirection property of the Wall’s LocationCurve. This YDirection tells us if we flipped endpoints 0 and 1.

All walls that do not fall into category A, fall into category B. This is our else condition and all we have to do is change from addition to subtraction to accommodate the flipped condition. And that is how you find the normal of a curved wall!

rotating elevation marker for curved walls

Once we find the normal of the curved wall, we need to rotate the elevation marker that we placed for the wall by the wall's normal minus 180 degrees. During testing, I noticed that rotating the marker by a negative angle did not work. So if angleViewtoWall is less than zero, we want to add 360 degrees.

summary

Since we are modifying the GetAngleViewtoWall method that we previously wrote, we add the else statement at the end with the code needed for walls that follow a straight line. And that wraps up finding the normal and rotating the marker for curved walls. Next, we will look at how to place the elevation marker correctly for curved walls so it is not located in the middle of the curve.

UPDATE: 4/23/2020: I would like to add one note about a challenge that I found with the wall's normal. When I was testing this plug-in I had always created new curved walls to try it and had placed them where I wanted to test them. It wasn’t until I accidentally copied and pasted walls and then rotated them when I realized an interesting feature. The endpoints of a wall’s LocationCurve stay the same when you rotate walls. But the x and y direction parameter changes. This means that the walls are first created in the model coordinate space but when you rotate them they will be in a transformed space. The methods we used to find the wall's normal won't work if a curved wall was rotated after it was placed. I believe that this will apply to a small number of cases so I won’t be addressing it in this series. I did want to point it out so you are aware and can adjust your code to accommodate. I do have it on my list to address in the future.

resources

If you want to learn to code and don’t know where to start check out my posts about Steps to Learn to Code [for architects and designers] Part 1 and Part 2.

Revit API Docs

bullet pont

align ViewSection CropBox to Wall CropBox link

April 11, 2020

ipad with title, large neon star, movie reel, marker, orange I hope you are all staying healthy. Due to some computer problems, I’ve had a slight delay in releasing some of my posts the past month, but I have my laptop back now and hopefully, everything keeps running smoothly.

As you know, I am tackling placing exterior elevations based on selected walls. Once the elevations are placed, adjust the CropBox of each elevation manually would be time-consuming. Instead, we want the program to adjust the CropBox to match the wall that we are viewing. So this week we will walk through how to align the CropBox of the ViewSection with that of the Wall.

goals and considerations

  • create an elevation marker for exterior walls by having the user select the walls
  • place the marker and elevation offset from the wall so it is legible
  • correctly phase the elevation markers
  • accommodate curved and angled walls

if you missed it:

Part 1: elevation by wall

Part 2: phases

Part 3: rotating elevation markers

wall endpoints

While testing this plug-in I found that the wall’s CropBox wasn’t always the same width as the wall. Because of this, I am going to use the endpoints of the wall to get the new coordinates for the ViewSection CropBox. First, we create a new public method and call it SetCropBox. It doesn’t need to return anything. We will need the document, the elevation marker we have created, and the wall as parameters. We need to find the values that we are going to use to set the minimum and maximum points of the ViewSection CropBox. The first step is to get the endpoints of the wall. We can do this by finding the LocationCurve of the wall and using the GetEndPoint method at the first and second index. Then we can get the wall’s height from the WALL_USER_HEIGHT_PARAM BuiltInParameter. The wall’s minimum coordinate will just be the first endpoint of the curve. To get the wall’s maximum coordinate, we will need to add the wall height to the Z coordinate.

transform

Now that we have the points we need, we have to transform these points into the ViewSection’s coordinate system. I had written a few utility methods for this which you can read about in my previous post about resizing CropBoxes for interior elevations. The methods transform the minimum and maximum values and the ViewSection’s origin from the project’s coordinate system into the ViewSection’s coordinate system.

check min and max

After we transform the coordinates, it is possible that the minimum is no longer the smaller value and is instead the maximum. Because of this, we want to check the two coordinates and take the higher value and assign it to the max and take the lower value an assign it to the min. Since I have been using this a few times now, I added it to my Utility methods.

So in our method we can just add the following:

update CropBox

The last step is just to update the crop box with the new coordinates. We keep the Z coordinate of the ViewSection’s original CropBox because this is the depth and we don’t need to change that. When we assign the X and Y values, we need to make sure to subtract the translated origin. This is because when we translated the wall’s endpoints, this translation was relative to ViewSection’s origin rather than the project’s origin.

We also want to subtract a small fraction from the height of the new CropBox. This ensures that the elevation marker is hidden in the plans that do not correspond to the same level as the wall. If we don’t subtract 0.01, the top of the CropBox aligns with the level at the top of the wall. So if the wall goes from 0’-0” at the first floor to 12’-0” at the second floor, and the CropBox goes from 0’-0” to 12’-0” then it will be visible on the second floor plan. If it goes to 11’-11.98” then it will not show on the second floor plan.

We can then also set the CropBox line to be invisible by setting CropBoxVisible to false.

summary

And that wraps up the steps we need to take to have the CropBox of the ViewSection match the CropBox of the wall. Since we have cropped the height of the elevation to the height of the wall, the elevation marker will only display on the floor plans that correspond to the same level as the wall. Now we need to make adjustments so that our plug-in works for curved walls and allow for the user to select the walls they want to elevate.

resources

If you want to learn to code and don’t know where to start check out my posts about Steps to Learn to Code [for architects and designers] Part 1 and Part 2.

Revit API Docs

bullet pont

rotating elevation markers link

March 27, 2020

ipad with title, large neon star, movie reel, marker, blue Happy Friday everyone! Today has completed my second week of WFH and I have to say, I appreciate the short commute. I hope you have settled into a new routine as well and have all been staying safe and healthy.

As you know, I am tackling placing exterior elevations based on selected walls. An important step of our plug-in is to correctly align our elevation marker to our wall. When we placed our marker in Part 1, we put the ViewSection on the first available index on the marker. Now, we need to rotate the marker to correctly align to the wall. This will work for both orthogonal and angled walls.

goals and considerations

  • create an elevation marker for exterior walls by having the user select the walls
  • place the marker and elevation offset from the wall so it is legible
  • correctly phase the elevation markers
  • accommodate curved and angled walls

if you missed it:

Part 1: elevation by wall

Part 2: phases

GetViewSectionNormal

In order to get the angle that we will use to rotate the elevation marker, we first need to get the normal of the ViewSection. This is the vector of the direction that the view is looking. The only points that you can look up for a ViewSection are the minimum and maximum corners of the crop box. Normally, when rotating elevation markers, you can work in the model coordinate system. This is because the ViewSection CropBox and the elevation Marker are both in the model coordinate system. However, it is not possible to find all four corners of a rectangle without also knowing the transform angle. Since we know that in the view’s coordinate system, the transform angle is zero, we need to transform our points into the view’s coordinate system. Once the points are transformed, we know that the vector we are looking for is in the negative Z direction. Then we apply the inverse transform to get the endpoints of the vector back into the model coordinate system and subtract them to get the ViewSection normal.

GetAngleViewtoWall

The second part is finding the normal of our wall. In Revit, the normal of an exterior walls points to the outside. Walls have an Orientation property which is the wall’s normal. Once we have the ViewSection normal and the Wall normal, we can determine the angle between. Since we want these two vectors facing each other, we want the angle between them to be Pi radians (180 degrees). So we take Pi radians and subtract the current angle between the two vectors that we found.

The other aspect to consider is that the AngleTo method does not return a negative angle. Because of this, we have to manually determine which direction to rotate the elevation marker (clockwise or counter clockwise). We can write a simple if statement to do this.

RotateMarker

Finally, we have the angle we need to rotate our elevation Marker. We can create an axis of rotation at the center of the elevation Marker and rotate it by the angle we determined in the previous step.

add to execute

The elevation marker needs to be rotated after it is placed so we can add our new methods to our Execute method after the marker is created.

And that is how we can rotate our markers to face our exterior walls regardless of if they are orthogonal or at a different angle. The last couple items we want to look at are associating the Marker with the correct level, cropping the view to the extents of the wall, and allowing users to select walls in their project.

resources

If you want to learn to code and don’t know where to start check out my posts about Steps to Learn to Code [for architects and designers] Part 1 and Part 2.

Revit API Docs

bullet pont

phases link

March 13, 2020

ipad with title, large neon star, movie reel, marker, blue For my next series, I am tackling placing exterior elevations based on selected walls. For our plug-in we need to understand the phase of views, rooms, and walls. This week, I will try to assist in letting you know where to look for and manipulate this information. When working with phases you will need to make some assumptions. Users can rename phases as they like so I always try to get the phase from an active view. It is important to review phases because Revit automatically uses the last phase in a project when creating an element and sometimes even when using a FilteredElementCollector. As a reminder, our goals for the complete plug-in are listed below.

goals and considerations

  • create an elevation marker for exterior walls by having the user select the walls
  • place the marker and elevation offset from the wall so it is legible
  • correctly phase the elevation markers
  • accommodate curved and angled walls

if you missed it:

Part 1: elevation by wall

element phases

If you have worked in Revit, you know that everything you place has a phase. These things are in the Element class in the Revit API and therefore have a CreatedPhaseId and a DemolishedPhaseId property. This is how you read and set the phase of Elements including walls, components, and other families. These are the most straight-forward to understand and are well documented.

view phases

There are some things that inherit the above-mentioned properties from the Element class, but do not use these properties. ViewSections inherit the Element class and thus inherit the CreatedPhaseId property and the DemolishedPhaseId property. However, for views like ViewSections and ViewPlans, these parameters are not used. It makes sense if you think about it because the ViewSection itself does not have a phase, instead it is displaying a specific phase. Because of that, what you actually need is the enum BuiltInParameter called VIEW_PHASE. The ElementId for a specific phase is always the same regardless of which parameter it is used in. So the ElementId to set the BuiltInParameter VIEW_PHASE to the phase "New Construction", for example, is the same as the ElementId used to set the CreatedPhaseId property to the phase "New Construction".

room phases

For rooms, there are four different places to look for phases, as you can see below. The one you want is BuiltInParameter.ROOM_PHASE.

Additionally, when you use a FilteredElementCollector to gather all the rooms in the project, it will automatically collect the rooms in the last phase of your project. I wrote a RoomHelper class with utility methods that takes the active document and the phase as inputs and then it filters for the rooms that were created in that phase. This makes sure that the collector is returning the expected list of rooms, even if the project has multiple phases.

elevation marker phases

When placing elevation markers through C#, they will automatically be created in the last phase of the project. You do not need a ViewPlan to place the ElevationMarker, but you do need one to create the elevation ViewSection on the marker. Generally, the phase of the ViewPlan that the ElevationMarker will be visible in, should be the same as the PHASE_CREATED of the marker. You can see how you can set the marker’s phase to that of the view plan phase (indicated by variable “p”) in the sample below.

Additionally, once you create an elevation ViewSection, you can set the phase that the view is displaying. Generally, you will also want to set this to be the same phase as the ViewPlan. The Elevation uses the BuiltInParameter VIEW_PHASE so we can set it to the same phase as our ViewPlan which is indicated by variable “p” below.

As you can see, phases are an intricate process and sometimes require trial and error. If you are expecting something to show up in Revit and it does not, a good thing to check is the phase. I hope to have clarified a few items to make your process easier. As we are creating and filtering elements, it is always a good idea to keep track of what phase they are in.

resources

If you want to learn to code and don’t know where to start check out my posts about Steps to Learn to Code [for architects and designers] Part 1 and Part 2.

Revit API Docs

bullet pont

elevation by wall link

March 6, 2020

ipad with title, large neon star, movie reel, marker, green For my next series, I am tackling placing exterior elevations based on selected walls. Generally, templates have North, South, East, and West elevations set up, however, there are many uses for exterior elevations where you would need more than just those four. Storefront schedules, for example, can be expedited if exterior elevations could be placed by selecting the wall and automatically cropping to that wall. This would also make it easier to add elevations for angled walls.

goals and considerations

  • create an elevation marker for exterior walls by having the user select the walls
  • place the marker and elevation offset from the wall so it is legible
  • correctly phase the elevation markers
  • accommodate curved and angled walls

inputs

To simplify the problem, I almost always hard-code the selection process and adjust it to be a user selection later on. This allows me to focus on the functionality of the plug-in and handle the user interaction once it works. So for now, I will gather all the exterior walls in a list. I am accomplishing this based on the assumption that the name of all exterior walls in the project contain “ext” in the name. You can customize this to filter the correct walls.

placing the marker

Once we have the walls, we can place the elevation marker. There are several parameters we need for the CreateElevationMarker method. We need the document, the FamilyTypeId of the exterior elevation marker, a location for the marker, and a scale. Passing through the document is straight forward and to get the FamilyTypeId we simply have to filter for it.

We can hard-code the scale for now and later adjust this to a user selection. That only leaves us the location. We want the location of the marker to be the center of the selected wall. We create a new public method that will return an ElevationMarker and name it Place Marker. The parameters that are required are the document and the bounding box of the wall. To find the center, we take the minimum and maximum values for the X and Y values of the bounding box and divide by two.

This method allows us to place the marker at the center of the wall. Next week, we will look at off-setting the elevation marker from the wall since this will allow the marker to be legible on drawings.

resources

If you want to learn to code and don’t know where to start check out my posts about Steps to Learn to Code [for architects and designers] Part 1 and Part 2.

Revit API Docs

bullet pont

strategic planning [part 2] link

February 28, 2020

Large light and wooden trees with quote and blue background A handful of unexpected turns during February meant some changes to the original plan. I'm back for the last post of the month to discuss the follow up to my thoughts on strategic planning. Next week, I will get back into coding!

As I discussed in January, this year was the first time DAHLIN has held a team-wide Design Technology group strategic planning session. Following our team process, which you can read about here, we had champions for our four major teams: Maintenance, Automation, Education, and Innovation. Their responsibilities since January were developing a path to meet the goals the group set and to refine these goals to ensure they fit in with the Design Technology and the company’s vision.

As champion for the Automation team and a member of two of our other teams, I was able to experience the process both as a champion and a team member.

as a team champion

One of the biggest challenges that I faced was shifting from the mindset of wanting to accomplish everything to being realistic with the time we have in the coming year. You have to be open when first gathering ideas. As you refine those ideas, you need to become increasingly realistic because you are narrowing them down to goals that the group will be held accountable for.

Some key items I learned:

overcome the tendency to focus on the fun tasks

When you have a long to-do list, many people focus on the fun tasks first. For example, if there are 15 template fixes mixed in with two new dynamo scripts, I will always want to focus on the scripts first. I have to intentionally complete the sometimes mundane items to make sure we’re on track. As a champion, it is your responsibility to manage those tasks and ensure the team is working on all the goals.

prioritize and adapt

It is your responsibility to keep the team on track with the goals you have set, however, unexpected circumstances will almost always arise. When some things just can’t get done, it’s okay to prioritize. Additionally, as other information or requirements come up throughout the year, don’t be afraid to adjust your priorities and even your goals to better align.

stay focused, but remember the bigger picture

It is so easy to get caught in the task at hand and only focus on your team’s goals. It is your responsibility to understand how your team's tasks fit into the big picture. Focus on moving your team’s goals forward, but always understand how they fit in with the company’s vision.

listen

Good leaders listen to their team members and respect everyone’s opinions. You are not responsible for having all the answers. You are responsible for asking the right questions and bringing out the best in everyone.

as a team member

We have organized our Design Technology group in a way that allows many opportunities for leadership and involvement. In addition to having a champion of each team (Maintenance, Automation, Education, and Innovation) we also have a champion for each goal. The champion is responsible for moving that goal forward but anyone can help out with the goal. People can champion multiple goals or they can co-champion goals. I feel that a benefit of this is it allows people to take responsibility for the tasks they are working on. Team members are the driving force for each team and critical in accomplishing the tasks at hand.

Some key items I learned:

stay engaged

A team is only as strong as its weakest link. Champions are there to make sure the team stays on track, but the strength lies in the team. Having an engaged team allows everyone to get things done. As a team member, you have the power to take responsibility for tasks and see them through to completion.

be involved in topics you are passionate about

It is much easier to focus on tasks when you are interested in them. Of course, there will always be some dull items on your list, but in general, stay involved in topics you enjoy.

bring your expertise

Different knowledge, interests, and backgrounds contribute to the success of a team. A diverse team is a strong team. Bring your knowledge to the team and don’t be afraid to share. Speak up if you disagree with something or have a new perspective to contribute to a topic.

As the year moves forward it will be exciting to see all the teams working towards their goals. We have weekly meetings for the Design Technology group that cover a range of topics and one meeting per month is dedicated to check-ins for each team. The intention of the team-wide strategic planning is to have input from everyone in the process and I feel that we accomplished that this year. It is exciting to see the team move forward with our goals and better the resources and support for our firm.