How to use the BIM360 PushPin Extension with Forge Viewer? - autodesk-forge

I am trying to use the PushPin extension to load issues in my custom Forge viewer, I follow the steps described in the official documentation but getting the following error after calling PushPinExtension.createItem:
issues.forEach(function (issue) {
var issueAttributes = issue.attributes;
var pushpinAttributes = issue.attributes.pushpin_attributes;
// Notice the last rendering condition, which will enforce rendering the pushpin on the current sheet.
// We simply compare the issue sheet metadata against the current sheet.
if (pushpinAttributes && issueAttributes.sheet_metadata &&
issueAttributes.sheet_metadata.sheetGuid === viewerApp.selectedItem.guid()) {
PushPinExtensionHandle.createItem({
id: issue.id, // The issue ID.
label: issueAttributes.identifier, // The value displayed when you select the pushpin.
// The shape and color of the pushpin, in the following format: ``type-status`` (e.g., ``issues-open``).
status: issue.type && issueAttributes.status.indexOf(issue.type) === -1 ?
`${issue.type}-${issueAttributes.status}` : issueAttributes.status,
position: pushpinAttributes.location, // The x, y, z coordinates of the pushpin.
type: issue.type, // The issue type.
objectId: pushpinAttributes.object_id, // (Only for 3D models) The object the pushpin is situated on.
viewerState: pushpinAttributes.viewer_state // The current viewer state. For example, angle, camera, zoom.
});
} // if
} // forEach
};
Looking at the source code of that extension, it seems there is now a pushPinManager which is responsible for adding items, but I couldn't figure out quickly enough how to use it.
It would help if you could provide a working example using the latest version of that extension and also make sure your doc is up-to-date, which will avoid some tension on the third party devs side ;)

:) how are you!
yes you found the truth that the document does not update with the latest change of the extension. While the Pushpin sample has been migrated to the latest version. It demos the workflow of loading issues and creating new issues with Pushpin extension.
https://github.com/Autodesk-Forge/forge-bim360-issues/blob/master/bim360issues/wwwroot/js/BIM360IssueExtension.js
Please let us know if it does not answer your question.
I have forwarded the suggestion asking for document updating.

Related

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

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

Autodesk forge transform extension turn on / off X, Y, Z axes

i'm using the transform extension. Sometimes I want the x, y and z axes to be closed. For example, in this three.js example, pressing the x, y or z keys can be opened and closed via a feature such as .showX. When I try this in the forge extension, there is no such feature. What can I do about it.
I am simply writing such code here. Console log is written, but the axis are still visible.
document.addEventListener('keydown', function (event) {
if (event.key === "x") {
console.log("X press");
_transformControlTx.showX = !_transformControlTx.showX;
}
if (event.key === "y") {
console.log("Y press");
_transformControlTx.showY = !_transformControlTx.showY;
}
if (event.key === "z") {
console.log("Z press");
_transformControlTx.showZ = !_transformControlTx.showZ;
}
});
This question has been discussed on Forge accelerator last week. The discussion is copied here for reference:
Xiaodong:
The transform tool is based on THREE.TransformControls. In the new version of TRHEE.js, it looks it supports handling visibility of the axis, but since Forge Viewer is packaged from old version of three.js, I am afraid it does not support yet. copied my colleagues #Varun Patil - Forge Team, #Petr Broz (Forge Team) (because of time diff, it may take some time they comment).
it seems one more workaround from community: Three.js Transform Controls - How to show only two arrows
Eason:
I compared two TransformControls between three.js example and Forge viewer’s. Unfortunately, they are totally different one. Forge Viewer’s TransformControls is based on three.js r71, so it doesn’t have the direct showing/hiding axises support. You need to do that as the Stack Overflow thread above does.
Petr:
I’m afraid that the transform tool from three.js might be manipulating the scene graph during runtime, adding and removing 3D objects as needed… that would explain why your modifications don’t seem to stick. in general, if you need to modify some component of three.js that is not extensible, instead of fighting with the implementation I’d probably suggest building your own… if all you need is a movement in X or Y, you could just have a 3D object with two thin cylinders, red and green, and handle their mouseover, mousedown, mousemove, and mouseup events

How to Enable the MiniMap extension and what is it?

