January 17, 2015

Revit: Ceiling Pattern Will Not Move

A hearty thanks goes out to Steve Stafford, who documented the solution to a problem that arose in my office yesterday, way back in 2012, in his Revit OpEd blog.

The problem is that if you use the Move tool with the Disjoin option checked, and then later in that session try to use it to move a Ceiling grid pattern or other model pattern, Revit "remembers" that the Disjoin option was selected previously, and starts out with it turned on. Since Disjoin is not applicable to moving a model pattern, Revit disables (grays out) this option when a model pattern is the object of the Move tool. You might think that since the option is disabled, that it would not have any effect on the command at hand, but you would be wrong. Having this option checked effectively breaks the command, and while you can go through the motions, no change will take place.

To add insult to injury, having the Disjoin option disabled means you cannot clear the checkmark while trying to move a model pattern. The solution, as Steve reported, is to select an object for which the Move Disjoin option is active, such as a Wall, and select the Move tool. Clear the check mark at the Disjoin option on the Options bar, and then press the ESC key twice to exit the command without actually moving the selected object. Now you cah select the Ceiling grid or other model pattern and use the Move tool to reposition the pattern.

Here is a Screencast showing both the problem and the solution, that I put together for users in my office who would rather see the solution than read about it.

January 08, 2015

Dynamo: Text Padding Nodes

I made an interesting discovery the other day, just as I was finishing up my article on zero-padding for an integer-to-string conversion. And while I do not regret the effort I put into developing the custom nodes to achieve that result, as I am still very much in learning mode, and that gave me a task in which I had some interest, I would be remiss if I did not pass along this "discovery".

In the Dynamo out-of-the-box Library, there are two nodes that, similar to my custom node, will "pad" a string to a specified length, using the character (or characters) of your choice. These can be found under Core > String > Actions, and are called PadLeft and PadRight.

In the image above, the same input is provided to each of these nodes, and the newWidth input is provided with a list of values, resulting in a list of results, so you can see the effects. The str input is "ABC" and a multi-character string, "wxyz" is used for the padChars input. As you can see, the PadLeft node adds padding characters to the left side of the string; the PadRight node adds padding characters to the right side of the string. Just like my custom node, if the length of the initial string is the same or greater than the newWidth value, the original string is passed through unmodified.

Unlike my custom node, you can specify any string to be used for padding. If the padding string has more than one character, then Dynamo uses the first character of the string when one character is required for padding, the first two characters when two characters are required, and so on. If the required number of characters for padding exceeds the length of the padChars string, as many instances of the full string plus a partial string with as many characters starting with the first as needed to bring the final string to the specified length will be used.

The Screencast below shows how the PadLeft node can be used to do the same thing as my custom node.

The lesson to be learned here is, prior to embarking on a programming task in Dynamo, take a careful look at what is provided out-of-the-box (as well as in "packages" of custom nodes that can be downloaded) to see if some or all of what you need to do is already available.

2015-11-13 UPDATE: In Dynamo 0.8.2, the ToString node is now called String from Object.

January 07, 2015

Dynamo: New Stable Build Available

Dynamo Version 0.7.5 is now available for download from the Dynamo download page.

January 06, 2015

Dyanmo: Custom Node, Integer To String - Zero Padding

Having created a node that would convert an integer to a string, padding a single-character string to two characters by adding an initial "0" so that a YYYYMMDD date string could be generated, it occurred to me that having a more general purpose node, where you could specify the number of characters to which the string should be zero-padded, would be more useful. As with the two-character node, no effort is made to truncate the original string if it exceeds the specified length, but strings with fewer characters will have the necessary number of zero characters ("0") added to the front of the string to bring it up to the specified number of characters.

As seen in the short Screencast below, the custom node takes two numeric inputs, the number of characters to which zero-padding is to be applied and an "integer" [see note at end of article] that is to be converted to a string, with zero-padding as necessary. In the Dynamo file I set up to demonstrate the custom node, an Integer Slider node (in the Library, Core > Input > Integer Slider) is used to specify the number of digits desired and a Number node (Core > Input > Number) is used to provide the integer to be converted to a string. Note that the Run Automatically toggle is checked, so as changes are made, the results are calculated and displayed without having to press the Run button each time.

