Community Tip - If community subscription notifications are filling up your inbox you can set up a daily digest and get all your notifications in a single email. X
Version: Windchill 13.0
Use Case: Working on getting specific WTPart attributes overlaid on published drawing PDFs.
Description:
I thought this would be simple enough but I ended up struggling the last two days in trying to achieve the following:
If this is a drawing:
EPMStructureHelper.service.navigateReferences(etc etc)
instead... from here I can't resolve either the EPMReferenceLink IDs or the EPMDocumentMasters (depending on the boolean settings) to get the related model.
It's not clear to me where to go to get the "rolename" values or "buildrule" integer values to be able to go directly from the drawing to the WTPart. That would be ideal.
There's CS351622 that goes over how to fetch an owner linked WTPart. Assuming here that if I change "OWNER" to "IMAGE" or "CALCULATED" (?) this may give me what I want?
I just feel like I'm missing some pretty important pages from some customization guide somewhere...
Solved! Go to Solution.
I think you'll have to split the code into two cases:
From drawings, Windchill stores at least 3 types of links to other CAD files:
Not a full solution, but hope that helps point you in the right direction
Something you may want to consider as a shortcut would be if you have any numbering conventions for your models / drawings / WTParts. We, for instance, basically match the number on all three, so as long as things are numbered correctly (BIG IF), I could use the number from the first EPMDocument, then run a query to get the WTPart with the number that corresponds.
What type of link are you using to link the WTPart and CAD drawing?
Image and Calculated?
Not Content?
Generally, the drawing will only ever be calculated. The model could be either image or owner but not content.
I meant is the drawing a Content link not the model. Regardless as long as we know it’s Calculated link that all we need to know.
Do you understand what a calculated link is?
Meaning how it is calculated?
The drawing is a calculated link to the WTPart.
From your description, it seems you are looking to navigate the DescribedBy from a WTPart to an EPMDocument Drawing?
You might want to chceck:
- https://www.ptc.com/en/support/article/CS131357
- https://www.ptc.com/en/support/article/CS240504
- https://support.ptc.com/help/windchill/r13.1.0.0/en/#page/Windchill_Help_Center/ManagingCADandPartRelationships/MCPR_AssociationOview.html
This code snippet may help:
wt.fc.collections.WTCollection parts = new wt.fc.collections.WTArrayList();
parts.add(part);
wt.fc.collections.WTKeyedMap associatedCADDocumentMap = ((wt.part.StandardPartDocService)wt.part.PartDocHelper.service).getAssociatedCADDocuments(parts);
I'm looking to navigate the opposite way: from an EPMDocument (either drawing or model) to a WTPart.
So likely this may give me what I want:
com.ptc.windchill.collector.api.cad
getAssociatedParts(EPMDocument seed)
I think you'll have to split the code into two cases:
From drawings, Windchill stores at least 3 types of links to other CAD files:
Not a full solution, but hope that helps point you in the right direction
Something you may want to consider as a shortcut would be if you have any numbering conventions for your models / drawings / WTParts. We, for instance, basically match the number on all three, so as long as things are numbered correctly (BIG IF), I could use the number from the first EPMDocument, then run a query to get the WTPart with the number that corresponds.
This tracks...
If I pass in a CADDRAWING docType (using a version of this code from CS35845 that @MalteSiefkes 's links at some point led to) I get the result you point out:
[PublisherQueue1.PollingThread] wt.system.out Administrator - EPMDocument: wt.epm.EPMDocument:128051679 collected
[PublisherQueue1.PollingThread] wt.system.out Administrator - Put results.iterator into items: [wt.epm.EPMDocument:128051679]
[PublisherQueue1.PollingThread] wt.system.out Administrator - Prt variable is still null... see: null
If the incoming EPM is a CADCOMPONENT docType (i.e. Model) then the result collects the associated WTPart.
[PublisherQueue1.PollingThread] wt.system.out Administrator - EPMDocument: wt.epm.EPMDocument:128037137 collected
[PublisherQueue1.PollingThread] wt.system.out Administrator - Put results.iterator into items: [wt.epm.EPMDocument:128037137, wt.part.WTPart:128037156]
[PublisherQueue1.PollingThread] wt.system.out Administrator - Part:<part info i want goes here>
This is close to the path I was on (already have logic for `if CADDRAWING then get CADCOMPONENT` in my code).
The numbering way is my plan B if this doesn't work. While we do have matching numbers (in theory...) I've seen typos more often than I would like.
Hello,
I can confirm that the methods
wt.part.PartDocHelper.service.getAssociatedCADDocuments
wt.part.PartDocHelper.service.getAssociatedEPMDescribeLinks
consider calculated links for given part, the later returns specifically only the required drawing.
For the reverse I found no applicable, supported API which considers the calculated link. As discussed, this apparently requires a two-step.
For this I checked CadCollector.GatherDependents.ONLY_REQUIRED, but it returns all Models associated to the drawing (incl. the lower CAD Models used in an Assembly).
For finding the main model from the Drawing, I only found as supported option the use of a QuerySpec:
wt.query.QuerySpec querySpec = new wt.query.QuerySpec();
int linkIndex = querySpec.addClassList(wt.epm.structure.EPMReferenceLink.class, true);
int[] indices = { linkIndex };
querySpec.setDescendantsIncluded(true, linkIndex);
querySpec.appendWhere(new wt.query.SearchCondition(wt.epm.structure.EPMReferenceLink.class, wt.epm.structure.EPMReferenceLink.REFERENCE_TYPE, "LIKE", "DRAWING"), indices);
wt.epm.EPMDocConfigSpec configSpec = new wt.epm.EPMDocConfigSpec();
configSpec.setAsStoredActive(true);
wt.fc.QueryResult queryResult= wt.epm.structure.EPMStructureHelper.service.navigateReferencesToIteration(epmdocument, querySpec, configSpec);
I provide above as pure "seems to work for me" and cannot provide any support on it. If needed, please open up a case with PTC Technical Support.
It would be great if you could create a Product Idea "Need supported API to retrieve for a given Drawing the corresponding main WTPart (considering calculated links)".
Kind regards
Malte
Thanks everyone for the help! I got it working.
It was a two-step approach for me since my incoming item could be either a model or drawing.
For going from drawing to WTPart attribute it ended up looking something like this:
EPMDocument cadDoc = //whatever gets passed in to this method;
if(cadDoc.getDocType().toString().equals("CADDRAWING")) {
// get the WTPart attribute for the drawing
String atr = myGetWTPartAttributeValue(cadDoc);
}
In the getWTPartAttribute method I went the route of what was written up in CS358450.
java.util.Collection<?> result = null;
wt.fc.collections.WTCollection seeds = new wt.fc.collections.WTArrayList();
model = getModelFromDrawing(epm); //when incoming EPM is drawing
seeds.add(model);
wt.epm.EPMDocConfigSpec configSpec = new wt.epm.EPMDocConfigSpec();
configSpec.setLatestActive();
wt.filter.NavigationCriteria nc = wt.filter.NavigationCriteria.newNavigationCriteria();
java.util.List<wt.epm.EPMDocConfigSpec> configpecs = new java.util.ArrayList<wt.epm.EPMDocConfigSpec>();
configpecs.add(configSpec);
nc.setConfigSpecs(configpecs);
com.ptc.windchill.collector.api.CollectedResult ccr = null;
ccr = com.ptc.windchill.collector.api.cad.CadCollector.newInstance(seeds, nc).associatedParts(com.ptc.windchill.collector.api.cad.CadCollector.GatherAssociatedParts.ONLY_FOR_SEEDS).collect();
result = ccr.getCollectedObjects();
java.util.Iterator<?> items = result.iterator();
while (items.hasNext()) {
Object item = items.next();
if (item instanceof wt.part.WTPart) {
prt = (wt.part.WTPart) item;
}
}
// then use PersistableAdapter to get my WTPart value
com.ptc.core.lwc.server.PersistableAdapter obj = new com.ptc.core.lwc.server.PersistableAdapter(prt,null,null, new com.ptc.core.meta.common.DisplayOperationIdentifier());
try {
obj.load("myAttribute");
ret = (String)obj.get("myAttribute");
return ret;
}
And to get the model from the drawing @joe_morton 's way worked just fine with this as the base and VersionControlHelper.service for the rest:
QueryResult qr = EPMStructureHelper.service.navigateReferences(drawing, null, false); // this returns EPMReferences
while (qr.hasMoreElements() && qr != null) {
EPMReferenceLink link = (EPMReferenceLink)qr.nextElement();
if(link.getDepType()==4) {
epmMaster = (EPMDocumentMaster)link.getReferences();
// other checks happen here to verify number matches in case of multiple references
}
}
QueryResult verQr = VersionControlHelper.service.allIterationsOf(epmMaster);
while (verQr.hasMoreElements()) {
Iterated itr = VersionControlHelper.service.getLatestIteration((Iterated)verQr.nextElement(), false);
model = (EPMDocument)itr;
// other checks go here
}
return model;
@MalteSiefkes I don't think so.
@Dobi stated the link is Calculated. Therefore, he needs to write his own code to go from Drawing to WTPart or WTPart to drawing.
I've recently had to do this myself. It's a lot more complicated than navigating an object to object link or version to version link or an object to master link.