def image_acquisition(num_proj, camera_port=0, wait=0, hsv='v', fancy_out=True): hsv_dict = {'h': 0, 's': 1, 'v': 2} camera = cv2.VideoCapture(camera_port) camera.set(3, 2000) camera.set(4, 2000) try: dims = camera.read()[1][:, :, 2].shape + (num_proj, ) except TypeError: error = ('Camera returning None. Check camera settings (port) and' ' ensure camera is not being run by other software.') raise TypeError(error) im_stack = np.zeros(dims) if fancy_out: fig, ax = plt.subplots(figsize=(4, 4)) fig.canvas.set_window_title('Acquisition') patch = Wedge((.5, .5), .375, 90, 90, width=0.1) ax.add_patch(patch) ax.axis('equal') ax.set_xlim([0, 1]) ax.set_ylim([0, 1]) ax.axis('off') t = ax.text(0.5, 0.5, '0%%', fontsize=15, ha='center', va='center') # Acquires defined number of images (saves slice from hsv) for i in range(num_proj): _, im = camera.read() im_stack[:, :, i] = color.rgb2hsv(im)[:, :, hsv_dict[hsv]] if fancy_out: patch.set_theta1(90 - 360 * (i + 1) / num_proj) progress = 100 * (i + 1) / num_proj t.set_text('%02d%%' % progress) plt.pause(0.001) else: sys.stdout.write('\rProgress: [{0:20s}] {1:.0f}%'.format( '#' * int(20 * (i + 1) / num_proj), 100 * ((i + 1) / num_proj))) sys.stdout.flush() time.sleep(wait) del camera if fancy_out: plt.close() return im_stack
def image_acquisition(num_proj, camera_port=0, wait=0, hsv='v', fancy_out=True): hsv_dict = {'h': 0, 's': 1, 'v': 2} camera = cv2.VideoCapture(camera_port) camera.set(3, 2000) camera.set(4, 2000) try: dims = camera.read()[1][:, :, 2].shape + (num_proj, ) except TypeError: error = ('Camera returning None. Check camera settings (port) and' ' ensure camera is not being run by other software.') raise TypeError(error) im_stack = np.zeros(dims) if fancy_out: fig, ax = plt.subplots(figsize=(4, 4)) fig.canvas.set_window_title('Acquisition') patch = Wedge((.5, .5), .375, 90, 90, width=0.1) ax.add_patch(patch) ax.axis('equal') ax.set_xlim([0, 1]) ax.set_ylim([0, 1]) ax.axis('off') t = ax.text(0.5, 0.5, '0%%', fontsize=15, ha='center', va='center') # Acquires defined number of images (saves slice from hsv) for i in range(num_proj): _, im = camera.read() im_stack[:, :, i] = color.rgb2hsv(im)[:, :, hsv_dict[hsv]] if fancy_out: patch.set_theta1(90 - 360 * (i+1) /num_proj) progress = 100 * (i+1) / num_proj t.set_text('%02d%%' % progress) plt.pause(0.001) else: sys.stdout.write('\rProgress: [{0:20s}] {1:.0f}%'.format('#' * int(20*(i + 1) / num_proj), 100*((i + 1)/num_proj))) sys.stdout.flush() time.sleep(wait) del camera if fancy_out: plt.close() return im_stack
def atualizar_setor(setor: Wedge, abertura_min: float) -> [Wedge]: """Atualiza os valores de theta e opacidade do setor, movimentando-o""" global glob_multip_alpha # O valor de theta = valor atual + incremento (Se a soma não ultrapassar 360) # Se a soma ultrapassar 360, o valor será o resto da divisão (soma / 360) setor.set_theta1((setor.theta1 + glob_increm_ang) % 360) setor.set_theta2(setor.theta1 + abertura_min) # Se a opacidade do setor for maior que 0.4 ou for menor que o valor mínimo: # inverta de incremento para decremento ou vice-versa if setor.get_alpha() >= 0.4 or setor.get_alpha() < glob_incremento_alpha: glob_multip_alpha = (-1) * glob_multip_alpha setor.set_alpha(setor.get_alpha() + glob_incremento_alpha * glob_multip_alpha) return [setor]
def reconstruct(self, downsample=(4, 4), crop=True, median_filter=False, kernel=9, recon_alg='fbp', sart_iters=1, crop_circle=False, save=True, fancy_out=True): """ Reconstruct the data using a radon transform. Reconstructed slices saved in folder specified upon class creation. # downsample: Downsample (local mean) data before reconstructing. Specify mean kernel size (height, width). # pre_filter: If True apply median filter to data before reconstructing # kernel: Kernel size to use for median filter """ if self.cor_offset >= 0: images = self.im_stack[:, self.cor_offset:] else: images = self.im_stack[:, :self.cor_offset] images = images[:, :, self.p0:self.num_images + self.p0] if crop: left, right, top, bottom = self.crop images = images[top:bottom, left:right] images = downscale_local_mean(images, downsample + (1, )) recon_height, recon_width = images.shape[:2] self.recon_data = np.zeros((recon_width, recon_width, recon_height)) if median_filter: print('Applying median filter...') for i in range(images.shape[-1]): sys.stdout.write('\rProgress: [{0:20s}] {1:.0f}%'.format('#' * int(20 * (i + 1) / images.shape[-1]), 100 * ((i + 1) / images.shape[-1]))) sys.stdout.flush() images[:, :, i] = medfilt(images[:, :, i], kernel_size=kernel) print('\nReconstructing...') if save: save_folder = os.path.join(self.folder, 'reconstruction') if not os.path.exists(save_folder): os.makedirs(save_folder) for the_file in os.listdir(save_folder): file_path = os.path.join(save_folder, the_file) if os.path.isfile(file_path): os.unlink(file_path) if fancy_out: fig, ax = plt.subplots(figsize=(4, 4)) fig.canvas.set_window_title('Reconstruction') patch = Wedge((.5, .5), .375, 90, 90, width=0.1) ax.add_patch(patch) ax.axis('equal') ax.set_xlim([0, 1]) ax.set_ylim([0, 1]) ax.axis('off') t = ax.text(0.5, 0.5, '0%%', fontsize=15, ha='center', va='center') for j in range(recon_height): # Update figure every other slice if fancy_out and j % 2 == 0: patch.set_theta1(90 - 360 * (j + 1) / recon_height) progress = 100 * (j + 1) / recon_height t.set_text('%02d%%' % progress) plt.pause(0.001) else: sys.stdout.write('\rProgress: [{0:20s}] {1:.0f}%'.format('#' * int(20 * (j + 1) / recon_height), 100 * ((j + 1) / recon_height))) sys.stdout.flush() sino_tmp = np.squeeze(images[j, :, :]) if recon_alg is 'sart': image_tmp = iradon_sart(sino_tmp, theta=self.angles) for i in range(sart_iters - 1): image_tmp = iradon_sart(sino_tmp, theta=self.angles, image=image_tmp) else: image_tmp = iradon(sino_tmp, theta=self.angles, filter=None, circle=True) # if crop_circle: # image_tmp = image_tmp[w0:wf, w0:wf] self.recon_data[:, :, j] = image_tmp if crop_circle: w = int((recon_width**2 / 2)**0.5) w = w if (w - recon_width) % 2 == 0 else w - 1 w0 = int((recon_width - w) / 2 ) wf = int(w0 + w) self.recon_data = self.recon_data[w0:wf, w0:wf] if save: for j in range(recon_height): image_tmp = self.recon_data[:, :, j] imsave(os.path.join(save_folder, '%04d.tif' % j), image_tmp) if fancy_out: plt.close()
import matplotlib as mpl from matplotlib.patches import Wedge import matplotlib.pyplot as plt mpl.rcParams['toolbar'] = 'None' plt.style.use('ggplot') fig, ax = plt.subplots(figsize=(3.5, 3.5)) fig.canvas.set_window_title('Acquisition') patch = Wedge((.5, .5), .45, 90, 90, width=0.15) ax.add_patch(patch) ax.axis('equal') ax.set_xlim([0, 1]) ax.set_ylim([0, 1]) ax.axis('off') t = ax.text(0.5, 0.5, '0%%', fontsize=15, ha='center', va='center') di = 1 for i in range(0, 360, di): patch.set_theta1(90 - i - di) progress = 100 * (i + di) / 360 t.set_text('%02d%%' % progress) plt.pause(0.0001) #plt.show() plt.close()
class ArtificialHorizonArtist(Artist): def __init__(self, ax: plt.Axes, attitude_data: SO3): if not isinstance(ax, plt.Axes): raise TypeError("The axes must be of plt.Axes type.") if not isinstance(attitude_data, SO3): raise TypeError("The attitude_data must be an SO3 element.") # Background ah_circle = Circle((0, 0), radius=1.0, color='w', ec='w') ah_colouring = Circle((0, 0), radius=5.0, color='k') ax.add_patch(ah_colouring) ax.add_patch(ah_circle) # Horizon line self._attitude_data = attitude_data true_horizon = self._compute_horizon(attitude_data) self._horizon_line, = ax.plot(true_horizon[0, :], true_horizon[1, :]) # Horizon shading height = self._compute_horizon_height(attitude_data) slope = self._compute_horizon_slope(attitude_data) * 180.0 / np.pi self._shade = Wedge((0, height), 2.0, -180 + slope, slope, alpha=0.5) ax.add_patch(self._shade) # Clip path clip_circle = Circle((0, 0), radius=1.0, transform=ax.transData) self._horizon_line.set_clip_path(clip_circle) self._shade.set_clip_path(clip_circle) # Center Overlay ax.add_patch(Arc((0, 0), 0.3, 0.3, theta1=180, lw=2.0)) ax.plot([0.15, 0.6], [0, 0], color='k', lw=2.0) ax.plot([-0.15, -0.6], [0, 0], color='k', lw=2.0) # Axes settings ax.axis('square') ax.set_xlim([-1, 1]) ax.set_ylim([-1, 1]) def set_attitude_data(self, attitude: SE3): if not isinstance(attitude, SO3): raise TypeError("The attitude_data must be an SO3 element.") self._attitude_data = attitude true_horizon = self._compute_horizon(attitude) self._horizon_line.set_data(true_horizon[0, :], true_horizon[1, :]) height = self._compute_horizon_height(attitude) slope = self._compute_horizon_slope(attitude) * 180.0 / np.pi self._shade.set_center((0, height)) self._shade.set_theta1(-180 + slope) self._shade.set_theta2(slope) @staticmethod def _compute_horizon(attitude: SO3): angles = np.linspace(0, 2 * np.pi, 50) base_horizon = np.vstack( (np.cos(angles), np.sin(angles), np.zeros(angles.shape))) true_horizon = attitude.inv() * base_horizon true_horizon = true_horizon[:, true_horizon[0, :] > 0] true_horizon = true_horizon / true_horizon[0, :] true_horizon = true_horizon[1:, :] return true_horizon @staticmethod def _compute_horizon_slope(attitude: SO3): theta = ArtificialHorizonArtist._find_heading_angle(attitude) H = attitude.inv() * np.array([[np.cos(theta)], [np.sin(theta)], [0.0] ]) DH = attitude.inv() * np.array([[-np.sin(theta)], [np.cos(theta)], [0.0]]) DH2 = H[0, 0] * DH - DH[0, 0] * H slope = np.arctan2(DH2[2, 0], DH2[1, 0]) return slope @staticmethod def _compute_horizon_height(attitude: SO3): theta = ArtificialHorizonArtist._find_heading_angle(attitude) H = attitude.inv() * np.array([[np.cos(theta)], [np.sin(theta)], [0.0] ]) H = H / H[0, 0] return H[2, 0] @staticmethod def _find_heading_angle(attitude): RT = attitude.as_matrix().T theta = np.arctan2(-RT[1, 0], RT[1, 1]) return theta
class PeakSelector(_SelectorWidget): """Draw a Peak as triangle.""" # pylint: disable=too-many-arguments # pylint: disable=too-many-instance-attributes # pylint: disable=invalid-name # pylint: disable=attribute-defined-outside-init def __init__(self, ax, onselect, minfwhm=None, minamp=None, useblit=False, wedgeprops=None, onmove_callback=None, peak_stays=False, button=None, limits=None): _SelectorWidget.__init__(self, ax, onselect, useblit=useblit, button=button) if minfwhm is not None or minamp is not None: raise NotImplementedError if wedgeprops is None: wedgeprops = dict(facecolor='red', alpha=0.5, fill=True) wedgeprops['animated'] = self.useblit self.wedge = None self.pressv = None if limits is None: limits = (-np.inf, np.inf) self.limits = limits self.wedgeprops = wedgeprops self.onmove_callback = onmove_callback self.minfwhm = minfwhm self.minamp = minamp self.peak_stays = peak_stays # Needed when dragging out of axes self.prev = (0, 0) # Reset canvas so that `new_axes` connects events. self.canvas = None self.new_axes(ax) def new_axes(self, ax): """Set SpanSelector to operate on a new Axes""" self.ax = ax if self.canvas is not ax.figure.canvas: if self.canvas is not None: self.disconnect_events() self.canvas = ax.figure.canvas self.connect_default_events() self.wedge = Wedge((0, 0), 1e10, 0, 0, visible=False, **self.wedgeprops) if self.peak_stays: self.stay_wedge = Wedge((0, 0), 1e10, 0, 0, visible=False, **self.wedgeprops) self.stay_wedge.set_animated(False) self.ax.add_patch(self.stay_wedge) self.ax.add_patch(self.wedge) self.artists = [self.wedge] def set_wedgeprops(self, wedgeprops): """Custom: set new rectprops.""" self.wedgeprops = wedgeprops self.new_axes(self.ax) def set_limits(self, limits): """Sets new limits. Peak will only be drawn when press event occurs inside these x values.""" self.limits = limits def ignore(self, event): """return *True* if *event* should be ignored""" return _SelectorWidget.ignore(self, event) or not self.visible def _press(self, event): """on button press event""" x0, y0 = self._get_data(event) if not self.limits[0] <= x0 <= self.limits[1]: return True self.wedge.set_visible(self.visible) if self.peak_stays: self.stay_wedge.set_visible(False) # really force a draw so that the stay rect is not in # the blit background if self.useblit: self.canvas.draw() self.pressv = (x0, y0) self.wedge.set_center((x0, y0)) return False def _release(self, event): """on button release event""" if self.pressv is None: return True self.buttonDown = False self.wedge.set_visible(False) if self.peak_stays: self.stay_wedge.set_center(self.wedge.center) self.stay_wedge.set_radius(self.wedge.r) self.stay_wedge.set_theta1(self.wedge.theta1) self.stay_wedge.set_theta2(self.wedge.theta2) self.stay_wedge.set_visible(True) self.canvas.draw_idle() x0, y0, = self.pressv center = x0 amplitude = y0 x, y = self._get_data(event) angle = abs(np.arctan((x - x0) / (y - y0))) self.onselect(center, amplitude, angle) self.pressv = None return False def _onmove(self, event): """on motion notify event""" if self.pressv is None: return True x, y = self._get_data(event) if x is None: return True x0, y0, = self.pressv angle = abs(np.arctan((x - x0) / (y - y0))) self.wedge.set_theta1(np.rad2deg(-angle) - 90) self.wedge.set_theta2(np.rad2deg(angle) - 90) if self.onmove_callback is not None: center = x0 amplitude = y0 self.onmove_callback(center, amplitude, angle) self.update() return False
def reconstruct(self, downsample=(4, 4), crop=True, median_filter=False, kernel=9, recon_alg='fbp', sart_iters=1, crop_circle=False, save=True, fancy_out=True): """ Reconstruct the data using a radon transform. Reconstructed slices saved in folder specified upon class creation. # downsample: Downsample (local mean) data before reconstructing. Specify mean kernel size (height, width). # pre_filter: If True apply median filter to data before reconstructing # kernel: Kernel size to use for median filter """ if self.cor_offset >= 0: images = self.im_stack[:, self.cor_offset:] else: images = self.im_stack[:, :self.cor_offset] images = images[:, :, self.p0:self.num_images + self.p0] if crop: left, right, top, bottom = self.crop images = images[top:bottom, left:right] images = downscale_local_mean(images, downsample + (1, )) recon_height, recon_width = images.shape[:2] self.recon_data = np.zeros((recon_width, recon_width, recon_height)) if median_filter: print('Applying median filter...') for i in range(images.shape[-1]): sys.stdout.write('\rProgress: [{0:20s}] {1:.0f}%'.format( '#' * int(20 * (i + 1) / images.shape[-1]), 100 * ((i + 1) / images.shape[-1]))) sys.stdout.flush() images[:, :, i] = medfilt(images[:, :, i], kernel_size=kernel) print('\nReconstructing...') if save: save_folder = os.path.join(self.folder, 'reconstruction') if not os.path.exists(save_folder): os.makedirs(save_folder) for the_file in os.listdir(save_folder): file_path = os.path.join(save_folder, the_file) if os.path.isfile(file_path): os.unlink(file_path) if fancy_out: fig, ax = plt.subplots(figsize=(4, 4)) fig.canvas.set_window_title('Reconstruction') patch = Wedge((.5, .5), .375, 90, 90, width=0.1) ax.add_patch(patch) ax.axis('equal') ax.set_xlim([0, 1]) ax.set_ylim([0, 1]) ax.axis('off') t = ax.text(0.5, 0.5, '0%%', fontsize=15, ha='center', va='center') for j in range(recon_height): # Update figure every other slice if fancy_out and j % 2 == 0: patch.set_theta1(90 - 360 * (j + 1) / recon_height) progress = 100 * (j + 1) / recon_height t.set_text('%02d%%' % progress) plt.pause(0.001) else: sys.stdout.write('\rProgress: [{0:20s}] {1:.0f}%'.format( '#' * int(20 * (j + 1) / recon_height), 100 * ((j + 1) / recon_height))) sys.stdout.flush() sino_tmp = np.squeeze(images[j, :, :]) if recon_alg is 'sart': image_tmp = iradon_sart(sino_tmp, theta=self.angles) for i in range(sart_iters - 1): image_tmp = iradon_sart(sino_tmp, theta=self.angles, image=image_tmp) else: image_tmp = iradon(sino_tmp, theta=self.angles, filter=None, circle=True) # if crop_circle: # image_tmp = image_tmp[w0:wf, w0:wf] self.recon_data[:, :, j] = image_tmp if crop_circle: w = int((recon_width**2 / 2)**0.5) w = w if (w - recon_width) % 2 == 0 else w - 1 w0 = int((recon_width - w) / 2) wf = int(w0 + w) self.recon_data = self.recon_data[w0:wf, w0:wf] if save: for j in range(recon_height): image_tmp = self.recon_data[:, :, j] imsave(os.path.join(save_folder, '%04d.tif' % j), image_tmp) if fancy_out: plt.close()
class MainWindow(QMainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.setWindowTitle('Lidar Boom Geometry') self.initializeValues() self.createLayout() self.initializeDrawing() def initializeValues(self): self.crestVal = [0.0, 6.5] self.backAngleVal = 2 self.backHeightVal = 4 self.frontAngleVal = 3 self.frontHeightVal = 1 self.frontDropVal = 1 self.baseDropVal = 1 self.baseOffsetVal = 12 self.baseHeightVal = 4 * 0.3048 self.boomAngleVal = 20 self.boomLengthVal = 44 * 0.3048 self.mountAngleVal = 80 self.hingeAngleVal = 10 self.mountLengthVal = 0.5 self.waterLevelVal = 1 # Cabling variables self.cableMountHeight = 5 * 0.3048 self.pulleyALocation = 34 * 0.3048 # Weights self.sensorWeight = 500 def drawBoomEnd(self): # The boom cut length = 15 height = 10 boomPts = [[0, 0], [length, 0], [length + height/tan(radians(self.mountAngleVal)), height], [0, height]] x = [i[0] for i in boomPts] y = [i[1] for i in boomPts] self.barAx.cla() self.barAx.plot(x, y, 'k') fill = Polygon(boomPts, facecolor='k') self.barAx.add_patch(fill) # The angled hinge hingeLength = sqrt((height/tan(radians(self.mountAngleVal)))**2 + height**2) angle = self.hingeAngleVal - 90 - (90 - self.mountAngleVal) hingePts = [boomPts[2], [boomPts[2][0] + hingeLength*cos(radians(angle)), boomPts[2][1] + hingeLength*sin(radians(angle))]] xh = [i[0] for i in hingePts] yh = [i[1] for i in hingePts] self.barAx.plot(xh, yh, 'k', lw=2) self.barAx.set_ylim([-2,12]) def initializeDrawing(self): self.waterLine, = self.ax.plot([0.0, 300.0], [self.waterLevelVal, self.waterLevelVal]) crestDrop = [self.crestVal[0], self.crestVal[1]-self.frontDropVal] waterPt = [(crestDrop[1]-self.frontHeightVal)/tan(radians(self.frontAngleVal)), self.frontHeightVal] landPt = [-(self.crestVal[1]-self.backHeightVal)/tan(radians(self.backAngleVal)), self.backHeightVal] x = [i[0] for i in [landPt, self.crestVal, crestDrop, waterPt]] y = [i[1] for i in [landPt, self.crestVal, crestDrop, waterPt]] self.duneLine, = self.ax.plot(x, y) baseGround = [self.crestVal[0] - self.baseOffsetVal, self.crestVal[1] - self.baseDropVal] baseTop = [baseGround[0], baseGround[1] + self.baseHeightVal] boomEnd = [baseTop[0] + self.boomLengthVal*cos(radians(self.boomAngleVal)), baseTop[1] + self.boomLengthVal*sin(radians(self.boomAngleVal))] self.oceanRange.setText(QString.number(boomEnd[0] + (boomEnd[1]-self.waterLevelVal)/tan(radians(self.mountAngleVal-60)), 'f', 1)) xb = [i[0] for i in [baseGround, baseTop, boomEnd]] yb = [i[1] for i in [baseGround, baseTop, boomEnd]] self.boomLine, = self.ax.plot(xb, yb) straightAngle = self.boomAngleVal - (90-self.mountAngleVal) - 90 + self.hingeAngleVal self.wedge = Wedge(boomEnd, 300, straightAngle-40, straightAngle+60, alpha=0.5, color='y') self.ax.add_artist(self.wedge) angle = -30+self.mountAngleVal+self.hingeAngleVal+self.boomAngleVal self.oceanRange.setText(QString.number(boomEnd[0] + (boomEnd[1]-self.waterLevelVal)*tan(radians(angle)), 'f', 1)) # Initialize cabling drawing cableMountBaseTop = [baseTop[0], baseTop[1] + self.cableMountHeight] pulleyA = [baseTop[0] + self.pulleyALocation*cos(radians(self.boomAngleVal)), baseTop[1] + self.pulleyALocation*sin(radians(self.boomAngleVal))] xc = [i[0] for i in [baseTop, cableMountBaseTop, pulleyA]] yc = [i[1] for i in [baseTop, cableMountBaseTop, pulleyA]] self.calculateCablingForces() self.cableLine, = self.ax.plot(xc, yc, 'k') self.fig.subplots_adjust(left=0.1) def update(self): # Dune calculations crestDrop = [self.crestVal[0], self.crestVal[1]-self.frontDropVal] waterPt = [(crestDrop[1]-self.frontHeightVal)/tan(radians(self.frontAngleVal)), self.frontHeightVal] landPt = [-(self.crestVal[1]-self.backHeightVal)/tan(radians(self.backAngleVal)), self.backHeightVal] xDune = [i[0] for i in [landPt, self.crestVal, crestDrop, waterPt]] yDune = [i[1] for i in [landPt, self.crestVal, crestDrop, waterPt]] # Base and boom calculations baseGround = [self.crestVal[0] - self.baseOffsetVal, self.crestVal[1] - self.baseDropVal] baseTop = [baseGround[0], baseGround[1] + self.baseHeightVal] boomEnd = [baseTop[0] + self.boomLengthVal*cos(radians(self.boomAngleVal)), baseTop[1] + self.boomLengthVal*sin(radians(self.boomAngleVal))] xBoom = [i[0] for i in [baseGround, baseTop, boomEnd]] yBoom = [i[1] for i in [baseGround, baseTop, boomEnd]] # Update drawing self.waterLine.set_ydata([self.waterLevelVal, self.waterLevelVal]) self.duneLine.set_xdata(xDune) self.duneLine.set_ydata(yDune) self.boomLine.set_xdata(xBoom) self.boomLine.set_ydata(yBoom) self.wedge.set_center(boomEnd) straightAngle = self.boomAngleVal - (90-self.mountAngleVal) - 90 + self.hingeAngleVal self.wedge.set_theta1(straightAngle-40) self.wedge.set_theta2(straightAngle+60) self.drawBoomEnd() # Calculate and draw cabling cableMountBaseTop = [baseTop[0], baseTop[1] + self.cableMountHeight] pulleyA = [baseTop[0] + self.pulleyALocation*cos(radians(self.boomAngleVal)), baseTop[1] + self.pulleyALocation*sin(radians(self.boomAngleVal))] xc = [i[0] for i in [baseTop, cableMountBaseTop, pulleyA]] yc = [i[1] for i in [baseTop, cableMountBaseTop, pulleyA]] self.cableLine.set_xdata(xc) self.cableLine.set_ydata(yc) self.calculateCablingForces() # Update the interface angle = -30+self.mountAngleVal+self.hingeAngleVal+self.boomAngleVal self.oceanRange.setText(QString.number(boomEnd[0] + (boomEnd[1]-self.waterLevelVal)*tan(radians(angle)), 'f', 1)) # Update the canvas self.fig.canvas.draw() def calculateCablingForces(self): h = self.pulleyALocation*sin(radians(self.boomAngleVal)) - self.cableMountHeight l = self.pulleyALocation*cos(radians(self.boomAngleVal)) innerAngle = abs(atan2(h,l) - radians(self.boomAngleVal)) f = (self.sensorWeight * sin(radians(90 - self.boomAngleVal)) / sin(innerAngle)) self.pulleyAForce.setText(QString.number(f, 'f', 1)) print degrees(innerAngle) def updateCrest(self, val): self.crestVal[1] = val self.update() def updateWaterLevel(self, val): self.waterLevelVal = val self.update() def updateBaseDrop(self, val): self.baseDropVal = val self.update() def updateBaseOffset(self, val): self.baseOffsetVal = val self.update() def updateBaseHeight(self, val): self.baseHeightVal = val self.update() def updateBoomAngle(self, val): self.boomAngleVal = val self.update() def updateBoomLength(self, val): self.boomLengthVal = val self.update() def updateMountAngle(self, val): self.mountAngleVal = val self.update() def updateHingeAngle(self, val): self.hingeAngleVal = val self.update() def updateCableTowerHeight(self, val): self.cableMountHeight = val self.update() def updatePulleyALocation(self, val): self.pulleyALocation = val self.update() def updateSensorWeight(self, val): self.sensorWeight = val self.update() def createLayout(self): self.mainFrame = QWidget() # Main horizontal layout mainLayout = QHBoxLayout() # Layouts controlLayout = QGridLayout() infoLayout = QGridLayout() leftLayout = QVBoxLayout() viewLayout = QVBoxLayout() line = QFrame(self.mainFrame) line.setFrameStyle(QFrame.HLine | QFrame.Raised) leftLayout.addLayout(controlLayout) leftLayout.addWidget(line) leftLayout.addLayout(infoLayout) leftLayout.addStretch() mainLayout.addLayout(leftLayout) mainLayout.addLayout(viewLayout) # Info List infoLayout.addWidget(QLabel('<b>LIDAR</b>'), 0, 0, 1, 2, Qt.AlignCenter) infoLayout.addWidget(QLabel('Ocean Sight Range:'), 1, 0) infoLayout.addWidget(QLabel('<b>Structural</b>'), 2, 0, 1, 2, Qt.AlignCenter) infoLayout.addWidget(QLabel('Force - Pulley A (lb)'), 3, 0) self.oceanRange = QLabel('-', self.mainFrame) self.pulleyAForce = QLabel('-', self.mainFrame) infoLayout.addWidget(self.oceanRange, 1, 1) infoLayout.addWidget(self.pulleyAForce, 3, 1) infoLayout.setColumnMinimumWidth(1, 100) # Control grid controlLayout.addWidget(QLabel('<b>Dune/Ocean</b>'), 0, 0, 1, 2, Qt.AlignCenter) controlLayout.addWidget(QLabel('Dune Crest'), 1, 0) controlLayout.addWidget(QLabel('Water Level'), 2, 0) controlLayout.addWidget(QLabel('<b>Boom Geometry</b>'), 3, 0, 1, 2, Qt.AlignCenter) controlLayout.addWidget(QLabel('Base Drop'), 4, 0) controlLayout.addWidget(QLabel('Base Offset'), 5, 0) controlLayout.addWidget(QLabel('Base Height'), 6, 0) controlLayout.addWidget(QLabel('Boom Length'), 7, 0) controlLayout.addWidget(QLabel('Boom Angle'), 8, 0) controlLayout.addWidget(QLabel('<b>Mount Geometry</b>'), 9, 0, 1, 2, Qt.AlignCenter) controlLayout.addWidget(QLabel('Mount Cut Angle'), 10, 0) controlLayout.addWidget(QLabel('Hinge Angle'), 11, 0) controlLayout.addWidget(QLabel('<b>Cabling Geometry</b>'), 12, 0, 1, 2, Qt.AlignCenter) controlLayout.addWidget(QLabel('Cable Mount Height'), 13, 0) controlLayout.addWidget(QLabel('Pulley A Location'), 14, 0) controlLayout.addWidget(QLabel('<b>Loading (lbs)</b>'), 15, 0, 1, 2, Qt.AlignCenter) controlLayout.addWidget(QLabel('LIDAR Weight'), 16, 0) controlLayout.addWidget(QLabel('Boom Weight'), 17, 0) self.crestHeight = QDoubleSpinBox(self.mainFrame) self.crestHeight.setSingleStep(0.1) self.crestHeight.setValue(self.crestVal[1]) controlLayout.addWidget(self.crestHeight, 1, 1) self.connect(self.crestHeight, SIGNAL('valueChanged(double)'), self.updateCrest) self.waterLevel = QDoubleSpinBox(self.mainFrame) self.waterLevel.setSingleStep(0.1) self.waterLevel.setValue(self.waterLevelVal) controlLayout.addWidget(self.waterLevel, 2, 1) self.connect(self.waterLevel, SIGNAL('valueChanged(double)'), self.updateWaterLevel) self.baseDrop = QDoubleSpinBox(self.mainFrame) self.baseDrop.setSingleStep(0.1) self.baseDrop.setValue(self.baseDropVal) controlLayout.addWidget(self.baseDrop, 4, 1) self.connect(self.baseDrop, SIGNAL('valueChanged(double)'), self.updateBaseDrop) self.baseOffset = QDoubleSpinBox(self.mainFrame) self.baseOffset.setSingleStep(0.1) self.baseOffset.setValue(self.baseOffsetVal) controlLayout.addWidget(self.baseOffset, 5, 1) self.connect(self.baseOffset, SIGNAL('valueChanged(double)'), self.updateBaseOffset) self.baseHeight = QDoubleSpinBox(self.mainFrame) self.baseHeight.setSingleStep(0.1) self.baseHeight.setValue(self.baseHeightVal) controlLayout.addWidget(self.baseHeight, 6, 1) self.connect(self.baseHeight, SIGNAL('valueChanged(double)'), self.updateBaseHeight) self.boomLength = QDoubleSpinBox(self.mainFrame) self.boomLength.setSingleStep(0.1) self.boomLength.setValue(self.boomLengthVal) controlLayout.addWidget(self.boomLength, 7, 1) self.connect(self.boomLength, SIGNAL('valueChanged(double)'), self.updateBoomLength) self.boomAngle = QDoubleSpinBox(self.mainFrame) self.boomAngle.setSingleStep(0.5) self.boomAngle.setMaximum(360) self.boomAngle.setValue(self.boomAngleVal) controlLayout.addWidget(self.boomAngle, 8, 1) self.connect(self.boomAngle, SIGNAL('valueChanged(double)'), self.updateBoomAngle) self.mountAngle = QDoubleSpinBox(self.mainFrame) self.mountAngle.setSingleStep(0.5) self.mountAngle.setMaximum(360) self.mountAngle.setValue(self.mountAngleVal) controlLayout.addWidget(self.mountAngle, 10, 1) self.connect(self.mountAngle, SIGNAL('valueChanged(double)'), self.updateMountAngle) self.hingeAngle = QDoubleSpinBox(self.mainFrame) self.hingeAngle.setSingleStep(0.5) self.hingeAngle.setMaximum(360) self.hingeAngle.setValue(self.hingeAngleVal) controlLayout.addWidget(self.hingeAngle, 11, 1) self.connect(self.hingeAngle, SIGNAL('valueChanged(double)'), self.updateHingeAngle) self.cableTowerHeight = QDoubleSpinBox(self.mainFrame) self.cableTowerHeight.setSingleStep(0.1) self.cableTowerHeight.setValue(self.cableMountHeight) controlLayout.addWidget(self.cableTowerHeight, 13, 1) self.connect(self.cableTowerHeight, SIGNAL('valueChanged(double)'), self.updateCableTowerHeight) self.pulleyADistance = QDoubleSpinBox(self.mainFrame) self.pulleyADistance.setSingleStep(0.1) self.pulleyADistance.setValue(self.pulleyALocation) controlLayout.addWidget(self.pulleyADistance, 14, 1) self.connect(self.pulleyADistance, SIGNAL('valueChanged(double)'), self.updatePulleyALocation) self.lidarWeight = QDoubleSpinBox(self.mainFrame) self.lidarWeight.setSingleStep(5) self.lidarWeight.setMaximum(9999999) self.lidarWeight.setValue(self.sensorWeight) controlLayout.addWidget(self.lidarWeight, 16, 1) self.connect(self.lidarWeight, SIGNAL('valueChanged(double)'), self.updateSensorWeight) # Create the axes self.fig = Figure((5.0, 4.0)) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self.mainFrame) self.ax = self.fig.add_subplot(211, aspect='equal') self.barAx = self.fig.add_subplot(212, aspect='equal') self.ax.set_xlim([-15,10]) self.drawBoomEnd() self.toolBar = NavigationToolbar(self.canvas, self.mainFrame) viewLayout.addWidget(self.canvas) viewLayout.addWidget(self.toolBar) # Set the main layout self.mainFrame.setLayout(mainLayout) self.setCentralWidget(self.mainFrame)
import matplotlib as mpl from matplotlib.patches import Wedge import matplotlib.pyplot as plt mpl.rcParams['toolbar'] = 'None' plt.style.use('ggplot') fig, ax = plt.subplots(figsize=(3.5,3.5)) fig.canvas.set_window_title('Acquisition') patch = Wedge((.5, .5), .45, 90, 90, width=0.15) ax.add_patch(patch) ax.axis('equal') ax.set_xlim([0,1]) ax.set_ylim([0,1]) ax.axis('off') t = ax.text(0.5, 0.5, '0%%', fontsize=15, ha='center', va='center') di = 1 for i in range(0,360,di): patch.set_theta1(90 - i - di) progress = 100 * (i+di) / 360 t.set_text('%02d%%' % progress) plt.pause(0.0001) #plt.show() plt.close()