Find Family "Source" Element of a given Element

Find Family "Source" Element of a given Element

Aminius
Enthusiast Enthusiast
2,479 Views
24 Replies
Message 1 of 25

Find Family "Source" Element of a given Element

Aminius
Enthusiast
Enthusiast

Hi all,

 

I've been looking for a solution to this particular problem for two days now, but I can't figure it out.

I'm afraid that the reason might be an incomplete understanding of how Objects in Revit are organized. Therefore, it might be that my description of the problem is clumsy and my nomenclature is wrong.

I'll describe the problem as good as I can.

 

It's about Parameters in nested families.

I have a family A. It contains 4 instances of another Family B. Each of these 4 instances, let's call them B1-B4, has different parameter settings.

One instance of A is in my Revit document.

 

I have the ElementId of an Element. It is of B type. I can read the Parameters off this element, but I cannot set them (as I need to), because they are Read-Only.

Apparently, these Parameter values get forwarded from one of the B1-B4 objects.

How can I find out from which one?

In other words, how do I get the Element which a given Element inherits its Parameters from (because it's an instance of it)?

 

Thanks,

Aminius

0 Likes
2,480 Views
24 Replies
Replies (24)
Message 2 of 25

jeremytammik
Autodesk
Autodesk

Dear Aminius,

 

Your nomenclature is clear enough.

 

In spite of that, I think this is best answered by first understanding it completely from the user interface point of view.

 

I would therefore suggest that you work through some content creation and family definition tutorials first.

 

Then, all will probably become much clearer.

 

Cheers,

 

Jeremy



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

0 Likes
Message 3 of 25

matthew_taylor
Advisor
Advisor

Understanding the difference between shared and non-shared families is also important in this instance. (Not to be confused with shared and non-shared parameters.) 


Cheers,

-Matt
_______________________________________________________________________________
Marking a post as a 'solution' helps the community. Giving a post 'Kudos' is as good as saying thanks. Why not do both?
0 Likes
Message 4 of 25

Aminius
Enthusiast
Enthusiast

Thanks for the replies.

 

I'm a bit of a dilemma when it comes to learning content creation in Revit - on the one hand, it is not really my business at all, I'm just in charge of a parameter synchronization plugin - on the other hand, I find I'm hitting walls every now and then as long as I don't understand how Revit really ticks inside.

 

My sincere apologies in case I waste your time with beginner questions; please believe me when I say that I always try to do research before posting here. But I also need to think economically - becoming an expert in all things Revit is just not in my job description. 🙂

 

That being said, I did heed your advice and looked at some basic family tutorials. I have learned enough from it to know that modifying the referenced element, even if I could find it, would not be something I would actually want to do, as that would modify the family itself.

 

(I'd still be interested in finding out how to actually get that referenced element or the referenced parameter, but that's more out of personal interest now.)

0 Likes
Message 5 of 25

Aminius
Enthusiast
Enthusiast

Hi again,

I did some research into families, but I'm still stuck with the very specific problem that made me start the thread.
I'll explain it in detail and with screenshots, and I hope you can give me some advice.

This is a nested family. Both the faucet and the basin are itself Family Instances.
They both have a Parameter "cpiFitMatchKey", which I will use as an example here. The idea is to make this modifyable on an instance basis.

 

basinFamily.png

 


This shows an Instance of the Family used in a Revit Document. The selected faucet is now a subpart. The Property "cpiFitMatchKey" is Read-Only because, in this scope, it is treated like a Family Parameter (as explained above, it is originally an Instance Parameter, but on an Instance that is itself nested in another Family).
As a result, it is greyed out in the UI, and trying to set it via API results in an exception (which is good, as I wouldn't want to modify the Family!).

basinRevitDoc.png

 

 

I want this Parameter modifyable, individually for each instance, so I create a new Instance Parameter "cpiFitMatchKey.Faucet" and associate the faucet's 'cpiFitMatchKey' with it.
I do the exact same thing for the basin.

 

FamilyParameter.pngAssociate.png

 

 

Result:

 

AssociatedParameters.png

 

 

So far, this does pretty much exactly what I want. When I set one of these Parameters, the respective subpart (of the Instance!) will be modified, and when exporting the model, the faucet and basin will have the updated cpiFitMatchKeys, while new instances of the entire basin family will have the old default values.

When setting Parameter values via Code, I check if the Parameter's Read-Only. If it is, I check if the Element I'm trying to modify is a FamilyInstance.
If it is, I get myself a FamilyManager and try to fetch the associated Parameter, using the same method as here:
http://adndevblog.typepad.com/aec/2016/02/revitapi-how-to-change-radius-of-connectorelement-how-to-g...

 

I will paste the important segment here so I can highlight the part where it breaks:

 

var sb = new StringBuilder();
foreach (var connectorPara in connectorElement.GetOrderedParameters())
{
    foreach (FamilyParameter familyPara in doc.FamilyManager.Parameters)
    {
        foreach (Parameter associatedPara in familyPara.AssociatedParameters)
        {
            if (connectorPara.Id == associatedPara.Id && associatedPara.Element.Id == connectorElement.Id)
            {
                //associate parameter found
                sb.AppendLine("'" + associatedPara.Definition.Name + 
                    "(" + (BuiltInParameter)associatedPara.Id.IntegerValue + 
                    ")' <-> '" + familyPara.Definition.Name + "'");
            }
        }
    }
}

 

(Note: I tried FamilyManager.GetAssociatedFamilyParameter() first, which never yielded any result whatsoever. Probably for the exact reason that I now come to.)


The two IDs in the highlighted comparison will never be identical.

What the method finds is the nested FamilyInstance inside the Family. Which is not the element I'm trying to access here, I'm trying to access the instance inside the basin instance in my revit document.
Even the type IDs of the two are different. In fact, I find nothing at all that connects the two.
As a result, while I can (by omitting the ID check from above code) retrieve the two associations
cpiFitMatchKey <-> cpiFitMatchKey.Faucet and
cpiFitMatchKey <-> cpiFitMatchKey.Basin,
I cannot tell which one of the two I must use.

The problem may not become obvious as long as we are talking faucets and basins; some indicators could surely be found to distinguish between the two.
But:
1. This should work generically. I don't want to need any knowledge about the elements I'm looking at.
2. These could actually be instances of the same type. Let's say the basin family had two faucets - two instances of the nested family in the basin family. The Parameters of these two could be associated differently, but otherwise they would be pretty much identical. So, when dealing with a faucet in my revit document, I need to know which faucet in the defining family it's a copy of.

TL;DR:
This leads me back to the original question of the thread:
How do I find out which subpart of a FamilyInstance corresponds to what subpart of a Family?

Alternatively: How do I tackle this differently to not have this problem in the first place? 😛

 

0 Likes
Message 6 of 25

matthew_taylor
Advisor
Advisor

Hi @Aminius,

I think my first comment is still where you need to concentrate.

A shared family will allow you to edit its parameters directly (via API or manually), without having to port or assign them. (In the family editor, properties window, 'shared' checkbox - you want it checked.) The *nested* families will need to be 'shared'.

You may get the nested families by using SubComponent, or the main family using SuperComponent. Beware multiple levels of nesting.

http://www.revitapidocs.com/2017.1/be37702c-1dcd-bc14-aa35-45f06f20210a.htm

http://www.revitapidocs.com/2017.1/1dcf3123-c2ea-867a-7b9a-73173343121e.htm

 


Cheers,

-Matt
_______________________________________________________________________________
Marking a post as a 'solution' helps the community. Giving a post 'Kudos' is as good as saying thanks. Why not do both?
0 Likes
Message 7 of 25

Aminius
Enthusiast
Enthusiast

Thanks for the reply.

 

All involved familes are, in fact, shared - and have been all along.

I checked it right after your first post, but forgot to mention it in my latest response, sorry for that.

 

I can navigate through the nesting hierarchy via SubComponent and SuperComponent (I'm in fact using the latter to access the top level family and then retrieve the Parameter assignments from it).

0 Likes
Message 8 of 25

matthew_taylor
Advisor
Advisor

@Aminius,

I think I know what you're talking about now.

The trick is to *not* have the parameter in the families. Just use a project wide shared parameter for that category.

I've attached a small model to illustrate. Each element can have the designation parameter modified at will, without gymnastics.

If that's not what you're talking about, you're going to have to try to titrate your thesis down to an understandable paragraph... Smiley Wink


Cheers,

-Matt
_______________________________________________________________________________
Marking a post as a 'solution' helps the community. Giving a post 'Kudos' is as good as saying thanks. Why not do both?
0 Likes
Message 9 of 25

Aminius
Enthusiast
Enthusiast

Thanks again for your efforts!

 

A global shared Parameter would have been the easiest solution indeed; the problem with that is (correct me if I'm wrong) that I can not have default values then, and newly created instances of the family would have no "designation" value at all.

 

(My first suggestion was to have an additional shared Parameter just for the overridden values.

That does not work, though, if the Parameter name must be fixed and unique.)

 

The way I'm doing it now, the initial value comes from the family, but can be overwritten on its instances. The problem is to (programmatically) find the correct associated parameter to actually do that for any given element.

 

As for trying to explaining it again plainly and simply, I find that very hard, but I'll try:

 

I want to set a Parameter to an Element (identified by ID) but I can't, since it's Read-Only.

I know there is an associated parameter that I can use instead, like a kind of proxy.

I look for associated parameters on the (SuperComponent) family, for the given Parameter.

I find some.

BUT:

I don't know which one I must set to modify the Element that I was originally looking at. Because the association is not actually refering to that element, it's refering to the nested family that this Element was instantiated from.

 

Somehow, internally, Revit must have a connection between the two, else how would the associated Parameters even work?

Question is how to get that information...

 

0 Likes
Message 10 of 25

matthew_taylor
Advisor
Advisor

Hi @Aminius,

Perhaps you should look at an IUpdater to modify the parameters (set defaults) of newly created instances? (in addition to my last suggestion)

It's a fairly simple way to implement defaults. There are plenty of examples in this forum, and in the SDK.

A single example: https://forums.autodesk.com/t5/revit-api-forum/set-instance-parameters-at-insertion-or-modification/...


Cheers,

-Matt
_______________________________________________________________________________
Marking a post as a 'solution' helps the community. Giving a post 'Kudos' is as good as saying thanks. Why not do both?
0 Likes
Message 11 of 25

Aminius
Enthusiast
Enthusiast

Not an option, unfortunately. The content creation process is not under my control.

0 Likes
Message 12 of 25

matthew_taylor
Advisor
Advisor

I have no idea what you just said.

You can't use an application level macro? Because that's all you need...


Cheers,

-Matt
_______________________________________________________________________________
Marking a post as a 'solution' helps the community. Giving a post 'Kudos' is as good as saying thanks. Why not do both?
0 Likes
Message 13 of 25

Aminius
Enthusiast
Enthusiast

What I meant is, I have to work with existing projects and content libraries, I can hardly have people rebuild everything for me.

I can certainly ask, but I'm not hopeful.

So while I greatly appreciate your suggestions to circumvent the problem, I'm afraid I have to solve it.

0 Likes
Message 14 of 25

matthew_taylor
Advisor
Advisor

Hi @Aminius,

What I'm suggesting has nothing to do with content libraries, would work just fine with existing projects, and could be entirely enclosed in one relatively simple application (with supporting IExternalCommands).

  1. Create an 'initialise' macro button that initialises your updater in each project. This macro should add your shared project parameter to the relevant categories. It should also add initial values to all relevant existing elements.
  2. Create an iUpdater that adds values to newly created (and relevant) elements.

Cheers,

-Matt
_______________________________________________________________________________
Marking a post as a 'solution' helps the community. Giving a post 'Kudos' is as good as saying thanks. Why not do both?
0 Likes
Message 15 of 25

Aminius
Enthusiast
Enthusiast

my last post disappeared without notice, trying again...

 

@Anonymous Taylor:

Two problems with that:

a) The shared project parameters must replace the original instance parameters, since some of them are used as unique keys elsewhere and may not be duplicated. So it does not suffice to add shared parameters to the project; one must also remove existing ones from familes (or rename them, see b).

b) Both initializer and iUpdater must know which is the correct default value for each parameter on each type of object. So the families would need to provide this information, possibly by the renamed former instance parameter (e.g. with a pre- or suffix "Default").


@Anonymous:

Once again (with feeling, and a sketch) an attempt to illustrate the original question:

nestedFamiliesDiagram.png

A is a Family.
B is a Family containing two nested instances of A. I call them A1 and A2.

b is an Instance of B.
So b now has two instances of A as subparts. I call them a1 and a2.

Question: What is the relation between a1 and A1, respectively a2 and A2?

Specifically, how does a1 "know" that it was created from A1 rather than A2?

a1 and a2 are clearly instances of A, but that is not enough information for associated parameters to work. Parameters associations would be attached to A1 and A2, respectively, so a1 and a2 need to know which one they were created from.

 

 

 

0 Likes
Message 16 of 25

matthew_taylor
Advisor
Advisor

Hi @Aminius,

'A1'->'a1' is not a direct comparison when dealing with shared families.

If you copy a familyInstance 'b' with nested familyInstances 'a1' and 'a2' of *shared* family 'B' (while in the model context), a copy of familyinstance 'b' will be created (I'll call it 'b1'), along with new family instances 'aa1' and 'aa2' (with the same respective family and familysymbols as 'a1' and 'a2').

 

If you refer to a newer copy of the model I sent you last time.

See also the screen caps showing RevitLookup details of two of the faucets (which are the same faucet, in different parent familyInstances).

Note also that I put a ring around the superComponent property - each of these values is different, as expected.

 

When you understand these relationships, the rest of issue (which I've ignored at this point) will probably fall into place.

 

If you don't have RevitLookup installed. Do it with the utmost urgency.


Cheers,

-Matt
_______________________________________________________________________________
Marking a post as a 'solution' helps the community. Giving a post 'Kudos' is as good as saying thanks. Why not do both?
0 Likes
Message 17 of 25

Aminius
Enthusiast
Enthusiast

Without RevitLookup, I probably would have killed myself a long time ago.

Means yes, I have it installed. 🙂

 

Thanks again for your troubles with the example file.

 

I can see that the Faucets have different SuperComponents, that part is obvious.

But they have the same Symbol (314493). Which again, is pretty obvious as they are instances of the same Family (323546).

 

The two problems with this are:

1. These are not the Symbol/Family IDs of the nested Faucets in the Family. When you edit the Family and snoop the faucets, you'll find they have Symbol ID 323481 and Family ID 323493.

2. If a family parameter would be associated with only one of the two, I could not tell which one. And that is my problem in a nutshell.

 

 

0 Likes
Message 18 of 25

matthew_taylor
Advisor
Advisor

@Aminius,

Right. I think I'm with you now. What a marathon.

Can you modify my example so that it depicts the associated family parameter that you speak of?

 

Have you read this blog post (including its comments)?: http://thebuildingcoder.typepad.com/blog/2010/03/nested-family-utility-methods.html

 

Have you tried the temporary transaction trick?: http://thebuildingcoder.typepad.com/blog/2012/11/temporary-transaction-trick-touchup.html


Cheers,

-Matt
_______________________________________________________________________________
Marking a post as a 'solution' helps the community. Giving a post 'Kudos' is as good as saying thanks. Why not do both?
0 Likes
Message 19 of 25

Aminius
Enthusiast
Enthusiast

Hi Matthew,

quite a Marathon indeed. It is a complex problem and English is not my first language, so it's difficult. 🙂

I want to thank you once again for your patience and the assistance!

I know the two Building Coder blog posts you linked to.

While I found the first one very helpful to get a general understanding of Families, nested Families, and how they are accessed through the API, it did not offer an immediate solution to my problem at hand (the additional issue of associated parameters). Unless I missed it, which I sure hope I did not!

As to the second one; I could use temporary transactions, probably with nested transaction groups, for an approach like this:
1. Find associate parameter "candidates" through some code similar to what I posted earlier.
2. Open a transaction group
3. Open a transaction
4. Modify the associated parameter candidate
5. Commit the transaction
6. Check if the original parameter got the new value. If yes, commit transaction group and be happy. If no, rollback transaction group and repeat steps 3 through 6.

 

Do that for every parameter and put another transaction group around it all.
I'm quite sure it would work, it's just so... meh. Trial and error, basically.

I have attached a modified version of your project, as you asked.
For making the problem clearer, the faucet was duplicated once more, so now there are three.
The faucets have a Parameter "Mark".
On two of them, this Parameter is associated with a Family Parameter "Mark.Faucet".

Now imagine you have a faucet instance; you want to modify "Mark"; it is write protected; you look for associated properties on the family; you find "Mark.Faucet".
Now you don't know if setting the value to Mark.Faucet will really modify "your" faucet. Not until you actually do it, that is.

Would be even nastier if those first two faucets were associated with different Family Parameters instead of the same one.

 

 

0 Likes
Message 20 of 25

FAIR59
Advisor
Advisor

You could consider the relative position of the nested instances (a1 and a2) to the position of the containing familyinstance (b1) in the project.

In the FamilyEditor (family B), you do the same for the placed instances (A1 and A2) relative to the Family Origin.

 

By comparing the positions (project versus family) you should be able to link instance a1 to A1 and instance a2 to A2.

 

This should be relatively easy if the families are as simple as the ones in your last project. (Faucet-2017-V3.rvt)