abort object3d.traverse in three.js - three.js

How can I abort the traverse when I traverse a three.js object?
scene.traverse(x => {
if (x.userData)
// stop traversing here
});
return and break do not work

Object3D.traverse code (r134)
You would need to modify the traverse function to bail based on output from your callback function.
Something like this (untested):
// three.js/src/core/Object3D.js
traverse( callback ) {
let bailedOut = callback( this );
if( !bailedOut ) {
const children = this.children;
for ( let i = 0, l = children.length; i < l && !bailedOut; i ++ ) {
bailedOut = children[ i ].traverse( callback );
}
}
return bailedOut;
}
And then call it like:
function doTheThing( node ) {
let bailOut = false;
if( node.userData ) {
bailOut = true;
}
else {
// do the thing
}
return bailOut;
}
scene.traverse( doTheThing );
The processing basically continues until your callback returns true, at which point it triggers a cascade back up the traverse recursion chain until it exits the original call.

Related

Cloning a THREE.Group hierarchy

I have a hierarchy of groups, A -> B -> C. I wish to create a clone of this hierarchy, A2 -> B2 -> C2.
But Object3D.clone() removes the parent reference of the group.
Other than manually setting the parent for each of the child-groups after cloning, what other way is there?
If the hierarchy is deep this could get take to compute.
Thanks for the help!
Maybe you can check out this question Will three.js Object3D.clone() create a deep copy of the geometry?
I extends the copyand clone methods in Object3D to deep clone mesh materials.
And in your case , this should works too.
First,extends two new methods in THREE:
THREE.Object3D.prototype.deepClone = function ( recursive ) {
return new this.constructor().deepCopy( this, recursive );
},
THREE.Object3D.prototype.deepCopy = function( source, recursive ) {
if ( recursive === undefined ) recursive = true;
this.name = source.name;
this.up.copy( source.up );
this.position.copy( source.position );
this.quaternion.copy( source.quaternion );
this.scale.copy( source.scale );
this.matrix.copy( source.matrix );
this.matrixWorld.copy( source.matrixWorld );
if(source.material){
//changed
this.material = source.material.clone()
}
if(source.geometry){
//changed
this.geometry = source.geometry.clone()
}
this.matrixAutoUpdate = source.matrixAutoUpdate;
this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
this.layers.mask = source.layers.mask;
this.visible = source.visible;
this.castShadow = source.castShadow;
this.receiveShadow = source.receiveShadow;
this.frustumCulled = source.frustumCulled;
this.renderOrder = source.renderOrder;
this.userData = JSON.parse( JSON.stringify( source.userData ) );
if ( recursive === true ) {
for ( var i = 0; i < source.children.length; i ++ ) {
var child = source.children[ i ];
this.add( child.deepClone() ); //changed
}
}
return this;
}
Second,when you want to deep clone a Object3D or Scene named originalObj.just do var newObj = originalObj.deepClone()

Compare most recent values from multiple BehaviorSubjects

Say I have this:
isMatchedCountLessThanTotalCountMessage(){
// I want to implement this
// "returns" a string asynchronously
}
getMatchedEventsCount() {
return this.dcs.matchCount.asObservable();
}
getTotalEventsCount() {
return this.dcs.totalCount.asObservable();
}
matchedCount and totalCount are like so:
public matchCount = new BehaviorSubject<number>(0);
public totalCount = new BehaviorSubject<number>(0);
these Observables fire integers as values change. Anytime a value is fired from either one, I want to compare the two most recent values from both, how do I do that?
What I want to do is return a boolean from the method
so I can display in the HTML:
<div>{{(isMatchedCountLessThanTotalCountMessage() | async)}}</div>
I think Observable.zip might do the trick:
isMatchedCountLessThanTotalCountMessage(){
return Observable.zip(
this.getMatchedEventsCount(),
this.getTotalEventsCount()
)
.subscribe(function(v){
const intA = v[0];
const intB = v[1];
if(intA > intB)
// but I don't know how to send a message the HTML from here
});
}
You can easily use .map() function to transform the data you want:
isMatchedCountLessThanTotalCountMessage() {
return Observable.combineLatest(
this.getMatchedEventsCount(),
this.getTotalEventsCount(),
)
.map(([intA, intB]) => {
return intA > intB ? '(results ARE filtered)' : '(results are not filtered)'
})
}
This works, although we might be able to use something other than Observable.zip.
isMatchedCountLessThanTotalCount() {
return Observable.create(obs => {
return Observable.zip(
this.getMatchedEventsCount(),
this.getTotalEventsCount()
)
.subscribe(v => {
if ((v[1] - v[0]) > 0) {
obs.next('(results ARE filtered)')
}
else {
obs.next('(results are not filtered)');
}
});
});
}
and there is actually a simpler way to do that using what's called a "projection function":
isMatchedCountLessThanTotalCount() {
return Observable.combineLatest(
this.getMatchedEventsCount(),
this.getTotalEventsCount(),
function (one, two) {
if ((two - one) > 0) {
return '(results ARE filtered)'
}
return '(results are not filtered)';
}
)
}
Observable.combineLatest() is similar to Observable.zip() but will fire upon the first new value, it doesn't wait for new values to come from all observables.

