source: sasview/src/sas/sasgui/guiframe/local_perspectives/plotting/SectorSlicer.py @ d85c194

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since d85c194 was d85c194, checked in by Piotr Rozyczko <piotr.rozyczko@…>, 8 years ago

Remaining modules refactored

  • Property mode set to 100644
File size: 20.4 KB
RevLine 
[b40ad40]1"""
2    Sector interactor
3"""
[ef0c170]4import math
[0d9dae8]5import wx
6from BaseInteractor import _BaseInteractor
[d85c194]7from sas.sasgui.guiframe.events import NewPlotEvent
8from sas.sasgui.guiframe.events import StatusEvent
9from sas.sasgui.guiframe.events import SlicerParameterEvent
10from sas.sasgui.guiframe.events import EVT_SLICER_PARS
11from sas.sasgui.guiframe.dataFitting import Data1D
[ef0c170]12
[32c0841]13
[ef0c170]14class SectorInteractor(_BaseInteractor):
15    """
[d955bf19]16    Draw a sector slicer.Allow to performQ averaging on data 2D
[ef0c170]17    """
[32c0841]18    def __init__(self, base, axes, color='black', zorder=3):
[b40ad40]19
[ef0c170]20        _BaseInteractor.__init__(self, base, axes, color=color)
[6c0568b]21        ## Class initialization
[ef0c170]22        self.markers = []
[b40ad40]23        self.axes = axes
24        ## connect the plot to event
[ef0c170]25        self.connect = self.base.connect
[b40ad40]26
27        ## compute qmax limit to reset the graph
28        x = math.pow(max(self.base.data2D.xmax,
[32c0841]29                         math.fabs(self.base.data2D.xmin)), 2)
[b40ad40]30        y = math.pow(max(self.base.data2D.ymax,
[32c0841]31                         math.fabs(self.base.data2D.ymin)), 2)
32        self.qmax = math.sqrt(x + y)
[ef0c170]33        ## Number of points on the plot
[b783024]34        self.nbins = 20
[6c0568b]35        ## Angle of the middle line
[b40ad40]36        self.theta2 = math.pi / 3
[6c0568b]37        ## Absolute value of the Angle between the middle line and any side line
[b40ad40]38        self.phi = math.pi / 12
[6c0568b]39        ## Middle line
[b40ad40]40        self.main_line = LineInteractor(self, self.base.subplot, color='blue',
[32c0841]41                                        zorder=zorder, r=self.qmax,
[b40ad40]42                                        theta=self.theta2)
[2dda74ac]43        self.main_line.qmax = self.qmax
[6c0568b]44        ## Right Side line
[32c0841]45        self.right_line = SideInteractor(self, self.base.subplot, color='black',
[b40ad40]46                                         zorder=zorder, r=self.qmax,
47                                         phi=-1 * self.phi, theta2=self.theta2)
[2dda74ac]48        self.right_line.qmax = self.qmax
[b40ad40]49        ## Left Side line
[32c0841]50        self.left_line = SideInteractor(self, self.base.subplot, color='black',
51                                        zorder=zorder, r=self.qmax,
[b40ad40]52                                        phi=self.phi, theta2=self.theta2)
[2dda74ac]53        self.left_line.qmax = self.qmax
[b40ad40]54        ## draw the sector
[ef0c170]55        self.update()
56        self._post_data()
[6c0568b]57        ## Bind to slice parameter events
[1ce365f8]58        self.base.Bind(EVT_SLICER_PARS, self._onEVT_SLICER_PARS)
[ef0c170]59
60    def _onEVT_SLICER_PARS(self, event):
[6c0568b]61        """
[d955bf19]62        receive an event containing parameters values to reset the slicer
[b40ad40]63
64        :param event: event of type SlicerParameterEvent with params as
[d955bf19]65        attribute
[b40ad40]66
[6c0568b]67        """
[32c0841]68        wx.PostEvent(self.base.parent,
69                     StatusEvent(status="SectorSlicer._onEVT_SLICER_PARS"))
[ef0c170]70        event.Skip()
71        if event.type == self.__class__.__name__:
72            self.set_params(event.params)
73            self.base.update()
[b40ad40]74
[ef0c170]75    def set_layer(self, n):
[6c0568b]76        """
[d955bf19]77         Allow adding plot to the same panel
[b40ad40]78
[d955bf19]79        :param n: the number of layer
[b40ad40]80
[6c0568b]81        """
[ef0c170]82        self.layernum = n
83        self.update()
[b40ad40]84
[ef0c170]85    def clear(self):
[6c0568b]86        """
[d955bf19]87        Clear the slicer and all connected events related to this slicer
[6c0568b]88        """
[ef0c170]89        self.clear_markers()
90        self.main_line.clear()
91        self.left_line.clear()
92        self.right_line.clear()
[18eba35]93        self.base.connect.clearall()
[d468daa]94        self.base.Unbind(EVT_SLICER_PARS)
[b40ad40]95
[ef0c170]96    def update(self):
97        """
[d955bf19]98        Respond to changes in the model by recalculating the profiles and
99        resetting the widgets.
[ef0c170]100        """
[b40ad40]101        # Update locations
102        ## Check if the middle line was dragged and
103        #update the picture accordingly
[ef0c170]104        if self.main_line.has_move:
105            self.main_line.update()
[b40ad40]106            self.right_line.update(delta=-self.left_line.phi / 2,
[32c0841]107                                   mline=self.main_line.theta)
[b40ad40]108            self.left_line.update(delta=self.left_line.phi / 2,
109                                  mline=self.main_line.theta)
110        ## Check if the left side has moved and update the slicer accordingly
[ef0c170]111        if self.left_line.has_move:
112            self.main_line.update()
[32c0841]113            self.left_line.update(phi=None, delta=None, mline=self.main_line,
114                                  side=True, left=True)
115            self.right_line.update(phi=self.left_line.phi, delta=None,
[b40ad40]116                                   mline=self.main_line, side=True,
117                                   left=False, right=True)
118        ## Check if the right side line has moved and
[32c0841]119        #update the slicer accordingly
[ef0c170]120        if self.right_line.has_move:
121            self.main_line.update()
[32c0841]122            self.right_line.update(phi=None, delta=None, mline=self.main_line,
123                                   side=True, left=False, right=True)
124            self.left_line.update(phi=self.right_line.phi, delta=None,
[b40ad40]125                                  mline=self.main_line, side=True, left=False)
126
[ef0c170]127    def save(self, ev):
128        """
129        Remember the roughness for this layer and the next so that we
130        can restore on Esc.
131        """
132        self.base.freeze_axes()
[6c0568b]133        self.main_line.save(ev)
134        self.right_line.save(ev)
135        self.left_line.save(ev)
[ef0c170]136
137    def _post_data(self, nbins=None):
[6c0568b]138        """
[d955bf19]139        compute sector averaging of data2D into data1D
[b40ad40]140
[d955bf19]141        :param nbins: the number of point to plot for the average 1D data
[6c0568b]142        """
143        ## get the data2D to average
[ef0c170]144        data = self.base.data2D
145        # If we have no data, just return
146        if data == None:
147            return
[6c0568b]148        ## Averaging
[b699768]149        from sas.sascalc.dataloader.manipulations import SectorQ
[b40ad40]150        radius = self.qmax
151        phimin = -self.left_line.phi + self.main_line.theta
[6c0568b]152        phimax = self.left_line.phi + self.main_line.theta
[32c0841]153        if nbins == None:
[1ce365f8]154            nbins = 20
[32c0841]155        sect = SectorQ(r_min=0.0, r_max=radius,
[b40ad40]156                       phi_min=phimin + math.pi,
157                       phi_max=phimax + math.pi, nbins=nbins)
158
[ef0c170]159        sector = sect(self.base.data2D)
[6c0568b]160        ##Create 1D data resulting from average
[b40ad40]161
[32c0841]162        if hasattr(sector, "dxl"):
163            dxl = sector.dxl
[ef0c170]164        else:
[32c0841]165            dxl = None
166        if hasattr(sector, "dxw"):
167            dxw = sector.dxw
[ef0c170]168        else:
[32c0841]169            dxw = None
[21969a4a]170        new_plot = Data1D(x=sector.x, y=sector.y, dy=sector.dy, dx=sector.dx)
[4ac8556]171        new_plot.dxl = dxl
172        new_plot.dxw = dxw
[32c0841]173        new_plot.name = "SectorQ" + "(" + self.base.data2D.name + ")"
174        new_plot.source = self.base.data2D.source
[8b30e62]175        #new_plot.info=self.base.data2D.info
[ef0c170]176        new_plot.interactive = True
[32c0841]177        new_plot.detector = self.base.data2D.detector
[21969a4a]178        ## If the data file does not tell us what the axes are, just assume...
179        new_plot.xaxis("\\rm{Q}", "A^{-1}")
[7f59ee8e]180        new_plot.yaxis("\\rm{Intensity}", "cm^{-1}")
[fcf072d]181        if hasattr(data, "scale") and data.scale == 'linear' and \
182                self.base.data2D.name.count("Residuals") > 0:
[7f59ee8e]183            new_plot.ytransform = 'y'
184            new_plot.yaxis("\\rm{Residuals} ", "/")
185
[940aca7]186        new_plot.group_id = "2daverage" + self.base.data2D.name
187        new_plot.id = "SectorQ" + self.base.data2D.name
[32c0841]188        new_plot.is_data = True
[b40ad40]189        self.base.parent.update_theory(data_id=data.id, theory=new_plot)
190        wx.PostEvent(self.base.parent,
191                     NewPlotEvent(plot=new_plot, title="SectorQ" + self.base.data2D.name))
192
[ef0c170]193    def moveend(self, ev):
[6c0568b]194        """
[b40ad40]195        Called a dragging motion ends.Get slicer event
[6c0568b]196        """
[ef0c170]197        self.base.thaw_axes()
[6c0568b]198        ## Post parameters
[0d9dae8]199        event = SlicerParameterEvent()
[ef0c170]200        event.type = self.__class__.__name__
201        event.params = self.get_params()
[6c0568b]202        ## Send slicer paramers to plotter2D
[d468daa]203        wx.PostEvent(self.base, event)
[b40ad40]204
[ef0c170]205    def restore(self):
206        """
207        Restore the roughness for this layer.
208        """
209        self.main_line.restore()
210        self.left_line.restore()
211        self.right_line.restore()
212
213    def move(self, x, y, ev):
214        """
215        Process move to a new position, making sure that the move is allowed.
216        """
217        pass
[b40ad40]218
[ef0c170]219    def set_cursor(self, x, y):
[d955bf19]220        """
221        """
[ef0c170]222        pass
[b40ad40]223
[ef0c170]224    def get_params(self):
[6c0568b]225        """
[d955bf19]226        Store a copy of values of parameters of the slicer into a dictionary.
[b40ad40]227
[d955bf19]228        :return params: the dictionary created
[b40ad40]229
[6c0568b]230        """
[ef0c170]231        params = {}
[b40ad40]232        ## Always make sure that the left and the right line are at phi
[6c0568b]233        ## angle of the middle line
[ef0c170]234        if math.fabs(self.left_line.phi) != math.fabs(self.right_line.phi):
[32c0841]235            msg = "Phi left and phi right are different"
236            msg += " %f, %f" % (self.left_line.phi, self.right_line.phi)
237            raise ValueError, msg
[b40ad40]238        params["Phi [deg]"] = self.main_line.theta * 180 / math.pi
239        params["Delta_Phi [deg]"] = math.fabs(self.left_line.phi * 180 / math.pi)
[ef0c170]240        params["nbins"] = self.nbins
241        return params
[b40ad40]242
[ef0c170]243    def set_params(self, params):
[6c0568b]244        """
[b40ad40]245        Receive a dictionary and reset the slicer with values contained
[d955bf19]246        in the values of the dictionary.
[b40ad40]247
248        :param params: a dictionary containing name of slicer parameters and
[6c0568b]249            values the user assigned to the slicer.
250        """
[b40ad40]251        main = params["Phi [deg]"] * math.pi / 180
252        phi = math.fabs(params["Delta_Phi [deg]"] * math.pi / 180)
[ef0c170]253        self.nbins = int(params["nbins"])
[32c0841]254        self.main_line.theta = main
[6c0568b]255        ## Reset the slicer parameters
[ef0c170]256        self.main_line.update()
[32c0841]257        self.right_line.update(phi=phi, delta=None, mline=self.main_line,
258                               side=True, right=True)
[b40ad40]259        self.left_line.update(phi=phi, delta=None,
[32c0841]260                              mline=self.main_line, side=True)
[6c0568b]261        ## post the new corresponding data
[ef0c170]262        self._post_data(nbins=self.nbins)
[b40ad40]263
[ef0c170]264    def freeze_axes(self):
[d955bf19]265        """
266        """
[ef0c170]267        self.base.freeze_axes()
[b40ad40]268
[ef0c170]269    def thaw_axes(self):
[d955bf19]270        """
271        """
[ef0c170]272        self.base.thaw_axes()
273
274    def draw(self):
[d955bf19]275        """
276        """
[ef0c170]277        self.base.draw()
278
[b40ad40]279
[ef0c170]280class SideInteractor(_BaseInteractor):
281    """
[d955bf19]282    Draw an oblique line
[b40ad40]283
[d955bf19]284    :param phi: the phase between the middle line and one side line
285    :param theta2: the angle between the middle line and x- axis
[b40ad40]286
[ef0c170]287    """
[32c0841]288    def __init__(self, base, axes, color='black', zorder=5, r=1.0,
[b40ad40]289                 phi=math.pi / 4, theta2=math.pi / 3):
[32c0841]290        """
291        """
[ef0c170]292        _BaseInteractor.__init__(self, base, axes, color=color)
[6c0568b]293        ## Initialize the class
[ef0c170]294        self.markers = []
295        self.axes = axes
[6c0568b]296        ## compute the value of the angle between the current line and
[b40ad40]297        ## the x-axis
[ef0c170]298        self.save_theta = theta2 + phi
[32c0841]299        self.theta = theta2 + phi
[6c0568b]300        ## the value of the middle line angle with respect to the x-axis
[ef0c170]301        self.theta2 = theta2
[6c0568b]302        ## Radius to find polar coordinates this line's endpoints
[ef0c170]303        self.radius = r
[6c0568b]304        ## phi is the phase between the current line and the middle line
[ef0c170]305        self.phi = phi
[6c0568b]306        ## End points polar coordinates
[32c0841]307        x1 = self.radius * math.cos(self.theta)
308        y1 = self.radius * math.sin(self.theta)
309        x2 = -1 * self.radius * math.cos(self.theta)
310        y2 = -1 * self.radius * math.sin(self.theta)
[b40ad40]311        ## defining a new marker
312        self.inner_marker = self.axes.plot([x1 / 2.5], [y1 / 2.5], linestyle='',
313                                           marker='s', markersize=10,
314                                           color=self.color, alpha=0.6,
315                                           pickradius=5, label="pick",
316                                           zorder=zorder, visible=True)[0]
317
[6c0568b]318        ## Defining the current line
[32c0841]319        self.line = self.axes.plot([x1, x2], [y1, y2],
[b40ad40]320                                   linestyle='-', marker='',
321                                   color=self.color, visible=True)[0]
[6c0568b]322        ## Flag to differentiate the left line from the right line motion
[32c0841]323        self.left_moving = False
[6c0568b]324        ## Flag to define a motion
[32c0841]325        self.has_move = False
[6c0568b]326        ## connecting markers and draw the picture
[7a28ba7]327        self.connect_markers([self.inner_marker, self.line])
[b40ad40]328
[ef0c170]329    def set_layer(self, n):
[6c0568b]330        """
[d955bf19]331        Allow adding plot to the same panel
[b40ad40]332
[d955bf19]333        :param n: the number of layer
[b40ad40]334
[6c0568b]335        """
[ef0c170]336        self.layernum = n
337        self.update()
[b40ad40]338
[ef0c170]339    def clear(self):
[6c0568b]340        """
[d955bf19]341        Clear the slicer and all connected events related to this slicer
[6c0568b]342        """
[ef0c170]343        self.clear_markers()
344        try:
345            self.line.remove()
[7a28ba7]346            self.inner_marker.remove()
[ef0c170]347        except:
348            # Old version of matplotlib
349            for item in range(len(self.axes.lines)):
350                del self.axes.lines[0]
[b40ad40]351
[6c0568b]352    def update(self, phi=None, delta=None, mline=None,
[b40ad40]353               side=False, left=False, right=False):
[ef0c170]354        """
[d955bf19]355        Draw oblique line
[b40ad40]356
[d955bf19]357        :param phi: the phase between the middle line and the current line
358        :param delta: phi/2 applied only when the mline was moved
[b40ad40]359
[ef0c170]360        """
361        #print "update left or right ", self.has_move
[32c0841]362        self.left_moving = left
363        theta3 = 0
364        if phi != None:
365            self.phi = phi
366        if delta == None:
[31e3298]367            delta = 0
[7a28ba7]368        if  right:
[32c0841]369            self.phi = -1 * math.fabs(self.phi)
[31e3298]370            #delta=-delta
[7a28ba7]371        else:
[32c0841]372            self.phi = math.fabs(self.phi)
[e23a20c]373        if side:
[32c0841]374            self.theta = mline.theta + self.phi
[b40ad40]375
376        if mline != None:
[32c0841]377            if delta != 0:
378                self.theta2 = mline + delta
[31e3298]379            else:
380                self.theta2 = mline.theta
[32c0841]381        if delta == 0:
382            theta3 = self.theta + delta
[31e3298]383        else:
[32c0841]384            theta3 = self.theta2 + delta
385        x1 = self.radius * math.cos(theta3)
386        y1 = self.radius * math.sin(theta3)
387        x2 = -1 * self.radius * math.cos(theta3)
388        y2 = -1 * self.radius * math.sin(theta3)
[b40ad40]389        self.inner_marker.set(xdata=[x1 / 2.5], ydata=[y1 / 2.5])
390        self.line.set(xdata=[x1, x2], ydata=[y1, y2])
391
[ef0c170]392    def save(self, ev):
393        """
394        Remember the roughness for this layer and the next so that we
395        can restore on Esc.
396        """
[32c0841]397        self.save_theta = self.theta
[ef0c170]398        self.base.freeze_axes()
399
400    def moveend(self, ev):
[d955bf19]401        """
402        """
[32c0841]403        self.has_move = False
[ef0c170]404        self.base.moveend(ev)
[b40ad40]405
[ef0c170]406    def restore(self):
407        """
408        Restore the roughness for this layer.
409        """
410        self.theta = self.save_theta
411
412    def move(self, x, y, ev):
413        """
414        Process move to a new position, making sure that the move is allowed.
415        """
[32c0841]416        self.theta = math.atan2(y, x)
417        self.has_move = True
[0c218d9]418        #ToDo: Simplify below
[7a28ba7]419        if not self.left_moving:
[32c0841]420            if  self.theta2 - self.theta <= 0 and self.theta2 > 0:
[0c218d9]421                self.restore()
[b40ad40]422                return
[32c0841]423            elif self.theta2 < 0 and self.theta < 0 and \
[b40ad40]424                self.theta - self.theta2 >= 0:
[0c218d9]425                self.restore()
[b40ad40]426                return
[32c0841]427            elif  self.theta2 < 0 and self.theta > 0 and \
[b40ad40]428                (self.theta2 + 2 * math.pi - self.theta) >= math.pi / 2:
[0c218d9]429                self.restore()
[b40ad40]430                return
[32c0841]431            elif  self.theta2 < 0 and self.theta < 0 and \
[b40ad40]432                (self.theta2 - self.theta) >= math.pi / 2:
[7a28ba7]433                self.restore()
[b40ad40]434                return
435            elif self.theta2 > 0 and (self.theta2 - self.theta >= math.pi / 2 or \
436                (self.theta2 - self.theta >= math.pi / 2)):
[7a28ba7]437                self.restore()
[b40ad40]438                return
[7a28ba7]439        else:
[b40ad40]440            if  self.theta < 0 and (self.theta + math.pi * 2 - self.theta2) <= 0:
[7a28ba7]441                self.restore()
[b40ad40]442                return
443            elif self.theta2 < 0 and (self.theta - self.theta2) <= 0:
[0c218d9]444                self.restore()
[b40ad40]445                return
446            elif  self.theta > 0 and self.theta - self.theta2 <= 0:
[0c218d9]447                self.restore()
[b40ad40]448                return
449            elif self.theta - self.theta2 >= math.pi / 2 or  \
450                ((self.theta + math.pi * 2 - self.theta2) >= math.pi / 2 and \
[32c0841]451                 self.theta < 0 and self.theta2 > 0):
[7a28ba7]452                self.restore()
[b40ad40]453                return
454
[32c0841]455        self.phi = math.fabs(self.theta2 - self.theta)
456        if self.phi > math.pi:
457            self.phi = 2 * math.pi - math.fabs(self.theta2 - self.theta)
[ef0c170]458        self.base.base.update()
[b40ad40]459
[ef0c170]460    def set_cursor(self, x, y):
[d955bf19]461        """
462        """
[ef0c170]463        self.move(x, y, None)
464        self.update()
[b40ad40]465
[ef0c170]466    def get_params(self):
[d955bf19]467        """
468        """
[ef0c170]469        params = {}
470        params["radius"] = self.radius
471        params["theta"] = self.theta
472        return params
[b40ad40]473
[ef0c170]474    def set_params(self, params):
[d955bf19]475        """
476        """
[b40ad40]477        x = params["radius"]
[4752c31]478        self.set_cursor(x, None)
[b40ad40]479
[d955bf19]480
[ef0c170]481class LineInteractor(_BaseInteractor):
482    """
[d955bf19]483    Select an annulus through a 2D plot
[ef0c170]484    """
[32c0841]485    def __init__(self, base, axes, color='black',
[b40ad40]486                 zorder=5, r=1.0, theta=math.pi / 4):
[d955bf19]487        """
488        """
[ef0c170]489        _BaseInteractor.__init__(self, base, axes, color=color)
[b40ad40]490
[ef0c170]491        self.markers = []
492        self.axes = axes
[b40ad40]493        self.save_theta = theta
494        self.theta = theta
[ef0c170]495        self.radius = r
496        self.scale = 10.0
497        # Inner circle
[32c0841]498        x1 = self.radius * math.cos(self.theta)
499        y1 = self.radius * math.sin(self.theta)
[b40ad40]500        x2 = -1 * self.radius * math.cos(self.theta)
501        y2 = -1 * self.radius * math.sin(self.theta)
502        # Inner circle marker
503        self.inner_marker = self.axes.plot([x1 / 2.5], [y1 / 2.5], linestyle='',
504                                           marker='s', markersize=10,
505                                           color=self.color, alpha=0.6,
506                                           pickradius=5, label="pick",
507                                           zorder=zorder,
508                                           visible=True)[0]
[32c0841]509        self.line = self.axes.plot([x1, x2], [y1, y2],
[b40ad40]510                                   linestyle='-', marker='',
511                                   color=self.color, visible=True)[0]
[ef0c170]512        self.npts = 20
[32c0841]513        self.has_move = False
[7a28ba7]514        self.connect_markers([self.inner_marker, self.line])
[ef0c170]515        self.update()
516
517    def set_layer(self, n):
[d955bf19]518        """
519        """
[ef0c170]520        self.layernum = n
521        self.update()
[b40ad40]522
[ef0c170]523    def clear(self):
[d955bf19]524        """
525        """
[ef0c170]526        self.clear_markers()
527        try:
[7a28ba7]528            self.inner_marker.remove()
[ef0c170]529            self.line.remove()
530        except:
531            # Old version of matplotlib
532            for item in range(len(self.axes.lines)):
533                del self.axes.lines[0]
[b40ad40]534
[ef0c170]535    def update(self, theta=None):
536        """
537        Draw the new roughness on the graph.
538        """
[b40ad40]539
[32c0841]540        if theta != None:
541            self.theta = theta
542        x1 = self.radius * math.cos(self.theta)
543        y1 = self.radius * math.sin(self.theta)
544        x2 = -1 * self.radius * math.cos(self.theta)
545        y2 = -1 * self.radius * math.sin(self.theta)
[b40ad40]546
547        self.inner_marker.set(xdata=[x1 / 2.5], ydata=[y1 / 2.5])
548        self.line.set(xdata=[x1, x2], ydata=[y1, y2])
549
[ef0c170]550    def save(self, ev):
551        """
552        Remember the roughness for this layer and the next so that we
553        can restore on Esc.
554        """
[b40ad40]555        self.save_theta = self.theta
[ef0c170]556        self.base.freeze_axes()
557
558    def moveend(self, ev):
[d955bf19]559        """
560        """
[32c0841]561        self.has_move = False
[ef0c170]562        self.base.moveend(ev)
[b40ad40]563
[ef0c170]564    def restore(self):
565        """
566        Restore the roughness for this layer.
567        """
568        self.theta = self.save_theta
569
570    def move(self, x, y, ev):
571        """
572        Process move to a new position, making sure that the move is allowed.
573        """
[32c0841]574        self.theta = math.atan2(y, x)
575        self.has_move = True
[ef0c170]576        self.base.base.update()
[b40ad40]577
[ef0c170]578    def set_cursor(self, x, y):
[d955bf19]579        """
580        """
[ef0c170]581        self.move(x, y, None)
582        self.update()
[b40ad40]583
[ef0c170]584    def get_params(self):
[d955bf19]585        """
586        """
[ef0c170]587        params = {}
588        params["radius"] = self.radius
589        params["theta"] = self.theta
590        return params
[b40ad40]591
[ef0c170]592    def set_params(self, params):
[d955bf19]593        """
594        """
[b40ad40]595        x = params["radius"]
[4752c31]596        self.set_cursor(x, None)
Note: See TracBrowser for help on using the repository browser.