├── robots └── __init__.py ├── controllers ├── __init__.py ├── hold.py ├── gotogoal.py ├── movingtopoint1.py ├── movingtopoint2.py ├── followpath.py ├── avoidobstacles.py ├── k3_avoidobstacles.py ├── blending.py ├── genetic_algorithm(not included).py ├── followwall.py └── pid_controller.py ├── supervisors └── __init__.py ├── worlds ├── dynamic_environment.xml ├── without_obstacle.xml ├── static_test.xml └── static_environment.xml ├── gui ├── pyqtgraph │ ├── opengl │ │ ├── items │ │ │ ├── __init__.py │ │ │ ├── GLBarGraphItem.py │ │ │ ├── GLGridItem.py │ │ │ ├── GLAxisItem.py │ │ │ ├── GLBoxItem.py │ │ │ ├── GLImageItem.py │ │ │ └── GLLinePlotItem.py │ │ ├── glInfo.py │ │ └── __init__.py │ ├── console │ │ ├── __init__.py │ │ └── CmdInput.py │ ├── metaarray │ │ ├── __init__.py │ │ ├── license.txt │ │ └── readMeta.m │ ├── GraphicsScene │ │ ├── __init__.py │ │ ├── exportDialogTemplate.ui │ │ └── exportDialogTemplate_pyqt.py │ ├── graphicsItems │ │ ├── PlotItem │ │ │ └── __init__.py │ │ ├── ViewBox │ │ │ └── __init__.py │ │ ├── ItemGroup.py │ │ ├── __init__.py │ │ ├── FillBetweenItem.py │ │ ├── GraphicsObject.py │ │ ├── ButtonItem.py │ │ ├── MultiPlotItem.py │ │ ├── GraphicsWidget.py │ │ ├── tests │ │ │ └── ViewBox.py │ │ ├── ScaleBar.py │ │ ├── UIGraphicsItem.py │ │ └── VTickGroup.py │ ├── dockarea │ │ └── __init__.py │ ├── canvas │ │ ├── __init__.py │ │ ├── TransformGuiTemplate.ui │ │ ├── CanvasManager.py │ │ └── TransformGuiTemplate_pyqt.py │ ├── flowchart │ │ ├── __init__.py │ │ ├── eq.py │ │ ├── library │ │ │ ├── Operators.py │ │ │ └── __init__.py │ │ ├── FlowchartTemplate.ui │ │ ├── FlowchartTemplate_pyqt.py │ │ ├── FlowchartCtrlTemplate_pyqt.py │ │ └── FlowchartCtrlTemplate.ui │ ├── imageview │ │ └── __init__.py │ ├── parametertree │ │ └── __init__.py │ ├── PIL_Fix │ │ └── README │ ├── widgets │ │ ├── FileDialog.py │ │ ├── __init__.py │ │ ├── GraphicsLayoutWidget.py │ │ ├── BusyCursor.py │ │ ├── HistogramLUTWidget.py │ │ ├── MatplotlibWidget.py │ │ ├── ComboBox.py │ │ ├── MultiPlotWidget.py │ │ ├── PathButton.py │ │ ├── JoystickButton.py │ │ ├── ValueLabel.py │ │ ├── DataTreeWidget.py │ │ ├── GradientWidget.py │ │ ├── CheckTable.py │ │ ├── VerticalLabel.py │ │ ├── LayoutWidget.py │ │ ├── ColorButton.py │ │ └── PlotWidget.py │ ├── pixmaps │ │ ├── compile.py │ │ └── __init__.py │ ├── exporters │ │ ├── __init__.py │ │ ├── CSVExporter.py │ │ ├── PrintExporter.py │ │ └── Matplotlib.py │ ├── numpy_fix.py │ ├── multiprocess │ │ ├── __init__.py │ │ └── bootstrap.py │ ├── ptime.py │ ├── Qt.py │ ├── Transform3D.py │ ├── units.py │ ├── ThreadsafeTimer.py │ ├── PlotData.py │ ├── python2_3.py │ ├── frozenSupport.py │ ├── Vector.py │ ├── graphicsWindows.py │ └── exceptionHandling.py ├── qt_logdock.py ├── qt_plotwindow.py └── qt_plotwindow_qtgraph.py ├── res └── image │ ├── grid.png │ ├── open.png │ ├── appicon.png │ ├── coursera.png │ ├── screenshot.png │ ├── zoom-robot.png │ ├── zoom-scene.png │ ├── appicon_8x8.png │ ├── arrow-right.png │ ├── robot-tracks.png │ ├── appicon_16x16.ico │ ├── appicon_32x32.ico │ ├── robot-sensors.png │ ├── zoom-robot-rot.png │ ├── arrow-left-double.png │ ├── robot-supervisors.png │ ├── media-skip-forward-7.png │ ├── media-playback-pause-7.png │ └── media-playback-stop-8.png ├── qtsimiam.py ├── .gitignore ├── LICENSE ├── README.md └── scripts ├── collision_detect.py ├── xmlobject.py ├── controller.py ├── robot.py └── xmlwriter.py /robots/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /controllers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /supervisors/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /worlds/dynamic_environment.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gui/pyqtgraph/opengl/items/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gui/pyqtgraph/console/__init__.py: -------------------------------------------------------------------------------- 1 | from .Console import ConsoleWidget -------------------------------------------------------------------------------- /gui/pyqtgraph/metaarray/__init__.py: -------------------------------------------------------------------------------- 1 | from .MetaArray import * 2 | -------------------------------------------------------------------------------- /gui/pyqtgraph/GraphicsScene/__init__.py: -------------------------------------------------------------------------------- 1 | from .GraphicsScene import * 2 | -------------------------------------------------------------------------------- /gui/pyqtgraph/graphicsItems/PlotItem/__init__.py: -------------------------------------------------------------------------------- 1 | from .PlotItem import PlotItem 2 | -------------------------------------------------------------------------------- /gui/pyqtgraph/graphicsItems/ViewBox/__init__.py: -------------------------------------------------------------------------------- 1 | from .ViewBox import ViewBox 2 | -------------------------------------------------------------------------------- /gui/pyqtgraph/dockarea/__init__.py: -------------------------------------------------------------------------------- 1 | from .DockArea import DockArea 2 | from .Dock import Dock -------------------------------------------------------------------------------- /res/image/grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y4h2/robot_path_planning/HEAD/res/image/grid.png -------------------------------------------------------------------------------- /res/image/open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y4h2/robot_path_planning/HEAD/res/image/open.png -------------------------------------------------------------------------------- /res/image/appicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y4h2/robot_path_planning/HEAD/res/image/appicon.png -------------------------------------------------------------------------------- /res/image/coursera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y4h2/robot_path_planning/HEAD/res/image/coursera.png -------------------------------------------------------------------------------- /res/image/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y4h2/robot_path_planning/HEAD/res/image/screenshot.png -------------------------------------------------------------------------------- /res/image/zoom-robot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y4h2/robot_path_planning/HEAD/res/image/zoom-robot.png -------------------------------------------------------------------------------- /res/image/zoom-scene.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y4h2/robot_path_planning/HEAD/res/image/zoom-scene.png -------------------------------------------------------------------------------- /gui/pyqtgraph/canvas/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from .Canvas import * 3 | from .CanvasItem import * -------------------------------------------------------------------------------- /res/image/appicon_8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y4h2/robot_path_planning/HEAD/res/image/appicon_8x8.png -------------------------------------------------------------------------------- /res/image/arrow-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y4h2/robot_path_planning/HEAD/res/image/arrow-right.png -------------------------------------------------------------------------------- /res/image/robot-tracks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y4h2/robot_path_planning/HEAD/res/image/robot-tracks.png -------------------------------------------------------------------------------- /res/image/appicon_16x16.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y4h2/robot_path_planning/HEAD/res/image/appicon_16x16.ico -------------------------------------------------------------------------------- /res/image/appicon_32x32.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y4h2/robot_path_planning/HEAD/res/image/appicon_32x32.ico -------------------------------------------------------------------------------- /res/image/robot-sensors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y4h2/robot_path_planning/HEAD/res/image/robot-sensors.png -------------------------------------------------------------------------------- /res/image/zoom-robot-rot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y4h2/robot_path_planning/HEAD/res/image/zoom-robot-rot.png -------------------------------------------------------------------------------- /res/image/arrow-left-double.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y4h2/robot_path_planning/HEAD/res/image/arrow-left-double.png -------------------------------------------------------------------------------- /res/image/robot-supervisors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y4h2/robot_path_planning/HEAD/res/image/robot-supervisors.png -------------------------------------------------------------------------------- /res/image/media-skip-forward-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y4h2/robot_path_planning/HEAD/res/image/media-skip-forward-7.png -------------------------------------------------------------------------------- /res/image/media-playback-pause-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y4h2/robot_path_planning/HEAD/res/image/media-playback-pause-7.png -------------------------------------------------------------------------------- /res/image/media-playback-stop-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/y4h2/robot_path_planning/HEAD/res/image/media-playback-stop-8.png -------------------------------------------------------------------------------- /gui/pyqtgraph/flowchart/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from .Flowchart import * 3 | 4 | from .library import getNodeType, registerNodeType, getNodeTree -------------------------------------------------------------------------------- /gui/pyqtgraph/imageview/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Widget used for display and analysis of 2D and 3D image data. 3 | Includes ROI plotting over time and image normalization. 4 | """ 5 | 6 | from .ImageView import ImageView 7 | -------------------------------------------------------------------------------- /gui/pyqtgraph/parametertree/__init__.py: -------------------------------------------------------------------------------- 1 | from .Parameter import Parameter, registerParameterType 2 | from .ParameterTree import ParameterTree 3 | from .ParameterItem import ParameterItem 4 | 5 | from . import parameterTypes as types -------------------------------------------------------------------------------- /gui/pyqtgraph/PIL_Fix/README: -------------------------------------------------------------------------------- 1 | The file Image.py is a drop-in replacement for the same file in PIL 1.1.6. 2 | It adds support for reading 16-bit TIFF files and converting then to numpy arrays. 3 | (I submitted the changes to the PIL folks long ago, but to my knowledge the code 4 | is not being used by them.) 5 | 6 | To use, copy this file into 7 | /usr/lib/python2.6/dist-packages/PIL/ 8 | or 9 | C:\Python26\lib\site-packages\PIL\ 10 | 11 | ..or wherever your system keeps its python modules. 12 | -------------------------------------------------------------------------------- /gui/pyqtgraph/widgets/FileDialog.py: -------------------------------------------------------------------------------- 1 | from pyqtgraph.Qt import QtGui, QtCore 2 | import sys 3 | 4 | __all__ = ['FileDialog'] 5 | 6 | class FileDialog(QtGui.QFileDialog): 7 | ## Compatibility fix for OSX: 8 | ## For some reason the native dialog doesn't show up when you set AcceptMode to AcceptSave on OS X, so we don't use the native dialog 9 | 10 | def __init__(self, *args): 11 | QtGui.QFileDialog.__init__(self, *args) 12 | 13 | if sys.platform == 'darwin': 14 | self.setOption(QtGui.QFileDialog.DontUseNativeDialog) -------------------------------------------------------------------------------- /gui/pyqtgraph/opengl/glInfo.py: -------------------------------------------------------------------------------- 1 | from pyqtgraph.Qt import QtCore, QtGui, QtOpenGL 2 | from OpenGL.GL import * 3 | app = QtGui.QApplication([]) 4 | 5 | class GLTest(QtOpenGL.QGLWidget): 6 | def __init__(self): 7 | QtOpenGL.QGLWidget.__init__(self) 8 | self.makeCurrent() 9 | print("GL version:" + glGetString(GL_VERSION)) 10 | print("MAX_TEXTURE_SIZE: %d" % glGetIntegerv(GL_MAX_TEXTURE_SIZE)) 11 | print("MAX_3D_TEXTURE_SIZE: %d" % glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE)) 12 | print("Extensions: " + glGetString(GL_EXTENSIONS)) 13 | 14 | GLTest() 15 | 16 | 17 | -------------------------------------------------------------------------------- /gui/pyqtgraph/graphicsItems/ItemGroup.py: -------------------------------------------------------------------------------- 1 | from pyqtgraph.Qt import QtGui, QtCore 2 | from .GraphicsObject import GraphicsObject 3 | 4 | __all__ = ['ItemGroup'] 5 | class ItemGroup(GraphicsObject): 6 | """ 7 | Replacement for QGraphicsItemGroup 8 | """ 9 | 10 | def __init__(self, *args): 11 | GraphicsObject.__init__(self, *args) 12 | if hasattr(self, "ItemHasNoContents"): 13 | self.setFlag(self.ItemHasNoContents) 14 | 15 | def boundingRect(self): 16 | return QtCore.QRectF() 17 | 18 | def paint(self, *args): 19 | pass 20 | 21 | def addItem(self, item): 22 | item.setParentItem(self) 23 | 24 | -------------------------------------------------------------------------------- /gui/pyqtgraph/pixmaps/compile.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from PyQt4 import QtGui 3 | import os, pickle, sys 4 | 5 | path = os.path.abspath(os.path.split(__file__)[0]) 6 | pixmaps = {} 7 | for f in os.listdir(path): 8 | if not f.endswith('.png'): 9 | continue 10 | print(f) 11 | img = QtGui.QImage(os.path.join(path, f)) 12 | ptr = img.bits() 13 | ptr.setsize(img.byteCount()) 14 | arr = np.asarray(ptr).reshape(img.height(), img.width(), 4).transpose(1,0,2) 15 | pixmaps[f] = pickle.dumps(arr) 16 | ver = sys.version_info[0] 17 | fh = open(os.path.join(path, 'pixmapData_%d.py' %ver), 'w') 18 | fh.write("import numpy as np; pixmapData=%s" % repr(pixmaps)) 19 | 20 | -------------------------------------------------------------------------------- /gui/pyqtgraph/widgets/__init__.py: -------------------------------------------------------------------------------- 1 | ## just import everything from sub-modules 2 | 3 | #import os 4 | 5 | #d = os.path.split(__file__)[0] 6 | #files = [] 7 | #for f in os.listdir(d): 8 | #if os.path.isdir(os.path.join(d, f)): 9 | #files.append(f) 10 | #elif f[-3:] == '.py' and f != '__init__.py': 11 | #files.append(f[:-3]) 12 | 13 | #for modName in files: 14 | #mod = __import__(modName, globals(), locals(), fromlist=['*']) 15 | #if hasattr(mod, '__all__'): 16 | #names = mod.__all__ 17 | #else: 18 | #names = [n for n in dir(mod) if n[0] != '_'] 19 | #for k in names: 20 | #print modName, k 21 | #globals()[k] = getattr(mod, k) 22 | -------------------------------------------------------------------------------- /gui/pyqtgraph/widgets/GraphicsLayoutWidget.py: -------------------------------------------------------------------------------- 1 | from pyqtgraph.Qt import QtGui 2 | from pyqtgraph.graphicsItems.GraphicsLayout import GraphicsLayout 3 | from .GraphicsView import GraphicsView 4 | 5 | __all__ = ['GraphicsLayoutWidget'] 6 | class GraphicsLayoutWidget(GraphicsView): 7 | def __init__(self, parent=None, **kargs): 8 | GraphicsView.__init__(self, parent) 9 | self.ci = GraphicsLayout(**kargs) 10 | for n in ['nextRow', 'nextCol', 'nextColumn', 'addPlot', 'addViewBox', 'addItem', 'getItem', 'addLabel', 'addLayout', 'addLabel', 'addViewBox', 'removeItem', 'itemIndex', 'clear']: 11 | setattr(self, n, getattr(self.ci, n)) 12 | self.setCentralItem(self.ci) 13 | -------------------------------------------------------------------------------- /controllers/hold.py: -------------------------------------------------------------------------------- 1 | # 2 | # (c) PySimiam Team 2013 3 | # 4 | # Contact person: Tim Fuchs 5 | # 6 | # This class was implemented as a weekly programming excercise 7 | # of the 'Control of Mobile Robots' course by Magnus Egerstedt. 8 | # 9 | from controller import Controller 10 | import math 11 | import numpy 12 | 13 | class Hold(Controller): 14 | """This controller halts the robot""" 15 | def __init__(self, params): 16 | Controller.__init__(self,params) 17 | 18 | def set_parameters(self,params): 19 | """This controller has no parameters""" 20 | pass 21 | 22 | def execute(self,state,dt): 23 | """Stop the robot""" 24 | return [0.,0.] 25 | -------------------------------------------------------------------------------- /gui/pyqtgraph/graphicsItems/__init__.py: -------------------------------------------------------------------------------- 1 | ### just import everything from sub-modules 2 | 3 | #import os 4 | 5 | #d = os.path.split(__file__)[0] 6 | #files = [] 7 | #for f in os.listdir(d): 8 | #if os.path.isdir(os.path.join(d, f)): 9 | #files.append(f) 10 | #elif f[-3:] == '.py' and f != '__init__.py': 11 | #files.append(f[:-3]) 12 | 13 | #for modName in files: 14 | #mod = __import__(modName, globals(), locals(), fromlist=['*']) 15 | #if hasattr(mod, '__all__'): 16 | #names = mod.__all__ 17 | #else: 18 | #names = [n for n in dir(mod) if n[0] != '_'] 19 | #for k in names: 20 | ##print modName, k 21 | #globals()[k] = getattr(mod, k) 22 | -------------------------------------------------------------------------------- /gui/pyqtgraph/widgets/BusyCursor.py: -------------------------------------------------------------------------------- 1 | from pyqtgraph.Qt import QtGui, QtCore 2 | 3 | __all__ = ['BusyCursor'] 4 | 5 | class BusyCursor(object): 6 | """Class for displaying a busy mouse cursor during long operations. 7 | Usage:: 8 | 9 | with pyqtgraph.BusyCursor(): 10 | doLongOperation() 11 | 12 | May be nested. 13 | """ 14 | active = [] 15 | 16 | def __enter__(self): 17 | QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor)) 18 | BusyCursor.active.append(self) 19 | 20 | def __exit__(self, *args): 21 | BusyCursor.active.pop(-1) 22 | if len(BusyCursor.active) == 0: 23 | QtGui.QApplication.restoreOverrideCursor() 24 | -------------------------------------------------------------------------------- /qtsimiam.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # QtSimiam for Coursera Week 7 3 | # Author: Tim Fuchs 4 | # Description: This is the top-level application for QtSimiam. 5 | from __future__ import print_function 6 | import sys 7 | sys.path.insert(0, './scripts') 8 | sys.path.insert(0, './gui') 9 | from PyQt4 import QtGui 10 | 11 | from qt_mainwindow import SimulationWidget 12 | #from coursera import Week7 13 | 14 | 15 | if __name__ == "__main__": 16 | 17 | app = QtGui.QApplication(sys.argv) 18 | simWidget = SimulationWidget() 19 | simWidget.superv_action.trigger() 20 | simWidget.show() 21 | #simWidget.setTestSuite(Week7) 22 | simWidget.load_world("without_obstacle.xml") 23 | 24 | app.exec_() 25 | -------------------------------------------------------------------------------- /gui/pyqtgraph/pixmaps/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Allows easy loading of pixmaps used in UI elements. 3 | Provides support for frozen environments as well. 4 | """ 5 | 6 | import os, sys, pickle 7 | from ..functions import makeQImage 8 | from ..Qt import QtGui 9 | if sys.version_info[0] == 2: 10 | from . import pixmapData_2 as pixmapData 11 | else: 12 | from . import pixmapData_3 as pixmapData 13 | 14 | 15 | def getPixmap(name): 16 | """ 17 | Return a QPixmap corresponding to the image file with the given name. 18 | (eg. getPixmap('auto') loads pyqtgraph/pixmaps/auto.png) 19 | """ 20 | key = name+'.png' 21 | data = pixmapData.pixmapData[key] 22 | if isinstance(data, basestring) or isinstance(data, bytes): 23 | pixmapData.pixmapData[key] = pickle.loads(data) 24 | arr = pixmapData.pixmapData[key] 25 | return QtGui.QPixmap(makeQImage(arr, alpha=True)) 26 | 27 | -------------------------------------------------------------------------------- /gui/pyqtgraph/graphicsItems/FillBetweenItem.py: -------------------------------------------------------------------------------- 1 | import pyqtgraph as pg 2 | 3 | class FillBetweenItem(pg.QtGui.QGraphicsPathItem): 4 | """ 5 | GraphicsItem filling the space between two PlotDataItems. 6 | """ 7 | def __init__(self, p1, p2, brush=None): 8 | pg.QtGui.QGraphicsPathItem.__init__(self) 9 | self.p1 = p1 10 | self.p2 = p2 11 | p1.sigPlotChanged.connect(self.updatePath) 12 | p2.sigPlotChanged.connect(self.updatePath) 13 | if brush is not None: 14 | self.setBrush(pg.mkBrush(brush)) 15 | self.setZValue(min(p1.zValue(), p2.zValue())-1) 16 | self.updatePath() 17 | 18 | def updatePath(self): 19 | p1 = self.p1.curve.path 20 | p2 = self.p2.curve.path 21 | path = pg.QtGui.QPainterPath() 22 | path.addPolygon(p1.toSubpathPolygons()[0] + p2.toReversed().toSubpathPolygons()[0]) 23 | self.setPath(path) 24 | -------------------------------------------------------------------------------- /gui/pyqtgraph/exporters/__init__.py: -------------------------------------------------------------------------------- 1 | Exporters = [] 2 | from pyqtgraph import importModules 3 | #from .. import frozenSupport 4 | import os 5 | d = os.path.split(__file__)[0] 6 | #files = [] 7 | #for f in frozenSupport.listdir(d): 8 | #if frozenSupport.isdir(os.path.join(d, f)) and f != '__pycache__': 9 | #files.append(f) 10 | #elif f[-3:] == '.py' and f not in ['__init__.py', 'Exporter.py']: 11 | #files.append(f[:-3]) 12 | 13 | #for modName in files: 14 | #mod = __import__(modName, globals(), locals(), fromlist=['*']) 15 | for mod in importModules('', globals(), locals(), excludes=['Exporter']).values(): 16 | if hasattr(mod, '__all__'): 17 | names = mod.__all__ 18 | else: 19 | names = [n for n in dir(mod) if n[0] != '_'] 20 | for k in names: 21 | if hasattr(mod, k): 22 | Exporters.append(getattr(mod, k)) 23 | 24 | 25 | def listExporters(): 26 | return Exporters[:] 27 | 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | -------------------------------------------------------------------------------- /gui/pyqtgraph/numpy_fix.py: -------------------------------------------------------------------------------- 1 | try: 2 | import numpy as np 3 | 4 | ## Wrap np.concatenate to catch and avoid a segmentation fault bug 5 | ## (numpy trac issue #2084) 6 | if not hasattr(np, 'concatenate_orig'): 7 | np.concatenate_orig = np.concatenate 8 | def concatenate(vals, *args, **kwds): 9 | """Wrapper around numpy.concatenate (see pyqtgraph/numpy_fix.py)""" 10 | dtypes = [getattr(v, 'dtype', None) for v in vals] 11 | names = [getattr(dt, 'names', None) for dt in dtypes] 12 | if len(dtypes) < 2 or all([n is None for n in names]): 13 | return np.concatenate_orig(vals, *args, **kwds) 14 | if any([dt != dtypes[0] for dt in dtypes[1:]]): 15 | raise TypeError("Cannot concatenate structured arrays of different dtype.") 16 | return np.concatenate_orig(vals, *args, **kwds) 17 | 18 | np.concatenate = concatenate 19 | 20 | except ImportError: 21 | pass 22 | 23 | -------------------------------------------------------------------------------- /worlds/without_obstacle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /gui/pyqtgraph/multiprocess/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Multiprocessing utility library 3 | (parallelization done the way I like it) 4 | 5 | Luke Campagnola 6 | 2012.06.10 7 | 8 | This library provides: 9 | 10 | - simple mechanism for starting a new python interpreter process that can be controlled from the original process 11 | (this allows, for example, displaying and manipulating plots in a remote process 12 | while the parent process is free to do other work) 13 | - proxy system that allows objects hosted in the remote process to be used as if they were local 14 | - Qt signal connection between processes 15 | - very simple in-line parallelization (fork only; does not work on windows) for number-crunching 16 | 17 | TODO: 18 | allow remote processes to serve as rendering engines that pass pixmaps back to the parent process for display 19 | (RemoteGraphicsView class) 20 | """ 21 | 22 | from .processes import * 23 | from .parallelizer import Parallelize, CanceledError 24 | from .remoteproxy import proxy -------------------------------------------------------------------------------- /gui/pyqtgraph/ptime.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | ptime.py - Precision time function made os-independent (should have been taken care of by python) 4 | Copyright 2010 Luke Campagnola 5 | Distributed under MIT/X11 license. See license.txt for more infomation. 6 | """ 7 | 8 | 9 | import sys 10 | import time as systime 11 | START_TIME = None 12 | time = None 13 | 14 | def winTime(): 15 | """Return the current time in seconds with high precision (windows version, use Manager.time() to stay platform independent).""" 16 | return systime.clock() + START_TIME 17 | #return systime.time() 18 | 19 | def unixTime(): 20 | """Return the current time in seconds with high precision (unix version, use Manager.time() to stay platform independent).""" 21 | return systime.time() 22 | 23 | if sys.platform.startswith('win'): 24 | cstart = systime.clock() ### Required to start the clock in windows 25 | START_TIME = systime.time() - cstart 26 | 27 | time = winTime 28 | else: 29 | time = unixTime 30 | 31 | -------------------------------------------------------------------------------- /gui/pyqtgraph/opengl/__init__.py: -------------------------------------------------------------------------------- 1 | from .GLViewWidget import GLViewWidget 2 | 3 | from pyqtgraph import importAll 4 | #import os 5 | #def importAll(path): 6 | #d = os.path.join(os.path.split(__file__)[0], path) 7 | #files = [] 8 | #for f in os.listdir(d): 9 | #if os.path.isdir(os.path.join(d, f)) and f != '__pycache__': 10 | #files.append(f) 11 | #elif f[-3:] == '.py' and f != '__init__.py': 12 | #files.append(f[:-3]) 13 | 14 | #for modName in files: 15 | #mod = __import__(path+"."+modName, globals(), locals(), fromlist=['*']) 16 | #if hasattr(mod, '__all__'): 17 | #names = mod.__all__ 18 | #else: 19 | #names = [n for n in dir(mod) if n[0] != '_'] 20 | #for k in names: 21 | #if hasattr(mod, k): 22 | #globals()[k] = getattr(mod, k) 23 | 24 | importAll('items', globals(), locals()) 25 | \ 26 | from .MeshData import MeshData 27 | ## for backward compatibility: 28 | #MeshData.MeshData = MeshData ## breaks autodoc. 29 | 30 | from . import shaders 31 | -------------------------------------------------------------------------------- /worlds/static_test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /gui/pyqtgraph/widgets/HistogramLUTWidget.py: -------------------------------------------------------------------------------- 1 | """ 2 | Widget displaying an image histogram along with gradient editor. Can be used to adjust the appearance of images. 3 | This is a wrapper around HistogramLUTItem 4 | """ 5 | 6 | from pyqtgraph.Qt import QtGui, QtCore 7 | from .GraphicsView import GraphicsView 8 | from pyqtgraph.graphicsItems.HistogramLUTItem import HistogramLUTItem 9 | 10 | __all__ = ['HistogramLUTWidget'] 11 | 12 | 13 | class HistogramLUTWidget(GraphicsView): 14 | 15 | def __init__(self, parent=None, *args, **kargs): 16 | background = kargs.get('background', 'default') 17 | GraphicsView.__init__(self, parent, useOpenGL=False, background=background) 18 | self.item = HistogramLUTItem(*args, **kargs) 19 | self.setCentralItem(self.item) 20 | self.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding) 21 | self.setMinimumWidth(95) 22 | 23 | 24 | def sizeHint(self): 25 | return QtCore.QSize(115, 200) 26 | 27 | 28 | 29 | def __getattr__(self, attr): 30 | return getattr(self.item, attr) 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /gui/pyqtgraph/metaarray/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 Luke Campagnola ('luke.campagnola@%s.com' % 'gmail') 2 | The MIT License 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 yu huang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NOTICE 2 | This project forks from pysimiam project and remove some unneccessary file
3 | PySimiam documents http://pysimiam.sourceforge.net/index.html 4 | 5 | # robot_path_planning 6 | Path planning of dynamic environment with genetic algorithm and Finite State Machine 7 | 8 | 9 | # Running Project 10 | ## Prerequest Library 11 | - Numpy 12 | - PyQt 13 | Recommend installing Anaconda Package which include all common library 14 | 15 | ## Running 16 | cd into robot_path_planning root folder, run command ```python qtpysimim.py``` 17 | 18 | # My Works 19 | ## three supervisors 20 | - /supervisors/ga.py (state machine for Quickbot) 21 | - /supervisors/ga_k3.py (state machine for khepera3) 22 | - /supervisors/movingobstacle.py (state machine for moving obstacle) 23 | 24 | ## Three controllers 25 | - /controllers/followpath.py (used in ga.py and ga_k3.py) 26 | - /controllers/movingtopoint1.py (used in movingobstacle.py) 27 | - /controllers/movingtopoint2.py (used in movingobstacle.py) 28 | 29 | ## Genetic algorithm with optimal operation 30 | - /scripts/genetic_algorithm.py 31 | 32 | ## Collision detect algorithm 33 | - /scripts/collision_detect.py 34 | -------------------------------------------------------------------------------- /gui/pyqtgraph/opengl/items/GLBarGraphItem.py: -------------------------------------------------------------------------------- 1 | from .GLMeshItem import GLMeshItem 2 | from ..MeshData import MeshData 3 | import numpy as np 4 | 5 | class GLBarGraphItem(GLMeshItem): 6 | def __init__(self, pos, size): 7 | """ 8 | pos is (...,3) array of the bar positions (the corner of each bar) 9 | size is (...,3) array of the sizes of each bar 10 | """ 11 | nCubes = reduce(lambda a,b: a*b, pos.shape[:-1]) 12 | cubeVerts = np.mgrid[0:2,0:2,0:2].reshape(3,8).transpose().reshape(1,8,3) 13 | cubeFaces = np.array([ 14 | [0,1,2], [3,2,1], 15 | [4,5,6], [7,6,5], 16 | [0,1,4], [5,4,1], 17 | [2,3,6], [7,6,3], 18 | [0,2,4], [6,4,2], 19 | [1,3,5], [7,5,3]]).reshape(1,12,3) 20 | size = size.reshape((nCubes, 1, 3)) 21 | pos = pos.reshape((nCubes, 1, 3)) 22 | verts = cubeVerts * size + pos 23 | faces = cubeFaces + (np.arange(nCubes) * 8).reshape(nCubes,1,1) 24 | md = MeshData(verts.reshape(nCubes*8,3), faces.reshape(nCubes*12,3)) 25 | 26 | GLMeshItem.__init__(self, meshdata=md, shader='shaded', smooth=False) 27 | 28 | 29 | -------------------------------------------------------------------------------- /controllers/gotogoal.py: -------------------------------------------------------------------------------- 1 | # 2 | # (c) PySimiam Team 2013 3 | # 4 | # Contact person: Tim Fuchs 5 | # 6 | # This class was implemented as a weekly programming excercise 7 | # of the 'Control of Mobile Robots' course by Magnus Egerstedt. 8 | # 9 | from pid_controller import PIDController 10 | import math 11 | import numpy 12 | 13 | class GoToGoal(PIDController): 14 | """Go-to-goal steers the robot to a predefined position in the world.""" 15 | def __init__(self, params): 16 | """Initialize internal variables""" 17 | PIDController.__init__(self,params) 18 | 19 | # Let's overwrite this way: 20 | def get_heading_angle(self, state): 21 | """Get the direction from the robot to the goal as a vector.""" 22 | 23 | # The goal: 24 | x_g, y_g = 0.0, 0.0 25 | 26 | # The robot: 27 | x_r, y_r, theta = state.pose 28 | 29 | # Where is the goal in the robot's frame of reference? 30 | return math.atan2(y_g - y_r, x_g - x_r) - theta 31 | 32 | def get_heading(self,state): 33 | 34 | goal_angle = self.get_heading_angle(state) 35 | return numpy.array([math.cos(goal_angle),math.sin(goal_angle),1]) -------------------------------------------------------------------------------- /gui/pyqtgraph/Qt.py: -------------------------------------------------------------------------------- 1 | ## Do all Qt imports from here to allow easier PyQt / PySide compatibility 2 | import sys, re 3 | 4 | ## Automatically determine whether to use PyQt or PySide. 5 | ## This is done by first checking to see whether one of the libraries 6 | ## is already imported. If not, then attempt to import PyQt4, then PySide. 7 | if 'PyQt4' not in sys.modules: 8 | try: 9 | import PyQt4 10 | except ImportError: 11 | raise Exception("PyQtGraph couldn't import PyQt4.") 12 | 13 | from PyQt4 import QtGui, QtCore 14 | try: 15 | from PyQt4 import QtSvg 16 | except ImportError: 17 | pass 18 | try: 19 | from PyQt4 import QtOpenGL 20 | except ImportError: 21 | pass 22 | 23 | QtCore.Signal = QtCore.pyqtSignal 24 | VERSION_INFO = 'PyQt4 ' + QtCore.PYQT_VERSION_STR + ' Qt ' + QtCore.QT_VERSION_STR 25 | 26 | 27 | ## Make sure we have Qt >= 4.7 28 | versionReq = [4, 7] 29 | QtVersion = QtCore.QT_VERSION_STR 30 | m = re.match(r'(\d+)\.(\d+).*', QtVersion) 31 | if m is not None and list(map(int, m.groups())) < versionReq: 32 | print(map(int, m.groups())) 33 | raise Exception('pyqtgraph requires Qt version >= %d.%d (your version is %s)' % (versionReq[0], versionReq[1], QtVersion)) 34 | 35 | -------------------------------------------------------------------------------- /gui/pyqtgraph/Transform3D.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from .Qt import QtCore, QtGui 3 | import pyqtgraph as pg 4 | import numpy as np 5 | 6 | class Transform3D(QtGui.QMatrix4x4): 7 | """ 8 | Extension of QMatrix4x4 with some helpful methods added. 9 | """ 10 | def __init__(self, *args): 11 | QtGui.QMatrix4x4.__init__(self, *args) 12 | 13 | def matrix(self, nd=3): 14 | if nd == 3: 15 | return np.array(self.copyDataTo()).reshape(4,4) 16 | elif nd == 2: 17 | m = np.array(self.copyDataTo()).reshape(4,4) 18 | m[2] = m[3] 19 | m[:,2] = m[:,3] 20 | return m[:3,:3] 21 | else: 22 | raise Exception("Argument 'nd' must be 2 or 3") 23 | 24 | def map(self, obj): 25 | """ 26 | Extends QMatrix4x4.map() to allow mapping (3, ...) arrays of coordinates 27 | """ 28 | if isinstance(obj, np.ndarray) and obj.ndim >= 2 and obj.shape[0] in (2,3): 29 | return pg.transformCoordinates(self, obj) 30 | else: 31 | return QtGui.QMatrix4x4.map(self, obj) 32 | 33 | def inverted(self): 34 | inv, b = QtGui.QMatrix4x4.inverted(self) 35 | return Transform3D(inv), b -------------------------------------------------------------------------------- /gui/pyqtgraph/flowchart/eq.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from numpy import ndarray, bool_ 3 | from pyqtgraph.metaarray import MetaArray 4 | 5 | def eq(a, b): 6 | """The great missing equivalence function: Guaranteed evaluation to a single bool value.""" 7 | if a is b: 8 | return True 9 | 10 | try: 11 | e = a==b 12 | except ValueError: 13 | return False 14 | except AttributeError: 15 | return False 16 | except: 17 | print("a:", str(type(a)), str(a)) 18 | print("b:", str(type(b)), str(b)) 19 | raise 20 | t = type(e) 21 | if t is bool: 22 | return e 23 | elif t is bool_: 24 | return bool(e) 25 | elif isinstance(e, ndarray) or (hasattr(e, 'implements') and e.implements('MetaArray')): 26 | try: ## disaster: if a is an empty array and b is not, then e.all() is True 27 | if a.shape != b.shape: 28 | return False 29 | except: 30 | return False 31 | if (hasattr(e, 'implements') and e.implements('MetaArray')): 32 | return e.asarray().all() 33 | else: 34 | return e.all() 35 | else: 36 | raise Exception("== operator returned type %s" % str(type(e))) 37 | -------------------------------------------------------------------------------- /gui/pyqtgraph/multiprocess/bootstrap.py: -------------------------------------------------------------------------------- 1 | """For starting up remote processes""" 2 | import sys, pickle, os 3 | 4 | if __name__ == '__main__': 5 | if hasattr(os, 'setpgrp'): 6 | os.setpgrp() ## prevents signals (notably keyboard interrupt) being forwarded from parent to this process 7 | if sys.version[0] == '3': 8 | #name, port, authkey, ppid, targetStr, path, pyside = pickle.load(sys.stdin.buffer) 9 | opts = pickle.load(sys.stdin.buffer) 10 | else: 11 | #name, port, authkey, ppid, targetStr, path, pyside = pickle.load(sys.stdin) 12 | opts = pickle.load(sys.stdin) 13 | #print "key:", ' '.join([str(ord(x)) for x in authkey]) 14 | path = opts.pop('path', None) 15 | if path is not None: 16 | ## rewrite sys.path without assigning a new object--no idea who already has a reference to the existing list. 17 | while len(sys.path) > 0: 18 | sys.path.pop() 19 | sys.path.extend(path) 20 | 21 | if opts.pop('pyside', False): 22 | import PySide 23 | 24 | 25 | targetStr = opts.pop('targetStr') 26 | target = pickle.loads(targetStr) ## unpickling the target should import everything we need 27 | target(**opts) ## Send all other options to the target function 28 | sys.exit(0) 29 | -------------------------------------------------------------------------------- /gui/pyqtgraph/widgets/MatplotlibWidget.py: -------------------------------------------------------------------------------- 1 | from pyqtgraph.Qt import QtGui, QtCore 2 | import matplotlib 3 | 4 | from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas 5 | from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar 6 | from matplotlib.figure import Figure 7 | 8 | class MatplotlibWidget(QtGui.QWidget): 9 | """ 10 | Implements a Matplotlib figure inside a QWidget. 11 | Use getFigure() and redraw() to interact with matplotlib. 12 | 13 | Example:: 14 | 15 | mw = MatplotlibWidget() 16 | subplot = mw.getFigure().add_subplot(111) 17 | subplot.plot(x,y) 18 | mw.draw() 19 | """ 20 | 21 | def __init__(self, size=(5.0, 4.0), dpi=100): 22 | QtGui.QWidget.__init__(self) 23 | self.fig = Figure(size, dpi=dpi) 24 | self.canvas = FigureCanvas(self.fig) 25 | self.canvas.setParent(self) 26 | self.toolbar = NavigationToolbar(self.canvas, self) 27 | 28 | self.vbox = QtGui.QVBoxLayout() 29 | self.vbox.addWidget(self.toolbar) 30 | self.vbox.addWidget(self.canvas) 31 | 32 | self.setLayout(self.vbox) 33 | 34 | def getFigure(self): 35 | return self.fig 36 | 37 | def draw(self): 38 | self.canvas.draw() 39 | -------------------------------------------------------------------------------- /gui/pyqtgraph/widgets/ComboBox.py: -------------------------------------------------------------------------------- 1 | from pyqtgraph.Qt import QtGui, QtCore 2 | from pyqtgraph.SignalProxy import SignalProxy 3 | 4 | 5 | class ComboBox(QtGui.QComboBox): 6 | """Extends QComboBox to add extra functionality. 7 | - updateList() - updates the items in the comboBox while blocking signals, remembers and resets to the previous values if it's still in the list 8 | """ 9 | 10 | 11 | def __init__(self, parent=None, items=None, default=None): 12 | QtGui.QComboBox.__init__(self, parent) 13 | 14 | #self.value = default 15 | 16 | if items is not None: 17 | self.addItems(items) 18 | if default is not None: 19 | self.setValue(default) 20 | 21 | def setValue(self, value): 22 | ind = self.findText(value) 23 | if ind == -1: 24 | return 25 | #self.value = value 26 | self.setCurrentIndex(ind) 27 | 28 | def updateList(self, items): 29 | prevVal = str(self.currentText()) 30 | try: 31 | self.blockSignals(True) 32 | self.clear() 33 | self.addItems(items) 34 | self.setValue(prevVal) 35 | 36 | finally: 37 | self.blockSignals(False) 38 | 39 | if str(self.currentText()) != prevVal: 40 | self.currentIndexChanged.emit(self.currentIndex()) 41 | -------------------------------------------------------------------------------- /controllers/movingtopoint1.py: -------------------------------------------------------------------------------- 1 | # modified by Yu Huang 2 | from controllers.pid_controller import PIDController 3 | import math 4 | import numpy 5 | 6 | 7 | class MovingToPoint1(PIDController): 8 | """FollowPath (i.e. move to next point) steers the robot to a predefined position in the world.""" 9 | def __init__(self, params): 10 | """Initialize internal variables""" 11 | PIDController.__init__(self,params) 12 | self.params = params 13 | #print params.path 14 | 15 | def get_heading_angle(self, state): 16 | """Get the direction from the robot to the goal as a vector.""" 17 | 18 | # generate heading angle to the next point 19 | x_g, y_g = self.params.path[0][0], self.params.path[0][1] 20 | #print point_cnt, 'FollowPath' 21 | # The robot: 22 | x_r, y_r, theta = state.pose 23 | 24 | # Where is the goal in the robot's frame of reference? 25 | return (math.atan2(y_g - y_r, x_g - x_r) - theta + math.pi)%(2*math.pi) - math.pi 26 | 27 | def get_heading(self,state): 28 | goal_angle = self.get_heading_angle(state) 29 | return numpy.array([math.cos(goal_angle),math.sin(goal_angle),1]) 30 | 31 | def execute(self, state, dt): 32 | v, w = PIDController.execute(self, state, dt) 33 | #print 'Move to point ', (self.params.ga_path[point_cnt][0], self.params.ga_path[point_cnt][1]) 34 | 35 | return v, w -------------------------------------------------------------------------------- /controllers/movingtopoint2.py: -------------------------------------------------------------------------------- 1 | # modified by Yu Huang 2 | from controllers.pid_controller import PIDController 3 | import math 4 | import numpy 5 | 6 | 7 | class MovingToPoint2(PIDController): 8 | """FollowPath (i.e. move to next point) steers the robot to a predefined position in the world.""" 9 | def __init__(self, params): 10 | """Initialize internal variables""" 11 | PIDController.__init__(self,params) 12 | self.params = params 13 | #print params.path 14 | 15 | def get_heading_angle(self, state): 16 | """Get the direction from the robot to the goal as a vector.""" 17 | 18 | # generate heading angle to the next point 19 | x_g, y_g = self.params.path[1][0], self.params.path[1][1] 20 | #print point_cnt, 'FollowPath' 21 | # The robot: 22 | x_r, y_r, theta = state.pose 23 | 24 | # Where is the goal in the robot's frame of reference? 25 | return (math.atan2(y_g - y_r, x_g - x_r) - theta + math.pi)%(2*math.pi) - math.pi 26 | 27 | def get_heading(self,state): 28 | goal_angle = self.get_heading_angle(state) 29 | return numpy.array([math.cos(goal_angle),math.sin(goal_angle),1]) 30 | 31 | def execute(self, state, dt): 32 | v, w = PIDController.execute(self, state, dt) 33 | #print 'Move to point ', (self.params.ga_path[point_cnt][0], self.params.ga_path[point_cnt][1]) 34 | 35 | return v/2, w -------------------------------------------------------------------------------- /scripts/collision_detect.py: -------------------------------------------------------------------------------- 1 | """ 2 | collision detect 3 | input: obstacles' vertex coordinates, list vertex_list[] 4 | """ 5 | 6 | def collision_detect(vertexs, point1, point2): 7 | positive_flag = 0 8 | negative_flag = 0 9 | step_b = False 10 | # line function 11 | line = lambda x1, y1, x2, y2, x, y: (y2-y1)*x + (x1-x2)*y + (x2*y1 - x1*y2) 12 | # step A 13 | for vertex in vertexs: 14 | if line(point1[0], point1[1],point2[0], point2[1], vertex[0], vertex[1]) == 0: 15 | step_b = True 16 | break 17 | elif line(point1[0], point1[1],point2[0], point2[1], vertex[0], vertex[1]) < 0: 18 | negative_flag += 1 19 | else: 20 | positive_flag += 1 21 | # step b 22 | if step_b or (not step_b and (positive_flag * negative_flag) != 0): 23 | max_x = 0.0 24 | max_y = 0.0 25 | min_x = 100.0 26 | min_y = 100.0 27 | for vertex in vertexs: 28 | max_x = max(max_x, vertex[0]) 29 | min_x = min(min_x, vertex[0]) 30 | max_y = max(max_y, vertex[1]) 31 | min_y = min(min_y, vertex[1]) 32 | if (point1[0] > max_x and point2[0] > max_x) or \ 33 | (point1[0] < min_x and point2[0] < min_x) or \ 34 | (point1[1] > max_y and point2[1] > max_y) or \ 35 | (point1[1] < min_y and point2[1] < min_y): 36 | return False 37 | else: 38 | return True 39 | else: 40 | return False -------------------------------------------------------------------------------- /controllers/followpath.py: -------------------------------------------------------------------------------- 1 | # modified by Yu Huang 2 | from controllers.pid_controller import PIDController 3 | import math 4 | import numpy 5 | 6 | 7 | class FollowPath(PIDController): 8 | """FollowPath (i.e. move to next point) steers the robot to a predefined position in the world.""" 9 | def __init__(self, params): 10 | """Initialize internal variables""" 11 | PIDController.__init__(self,params) 12 | self.params = params 13 | print params.ga_path 14 | 15 | def get_heading_angle(self, state): 16 | """Get the direction from the robot to the goal as a vector.""" 17 | 18 | # generate heading angle to the next point 19 | point_cnt = self.params.point_cnt 20 | x_g, y_g = self.params.ga_path[point_cnt][0], self.params.ga_path[point_cnt][1] 21 | #print point_cnt, 'FollowPath' 22 | # The robot: 23 | x_r, y_r, theta = state.pose 24 | 25 | # Where is the goal in the robot's frame of reference? 26 | return (math.atan2(y_g - y_r, x_g - x_r) - theta + math.pi)%(2*math.pi) - math.pi 27 | 28 | def get_heading(self,state): 29 | goal_angle = self.get_heading_angle(state) 30 | return numpy.array([math.cos(goal_angle),math.sin(goal_angle),1]) 31 | 32 | def execute(self, state, dt): 33 | v, w = PIDController.execute(self, state, dt) 34 | #print 'Move to point ', (self.params.ga_path[point_cnt][0], self.params.ga_path[point_cnt][1]) 35 | 36 | return v, w -------------------------------------------------------------------------------- /gui/qt_logdock.py: -------------------------------------------------------------------------------- 1 | from PyQt4 import QtGui 2 | from PyQt4.QtCore import Qt, pyqtSignal 3 | 4 | class LogDock(QtGui.QDockWidget): 5 | closed = pyqtSignal(bool) 6 | def __init__(self, parent): 7 | """Construct a new dockwindow with the log """ 8 | 9 | QtGui.QDockWidget.__init__(self, "Message log", parent) 10 | self.setAllowedAreas(Qt.TopDockWidgetArea | Qt.BottomDockWidgetArea) 11 | 12 | self.table = QtGui.QTableWidget(0,2,self) 13 | self.table.setHorizontalHeaderLabels(["Sender","Message"]) 14 | 15 | self.table.verticalHeader().setResizeMode(QtGui.QHeaderView.ResizeToContents) 16 | hhdrs = self.table.horizontalHeader() 17 | hhdrs.setResizeMode(0,QtGui.QHeaderView.ResizeToContents) 18 | hhdrs.setResizeMode(1,QtGui.QHeaderView.Stretch) 19 | 20 | self.setWidget(self.table) 21 | 22 | def append(self,message,name,color): 23 | row = self.table.rowCount() 24 | self.table.insertRow(row) 25 | self.table.setItem(row,0,QtGui.QTableWidgetItem(name)) 26 | self.table.setItem(row,1,QtGui.QTableWidgetItem(message)) 27 | clr = QtGui.QTableWidgetItem(" ") 28 | self.table.setVerticalHeaderItem(row,clr) 29 | if color is not None: 30 | clr.setBackground(QtGui.QColor(color)) 31 | 32 | def closeEvent(self,event): 33 | super(LogDock,self).closeEvent(event) 34 | if event.isAccepted(): 35 | print('closed') 36 | self.closed.emit(True) -------------------------------------------------------------------------------- /gui/pyqtgraph/graphicsItems/GraphicsObject.py: -------------------------------------------------------------------------------- 1 | from pyqtgraph.Qt import QtGui, QtCore 2 | import sip 3 | from .GraphicsItem import GraphicsItem 4 | 5 | __all__ = ['GraphicsObject'] 6 | class GraphicsObject(GraphicsItem, QtGui.QGraphicsObject): 7 | """ 8 | **Bases:** :class:`GraphicsItem `, :class:`QtGui.QGraphicsObject` 9 | 10 | Extension of QGraphicsObject with some useful methods (provided by :class:`GraphicsItem `) 11 | """ 12 | _qtBaseClass = QtGui.QGraphicsObject 13 | def __init__(self, *args): 14 | self.__inform_view_on_changes = True 15 | QtGui.QGraphicsObject.__init__(self, *args) 16 | self.setFlag(self.ItemSendsGeometryChanges) 17 | GraphicsItem.__init__(self) 18 | 19 | def itemChange(self, change, value): 20 | ret = QtGui.QGraphicsObject.itemChange(self, change, value) 21 | if change in [self.ItemParentHasChanged, self.ItemSceneHasChanged]: 22 | self.parentChanged() 23 | if self.__inform_view_on_changes and change in [self.ItemPositionHasChanged, self.ItemTransformHasChanged]: 24 | self.informViewBoundsChanged() 25 | 26 | ## workaround for pyqt bug: 27 | ## http://www.riverbankcomputing.com/pipermail/pyqt/2012-August/031818.html 28 | if change == self.ItemParentChange and isinstance(ret, QtGui.QGraphicsItem): 29 | ret = sip.cast(ret, QtGui.QGraphicsItem) 30 | 31 | return ret 32 | -------------------------------------------------------------------------------- /scripts/xmlobject.py: -------------------------------------------------------------------------------- 1 | import xml.etree.ElementTree as ET 2 | 3 | class XMLObject(object): 4 | """ 5 | Base class for XML handling. 6 | """ 7 | 8 | _file = None 9 | _template = None 10 | 11 | def __init__(self, file_, template): 12 | """ 13 | Construct a new XMLObject instance 14 | 15 | Scope: 16 | Public 17 | Parameters: 18 | file_ ------> the XML file 19 | template ---> 'simulation' or 'parameters' 20 | Return: 21 | A new XMLObject instance 22 | """ 23 | self._file = file_ 24 | self._template = template 25 | 26 | def validate(self, schema): 27 | """ 28 | Validate the XML in *file_* against a given schema. 29 | 30 | | *Parameters:* 31 | | *schema*........path to the schema file (*must* be RelaxNG) 32 | | *Return:* 33 | | True if schema validates successfully, False otherwise 34 | """ 35 | 36 | try: 37 | from lxml import etree 38 | from lxml.etree import RelaxNG 39 | except ImportError: 40 | raise Exception( 41 | '[XMLObject.validate] Need lxml to validate xml!') 42 | 43 | try: 44 | relaxng_doc = etree.parse(schema) 45 | relaxng = RelaxNG(relaxng_doc) 46 | xml_doc = etree.parse(self._file) 47 | except etree.XMLSyntaxError as e: 48 | raise Exception( 49 | '[XMLObject.validate] Cannot validate xml: ' + str(e)) 50 | 51 | return relaxng.validate(xml_doc) 52 | 53 | -------------------------------------------------------------------------------- /gui/pyqtgraph/units.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ## Very simple unit support: 3 | ## - creates variable names like 'mV' and 'kHz' 4 | ## - the value assigned to the variable corresponds to the scale prefix 5 | ## (mV = 0.001) 6 | ## - the actual units are purely cosmetic for making code clearer: 7 | ## 8 | ## x = 20*pA is identical to x = 20*1e-12 9 | 10 | ## No unicode variable names (μ,Ω) allowed until python 3 11 | 12 | SI_PREFIXES = 'yzafpnum kMGTPEZY' 13 | UNITS = 'm,s,g,W,J,V,A,F,T,Hz,Ohm,S,N,C,px,b,B'.split(',') 14 | allUnits = {} 15 | 16 | def addUnit(p, n): 17 | g = globals() 18 | v = 1000**n 19 | for u in UNITS: 20 | g[p+u] = v 21 | allUnits[p+u] = v 22 | 23 | for p in SI_PREFIXES: 24 | if p == ' ': 25 | p = '' 26 | n = 0 27 | elif p == 'u': 28 | n = -2 29 | else: 30 | n = SI_PREFIXES.index(p) - 8 31 | 32 | addUnit(p, n) 33 | 34 | cm = 0.01 35 | 36 | 37 | 38 | 39 | 40 | 41 | def evalUnits(unitStr): 42 | """ 43 | Evaluate a unit string into ([numerators,...], [denominators,...]) 44 | Examples: 45 | N m/s^2 => ([N, m], [s, s]) 46 | A*s / V => ([A, s], [V,]) 47 | """ 48 | pass 49 | 50 | def formatUnits(units): 51 | """ 52 | Format a unit specification ([numerators,...], [denominators,...]) 53 | into a string (this is the inverse of evalUnits) 54 | """ 55 | pass 56 | 57 | def simplify(units): 58 | """ 59 | Cancel units that appear in both numerator and denominator, then attempt to replace 60 | groups of units with single units where possible (ie, J/s => W) 61 | """ 62 | pass 63 | 64 | -------------------------------------------------------------------------------- /gui/pyqtgraph/ThreadsafeTimer.py: -------------------------------------------------------------------------------- 1 | from pyqtgraph.Qt import QtCore, QtGui 2 | 3 | class ThreadsafeTimer(QtCore.QObject): 4 | """ 5 | Thread-safe replacement for QTimer. 6 | """ 7 | 8 | timeout = QtCore.Signal() 9 | sigTimerStopRequested = QtCore.Signal() 10 | sigTimerStartRequested = QtCore.Signal(object) 11 | 12 | def __init__(self): 13 | QtCore.QObject.__init__(self) 14 | self.timer = QtCore.QTimer() 15 | self.timer.timeout.connect(self.timerFinished) 16 | self.timer.moveToThread(QtCore.QCoreApplication.instance().thread()) 17 | self.moveToThread(QtCore.QCoreApplication.instance().thread()) 18 | self.sigTimerStopRequested.connect(self.stop, QtCore.Qt.QueuedConnection) 19 | self.sigTimerStartRequested.connect(self.start, QtCore.Qt.QueuedConnection) 20 | 21 | 22 | def start(self, timeout): 23 | isGuiThread = QtCore.QThread.currentThread() == QtCore.QCoreApplication.instance().thread() 24 | if isGuiThread: 25 | #print "start timer", self, "from gui thread" 26 | self.timer.start(timeout) 27 | else: 28 | #print "start timer", self, "from remote thread" 29 | self.sigTimerStartRequested.emit(timeout) 30 | 31 | def stop(self): 32 | isGuiThread = QtCore.QThread.currentThread() == QtCore.QCoreApplication.instance().thread() 33 | if isGuiThread: 34 | #print "stop timer", self, "from gui thread" 35 | self.timer.stop() 36 | else: 37 | #print "stop timer", self, "from remote thread" 38 | self.sigTimerStopRequested.emit() 39 | 40 | def timerFinished(self): 41 | self.timeout.emit() -------------------------------------------------------------------------------- /gui/pyqtgraph/widgets/MultiPlotWidget.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | MultiPlotWidget.py - Convenience class--GraphicsView widget displaying a MultiPlotItem 4 | Copyright 2010 Luke Campagnola 5 | Distributed under MIT/X11 license. See license.txt for more infomation. 6 | """ 7 | 8 | from .GraphicsView import GraphicsView 9 | import pyqtgraph.graphicsItems.MultiPlotItem as MultiPlotItem 10 | 11 | __all__ = ['MultiPlotWidget'] 12 | class MultiPlotWidget(GraphicsView): 13 | """Widget implementing a graphicsView with a single PlotItem inside.""" 14 | def __init__(self, parent=None): 15 | GraphicsView.__init__(self, parent) 16 | self.enableMouse(False) 17 | self.mPlotItem = MultiPlotItem.MultiPlotItem() 18 | self.setCentralItem(self.mPlotItem) 19 | ## Explicitly wrap methods from mPlotItem 20 | #for m in ['setData']: 21 | #setattr(self, m, getattr(self.mPlotItem, m)) 22 | 23 | def __getattr__(self, attr): ## implicitly wrap methods from plotItem 24 | if hasattr(self.mPlotItem, attr): 25 | m = getattr(self.mPlotItem, attr) 26 | if hasattr(m, '__call__'): 27 | return m 28 | raise NameError(attr) 29 | 30 | def widgetGroupInterface(self): 31 | return (None, MultiPlotWidget.saveState, MultiPlotWidget.restoreState) 32 | 33 | def saveState(self): 34 | return {} 35 | #return self.plotItem.saveState() 36 | 37 | def restoreState(self, state): 38 | pass 39 | #return self.plotItem.restoreState(state) 40 | 41 | def close(self): 42 | self.mPlotItem.close() 43 | self.mPlotItem = None 44 | self.setParent(None) 45 | GraphicsView.close(self) -------------------------------------------------------------------------------- /gui/pyqtgraph/widgets/PathButton.py: -------------------------------------------------------------------------------- 1 | from pyqtgraph.Qt import QtGui, QtCore 2 | import pyqtgraph as pg 3 | __all__ = ['PathButton'] 4 | 5 | 6 | class PathButton(QtGui.QPushButton): 7 | """Simple PushButton extension which paints a QPainterPath on its face""" 8 | def __init__(self, parent=None, path=None, pen='default', brush=None, size=(30,30)): 9 | QtGui.QPushButton.__init__(self, parent) 10 | self.path = None 11 | if pen == 'default': 12 | pen = 'k' 13 | self.setPen(pen) 14 | self.setBrush(brush) 15 | if path is not None: 16 | self.setPath(path) 17 | if size is not None: 18 | self.setFixedWidth(size[0]) 19 | self.setFixedHeight(size[1]) 20 | 21 | 22 | def setBrush(self, brush): 23 | self.brush = pg.mkBrush(brush) 24 | 25 | def setPen(self, pen): 26 | self.pen = pg.mkPen(pen) 27 | 28 | def setPath(self, path): 29 | self.path = path 30 | self.update() 31 | 32 | def paintEvent(self, ev): 33 | QtGui.QPushButton.paintEvent(self, ev) 34 | margin = 7 35 | geom = QtCore.QRectF(0, 0, self.width(), self.height()).adjusted(margin, margin, -margin, -margin) 36 | rect = self.path.boundingRect() 37 | scale = min(geom.width() / float(rect.width()), geom.height() / float(rect.height())) 38 | 39 | p = QtGui.QPainter(self) 40 | p.setRenderHint(p.Antialiasing) 41 | p.translate(geom.center()) 42 | p.scale(scale, scale) 43 | p.translate(-rect.center()) 44 | p.setPen(self.pen) 45 | p.setBrush(self.brush) 46 | p.drawPath(self.path) 47 | p.end() 48 | 49 | 50 | -------------------------------------------------------------------------------- /gui/pyqtgraph/PlotData.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class PlotData(object): 4 | """ 5 | Class used for managing plot data 6 | - allows data sharing between multiple graphics items (curve, scatter, graph..) 7 | - each item may define the columns it needs 8 | - column groupings ('pos' or x, y, z) 9 | - efficiently appendable 10 | - log, fft transformations 11 | - color mode conversion (float/byte/qcolor) 12 | - pen/brush conversion 13 | - per-field cached masking 14 | - allows multiple masking fields (different graphics need to mask on different criteria) 15 | - removal of nan/inf values 16 | - option for single value shared by entire column 17 | - cached downsampling 18 | - cached min / max / hasnan / isuniform 19 | """ 20 | def __init__(self): 21 | self.fields = {} 22 | 23 | self.maxVals = {} ## cache for max/min 24 | self.minVals = {} 25 | 26 | def addFields(self, **fields): 27 | for f in fields: 28 | if f not in self.fields: 29 | self.fields[f] = None 30 | 31 | def hasField(self, f): 32 | return f in self.fields 33 | 34 | def __getitem__(self, field): 35 | return self.fields[field] 36 | 37 | def __setitem__(self, field, val): 38 | self.fields[field] = val 39 | 40 | def max(self, field): 41 | mx = self.maxVals.get(field, None) 42 | if mx is None: 43 | mx = np.max(self[field]) 44 | self.maxVals[field] = mx 45 | return mx 46 | 47 | def min(self, field): 48 | mn = self.minVals.get(field, None) 49 | if mn is None: 50 | mn = np.min(self[field]) 51 | self.minVals[field] = mn 52 | return mn 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /gui/pyqtgraph/graphicsItems/ButtonItem.py: -------------------------------------------------------------------------------- 1 | from pyqtgraph.Qt import QtGui, QtCore 2 | from .GraphicsObject import GraphicsObject 3 | 4 | __all__ = ['ButtonItem'] 5 | class ButtonItem(GraphicsObject): 6 | """Button graphicsItem displaying an image.""" 7 | 8 | clicked = QtCore.Signal(object) 9 | 10 | def __init__(self, imageFile=None, width=None, parentItem=None, pixmap=None): 11 | self.enabled = True 12 | GraphicsObject.__init__(self) 13 | if imageFile is not None: 14 | self.setImageFile(imageFile) 15 | elif pixmap is not None: 16 | self.setPixmap(pixmap) 17 | 18 | if width is not None: 19 | s = float(width) / self.pixmap.width() 20 | self.scale(s, s) 21 | if parentItem is not None: 22 | self.setParentItem(parentItem) 23 | self.setOpacity(0.7) 24 | 25 | def setImageFile(self, imageFile): 26 | self.setPixmap(QtGui.QPixmap(imageFile)) 27 | 28 | def setPixmap(self, pixmap): 29 | self.pixmap = pixmap 30 | self.update() 31 | 32 | def mouseClickEvent(self, ev): 33 | if self.enabled: 34 | self.clicked.emit(self) 35 | 36 | def mouseHoverEvent(self, ev): 37 | if not self.enabled: 38 | return 39 | if ev.isEnter(): 40 | self.setOpacity(1.0) 41 | else: 42 | self.setOpacity(0.7) 43 | 44 | def disable(self): 45 | self.enabled = False 46 | self.setOpacity(0.4) 47 | 48 | def enable(self): 49 | self.enabled = True 50 | self.setOpacity(0.7) 51 | 52 | def paint(self, p, *args): 53 | p.setRenderHint(p.Antialiasing) 54 | p.drawPixmap(0, 0, self.pixmap) 55 | 56 | def boundingRect(self): 57 | return QtCore.QRectF(self.pixmap.rect()) 58 | 59 | -------------------------------------------------------------------------------- /gui/pyqtgraph/opengl/items/GLGridItem.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | from .. GLGraphicsItem import GLGraphicsItem 3 | from pyqtgraph import QtGui 4 | 5 | __all__ = ['GLGridItem'] 6 | 7 | class GLGridItem(GLGraphicsItem): 8 | """ 9 | **Bases:** :class:`GLGraphicsItem ` 10 | 11 | Displays a wire-grame grid. 12 | """ 13 | 14 | def __init__(self, size=None, color=None, antialias=True, glOptions='translucent'): 15 | GLGraphicsItem.__init__(self) 16 | self.setGLOptions(glOptions) 17 | self.antialias = antialias 18 | if size is None: 19 | size = QtGui.QVector3D(1,1,1) 20 | self.setSize(size=size) 21 | 22 | def setSize(self, x=None, y=None, z=None, size=None): 23 | """ 24 | Set the size of the axes (in its local coordinate system; this does not affect the transform) 25 | Arguments can be x,y,z or size=QVector3D(). 26 | """ 27 | if size is not None: 28 | x = size.x() 29 | y = size.y() 30 | z = size.z() 31 | self.__size = [x,y,z] 32 | self.update() 33 | 34 | def size(self): 35 | return self.__size[:] 36 | 37 | 38 | def paint(self): 39 | self.setupGLState() 40 | 41 | if self.antialias: 42 | glEnable(GL_LINE_SMOOTH) 43 | glEnable(GL_BLEND) 44 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 45 | glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); 46 | 47 | glBegin( GL_LINES ) 48 | 49 | x,y,z = self.size() 50 | glColor4f(1, 1, 1, .3) 51 | for x in range(-10, 11): 52 | glVertex3f(x, -10, 0) 53 | glVertex3f(x, 10, 0) 54 | for y in range(-10, 11): 55 | glVertex3f(-10, y, 0) 56 | glVertex3f( 10, y, 0) 57 | 58 | glEnd() 59 | -------------------------------------------------------------------------------- /scripts/controller.py: -------------------------------------------------------------------------------- 1 | #PySimiam 2 | #Author: John Alexander 3 | #ChangeDate: 8 FEB 2013; 2300EST 4 | #Description: This is the Controller class for PySimiam. 5 | import math 6 | 7 | class Controller(): 8 | """ 9 | The controller class defines a behavior for the supervisor class. 10 | Any implemention must inherit from this class and implement the 11 | :meth:`~Controller,execute` method to return a unicycle model output. 12 | 13 | :param params: A structure containing the internal controller parameters, such as PID constants. 14 | :type params: :class:`~helpers.Struct` 15 | """ 16 | def __init__(self,params): 17 | """Initialize the controller with parameters 18 | :params params: A structure containing the internal controller parameters, such as PID constants. 19 | :type params: :class:`~helpers.Struct` 20 | """ 21 | self.set_parameters(params) 22 | self.restart() 23 | 24 | def execute(self, state, dt): 25 | """Given a state and elapsed time, calculate and return robot motion parameters 26 | 27 | :param state: Output from the supervisor :meth:`~Supervisor.process` method 28 | :type state: :class:`~helpers.Struct` 29 | :param float dt: Time elapsed since last call to `execute()` 30 | 31 | To be implemented in subclasses. 32 | """ 33 | raise NotImplementedError("Controller.execute") 34 | 35 | def set_parameters(self,params): 36 | """Set the internal parameters of the controller. 37 | 38 | :param params: A structure containing the internal controller parameters, such as PID constants. 39 | :type params: :class:`~helpers.Struct` 40 | 41 | To be implemented in subclasses, 42 | """ 43 | raise NotImplementedError("Controller.set_parameters") 44 | 45 | def restart(self): 46 | """Reset the controller to the initial state.""" 47 | pass 48 | -------------------------------------------------------------------------------- /gui/pyqtgraph/python2_3.py: -------------------------------------------------------------------------------- 1 | """ 2 | Helper functions which smooth out the differences between python 2 and 3. 3 | """ 4 | import sys 5 | 6 | def asUnicode(x): 7 | if sys.version_info[0] == 2: 8 | if isinstance(x, unicode): 9 | return x 10 | elif isinstance(x, str): 11 | return x.decode('UTF-8') 12 | else: 13 | return unicode(x) 14 | else: 15 | return str(x) 16 | 17 | def cmpToKey(mycmp): 18 | 'Convert a cmp= function into a key= function' 19 | class K(object): 20 | def __init__(self, obj, *args): 21 | self.obj = obj 22 | def __lt__(self, other): 23 | return mycmp(self.obj, other.obj) < 0 24 | def __gt__(self, other): 25 | return mycmp(self.obj, other.obj) > 0 26 | def __eq__(self, other): 27 | return mycmp(self.obj, other.obj) == 0 28 | def __le__(self, other): 29 | return mycmp(self.obj, other.obj) <= 0 30 | def __ge__(self, other): 31 | return mycmp(self.obj, other.obj) >= 0 32 | def __ne__(self, other): 33 | return mycmp(self.obj, other.obj) != 0 34 | return K 35 | 36 | def sortList(l, cmpFunc): 37 | if sys.version_info[0] == 2: 38 | l.sort(cmpFunc) 39 | else: 40 | l.sort(key=cmpToKey(cmpFunc)) 41 | 42 | if sys.version_info[0] == 3: 43 | import builtins 44 | builtins.basestring = str 45 | #builtins.asUnicode = asUnicode 46 | #builtins.sortList = sortList 47 | basestring = str 48 | def cmp(a,b): 49 | if a>b: 50 | return 1 51 | elif b > a: 52 | return -1 53 | else: 54 | return 0 55 | builtins.cmp = cmp 56 | builtins.xrange = range 57 | #else: ## don't use __builtin__ -- this confuses things like pyshell and ActiveState's lazy import recipe 58 | #import __builtin__ 59 | #__builtin__.asUnicode = asUnicode 60 | #__builtin__.sortList = sortList 61 | -------------------------------------------------------------------------------- /gui/pyqtgraph/exporters/CSVExporter.py: -------------------------------------------------------------------------------- 1 | import pyqtgraph as pg 2 | from pyqtgraph.Qt import QtGui, QtCore 3 | from .Exporter import Exporter 4 | from pyqtgraph.parametertree import Parameter 5 | 6 | 7 | __all__ = ['CSVExporter'] 8 | 9 | 10 | class CSVExporter(Exporter): 11 | Name = "CSV from plot data" 12 | windows = [] 13 | def __init__(self, item): 14 | Exporter.__init__(self, item) 15 | self.params = Parameter(name='params', type='group', children=[ 16 | {'name': 'separator', 'type': 'list', 'value': 'comma', 'values': ['comma', 'tab']}, 17 | {'name': 'precision', 'type': 'int', 'value': 10, 'limits': [0, None]}, 18 | ]) 19 | 20 | def parameters(self): 21 | return self.params 22 | 23 | def export(self, fileName=None): 24 | 25 | if not isinstance(self.item, pg.PlotItem): 26 | raise Exception("Must have a PlotItem selected for CSV export.") 27 | 28 | if fileName is None: 29 | self.fileSaveDialog(filter=["*.csv", "*.tsv"]) 30 | return 31 | 32 | fd = open(fileName, 'w') 33 | data = [] 34 | header = [] 35 | for c in self.item.curves: 36 | data.append(c.getData()) 37 | header.extend(['x', 'y']) 38 | 39 | if self.params['separator'] == 'comma': 40 | sep = ',' 41 | else: 42 | sep = '\t' 43 | 44 | fd.write(sep.join(header) + '\n') 45 | i = 0 46 | numFormat = '%%0.%dg' % self.params['precision'] 47 | numRows = reduce(max, [len(d[0]) for d in data]) 48 | for i in range(numRows): 49 | for d in data: 50 | if i < len(d[0]): 51 | fd.write(numFormat % d[0][i] + sep + numFormat % d[1][i] + sep) 52 | else: 53 | fd.write(' %s %s' % (sep, sep)) 54 | fd.write('\n') 55 | fd.close() 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /gui/pyqtgraph/frozenSupport.py: -------------------------------------------------------------------------------- 1 | ## Definitions helpful in frozen environments (eg py2exe) 2 | import os, sys, zipfile 3 | 4 | def listdir(path): 5 | """Replacement for os.listdir that works in frozen environments.""" 6 | if not hasattr(sys, 'frozen'): 7 | return os.listdir(path) 8 | 9 | (zipPath, archivePath) = splitZip(path) 10 | if archivePath is None: 11 | return os.listdir(path) 12 | 13 | with zipfile.ZipFile(zipPath, "r") as zipobj: 14 | contents = zipobj.namelist() 15 | results = set() 16 | for name in contents: 17 | # components in zip archive paths are always separated by forward slash 18 | if name.startswith(archivePath) and len(name) > len(archivePath): 19 | name = name[len(archivePath):].split('/')[0] 20 | results.add(name) 21 | return list(results) 22 | 23 | def isdir(path): 24 | """Replacement for os.path.isdir that works in frozen environments.""" 25 | if not hasattr(sys, 'frozen'): 26 | return os.path.isdir(path) 27 | 28 | (zipPath, archivePath) = splitZip(path) 29 | if archivePath is None: 30 | return os.path.isdir(path) 31 | with zipfile.ZipFile(zipPath, "r") as zipobj: 32 | contents = zipobj.namelist() 33 | archivePath = archivePath.rstrip('/') + '/' ## make sure there's exactly one '/' at the end 34 | for c in contents: 35 | if c.startswith(archivePath): 36 | return True 37 | return False 38 | 39 | 40 | def splitZip(path): 41 | """Splits a path containing a zip file into (zipfile, subpath). 42 | If there is no zip file, returns (path, None)""" 43 | components = os.path.normpath(path).split(os.sep) 44 | for index, component in enumerate(components): 45 | if component.endswith('.zip'): 46 | zipPath = os.sep.join(components[0:index+1]) 47 | archivePath = ''.join([x+'/' for x in components[index+1:]]) 48 | return (zipPath, archivePath) 49 | else: 50 | return (path, None) 51 | 52 | -------------------------------------------------------------------------------- /gui/pyqtgraph/metaarray/readMeta.m: -------------------------------------------------------------------------------- 1 | function f = readMeta(file) 2 | info = hdf5info(file); 3 | f = readMetaRecursive(info.GroupHierarchy.Groups(1)); 4 | end 5 | 6 | 7 | function f = readMetaRecursive(root) 8 | typ = 0; 9 | for i = 1:length(root.Attributes) 10 | if strcmp(root.Attributes(i).Shortname, '_metaType_') 11 | typ = root.Attributes(i).Value.Data; 12 | break 13 | end 14 | end 15 | if typ == 0 16 | printf('group has no _metaType_') 17 | typ = 'dict'; 18 | end 19 | 20 | list = 0; 21 | if strcmp(typ, 'list') || strcmp(typ, 'tuple') 22 | data = {}; 23 | list = 1; 24 | elseif strcmp(typ, 'dict') 25 | data = struct(); 26 | else 27 | printf('Unrecognized meta type %s', typ); 28 | data = struct(); 29 | end 30 | 31 | for i = 1:length(root.Attributes) 32 | name = root.Attributes(i).Shortname; 33 | if strcmp(name, '_metaType_') 34 | continue 35 | end 36 | val = root.Attributes(i).Value; 37 | if isa(val, 'hdf5.h5string') 38 | val = val.Data; 39 | end 40 | if list 41 | ind = str2num(name)+1; 42 | data{ind} = val; 43 | else 44 | data.(name) = val; 45 | end 46 | end 47 | 48 | for i = 1:length(root.Datasets) 49 | fullName = root.Datasets(i).Name; 50 | name = stripName(fullName); 51 | file = root.Datasets(i).Filename; 52 | data2 = hdf5read(file, fullName); 53 | if list 54 | ind = str2num(name)+1; 55 | data{ind} = data2; 56 | else 57 | data.(name) = data2; 58 | end 59 | end 60 | 61 | for i = 1:length(root.Groups) 62 | name = stripName(root.Groups(i).Name); 63 | data2 = readMetaRecursive(root.Groups(i)); 64 | if list 65 | ind = str2num(name)+1; 66 | data{ind} = data2; 67 | else 68 | data.(name) = data2; 69 | end 70 | end 71 | f = data; 72 | return; 73 | end 74 | 75 | 76 | function f = stripName(str) 77 | inds = strfind(str, '/'); 78 | if isempty(inds) 79 | f = str; 80 | else 81 | f = str(inds(length(inds))+1:length(str)); 82 | end 83 | end 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /gui/pyqtgraph/opengl/items/GLAxisItem.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | from .. GLGraphicsItem import GLGraphicsItem 3 | from pyqtgraph import QtGui 4 | 5 | __all__ = ['GLAxisItem'] 6 | 7 | class GLAxisItem(GLGraphicsItem): 8 | """ 9 | **Bases:** :class:`GLGraphicsItem ` 10 | 11 | Displays three lines indicating origin and orientation of local coordinate system. 12 | 13 | """ 14 | 15 | def __init__(self, size=None, antialias=True, glOptions='translucent'): 16 | GLGraphicsItem.__init__(self) 17 | if size is None: 18 | size = QtGui.QVector3D(1,1,1) 19 | self.antialias = antialias 20 | self.setSize(size=size) 21 | self.setGLOptions(glOptions) 22 | 23 | def setSize(self, x=None, y=None, z=None, size=None): 24 | """ 25 | Set the size of the axes (in its local coordinate system; this does not affect the transform) 26 | Arguments can be x,y,z or size=QVector3D(). 27 | """ 28 | if size is not None: 29 | x = size.x() 30 | y = size.y() 31 | z = size.z() 32 | self.__size = [x,y,z] 33 | self.update() 34 | 35 | def size(self): 36 | return self.__size[:] 37 | 38 | 39 | def paint(self): 40 | 41 | #glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 42 | #glEnable( GL_BLEND ) 43 | #glEnable( GL_ALPHA_TEST ) 44 | self.setupGLState() 45 | 46 | if self.antialias: 47 | glEnable(GL_LINE_SMOOTH) 48 | glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); 49 | 50 | glBegin( GL_LINES ) 51 | 52 | x,y,z = self.size() 53 | glColor4f(0, 1, 0, .6) # z is green 54 | glVertex3f(0, 0, 0) 55 | glVertex3f(0, 0, z) 56 | 57 | glColor4f(1, 1, 0, .6) # y is yellow 58 | glVertex3f(0, 0, 0) 59 | glVertex3f(0, y, 0) 60 | 61 | glColor4f(0, 0, 1, .6) # x is blue 62 | glVertex3f(0, 0, 0) 63 | glVertex3f(x, 0, 0) 64 | glEnd() 65 | -------------------------------------------------------------------------------- /gui/pyqtgraph/canvas/TransformGuiTemplate.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form 4 | 5 | 6 | 7 | 0 8 | 0 9 | 224 10 | 117 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | Form 21 | 22 | 23 | 24 | 1 25 | 26 | 27 | 0 28 | 29 | 30 | 31 | 32 | Translate: 33 | 34 | 35 | 36 | 37 | 38 | 39 | Rotate: 40 | 41 | 42 | 43 | 44 | 45 | 46 | Scale: 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | Mirror 59 | 60 | 61 | 62 | 63 | 64 | 65 | Reflect 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /controllers/avoidobstacles.py: -------------------------------------------------------------------------------- 1 | # 2 | # (c) PySimiam Team 2013 3 | # 4 | # Contact person: Tim Fuchs 5 | # 6 | # This class was implemented as a weekly programming excercise 7 | # of the 'Control of Mobile Robots' course by Magnus Egerstedt. 8 | # 9 | from controllers.pid_controller import PIDController 10 | import math 11 | import numpy 12 | from pose import Pose 13 | 14 | class AvoidObstacles(PIDController): 15 | """Avoid obstacles is an example controller that checks the sensors 16 | for any readings, constructs 'obstacle' vectors and directs the robot 17 | in the direction of their weighted sum.""" 18 | def __init__(self, params): 19 | '''Initialize internal variables''' 20 | PIDController.__init__(self,params) 21 | 22 | def set_parameters(self, params): 23 | """Set PID values and sensor poses. 24 | 25 | The params structure is expected to have sensor poses in the robot's 26 | reference frame as ``params.sensor_poses``. 27 | """ 28 | PIDController.set_parameters(self,params) 29 | 30 | self.sensor_poses = params.sensor_poses 31 | 32 | # Now we know the poses, it makes sense to also 33 | # calculate the weights 34 | #self.weights = [(math.cos(p.theta)+1.5) for p in self.sensor_poses] 35 | self.weights = [1.0, 1.0, 0.5, 1.0, 1.0] 36 | 37 | # Normalizing weights 38 | ws = sum(self.weights) 39 | self.weights = [w/ws for w in self.weights] 40 | 41 | def get_heading(self, state): 42 | """Get the direction away from the obstacles as a vector.""" 43 | 44 | # Calculate heading: 45 | x, y = 0, 0 46 | for d,p,w in zip(state.sensor_distances, self.sensor_poses, self.weights): 47 | pose = Pose(d) >> p 48 | x += pose.x*w 49 | y += pose.y*w 50 | 51 | return numpy.array([x, y, 1]) 52 | 53 | def execute(self, state, dt): 54 | 55 | v, w = PIDController.execute(self, state, dt) 56 | 57 | dmin = min(state.sensor_distances) 58 | v *= ((dmin - 0.04)/0.26)**2 59 | 60 | # 61 | 62 | return v, w -------------------------------------------------------------------------------- /gui/pyqtgraph/console/CmdInput.py: -------------------------------------------------------------------------------- 1 | from pyqtgraph.Qt import QtCore, QtGui 2 | from pyqtgraph.python2_3 import asUnicode 3 | 4 | class CmdInput(QtGui.QLineEdit): 5 | 6 | sigExecuteCmd = QtCore.Signal(object) 7 | 8 | def __init__(self, parent): 9 | QtGui.QLineEdit.__init__(self, parent) 10 | self.history = [""] 11 | self.ptr = 0 12 | #self.lastCmd = None 13 | #self.setMultiline(False) 14 | 15 | def keyPressEvent(self, ev): 16 | #print "press:", ev.key(), QtCore.Qt.Key_Up, QtCore.Qt.Key_Down, QtCore.Qt.Key_Enter 17 | if ev.key() == QtCore.Qt.Key_Up and self.ptr < len(self.history) - 1: 18 | self.setHistory(self.ptr+1) 19 | ev.accept() 20 | return 21 | elif ev.key() == QtCore.Qt.Key_Down and self.ptr > 0: 22 | self.setHistory(self.ptr-1) 23 | ev.accept() 24 | return 25 | elif ev.key() == QtCore.Qt.Key_Return: 26 | self.execCmd() 27 | else: 28 | QtGui.QLineEdit.keyPressEvent(self, ev) 29 | self.history[0] = asUnicode(self.text()) 30 | 31 | def execCmd(self): 32 | cmd = asUnicode(self.text()) 33 | if len(self.history) == 1 or cmd != self.history[1]: 34 | self.history.insert(1, cmd) 35 | #self.lastCmd = cmd 36 | self.history[0] = "" 37 | self.setHistory(0) 38 | self.sigExecuteCmd.emit(cmd) 39 | 40 | def setHistory(self, num): 41 | self.ptr = num 42 | self.setText(self.history[self.ptr]) 43 | 44 | #def setMultiline(self, m): 45 | #height = QtGui.QFontMetrics(self.font()).lineSpacing() 46 | #if m: 47 | #self.setFixedHeight(height*5) 48 | #else: 49 | #self.setFixedHeight(height+15) 50 | #self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) 51 | #self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) 52 | 53 | 54 | #def sizeHint(self): 55 | #hint = QtGui.QPlainTextEdit.sizeHint(self) 56 | #height = QtGui.QFontMetrics(self.font()).lineSpacing() 57 | #hint.setHeight(height) 58 | #return hint 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /controllers/k3_avoidobstacles.py: -------------------------------------------------------------------------------- 1 | # 2 | # (c) PySimiam Team 2013 3 | # 4 | # Contact person: Tim Fuchs 5 | # 6 | # This class was implemented as a weekly programming excercise 7 | # of the 'Control of Mobile Robots' course by Magnus Egerstedt. 8 | # 9 | from pid_controller import PIDController 10 | import math 11 | import numpy 12 | 13 | class K3_AvoidObstacles(PIDController): 14 | """Avoid obstacles is an example controller that checks the sensors 15 | for any readings, constructs 'obstacle' vectors and directs the robot 16 | in the direction of their weightd sum.""" 17 | def __init__(self, params): 18 | '''Initialize internal variables''' 19 | PIDController.__init__(self,params) 20 | 21 | # This variable should contain a list of vectors 22 | # calculated from sensor readings. It is used by 23 | # the supervisor to draw & debug the controller's 24 | # behaviour 25 | self.vectors = [] 26 | 27 | def set_parameters(self, params): 28 | """Set PID values and sensor poses. 29 | 30 | The params structure is expected to have sensor poses in the robot's 31 | reference frame as ``params.sensor_poses``. 32 | """ 33 | PIDController.set_parameters(self,params) 34 | 35 | self.poses = params.sensor_poses 36 | 37 | # Now we know the poses, it makes sense to also 38 | # calculate the weights 39 | self.weights = [(math.cos(p.theta)+1.5) for p in self.poses] 40 | 41 | # Normalizing weights 42 | ws = sum(self.weights) 43 | self.weights = [w/ws for w in self.weights] 44 | 45 | def get_heading(self, state): 46 | """Get the direction away from the obstacles as a vector.""" 47 | 48 | # Calculate heading: 49 | 50 | # 1. Transform distances to vectors in the robot's frame of reference 51 | self.vectors = \ 52 | numpy.array( 53 | [numpy.dot( 54 | p.get_transformation(), 55 | numpy.array([d,0,1]) 56 | ) 57 | for d, p in zip(state.sensor_distances, self.poses) ] ) 58 | 59 | # 2. Calculate weighted sum: 60 | heading = numpy.dot(self.vectors.transpose(), self.weights) 61 | 62 | return heading -------------------------------------------------------------------------------- /gui/qt_plotwindow.py: -------------------------------------------------------------------------------- 1 | from PyQt4 import QtGui 2 | from PyQt4.QtCore import pyqtSlot, pyqtSignal, Qt 3 | 4 | import sys 5 | import numpy 6 | from random import random 7 | 8 | mplPlotWindow = None 9 | qwtPlotWindow = None 10 | pqgPlotWindow = None 11 | PlotWindow = None 12 | 13 | def use_qwt_backend(): 14 | global PlotWindow, qwtPlotWindow 15 | if qwtPlotWindow is None: 16 | qwtPlotWindow = __import__('qt_plotwindow_qwt', 17 | globals(), locals(), 18 | ['PlotWindow'], sys.version_info.major-3).PlotWindow 19 | PlotWindow = qwtPlotWindow 20 | 21 | def use_qtgraph_backend(): 22 | global PlotWindow, pqgPlotWindow 23 | if pqgPlotWindow is None: 24 | pqgPlotWindow = __import__('qt_plotwindow_qtgraph', 25 | globals(), locals(), 26 | ['PlotWindow'], sys.version_info.major-3).PlotWindow 27 | PlotWindow = pqgPlotWindow 28 | 29 | def use_matplotlib_backend(): 30 | global PlotWindow, mplPlotWindow 31 | if mplPlotWindow is None: 32 | mplPlotWindow = __import__('qt_plotwindow_mpl', 33 | globals(), locals(), 34 | ['PlotWindow'], sys.version_info.major-3).PlotWindow 35 | PlotWindow = mplPlotWindow 36 | 37 | def use_some_backend(): 38 | global PlotWindow 39 | if PlotWindow is not None: 40 | return 41 | try: 42 | use_qtgraph_backend() 43 | except ImportError: 44 | try: 45 | use_qwt_backend() 46 | except ImportError: 47 | try: 48 | use_matplotlib_backend() 49 | except ImportError: 50 | raise ImportError("No suitable plot backend found") 51 | if PlotWindow is None: 52 | raise ImportError("No suitable plot backend found") 53 | 54 | def create_predefined_plot_window(plots): 55 | """Create a window with plots from plot dictionary""" 56 | try: 57 | use_some_backend() 58 | except ImportError as e: 59 | print(str(e)) 60 | return None, None 61 | w = PlotWindow() 62 | es = [] 63 | for plot in plots: 64 | p = w.add_plot() 65 | for l,e,c in plot: 66 | p.add_curve(l,e,c) 67 | es.append(e) 68 | return es, w 69 | -------------------------------------------------------------------------------- /gui/pyqtgraph/graphicsItems/MultiPlotItem.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | MultiPlotItem.py - Graphics item used for displaying an array of PlotItems 4 | Copyright 2010 Luke Campagnola 5 | Distributed under MIT/X11 license. See license.txt for more infomation. 6 | """ 7 | 8 | from numpy import ndarray 9 | from . import GraphicsLayout 10 | 11 | try: 12 | from metaarray import * 13 | HAVE_METAARRAY = True 14 | except: 15 | #raise 16 | HAVE_METAARRAY = False 17 | 18 | 19 | __all__ = ['MultiPlotItem'] 20 | class MultiPlotItem(GraphicsLayout.GraphicsLayout): 21 | """ 22 | Automaticaly generates a grid of plots from a multi-dimensional array 23 | """ 24 | 25 | def plot(self, data): 26 | #self.layout.clear() 27 | self.plots = [] 28 | 29 | if HAVE_METAARRAY and (hasattr(data, 'implements') and data.implements('MetaArray')): 30 | if data.ndim != 2: 31 | raise Exception("MultiPlot currently only accepts 2D MetaArray.") 32 | ic = data.infoCopy() 33 | ax = 0 34 | for i in [0, 1]: 35 | if 'cols' in ic[i]: 36 | ax = i 37 | break 38 | #print "Plotting using axis %d as columns (%d plots)" % (ax, data.shape[ax]) 39 | for i in range(data.shape[ax]): 40 | pi = self.addPlot() 41 | self.nextRow() 42 | sl = [slice(None)] * 2 43 | sl[ax] = i 44 | pi.plot(data[tuple(sl)]) 45 | #self.layout.addItem(pi, i, 0) 46 | self.plots.append((pi, i, 0)) 47 | title = None 48 | units = None 49 | info = ic[ax]['cols'][i] 50 | if 'title' in info: 51 | title = info['title'] 52 | elif 'name' in info: 53 | title = info['name'] 54 | if 'units' in info: 55 | units = info['units'] 56 | 57 | pi.setLabel('left', text=title, units=units) 58 | 59 | else: 60 | raise Exception("Data type %s not (yet?) supported for MultiPlot." % type(data)) 61 | 62 | def close(self): 63 | for p in self.plots: 64 | p[0].close() 65 | self.plots = None 66 | self.clear() 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /gui/pyqtgraph/Vector.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Vector.py - Extension of QVector3D which adds a few missing methods. 4 | Copyright 2010 Luke Campagnola 5 | Distributed under MIT/X11 license. See license.txt for more infomation. 6 | """ 7 | 8 | from .Qt import QtGui, QtCore 9 | import numpy as np 10 | 11 | class Vector(QtGui.QVector3D): 12 | """Extension of QVector3D which adds a few helpful methods.""" 13 | 14 | def __init__(self, *args): 15 | if len(args) == 1: 16 | if isinstance(args[0], QtCore.QSizeF): 17 | QtGui.QVector3D.__init__(self, float(args[0].width()), float(args[0].height()), 0) 18 | return 19 | elif isinstance(args[0], QtCore.QPoint) or isinstance(args[0], QtCore.QPointF): 20 | QtGui.QVector3D.__init__(self, float(args[0].x()), float(args[0].y()), 0) 21 | elif hasattr(args[0], '__getitem__'): 22 | vals = list(args[0]) 23 | if len(vals) == 2: 24 | vals.append(0) 25 | if len(vals) != 3: 26 | raise Exception('Cannot init Vector with sequence of length %d' % len(args[0])) 27 | QtGui.QVector3D.__init__(self, *vals) 28 | return 29 | elif len(args) == 2: 30 | QtGui.QVector3D.__init__(self, args[0], args[1], 0) 31 | return 32 | QtGui.QVector3D.__init__(self, *args) 33 | 34 | def __len__(self): 35 | return 3 36 | 37 | def __add__(self, b): 38 | return QtGui.QVector3D.__add__(self, b) 39 | 40 | #def __reduce__(self): 41 | #return (Point, (self.x(), self.y())) 42 | 43 | def __getitem__(self, i): 44 | if i == 0: 45 | return self.x() 46 | elif i == 1: 47 | return self.y() 48 | elif i == 2: 49 | return self.z() 50 | else: 51 | raise IndexError("Point has no index %s" % str(i)) 52 | 53 | def __setitem__(self, i, x): 54 | if i == 0: 55 | return self.setX(x) 56 | elif i == 1: 57 | return self.setY(x) 58 | elif i == 2: 59 | return self.setZ(x) 60 | else: 61 | raise IndexError("Point has no index %s" % str(i)) 62 | 63 | def __iter__(self): 64 | yield(self.x()) 65 | yield(self.y()) 66 | yield(self.z()) 67 | -------------------------------------------------------------------------------- /gui/pyqtgraph/graphicsItems/GraphicsWidget.py: -------------------------------------------------------------------------------- 1 | from pyqtgraph.Qt import QtGui, QtCore 2 | from pyqtgraph.GraphicsScene import GraphicsScene 3 | from .GraphicsItem import GraphicsItem 4 | 5 | __all__ = ['GraphicsWidget'] 6 | 7 | class GraphicsWidget(GraphicsItem, QtGui.QGraphicsWidget): 8 | 9 | _qtBaseClass = QtGui.QGraphicsWidget 10 | def __init__(self, *args, **kargs): 11 | """ 12 | **Bases:** :class:`GraphicsItem `, :class:`QtGui.QGraphicsWidget` 13 | 14 | Extends QGraphicsWidget with several helpful methods and workarounds for PyQt bugs. 15 | Most of the extra functionality is inherited from :class:`GraphicsItem `. 16 | """ 17 | QtGui.QGraphicsWidget.__init__(self, *args, **kargs) 18 | GraphicsItem.__init__(self) 19 | 20 | ## done by GraphicsItem init 21 | #GraphicsScene.registerObject(self) ## workaround for pyqt bug in graphicsscene.items() 22 | 23 | # Removed due to https://bugreports.qt-project.org/browse/PYSIDE-86 24 | #def itemChange(self, change, value): 25 | ## BEWARE: Calling QGraphicsWidget.itemChange can lead to crashing! 26 | ##ret = QtGui.QGraphicsWidget.itemChange(self, change, value) ## segv occurs here 27 | ## The default behavior is just to return the value argument, so we'll do that 28 | ## without calling the original method. 29 | #ret = value 30 | #if change in [self.ItemParentHasChanged, self.ItemSceneHasChanged]: 31 | #self._updateView() 32 | #return ret 33 | 34 | def setFixedHeight(self, h): 35 | self.setMaximumHeight(h) 36 | self.setMinimumHeight(h) 37 | 38 | def setFixedWidth(self, h): 39 | self.setMaximumWidth(h) 40 | self.setMinimumWidth(h) 41 | 42 | def height(self): 43 | return self.geometry().height() 44 | 45 | def width(self): 46 | return self.geometry().width() 47 | 48 | def boundingRect(self): 49 | br = self.mapRectFromParent(self.geometry()).normalized() 50 | #print "bounds:", br 51 | return br 52 | 53 | def shape(self): ## No idea why this is necessary, but rotated items do not receive clicks otherwise. 54 | p = QtGui.QPainterPath() 55 | p.addRect(self.boundingRect()) 56 | #print "shape:", p.boundingRect() 57 | return p 58 | 59 | 60 | -------------------------------------------------------------------------------- /controllers/blending.py: -------------------------------------------------------------------------------- 1 | # 2 | # (c) PySimiam Team 2013 3 | # 4 | # Contact person: Tim Fuchs 5 | # 6 | # This class was implemented for the weekly programming excercises 7 | # of the 'Control of Mobile Robots' course by Magnus Egerstedt. 8 | # 9 | from controllers.pid_controller import PIDController 10 | from controllers.avoidobstacles import AvoidObstacles 11 | from controllers.followpath import FollowPath 12 | import controllers.followpath 13 | 14 | import math 15 | import numpy 16 | 17 | class Blending(FollowPath, AvoidObstacles): 18 | """A controller blending go-to-goal and avoid-obstacles behaviour""" 19 | def __init__(self, params): 20 | """Initialize internal variables""" 21 | PIDController.__init__(self,params) 22 | #self.params = params 23 | # These two angles are used by the supervisor 24 | # to debug the controller's behaviour, and contain 25 | # the headings as returned by the two subcontrollers. 26 | self.goal_angle = 0 27 | self.away_angle = 0 28 | 29 | def set_parameters(self, params): 30 | """Set PID values and sensor poses. 31 | 32 | The params structure is expected to have sensor poses in the robot's 33 | reference frame as ``params.sensor_poses``. 34 | """ 35 | AvoidObstacles.set_parameters(self,params) 36 | 37 | def get_heading_angle(self, state): 38 | return PIDController.get_heading_angle(self,state) 39 | 40 | def get_heading(self, state): 41 | """Blend the two heading vectors""" 42 | 43 | # Get the outputs of the two subcontrollers 44 | u_ao = AvoidObstacles.get_heading(self,state) 45 | self.away_angle = math.atan2(u_ao[1],u_ao[0]) 46 | u_ao = numpy.array([math.cos(self.away_angle),math.sin(self.away_angle),1]) 47 | 48 | self.goal_angle = FollowPath.get_heading_angle(self,state) 49 | u_gtg = numpy.array([math.cos(self.goal_angle),math.sin(self.goal_angle),1]) 50 | 51 | # Week 5 Assigment Code goes here: 52 | a = 0.9 53 | u = u_gtg * (1 - a) + a * u_ao 54 | 55 | # End Week 5 Assigment 56 | 57 | return u 58 | 59 | def execute(self, state, dt): 60 | 61 | v, w = PIDController.execute(self, state, dt) 62 | 63 | # Week 5 Assigment Code goes here: 64 | # End Week 5 Assigment 65 | 66 | return v, w -------------------------------------------------------------------------------- /gui/pyqtgraph/canvas/CanvasManager.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from pyqtgraph.Qt import QtCore, QtGui 3 | if not hasattr(QtCore, 'Signal'): 4 | QtCore.Signal = QtCore.pyqtSignal 5 | import weakref 6 | 7 | class CanvasManager(QtCore.QObject): 8 | SINGLETON = None 9 | 10 | sigCanvasListChanged = QtCore.Signal() 11 | 12 | def __init__(self): 13 | if CanvasManager.SINGLETON is not None: 14 | raise Exception("Can only create one canvas manager.") 15 | CanvasManager.SINGLETON = self 16 | QtCore.QObject.__init__(self) 17 | self.canvases = weakref.WeakValueDictionary() 18 | 19 | @classmethod 20 | def instance(cls): 21 | return CanvasManager.SINGLETON 22 | 23 | def registerCanvas(self, canvas, name): 24 | n2 = name 25 | i = 0 26 | while n2 in self.canvases: 27 | n2 = "%s_%03d" % (name, i) 28 | i += 1 29 | self.canvases[n2] = canvas 30 | self.sigCanvasListChanged.emit() 31 | return n2 32 | 33 | def unregisterCanvas(self, name): 34 | c = self.canvases[name] 35 | del self.canvases[name] 36 | self.sigCanvasListChanged.emit() 37 | 38 | def listCanvases(self): 39 | return list(self.canvases.keys()) 40 | 41 | def getCanvas(self, name): 42 | return self.canvases[name] 43 | 44 | 45 | manager = CanvasManager() 46 | 47 | 48 | class CanvasCombo(QtGui.QComboBox): 49 | def __init__(self, parent=None): 50 | QtGui.QComboBox.__init__(self, parent) 51 | man = CanvasManager.instance() 52 | man.sigCanvasListChanged.connect(self.updateCanvasList) 53 | self.hostName = None 54 | self.updateCanvasList() 55 | 56 | def updateCanvasList(self): 57 | canvases = CanvasManager.instance().listCanvases() 58 | canvases.insert(0, "") 59 | if self.hostName in canvases: 60 | canvases.remove(self.hostName) 61 | 62 | sel = self.currentText() 63 | if sel in canvases: 64 | self.blockSignals(True) ## change does not affect current selection; block signals during update 65 | self.clear() 66 | for i in canvases: 67 | self.addItem(i) 68 | if i == sel: 69 | self.setCurrentIndex(self.count()) 70 | 71 | self.blockSignals(False) 72 | 73 | def setHostName(self, name): 74 | self.hostName = name 75 | self.updateCanvasList() 76 | 77 | -------------------------------------------------------------------------------- /gui/pyqtgraph/flowchart/library/Operators.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from ..Node import Node 3 | 4 | class UniOpNode(Node): 5 | """Generic node for performing any operation like Out = In.fn()""" 6 | def __init__(self, name, fn): 7 | self.fn = fn 8 | Node.__init__(self, name, terminals={ 9 | 'In': {'io': 'in'}, 10 | 'Out': {'io': 'out', 'bypass': 'In'} 11 | }) 12 | 13 | def process(self, **args): 14 | return {'Out': getattr(args['In'], self.fn)()} 15 | 16 | class BinOpNode(Node): 17 | """Generic node for performing any operation like A.fn(B)""" 18 | def __init__(self, name, fn): 19 | self.fn = fn 20 | Node.__init__(self, name, terminals={ 21 | 'A': {'io': 'in'}, 22 | 'B': {'io': 'in'}, 23 | 'Out': {'io': 'out', 'bypass': 'A'} 24 | }) 25 | 26 | def process(self, **args): 27 | if isinstance(self.fn, tuple): 28 | for name in self.fn: 29 | try: 30 | fn = getattr(args['A'], name) 31 | break 32 | except AttributeError: 33 | pass 34 | else: 35 | fn = getattr(args['A'], self.fn) 36 | out = fn(args['B']) 37 | if out is NotImplemented: 38 | raise Exception("Operation %s not implemented between %s and %s" % (fn, str(type(args['A'])), str(type(args['B'])))) 39 | #print " ", fn, out 40 | return {'Out': out} 41 | 42 | 43 | class AbsNode(UniOpNode): 44 | """Returns abs(Inp). Does not check input types.""" 45 | nodeName = 'Abs' 46 | def __init__(self, name): 47 | UniOpNode.__init__(self, name, '__abs__') 48 | 49 | class AddNode(BinOpNode): 50 | """Returns A + B. Does not check input types.""" 51 | nodeName = 'Add' 52 | def __init__(self, name): 53 | BinOpNode.__init__(self, name, '__add__') 54 | 55 | class SubtractNode(BinOpNode): 56 | """Returns A - B. Does not check input types.""" 57 | nodeName = 'Subtract' 58 | def __init__(self, name): 59 | BinOpNode.__init__(self, name, '__sub__') 60 | 61 | class MultiplyNode(BinOpNode): 62 | """Returns A * B. Does not check input types.""" 63 | nodeName = 'Multiply' 64 | def __init__(self, name): 65 | BinOpNode.__init__(self, name, '__mul__') 66 | 67 | class DivideNode(BinOpNode): 68 | """Returns A / B. Does not check input types.""" 69 | nodeName = 'Divide' 70 | def __init__(self, name): 71 | # try truediv first, followed by div 72 | BinOpNode.__init__(self, name, ('__truediv__', '__div__')) 73 | 74 | 75 | -------------------------------------------------------------------------------- /gui/pyqtgraph/flowchart/FlowchartTemplate.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form 4 | 5 | 6 | 7 | 0 8 | 0 9 | 529 10 | 329 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 260 20 | 10 21 | 264 22 | 222 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop 33 | 34 | 35 | true 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 75 44 | true 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 1 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 0 67 | 240 68 | 521 69 | 81 70 | 71 | 72 | 73 | 74 | 75 | 76 | 0 77 | 0 78 | 256 79 | 192 80 | 81 | 82 | 83 | 84 | 85 | 86 | DataTreeWidget 87 | QTreeWidget 88 |
pyqtgraph.widgets.DataTreeWidget
89 |
90 | 91 | FlowchartGraphicsView 92 | QGraphicsView 93 |
pyqtgraph.flowchart.FlowchartGraphicsView
94 |
95 |
96 | 97 | 98 |
99 | -------------------------------------------------------------------------------- /controllers/genetic_algorithm(not included).py: -------------------------------------------------------------------------------- 1 | from random import randint 2 | def individual (length, min, max): 3 | 'Create a member of the population' 4 | return [ randint(min,max) for x in xrange(length) ] 5 | 6 | def population(count, length, min, max): 7 | """ 8 | Create a number of individuals (i.e. a population). 9 | 10 | count: the number of individuals in the population 11 | length: the number of values per individual 12 | min: the min possible value in an individual's list of values 13 | max: the max possible value in an individual's list of values 14 | 15 | """ 16 | return [ individual(length, min, max) for x in xrange(count) ] 17 | 18 | from operator import add 19 | def fitness(individual, target): 20 | """ 21 | Determine the fitness of an individual. Lower is better. 22 | 23 | individual: the individual to evaluate 24 | target: the sum of numbers that individuals are aiming for 25 | """ 26 | sum = reduce(add, individual, 0) 27 | return abs(target-sum) 28 | 29 | def grade(pop, target): 30 | 'Find average fitness for a population.' 31 | summed = reduce(add, (fitness(x, target) for x in pop), 0) 32 | return summed / (len(pop) * 1.0) 33 | 34 | # evolution operations 35 | def evolve(pop, target, retain=0.2, random_select=0.05, mutate=0.01): 36 | graded = [ (fitness(x, target), x) for x in pop] 37 | graded = [ x[1] for x in sorted(graded)] 38 | retain_length = int(len(graded)*retain) 39 | parents = graded[:retain_length] 40 | 41 | # randomly add other individuals to promote genetic diversity 42 | for individual in graded[retain_length:]: 43 | if random_select > random(): 44 | parents.append(individual) 45 | 46 | # mutate some individuals 47 | for individual in parents: 48 | if mutate > random(): 49 | pos_to_mutate = randint(0, len(individual)-1) 50 | # this mutation is not ideal, because it 51 | # restricts the range of possible values, 52 | # but the function is unaware of the min/max 53 | # values used to create the individuals, 54 | individual[pos_to_mutate] = randint( 55 | min(individual), max(individual)) 56 | 57 | # crossover parents to create children 58 | parents_length = len(parents) 59 | desired_length = len(pop) - parents_length 60 | children = [] 61 | while len(children) < desired_length: 62 | male = randint(0, parents_length-1) 63 | female = randint(0, parents_length-1) 64 | if male != female: 65 | male = parents[male] 66 | female = parents[female] 67 | half = len(male) / 2 68 | child = male[:half] + female[half:] 69 | children.append(child) 70 | 71 | parents.extend(children) 72 | return parents -------------------------------------------------------------------------------- /gui/pyqtgraph/flowchart/FlowchartTemplate_pyqt.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file './flowchart/FlowchartTemplate.ui' 4 | # 5 | # Created: Sun Feb 24 19:47:29 2013 6 | # by: PyQt4 UI code generator 4.9.3 7 | # 8 | # WARNING! All changes made in this file will be lost! 9 | 10 | from PyQt4 import QtCore, QtGui 11 | 12 | try: 13 | _fromUtf8 = QtCore.QString.fromUtf8 14 | except AttributeError: 15 | _fromUtf8 = lambda s: s 16 | 17 | class Ui_Form(object): 18 | def setupUi(self, Form): 19 | Form.setObjectName(_fromUtf8("Form")) 20 | Form.resize(529, 329) 21 | self.selInfoWidget = QtGui.QWidget(Form) 22 | self.selInfoWidget.setGeometry(QtCore.QRect(260, 10, 264, 222)) 23 | self.selInfoWidget.setObjectName(_fromUtf8("selInfoWidget")) 24 | self.gridLayout = QtGui.QGridLayout(self.selInfoWidget) 25 | self.gridLayout.setMargin(0) 26 | self.gridLayout.setObjectName(_fromUtf8("gridLayout")) 27 | self.selDescLabel = QtGui.QLabel(self.selInfoWidget) 28 | self.selDescLabel.setText(_fromUtf8("")) 29 | self.selDescLabel.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) 30 | self.selDescLabel.setWordWrap(True) 31 | self.selDescLabel.setObjectName(_fromUtf8("selDescLabel")) 32 | self.gridLayout.addWidget(self.selDescLabel, 0, 0, 1, 1) 33 | self.selNameLabel = QtGui.QLabel(self.selInfoWidget) 34 | font = QtGui.QFont() 35 | font.setBold(True) 36 | font.setWeight(75) 37 | self.selNameLabel.setFont(font) 38 | self.selNameLabel.setText(_fromUtf8("")) 39 | self.selNameLabel.setObjectName(_fromUtf8("selNameLabel")) 40 | self.gridLayout.addWidget(self.selNameLabel, 0, 1, 1, 1) 41 | self.selectedTree = DataTreeWidget(self.selInfoWidget) 42 | self.selectedTree.setObjectName(_fromUtf8("selectedTree")) 43 | self.selectedTree.headerItem().setText(0, _fromUtf8("1")) 44 | self.gridLayout.addWidget(self.selectedTree, 1, 0, 1, 2) 45 | self.hoverText = QtGui.QTextEdit(Form) 46 | self.hoverText.setGeometry(QtCore.QRect(0, 240, 521, 81)) 47 | self.hoverText.setObjectName(_fromUtf8("hoverText")) 48 | self.view = FlowchartGraphicsView(Form) 49 | self.view.setGeometry(QtCore.QRect(0, 0, 256, 192)) 50 | self.view.setObjectName(_fromUtf8("view")) 51 | 52 | self.retranslateUi(Form) 53 | QtCore.QMetaObject.connectSlotsByName(Form) 54 | 55 | def retranslateUi(self, Form): 56 | Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8)) 57 | 58 | from pyqtgraph.widgets.DataTreeWidget import DataTreeWidget 59 | from pyqtgraph.flowchart.FlowchartGraphicsView import FlowchartGraphicsView 60 | -------------------------------------------------------------------------------- /gui/pyqtgraph/opengl/items/GLBoxItem.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | from .. GLGraphicsItem import GLGraphicsItem 3 | from pyqtgraph.Qt import QtGui 4 | import pyqtgraph as pg 5 | 6 | __all__ = ['GLBoxItem'] 7 | 8 | class GLBoxItem(GLGraphicsItem): 9 | """ 10 | **Bases:** :class:`GLGraphicsItem ` 11 | 12 | Displays a wire-frame box. 13 | """ 14 | def __init__(self, size=None, color=None, glOptions='translucent'): 15 | GLGraphicsItem.__init__(self) 16 | if size is None: 17 | size = QtGui.QVector3D(1,1,1) 18 | self.setSize(size=size) 19 | if color is None: 20 | color = (255,255,255,80) 21 | self.setColor(color) 22 | self.setGLOptions(glOptions) 23 | 24 | def setSize(self, x=None, y=None, z=None, size=None): 25 | """ 26 | Set the size of the box (in its local coordinate system; this does not affect the transform) 27 | Arguments can be x,y,z or size=QVector3D(). 28 | """ 29 | if size is not None: 30 | x = size.x() 31 | y = size.y() 32 | z = size.z() 33 | self.__size = [x,y,z] 34 | self.update() 35 | 36 | def size(self): 37 | return self.__size[:] 38 | 39 | def setColor(self, *args): 40 | """Set the color of the box. Arguments are the same as those accepted by functions.mkColor()""" 41 | self.__color = pg.Color(*args) 42 | 43 | def color(self): 44 | return self.__color 45 | 46 | def paint(self): 47 | #glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 48 | #glEnable( GL_BLEND ) 49 | #glEnable( GL_ALPHA_TEST ) 50 | ##glAlphaFunc( GL_ALWAYS,0.5 ) 51 | #glEnable( GL_POINT_SMOOTH ) 52 | #glDisable( GL_DEPTH_TEST ) 53 | self.setupGLState() 54 | 55 | glBegin( GL_LINES ) 56 | 57 | glColor4f(*self.color().glColor()) 58 | x,y,z = self.size() 59 | glVertex3f(0, 0, 0) 60 | glVertex3f(0, 0, z) 61 | glVertex3f(x, 0, 0) 62 | glVertex3f(x, 0, z) 63 | glVertex3f(0, y, 0) 64 | glVertex3f(0, y, z) 65 | glVertex3f(x, y, 0) 66 | glVertex3f(x, y, z) 67 | 68 | glVertex3f(0, 0, 0) 69 | glVertex3f(0, y, 0) 70 | glVertex3f(x, 0, 0) 71 | glVertex3f(x, y, 0) 72 | glVertex3f(0, 0, z) 73 | glVertex3f(0, y, z) 74 | glVertex3f(x, 0, z) 75 | glVertex3f(x, y, z) 76 | 77 | glVertex3f(0, 0, 0) 78 | glVertex3f(x, 0, 0) 79 | glVertex3f(0, y, 0) 80 | glVertex3f(x, y, 0) 81 | glVertex3f(0, 0, z) 82 | glVertex3f(x, 0, z) 83 | glVertex3f(0, y, z) 84 | glVertex3f(x, y, z) 85 | 86 | glEnd() 87 | 88 | -------------------------------------------------------------------------------- /gui/pyqtgraph/widgets/JoystickButton.py: -------------------------------------------------------------------------------- 1 | from pyqtgraph.Qt import QtGui, QtCore 2 | 3 | 4 | __all__ = ['JoystickButton'] 5 | 6 | class JoystickButton(QtGui.QPushButton): 7 | sigStateChanged = QtCore.Signal(object, object) ## self, state 8 | 9 | def __init__(self, parent=None): 10 | QtGui.QPushButton.__init__(self, parent) 11 | self.radius = 200 12 | self.setCheckable(True) 13 | self.state = None 14 | self.setState(0,0) 15 | self.setFixedWidth(50) 16 | self.setFixedHeight(50) 17 | 18 | 19 | def mousePressEvent(self, ev): 20 | self.setChecked(True) 21 | self.pressPos = ev.pos() 22 | ev.accept() 23 | 24 | def mouseMoveEvent(self, ev): 25 | dif = ev.pos()-self.pressPos 26 | self.setState(dif.x(), -dif.y()) 27 | 28 | def mouseReleaseEvent(self, ev): 29 | self.setChecked(False) 30 | self.setState(0,0) 31 | 32 | def wheelEvent(self, ev): 33 | ev.accept() 34 | 35 | 36 | def doubleClickEvent(self, ev): 37 | ev.accept() 38 | 39 | def getState(self): 40 | return self.state 41 | 42 | def setState(self, *xy): 43 | xy = list(xy) 44 | d = (xy[0]**2 + xy[1]**2)**0.5 45 | nxy = [0,0] 46 | for i in [0,1]: 47 | if xy[i] == 0: 48 | nxy[i] = 0 49 | else: 50 | nxy[i] = xy[i]/d 51 | 52 | if d > self.radius: 53 | d = self.radius 54 | d = (d/self.radius)**2 55 | xy = [nxy[0]*d, nxy[1]*d] 56 | 57 | w2 = self.width()/2. 58 | h2 = self.height()/2 59 | self.spotPos = QtCore.QPoint(w2*(1+xy[0]), h2*(1-xy[1])) 60 | self.update() 61 | if self.state == xy: 62 | return 63 | self.state = xy 64 | self.sigStateChanged.emit(self, self.state) 65 | 66 | def paintEvent(self, ev): 67 | QtGui.QPushButton.paintEvent(self, ev) 68 | p = QtGui.QPainter(self) 69 | p.setBrush(QtGui.QBrush(QtGui.QColor(0,0,0))) 70 | p.drawEllipse(self.spotPos.x()-3,self.spotPos.y()-3,6,6) 71 | 72 | def resizeEvent(self, ev): 73 | self.setState(*self.state) 74 | QtGui.QPushButton.resizeEvent(self, ev) 75 | 76 | 77 | 78 | if __name__ == '__main__': 79 | app = QtGui.QApplication([]) 80 | w = QtGui.QMainWindow() 81 | b = JoystickButton() 82 | w.setCentralWidget(b) 83 | w.show() 84 | w.resize(100, 100) 85 | 86 | def fn(b, s): 87 | print("state changed:", s) 88 | 89 | b.sigStateChanged.connect(fn) 90 | 91 | ## Start Qt event loop unless running in interactive mode. 92 | import sys 93 | if sys.flags.interactive != 1: 94 | app.exec_() 95 | -------------------------------------------------------------------------------- /gui/pyqtgraph/graphicsWindows.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | graphicsWindows.py - Convenience classes which create a new window with PlotWidget or ImageView. 4 | Copyright 2010 Luke Campagnola 5 | Distributed under MIT/X11 license. See license.txt for more infomation. 6 | """ 7 | 8 | from .Qt import QtCore, QtGui 9 | from .widgets.PlotWidget import * 10 | from .imageview import * 11 | from .widgets.GraphicsLayoutWidget import GraphicsLayoutWidget 12 | from .widgets.GraphicsView import GraphicsView 13 | QAPP = None 14 | 15 | def mkQApp(): 16 | if QtGui.QApplication.instance() is None: 17 | global QAPP 18 | QAPP = QtGui.QApplication([]) 19 | 20 | 21 | class GraphicsWindow(GraphicsLayoutWidget): 22 | def __init__(self, title=None, size=(800,600), **kargs): 23 | mkQApp() 24 | #self.win = QtGui.QMainWindow() 25 | GraphicsLayoutWidget.__init__(self, **kargs) 26 | #self.win.setCentralWidget(self) 27 | self.resize(*size) 28 | if title is not None: 29 | self.setWindowTitle(title) 30 | self.show() 31 | 32 | 33 | class TabWindow(QtGui.QMainWindow): 34 | def __init__(self, title=None, size=(800,600)): 35 | mkQApp() 36 | QtGui.QMainWindow.__init__(self) 37 | self.resize(*size) 38 | self.cw = QtGui.QTabWidget() 39 | self.setCentralWidget(self.cw) 40 | if title is not None: 41 | self.setWindowTitle(title) 42 | self.show() 43 | 44 | def __getattr__(self, attr): 45 | if hasattr(self.cw, attr): 46 | return getattr(self.cw, attr) 47 | else: 48 | raise NameError(attr) 49 | 50 | 51 | class PlotWindow(PlotWidget): 52 | def __init__(self, title=None, **kargs): 53 | mkQApp() 54 | self.win = QtGui.QMainWindow() 55 | PlotWidget.__init__(self, **kargs) 56 | self.win.setCentralWidget(self) 57 | for m in ['resize']: 58 | setattr(self, m, getattr(self.win, m)) 59 | if title is not None: 60 | self.win.setWindowTitle(title) 61 | self.win.show() 62 | 63 | 64 | class ImageWindow(ImageView): 65 | def __init__(self, *args, **kargs): 66 | mkQApp() 67 | self.win = QtGui.QMainWindow() 68 | self.win.resize(800,600) 69 | if 'title' in kargs: 70 | self.win.setWindowTitle(kargs['title']) 71 | del kargs['title'] 72 | ImageView.__init__(self, self.win) 73 | if len(args) > 0 or len(kargs) > 0: 74 | self.setImage(*args, **kargs) 75 | self.win.setCentralWidget(self) 76 | for m in ['resize']: 77 | setattr(self, m, getattr(self.win, m)) 78 | #for m in ['setImage', 'autoRange', 'addItem', 'removeItem', 'blackLevel', 'whiteLevel', 'imageItem']: 79 | #setattr(self, m, getattr(self.cw, m)) 80 | self.win.show() 81 | -------------------------------------------------------------------------------- /gui/pyqtgraph/exporters/PrintExporter.py: -------------------------------------------------------------------------------- 1 | from .Exporter import Exporter 2 | from pyqtgraph.parametertree import Parameter 3 | from pyqtgraph.Qt import QtGui, QtCore, QtSvg 4 | import re 5 | 6 | __all__ = ['PrintExporter'] 7 | #__all__ = [] ## Printer is disabled for now--does not work very well. 8 | 9 | class PrintExporter(Exporter): 10 | Name = "Printer" 11 | def __init__(self, item): 12 | Exporter.__init__(self, item) 13 | tr = self.getTargetRect() 14 | self.params = Parameter(name='params', type='group', children=[ 15 | {'name': 'width', 'type': 'float', 'value': 0.1, 'limits': (0, None), 'suffix': 'm', 'siPrefix': True}, 16 | {'name': 'height', 'type': 'float', 'value': (0.1 * tr.height()) / tr.width(), 'limits': (0, None), 'suffix': 'm', 'siPrefix': True}, 17 | ]) 18 | self.params.param('width').sigValueChanged.connect(self.widthChanged) 19 | self.params.param('height').sigValueChanged.connect(self.heightChanged) 20 | 21 | def widthChanged(self): 22 | sr = self.getSourceRect() 23 | ar = sr.height() / sr.width() 24 | self.params.param('height').setValue(self.params['width'] * ar, blockSignal=self.heightChanged) 25 | 26 | def heightChanged(self): 27 | sr = self.getSourceRect() 28 | ar = sr.width() / sr.height() 29 | self.params.param('width').setValue(self.params['height'] * ar, blockSignal=self.widthChanged) 30 | 31 | def parameters(self): 32 | return self.params 33 | 34 | def export(self, fileName=None): 35 | printer = QtGui.QPrinter(QtGui.QPrinter.HighResolution) 36 | dialog = QtGui.QPrintDialog(printer) 37 | dialog.setWindowTitle("Print Document") 38 | if dialog.exec_() != QtGui.QDialog.Accepted: 39 | return; 40 | 41 | #dpi = QtGui.QDesktopWidget().physicalDpiX() 42 | 43 | #self.svg.setSize(QtCore.QSize(100,100)) 44 | #self.svg.setResolution(600) 45 | #res = printer.resolution() 46 | sr = self.getSourceRect() 47 | #res = sr.width() * .4 / (self.params['width'] * 100 / 2.54) 48 | res = QtGui.QDesktopWidget().physicalDpiX() 49 | printer.setResolution(res) 50 | rect = printer.pageRect() 51 | center = rect.center() 52 | h = self.params['height'] * res * 100. / 2.54 53 | w = self.params['width'] * res * 100. / 2.54 54 | x = center.x() - w/2. 55 | y = center.y() - h/2. 56 | 57 | targetRect = QtCore.QRect(x, y, w, h) 58 | sourceRect = self.getSourceRect() 59 | painter = QtGui.QPainter(printer) 60 | try: 61 | self.setExportMode(True, {'painter': painter}) 62 | self.getScene().render(painter, QtCore.QRectF(targetRect), QtCore.QRectF(sourceRect)) 63 | finally: 64 | self.setExportMode(False) 65 | painter.end() 66 | -------------------------------------------------------------------------------- /gui/pyqtgraph/graphicsItems/tests/ViewBox.py: -------------------------------------------------------------------------------- 1 | """ 2 | ViewBox test cases: 3 | 4 | * call setRange then resize; requested range must be fully visible 5 | * lockAspect works correctly for arbitrary aspect ratio 6 | * autoRange works correctly with aspect locked 7 | * call setRange with aspect locked, then resize 8 | * AutoRange with all the bells and whistles 9 | * item moves / changes transformation / changes bounds 10 | * pan only 11 | * fractional range 12 | 13 | 14 | """ 15 | 16 | import pyqtgraph as pg 17 | app = pg.mkQApp() 18 | 19 | imgData = pg.np.zeros((10, 10)) 20 | imgData[0] = 3 21 | imgData[-1] = 3 22 | imgData[:,0] = 3 23 | imgData[:,-1] = 3 24 | 25 | def testLinkWithAspectLock(): 26 | global win, vb 27 | win = pg.GraphicsWindow() 28 | vb = win.addViewBox(name="image view") 29 | vb.setAspectLocked() 30 | vb.enableAutoRange(x=False, y=False) 31 | p1 = win.addPlot(name="plot 1") 32 | p2 = win.addPlot(name="plot 2", row=1, col=0) 33 | win.ci.layout.setRowFixedHeight(1, 150) 34 | win.ci.layout.setColumnFixedWidth(1, 150) 35 | 36 | def viewsMatch(): 37 | r0 = pg.np.array(vb.viewRange()) 38 | r1 = pg.np.array(p1.vb.viewRange()[1]) 39 | r2 = pg.np.array(p2.vb.viewRange()[1]) 40 | match = (abs(r0[1]-r1) <= (abs(r1) * 0.001)).all() and (abs(r0[0]-r2) <= (abs(r2) * 0.001)).all() 41 | return match 42 | 43 | p1.setYLink(vb) 44 | p2.setXLink(vb) 45 | print "link views match:", viewsMatch() 46 | win.show() 47 | print "show views match:", viewsMatch() 48 | img = pg.ImageItem(imgData) 49 | vb.addItem(img) 50 | vb.autoRange() 51 | p1.plot(x=imgData.sum(axis=0), y=range(10)) 52 | p2.plot(x=range(10), y=imgData.sum(axis=1)) 53 | print "add items views match:", viewsMatch() 54 | #p1.setAspectLocked() 55 | #grid = pg.GridItem() 56 | #vb.addItem(grid) 57 | pg.QtGui.QApplication.processEvents() 58 | pg.QtGui.QApplication.processEvents() 59 | #win.resize(801, 600) 60 | 61 | def testAspectLock(): 62 | global win, vb 63 | win = pg.GraphicsWindow() 64 | vb = win.addViewBox(name="image view") 65 | vb.setAspectLocked() 66 | img = pg.ImageItem(imgData) 67 | vb.addItem(img) 68 | 69 | 70 | #app.processEvents() 71 | #print "init views match:", viewsMatch() 72 | #p2.setYRange(-300, 300) 73 | #print "setRange views match:", viewsMatch() 74 | #app.processEvents() 75 | #print "setRange views match (after update):", viewsMatch() 76 | 77 | #print "--lock aspect--" 78 | #p1.setAspectLocked(True) 79 | #print "lockAspect views match:", viewsMatch() 80 | #p2.setYRange(-200, 200) 81 | #print "setRange views match:", viewsMatch() 82 | #app.processEvents() 83 | #print "setRange views match (after update):", viewsMatch() 84 | 85 | #win.resize(100, 600) 86 | #app.processEvents() 87 | #vb.setRange(xRange=[-10, 10], padding=0) 88 | #app.processEvents() 89 | #win.resize(600, 100) 90 | #app.processEvents() 91 | #print vb.viewRange() 92 | 93 | 94 | if __name__ == '__main__': 95 | testLinkWithAspectLock() 96 | -------------------------------------------------------------------------------- /gui/pyqtgraph/exporters/Matplotlib.py: -------------------------------------------------------------------------------- 1 | import pyqtgraph as pg 2 | from pyqtgraph.Qt import QtGui, QtCore 3 | from .Exporter import Exporter 4 | 5 | 6 | __all__ = ['MatplotlibExporter'] 7 | 8 | 9 | class MatplotlibExporter(Exporter): 10 | Name = "Matplotlib Window" 11 | windows = [] 12 | def __init__(self, item): 13 | Exporter.__init__(self, item) 14 | 15 | def parameters(self): 16 | return None 17 | 18 | def export(self, fileName=None): 19 | 20 | if isinstance(self.item, pg.PlotItem): 21 | mpw = MatplotlibWindow() 22 | MatplotlibExporter.windows.append(mpw) 23 | fig = mpw.getFigure() 24 | 25 | ax = fig.add_subplot(111) 26 | ax.clear() 27 | #ax.grid(True) 28 | 29 | for item in self.item.curves: 30 | x, y = item.getData() 31 | opts = item.opts 32 | pen = pg.mkPen(opts['pen']) 33 | if pen.style() == QtCore.Qt.NoPen: 34 | linestyle = '' 35 | else: 36 | linestyle = '-' 37 | color = tuple([c/255. for c in pg.colorTuple(pen.color())]) 38 | symbol = opts['symbol'] 39 | if symbol == 't': 40 | symbol = '^' 41 | symbolPen = pg.mkPen(opts['symbolPen']) 42 | symbolBrush = pg.mkBrush(opts['symbolBrush']) 43 | markeredgecolor = tuple([c/255. for c in pg.colorTuple(symbolPen.color())]) 44 | markerfacecolor = tuple([c/255. for c in pg.colorTuple(symbolBrush.color())]) 45 | 46 | if opts['fillLevel'] is not None and opts['fillBrush'] is not None: 47 | fillBrush = pg.mkBrush(opts['fillBrush']) 48 | fillcolor = tuple([c/255. for c in pg.colorTuple(fillBrush.color())]) 49 | ax.fill_between(x=x, y1=y, y2=opts['fillLevel'], facecolor=fillcolor) 50 | 51 | ax.plot(x, y, marker=symbol, color=color, linewidth=pen.width(), linestyle=linestyle, markeredgecolor=markeredgecolor, markerfacecolor=markerfacecolor) 52 | 53 | xr, yr = self.item.viewRange() 54 | ax.set_xbound(*xr) 55 | ax.set_ybound(*yr) 56 | mpw.draw() 57 | else: 58 | raise Exception("Matplotlib export currently only works with plot items") 59 | 60 | 61 | 62 | class MatplotlibWindow(QtGui.QMainWindow): 63 | def __init__(self): 64 | import pyqtgraph.widgets.MatplotlibWidget 65 | QtGui.QMainWindow.__init__(self) 66 | self.mpl = pyqtgraph.widgets.MatplotlibWidget.MatplotlibWidget() 67 | self.setCentralWidget(self.mpl) 68 | self.show() 69 | 70 | def __getattr__(self, attr): 71 | return getattr(self.mpl, attr) 72 | 73 | def closeEvent(self, ev): 74 | MatplotlibExporter.windows.remove(self) 75 | -------------------------------------------------------------------------------- /gui/pyqtgraph/GraphicsScene/exportDialogTemplate.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form 4 | 5 | 6 | 7 | 0 8 | 0 9 | 241 10 | 367 11 | 12 | 13 | 14 | Export 15 | 16 | 17 | 18 | 0 19 | 20 | 21 | 22 | 23 | Item to export: 24 | 25 | 26 | 27 | 28 | 29 | 30 | false 31 | 32 | 33 | 34 | 1 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | Export format 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | Export 53 | 54 | 55 | 56 | 57 | 58 | 59 | Close 60 | 61 | 62 | 63 | 64 | 65 | 66 | false 67 | 68 | 69 | 70 | 1 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | Export options 79 | 80 | 81 | 82 | 83 | 84 | 85 | Copy 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | ParameterTree 94 | QTreeWidget 95 |
pyqtgraph.parametertree
96 |
97 |
98 | 99 | 100 |
101 | -------------------------------------------------------------------------------- /scripts/robot.py: -------------------------------------------------------------------------------- 1 | from simobject import SimObject 2 | 3 | class Robot(SimObject): 4 | """The robot is a :class:`~simobject.SimObject` that implements drawing 5 | and information functions to interface with supervisor. 6 | 7 | This class is not intended to be subclassed in user code. Use one 8 | of the provided subclasses instead: :class:`~robot.SimBot` for emulated robots 9 | or :class:`~robot.RealBot` for physical robots. 10 | """ 11 | 12 | def get_info(self): 13 | """Return the robot information structure, including sensor readings and 14 | shape information""" 15 | raise NotImplementedError("Robot.get_info") 16 | 17 | def set_inputs(self,inputs): 18 | """Set drive inputs in the format needed by this robot""" 19 | pass 20 | 21 | def draw_sensors(self,renderer): 22 | """Draw the sensors that this robot has""" 23 | pass 24 | 25 | def set_logqueue(self,logqueue): 26 | self.logqueue = logqueue 27 | 28 | def log(self, message): 29 | print("{}: {}".format(self.__class__.__name__,message)) 30 | if self.logqueue is not None: 31 | self.logqueue.append((self,message)) 32 | 33 | class SimBot(Robot): 34 | """The robot defined by this class is a simulated robot, and implements 35 | its own motion in :meth:`~robot.SimBot.move`. 36 | 37 | To implement a new type of robot, subclass :class:`SimBot` and implement 38 | :meth:`~robot.Robot.get_info` and :meth:`~robot.SimBot.get_external_sensors`. 39 | 40 | To make your robot move, implement :meth:`~robot.SimBot.move`. 41 | 42 | To make you robot controllable, implement :meth:`~robot.Robot.set_inputs`. 43 | 44 | If your robot has sensors that can be drawn in the view, implement 45 | :meth:`~robot.Robot.draw_sensors`. 46 | """ 47 | 48 | def move(self,dt): 49 | """Move the robot for a time interval `dt`.""" 50 | pass 51 | 52 | def get_external_sensors(self): 53 | """Get the external sensors of the robot as a list. 54 | This function is used to update the sensor readings in proximity 55 | sensors.""" 56 | raise NotImplementedError("SimBot.get_external_sensors") 57 | 58 | class RealBot(Robot): 59 | """This type of robots implements communication with a real-world robot. 60 | 61 | Although this is a SimObject, it doesn't move by itself. 62 | Use :meth:`~simobject.SimObject.set_pose()` to move the robot. 63 | """ 64 | 65 | def update_external_info(self): 66 | """Initiate communication with the real robot and get state info back. 67 | """ 68 | raise NotImplementedError("RealBot.update_external_info") 69 | 70 | def pause(self): 71 | """Stops the robot, saving the state""" 72 | raise NotImplementedError("RealBot.pause") 73 | 74 | def resume(self): 75 | """Restarts the robot from the saved state""" 76 | raise NotImplementedError("RealBot.resume") 77 | -------------------------------------------------------------------------------- /gui/pyqtgraph/widgets/ValueLabel.py: -------------------------------------------------------------------------------- 1 | from pyqtgraph.Qt import QtCore, QtGui 2 | from pyqtgraph.ptime import time 3 | import pyqtgraph as pg 4 | from functools import reduce 5 | 6 | __all__ = ['ValueLabel'] 7 | 8 | class ValueLabel(QtGui.QLabel): 9 | """ 10 | QLabel specifically for displaying numerical values. 11 | Extends QLabel adding some extra functionality: 12 | 13 | - displaying units with si prefix 14 | - built-in exponential averaging 15 | """ 16 | 17 | def __init__(self, parent=None, suffix='', siPrefix=False, averageTime=0, formatStr=None): 18 | """ 19 | ============ ================================================================================== 20 | Arguments 21 | suffix (str or None) The suffix to place after the value 22 | siPrefix (bool) Whether to add an SI prefix to the units and display a scaled value 23 | averageTime (float) The length of time in seconds to average values. If this value 24 | is 0, then no averaging is performed. As this value increases 25 | the display value will appear to change more slowly and smoothly. 26 | formatStr (str) Optionally, provide a format string to use when displaying text. The text 27 | will be generated by calling formatStr.format(value=, avgValue=, suffix=) 28 | (see Python documentation on str.format) 29 | This option is not compatible with siPrefix 30 | ============ ================================================================================== 31 | """ 32 | QtGui.QLabel.__init__(self, parent) 33 | self.values = [] 34 | self.averageTime = averageTime ## no averaging by default 35 | self.suffix = suffix 36 | self.siPrefix = siPrefix 37 | if formatStr is None: 38 | formatStr = '{avgValue:0.2g} {suffix}' 39 | self.formatStr = formatStr 40 | 41 | def setValue(self, value): 42 | now = time() 43 | self.values.append((now, value)) 44 | cutoff = now - self.averageTime 45 | while len(self.values) > 0 and self.values[0][0] < cutoff: 46 | self.values.pop(0) 47 | self.update() 48 | 49 | def setFormatStr(self, text): 50 | self.formatStr = text 51 | self.update() 52 | 53 | def setAverageTime(self, t): 54 | self.averageTime = t 55 | 56 | def averageValue(self): 57 | return reduce(lambda a,b: a+b, [v[1] for v in self.values]) / float(len(self.values)) 58 | 59 | 60 | def paintEvent(self, ev): 61 | self.setText(self.generateText()) 62 | return QtGui.QLabel.paintEvent(self, ev) 63 | 64 | def generateText(self): 65 | if len(self.values) == 0: 66 | return '' 67 | avg = self.averageValue() 68 | val = self.values[-1][1] 69 | if self.siPrefix: 70 | return pg.siFormat(avg, suffix=self.suffix) 71 | else: 72 | return self.formatStr.format(value=val, avgValue=avg, suffix=self.suffix) 73 | 74 | -------------------------------------------------------------------------------- /controllers/followwall.py: -------------------------------------------------------------------------------- 1 | # 2 | # (c) PySimiam Team 2013 3 | # 4 | # Contact person: Tim Fuchs 5 | # 6 | # This class was implemented for the weekly programming excercises 7 | # of the 'Control of Mobile Robots' course by Magnus Egerstedt. 8 | # 9 | from controllers.pid_controller import PIDController 10 | import math 11 | import numpy 12 | from pose import Pose 13 | 14 | class FollowWall(PIDController): 15 | """Follow walls is a controller that keeps a certain distance 16 | to the wall and drives alongside it in clockwise or counter-clockwise 17 | fashion.""" 18 | def __init__(self, params): 19 | '''Initialize internal variables''' 20 | PIDController.__init__(self,params) 21 | 22 | def set_parameters(self, params): 23 | """Set PID values, sensor poses, direction and distance. 24 | 25 | The params structure is expected to have sensor poses in the robot's 26 | reference frame as ``params.sensor_poses``, the direction of wall 27 | following (either 'right' for clockwise or 'left' for anticlockwise) 28 | as ``params.direction`` and the desired distance to the wall 29 | to maintain as ``params.distance``. 30 | """ 31 | PIDController.set_parameters(self,params) 32 | 33 | self.sensor_poses = params.sensor_poses 34 | self.direction = params.direction 35 | self.distance = params.distance 36 | 37 | def get_heading(self, state): 38 | """Get the direction along the wall as a vector.""" 39 | 40 | # Calculate vectors for the sensors 41 | if state.direction == 'left': # 0-2 42 | d, i = min( zip(state.sensor_distances[:3],[0,1,2]) ) 43 | if i == 0 or (i == 1 and state.sensor_distances[0] <= state.sensor_distances[2]): 44 | i, j, k = 1, 0, 2 45 | 46 | else: 47 | i, j, k = 2, 1, 0 48 | 49 | else : # 2-4 50 | d, i = min( zip(state.sensor_distances[2:],[2,3,4]) ) 51 | if i == 4 or (i == 3 and state.sensor_distances[4] <= state.sensor_distances[2]): 52 | i, j, k = 3, 4, 2 53 | else: 54 | i, j, k = 2, 3, 4 55 | 56 | p_front = Pose(state.sensor_distances[i]) >> self.sensor_poses[i] 57 | p_back = Pose(state.sensor_distances[j]) >> self.sensor_poses[j] 58 | 59 | self.vectors = [(p_front.x,p_front.y,1), (p_back.x, p_back.y, 1)] 60 | 61 | # Calculate the two vectors: 62 | ds = ((p_front.x-p_back.x)**2 + (p_front.y-p_back.y)**2) 63 | ms = (p_front.x*p_back.y - p_front.y*p_back.x) 64 | self.to_wall_vector = numpy.array([(p_back.y-p_front.y)*ms/ds,(p_front.x-p_back.x)*ms/ds,1]) 65 | self.along_wall_vector = numpy.array([p_front.x-p_back.x, p_front.y-p_back.y, 1]) 66 | 67 | # Calculate and return the heading vector: 68 | offset = abs(ms/math.sqrt(ds)) - state.distance 69 | if offset > 0: 70 | return 0.3*self.along_wall_vector + 2 * offset * self.to_wall_vector 71 | else: 72 | return 0.3*self.along_wall_vector + 3 * offset * self.to_wall_vector 73 | 74 | -------------------------------------------------------------------------------- /gui/pyqtgraph/canvas/TransformGuiTemplate_pyqt.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file './canvas/TransformGuiTemplate.ui' 4 | # 5 | # Created: Sun Sep 9 14:41:30 2012 6 | # by: PyQt4 UI code generator 4.9.1 7 | # 8 | # WARNING! All changes made in this file will be lost! 9 | 10 | from PyQt4 import QtCore, QtGui 11 | 12 | try: 13 | _fromUtf8 = QtCore.QString.fromUtf8 14 | except AttributeError: 15 | _fromUtf8 = lambda s: s 16 | 17 | class Ui_Form(object): 18 | def setupUi(self, Form): 19 | Form.setObjectName(_fromUtf8("Form")) 20 | Form.resize(224, 117) 21 | sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) 22 | sizePolicy.setHorizontalStretch(0) 23 | sizePolicy.setVerticalStretch(0) 24 | sizePolicy.setHeightForWidth(Form.sizePolicy().hasHeightForWidth()) 25 | Form.setSizePolicy(sizePolicy) 26 | self.verticalLayout = QtGui.QVBoxLayout(Form) 27 | self.verticalLayout.setSpacing(1) 28 | self.verticalLayout.setMargin(0) 29 | self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) 30 | self.translateLabel = QtGui.QLabel(Form) 31 | self.translateLabel.setObjectName(_fromUtf8("translateLabel")) 32 | self.verticalLayout.addWidget(self.translateLabel) 33 | self.rotateLabel = QtGui.QLabel(Form) 34 | self.rotateLabel.setObjectName(_fromUtf8("rotateLabel")) 35 | self.verticalLayout.addWidget(self.rotateLabel) 36 | self.scaleLabel = QtGui.QLabel(Form) 37 | self.scaleLabel.setObjectName(_fromUtf8("scaleLabel")) 38 | self.verticalLayout.addWidget(self.scaleLabel) 39 | self.horizontalLayout = QtGui.QHBoxLayout() 40 | self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) 41 | self.mirrorImageBtn = QtGui.QPushButton(Form) 42 | self.mirrorImageBtn.setToolTip(_fromUtf8("")) 43 | self.mirrorImageBtn.setObjectName(_fromUtf8("mirrorImageBtn")) 44 | self.horizontalLayout.addWidget(self.mirrorImageBtn) 45 | self.reflectImageBtn = QtGui.QPushButton(Form) 46 | self.reflectImageBtn.setObjectName(_fromUtf8("reflectImageBtn")) 47 | self.horizontalLayout.addWidget(self.reflectImageBtn) 48 | self.verticalLayout.addLayout(self.horizontalLayout) 49 | 50 | self.retranslateUi(Form) 51 | QtCore.QMetaObject.connectSlotsByName(Form) 52 | 53 | def retranslateUi(self, Form): 54 | Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8)) 55 | self.translateLabel.setText(QtGui.QApplication.translate("Form", "Translate:", None, QtGui.QApplication.UnicodeUTF8)) 56 | self.rotateLabel.setText(QtGui.QApplication.translate("Form", "Rotate:", None, QtGui.QApplication.UnicodeUTF8)) 57 | self.scaleLabel.setText(QtGui.QApplication.translate("Form", "Scale:", None, QtGui.QApplication.UnicodeUTF8)) 58 | self.mirrorImageBtn.setText(QtGui.QApplication.translate("Form", "Mirror", None, QtGui.QApplication.UnicodeUTF8)) 59 | self.reflectImageBtn.setText(QtGui.QApplication.translate("Form", "Reflect", None, QtGui.QApplication.UnicodeUTF8)) 60 | 61 | -------------------------------------------------------------------------------- /gui/pyqtgraph/widgets/DataTreeWidget.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from pyqtgraph.Qt import QtGui, QtCore 3 | from pyqtgraph.pgcollections import OrderedDict 4 | import types, traceback 5 | import numpy as np 6 | 7 | try: 8 | import metaarray 9 | HAVE_METAARRAY = True 10 | except: 11 | HAVE_METAARRAY = False 12 | 13 | __all__ = ['DataTreeWidget'] 14 | 15 | class DataTreeWidget(QtGui.QTreeWidget): 16 | """ 17 | Widget for displaying hierarchical python data structures 18 | (eg, nested dicts, lists, and arrays) 19 | """ 20 | 21 | 22 | def __init__(self, parent=None, data=None): 23 | QtGui.QTreeWidget.__init__(self, parent) 24 | self.setVerticalScrollMode(self.ScrollPerPixel) 25 | self.setData(data) 26 | self.setColumnCount(3) 27 | self.setHeaderLabels(['key / index', 'type', 'value']) 28 | 29 | def setData(self, data, hideRoot=False): 30 | """data should be a dictionary.""" 31 | self.clear() 32 | self.buildTree(data, self.invisibleRootItem(), hideRoot=hideRoot) 33 | #node = self.mkNode('', data) 34 | #while node.childCount() > 0: 35 | #c = node.child(0) 36 | #node.removeChild(c) 37 | #self.invisibleRootItem().addChild(c) 38 | self.expandToDepth(3) 39 | self.resizeColumnToContents(0) 40 | 41 | def buildTree(self, data, parent, name='', hideRoot=False): 42 | if hideRoot: 43 | node = parent 44 | else: 45 | typeStr = type(data).__name__ 46 | if typeStr == 'instance': 47 | typeStr += ": " + data.__class__.__name__ 48 | node = QtGui.QTreeWidgetItem([name, typeStr, ""]) 49 | parent.addChild(node) 50 | 51 | if isinstance(data, types.TracebackType): ## convert traceback to a list of strings 52 | data = list(map(str.strip, traceback.format_list(traceback.extract_tb(data)))) 53 | elif HAVE_METAARRAY and (hasattr(data, 'implements') and data.implements('MetaArray')): 54 | data = { 55 | 'data': data.view(np.ndarray), 56 | 'meta': data.infoCopy() 57 | } 58 | 59 | if isinstance(data, dict): 60 | for k in data: 61 | self.buildTree(data[k], node, str(k)) 62 | elif isinstance(data, list) or isinstance(data, tuple): 63 | for i in range(len(data)): 64 | self.buildTree(data[i], node, str(i)) 65 | else: 66 | node.setText(2, str(data)) 67 | 68 | 69 | #def mkNode(self, name, v): 70 | #if type(v) is list and len(v) > 0 and isinstance(v[0], dict): 71 | #inds = map(unicode, range(len(v))) 72 | #v = OrderedDict(zip(inds, v)) 73 | #if isinstance(v, dict): 74 | ##print "\nadd tree", k, v 75 | #node = QtGui.QTreeWidgetItem([name]) 76 | #for k in v: 77 | #newNode = self.mkNode(k, v[k]) 78 | #node.addChild(newNode) 79 | #else: 80 | ##print "\nadd value", k, str(v) 81 | #node = QtGui.QTreeWidgetItem([unicode(name), unicode(v)]) 82 | #return node 83 | 84 | -------------------------------------------------------------------------------- /gui/pyqtgraph/widgets/GradientWidget.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from pyqtgraph.Qt import QtGui, QtCore 3 | from .GraphicsView import GraphicsView 4 | from pyqtgraph.graphicsItems.GradientEditorItem import GradientEditorItem 5 | import weakref 6 | import numpy as np 7 | 8 | __all__ = ['TickSlider', 'GradientWidget', 'BlackWhiteSlider'] 9 | 10 | 11 | class GradientWidget(GraphicsView): 12 | """ 13 | Widget displaying an editable color gradient. The user may add, move, recolor, 14 | or remove colors from the gradient. Additionally, a context menu allows the 15 | user to select from pre-defined gradients. 16 | """ 17 | sigGradientChanged = QtCore.Signal(object) 18 | sigGradientChangeFinished = QtCore.Signal(object) 19 | 20 | def __init__(self, parent=None, orientation='bottom', *args, **kargs): 21 | """ 22 | The *orientation* argument may be 'bottom', 'top', 'left', or 'right' 23 | indicating whether the gradient is displayed horizontally (top, bottom) 24 | or vertically (left, right) and on what side of the gradient the editable 25 | ticks will appear. 26 | 27 | All other arguments are passed to 28 | :func:`GradientEditorItem.__init__ `. 29 | 30 | Note: For convenience, this class wraps methods from 31 | :class:`GradientEditorItem `. 32 | """ 33 | GraphicsView.__init__(self, parent, useOpenGL=False, background=None) 34 | self.maxDim = 31 35 | kargs['tickPen'] = 'k' 36 | self.item = GradientEditorItem(*args, **kargs) 37 | self.item.sigGradientChanged.connect(self.sigGradientChanged) 38 | self.item.sigGradientChangeFinished.connect(self.sigGradientChangeFinished) 39 | self.setCentralItem(self.item) 40 | self.setOrientation(orientation) 41 | self.setCacheMode(self.CacheNone) 42 | self.setRenderHints(QtGui.QPainter.Antialiasing | QtGui.QPainter.TextAntialiasing) 43 | self.setFrameStyle(QtGui.QFrame.NoFrame | QtGui.QFrame.Plain) 44 | #self.setBackgroundRole(QtGui.QPalette.NoRole) 45 | #self.setBackgroundBrush(QtGui.QBrush(QtCore.Qt.NoBrush)) 46 | #self.setAutoFillBackground(False) 47 | #self.setAttribute(QtCore.Qt.WA_PaintOnScreen, False) 48 | #self.setAttribute(QtCore.Qt.WA_OpaquePaintEvent, True) 49 | 50 | def setOrientation(self, ort): 51 | """Set the orientation of the widget. May be one of 'bottom', 'top', 52 | 'left', or 'right'.""" 53 | self.item.setOrientation(ort) 54 | self.orientation = ort 55 | self.setMaxDim() 56 | 57 | def setMaxDim(self, mx=None): 58 | if mx is None: 59 | mx = self.maxDim 60 | else: 61 | self.maxDim = mx 62 | 63 | if self.orientation in ['bottom', 'top']: 64 | self.setFixedHeight(mx) 65 | self.setMaximumWidth(16777215) 66 | else: 67 | self.setFixedWidth(mx) 68 | self.setMaximumHeight(16777215) 69 | 70 | def __getattr__(self, attr): 71 | ### wrap methods from GradientEditorItem 72 | return getattr(self.item, attr) 73 | 74 | 75 | -------------------------------------------------------------------------------- /controllers/pid_controller.py: -------------------------------------------------------------------------------- 1 | # 2 | # (c) PySimiam Team 2013 3 | # 4 | # Contact person: Tim Fuchs 5 | # 6 | # This class was implemented as a weekly programming excercise 7 | # of the 'Control of Mobile Robots' course by Magnus Egerstedt. 8 | # 9 | from controller import Controller 10 | import math 11 | import numpy 12 | 13 | class PIDController(Controller): 14 | """The PID controller is a general-purpose controller that steers the robot to a certain heading direction. The heading is recalculated on every execution.""" 15 | def __init__(self, params): 16 | '''Initialize internal variables''' 17 | Controller.__init__(self,params) 18 | 19 | # This angle shows the direction that the controller 20 | # tries to follow. It is used by the supervisor 21 | # to draw and debug this controller 22 | self.heading_angle = 0 23 | 24 | def restart(self): 25 | """Set the integral and differential errors to zero""" 26 | self.E = 0 27 | self.error_1 = 0 28 | 29 | def set_parameters(self, params): 30 | """Set PID values 31 | 32 | The params structure is expected to have in the `gains` field three 33 | parameters for the PID gains. 34 | 35 | :param params.gains.kp: Proportional gain 36 | :type params.gains.kp: float 37 | :param params.gains.ki: Integral gain 38 | :type params.gains.ki: float 39 | :param params.gains.kd: Differential gain 40 | :type params.gains.kd: float 41 | """ 42 | self.kp = params.gains.kp 43 | self.ki = params.gains.ki 44 | self.kd = params.gains.kd 45 | 46 | def get_heading(self, state): 47 | """Get the direction in which the controller wants to move the robot 48 | as a vector in the robot's frame of reference. 49 | 50 | :return: a numpy array [x, y, z] with z = 1. 51 | """ 52 | raise NotImplementedError("PIDController.get_heading") 53 | 54 | def get_heading_angle(self, state): 55 | """Return the heading as an angle in the robot's frame of reference.""" 56 | 57 | # The vector to follow 58 | heading = self.get_heading(state) 59 | 60 | return math.atan2(heading[1],heading[0]) 61 | 62 | def execute(self, state, dt): 63 | """Calculate errors and steer the robot""" 64 | 65 | # This is the direction we want to go 66 | self.heading_angle = self.get_heading_angle(state) 67 | 68 | # 1. Calculate simple proportional error 69 | # The direction is in the robot's frame of reference, 70 | # so the error is the direction. 71 | # Note that the error is automatically between pi and -pi. 72 | error = self.heading_angle 73 | 74 | # 2. Calculate integral error 75 | self.E += error*dt 76 | self.E = (self.E + math.pi)%(2*math.pi) - math.pi 77 | 78 | # 3. Calculate differential error 79 | dE = (error - self.error_1)/dt 80 | self.error_1 = error #updates the error_1 var 81 | 82 | # 4. Calculate desired omega 83 | w_ = self.kp*error + self.ki*self.E + self.kd*dE 84 | 85 | # The linear velocity is given to us: 86 | v_ = state.velocity.v 87 | 88 | return [v_, w_] 89 | -------------------------------------------------------------------------------- /worlds/static_environment.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /scripts/xmlwriter.py: -------------------------------------------------------------------------------- 1 | from xmlobject import XMLObject 2 | import xml.etree.ElementTree as ET 3 | import xml.dom.minidom as dom 4 | 5 | class XMLWriter(XMLObject): 6 | """ 7 | A class to handle saving XML files for the simulator and parameters 8 | entered via the UI. 9 | """ 10 | 11 | _file = None 12 | _root = None 13 | _tree = None 14 | 15 | def __init__(self, file_, template, tree): 16 | """ 17 | Construct a new XMLWriter instance 18 | 19 | Scope: 20 | Public 21 | Parameters: 22 | file ------> path to the file to which XML should be saved 23 | template ---> 'simulator' or 'parameters' 24 | Return: 25 | A new XMLWriter instance 26 | """ 27 | 28 | super(XMLWriter, self).__init__(file_, template) 29 | 30 | self._tree = tree 31 | 32 | def _write_parameters(self): 33 | """ 34 | Write out the parameters to the XML file. 35 | 36 | Scope: 37 | Private 38 | Parameters: 39 | None 40 | Return: 41 | void 42 | """ 43 | 44 | def write_subtree(root, tree): 45 | for key, value in tree: 46 | # Parameter key must be either a string or a tuple 47 | # Parameter value is either a list or a number/string: 48 | if isinstance(value, list): 49 | if isinstance(key, basestring): 50 | tag = ET.SubElement(root, key) 51 | elif isinstance(key, tuple): 52 | tag = ET.SubElement(root, str(key[0])) 53 | tag.set("id",str(key[1])) 54 | else: 55 | raise Exception('[XMLWriter._write_parameters] Invalid key: {}'.format(key)) 56 | write_subtree(tag, value) 57 | else: 58 | if isinstance(key, basestring): 59 | root.set(key, str(value)) 60 | else: 61 | raise Exception('[XMLWriter._write_parameters] Invalid key: {}'.format(key)) 62 | 63 | xml = ET.ElementTree(ET.Element('parameters')) 64 | xml_root = xml.getroot() 65 | 66 | write_subtree(xml_root, self._tree) 67 | 68 | with open(self._file, 'w') as f: 69 | dom.parseString(ET.tostring(xml_root)).writexml(f,'',' ','\n') 70 | 71 | def _write_simulation(self): 72 | """ 73 | Write out the simulation to the XML file. 74 | 75 | Scope: 76 | Private 77 | Parameters: 78 | None 79 | Return: 80 | void 81 | """ 82 | 83 | # TODO 84 | pass 85 | 86 | def write(self): 87 | """ 88 | Write out the *tree* as XML representing the specified *template* to the given *file_*. 89 | 90 | | *Paramaters:* 91 | | None 92 | | *Return:* 93 | | void 94 | """ 95 | 96 | if self._tree == None: 97 | raise Exception( 98 | '[XMLWriter._write_simulation] No tree specified to write!') 99 | 100 | if self._template == "parameters": 101 | return self._write_parameters() 102 | elif self._template == "simulation": 103 | return self._write_simulation() 104 | else: 105 | raise Exception( 106 | '[XMLReader.write] Unknown template!') 107 | -------------------------------------------------------------------------------- /gui/pyqtgraph/GraphicsScene/exportDialogTemplate_pyqt.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file './GraphicsScene/exportDialogTemplate.ui' 4 | # 5 | # Created: Wed Jan 30 21:02:28 2013 6 | # by: PyQt4 UI code generator 4.9.3 7 | # 8 | # WARNING! All changes made in this file will be lost! 9 | 10 | from PyQt4 import QtCore, QtGui 11 | 12 | try: 13 | _fromUtf8 = QtCore.QString.fromUtf8 14 | except AttributeError: 15 | _fromUtf8 = lambda s: s 16 | 17 | class Ui_Form(object): 18 | def setupUi(self, Form): 19 | Form.setObjectName(_fromUtf8("Form")) 20 | Form.resize(241, 367) 21 | self.gridLayout = QtGui.QGridLayout(Form) 22 | self.gridLayout.setSpacing(0) 23 | self.gridLayout.setObjectName(_fromUtf8("gridLayout")) 24 | self.label = QtGui.QLabel(Form) 25 | self.label.setObjectName(_fromUtf8("label")) 26 | self.gridLayout.addWidget(self.label, 0, 0, 1, 3) 27 | self.itemTree = QtGui.QTreeWidget(Form) 28 | self.itemTree.setObjectName(_fromUtf8("itemTree")) 29 | self.itemTree.headerItem().setText(0, _fromUtf8("1")) 30 | self.itemTree.header().setVisible(False) 31 | self.gridLayout.addWidget(self.itemTree, 1, 0, 1, 3) 32 | self.label_2 = QtGui.QLabel(Form) 33 | self.label_2.setObjectName(_fromUtf8("label_2")) 34 | self.gridLayout.addWidget(self.label_2, 2, 0, 1, 3) 35 | self.formatList = QtGui.QListWidget(Form) 36 | self.formatList.setObjectName(_fromUtf8("formatList")) 37 | self.gridLayout.addWidget(self.formatList, 3, 0, 1, 3) 38 | self.exportBtn = QtGui.QPushButton(Form) 39 | self.exportBtn.setObjectName(_fromUtf8("exportBtn")) 40 | self.gridLayout.addWidget(self.exportBtn, 6, 1, 1, 1) 41 | self.closeBtn = QtGui.QPushButton(Form) 42 | self.closeBtn.setObjectName(_fromUtf8("closeBtn")) 43 | self.gridLayout.addWidget(self.closeBtn, 6, 2, 1, 1) 44 | self.paramTree = ParameterTree(Form) 45 | self.paramTree.setObjectName(_fromUtf8("paramTree")) 46 | self.paramTree.headerItem().setText(0, _fromUtf8("1")) 47 | self.paramTree.header().setVisible(False) 48 | self.gridLayout.addWidget(self.paramTree, 5, 0, 1, 3) 49 | self.label_3 = QtGui.QLabel(Form) 50 | self.label_3.setObjectName(_fromUtf8("label_3")) 51 | self.gridLayout.addWidget(self.label_3, 4, 0, 1, 3) 52 | self.copyBtn = QtGui.QPushButton(Form) 53 | self.copyBtn.setObjectName(_fromUtf8("copyBtn")) 54 | self.gridLayout.addWidget(self.copyBtn, 6, 0, 1, 1) 55 | 56 | self.retranslateUi(Form) 57 | QtCore.QMetaObject.connectSlotsByName(Form) 58 | 59 | def retranslateUi(self, Form): 60 | Form.setWindowTitle(QtGui.QApplication.translate("Form", "Export", None, QtGui.QApplication.UnicodeUTF8)) 61 | self.label.setText(QtGui.QApplication.translate("Form", "Item to export:", None, QtGui.QApplication.UnicodeUTF8)) 62 | self.label_2.setText(QtGui.QApplication.translate("Form", "Export format", None, QtGui.QApplication.UnicodeUTF8)) 63 | self.exportBtn.setText(QtGui.QApplication.translate("Form", "Export", None, QtGui.QApplication.UnicodeUTF8)) 64 | self.closeBtn.setText(QtGui.QApplication.translate("Form", "Close", None, QtGui.QApplication.UnicodeUTF8)) 65 | self.label_3.setText(QtGui.QApplication.translate("Form", "Export options", None, QtGui.QApplication.UnicodeUTF8)) 66 | self.copyBtn.setText(QtGui.QApplication.translate("Form", "Copy", None, QtGui.QApplication.UnicodeUTF8)) 67 | 68 | from pyqtgraph.parametertree import ParameterTree 69 | -------------------------------------------------------------------------------- /gui/pyqtgraph/flowchart/FlowchartCtrlTemplate_pyqt.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file './flowchart/FlowchartCtrlTemplate.ui' 4 | # 5 | # Created: Sun Sep 9 14:41:30 2012 6 | # by: PyQt4 UI code generator 4.9.1 7 | # 8 | # WARNING! All changes made in this file will be lost! 9 | 10 | from PyQt4 import QtCore, QtGui 11 | 12 | try: 13 | _fromUtf8 = QtCore.QString.fromUtf8 14 | except AttributeError: 15 | _fromUtf8 = lambda s: s 16 | 17 | class Ui_Form(object): 18 | def setupUi(self, Form): 19 | Form.setObjectName(_fromUtf8("Form")) 20 | Form.resize(217, 499) 21 | self.gridLayout = QtGui.QGridLayout(Form) 22 | self.gridLayout.setMargin(0) 23 | self.gridLayout.setVerticalSpacing(0) 24 | self.gridLayout.setObjectName(_fromUtf8("gridLayout")) 25 | self.loadBtn = QtGui.QPushButton(Form) 26 | self.loadBtn.setObjectName(_fromUtf8("loadBtn")) 27 | self.gridLayout.addWidget(self.loadBtn, 1, 0, 1, 1) 28 | self.saveBtn = FeedbackButton(Form) 29 | self.saveBtn.setObjectName(_fromUtf8("saveBtn")) 30 | self.gridLayout.addWidget(self.saveBtn, 1, 1, 1, 2) 31 | self.saveAsBtn = FeedbackButton(Form) 32 | self.saveAsBtn.setObjectName(_fromUtf8("saveAsBtn")) 33 | self.gridLayout.addWidget(self.saveAsBtn, 1, 3, 1, 1) 34 | self.reloadBtn = FeedbackButton(Form) 35 | self.reloadBtn.setCheckable(False) 36 | self.reloadBtn.setFlat(False) 37 | self.reloadBtn.setObjectName(_fromUtf8("reloadBtn")) 38 | self.gridLayout.addWidget(self.reloadBtn, 4, 0, 1, 2) 39 | self.showChartBtn = QtGui.QPushButton(Form) 40 | self.showChartBtn.setCheckable(True) 41 | self.showChartBtn.setObjectName(_fromUtf8("showChartBtn")) 42 | self.gridLayout.addWidget(self.showChartBtn, 4, 2, 1, 2) 43 | self.ctrlList = TreeWidget(Form) 44 | self.ctrlList.setObjectName(_fromUtf8("ctrlList")) 45 | self.ctrlList.headerItem().setText(0, _fromUtf8("1")) 46 | self.ctrlList.header().setVisible(False) 47 | self.ctrlList.header().setStretchLastSection(False) 48 | self.gridLayout.addWidget(self.ctrlList, 3, 0, 1, 4) 49 | self.fileNameLabel = QtGui.QLabel(Form) 50 | font = QtGui.QFont() 51 | font.setBold(True) 52 | font.setWeight(75) 53 | self.fileNameLabel.setFont(font) 54 | self.fileNameLabel.setText(_fromUtf8("")) 55 | self.fileNameLabel.setAlignment(QtCore.Qt.AlignCenter) 56 | self.fileNameLabel.setObjectName(_fromUtf8("fileNameLabel")) 57 | self.gridLayout.addWidget(self.fileNameLabel, 0, 1, 1, 1) 58 | 59 | self.retranslateUi(Form) 60 | QtCore.QMetaObject.connectSlotsByName(Form) 61 | 62 | def retranslateUi(self, Form): 63 | Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8)) 64 | self.loadBtn.setText(QtGui.QApplication.translate("Form", "Load..", None, QtGui.QApplication.UnicodeUTF8)) 65 | self.saveBtn.setText(QtGui.QApplication.translate("Form", "Save", None, QtGui.QApplication.UnicodeUTF8)) 66 | self.saveAsBtn.setText(QtGui.QApplication.translate("Form", "As..", None, QtGui.QApplication.UnicodeUTF8)) 67 | self.reloadBtn.setText(QtGui.QApplication.translate("Form", "Reload Libs", None, QtGui.QApplication.UnicodeUTF8)) 68 | self.showChartBtn.setText(QtGui.QApplication.translate("Form", "Flowchart", None, QtGui.QApplication.UnicodeUTF8)) 69 | 70 | from pyqtgraph.widgets.FeedbackButton import FeedbackButton 71 | from pyqtgraph.widgets.TreeWidget import TreeWidget 72 | -------------------------------------------------------------------------------- /gui/pyqtgraph/flowchart/FlowchartCtrlTemplate.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form 4 | 5 | 6 | 7 | 0 8 | 0 9 | 217 10 | 499 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 0 19 | 20 | 21 | 0 22 | 23 | 24 | 25 | 26 | Load.. 27 | 28 | 29 | 30 | 31 | 36 | 37 | 38 | 43 | 44 | 45 | 56 | 57 | 58 | 59 | 60 | Flowchart 61 | 62 | 63 | true 64 | 65 | 66 | 67 | 68 | 69 | 70 | false 71 | 72 | 73 | false 74 | 75 | 76 | false 77 | 78 | 79 | false 80 | 81 | 82 | 83 | 1 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 75 93 | true 94 | 95 | 96 | 97 | 98 | 99 | 100 | Qt::AlignCenter 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | TreeWidget 109 | QTreeWidget 110 |
pyqtgraph.widgets.TreeWidget
111 |
112 | 113 | FeedbackButton 114 | QPushButton 115 |
pyqtgraph.widgets.FeedbackButton
116 |
117 |
118 | 119 | 120 |
121 | -------------------------------------------------------------------------------- /gui/qt_plotwindow_qtgraph.py: -------------------------------------------------------------------------------- 1 | import pyqtgraph as pg 2 | from random import randint 3 | 4 | pg.setConfigOption('background', 'w') 5 | pg.setConfigOption('foreground', 'k') 6 | 7 | def get_color(color): 8 | if color is None: 9 | color = 'random' 10 | if isinstance(color,str): 11 | if color == 'random': 12 | return (randint(0,0xFF),randint(0,0xFF),randint(0,0xFF)) 13 | elif color == 'black': 14 | return 0 15 | elif color == 'blue': 16 | return 'b' 17 | elif color == 'red': 18 | return 'r' 19 | elif color == 'green': 20 | return 'g' 21 | elif isinstance(color,tuple) or isinstance(color,list): 22 | if sum(color) <= 4.0: 23 | return [int(0xFF*c) for c in color] 24 | else: 25 | return color 26 | else: 27 | color = int(0xFF*float(color)) 28 | return (color,color,color) 29 | 30 | class PlotVariable: 31 | """ 32 | A plot variable corresponds to one curve on the plot. 33 | It keeps track of the generating expression and of the 34 | values of the expression over time. 35 | """ 36 | def __init__(self,label,expression,plot,color = None): 37 | self.expression = expression 38 | self.xdata = [] 39 | self.ydata = [] 40 | self.curve = plot.plot(name=label,pen=get_color(color)) 41 | 42 | def add_point(self,x,y): 43 | self.xdata.append(x) 44 | self.ydata.append(y) 45 | self.curve.setData(self.xdata,self.ydata) 46 | 47 | def clear_data(self): 48 | self.xdata = [] 49 | self.ydata = [] 50 | self.curve.setData() 51 | 52 | class Plot: 53 | """ 54 | The plot follows one or more variables through time. 55 | It keeps track of the variables. 56 | """ 57 | def __init__(self,plot): 58 | self.plot = plot 59 | plot.enableAutoRange('y',0.95) 60 | plot.addLegend() 61 | self.variables = [] 62 | 63 | def add_curve(self,label,expression,color=None): 64 | self.variables.append(PlotVariable(label,expression,self.plot,color)) 65 | 66 | def add_data(self,data): 67 | 68 | for variable in self.variables: 69 | if variable.expression not in data: 70 | print("No value for {}".format(variable.expression)) 71 | else: 72 | variable.add_point(data['time'], data[variable.expression]) 73 | self.plot.setXRange(max(0,data['time']-10),data['time']) 74 | 75 | def clear_data(self): 76 | for v in self.variables: 77 | v.clear_data() 78 | 79 | class PlotWindow(pg.GraphicsWindow): 80 | """ 81 | The window consists of a figure with a nav toolbar and subplots. 82 | It keeps track of all subplots 83 | """ 84 | 85 | def __init__(self): 86 | pg.GraphicsWindow.__init__(self) 87 | 88 | self.plots = [] 89 | 90 | #Slots 91 | def clear_data(self): 92 | for plot in self.plots: 93 | plot.clear_data() 94 | 95 | def add_plot(self): 96 | """Add a new subplot with a curve given by expression""" 97 | n = len(self.plots) 98 | if n > 0: 99 | self.nextRow() 100 | self.plots.append(Plot(self.addPlot())) 101 | if n > 0: 102 | self.plots[-1].plot.setXLink(self.plots[0].plot) 103 | 104 | return self.plots[-1] 105 | 106 | def add_data(self,data): 107 | for plot in self.plots: 108 | plot.add_data(data) 109 | -------------------------------------------------------------------------------- /gui/pyqtgraph/widgets/CheckTable.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from pyqtgraph.Qt import QtGui, QtCore 3 | from . import VerticalLabel 4 | 5 | __all__ = ['CheckTable'] 6 | 7 | class CheckTable(QtGui.QWidget): 8 | 9 | sigStateChanged = QtCore.Signal(object, object, object) # (row, col, state) 10 | 11 | def __init__(self, columns): 12 | QtGui.QWidget.__init__(self) 13 | self.layout = QtGui.QGridLayout() 14 | self.layout.setSpacing(0) 15 | self.setLayout(self.layout) 16 | self.headers = [] 17 | self.columns = columns 18 | col = 1 19 | for c in columns: 20 | label = VerticalLabel.VerticalLabel(c, orientation='vertical') 21 | self.headers.append(label) 22 | self.layout.addWidget(label, 0, col) 23 | col += 1 24 | 25 | self.rowNames = [] 26 | self.rowWidgets = [] 27 | self.oldRows = {} ## remember settings from removed rows; reapply if they reappear. 28 | 29 | 30 | def updateRows(self, rows): 31 | for r in self.rowNames[:]: 32 | if r not in rows: 33 | self.removeRow(r) 34 | for r in rows: 35 | if r not in self.rowNames: 36 | self.addRow(r) 37 | 38 | def addRow(self, name): 39 | label = QtGui.QLabel(name) 40 | row = len(self.rowNames)+1 41 | self.layout.addWidget(label, row, 0) 42 | checks = [] 43 | col = 1 44 | for c in self.columns: 45 | check = QtGui.QCheckBox('') 46 | check.col = c 47 | check.row = name 48 | self.layout.addWidget(check, row, col) 49 | checks.append(check) 50 | if name in self.oldRows: 51 | check.setChecked(self.oldRows[name][col]) 52 | col += 1 53 | #QtCore.QObject.connect(check, QtCore.SIGNAL('stateChanged(int)'), self.checkChanged) 54 | check.stateChanged.connect(self.checkChanged) 55 | self.rowNames.append(name) 56 | self.rowWidgets.append([label] + checks) 57 | 58 | def removeRow(self, name): 59 | row = self.rowNames.index(name) 60 | self.oldRows[name] = self.saveState()['rows'][row] ## save for later 61 | self.rowNames.pop(row) 62 | for w in self.rowWidgets[row]: 63 | w.setParent(None) 64 | #QtCore.QObject.disconnect(w, QtCore.SIGNAL('stateChanged(int)'), self.checkChanged) 65 | if isinstance(w, QtGui.QCheckBox): 66 | w.stateChanged.disconnect(self.checkChanged) 67 | self.rowWidgets.pop(row) 68 | for i in range(row, len(self.rowNames)): 69 | widgets = self.rowWidgets[i] 70 | for j in range(len(widgets)): 71 | widgets[j].setParent(None) 72 | self.layout.addWidget(widgets[j], i+1, j) 73 | 74 | def checkChanged(self, state): 75 | check = QtCore.QObject.sender(self) 76 | #self.emit(QtCore.SIGNAL('stateChanged'), check.row, check.col, state) 77 | self.sigStateChanged.emit(check.row, check.col, state) 78 | 79 | def saveState(self): 80 | rows = [] 81 | for i in range(len(self.rowNames)): 82 | row = [self.rowNames[i]] + [c.isChecked() for c in self.rowWidgets[i][1:]] 83 | rows.append(row) 84 | return {'cols': self.columns, 'rows': rows} 85 | 86 | def restoreState(self, state): 87 | rows = [r[0] for r in state['rows']] 88 | self.updateRows(rows) 89 | for r in state['rows']: 90 | rowNum = self.rowNames.index(r[0]) 91 | for i in range(1, len(r)): 92 | self.rowWidgets[rowNum][i].setChecked(r[i]) 93 | 94 | -------------------------------------------------------------------------------- /gui/pyqtgraph/widgets/VerticalLabel.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from pyqtgraph.Qt import QtGui, QtCore 3 | 4 | __all__ = ['VerticalLabel'] 5 | #class VerticalLabel(QtGui.QLabel): 6 | #def paintEvent(self, ev): 7 | #p = QtGui.QPainter(self) 8 | #p.rotate(-90) 9 | #self.hint = p.drawText(QtCore.QRect(-self.height(), 0, self.height(), self.width()), QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter, self.text()) 10 | #p.end() 11 | #self.setMinimumWidth(self.hint.height()) 12 | #self.setMinimumHeight(self.hint.width()) 13 | 14 | #def sizeHint(self): 15 | #if hasattr(self, 'hint'): 16 | #return QtCore.QSize(self.hint.height(), self.hint.width()) 17 | #else: 18 | #return QtCore.QSize(16, 50) 19 | 20 | class VerticalLabel(QtGui.QLabel): 21 | def __init__(self, text, orientation='vertical', forceWidth=True): 22 | QtGui.QLabel.__init__(self, text) 23 | self.forceWidth = forceWidth 24 | self.orientation = None 25 | self.setOrientation(orientation) 26 | 27 | def setOrientation(self, o): 28 | if self.orientation == o: 29 | return 30 | self.orientation = o 31 | self.update() 32 | self.updateGeometry() 33 | 34 | def paintEvent(self, ev): 35 | p = QtGui.QPainter(self) 36 | #p.setBrush(QtGui.QBrush(QtGui.QColor(100, 100, 200))) 37 | #p.setPen(QtGui.QPen(QtGui.QColor(50, 50, 100))) 38 | #p.drawRect(self.rect().adjusted(0, 0, -1, -1)) 39 | 40 | #p.setPen(QtGui.QPen(QtGui.QColor(255, 255, 255))) 41 | 42 | if self.orientation == 'vertical': 43 | p.rotate(-90) 44 | rgn = QtCore.QRect(-self.height(), 0, self.height(), self.width()) 45 | else: 46 | rgn = self.contentsRect() 47 | align = self.alignment() 48 | #align = QtCore.Qt.AlignTop|QtCore.Qt.AlignHCenter 49 | 50 | self.hint = p.drawText(rgn, align, self.text()) 51 | p.end() 52 | 53 | if self.orientation == 'vertical': 54 | self.setMaximumWidth(self.hint.height()) 55 | self.setMinimumWidth(0) 56 | self.setMaximumHeight(16777215) 57 | if self.forceWidth: 58 | self.setMinimumHeight(self.hint.width()) 59 | else: 60 | self.setMinimumHeight(0) 61 | else: 62 | self.setMaximumHeight(self.hint.height()) 63 | self.setMinimumHeight(0) 64 | self.setMaximumWidth(16777215) 65 | if self.forceWidth: 66 | self.setMinimumWidth(self.hint.width()) 67 | else: 68 | self.setMinimumWidth(0) 69 | 70 | def sizeHint(self): 71 | if self.orientation == 'vertical': 72 | if hasattr(self, 'hint'): 73 | return QtCore.QSize(self.hint.height(), self.hint.width()) 74 | else: 75 | return QtCore.QSize(19, 50) 76 | else: 77 | if hasattr(self, 'hint'): 78 | return QtCore.QSize(self.hint.width(), self.hint.height()) 79 | else: 80 | return QtCore.QSize(50, 19) 81 | 82 | 83 | if __name__ == '__main__': 84 | app = QtGui.QApplication([]) 85 | win = QtGui.QMainWindow() 86 | w = QtGui.QWidget() 87 | l = QtGui.QGridLayout() 88 | w.setLayout(l) 89 | 90 | l1 = VerticalLabel("text 1", orientation='horizontal') 91 | l2 = VerticalLabel("text 2") 92 | l3 = VerticalLabel("text 3") 93 | l4 = VerticalLabel("text 4", orientation='horizontal') 94 | l.addWidget(l1, 0, 0) 95 | l.addWidget(l2, 1, 1) 96 | l.addWidget(l3, 2, 2) 97 | l.addWidget(l4, 3, 3) 98 | win.setCentralWidget(w) 99 | win.show() -------------------------------------------------------------------------------- /gui/pyqtgraph/flowchart/library/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from pyqtgraph.pgcollections import OrderedDict 3 | from pyqtgraph import importModules 4 | import os, types 5 | from pyqtgraph.debug import printExc 6 | from ..Node import Node 7 | import pyqtgraph.reload as reload 8 | 9 | 10 | NODE_LIST = OrderedDict() ## maps name:class for all registered Node subclasses 11 | NODE_TREE = OrderedDict() ## categorized tree of Node subclasses 12 | 13 | def getNodeType(name): 14 | try: 15 | return NODE_LIST[name] 16 | except KeyError: 17 | raise Exception("No node type called '%s'" % name) 18 | 19 | def getNodeTree(): 20 | return NODE_TREE 21 | 22 | def registerNodeType(cls, paths, override=False): 23 | """ 24 | Register a new node type. If the type's name is already in use, 25 | an exception will be raised (unless override=True). 26 | 27 | Arguments: 28 | cls - a subclass of Node (must have typ.nodeName) 29 | paths - list of tuples specifying the location(s) this 30 | type will appear in the library tree. 31 | override - if True, overwrite any class having the same name 32 | """ 33 | if not isNodeClass(cls): 34 | raise Exception("Object %s is not a Node subclass" % str(cls)) 35 | 36 | name = cls.nodeName 37 | if not override and name in NODE_LIST: 38 | raise Exception("Node type name '%s' is already registered." % name) 39 | 40 | NODE_LIST[name] = cls 41 | for path in paths: 42 | root = NODE_TREE 43 | for n in path: 44 | if n not in root: 45 | root[n] = OrderedDict() 46 | root = root[n] 47 | root[name] = cls 48 | 49 | 50 | 51 | def isNodeClass(cls): 52 | try: 53 | if not issubclass(cls, Node): 54 | return False 55 | except: 56 | return False 57 | return hasattr(cls, 'nodeName') 58 | 59 | def loadLibrary(reloadLibs=False, libPath=None): 60 | """Import all Node subclasses found within files in the library module.""" 61 | 62 | global NODE_LIST, NODE_TREE 63 | #if libPath is None: 64 | #libPath = os.path.dirname(os.path.abspath(__file__)) 65 | 66 | if reloadLibs: 67 | reload.reloadAll(libPath) 68 | 69 | mods = importModules('', globals(), locals()) 70 | #for f in frozenSupport.listdir(libPath): 71 | #pathName, ext = os.path.splitext(f) 72 | #if ext not in ('.py', '.pyc') or '__init__' in pathName or '__pycache__' in pathName: 73 | #continue 74 | #try: 75 | ##print "importing from", f 76 | #mod = __import__(pathName, globals(), locals()) 77 | #except: 78 | #printExc("Error loading flowchart library %s:" % pathName) 79 | #continue 80 | 81 | for name, mod in mods.items(): 82 | nodes = [] 83 | for n in dir(mod): 84 | o = getattr(mod, n) 85 | if isNodeClass(o): 86 | #print " ", str(o) 87 | registerNodeType(o, [(name,)], override=reloadLibs) 88 | #nodes.append((o.nodeName, o)) 89 | #if len(nodes) > 0: 90 | #NODE_TREE[name] = OrderedDict(nodes) 91 | #NODE_LIST.extend(nodes) 92 | #NODE_LIST = OrderedDict(NODE_LIST) 93 | 94 | def reloadLibrary(): 95 | loadLibrary(reloadLibs=True) 96 | 97 | loadLibrary() 98 | #NODE_LIST = [] 99 | #for o in locals().values(): 100 | #if type(o) is type(AddNode) and issubclass(o, Node) and o is not Node and hasattr(o, 'nodeName'): 101 | #NODE_LIST.append((o.nodeName, o)) 102 | #NODE_LIST.sort(lambda a,b: cmp(a[0], b[0])) 103 | #NODE_LIST = OrderedDict(NODE_LIST) -------------------------------------------------------------------------------- /gui/pyqtgraph/opengl/items/GLImageItem.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | from .. GLGraphicsItem import GLGraphicsItem 3 | from pyqtgraph.Qt import QtGui 4 | import numpy as np 5 | 6 | __all__ = ['GLImageItem'] 7 | 8 | class GLImageItem(GLGraphicsItem): 9 | """ 10 | **Bases:** :class:`GLGraphicsItem ` 11 | 12 | Displays image data as a textured quad. 13 | """ 14 | 15 | 16 | def __init__(self, data, smooth=False, glOptions='translucent'): 17 | """ 18 | 19 | ============== ======================================================================================= 20 | **Arguments:** 21 | data Volume data to be rendered. *Must* be 3D numpy array (x, y, RGBA) with dtype=ubyte. 22 | (See functions.makeRGBA) 23 | smooth (bool) If True, the volume slices are rendered with linear interpolation 24 | ============== ======================================================================================= 25 | """ 26 | 27 | self.smooth = smooth 28 | self.data = data 29 | GLGraphicsItem.__init__(self) 30 | self.setGLOptions(glOptions) 31 | 32 | def initializeGL(self): 33 | glEnable(GL_TEXTURE_2D) 34 | self.texture = glGenTextures(1) 35 | glBindTexture(GL_TEXTURE_2D, self.texture) 36 | if self.smooth: 37 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 38 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) 39 | else: 40 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) 41 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) 42 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER) 43 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER) 44 | #glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER) 45 | shape = self.data.shape 46 | 47 | ## Test texture dimensions first 48 | glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGBA, shape[0], shape[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, None) 49 | if glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH) == 0: 50 | raise Exception("OpenGL failed to create 2D texture (%dx%d); too large for this hardware." % shape[:2]) 51 | 52 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, shape[0], shape[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, self.data.transpose((1,0,2))) 53 | glDisable(GL_TEXTURE_2D) 54 | 55 | #self.lists = {} 56 | #for ax in [0,1,2]: 57 | #for d in [-1, 1]: 58 | #l = glGenLists(1) 59 | #self.lists[(ax,d)] = l 60 | #glNewList(l, GL_COMPILE) 61 | #self.drawVolume(ax, d) 62 | #glEndList() 63 | 64 | 65 | def paint(self): 66 | 67 | glEnable(GL_TEXTURE_2D) 68 | glBindTexture(GL_TEXTURE_2D, self.texture) 69 | 70 | self.setupGLState() 71 | 72 | #glEnable(GL_DEPTH_TEST) 73 | ##glDisable(GL_CULL_FACE) 74 | #glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 75 | #glEnable( GL_BLEND ) 76 | #glEnable( GL_ALPHA_TEST ) 77 | glColor4f(1,1,1,1) 78 | 79 | glBegin(GL_QUADS) 80 | glTexCoord2f(0,0) 81 | glVertex3f(0,0,0) 82 | glTexCoord2f(1,0) 83 | glVertex3f(self.data.shape[0], 0, 0) 84 | glTexCoord2f(1,1) 85 | glVertex3f(self.data.shape[0], self.data.shape[1], 0) 86 | glTexCoord2f(0,1) 87 | glVertex3f(0, self.data.shape[1], 0) 88 | glEnd() 89 | glDisable(GL_TEXTURE_3D) 90 | 91 | -------------------------------------------------------------------------------- /gui/pyqtgraph/graphicsItems/ScaleBar.py: -------------------------------------------------------------------------------- 1 | from pyqtgraph.Qt import QtGui, QtCore 2 | from .GraphicsObject import * 3 | from .GraphicsWidgetAnchor import * 4 | from .TextItem import TextItem 5 | import numpy as np 6 | import pyqtgraph.functions as fn 7 | import pyqtgraph as pg 8 | 9 | __all__ = ['ScaleBar'] 10 | 11 | class ScaleBar(GraphicsObject, GraphicsWidgetAnchor): 12 | """ 13 | Displays a rectangular bar to indicate the relative scale of objects on the view. 14 | """ 15 | def __init__(self, size, width=5, brush=None, pen=None, suffix='m'): 16 | GraphicsObject.__init__(self) 17 | GraphicsWidgetAnchor.__init__(self) 18 | self.setFlag(self.ItemHasNoContents) 19 | self.setAcceptedMouseButtons(QtCore.Qt.NoButton) 20 | 21 | if brush is None: 22 | brush = pg.getConfigOption('foreground') 23 | self.brush = fn.mkBrush(brush) 24 | self.pen = fn.mkPen(pen) 25 | self._width = width 26 | self.size = size 27 | 28 | self.bar = QtGui.QGraphicsRectItem() 29 | self.bar.setPen(self.pen) 30 | self.bar.setBrush(self.brush) 31 | self.bar.setParentItem(self) 32 | 33 | self.text = TextItem(text=fn.siFormat(size, suffix=suffix), anchor=(0.5,1)) 34 | self.text.setParentItem(self) 35 | 36 | def parentChanged(self): 37 | view = self.parentItem() 38 | if view is None: 39 | return 40 | view.sigRangeChanged.connect(self.updateBar) 41 | self.updateBar() 42 | 43 | 44 | def updateBar(self): 45 | view = self.parentItem() 46 | if view is None: 47 | return 48 | p1 = view.mapFromViewToItem(self, QtCore.QPointF(0,0)) 49 | p2 = view.mapFromViewToItem(self, QtCore.QPointF(self.size,0)) 50 | w = (p2-p1).x() 51 | self.bar.setRect(QtCore.QRectF(-w, 0, w, self._width)) 52 | self.text.setPos(-w/2., 0) 53 | 54 | def boundingRect(self): 55 | return QtCore.QRectF() 56 | 57 | 58 | 59 | 60 | 61 | #class ScaleBar(UIGraphicsItem): 62 | #""" 63 | #Displays a rectangular bar with 10 divisions to indicate the relative scale of objects on the view. 64 | #""" 65 | #def __init__(self, size, width=5, color=(100, 100, 255)): 66 | #UIGraphicsItem.__init__(self) 67 | #self.setAcceptedMouseButtons(QtCore.Qt.NoButton) 68 | 69 | #self.brush = fn.mkBrush(color) 70 | #self.pen = fn.mkPen((0,0,0)) 71 | #self._width = width 72 | #self.size = size 73 | 74 | #def paint(self, p, opt, widget): 75 | #UIGraphicsItem.paint(self, p, opt, widget) 76 | 77 | #rect = self.boundingRect() 78 | #unit = self.pixelSize() 79 | #y = rect.top() + (rect.bottom()-rect.top()) * 0.02 80 | #y1 = y + unit[1]*self._width 81 | #x = rect.right() + (rect.left()-rect.right()) * 0.02 82 | #x1 = x - self.size 83 | 84 | #p.setPen(self.pen) 85 | #p.setBrush(self.brush) 86 | #rect = QtCore.QRectF( 87 | #QtCore.QPointF(x1, y1), 88 | #QtCore.QPointF(x, y) 89 | #) 90 | #p.translate(x1, y1) 91 | #p.scale(rect.width(), rect.height()) 92 | #p.drawRect(0, 0, 1, 1) 93 | 94 | #alpha = np.clip(((self.size/unit[0]) - 40.) * 255. / 80., 0, 255) 95 | #p.setPen(QtGui.QPen(QtGui.QColor(0, 0, 0, alpha))) 96 | #for i in range(1, 10): 97 | ##x2 = x + (x1-x) * 0.1 * i 98 | #x2 = 0.1 * i 99 | #p.drawLine(QtCore.QPointF(x2, 0), QtCore.QPointF(x2, 1)) 100 | 101 | 102 | #def setSize(self, s): 103 | #self.size = s 104 | 105 | -------------------------------------------------------------------------------- /gui/pyqtgraph/exceptionHandling.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """This module installs a wrapper around sys.excepthook which allows multiple 3 | new exception handlers to be registered. 4 | 5 | Optionally, the wrapper also stops exceptions from causing long-term storage 6 | of local stack frames. This has two major effects: 7 | - Unhandled exceptions will no longer cause memory leaks 8 | (If an exception occurs while a lot of data is present on the stack, 9 | such as when loading large files, the data would ordinarily be kept 10 | until the next exception occurs. We would rather release this memory 11 | as soon as possible.) 12 | - Some debuggers may have a hard time handling uncaught exceptions 13 | 14 | The module also provides a callback mechanism allowing others to respond 15 | to exceptions. 16 | """ 17 | 18 | import sys, time 19 | #from lib.Manager import logMsg 20 | import traceback 21 | #from log import * 22 | 23 | #logging = False 24 | 25 | callbacks = [] 26 | clear_tracebacks = False 27 | 28 | def register(fn): 29 | """ 30 | Register a callable to be invoked when there is an unhandled exception. 31 | The callback will be passed the output of sys.exc_info(): (exception type, exception, traceback) 32 | Multiple callbacks will be invoked in the order they were registered. 33 | """ 34 | callbacks.append(fn) 35 | 36 | def unregister(fn): 37 | """Unregister a previously registered callback.""" 38 | callbacks.remove(fn) 39 | 40 | def setTracebackClearing(clear=True): 41 | """ 42 | Enable or disable traceback clearing. 43 | By default, clearing is disabled and Python will indefinitely store unhandled exception stack traces. 44 | This function is provided since Python's default behavior can cause unexpected retention of 45 | large memory-consuming objects. 46 | """ 47 | global clear_tracebacks 48 | clear_tracebacks = clear 49 | 50 | class ExceptionHandler(object): 51 | def __call__(self, *args): 52 | ## call original exception handler first (prints exception) 53 | global original_excepthook, callbacks, clear_tracebacks 54 | print("===== %s =====" % str(time.strftime("%Y.%m.%d %H:%m:%S", time.localtime(time.time())))) 55 | ret = original_excepthook(*args) 56 | 57 | for cb in callbacks: 58 | try: 59 | cb(*args) 60 | except: 61 | print(" --------------------------------------------------------------") 62 | print(" Error occurred during exception callback %s" % str(cb)) 63 | print(" --------------------------------------------------------------") 64 | traceback.print_exception(*sys.exc_info()) 65 | 66 | 67 | ## Clear long-term storage of last traceback to prevent memory-hogging. 68 | ## (If an exception occurs while a lot of data is present on the stack, 69 | ## such as when loading large files, the data would ordinarily be kept 70 | ## until the next exception occurs. We would rather release this memory 71 | ## as soon as possible.) 72 | if clear_tracebacks is True: 73 | sys.last_traceback = None 74 | 75 | def implements(self, interface=None): 76 | ## this just makes it easy for us to detect whether an ExceptionHook is already installed. 77 | if interface is None: 78 | return ['ExceptionHandler'] 79 | else: 80 | return interface == 'ExceptionHandler' 81 | 82 | 83 | 84 | ## replace built-in excepthook only if this has not already been done 85 | if not (hasattr(sys.excepthook, 'implements') and sys.excepthook.implements('ExceptionHandler')): 86 | original_excepthook = sys.excepthook 87 | sys.excepthook = ExceptionHandler() 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /gui/pyqtgraph/widgets/LayoutWidget.py: -------------------------------------------------------------------------------- 1 | from pyqtgraph.Qt import QtGui, QtCore 2 | 3 | __all__ = ['LayoutWidget'] 4 | class LayoutWidget(QtGui.QWidget): 5 | """ 6 | Convenience class used for laying out QWidgets in a grid. 7 | (It's just a little less effort to use than QGridLayout) 8 | """ 9 | 10 | def __init__(self, parent=None): 11 | QtGui.QWidget.__init__(self, parent) 12 | self.layout = QtGui.QGridLayout() 13 | self.setLayout(self.layout) 14 | self.items = {} 15 | self.rows = {} 16 | self.currentRow = 0 17 | self.currentCol = 0 18 | 19 | def nextRow(self): 20 | """Advance to next row for automatic widget placement""" 21 | self.currentRow += 1 22 | self.currentCol = 0 23 | 24 | def nextColumn(self, colspan=1): 25 | """Advance to next column, while returning the current column number 26 | (generally only for internal use--called by addWidget)""" 27 | self.currentCol += colspan 28 | return self.currentCol-colspan 29 | 30 | def nextCol(self, *args, **kargs): 31 | """Alias of nextColumn""" 32 | return self.nextColumn(*args, **kargs) 33 | 34 | 35 | def addLabel(self, text=' ', row=None, col=None, rowspan=1, colspan=1, **kargs): 36 | """ 37 | Create a QLabel with *text* and place it in the next available cell (or in the cell specified) 38 | All extra keyword arguments are passed to QLabel(). 39 | Returns the created widget. 40 | """ 41 | text = QtGui.QLabel(text, **kargs) 42 | self.addItem(text, row, col, rowspan, colspan) 43 | return text 44 | 45 | def addLayout(self, row=None, col=None, rowspan=1, colspan=1, **kargs): 46 | """ 47 | Create an empty LayoutWidget and place it in the next available cell (or in the cell specified) 48 | All extra keyword arguments are passed to :func:`LayoutWidget.__init__ ` 49 | Returns the created widget. 50 | """ 51 | layout = LayoutWidget(**kargs) 52 | self.addItem(layout, row, col, rowspan, colspan) 53 | return layout 54 | 55 | def addWidget(self, item, row=None, col=None, rowspan=1, colspan=1): 56 | """ 57 | Add a widget to the layout and place it in the next available cell (or in the cell specified). 58 | """ 59 | if row == 'next': 60 | self.nextRow() 61 | row = self.currentRow 62 | elif row is None: 63 | row = self.currentRow 64 | 65 | 66 | if col is None: 67 | col = self.nextCol(colspan) 68 | 69 | if row not in self.rows: 70 | self.rows[row] = {} 71 | self.rows[row][col] = item 72 | self.items[item] = (row, col) 73 | 74 | self.layout.addWidget(item, row, col, rowspan, colspan) 75 | 76 | def getWidget(self, row, col): 77 | """Return the widget in (*row*, *col*)""" 78 | return self.row[row][col] 79 | 80 | #def itemIndex(self, item): 81 | #for i in range(self.layout.count()): 82 | #if self.layout.itemAt(i).graphicsItem() is item: 83 | #return i 84 | #raise Exception("Could not determine index of item " + str(item)) 85 | 86 | #def removeItem(self, item): 87 | #"""Remove *item* from the layout.""" 88 | #ind = self.itemIndex(item) 89 | #self.layout.removeAt(ind) 90 | #self.scene().removeItem(item) 91 | #r,c = self.items[item] 92 | #del self.items[item] 93 | #del self.rows[r][c] 94 | #self.update() 95 | 96 | #def clear(self): 97 | #items = [] 98 | #for i in list(self.items.keys()): 99 | #self.removeItem(i) 100 | 101 | 102 | -------------------------------------------------------------------------------- /gui/pyqtgraph/graphicsItems/UIGraphicsItem.py: -------------------------------------------------------------------------------- 1 | from pyqtgraph.Qt import QtGui, QtCore 2 | import weakref 3 | from .GraphicsObject import GraphicsObject 4 | import sip 5 | 6 | __all__ = ['UIGraphicsItem'] 7 | class UIGraphicsItem(GraphicsObject): 8 | """ 9 | Base class for graphics items with boundaries relative to a GraphicsView or ViewBox. 10 | The purpose of this class is to allow the creation of GraphicsItems which live inside 11 | a scalable view, but whose boundaries will always stay fixed relative to the view's boundaries. 12 | For example: GridItem, InfiniteLine 13 | 14 | The view can be specified on initialization or it can be automatically detected when the item is painted. 15 | 16 | NOTE: Only the item's boundingRect is affected; the item is not transformed in any way. Use viewRangeChanged 17 | to respond to changes in the view. 18 | """ 19 | 20 | #sigViewChanged = QtCore.Signal(object) ## emitted whenever the viewport coords have changed 21 | 22 | def __init__(self, bounds=None, parent=None): 23 | """ 24 | ============== ============================================================================= 25 | **Arguments:** 26 | bounds QRectF with coordinates relative to view box. The default is QRectF(0,0,1,1), 27 | which means the item will have the same bounds as the view. 28 | ============== ============================================================================= 29 | """ 30 | GraphicsObject.__init__(self, parent) 31 | self.setFlag(self.ItemSendsScenePositionChanges) 32 | 33 | if bounds is None: 34 | self._bounds = QtCore.QRectF(0, 0, 1, 1) 35 | else: 36 | self._bounds = bounds 37 | 38 | self._boundingRect = None 39 | self._updateView() 40 | 41 | def paint(self, *args): 42 | ## check for a new view object every time we paint. 43 | #self.updateView() 44 | pass 45 | 46 | def itemChange(self, change, value): 47 | ret = GraphicsObject.itemChange(self, change, value) 48 | 49 | ## workaround for pyqt bug: 50 | ## http://www.riverbankcomputing.com/pipermail/pyqt/2012-August/031818.html 51 | if change == self.ItemParentChange and isinstance(ret, QtGui.QGraphicsItem): 52 | ret = sip.cast(ret, QtGui.QGraphicsItem) 53 | 54 | if change == self.ItemScenePositionHasChanged: 55 | self.setNewBounds() 56 | return ret 57 | 58 | def boundingRect(self): 59 | if self._boundingRect is None: 60 | br = self.viewRect() 61 | if br is None: 62 | return QtCore.QRectF() 63 | else: 64 | self._boundingRect = br 65 | return QtCore.QRectF(self._boundingRect) 66 | 67 | def dataBounds(self, axis, frac=1.0, orthoRange=None): 68 | """Called by ViewBox for determining the auto-range bounds. 69 | By default, UIGraphicsItems are excluded from autoRange.""" 70 | return None 71 | 72 | def viewRangeChanged(self): 73 | """Called when the view widget/viewbox is resized/rescaled""" 74 | self.setNewBounds() 75 | self.update() 76 | 77 | def setNewBounds(self): 78 | """Update the item's bounding rect to match the viewport""" 79 | self._boundingRect = None ## invalidate bounding rect, regenerate later if needed. 80 | self.prepareGeometryChange() 81 | 82 | 83 | def setPos(self, *args): 84 | GraphicsObject.setPos(self, *args) 85 | self.setNewBounds() 86 | 87 | def mouseShape(self): 88 | """Return the shape of this item after expanding by 2 pixels""" 89 | shape = self.shape() 90 | ds = self.mapToDevice(shape) 91 | stroker = QtGui.QPainterPathStroker() 92 | stroker.setWidh(2) 93 | ds2 = stroker.createStroke(ds).united(ds) 94 | return self.mapFromDevice(ds2) 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /gui/pyqtgraph/widgets/ColorButton.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from pyqtgraph.Qt import QtGui, QtCore 3 | import pyqtgraph.functions as functions 4 | 5 | __all__ = ['ColorButton'] 6 | 7 | class ColorButton(QtGui.QPushButton): 8 | """ 9 | **Bases:** QtGui.QPushButton 10 | 11 | Button displaying a color and allowing the user to select a new color. 12 | 13 | ====================== ============================================================ 14 | **Signals**: 15 | sigColorChanging(self) emitted whenever a new color is picked in the color dialog 16 | sigColorChanged(self) emitted when the selected color is accepted (user clicks OK) 17 | ====================== ============================================================ 18 | """ 19 | sigColorChanging = QtCore.Signal(object) ## emitted whenever a new color is picked in the color dialog 20 | sigColorChanged = QtCore.Signal(object) ## emitted when the selected color is accepted (user clicks OK) 21 | 22 | def __init__(self, parent=None, color=(128,128,128)): 23 | QtGui.QPushButton.__init__(self, parent) 24 | self.setColor(color) 25 | self.colorDialog = QtGui.QColorDialog() 26 | self.colorDialog.setOption(QtGui.QColorDialog.ShowAlphaChannel, True) 27 | self.colorDialog.setOption(QtGui.QColorDialog.DontUseNativeDialog, True) 28 | self.colorDialog.currentColorChanged.connect(self.dialogColorChanged) 29 | self.colorDialog.rejected.connect(self.colorRejected) 30 | self.colorDialog.colorSelected.connect(self.colorSelected) 31 | #QtCore.QObject.connect(self.colorDialog, QtCore.SIGNAL('currentColorChanged(const QColor&)'), self.currentColorChanged) 32 | #QtCore.QObject.connect(self.colorDialog, QtCore.SIGNAL('rejected()'), self.currentColorRejected) 33 | self.clicked.connect(self.selectColor) 34 | self.setMinimumHeight(15) 35 | self.setMinimumWidth(15) 36 | 37 | def paintEvent(self, ev): 38 | QtGui.QPushButton.paintEvent(self, ev) 39 | p = QtGui.QPainter(self) 40 | rect = self.rect().adjusted(6, 6, -6, -6) 41 | ## draw white base, then texture for indicating transparency, then actual color 42 | p.setBrush(functions.mkBrush('w')) 43 | p.drawRect(rect) 44 | p.setBrush(QtGui.QBrush(QtCore.Qt.DiagCrossPattern)) 45 | p.drawRect(rect) 46 | p.setBrush(functions.mkBrush(self._color)) 47 | p.drawRect(rect) 48 | p.end() 49 | 50 | def setColor(self, color, finished=True): 51 | """Sets the button's color and emits both sigColorChanged and sigColorChanging.""" 52 | self._color = functions.mkColor(color) 53 | if finished: 54 | self.sigColorChanged.emit(self) 55 | else: 56 | self.sigColorChanging.emit(self) 57 | self.update() 58 | 59 | def selectColor(self): 60 | self.origColor = self.color() 61 | self.colorDialog.setCurrentColor(self.color()) 62 | self.colorDialog.open() 63 | 64 | def dialogColorChanged(self, color): 65 | if color.isValid(): 66 | self.setColor(color, finished=False) 67 | 68 | def colorRejected(self): 69 | self.setColor(self.origColor, finished=False) 70 | 71 | def colorSelected(self, color): 72 | self.setColor(self._color, finished=True) 73 | 74 | def saveState(self): 75 | return functions.colorTuple(self._color) 76 | 77 | def restoreState(self, state): 78 | self.setColor(state) 79 | 80 | def color(self, mode='qcolor'): 81 | color = functions.mkColor(self._color) 82 | if mode == 'qcolor': 83 | return color 84 | elif mode == 'byte': 85 | return (color.red(), color.green(), color.blue(), color.alpha()) 86 | elif mode == 'float': 87 | return (color.red()/255., color.green()/255., color.blue()/255., color.alpha()/255.) 88 | 89 | def widgetGroupInterface(self): 90 | return (self.sigColorChanged, ColorButton.saveState, ColorButton.restoreState) 91 | 92 | -------------------------------------------------------------------------------- /gui/pyqtgraph/widgets/PlotWidget.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | PlotWidget.py - Convenience class--GraphicsView widget displaying a single PlotItem 4 | Copyright 2010 Luke Campagnola 5 | Distributed under MIT/X11 license. See license.txt for more infomation. 6 | """ 7 | 8 | from pyqtgraph.Qt import QtCore, QtGui 9 | from .GraphicsView import * 10 | from pyqtgraph.graphicsItems.PlotItem import * 11 | 12 | __all__ = ['PlotWidget'] 13 | class PlotWidget(GraphicsView): 14 | 15 | #sigRangeChanged = QtCore.Signal(object, object) ## already defined in GraphicsView 16 | 17 | """ 18 | :class:`GraphicsView ` widget with a single 19 | :class:`PlotItem ` inside. 20 | 21 | The following methods are wrapped directly from PlotItem: 22 | :func:`addItem `, 23 | :func:`removeItem `, 24 | :func:`clear `, 25 | :func:`setXRange `, 26 | :func:`setYRange `, 27 | :func:`setRange `, 28 | :func:`autoRange `, 29 | :func:`setXLink `, 30 | :func:`setYLink `, 31 | :func:`viewRect `, 32 | :func:`setMouseEnabled `, 33 | :func:`enableAutoRange `, 34 | :func:`disableAutoRange `, 35 | :func:`setAspectLocked `, 36 | :func:`register `, 37 | :func:`unregister ` 38 | 39 | 40 | For all 41 | other methods, use :func:`getPlotItem `. 42 | """ 43 | def __init__(self, parent=None, background='default', **kargs): 44 | """When initializing PlotWidget, *parent* and *background* are passed to 45 | :func:`GraphicsWidget.__init__() ` 46 | and all others are passed 47 | to :func:`PlotItem.__init__() `.""" 48 | GraphicsView.__init__(self, parent, background=background) 49 | self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) 50 | self.enableMouse(False) 51 | self.plotItem = PlotItem(**kargs) 52 | self.setCentralItem(self.plotItem) 53 | ## Explicitly wrap methods from plotItem 54 | ## NOTE: If you change this list, update the documentation above as well. 55 | for m in ['addItem', 'removeItem', 'autoRange', 'clear', 'setXRange', 'setYRange', 'setRange', 'setAspectLocked', 'setMouseEnabled', 'setXLink', 'setYLink', 'enableAutoRange', 'disableAutoRange', 'register', 'unregister', 'viewRect']: 56 | setattr(self, m, getattr(self.plotItem, m)) 57 | #QtCore.QObject.connect(self.plotItem, QtCore.SIGNAL('viewChanged'), self.viewChanged) 58 | self.plotItem.sigRangeChanged.connect(self.viewRangeChanged) 59 | 60 | def close(self): 61 | self.plotItem.close() 62 | self.plotItem = None 63 | #self.scene().clear() 64 | #self.mPlotItem.close() 65 | self.setParent(None) 66 | GraphicsView.close(self) 67 | 68 | def __getattr__(self, attr): ## implicitly wrap methods from plotItem 69 | if hasattr(self.plotItem, attr): 70 | m = getattr(self.plotItem, attr) 71 | if hasattr(m, '__call__'): 72 | return m 73 | raise NameError(attr) 74 | 75 | def viewRangeChanged(self, view, range): 76 | #self.emit(QtCore.SIGNAL('viewChanged'), *args) 77 | self.sigRangeChanged.emit(self, range) 78 | 79 | def widgetGroupInterface(self): 80 | return (None, PlotWidget.saveState, PlotWidget.restoreState) 81 | 82 | def saveState(self): 83 | return self.plotItem.saveState() 84 | 85 | def restoreState(self, state): 86 | return self.plotItem.restoreState(state) 87 | 88 | def getPlotItem(self): 89 | """Return the PlotItem contained within.""" 90 | return self.plotItem 91 | 92 | 93 | -------------------------------------------------------------------------------- /gui/pyqtgraph/opengl/items/GLLinePlotItem.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | from OpenGL.arrays import vbo 3 | from .. GLGraphicsItem import GLGraphicsItem 4 | from .. import shaders 5 | from pyqtgraph import QtGui 6 | import numpy as np 7 | 8 | __all__ = ['GLLinePlotItem'] 9 | 10 | class GLLinePlotItem(GLGraphicsItem): 11 | """Draws line plots in 3D.""" 12 | 13 | def __init__(self, **kwds): 14 | """All keyword arguments are passed to setData()""" 15 | GLGraphicsItem.__init__(self) 16 | glopts = kwds.pop('glOptions', 'additive') 17 | self.setGLOptions(glopts) 18 | self.pos = None 19 | self.width = 1. 20 | self.color = (1.0,1.0,1.0,1.0) 21 | self.setData(**kwds) 22 | 23 | def setData(self, **kwds): 24 | """ 25 | Update the data displayed by this item. All arguments are optional; 26 | for example it is allowed to update vertex positions while leaving 27 | colors unchanged, etc. 28 | 29 | ==================== ================================================== 30 | Arguments: 31 | ------------------------------------------------------------------------ 32 | pos (N,3) array of floats specifying point locations. 33 | color (N,4) array of floats (0.0-1.0) or 34 | tuple of floats specifying 35 | a single color for the entire item. 36 | width float specifying line width 37 | antialias enables smooth line drawing 38 | ==================== ================================================== 39 | """ 40 | args = ['pos', 'color', 'width', 'connected', 'antialias'] 41 | for k in kwds.keys(): 42 | if k not in args: 43 | raise Exception('Invalid keyword argument: %s (allowed arguments are %s)' % (k, str(args))) 44 | self.antialias = False 45 | for arg in args: 46 | if arg in kwds: 47 | setattr(self, arg, kwds[arg]) 48 | #self.vbo.pop(arg, None) 49 | self.update() 50 | 51 | def initializeGL(self): 52 | pass 53 | 54 | #def setupGLState(self): 55 | #"""Prepare OpenGL state for drawing. This function is called immediately before painting.""" 56 | ##glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ## requires z-sorting to render properly. 57 | #glBlendFunc(GL_SRC_ALPHA, GL_ONE) 58 | #glEnable( GL_BLEND ) 59 | #glEnable( GL_ALPHA_TEST ) 60 | #glDisable( GL_DEPTH_TEST ) 61 | 62 | ##glEnable( GL_POINT_SMOOTH ) 63 | 64 | ##glHint(GL_POINT_SMOOTH_HINT, GL_NICEST) 65 | ##glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, (0, 0, -1e-3)) 66 | ##glPointParameterfv(GL_POINT_SIZE_MAX, (65500,)) 67 | ##glPointParameterfv(GL_POINT_SIZE_MIN, (0,)) 68 | 69 | def paint(self): 70 | if self.pos is None: 71 | return 72 | self.setupGLState() 73 | 74 | glEnableClientState(GL_VERTEX_ARRAY) 75 | 76 | try: 77 | glVertexPointerf(self.pos) 78 | 79 | if isinstance(self.color, np.ndarray): 80 | glEnableClientState(GL_COLOR_ARRAY) 81 | glColorPointerf(self.color) 82 | else: 83 | if isinstance(self.color, QtGui.QColor): 84 | glColor4f(*fn.glColor(self.color)) 85 | else: 86 | glColor4f(*self.color) 87 | glLineWidth(self.width) 88 | #glPointSize(self.width) 89 | 90 | if self.antialias: 91 | glEnable(GL_LINE_SMOOTH) 92 | glEnable(GL_BLEND) 93 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 94 | glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); 95 | 96 | glDrawArrays(GL_LINE_STRIP, 0, int(self.pos.size / self.pos.shape[-1])) 97 | finally: 98 | glDisableClientState(GL_COLOR_ARRAY) 99 | glDisableClientState(GL_VERTEX_ARRAY) 100 | 101 | 102 | -------------------------------------------------------------------------------- /gui/pyqtgraph/graphicsItems/VTickGroup.py: -------------------------------------------------------------------------------- 1 | if __name__ == '__main__': 2 | import os, sys 3 | path = os.path.abspath(os.path.dirname(__file__)) 4 | sys.path.insert(0, os.path.join(path, '..', '..')) 5 | 6 | from pyqtgraph.Qt import QtGui, QtCore 7 | import pyqtgraph.functions as fn 8 | import weakref 9 | from .UIGraphicsItem import UIGraphicsItem 10 | 11 | __all__ = ['VTickGroup'] 12 | class VTickGroup(UIGraphicsItem): 13 | """ 14 | **Bases:** :class:`UIGraphicsItem ` 15 | 16 | Draws a set of tick marks which always occupy the same vertical range of the view, 17 | but have x coordinates relative to the data within the view. 18 | 19 | """ 20 | def __init__(self, xvals=None, yrange=None, pen=None): 21 | """ 22 | ============= =================================================================== 23 | **Arguments** 24 | xvals A list of x values (in data coordinates) at which to draw ticks. 25 | yrange A list of [low, high] limits for the tick. 0 is the bottom of 26 | the view, 1 is the top. [0.8, 1] would draw ticks in the top 27 | fifth of the view. 28 | pen The pen to use for drawing ticks. Default is grey. Can be specified 29 | as any argument valid for :func:`mkPen` 30 | ============= =================================================================== 31 | """ 32 | if yrange is None: 33 | yrange = [0, 1] 34 | if xvals is None: 35 | xvals = [] 36 | 37 | UIGraphicsItem.__init__(self) 38 | 39 | if pen is None: 40 | pen = (200, 200, 200) 41 | 42 | self.path = QtGui.QGraphicsPathItem() 43 | 44 | self.ticks = [] 45 | self.xvals = [] 46 | self.yrange = [0,1] 47 | self.setPen(pen) 48 | self.setYRange(yrange) 49 | self.setXVals(xvals) 50 | 51 | def setPen(self, *args, **kwargs): 52 | """Set the pen to use for drawing ticks. Can be specified as any arguments valid 53 | for :func:`mkPen`""" 54 | self.pen = fn.mkPen(*args, **kwargs) 55 | 56 | def setXVals(self, vals): 57 | """Set the x values for the ticks. 58 | 59 | ============= ===================================================================== 60 | **Arguments** 61 | vals A list of x values (in data/plot coordinates) at which to draw ticks. 62 | ============= ===================================================================== 63 | """ 64 | self.xvals = vals 65 | self.rebuildTicks() 66 | #self.valid = False 67 | 68 | def setYRange(self, vals): 69 | """Set the y range [low, high] that the ticks are drawn on. 0 is the bottom of 70 | the view, 1 is the top.""" 71 | self.yrange = vals 72 | self.rebuildTicks() 73 | 74 | def dataBounds(self, *args, **kargs): 75 | return None ## item should never affect view autoscaling 76 | 77 | def yRange(self): 78 | return self.yrange 79 | 80 | def rebuildTicks(self): 81 | self.path = QtGui.QPainterPath() 82 | yrange = self.yRange() 83 | for x in self.xvals: 84 | self.path.moveTo(x, 0.) 85 | self.path.lineTo(x, 1.) 86 | 87 | def paint(self, p, *args): 88 | UIGraphicsItem.paint(self, p, *args) 89 | 90 | br = self.boundingRect() 91 | h = br.height() 92 | br.setY(br.y() + self.yrange[0] * h) 93 | br.setHeight(h - (1.0-self.yrange[1]) * h) 94 | p.translate(0, br.y()) 95 | p.scale(1.0, br.height()) 96 | p.setPen(self.pen) 97 | p.drawPath(self.path) 98 | 99 | 100 | if __name__ == '__main__': 101 | app = QtGui.QApplication([]) 102 | import pyqtgraph as pg 103 | vt = VTickGroup([1,3,4,7,9], [0.8, 1.0]) 104 | p = pg.plot() 105 | p.addItem(vt) 106 | 107 | if sys.flags.interactive == 0: 108 | app.exec_() 109 | 110 | 111 | 112 | 113 | --------------------------------------------------------------------------------