OpenSCAD: How to avoid extra grouping in CSG tree - openscad

I want to write a module that can optionally combine its children as either a union or a difference.
module u_or_d(option="d") {
if (option == "d") {
difference() children();
} else {
union() children();
}
}
module thing(option) {
u_or_d(option) {
cube(10, center=true);
cylinder(h=20, d=5, center=true);
}
}
translate([-15, 0, 0]) thing("d");
translate([ 15, 0, 0]) thing("u");
I was surprised that this doesn't work. Both instances of thing appear to create a union of the cube and the cylinder.
The CSG Tree Dump shows the problem. Here's the relevant excerpt:
difference() {
group() {
cube(size = [10, 10, 10], center = true);
cylinder($fn = 0, $fa = 12, $fs = 2, h = 20, r1 = 2.5, r2 = 2.5, center = true);
}
}
The children are wrapped in a group, so the difference() effectively has only one child, which happens to be an implicit union of the wrapped children.
Is there a way to invoke children() that avoids this unwanted grouping? If not, is there another way for a module to allow the invoker to select how the module combines its children?

I found a solution:
module u_or_d(option="d") {
if (option == "d" && $children > 1) {
difference() {
children([0]);
children([1:$children-1]);
}
} else {
union() children();
}
}
You still get a group wrapped around each invocation of children, but at least we can make two groups.

Related

How to set agents location using for loop in Java

I am using this code for assigning dfferent node to different agents
int[] node = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for (int i = 0; i < node.length; i++) {
if(agent.participant == i + 1){
agent.setLocation(node[i]);
}
}
The only problem is setLocation() function only accept point arguments not integer.
I also try to make the list of points but it does not work. Let me know how to solve this issue.
As per Emile:
Node[] nodes = {node0, node1, ...};
int counter=0;
for (Node currNode : nodes) {
if(agent.participant == counter + 1){
agent.setLocation(nodes [i]);
counter++;
}
}
You need to understand function arguments. setLocation(...) cannot work with an int, it needs something that is an actual location. Check the API, code-complete help, etc

How do I apply a list of translations to the same object?

imagine I have a list of translations which I want to apply to the same object.
for instance, a list which defines rotation and translation
list = [[10,20],[30,45]]
how to I apply them in a for loop to one object?
I am looking for something like
for (i=list) {
translate([i[0],0,0])
rotate([i[1],0,0])
}
cube([10,1,1]);
obviously, that is the wrong approach...
any ideas?
This could be done by defining a module that steps through the list recursively.
list = [[10,20],[30,45]];
module transform(list, idx = 0) {
if (idx >= len(list)) {
children();
} else {
translate([list[idx][0],0,0])
rotate([list[idx][1],0,0])
transform(list, idx + 1)
children();
}
}
transform(list) cube([10,1,1]);

Operator CombineLatest - is possible determine stream of last emited item?

I use combineLatest for join of two streams with two types of tasks. Processing two types of tasks should be interleaved. Is possible to determine which stream emits last value of pair?
I use solution with timestamp, but it is not correct. Each subject contain default value.
List<Flowable<? extends Timed<? extends Task>>> sources = new ArrayList<>();
Flowable<Timed<TaskModification>> modificationSource = mTaskModificationSubject
.onBackpressureDrop()
.observeOn(Schedulers.io(), false, 1)
.timestamp();
Flowable<Timed<TaskSynchronization>> synchronizationSource = mTaskSynchronizationSubject
.onBackpressureDrop()
.observeOn(Schedulers.io(), false, 1)
.flatMap(TaskSynchronizationWrapper::getSources)
.timestamp();
sources.add(0, modificationSource);
sources.add(1, synchronizationSource);
return Flowable
.combineLatest(sources, array -> {
Timed<TaskModification> taskModification = (Timed<TaskModification>) array[0];
Timed<TaskSynchronization> taskSynchronization = (Timed<TaskSynchronization>) array[1];
return (taskModification.time() > taskSynchronization.time())
? taskModification.value()
: taskSynchronization.value();
}, 1)
.observeOn(Schedulers.io(), false, 1)
.flatMapSingle(
Task::getSource
)
.ignoreElements();
When modification task is emitted than should have priority before synchronization tasks.
Without implementing a custom operator, you could introduce queues, merge the signals, then pick items from the priority queue first:
Flowable<X> prioritySource = ...
Flowable<X> source = ...
Flowable<X> output = Flowable.defer(() -> {
Queue<X> priorityQueue = new ConcurrentLinkedQueue<>();
Queue<X> queue = new ConcurrentLinkedQueue<>();
return Flowable.merge(
prioritySource.map(v -> {
priorityQueue.offer(v);
return 1;
}),
source.map(v -> {
queue.offer(v);
return 1;
})
)
.map(v -> {
if (!priorityQueue.isEmpty()) {
return priorityQueue.poll();
}
return queue.poll();
});
});

