<commit_before># Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.

from UM.Mesh.MeshData import MeshData
from UM.Mesh.MeshBuilder import MeshBuilder
from UM.Math.Color import Color
from UM.Math.Vector import Vector

import numpy
import math
import copy

class LayerData(MeshData):
    def __init__(self):
        super().__init__()
        self._layers = {}
        self._element_counts = {}

    def addLayer(self, layer):
        if layer not in self._layers:
            self._layers[layer] = Layer(layer)

    def addPolygon(self, layer, type, data, line_width):
        if layer not in self._layers:
            self.addLayer(layer)

        p = Polygon(self, type, data, line_width)
        self._layers[layer].polygons.append(p)

    def getLayer(self, layer):
        if layer in self._layers:
            return self._layers[layer]

    def getLayers(self):
        return self._layers

    def getElementCounts(self):
        return self._element_counts

    def setLayerHeight(self, layer, height):
        if layer not in self._layers:
            self.addLayer(layer)

        self._layers[layer].setHeight(height)

    def setLayerThickness(self, layer, thickness):
        if layer not in self._layers:
            self.addLayer(layer)

        self._layers[layer].setThickness(thickness)

    def build(self):
        vertex_count = 0
        for layer, data in self._layers.items():
            vertex_count += data.vertexCount()

        vertices = numpy.empty((vertex_count, 3), numpy.float32)
        colors = numpy.empty((vertex_count, 4), numpy.float32)
        indices = numpy.empty((vertex_count, 2), numpy.int32)

        offset = 0
        for layer, data in self._layers.items():
            offset = data.build(offset, vertices, colors, indices)
            self._element_counts[layer] = data.elementCount

        self.addVertices(vertices)
        self.addColors(colors)
        self.addIndices(indices.flatten())

class Layer():
    def __init__(self, id):
        self._id = id
        self._height = 0.0
        self._thickness = 0.0
        self._polygons = []
        self._element_count = 0

    @property
    def height(self):
        return self._height

    @property
    def thickness(self):
        return self._thickness

    @property
    def polygons(self):
        return self._polygons

    @property
    def elementCount(self):
        return self._element_count

    def setHeight(self, height):
        self._height = height

    def setThickness(self, thickness):
        self._thickness = thickness

    def vertexCount(self):
        result = 0
        for polygon in self._polygons:
            result += polygon.vertexCount()

        return result

    def build(self, offset, vertices, colors, indices):
        result = offset
        for polygon in self._polygons:
            if polygon._type == Polygon.InfillType or polygon._type == Polygon.SupportInfillType:
                continue

            polygon.build(result, vertices, colors, indices)
            result += polygon.vertexCount()
            self._element_count += polygon.elementCount

        return result

    def createMesh(self):
        return self.createMeshOrJumps(True)

    def createJumps(self):
        return self.createMeshOrJumps(False)

    def createMeshOrJumps(self, make_mesh):
        builder = MeshBuilder()

        for polygon in self._polygons:
            if make_mesg and (polygon.type == Polygon.MoveCombingType or polygon.type == Polygon.MoveRetractionType):
                continue
            if not make_mesg and not (polygon.type == Polygon.MoveCombingType or polygon.type == Polygon.MoveRetractionType):
                continue

            poly_color = polygon.getColor()

            points = numpy.copy(polygon.data)
            if polygon.type == Polygon.InfillType or polygon.type == Polygon.SkinType or polygon.type == Polygon.SupportInfillType:
                points[:,1] -= 0.01

            # Calculate normals for the entire polygon using numpy.
            normals = numpy.copy(points)
            normals[:,1] = 0.0 # We are only interested in 2D normals

            # Calculate the edges between points.
            # The call to numpy.roll shifts the entire array by one so that
            # we end up subtracting each next point from the current, wrapping
            # around. This gives us the edges from the next point to the current
            # point.
            normals[:] = normals[:] - numpy.roll(normals, -1, axis = 0)
            # Calculate the length of each edge using standard Pythagoras
            lengths = numpy.sqrt(normals[:,0] ** 2 + normals[:,2] ** 2)
            # The normal of a 2D vector is equal to its x and y coordinates swapped
            # and then x inverted. This code does that.
            normals[:,[0, 2]] = normals[:,[2, 0]]
            normals[:,0] *= -1

            # Normalize the normals.
            normals[:,0] /= lengths
            normals[:,2] /= lengths

            # Scale all by the line width of the polygon so we can easily offset.
            normals *= (polygon.lineWidth / 2)

            #TODO: Use numpy magic to perform the vertex creation to speed up things.
            for i in range(len(points)):
                start = points[i - 1]
                end = points[i]

                normal = normals[i - 1]

                point1 = Vector(data = start - normal)
                point2 = Vector(data = start + normal)
                point3 = Vector(data = end + normal)
                point4 = Vector(data = end - normal)

                builder.addQuad(point1, point2, point3, point4, color = poly_color)

        return builder.getData()

class Polygon():
    NoneType = 0
    Inset0Type = 1
    InsetXType = 2
    SkinType = 3
    SupportType = 4
    SkirtType = 5
    InfillType = 6
    SupportInfillType = 7
    MoveCombingType = 8
    MoveRetractionType = 9

    def __init__(self, mesh, type, data, line_width):
        super().__init__()
        self._mesh = mesh
        self._type = type
        self._data = data
        self._line_width = line_width / 1000

    def build(self, offset, vertices, colors, indices):
        self._begin = offset

        color = self.getColor()
        color.setValues(color.r * 0.5, color.g * 0.5, color.b * 0.5, color.a)

        for i in range(len(self._data)):
            vertices[offset + i, :] = self._data[i, :]
            colors[offset + i, 0] = color.r
            colors[offset + i, 1] = color.g
            colors[offset + i, 2] = color.b
            colors[offset + i, 3] = color.a

        self._end = self._begin + len(self._data) - 1

        for i in range(self._begin, self._end):
            indices[i, 0] = i
            indices[i, 1] = i + 1

        indices[self._end, 0] = self._end
        indices[self._end, 1] = self._begin

    def getColor(self):
        if self._type == self.Inset0Type:
            return Color(1.0, 0.0, 0.0, 1.0)
        elif self._type == self.InsetXType:
            return Color(0.0, 1.0, 0.0, 1.0)
        elif self._type == self.SkinType:
            return Color(1.0, 1.0, 0.0, 1.0)
        elif self._type == self.SupportType:
            return Color(0.0, 1.0, 1.0, 1.0)
        elif self._type == self.SkirtType:
            return Color(0.0, 1.0, 1.0, 1.0)
        elif self._type == self.InfillType:
            return Color(1.0, 0.74, 0.0, 1.0)
        elif self._type == self.SupportInfillType:
            return Color(0.0, 1.0, 1.0, 1.0)
        elif self._type == self.MoveCombingType:
            return Color(0.0, 0.0, 1.0, 1.0)
        elif self._type == self.MoveRetractionType:
            return Color(0.5, 0.5, 1.0, 1.0)
        else:
            return Color(1.0, 1.0, 1.0, 1.0)

    def vertexCount(self):
        return len(self._data)

    @property
    def type(self):
        return self._type

    @property
    def data(self):
        return self._data

    @property
    def elementCount(self):
        return ((self._end - self._begin) + 1) * 2 #The range of vertices multiplied by 2 since each vertex is used twice

    @property
    def lineWidth(self):
        return self._line_width
<commit_msg>hide jumps from line view + fix solid display<commit_after># Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.

from UM.Mesh.MeshData import MeshData
from UM.Mesh.MeshBuilder import MeshBuilder
from UM.Math.Color import Color
from UM.Math.Vector import Vector

import numpy
import math
import copy

class LayerData(MeshData):
    def __init__(self):
        super().__init__()
        self._layers = {}
        self._element_counts = {}

    def addLayer(self, layer):
        if layer not in self._layers:
            self._layers[layer] = Layer(layer)

    def addPolygon(self, layer, type, data, line_width):
        if layer not in self._layers:
            self.addLayer(layer)

        p = Polygon(self, type, data, line_width)
        self._layers[layer].polygons.append(p)

    def getLayer(self, layer):
        if layer in self._layers:
            return self._layers[layer]

    def getLayers(self):
        return self._layers

    def getElementCounts(self):
        return self._element_counts

    def setLayerHeight(self, layer, height):
        if layer not in self._layers:
            self.addLayer(layer)

        self._layers[layer].setHeight(height)

    def setLayerThickness(self, layer, thickness):
        if layer not in self._layers:
            self.addLayer(layer)

        self._layers[layer].setThickness(thickness)

    def build(self):
        vertex_count = 0
        for layer, data in self._layers.items():
            vertex_count += data.vertexCount()

        vertices = numpy.empty((vertex_count, 3), numpy.float32)
        colors = numpy.empty((vertex_count, 4), numpy.float32)
        indices = numpy.empty((vertex_count, 2), numpy.int32)

        offset = 0
        for layer, data in self._layers.items():
            offset = data.build(offset, vertices, colors, indices)
            self._element_counts[layer] = data.elementCount

        self.addVertices(vertices)
        self.addColors(colors)
        self.addIndices(indices.flatten())

