Autodesk Forge Design Automation/Model Derivative API - Viewer caching svf file - javascript

I'm using the Design Automation API to generate a model, i then wan't to load the viewable into the viewer, im using v6. When i do this the first time it works fine but the viewer will then continue to always load the same .svf file, i've tried deleting the manifest, i'm passing true to to the x-ads-force parameter and i've included the If-Modified-Since header when initializing the viewer...
im using the .net SDK
DerivativesAPI.Translate(Job, True)
Forge Javascript....
var viewer;
function showModel(AccessToken, urn) {
var options = {
env: 'AutodeskProduction',
accessToken: AccessToken,
api: 'derivativeV2' // for models uploaded to EMEA change this option to 'derivativeV2_EU'
};
var documentId = 'urn:' + urn;
Autodesk.Viewing.endpoint.HTTP_REQUEST_HEADERS['If-Modified-Since'] = 'Sat, 29 Oct 1994 19:43:31 GMT';
Autodesk.Viewing.Initializer(options, function onInitialized() {
Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
});
}
function onDocumentLoadSuccess(doc) {
// A document contains references to 3D and 2D geometries.
var geometries = doc.getRoot().search({ 'type': 'geometry' });
if (geometries.length === 0) {
console.error('Document contains no geometries.');
return;
}
// Choose any of the avialable geometries
var initGeom = geometries[0];
// Create Viewer instance
var viewerDiv = document.getElementById('MyViewerDiv');
var config = {
extensions: initGeom.extensions() || []
};
viewer = new Autodesk.Viewing.Private.GuiViewer3D(viewerDiv, config);
// Load the chosen geometry
var svfUrl = doc.getViewablePath(initGeom);
var modelOptions = {
sharedPropertyDbPath: doc.getPropertyDbPath()
};
viewer.start(svfUrl, modelOptions, onLoadModelSuccess, onLoadModelError);
}
function onDocumentLoadFailure(viewerErrorCode) {
console.error('onDocumentLoadFailure() - errorCode:' + viewerErrorCode);
}
function onLoadModelSuccess(model) {
console.log('onLoadModelSuccess()!');
console.log('Validate model loaded: ' + (viewer.model === model));
console.log(model);
}
function onLoadModelError(viewerErrorCode) {
console.error('onLoadModelError() - errorCode:' + viewerErrorCode);
}

Please change this line to load other SVF:
// Choose any of the avialable geometries
var initGeom = geometries[0];
To Switch on runtime, you can use the Autodesk.DocumentBrowser
var config = {
extensions: ['Autodesk.DocumentBrowser'].concat( initGeom.extensions() )
};
viewer = new Autodesk.Viewing.Private.GuiViewer3D(viewerDiv, config);
Lastly, please be aware of the Publish Settings of the RVT model, Model Derivative API will export view sets chosen in the Publish Settings only. If there is no predefined view sets of the Publish Settings, it will use the default 3D view to export by default.

Its because i was running in Debug mode from Visual Studio, switching to release mode solved the issue

Related

Copying Files based on a custom column value between document libraries in SharePoint using javascript

