Hi all!
I started working with OpenSCAD but some things have seemed challenging for me to do programmatically and wanted to build some features if it would be considered for master branch. If I built bitwise operators into the language, would that be accepted to master, or should users be using Processing or similar tool for those sorts of things, or am I using OpenSCAD incorrectly or haven't learned the right way to use it?
Bitwise operators were one of the things I immediately ran into that complicated a project.
To implement bitwise AND, I needed to build a recursive and somewhat excessive arithmetic function, and wasteful on large operations since the CPU/GPUs can perform bitwise operations quickly, and I'm specifically using OpenSCAD to perform many-polygon type projects rather than traditional CAD.
// 16-bit OpenSCAD AND function -samy kamkar
function and(a, b, c=0, s=0) =
s == 15 ?
c :
and(a, b,
(c + ((floor(a/exp(ln(2)*s) % 2) *
floor(b/exp(ln(2)*s)) % 2)) *
exp(ln(2)*s)
),
s+1);
The non-return modules and single-expression functions also makes things a bit challenging. Are these restrictions due to some underlying optimization that prevents a more natural, multi-expression subroutine with a return value?
Thanks,
samy
Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.
This does not answer your primary question, but have you seen
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/List_Comprehensions
Thank for sharing, I checked the page out but is there something there that would simplify something here? I didn't notice anything.
Another challenge was doing bitwise adjustment on an iterator in a for loop, but as conditionals aren't part of for
loops and while loops don't exist, again a recursive function is necessary to do a conditional with a non-static change of the iterator.
I'm sure this is for a reason but would love to understand why and if additions of features like this would be accepted.
Thanks!
Bitwise operations are typically performed on integer types, but OpenSCAD language only has a single numeric type, which is double precision floating point. So I'm not even sure how you would define such bitwise operations over floating point values in a robust consistent way.
I've used bitwise operations plenty in other general purpose or lower level programming languages; things like defining compact data structures, handling binary I/O protocols, file formats, etc.
But I can't think of a single instance in years of using OpenSCAD where I felt like it needed them.
OpenSCAD is strictly designed for describing geometry, and general I/O isn't even part of the language. I honestly am having trouble just trying to imagine a scenario where bitwise operators would be needed or helpful in describing geometry.
Anyways, in the world of geometry, the Boolean operations union()
(OR), intersection()
(AND), difference()
(AND NOT), are the ultimate "bitwise" ops (well, more like point-wise or voluime-wise) :smiley:
You could do bitwise-and compactly if you needed it for some mathematical purpose:
function and(a,b) = (a<1 || b<1) ? 0 : ((a%2>=1) && (b%2>=1) ? 1 : 0) + 2*and(a/2, b/2);
And if needed, sequential assignment operations can be done in functions using a chain of calculations with the let() feature for variable assignments. But for most of the things you would use bit-packing for, you can probably do these in a way that better fits the language design by using comprehensions to operate on boolean lists. Almost every design I've seen created in the language, even with manually creating polyhedrons mathematically, is only computationally heavy at the geometry rendering step, so not much effort has been put into optimizing the computational side. Even if you put primitives in to convert to integers and do cpu-level bitwise operators, it would still be going through a tree of atomic-guarded shared pointers just to get to each bitwise operator. I would encourage trying it with functions operating on lists and making use of comprehensions. If a calculation is so intense that it actually requires native-level performance, then it should be done externally and output some pre-computed source code for an include statement in OpenSCAD to bring into a polyhedron call.
This is my first OpenSCAD project (I typically use Fusion360 for CAD, but at first blush it appeared to make more sense to use CAD since I needed something more programatic) and I I've ran into a number of features that would simplify this listed below, including missing bitwise operators like >>, <<, and &.
I'm producing (2D) geometry that encodes multiple consumer IR remote control commands into a single "wheel" which will be laser cut. Different commands are at different distances from the center. This is to create a mechanical IR remote control that spins around an IR LED (adjustable on the X axis), with another wheel behind it to produce the carrier wave (normally 38kHz, but most IR receivers will read at much lower rates like 10kHz) that the command signal will ride on top, and the wheels gets spun together either by a small motor or your hand.
Most IR commands (for TVs, receivers, etc) are described by a single number, and the data is encoded in those commands...which would use bitwise operators to easily extract the data and thus produce the geometry, in this case, rectangles of differing lengths around an axis.
OpenSCAD is great but simply may not be the right tool, but I'm contemplating if it's worth me investing some effort into implementing some features that made this project more difficult than I imagined (Fusion 360 allows Python and C but the primitives aren't as simple as OpenSCAD which is why I thought it made more sense).
The specific areas that have made this project quite a bit more challenging:
While I can see this can all be done in other ways, it's going to be much more complicated for users who are already used to programming in any modern language, which might be acceptable for this project, that's essentially my ask. Is this meant to be an opinionated language that would balk at new features like the above, or is the project interested in a larger user base by making some things easier such as providing familiar programming functionality? Had I not been stubborn and curious about the mental exercise of getting this working, I would have switched back to Processing/Fusion to perform this.
Extending the language is certainly on the list, this happens all the time. There's quite a number of discussions open in that regard (e.g. #3087, #3115), so I'm not sure what specifically you are asking.
In general, language changes need to be discussed for compatibility and future extensibility. So working together towards additional features is great. What's not going to work is dropping a patch for a specific case and assume someone else will take care of the details.
Thanks @t-paul, that's helpful information! I'll review those tickets to get an idea of the process.
Also, although not part of the language all those things can be implemented
in user code. For example it would be possible to store long hex values in
strings and loop through them.
Bit-wise AND could be done with a recursive function. The shifts are just
multiple and divide by powers of two, etc. You would be limited to the
range of integers that can be stored as floats.
As pointed out previously, you can have multi-line expressions in function
bodies using let().
Making physical objects from hex strings does seem to be a bit of niche use
case, which is why OpenSCAD doesn't have support for it.
On Mon, 1 Jun 2020 at 18:16, Samy Kamkar notifications@github.com wrote:
Thanks @t-paul https://github.com/t-paul, that's helpful information!
I'll review those tickets to get an idea of the process.—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/openscad/openscad/issues/3345#issuecomment-636995504,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAEKHBIDYLX5XB24FW3ZX43RUPO65ANCNFSM4NPPPAGA
.
Agreed, more flexible data types and maybe even the multi-expressions (without let) would likely be much more useful for general OpenSCAD usage than bitwise operations.
So basically the range is between just adding every feature imaginable and trying to minimize the core (while empowering users to write libraries). Considering the development hours available the tendency is certainly towards a more maintainable core and adding high level features that are not feasible via user code.
But at any rate, it's useful to hear all cases and suggestions so they can be discussed and justified. Maybe it turns out there's a different core change possible making the feature easier to implement in user space.
rcolyer gave a good example of another way to do Bitwise-AND.
For some of the other operations:
Here is my own example code for how I would handle most of what you are asking about:
// Logical shift operations expect positive integer inputs
function shl(x,y) = x * pow(2,y);
function shr(x,y) = floor(x * pow(2,-y));
// convert hex character to number
function hexDigit(c) =
let(o = ord(c))
c >= "0" && c <= "9" ? o - ord("0") :
c >= "a" && c <= "f" ? o - ord("a") + 10 :
c >= "A" && c <= "F" ? o - ord("A") + 10 : undef;
// convert hex string to number
function hexToNum(s, i=0, temp=0) =
i==0 && s[0]=="0" && s[1]=="x" ? hexToNum(s,2,0) :
i>=len(s) ? temp : hexToNum(s,i+1, temp*16+hexDigit(s[i]));
// Convert positive integer to list of bits **from least significant to most significant**
// For results going in the other direction, use the following "reverse" function
function numToBits(x) = x==0 ? [0] : [for(n=x; n>=1; n=shr(n,1)) n%2];
function reverse(v) = [for(i=[len(v)-1:-1:0]) v[i] ];
// A few usage examples:
echo([for(i=[0:1:16]) shl(1,i)]);
echo([for(i=[0:1:16]) shr(65536,i)]);
echo(hexToNum("0x64"));
echo(hexToNum("ff"));
echo(hexToNum("0xFF"));
echo(hexToNum("100"));
echo(numToBits(hexToNum("0xF0")));
echo(numToBits(100));
echo(reverse(numToBits(100)));
Most helpful comment
Agreed, more flexible data types and maybe even the multi-expressions (without let) would likely be much more useful for general OpenSCAD usage than bitwise operations.
So basically the range is between just adding every feature imaginable and trying to minimize the core (while empowering users to write libraries). Considering the development hours available the tendency is certainly towards a more maintainable core and adding high level features that are not feasible via user code.
But at any rate, it's useful to hear all cases and suggestions so they can be discussed and justified. Maybe it turns out there's a different core change possible making the feature easier to implement in user space.