class Base(object): def __init__(self, data, linetype=Point(), shaders=None): self.data = data self._model = m.Identity() self._plot_prop = linetype self._shaders = Shaders() if shaders is not None: for v in shaders: self._shaders += v def createShaders(self, parent): if len(self._shaders) == 0: self._shaders += t.shader_path("basic.vsh") self._shaders += t.shader_path("basic.fsh") self._shaders.link() def show(self, parent): if self._modified_data: # self._plot_prop.init() pass GL.glEnable(GL.GL_DEPTH_TEST) GL.glClear(GL.GL_DEPTH_BUFFER_BIT | GL.GL_COLOR_BUFFER_BIT) matrice = parent._view * self._model self._shaders.bind() self._shaders.setUniformValue("modelview", matrice) self._shaders.setUniformValue("projection", parent._projection) self._shaders.enableAttributeArray("position") self._shaders.setAttributeArray("position", self._data) self._plot_prop(self._data) self._shaders.disableAttributeArray("position") self._shaders.release() @property def data(self): self._modified_data = True return self._data @data.setter def data(self, val): self._modified_data = True if len(val.shape) != 1: self._data = val.flatten() else: self._data = val @property def model(self): return self._model @model.setter def model(self, model): self._model = model @property def shaders(self): return self._shaders def __lshift__(self, inst): self._plot_prop = inst
class Widget(object): def __init__(self): # the mesh used to draw the widget on the screen self._mesh = np.array( [0., 0., 0.0, 0., 1, 0.0, 1, 1, 0.0, 1, 0, 0.0], dtype=np.float32, ) self._indices = np.array([0, 1, 2, 3], dtype=np.uint32) self._npoints = len(self._indices) # the upper left corner of the widget self._corner = Vector(0, 0, dtype=np.float32) # the size of the widget self._size = Vector(1., 1., dtype=np.float32) self._minWidth, self._minHeight = 0., 0. # for borders self._borders = [10, 10] # for events self._mousePress = False self._mousePressBorders = False self._mouse = Vector(0., 0., dtype=np.float32) self._mouseOffset = Vector(0., 0., dtype=np.float32) # init shaders self._shaders = Shaders() # the matrix model self._model = m.Identity() # a list of children object self._children = [] # set default padding and margin for the widget self.padding = 5 self.margin = 3 # set the size_hint self.size_hint = None # set the parent self._parent = None def addWidget(self, widget): """ Add a widget in the list of children and set correctly sizes accordingly to the parent. """ # set the parent of the widget widget.parent = self # append the widget to children self._children.append(widget) @property def parent(self): return self._parent @parent.setter def parent(self, parent): self._parent = parent @property def minWidth(self): return self._minWidth @minWidth.setter def minWidth(self, minWidth): self._minWidth = minWidth if self.parent is not None: self.parent.minWidth = float(self._minWidth + self.margin_x.sum()) self.width = self.width @property def minHeight(self): return self._minHeight @minHeight.setter def minHeight(self, minHeight): self._minHeight = minHeight if self.parent is not None: self.parent.minHeight = float( self._minHeight + self.margin_y.sum() ) self.height = self.height @property def x_border(self): return self._x_border @x_border.setter def x_border(self, x_border): self._x_border = x_border self._border[0] = self._x_border @property def y_border(self): return self._y_border @y_border.setter def y_border(self, y_border): self._y_border = y_border self._border[1] = self._y_border @property def width(self): return self._size[0] @width.setter def width(self, width): self._size[0] = width if self._size[0] <= self.minWidth: self._size[0] = self.minWidth if self.parent is not None: self.parent.width = self._size[0] @property def height(self): return self._size[1] @height.setter def height(self, height): self._size[1] = height if self._size[1] < self.minHeight: self._size[1] = self.minHeight if self.parent is not None: self.parent.height = self._size[1] @property def x(self): return self._corner[0] @x.setter def x(self, x): self._corner[0] = x @property def y(self): return self._corner[1] @y.setter def y(self, y): self._corner[1] = y @property def size_hint(self): return self._size_hint @size_hint.setter def size_hint(self, size_hint): self._size_hint = [size_hint] * 2 @property def size_hint_x(self): return self._size_hint[0] @size_hint_x.setter def size_hint_x(self, size_hint_x): self._size_hint[0] = size_hint_x @property def size_hint_y(self): return self._size_hint[1] @size_hint_y.setter def size_hint_y(self, size_hint_y): self._size_hint[1] = size_hint_y @property def padding(self): return self._padding @padding.setter def padding(self, padding): self._padding = Vector(*[padding] * 4, dtype=np.float32) @property def padding_x(self): return self._padding[:2] @padding_x.setter def padding_x(self, padding_x): self._padding[:2] = padding_x @property def padding_y(self): return self._padding[2:] @padding_y.setter def padding_y(self, padding_y): self._padding[2:] = padding_y @property def padding_left(self): return self._padding[0] @padding_left.setter def padding_left(self, padding_left): self._padding[0] = padding_left @property def padding_right(self): return self._padding[1] @padding_right.setter def padding_right(self, padding_right): self._padding[1] = padding_right @property def padding_top(self): return self._padding[2] @padding_top.setter def padding_top(self, padding_top): self._padding[2] = padding_top @property def padding_bottom(self): return self._padding[3] @padding_bottom.setter def padding_bottom(self, padding_bottom): self._padding[3] = padding_bottom @property def margin(self): return self._margin @margin.setter def margin(self, margin): self._margin = Vector(*[margin] * 4, dtype=np.float32) @property def margin_x(self): return self._margin[:2] @margin_x.setter def margin_x(self, margin_x): self._margin[:2] = margin_x @property def margin_y(self): return self._margin[2:] @margin_y.setter def margin_y(self, margin_y): self._margin[2:] = margin_y @property def margin_left(self): return self._margin[0] @margin_left.setter def margin_left(self, margin_left): self._margin[0] = margin_left @property def margin_right(self): return self._margin[1] @margin_right.setter def margin_right(self, margin_right): self._margin[1] = margin_right @property def margin_top(self): return self._margin[2] @margin_top.setter def margin_top(self, margin_top): self._margin[2] = margin_top @property def margin_bottom(self): return self._margin[3] @margin_bottom.setter def margin_bottom(self, margin_bottom): self._margin[3] = margin_bottom def createShaders(self): self._shaders += t.shader_path("widget/widget.vsh") self._shaders += t.shader_path("widget/widget.fsh") # create buffers self._vertices = VBO(VERTEX_BUFFER) self._index = VBO(INDEX_BUFFER) self._vertices.create() self._index.create() # allocate buffers self._vertices.bind() self._vertices.allocate( self._mesh, len(self._mesh) * 4 ) self._vertices.release() self._index.bind() self._index.allocate( self._indices, len(self._indices) * 4 ) self._index.release() for widget in self._children: widget.createShaders() def draw(self, parent): GL.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL) GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA) GL.glEnable(GL.GL_BLEND) self._shaders.bind() self._shaders.setUniformValue( "modelview", parent._widget_projection * self._model ) self._shaders.setUniformValue( "corner", self._corner, ) self._shaders.setUniformValue( "size", self._size, ) self._vertices.bind() self._shaders.enableAttributeArray("window") self._shaders.setAttributeBuffer( "window", self._mesh, ) self._vertices.release() self._index.bind() GL.glDrawElements( GL.GL_QUADS, self._npoints, GL.GL_UNSIGNED_INT, None ) self._index.release() self._shaders.disableAttributeArray("window") self._shaders.release() for widget in self._children: widget.draw(parent) def mouseEvent(self, event): for widget in self._children: if widget.mouseEvent(event): return True def keyEvent(self, event): for widget in self._children: if widget.keyEvent(event): return True def wheelEvent(self, event): for widget in self._children: if widget.wheelEvent(event): return True def inside(self, x, y): """ Method returning true if the widget accepts the events because the mouse is over it, else returns false. """ return ( self._corner[0] <= x <= self._corner[0] + self._size[0] and self._corner[1] <= y <= self._corner[1] + self._size[1] ) def _inside_border(self, x, y): return ( self._corner[0] + self._size[0] - self._borders[0] <= x <= self._corner[0] + self._size[0] and self._corner[1] + self._size[1] - self._borders[1] <= y <= self._corner[1] + self._size[1] )
class Mock(ReadMock): def __init__(self, *args, **kwargs): # set the reader super(Mock, self).__init__(*args, **kwargs) self._projections = ["Celestial sphere", "Redshift space", "Cartesian"] self.widgetChanged = Signal() self.widgetChanged.connect(self.updateWidget) # load data from mock catalogue self._load_data() # make cartesian projection by default self._projection_cartesian() # colormap colormap = getattr(CM, "LinearInterpolation") self._colormap = colormap(self._data[self._quantity].values) self._callback_colormap() self._colormap.changed.connect(self._callback_colormap) self._voxelSize = 0.01 self._voxelSize_max = 0.05 self._shaders = Shaders() self._shaders += t.shader_path("reader/mock/couleurs.vsh") self._shaders += t.shader_path("reader/mock/couleurs.fsh") def _callback_colormap(self): self._color = self._colormap(self._data[self._quantity].values) def _load_data(self): # store the data of the mock catalogue self._data = self.__call__( select="positions_x, positions_y, positions_z, alpha, delta, " + "redshift" ) # rescale data for i in "xyz": field = "positions_{0}".format(i) self._data[field] = ( self._data[field] - self._data[field].min() ) / (self._data[field].max() - self._data[field].min()) field = "redshift" self._quantity = field self._data[field] = ( self._data[field] - self._data[field].min() ) / (self._data[field].max() - self._data[field].min()) def createShaders(self, parent): GL.glEnable(GL.GL_PROGRAM_POINT_SIZE) GL.glEnable(GL.GL_POINT_SPRITE) GL.glEnable(GL.GL_DEPTH_TEST) GL.glEnable(GL.GL_BLEND) GL.glDepthMask(GL.GL_FALSE) def show(self, parent): GL.glClear(GL.GL_DEPTH_BUFFER_BIT | GL.GL_COLOR_BUFFER_BIT) matrice = parent._view * parent._model self._shaders.bind() self._shaders.setUniformValue("modelview", matrice) self._shaders.setUniformValue("projection", parent._projection) self._shaders.setUniformValue("screenSize", parent._screensize) self._shaders.setUniformValue("voxelSize", Vector(self._voxelSize)) self._shaders.enableAttributeArray("position") self._shaders.setAttributeArray( "position", self._pos, ) self._shaders.enableAttributeArray("color") self._shaders.setAttributeArray( "color", self._color, ) GL.glDrawArrays(GL.GL_POINTS, 0, self._pos.shape[0] // 3) self._shaders.disableAttributeArray("position") self._shaders.disableAttributeArray("color") self._shaders.release() def createWidget(self, title="Mock catalogue controls", parent=None): pass # create a dialig window # self._dialog = Qt.QDialog(parent=parent) # self._dialog.setWindowOpacity(0.4) # self._dialog.setWindowTitle(title) # # set a layout # self._dialog.setLayout(Qt.QVBoxLayout()) # self.updateWidget() # return self._dialog def updateWidget(self): pass # get the layout and clear children # try: # layout = self._dialog.layout() # while layout.takeAt(0): # child = layout.takeAt(0) # del child # except: # pass # # create a slider # slider = Qt.QSlider(QtCore.Qt.Horizontal) # slider.valueChanged[int].connect(self._set_voxelsize) # # add a label for slider and the slider # self._dialog.layout().addWidget( # Qt.QLabel("Point size") # ) # self._dialog.layout().addWidget(slider) # # create a list of projections # combo = Qt.QComboBox() # for projection in self._projections: # combo.addItem(projection) # self._dialog.layout().addWidget( # Qt.QLabel("Kind of projections") # ) # combo.activated[str].connect(self._projection_changed) # self._dialog.layout().addWidget(combo) # # get the quantity to color # self._dialog.layout().addWidget(Qt.QLabel("Colormap quantity")) # lineInput = Qt.QLineEdit() # def _getText(): # text = lineInput.text() # self._load_quantity(text) # lineInput.returnPressed.connect(_getText) # self._dialog.layout().addWidget(lineInput) # # create a list of colormaps # combomap = Qt.QComboBox() # for colormap in CM.ColorMap.__subclasses__(): # combomap.addItem(colormap.__name__) # self._dialog.layout().addWidget( # Qt.QLabel("Kind of colormap") # ) # combomap.activated[str].connect(self._colormap_changed) # self._dialog.layout().addWidget(combomap) # # add the widget of the colormap # self._dialog.layout().addWidget( # Qt.QLabel("Colormap controls") # ) # self._colormap.createWidget(self._dialog.layout()) def _load_quantity(self, quantity): if quantity not in self._data: try: self._data[quantity] = self.__call__(select=quantity) self._quantity = quantity self._colormap.data = self._data[self._quantity].values self._callback_colormap() except: pass def _colormap_changed(self, text): # get the new colormap colormap = getattr(CM, text) self._colormap = colormap(self._data[self._quantity].values) self._callback_colormap() self._colormap.changed.connect(self._callback_colormap) self.widgetChanged() def _projection_changed(self, text): # get the method to call according to the projection projection = text.lower().replace(" ", "_") method = getattr(self, "_projection_" + projection) method() def _projection_celestial_sphere(self): X = np.cos(self._data["alpha"]) * np.cos(self._data["delta"]) Y = np.sin(self._data["alpha"]) * np.cos(self._data["delta"]) Z = np.sin(self._data["delta"]) self._pos = np.vstack([X, Y, Z]).T.astype(np.float32).flatten() def _projection_cartesian(self): self._pos = np.vstack([ self._data["positions_x"].values, self._data["positions_y"].values, self._data["positions_z"].values, ]).T.astype(np.float32).flatten() def _projection_redshift_space(self): redshift = self._data["redshift"] X = np.cos(self._data["alpha"]) * np.cos(self._data["delta"]) Y = np.sin(self._data["alpha"]) * np.cos(self._data["delta"]) Z = np.sin(self._data["delta"]) self._pos = np.vstack( [ redshift * X, redshift * Y, redshift * Z ] ).T.astype(np.float32).flatten() def _set_voxelsize(self, value): self._voxelSize = value / 100. * self._voxelSize_max