I'm interested to use the minimap extension but i find that there is no documentation.
here is the question i want to know:
What is the minimap extenstion?
what is the requirement to use it?
I've tried to load the extension by running viewer v7.1 and its stop by can't get the DocumentNode.
var optionObject = {
extensions: ['Autodesk.AEC.Minimap3DExtension']
};
var viewer = new Autodesk.Viewing.Private.GuiViewer3D(myViewerDiv, optionObject);
NOP_VIEWER.model.getDocumentNode()
NOP_VIEWER.model.getDocumentNode() is return null, the minimap didn't show up.
You will need to be in first person walking mode for the minimap to show up:
And getDocumentNode() will only return the current view object if the model is loaded using loadDocumentNode, e.g.:
NOP_VIEWER.loadDocumentNode(doc,doc.getRoot().getDefaultGeometry())

How to set Google Maps API key in PrimeFaces extensions gChart

I'm using PrimeFaces extensions (6.1.0) to create some charts using pe:gChart.
One of the charts is a geo chart as appears in the showcase. No problems so far.
Another chart I need to render is a marker geo chart. This is not explained in the PrimeFaces extensions showcase, but I was hoping this would be an easy job. I ended up with this model (which I believe is correct):
GChartModelBuilder builder = new GChartModelBuilder();
builder.setChartType(GChartType.GEO);
builder.addOption("displayMode", "markers");
builder.addOption("region", country);
builder.addColumns("City", "Total");
for (...) {
builder.addRow(city, total);
}
When I run my project I do see a map for this chart. The region is correct, but no markers appear. There is marker data generated though.
My browser console tells me:
Google Maps API error: MissingKeyMapError https://developers.google.com/maps/documentation/javascript/error-messages#missing-key-map-error
Is there any way I can set this API key without creating hacks?
Update
I've created a custom renderer:
public class MyGChartsRenderer extends GChartRenderer
{
#Override
protected void encodeMarkup(FacesContext context, GChart chart) throws IOException
{
...
this.startScript(writer, chart.getClientId());
// Appended ?key=xxxxx to the URL (other lines are not modified)
writer.writeAttribute("src", "https://www.google.com/jsapi?key=xxxxx", null);
this.endScript(writer);
}
}
And loaded it in the faces-config.xml:
<render-kit>
<renderer>
<component-family>org.primefaces.extensions.component</component-family>
<renderer-type>org.primefaces.extensions.component.GChartRenderer</renderer-type>
<renderer-class>MyGChartsRenderer</renderer-class>
</renderer>
</render-kit>
But the Google Maps API error keeps appearing in my console.
DISCLAIMER: I created an answer, not because it is the answer but because it is so much information that it won't fit in a comment in any way any way (hmmm ;-))
DISCLAIMER 2: I might have missed some things and did not actually try... Hope you don't mind.
Note: Three months ago PrimeFaces extensions updated to a newer Google charts api version according to the commits and issue 452 with upcoming changes so I focussed on that!
In the PrimeFaces-extensions gchart.js I noticed
google.charts.load('current', {
packages : [ 'corechart', 'geochart', 'orgchart' ]
});
jQuery(document).ready(function() {
google.charts.setOnLoadCallback(function() {
that.draw();
});
});
While on on Visualization: GeoChart | Charts | Google Developers I saw
google.charts.load('current', {
'packages':['geochart'],
// Note: you will need to get a mapsApiKey for your project.
// See: https://developers.google.com/chart/interactive/docs/basic_load_libs#load-settings
'mapsApiKey': 'AIzaSyD-9tSrke72PouQMnMX-a7eZSW0jkFMBWY'
});
google.charts.setOnLoadCallback(drawRegionsMap);
Related tot the issue commit/fix/issue, in the PrimeFaces extensions showcase source trunk I also noted they explicitly load
<script src="https://www.gstatic.com/charts/loader.js"></script>
in the xhtml.
Lots of upcoming changes, so the most future proof solution would be to try 6.2-SNAPSHOT and create a real good fix where you
add a mapsApiKey property and getters/setters to GChart.java
add .attr("mapsApiKey", chart.getMapsApiKey()) to GChartRenderer.java
add this.mapsApiKey = cfg.mapsApiKey -and 'mapsApiKey': this.mapsApiKey to gchart.js in the right places
As a workaround / hack I've put this script in my XHTML:
<script src="https://maps.googleapis.com/maps/api/js?key=xxxxx&v=3&callback=google.loader.callbacks.maps&sensor=false"></script>

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