Integer To String - Zero Padding Node
The image above shows the graph of the Integer To String - Zero Padding custom node. A description of the graph function follows.
  1. The integer to be converted to a string is processed by the Math.Floor node (Core > Math > Actions > Floor) to remove any fractional part (see note below) prior to being passed to the ToString node (Builtin Function > ToString), which converts it to a string.
  2. The integer string created in Step 1 is passed to a String.Length node (Core > String > Actions > Length), which returns the string length as an integer. A custom node called Zero Padding String takes the Final String Length as input to the Integer To String - Zero Padding custom node, and the string length of the integer string and returns a string containing the zeros that need to be added to the front of the integer string (if any). See below for the graph of this custom node.
  3. The zeros string from Step 2 is concatenated onto the front of the integer string from Step 1 by a String.Concat node (Core > String > Actions > Concat), which is then passed as the output of the Integer To String - Zero Padding custom node. Note that if the length of the Step 1 integer string is greater than or equal to the Final String Length, the zero string will be an empty string, and the end result will be equivalent to the Step 1 integer string.

Zero Padding String Node
The image above shows the graph of the Zero Padding String custom node. A description of the graph function follows.
  1. The easiest way to explain how this graph functions is to start with the LoopWhile node (Builtin Functions > LoopWhile). The LoopWhile node takes three inputs: init, the intial state of the object being processed; continueWhile, the test condition that determines whether or not the current object being processed should be processed again; and loopBody, which defines what action(s) are taken on each pass of the loop.
  2. The init input is provided by a Code Block node (Core > Input > Code Block; or double-click in the graph canvas). Code Blocks allow for custom scripting in Dynamo; in this case, it is being used to simply generate an empty string. A String node (Core > Input > String), with the input left blank, could also have been used; I felt that seeing the two double quotation mark characters, with no other characters in between, in the Code Block made the node read better. I also double-clicked on the Code Block title and renamed it to "Empty String" to more clearly indicate its purpose.
  3. The continueWhile input is the most complicated. A - [Subtraction] node (Operators > -) calculates the difference between the Final String Length input and the Starting String Length. If this is a positive number, it represents the number of zero characters needed in the final padding string. We want to compare the length of the current string to this number, and continue to process the string if the current string length is less than the desired string length. This comparison is done by the < [Less Than] node (Operators > <), and the current string length is generated by the String.Length node. For reasons beyond my current understanding, the output of the String.Length node cannot simply be put into the x input of the < node, and the result of that fed to the continueWhile input. The continueWhile input requires a single function as the input, and so a Function.Compose node (Core > Evaluate > Function.Compose) is used to combine these nodes in a way that is acceptable as input for the continueWhile input. The + and - buttons on the node allow you to add or remove function inputs so that you have the correct amount for your application. In this case, the initial default of two inputs was what was needed.
    You may have noticed that both the < and String.Length nodes have unconnected inputs. The LoopWhile node presumes that you will be doing something to whatever is passed to the init input, in this case, a string, and will supply that value to any open input of matching type. Likewise, the Function.Compose node supplies the integer value passed to the func0 input by the String.Length node to the open x input of the < node. Also note that by including the current value of the processed object in the evaluation, we make it possible for the the comparison to eventually be false, and for the loop to terminate. Failure to do so would result in an infinite loop, which is not a good thing.
  4. The loopBody input is fairly straightforward. Another Code Block node, renamed to "Zero String" creates a string with a single zero character in it. This is the input to the string0 input of a String.Concat node. The string1 input is left open, so the processed object string will be supplied here. Each time the loop body is entered, a zero character will be added to the front of the current processed object string, making it one character larger. Eventually, the processed string length will be equal to the difference between the Final String Length and the Starting String Length, the loop will terminate and the final result will be a string with the proper number of zero characters.
  5. To summarize, the loop starts with an initial value of an empty string. The length of that empty string (0) is compared to the difference between the Final String Length and Starting String Length inputs, to see if it is less than the difference. If that difference is 0 or a negative number, then the value fed to the continueWhile input is false, no action will be taken, and the result of the custom node will be an empty string. If the difference is 1 or greater, then the value fed to the continueWhile input is true, and the loop body code will be run, adding a zero character to the empty string. The loop process is then run again, but this time the current value is not an empty string but "0", and the string length is 1. If the difference is 1, then the less than condition is false and the "0" string is passed to the output of the custom node. Otherwise, the loop body is run again and "00" becomes the new current value of the string. This continues until the string length is not less than the difference, at which point the loop terminates and the current string value becomes the custom node result.

