Repository: ManiacalLabs/BiblioPixel
Pull request #90 (2017-01-03 13:37:43)

Multimap code.
Note that the first commit fixes a regression :-/ from October!  Clearly no one caught this...

adammhaile: What regression? That first commit doesn't seem to change anything old.
Otherwise +1
rec: There is no variable `self.driver`.  The right name was `self.drivers`.

Had that code been executed, it would have failed! 
adammhaile: Ahh...oops. Gotcha


On Tue, Jan 3, 2017 at 9:05 AM, Tom Swirly <notifications@github.com> wrote:

> There is no variable self.driver. The right name was self.drivers.
>
> Had that code been executed, it would have failed!
>
> —
> You are receiving this because you commented.
> Reply to this email directly, view it on GitHub
> <https://github.com/ManiacalLabs/BiblioPixel/pull/90#issuecomment-270120897>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AA6a6vL8AHmPsxUHLYHViPnlA8NI5kaaks5rOlXEgaJpZM4LZn-7>
> .
>


Patch:
diff --git a/bibliopixel/__init__.py b/bibliopixel/__init__.py
index b5af99d..1b20aa0 100644
--- a/bibliopixel/__init__.py
+++ b/bibliopixel/__init__.py
@@ -1,6 +1,5 @@
-from . led import (LEDCircle, LEDMatrix, LEDPOV, LEDStrip,
-                   MatrixRotation, MultiMapBuilder, mapGen)
-
+from . led import LEDCircle, LEDMatrix, LEDPOV, LEDStrip
+from . led.multimap import MatrixRotation, MultiMapBuilder, mapGen
 from . import animation, colors, font, gamma, led, log, util
 
 __version__ = VERSION = '3.0.0b0'
diff --git a/bibliopixel/drivers/dummy_driver.py b/bibliopixel/drivers/dummy_driver.py
index 4e593c8..4fc1854 100644
--- a/bibliopixel/drivers/dummy_driver.py
+++ b/bibliopixel/drivers/dummy_driver.py
@@ -5,7 +5,7 @@ import time
 class DriverDummy(DriverBase):
     """For Testing: Provides no ouput, just a valid interface"""
 
-    def __init__(self, num, delay=0):
+    def __init__(self, num, delay=0, **_):
         """delay: time to wait in milliseconds to simulate actual hardware interface time"""
         super(DriverDummy, self).__init__(num)
         self._delay = delay
diff --git a/bibliopixel/led/__init__.py b/bibliopixel/led/__init__.py
index 29b624e..93c6ae0 100644
--- a/bibliopixel/led/__init__.py
+++ b/bibliopixel/led/__init__.py
@@ -1,5 +1,6 @@
 from . circle import LEDCircle
-from . matrix import MatrixRotation, mapGen, MultiMapBuilder, LEDMatrix
+from . matrix import LEDMatrix
+from . multimap import MatrixRotation, mapGen, MultiMapBuilder
 from . pov import LEDPOV
 from . strip import LEDStrip
 
diff --git a/bibliopixel/led/matrix.py b/bibliopixel/led/matrix.py
index 7b7dd8e..4ad58ba 100644
--- a/bibliopixel/led/matrix.py
+++ b/bibliopixel/led/matrix.py
@@ -2,61 +2,7 @@ import math, threading, time
 
 from .. import colors, font, matrix, timedata
 from . base import LEDBase
-
-
-class MatrixRotation:
-    ROTATE_0 = 0  # no rotation
-    ROTATE_90 = 3  # rotate 90 degrees
-    ROTATE_180 = 2  # rotate 180 degrees
-    ROTATE_270 = 1  # rotate 270 degrees
-
-
-def mapGen(width, height, serpentine=True, offset=0,
-           rotation=MatrixRotation.ROTATE_0, vert_flip=False):
-    """Helper method to generate X,Y coordinate maps for strips"""
-
-    result = []
-    for y in range(height):
-        if not serpentine or y % 2 == 0:
-            result.append([(width * y) + x + offset for x in range(width)])
-        else:
-            result.append([((width * (y + 1)) - 1) - x +
-                           offset for x in range(width)])
-
-    for i in range(rotation):
-        result = list(zip(*result[::-1]))
-
-    if vert_flip:
-        result = result[::-1]
-
-    return result
-
-
-class MultiMapBuilder(object):
-
-    def __init__(self):
-        self.map = []
-        self.offset = 0
-
-    def addRow(self, *maps):
-        yOff = len(self.map)
-        lengths = [len(m) for m in maps]
-        h = max(lengths)
-        if(min(lengths) != h):
-            raise ValueError("All maps in row must be the same height!")
-
-        offsets = [0 + self.offset]
-        count = 0
-        for m in maps:
-            offsets.append(h * len(m[0]) + offsets[count])
-            count += 1
-
-        for y in range(h):
-            self.map.append([])
-            for x in range(len(maps)):
-                self.map[y + yOff] += [i + offsets[x] for i in maps[x][y]]
-
-        self.offset = offsets[len(offsets) - 1]
+from . multimap import MatrixRotation, mapGen, MultiMapBuilder
 
 
 class LEDMatrix(LEDBase):
