Switch AutoDesk Forge Viewer Environment from Local to AutodeskProduction - autodesk-forge

We are using autodesk-forge viewer to show 3D Models, We have a requirement as to load the models from the local environment and the auto desk cloud environment
Previously we are using only local environment, Viewer initialized with the "env":"Local"
let initOptions = {
'env': 'Local'
'language': 'en'
}
Autodesk.Viewing.Initializer(initOptions)
Now we need to switch between the Local Environment and AutodeskProduction, is that Possible?
To achieve switching, what cloud i have to do.
Have to re-Initialize the Viewer with new env?
Please help me...

Simply terminate/finish the previous/existing Viewer and re-initialize as you normally would all over again:
Autodesk.Viewing.Initializer( {'env' : 'Local', getAccessToken:
//...
}, () =>{
// viewer = ...
})
})
//...
viewer.finish()
Autodesk.Viewing.Initializer( {'env' : 'AutodeskProduction', getAccessToken:
//...
}, () =>{
// viewer = ...
})
})

Related

How to mock Forge Viewer in React Unit Tests

we're currently trying to unit / integration test our react application, which uses the forge viewer cdn script.
the to be tested code assumes that Autodesk is available on the window object, which is the case in the application (via script tags), but not in the context of testing. this leads to errors like these:
Test suite failed to run
ReferenceError: Autodesk is not defined
> 1 | export class ExtendedGuiViewer3D extends Autodesk.Viewing.GuiViewer3D {
according to the license comments, the forge viewer script only allows using it through the Autodesk servers, so I cant just download it, and require the file locally.
has anyone successfully tested components that use the forge viewer scripts?
Intro
Disclaimer, I've only recently been experimenting with "Reactifying" the Autodesk Forge Viewer!
I currently believe the 'correct' way to consume the forge viewer css / js is to pull code from the Autodesk hosted cdn. The types are still available on npm though.
For example, the endpoints for v7.52.0:
js https://developer.api.autodesk.com/modelderivative/v2/viewers/7.52.0/viewer3D.min.js
css https://developer.api.autodesk.com/modelderivative/v2/viewers/7.52.0/style.min.css
Steps
1. Add type information from npm
Firstly, if you are using typescript, you can still install the viewer types from npm with:
yarn add -D #types/forge-viewer (check/add specific version to match the version of the script from the cdn - you can verify in your package.json)
2. Sample ViewingContext.tsx
In your React code you may wish to create a React Context to manage the the script downloading for you. This example is based on next.js:
import React, { PropsWithChildren, useEffect, useState } from "react";
import Script from "next/script";
export const ViewingContext = React.createContext({
initialized: false,
});
export interface ViewingContextProps {
options: Autodesk.Viewing.InitializerOptions;
}
// Place a single global ViewingContextProvider component around the common root of all your Autodesk.Viewing (LMV) components.
// https://forge.autodesk.com/en/docs/viewer/v7/developers_guide/overview/
export const ViewingContextProvider = ({
options,
children,
}: PropsWithChildren<ViewingContextProps>): JSX.Element => {
const [scriptLoaded, setScriptLoaded] = useState(
typeof window !== "undefined" &&
window.Autodesk?.Viewing?.Initializer !== undefined
);
const [initialized, setInitialized] = useState(false);
useEffect(() => {
if (scriptLoaded && !initialized) {
Autodesk.Viewing.Initializer(options, () => setInitialized(true));
}
}, [options, initialized, scriptLoaded]);
return (
<ViewingContext.Provider value={{ initialized }}>
<link
rel="stylesheet"
href="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.52.0/style.min.css"
type="text/css"
/>
<Script
async
src="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.52.0/viewer3D.min.js"
onLoad={(): void => setScriptLoaded(true)}
/>
{children}
</ViewingContext.Provider>
);
};
3. Sample Viewer.tsx Component
Only mount this component as a child of the ViewingContext. You can also modify/replace this component with the ExtendedGuiViewer3D you mentioned.
import React, { useContext, useEffect, useRef } from "react";
import { ViewingContext } from "./ViewingContext";
export interface ViewerProps {
config?: Autodesk.Viewing.Viewer3DConfig;
onLoaded?: (viewer: Autodesk.Viewing.GuiViewer3D) => void;
onError?: (code: number) => void;
}
// Thin wrapper around https://forge.autodesk.com/en/docs/viewer/v7/developers_guide/overview/
// Add your own imperative hook code after GuiViewer object is loaded with the onLoaded callback.
// Place inside a relative layout div.
export const Viewer = ({
config,
onLoaded,
onError,
}: ViewerProps): JSX.Element => {
const { initialized: viewingContextInitialized } = useContext(ViewingContext);
const viewerDivRef = useRef<HTMLDivElement>(null);
const viewer = useRef<Autodesk.Viewing.GuiViewer3D>();
// Viewer imperative loading code
useEffect(() => {
if (viewingContextInitialized && !viewer.current && viewerDivRef.current) {
viewer.current = new Autodesk.Viewing.GuiViewer3D(
viewerDivRef.current,
config
);
const startedCode = viewer.current.start();
if (startedCode > 0) {
onError && onError(startedCode);
return;
}
if (onLoaded) onLoaded(viewer.current);
}
}, [config, onLoaded, onError, viewingContextInitialized]);
// Viewer destructor
useEffect(() => {
return (): void => {
if (viewer.current) {
viewer.current.finish();
}
};
}, []);
return (
<div
style={{
position: "absolute",
width: "100%",
height: "100%",
overflow: "hidden",
}}
>
<div
style={{
margin: 0,
width: "100%",
height: "100%",
}}
ref={viewerDivRef}
/>
</div>
);
};
Hope this answers your question!
so after months of fighting, these are the two options I've come up with so far.
option 1: dirty mock everything
there's a few #ts-ignore, because I dont want to mock out the whole package. i'll only mock the parts my application uses.
you could to type assertion like global.THREE = {...} as unknown as typeof THREE too. whatever floats your boat.
// setupTests.ts
// NOP_VIEWER global is not part of the #types declaration, so we need to tell typescript that there will be a global
declare global {
namespace NodeJS {
interface Global {
NOP_VIEWER: ExtendedGuiViewer3DTypes;
}
}
}
global.Autodesk = {
// #ts-ignore
Viewing: {
GuiViewer3D: jest.fn(),
Extension: jest.fn(),
ToolInterface: jest.fn(),
},
};
// #ts-ignore
global.THREE = {
Color: jest.fn(),
Vector4: jest.fn(),
};
global.NOP_VIEWER = {
disableSelection: jest.fn(),
resize: jest.fn(),
// #ts-ignore
model: {
getExternalIdMapping: (successCallback: any, _: any) => {
successCallback({ 'test-guid': 1 });
},
},
clearThemingColors: jest.fn(),
setThemingColor: jest.fn(),
isLoadDone: () => true,
isolate: jest.fn(),
};
option 2: download and require
As Autodesk Developer Adam Nagy pointed out, you probably wont get sent to jail, if you download the script file and require it locally for your tests only. (note that this is just a "probably")
keep in mind that even if you require the file, you still have to mock NOP_VIEWER as this global is only available after initializing the viewer (which you dont want to do in your tests)
// setupTests.ts
// replace the mocks of `Autodesk` and `THREE` with this require.
require('./vendors/Autodesk/viewer3D.min');
in my tests i can then use the jest spies on NOP_VIEWER
expect(NOP_VIEWER.clearThemingColors).toHaveBeenCalled();

Why I got error when try to load gltTF using Autodesk Forge?

I tried to load the model locally, but came across this problem. I'm using react here.
viewer.start();
viewer.setTheme("light-theme");
viewer.loadExtension("Autodesk.glTF").then(() => {
viewer.loadModel("./2floor.gltf");
});
});
This is the error I got :
gltf forge
And can I load 2 model in one viewer ?
Load from model derivative
Load glTF locally
Here's all the code that's needed for the client side:
Autodesk.Viewing.Initializer({ accessToken: '' }, async function () { const viewer = new Autodesk.Viewing.GuiViewer3D(document.getElementById('preview'));
viewer.start();
viewer.setTheme('light-theme');
await viewer.loadExtension('Autodesk.glTF');
//viewer.loadModel('models/rac_basic_sample_project/gltf/model.gltf');
viewer.loadModel('models/Sponza/glTF/Sponza.gltf');
});
Please follow https://forge.autodesk.com/blog/gltf-20-support-forge-viewer for the solution.