Is it possible to create a macro which counts the number of expanded items?

Is it possible to create a macro which counts the number of expanded items?
macro_rules! count {
($($name:ident),*) => {
pub enum Count {
$(
$name = 1 << $i // $i is the current expansion index
),*
}
}
}
count!(A, B, C);
Here is a macro that counts the number of matched items:
macro_rules! count_items {
($name:ident) => { 1 };
($first:ident, $($rest:ident),*) => {
1 + count_items!($($rest),*)
}
}
fn main() {
const X: usize = count_items!(a);
const Y: usize = count_items!(a, b);
const Z: usize = count_items!(a, b, c);
assert_eq!(1, X);
assert_eq!(2, Y);
assert_eq!(3, Z);
}
Note that the counting is computed at compile time.
For your example, you can do it using accumulation:
macro_rules! count {
($first:ident, $($rest:ident),*) => (
count!($($rest),+ ; 0; $first = 0)
);
($cur:ident, $($rest:ident),* ; $last_index: expr ; $($var:ident = $index:expr)+) => (
count!($($rest),* ; $last_index + 1; $($var = $index)* $cur = $last_index + 1)
);
($cur:ident; $last_index:expr ; $($var:ident = $index:expr)+) => (
#[repr(C)]
enum Count {
$($var = 1 << $index),*,
$cur = 1 << ($last_index + 1),
}
);
}
pub fn main() {
count!(A, B, C, D);
assert_eq!(1, Count::A as usize);
assert_eq!(2, Count::B as usize);
assert_eq!(4, Count::C as usize);
assert_eq!(8, Count::D as usize);
}
Yes, if you pack it as array of idents:
macro_rules! count {
($($name:ident),*) => {
{
let counter = [$(stringify!($name),)*];
counter.len()
}
}
}
Count, names, reverse order of names are available. After, you can use it to construct something. For enum building you have to join it with something like this.
In this context, no. A macro could create an expression that counts the number of identifiers passed to it, but it would only be evaluated at runtime. I created this example in just a few minutes, but I realized it would not work for what you're doing.
Compiler plugins, however, are particularly suited to this sort of work. While they're not trivial to implement, I don't think it would be overly difficult to create one for this purpose. Maybe take a look, try your hand at it, and come back if you get stuck?
Since this question is general, posting an example of counting where arguments are separated by white-space (not commas).
Although in retrospect it seems obvious, it took me a while to figure out:
/// Separated by white-space.
#[macro_export]
macro_rules! count_args_space {
($name:ident) => { 1 };
($first:ident $($rest:ident) *) => {
1 + count_args_space!($($rest) *)
}
}
/// Separated by commas.
#[macro_export]
macro_rules! count_args_comma {
($name:ident) => { 1 };
($first:ident, $($rest:ident),*) => {
1 + count_args_comma!($($rest),*)
}
}
Second example is from #malbarbo, just posting to so you can see the 2x changes that were needed.

Is there a way to auto expand objects in Chrome Dev Tools?