I am new to Javascript and currently working on a task where I need to copy files based on a custom column name "PID" from One Document Library to the other.
I was able to get the below code to work which copies all the files
$scope.copyFiles=function()
{
var sourceLib = '/sites/Protocol/ProtocolDocument';
var destLib = '/sites/Protocol/FinalProtocolDocuments';
var context = new SP.ClientContext.get_current();
var web = context.get_web().get_lists();
var folderSrc = web.getFolderByServerRelativeUrl(sourceLib);
//var cq = "<Query><Where><Eq><FieldRef Name="ProtocolID" LookupId="TRUE"/><Value Type="Text">' + 466 + '</Value></Eq></Where></Query>"
context.load(folderSrc,'Files');
context.executeQueryAsync(
function() {
console.log("Got the source folder right here!");
var files = folderSrc.get_files();
var e = files.getEnumerator();
var dest = [];
while (e.moveNext()) {
var file = e.get_current();
var destLibUrl = destLib + "/" + file.get_name();
dest.push(destLibUrl); //delete this when we're happy we got the file paths right
file.copyTo(destLibUrl, true);
}
console.log(dest); //delete this when we're happy we got the file paths right
context.executeQueryAsync(function() { console.log("Files moved successfully!");}, function(sender, args) {console.log("error: ") + args.get_message()});
},
function(sender, args){console.log("Sorry, something messed up: " + args.get_message());}
);
}
I did some research online to get the Filenames based on a custom column value with no luck
Also tried to use CAML , however not sure how to use it in the code.
Would appreciate if anyone could help me get the filenames from a Document Library based on custom column name "PID" so that only selected/filtered files are moved to the destination Library.
UPDATED CODE
$scope.copyFiles=function()
{
var sourceLib = '/sites/Protocol/ProtocolDocument';
var destLib = '/sites/Protocol/FinalProtocolDocuments';
PID='466'
var context = new SP.ClientContext();
var list = context.get_web().get_lists().getByTitle("ProtocolDocument");
var cq = new SP.CamlQuery();
cq.set_viewXml("<View><Query>" +
"<Where>" +
"<Eq><FieldRef Name=\"ProtocolID\"/><Value Type=\"Text\">PID</Value></Eq>" +
"</Where>" +
"</Query>" +
"</View>");
var items = list.getItems(cq);
context.load(items);
context.executeQueryAsync(
function() {
var e = items.getEnumerator();
var dest = [];
while (e.moveNext())
{
var file = e.get_current();
var destLibUrl = destLib + "/" + file.get_name();
dest.push(destLibUrl); //delete this when we're happy we got the file paths right
file.copyTo(destLibUrl, true);
}
console.log(dest); //delete this when we're happy we got the file paths right
context.executeQueryAsync(function() { console.log("Files moved successfully!");}, function(sender, args) {console.log("error: ") + args.get_message()});
},
function(sender, args){console.log("Sorry, something messed up: " + args.get_message());}
);
}
});
Here is my attempt. I tested it successfully on SharePoint 2013, and it copies files from one document library to another, but only the files with a lookup field set to a specific value. I have included a short summary, but if you only want the code then jump down to Now to the actual code.
Please note that I have used syntax not supported by Internet Explorer, so let me know if you need to support that browser. I also believe that a function or method should only do one thing, so I split the functionality into three separate functions. This also helps keep the code clean and easier to read.
To summarize: The first function, findAndCopyFiles(), will run once and find all the files with the lookup field value you set. It will then send each file to the loadAndCopyFile() function to load the file object. This function will run once for every file that should be copied. When the file object is loaded, it is sent to the third and final function, copyFileTo(), that will actually copy the file to the destination document library. This function will also run once per file.
Now to the actual code
First you need to set these configuration variables according to your setup:
const destinationLibraryPath = 'The path to your destination document library';
const sourceLibraryName = 'The name (not path) of your source document library';
const lookupField = 'The name of your lookup field';
const lookupValue = 'The value your lookup field should equal for files to be copied';
findAndCopyFiles()
This function is responsible for finding all the files in the source document library with the lookup field set to the value of lookupValue. We use what is known as a CAML query to filter the files. You can filter on all available fields and columns, not only lookup fields.
const findAndCopyFiles = () => {
const clientContext = SP.ClientContext.get_current();
const sourceList = clientContext.get_web().get_lists().getByTitle(sourceLibraryName);
const camlQuery = new SP.CamlQuery();
const whereQuery = `<Eq><FieldRef Name="${lookupField}"/><Value Type="Text">${lookupValue}</Value></Eq>`;
camlQuery.set_viewXml(`<View><Query><Where>${whereQuery}</Where></Query></View>`);
const sourceListItems = sourceList.getItems(camlQuery);
clientContext.load(sourceListItems);
clientContext.executeQueryAsync(
() => {
const filesEnumerator = sourceListItems.getEnumerator();
while (filesEnumerator.moveNext()) {
loadAndCopyFile(filesEnumerator.get_current(), clientContext);
}
},
(_sender, args) => {
console.log(args.get_message());
}
);
}
When the query executes, we use the getEnumerator() method to iterate through all the files returned by the query, in other words all the files that will be copied.
loadAndCopyFile()
After finding all the relevant files, we send each file to the next function to continue our process. This function will load the file object (as in the actual file) and construct the destination URL using the path to the destination document library and the filename of the file.
const loadAndCopyFile = (file, clientContext) => {
const fileRef = file.get_file();
clientContext.load(fileRef);
clientContext.executeQueryAsync(
() => {
const destinationUrl = `${destinationLibraryPath}/${fileRef.get_name()}`;
copyFileTo(fileRef, destinationUrl, clientContext);
},
(_sender, args) => {
console.log(args.get_message());
}
);
}
copyFileTo()
The final function is responsible for actually copying the file to the destination document library. It is quite simple, and looks like this:
const copyFileTo = (file, destinationUrl, clientContext) => {
file.copyTo(destinationUrl, true);
clientContext.executeQueryAsync(
() => {
console.log(`File copied to ${destinationUrl}!`);
},
(_sender, args) => {
console.log(args.get_message());
}
);
}
Putting it all together
And finally, we execute the findAndCopyFiles() function when all the required libraries are ready:
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', () => {
findAndCopyFiles();
});
Disclaimer: I wrote this post on another computer than the one where I tested the code, so if something does not work it may be because of a simple syntax error. In that case, add a comment and let me know!