how to use lockf with xerces-c

I am new to programming and I am trying to use lockf to lock a XML file. I using xerces-c to parse the XML file and I need to lock the file. The function is similar the the example below:
void GetConfig::readConfigFile(string& configFile)
throw( std::runtime_error )
{
// Configure DOM parser.
m_ConfigFileParser->setValidationScheme( XercesDOMParser::Val_Never );
m_ConfigFileParser->setDoNamespaces( false );
m_ConfigFileParser->setDoSchema( false );
m_ConfigFileParser->setLoadExternalDTD( false );
try
{
m_ConfigFileParser->parse( configFile.c_str() );
// no need to free this pointer - owned by the parent parser object
DOMDocument* xmlDoc = m_ConfigFileParser->getDocument();
// Get the top-level element: NAme is "root". No attributes for "root"
DOMElement* elementRoot = xmlDoc->getDocumentElement();
if( !elementRoot ) throw(std::runtime_error( "empty XML document" ));
// Parse XML file for tags of interest: "ApplicationSettings"
// Look one level nested within "root". (child of root)
DOMNodeList* children = elementRoot->getChildNodes();
const XMLSize_t nodeCount = children->getLength();
// For all nodes, children of "root" in the XML tree.
for( XMLSize_t xx = 0; xx < nodeCount; ++xx )
{
DOMNode* currentNode = children->item(xx);
if( currentNode->getNodeType() && // true is not NULL
currentNode->getNodeType() == DOMNode::ELEMENT_NODE ) // is element
{
// Found node which is an Element. Re-cast node as element
DOMElement* currentElement
= dynamic_cast< xercesc::DOMElement* >( currentNode );
if( XMLString::equals(currentElement->getTagName(), TAG_ApplicationSettings))
{
// Already tested node as type element and of name "ApplicationSettings".
// Read attributes of element "ApplicationSettings".
const XMLCh* xmlch_OptionA
= currentElement->getAttribute(ATTR_OptionA);
m_OptionA = XMLString::transcode(xmlch_OptionA);
const XMLCh* xmlch_OptionB
= currentElement->getAttribute(ATTR_OptionB);
m_OptionB = XMLString::transcode(xmlch_OptionB);
break; // Data found. No need to look at other elements in tree.
}
}
}
}
}
So, can anyone help me to implement lockf in this function?

Ace Editor: Lock or Readonly Code Segment

