Forge viewer: how to isolate custom objects? - autodesk-forge

We use custom objects to visualize ifc space data (mostly rooms). As a guidance, we used this very helpful blog. After drawing the objects, we would also like to select the custom objects from outside and isolate them in the viewer. As the tutorial suggests, we change the model builder's changeFragmentsDbId function to set DbIds that do not exist yet and therefor do not overlap with already existing DbIds. One approach is to use the negative space [-1, -2, -3...] for our custom objects DbIds like this:
const roomFragId = this.modelBuilder.addFragment(roomGeometryId, materialName, transform);
this.modelBuilder.changeFragmentsDbId(roomFragId, -roomFragId);
Another one is to find the maximum DbId (eg. 4905) and use numbers higher than this maximum DbId for our custom objects DbIds (eg. [4906, 4907, 4908...]):
const roomFragId = this.modelBuilder.addFragment(roomGeometryId, materialName, transform);
this.modelBuilder.changeFragmentsDbId(roomFragId, maxDbId + roomFragId);
However, when we try to isolate a custom drawn object (viewer.isolate(-1) or viewer.isolate(4906)), the viewer kind of refreshs itself, but no object gets isolated...
Thus, we would like to know how we can isolate custom objects?
The other way, when we select the object in the viewer works for the negative space approach => we get the DbId (eg. -1) in the aggregate selection event.
Thank you for any kind of help!

To isolate or select custom objects created by the SceneBuilder ext, you need to pass model object to Viewer3D#isolate / Viewer3D#select like the below. Otherwise, viewer will use viewer.model instead.
viewer.isolate( [4906, 4907, 4908...], this.modelBuilder.model )
viewer.select( [4906, 4907, 4908...], this.modelBuilder.model )

Related

combine model on Autodesk Forge

I have couple of questions about combine model on forge viewer (load list urn to 1 viewer):
when i combine model. i only can get data from 1 main model in that combine. for instance, 
var instanceTree = GlobalViewer.model.getData().instanceTree;
var allDbIdsStr = Object.keys(instanceTree.nodeAccess.dbIdToIndex);
var list = allDbIdsStr.map(function (id) { return parseInt(id) });
list will return all dbid of main model, how can i access all data of all model when i combine?
what is the unique id for object in combine model. i do some function with dbid and i realize it can appear in others model too.
When i combine 3d model(revit) with 2d model(autocad). it has 2 case: if 3d model load first i can rotate like normal, if 2d model load first i cant rotate the model any more. how can i force it always can rotate?
Autocad unit seems different with model in viewer. it always scale down compare with the model. how can i fix that?
Appreciate any comments,
Regarding #1: viewer.model obviously only references one of the models (I believe it's the last one you loaded), but you can use viewer.getVisibleModels() or viewer.getHiddenModels() to get other loaded models as well.
Regarding #2: dbIDs are only unique within a single model; many of the viewer methods accept an additional parameter specifying the model on which to operate, for example, you could say viewer.select([123, 456], oneOfMyModels).
Regarding #3: that's a good question; loading a 2D model first puts the viewer into 2D viewing mode (where only zoom and pan is allowed); if you know you will be working with 3D models, I'd recommend always loading those first
Regarding #4: yes, each loaded model can have different units; when loading a model using the loadDocumentNode method you can specify additional options (for example, a placement transform for the loaded geometries), and one of them is an object called applyScaling, for example, like so:
viewer.loadDocumentNode(doc, viewable, {
applyScaling: { to: 'mm' }
});

How to select by dbid in viewer when several models are loaded?

I load several models in my scene. I would like to:
Fit to view from dbId -> this can be done with viewer.fitToView(objectIds,model)
Select an element from dbid on a particular model. But viewer.select(dbids,selectionType) does not offer possibility to select the model.
How can we make a selection on a dbid, on specific model, when several models are loaded?
Thanks
Looking at the code of Forge Viewer v6, the select method is defined as
Viewer3D.prototype.select = function (dbids, model) { ... }
So the second parameter should actually be the model, not a selection type.