class Layer():
    def __init__(self, id):
        self._id = id
        self._height = 0.0
        self._thickness = 0.0
        self._polygons = []
        self._element_count = 0

    @property
    def height(self):
        return self._height

    @property
    def thickness(self):
        return self._thickness

    @property
    def polygons(self):
        return self._polygons

    @property
    def elementCount(self):
        return self._element_count

    def setHeight(self, height):
        self._height = height

    def setThickness(self, thickness):
        self._thickness = thickness

    def vertexCount(self):
        result = 0
        for polygon in self._polygons:
            result += polygon.vertexCount()

        return result

    def build(self, offset, vertices, colors, indices):
        result = offset
        for polygon in self._polygons:
            if polygon._type == Polygon.InfillType or polygon._type == Polygon.SupportInfillType or polygon.type == Polygon.MoveCombingType or polygon.type == Polygon.MoveRetractionType:
                continue

            polygon.build(result, vertices, colors, indices)
            result += polygon.vertexCount()
            self._element_count += polygon.elementCount

        return result

    def createMesh(self):
        return self.createMeshOrJumps(True)

    def createJumps(self):
        return self.createMeshOrJumps(False)

    def createMeshOrJumps(self, make_mesh):
        builder = MeshBuilder()

        for polygon in self._polygons:
            if make_mesh and (polygon.type == Polygon.MoveCombingType or polygon.type == Polygon.MoveRetractionType):
                continue
            if not make_mesh and not (polygon.type == Polygon.MoveCombingType or polygon.type == Polygon.MoveRetractionType):
                continue

            poly_color = polygon.getColor()

            points = numpy.copy(polygon.data)
            if polygon.type == Polygon.InfillType or polygon.type == Polygon.SkinType or polygon.type == Polygon.SupportInfillType:
                points[:,1] -= 0.01

            # Calculate normals for the entire polygon using numpy.
            normals = numpy.copy(points)
            normals[:,1] = 0.0 # We are only interested in 2D normals

            # Calculate the edges between points.
            # The call to numpy.roll shifts the entire array by one so that
            # we end up subtracting each next point from the current, wrapping
            # around. This gives us the edges from the next point to the current
            # point.
            normals[:] = normals[:] - numpy.roll(normals, -1, axis = 0)
            # Calculate the length of each edge using standard Pythagoras
            lengths = numpy.sqrt(normals[:,0] ** 2 + normals[:,2] ** 2)
            # The normal of a 2D vector is equal to its x and y coordinates swapped
            # and then x inverted. This code does that.
            normals[:,[0, 2]] = normals[:,[2, 0]]
            normals[:,0] *= -1

            # Normalize the normals.
            normals[:,0] /= lengths
            normals[:,2] /= lengths

            # Scale all by the line width of the polygon so we can easily offset.
            normals *= (polygon.lineWidth / 2)

            #TODO: Use numpy magic to perform the vertex creation to speed up things.
            for i in range(len(points)):
                start = points[i - 1]
                end = points[i]

                normal = normals[i - 1]

                point1 = Vector(data = start - normal)
                point2 = Vector(data = start + normal)
                point3 = Vector(data = end + normal)
                point4 = Vector(data = end - normal)

                builder.addQuad(point1, point2, point3, point4, color = poly_color)

        return builder.getData()

class Polygon():
    NoneType = 0
    Inset0Type = 1
    InsetXType = 2
    SkinType = 3
    SupportType = 4
    SkirtType = 5
    InfillType = 6
    SupportInfillType = 7
    MoveCombingType = 8
    MoveRetractionType = 9

    def __init__(self, mesh, type, data, line_width):
        super().__init__()
        self._mesh = mesh
        self._type = type
        self._data = data
        self._line_width = line_width / 1000

    def build(self, offset, vertices, colors, indices):
        self._begin = offset

        color = self.getColor()
        color.setValues(color.r * 0.5, color.g * 0.5, color.b * 0.5, color.a)

        for i in range(len(self._data)):
            vertices[offset + i, :] = self._data[i, :]
            colors[offset + i, 0] = color.r
            colors[offset + i, 1] = color.g
            colors[offset + i, 2] = color.b
            colors[offset + i, 3] = color.a

        self._end = self._begin + len(self._data) - 1

        for i in range(self._begin, self._end):
            indices[i, 0] = i
            indices[i, 1] = i + 1

        indices[self._end, 0] = self._end
        indices[self._end, 1] = self._begin

    def getColor(self):
        if self._type == self.Inset0Type:
            return Color(1.0, 0.0, 0.0, 1.0)
        elif self._type == self.InsetXType:
            return Color(0.0, 1.0, 0.0, 1.0)
        elif self._type == self.SkinType:
            return Color(1.0, 1.0, 0.0, 1.0)
        elif self._type == self.SupportType:
            return Color(0.0, 1.0, 1.0, 1.0)
        elif self._type == self.SkirtType:
            return Color(0.0, 1.0, 1.0, 1.0)
        elif self._type == self.InfillType:
            return Color(1.0, 0.74, 0.0, 1.0)
        elif self._type == self.SupportInfillType:
            return Color(0.0, 1.0, 1.0, 1.0)
        elif self._type == self.MoveCombingType:
            return Color(0.0, 0.0, 1.0, 1.0)
        elif self._type == self.MoveRetractionType:
            return Color(0.5, 0.5, 1.0, 1.0)
        else:
            return Color(1.0, 1.0, 1.0, 1.0)

    def vertexCount(self):
        return len(self._data)

    @property
    def type(self):
        return self._type

    @property
    def data(self):
        return self._data

    @property
    def elementCount(self):
        return ((self._end - self._begin) + 1) * 2 #The range of vertices multiplied by 2 since each vertex is used twice

    @property
    def lineWidth(self):
        return self._line_width
<|endoftext|>


<commit_before># Copyright (c) 2015 Ultimaker B.V.
# Uranium is released under the terms of the AGPLv3 or higher.

from PyQt5.QtWidgets import QApplication

from UM.Tool import Tool
from UM.Event import Event, MouseEvent, KeyEvent
from UM.Application import Application
from UM.Message import Message
from UM.Scene.ToolHandle import ToolHandle
from UM.Scene.Selection import Selection
from UM.Scene.SceneNode import SceneNode

from UM.Math.Plane import Plane
from UM.Math.Vector import Vector
from UM.Math.Quaternion import Quaternion
from UM.Math.Matrix import Matrix
from UM.Math.Float import Float

from UM.Operations.RotateOperation import RotateOperation
from UM.Operations.TranslateOperation import TranslateOperation
from UM.Operations.GroupedOperation import GroupedOperation
from UM.Operations.SetTransformOperation import SetTransformOperation

from . import RotateToolHandle

import math
import time

