Exemple #1
0
    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
Exemple #2
0
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")
Exemple #3
0
    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)
Exemple #4
0
    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
Exemple #5
0
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