Changeset - 14508266a00a
[Not reviewed]
default
0 4 0
Drew Perttula - 8 years ago 2017-05-22 06:42:37
drewp@bigasterisk.com
more work on solver api updates.
Ignore-this: 52382237d531582cbf64e7a95acf4547
4 files changed with 70 insertions and 52 deletions:
0 comments (0 inline, 0 general)
light9/effect/settings.py
Show inline comments
 
from __future__ import division
 
"""
 
Data structure and convertors for a table of (device,attr,value)
 
rows. These might be effect attrs ('strength'), device attrs ('rx'),
 
or output attrs (dmx channel).
 
"""
 
import decimal
 
import numpy
 
from rdflib import URIRef, Literal
 
from light9.namespaces import RDF, L9, DEV
 
from light9.rdfdb.patch import Patch
 

	
 

	
 
def parseHex(h):
 
    if h[0] != '#': raise ValueError(h)
 
    return [int(h[i:i+2], 16) for i in 1, 3, 5]
 

	
 
def toHex(rgbFloat):
 
    return '#%02x%02x%02x' % tuple(int(v * 255) for v in rgbFloat)
 

	
 
def getVal(graph, subj):
 
    lit = graph.value(subj, L9['value']) or graph.value(subj, L9['scaledValue'])
 
    ret = lit.toPython()
 
@@ -18,12 +27,12 @@ def getVal(graph, subj):
 

	
 
class _Settings(object):
 
    """
 
    default values are 0. Internal rep must not store zeros or some
 
    default values are 0 or '#000000'. Internal rep must not store zeros or some
 
    comparisons will break.
 
    """
 
    def __init__(self, graph, settingsList):
 
        self.graph = graph # for looking up all possible attrs
 
        self._compiled = {} # dev: { attr: val }
 
        self._compiled = {} # dev: { attr: val }; val is number or colorhex
 
        for row in settingsList:
 
            self._compiled.setdefault(row[0], {})[row[1]] = row[2]
 
        # self._compiled may not be final yet- see _fromCompiled
 
@@ -50,14 +59,26 @@ class _Settings(object):
 
    @classmethod
 
    def fromVector(cls, graph, vector):
 
        compiled = {}
 
        for (d, a), v in zip(cls(graph, [])._vectorKeys(), vector):
 
        i = 0
 
        for (d, a) in cls(graph, [])._vectorKeys():
 
            if a == L9['color']:
 
                v = toHex(vector[i:i+3])
 
                i += 3
 
            else:
 
                v = vector[i]
 
                i += 1
 
            compiled.setdefault(d, {})[a] = v
 
        return cls._fromCompiled(graph, compiled)
 

	
 
    def _zeroForAttr(self, attr):
 
        if attr == L9['color']:
 
            return '#000000'
 
        return 0
 

	
 
    def _delZeros(self):
 
        for dev, av in self._compiled.items():
 
            for attr, val in av.items():
 
                if val == 0:
 
                if val == self._zeroForAttr(attr):
 
                    del av[attr]
 
            if not av:
 
                del self._compiled[dev]
 
