Community Tip - Visit the PTCooler (the community lounge) to get to know your fellow community members and check out some of Dale's Friday Humor posts! X
Hi all,
I have a question about Vuforia in interaction with HoloLens 2.
In my scenario, I need to switch between different sequences (that I created with Creo).
This should be done by clicking on a button. I know the underlying command via JavaScript and have already used it successfully several times - but so far only for iPad (2D) Experiences.
For this I always use:
$scope.view.wdg['model-1']['sequence'] = 'l-Creo%203D%20-%20sequence.pvi';
In the preview everything works as it should.
Now when I test my scenario on the HoloLens, it seems to me that the HoloLens does not know this command. It loads the "default sequence" of the 3D model. Generally, I can't jump between sequences....
Do you know what I am doing wrong? To me it looks like there is a bug in the HoloLens interpreter. Is there another command that makes jumping between sequences work on the HoloLens?
I am grateful for any help!
Many greetings
Jonas
Hello @JH_9310184 ,
I see that use encoded characters in the path but this is not necessary. So to translate /encode decode you can use e.g. this web side to check if you input is correct https://meyerweb.com/eric/tools/dencoder/
The question is where is the sequence, pvz model - is it in the project upload folder? I used some javaScript code which should also work on the HL device. Sample code of function:
//////////////
//definition of the function
$scope.app.playModelStep = function (sequence,modelName,step_number,play) {
//sequnece -sequnece name e.g. TestFigure1 - as shown in UI
//modelName - model name e.g. model-1
//step_number - set this number to current step
//play true/false execute play for the model
$scope.$applyAsync(()=>{$scope.setWidgetProp(modelName, 'sequence', '');});
$timeout(function () {
$scope.$applyAsync(()=>{$scope.setWidgetProp(modelName, 'sequence', 'app/resources/Uploaded/l-Creo 3D - '+sequence +'.pvi');});
},50);
$timeout(function () {
$scope.$applyAsync(()=>{$scope.setWidgetProp(modelName, 'currentStep', parseInt(step_number));});
if(play) //check if play should be applyed
$timeout(function () {angular.element(document.getElementById(modelName)).scope().play(); }, 100);
}, 500);
};
//////////////////////////////////
//==========
...
...
// later call example
$scope.app.playModelStep("Figure 1","model-1",3,true)
The example code will set sequence for specific modelWidget and will set the current step to a number and if play is true will paly the step. You can use as define or omit some parts if do not require it (e.g. the setting of the step and playl)
Please , let me know if this code is working for you on HL 2. Thanks
Hello Roland,
thank you for your advice. It works on my laptop, but the HoloLens doesn't manage to open the correct Sequence even through this. Unfortunately, this also leaves me in the default sequence (-- Choose a resource --)
Is there another command to change the sequence via JS?
Best regards
Jonas
Hi Jonas, thanks for the feedback.
let me check on the HoloLens 2 device.
I need the following info:
- is the pvi file inside the pvz file or is extracted-means - (e.g. pvz is renamed then unzip and open or extract it to folder) Could you check project folder where is pvz file , name of pvz file and name of the pvi file and if it is extracted . e.g. to upload folder
So I will test this scenario on HL2 to see if currently is there an issue.
Thanks
Hi Roland,
I have imported the .pvz file from Creo as a resource on my model.
As a result, the .pvz can be found in the Uploads folder.
In addition the two included sequences have been deposited as .pvi files in the uploaded folder of the corresponding .pvz file within my Vuforia Studio files.
I hope the screenshots help you! Thanks for your support & hopefully you can come up with a solution.
Greetings
Jonas
Jonas, could you test , please, this code:
// in case that you model widget is named model-1
//for the other sequence
$timeout(function() {
$scope.setWidgetProp('model-1','sequence','app/resources/Uploaded/l-Creo 3D - Reserveschiene.pvi');
$scope.$applyAsync();
}, 200);
// or with encode
// in case that you model widget is named model-1
$timeout(function() {
$scope.setWidgetProp('model-1','sequence','app%2Fresources%2FUploaded%2Fl-Creo%203D%20-%20Reserveschiene.pvi');
$scope.$applyAsync();
}, 200);
//and for the other sequence
$timeout(function() {
$scope.setWidgetProp('model-1','sequence','app/resources/Uploaded/l-Creo 3D - Startansicht.pvi');
}, 200);
// or with encode
$timeout(function() {
$scope.setWidgetProp('model-1','sequence','app%2Fresources%2FUploaded%2Fl-Creo%203D%20-%20Startansicht.pvi');
$scope.$applyAsync();
}, 200);
Anothger point is that where you will try to call the code. Is this from button or this is on ar view start. I think the HL2 need more time to init when you try to start it on load so therefore possibly you can call the code in the onModelLoad event - e.g.:
///////////////////////
$rootScope.$on('modelLoaded', function() {
const args = Array.from(arguments);
console.log("modelLoad event args.length="+args.length)
for(i=0;i < args.length; i++){
console.log("args["+i+"]=>>"+args[i]);
// args[1] -> this is the model widget name where the event was called
// means that if it is == model-1 then the load of geometry loading
// for model-1 is completed
if(i ==1 ) //model widgetg name
if(args[i] == 'model-1') // is the the event for model-1
{//execute the code for set the sequence e.g.
$timeout(function() {
$scope.setWidgetProp('model-1','sequence','app%2Fresources%2FUploaded%2Fl-Creo%203D%20-%20Startansicht.pvi');
$scope.$applyAsync();
}, 200);
}
} //end for
})//end
This post may have been answered -
Just some additional input - Timeouts work but they are really indeterminant, listening for the sequenceloaded event is a better approach.
$scope.play_part_sequence = function(modelName,figName){
animation_sequence = true;
$scope.view.wdg[modelName]["sequence"] = figName;
}
$scope.$on('sequenceloaded', function(evt, model, type, sequence) {
// do something
twx.app.fn.triggerWidgetService(model, 'playAll');
}); // end of event
Hi @sgreywilson ,
thanks for the feedback. Yes , I agree that with the suggested code (calling the play service form the sequenceloaded event) we will ensure that the sequence is complete loaded when we try to play a step (or all steps) . In some cases when the sequence is very long the small timeout could possibly will not work. So means that the sequence is not initialized yet when we try to play. Because this calls are asynchronous – in this case the play will be ignored. Therefore we can “outsource” the call of play outside the function and set some variable which will be check in the sequenceloaded callback - in this case my original code should be changed to some code like this:
$scope.playSeq4Step=false
$scope.playStepNumber=1
//////////////
//definition of the function
$scope.app.playModelStep = function (sequence,modelName,step_number,play) {
//sequnece -sequnece name e.g. TestFigure1 - as shown in UI
//modelName - model name e.g. model-1
//step_number - set this number to current step
//play true/false execute play for the model
$scope.$applyAsync(()=>{$scope.setWidgetProp(modelName, 'sequence', '');});
$timeout(function () {
$scope.$applyAsync(()=>{$scope.setWidgetProp(modelName, 'sequence', 'app/resources/Uploaded/l-Creo 3D - '+sequence +'.pvi');});
},50);
// this will be commeted , because it will be outsources in the 'sequenceloaded'
//$timeout(function () {angular.element(document.getElementById(modelName)).scope().play(); }, 100);
//use here the setting of variable
$scope.playStepNumber=step_number // the current step
$scope.playSeq4Step=play //set variable for playing in the sequenceload event
};
//////////////////////////////////
$scope.$on('sequenceloaded', function(evt, model, type, sequence) {
$scope.$applyAsync(()=>{$scope.setWidgetProp(modelName, 'currentStep', parseInt($scope.playStepNumber));},50);
if( $scope.playSeq4Step) { // check if variable is set to play
//call the play with some delay to be sure that stepNumber is set
$timeout(function () {twx.app.fn.triggerWidgetService(model, 'play');}, 200);
$scope.playSeq4Step=false
}
}); // end of event
//==========
...
...
// later call example
$scope.app.playModelStep("Figure 1","model-1",3,true)
I think one problem we could have with this approach . If we have many modelwidgets and different functions which will try to set a sequences and then play a step in this case we need to check for which modelwidget (check event callback argument) is the sequenceload event called and who (which funciton) was the caller (this could be based on passing variable settings)
Here an example for the sequenceload event where we check the arguments:
$scope.$on("sequenceloaded", function (evt, arg) {
console.log("sequence loaded, starting play");
console.warn("arg:");
console.warn(arg); //this should be a model-1 means a model widget
//where the sequence was loaded
let metaDATA=PTC.Metadata.fromId(arg.toString())
// ========= starting here handling of meta data for arg modelwidget
metaDATA.then(function(meta) { console.log("success func of metaData");
}) .catch(function(err)
{console.log("problem with the read of metadata ");console.warn(err);});
//=========
});