Autodesk forge configurator inventor add new model authorization error

Hello we are using Autodesk forge configurator inventor And we created our own js function. Below, you will find the logic we want to import to the application. On it's own, we make it work, but with forge configurator inventor, we get the authentication error. We tried a lot of different options but failed to make it load the document.
Error is --> GET 401 (Unauthorized)
import repo from '../../Repository';
var options = repo.hasAccessToken() ?
{ accessToken: repo.getAccessToken() } :
{ env: 'Local' };
var documentId = 'urn:MyUrn';
Autodesk.Viewing.Document.load(
documentId, (doc) => {
console.log("test");
let items = doc.getRoot().search(
{
type: "geometry",
role: "3d",
},
true
);
if (items.length === 0) {
console.error("Document contains no viewables.");
return;
}
viewer.loadDocumentNode(doc, items[0], {
keepCurrentModels: true,
//placementTransform: tr,
})
.then(function (model2) {
secondModel = model2;
let tr = secondModel.getPlacementTransform();
let _selecterTr = _selectedModel.getPlacementTransform();
console.log(_selecterTr);
tr = _selecterTr;
secondModel.setPlacementTransform(tr);
viewer.impl.invalidate(true, true, true);
});
}, onDocumentLoadFailure,options);
function onDocumentLoadFailure() {
console.error('Failed fetching Forge manifest');
}
The main issue is that repo does not provide an access token because it was never needed. The models' SVF contents are always loaded directly from the server - instead of relying on the Model Derivative service to provide them.
You just have to provide an endpoint (e.g. /api/viewables/token) on the server-side by adding a Controller that could be called from the client-side in order to get an access token with viewables:read scope.
Detailed information here:
https://forge.autodesk.com/blog/drag-and-drop-design-automation-inventor-sample