class RotateTool(Tool):
    def __init__(self):
        super().__init__()
        self._handle = RotateToolHandle.RotateToolHandle()

        self._snap_rotation = True
        self._snap_angle = math.radians(15)

        self._angle = None

        self._angle_update_time = None

        self.setExposedProperties("Rotation", "RotationSnap", "RotationSnapAngle")

    def event(self, event):
        super().event(event)

        if event.type == Event.KeyPressEvent and event.key == KeyEvent.ShiftKey:
            self._snap_rotation = (not self._snap_rotation)
            self.propertyChanged.emit()

        if event.type == Event.KeyReleaseEvent and event.key == KeyEvent.ShiftKey:
            self._snap_rotation = (not self._snap_rotation)
            self.propertyChanged.emit()

        if event.type == Event.MousePressEvent:
            if MouseEvent.LeftButton not in event.buttons:
                return False

            id = self._selection_pass.getIdAtPosition(event.x, event.y)
            if not id:
                return

            if ToolHandle.isAxis(id):
                self.setLockedAxis(id)
                handle_position = self._handle.getWorldPosition()

                if id == ToolHandle.XAxis:
                    self.setDragPlane(Plane(Vector(1, 0, 0), handle_position.x))
                elif id == ToolHandle.YAxis:
                    self.setDragPlane(Plane(Vector(0, 1, 0), handle_position.y))
                elif self._locked_axis == ToolHandle.ZAxis:
                    self.setDragPlane(Plane(Vector(0, 0, 1), handle_position.z))

                self.setDragStart(event.x, event.y)
                self._angle = 0
                self.operationStarted.emit(self)

        if event.type == Event.MouseMoveEvent:
            if not self.getDragPlane():
                return False

            if not self.getDragStart():
                self.setDragStart(event.x, event.y)

            handle_position = self._handle.getWorldPosition()

            drag_start = (self.getDragStart() - handle_position).normalize()
            drag_position = self.getDragPosition(event.x, event.y)
            if not drag_position:
                return
            drag_end = (drag_position - handle_position).normalize()

            try:
                angle = math.acos(drag_start.dot(drag_end))
            except ValueError:
                angle = 0

            if self._snap_rotation:
                angle = int(angle / self._snap_angle) * self._snap_angle
                if angle == 0:
                    return

            rotation = None
            if self.getLockedAxis() == ToolHandle.XAxis:
                direction = 1 if Vector.Unit_X.dot(drag_start.cross(drag_end)) > 0 else -1
                rotation = Quaternion.fromAngleAxis(direction * angle, Vector.Unit_X)
            elif self.getLockedAxis() == ToolHandle.YAxis:
                direction = 1 if Vector.Unit_Y.dot(drag_start.cross(drag_end)) > 0 else -1
                rotation = Quaternion.fromAngleAxis(direction * angle, Vector.Unit_Y)
            elif self.getLockedAxis() == ToolHandle.ZAxis:
                direction = 1 if Vector.Unit_Z.dot(drag_start.cross(drag_end)) > 0 else -1
                rotation = Quaternion.fromAngleAxis(direction * angle, Vector.Unit_Z)

            self._angle += direction * angle

            # Rate-limit the angle change notification
            # This is done to prevent the UI from being flooded with property change notifications,
            # which in turn would trigger constant repaints.
            new_time = time.monotonic()
            if not self._angle_update_time or new_time - self._angle_update_time > 0.01:
                self.propertyChanged.emit()
                self._angle_update_time = new_time

            Selection.applyOperation(RotateOperation, rotation)

            self.setDragStart(event.x, event.y)

        if event.type == Event.MouseReleaseEvent:
            if self.getDragPlane():
                self.setDragPlane(None)
                self.setLockedAxis(None)
                self._angle = None
                self.propertyChanged.emit()
                self.operationStopped.emit(self)
                return True

    def getRotation(self):
        return round(math.degrees(self._angle)) if self._angle else None

    def getRotationSnap(self):
        return self._snap_rotation

    def setRotationSnap(self, snap):
        if snap != self._snap_rotation:
            self._snap_rotation = snap
            self.propertyChanged.emit()

    def getRotationSnapAngle(self):
        return self._snap_angle

    def setRotationSnapAngle(self, angle):
        if angle != self._snap_angle:
            self._snap_angle = angle
            self.propertyChanged.emit()

    def resetRotation(self):
        Selection.applyOperation(SetTransformOperation, None, Quaternion(), None)

    def layFlat(self):
        # Based on https://github.com/daid/Cura/blob/SteamEngine/Cura/util/printableObject.py#L207
        # Note: Y & Z axis are swapped

        self.operationStarted.emit(self)
        progress_message = Message("Laying object flat on buildplate...", lifetime = 0, dismissable = False)
        progress_message.setProgress(0)
        progress_message.show()

        selected_object = Selection.getSelectedObject(0)
        transformed_vertices = selected_object.getMeshDataTransformed().getVertices()
        min_y_vertex = transformed_vertices[transformed_vertices.argmin(0)[1]]
        dot_min = 1.0
        dot_v = None

        iterations = 0
        total_iterations = len(transformed_vertices) * 2
        last_progress = 0

        for v in transformed_vertices:
            diff = v - min_y_vertex
            length = math.sqrt(diff[0] * diff[0] + diff[2] * diff[2] + diff[1] * diff[1])
            if length < 5:
                continue
            dot = (diff[1] / length)
            if dot_min > dot:
                dot_min = dot
                dot_v = diff
            iterations += 1
            progress = round(100*iterations/total_iterations)
            if progress != last_progress:
                last_progress = progress
                progress_message.setProgress(progress)
                QApplication.processEvents()

        if dot_v is None:
            progress_message.hide()
            self.operationStopped.emit(self)
            return

        rad = -math.asin(dot_min)
        m = Matrix([
            [ math.cos(rad), math.sin(rad), 0 ],
            [-math.sin(rad), math.cos(rad), 0 ],
            [ 0,             0,             1 ]
        ])
        selected_object.rotate(Quaternion.fromMatrix(m), SceneNode.TransformSpace.Parent)

        rad = math.atan2(dot_v[2], dot_v[0])
        m = Matrix([
            [ math.cos(rad), 0, math.sin(rad)],
            [ 0,             1, 0 ],
            [-math.sin(rad), 0, math.cos(rad)]
        ])
        selected_object.rotate(Quaternion.fromMatrix(m), SceneNode.TransformSpace.Parent)

        transformed_vertices = selected_object.getMeshDataTransformed().getVertices()
        min_y_vertex = transformed_vertices[transformed_vertices.argmin(0)[1]]
        dot_min = 1.0
        dot_v = None

        for v in transformed_vertices:
            diff = v - min_y_vertex
            length = math.sqrt(diff[2] * diff[2] + diff[1] * diff[1])
            if length < 5:
                continue
            dot = (diff[1] / length)
            if dot_min > dot:
                dot_min = dot
                dot_v = diff
            iterations += 1
            progress = round(100*iterations/total_iterations)
            if progress != last_progress:
                last_progress = progress
                progress_message.setProgress(progress)
                QApplication.processEvents()

        if dot_v is None:
            progress_message.hide()
            self.operationStopped.emit(self)
            return

        if dot_v[2] < 0:
            rad = -math.asin(dot_min)
        else:
            rad = math.asin(dot_min)
        m = Matrix([
            [ 1, 0,             0 ],
            [ 0, math.cos(rad),-math.sin(rad) ],
            [ 0, math.sin(rad), math.cos(rad) ]
        ])
        selected_object.rotate(Quaternion.fromMatrix(m), SceneNode.TransformSpace.Parent)

        progress_message.hide()
        self.operationStopped.emit(self)
<commit_msg>Add support for multiselection<commit_after># Copyright (c) 2015 Ultimaker B.V.
# Uranium is released under the terms of the AGPLv3 or higher.

from PyQt5.QtWidgets import QApplication

from UM.Tool import Tool
from UM.Event import Event, MouseEvent, KeyEvent
from UM.Application import Application
from UM.Message import Message
from UM.Scene.ToolHandle import ToolHandle
from UM.Scene.Selection import Selection
from UM.Scene.SceneNode import SceneNode

from UM.Math.Plane import Plane
from UM.Math.Vector import Vector
from UM.Math.Quaternion import Quaternion
from UM.Math.Matrix import Matrix
from UM.Math.Float import Float

from UM.Operations.RotateOperation import RotateOperation
from UM.Operations.TranslateOperation import TranslateOperation
from UM.Operations.GroupedOperation import GroupedOperation
from UM.Operations.SetTransformOperation import SetTransformOperation

from . import RotateToolHandle

import math
import time

class RotateTool(Tool):
    def __init__(self):
        super().__init__()
        self._handle = RotateToolHandle.RotateToolHandle()

        self._snap_rotation = True
        self._snap_angle = math.radians(15)

        self._angle = None

        self._angle_update_time = None

        self.setExposedProperties("Rotation", "RotationSnap", "RotationSnapAngle")

    def event(self, event):
        super().event(event)

        if event.type == Event.KeyPressEvent and event.key == KeyEvent.ShiftKey:
            self._snap_rotation = (not self._snap_rotation)
            self.propertyChanged.emit()

        if event.type == Event.KeyReleaseEvent and event.key == KeyEvent.ShiftKey:
            self._snap_rotation = (not self._snap_rotation)
            self.propertyChanged.emit()

        if event.type == Event.MousePressEvent:
            if MouseEvent.LeftButton not in event.buttons:
                return False

            id = self._selection_pass.getIdAtPosition(event.x, event.y)
            if not id:
                return

            if ToolHandle.isAxis(id):
                self.setLockedAxis(id)
                handle_position = self._handle.getWorldPosition()

                if id == ToolHandle.XAxis:
                    self.setDragPlane(Plane(Vector(1, 0, 0), handle_position.x))
                elif id == ToolHandle.YAxis:
                    self.setDragPlane(Plane(Vector(0, 1, 0), handle_position.y))
                elif self._locked_axis == ToolHandle.ZAxis:
                    self.setDragPlane(Plane(Vector(0, 0, 1), handle_position.z))

                self.setDragStart(event.x, event.y)
                self._angle = 0
                self.operationStarted.emit(self)

        if event.type == Event.MouseMoveEvent:
            if not self.getDragPlane():
                return False

            if not self.getDragStart():
                self.setDragStart(event.x, event.y)

            handle_position = self._handle.getWorldPosition()

            drag_start = (self.getDragStart() - handle_position).normalize()
            drag_position = self.getDragPosition(event.x, event.y)
            if not drag_position:
                return
            drag_end = (drag_position - handle_position).normalize()

            try:
                angle = math.acos(drag_start.dot(drag_end))
            except ValueError:
                angle = 0

            if self._snap_rotation:
                angle = int(angle / self._snap_angle) * self._snap_angle
                if angle == 0:
                    return

            rotation = None
            if self.getLockedAxis() == ToolHandle.XAxis:
                direction = 1 if Vector.Unit_X.dot(drag_start.cross(drag_end)) > 0 else -1
                rotation = Quaternion.fromAngleAxis(direction * angle, Vector.Unit_X)
            elif self.getLockedAxis() == ToolHandle.YAxis:
                direction = 1 if Vector.Unit_Y.dot(drag_start.cross(drag_end)) > 0 else -1
                rotation = Quaternion.fromAngleAxis(direction * angle, Vector.Unit_Y)
            elif self.getLockedAxis() == ToolHandle.ZAxis:
                direction = 1 if Vector.Unit_Z.dot(drag_start.cross(drag_end)) > 0 else -1
                rotation = Quaternion.fromAngleAxis(direction * angle, Vector.Unit_Z)

            self._angle += direction * angle

            # Rate-limit the angle change notification
            # This is done to prevent the UI from being flooded with property change notifications,
            # which in turn would trigger constant repaints.
            new_time = time.monotonic()
            if not self._angle_update_time or new_time - self._angle_update_time > 0.01:
                self.propertyChanged.emit()
                self._angle_update_time = new_time

            Selection.applyOperation(RotateOperation, rotation)

            self.setDragStart(event.x, event.y)

        if event.type == Event.MouseReleaseEvent:
            if self.getDragPlane():
                self.setDragPlane(None)
                self.setLockedAxis(None)
                self._angle = None
                self.propertyChanged.emit()
                self.operationStopped.emit(self)
                return True

    def getRotation(self):
        return round(math.degrees(self._angle)) if self._angle else None

    def getRotationSnap(self):
        return self._snap_rotation

    def setRotationSnap(self, snap):
        if snap != self._snap_rotation:
            self._snap_rotation = snap
            self.propertyChanged.emit()

    def getRotationSnapAngle(self):
        return self._snap_angle

    def setRotationSnapAngle(self, angle):
        if angle != self._snap_angle:
            self._snap_angle = angle
            self.propertyChanged.emit()

    def resetRotation(self):
        Selection.applyOperation(SetTransformOperation, None, Quaternion(), None)

    def layFlat(self):
        # Based on https://github.com/daid/Cura/blob/SteamEngine/Cura/util/printableObject.py#L207
        # Note: Y & Z axis are swapped

        self.operationStarted.emit(self)
        progress_message = Message("Laying object flat on buildplate...", lifetime = 0, dismissable = False)
        progress_message.setProgress(0)
        progress_message.show()

        iterations = 0
        last_progress = 0
        total_iterations = 0
        for selected_object in Selection.getAllSelectedObjects():
            total_iterations += len(selected_object.getMeshDataTransformed().getVertices()) * 2

        for selected_object in Selection.getAllSelectedObjects():
            transformed_vertices = selected_object.getMeshDataTransformed().getVertices()
            min_y_vertex = transformed_vertices[transformed_vertices.argmin(0)[1]]
            dot_min = 1.0
            dot_v = None

            for v in transformed_vertices:
                diff = v - min_y_vertex
                length = math.sqrt(diff[0] * diff[0] + diff[2] * diff[2] + diff[1] * diff[1])
                if length < 5:
                    continue
                dot = (diff[1] / length)
                if dot_min > dot:
                    dot_min = dot
                    dot_v = diff
                iterations += 1
                progress = round(100*iterations/total_iterations)
                if progress != last_progress:
                    last_progress = progress
                    progress_message.setProgress(progress)
                    QApplication.processEvents()

            if dot_v is None:
                iterations += len(transformed_vertices)
                continue

            rad = -math.asin(dot_min)
            m = Matrix([
                [ math.cos(rad), math.sin(rad), 0 ],
                [-math.sin(rad), math.cos(rad), 0 ],
                [ 0,             0,             1 ]
            ])
            selected_object.rotate(Quaternion.fromMatrix(m), SceneNode.TransformSpace.Parent)

            rad = math.atan2(dot_v[2], dot_v[0])
            m = Matrix([
                [ math.cos(rad), 0, math.sin(rad)],
                [ 0,             1, 0 ],
                [-math.sin(rad), 0, math.cos(rad)]
            ])
            selected_object.rotate(Quaternion.fromMatrix(m), SceneNode.TransformSpace.Parent)

            transformed_vertices = selected_object.getMeshDataTransformed().getVertices()
            min_y_vertex = transformed_vertices[transformed_vertices.argmin(0)[1]]
            dot_min = 1.0
            dot_v = None

            for v in transformed_vertices:
                diff = v - min_y_vertex
                length = math.sqrt(diff[2] * diff[2] + diff[1] * diff[1])
                if length < 5:
                    continue
                dot = (diff[1] / length)
                if dot_min > dot:
                    dot_min = dot
                    dot_v = diff
                iterations += 1
                progress = round(100*iterations/total_iterations)
                if progress != last_progress:
                    last_progress = progress
                    progress_message.setProgress(progress)
                    QApplication.processEvents()

            if dot_v is None:
                continue

            if dot_v[2] < 0:
                rad = -math.asin(dot_min)
            else:
                rad = math.asin(dot_min)
            m = Matrix([
                [ 1, 0,             0 ],
                [ 0, math.cos(rad),-math.sin(rad) ],
                [ 0, math.sin(rad), math.cos(rad) ]
            ])
            selected_object.rotate(Quaternion.fromMatrix(m), SceneNode.TransformSpace.Parent)

        progress_message.hide()
        self.operationStopped.emit(self)
