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:
1.
import
rhinoscriptsyntax as rs
2.
3.
print
rs.filter.point
# prints 1
4.
print
rs.filter.curve
# prints 4
5.
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:
01.
class
filter:
02.
allobjects
=
0
03.
point
=
1
04.
pointcloud
=
2
05.
curve
=
4
06.
surface
=
8
07.
polysurface
=
16
08.
mesh
=
32
09.
light
=
256
10.
annotation
=
512
11.
instance
=
4096
12.
textdot
=
8192
13.
grip
=
16384
14.
detail
=
32768
15.
hatch
=
65536
16.
morph
=
13072
17.
cage
=
134217728
18.
phantom
=
268435456
19.
clippingplane
=
536870912
20.
extrusion
=
1073741824
Notice that the values correspond to powers of 2. Therefore they each correspond to a different digit in the binary system:
1.
print
bin(rs.filter.point)
# prints '0b1'
2.
print
bin(rs.filter.curve)
# prints '0b100'
3.
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:
1.
print
0
&
1
# prints 0 (0000), since 0000 'and' 0001 => 0000
2.
print
2
&
3
# prints 2 (0010), since 0010 'and' 0011 => 0010
3.
print
2
&
7
# prints 2 (0010), since 0010 'and' 0111 => 0010
4.
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:
1.
print
0
&
1
# prints 1 (0001), since 0000 'and' 0001 => 0001
2.
print
2
&
3
# prints 3 (0011), since 0010 'and' 0011 => 0011
3.
print
2
&
7
# prints 7 (0111), since 0010 'and' 0111 => 0111
4.
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:
1.
guids
=
rs.ObjectsByType(rs.filter.point | rs.filter.curve)
What happens in the background is the following. The result of the combined filter is:
1.
filter
=
rs.filter.point | rs.filter.curve
2.
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:
01.
include_points
=
False
02.
include_curves
=
False
03.
include_surfaces
=
False
04.
05.
if
filter & rs.filter.point:
06.
include_points
=
True
07.
08.
if
filter & rs.filter.curve:
09.
include_curves
=
True
10.
11.
if
filter & rs.filter.surface:
12.
include_surfaces
=
True
13.
14.
print
include_points
# prints True
15.
print
include_curves
# prints True
16.
print
include_surfaces
# prints False