Groups - Check for Mirrored

Groups - Check for Mirrored

Ryan
Enthusiast Enthusiast
3,042 Views
23 Replies
Message 1 of 24

Groups - Check for Mirrored

Ryan
Enthusiast
Enthusiast

I was wondering what would be the best practice to check a group if its mirrored. My groups consist of walls, and as far as i can tell they don't have a Mirrored property to access as well. 

 

Can getting the Transform of a Wall in the group do the trick? Which is something else i cant figure out. Walls can't be a Familyinstance? So i can't use .GetTransform() on a wall, correct?

 

Thanks!

3,043 Views
23 Replies
Replies (23)
Message 2 of 24

jeremytammik
Autodesk
Autodesk

Dear Ryan,

 

Thank you for your query.

 

Does this previous answer help?

 

http://forums.autodesk.com/t5/revit-api/mirrored-members/td-p/1575067

 

Or have you already looked at that, since you mention the transforms?

 

Walls are system families, so they can indeed not be represented by FamilyInstance elements.

 

Best regards,

 

Jeremy



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

0 Likes
Message 3 of 24

hemmesMW2F3
Contributor
Contributor

As far as I'm aware, it's still not possible all the way in 2023 to check whether a Group is mirrored or not. Why is that? It seems such a basic property to have in a 3d software package.

0 Likes
Message 4 of 24

jeremy_tammik
Alumni
Alumni

I am checking with the development team for you.

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 5 of 24

hemmesMW2F3
Contributor
Contributor

Very interested in what they came back with! Thanks for asking Jeremy.

0 Likes
Message 6 of 24

jeremy_tammik
Alumni
Alumni

They reply: 

  

They could find the coordinate system at parameter 0 for the first wall of the group instance and compare that to the coordinate system at parameter 0 of the first wall of the group type. The transform can then be built from those two, although it’ll require they understand the gymnastics to do so.
  
Similarly if the entirety of the group is in place geometry or imports, they can use the coordinate system at parameter 0 of the first geometry that a coordinate system can be pulled from.

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 7 of 24

hemmesMW2F3
Contributor
Contributor

Thanks a lot for asking Jeremy. I understand the approach the devs took, but I'm stumped as to how to recreate it as I can't seem to figure out what "parameter 0" is. Here are my attempts on a simple System Wall:

// attempt 1 is null
Parameter attempt1 = wall.LookUpParameter("0");

// attempt 2 is the 'Structural' parameter
Parameter attempt2 = wall.Parameters.Cast<Parameter>().First();

// attempt 3 is the 'Structural' parameter
Parameter attempt3 = wall.GetOrderedParameters[0];

// attempt 4 is the 'Top Offset' parameter
Parameter attempt4 = wall.ParametersMap.Cast<Parameter>().First();

 
Could you shed some light on how to retrieve this mysterious "parameter 0"?

0 Likes
Message 8 of 24

jeremy_tammik
Alumni
Alumni

Not really. I can only guess the intent (or, in extemis, simply ask them). My naive guess at the intent would be to grab the coordinates of the lower left-hand corner. That could possibly be formulated as 'parameter 0'. I will ask them as well, though.

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 9 of 24

jeremy_tammik
Alumni
Alumni

Reply:

  

1) Get a wall or other line based element type from the group instance.
2) Get the location curve of that element
3) Compute the derivatives of the curve at parameter 0.
4) Do steps 1-3 for the group type.
5) Compare the transforms from steps 3 and 4.

  

If the group doesn't have a linear element, the transform of family instances or other element transforms can be utilized.

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 10 of 24

jeremy_tammik
Alumni
Alumni

Oh, and now I know what parameter 0 means: for a curve based element, the start parameter of the curve; feed in GetEndParameter(0) in ComputeDerivatives:

  

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 11 of 24

hemmesMW2F3
Contributor
Contributor
Thanks Jeremy!
I'll come back here to post the code for the solutions I've come up with based on this approach. I think it's enough for my use case(s).

I am left wondering however: does the Revit codebase itself have an actual proper implementation of this that the API does not? I can't possibly imagine that Revit code itself needs to jump through these hoops to simply get the mirrored state (or rotation for that matter) of a GroupInstance.
For example, the gizmo when selecting a GroupInstance shows the current rotation/mirror of the selection, so Revit itself clearly knows. This bandaid approach couldn't possibly be the way that's implemented as it's an approach that does not work for every single group (as the prequisites are that the group should contain either a FamilyInstance or linebased element).
0 Likes
Message 12 of 24

jeremy_tammik
Alumni
Alumni

I already asked something similar, and they said: Not something I have needed in a while, but it is one of those ‘this is 10x harder than it ought to be’ tasks in the API so it has stuck with me. I now also asked whether there is a better solution internally...

  

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

hemmesMW2F3
Contributor
Contributor

So my implementation to get the rotation or mirrored state of a Group instance goes like this:
- Find a suitable child element within the Group to retrieve a Transform of. This is either a FamilyInstance, or a linebased element.
- Get the Transform either from the FamilyInstance itself, or from the direction of the linebased element's LocationCurve at the starting point (0).