<|endoftext|>


<commit_before># Copyright (c) 2015 Ultimaker B.V.
# Uranium is released under the terms of the AGPLv3 or higher.

from UM.Resources import Resources
from UM.Application import Application
from UM.Math.Color import Color
from UM.Preferences import Preferences

from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator

from UM.View.View import View
from UM.View.GL.OpenGL import OpenGL

import math

## Standard view for mesh models.
class SimpleView(View):
    def __init__(self):
        super().__init__()

        self._material = None

    def beginRendering(self):
        scene = self.getController().getScene()
        renderer = self.getRenderer()

        if not self._material:
            self._material = OpenGL.getInstance().createMaterial(Resources.getPath(Resources.Shaders, "object.shader"))

        for node in DepthFirstIterator(scene.getRoot()):
            if not node.render(renderer):
                if node.getMeshData() and node.isVisible():
                    renderer.queueNode(node, material = self._material)

    def endRendering(self):
        pass
<commit_msg>Fix SimpleView with updated API<commit_after># Copyright (c) 2015 Ultimaker B.V.
# Uranium is released under the terms of the AGPLv3 or higher.

from UM.Resources import Resources
from UM.Application import Application
from UM.Math.Color import Color
from UM.Preferences import Preferences

from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator

from UM.View.View import View
from UM.View.GL.OpenGL import OpenGL

import math

## Standard view for mesh models.
class SimpleView(View):
    def __init__(self):
        super().__init__()

        self._shader = None

    def beginRendering(self):
        scene = self.getController().getScene()
        renderer = self.getRenderer()

        if not self._shader:
            self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "object.shader"))

        for node in DepthFirstIterator(scene.getRoot()):
            if not node.render(renderer):
                if node.getMeshData() and node.isVisible():
                    renderer.queueNode(node, material = self._shader)

    def endRendering(self):
        pass
<|endoftext|>


<commit_before>#!/usr/bin/env python
#Copyright (c) 2011, 2012 Walter Bender
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

from gettext import gettext as _

try:
    from numpy import append
    from numpy.fft import rfft
    PITCH_AVAILABLE = True
except:
    PITCH_AVAILABLE = False

from plugins.plugin import Plugin

from plugins.audio_sensors.audiograb import AudioGrab, \
    SENSOR_DC_NO_BIAS, SENSOR_DC_BIAS, SENSOR_AC_BIAS

from plugins.audio_sensors.ringbuffer import RingBuffer1d

from TurtleArt.tapalette import make_palette
from TurtleArt.taconstants import XO1, XO15, XO175, XO30
from TurtleArt.talogo import primitive_dictionary
from TurtleArt.tautils import debug_output

import logging
_logger = logging.getLogger('turtleart-activity audio sensors plugin')

def _avg(array, abs_value=False):
    ''' Calc. the average value of an array '''
    if len(array) == 0:
        return 0
    array_sum = 0
    if abs_value:
        for a in array:
            array_sum += abs(a)
    else:
        for a in array:
            array_sum += a
    return float(array_sum) / len(array)

