def test_draw_border(self): """ Tests that the border is drawn if requested """ generator = WorkingAreaGenerator(self.to_uu, "wId") generator.set_size(400, 300) root = etree.Element("root") generator.upsert(root) border_index = len(root[0]) # border is added at the end of the list of children border = Border([[(40, 20), (160, 200)]], 0) painter = BorderPainter(border) painter.paint(generator) self.assertEqual(root[0][border_index].tag, "rect") self.assertEqual(root[0][border_index].get("x"), "10.0") self.assertEqual(root[0][border_index].get("y"), "5.0") self.assertEqual(root[0][border_index].get("width"), "30.0") self.assertEqual(root[0][border_index].get("height"), "45.0") self.assertEqual(root[0][border_index].get("style"), ("stroke-width:0.0625;" "stroke-miterlimit:4;" "stroke-dasharray:0.25,0.25;" "stroke-dashoffset:0;" "fill:none"))
def test_skip_initial_path(self): """ Tests that an empty paths as the first path is skipped """ border = Border([[], [(30, 15), (20, 20), (25, 40)], [(90, 30), (30, 90)]], 10) self.assertEqual(border.width(), 90) self.assertEqual(border.height(), 95) self.assertEqual(border.left(), 10) self.assertEqual(border.right(), 100) self.assertEqual(border.top(), 100) self.assertEqual(border.bottom(), 5)
def test_skip_empty_paths(self): """ Tests that empty paths are skipped """ border = Border([[(30, 15), (20, 20), (25, 40)], [], [(90, 30), (30, 90)], []], 10) self.assertEqual(border.width(), 90) self.assertEqual(border.height(), 95) self.assertEqual(border.left(), 10) self.assertEqual(border.right(), 100) self.assertEqual(border.top(), 100) self.assertEqual(border.bottom(), 5)
def test_build_border_with_multiple_paths(self): # pylint: disable=invalid-name """ Tests that Border instance is correctly build when multiple paths are present """ border = Border([[(30, 15), (20, 20), (25, 40)], [(90, 30), (30, 90)]], 10) self.assertEqual(border.width(), 90) self.assertEqual(border.height(), 95) self.assertEqual(border.left(), 10) self.assertEqual(border.right(), 100) self.assertEqual(border.top(), 100) self.assertEqual(border.bottom(), 5)
def test_build_border_with_one_path(self): """ Tests that Border instance is correctly build when one path is present """ border = Border([[(30, 15), (20, 20), (25, 40)]], 10) self.assertEqual(border.width(), 30) self.assertEqual(border.height(), 45) self.assertEqual(border.left(), 10) self.assertEqual(border.right(), 40) self.assertEqual(border.top(), 50) self.assertEqual(border.bottom(), 5)
def test_build_border_with_empty_path(self): # pylint: disable=invalid-name """ Tests that Border instance is correctly built when no path is present """ border = Border([[]], 10) self.assertEqual(border.width(), 0) self.assertEqual(border.height(), 0) self.assertEqual(border.left(), 0) self.assertEqual(border.right(), 0) self.assertEqual(border.top(), 0) self.assertEqual(border.bottom(), 0)
def test_build_border_with_one_path_one_point(self): # pylint: disable=invalid-name """ Tests that Border instance is correctly built when one path with one point is present """ border = Border([[(10, 20)]], 10) self.assertEqual(border.width(), 20) self.assertEqual(border.height(), 20) self.assertEqual(border.left(), 0) self.assertEqual(border.right(), 20) self.assertEqual(border.top(), 30) self.assertEqual(border.bottom(), 10)
def test_build_border_with_no_path(self): """ Tests that Border instance is correctly built when no path is present """ border = Border([], 10) self.assertEqual(border.width(), 0) self.assertEqual(border.height(), 0) self.assertEqual(border.left(), 0) self.assertEqual(border.right(), 0) self.assertEqual(border.top(), 0) self.assertEqual(border.bottom(), 0)
def test_border_vertices(self): """ Tests that Border reports its vertices correctly """ border = Border([[(30, 15), (20, 20), (25, 40)]], 10) self.assertEqual(border.bottom_left(), (10, 5)) self.assertEqual(border.bottom_right(), (40, 5)) self.assertEqual(border.top_left(), (10, 50)) self.assertEqual(border.top_right(), (40, 50))
def test_border_with_margin(self): """ Tests that commands to square the piece with a margin are added if requested Path starts with the point nearest to the bottom left border point """ border = Border([[(2, 2), (8, 18)]], 0) path = [(5, 7), (3, 4), (5, 9), (1, 1), (2.1, 2.1), (8, 2), (5, 7)] generator = CuttingToolPathsGenerator(path, 1, border) generator.generate() # Same initial and final point (the one closest to (0, 0) and (5, 7) not repeated expected_path = [(0, 0), (2, 2), (2.1, 2.1), (8, 2), (5, 7), (3, 4), (5, 9), (1, 1), (2.1, 2.1), (2, 2), (8, 2), (8, 18), (2, 18), (2, 2), (0, 0)] self.assertEqual(generator.path(), expected_path)
def test_border_with_no_margin(self): """ Tests that commands to square the piece are added if requested Margin is 0, path starts from the point nearest to (0, 0) """ border = Border([[(0, 0), (10, 20)]], 0) path = [(5, 7), (3, 4), (5, 9), (1, 1), (8, 2), (5, 7)] generator = CuttingToolPathsGenerator(path, 1, border) generator.generate() # Same initial and final point (the one closest to (0, 0) and (5, 7) not repeated expected_path = [(0, 0), (1, 1), (8, 2), (5, 7), (3, 4), (5, 9), (1, 1), (0, 0), (10, 0), (10, 20), (0, 20), (0, 0)] self.assertEqual(generator.path(), expected_path)
def test_do_not_draw_border_if_equal_working_area(self): # pylint: disable=invalid-name """ Tests that no border is drawn if border is coincident with the working area """ generator = WorkingAreaGenerator(self.to_uu, "wId") generator.set_size(400, 300) root = etree.Element("root") generator.upsert(root) num_initial_root_children = len(root[0]) border = Border([[(0, 0), (400, 300)]], 0) painter = BorderPainter(border) painter.paint(generator) self.assertEqual(len(root[0]), num_initial_root_children)
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)