API bug in Document.Regenerate()?

API bug in Document.Regenerate()?

Anonymous
Not applicable
1,676 Views
14 Replies
Message 1 of 15

API bug in Document.Regenerate()?

Anonymous
Not applicable

further to this post I made a little while back I have done some more investigation and have kind-of narrowed it down to a bug in the API (I say kind-of because although I can watch it happen and recreate it reliably in my production code I am as yet unable to reproduce it in isolation using minimal example code that would be suitable for posting here). whatever is happening is definitely triggered by Document.Regenerate() though, which is why I am blaming the API.

 

the basic outline of the problem is as follows:

 

  • I obtain the PlanarFace that was created in a wall by the opening cut of a door instance and store it in a variable (specifically the head face which has face normal of 0, 0, -1)
  • I then place some line-based family instances on some other wall faces created by the same door without any problems
  • I call Document.Regenerate()
  • I then attempt to place a line-based family instance on the head face and CreateFamilyInstance fails.
  • If I remove the Regenerate call and try again it all works perfectly.

stepping through with the debugger I put a watch on both the Normal and Origin property of the PlanarFace object and vaerified that they remained unchanged all of the way through untill after the Document.Regenerate() call where the values for both instantly changed. It's as if the object now references a completely different face.

 

Another strange behaviour is that if I call Document.Regenerate() before obtaining the Face objects then subsequent calls do not trigger the bug, it seems to only happen for the first regen call within a transaction.

0 Likes
1,677 Views
14 Replies
Replies (14)
Message 2 of 15

jeremytammik
Autodesk
Autodesk

Dear Scott,

 

I do not believe this is a bug.

 

This is simply a proof that you cannot store a PlanarFace.

 

How do you want to achieve that?

 

It is not possible.

 

Revit geometry is read-only, and represents a view of the parametric BIM, a momentary snapshot.

 

As soon as you add something to the wall, e.g. the family instances you mention, the wall is affected.

 

Regenerate creates a new snapshot of the current situation, and the planar face that you previously "stored" (I wish I had triple double quotes here) is in blissful oblivion.

 

I hope this clarifies.

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 3 of 15

Anonymous
Not applicable

Thanks Jeremy,

 

sorry if I wasn't clear with my terminology, when i said "store" I mean that I gathered the face objects using the API and then performed some other actions before using the faces that were gathered further down in my command. I am not attempting to persist them as objects (that's what stable reference strings are for) I was just attempting to be clear about the fact that I was already in posession of the face objects before the regen was called. I work with PlanarFaces and references extensively so I'm pretty familiar with thier behaviour but this is just strange. It also doesn't happen on every wall (which is why I have only just stumbled upon it. My test model must have only had well-behaved walls in it),  but an affected wall will reliably repeat the problem over and over.

 

As a further test scenario when i first get the face I imediately grabbed its reference and converted it to a stable string representation then used the face's edge loops to compute the centreline of the face (ensuring that it is coplanar and within bounds).

then after performing the other operations and calling regenerate I parsed the stable reference back into a new live reference.

I then retrieve the face again by passing the new reference into Element.GetGeometryObjectFromReference().

I then use the edge loops of the new face to compute a new face centreline and confirm that it matches the originally computed line.

now because GetGeometryObjectFromReference() doesn't return objects with computed references I use the newly parsed reference along with the computed centreline to create a line-based family instance and it throws an exception with the message "Family cannot be placed on this line as it does not coincide with the input face.
Parameter name: multiple"

again if I either call regenerate before extracting the face or just don't call it at all then everything behaves normally.

BTW, the values of the normal, origin and the computed centreline of the original un-corrupted face match in both scenarios.

 

I can smell a bug...

0 Likes
Message 4 of 15

jeremytammik
Autodesk
Autodesk

Dear Scott,

 

Sorry, too complicated for me. Tilt.

 

I'm like Winnie the Poo, a bear of very little brain.

 

Question: can you reparse the geometry, grab a completely dewy-fresh planar face after regenerating, and use that?

 

If yes, I would suggest doing so.

 

If that does not help, could you package this as a minimal reproducible test case for me to submit to the internal database and pass on to the development team?

 

http://thebuildingcoder.typepad.com/blog/about-the-author.html#1b

 

Thank you!

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 5 of 15

Anonymous
Not applicable
I'll see what i can do. But it's a hard one to reproduce in a minimal example. The command in question does a lot of geometry processing before it gets to this problem section, so combined with it only happening on a few walls here and there, I strongly suspect that it is triggering some sloppy unmanaged code somewhere in the geometry API which just doesn't get touched by a focussed example. I already have a work around so I can't afford to spend any more time on it
I was just trying to alert the factory that someyhing is wrong. There should be enough diagnostic information in my posts for the API team to identify and test the code most likely responsible should.
This is just one of many obscure bugs I have found in the API. Some of them are just too difficult to explain or demonstrate so I tend to just keep them to myself once I have developed a work-around.
0 Likes
Message 6 of 15

arnostlobel
Alumni
Alumni

Scott,

 

It is not a bug; Jeremy was correct. Faces are not guaranteed to survive regenerations; there are no elements. Thus it is not surprising that you cannot use your “held to” face anymore after you regenerate the model. In fact, it is possible that Revit will recreated faces even if they were not changed, technically.

 