class Audio_sensors(Plugin):

    def __init__(self, parent):
        self._parent = parent
        self._status = True  # TODO: test for audio device
        # These flags are referenced by audiograb
        self.hw = self._parent.hw
        self.running_sugar = self._parent.running_sugar

    def setup(self):
        ''' set up audio-sensor-specific blocks '''
        self.max_samples = 1500
        self.input_step = 1

        self.ringbuffer = []

        palette = make_palette('sensor',
                               colors=["#FF6060", "#A06060"],
                               help_string=_('Palette of sensor blocks'))

        primitive_dictionary['sound'] = self.prim_sound
        primitive_dictionary['volume'] = self.prim_volume
        if self._status:
            palette.add_block('sound',
                              style='box-style',
                              label=_('sound'),
                              help_string=_('raw microphone input signal'),
                              value_block=True,
                              prim_name='sound')

            palette.add_block('volume',
                              style='box-style',
                              label=_('loudness'),
                              help_string=_('microphone input volume'),
                              value_block=True,
                              prim_name='volume')
        else:
            palette.add_block('sound',
                              hidden=True,
                              style='box-style',
                              label=_('sound'),
                              help_string=_('raw microphone input signal'),
                              value_block=True,
                              prim_name='sound')
            palette.add_block('volume',
                              hidden=True,
                              style='box-style',
                              label=_('loudness'),
                              help_string=_('microphone input volume'),
                              value_block=True,
                              prim_name='volume')

        self._parent.lc.def_prim(
            'sound', 0, lambda self: primitive_dictionary['sound'](0))
        self._parent.lc.def_prim(
            'volume', 0, lambda self: primitive_dictionary['volume'](0))

        primitive_dictionary['pitch'] = self.prim_pitch
        if PITCH_AVAILABLE and self._status:
            palette.add_block('pitch',
                              style='box-style',
                              label=_('pitch'),
                              help_string=_('microphone input pitch'),
                              value_block=True,
                              prim_name='pitch')
        else:
            palette.add_block('pitch',
                              hidden=True,
                              style='box-style',
                              label=_('pitch'),
                              help_string=_('microphone input pitch'),
                              value_block=True,
                              prim_name='pitch')
        self._parent.lc.def_prim('pitch', 0,
                                 lambda self: primitive_dictionary['pitch'](0))

        primitive_dictionary['resistance'] = self.prim_resistance
        primitive_dictionary['voltage'] = self.prim_voltage
        if self.hw in [XO1, XO15, XO175, XO30] and self._status:
            if self.hw == XO1:
                self.voltage_gain = 0.00002225
                self.voltage_bias = 1.140
            elif self.hw == XO15:
                self.voltage_gain = -0.0001471
                self.voltage_bias = 1.695
            elif self.hw == XO175:
                self.voltage_gain = 0.000051
                self.voltage_bias = 1.372
            else:  # XO 3.0
                self.voltage_gain = 0.00007692
                self.voltage_bias = 0.719
            palette.add_block('resistance',
                              style='box-style',
                              label=_('resistance'),
                              help_string=_('microphone input resistance'),
                              value_block=True,
                              prim_name='resistance')
            palette.add_block('voltage',
                              style='box-style',
                              label=_('voltage'),
                              help_string=_('microphone input voltage'),
                              value_block=True,
                              prim_name='voltage')
        else:
            palette.add_block('resistance',
                              hidden=True,
                              style='box-style',
                              label=_('resistance'),
                              help_string=_('microphone input resistance'),
                              prim_name='resistance')
            palette.add_block('voltage',
                              hidden=True,
                              style='box-style',
                              label=_('voltage'),
                              help_string=_('microphone input voltage'),
                              prim_name='voltage')

        if self.hw in [XO15, XO175, XO30] and self._status:
            palette.add_block('resistance2',
                              style='box-style',
                              label=_('resistance') + '2',
                              help_string=_('microphone input resistance'),
                              value_block=True,
                              prim_name='resistance2')
            palette.add_block('voltage2',
                              style='box-style',
                              label=_('voltage') + '2',
                              help_string=_('microphone input voltage'),
                              value_block=True,
                              prim_name='voltage2')
        else:
            palette.add_block('resistance2',
                              hidden=True,
                              style='box-style',
                              label=_('resistance') + '2',
                              help_string=_('microphone input resistance'),
                              prim_name='resistance2')
            palette.add_block('voltage2',
                              hidden=True,
                              style='box-style',
                              label=_('voltage') + '2',
                              help_string=_('microphone input voltage'),
                              prim_name='voltage2')
        self._parent.lc.def_prim(
            'resistance', 0,
            lambda self: primitive_dictionary['resistance'](0))
        self._parent.lc.def_prim(
            'voltage', 0, lambda self: primitive_dictionary['voltage'](0))
        self._parent.lc.def_prim(
            'resistance2', 0,
            lambda self: primitive_dictionary['resistance'](1))
        self._parent.lc.def_prim(
            'voltage2', 0, lambda self: primitive_dictionary['voltage'](1))

        self.audio_started = False
        if self.hw in [XO175, XO30]:
            self.PARAMETERS = {
                SENSOR_AC_BIAS: (False, True, 80, True),
                SENSOR_DC_NO_BIAS: (True, False, 80, False),
                SENSOR_DC_BIAS: (True, True, 90, False)
                }
        elif self.hw == XO15:
            self.PARAMETERS = {
                SENSOR_AC_BIAS: (False, True, 80, True),
                SENSOR_DC_NO_BIAS: (True, False, 80, False),
                SENSOR_DC_BIAS: (True, True, 90, False)
                }
        elif self.hw == XO1:
            self.PARAMETERS = {
                SENSOR_AC_BIAS: (False, True, 40, True),
                SENSOR_DC_NO_BIAS: (True, False, 0, False),
                SENSOR_DC_BIAS: (True, True, 0, False)
                }
        else:
            self.PARAMETERS = {
                SENSOR_AC_BIAS: (None, True, 40, True),
                SENSOR_DC_NO_BIAS: (True, False, 80, False),
                SENSOR_DC_BIAS: (True, True, 90, False)
                }

    def start(self):
        ''' Start grabbing audio if there is an audio block in use '''
        if not self._status:
            return
        if self.audio_started:
            self.audiograb.stop_grabbing()
        if len(self._parent.block_list.get_similar_blocks(
                'block', ['volume', 'sound', 'pitch'])) > 0:
            mode, bias, gain, boost = self.PARAMETERS[SENSOR_AC_BIAS]
        elif len(self._parent.block_list.get_similar_blocks(
                'block', ['resistance', 'resistance2'])) > 0:
            mode, bias, gain, boost = self.PARAMETERS[SENSOR_DC_BIAS]
        elif len(self._parent.block_list.get_similar_blocks(
                'block', ['voltage', 'voltage2'])) > 0:
            mode, bias, gain, boost = self.PARAMETERS[SENSOR_DC_NO_BIAS]
        else:
            return  # No audio blocks in use.
        self.audiograb = AudioGrab(self.new_buffer, self,
                                   mode, bias, gain, boost)
        self._channels = self.audiograb.channels
        for i in range(self._channels):
            self.ringbuffer.append(RingBuffer1d(self.max_samples,
                                                dtype='int16'))
        self.audiograb.start_grabbing()
        self.audio_started = True

    def new_buffer(self, buf, channel=0):
        ''' Append a new buffer to the ringbuffer '''
        self.ringbuffer[channel].append(buf)
        return True

    def stop(self):
        ''' This gets called by the stop button '''
        if self._status and self.audio_started:
            self.audiograb.on_activity_quit()  # reset all setting
        self.audio_started = False

    def goto_background(self):
        ''' This gets called when your process is sent to the background '''
        pass

    def return_to_foreground(self):
        ''' This gets called when your process returns from the background '''
        pass

    def quit(self):
        ''' This gets called by the quit button '''
        if self._status and self.audio_started:
            self.audiograb.on_activity_quit()

    def _status_report(self):
        debug_output(
            'Reporting audio sensor status: %s' % (str(self._status)),
            self._parent.running_sugar)
        return self._status

    # Block primitives used in talogo

    def prim_volume(self, channel):
        ''' return mic in value '''
        if not self._status:
            return 0
        buf = self.ringbuffer[channel].read(None, self.input_step)
        if len(buf) > 0:
            volume = float(_avg(buf, abs_value=True))
            self._parent.lc.update_label_value('volume', volume)
            return volume
        else:
            return 0

    def prim_sound(self, channel):
        ''' return raw mic in value '''
        if not self._status:
            return 0
        buf = self.ringbuffer[channel].read(None, self.input_step)
        if len(buf) > 0:
            sound = float(buf[0])
            self._parent.lc.update_label_value('sound', sound)
            return sound
        else:
            return 0

    def prim_pitch(self, channel):
        ''' return index of max value in fft of mic in values '''
        if not PITCH_AVAILABLE or not self._status:
            return 0
        buf = []
        for i in range(4):
            buf = append(
                buf, self.ringbuffer[channel].read(None, self.input_step))
        if len(buf) > 0:
            buf = rfft(buf)
            buf = abs(buf)
            maxi = buf.argmax()
            if maxi == 0:
                pitch = 0
            else:  # Simple interpolation
                a, b, c = buf[maxi - 4], buf[maxi], buf[maxi + 4]
                maxi -= (4. * a) / float(a + b + c)
                maxi += (4. * c) / float(a + b + c)
                pitch = maxi * 48000 / (len(buf) * 2)

            self._parent.lc.update_label_value('pitch', pitch)
            return pitch
        else:
            return 0

    def prim_resistance(self, channel):
        ''' return resistance sensor value '''
        if not self.hw in [XO1, XO15, XO175, XO30] or not self._status:
            return 0
        if self.hw == XO1 and channel != 0:
            return 0
        buf = self.ringbuffer[channel].read(None, self.input_step)
        if len(buf) > 0:
            # See <http://bugs.sugarlabs.org/ticket/552#comment:7>
            # TODO: test this calibration on XO 1.5, XO 1.75
            avg_buf = float(_avg(buf))
            if self.hw == XO1:
                resistance = 2.718 ** ((avg_buf * 0.000045788) + 8.0531)
            elif self.hw == XO15:
                if avg_buf > 0:
                    resistance = (420000000 / avg_buf) - 13500
                else:
                    resistance = 420000000
            elif self.hw == XO175:
                if avg_buf < 30700:
                    resistance = (180000000 / (30700 - avg_buf)) - 3150
                else:
                    resistance = 999999999
            else:  # XO 3.0
                if avg_buf < 30514:
                    resistance = (46000000 / (30514 - avg_buf)) - 1150
                else:
                    resistance = 999999999
            if channel == 0:
                self._parent.lc.update_label_value('resistance', resistance)
            else:
                self._parent.lc.update_label_value('resistance2', resistance)
            if resistance < 0:
                resistance = 0
            return resistance
        else:
            return 0

    def prim_voltage(self, channel):
        ''' return voltage sensor value '''
        if not self.hw in [XO1, XO15, XO175, XO30] or not self._status:
            return 0
        if self.hw == XO1 and channel != 0:
            return 0
        buf = self.ringbuffer[channel].read(None, self.input_step)
        if len(buf) > 0:
            # See <http://bugs.sugarlabs.org/ticket/552#comment:7>
            voltage = float(_avg(buf)) * self.voltage_gain + self.voltage_bias
            if channel == 0:
                self._parent.lc.update_label_value('voltage', voltage)
            else:
                self._parent.lc.update_label_value('voltage2', voltage)
            return voltage
        else:
            return 0
<commit_msg>simplified freq. code<commit_after>#!/usr/bin/env python
#Copyright (c) 2011, 2012 Walter Bender
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

from gettext import gettext as _

try:
    from numpy import append
    from numpy.fft import rfft
    PITCH_AVAILABLE = True
except:
    PITCH_AVAILABLE = False

from plugins.plugin import Plugin

from plugins.audio_sensors.audiograb import AudioGrab, \
    SENSOR_DC_NO_BIAS, SENSOR_DC_BIAS, SENSOR_AC_BIAS

from plugins.audio_sensors.ringbuffer import RingBuffer1d

from TurtleArt.tapalette import make_palette
from TurtleArt.taconstants import XO1, XO15, XO175, XO30
from TurtleArt.talogo import primitive_dictionary
from TurtleArt.tautils import debug_output

import logging
_logger = logging.getLogger('turtleart-activity audio sensors plugin')

def _avg(array, abs_value=False):
    ''' Calc. the average value of an array '''
    if len(array) == 0:
        return 0
    array_sum = 0
    if abs_value:
        for a in array:
            array_sum += abs(a)
    else:
        for a in array:
            array_sum += a
    return float(array_sum) / len(array)