@@ -81,7 +102,7 @@ class _Settings(object):
 
        def accum():
 
            for dev, av in self._compiled.iteritems():
 
                for attr, val in av.iteritems():
 
                    words.append('%s.%s=%g' % (dev.rsplit('/')[-1],
 
                    words.append('%s.%s=%s' % (dev.rsplit('/')[-1],
 
                                               attr.rsplit('/')[-1],
 
                                               val))
 
                    if len(words) > 5:
 
@@ -91,7 +112,7 @@ class _Settings(object):
 
        return '<%s %s>' % (self.__class__.__name__, ' '.join(words))
 
        
 
    def getValue(self, dev, attr):
 
        return self._compiled.get(dev, {}).get(attr, 0)
 
        return self._compiled.get(dev, {}).get(attr, self._zeroForAttr(attr))
 

	
 
    def _vectorKeys(self):
 
        """stable order of all the dev,attr pairs for this type of settings"""
 
@@ -111,7 +132,12 @@ class _Settings(object):
 
    def toVector(self):
 
        out = []
 
        for dev, attr in self._vectorKeys():
 
            out.append(self._compiled.get(dev, {}).get(attr, 0))
 
            # color components may need to get spread out
 
            v = self.getValue(dev, attr)
 
            if attr == L9['color']:
 
                out.extend([x / 255 for x in parseHex(v)])
 
            else:
 
                out.append(v)
 
        return out
 

	
 
    def byDevice(self):
 
@@ -123,14 +149,9 @@ class _Settings(object):
 
                                            {dev: self._compiled.get(dev, {})})
 
        
 
    def distanceTo(self, other):
 
        raise NotImplementedError
 
        dist = 0
 
        for key in set(attrs1).union(set(attrs2)):
 
            if key not in attrs1 or key not in attrs2:
 
                dist += 999
 
            else:
 
                dist += abs(attrs1[key] - attrs2[key])
 
        return dist
 
        diff = numpy.array(self.toVector()) - other.toVector()
 
        d = numpy.linalg.norm(diff, ord=None)
 
        return d
 

	
 
    def statements(self, subj, ctx, settingRoot, settingsSubgraphCache):
 
        """
light9/effect/settings_test.py
Show inline comments
 
@@ -12,7 +12,7 @@ class TestDeviceSettings(unittest.TestCa
 

	
 
    def testToVectorZero(self):
 
        ds = DeviceSettings(self.graph, [])
 
        self.assertEqual([0] * 20, ds.toVector())
 
        self.assertEqual([0] * 30, ds.toVector())
 

	
 
    def testEq(self):
 
        s1 = DeviceSettings(self.graph, [
 
@@ -53,17 +53,20 @@ class TestDeviceSettings(unittest.TestCa
 
    def testToVector(self):
 
        v = DeviceSettings(self.graph, [
 
            (DEV['aura1'], L9['rx'], 0.5),
 
            (DEV['aura1'], L9['color'], '#00ff00'),
 
        ]).toVector()
 
        self.assertEqual(
 
            [0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], v)
 
            [0, 1, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 
            v)
 
        
 
    def testFromVector(self):
 
        s = DeviceSettings.fromVector(
 
            self.graph,
 
            [0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
 
            [0, 1, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
 
        
 
        self.assertEqual(DeviceSettings(self.graph, [
 
            (DEV['aura1'], L9['rx'], 0.5),
 
            (DEV['aura1'], L9['color'], '#00ff00'),
 
        ]), s)                            
 

	
 
    def testAsList(self):
 
@@ -75,22 +78,33 @@ class TestDeviceSettings(unittest.TestCa
 

	
 
    def testDevices(self):
 
        s = DeviceSettings(self.graph, [
 
            (L9['aura1'], L9['rx'], 0),
 
            (L9['aura2'], L9['rx'], 0.1),
 
            (DEV['aura1'], L9['rx'], 0),
 
            (DEV['aura2'], L9['rx'], 0.1),
 
            ])
 
        # aura1 is all defaults (zeros), so it doesn't get listed
 
        self.assertItemsEqual([L9['aura2']], s.devices())
 
        self.assertItemsEqual([DEV['aura2']], s.devices())
 

	
 
    def testAddStatements(self):
 
        s = DeviceSettings(self.graph, [
 
            (L9['aura2'], L9['rx'], 0.1),
 
            (DEV['aura2'], L9['rx'], 0.1),
 
            ])
 
        stmts = s.statements(L9['foo'], L9['ctx1'], L9['s_'], set())
 
        self.maxDiff=None
 
        self.assertItemsEqual([
 
            (L9['foo'], L9['setting'], L9['s_set8011962'], L9['ctx1']),
 
            (L9['s_set8011962'], L9['device'], L9['aura2'], L9['ctx1']),
 
            (L9['s_set8011962'], L9['deviceAttr'], L9['rx'], L9['ctx1']),
 
            (L9['s_set8011962'], L9['value'], Literal(0.1), L9['ctx1']),
 
            (L9['foo'], L9['setting'], L9['s_set4350023'], L9['ctx1']),
 
            (L9['s_set4350023'], L9['device'], DEV['aura2'], L9['ctx1']),
 
            (L9['s_set4350023'], L9['deviceAttr'], L9['rx'], L9['ctx1']),
 
            (L9['s_set4350023'], L9['value'], Literal(0.1), L9['ctx1']),
 
        ], stmts)
 
        
 
    def testDistanceTo(self):
 
        s1 = DeviceSettings(self.graph, [
 
            (DEV['aura1'], L9['rx'], 0.1),
 
            (DEV['aura1'], L9['ry'], 0.6),
 
        ])
 
        s2 = DeviceSettings(self.graph, [
 
            (DEV['aura1'], L9['rx'], 0.3),
 
            (DEV['aura1'], L9['ry'], 0.3),
 
        ])
 
        self.assertEqual(0.36055512754639896, s1.distanceTo(s2))
 
        
light9/paint/solve.py
Show inline comments
 
@@ -5,7 +5,7 @@ import numpy
 
import scipy.misc, scipy.ndimage, scipy.optimize
 
import cairo
 

	
 
from light9.effect.settings import DeviceSettings
 
from light9.effect.settings import DeviceSettings, parseHex, toHex
 

	
 
# numpy images in this file are (x, y, c) layout.
 

	
 
@@ -27,13 +27,6 @@ def loadNumpy(path, thumb=(100, 100)):
 
def saveNumpy(path, img):
 
    scipy.misc.imsave(path, img.transpose((1, 0, 2)))
 

	
 
def parseHex(h):
 
    if h[0] != '#': raise ValueError(h)
 
    return [int(h[i:i+2], 16) for i in 1, 3, 5]
 

	
 
def toHex(rgbFloat):
 
    return '#%02x%02x%02x' % tuple(int(v * 255) for v in rgbFloat)
 

	
 
def scaledHex(h, scale):
 
    rgb = parseHex(h)
 
    rgb8 = (rgb * scale).astype(numpy.uint8)
 
@@ -66,7 +59,7 @@ class Solver(object):
 
                self.samples[samp] = self.fromPath[base] = loadNumpy(path)
 
                self.blurredSamples[samp] = self._blur(self.samples[samp])
 
                
 
                key = (samp, g.value(samp, L9['path']).toPython())
 
                key = (samp, g.value(samp, L9['path']).toPython().encode('utf8'))
 
                self.sampleSettings[key] = DeviceSettings.fromResource(self.graph, samp)
 

	
 
    def _blur(self, img):
 
@@ -117,7 +110,7 @@ class Solver(object):
 
        brightestSample = brightest(self.samples[sample])
 
        
 
        if max(brightest0) < 1 / 255:
 
            return []
 
            return DeviceSettings(self.graph, [])
 

	
 
        scale = brightest0 / brightestSample
 

	
 
@@ -138,19 +131,6 @@ class Solver(object):
 
                                         slice(0, 1 + colorStep, colorStep),
 
                                         slice(0, 1 + colorStep, colorStep)]),
 
        ]
 

	
 
        def settingsFromVector(x):
 
            settings = []
 

	
 
            xLeft = x.tolist()
 
            for dev, attr, _ in dims:
 
                if attr == L9['color']:
 
                    rgb = (xLeft.pop(), xLeft.pop(), xLeft.pop())
 
                    settings.append((dev, attr, toHex(rgb)))
 
                else:
 
                    settings.append((dev, attr, xLeft.pop()))
 
            return DeviceSettings(self.graph, settings)
 

	
 
        
 
        def drawError(x):
 
            settings = DeviceSettings.fromVector(self.graph, x)
light9/paint/solve_test.py
Show inline comments
 
@@ -7,7 +7,8 @@ from light9.effect.settings import Devic
 

	
 
class TestSolve(unittest.TestCase):
 
    def setUp(self):
 
        self.graph = LocalSyncedGraph(files=['show/dance2017/cam/test/bg.n3'])
 
        self.graph = LocalSyncedGraph(files=['show/dance2017/cam/test/lightConfig.n3',
 
                                             'show/dance2017/cam/test/bg.n3'])
 
        self.solver = solve.Solver(self.graph)
 
        self.solver.loadSamples()
 
        self.solveMethod = self.solver.solve
 
@@ -33,7 +34,8 @@ class TestSolveBrute(TestSolve):
 
        
 
class TestSimulationLayers(unittest.TestCase):
 
    def setUp(self):
 
        self.graph = LocalSyncedGraph(files=['show/dance2017/cam/test/bg.n3'])
 
        self.graph = LocalSyncedGraph(files=['show/dance2017/cam/test/lightConfig.n3',
 
                                             'show/dance2017/cam/test/bg.n3'])
 
        self.solver = solve.Solver(self.graph)
 
        self.solver.loadSamples()
 
        
 
@@ -72,7 +74,8 @@ class TestSimulationLayers(unittest.Test
 

	
 
class TestCombineImages(unittest.TestCase):
 
    def setUp(self):
 
        graph = LocalSyncedGraph(files=['show/dance2017/cam/test/bg.n3'])
 
        graph = LocalSyncedGraph(files=['show/dance2017/cam/test/lightConfig.n3',
 
                                        'show/dance2017/cam/test/bg.n3'])
 
        self.solver = solve.Solver(graph)
 
        self.solver.loadSamples()
 
    def test(self):
0 comments (0 inline, 0 general)