예제 #1
0
    def test_extract_paths_inside_group_keeping_nested_transform(self):  #pylint: disable=invalid-name
        """ Tests that extracted path from elements with nested transformation works correctly
        """

        root = etree.Element("root")
        group = etree.SubElement(root, "{http://www.w3.org/2000/svg}g",
                                 {'transform': "translate(10,20)"})
        subgroup = etree.SubElement(group, "{http://www.w3.org/2000/svg}g",
                                    {'transform': "matrix(1,2,3,4,5,6)"})
        etree.SubElement(subgroup, "{http://www.w3.org/2000/svg}path",
                         {'d': "M 10,20 L 50,30 L 20,70"})

        extractor = PathsExtractor([group], to_mm, "wId")
        extractor.extract()

        self.assertEqual(extractor.paths()[0], [(85.0, 126.0), (155.0, 246.0),
                                                (245.0, 346.0)])
예제 #2
0
    def test_use_parent_transform_for_single_path_with_multiple_parents(self):  #pylint: disable=invalid-name
        """ Tests that extracted path takes all the ancestors transformations into account
        """

        root = etree.Element("root", {'transform': "scale(10)"})
        parent = etree.SubElement(root, "{http://www.w3.org/2000/svg}g",
                                  {'transform': "translate(10,20)"})
        element = etree.SubElement(parent, "{http://www.w3.org/2000/svg}path",
                                   {
                                       'transform': "matrix(1,2,3,4,5,6)",
                                       'd': "M 10,20 L 50,30 L 20,70"
                                   })

        extractor = PathsExtractor([element], to_mm, "wId")
        extractor.extract()

        self.assertEqual(extractor.paths()[0], [(850.0, 1260.0),
                                                (1550.0, 2460.0),
                                                (2450.0, 3460.0)])
예제 #3
0
    def effect(self):
        """ Main function
        """

        # A function to convert to millimiters
        to_mm = lambda value: self.uutounit(value, 'mm')
        # A function to convert to user units. This must be used to write units in the svg
        to_uu = lambda value: self.unittouu(str(value) + "mm")

        # Draw the working area
        working_area_generator = WorkingAreaGenerator(to_uu, WORKING_AREA_ID)
        working_area_generator.set_size(self.options.dim_x, self.options.dim_y)
        working_area_generator.upsert(self.document.getroot())

        if not self.options.ids:
            # print info and exit
            # Using error message even if this it not really an error...
            inkex.debug(_(("No path was seletect, only the working area was generated. Now draw a "
                           "path inside the working area and select it to generate the g-code")))
        else:
            # Extracting paths in machine coordinates
            paths_extractor = PathsExtractor(self.selected.values(), to_mm, WORKING_AREA_ID,
                                             FlattenBezier(FLATNESS))
            paths_extractor.extract()

            # Generate tool positions and orientations
            tool_path_generator = EngravingToolPathsGenerator(paths_extractor.paths(),
                                                              self.options.depth_z, MIN_DISTANCE,
                                                              DISCRETIZATION_STEP)
            tool_path_generator.generate()

            # Generating g-code
            gcode_generator = EngravingGCodeGenerator(tool_path_generator.paths(), MM_PER_DEGREE,
                                                      SAFE_Z, SMALL_DISTANCE, SMALL_ANGLE)
            gcode_generator.generate()

            # Writing to file
            filename = base_filename(self.options.filename, self.gcode_file_path) + ".gcode"
            write_file(filename, lambda f: f.write(gcode_generator.gcode()))

            inkex.debug(_("The generate g-code has been save to ") + filename)
예제 #4
0
    def test_closed_paths_with_multiple_paths(self):  #pylint: disable=invalid-name
        """ Tests that closed paths are extracted correctly also when multiple subpaths are present
        """

        root = etree.Element("root")
        element = etree.SubElement(
            root, "{http://www.w3.org/2000/svg}path",
            {'d': "M 70,800 l 125,-300 l 60,490 Z M 100,100 L 200,200"})

        extractor = PathsExtractor([element], to_mm, "wId")
        extractor.extract()

        self.assertEqual(len(extractor.paths()), 2)
        self.assertEqual(extractor.paths()[0], [(70.0, 800.0), (195.0, 500.0),
                                                (255.0, 990.0), (70.0, 800.0)])
        self.assertEqual(extractor.paths()[1], [(100.0, 100.0),
                                                (200.0, 200.0)])