class Audio_sensors(Plugin):

    def __init__(self, parent):
        self._parent = parent
        self._status = True  # TODO: test for audio device
        # These flags are referenced by audiograb
        self.hw = self._parent.hw
        self.running_sugar = self._parent.running_sugar

    def setup(self):
        ''' set up audio-sensor-specific blocks '''
        self.max_samples = 1500
        self.input_step = 1

        self.ringbuffer = []

        palette = make_palette('sensor',
                               colors=["#FF6060", "#A06060"],
                               help_string=_('Palette of sensor blocks'))

        primitive_dictionary['sound'] = self.prim_sound
        primitive_dictionary['volume'] = self.prim_volume
        if self._status:
            palette.add_block('sound',
                              style='box-style',
                              label=_('sound'),
                              help_string=_('raw microphone input signal'),
                              value_block=True,
                              prim_name='sound')

            palette.add_block('volume',
                              style='box-style',
                              label=_('loudness'),
                              help_string=_('microphone input volume'),
                              value_block=True,
                              prim_name='volume')
        else:
            palette.add_block('sound',
                              hidden=True,
                              style='box-style',
                              label=_('sound'),
                              help_string=_('raw microphone input signal'),
                              value_block=True,
                              prim_name='sound')
            palette.add_block('volume',
                              hidden=True,
                              style='box-style',
                              label=_('loudness'),
                              help_string=_('microphone input volume'),
                              value_block=True,
                              prim_name='volume')

        self._parent.lc.def_prim(
            'sound', 0, lambda self: primitive_dictionary['sound'](0))
        self._parent.lc.def_prim(
            'volume', 0, lambda self: primitive_dictionary['volume'](0))

        primitive_dictionary['pitch'] = self.prim_pitch
        if PITCH_AVAILABLE and self._status:
            palette.add_block('pitch',
                              style='box-style',
                              label=_('pitch'),
                              help_string=_('microphone input pitch'),
                              value_block=True,
                              prim_name='pitch')
        else:
            palette.add_block('pitch',
                              hidden=True,
                              style='box-style',
                              label=_('pitch'),
                              help_string=_('microphone input pitch'),
                              value_block=True,
                              prim_name='pitch')
        self._parent.lc.def_prim('pitch', 0,
                                 lambda self: primitive_dictionary['pitch'](0))

        primitive_dictionary['resistance'] = self.prim_resistance
        primitive_dictionary['voltage'] = self.prim_voltage
        if self.hw in [XO1, XO15, XO175, XO30] and self._status:
            if self.hw == XO1:
                self.voltage_gain = 0.00002225
                self.voltage_bias = 1.140
            elif self.hw == XO15:
                self.voltage_gain = -0.0001471
                self.voltage_bias = 1.695
            elif self.hw == XO175:
                self.voltage_gain = 0.000051
                self.voltage_bias = 1.372
            else:  # XO 3.0
                self.voltage_gain = 0.00007692
                self.voltage_bias = 0.719
            palette.add_block('resistance',
                              style='box-style',
                              label=_('resistance'),
                              help_string=_('microphone input resistance'),
                              value_block=True,
                              prim_name='resistance')
            palette.add_block('voltage',
                              style='box-style',
                              label=_('voltage'),
                              help_string=_('microphone input voltage'),
                              value_block=True,
                              prim_name='voltage')
        else:
            palette.add_block('resistance',
                              hidden=True,
                              style='box-style',
                              label=_('resistance'),
                              help_string=_('microphone input resistance'),
                              prim_name='resistance')
            palette.add_block('voltage',
                              hidden=True,
                              style='box-style',
                              label=_('voltage'),
                              help_string=_('microphone input voltage'),
                              prim_name='voltage')

        if self.hw in [XO15, XO175, XO30] and self._status:
            palette.add_block('resistance2',
                              style='box-style',
                              label=_('resistance') + '2',
                              help_string=_('microphone input resistance'),
                              value_block=True,
                              prim_name='resistance2')
            palette.add_block('voltage2',
                              style='box-style',
                              label=_('voltage') + '2',
                              help_string=_('microphone input voltage'),
                              value_block=True,
                              prim_name='voltage2')
        else:
            palette.add_block('resistance2',
                              hidden=True,
                              style='box-style',
                              label=_('resistance') + '2',
                              help_string=_('microphone input resistance'),
                              prim_name='resistance2')
            palette.add_block('voltage2',
                              hidden=True,
                              style='box-style',
                              label=_('voltage') + '2',
                              help_string=_('microphone input voltage'),
                              prim_name='voltage2')
        self._parent.lc.def_prim(
            'resistance', 0,
            lambda self: primitive_dictionary['resistance'](0))
        self._parent.lc.def_prim(
            'voltage', 0, lambda self: primitive_dictionary['voltage'](0))
        self._parent.lc.def_prim(
            'resistance2', 0,
            lambda self: primitive_dictionary['resistance'](1))
        self._parent.lc.def_prim(
            'voltage2', 0, lambda self: primitive_dictionary['voltage'](1))

        self.audio_started = False
        if self.hw in [XO175, XO30]:
            self.PARAMETERS = {
                SENSOR_AC_BIAS: (False, True, 80, True),
                SENSOR_DC_NO_BIAS: (True, False, 80, False),
                SENSOR_DC_BIAS: (True, True, 90, False)
                }
        elif self.hw == XO15:
            self.PARAMETERS = {
                SENSOR_AC_BIAS: (False, True, 80, True),
                SENSOR_DC_NO_BIAS: (True, False, 80, False),
                SENSOR_DC_BIAS: (True, True, 90, False)
                }
        elif self.hw == XO1:
            self.PARAMETERS = {
                SENSOR_AC_BIAS: (False, True, 40, True),
                SENSOR_DC_NO_BIAS: (True, False, 0, False),
                SENSOR_DC_BIAS: (True, True, 0, False)
                }
        else:
            self.PARAMETERS = {
                SENSOR_AC_BIAS: (None, True, 40, True),
                SENSOR_DC_NO_BIAS: (True, False, 80, False),
                SENSOR_DC_BIAS: (True, True, 90, False)
                }

    def start(self):
        ''' Start grabbing audio if there is an audio block in use '''
        if not self._status:
            return
        if self.audio_started:
            self.audiograb.stop_grabbing()
        if len(self._parent.block_list.get_similar_blocks(
                'block', ['volume', 'sound', 'pitch'])) > 0:
            mode, bias, gain, boost = self.PARAMETERS[SENSOR_AC_BIAS]
        elif len(self._parent.block_list.get_similar_blocks(
                'block', ['resistance', 'resistance2'])) > 0:
            mode, bias, gain, boost = self.PARAMETERS[SENSOR_DC_BIAS]
        elif len(self._parent.block_list.get_similar_blocks(
                'block', ['voltage', 'voltage2'])) > 0:
            mode, bias, gain, boost = self.PARAMETERS[SENSOR_DC_NO_BIAS]
        else:
            return  # No audio blocks in use.
        self.audiograb = AudioGrab(self.new_buffer, self,
                                   mode, bias, gain, boost)
        self._channels = self.audiograb.channels
        for i in range(self._channels):
            self.ringbuffer.append(RingBuffer1d(self.max_samples,
                                                dtype='int16'))
        self.audiograb.start_grabbing()
        self.audio_started = True

    def new_buffer(self, buf, channel=0):
        ''' Append a new buffer to the ringbuffer '''
        self.ringbuffer[channel].append(buf)
        return True

    def stop(self):
        ''' This gets called by the stop button '''
        if self._status and self.audio_started:
            self.audiograb.on_activity_quit()  # reset all setting
        self.audio_started = False

    def goto_background(self):
        ''' This gets called when your process is sent to the background '''
        pass

    def return_to_foreground(self):
        ''' This gets called when your process returns from the background '''
        pass

    def quit(self):
        ''' This gets called by the quit button '''
        if self._status and self.audio_started:
            self.audiograb.on_activity_quit()

    def _status_report(self):
        debug_output(
            'Reporting audio sensor status: %s' % (str(self._status)),
            self._parent.running_sugar)
        return self._status

    # Block primitives used in talogo

    def prim_volume(self, channel):
        ''' return mic in value '''
        if not self._status:
            return 0
        buf = self.ringbuffer[channel].read(None, self.input_step)
        if len(buf) > 0:
            volume = float(_avg(buf, abs_value=True))
            self._parent.lc.update_label_value('volume', volume)
            return volume
        else:
            return 0

    def prim_sound(self, channel):
        ''' return raw mic in value '''
        if not self._status:
            return 0
        buf = self.ringbuffer[channel].read(None, self.input_step)
        if len(buf) > 0:
            sound = float(buf[0])
            self._parent.lc.update_label_value('sound', sound)
            return sound
        else:
            return 0

    def prim_pitch(self, channel):
        ''' return index of max value in fft of mic in values '''
        if not PITCH_AVAILABLE or not self._status:
            return 0
        buf = self.ringbuffer[channel].read(None, self.input_step)
        if len(buf) > 0:
            buf = rfft(buf)
            buf = abs(buf)
            maxi = buf.argmax()
            if maxi == 0:
                pitch = 0
            else:  # Simple interpolation
                a, b, c = buf[maxi - 1], buf[maxi], buf[maxi + 1]
                maxi -= a / float(a + b + c)
                maxi += c / float(a + b + c)
                pitch = maxi * 48000 / (len(buf) * 2)

            self._parent.lc.update_label_value('pitch', pitch)
            return pitch
        else:
            return 0

    def prim_resistance(self, channel):
        ''' return resistance sensor value '''
        if not self.hw in [XO1, XO15, XO175, XO30] or not self._status:
            return 0
        if self.hw == XO1 and channel != 0:
            return 0
        buf = self.ringbuffer[channel].read(None, self.input_step)
        if len(buf) > 0:
            # See <http://bugs.sugarlabs.org/ticket/552#comment:7>
            # TODO: test this calibration on XO 1.5, XO 1.75
            avg_buf = float(_avg(buf))
            if self.hw == XO1:
                resistance = 2.718 ** ((avg_buf * 0.000045788) + 8.0531)
            elif self.hw == XO15:
                if avg_buf > 0:
                    resistance = (420000000 / avg_buf) - 13500
                else:
                    resistance = 420000000
            elif self.hw == XO175:
                if avg_buf < 30700:
                    resistance = (180000000 / (30700 - avg_buf)) - 3150
                else:
                    resistance = 999999999
            else:  # XO 3.0
                if avg_buf < 30514:
                    resistance = (46000000 / (30514 - avg_buf)) - 1150
                else:
                    resistance = 999999999
            if channel == 0:
                self._parent.lc.update_label_value('resistance', resistance)
            else:
                self._parent.lc.update_label_value('resistance2', resistance)
            if resistance < 0:
                resistance = 0
            return resistance
        else:
            return 0

    def prim_voltage(self, channel):
        ''' return voltage sensor value '''
        if not self.hw in [XO1, XO15, XO175, XO30] or not self._status:
            return 0
        if self.hw == XO1 and channel != 0:
            return 0
        buf = self.ringbuffer[channel].read(None, self.input_step)
        if len(buf) > 0:
            # See <http://bugs.sugarlabs.org/ticket/552#comment:7>
            voltage = float(_avg(buf)) * self.voltage_gain + self.voltage_bias
            if channel == 0:
                self._parent.lc.update_label_value('voltage', voltage)
            else:
                self._parent.lc.update_label_value('voltage2', voltage)
            return voltage
        else:
            return 0