SVF2 Public Beta - Models are not translated to SVF2

i just tried the SVF2 public beta.
I tried the translation on four models, but none of them worked. They are still in svf format and my cloud credits have been deducted.
As explained in the documentation, i just changed the output.formats.type to "svf2".
const job = {
input,
output: {
//force: true,
formats: [
{
views: ["2d", "3d"],
type: "svf2",
},
],
},
},
I am using node.js sdk version:
"forge-apis": "^0.7.3",
Viewer Version 7.29 with the init options:
const viewerEnv = await this.initialize({
// useConsolidation: true,
// env: dbModel.env,
// edgeRendering: true,
// lightPreset: "Boardwalk",
// envMapBackground: true,
// getAccessToken: function(onGetAccessToken) {
// onGetAccessToken(accessToken, expireTimeSeconds)
// }
env: "MD20ProdUS",
api: "D3S",
});
I checked the output-format with:
For all four translations, the translation-progress callback stopped between 90-98%. I never reached the 100% callback, but all models are translated.
we have not updated the node.js SDK yet for SVF2, so I suspect even with those changes, it may be reverting to SVF.

Is there any way to output logs using log4js on Cloud Functions?

I'm using GCP's cloud function. What I want to achieve is to output logs by log4js.
I know and have tried that using console.xxx() works well.
Environment:
- Google Cloud Functions
- Functions-framework
- nodejs10 as Runtime
logger.js
const log4js = require('log4js');
const logger = exports = module.exports = {};
log4js.configure({
appenders: {
out: { type: 'console' },
trail: {
type: 'dateFile',
filename: './logs/trail',
pattern: '-yyyy-MMdd-hh.log',
alwaysIncludePattern: true
}
},
categories: {
default: { appenders: [ 'out' ], level: 'info' },
trail: { appenders: [ 'trail' ], level: 'DEBUG' }
}
})
logger.trail = log4js.getLogger('trail')
index.js
const { logger } = require('./logger');
exports.spTest = (pubSubEvent, context) => {
console.log('console.log should appear'); // => properly logged
logger.trail.error('logger should appear'); => doesn't show up
};
Thanks in advance!
According to the oficial documentation link:
Cloud Logging is part of the Google Cloud's operations suite of
products in Google Cloud. It includes storage for logs, a user
interface called the Logs Viewer, and an API to manage logs
programmatically.
Also Custom StackDriver logs
Cloud Functions logs are backed by StackDriver Logging. You can use
the StackDriver Logging library for Node.js to log events with
structured data, enabling easier analysis and monitoring.
const { Logging } = require('#google-cloud/logging');
// ...
// Instantiate the StackDriver Logging SDK. The project ID will
// be automatically inferred from the Cloud Functions environment.
const logging = new Logging();
const log = logging.log('my-custom-log-name');
// This metadata is attached to each log entry. This specifies a fake
// Cloud Function called 'Custom Metrics' in order to make your custom
// log entries appear in the Cloud Functions logs viewer.
const METADATA = {
resource: {
type: 'cloud_function',
labels: {
function_name: 'CustomMetrics',
region: 'us-central1'
}
}
};
// ...
// Data to write to the log. This can be a JSON object with any properties
// of the event you want to record.
const data = {
event: 'my-event',
value: 'foo-bar-baz',
// Optional 'message' property will show up in the Firebase
// console and other human-readable logging surfaces
message: 'my-event: foo-bar-baz'
};
// Write to the log. The log.write() call returns a Promise if you want to
// make sure that the log was written successfully.
const entry = log.entry(METADATA, data);
log.write(entry);index.js
Therefore, I do not think you can use log4js on Cloud Functions.