Using the Ace Code Editor can I lock or make readonly a segment of code but still allow other lines of code to be written or edited during a session?
Here is the start of a solution:
$(function() {
var editor = ace.edit("editor1")
, session = editor.getSession()
, Range = require("ace/range").Range
, range = new Range(1, 4, 1, 10)
, markerId = session.addMarker(range, "readonly-highlight");
session.setMode("ace/mode/javascript");
editor.keyBinding.addKeyboardHandler({
handleKeyboard : function(data, hash, keyString, keyCode, event) {
if (hash === -1 || (keyCode <= 40 && keyCode >= 37)) return false;
if (intersects(range)) {
return {command:"null", passEvent:false};
}
}
});
before(editor, 'onPaste', preventReadonly);
before(editor, 'onCut', preventReadonly);
range.start = session.doc.createAnchor(range.start);
range.end = session.doc.createAnchor(range.end);
range.end.$insertRight = true;
function before(obj, method, wrapper) {
var orig = obj[method];
obj[method] = function() {
var args = Array.prototype.slice.call(arguments);
return wrapper.call(this, function(){
return orig.apply(obj, args);
}, args);
}
return obj[method];
}
function intersects(range) {
return editor.getSelectionRange().intersects(range);
}
function preventReadonly(next, args) {
if (intersects(range)) return;
next();
}
});
see it working in this fiddle: http://jsfiddle.net/bzwheeler/btsxgena/
The major working pieces are:
create start and end ace anchors which track the location of a 'readonly' portion as the document around it changes.
create a range to encapsulate the anchors
add a custom keyhandler to check if the current impending keypress will affect the readonly range and cancel it if so.
add custom paste/cut handlers to protect against right-click menu and browser menu cut/paste actions
You can do it by listening to the exec events:
// Prevent editing first and last line of editor
editor.commands.on("exec", function(e) {
var rowCol = editor.selection.getCursor();
if ((rowCol.row === 0) || ((rowCol.row + 1) === editor.session.getLength())) {
e.preventDefault();
e.stopPropagation();
}
});
Source: https://jsfiddle.net/tripflex/y0huvc1b/
I suggest something else easier and more reliable to prevent range to be modified (check it!)
var old$tryReplace = editor.$tryReplace;
editor.$tryReplace = function(range, replacement) {
return intersects(range)?null:old$tryReplace.apply(this, arguments);
}
var session = editor.getSession();
var oldInsert = session.insert;
session.insert = function(position, text) {
return oldInsert.apply(this, [position, outsideRange(position)?text:""]);
}
var oldRemove = session.remove;
session.remove = function(range) {
return intersects(range)?false:oldRemove.apply(this, arguments);
}
var oldMoveText = session.moveText;
session.moveText = function(fromRange, toPosition, copy) {
if (intersects(fromRange) || !outsideRange(toPosition)) return fromRange;
return oldMoveText.apply(this, arguments)
}
outsideRange = function (position) {
var s0 = range.start;
if (position.row < s0.row || (position.row == s0.row && position.column <= s0.column)) return true; // position must be before range.start
var e0 = range.end;
if (position.row > e0.row || (position.row == e0.row && position.column >= e0.column)) return true; // or after range.end
return false;
}
intersects = function(withRange) {
var e = withRange.end, s0 = range.start, s = withRange.start, e0 = range.end;
if (e.row < s0.row || (e.row == s0.row && e.column <= s0.column)) return false; // withRange.end must be before range.start
if (s.row > e0.row || (s.row == e0.row && s.column >= e0.column)) return false; // or withRange.start must be after range.end
return true;
}

How to Hide/Show Objects using Three.js release 54?

I've asked this question as a part of Huge question but was recommended to ask in parts. Here comes the part of my previous question. My previous question was: Here
I've been using Three.js Release 50 and able to show/hide the objects (In my application, it is a mesh child) with the help of:
THREE.SceneUtils.traverseHierarchy(mesh,function(child){
var z = document.getElementById("cameras").selectedIndex*5 -10;
if (z === -10){
child.visible = true;
} else if (child.position.z !== z){
child.visible = false;
} else {
child.visible = true;
};
});
But while using release 54, it is said that to use, object.traverse but found very difficult to the same. How to replace the above code using release 54? The error I'm getting while using release 54 is:
Please help me to sort this out.
Is the 'mesh' variable you are sending the 'traverseHierarchy' function an Object3d?
If so have you tried 'mesh.children' which should return an array of child objects, or you could use the traverse function on the mesh object.
See: http://mrdoob.github.com/three.js/docs/54/#Reference/Core/Object3D
mesh.traverse(function(child) {
var z = document.getElementById("cameras").selectedIndex * 5 - 10;
if (z === -10) {
child.visible = true;
} else if (child.position.z !== z) {
child.visible = false;
} else {
child.visible = true;
};
});
Dig deeper, answers you will find.
object.traverseHierarchy() was renamed to object.traverse()
$ grep -A10 'traverse: function' build/three.js
traverse: function ( callback ) {
callback( this );
for ( var i = 0, l = this.children.length; i < l; i ++ ) {
this.children[ i ].traverse( callback );
}
},
simply use the object traverse method to hide the mesh in three.js.In my code hide the object based on its name
object.traverse ( function (child) {
if (child instanceof THREE.Mesh) {
if (child.name.includes("3F")) {
child.visible = true;
} else {
child.visible = false;
}
}
});

Resources