<|endoftext|>


<commit_before>from proton_decay_study.generators.base import BaseDataGenerator
from proton_decay_study.generators.single_file import SingleFileDataGenerator
import h5py
import logging
import threading
import subprocess
import Queue
import traceback
import signal
import sys

class SingleFileThread(threading.Thread):
  """
    Represents a single file that is asynchronously
  """

  # Locks class for the duration of parent lifetime
  # Currently, hierarchal threading is not supported
  threadLock = threading.Lock()

  # Set this to 0 to kill all threads once prefetch is finished.
  __ThreadExitFlag__ = 1

  # Holds the current thread queue
  queue = Queue.Queue(100000)

  # Locks the thread queue
  queueLock = threading.Lock()
  logger = logging.getLogger('pdk.gen.singlefilethread')

  activeThreads = []

  def __init__(self, datasetname,
               labelsetname, batch_size):
    """
        :param: datasetname The name used to pull the dataset from file
        :type: datasetname string
        :param: labelsetname The name used to pull the labelset from file
        :type: labelsetname string
        :param: batch_size The number of images and truths to pull from the file.
        :type: batch_size int
    """
    super(SingleFileThread, self).__init__()
    self.datasetname = datasetname
    self.labelsetname = labelsetname
    self.batch_size = batch_size

    # prefetched means that there's data ready
    self._buffer = None
    self.single_thread_lock = threading.Lock()

    # This holds the
    self._filegen = None

  @property
  def get(self):
    self.single_thread_lock.acquire()
    if self._buffer is None:
      pass

  def run(self):
    """
      Loops over queue to accept new configurations
    """
    while SingleFileThread.__ThreadExitFlag__:
      if self.single_thread_lock.locked():
        continue
      else:
        self.single_thread_lock.acquire()
        if self._buffer is not None:
          self.single_thread_lock.release()
          continue

      if self._filegen is None:
        self.queueLock.acquire()
        if not self.queue.empty():
          self._filegen = SingleFileDataGenerator(SingleFileThread.queue.get(),
                                              self.datasetname, self.labelsetname,
                                              self.batch_size)
        self.queueLock.release()
      else:
        try:
          try:
            self.single_thread_lock.acquire()
            self._buffer  = self._filegen.next()
            self.single_thread_lock.release()
          except StopIteration:
            self._buffer  = None
            self.single_thread_lock.release()
            self._filegen = None
        except Exception:
          exc_type, exc_value, exc_traceback = sys.exc_info()
          self.logger.error(repr(traceback.format_exception(exc_type, exc_value,
                                                exc_traceback)))

  @staticmethod
  def killRunThreads(signum, frame):
      """
          Sets the thread kill flag to each of the ongoing analysis threads
      """
      logger.info("Killing Single File threads...")
      SingleFileThread.__ThreadExitFlag__ = 0
      sys.exit(signum)

  @staticmethod
  def startThreads(nThreads, datasetname,
                            labelsetname, batch_size):
    logger.info("Starting {} Single File threads".format(nThreads))
    for i in range(nThreads):
        thread = SingleFileThread(datasetname,
                          labelsetname, batch_size)
        thread.start()
        SingleFileThread.activeThreads.append(thread)

  @staticmethod
  def waitTillComplete(callback=None):
      if callback is None:
          while not SingleFileThread.queue.empty() and SingleFileThread.__ThreadExitFlag__:
              sys.stdout.flush()
      else:
          while not SingleFileThread.queue.empty() and SingleFileThread.__ThreadExitFlag__:
              callback()

      # Notify threads it's time to exit
      SingleFileThread.__ThreadExitFlag__ = 0

      # Wait for all threads to complete
      for t in SingleFileThread.activeThreads:
          t.join()
      # dealloc
      SingleFileThread.activeThreads = []

signal.signal(signal.SIGINT, SingleFileThread.killRunThreads)

class ThreadedMultiFileDataGenerator(BaseDataGenerator):
  """
      Uses threads to pull asynchronously from files
  """
  logger = logging.getLogger("pdk.generator.threaded_multi")

  def __init__(self, datapaths, datasetname,
               labelsetname, batch_size=1, nThreads=4):

    SingleFileThread.threadLock.acquire()
    self._threads = SingleFileThread.startThreads(nThreads, datasetname,
                                                  labelsetname, batch_size)
    SingleFileThread.queueLock.acquire()
    for config in datapaths:
        SingleFileThread.queue.put(config)
    SingleFileThread.queueLock.release()

    self.datapaths = datapaths

  def __del__(self):
    SingleFileThread.threadLock.release()
    del self._threads

  @property
  def output(self):
    x,y = self.next()
    return x[0].shape

  @property
  def input(self):
    x,y = self.next()
    return y[0].shape[0]

  def __len__(self):
    """
      Iterates over files to create the total sum length
      of the datasets in each file.
    """
    return 0

  def next(self):
    #see if there's any pre-fetched data

    # If the filename queue is empty, fill it back up again.
    # This ensures that files are all used up before they
    # are iterated over again.
    SingleFileThread.queueLock.acquire()
    if SingleFileThread.queue.empty():
      for i in self.datapaths:
        SingleFileThread.queue.put(i)
    SingleFileThread.queueLock.release()

    for thread in SingleFileThread.activeThreads:
      thread.single_thread_lock.acquire()
      if thread._buffer is not None:
        new_buff = thread._buffer
        thread._buffer = None
        thread.single_thread_lock.release()
        return new_buff
      thread.single_thread_lock.release()
    self.logger.warning("Threaded buffer found queue is empty. Trying again...")
    return self.next()

<commit_msg>Bugfix<commit_after>from proton_decay_study.generators.base import BaseDataGenerator
from proton_decay_study.generators.single_file import SingleFileDataGenerator
import h5py
import logging
import threading
import subprocess
import Queue
import traceback
import signal
import sys

class SingleFileThread(threading.Thread):
  """
    Represents a single file that is asynchronously
  """

  # Locks class for the duration of parent lifetime
  # Currently, hierarchal threading is not supported
  threadLock = threading.Lock()

  # Set this to 0 to kill all threads once prefetch is finished.
  __ThreadExitFlag__ = 1

  # Holds the current thread queue
  queue = Queue.Queue(100000)

  # Locks the thread queue
  queueLock = threading.Lock()
  logger = logging.getLogger('pdk.gen.singlefilethread')

  activeThreads = []

  def __init__(self, datasetname,
               labelsetname, batch_size):
    """
        :param: datasetname The name used to pull the dataset from file
        :type: datasetname string
        :param: labelsetname The name used to pull the labelset from file
        :type: labelsetname string
        :param: batch_size The number of images and truths to pull from the file.
        :type: batch_size int
    """
    super(SingleFileThread, self).__init__()
    self.datasetname = datasetname
    self.labelsetname = labelsetname
    self.batch_size = batch_size

    # prefetched means that there's data ready
    self._buffer = None
    self.single_thread_lock = threading.Lock()

    # This holds the
    self._filegen = None

  @property
  def get(self):
    self.single_thread_lock.acquire()
    if self._buffer is None:
      pass

  def run(self):
    """
      Loops over queue to accept new configurations
    """
    while SingleFileThread.__ThreadExitFlag__:
      if self.single_thread_lock.locked():
        continue
      else:
        self.single_thread_lock.acquire()
        if self._buffer is not None:
          self.single_thread_lock.release()
          continue

      if self._filegen is None:
        self.queueLock.acquire()
        if not self.queue.empty():
          self._filegen = SingleFileDataGenerator(SingleFileThread.queue.get(),
                                              self.datasetname, self.labelsetname,
                                              self.batch_size)
        self.queueLock.release()
      else:
        try:
          try:
            self.single_thread_lock.acquire()
            self._buffer  = self._filegen.next()
            self.single_thread_lock.release()
          except StopIteration:
            self._buffer  = None
            self.single_thread_lock.release()
            self._filegen = None
        except Exception:
          exc_type, exc_value, exc_traceback = sys.exc_info()
          self.logger.error(repr(traceback.format_exception(exc_type, exc_value,
                                                exc_traceback)))

  @staticmethod
  def killRunThreads(signum, frame):
      """
          Sets the thread kill flag to each of the ongoing analysis threads
      """
      logging.info("Killing Single File threads...")
      SingleFileThread.__ThreadExitFlag__ = 0
      sys.exit(signum)

  @staticmethod
  def startThreads(nThreads, datasetname,
                            labelsetname, batch_size):
    logging.info("Starting {} Single File threads".format(nThreads))
    for i in range(nThreads):
        thread = SingleFileThread(datasetname,
                          labelsetname, batch_size)
        thread.start()
        SingleFileThread.activeThreads.append(thread)

  @staticmethod
  def waitTillComplete(callback=None):
      if callback is None:
          while not SingleFileThread.queue.empty() and SingleFileThread.__ThreadExitFlag__:
              sys.stdout.flush()
      else:
          while not SingleFileThread.queue.empty() and SingleFileThread.__ThreadExitFlag__:
              callback()

      # Notify threads it's time to exit
      SingleFileThread.__ThreadExitFlag__ = 0

      # Wait for all threads to complete
      for t in SingleFileThread.activeThreads:
          t.join()
      # dealloc
      SingleFileThread.activeThreads = []