So, it leavers two options:

  1. You need to re-fetch the faces you need based on some criteria, e.g. their location.
  2. You store a reference object to the face instead of the face itself. Then you use the reference (or its “stable reference”) to obtain the face it refers. If it still exist you ought to get it.
Arnošt Löbel
0 Likes
Message 7 of 15

Anonymous
Not applicable
I accept that the faces can be unreliable after a regenerate call. As mentioned in my last post I did also test just getting the face again using the stable representation but it still causes an error in NewFamilyInstance. Surely the stable representation can survive a regenerate provided the face stll exists. Otherwise what are they for? Why does it work correctly 95% of the time but some walls just trigger the behavior over and over? I'll do some more investigation and get back to you.
0 Likes
Message 8 of 15

jeremytammik
Autodesk
Autodesk

Dear Scott,

 

Thank you for your understanding and hope that the further testing will clarify more.

 

Meanwhile, I published the currrent state of affairs on The Building Coder:

 

http://thebuildingcoder.typepad.com/blog/2015/11/connecting-desktop-and-cloud-at-au-and-devdays.html

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 9 of 15

arnostlobel
Alumni
Alumni

Scott, my bad. I missed your second post completely, thus I was totally unaware of your experimenting with geometry references already. Please accept my apology.

 

With the new info it looks indeed like there might be a bug somewhere. However, I kind of doubt it is on the managed side, although it is also possible. Unfortunately, even if it does not look like it, we really need a sample to reproduce. Unless the problem (either a bug or not) occurs every time no matter what the geometry and face is and what happens to the element the face was taken from, it is practically impossible for us to test it (I mean, in a reasonable time). We do not necessarily need your code – I can write the code myself – but we need some workflow to reproduce, and the workflow needs to be quite detailed; like – create this wall, of this type and this position/length, at this level; then put this specific window there at this exact location; etc. Let me put it this way – if I get a case from our QA team and the description does not specify each click exactly to get to the point of failure, no matter how trivial the commands are, I will not take the case and return it to the reporter. With customers, naturally, I am not so strict and I always try my best to deduce the actual scenario, but I can only do so much (or ask others to do only so much). So, please, if you can give us something more concrete it would be of a benefit to both of us.

 

A propos, let me tell you a secret: There is no API team!

Arnošt Löbel
0 Likes
Message 10 of 15

jeremytammik
Autodesk
Autodesk

Thank you for the very nice explanation, Arnošt!

 

Naturally, I added it to the blog for future reference:

 

http://thebuildingcoder.typepad.com/blog/about-the-author.html#1b

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 11 of 15

rhanzlick
Advocate
Advocate

This is a somewhat old post, but I am now running into the same issue. As an example, I am creating elevations using room faces. I do quite a lot of filtering, grouping and organizing of the rooms faces in terms of their orientation before creating an elevation for each group of faces. However, as you know the elevationMarker is created separately, so I have created the marker and view into (2) separate transactions and wrapped them into a transactionGroup. However, my stored faces are no longer valid after the elevationMarker transaction is committed. This catastrophic failure of faces seems to occur most consistently on Room faces whose boundary is created by masonry walls or walls containing a cavity.  

0 Likes
Message 12 of 15

jeremy_tammik
Alumni
Alumni

Can you produce a minimal complete reproducible case to demonstrate the problem?

 

https://thebuildingcoder.typepad.com/blog/about-the-author.html#1b

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 13 of 15

rhanzlick
Advocate
Advocate

our company does a particularly large amount of customization of revit families and content, but a perfect case seems to be:

1. create a room bounded by CMU cavity walls (not sure if this type is native to revit).

2. obtain room faces using SpatialElementGeometryCalculator (ie geomResult.GetGeometry().Cast<Face>().ToList())

3. check any property of any face (this should work without issue)

4. commit a transaction of any kind (not tested but I suspect that even Document.Regenerate() will do the trick)

5. check any property of any face again (need not be same property or same face as before) and the API should throw an internal error.

 

inspection in debug mode should make it pretty obvious that the faces are invalid - see attached image

 

rhanzlick_0-1632506179946.png

 

 

0 Likes
Message 14 of 15

TripleM-Dev.net
Advisor
Advisor

Hi,

 

Possibly by placing the markers and a end of transaction the faces of rooms are re-calculated and thus no longer valid.

(See one of the earlier posts)

 

Can't you gather the needed info from the Faces and save the orientations (I assume) into variables/list and create the markers and view from the saved variables, so you no longer need the faces after a commit/regen

 

- Michel

0 Likes
Message 15 of 15

rhanzlick
Advocate
Advocate

thanks for your response, that is exactly the solution I plan to implement. I understand the logic of potentially modified faces, and needed to regenerate faces that have been changed. It is just unfortunate considering transactions contain the modified elements, and geometric objects (mostly) have a reference of the element to which they belong. I would think only geometries with a reference Id contained in the modified/deleted elements within the transaction need to be regenerated?

 

I also just tried pre saving the Id of each face (available in 2022) and repeatedly looking up the faces in the wall by Id in each iteration... it seems Ids are applied randomly upon regeneration.

 

0 Likes