forge autodesk viewer api , onDocumentLoadFailure() - errorCode:4

i want to use the autodesk's viewer in my application so i used the forge ph client sdk,i made the 5 steps that are herehttps://forge.autodesk.com/blog/basic-usage-forge-sdk-php everything worked good.
but now, i want to view files in the viewer but it doesn't work i have thies error in my browser's concole :onDocumentLoadFailure() - errorCode:4
function viewObject(access,urn,divId){
var viewer;
var viewerDivId;
var options = {
env: 'AutodeskProduction',
accessToken: access
};
function onDocumentLoadSuccess(doc) {
// A document contains references to 3D and 2D viewables.
var viewables = Autodesk.Viewing.Document.getSubItemsWithProperties(doc.getRootItem(), {'type':'geometry'}, true);
if (viewables.length === 0) {
console.error('Document contains no viewables.');
return;
}
// Choose any of the avialble viewables
var initialViewable = viewables[0];
var svfUrl = doc.getViewablePath(initialViewable);
var modelOptions = {
sharedPropertyDbPath: doc.getPropertyDbPath()
};
var viewerDiv = document.getElementById('viewerDivId');
viewer = new Autodesk.Viewing.Private.GuiViewer3D(viewerDiv);
viewer.start(svfUrl, modelOptions, onLoadModelSuccess, onLoadModelError);
}
function onDocumentLoadFailure(viewerErrorCode) {
console.error('onDocumentLoadFailure() - errorCode:' + viewerErrorCode);
}
function onLoadModelSuccess(model) {
console.log('onLoadModelSuccess()!');
console.log('Validate model loaded: ' + (viewer.model === model));
console.log(model);
}
function onLoadModelError(viewerErrorCode) {
console.error('onLoadModelError() - errorCode:' + viewerErrorCode);
}
var documentId = 'urn:'+urn;
viewerDivId = divId;
Autodesk.Viewing.Initializer(options, function onInitialized(){
Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
});
}
</script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1 /jquery.min.js"></script>
<script>
function buttonViewClicked() {
var access = $('#token').val();
var urn = $('#urn').val();
viewObject(access, urn, "MonViewer");
}
</script>
Error code 4 refers to situations where the viewer gets 403 Access Denied when trying to download files from Forge. Make sure that the access token you're providing to the viewer is valid and that it has access to the model you're trying to view.
If you're still having issues, feel free to shoot us an email to forge (dot) help (at) autodesk (dot) com, and include as many details about your project, for example, how does the access token look like, the URN of your model, your Forge app ID, etc.

how to move heavy geocoding to a web-worker?

