load 2D & 3D forge viewers in single web page - autodesk-forge

I would like to link between elements from the 2D sheet and 3D model, so when I select the element from 2D it should reflect and select (isolate) in the 3D also if I change the color it does the same on both e.g. and the other way around.
so I can use the document browser extensions to open the 2d sheet on 1st viewer and the 3d model on the 2nd viewer:
const firstModel = new Autodesk.Viewing.Private.GuiViewer3D(document.getElementById('MyViewerDiv1'));
const secondModel = new Autodesk.Viewing.Private.GuiViewer3D(document.getElementById('MyViewerDiv2'));
Autodesk.Viewing.Initializer(options1, function() {
viewer1.start();
viewer1.load(...);
});
Autodesk.Viewing.Initializer(options2, function() {
viewer2.start();
viewer2.load(...);
});
if the example above is correct I am still missing how to links both viewers.
I hope someone could help me with this issue

Note that we have a viewer extension that might already give you what you're looking for: https://github.com/Autodesk-Forge/forge-extensions/blob/master/public/extensions/NestedViewerExtension/README.md.
If you want to implement the cross-selection between two viewer instances yourself, you can. Just subscribe to the SELECTION_CHANGED event in one of the viewers, get the selected IDs, and select the same IDs in the other viewer using the usual viewer.select([...]); method.
Btw. regarding your code snippet:
the Autodesk.Viewing.Initializer only needs to be called once per the entire webpage
the Autodesk.Viewing.Private.GuiViewer3D instances should be created after the initializer has done its work

Related

Enabeling the 'perspective with ortho faces' in viewer

