def coalesce_points(path: ICurveCollection): """ gathers all small steps and stores them as floats in "change" if one of coordinates (or both) changes more than by one after some number of points, new shift point is generated conserving leftover step that are smaller than 1 """ for curve in path.get_curves(): curve_points = curve.components new_curve_points = [] change: Point = curve.start curve.start = Point(round(change.x), round(change.y)) change -= curve.start i = 0 while i < len(curve_points): while change.in_range(-1, 1) and i < len(curve_points): change.shift_inplace(curve_points[i]) i += 1 new_point = Point(round(change.x), round(change.y)) # conserve all changes that are less than integer value change -= new_point new_curve_points.append(new_point) # replace all elements of shifts list with new shifts curve.components.clear() curve.components.extend(new_curve_points)
def init_path(): return HandwrittenPath(curves=[ Curve([Point(1, 1), Point(1, 1), Point(1, 1)]), Curve(start=Point(10, 10)), Curve([Point(1, 1)]) ])
def write_text(self, text_input: str) -> PathsCollection: text_path = PathsCollection() self.dict_transformer.scale(0.5, 0.5) transformed_dict = self.dict_transformer.get_result() letter_size: list = transformed_dict.get_max_letter_size() cur_write_position = Point(0, self.line_height) for letter_index, char in enumerate(text_input): try: char_variants = transformed_dict[char] char_path = char_variants[0] boxed_path = PathShiftBox(char_path) boxed_path.extend_height(letter_size[1]) boxed_path.set_position(cur_write_position) text_path.append(boxed_path) cur_write_position.x += boxed_path.box.get_size_x() except ObjectNotFound: if char == '\n': self.current_line += 1 cur_write_position = Point(0, self.current_line * self.line_height) elif char == ' ': cur_write_position.x += self.space_size else: raise ObjectNotFound(f"'{repr(char)}' not found in dictionary") return text_path
def new_curve(self, start: Point, previous: Point = None): previous = previous if previous is not None else Point(0, 0) curve_shift = start.get_shift(previous) curve = Curve(start=curve_shift) curve.last_absolute_point = start # must be assigned to continue adding points to curve self.components.append(curve)
def handle_motion_draw(self, event): if self.path_drawer.try_draw(): if self._mouse_released: self._mouse_released = False self.path_drawer.start_curve(Point(event.x, event.y)) else: self.path_drawer.continue_curve(Point(event.x, event.y)) else: messagebox.showinfo("Warning", self.message_warning_cannot_draw)
def init_path_plus_5(): return HandwrittenPath(curves=[ Curve([ Point(1, 0), Point(1, 0), Point(1, 0), Point(1, 0), Point(1, 0) ]) ])
def test_draw_multiple_anchors(self): self.app.page_iterator.get_page().lines_points = [[ Point(100, 150), Point(120, 80), Point(116, 90) ]] self.app.handle_edit_page_points() self.app.mouse_position = Point(128, 128) self.assertEqual( self.app.mouse_position, self.app.page_iterator.anchor_manager.get_current_point())
def test_create_new_curve_from_iterator(self): self.get_lines(self.path_iter) self.path_iter._new_curve(Point(50, 50)) self.path_iter.append_absolute(Point(55, 55)) self.path_iter.append_absolute(Point(60, 80)) self.path_iter.append_absolute(Point(65, 85)) lines = self.get_lines(self.path_iter) self.assertListEqual(lines, [ (Point(50, 50), Point(55, 55)), (Point(55, 55), Point(60, 80)), (Point(60, 80), Point(65, 85)) ])
def test_path_with_shift_to_bytes(self): self.path.set_position(Point(10, 10)) a = copy.deepcopy(self.path) bt = a.get_bytes() b = HandwrittenPath.read_next(io.BytesIO(bt)) self.assertEqual(a, b)
def test_empty_path_filled(self): path = HandwrittenPath() itr = path.get_lines() itr._new_curve(Point(50, 50)) itr.append_absolute(Point(55, 55)) itr.append_absolute(Point(60, 80)) itr.append_absolute(Point(65, 85)) lines = self.get_lines(itr) self.assertListEqual(lines, [ (Point(50, 50), Point(55, 55)), (Point(55, 55), Point(60, 80)), (Point(60, 80), Point(65, 85)) ])
def test_anchor_draw(self): self.app.mouse_position = Point(128, 128) self.app.handle_edit_page_points() self.assertEqual( self.app.mouse_position, self.app.page_iterator.anchor_manager.get_current_point())
def test_space_written(self): test_text = 'a a' writer = PathTextWriter(self.page, self.dictionary) writer.set_space_size(5) text_path_iter = iter(writer.write_text(test_text)) self.path_group_a[0].set_position(Point(0, 0)) last_point = self.path_group_a[0].get_last_point() self.check_iterator_continues_with_other(text_path_iter, iter(self.path_group_a[0])) a_iter_shifted = self.path_group_a[0].get_lines( last_point.shift(Point(5, 0))) self.check_iterator_continues_with_other(text_path_iter, a_iter_shifted)
def __init__(self, display: CanvasDisplay, page: Page): self.display = DisplayDrawHistory(display) self.page = page self.point_draw_objects: Dict[Point, DrawTransaction] = {} self.temp_point = Point(0, 0) self.points_iterator = CyclicIterator( self.page.get_line_transform().anchors) # must be called to init iterators. or else will not work! self.reset_iterator()
def redraw(self): try: self.reset() current_path = self.dictionary_manager.iterator.get_variant_or_raise( ) # place path at (0, 0) and shift according to entered shift point current_path.set_position(Point(0, 0)) self.path_lines_iterator = current_path.get_lines(self.shift_point) self.draw_lines_to_end(self.path_lines_iterator) except ObjectNotFound: pass
def __init__(self, path: ICurveCollection): """ Parameters ---------- path iterable path box_size collection of two numbers (width, height) """ self.box_position: Point = Point(0, 0) self.path = path self.box = self.get_lines_box(self.path.get_lines()) self.box_size = self.box.get_size() self.rectangle_shift: Point = self.get_rectangle_shift(self.box)
def get_rectangle_shift(cls, box: Box) -> Point: """ Rectangle will be aligned to bottom left corner top left corner is (0, 0) y axis is inverted path_box: contains box from function get_path_box() """ shift = Point(0, 0) # displacement from start to left border shift.x -= box.min_x # desired box height minus displacement down from beginning shift.y += box.get_size_y() - box.max_y return shift
def __init__(self, root): tk.Frame.__init__(self, root) self.parent = root self.parent.title("Handwriting manager") self._mouse_released = True grid_width = 15 # dict_manager of path groups with default value self.dictionary_manager = DictionaryManager() self.canvas = tk.Canvas(root, width=500, height=450, bg="white") display = CanvasDisplay(self.canvas) self.path_drawer = PathDrawer(self.dictionary_manager, display) self.point_entry = PointEntry(root, grid_width) self.point_entry.set(Point(100, 100)) self.path_drawer.set_global_shift(self.point_entry.get_point()) self.path_cursor = PathCursorWidget(root, grid_width, self.path_drawer) self.path_cursor.update_menu_labels() self.dictionary_opener = DictionaryOpenerWidget(root, grid_width, self.dictionary_manager, self.path_drawer.redraw, self.path_cursor.update_menus) self.dictionary_editor = DictionaryEditorWidget(root, grid_width, self.dictionary_manager, self.path_cursor.update_menus, self.path_drawer.redraw) put_objects_on_grid(self, [ [tk.Label(root, text="Base shift: "), self.point_entry], [(self.dictionary_opener, {"columnspan": 2})], [(self.path_cursor, {"columnspan": 2})], [(self.dictionary_editor, {"columnspan": 2})], [(self.canvas, {"columnspan": 2})], ]) self.bind_handlers(self.create_events_dict())
def init_absolute_points(): return [ Point(*elem) for elem in [(15, 15), (20, 15), (30, 40), (80, 60)] ]
def setUp(self) -> None: self.path = HandwrittenPath() self.path.new_curve(Point(20, 20)) self.path.append_absolute(Point(25, 30)) # (+5, +10) self.path.append_absolute(Point(28, 28)) # (+3, -2)
def test_get_rectangle_shift(self): box = PathShiftBox.get_lines_box(self.path.get_lines()) shift = PathShiftBox.get_rectangle_shift(box, (50, 50)) self.assertEqual(Point(-20, 20), shift)
def test_get_shifted_path_box(self): self.path.set_position(Point(0, 0)) box = PathShiftBox.get_lines_box(self.path.get_lines()) self.assertEqual(Box(min_x=0, max_x=8, min_y=0, max_y=10), box)
def get_letter_position(self, text_index, size): return Point(text_index * size[0], 0)
def set_space_size(self, space_size): self.space_size = Point(space_size, 0)
def set_parameters(self, width, height, line_height): self.top_left = Point(0, 0) self.bottom_right = Point(0, height) self.top_right = Point(width, 0) self.line_bottom_start = Point(0, line_height)
def __init__(self, shifts: list = None, start: Point = None): self.start = start if start is not None else Point(0, 0) self.components = shifts if shifts is not None else [] self.last_absolute_point = self.get_last_point()
def test_curve_last_point(self): self.assertEqual(self.curve.get_last_point(), Point(3, 3)) self.assertEqual(self.curve.get_last_point(Point(10, 10)), Point(13, 13))
def test_append_shift_to_path(self): self.empty_path.append_shift(Point(1, 1)) self.assertEqual(self.empty_path.get_last_point(), Point(1, 1)) self.empty_path.append_shift(Point(10, 10)) self.assertEqual(self.empty_path.get_last_point(), Point(11, 11))
def test_set_path_position(self): self.path.set_position(Point(10, 10)) self.assertEqual(self.path.get_last_point(), Point(24, 24))
def test_create_empty_path(self): self.assertEqual(self.empty_path.get_last_point(), Point(0, 0)) self.assertTrue(self.empty_path.empty())
def append_absolute(self, point: Point): self.components.append(point.get_shift(self.last_absolute_point)) self.last_absolute_point = point