def save_area(self): """ Save the dock area for the workspace. """ area = self.content.find('dock_area') try: with open(self._workspace_file, 'w') as f: f.write(pickle.dumps(area)) except Exception as e: log.debug("Error saving dock area: {}".format(e)) return e
def patch_pyserial_if_needed(): """ A workaround for https://github.com/pyserial/pyserial/issues/286 """ try: from serial.tools.list_ports_common import ListPortInfo except ImportError: return from declaracad.core.utils import log try: dummy = ListPortInfo() dummy == None log.debug("pyserial patch not needed") except AttributeError: def __eq__(self, other): return isinstance(other, ListPortInfo) \ and self.device == other.device ListPortInfo.__eq__ = __eq__ log.debug("pyserial patched")
def load_area(self): """ Load the dock area into the workspace content. """ area = None plugin = self.workbench.get_plugin("declaracad.ui") try: with open(self._workspace_file, 'r') as f: area = pickle.loads(f.read()) except Exception as e: log.debug(e) if area is None: log.debug("Creating new area") area = plugin.create_new_area() else: log.debug("Loading existing doc area") area.set_parent(self.content)
def _do_update(self): # Only update when all changes are done self._update_count -= 1 if self._update_count != 0: return qtapp = Application.instance()._qapp start_time = datetime.now() self.declaration.loading = True try: view = self.v3d_view self.clear_display() displayed_shapes = {} ais_shapes = [] log.debug("Rendering...") #: Expand all parts otherwise we lose the material information self.dimensions = set() shapes = self._expand_shapes(self.children(), self.dimensions) if not shapes: log.debug("No shapes to display") return self.set_selection_mode(self.declaration.selection_mode) n = len(shapes) for i, occ_shape in enumerate(shapes): qtapp.processEvents() if self._update_count != 0: log.debug("Aborted!") return # Another update coming abort d = occ_shape.declaration topods_shape = occ_shape.shape if not topods_shape or topods_shape.IsNull(): log.error("{} has no shape!".format(occ_shape)) continue # Translate part locations parent = occ_shape.parent() if parent and isinstance(parent, OccPart) \ and not topods_shape.Locked(): # Build transform for nested parts l = topods_shape.Location() while isinstance(parent, OccPart): l = parent.location.Multiplied(l) parent = parent.parent() topods_shape.Location(l) # HACK: Prevent doing this multiple times when the view is # force updated and the same part is rendered topods_shape.Locked(True) # Save the mapping of topods_shape to declaracad shape displayed_shapes[topods_shape] = occ_shape progress = self.declaration.progress = min( 100, max(0, i * 100 / n)) #log.debug("Displaying {} ({}%)".format( # topods_shape, round(progress, 2))) ais_shape = self.display_shape( topods_shape, d.color, d.transparency, d.material if d.material.name else None, d.texture, update=False) occ_shape.ais_shape = ais_shape if ais_shape: ais_shapes.append(ais_shape) # Display all dimensions log.debug("Adding {} dimensions...".format(len(self.dimensions))) displayed_dimensions = {} for item in self.dimensions: dim = item.dimension if dim is not None and item.declaration.display: displayed_dimensions[dim] = item self.display_ais(dim, update=False) # Update self.ais_context.UpdateCurrentViewer() self._displayed_shapes = displayed_shapes self._displayed_dimensions = displayed_dimensions # Update bounding box bbox = self.get_bounding_box(displayed_shapes.keys()) self.declaration.bbox = BBox(*bbox) log.debug("Took: {}".format(datetime.now() - start_time)) self.declaration.progress = 100 except: log.error("Failed to display shapes: {}".format( traceback.format_exc())) finally: self.declaration.loading = False
def load_gcode(filename, **options): """ Load a GCode file into a list of shapes to render Parameters ---------- filename: String The file path to load options: Dict merge_points: Bool If true, connected merge line segments of the same command into a single polyline (faster but doesn't show individual commands). colors: Dict A dict to update the colormap Returns ------- toolpath: List[Shape] List of shapes to visualize the toolpath """ doc = gcode.parse(filename) start = Point(0, 0, 0) last = start items = [] # merge_points = options.get('merge_points', True) # Add color options colors = COLORMAP.copy() if 'colors' in options: colors.update(options['colors']) rapid_color = colors['rapid'] normal_color = colors['normal'] arc_color = colors['arc'] plunge_color = colors['plunge'] zero = Point() last_color = None last_cmd = gcode.Command() mode = 'absolute' log.debug(doc) for cmd in doc.commands: data = cmd.data if cmd.id in ('G0', 'G1'): if mode == 'absolute': pos = cmd.position(last) else: pos = last + cmd.position(zero) if last == pos: log.debug(f"Duplicate: {cmd}") continue if cmd.id == 'G0': color = rapid_color elif last_cmd and last_cmd.id == 'G0': color = plunge_color else: color = normal_color if 'R' in data: # Radius'd corner # TODO: THIS log.warning(f"Radius ignored: {cmd}") if merge_points and last_cmd.id == cmd.id \ and color == last_color: items[-1].points.append(pos) else: # Start a new one items.append( Polyline(points=[last, pos], description=cmd.source, color=color)) last = pos last_cmd = cmd last_color = color elif cmd.id in ('G2', 'G3'): # TODO: Helical arcs using Z is not implemented pos = cmd.position(last) clockwise = cmd.id == 'G2' r = data.get('R') if r is not None: # Solve for center delta = pos - last if delta.z != 0: raise NotImplementedError( f"Helix is not implemented {cmd}") midpoint = pos.midpoint(last) q = pos.distance(last) if q == 0: raise ValueError(f"Invalid command {cmd} (d=0)") u = cmath.sqrt(r**2 - (q / 2)**2) if clockwise: u = -u x = (midpoint.x - u * delta.y / q).real y = (midpoint.y + u * delta.x / q).real center = Point(x, y, pos.z) items.append( Arc(position=center, radius=r, clockwise=clockwise, points=[last, pos], color=arc_color, description=cmd.source)) #elif 'U' in data: else: # Center format i, j = data.get('I'), data.get('J') if i is None and j is None: raise ValueError( f"Invalid arc {cmd} (both I and J missing)") if 'P' in data: raise NotImplementedError( f"Helix is not implemented {cmd}") center = last + (i or 0, j or 0) r = center.distance(last) items.append( Arc(position=center, radius=r, clockwise=clockwise, points=[last, pos], color=arc_color, description=cmd.source)) last = pos last_cmd = cmd elif cmd.id == 'G4': t = cmd.data.get('P') if not t or t < 0: raise ValueError(f"Invalid dwell time {cmd}") items.append(Vertex( position=last, description=f"Dwell {t}s", )) last_cmd = cmd elif cmd.id == 'G5': # Cubic B-Spline points = [last, last + Point(data['X'], data['Y'])] # For first if last_cmd.id != 'G5': points.append(points[-1] + Point(data['I'], data['J'])) elif 'I' in data and 'J' in data: points.append(points[-1] + Point(data['I'], data['J'])) elif 'I' in data or 'J' in data: # Must both be specified or nether raise ValueError(f"Incomplete G5 command {cmd}") # Last point points.append(points[-1] + Point(cmd['P'], cmd['Q'])) items.append( Bezier( points=points, color=normal_color, description=cmd.source, )) last = points[-1] last_cmd = cmd elif cmd.id == 'G5.1': c1 = last + Point(data['X'], data['Y']) i, j = data.get('I'), data.get('J') if i is None and j is None: raise ValueError(f"Incomplete G5.1 command {cmd}") c2 = c1 + Point(i or 0, j or 0) items.append( Bezier( points=[last, c1, c2], color=normal_color, description=cmd.source, )) last_cmd = cmd last = c2 elif cmd.id == 'G90': mode = 'absolute' elif cmd.id == 'G91': mode = 'incremental' else: log.debug(f"Ignoring: {cmd}") return items