I can currently do:
this.viewer.navigation.toOrthographic()
and
this.viewer.navigation.toPerspective()
Is there a way that I could also use the perspective with ortho faces and change the current viewer into that on the go?
I get that there are view_types (https://forge.autodesk.com/en/docs/viewer/v7/reference/globals/VIEW_TYPES/) I could set up on initialize, but i would like to change this option after model load without having to use the view cube.
Thank you all in advance!
If I understood what you are after correctly then it's possible to call shots for viewcube as an extension programmatically (since v7.x and onwards), say for example:
//wait after model is rendered ...
const viewCubeUI = NOP_VIEWER.getExtension("Autodesk.ViewCubeUi")
viewCubeUI.setViewType(Autodesk.Viewing.Private.VIEW_TYPES.PERSPECTIVE_ORTHO_FACES)
See documentation here for details...

how to change a CesiumJS viewer's baselayer url

i am using a CesiumJS instance to display a base map of the earth using a imageryProvider from source A.
var viewer = new Cesium.Viewer('cesiumContainer', imageryProvider:providerA);
Now while using the Viewer I would like to be able to change this map to get images from providerB at a certain event.
I tried:
viewer.scene.imageryLayers.get(0).imageryProvider.url = providerB.url
However that does not seem to work and also feels quite like hack anyway.
I could not find anything in Cesium's documentation .
Is this at all possible without restarting / recreating the viewer instance?
I know that there is a Cesium.BaseLayerPicker (https://cesium.com/docs/cesiumjs-ref-doc/BaseLayerPicker.html)
However I do not see what method this picker calls on "select" )
Thanks a lot.
The BaseLayerPicker widget calls this code when the user selects a new layer.
There's a lot of boilerplate widget management in that block of code, but for your sake, only a couple of the lines are critical. First, the old existing active imagery layer is searched for, and removed:
imageryLayers.remove(layer);
Then, a new imagery provider is constructed and added at index 0, the first position, which is the base imagery layer:
imageryLayers.addImageryProvider(newProviders, 0);
You can directly change the URL of the provider but you should also change appropriate parameters("layers" in case of WMS, "layer", "style", "format", "tileMatrixSetID " ... in case of WMTS) depending on the type of provider(WMS or WMTS).

Mouse click vs viewer.select function selection behave differently in Autodesk Forge multi models viewer

I have been working on multi-model from the last couple of weeks and found that selection of a model object using mouse click vs viewer select function behave differently.
I have two models one architectural and another mechanical. When I select a wall or room on the architectural model using mouse click, Object select with overlay without having any problem but when I try using viewer select function with same object, it hides behind the wall and overlay doesn't work. It is only happening with the architectural model and working fine with the mechanical model.
Please suggest me if I am doing something wrong with multi-model.
To programmatically select components when working with multiple models use viewer.select(dbid, model):
let model = viewer.impl.modelQueue().getModels()[index] or viewer.impl.findModel(modelId);
viewer.select(dbid, model)
And to get selected dbids use viewer.getAggregateSelection (see doc here) the event to subscribe to AGGREGATE_SELECTION_CHANGED_EVENT (doc here) to track selection changes:
If the issue persists can you send some screenshots and your models (links via a sharing service like weTransfer/Dropbox) for further investigation over to forge.help#autodesk.com?

How to load two forge viewers in single web page

I am trying to add two forge viewers in a single web page. I am using "react-forge-viewer" npm package to do that, but for some reason, only one viewer gets loaded and another one stays at "starting viewer..." state. It would be really great if anyone could help me resolve this problem.
I think this might be because of the dependency on class names or ID's.
Also, I want to synch their events in such a way that if I change camera view by dragging on on viewer same thing should reflect on another viewer as well.
You can easily fit multiple Viewers together, just be sure to initialize them separately with distinct container divs:
var viewer1 = new Autodesk.Viewing.Private.GuiViewer3D(document.getElementById('MyViewerDiv1'));
var viewer2 = new Autodesk.Viewing.Private.GuiViewer3D(document.getElementById('MyViewerDiv2'));
Autodesk.Viewing.Initializer(options1, function() {
viewer1.start();
viewer1.load(...);
});
Autodesk.Viewing.Initializer(options2, function() {
viewer2.start();
viewer2.load(...);
});
And you can sync the states of two viewers by subscribing to the CAMERA_CHANGE_EVENT, but beware pitfalls like endless loops - you can overcome this by implementing critical blocks to ensure only one viewer is exclusively requesting the other viewer to sync at any given time:
viewer1.addEventListener(Autodesk.Viewing.CAMERA_CHANGE_EVENT, function()
{
//critical block to prevent endless chained loop of events
viewer2.restoreState(viewer1.getState())
});
viewer2.addEventListener(Autodesk.Viewing.CAMERA_CHANGE_EVENT, function()
{
//critical block to prevent endless chained loop of events
viewer1.restoreState(viewer2.getState())
});
See a working sample here.
P.S:react-forge-viewer is a third party package not authored by Autodesk as is noted in its own README so you might need to contact its author if you have issues with it.

google maps using three.js and webgl

I have thousands of points that need to be plotted on google maps and got a very responsive maps using the example from https://github.com/ubilabs/google-maps-api-threejs-layer .
Did anyone have a play at this and wondering if it is possible to have different colored markers and possible marker click events?
Appreciate any pointers or examples online.
Millions of clickable data points can be painted on a google map using webgl.
A data point is represented by an x,y pair for a location on the canvas, an int for size, an off screen color, and an on screen color. These values are stored in separate typed arrays.
Each data point has a unique rgb color to act as a key in a lookup table of data point ids.
Create a texture to store the off screen colors and render it to an off screen buffer. On event, load the off screen buffer and use glReadPixels to retrieve the rgb color of the pixel clicked and then find the id in the lookup table. Points on the on screen buffer, what the user sees, can share a common color.
canvas.addEventListener('click', function(ev) {
# insert code to get mouse x,y position on canvas
pixels = new Uint8Array(4);
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
if (colorToId[pixels[0] + " " + pixels[1] + " " + pixels[2]]) {
# Pixel clicked is a data point on the map
}
});
Webgl code is lengthy, so only the click event is included.
Here is a live demo and a repo. (angular and coffeescript)
Here is a second example using plain js: webgl-picking-geo-polygons
Here is react-webgl-leaflet
The solution is based on Brendan Kenny's Google Maps + HTML5 + Spatial Data Visualization which explains some of the code in the excerpt above at the 30 min mark, and Displaying WebGL data on Google Maps.
The demo features less than ten data points, but you can just as easily paint over 16 million pickable data points using all combinations of rgb values.
I discovered OpenLayers this past week. Very, very impressive framework. I would strongly suggest taking a look at it. OpenLayers.org is an open source JavaScript web mapping library distinguished from other alternatives, like Leaflet or Google Maps APIs, because of its huge set of components.
I spent the entire weekend creating sample apps by integrating OpenLayers with API's such as MapBox, WebGL etc... After all was said and done, I was extremely impressed with OpenLayers - and I plan to make use of OpenLayers in an upcoming POC/Project.
Here is a link to my test harness. From there you can also download the code for all of the examples, too.
Updates for 2021!!
Google Maps JS now has a WebglOverlayView class and exposes the WebGL context.
const webglOverlayView = new google.maps.WebglOverlayView();
webglOverlayView.onAdd = () => {
// Do setup that does not require access to rendering context.
}
webglOverlayView.onContextRestored = gl => {
// Do setup that requires access to rendering context before onDraw call.
}
webglOverlayView.onDraw = (gl, coordinateTransformer) => {
// Render objects.
}
webglOverlayView.onContextLost = () => {
// Clean up pre-existing GL state.
}
webglOverlayView.onRemove = () => {
// Remove all intermediate objects.
}
webglOverlayView.setMap(map);
Additionally, #googlemaps/three extends this class for easier use with ThreeJS.
// instantiate a ThreeJS Scene
const scene = new Scene();
// Create a box mesh
const box = new Mesh(
new BoxBufferGeometry(10, 50, 10),
new MeshNormalMaterial(),
);
// set position at center of map
box.position.copy(latLngToVector3(mapOptions.center));
// set position vertically
box.position.setY(25);
// add box mesh to the scene
scene.add(box);
// instantiate the ThreeJS Overlay with the scene and map
new ThreeJSOverlayView({
scene,
map,
});
Here is a link to a jQuery/google map app. Not exactly what you are looking for; however you might find the example useful. Feel free to use - it can be downloaded from my site.
Link to app on my website
Click here to download the zip