Auto desk - Forge Viewer - Markup - am not able to get markups array in markup extension while loading markups - autodesk-forge

While loading markups, I am not able to get markups array from markup extension as referneced in below code, actually I need client position coordinates of the loaded markup. In below code am getting markups array empty. But while drawing a new markup, we always have markup array filled.
Please advise
markup.viewer.restoreState(viewState);
markup.loadMarkups(svgTxt, "layerName")
var pos = markup.markups[0].getClientPosition()

Since you're not editing the layer you specified, the markupExt.markups will not contain anything. Please use this instead:
const activeLayerMarkup = markupExt.svgLayersMap[markupExt.activeLayer]
activeLayerMarkup.markups[0].getClientPosition()
Or try to edit the layer
markupExt.loadMarkups(svgTxt, 'layerName')
markupExt.enterEditMode('layerName')
markup.markups[0].getClientPosition()

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 Markups Core

I have a markup extension in Autodesk Forge Viewer for 3D models. I have problems removing only one markup. I want to know if it is possible to show annotations in edit mode or delete markups in show mode. When I try to show markups in editing mode, I see a warning that "markups cant be showed in editing mode."
Does anyone know how to solve this problem?
Edit
And to remove a specific markup from a layer after they are loaded try:
markExt.svgLayersMap['layerId'].markups[index].destroy()
Leave the editmode before showing markups - (in response to user input) you can programmatically re-enter editmode once the markups are shown:
ext.leaveEditMode()
ext.loadMarkups(asb,'233') //or ext.showMarkups(layerID)
ext.enterEditMode()
And to remove markups try:
ext.markups[0].destroy()
show annotations in edit mode
Not exactly sure what you are trying to achieve here? But you can create text markup programmatically - say for exp:
const styleObject = Autodesk.Viewing.Extensions.Markups.Core.Utils.createStyle(['font-size'], window.ext);
styleObject['font-size'] = 100;
(new Autodesk.Viewing.Extensions.Markups.Core.CreateText(window.ext, 2333, {x:20,y:20}, {x:100,y:100},'233', styleObject)).execute()
or delete markups in show mode.
And in show mode if the markups are loaded you will need to hide on their layer level and wouldn't be able to hide a specific markup - you may fine tune this by separating them to different layers

BIM Viewer Markup - Can we edit saved markups or is it only supports view?

Can we edit saved markups which we draw on a viewer?
Does it only support view using restoreState and loadMarkups functions?
Or is there anyway I can update the created and saved markups as my functionality requires reviewer User should be able to update this markups.
var markupsPersist = markup.generateData()
// current view state (zoom, direction, sections)
var viewerStatePersist = markup.viewer.getState()
// finish edit of markup
markup.leaveEditMode()
// hide markups (and restore Viewer tools)
markup.hide()
// restore the view to the state where the markups were created
markup.viewer.restoreState(viewerStatePersist)
// show markups
markup.show();
// show the markups on a layer
markup.loadMarkups(markupsPersist, "layerName")
Of course you can access the markups via markupExt.markups and for example you can edit the text markup with below:
const textMarkup = markupExtension.markups[0]; //access the existing markups via markupExtensionObject.markups
textMarkup.setText('new text');
markupExtension.leaveEditMode();
markupExtension.enterEditMode() //be sure to re-enter edit mode for the changes to take effect
I ran into this this scenario too and you can edit a saved markup. You may need to store your markup state to your own database to be accessed and restored later by the Reviewer. Here is a sample that shows this functionality.
https://forge-rcdb.autodesk.io/configurator?id=598d7ec14cabf2c1f4dec948
Here is blog post discussing this as well.
https://forge.autodesk.com/blog/high-performance-3d-markups-pointcloud-forge-viewer

Draw polygon using ngmap