I have very big list of geo points which I want to translate to coordinates with the geocoder and the best way I think is to move the task to a web worker, otherwise the Firefox times out and never loads the page.
// the main html file:
var myWorker = new Worker('datapointscollection.js');
myWorker.onmessage = function(e) {
document.getElementById('loadingStatus').innerHTML = count + " elements from " + all + "are ready.";
if (count == all) {
myWorker.terminate();
myWorker = undefined;
}
};
myWorker.postMessage([geocodingParams]);
// the worker js file:
self.importScripts("http://js.api.here.com/v3/3.0/mapsjs-core.js");
self.importScripts("http://js.api.here.com/v3/3.0/mapsjs-service.js");
self.importScripts("http://js.api.here.com/v3/3.0/mapsjs-ui.js");
self.importScripts("http://js.api.here.com/v3/3.0/mapsjs-mapevents.js");
self.addEventListener(
'message',
function(e) {
var count = 0;
var all = 0;
// Initialize the platform object:
var platform = new H.service.Platform({
'app_id': 'myappID',
'app_code': 'myappCODE'
});
var geocoder = platform.getGeocodingService();
var onResult = function(result) {};
var findLocations = function(geocodingParams) {
var i=0;
all = geocodingParams.length;
for (i=0; i<geocodingParams.length; i++) {
geocoder.geocode(
geocodingParams[i],
onResult,
function(e){
alert(e);
} );
count = i;
self.postMessage(count, all);
}
};
findLocations(e.data[0]);
},
false);
I tried different approaches, but executing the worker script fails with different errors. The last problem is ReferenceError: document is not defined in mapsjs-core.js:158:623. and after a while another error:
NetworkError: A network error occurred. from datapointscollection.js:1
For huge number of geocodes, you should consider batch geocoding.
Check developer’s guide at developer.here.com
It looks like the files you are importing into your worker depend on a DOM existing. Your web worker doesn't have a DOM, so you will have to use dependencies that don't need a DOM (if it will work in node, it will work without a DOM). Check the documentation for your dependencies to see if there a version that works in node or doesn't need a DOM, and use that version in your web worker. (It might be just the mapsjs-service.js file. see if you can get away with just that).
See also Web Workers API

document generation only works the first time

I'm using openxml in my HTML5 mobile app to generate word documents on the mobile device.
In general openxml works fine and straight forward, but I'm struggling with an annyoing problem.
The document generation only works the first time after I've started the app. This time I can open and view the document. Restart the app means:
- Redeploy from development machine
- Removing the app from the task pane (pushing aside; I assume the app is removed then?)
The second time I get the message the document is corrupted and I'm unable to view the file
UPDATE:
I can't reproduce this behaviour when I'm running the app connected to the remote debugger without having a breakpoint set. Doing it this way I always get a working document.
I doesn't make a difference wether I do any changes on the document or not. Simply open and saving reproduce this error.
After doing some research I've found that structure of the docx.zip file of the working and the corrupt file is the same. They also have the same file length. But in the corrupt docx there are some files I've found some files having a wrong/invalid CRC. See here an example when trying to get a corrupt file out of the zip. Other files are working as expected.
The properties for this file are->
(CRC in a working version is: 44D3906C)
Code for processing the doc-template:
/*
* Process the template
*/
function processTemplate(doc64, callback)
{
"use strict";
console.log("PROCESS TEMPLATE");
var XAttribute = Ltxml.XAttribute;
var XCData = Ltxml.XCData;
var XComment = Ltxml.XComment;
var XContainer = Ltxml.XContainer;
var XDeclaration = Ltxml.XDeclaration;
var XDocument = Ltxml.XDocument;
var XElement = Ltxml.XElement;
var XName = Ltxml.XName;
var XNamespace = Ltxml.XNamespace;
var XNode = Ltxml.XNode;
var XObject = Ltxml.XObject;
var XProcessingInstruction = Ltxml.XProcessingInstruction;
var XText = Ltxml.XText;
var XEntity = Ltxml.XEntity;
var cast = Ltxml.cast;
var castInt = Ltxml.castInt;
var W = openXml.W;
var NN = openXml.NoNamespace;
var wNs = openXml.wNs;
var doc = new openXml.OpenXmlPackage(doc64);
// add a paragraph to the beginning of the document.
var body = doc.mainDocumentPart().getXDocument().root.element(W.body);
var tpl_row = ((doc.mainDocumentPart().getXDocument().descendants(W.tbl)).elementAt(1).descendants(W.tr)).elementAt(2);
var newrow = new XElement(tpl_row);
doc.mainDocumentPart().getXDocument().descendants(W.tbl).elementAt(1).add(newrow);
// callback(doc);
var mod_file = null;
var newfile;
var path;
if (doc != null && doc != undefined ) {
mod_file = doc.saveToBlob();
// Start writing document
path = "Templates";
newfile = "Templates/Bau.docx";
console.log("WRITE TEMPLATE DOCUMENT");
fs.root.getFile("Templates/" + "MyGenerated.docx", {create: true, exclusive: false},
function(fileEntry)
{
fileEntry.createWriter(
function(fileWriter)
{
fileWriter.onwriteend = function(e) {
console.log("TEMPLATE DOCUMENT WRITTEN:"+e.target.length);
};
fileWriter.onerror = function(e) {
console.log("ERROR writing DOCUMENT:" + e.code + ";" + e.message);
};
var blobreader = new FileReader();
blobreader.onloadend = function()
{
fileWriter.write(blobreader.result); // reader.result contains the contents of blob as a typed array
};
blobreader.readAsArrayBuffer(mod_file);
},
null);
}, null);
};
Any ideas what I'm doing wrong?
Thanks for posting about the error. There were some issues with jszip.js that I encountered when I was developing the Open XML SDK for JavaScript.
At the following link, there is a sample javascript app that demonstrates generating a document.
Open XML SDK for JavaScript Demo
In that app you can save multiple DOCXs, one after another, and they are not corrupted.
In order to work on this issue, I need to be able to re-produce locally. Maybe you can take that little working web app and replace parts with your parts until it is generating invalid files?
Cheers, Eric
P.S. I am traveling and have intermittent access to internet. If you can continue the thread on OpenXmlDeveloper.org, then it will help me to answer quicker. :-)
What made it work for me, was changing the way of adding images (Parts) to the document. I was using the type "binary" for adding images to document. I changed this to "base64"
So I changed the source from:
mydoc.addPart( "/word/"+reltarget, openXml.contentTypes.png, "binary", fotodata ); // add Image Part to doc
to:
mydoc.addPart( "/word/"+reltarget, openXml.contentTypes.png, "base64", window.btoa(fotodata) ); // add Image Part to doc

