## 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