Splits: Persona, Collector, Region, Tag, Modification

I need to come to terms with the split personality recently foisted upon me. Thank God, RevitLookup now handles split regions.

Meanwhile, lots more going on in the Revit API discussion forum and elsewhere in the world:

Two Jeremys

Apparently, the user account handling for the Revit API discussion forum thread recently changed.

I can no longer log in with the non-standard Autodesk jeremytammik account that I have been using all these years; the login automatically switches that over to my standard Autodesk jeremy.tammik account with a dot . instead.

As a result, we now have two active Jeremys in the forum:

Two Jeremys

I guess the previous one will fade away as time goes on.

I wish I could meet him in person before he disappears.

Multiple Collectors versus Multiple Filters

This question arose repeatedly in the past few weeks, so let's reiterate it in detail, prompted by the Revit API discussion forum thread on multiple collectors

Question: I noticed that if I create multiple collectors in the same script, they don't work properly and most likely end up empty. I've tried to use Dispose before creating the second collector to see if it can sort of "reset" the collector, but I always get this error:

What am I missing?

Here is a simple example where I collect all shared parameters in a project first, so I can use their GUIDs to collect data from them in families.

  collector = FilteredElementCollector(doc)

  # Find GUID of desired shared parameters

  sharedPars = collector.OfClass(SharedParameterElement)

  # Collect data from families based on parameter GUID.

  families = collector.OfClass(FamilyInstance)
    .WhereElementIsViewIndependent()

Answer: You are not in fact creating multiple collectors.

You are creating one single collector and applying multiple filters to that.

Applying several different filters to one single collector does exactly what it should:

Every single filter is applied to the collector results.

If the filters are mutually exclusive, you end up with an empty result.

For a previous explanation, please read the discussion on reinitialising the filtered element collector.

The same question also came up in a few other recent threads, e.g., on how to extract the geometry and the texts of the title block in a sheet view, summarised in the blog post on extracting title block geometry and text.

In your sample code snippet, simply create two separate collectors for shared parameters and family instances.

Response: I appreciate the reply and support.

I definitely understand what I did wrong now; I can't reuse the same collector variable as the filters just pile up, which obviously causes the collector to be empty, so simple.

It does worry me that after so much research I couldn't find the answer anywhere.

Answer: Thank you for your appreciation. Happy to hear that the problem is solved and the solution clear and simple.

I'll spell it out in the blog again and hope that will be easier to find in case anyone runs into this again in the future.

Rain water collector

RevitLookup Handles Split Region Offsets

Thanks to Michael @RevitArkitek Coffey, RevitLookup can now handle split region offsets.

He submitted the issue #68 – split region offsets (2021) and a subsequent pull request – adds handler for GetSplitRegionOffsets, explaining:

The ViewCropRegionShapeManager method GetSplitRegionOffset was added in 2021. This returns an XYZ but requires an integer index parameter. A list of XYZs can be returned, named by the index that was used.

This enhancement is captured in RevitLookup release 2021.0.0.12.

Many thanks to Michael for implementing and sharing this!

Python and Dynamo Autotag Without Overlap

Christopher Kepner shared a nice brute force Python solution implementing Auto Tagging without overlap, explaining the algorithm like this:

A python script to auto-tag all doors and place them without clashing with other tags or doors, using a custom smart tag that is much bigger than typical door tag.

It starts with a list of doors in the variable doorFiltered.

The location point of the first door in the list is fed into the function below to provide a test point to see if it overlaps any location points in the list of doors:

  def move_right(x,y,z):
    n = scaleFactor
    return x+n, y, z

  def move_down(x,y,z):
    n = scaleFactor
    return x,y-n,z

  def move_left(x,y,z):
    n = scaleFactor
    return x-n,y,z

  def move_up(x,y,z):
    n = scaleFactor
    return x,y+n,z

  moves = [move_right, move_down, move_left, move_up]

  def shift(end, point):
    from itertools import cycle
    _moves = cycle(moves)
    n = 1
    pos = point
    times_to_move = 1

    yield pos

    while True:
      for _ in range(2):
        move = next(_moves)
        for _ in range(times_to_move):
          if n >= end:
            return
          pos = move(*pos)
          n+=1
          yield pos

      times_to_move+=1

If the point lands too close to any door locations in the list, the code adds a integer to the function and runs again to provide the next test point. Each time the function is re-run, the next point follows a spiral pattern from the origin (location point of the first door):

Autotagging spiral

Once a point is found that is far enough from the list of door locations, a tag is placed and the tag location is added to the list of door locations.

The process loops to the next door, checking against the list of door location plus the new tag location.

It's a working concept, but the output is inconsistent.

Issues include:

Answer: LOL. If you make the tags small enough, the problem will disappear entirely, along with the tags.

Thank you very much for the explanation. Brute force and effective, given time. I love that straightforward approach!

Another recent tagging conversation on tags without overlapping mentions a couple of other useful possibilities.

More complex approaches are discussed on the Internet under the term 'map labelling algorithms'.

Finally, Konrad Sobon of archi+lab discussed element tagging with dynamo to create roof plans for a glass canopy system and tag each panel with its unique Mark value:

basically, it's a Revit’s Tag All tool, but with extra control over where the tag actually gets placed.

Custom Errors and Preventing Changes

Harry Mattison presents a nice solution implementing custom errors – preventing specific changes to the Revit model, explaining:

Let's say there is a specific list of View Scales that you want allowed in your Revit projects. Or certain naming conventions that should be used. Or something else like that where you'd like to automate the process of checking a user's change and determining if it should be allowed, prevented, or trigger a warning.

Custom error

This can be achieved with two pieces of Revit API functionality – Updater and Custom Failures...

Many thanks to Harry for sharing this nice explanation and implementation!

Ecological Cost of Crypto Currency and Art

I was intrigued and astounded at some of the information shared by Memo Akten in the analysis of the unreasonable ecological cost of #CryptoArt, and crypto-currencies as well.