How to properly create a new Producer?

I'm using the driven object model tool CodeFluentEntities in order to deploy a model to a DataBase engine.
I'm thinking about using localStorage database engines (like IndexedDB or Web SQL) in order to store my datas for a web application without server.
I looked into the documentation but it seems to me a little poor... I think I understood the basic principles like the injection points that are Produce() and Terminate() but what about the target directory of the actual production ?
In my case, which is Javascript source code files, how can I specify correctly (in a referenced manner) where to generate them ? And does it have to be in an external project, or could I just fill a directory in an other project (which is the .vsproj of my webapp, per example) ?
Can the documentation integrate a sample of code regarding this aspects, or someone can redirect me to an article fitting my needs ?
The Template approach
According to your needs, I suggest you to use a template instead of developing your custom Producer because of, among others, deployment reasons. Using the template producer (shipped with CodeFluent Entities) you can quickly and easily create complex scripts by taking advantage of the CodeFluent Entities meta model.
This producer is based on CodeFluent Entities' template engine and allow you to generate text files (JavaScript in your case) at production time.
As a reminder, A template is simply a mixture of text blocks and control logic that can generate an output file
This producer takes care of all common operations : update the project (.XXproj) to add your generated files, add missing references, etc.
You can find thereafter an example to generate an IndexDB script file based on a CodeFluent Entities model (demonstration purposes only). Here's the template source file :
[%# reference name="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Core.dll" %]
[%# namespace name="System" %]
[%# namespace name="System.Linq" %]
[%# namespace name="CodeFluent.Model" %]
var context = {};
context.indexedDB = {};
context.indexedDB.db = null;
context.indexedDB.open = function () {
var version = 11;
var request = indexedDB.open([%=Producer.Project.DefaultNamespace%], version);
request.onupgradeneeded = function (e) {
var db = e.target.result;
e.target.transaction.onerror = context.indexedDB.onerror;
[%foreach(Entity entity in Producer.Project.Entities){
string properties = String.Join(", ", entity.Properties.Where(p => !p.IsPersistenceIdentity).Select(p => "\"" + p.Name + "\""));
%]
if (db.objectStoreNames.contains("[%=entity.Name%]")) {
db.deleteObjectStore("[%=entity.Name%]");
}
var store = db.createObjectStore("[%=entity.Name%]",
{ keyPath: "id", autoIncrement: true });
store.createIndex([%=properties %], { unique: false });[%}%]
};
request.onsuccess = function (e) {
context.indexedDB.db = e.target.result;
};
request.onerror = context.indexedDB.onerror;
};
[%foreach(Entity entity in Producer.Project.Entities){
string parameters = String.Join(", ", entity.Properties.Where(p => !p.IsPersistenceIdentity).Select(p => p.Name));%]
context.indexedDB.[%=entity.Name%] = {}
context.indexedDB.[%=entity.Name%].add = function ([%= parameters %]) {
var db = context.indexedDB.db;
var trans = db.transaction(["[%=entity.Name%]"], "readwrite");
var store = trans.objectStore("[%=entity.Name%]");
var request = store.put({
[%
foreach (Property property in entity.Properties.Where(p => !p.IsPersistenceIdentity)) {%]
"[%=property.Name%]": [%=property.Name%], [%}%]
"timeStamp": new Date().getTime()
});
request.onsuccess = function (e) {
console.log(e.value);
};
request.onerror = function (e) {
console.log(e.value);
};
};
context.indexedDB.[%=entity.Name%].delete = function (id) {
var db = context.indexedDB.db;
var trans = db.transaction(["[%=entity.Name%]"], "readwrite");
var store = trans.objectStore("[%=entity.Name%]");
var request = store.delete(id);
request.onsuccess = function (e) {
console.log(e);
};
request.onerror = function (e) {
console.log(e);
};
};
context.indexedDB.[%=entity.Name%].loadAll = function () {
var db = context.indexedDB.db;
var trans = db.transaction(["[%=entity.Name%]"], "readwrite");
var store = trans.objectStore("[%=entity.Name%]");
var keyRange = IDBKeyRange.lowerBound(0);
var cursorRequest = store.openCursor(keyRange);
request.onsuccess = function (e) {
// not implemented
};
request.onerror = function (e) {
console.log(e);
};
};
[%}%]
function init() {
context.indexedDB.open(); // initialize the IndexDB context.
}
window.addEventListener("DOMContentLoaded", init, false);
Then you need to configure your CodeFluent Entities Project by adding the Template Producer and define the template above as the source file.
If you consider the following model :
Just build it to generate the IndexDB script file in the target project (a web application for example) and you'll be able to manipulate the generated API like this :
context.indexedDB.Contact.add("Peter", "Boby")
context.indexedDB.Product.add("Tablet")
context.indexedDB.Product.add("Computer")
context.indexedDB.Contact.delete(1)
context.indexedDB.Product.loadAll()
The custom Producer approach
Nevertheless, if ever you need to target a technology or platform that isn't supported by CodeFluent Entities natively, you may create your own custom producer by implementing the IProducer interface :
public interface IProducer
{
event Producer.OnProductionEventHandler Production;
void Initialize(Project project, Producer producer);
void Produce();
void Terminate();
}
First of all, you need to understand that the CodeFluent Entitie Build engine calls each of your configured producers one by one to generate your code.
Firstly, CodeFluent Entities calls the Initialize method for each producers. It takes as a parameter an instance of the CodeFluent Entities project and the current producer.
Then it calls the Product method following the same process. It's the right place to implement your generation logic.
Finally, you could implement a finalize logic in the Terminate method.
CodeFluent provides some base classes that implement the IProducer interface such as BaseProducer which is located in CodeFluent.Producers.CodeDom assembly that provides behaviors like "add missing references" or "update Visual Studio project (.XXproj).
In addition, here's a blog post that can help you to integrate a custom producer to the modeler.
The Sub-Producer approach
An other approach might be to develop a custom Sub-Producer but, in my opinion, it is not suitable according to your needs.

Categories

Resources