NOTE: I put "integer" in quotation marks when describing the node input above because while that is the intended input, both inputs will accept a double (precision real number), with a non-zero fractional value, as input. For the number to be converted, any fractional part is discarded prior to the conversion to a string. The way the Final String Length value is used, any fractional amount will be the same as specifying the next higher integer. If a given application could generate a value with a fractional amount as the input for the Final String Length and only the whole number value is desired, the Math.Floor node should be used to strip the fractional amount. This works for non-negative numbers; the function returns the first integer that is lower than the input value. For negative numbers, this will change the units number. So 1.9 becomes 1, but -1.1 becomes -2. I was not expecting to be using zero-padding on negative numbers; if you have an application that would require that, then you may want to modify the code to accommodate that. Note also that the sign ("-") counts as a character after a negative number is converted to a string. If you want the zero padding of a negative number to be calculated without including the "-" sign in the number of characters, the code would have to be modified to account for that.

January 05, 2015

ACA: AEC Modify Tools, Part 5, AEC Obscure

First post in series [AecLineworkExtend].
Previous post in series [AECLineworkSubtract].

The AecLineworkObscure command can be found on the Home ribbon tab, on the Modify panel flyout, by selecting the Obscure tool from the Obscure/Crop flyout. If the Obscure tool is not the displayed tool on the Obscure/Crop flyout, select the right side of the split button (down arrow icon) to deploy the flyout and choose the Obscure tool. Or, with no command active, you can right click in the drawing window, and choose AEC Modify Tools > Obscure from the context menu.

The AecLineworkObscure command is used to change the parts of linework, AEC Polygons, Mass Element Extrusions that have an embedded profile, Spaces and Hatches as well as Block References which contain any of these objects that fall within a user-defined obscuration area, replacing the linework or boundaries of the other items with linework placed on the layer defined by the HIDDEN Layer Key in the current Layer Key Style. This layer typically has a dashed linetype assigned. In the out-of-the-box Imperial content, using the AEC Title Case - NCS 256 Color Layer Key Style, this layer is G-Detl-Hidd, color Red and linetype HIDDEN2.

As with the AecLineworkSubtract command, there are two options for specifying the extents of the obscuration area:
  • Select one or more items in the drawing, which form at least one closed loop. Any single closed item will work (closed Polyline, Circle, Ellipse, AEC Polygon, Mass Element or Space), as will any combination of objects that, combined, form at least one closed loop.
  • Press the ENTER key when prompted to select items to be obscured, and then define an obscuration rectangle by selecting opposite corners of a rectangle. The rectangle will have sides parallel to the X- and Y-axes of the current UCS.
