In Vuforia Studio version 8.5.13 a new metadata is intruduced. This will make the techniques described e.g. in the posts "How to extract the components with properties from a pvz file","Extracting the viewables and the seqnece steps information from a .pvz file for the usage in TWX" and "How to extract model data of 3d models in Vuforia Studio (without external Tools)?" for the most cases not neccessarly any more. as In Vuforia Studio when a model is imported (add Resource) there is a new check button “Allow the Experience access to CAD metadata” :
The selection of this checkbox lead that when the model is loaded to the “app/resources/Uploaded” folder but also an a json object with the name <model name>.metadata.json Example when we load the model “Coffee Maker Model_High.pvz” then we have also a json file named “Coffee Maker Model_High.metadata.json”. This JSON file contains the metadata to the coffee maker model
The metadata json file contains some different sections for each component /
For each component / CompPath Id we have a sub object – comp obj
{"/":{"":{"Adapter_name":"proepview",…
"/11":{"":{"Feature_Id":"11","Source_file_name": …
"/14":{"":{"Feature_Id":"14","Source_file_name": …
Where “/” means the root asm , “/11” and “/14” are components paths
The component object contains the following sections : general(empty string as key of the json obj) “”, "PROE Parameters" and "__PV_SystemProperties"
(see the attached example “Coffee Maker Model_High.metadata.json”)
The one possible approach could be , to use only this json object directly but we can use also the PTC API which is provided starting with the Vuforia Studio 8.5.13
Metadata Access:
Read the json object into memory (javascript):
In this case we can use the json object which was already created when the model data is omported in Studio.
var metaDataArray=[];
////////////////////////////////////////////////////////
//========================== When Model Loaded Event
$rootScope.$on("modelLoaded", function() {
if (arguments.length >0){
//================== if args >1 ======================
var modelWidgetId=arguments[1];
metaDataArray[modelWidgetId]={}; console.warn($scope.view.wdg);
let wdg= $scope.view.wdg[modelWidgetId];
let mdlsrc=$scope.getWidgetProp(modelWidgetId,'src'); console.log( "mdlsrc="+mdlSrc);
//==== extracts the model file name with extension
let mdlNameExt= mdlSrc.replace(/^.*[\\\/]/, ''); console.log( "mdlNameExt="+mdlNameExt);
//==== extracts the model file name without extension
var mdlName=mdlNameExt.replace(/\.[^/.]+$/, ""); console.log( "mdlName="+mdlName);
// ---adds the modelname to the array element for the widget
metaDataArray[modelWidgetId]['mdlName']=mdlName;
metaDataArray[modelWidgetId]['CompIdList']=[];
// $https call of the JSON file form the UPLOAD folder
$http.get('app/resources/Uploaded/' + metaDataArray[modelWidgetId]['mdlName']+'.metadata.json')
.success(function(data, status, headers, config) {//-------- success fnc
metaDataArray[modelWidgetId]['data']=data;
angular.forEach(data , function(value ,key){ //-------- ForEach json loop
metaDataArray[modelWidgetId]['CompIdList'].push(key);
});//--------end of ForEach json loop
// print the data to the console
console.log("metaDataArray[]"); console.warn(metaDataArray);
})//-------- end success fnic
.error(function(data, status, headers, config) {console.log("problem in the http will create a new ");});
////////////////////////////////////////////////////////
})
The code listed above will load the json file to the modelWidget/s (it will works also if we have many model widngets there - and each model widget ponts to model which is imported with metadata)
When we test this code we can check the object in memory (console.warn() ) :
Now we can access the metadata using the normal JSON functionality - so we can access the component data via the Comp Path Id / id paths - corresponds to the modelItem widget property occurrence:
$scope.app.testFunction= function() {
// visiting array with string index
Object.keys(metaDataArray).forEach(function(key){
console.log(" model Widget = "+ key);
let compList = metaDataArray[key]['CompIdList'];
//select randomly from the coponent list
let randomNum= parseInt(Math.random()*metaDataArray[key]['CompIdList'].length)
let randomComp= metaDataArray[key]['CompIdList'][randomNum];
console.log("random component selected = " +randomComp);
// let DispName = metadata.get(randomComp, 'Display Name')
/*** you can use here one of the following fields
"Child Count","Component Name","Display Name","Model Extents (mm)","OL File Name","Part Depth""Part ID","Part ID Path","Part Name","Part Path"
****/
let DispName = metaDataArray[key]['data'][randomComp]['__PV_SystemProperties']['Display Name']
console.log("DispName= "+ DispName)
let model_extend_mm = metaDataArray[key]['data'][randomComp]['__PV_SystemProperties']['Model Extents (mm)']
console.log("model_extend_mm= "+ model_extend_mm)
let creaDate = metaDataArray[key]['data'][randomComp]['PROE Parameters']['CREATION_DATE']
console.log("creaDate= "+ creaDate)
console.log("model_extend_mm= "+ model_extend_mm)
let designState = metaDataArray[key]['data'][randomComp]['PROE Parameters']['DESIGN_STATE']
console.log(" designState= "+ designState)
// make a selection string for this component
let mdl_selection= key+"-"+randomComp;
console.log ("mdl_selection="+mdl_selection)
// generate some random rgbá color
let r =parseInt(Math.random()*255);
let g =parseInt(Math.random()*255);
let b =parseInt(Math.random()*255);
let a =parseInt(Math.random()*0.8)+0.2;
//apply blink funciton for this component selection with random color
$scope.blinkSelection(mdl_selection,'rgba('+r+','+g+','+b+','+a+')',200,22);
});
}
When we test the listed code above we will have in the chrome console window:
Using furhter the json functionality we can also implement e.g. some user picks where you can associate it with the metadata :
angular.forEach($element.find('twx-dt-model'), function(value, key) {
// find all model widget feature and perform funciton()
// for each model widget - key == modelWidgetId
//define the userpick function for each modelWidgetId
angular.element(value).scope().$on('userpick',function(event,target,parent,edata) {
if (edata) {
if ($scope.currentSelection) { // selection is not null make it undefined
tml3dRenderer.setColor($scope.currentSelection, undefined); }
//create the selection string <modelWidgetId>-<occurance Path Id>
$scope.currentSelection = target + '-' + JSON.parse(edata).occurrence;
//generate a random rgba color
let r =parseInt(Math.random()*255);
let g =parseInt(Math.random()*255);
let b =parseInt(Math.random()*255);
let a =parseInt(Math.random()*0.8)+0.2;
//call blinkSelection function for the selected component
$scope.blinkSelection($scope.currentSelection,'rgba('+r+','+g+','+b+','+a+')',200,10);
//write the data SystemProperty of this compoonent in to a textArea Widget
$scope.setWidgetProp('textArea-1','text',JSON.stringify( metaDataArray[target]['data'][JSON.parse(edata).occurrence]['__PV_SystemProperties']));
} })
})
This code will write the meta data to the selected component form the __PV_SystemPoperties section to a text area widget. Also the component will blink fwith random rgba color:
I attached an small example (modelMetaDataMobilTest.zip) which should demonstrated the described techniques
Vuforia Studio metadata API
The first step is to call the metadata for a model widget. For this we can use the following construct e.g. WidgetId is ‘model-1’ :
PTC.Metadata.fromId('model-1').then(
(metadata) => {
// <HERE CALL YOUR CODE with metadata >
});
So for example we can use get the “Display Name of the component with the path Id =’/0/6’:
PTC.Metadata.fromId('model-1').then( (metadata) => {
Let disp_name= metadata.get('/0/6', 'Display Name');
console.log(“Display Name=”+disp_name);
});
The most of the methods which could be applied to the metadata object and also some examples are described in the PTC Help (Incorporate CAD Metadata Into an Experience)
This functionality is available first with Vuforia Studio 8.5.13. To this article is also attached a PDF copy of the metioned link above.
There we can use 2 different approaches:
To get a selected object or list of objects: let metaDATA=PTC.Metadata.fromId('model-1')
metaDATA.then(function(meta) { console.log("success func of metaData");
//a test with a fix model widget id
var designer = meta.get('/11','DESIGNER','PROE Parameters');
console.log("Designer= " + designer);
var ptc_mat = meta.get('/11','PTC_MATERIAL_NAME','PROE Parameters');
console.log("PTC_MATERIAL_NAME= " + ptc_mat);
var dispName = meta.get('/11','Display Name','__PV_SystemProperties');
console.log("dispName= " + dispName);
var DV_System_Categ= meta.get('/11'). getCategory ('__PV_SystemProperties')
console.log(JSON.stringify(DV_System_Categ))
let myQuery=meta.find('Display Name').like('PRT').find('Part Depth').in(0,3);
console.log("myQuery Name:"+myQuery._friendlyName);
console.log("myQuery selected Paths :"+JSON.stringify(myQuery._selectedPaths));
}) .catch(function(err)
{console.log("problem with the read of metadata ");console.warn(err);});
To call for the selected object a callback function where the Path id was passed as function argument:
$scope.app.testCustomSel= function(){
let pathDepth=4
$scope.app.testCustomSelection('model-2',
$scope.app.whereFunc,$scope.app.selectFunc,pathDepth)
$scope.app.testFind1_modelId='model-1'
PTC.Metadata.fromId( $scope.app.testFind1_modelId)
.then(function(meta)
{meta.find('Part Depth').lessThan(3).find('Display Name')
.like('PRT',$scope.app.selectFunc);})
}
//========================== app.testCustomSelection
$scope.app.testCustomSelection= function(modelId,whereFunc,selectFunc,pathDepth) {
BPRN("app.testCustomSelection()");
$scope.app.testCustomSelection.modelId=modelId;
$scope.app.testCustomSelection.pathDepth=pathDepth
var metaDATA= PTC.Metadata.fromId(modelId)
.then(function(meta) {meta.findCustom(whereFunc,selectFunc);})
}
//-------------------------------------------------
$scope.app.whereFunc = function(idpath) {
// scope var `this` is the metadata instance
const depth = this.get(idpath, 'Part Depth')
const name = this.get(idpath, 'Display Name')
return parseFloat(depth) > $scope.app.testCustomSelection.pathDepth ||
(name && name.search('PRT') >= 0)
}
//-------------------------------------------------
$scope.app.selectFunc = function(idpath) {
const name = this.get(idpath, 'Display Name')
console.log("app.selectFunc["+$scope.app.testCustomSelection.modelId+"] idpath="
+idpath+ " >>>Name: "+name);
return this.get(idpath, 'Display Name');}
In the example above the query is done by the where function and for all selected models the callback function select Func is called where the pathId was passed to the function
I attached an small example (modelMetaDataMobilAPItest.zip) which should demonstrated the described techniques
View full tip