예제 #5
0
    def test_extract_multiple_paths_when_lines_interrupted(self):  #pylint: disable=invalid-name
        """ Tests that multiple paths are generated when svg path is not continuos
        """

        root = etree.Element("root")
        element = etree.SubElement(
            root, "{http://www.w3.org/2000/svg}path",
            {'d': "M 70,800 l 125,-300 l 60,490 M 100,100 L 200,200"})

        extractor = PathsExtractor([element], to_mm, "wId")
        extractor.extract()

        self.assertEqual(len(extractor.paths()), 2)
        self.assertEqual(extractor.paths()[0], [(70.0, 800.0), (195.0, 500.0),
                                                (255.0, 990.0)])
        self.assertEqual(extractor.paths()[1], [(100.0, 100.0),
                                                (200.0, 200.0)])
예제 #6
0
    def test_extract_svg_path_with_only_straight_lines(self):  #pylint: disable=invalid-name
        """ Tests that svg paths are correctly extracted
        """

        root = etree.Element("root")
        element = etree.SubElement(root, "{http://www.w3.org/2000/svg}path",
                                   {'d': "M 70,800 l 125,-300 l 60,490"})

        extractor = PathsExtractor([element], to_mm, "wId")
        extractor.extract()

        self.assertEqual(len(extractor.paths()), 1)
        self.assertEqual(extractor.paths()[0], [(70.0, 800.0), (195.0, 500.0),
                                                (255.0, 990.0)])
예제 #7
0
    def test_closed_paths(self):
        """ Tests that closed paths are extracted correctly by repeating the first point at the end
        """

        root = etree.Element("root")
        group = etree.SubElement(root, "{http://www.w3.org/2000/svg}g")
        etree.SubElement(group, "{http://www.w3.org/2000/svg}path",
                         {'d': "M 70,800 l 125,-300 l 60,490 Z"})

        extractor = PathsExtractor([group], to_mm, "wId")
        extractor.extract()

        self.assertEqual(len(extractor.paths()), 1)
        self.assertEqual(extractor.paths()[0], [(70.0, 800.0), (195.0, 500.0),
                                                (255.0, 990.0), (70.0, 800.0)])
예제 #8
0
    def test_extract_path_inside_groups(self):  #pylint: disable=invalid-name
        """ Tests that a path inside a group is correctly extracted
        """

        root = etree.Element("root")
        group = etree.SubElement(root, "{http://www.w3.org/2000/svg}g")
        etree.SubElement(group, "{http://www.w3.org/2000/svg}path",
                         {'d': "M 70,800 l 125,-300 l 60,490"})

        extractor = PathsExtractor([group], to_mm, "wId")
        extractor.extract()

        self.assertEqual(len(extractor.paths()), 1)
        self.assertEqual(extractor.paths()[0], [(70.0, 800.0), (195.0, 500.0),
                                                (255.0, 990.0)])
예제 #9
0
    def test_automatically_close_open_paths_does_nothing_if_paths_closed(self):  #pylint: disable=invalid-name
        """ Tests that nothing changes if closing paths is requested but paths are closed
        """

        root = etree.Element("root")
        element = etree.SubElement(
            root, "{http://www.w3.org/2000/svg}path", {
                'd': ("M 70,800 l 125,-300 l 60,490 Z "
                      "M 100,100 L 200,200 L 100,100")
            })

        extractor = PathsExtractor([element], to_mm, "wId")
        extractor.extract()

        self.assertEqual(len(extractor.paths()), 2)
        self.assertEqual(extractor.paths()[0], [(70.0, 800.0), (195.0, 500.0),
                                                (255.0, 990.0), (70.0, 800.0)])
        self.assertEqual(extractor.paths()[1], [(100.0, 100.0), (200.0, 200.0),
                                                (100.0, 100.0)])
