cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

Community Tip - New to the community? Learn how to post a question and get help from PTC and industry experts! X

Vuforia Studio and Chalk Tech Tips

Sort by:
How to define Widget at runtime time and what is possible?  For example, the following problem: required is a button e.g. 'button-1' - widget to start a sequence. Now user want to create an 3D-Label that becomes visible after click the 'button-1' and  now for each sequence and step a the 3D-Label have to be visible as long as the sequence is played. The 3d label should display an information for the specific step and also should to have specific position. Unfortunately, it is not possible (using the supported functionality) to create widget on the fly - means create a new feature on run time where the widget was not defined in the design time. Theoretical with some more intensive work – it will be possible – we simple need to check what the UI is doing when you copy and paste widget  (but it is not easy ☹-  and it is not sure if this solution will be stable(if you will be able to implement 1:1 UI) and if it will work in later version -because PTC dev team could change some functionality – but will not change your code. For the most tasks it enough to use few 3d widgets (3Dlabels) the most are invisible and then switch the visibility on runtime and move them on the desired location. According request on address of this issue  , may be it is worth here to mention following statements of the PTC dev  :   .) Question: “Vuforia Studio 8.5.3.Is it possible to create 2D and 3D widgets from Java Script? Answer: If you mean to dynamically create/instatiate a widget and set its properties at runtime, no we have no such capability today. The simplest workaround is to pre-generate the widgets and manage their visibility at runtime. 2.) Question: Is it possible to create 2D widget dynamically by Java Script? Answer: Its fairly easy to have a couple of hidden widgets that are displayed and moved with a tap event. It might be possible to create some 2d widgets on the fly, but 3d widgets would be a bit harder as more of the unsupported api under the hood would be needed.   According to the statement of the PTC development team  - here the we will consider the possible workaround :. The following requirement: When the sequence 1 is played the labels 1, 2 and 3 have to be visible. When the sequence 2 is played the labels 4, 5 and 6 have to be visible. In all of these labels are only one word in it, so not a step description or something like this. Here is a sample table with coordinates for a better overview:   There is no a real reason to have 4,5,6 here. In this case we can use 1,2,3 again - also for step 2 but we could here change the position and will change the text content. In this case we need to have to define number of 3DLabel widgets which is equal to the maximum of used notes per step - and display and update only the necessary number of widget in particular step.   To demonstrate the workaround the following example was created and tested. This   example should show the suggestion above. It is not perfect but should demonstrate the general approach to achieve similar goal. The table with values is a json file- in the attached example is the file steps.json in the Project upload folder. Here example of values: {"1":{"3DLabel-1":{"visible":true,"text":"text Label1 Step 1", "x":0.0,"y":0.1,"z":0.0,"rx":0.0,"ry":0.0,"rz":0.0,"scale":1.0,"class":"ptc-3DLabel1"}, "3DLabel-2":{"visible":true,"text":"text Label2 Step 1", "x":0.0,"y":0.2,"z":0.0,"rx":0.0,"ry":0.0,"rz":0.0,"scale":1.0,"class":"ptc-3DLabel2"}, "3DLabel-3":{"visible":true,"text":"text Label3 Step 1", "x":0.0,"y":0.3,"z":0.0,"rx":0.0,"ry":0.0,"rz":0.0,"scale":1.0,"class":"ptc-3DLabel3"}}, "2":{"3DLabel-1":{"visible":true,"text":"text Label1 Step 2", "x":0.0,"y":0.1,"z":0.1,"rx":0.0,"ry":10.0,"rz":0.0,"scale":1.0,"class":"ptc-3DLabel2"}, "3DLabel-2":{"visible":false,"text":"text Label2 Step 2", "x":0.0,"y":0.2,"z":0.0,"rx":0.0,"ry":10.0,"rz":0.0,"scale":1.0,"class":"ptc-3DLabel2"}, "3DLabel-3":{"visible":true,"text":"text Label3 Step 2", "x":0.0,"y":0.3,"z":0.1,"rx":0.0,"ry":10.0,"rz":0.0,"scale":1.0,"class":"ptc-3DLabel2"}}, "3":{"3DLabel-1":{"visible":true,"text":"text Label1 Step 3", "x":0.0,"y":0.1,"z":0.0,"rx":0.0,"ry":20.0,"rz":0.0,"scale":1.0,"class":"ptc-3DLabel3"}, .... "8":{"3DLabel-1":{"visible":true,"text":"text Label1 Step 8", "x":0.0,"y":0.1,"z":0.0,"rx":0.0,"ry":0.0,"rz":0.0,"scale":1.0,"class":"ptc-3DLabel1"}, "3DLabel-2":{"visible":true,"text":"text Label2 Step 8", "x":0.0,"y":0.2,"z":0.0,"rx":0.0,"ry":0.0,"rz":0.0,"scale":1.0,"class":"ptc-3DLabel2"}, "3DLabel-3":{"visible":true,"text":"text Label3 Step 8", "x":0.0,"y":0.3,"z":0.0,"rx":0.0,"ry":0.0,"rz":0.0,"scale":1.0,"class":"ptc-3DLabel3"}}}      The table contains the most possible values to set for 3DLabels. We can add other or omit values in the list. In generally we need only the values which should be changed but such list template which contains all values is better for editing. It should still work so far, the json syntax is correct First point is to load the list to a global variable from the project upload folder. Here a sample code:   $scope.jsonData_steps={}; //global $scope variable //================================== readSteps=function (jsonFile){ console.warn("**=>readSteps :: "+jsonFile); fetch(jsonFile) .then(response=>response.text()) .then(data=>{$scope.jsonData_steps=JSON.parse(data); console.warn( JSON.stringify($scope.jsonData_steps))}) .catch((wrong) => {console.log("problem in fetch: "); console.warn(wrong)}) } //================================== $scope.Init=function() { $timeout(readSteps('app/resources/Uploaded/'+stepsjson),200); } //================================================================================================= // $ionicView.afterEnter -> this event fires when 2d view was entered //================================================================================================= $scope.$on('$ionicView.afterEnter',function(){ console.log("$ionicView.afterEnter was called"); $scope.Init();}) //event: when 2d View loaded //=================================================================================================     further in the "stepstarted" event the code will set the values of the widget properties which are contained by the json object  with the same number as the started step number:     //================================================================================================= $scope.$on('stepstarted', function(evt, arg1, arg2, arg3) { var parsedArg3 = JSON.parse(arg3); console.log("stepstarted stepNumber="+parsedArg3.stepNumber + " nextStep="+parsedArg3.nextStep); $timeout(()=>{ $scope.setMutipleProps($scope.jsonData_steps[parsedArg3.stepNumber.toString()])},10) $scope.setWidgetProp('label-1', 'text',"STEP: "+ parsedArg3.stepNumber) $scope.$applyAsync(); }); //================================================================================================= //this function set multiply properties from a list //================================================================================================= $scope.setMutipleProps = function(obj){ Object.keys(obj).forEach(function (item) { for(var prop in obj[item]) { $scope.view.wdg[item][prop]=obj[item][prop]; //print the setting for debugging console.log("==>$scope.view.wdg["+item+"]["+prop+"]="+obj[item][prop] ) } }) $scope.$applyAsync(); }; ///=================================================================================================     Finally,  the project was  tested  and  it was working as expected:     The demo project is attached to this article.
View full tip
Sometimes it is required and will be nice to use a picker functionality. For example, some data picker – so the question: How to achieve this. Yes it is possible in JavaScript that we can incorporate a data/calendar picker into the Vuforia Studio environment? In the Web there are some open source libraries and at least it works 1:1 in preview mode. But mostly they work also fine on mobile devices. In this article a data picker was tested and it was working fine in Preview mode but also was working fine on IOS and on Android devices  The example here is based on the follow link:  https://www.cssscript.com/tag/date-picker/ there are some data picker implemented. Here in this example the library (data-picker) is copied to  the Studio Project download folder and it javascript code will   load the lib and defined a function which is called from button First step is to define a function which enables to load javascript and css from a file / project folder:   // this code load a javascript or css file $scope.loadjscssfile= function(filename, filetype){ console.log("loading "+filename+":: type="+filetype) if (filetype=="js"){ //if filename is a external JavaScript file var fileref=document.createElement('script') fileref.setAttribute("type","text/javascript") fileref.setAttribute("src", filename) } else if (filetype=="css"){ //if filename is an external CSS file var fileref=document.createElement("link") fileref.setAttribute("rel", "stylesheet") fileref.setAttribute("type", "text/css") fileref.setAttribute("href", filename) } if (typeof fileref!="undefined") document.getElementsByTagName("head")[0].appendChild(fileref) } // this function will load the simplepicker javascript lib and the css lib $scope.testLoad= function() { $scope.loadjscssfile("app/resources/Uploaded/lib/simplepicker.css", "css") $scope.loadjscssfile("app/resources/Uploaded/dist/simplepicker.js", "js") }   In this example the $inoicView.afterEnter (after 2d/view  is loaded) event is used to load the library. The function for the picker call is defined -  $scope.app.TestPicker()- which is called from a button .   //============================= $scope.$on('$ionicView.afterEnter', function() { $scope.testLoad(); $timeout(() => { $scope.setWidgetProp("button-1","class", "simplepicker-btn"); $scope.$applyAsync(); },500) }) //https://www.cssscript.com/material-date-time-picker-simplepicker/ // function called from a button $scope.app.TestPicker = function() { let simplepicker = new SimplePicker({ zIndex: 10 }); simplepicker.open(); simplepicker.on('submit', (date, readableDate) => { console.warn( readableDate ); $scope.setWidgetProp('label-1','text', readableDate); $scope.$applyAsync(); }); simplepicker.on('close', (date) => { console.log('Picker Closed' ); }); }   When the picker is closed after date was selected - the javascript code will set the selected value to the text property of a label widget (label-2). The javascript and the style (css)  implementation was copied to the resource folder:       Now the   simplepicker could be tested and it has the following appearance in preview mode:     The test picker Studio project was attached to this case.  
View full tip
How to associate my image texture UV on my 3D Model Here the suggested   workflow is the following: 1.) we will create the CAD data in any CAD tools /   Creo Parametric or any AutoDesk , Catia, Solidwors and etc. / In generally when we prepare the model for the AR usage and there /in the CAD tool/ we will also assigned the texture to a model, component or particular surfaces. So means  the native CAD data will contain already the texture/'s before we will try to use it in Vuforia Studio 2.) So to use the data in Vuforia Studio we need to import it. The import tool is a part of studio and will convert the geometry . Internal Studio used the optimizer tool (here want to refer to the post: "Optimize PVZ before") So means that the native cad data is converted always to PTC light ware format pvz. According to rcp. setting it will  import also the textures or will not import them. So this is the most used way to use textures in Vuforia Studio.  Also UV setting are something what should be set in the CAD tool - e.g. in Creo Parametric:      3.) In case that we have a texture file  and want to assigned it to a model or modelItem  using some U V parameters in Vuforia Studio  this will make it more difficult. It is possible but you need to define an GLSL shader in the tmlText widget and assigned to the shader property. The glsl shader will used also the file refer in the texture property and could display it projected on the UV model geometry:     e.g. in Javascript;   $scope.app.shaderString="texture_test;scale f 2;moveX f 0;moveY f 0"; $rootScope.$on('modelLoaded', function() { $scope.view.wdg['modelItem-1']['texture'] = "app/resources/Uploaded/cvc.jpg?name=Texture0&edge=repeat"; $scope.setWidgetProp('modelItem-1', 'shader', $scope.app.shaderString); $scope.view.wdg['3DImage-1']['src'] = "app/resources/Uploaded/pinger_half.png?name=Texture0&edge=mirror"; $scope.setWidgetProp('3DImage-1', 'shader',$scope.app.shaderString); })     Here the pictures are created in project wher I used the following tmlText defintion. Please, pay attention that it is not a solution , but more only an example which display the general usage. If you need more to optimize the display you need to do some improvements - ,please, refer to some addtional links: https://wiki.delphigl.com/index.php/Tutorial_glsl2 https://viscircle.de/einsteigerguide-einfuehrung-in-glsl/ https://stackoverflow.com/questions/27646383/glsl-shader-for-texture-smoke-effect or lot of other links / key words glsl  fragmet vertex shader defintion, web.gl javascipt/   So in this example I used the following test shader code:     <script name="texture_test" type="x-shader/x-fragment"> precision mediump float; uniform sampler2D Texture0; uniform float scale; uniform float moveX; uniform float moveY; // determine varying parameters varying vec3 N; varying vec4 vertexCoord; // determine shader input parameters uniform vec4 surfaceColor; const vec3 lightPos = vec3(1.0, 2.2, 0.5); const vec4 ambientColor = vec4(0.3, 0.3, 0.3, 1.0); void main() { // calc the dot product and clamp based on light position // 0 -> 1 rather than -1 -> 1 // ensure everything is normalized vec3 lightDir = -(normalize(lightPos)); vec3 NN = normalize(N); // calculate the dot product of the light to the vertex normal float dProd = max(0.0, dot(NN, -lightDir)); { // calculate the color based on light-source and shadows on model vec2 TexCoord = vec2( vertexCoord )*scale; TexCoord.x=TexCoord.x+moveX; TexCoord.y=TexCoord.y+moveY; vec4 color = texture2D(Texture0, TexCoord) ; gl_FragColor = (ambientColor + vec4(dProd)) *color ;// surfaceColor; } } </script> <script name="texture_test" type="x-shader/x-vertex"> attribute vec3 vertexPosition; attribute vec3 vertexNormal; varying vec3 N; varying vec4 vertexCoord; uniform mat4 modelMatrix; uniform mat4 modelViewProjectionMatrix; void main() { vec4 vp = vec4(vertexPosition, 1.0); gl_Position = modelViewProjectionMatrix * vp; vertexCoord = modelMatrix*vp; // the surface normal vector N = vec3(normalize(modelMatrix* vec4(vertexNormal,0.0))); } </script>   The GLSL code should be added in the text area of the tmlText widget:     At the end I want to provide to this post  a sample project which demonstrate how to use the textures with shaders in Studio. Please, pay attention this is only an example which demonstrate the general principle. So far I now this way , works only on mobile devices. I did not get it work with the shader on the HoloLens. I tested the project in preview on Android and on IOS. On Android and in preview mode it work fine. On IOS it works fine for the ModelItem but not for the 3dImage- but I think there we need to downscale the value of the light intensity:   gl_FragColor = (ambientColor*lightscale + vec4(dProd)) *color ;// s project was attached : testShaderProperties-EXAMPLE.zip
View full tip
Vuforia Studio New Camera widget for 3D Eyewear projects Bug fixes and minor improvements Vuforia View Improved detection and tracking for Model Targets and Spatial Targets Bug fixes and minor improvements Experience Service Bug fixes and minor improvements
View full tip
Vuforia Studio Support for Microsoft Edge browser (version 79 or greater) Bug fixes and minor improvements Vuforia View Bug fixes and minor improvements Experience Service Experience Service 8.5.6 address a critical security issue (CVE) in Node.js Bug fixes and minor improvements
View full tip
Vuforia Studio Bug fixes and minor improvements Vuforia View Bug fixes and minor improvements Experience Service (On-premises) Support for single sign-on (SSO) authentication for on-premises installations NOTE: Requires Vuforia Studio and Vuforia View 8.5.5 Bug fixes and minor improvements   For more information on configuring Vuforia Experience Service with single sign-on (SSO), see the Experience Service Installation and Deployment Guide. 
View full tip
Vuforia Studio Bug fixes and minor improvements Vuforia View RealWear 6.0 is no longer supported Bug fixes and minor improvements Experience Service An 8.5.3 version of the Experience Service was not released
View full tip
Vuforia Studio Bug fixes and minor improvements Vuforia View Bug fixes and minor improvements To download the latest version of Vuforia View on HoloLens, the app store must be updated to version 11911.1001.9.0 or higher Experience Service An 8.5.2 version of the Experience Service was not released
View full tip
Vuforia Studio Improved Image Target and Model Target generation Bug fixes and minor improvements Vuforia View Improved detection and tracking for Model Targets and Spatial Targets Bug fixes and minor improvements Experience Service Improved Image Target and Model Target generation Bug fixes and minor improvements
View full tip
ThingWorx properties can be updated from a Vuforia Studio experience.    Below is a simple example: Create a test Thing and a test property for the Thing in ThingWorx :   Create a service for the Thing with text input parameter(Test) and add the below code to update the TestProperty value:   Click Done and Save the Thing In Vuforia Studio, Add a Text Input widget and a Button widget in 2D canvas Add the service of the Thing in the External data Panel Now, bind the Text property of the ‘Text Input’ widget to the Test Parameter of the service as shown below:   Bind the Click event of the Button widget to the Service to update the value of Thing property in ThingWorx   Test the experience by clicking Preview. Enter text in the Text Input widget and click the button. The Thing property should then be updated.      If you are creating a public experience, ensure that run time permissions for the es-public-access user have been assigned to the properties, events and services of the entity.  From ThingWorx composer, open the entity whose data must be accessed by a public experience Click the Permissions icon in the last column of the row containing the entity Click Run Time under Permissions Under All Properties, Events, Services, use the search box to find and add the es-public-access user Click green dot under the appropriate permissions columns   Click Save See the Vuforia Studio Help Center for more information on granting user permissions in ThingWorx for Vuforia Studio.  
View full tip
To reference a function on a voice command or gesture use  viewCtrl.myFunction() where "myFunction" is the name of your function.     Check out the Vuforia Studio Help Center for detailed instructions on creating a HoloLens experience using gestures.  
View full tip
PDFs can be linked to experiences using a few methods. Below is an example of using the toggle widget or a toggle button to open and close a PDF within your experience.          Example of JavaScript code to add to Home.js file: $scope.toggleButton = function() { //if the toggle is pressed if ( $scope.view.wdg['toggleButton-1']['pressed']==true) { window.location='app/resources/Uploaded/%5BBD-Logbuch%5D20190208-20190310.pdf' console.log($scope.view.wdg['file-1']['url']) } //unpress the toggle button after 1,5 sec $timeout(function () { $scope.view.wdg['toggleButton-1']['pressed']=false;}, 1500); }      
View full tip
Vuforia Studio New 3D Button widget that supports HoloLens 2 articulated hand tracking (3D Eyewear projects only) Bug fixes and minor improvements Vuforia View Support for Microsoft HoloLens 2 Bug fixes and minor improvements Experience Service An 8.5.0 version of Experience Service was not released. However, Experience Service 8.4.6 will support the upcoming ThingWorx 8.5 release.  
View full tip
Vuforia Studio Bug fixes and minor improvements Vuforia View Bug fixes and minor improvements Experience Service  An 8.4.7 version of Experience Service was not released  
View full tip
Vuforia Studio Bug fixes and minor improvements Vuforia View Vuforia View 8.4.6 is required for viewing Experiences that include Model Targets created with Vuforia Studio 8.4.6 Improved detection and tracking of Model Targets and Spatial Targets Bug fixes and minor improvements Experience Service Support for Ubuntu 18.04 and RHEL 7.2 - 7.6 Bug fixes and minor improvements
View full tip
1.) The first point  here is to clarify : is it possible to extract model data of 3d models in Vuforia Studio?  ( data could be extracted by Creo View Toolkit apps but here is considered only the Vuforia Studio environment) Supposing , we have a model widget for an assembly model without explicit modelitem  widget definitions. The question is: Can we extract data for the components and if yes,  then what data we can extract? In Vuforia Studio Environment Extracting of data is possible only in Preview mode, because we have in preview mode the method tml3dRenderer.GetObject() where we can access a model object (a component) example:   let comp_widget=tml3dRenderer.GetObject(selection).GetWidget()   where the selection is some thing like "<modelname>-<compPath>" e.g. : "model-1-/0/0/3/2"   Then from the widget we can extract data:   var loc=tml3dRenderer.GetObject(selection).GetWidget().GetLocation() console.error("DEBUG getObj.GetWidget()") console.warn(tml3dRenderer.GetObject(selection).GetWidget())   When we   explore  the different methods in the crome debugging console,  we will find methods to  get or  to set  properties. To extract data, we can use the get... methods.   The methods of  tml3dRenderer.GetObject() seems currently not to work in Vuforia View on end devices (the tml3dRenderer object is a handle of the cordova vuforia plug in and it has a different implementation on the different end devices.In preview mode so far I know, the graphic is based on WebGL and Three.js)  Therefore we will be not able for example to get the data of a component selection on the end device. So means we need a way to extract data in Preview mode and make it available in the Vuforia view on the end device.  Here I did not find a methods to extract the original component name but I was able to create a list (json) with the position data ( I did not add color but this is possible to access it - e.g. tml3dRenderer.GetObject(selection).GetWidget().GetColor()) We can create a json  e.g. of  following data:   {"model-1-/0/0/0":{"valid":false,"orientation":{"x":0,"y":0,"z":0}, "size":{"x":1,"y":1,"z":1},"scale":{"x":1,"y":1,"z":1}, "position":{"x":9.999999998199587e-24,"y":9.999999998199587e-24,"z":9.999999998199587e-24}}, "model-1-/0/0":{"valid":false,"orientation":{"x":0,"y":0,"z":0},"size":{"x":1,"y":1,"z":1}, "scale":{"x":1,"y":1,"z":1},"position":{"x":0,"y":0,"z":0}}, "model-1-/0/0/2":{"valid":false,"orientation":{"x":0,"y":90,"z":0},"size":{"x":1,"y":1,"z":1}, "scale":{"x":1,"y":1,"z":1},"position":{"x":0,"y":0.029500000178813934,"z":-5.51091050576101e-18}}, ...}   we can  assign the json to a variable e.g. $scope.COMP_LOCs So later we can read the current position data on end device:   var selection_location=$scope.COMP_LOCs[l_currentSelection] //read the location data from json varible console.log("selection:"+l_currentSelection+"->X= "+ selection_location.position.x); //print it to console selection_location.position.x= round(parseFloat(selection_location.position.x) + 0.005,4) //add 0.005 shift and round to 4 dec   2.)In point 1.)  we checked how to  extract the data of an compoent (a selection) .But Actually  we have a couple of methods to extract the data but what we do not have is a valid  selection of an assembly  component . This is required to obtain a valid modelitem widget (temporar) via tml3dRenderer.GetObject(). For the selection generation we have the model widget name e.g. “model-1” but   we do not have the component ID paths. To be able to construct a selection handle we need to construct the ID path of a component and then we need to check if it exist. This is some kind of graph search where we have an assembly with a components tree.  There the edges are the ids of the components. e.g. /0/0/1/1 , /0/0/1/2, /0/0/1/4, … etc. One possible algorithm is the deep first search:     To implement this I used the following javaScript code:   ///////////////////////////// var max_asm_depth=6; //this is the max depth in Creo Parametric var max_numb_comp_asm=25; /////////////////////////// ->deep first function check_comp_deep_first_recursively(target,path,arr) { //console.warn("called check_comp_deep_first_recursively(target="+target+",path="+path+")"); var selection = target+'-'+path var path_array = path.split('/') var depth = parseInt(path_array.length) var num = parseInt(path_array[depth -1]) var prev_num = parseInt(path_array[depth -2]) var prev_path = '' for (var i=1;i < depth -1;i++) {prev_path= prev_path +'/' + path_array[i]} if( check_for_valid_selection(selection) == 1) { arr[selection]=tml3dRenderer.GetObject(selection).GetWidget().GetLocation() if( (depth+1) < max_asm_depth) check_comp_deep_first_recursively(target, path + '/0', arr) else { if(num +1 < max_numb_comp_asm) check_comp_deep_first_recursively(target, prev_path + '/'+(num +1), arr)} } else { var right_num = num +1 if(right_num < max_numb_comp_asm) check_comp_deep_first_recursively(target, prev_path + '/'+right_num, arr) else if(!Number.isNaN(prev_num) ) {//console.log("--2") prev_path = '' for (var i=1;i < depth -2;i++) {prev_path = prev_path +'/' + path_array[i]} prev_path = prev_path +'/' + (prev_num +1) check_comp_deep_first_recursively(target, prev_path , arr) } } } ////////////////////////// ///call of the function: $scope.compJSON_loc_Data = new Object(); var target="model-1" check_comp_deep_first_recursively(target,'/0',$scope.compJSON_loc_Data) ...   The code above has the following weak spot - I need to give the maximum depth (max_asm_depth) and the maximum possible branches (max_numb_comp_asm)  The maximum depth currently in Creo assembly is 25 so that value which > 25 will not make a sense.  The value of  max_numb_comp_asm  in a flat assembly (only one level of depth) corresponds to the number of the components - the maximum number of branches on particular level of depth   The another possible algorithm is the breadth first search:     To implement this  I used the following JavaScript code:   ///////////////////////////// var max_asm_depth=6; //this is the max depth in Creo Parametric var max_numb_comp_asm=25; /////////////////function check_comp_at_level(target,num,depth,arr) // ->breadth first function check_comp_at_level(selection,num,depth,arr) { var position =''; // console.log("call check_comp_at_level =>"+selection); try{ // console.log("====== check here ==========="); //console.warn(tml3dRenderer.GetObject(selection).GetWidget().GetLocation()); var loc=tml3dRenderer.GetObject(selection).GetWidget().GetLocation() if( (loc.scale.x == 0) || (loc.scale.y == 0) || (loc.scale.z == 0) ) return 0; // the scale could not be zero //position= tml3dRenderer.GetObject(selection).GetWidget().GetLocation().position //console.warn(position); //arr[selection]=position arr[selection]=loc return arr[selection]; } catch (e) {console.error("failsed with error="+e); return 0;} } /////////////////////////// function check_comp_at_level_recursively(selection,depth,arr) { //console.warn("called check_comp_at_level_recursively("+selection+",depth="+depth+")"); var num =0; if(depth >= max_asm_depth) { //console.log("maximum depth of max_asm_depth ="+max_asm_depth+" reached"); return 0;} for (num=0;num < max_numb_comp_asm; num++) { var currentSelection =selection+'/'+num if(depth <0) return 0; var pos = check_comp_at_level(currentSelection,num,depth,arr) if(pos ==0 ) { continue;} else {check_comp_at_level_recursively(currentSelection,(depth+1),arr) } } //end of for } ////////////////////////// //////////////////////////////// function check_for_valid_selection(selection) { //console.log(" check_for_valid_selection =>"+selection); try{ var loc=tml3dRenderer.GetObject(selection).GetWidget().GetLocation() if( (loc.scale.x == 0) || (loc.scale.y == 0) || (loc.scale.z == 0) ) return 0; return 1; } catch (e) {console.error("failsed with error="+e); return 0;} } /////////////////////////// ///call of the function: $scope.compJSON_loc_Data = new Object(); var target="model-1" check_comp_at_level_recursively(target,'/0',$scope.compJSON_loc_Data) ...     The code for the breadth first search uses also the parameters for maximum depth (max_asm_depth) and the maximum possible branches (max_numb_comp_asm)  - so means it have the mentioned  restriction. If we set a value which is large this will increase the time until the search is completed so therefore depending of the particular assembly we need to set the both parameter properly ( we need to be able to scan the whole assembly but to minimize the search time) For different assemblies the first deep or first breadth could lead to better results. For example, for flat assembly structures the better approach will be to use the first breadth algorithm  But actually the performance is not so important here, because the search will be called one time and  then the json list should be saved.  With the current functionality we can read a file (json file ) from the project  upload directory , but it seems that it is  not  possible to save the information to a e.g. json file there (upload folder). To read a json file form the upload folder we can use some code like this:     target='model-1' $http.get('app/resources/Uploaded/' + jsonFile).success(function(data, status, headers, config) { $scope.compJSON_mod=data; // in this case the data is the received json object angular.forEach(data , function(color, path_id){ $scope.compJSON_Data[path_id] =position; console.log("target="+target+" --> $scope.compJSON_Data["+path_id+"] = "+$scope.compJSON_Data[path_id]); });//end of the error function ////////// finish for each path_id }) .error(function(data, status, headers, config) {console.log("problem in the http will create a new ");   When we want to save data  (the generated json list) we need to use another workaround - we can use a thingworx repository. Following functions /events could be used to save and receive an json object to/from a twx repository:   // the methods SaveJSON and LoadJSON // for the repository object should have //run permision for es-public-access user ////////////////////////////////////////////////////////////// $scope.SaveJsonToTwxRepository = function(path, content) { $scope.$applyAsync(function() { $rootScope.$broadcast('app.mdl.CAD-Files-Repository.svc.SaveJSON', {"content": content, "path":path} );} ,500 ); }; ////////////////////////////////////////////////////////////// $scope.GetJsonFromTwxRepository = function(path) { $scope.$applyAsync(function() { $rootScope.$broadcast('app.mdl.CAD-Files-Repository.svc.LoadJSON', {"path":path} );} ,500 ); $scope.app.speak("after call of GetJsonFromTwxRepository") //in the modelloaded listener register // LoadJSON-complete event -> to laod the data into session rootScope.$on('modelLoaded', function() { //// $scope.$root.$on('LoadJSON-complete', function(event, args) { console.log("LoadJSON-complete event"); $scope.COMP_LOCs=args.data console.log(JSON.stringify( $scope.COMP_LOCs)) }); /// });   In  the code above I use the 'modelloaded' listener to register LoadJSON-complete event . Because the service is called asyncronously- we need this event to load the data into session when it is received from thingworx. Here in this example the repository object is named "CAD-Files-Repository" The Thingworx services should have run permission and it is required to be added in the external data panel :     So when we start the project in PREVIEW mode we can call the search for the assembly structure and save it then  to thingworx. In Vuforia View mode   then we can receive the previously saved json object from thingworx. To check the current mode (if Preview or End Device)  we can use    if(twx.app.isPreview() == true) ...   it will  check if the current mode is preview mode or Vuforia View on the end device - here an example of the workflow:   if(twx.app.isPreview() == true) {// preview mode //calling breadth first - test check_comp_at_level_recursively(target+'-',0,$scope.compJSON_POS_Data) //console.warn($scope.compJSON_POS_Data) //calling deep first a second test and generating a data - locations check_comp_deep_first_recursively(target,'/0',$scope.compJSON_loc_Data) console.log("========================================") console.log("$scope.compJSON_POS_Data ->breadth first") console.log("========================================") console.log(JSON.stringify($scope.compJSON_POS_Data)) console.log("========================================") console.log("") console.log("") console.log("========================================") console.log("$scope.compJSON_loc_Data ->deep first") console.log("========================================") console.log(JSON.stringify($scope.compJSON_loc_Data)) $scope.SaveJsonToTwxRepository('/CADFiles/json_lists/compJSON_loc_Data.json',$scope.compJSON_loc_Data) $scope.GetJsonFromTwxRepository('/CADFiles/json_lists/compJSON_loc_Data.json') console.log("========================================") console.log("") } else { //here is the part on mobile device $scope.GetJsonFromTwxRepository('/CADFiles/json_lists/compJSON_loc_Data.json') }   I tested all points of  the described techniques above in a  test project which I want to provide here as zip file for the HoloLens (hideComponetsHoloLens .zip):     So to be able to test it you need to create in Thingworx a repository thing - means a thing which uses  the thing template "FileRepositroy" with the name "CAD-Files-Repository" and create a folder there "/CADFiles/json_lists/" (if you use another name and another folder (e.g. "/" no folder - the root repository folder) you have to adapt the javaScript code:   ... /CADFiles/json_lists/compJSON_loc_Data.json ... app.mdl.CAD-Files-Repository.svc.SaveJSON' ... app.mdl.CAD-Files-Repository.svc.LoadJSON'    
View full tip
You can get the view count for all public experiences by using the below REST API call.   GET <your ES URL>/compliance/views   This will return a JSON object with a views and billables field where: views = the download number of publicly accessible projects & billables = how many downloads are counted towards billable tokens   You can also specify the startDate and endDate in your request. These parameters can be defined by a UTC date string, JSON date string, or time in milliseconds since a specified date.   
View full tip
Often issues connecting to the Thingworx Experience Service from Thingworx Studio are related to more complex proxy configurations. One such configuration uses a .pac script that dynamically resolves the proxy based on the requested URL. Thingworx Studio has the ability to configure a proxy server but you have to explicitly specify one server URL, you can't replicate the settings in your internet connections when these use a .pac script. No worries - there is a workaround - Proxy-Vole at your rescue!   You can find Proxy Vole (https://proxy-vole.kenai.com/ ) on the Internet. It is a little java-based application that can be used to auto-resolve your proxy configuration. It has a command line and a UI frontend. The documentation is somewhat unstructured - for the test you only need a few of the steps: Download the Proxy Vole jar-with-dependencies Start the proxy vole application in a command shell using the following command: java -cp ./proxy-vole-1.0.1-jar-with-dependencies.jar com.github.markusbernhardt.proxy.ui.ProxyTester Enter the following in the dialog box: 4. Specify the resulting proxy URL in Thingworx Studio: That's it! If you still have issues, please post the log on the Developer Forum site.  
View full tip
With various Augmented Reality applications in PTC's product portfolio the technical aspects and use cases could leave you with some questions. Did you know that we do not only have a full blown Augmented Reality SDK but offer also the possibility for a easy to use integration with live sensor data coming in via ThingWorx?   This blog post hopefully clarifies some of the questions around what can be done with Vuforia SDK and Vuforia Studio.   Welcome to the real world   In the real world, or the "real reality" (sounds weird, but it's basically what you can see with your own eyes - no augmentation involved) there are various objects. These might look the same - or not. Just take the following example... that's what we perceive when looking at things around us:     These objects are recognized​ via shapes, contrasts (black & white) and whatever defines the actual form. ​Vuforia SDK ​is able to recognize those objects via it's built-in object recognition capabilities. However, there might be limits - depending on the use cases...   While buildings could be distinguished by their form, playing cards could be distinguished via their suits and nominations. The machines however, they all look the same, they probably all ​are​ the same.   Combining the real world with a virtual world   "Augmented Reality" will allow to enhance this physical object with virtual properties, e.g. overlay its CAD-Model or overlay some animations for a better gaming experience. Check out this video for the Genesis Augmented Reality Trading Card Game example.   Object Recognition allows to put actual names to what the (digital) eye can see:     Once the object is recognized and identified all kinds of virtual attributes can be added. Vuforia SDK allows to do this with e.g. Unity.   As all of the machines are basically the same... they look the same, come from the same manufacturer and behave the same, ​identification​ can only be done via a manual effort, e.g. selecting the actual machine manually within an app (via a menu etc.). This manual selection process will then map a generic form and shape of the machine to the actual physical machine you can see and touch just in front of you.   In an app this might be necessary if you can recognize the generic form of a playing card but forgot to implement the suit and nominations. In that case, either extend the recognition part, or choose a drop-down list when the card is identified to choose the actual​ card in front of you.   How do ThingMarks fit in?   Using the functionality of Vuforia SDK, Vuforia Studio combines the power of Vuforia (AR) with the power of ThingWorx (live sensor data / object information). In an industry environment I could select the correct machine I'm looking at. However, what's the identifier? It is probably written somewhere on the back of the machine with lots of other information, so I don't really know what to look for. Therefore I could be looking at any machine, but without the identifier I can not retrieve information for ​my​ machine.   Vuforia Studio uses ThingMarks​. They work similar to a QR-Code and allow for direct identification of individual machines. So instead of choosing manually in the app, the ThingMark automatically chooses the correct object and relates that ID to a Thing Entity in ThingWorx.     In above image, the ThingMark allows to a) identify we're looking at a machine and b) are looking at the specific machine A03 It's basic point and shoot. Scan the ThingMark with your mobile device and you're directly taken to this particular experience for this particular machine.   In this case, it's not the machine that defines our object's properties and shapes and contrasts and sizes etc. In this case, it's the ThingMark that's the object being recognized. That's quite a difference.   So now, in an additional step, we're using the power of Vuforia to identify individual machines by a ThingMark. Recognition is driven by the ThingMark's shape which includes an encoded object ID (the QR-code looking pattern).   How does ThingWorx fit in?   After recognizing the machine, ThingWorx studio provides the link between this specific object (or its instance) and the ThingWorx Thing Entity we've defined in Vuforia Studio.   This allows to retrieve individual properties, services, events, alerts etc. directly via ThingWorx. Those values are unique per object, not per shape!   So this allows to directly look at temperature, level and failure-indicator for the actual machine in front of us:     Bridging the gap   Vuforia Studio​ is used to bridge the gap between ​Vuforia ​and its Augmented Reality capabilites as well as ThingWorx ​and its Internet of Things (IoT) capabilities. Vuforia Studio uses parts of both applications, adds own functionality and defines its own product category: Connected Augmented Reality​     There are quite some components involved in this:     This can be split into two processes: developing and experiencing   Development   Create a new experience in VuforiaStudio, map the experience to the ThingMark ID, map the experience to a Thing Entity in ThingWorx. Publish the experience to the Experience Server. Done.   Experience   Scan the ThingMark with the Vuforia View app. Vuforia View will utilize Vuforia to recognize the ThingMark Vuforia View will load the data and the model(s) for this ThingMark from the Experience Server Vuforia View will automatically receive and update the experience you're viewing with live data from the ThingWorx platform Enjoy.   Resources   There are quite some videos, tutorial, best practices etc. available on how to develop and experience the world of Vuforia Studio. Check out ThingWorx Studio Resources: Getting Started Guides, Tutorials, Troubleshooting for the Article Hub and quite a lot of good stuff!   More information   To get more information visit the product pages at https://www.vuforia.com https://trial.studio.vuforia.com/   If you're looking for help, these might be of interest:   https://developer.vuforia.com/support for Vuforia SDK https://community.ptc.com/t5/Studio/bd-p/studio for Vuforia Studio https://community.ptc.com/t5/ThingWorx-Developers/bd-p/twxdevs for ThingWorx https://support.ptc.com/    What's next?   Get involved, create your own experience. It's fun, it's quite easy and well... it looks good, too!  
View full tip
With release 1.9.1, pilot and free trial participants can auto-configure Vuforia Studio to make it easier to get up and running quickly.  The auto-configure process does the following:​ Configures the sample projects included with your Vuforia Studio installation so that when you publish those projects they are published to your experience service and can be viewed in Vuforia View using one of your ThingMarks Retrieves the Experience Service (ES) URL - can find at Project -> Configuration -> Info section. We are no longer sending the ES url through welcome email. Downloads your ThingMarks and makes them available on the My ThingMarks page inside Vuforia Studio so that you can view your ThingMarks and print them out In order to complete the auto-configuration process, users are first required to authenticate using their PTC Account credentials.  For participants in the Vuforia Studio Free Trial, this does not introduce any confusion since they use their PTC Account credentials for everything: accessing the Studio Portal, publishing experiences from Vuforia Studio, downloading experiences to Vuforia View and working in ThingWorx Composer.   However, for participants in the Vuforia Studio Pilot Program, this may introduce some confusion.  Unlike free trial participants, pilot participants have two sets of credentials: PTC Account credentials used to access the Studio Portal and Auto-Configure Vuforia Studio Experience Service credentials provided in their Pilot Program Welcome Email that are used to publish experiences from Vuforia Studio, view experiences in Vuforia View and access ThingWorx Composer The auto-configuration process requires users to authenticate using their PTC Account credentials.  Since the auto-configuration process occurs inside Vuforia Studio and pilot participants do not normally use their PTC Account credentials inside Vuforia Studio, this may cause some confusion.   Note   The users that received access to an experience service instance before February 17, 2017 is a participant in the pilot program Any user that received access to an experience service on or after February 17, 2017 is a participant in the free trial.  
View full tip
If the experience project exists in Vuforia Studio Unpublish the project by hovering over the project and clicking the unpublish project Experiences icon . This action removes Experiences from the Experience Service. If the experience project does not exist in Vuforia Studio Using CURL Command Curl -u <username>:<password> -H "Content-Type: Application/JSON" -X "DELETE" https://<your-domain-name>/ExperienceService/content/projects/<projectname> username: Experience Service username password: Experience Service password your-domain-name: Experience Service domain projectname: Experience project name to be deleted Using REST call from Postman Select query method as 'DELETE' Enter the URL as https://​<your-domain-name>/ExperienceService/content/projects/<project-name> your-domain-name: Experience Service domain projectname: Experience project name to be deleted In Authorization menu Choose Authorization type as 'Basic Auth'. Add the user credentials and update request.  
View full tip
Announcements