EVERY SINGLE TIME I view an object in the console I am going to want to expand it, so it gets tiresome to have to click the arrow to do this EVERY SINGLE TIME :) Is there a shortcut or setting to have this done automatically?
Consider using console.table().
To expand / collapse a node and all its children,
Ctrl + Alt + Click or Opt + Click on arrow icon
(note that although the dev tools doc lists Ctrl + Alt + Click, on Windows all that is needed is Alt + Click).
While the solution mentioning JSON.stringify is pretty great for most of the cases, it has a few limitations
It can not handle items with circular references where as console.log can take care of such objects elegantly.
Also, if you have a large tree, then ability to interactively fold away some nodes can make exploration easier.
Here is a solution that solves both of the above by creatively (ab)using console.group:
function expandedLog(item, maxDepth = 100, depth = 0){
if (depth > maxDepth ) {
console.log(item);
return;
}
if (typeof item === 'object' && item !== null) {
Object.entries(item).forEach(([key, value]) => {
console.group(key + ' : ' +(typeof value));
expandedLog(value, maxDepth, depth + 1);
console.groupEnd();
});
} else {
console.log(item);
}
}
Now running:
expandedLog({
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
})
Will give you something like:
The value of maxDepth can be adjusted to a desired level, and beyond that level of nesting - expanded log will fall back to usual console.log
Try running something like:
x = { a: 10, b: 20 }
x.x = x
expandedLog(x)
Also please note that console.group is non-standard.
Might not be the best answer, but I've been doing this somewhere in my code.
Update:
Use JSON.stringify to expand your object automatically:
> a = [{name: 'Joe', age: 5}, {name: 'John', age: 6}]
> JSON.stringify(a, true, 2)
"[
{
"name": "Joe",
"age": 5
},
{
"name": "John",
"age": 6
}
]"
You can always make a shortcut function if it hurts to type all that out:
j = function(d) {
return JSON.stringify(d, true, 2)
}
j(a)
Previous answer:
pretty = function(d)
{
var s = []
for (var k in d) {
s.push(k + ': ' + d[k])
}
console.log(s.join(', '))
}
then, instead of:
-> a = [{name: 'Joe', age: 5}, {name: 'John', age: 6}]
-> a
<- [Object, Object]
You do:
-> a.forEach(pretty)
<- name: Joe, age: 5
name: John, age: 6
Not the best solution, but works well for my usage. Deeper objects will not work so that's something that can be improved on.
option+Click on a Mac. Just discovered it now myself and have made my week! This has been as annoying as anything
By default the console on Chrome and Safari browsers will output objects which are collapsed, with sorted property keys, and include all inherited prototype chains.
I'm personally not a fan. Most developers need raw output of an object without the prototype chain, and anything else should be opt-in. Collapsed objects waste the developer's time, because they need to expand them, and if they wanted less output they could just log the property keys they need. Auto-sorting the property keys, leaves the developer without a way to check if their own sort works correctly, which could cause bugs. And lastly, the common Javascript developer does not spend much time working on the inherited prototype chain, so that adds noise to the logs.
How to expand objects in Console
Recommended
console.log(JSON.stringify({}, undefined, 2));
Could also use as a function:
console.json = object => console.log(JSON.stringify(object, undefined, 2));
console.json({});
"Option + Click" (Chrome on Mac) and "Alt + Click" (Chrome on Window)
However, it's not supported by all browsers (e.g. Safari), and Console still prints the prototype chains, auto-sorts property keys, etc.
Not Recommended
I would not recommend either of the top answers
console.table() - this is shallow expansion only, and does not expand nested objects
Write a custom underscore.js function - too much overhead for what should be a simple solution
Here is a modified version of lorefnon's answer which does not depend on underscorejs:
var expandedLog = (function(MAX_DEPTH){
return function(item, depth){
depth = depth || 0;
isString = typeof item === 'string';
isDeep = depth > MAX_DEPTH
if (isString || isDeep) {
console.log(item);
return;
}
for(var key in item){
console.group(key + ' : ' +(typeof item[key]));
expandedLog(item[key], depth + 1);
console.groupEnd();
}
}
})(100);
Here is my solution, a function that iterates an all the properties of the object, including arrays.
In this example I iterate over a simple multi-level object:
var point = {
x: 5,
y: 2,
innerobj : { innerVal : 1,innerVal2 : 2 },
$excludedInnerProperties : { test: 1},
includedInnerProperties : { test: 1}
};
You have also the possibility to exclude the iteration if the properties starts with a particular suffix (i.e. $ for angular objects)
discoverProperties = function (obj, level, excludePrefix) {
var indent = "----------------------------------------".substring(0, level * 2);
var str = indent + "level " + level + "\r\n";
if (typeof (obj) == "undefined")
return "";
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
var propVal;
try {
propVal = eval('obj.' + property);
str += indent + property + "(" + propVal.constructor.name + "):" + propVal + "\r\n";
if (typeof (propVal) == 'object' && level < 10 && propVal.constructor.name != "Date" && property.indexOf(excludePrefix) != 0) {
if (propVal.hasOwnProperty('length')) {
for (var i = 0; i < propVal.length; i++) {
if (typeof (propVal) == 'object' && level < 10) {
if (typeof (propVal[i]) != "undefined") {
str += indent + (propVal[i]).constructor.name + "[" + i + "]\r\n";
str += this.discoverProperties(propVal[i], level + 1, excludePrefix);
}
}
else
str += indent + propVal[i].constructor.name + "[" + i + "]:" + propVal[i] + "\r\n";
}
}
else
str += this.discoverProperties(propVal, level + 1, excludePrefix);
}
}
catch (e) {
}
}
}
return str;
};
var point = {
x: 5,
y: 2,
innerobj : { innerVal : 1,innerVal2 : 2 },
$excludedInnerProperties : { test: 1},
includedInnerProperties : { test: 1}
};
document.write("<pre>" + discoverProperties(point,0,'$')+ "</pre>");
Here is the output of the function:
level 0
x(Number):5
y(Number):2
innerobj(Object):[object Object]
--level 1
--innerVal(Number):1
--innerVal2(Number):2
$excludedInnerProperties(Object):[object Object]
includedInnerProperties(Object):[object Object]
--level 1
--test(Number):1
You can also inject this function in any web page and copy and analyze all the properties, try in on the google page using the chrome command:
discoverProperties(google,0,'$')
Also you can copy the output of the command using the chrome command:
copy(discoverProperties(myvariable,0,'$'))
if you have a big object, JSON.stringfy will give error Uncaught TypeError: Converting circular structure to JSON
, here is trick to use modified version of it
JSON.stringifyOnce = function(obj, replacer, indent){
var printedObjects = [];
var printedObjectKeys = [];
function printOnceReplacer(key, value){
if ( printedObjects.length > 2000){ // browsers will not print more than 20K, I don't see the point to allow 2K.. algorithm will not be fast anyway if we have too many objects
return 'object too long';
}
var printedObjIndex = false;
printedObjects.forEach(function(obj, index){
if(obj===value){
printedObjIndex = index;
}
});
if ( key == ''){ //root element
printedObjects.push(obj);
printedObjectKeys.push("root");
return value;
}
else if(printedObjIndex+"" != "false" && typeof(value)=="object"){
if ( printedObjectKeys[printedObjIndex] == "root"){
return "(pointer to root)";
}else{
return "(see " + ((!!value && !!value.constructor) ? value.constructor.name.toLowerCase() : typeof(value)) + " with key " + printedObjectKeys[printedObjIndex] + ")";
}
}else{
var qualifiedKey = key || "(empty key)";
printedObjects.push(value);
printedObjectKeys.push(qualifiedKey);
if(replacer){
return replacer(key, value);
}else{
return value;
}
}
}
return JSON.stringify(obj, printOnceReplacer, indent);
};
now you can use JSON.stringifyOnce(obj)
Its a work around, but it works for me.
I use in the case where a control/widget auto updates depending on user actions. For example, when using twitter's typeahead.js, once you focus out of the window, the dropdown disappears and the suggestions get removed from the DOM.
In dev tools right click on the node you want to expand enable break on... -> subtree modifications, this will then send you to the debugger. Keep hitting F10 or Shift+F11 untill you dom mutates. Once that mutates then you can inspect. Since the debugger is active the UI of Chrome is locked and doesn't close the dropdown and the suggestions are still in the DOM.
Very handy when troubleshooting layout of dynamically inserted nodes that are begin inserted and removed constantly.
Another easier way would be
Use JSON.stringify(jsonObject)
Copy and Paste the result to Visual Studio Code
Use Ctrl+K and Ctrl+F to format the result
You will see formatted expanded object
I have tried this for simple objects.
You can package JSON.stringify into a new function eg
jsonLog = function (msg, d) {
console.log(msg + '\n' + JSON.stringify(d, true, 2))
}
then
jsonLog('root=', root)
FWIW.
Murray
For lazy folks
/**
* _Universal extensive multilevel logger for lazy folks_
* #param {any} value **`Value` you want to log**
* #param {number} tab **Abount of `tab`**
*/
function log(value, tab = 4) {
console.log(JSON.stringify(value, undefined, tab));
}
Usage
log(anything) // [] {} 1 true null
Alt-click will expand all child nodes in the Chrome console.
You could view your element by accessing document.getElementsBy... and then right click and copy of the resulted object. For example:
document.getElementsByTagName('ion-app') gives back javascript object that can be copy pasted to text editor and it does it in full.
Better yet: right click on the resulted element - 'Edit as html' - 'Select all' - 'Copy' - 'Paste'