예제 #10
0
    def test_extract_paths_inside_groups_and_outside(self):  #pylint: disable=invalid-name
        """ Tests that a mix of paths inside groups and outside are correctly extracted
        """

        root = etree.Element("root")
        element = etree.SubElement(root, "{http://www.w3.org/2000/svg}path",
                                   {'d': "M 70,800 l 125,-300 l 60,390"})
        group = etree.SubElement(root, "{http://www.w3.org/2000/svg}g")
        etree.SubElement(group, "{http://www.w3.org/2000/svg}path",
                         {'d': "M 70,800 l 125,-300 l 60,490"})
        etree.SubElement(group, "{http://www.w3.org/2000/svg}path",
                         {'d': "M 60,700 l 127,-500 l 70,900"})

        extractor = PathsExtractor([element, group], to_mm, "wId")
        extractor.extract()

        self.assertEqual(len(extractor.paths()), 3)
        self.assertEqual(extractor.paths()[0], [(70.0, 800.0), (195.0, 500.0),
                                                (255.0, 890.0)])
        self.assertEqual(extractor.paths()[1], [(70.0, 800.0), (195.0, 500.0),
                                                (255.0, 990.0)])
        self.assertEqual(extractor.paths()[2], [(60.0, 700.0), (187.0, 200.0),
                                                (257.0, 1100.0)])
예제 #11
0
    def test_automatically_close_open_paths(self):  #pylint: disable=invalid-name
        """ Tests that open paths are automatically closed if requested
        """

        root = etree.Element("root")
        element = etree.SubElement(
            root, "{http://www.w3.org/2000/svg}path",
            {'d': "M 70,800 l 125,-300 l 60,490 M 100,100 L 200,200"})

        extractor = PathsExtractor([element],
                                   to_mm,
                                   "wId",
                                   auto_close_path=True)
        extractor.extract()

        self.assertEqual(len(extractor.paths()), 2)
        self.assertEqual(extractor.paths()[0], [(70.0, 800.0), (195.0, 500.0),
                                                (255.0, 990.0), (70.0, 800.0)])
        self.assertEqual(extractor.paths()[1], [(100.0, 100.0), (200.0, 200.0),
                                                (100.0, 100.0)])
예제 #12
0
    def test_use_parent_transform_for_multiple_path(self):  #pylint: disable=invalid-name
        """ Tests that extracted path takes the parent transformation into account
        """

        root1 = etree.Element("root", {'transform': "translate(10,20)"})
        element1 = etree.SubElement(root1, "{http://www.w3.org/2000/svg}path",
                                    {
                                        'transform': "matrix(1,2,3,4,5,6)",
                                        'd': "M 10,20 L 50,30 L 20,70"
                                    })
        root2 = etree.Element("root", {'transform': "translate(5,10)"})
        element2 = etree.SubElement(root2, "{http://www.w3.org/2000/svg}path",
                                    {
                                        'transform': "matrix(1,2,3,4,5,6)",
                                        'd': "M 10,20 L 50,30 L 20,70"
                                    })

        extractor = PathsExtractor([element1, element2], to_mm, "wId")
        extractor.extract()

        self.assertEqual(extractor.paths()[0], [(85.0, 126.0), (155.0, 246.0),
                                                (245.0, 346.0)])
        self.assertEqual(extractor.paths()[1], [(80.0, 116.0), (150.0, 236.0),
                                                (240.0, 336.0)])
