Bitwise operators in Python
Python has logical operators (like ‘and’) and bitwise operators (like ‘&’). Bitwise operators are not that common in Python code, but they can be extremely useful in some cases. For example, in RhinoPython they are used to work with geometry type filters.
The geometry types in the rhinoscripsyntax package are defined in the selection module and can be accessed like this:
import rhinoscriptsyntax as rs print rs.filter.point # prints 1 print rs.filter.curve # prints 4 print rs.filter.surface # prints 8
The entire list of values can be found on GitHub, but i will copy the code here for simplicity:
class filter: allobjects = 0 point = 1 pointcloud = 2 curve = 4 surface = 8 polysurface = 16 mesh = 32 light = 256 annotation = 512 instance = 4096 textdot = 8192 grip = 16384 detail = 32768 hatch = 65536 morph = 13072 cage = 134217728 phantom = 268435456 clippingplane = 536870912 extrusion = 1073741824
Notice that the values correspond to powers of 2. Therefore they each correspond to a different digit in the binary system:
print bin(rs.filter.point) # prints '0b1' print bin(rs.filter.curve) # prints '0b100' print bin(rs.filter.surface) # prints '0b1000'
This is where bitwise operators come in. Bitwise operators compare corresponding digits in two binary numbers and return a result in binary form accordingly.
Bitwise ‘and’ (&) returns a binary number with 1 at digits where both of the corresponding digits of the operands are 1:
print 0 & 1 # prints 0 (0000), since 0000 'and' 0001 => 0000 print 2 & 3 # prints 2 (0010), since 0010 'and' 0011 => 0010 print 2 & 7 # prints 2 (0010), since 0010 'and' 0111 => 0010 print 15 & 10 # prints 10 (1010), since 1111 'and' 1010 => 1010
Bitwise ‘or’ (|) returns a binary number with 1 at digits where at least one of the digits of the operands was 1:
print 0 & 1 # prints 1 (0001), since 0000 'and' 0001 => 0001 print 2 & 3 # prints 3 (0011), since 0010 'and' 0011 => 0011 print 2 & 7 # prints 7 (0111), since 0010 'and' 0111 => 0111 print 15 & 10 # prints 15 (1111), since 1111 'and' 1010 => 1111
Getting back to the example of geometry filters in rhinoscriptsyntax, this snippet returns the guids of both points and curves:
guids = rs.ObjectsByType(rs.filter.point | rs.filter.curve)
What happens in the background is the following. The result of the combined filter is:
filter = rs.filter.point | rs.filter.curve print filter # prints 5 (0101), since 0001 'or' 0100 => 0101
Comparing this combined filter with the filter values of the different geometry types using bitwise ‘and’ the function can figure out which types to include in the result:
include_points = False include_curves = False include_surfaces = False if filter & rs.filter.point: include_points = True if filter & rs.filter.curve: include_curves = True if filter & rs.filter.surface: include_surfaces = True print include_points # prints True print include_curves # prints True print include_surfaces # prints False