Commit 47db59a2 authored by JosefBrandt's avatar JosefBrandt

ParticlePainting Working, still bug in contour selection...
parent 9ae5cb90
......@@ -113,11 +113,18 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
self.navigationGroup = QtWidgets.QGroupBox('Navigate through polymers')
self.navigationGroup.setDisabled(True)
navigationLayout = QtWidgets.QHBoxLayout()
self.specNumberSelector = QtWidgets.QSpinBox()
self.specNumberSelector.setMinimumWidth(150)
self.specNumberSelector.setMinimum(1)
self.specNumberSelector.setMaximum(1E6)
self.jumpToSpecBtn = QtWidgets.QPushButton('Jump To Spectrum of Number:')
self.jumpToSpecBtn.released.connect(self.jumpToSpectrumOfNumber)
self.typeSelectorCombo = QtWidgets.QComboBox()
self.typeSelectorCombo.currentIndexChanged.connect(self.displayNewPolymerType)
self.typeSelectorCombo.setMinimumWidth(150)
self.particleSelector = QtWidgets.QSpinBox()
self.particleSelector.valueChanged.connect(self.updateToSelectedParticle)
self.particleSelector.valueChanged.connect(self.updateSpecPlotToSelectedParticle)
self.particleNumberLabel = QtWidgets.QLabel('of xx particles; ')
self.spectrumSelector = QtWidgets.QSpinBox()
......@@ -128,6 +135,8 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
spinbox.setSingleStep(1)
spinbox.setValue(1)
navigationLayout.addWidget(self.jumpToSpecBtn)
navigationLayout.addWidget(self.specNumberSelector)
navigationLayout.addWidget(QtWidgets.QLabel('Select Polymer Type:'))
navigationLayout.addWidget(self.typeSelectorCombo)
navigationLayout.addStretch()
......@@ -214,7 +223,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
self.updateDisplays()
self.initializeSpecPlot()
self.displayNewPolymerType()
self.updateToSelectedParticle()
self.updateSpecPlotToSelectedParticle()
# self.createPolymerOverlay()
def createActions(self):
......@@ -390,16 +399,16 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
self.createHistogramData()
t0 = time.time()
self.updateTypeHistogram()
print('update type hist:', round((time.time()-t0)*1000))
print('update type hist: {} ms'.format(round((time.time()-t0)*1000)))
t0 = time.time()
self.updateSizeHistogram()
print('update size hist:', round((time.time()-t0)*1000))
print('update size hist: {} ms'.format(round((time.time()-t0)*1000)))
t0 = time.time()
self.updateContourColors()
print('update contours:', round((time.time()-t0)*1000))
print('update contours: {} ms'.format(round((time.time()-t0)*1000)))
t0 = time.time()
self.updateLegend()
print('update legend:', round((time.time()-t0)*1000))
print('update legend: {} ms'.format(round((time.time()-t0)*1000)))
self.dataset.save()
def initializeSpecPlot(self):
......@@ -474,7 +483,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
def updateContourColors(self):
contours = self.parent.contourItems
alpha = (128 if self.transpAct.isChecked() else 255)
alpha = (64 if self.transpAct.isChecked() else 255)
selectedPolymers = self.getSelectedPolymers()
for particleIndex, contour in enumerate(contours):
......@@ -501,10 +510,22 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
def getSelectedPolymers(self):
return [checkbox.text() for checkbox in self.polymerCheckBoxes if checkbox.isChecked()]
def jumpToSpectrumOfNumber(self):
specIndex = self.specNumberSelector.value()-1
assert specIndex is not None
partIndex = self.particleContainer.getParticleIndexContainingSpecIndex(specIndex)
assignment = self.particleContainer.getParticleAssignmentByIndex(partIndex)
self.typeSelectorCombo.setCurrentText(assignment)
#TODO: Connect to widget that allows jumping to particular particle
def selectParticleIndex(self, particleIndex, centerOn=True):
self.typeSelectorCombo.currentIndexChanged.disconnect()
partIndices = self.particleContainer.getIndicesOfParticleType(assignment)
self.particleSelector.setValue(partIndices.index(partIndex)+1)
specIndices = self.particleContainer.getSpectraIndicesOfParticle(partIndex)
self.spectrumSelector.setValue(specIndices.index(specIndex)+1)
def selectParticleOfIndex(self, particleIndex, centerOn=True):
assignment = self.particleContainer.getParticleAssignmentByIndex(particleIndex)
self.typeSelectorCombo.setCurrentText(assignment)
self.typeSelectorCombo.currentIndexChanged.connect(self.displayNewPolymerType)
......@@ -512,9 +533,9 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
self.particleSelector.valueChanged.disconnect()
particleIndices = self.particleContainer.getIndicesOfParticleType(assignment)
self.particleSelector.setValue(particleIndices.index(particleIndex)+1)
self.particleSelector.valueChanged.connect(self.updateToSelectedParticle)
self.particleSelector.valueChanged.connect(self.updateSpecPlotToSelectedParticle)
self.updateToSelectedParticle(resetSpectrumCount=True, centerOn=centerOn)
self.updateSpecPlotToSelectedParticle(resetSpectrumCount=True, centerOn=centerOn)
def displayNewPolymerType(self, resetCurrentIndex=True):
polymerName = self.typeSelectorCombo.currentText()
......@@ -532,7 +553,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
self.currentSpectrumIndex = self.getSpectrumIndexFromSpectrumSelector()
self.updateSpecPlot(centerOn=False)
def updateToSelectedParticle(self, resetSpectrumCount=True, centerOn=True):
def updateSpecPlotToSelectedParticle(self, resetSpectrumCount=True, centerOn=True):
polymerName = self.typeSelectorCombo.currentText()
if polymerName != '':
self.currentParticleIndex = self.getParticleIndexFromParticleSelector()
......
......@@ -115,7 +115,12 @@ class ParticleContainer(object):
particle = self.particles[index]
assert particle.index == index, f'particle.index ({particle.index}) does match requested index in particleList ({index})'
return particle
def getParticleIndexContainingSpecIndex(self, index):
for particle in self.particles:
if index in particle.getMeasurementIndices():
return particle.index
def getNumberOfParticles(self):
return len(self.particles)
......
......@@ -21,54 +21,146 @@ If not, see <https://www.gnu.org/licenses/>.
"""
from PyQt5 import QtWidgets, QtCore, QtGui
import numpy as np
import cv2
class ParticlePainter(QtWidgets.QGraphicsItem):
def __init__(self, particleContour, pos=(0,0)):
super().__init__()
self.setZValue(1)
self.setPos(pos[0], pos[1])
self.polygon = None
self.particleContour = particleContour
def __init__(self, editorParent, contours, pos=(500,500)):
super(ParticlePainter, self).__init__()
self.editorParent = editorParent
self.viewparent = self.editorParent.viewparent
self.setZValue(5)
self.polygons = None
self.contours = contours
self.mousePos = None
self.minRadius = 1
self.minRadius = 10
self.maxRadius = 500
self.radius = 20
self.radius = 50
self.brect = QtCore.QRectF(0,0,1,1)
# self.getBrectAndPolygon()
# def getBrectAndPolygon(self):
# polygon = QtGui.QPolygonF()
# x0 = self.particleContour[:,0,0].min()
# x1 = self.particleContour[:,0,0].max()
# y0 = self.particleContour[:,0,1].min()
# y1 = self.particleContour[:,0,1].max()
# for point in self.particleContour:
# polygon.append(QtCore.QPointF(point[0,0], point[0,1]))
self.getBrectAndPolygon()
self.painting = False
self.erasing = False
# self.brect.setCoords(x0, y0, x1, y1)
# self.polygon = polygon
def getBrectAndPolygon(self):
polygons = []
x0 = None
for c in self.contours:
polygon = QtGui.QPolygonF()
if x0 is None:
x0 = c[:,0,0].min()
x1 = c[:,0,0].max()
y0 = c[:,0,1].min()
y1 = c[:,0,1].max()
else:
x0 = min(x0, c[:,0,0].min())
x1 = max(x1, c[:,0,0].max())
y0 = min(y0, c[:,0,1].min())
y1 = max(y1, c[:,0,1].max())
for ci in c:
polygon.append(QtCore.QPointF(ci[0,0],ci[0,1]))
polygons.append(polygon)
if x0 is None:
self.brect = QtCore.QRectF(0,0,1,1)
else:
self.brect.setCoords(x0,y0,x1,y1)
self.polygons = polygons
def boundingRect(self):
return self.brect
def mousePressEvent(self, event):
self.mousePos = self.viewparent.mapToScene(event.pos())
self.erasing = self.painting = False
if event.modifiers()==QtCore.Qt.ControlModifier:
self.painting = True
elif event.modifiers()==QtCore.Qt.ShiftModifier:
self.erasing = True
if self.painting or self.erasing:
drawPos = self.viewparent.mapToScene(event.pos()) - self.brect.topLeft()
self.drawParticle(drawPos)
def mouseMoveEvent(self, event):
p = event.pos()
self.brect.setCoords(p.x()-self.radius/2, p.y()-self.radius/2, p.x()+self.radius/2, p.y()+self.radius/2)
self.mousePos = p
self.mousePos = self.viewparent.mapToScene(event.pos())
self.update()
if self.painting or self.erasing:
drawPos = self.viewparent.mapToScene(event.pos()) - self.brect.topLeft()
self.drawParticle(drawPos)
def wheelEvent(self, event):
if event.angleDelta().y() > 0:
self.radius = np.clip(self.radius+1, self.minRadius, self.maxRadius)
if event.angleDelta().y() < 0:
self.radius = int(np.clip(self.radius+self.radius*0.1, self.minRadius, self.maxRadius))
else:
self.radius = int(np.clip(self.radius-self.radius*0.1, self.minRadius, self.maxRadius))
self.update()
def mouseReleaseEvent(self, event):
self.erasing = self.painting = False
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_Escape:
self.editorParent.destroyParticlePainter()
elif event.key() == QtCore.Qt.Key_Return:
self.editorParent.acceptPaintedResult()
def drawParticle(self, pos):
img, xmin, ymin, padding = self.contoursToImg(self.contours)
center = (int(pos.x()+self.radius), int(pos.y()+self.radius))
if self.painting:
cv2.circle(img, center, self.radius, 255, -1)
elif self.erasing:
cv2.circle(img, center, self.radius, 0, -1)
img = np.uint8(img)
self.contours = self.imgToCnt(img, xmin, ymin, padding)
self.getBrectAndPolygon()
self.update()
def contoursToImg(self, contours):
cnt = np.vstack(tuple(contours)) #combine contous
#draw contours
xmin, xmax = cnt[:,0,:][:, 0].min(), cnt[:,0,:][:, 0].max()
ymin, ymax = cnt[:,0,:][:, 1].min(), cnt[:,0,:][:, 1].max()
padding = self.radius+2 #pixel in each direction
rangex = int(np.round((xmax-xmin)+2*padding))
rangey = int(np.round((ymax-ymin)+2*padding))
img = np.zeros((rangey, rangex), dtype = np.uint8)
for curCnt in contours:
for i in range(len(curCnt)):
curCnt[i][0][0] -= xmin-padding
curCnt[i][0][1] -= ymin-padding
cv2.drawContours(img, [curCnt], -1, 255, -1)
cv2.drawContours(img, [curCnt], -1, 255, 1)
return img, xmin, ymin, padding
def imgToCnt(self, img, xmin, ymin, padding):
if cv2.__version__ > '3.5':
contours, hierarchy = cv2.findContours(img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
else:
self.radius = np.clip(self.radius-1, self.minRadius, self.maxRadius)
temp, contours, hierarchy = cv2.findContours(img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
def paint(self, painter, option, widget):
for contour in contours:
for i in range(len(contour)):
contour[i][0][0] += xmin-padding
contour[i][0][1] += ymin-padding
return contours
def paint(self, painter, option, widget):
painter.setPen(QtCore.Qt.white)
painter.drawRect(self.brect)
if self.mousePos is not None:
p = [self.mousePos.x(), self.mousePos.y(), self.radius]
painter.drawEllipse(p[0]-p[2], p[1]-p[2], 2*p[2], 2*p[2])
# if self.polygon is not None:
# painter.setPen(QtCore.Qt.white)
# painter.setBrush(QtGui.QColor(200, 200, 200, 128))
# painter.drawPolygon(self.polygon)
\ No newline at end of file
if self.polygons is not None:
for poly in self.polygons:
painter.setBrush(QtGui.QColor(200, 200, 255, 128))
painter.drawPolygon(poly)
\ No newline at end of file
......@@ -29,9 +29,12 @@ import numpy as np
import cv2
from PyQt5 import QtWidgets, QtCore
from analysis.particlePainter import ParticlePainter
class ParticleContextMenu(QtWidgets.QMenu):
combineParticlesSignal = QtCore.pyqtSignal(list, str)
reassignParticlesSignal = QtCore.pyqtSignal(list, str)
paintParticlesSignal = QtCore.pyqtSignal(list, str)
def __init__(self, viewparent):
super(ParticleContextMenu, self).__init__()
self.viewparent = viewparent
......@@ -41,18 +44,25 @@ class ParticleContextMenu(QtWidgets.QMenu):
def executeAtScreenPos(self, screenPos):
self.combineActs = []
self.combineMenu = QtWidgets.QMenu("Combine Particles into")
assignments = []
self.paintActs = []
self.paintMenu = QtWidgets.QMenu("Paint Mode, merge into")
selctedAssignments = []
for particleIndex in self.selectedParticleIndices:
try:
assignment = self.particleContainer.getParticleAssignmentByIndex(particleIndex)
except:
return
assignments.append(assignment)
selctedAssignments.append(assignment)
for assignment in np.unique(assignments):
for assignment in np.unique(selctedAssignments):
self.combineActs.append(self.combineMenu.addAction(assignment))
self.paintActs.append(self.paintMenu.addAction(assignment))
self.combineActs.append(self.combineMenu.addAction("other"))
self.paintActs.append(self.paintMenu.addAction("other"))
self.reassignActs = []
self.reassignMenu = QtWidgets.QMenu("Reassign particle(s) into")
......@@ -69,15 +79,19 @@ class ParticleContextMenu(QtWidgets.QMenu):
self.addMenu(self.combineMenu)
self.addMenu(self.reassignMenu)
self.addMenu(self.paintMenu)
action = self.exec_(screenPos)
if action in self.combineActs:
newAssignment = self.validifyAssignment(action.text())
self.combineParticlesSignal.emit(self.selectedParticleIndices, newAssignment)
elif action in self.reassignActs:
if action:
newAssignment = self.validifyAssignment(action.text())
self.reassignParticlesSignal.emit(self.selectedParticleIndices, newAssignment)
if action in self.combineActs:
self.combineParticlesSignal.emit(self.selectedParticleIndices, newAssignment)
elif action in self.reassignActs:
self.reassignParticlesSignal.emit(self.selectedParticleIndices, newAssignment)
elif action in self.paintActs:
self.paintParticlesSignal.emit(self.selectedParticleIndices, newAssignment)
def validifyAssignment(self, assignment):
if assignment == "other":
......@@ -85,7 +99,7 @@ class ParticleContextMenu(QtWidgets.QMenu):
return assignment
def getNewEntry(self):
text, okClicked = QtWidgets.QInputDialog.getText(QtWidgets.QWidget(), "Custom assignment", "Enter new assignment")
text, okClicked = QtWidgets.QInputDialog.getText(self.viewparent, "Custom assignment", "Enter new assignment")
if okClicked and text != '':
return text
......@@ -93,22 +107,26 @@ class ParticleContextMenu(QtWidgets.QMenu):
class ParticleEditor(QtCore.QObject):
particleContoursChanged = QtCore.pyqtSignal()
particleAssignmentChanged = QtCore.pyqtSignal()
def __init__(self, analysisparent, particleContainer):
def __init__(self, viewparent, particleContainer):
super(ParticleEditor, self).__init__()
self.particleContainer = particleContainer
self.analysisparent = analysisparent #the assigned analysis widget
self.viewparent = viewparent #the assigned analysis widget
self.backupFreq = 3 #save a backup every n actions
self.neverBackedUp = True
self.actionCounter = 0
self.storedIndices = []
self.storedAssignmend = None
def connectToSignals(self, contextMenu):
contextMenu.combineParticlesSignal.connect(self.combineParticles)
contextMenu.reassignParticlesSignal.connect(self.reassignParticles)
contextMenu.paintParticlesSignal.connect(self.paintParticles)
def createSafetyBackup(self):
self.actionCounter += 1
if self.actionCounter == self.backupFreq-1 or self.neverBackedUp:
backupname = self.analysisparent.dataset.saveBackup()
backupname = self.viewparent.dataset.saveBackup()
print('backing up as', backupname)
self.neverBackedUp = False
self.actionCounter = 0
......@@ -122,14 +140,13 @@ class ParticleEditor(QtCore.QObject):
stats = self.characterizeParticle(newContour)
self.particleContainer.mergeParticles(contourIndices, newContour, stats, newAssignment=newAssignment)
self.particleContoursChanged.emit()
# #save data
# minHQI = self.parent.hqiSpinBox.value()
# compHQI = self.parent.compHqiSpinBox.value()
# if not self.datastats.saveAnalysisResults(minHQI, compHQI):
# QtWidgets.QMessageBox.warning(self.parent, 'Error!',
# 'Data inconsistency after saving!', QtWidgets.QMessageBox.Ok,
# QtWidgets.QMessageBox.Ok)
for ind in contourIndices:
self.viewparent.removeParticleContour(ind)
self.viewparent.resetContourIndices()
self.viewparent.addParticleContour(newContour, len(self.viewparent.contourItems))
#TODO: INCLUDE SANITY CHECK!!!!!!!!!
@QtCore.pyqtSlot(list, str)
def reassignParticles(self, contourindices, newAssignment):
......@@ -139,6 +156,41 @@ class ParticleEditor(QtCore.QObject):
self.particleContainer.reassignParticleToAssignment(partIndex, newAssignment)
self.particleAssignmentChanged.emit()
@QtCore.pyqtSlot(list, str)
def paintParticles(self, contourIndices, newAssignment):
self.createSafetyBackup
self.storedIndices = contourIndices
self.storedAssignmend = newAssignment
contours = self.particleContainer.getParticleContoursByIndex(contourIndices)
self.particlePainter = ParticlePainter(self, contours)
self.viewparent.normalSize()
self.viewparent.particlePainter = self.particlePainter
self.viewparent.scene().addItem(self.particlePainter)
self.viewparent.update()
def acceptPaintedResult(self):
newContour = self.mergeContours(self.particlePainter.contours.copy())
stats = self.characterizeParticle(newContour)
self.particleContainer.mergeParticles(self.storedIndices, newContour, stats, newAssignment=self.storedAssignmend)
for ind in self.storedIndices:
self.viewparent.removeParticleContour(ind)
self.viewparent.resetContourIndices()
self.viewparent.addParticleContour(newContour, len(self.viewparent.contourItems))
#TODO: INCLUDE SANITY CHECK!!!!!!!!!
self.storedIndices = []
self.storedAssignmend = None
self.destroyParticlePainter()
def destroyParticlePainter(self):
if self.particlePainter is not None:
self.viewparent.particlePainter = None
self.viewparent.scene().removeItem(self.particlePainter)
self.viewparent.update()
self.particlePainter = None
def mergeContours(self, contours):
cnt = np.vstack(tuple(contours)) #combine contous
......@@ -177,7 +229,6 @@ class ParticleEditor(QtCore.QObject):
return newContour
def characterizeParticle(self, contours):
##characterize particle
longellipse, shortellipse = np.nan, np.nan
......
......@@ -38,8 +38,6 @@ from helperfunctions import polygoncovering, cv2imread_fix
from ramancom.configRaman import RamanConfigWin
from analysis.particleeditor import ParticleEditor
from analysis.particlePainter import ParticlePainter
class SampleView(QtWidgets.QGraphicsView):
ScalingChanged = QtCore.pyqtSignal(float)
......@@ -62,7 +60,6 @@ class SampleView(QtWidgets.QGraphicsView):
self.setRenderHint(QtGui.QPainter.Antialiasing)
self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorViewCenter)
self.disableSelection = False
self.ramanctrl = RamanControl()
self.simulatedRaman = simulatedRaman
......@@ -89,6 +86,7 @@ class SampleView(QtWidgets.QGraphicsView):
self.isblocked = False
self.contourItems = []
self.selectedParticleIndices = []
self.particlePainter = None
self.detectionwidget = None
self.ramanwidget = RamanScanUI(self.ramanctrl, None, self.logpath, self)
......@@ -101,8 +99,7 @@ class SampleView(QtWidgets.QGraphicsView):
self.darkenPixmap = False
self.microscopeMode = None
self.painter = ParticlePainter([])
self.scene().addItem(self.painter)
self.update()
def takeScreenshot(self):
......@@ -216,7 +213,6 @@ class SampleView(QtWidgets.QGraphicsView):
print('show maximized already exisiting analysiswidget')
self.analysiswidget.showMaximized()
# self.ramanwidget.setVisible(False)
if self.detectionwidget is not None:
self.detectionwidget.setVisible(False)
......@@ -321,40 +317,28 @@ class SampleView(QtWidgets.QGraphicsView):
return maxmode
def mousePressEvent(self, event):
if not self.disableSelection:
if event.button()==QtCore.Qt.MiddleButton:
self.drag = event.pos()
elif event.button()==QtCore.Qt.LeftButton:
if event.button()==QtCore.Qt.MiddleButton:
self.drag = event.pos()
elif self.particlePainter is None:
if event.button()==QtCore.Qt.LeftButton:
self.checkForContourSelection(event)
event.ignore()
elif event.button()==QtCore.Qt.LeftButton and self.mode in ["OpticalScan", "RamanScan"] \
and event.modifiers()==QtCore.Qt.ControlModifier:
p0 = self.mapToScene(event.pos())
if self.dataset is not None and self.dataset.pshift is not None:
if self.dataset.readin:
reply = QtWidgets.QMessageBox.critical(self, 'Dataset is newly read from disk!',
"Coordinate systems might have changed since. Do you want to continue with saved coordinates?",
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes:
self.dataset.readin = False
else:
return
# x, y, z = self.dataset.mapToLengthRaman([p0.x(), p0.y()],
# microscopeMode=self.microscopeMode,
# noz=(False if self.mode=="RamanScan" else True))
x, y, z = self.dataset.mapToLengthRaman([p0.x(), p0.y()], microscopeMode=self.microscopeMode, noz=False)
if z is not None:
assert z>-100.
self.ramanctrl.moveToAbsolutePosition(x, y, z)
elif event.button()==QtCore.Qt.LeftButton and self.mode=="ParticleDetection":
p0 = self.mapToScene(event.pos())
self.detectionwidget.setImageCenter([p0.x(), p0.y()])
if self.mode in ["OpticalScan", "RamanScan"] and event.modifiers()==QtCore.Qt.ControlModifier:
p0 = self.mapToScene(event.pos())
self.moveStageToPosition(p0)
elif self.mode=="ParticleDetection":
p0 = self.mapToScene(event.pos())
self.detectionwidget.setImageCenter([p0.x(), p0.y()])
else:
p0 = self.mapToScene(event.pos())
super(SampleView, self).mousePressEvent(event)
elif self.particlePainter is not None:
self.particlePainter.mousePressEvent(event)
def mouseMoveEvent(self, event):
if self.drag is not None:
p0 = event.pos()
......@@ -363,17 +347,50 @@ class SampleView(QtWidgets.QGraphicsView):
self.verticalScrollBar().setValue(move.y() + self.verticalScrollBar().value())
self.drag = p0
else:
elif self.particlePainter is None:
p0 = self.mapToScene(event.pos())
super(SampleView, self).mouseMoveEvent(event)
else:
self.particlePainter.mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.drag = None
super(SampleView, self).mouseReleaseEvent(event)
if self.particlePainter is None:
super(SampleView, self).mouseReleaseEvent(event)
else: