def toggle_NV(self, pt):
        '''
        If there is not currently a selected NV within self.settings[patch_size] of pt, adds it to the selected list. If
        there is, removes that point from the selected list.
        Args:
            pt: the point to add or remove from the selected list
        Poststate: updates selected list
        '''
        if not self.data['nv_locations']: #if self.data is empty so this is the first point
            self.data['nv_locations'].append(pt)
            self.data['image_data'] = None # clear image data
        else:
            # use KDTree to find NV closest to mouse click
            tree = scipy.spatial.KDTree(self.data['nv_locations'])
            #does a search with k=1, that is a search for the nearest neighbor, within distance_upper_bound
            d, i = tree.query(pt,k = 1, distance_upper_bound = self.settings['patch_size'])

            # removes NV if previously selected
            if d is not np.inf:
                self.data['nv_locations'].pop(i)
            # adds NV if not previously selected
            else:
                self.data['nv_locations'].append(pt)

            # randomize
            if self.settings['randomize']:
                self.log('warning! randomize not avalable when manually selecting points')

        # if type is not free we calculate the total points of locations from the first selected points
        if self.settings['type'] == 'square' and len(self.data['nv_locations'])>1:
            # here we create a rectangular grid, where pts a and be define the top left and bottom right corner of the rectangle
            Nx, Ny = self.settings['Nx'], self.settings['Ny']
            pta = self.data['nv_locations'][0]
            ptb = self.data['nv_locations'][1]
            tmp  = np.array([[[pta[0] + 1.0*i*(ptb[0]-pta[0])/(Nx-1), pta[1] + 1.0*j*(ptb[1]-pta[1])/(Ny-1)] for i in range(Nx)] for j in range(Ny)])
            nv_pts = np.reshape(tmp, (Nx * Ny, 2))

            # randomize
            if self.settings['randomize']:
                random.shuffle(nv_pts)  # shuffles in place

            self.data['nv_locations'] = nv_pts

            self.stop()
        elif self.settings['type'] == 'line' and len(self.data['nv_locations'])>1:
            # here we create a straight line between points a and b
            N = self.settings['Nx']
            pta = self.data['nv_locations'][0]
            ptb = self.data['nv_locations'][1]
            nv_pts = [np.array([pta[0] + 1.0*i*(ptb[0]-pta[0])/(N-1), pta[1] + 1.0*i*(ptb[1]-pta[1])/(N-1)]) for i in range(N)]


            # randomize
            if self.settings['randomize']:
                random.shuffle(nv_pts)  # shuffles in place

            self.data['nv_locations'] = nv_pts

            self.stop()
        elif self.settings['type'] == 'ring' and len(self.data['nv_locations'])>1:
            # here we create a circular grid, where pts a and be define the center and the outermost ring
            Nx, Ny = self.settings['Nx'], self.settings['Ny']
            pt_center = self.data['nv_locations'][0] # center
            pt_outer = self.data['nv_locations'][1] # outermost ring
            # radius of outermost ring:
            rmax = np.sqrt((pt_center[0] - pt_outer[0]) ** 2 + (pt_center[1] - pt_outer[1]) ** 2)

            # angles
            angles = np.linspace(0, 2 * np.pi, Nx+1)[0:-1]
            # create points on rings
            nv_pts = []
            for r in np.linspace(rmax, 0, Ny + 1)[0:-1]:
                for theta in angles:
                    nv_pts += [[r * np.sin(theta)+pt_center[0], r * np.cos(theta)+pt_center[1]]]



            # randomize
            if self.settings['randomize']:
                coarray = list(zip(nv_pts, angles))
                random.shuffle(coarray)  # shuffles in place
                nv_pts, angles = zip(*coarray)

            self.data['nv_locations'] = np.array(nv_pts)
            self.data['angles'] = np.array(angles)* 180 / np.pi
            self.data['ring_data'] = [pt_center, pt_outer]
            self.stop()

        elif self.settings['type'] == 'arc' and len(self.data['nv_locations']) > 3:
            # here we create a circular grid, where pts a and be define the center and the outermost ring
            Nx, Ny = self.settings['Nx'], self.settings['Ny']
            pt_center = self.data['nv_locations'][0]  # center
            pt_start = self.data['nv_locations'][1]  # arc point one (radius)
            pt_dir = self.data['nv_locations'][2]  # arc point two (direction)
            pt_end = self.data['nv_locations'][3]  # arc point three (angle)

            # radius of outermost ring:
            rmax = np.sqrt((pt_center[0] - pt_start[0]) ** 2 + (pt_center[1] - pt_start[1]) ** 2)
            angle_start = np.arctan((pt_start[1] - pt_center[1]) / (pt_start[0] - pt_center[0]))
            # arctan always returns between -pi/2 and pi/2, so adjust to allow full range of angles
            if ((pt_start[0] - pt_center[0]) < 0):
                angle_start += np.pi

            angle_end = np.arctan((pt_end[1] - pt_center[1]) / (pt_end[0] - pt_center[0]))
            # arctan always returns between -pi/2 and pi/2, so adjust to allow full range of angles
            if ((pt_end[0] - pt_center[0]) < 0):
                angle_end += np.pi

            if pt_dir[0] < pt_start[0]:
                # counter-clockwise: invert the order of the angles
                angle_start, angle_end = angle_end, angle_start

            if angle_start > angle_end:
                # make sure that start is the smaller
                # (e.g. angle_start= 180 deg and angle_end =10, we want to got from 180 to 370 deg)
                angle_end += 2 * np.pi

            # create points on arcs
            nv_pts = []
            for r in np.linspace(rmax, 0, Ny + 1)[0:-1]:
                for theta in np.linspace(angle_start, angle_end, Nx, endpoint=True):
                    nv_pts += [[r * np.cos(theta) + pt_center[0], r * np.sin(theta) + pt_center[1]]]

            # randomize
            if self.settings['randomize']:
                coarray = list(zip(nv_pts, np.linspace(angle_start, angle_end, Nx, endpoint=True)))
                random.shuffle(coarray)  # shuffles in place
                nv_pts, angles = zip(*coarray)
            else:
                angles = np.linspace(angle_start, angle_end, Nx, endpoint=True)
            self.data['nv_locations'] = np.array(nv_pts)
            self.data['arc_data'] = [pt_center, pt_start, pt_end]
            self.data['angles'] = np.array(angles) * 180 / np.pi
            self.stop()
def toggle_NV ( self , pt ) : if not self . data [ 'nv_locations' ] : self . data [ 'nv_locations' ] . append ( pt ) self . data [ 'image_data' ] = None else : tree = scipy . spatial . KDTree ( self . data [ 'nv_locations' ] ) d , i = tree . query ( pt , k = 1 , distance_upper_bound = self . settings [ 'patch_size' ] ) if d is not np . inf : self . data [ 'nv_locations' ] . pop ( i ) else : self . data [ 'nv_locations' ] . append ( pt ) if self . settings [ 'randomize' ] : self . log ( 'warning! randomize not avalable when manually selecting points' ) if self . settings [ 'type' ] == 'square' and len ( self . data [ 'nv_locations' ] ) > 1 : Nx , Ny = self . settings [ 'Nx' ] , self . settings [ 'Ny' ] pta = self . data [ 'nv_locations' ] [ 0 ] ptb = self . data [ 'nv_locations' ] [ 1 ] tmp = np . array ( [ [ [ pta [ 0 ] + 1.0 * i * ( ptb [ 0 ] - pta [ 0 ] ) / ( Nx - 1 ) , pta [ 1 ] + 1.0 * j * ( ptb [ 1 ] - pta [ 1 ] ) / ( Ny - 1 ) ] for i in range ( Nx ) ] for j in range ( Ny ) ] ) nv_pts = np . reshape ( tmp , ( Nx * Ny , 2 ) ) if self . settings [ 'randomize' ] : random . shuffle ( nv_pts ) self . data [ 'nv_locations' ] = nv_pts self . stop ( ) elif self . settings [ 'type' ] == 'line' and len ( self . data [ 'nv_locations' ] ) > 1 : N = self . settings [ 'Nx' ] pta = self . data [ 'nv_locations' ] [ 0 ] ptb = self . data [ 'nv_locations' ] [ 1 ] nv_pts = [ np . array ( [ pta [ 0 ] + 1.0 * i * ( ptb [ 0 ] - pta [ 0 ] ) / ( N - 1 ) , pta [ 1 ] + 1.0 * i * ( ptb [ 1 ] - pta [ 1 ] ) / ( N - 1 ) ] ) for i in range ( N ) ] if self . settings [ 'randomize' ] : random . shuffle ( nv_pts ) self . data [ 'nv_locations' ] = nv_pts self . stop ( ) elif self . settings [ 'type' ] == 'ring' and len ( self . data [ 'nv_locations' ] ) > 1 : Nx , Ny = self . settings [ 'Nx' ] , self . settings [ 'Ny' ] pt_center = self . data [ 'nv_locations' ] [ 0 ] pt_outer = self . data [ 'nv_locations' ] [ 1 ] rmax = np . sqrt ( ( pt_center [ 0 ] - pt_outer [ 0 ] ) ** 2 + ( pt_center [ 1 ] - pt_outer [ 1 ] ) ** 2 ) angles = np . linspace ( 0 , 2 * np . pi , Nx + 1 ) [ 0 : - 1 ] nv_pts = [ ] for r in np . linspace ( rmax , 0 , Ny + 1 ) [ 0 : - 1 ] : for theta in angles : nv_pts += [ [ r * np . sin ( theta ) + pt_center [ 0 ] , r * np . cos ( theta ) + pt_center [ 1 ] ] ] if self . settings [ 'randomize' ] : coarray = list ( zip ( nv_pts , angles ) ) random . shuffle ( coarray ) nv_pts , angles = zip ( * coarray ) self . data [ 'nv_locations' ] = np . array ( nv_pts ) self . data [ 'angles' ] = np . array ( angles ) * 180 / np . pi self . data [ 'ring_data' ] = [ pt_center , pt_outer ] self . stop ( ) elif self . settings [ 'type' ] == 'arc' and len ( self . data [ 'nv_locations' ] ) > 3 : Nx , Ny = self . settings [ 'Nx' ] , self . settings [ 'Ny' ] pt_center = self . data [ 'nv_locations' ] [ 0 ] pt_start = self . data [ 'nv_locations' ] [ 1 ] pt_dir = self . data [ 'nv_locations' ] [ 2 ] pt_end = self . data [ 'nv_locations' ] [ 3 ] rmax = np . sqrt ( ( pt_center [ 0 ] - pt_start [ 0 ] ) ** 2 + ( pt_center [ 1 ] - pt_start [ 1 ] ) ** 2 ) angle_start = np . arctan ( ( pt_start [ 1 ] - pt_center [ 1 ] ) / ( pt_start [ 0 ] - pt_center [ 0 ] ) ) if ( ( pt_start [ 0 ] - pt_center [ 0 ] ) < 0 ) : angle_start += np . pi angle_end = np . arctan ( ( pt_end [ 1 ] - pt_center [ 1 ] ) / ( pt_end [ 0 ] - pt_center [ 0 ] ) ) if ( ( pt_end [ 0 ] - pt_center [ 0 ] ) < 0 ) : angle_end += np . pi if pt_dir [ 0 ] < pt_start [ 0 ] : angle_start , angle_end = angle_end , angle_start if angle_start > angle_end : angle_end += 2 * np . pi nv_pts = [ ] for r in np . linspace ( rmax , 0 , Ny + 1 ) [ 0 : - 1 ] : for theta in np . linspace ( angle_start , angle_end , Nx , endpoint = True ) : nv_pts += [ [ r * np . cos ( theta ) + pt_center [ 0 ] , r * np . sin ( theta ) + pt_center [ 1 ] ] ] if self . settings [ 'randomize' ] : coarray = list ( zip ( nv_pts , np . linspace ( angle_start , angle_end , Nx , endpoint = True ) ) ) random . shuffle ( coarray ) nv_pts , angles = zip ( * coarray ) else : angles = np . linspace ( angle_start , angle_end , Nx , endpoint = True ) self . data [ 'nv_locations' ] = np . array ( nv_pts ) self . data [ 'arc_data' ] = [ pt_center , pt_start , pt_end ] self . data [ 'angles' ] = np . array ( angles ) * 180 / np . pi self . stop ( )
If there is not currently a selected NV within self.settings[patch_size] of pt, adds it to the selected list. If
        there is, removes that point from the selected list.
        Args:
            pt: the point to add or remove from the selected list
        Poststate: updates selected list