I'm trying to draw polygon on my map using ngmap. The map is displayed correctly as this example is showing, but when I finish the draw, this is what I'm getting:
ng-map.min.js:25 Uncaught TypeError: Cannot read property 'onMapOverlayCompleted' of undefined
I used the same code of the example.
My questions:
1- How can I solve this error?
2- If I want to let the user draw only polygon form, I have tried to set the value of drawingMode to "polygon" but I'm always having the other draw options (circle...). How can let only the polygon draw?
3- How can I let the user clear the drawn polygon?
4- Is it possible to detect the action of putting (drawing) every points. I mean that to draw a line in the polygon for example I need at least two points. Can I detect when the user draw the first point then the second and get its coordinates?
Edit
This is the whole error that I see when I include ng-map.js instead of ng-map.min.js :
Uncaught TypeError: Cannot read property 'onMapOverlayCompleted' of undefined
at index (http://localhost:8080/bower_components/ngmap/build/scripts/ng-map.js:2690:44)
at Array.reduce (native)
at Uw.<anonymous> (http://localhost:8080/bower_components/ngmap/build/scripts/ng-map.js:2691:39)
at P4._.z.trigger (https://maps.google.com/maps/api/js?key=MY_API_KEY&libraries=placeses,visualization,drawing,geometry,places:99:121)
at P4.<anonymous> (https://maps.google.com/maps/api/js?key=MY_API_KEY&libraries=placeses,visualization,drawing,geometry,places:37:81)
at C4._.z.trigger (https://maps.google.com/maps/api/js?key=MY_API_KEY&libraries=placeses,visualization,drawing,geometry,places:99:121)
at C4.<anonymous> (https://maps.google.com/maps/api/js?key=MY_API_KEY&libraries=placeses,visualization,drawing,geometry,places:37:81)
at Object._.z.trigger (https://maps.google.com/maps/api/js?key=MY_API_KEY&libraries=placeses,visualization,drawing,geometry,places:99:121)
at F4 (https://maps.google.com/maps-api-v3/api/js/28/14/drawing_impl.js:7:70)
at G4 (https://maps.google.com/maps-api-v3/api/js/28/14/drawing_impl.js:4:249)
Edit 2
I solved the first question:
My problem was that I'm using routes in the app.js. So the html and the controller are linked in it. To solve the problem, I put $scope.onMapOverlayCompleted instead of
var vm = this;
vm.onMapOverlayCompleted because I don't write the the ng-controller="DrawingManagerCtrl as vm" in my HTML. Then in the HTML I put on-overlaycomplete="onMapOverlayCompleted()" and it works.
I solved also the second question by using:
drawing-control-options="{position: 'TOP_CENTER',drawingModes:['polygon']}"
I'm want now to solve the other problems.
Any help please?
3
As the example you referenced shows, the overlaycomplete callback function receives e (Event) as the first parameter. This OverlayCompleteEvent object contains reference to the drawn overlay at Event.overlay (see docs of the original Google Maps JS API more info, since ng-map is only wrapper of the original API after all, specifically "OverlayCompleteEvent object specification" section).
Using that you can get the reference to the created overlay, store it and then later call .setMap(null) on it to delete it from map. E.g:
$scope.myDrawnOverlays = []; //array where you store drawn overlays
$scope.onMapOverlayCompleted(e){
...
myDrawnOverlays.push(e.overlay); //store reference to the drawn overlay after it's drawn
}
$scope.deleteAllDrawnOverlays(){
for(var i = 0; i < myDrawnOverlays.length; i++){
myDrawnOverlays[i].setMap(null); //remove overlays from map one by one
}
myDrawnOverlays = [];
}
Then whenever you want to delete all overlays, just call the function $scope.deleteAllDrawnOverlays (you can tie it to some button using ng-click or do whatever you want with it).
4
This is NOT possible using google.maps.drawing.DrawingManager which is used in your example. The reason is that DrawingManager doesn't support events for clicking at the map while drawing (see docs again for possible events, section "DrawingManager class").
So except hacky workarounds which could break any time with new api release, the only possible solution is to implement drawing of polygon yourself and not use DrawingManager. Check for example this SO answer, specifically the referenced example (right-clicks on map). They don't use ng-map, but basically what would you have to do is to add on-click="mapClickHandler" to your ng-map, in the mapClickHandler get position where you clicked on map, draw Marker there which would look like a dot and if you have more dots connect them with lines.
This is however too much for one question, you would have to probably read up on ng-map and relevant sections of Google Maps Js Api yourself.

WebGL - change mapAmbient material property in Three.js

I'm trying to update an image in a material of a pre-loaded .js model - i want it to have the same properties, whereas only the image is changed.
Was trying to use this post as a reference, but in the .js model file, the map appears as the "mapAmbient" property. I was thinking of somehow using the THREE.ImageUtils.loadTexture() function, but couldn't find where exactly it should be placed.
Moreover, the texture should be loaded using an Image() object generated using another canvas. Any help would be appriciated
*Edit:
Wasn't able to find actual way to change that property in runtime, but was able to change the image using base64 encoding:
//img is base64 encoded image
var tex = new THREE.ImageUtils.loadTexture(img);
currentMesh.material.materials[1].map = tex;