@@ -73,11 +19,11 @@ class LEDMatrix(LEDBase):
         super().__init__(drivers, threadedUpdate, masterBrightness)
 
         if width == 0 and height == 0:
-            if len(self.driver) != 1:
+            if len(self.drivers) != 1:
                 raise TypeError(
                     "Must provide width and height if using multiple drivers!")
-            width = self.driver[0].width
-            height = self.driver[0].height
+            width = self.drivers[0].width
+            height = self.drivers[0].height
 
         self.width = width
         self.height = height
diff --git a/bibliopixel/led/multimap.py b/bibliopixel/led/multimap.py
new file mode 100644
index 0000000..6c9cc38
--- /dev/null
+++ b/bibliopixel/led/multimap.py
@@ -0,0 +1,53 @@
+class MatrixRotation:
+    ROTATE_0 = 0  # no rotation
+    ROTATE_90 = 3  # rotate 90 degrees
+    ROTATE_180 = 2  # rotate 180 degrees
+    ROTATE_270 = 1  # rotate 270 degrees
+
+
+def mapGen(width, height, serpentine=True, offset=0,
+           rotation=MatrixRotation.ROTATE_0, vert_flip=False):
+    """Helper method to generate X,Y coordinate maps for strips"""
+
+    result = []
+    for y in range(height):
+        if not serpentine or y % 2 == 0:
+            result.append([(width * y) + x + offset for x in range(width)])
+        else:
+            result.append([((width * (y + 1)) - 1) - x +
+                           offset for x in range(width)])
+
+    for i in range(rotation):
+        result = list(zip(*result[::-1]))
+
+    if vert_flip:
+        result = result[::-1]
+
+    return result
+
+
+class MultiMapBuilder(object):
+
+    def __init__(self):
+        self.map = []
+        self.offset = 0
+
+    def addRow(self, *maps):
+        yOff = len(self.map)
+        lengths = [len(m) for m in maps]
+        h = max(lengths)
+        if(min(lengths) != h):
+            raise ValueError("All maps in row must be the same height!")
+
+        offsets = [0 + self.offset]
+        count = 0
+        for m in maps:
+            offsets.append(h * len(m[0]) + offsets[count])
+            count += 1
+
+        for y in range(h):
+            self.map.append([])
+            for x in range(len(maps)):
+                self.map[y + yOff] += [i + offsets[x] for i in maps[x][y]]
+
+        self.offset = offsets[len(offsets) - 1]
diff --git a/bibliopixel/util/project.py b/bibliopixel/util/project.py
index 0c7cc17..9083b82 100644
--- a/bibliopixel/util/project.py
+++ b/bibliopixel/util/project.py
@@ -1,12 +1,31 @@
 import sys
 from . importer import make_object
 from . read_dict import read_dict
+from .. led.multimap import MultiMapBuilder, mapGen
+
+
+def make_drivers(multimap=False, **kwds):
+    def multi(device_ids, width, height, serpentine=False, **kwds):
+        build = MultiMapBuilder()
+        drivers = []
+
+        for id in device_ids:
+            build.addRow(mapGen(width, height, serpentine=serpentine))
+            d = make_object(width=width, height=height, deviceID=id, **kwds)
+            drivers.append(d)
+
+        return drivers, build.map
+
+    return multi(**kwds) if multimap else ([make_object(**kwds)], None)
 
 
 class Project(object):
     def __init__(self, driver, led, animation, run):
-        self.drivers = [make_object(**driver)]
-        self.led = make_object(self.drivers, **led)
+        self.drivers, coordMap = make_drivers(**driver)
+        if coordMap:
+            self.led = make_object(self.drivers, coordMap=coordMap, **led)
+        else:
+            self.led = make_object(self.drivers, **led)
         self.animation = make_object(self.led, **animation)
         self.run = lambda: self.animation.run(**run)
 


Test patch:
diff --git a/test/project_test.py b/test/project_test.py
index b908d8f..8ad7383 100644
--- a/test/project_test.py
+++ b/test/project_test.py
@@ -18,7 +18,32 @@ PROJECT = """
     },
 
     "run": {
-        "max_steps": 5
+        "max_steps": 2
+    }
+}
+"""
+
+PROJECT_MULTI = """
+{
+    "driver": {
+        "typename": "bibliopixel.drivers.dummy_driver.DriverDummy",
+        "multi": true,
+        "width": 128,
+        "height": 32,
+        "num": 4096,
+        "device_ids": [10, 11, 12]
+    },
+
+    "led": {
+        "typename": "bibliopixel.led.matrix.LEDMatrix"
+    },
+
+    "animation": {
+        "typename": "bibliopixel.animation.tests.MatrixChannelTest"
+    },
+
+    "run": {
+        "max_steps": 2
     }
 }
 """
@@ -30,3 +55,6 @@ class ProjectTest(unittest.TestCase):
 
     def test_file(self):
         project.run('test/project.json')
+
+    def test_multi(self):
+        project.run(PROJECT_MULTI)