예제 #13
0
    def test_flatten_path_if_requested(self):
        """ Tests that path is flattened if the constructor flatten parameter is not None
        """

        root = etree.Element("root")
        element = etree.SubElement(root, "{http://www.w3.org/2000/svg}path",
                                   {'d': "dummy value to check"})

        class FlattenMock:  #pylint: disable=missing-docstring,too-few-public-methods
            def __init__(self, test):
                self.test = test

            def __call__(self, curve):  #pylint: disable=missing-docstring
                self.test.assertEqual(curve, "dummy value to check")

                return [('M', (70.0, 800.0)), ('L', (195.0, 500.0)),
                        ('L', (255.0, 990.0))]

        extractor = PathsExtractor([element], to_mm, "wId", FlattenMock(self))
        extractor.extract()

        self.assertEqual(len(extractor.paths()), 1)
        self.assertEqual(extractor.paths()[0], [(70.0, 800.0), (195.0, 500.0),
                                                (255.0, 990.0)])
    def effect(self):
        """ Main function
        """

        # First of all generating the machine instance and checking piece dimensions fit
        machine = machine_factory(self.options.machine_type)
        if machine:
            valid_dimensions = machine.piece_dimensions_allowed(
                self.options.dim_x, self.options.dim_y)
            if not valid_dimensions:
                raise InvalidWorkpieceDimensions(machine.working_area_width(),
                                                 machine.working_area_height())

        # A function to convert to millimiters
        to_mm = lambda value: self.uutounit(value, 'mm')
        # A function to convert to user units. This must be used to write units in the svg
        to_uu = lambda value: self.unittouu(str(value) + "mm")

        # Draw the working area
        working_area_generator = WorkingAreaGenerator(to_uu, WORKING_AREA_ID)
        working_area_generator.set_size(self.options.dim_x, self.options.dim_y)
        working_area_generator.upsert(self.document.getroot())

        if not self.options.ids:
            # print info and exit
            inkex.debug(
                _(("No path was seletect, only the working area was generated. Now draw a "
                   "path inside the working area and select it to generate the g-code"
                   )))
        else:
            # Extracting paths in machine coordinates
            paths_extractor = PathsExtractor(
                self.selected.values(), to_mm, WORKING_AREA_ID,
                FlattenBezier(self.options.flatness),
                self.options.auto_close_path)
            paths_extractor.extract()

            # The border to use. This is None if no border is requested. If border is present, also
            # draws it
            border = None
            if self.options.square:
                border = Border(paths_extractor.paths(), self.options.margin)
                painter = BorderPainter(border)
                painter.paint(working_area_generator)

            # Joining paths. This will also check that all paths are closed
            paths_joiner = PathsJoiner(paths_extractor.paths(), CLOSE_DISTANCE)
            paths_joiner.unite()

            # Generate tool positions
            tool_path_generator = CuttingToolPathsGenerator(
                paths_joiner.union_path(), CLOSE_DISTANCE, border)
            tool_path_generator.generate()

            # The object drawing the tool path
            painter = ToolPathPainter(tool_path_generator.path())

            # Draw tool path on original svg if requested
            if self.options.draw_toolpath:
                painter.paint(working_area_generator.get_element(),
                              working_area_generator.get_factor(), "255,0,0")

            # Generating g-code
            gcode_generator = CuttingGCodeGenerator(tool_path_generator.path(),
                                                    self.options.speed)
            gcode_generator.generate()

            # Computing information about path
            generic_filename = base_filename(self.options.shapename,
                                             self.gcode_file_path)
            info = PathInfo(tool_path_generator.path(), self.options,
                            generic_filename)

            # Writing gcode to file
            write_file(
                os.path.join(self.gcode_file_path, info.gcode_filename()),
                lambda f: f.write(gcode_generator.gcode()))

            # Writing svg to file
            doc = generate_path_svg(painter)
            write_file(os.path.join(self.gcode_file_path, info.svg_filename()),
                       lambda f: doc.write(f))

            # Writing metainfo to file
            write_file(
                os.path.join(self.gcode_file_path, info.metainfo_filename()),
                lambda f: f.write(json.dumps(info.metainfo(), indent=2)))

            message = (_("The generate g-code has been saved to ") +
                       info.gcode_filename() +
                       _(". Estimated working time: ") +
                       str(info.working_time_min()) + _(" minutes"))
            if not info.is_path_inside_workpiece():
                message += _(
                    ". WARNING: some points are outside the workpiece")

            inkex.debug(message)