The primary use of this command is to make it easy to show parts of Detail Components that, for the detail at hand, occur behind another item, with a hidden linetype, without having to explode or manually break linework. It will work on linework and block references generated by other means.
Here are some additional notes regarding the AecLineworkObscure command:
  • MText, Text, Ellipses and Ellipse Arcs cannot be added to the selection set of objects to be obscured.
  • Ellipses and Ellipse Arcs can be selected as (part of) a boundary defining the area to be obscured.
  • Mass Elements with a shape other than "Extrusion" and Mass Element Extrusions that have an external Profile can be selected as objects to be obscured, but will not affected by the AecLineworkObscure command. These types of Mass Elements can be used to define the area to be obscured.
  • If a Block Reference is selected as an object to be obscured, only those nested objects within the block on which the AecLineworkObscure command works will be affected.
  • Attributes within a Block Reference will not be affected by the AecLineworkObscure command.
  • If a Block Reference is selected as an object to be obscured, it has obuscurable nested elements and it is the only instance of that Block Reference in the drawing, then the original block definition will be redefined to include the effects of the obscuration. If at least one instance of the Block Reference remains unaffected by the obscuration, then the original block definition will remain unchanged and the affected instance(s) will become instance(s) of new, anonymous block definition(s).
  • Multi-View Blocks can be selected as an object to have a part obscured, but will not be affected by the command.
  • If the active View Block of a Multi-View Block contains linework that forms a closed boundary or contributes to a closed boundary, it can used to define the area to be obscured.
  • Unlike the AecLineworkTrim, AecLineworkDivide and AecLineworkSubtract commands, use of the AecLineworkObscure command on a closed Polyline or Circle does not result in one or more closed Polylines.
  • A Line or Arc, freestanding or within a block reference, that is in the selection set of the AecLineworkObscure command is replaced with one or more Polylines.
  • A Circle, freestanding or within a block reference, that is in the selection set of the AecLineworkObscure command is replaced with one or more Polylines for the portion(s) outside of the area being obscured and one or more Arcs for the portion(s) within the area being obscured. The Polyline(s) and/or Arcs will have vertices/endpoints at the World Coordinate System 0-degree and 180-degree locations on the original Circle.
  • A closed Polyline, freestanding or within a block reference, that is in the selection set of the AecLineworkObscure command is replaced with one or more Polylines for the portion(s) outside of the area being obscured and Lines/Arcs for the portion(s) within the area being obscured.
  • An open Polyline, freestanding or within a block reference, that is in the selection set of the AecLineworkObscure command is replaced with one or more Polylines for all portions, whether within or outside of the area being obscured.
  • If a hatch object is to be obscured, the hatch will be removed from the from the obscuration area, but no hidden graphics will be generated.
  • Obscuring an associative Hatch will result in a non-associative Hatch, regardless of whether or not the boundary of the Hatch is included in the obscuration.
  • Associative Spaces, Walls, Doors, Windows and Door/Window Assemblies can be selected as items to be obscured, but will not be affected by the command. Non-associative Spaces do work with the AecLineworkObscure command.
  • If you obscure an AEC Polygon, the Exterior Edge components of the AEC Polygon that fall with in the obscuration area will be replaced with "hidden" lines or arcs. Interior Edge components of the AEC Polygon, if present, are removed, but not replaced with "hidden" linework. New Exterior Edges and, if present, Interior Edges are created when the AEC Polygon extends beyond the obscuration area, but these new edges are "invisible" - no linework is drawn on screen. If Interior or Exterior Hatch or Fill components are turned on, they will, however, change to fill in the modified AEC Polygon extents, which does not give a true obscuration effect.
  • If the area to be obscured effectively splits an object into two or more separate pieces, the result depends upon the selected object. Hatches, Mass Element Extrusions (embedded Profiles), AEC Polygons and Spaces will result in one object, with two (or more) separate, non-contiguous regions. See above for note on how new AEC Polygon Edges will not have any visible graphics.
  • If an object (or nested object, in the case of a block reference) in the obscure selection set is entirely within the obscuration boundary, it will be completely replaced with hidden linework.
  • Unlike the AecLineworkSubtract command, if you select one or more objects to define the extents to be obscured, you are not prompted as to whether the boundary objects are to be erased.
  • Even though Mass Element Extrusions (with embedded profile) are 3D objects and Spaces can be 3D objects, the hidden linework is only 2D, in the current X-Y plane. The removal of portion of these objects in the obscuration area does affect the object in 3D.

As with the AecLineworkDivide and AecLineworkSubtract commands, there are object types and combinations of objects within a Block Reference that I did not test. If you are thinking of using the AecLineworkObscure command in a situation that you have not previously encountered, you may want to use the Mark option of the UNDO command to place one or more UNDO Marks prior to using the command, so that you can easily UNDO Back to the point before the command was used if you get unexpected results.

Next post in series [AECLineworkMerge]

January 03, 2015

Autodesk Application Manager - Update README

Perhaps unlike many, I prefer to look through the README that generally accompanies updates to the Autodesk products I use. These are usually available from a link on the same webpage from which the update is downloaded. With the introduction of the Autodesk® Application Manager, access to updates is made easier (at least for an individual user) and often earlier than on the Autodesk website. I was initially disappointed that there was not a link to the README available in the Application Manager. It turns out I just did not know where to look (and the fact that the link to the README does not include "README" in the link label made it somewhat less discoverable). This brief Screencast shows how to expose the "Details" (a brief description) of an update, as well as the View Details link to the README.

My other reservation was not having the update file for later use, if necessary. Those do get downloaded and saved to your computer; you can find (and, if you like, customize) the location where the updates are saved by selecting the Settings tool in the upper right corner of the Application Manager, and then selecting the Files tab. The Local Files Location specifies where the folder under which updates are stored. Look at the edit box to see the current location or click on the ellipsis (...) button to open a dialog to see the current location and, if desired, navigate to a new one.