signal.signal(signal.SIGINT, SingleFileThread.killRunThreads)

class ThreadedMultiFileDataGenerator(BaseDataGenerator):
  """
      Uses threads to pull asynchronously from files
  """
  logger = logging.getLogger("pdk.generator.threaded_multi")

  def __init__(self, datapaths, datasetname,
               labelsetname, batch_size=1, nThreads=4):

    SingleFileThread.threadLock.acquire()
    self._threads = SingleFileThread.startThreads(nThreads, datasetname,
                                                  labelsetname, batch_size)
    SingleFileThread.queueLock.acquire()
    for config in datapaths:
        SingleFileThread.queue.put(config)
    SingleFileThread.queueLock.release()

    self.datapaths = datapaths

  def __del__(self):
    SingleFileThread.threadLock.release()
    del self._threads

  @property
  def output(self):
    x,y = self.next()
    return x[0].shape

  @property
  def input(self):
    x,y = self.next()
    return y[0].shape[0]

  def __len__(self):
    """
      Iterates over files to create the total sum length
      of the datasets in each file.
    """
    return 0

  def next(self):
    #see if there's any pre-fetched data

    # If the filename queue is empty, fill it back up again.
    # This ensures that files are all used up before they
    # are iterated over again.
    SingleFileThread.queueLock.acquire()
    if SingleFileThread.queue.empty():
      for i in self.datapaths:
        SingleFileThread.queue.put(i)
    SingleFileThread.queueLock.release()

    for thread in SingleFileThread.activeThreads:
      thread.single_thread_lock.acquire()
      if thread._buffer is not None:
        new_buff = thread._buffer
        thread._buffer = None
        thread.single_thread_lock.release()
        return new_buff
      thread.single_thread_lock.release()
    self.logger.warning("Threaded buffer found queue is empty. Trying again...")
    return self.next()

<|endoftext|>


<commit_before>#     Copyright 2021. ThingsBoard
#
#     Licensed under the Apache License, Version 2.0 (the "License");
#     you may not use this file except in compliance with the License.
#     You may obtain a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#     Unless required by applicable law or agreed to in writing, software
#     distributed under the License is distributed on an "AS IS" BASIS,
#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#     See the License for the specific language governing permissions and
#     limitations under the License.

from simplejson import dumps

from thingsboard_gateway.connectors.request.request_converter import RequestConverter, log

class JsonRequestDownlinkConverter(RequestConverter):
    def __init__(self, config):
        self.__config = config

    def convert(self, config, data):
        try:
            if data["data"].get("id") is None:
                attribute_key = list(data["data"].keys())[0]
                attribute_value = list(data["data"].values())[0]

                result = {"url": self.__config["requestUrlExpression"].replace("${attributeKey}", attribute_key) \
                    .replace("${attributeValue}", attribute_value) \
                    .replace("${deviceName}", data["device"]),
                          "data": self.__config["valueExpression"].replace("${attributeKey}", attribute_key) \
                              .replace("${attributeValue}", attribute_value) \
                              .replace("${deviceName}", data["device"])}
            else:
                request_id = str(data["data"]["id"])
                method_name = data["data"]["method"]
                params = dumps(data["data"]["params"]) or str(data["data"]["params"])

                result = {"url": self.__config["requestUrlExpression"].replace("${requestId}", request_id) \
                    .replace("${methodName}", method_name) \
                    .replace("${params}", params) \
                    .replace("${deviceName}", data["device"]),
                          "data": self.__config["valueExpression"].replace("${requestId}", request_id) \
                              .replace("${methodName}", method_name) \
                              .replace("${params}", params) \
                              .replace("${deviceName}", data["device"])}
            return result
        except Exception as e:
            log.exception(e)
<commit_msg>Fixed RPC Handler for Request connector<commit_after>#     Copyright 2021. ThingsBoard
#
#     Licensed under the Apache License, Version 2.0 (the "License");
#     you may not use this file except in compliance with the License.
#     You may obtain a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#     Unless required by applicable law or agreed to in writing, software
#     distributed under the License is distributed on an "AS IS" BASIS,
#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#     See the License for the specific language governing permissions and
#     limitations under the License.

from urllib.parse import quote

from thingsboard_gateway.connectors.request.request_converter import RequestConverter, log
from thingsboard_gateway.tb_utility.tb_utility import TBUtility

class JsonRequestDownlinkConverter(RequestConverter):
    def __init__(self, config):
        self.__config = config

    def convert(self, config, data):
        try:
            if data["data"].get("id") is None:
                attribute_key = list(data["data"].keys())[0]
                attribute_value = list(data["data"].values())[0]

                result = {
                    "url": self.__config["requestUrlExpression"].replace("${attributeKey}", quote(attribute_key))
                                                                .replace("${attributeValue}", quote(attribute_value))
                                                                .replace("${deviceName}", quote(data["device"])),
                    "data": self.__config["valueExpression"].replace("${attributeKey}", quote(attribute_key))
                                                            .replace("${attributeValue}", quote(attribute_value))
                                                            .replace("${deviceName}", quote(data["device"]))
                }
            else:
                request_id = str(data["data"]["id"])
                method_name = data["data"]["method"]

                result = {
                    "url": self.__config["requestUrlExpression"].replace("${requestId}", request_id)
                                                                .replace("${methodName}", method_name)
                                                                .replace("${deviceName}", quote(data["device"])),
                    "data": self.__config["valueExpression"].replace("${requestId}", request_id)
                                                            .replace("${methodName}", method_name)
                                                            .replace("${deviceName}", quote(data["device"]))
                }

                result['url'] = TBUtility.replace_params_tags(result['url'], data)

                data_tag = '${' + TBUtility.get_value(config.get('valueExpression'), data['data'], 'params',
                                                      get_tag=True) + '}'
                data_value = TBUtility.get_value(config.get('valueExpression'), data['data'], 'params',
                                                 expression_instead_none=True)
                result['data'] = result["data"].replace(data_tag, str(data_value))
            print('>>>>!!', result)
            return result
        except Exception as e:
            log.exception(e)
<|endoftext|>


<commit_before>__author__ = 'katharine'

import PyV8 as v8

class LocalStorage(object):
    def __init__(self, runtime):
        self.storage = {}
        self.extension = v8.JSExtension(runtime.ext_name("localstorage"), """
        (function() {
            native function _internal();

            var proxy = _make_proxies({}, _internal(), ['set', 'has', 'delete_', 'keys', 'enumerate']);
            var methods = _make_proxies({}, _internal(), ['clear', 'getItem', 'setItem', 'removeItem', 'key']);
            proxy.get = function get(p, name) { return methods[name] || _internal().get(p, name); }

            this.localStorage = Proxy.create(proxy);
        })();
        """, lambda f: lambda: self, dependencies=["runtime/internal/proxy"])

    def get(self, p, name):
        return self.storage.get(name, v8.JSNull())

    def set(self, p, name, value):
        self.storage[str(name)] = str(value)
        #TODO: actually store this somewhere.
        return True

    def has(self, p, name):
        return name in self.storage

    def delete_(self, p, name):
        if name in self.storage:
            del self.storage[name]
            #TODO: actually store this somewhere.
            return True
        else:
            return False

    def keys(self, p):
        return v8.JSArray(self.storage.keys())

    def enumerate(self):
        return v8.JSArray(self.storage.keys())

    def clear(self, *args):
        self.storage.clear()

    def getItem(self, name, *args):
        return self.storage.get(name, v8.JSNull())

    def setItem(self, name, value, *args):
        self.set(None, name, value)

    def removeItem(self, name, *args):
        return self.delete_(None, name)

    def key(self, index, *args):
        if len(self.storage) > index:
            return self.storage.keys()[index]
        else:
            return v8.JSNull()
<commit_msg>Persist localstorage for the life of the emulator.<commit_after>__author__ = 'katharine'

import PyV8 as v8

_storage_cache = {}

class LocalStorage(object):
    def __init__(self, runtime):
        self.storage = _storage_cache.setdefault(runtime.manifest['uuid'], {})
        self.extension = v8.JSExtension(runtime.ext_name("localstorage"), """
        (function() {
            native function _internal();

            var proxy = _make_proxies({}, _internal(), ['set', 'has', 'delete_', 'keys', 'enumerate']);
            var methods = _make_proxies({}, _internal(), ['clear', 'getItem', 'setItem', 'removeItem', 'key']);
            proxy.get = function get(p, name) { return methods[name] || _internal().get(p, name); }

            this.localStorage = Proxy.create(proxy);
        })();
        """, lambda f: lambda: self, dependencies=["runtime/internal/proxy"])

    def get(self, p, name):
        return self.storage.get(name, v8.JSNull())

    def set(self, p, name, value):
        self.storage[str(name)] = str(value)
        #TODO: actually store this somewhere.
        return True

    def has(self, p, name):
        return name in self.storage

    def delete_(self, p, name):
        if name in self.storage:
            del self.storage[name]
            #TODO: actually store this somewhere.
            return True
        else:
            return False

    def keys(self, p):
        return v8.JSArray(self.storage.keys())

    def enumerate(self):
        return v8.JSArray(self.storage.keys())

    def clear(self, *args):
        self.storage.clear()

    def getItem(self, name, *args):
        return self.storage.get(name, v8.JSNull())

    def setItem(self, name, value, *args):
        self.set(None, name, value)

    def removeItem(self, name, *args):
        return self.delete_(None, name)

    def key(self, index, *args):
        if len(self.storage) > index:
            return self.storage.keys()[index]
        else:
            return v8.JSNull()
<|endoftext|>