I am trying to generate a list of elements (dbIDs) of a navisworks model that comes from revit and istram IFC files. I have a problem in the selection tree levels since I need the first elements of each object and for revit files I select the body. How can I build this code so that it reads me the components of a higher level?
If someone can help me, I would really appreciate it
constructor(viewer) {
this._modelData = {};
this._viewer = viewer;
}
init(callback) {
var _this = this;
_this.getAllLeafComponents(function (dbIds) {
console.log(dbIds);
var count = dbIds.length;
dbIds.forEach(function (dbId) {
viewer.getProperties(dbId, function (props) {
props.properties.forEach(function (prop) {
if (!isNaN(prop.displayValue)) return; // let's not categorize properties that store numbers
// some adjustments for revit:
prop.displayValue = prop.displayValue.replace('Revit ', ''); // remove this Revit prefix
if (prop.displayValue.indexOf('<') == 0) return; // skip categories that start with <
// ok, now let's organize the data into this hash table
if (_this._modelData[prop.displayName] == null) _this._modelData[prop.displayName] = {};
if (_this._modelData[prop.displayName][prop.displayValue] == null) _this._modelData[prop.displayName][prop.displayValue] = [];
_this._modelData[prop.displayName][prop.displayValue].push(dbId);
})
if ((--count) === 1) callback();
});
})
});
Related
I have this script, attr is hash object to keep application data.
const [attr,setAttr] = useState()
const onSetAttr = (data) =>{
console.log(data);
var new_attr = attr;
for (let key in new_attr) {
if (key in data){
new_attr[key] = data[key];
}
}
setAttr(new_attr);
console.log(new_attr);
}
It means the data and attr_should be marged as hash.
However setAttr works well but component is not re-rendered.
I google around and found this is related with imutable/mutable.
However in this case, how can i re-rendering forcebly?
You're mutating the same object, so reconciliation doesn't work properly. You should create a new one:
const [attr,setAttr] = useState()
const onSetAttr = (data) =>{
var new_attr = {...attr}; // <= object destructuring creates a new object
for (let key in new_attr) {
if (key in data){
new_attr[key] = data[key];
}
}
setAttr(new_attr);
console.log(new_attr);
}
I have tried to start the model browser with all nodes collapsed when loading several aggregated models, but it do no collapse all nodes. Is there any way to do this?
Try the code below on these model: https://wallabyway.github.io/federatedmodels-v7/
var ext = NOP_VIEWER.getExtension('Autodesk.ModelStructure')
ext._modelstructure.options.startCollapsed = true
Try to use this one instead. The ModelStructralPanel will read options in its constructor only.
var viewer = new Autodesk.Viewing.GuiViewer3D(container, {startCollapsed: true});
var ext = viewer.getExtension('Autodesk.ModelStructure');
// or
// viewer.unloadExtension('Autodesk.ModelStructure');
// var ext = await viewer.loadExtension('Autodesk.ModelStructure', {startCollapsed: true});
Workaround:
Add this code snippet before opening the modelstructure panel.
var ext = viewer.getExtension('Autodesk.ModelStructure');
ext._modelstructure.addVisibilityListener( show => {
if( show && (!ext._modelstructure.uiCreated) ) {
ext._modelstructure.tree.delegates.forEach( d => ext._modelstructure.tree.setAllCollapsed( d, true ) )
}
});
When creating the viewer, pass the following option to it:
var viewer = new Autodesk.Viewing.GuiViewer3D(container, {modelBrowserStartCollapsed: true});
It should cascade until reaching the model browser.
Background
The option "modelBrowserStartCollapsed" is passed on from the Viewer3D constructor up until the ModelStructureExtension, where it changes name to "startCollapsed" as it is passed to the ViewerModelStructurePanel.
proto.restoreDefaultPanel = function () {
var config = this.viewer.config;
var options = {
docStructureConfig: config.docStructureConfig,
hideSearch: (0, _src_compat__WEBPACK_IMPORTED_MODULE_2__.isMobileDevice)(),
excludeRoot: config.modelBrowserExcludeRoot,
startCollapsed: config.modelBrowserStartCollapsed // HERE
};
var modelTitle = config.defaultModelStructureTitle || 'Browser';
var panelInstance = new _src_gui_ViewerModelStructurePanel__WEBPACK_IMPORTED_MODULE_1__.ViewerModelStructurePanel(_objectSpread(_objectSpread({},
options),
(0, _src_gui_ViewerModelStructurePanel__WEBPACK_IMPORTED_MODULE_1__.generateDefaultViewerHandlerOptions)(this.viewer)),
modelTitle);
this.setModelStructurePanel(panelInstance);
};
The source for ViewerModelStructurePanel shows that it takes the option "startCollapsed" as stated, among other options.
function ViewerModelStructurePanel(viewer, userTitle, ops) {
...
options.startCollapsed = options.startCollapsed !== undefined ? options.startCollapsed : false;
I try to show snap icon (some yellow icon go with cursor appear when make measurement) when the cursor hover on the 3d model. This is my function and it not work for me at all. Do i miss some thing ?
onMouseMove = (event) => {
const snapper = new Autodesk.Viewing.Extensions.Snapping.Snapper(this.viewer);
const worldCoordinate = this.viewer.impl.hitTest(event.clientX, event.clientY);
if (worldCoordinate === null) return;
const hitTestResult = this.viewer.impl.snappingHitTest(
worldCoordinate.x,
worldCoordinate.y,
worldCoordinate.z
);
if (hitTestResult === null) return;
snapper.snapping3D(hitTestResult);
const result = snapper.getSnapResult();
}
I'm also reference some of these topic but not work for me. How to use Forge Viewer Snapper?
How to activate Autodesk Forge Snapper?
https://autodeskviewer.com/viewers/latest/docs/extensions_Measure_Measure.js.html
. Thank in advance !
I would think this issue is caused from the missing of container offset of the viewer. The world coordinates cannot be tested correctly. Please check the code below if it helps.
If I misunderstood the question,could you share a bit more information on what it is not working?
UPDATE:
onMouseMove = (event) => {
const snapper = new Autodesk.Viewing.Extensions.Snapping.Snapper(this.viewer);
const viewer_pos = this.viewer.container.getBoundingClientRect();
const worldCoordinate = this.viewer.impl.hitTest(event.clientX-viewer_pos.x, event.clientY-viewer_pos.y);
if (worldCoordinate === null) return;
// const hitTestResult = this.viewer.impl.snappingHitTest(
// worldCoordinate.point.x,
// worldCoordinate.point.y,
// worldCoordinate.point.z
// );
//if (hitTestResult === null) return;
snapper.snapping3D(worldCoordinate);
const result = snapper.getSnapResult();
snapper.indicator.render()
}
I know there is NOT a direct way to get all files + folders of a hierarchy of BOX folder. we have to recursively get items of subfolders.
However, if I simply need a count estimation, is it possible to get the basic info?
The Transferring tool https://www.multcloud.com can estimate the file count firstly, after it is done, it will start the transferring. In my observation, it looks it also recursively iterates the folders, but how it can know the recursive has completed?
Thank you for any hints!
If your tool is executed on the same machine on different dates, you can maintain some "estimation data" (i.e. persist the number of files of certain directories in a run, and use this old number of files contained in a subtree as estimation values for further runs)
Hi finally found it is just a common question on how to determine a recursively iteration has completed. The other post helped a lot. How to detect completion of recursive asynchronous calls in javascript
With the hints, my code works well. The below is the script for reference. It can be converted to Promise. I have not tried, though.
function buildTreeNodes(boxTopFolderId){
function startBuild(){
//get the top folder info
box.folders.getItems(boxTopFolderId ,
function (err, data) {
var results = [];
results.finished = 0;
var len = data.entries.length;
if (err){
console.log(err);
}
else{
//iterate from the top folder
data.entries.forEach(function (item, index) {
// BOX of file or folder
var boxid = item.id;
// file or folder
var boxtype = item.type;
//item name
var boxname = item.name;
if(boxtype === 'folder'){
recursiveFolder(boxid,function(result){
results[index] = result;
if (++results.finished == len) {
//recursion done!
}
});
}else{
results[index] = item;
if (++results.finished == len) {
//recursion done!
}
}
}); //end for each
if(len == 0)
//recursion done!
}
});
}
function recursiveFolder(folderId,callback){
box.folders.getItems(folderId,
function (err, data) {
var results = [];
results.finished = 0;
var len = data.entries.length;
if (err){
console.log(err);
}
else{
//iterate from the top folder
data.entries.forEach(function (item, index) {
// BOX of file or folder
var boxid = item.id;
// file or folder
var boxtype = item.type;
//item name
var boxname = item.name;
if(boxtype === 'folder'){
recursiveFolder(boxid,function(result)
{
results[index] = result;
if (++results.finished == len) {
callback(results);
}
});
}
else{
results[index] = item;
if (++results.finished == len){
callback(results);
}
}
});
if(len == 0)
callback(results);
}
});
}
startBuild();
}
New to node, As I am cycling through a roster of students, I need to check and see if a teacher has requested them for tutoring.
I realized I can't just do this:
var checkRequest = function(id){
var value = '';
roster.query('SELECT * FROM teacher_request WHERE student_id ='+id, function(err, row){
value = row.length;
}
return value;
}
After a bit of digging around promises looked like a great solution, but if I simply return the deferred.promise from the checkRequest function, all I get is an object that says [deferred promise] which I can't access the actual data from. (Or have not figured out how yet)
If I follow along with their api and use .then (as illustrated in the getRow) function, I am back in the same problem I was in before.
function checkRequest(id) {
console.log(id);
var deferred = Q.defer();
connection.query('SELECT * FROM teacher_request WHERE student_id ='+id, function(err, row){
deferred.resolve(row.length);
});
return deferred.promise;
}
var getRow = function(id){
checkRequest(id).then(function(val) {
console.log(val); // works great
return val; //back to the same problem
});
}
The roster needs to be able to be pulled from an external API which is why I am not bundling the request check with the original roster query.
Thanks in advance
From the stuff you posted, I assume you have not really understood the concept of promises. They allow you to queue up callbacks, that get executed, when the asynchronous operation has finished (by succeeding or failing).
So instead of somehow getting the results back to your synchronous workflow, you should convert that workflow to work asynchronous as well. So a small example for your current problem:
// your students' ids in here
var studentsArray = [ 1, 2, 5, 6, 9 ];
for( var i=0; i<studentsArray.length; i++ ) {
checkRequest( i )
.then( function( data ){
console.log( data.student_id );
// any other code related to a specific student in here
});
}
or another option, if you need all students' data at the same time:
// your students' ids in here
var studentsArray = [ 1, 2, 5, 6, 9 ];
// collect all promises
var reqs = [];
for( var i=0; i<studentsArray.length; i++ ) {
reqs.push( checkRequest( i ) );
}
Q.all( reqs )
.then( function(){
// code in here
// use `arguments` to access data
});