#FEATURE by cg
authorClaus Gittinger <cg@exept.de>
Mon, 28 Aug 2017 15:14:38 +0200
changeset 22219 3dadc5038ad8
parent 22218 d501998293f7
child 22220 afff1eb8cb71
#FEATURE by cg class: Integer added: #bitDeinterleave: #bitInterleaveWith: #bitInterleaveWith:and: comment/format in: #bitInterleave:
Integer.st
--- a/Integer.st	Mon Aug 28 13:54:25 2017 +0200
+++ b/Integer.st	Mon Aug 28 15:14:38 2017 +0200
@@ -1660,6 +1660,142 @@
     "Modified (comment): / 09-01-2012 / 19:51:00 / cg"
 !
 
+bitDeinterleave:n
+    "extract count integers from an n-way Morton number as a vector;
+     i.e. if count is 3,
+     and the receiver's bits are
+        cN bN aN ... c2 b2 a2 c1 b1 a1 c0 b0 a0
+     then the result will be a vector containing the numbers a,b,c with bits:
+        aN ... a2 a1 a0
+        bN ... b2 b1 b0 
+        cN ... c2 c1 c0.
+     This is the inverse operation from bitInterleave:"
+     
+    |v shift tuple|
+
+    tuple := Array new:n withAll:0.
+
+    shift := 0.
+    v := self.
+    [ v > 0 ] whileTrue:[
+        1 to:n do:[:i |
+            tuple at:i put:((tuple at:i) bitOr:((v bitAnd:1) bitShift:shift)).
+            v := v rightShift:1.
+        ].
+        shift := shift + 1.
+    ].
+    ^ tuple
+
+    "
+     (2r1100 bitInterleaveWith:2r1001) -> 2r11100001
+     (2r11000110 bitInterleaveWith:2r10011100 and:2r10100101) -> 2r111100001010010111100001.
+
+     2r11100001 bitDeinterleave:2
+     
+     (2r11000110 bitInterleaveWith:2r10011100 and:2r10100101) 
+     (198 bitInterleaveWith:156 and:165) bitDeinterleave:3
+    "
+
+    "Created: / 28-08-2017 / 15:02:31 / cg"
+!
+
+bitInterleaveWith:anInteger
+    "generate a Morton number (-> https://en.wikipedia.org/wiki/Morton_number_(number_theory)) 
+     by interleaving bits of the receiver (at odd positions if counting from 1) 
+     with bits of the argument (at even bit positions).
+     
+     Thus, if the bits of the receiver are
+        aN ... a2 a1 a0
+     and those of the argument are:
+        bN ... b2 b1 b0
+     the result is
+        bN aN ... b2 a2 b1 a1 b0 a0.
+
+     Morton numbers are great to linearize 2D coordinates
+     eg. to sort 2D points by distances"    
+
+    "/ a naive and slow fallback here, using a small map to process cunks of 4 bits
+
+    |a b shift ma mb val|
+
+    a := self.
+    b := anInteger.
+    val := 0.
+    shift := 0.
+    [ (a == 0) and:[b == 0]] whileFalse:[
+        "/ strip off 4 bits from each...
+        "/ 0000       0001       0010       0011       0100       0101       0110       0111       1000       1001       1010       1011       1100       1101       1110       1111 
+        mb := #[ 2r00000000 2r00000010 2r00001000 2r00001010 2r00100000 2r00100010 2r00101000 2r00101010 2r10000000 2r10000010 2r10001000 2r10001010 2r10100000 2r10100010 2r10101000 2r10101010 ] 
+                at:((b bitAnd:2r1111)+1).
+        ma := #[ 2r00000000 2r00000001 2r00000100 2r00000101 2r00010000 2r00010001 2r00010100 2r00010101 2r01000000 2r01000001 2r01000100 2r01000101 2r01010000 2r01010001 2r01010100 2r01010101 ]
+                at:((a bitAnd:2r1111)+1).
+        val := val bitOr:((ma bitOr:mb) bitShift:shift).
+        shift := shift + 8.
+        a := a rightShift:4.
+        b := b rightShift:4.
+    ].
+    ^ val.
+
+    "
+     (2r11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 
+     bitInterleaveWith:2r10010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) 
+        -> 2r1101001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+
+     (2r11000101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 
+     bitInterleaveWith:2r10010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) 
+        -> 2r1101001000010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+    "
+
+    "Created: / 28-08-2017 / 14:33:08 / cg"
+!
+
+bitInterleaveWith:integer1 and:integer2
+    "generate a Morton3 number (-> https://en.wikipedia.org/wiki/Morton_number_(number_theory)) 
+     by interleaving bits of the receiver with bits of the arguments.
+     Thus, if the bits of the receiver are
+        aN ... a2 a1 a0
+     and those of the integer1 are:
+        bN ... b2 b1 b0
+     and those of the integer2 are:
+        cN ... c2 c1 c0
+     the result is
+        cN bN aN ... c2 b2 a2 c1 b1 a1 c0 b0 a0.
+
+     Morton3 numbers are great to linearize 3D coordinates
+     eg. to sort 3D points by distances"    
+
+    |a b c shift ma mb mc val|
+
+    a := self.
+    b := integer1.
+    c := integer2.
+    val := 0.
+    shift := 0.
+    [ (a == 0) and:[b == 0]] whileFalse:[
+        "/ strip off 4 bits from each...
+        "/ 0000       0001       0010       0011       0100       0101       0110       0111       1000       1001       1010       1011       1100       1101       1110       1111 
+        mc := #( 2r000000000000 2r000000000100 2r000000100000 2r000000100100 2r000100000000 2r000100000100 2r000100100000 2r000100100100 2r100000000000 2r100000000100 2r100000100000 2r100000100100 2r100100000000 2r100100000100 2r100100100000 2r100100100100 ) 
+                at:((c bitAnd:2r1111)+1).
+        mb := #( 2r000000000000 2r000000000010 2r000000010000 2r000000010010 2r000010000000 2r000010000010 2r000010010000 2r000010010010 2r010000000000 2r010000000010 2r010000010000 2r010000010010 2r010010000000 2r010010000010 2r010010010000 2r010010010010 )
+                at:((b bitAnd:2r1111)+1).
+        ma := #( 2r000000000000 2r000000000001 2r000000001000 2r000000001001 2r000001000000 2r000001000001 2r000001001000 2r000001001001 2r001000000000 2r001000000001 2r001000001000 2r001000001001 2r001001000000 2r001001000001 2r001001001000 2r001001001001 )
+                at:((a bitAnd:2r1111)+1).
+        val := val bitOr:(((ma bitOr:mb) bitOr:mc) bitShift:shift).
+        shift := shift + 12.
+        a := a rightShift:4.
+        b := b rightShift:4.
+        c := c rightShift:4.
+    ].
+    ^ val.
+
+    "
+     (2r1100 bitInterleaveWith:2r1001 and:2r1010) printStringRadix:2 -> '111 001 100 010'
+     (2r11000110 bitInterleaveWith:2r10011100 and:2r10100101) printStringRadix:2 -> '111 001 100 010 010 111 001 100'
+    "
+
+    "Created: / 28-08-2017 / 14:33:04 / cg"
+!
+
 bitInvert
     "return a new integer, where all bits are complemented.
      This does not really make sense for negative largeIntegers,