Autodesk Forge Viewer getting fragment position - autodesk-forge

I'm trying to get the position of separate meshes in a model (translated from a revit file).
What I'm doing is to get fragmentProxy, then use getOriginalWorldMatrix() to get the THREE.Matrix4(). Then from the Matrix4, call getPosition() to get the THREE.Vector3 world position of the fragment.
However, every mesh returns the same position value. Is that because of how the model is built originally? Or I have to get the fragment position using a different method?

Your process of retrieving the fragment transform is correct. Alternatively, you could use something like this:
function getFragmentTransform(model, fragid) {
const frags = model.getFragmentList();
let xform = new THREE.Matrix4();
frags.getOriginalWorldMatrix(fragid, xform);
return xform;
}
I'm afraid you are correct that, in some cases, the transform may be baked directly into the mesh vertices.

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 Viewer: Change Texture in IFC Model

we run a webapplication using Autodesk Forge. In the webapplication we'd like to change surface apperances. Therefore we use the following Audodesk functions
...
event.fragIdsArray.forEach(frag => {
const model = this.viewer.model;
model.getFragmentList().setMaterial(frag, this.material)
var object = this.viewer.impl.getFragmentProxy(this.viewer.impl.model, frag)
object.updateAnimTransform()
}
The code works fine for Autodesk Revit imported model. Using imported IFC models does not work as expected. Both models were imported to the AD Forge viewer by ADs model derivate api.
To geht our expected results we tried to use MeshBasicMaterial and MeshPhongMaterial. Both with the same result: Revit model is fine, IFC model aint so.
In Order to lookup for some workaround we tried to copy the fragment meshes and creating overlays with the same mashes and changed materials. Code was like
...
var obj = this.viewer.impl.getRenderProxy(this.viewer.impl.model, frag)
var meshProxy = new THREE.Mesh(obj.geometry, this.material);
meshProxy.matrix.copy(obj.matrixWorld);
meshProxy.matrixWorldNeedsUpdate = true;
meshProxy.matrixAutoUpdate = false;
meshProxy.frustumCulled = false;
this.viewer.impl.addOverlay("parkett", meshProxy);
...
The result is shown in the image (right side is the expected result):
Somehow it looks like the image texture is not shown "detailed" enough...
Thanks in advance for any suggestion!
From the question I'm not entirely sure what the problem is. Are there no visible changes when applying a custom material to IFC models? Or is the custom material applied, but in a "wrong way"?
If the custom material is not applied at all, make sure that the model is not consolidated. You can ensure that using viewer.model.unconsolidate();.
If the custom material is applied but its texture doesn't look correct, it could be because the geoemtries in the IFC model do not include proper texture coordinates. In that case you would have to map the texture yourself, for example, using a custom shader: https://github.com/petrbroz/forge-basic-app/blob/custom-texture-mapping/public/CustomTextureExtension.js.

threejs cannot parse material in json object

Dear all I am using angular 2.4.10 and three js 0.85.0. After downloading a JSON file from the server, I have at my disposal the following JSON object:
https://drive.google.com/file/d/0B7IcIHZN137RdmVRTXpLZmlPaDg/view?usp=sharing
I am trying to load the object without using the loader URL using the following code suggested in another StackOverflow post:
loadModel(aJSONObject) {
console.log(aJSONObject);
let loader = new THREE.ObjectLoader();
let model = loader.parse( aJSONObject );
console.log(model);
.....
}
and it's working but it is not getting the materials. How can I get the material from the JSON file?
I tried to load your model and the unique material got imported correctly.
However, there is no texture nor color defined for this material in the JSON model. So the object will look white, the default color used for three.js materials.
Fiddle here.
To see your model in three.js make sure to scale it appropriately based on you camera position (I had to scale it down).Moreover, as the model is using a THREE.MeshPhongMaterial, don't forget to add some lights.
By the way, there are some X, Y and Z individual attributes defined in your model that increase its size uselessly (three.js won't use them).

geotools draw symbol on overlay

I'm new to Geotools. I am developing a simple application that shows a map and I would like to dynamically place a bitmap or vector symbol on it (for example to show where the current position is, like in navigation systems).
Now, what I've done already is:
showing a map given one or more shapefile.
center the map on the last inserted position.
add shapes to new layers when needed.
What I need to do is to create an overlay with images at given coordinates on the map area (to be clear, I don't want to generate a raster layer on disk, I just want to paint on the screen).
My guess is that I have to somehow directly use the Graphics2D instance inside JMapPane, is that correct? In this case how can I convert from the geographic coordinates to pixel coordinates on the drawing pane? Or are there some geotools functions/classes that I should be looking for?
Thank you.
Answering myself, since I found the solution.
I did it by extending class org.geotools.map.DirectLayer, which provides a way to define a custom layer by extending its draw(Graphics2D, MapContent) method. Graphic elements are placed at the correct coordinates by using the worldToScreen affine transform provided by geotools. For example, to define a Point2D placed at the current position given real-world coordinates:
AffineTransform worldToScreen = viewport.getWorldToScreen();
Point2D worldPoint = new Point2D.Double(currentPosition.x, currentPosition.y);
Point2D screenPoint = worldToScreen.transform(worldPoint, null);
Once the draw() method is defined, just instantiate and add as a layer to your MapContent instance.

HTML5 Canvas: Calculate the Mouseposition after Zooming and Translating

I try to develope an interactive viewer for vector drawings and want to have the feature of zooming.
The function for zooming works pretty good but now I have the problem to calculate the mouseposition for picking objects.
The event gives back the screen coordinates. The canvas doesn't have a methode to use the transformation matrix in the inverse way.
Does anyone have a solution to this problem?
I made a very small a simple class for keeping track of the transformation matrix.
I added an invert() function for reasons like this. I also made an invertPoint() function but didn't put it in the final version. It's not hard to deduce though, just invert and transform point together.
I often just calculate the appropraite transform with this class and then use setTransform, depending on the application.
I wish I could give you a more specific solution but without a code sample of what you want that'd be hard to do.
Here's the transformation class code. And here's a blog post with a bit of an explanation.
Here are some valuable functions for your library that preserve the matrix state and needed to build up a scene graph:
Transform.prototype.reset = function() {
this.m = [1,0,0,1,0,0];
this.stack = [];
};
Transform.prototype.push = function() {
this.stack.push(this.m.slice());
};
Transform.prototype.pop = function() {
this.m = this.stack.pop();
};