- Instantiate a temporary new Group instance of the GroupType to retrieve a matching child element in the GroupType to compare Transforms with. (You have to do this extra hoop, as it's not possible to query elements within a GroupType).
- Get the matching Transform in that temporary Group and delete it afterwards or roll back.
- Compare the Transforms to retrieve the rotation/mirrored state of the Group instance.

The following code demonstrates this from the point you've found a suitable child element in the Group instance:

 

 

private Transform GetTypeChildTransform(GroupType groupType, Element child)
{
    Document doc = groupType.Document;
    using Transaction? t = doc.IsModifiable ? null : new Transaction(doc);
    t?.Start("Temp instance to retrieve transform")
    Group tempInstance = doc.Create.PlaceGroup(new XYZ(100000, 100000, 0), groupType)
    IEnumerable<Element> typeChildren = GetChildren(doc, tempInstance.GetMemberIds())
    Element typeChild = child is FamilyInstance
        ? typeChildren.First(e => e is FamilyInstance && e.Name == child.Name)
        : typeChildren.First(e => e.Location is LocationCurve && e.Name == child.Name)
    Transform transform = GetTransform(typeChild)
    if (t == null)
        doc.Delete(tempInstance.Id);
    else
        t.RollBack()
    return transform;
}

private Transform GetTransform(Element element)
{
    if (element is FamilyInstance instance)
        return instance.GetTransform();
    if (element.Location is LocationCurve curve)
        return curve.Curve.ComputeDerivatives(0, false)
    throw new ArgumentException("Element is not a familyinstance or a linebased element");
}

 

 

Message 14 of 24

jeremy_tammik
Alumni
Alumni

Wow. Thank you for the interesting code. Cool use of the optional transaction. Isn't the a missing closing brace somewhere? Well, a snippet is a snippet, isn't it? Take it or leave it!   🙂

   

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

hemmesMW2F3
Contributor
Contributor

Hi Jeremy, I've edited the missing brace back in, sorry.

I've hit a snag in implementing this further. It seemed quite straightforward to get the difference in rotation from a linebased element in the queried instance vs the temp instantiated instance, but when starting on whether the group is mirrored or not, I find that I cannot seem to figure out whether the group is mirrored.
I'll illustrate with an example: let's say there's a group with a single wall, horizontally drawn from left to right. Computing the derivative from this wall's curve at the starting point (0) will yield a Transform where the BasisX is (1, 0, 0).
If that group had an instance that was rotated 180 degrees, we'd find (-1, 0, 0). Some math when comparing that to a temporary unrotated instance will correctly return the 180 degrees.
BUT, now let's mirror this same group. BasisX will again be (-1, 0, 0). There's no way to tell these cases apart! At least I haven't found any, scouring through the other properties of Transform. I'm stumped. Am I missing something? Or is the only way to get the mirror & rotation of a Group by querying a child FamilyInstance within the Group (and is the linebased element approach infeasible)?

private bool GetMirroredStateByComparingTransforms(Transform groupTransform, Transform typeTransform)
{
    throw new NotImplementedException("Stumped as to what can be done here");
}




0 Likes
Message 16 of 24

jeremy_tammik
Alumni
Alumni

How about not worrying about any curve-based elements and all that stuff.

  

Just find three unique identifiable non-collinear points in your object and check their locations in the transformed instance.

  

That should enable you to easily detect all transformations: rotation, scaling, reflection, you name it.

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 17 of 24

hemmesMW2F3
Contributor
Contributor
Oh, that is devious!! (And totally works)
0 Likes
Message 18 of 24

jeremy_tammik
Alumni
Alumni

Actually, the absolute contrary: it is much simpler! That is the reason it works better! Keep it simple!

  

  

For me, that is the highest grail of programming, and actually of life in general.

  

Unfortunately for me, I am better at achieving it in programming than in life in general.

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 19 of 24

hemmesMW2F3
Contributor
Contributor
I've managed to successfully try out your suggestion Jeremy, so in summary:

To find out the mirror and rotation of a Group:
- Instantiate a new temporary control Group of the same type
- Either: find a corresponding FamilyInstance within the Groups to compare rotation and mirror
- Or if no FamilyInstance is in the Group: find 3 non-collinear corresponding points (anything identifiable in both Groups will do) within the Groups and apply some maths to find the difference in rotation and mirror.

This works.

For our use case, we have configurators that create buildings in Revit based on user input. When reconfiguring an already existing building, we'd like to only apply the necessary changes (reposition, rotate, mirror, change type, change parametervalues, you name it) so the configuration is applied as fast as it can be based on the required changes. The above solution cannot be used for Groups in our use case, as it is terribly slow. The requirement of instantiating a new Group (even just temporarily) is too much. This is because the simpler existing method is: throwing away the Group and creating a new one based on the new configuration. We will continue doing this for now in the hopes of a future API addition.
Message 20 of 24

jeremy_tammik
Alumni
Alumni

Glad to hear that the solution works. Thank you for testing ad confirming. Sorry to hear that it is too slow, though.

  

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