AS3: how to pass by "object"

I was actually looking for a way to pass by reference in AS3 but then it seemed that adobe and lots of people's understanding of pass by reference is different from what I have been taught at the university. I was taught java was pass by value and C++ allowed pass by reference.
I'm not trying to argue what pass by value and reference are. I just want to explain why I'm using pass by object in the question...
Back to the question, I would like to do something like:
public function swapCard(cardA:Cards, cardB:Cards) {
var temp:Cards = cardA;
cardA = cardB;
cardB = temp;
}
...
swapCard(c1, c2);
EDIT: adding two examples on how I'm using the swapCard function
1) in the process of swaping a card between player1 and player2's hand
swapCard(player1.hand[s], player2.hand[t]);
2) in the process of swaping a card between player1's hand and deck
swapCard(player1.hand[s], player1.deck[rand]);
In C++, we only need to add a symbol before the parameters to make it work (and we call THIS pass by reference). But in AS3, cardA and cardB are just pointers to the formal parameters. Here in the function, changing the pointers does not do anything to the formal parameters :(
I have been searching for hours but I couldn't find a way to without knowing all the properties of the Cards.
If I have to change the properties of the cards one by one then maybe I should change swapCard to a static function in class Cards? (because I don't want to expose everything to another class) I'm not sure if this is a good practice either. This is like adding a swap_cars function into class Cars. If I let this happen, what will be next? Wash car, lend car, rent car... I really want to keep the Cards class clean and holds only the details of the card. Is there a possible way to do this properly in AS3?
The kind of swap function that you're trying to implement is not possible in AS3. The input parameters are references to the input objects but the references themselves are passed by value. This means that inside the function you can change the cardA and cardB but those changes will not be visible outside the function.
Edit: I added this portion after you edited your question with sample usage.
It seems like you're trying to swap two objects in 2 different arrays at given array positions in each - you can create a function for this in AS3 but not the way you attempted.
One possible implementation is to pass the arrays themselves and the positions that you're trying to exchange; something like this:
// Assumes arrays and indices are correct.
public function SwapCards(playerHand:Array, playerCardIndex:int,
playerDeck:Array, playerDeckIndex:int):void
{
var tempCard:Card = playerHand[playerHandIndex];
playerHand[playerHandIndex] = playerDeck[playerDeckIndex];
playerDeck[playerDeckIndex] = tempCard;
}
Note that you still exchange references and the arrays themselves are still passed by reference (and the array references are passed by value - you could, if you wanted, change the arrays to new arrays inside this function but you wouldn't see new arrays outside). However, because the array parameters refer to the same arrays inside and outside the function, you can make changes to the contents of the array (or other array properties) and those changes will be visible outside.
This solution is faster than cloning the card because that involves allocating memory for a new Card instance (which is expensive) and that temporary instance will also have to be freed by the garbage collector (which is also expensive).
You mentioned in a comment that you pass cards down to lower levels of code - if you don't have a back reference to the arrays (and the positions of the cards), you will not be able to easily swap cards - in AS3, all input parameters are copies (either the copy of the value for primitive types or the copy of the reference for complex objects - changes to the input parameters in a function will not be visible outside).
EDIT: renaming the function from clone to copyFrom as pointed out by aaron. Seems like clone is supposed to be used as objA = objB.clone()
At this point, I'm adding a copyFrom() function in the Cards class such that
var temp:Cards = new Cards(...);
var a:Cards = new Cards(...);
...
temp.copyFrom(a);
...
temp will be copying everything from a.
public function swapCard(cardA:Cards, cardB:Cards) {
var temp:Cards = new Cards();
temp.copyFrom(cardA);
cardA.copyFrom(cardB);
cardB.copyFrom(temp);
}
I will wait for a week or so to see if there are any other options
You have some good answers already, but based on the comments back-and-forth with me, here's my suggestion (I use "left" and "right" naming because it helps me visualize, but it doesn't matter):
function swapCard(leftCards:Array, leftCard:Card, rightCards:Array, rightCard:Card):void {
var leftIndex:int = leftCards.indexOf(leftCard);
var rightIndex:int = rightCards.indexOf(rightCard);
leftCards[leftIndex] = rightCard;
rightCards[rightIndex] = leftCard;
}
Now you can swap the cards in the two examples you posted like this:
swapCard(player1.hand, player1.hand[s], player2.hand, player2.hand[t]);
swapCard(player1.hand, player1.hand[s], player1.deck, player1.deck[rand]);
However, note that while this swaps the cards in the arrays, it does not swap direct references to the cards in those arrays. In other words:
var a:Card = player1.hand[0];
var b:Card = player2.hand[0];
swapCard(player1.hand, a, player2.hand, b);
// does not change the references a and b, they still refer to the same card
a == player2.hand[0];
a != player1.hand[0];
b == player1.hand[0];
b != player2.hand[0];
Typically, this sort of thing is handled by dispatching a "changed" event so that any code that cares about the state of a player's hand array will know to re-evaluate the state of the hand.
There's a deep misunderstanding going on here. The question is about object reference but the PO is not trying to swap any Object reference at all.
The problem comes from the fact that the PO does not understand the difference between variable and objects. He's trying to swap variable/object reference which is not dynamically possible of course. He wants with a function to make the variable holding a reference to Object A, swap its object reference with another variable. Since Objects can be passed around but not variables (since they are just holders (not pointers)) the task is not possible without a direct use of the given variable.
To resume:
variables are not Objects!
variables hold a reference to an object.
variables cannot be passed in function or referenced in functions because THEY ARE NOT OBJECTS.

How a linked list is practically possible in AS3.0

I stumbled across this page : Create Linked List in AS3
Since AS3.0 is a scripting language. I wonder how come linked list is possible in AS3.0 ? Isn't pointer ( a way to access memory location ) mandatory to create a linked list. That ultimately makes array of data faster in performance ?
In AS3 you have object references, you don't have pointers exactly, but you can achieve a linked list using the references in a very similar way. The advantage of a Linked List (in general) is in insertion and deletion within the list (you don't have to shift all elements as in using an array). You still get this benefit using object references.
Note: Objects in AS3 are passed by reference, primitives are passed by value.
Effectively all scripting languages do work with pointers.
They only decided to call them differently (most times they call them "references") and to hide the complexity (or even possibilities) of managing the memory allocation and releasing.
Having said that the simplest way to create a linked list in ActionScript (or JavaScript) would be
var node1 = {value: 1};
var node2 = {value: "foo"};
var node3 = {value: "bar"};
//of course this code should be localices within a separate class
//with some nice API
((node1.next = node2).next = node3).next = null;
//and then use like that e.g.
var n = node1;
while (n) {
trace(n.value);
n = n.next;
}

as3 Vector.map and Vector.filter

Gone thru the livedocs but the examples are quite sparse.
Can anyone give me some good 'real world' examples of when and why you might use the
map and filter methods of the new Vector class in Actionscript?
The Vector filter and map methods work just the same as the methods in the Array class of the same name. Check the following two pages for filter examples for arrays (they work just the same for the Vector class):
http://troyworks.com/blog/2007/12/16/as3-arrayfilter-r0xr/
http://www.onebyonedesign.com/tutorials/array_methods/
I couldn't find any decent as3 map examples, but the jQuery equivalent explains how/why you would use it fairly well:
http://api.jquery.com/jQuery.map/
As for real world uses, filter is unbelievably useful. Suppose you have a Vector filled with Employee objects. You can use the filter method as a non-destructive way to get all the Employees whose name starts with "A", or whose salary is greater than $50,000. The map function is similar, but it creates a new Vector and allows you to alter the objects, so you could potentially cast each Employee as a new type, such as HighlyPaidEmployee.