diff --git a/cartuli/measure.py b/cartuli/measure.py index a6e2fc3..be578fb 100644 --- a/cartuli/measure.py +++ b/cartuli/measure.py @@ -19,7 +19,7 @@ ] -isclose = partial(isclose, rel_tol=1e-04) +measure_is_close = partial(isclose, abs_tol=0.001*mm) def from_str(measure: str | int | float) -> float: @@ -36,7 +36,7 @@ class Size: height: float | int def __eq__(self, other): - return isclose(self.width, other.width) and isclose(self.height, other.height) + return measure_is_close(self.width, other.width) and measure_is_close(self.height, other.height) def __str__(self): return f"({self.width}, {self.height})" @@ -72,7 +72,7 @@ class Point: y: float | int def __eq__(self, other): - return isclose(self.x, other.x) and isclose(self.y, other.y) + return measure_is_close(self.x, other.x) and measure_is_close(self.y, other.y) def __str__(self): return f"({self.x}, {self.y})" @@ -88,6 +88,10 @@ class Line: a: Point b: Point + def __eq__(self, other): + return ((self.a == other.a) and (self.b == other.b) or + (self.a == other.b) and (self.b == other.a)) + def __str__(self): return f"{self.a} <-> {self.b}" diff --git a/cartuli/sheet.py b/cartuli/sheet.py index f2af8a5..453bdba 100644 --- a/cartuli/sheet.py +++ b/cartuli/sheet.py @@ -90,6 +90,7 @@ def crop_marks_padding(self) -> float: def __len__(self): return len(self.__cards) + # TODO: Add minimum crop mark length @property def margin(self) -> float: """Return sheet margin to center content.""" @@ -146,72 +147,113 @@ def card_position(self, coordinates: Coordinates) -> Point: coordinates.y * self.padding) return Point(x, y) + def _calculate_border_horizontal_crop_marks(self) -> list[Line]: + crop_marks = [] + + for y in range(self.cards_per_page.height): + start_y_point = self.margin.height + y * (self.card_size.height + self.padding) + end_y_point = start_y_point + self.card_size.height + + crop_marks.append(Line( + Point(self.print_margin, start_y_point), + Point(self.margin.width - self.crop_marks_padding, start_y_point))) + + crop_marks.append(Line( + Point(self.print_margin, end_y_point), + Point(self.margin.width - self.crop_marks_padding, end_y_point))) + + crop_marks.append(Line( + Point(self.size.width - self.margin.width + self.crop_marks_padding, start_y_point), + Point(self.size.width - self.print_margin, start_y_point))) + + crop_marks.append(Line( + Point(self.size.width - self.margin.width + self.crop_marks_padding, end_y_point), + Point(self.size.width - self.print_margin, end_y_point))) + + return crop_marks + + def _calculate_middle_horizontal_crop_marks(self) -> list[Line]: + crop_marks = [] + + for y in range(self.cards_per_page.height): + start_y_point = self.margin.height + y * (self.card_size.height + self.padding) + end_y_point = start_y_point + self.card_size.height + + if 2 * self.crop_marks_padding < self.padding: + for x in range(self.cards_per_page.width - 1): + crop_marks.append(Line( + Point(self.margin.width + (x + 1) * self.card_size.width + x * self.padding + + self.crop_marks_padding, start_y_point), + Point(self.margin.width + (x + 1) * (self.card_size.width + self.padding) + - self.crop_marks_padding, start_y_point))) + + crop_marks.append(Line( + Point(self.margin.width + (x + 1) * self.card_size.width + x * self.padding + + self.crop_marks_padding, end_y_point), + Point(self.margin.width + (x + 1) * (self.card_size.width + self.padding) + - self.crop_marks_padding, end_y_point))) + + return crop_marks + + def _calculate_border_vertical_crop_marks(self) -> list[Line]: + crop_marks = [] + for x in range(self.cards_per_page.width): + start_x_point = self.margin.width + x * (self.card_size.width + self.padding) + end_x_point = start_x_point + self.card_size.width + + crop_marks.append(Line( + Point(start_x_point, self.print_margin), + Point(start_x_point, self.margin.height - self.crop_marks_padding))) + + crop_marks.append(Line( + Point(end_x_point, self.print_margin), + Point(end_x_point, self.margin.height - self.crop_marks_padding))) + + crop_marks.append(Line( + Point(start_x_point, self.size.height - self.margin.height + self.crop_marks_padding), + Point(start_x_point, self.size.height - self.print_margin))) + + crop_marks.append(Line( + Point(end_x_point, self.size.height - self.margin.height + self.crop_marks_padding), + Point(end_x_point, self.size.height - self.print_margin))) + + return crop_marks + + def _calculate_middle_vertical_crop_marks(self) -> list[Line]: + crop_marks = [] + + for x in range(self.cards_per_page.width): + start_x_point = self.margin.width + x * (self.card_size.width + self.padding) + end_x_point = start_x_point + self.card_size.width + + if 2 * self.crop_marks_padding < self.padding: + for y in range(self.cards_per_page.height - 1): + crop_marks.append(Line( + Point(start_x_point, self.margin.height + (y + 1) * self.card_size.height + + y * self.padding + self.crop_marks_padding), + Point(start_x_point, self.margin.height + + (y + 1) * (self.card_size.height + self.padding) - self.crop_marks_padding))) + + crop_marks.append(Line( + Point(end_x_point, self.margin.height + (y + 1) * self.card_size.height + + y * self.padding + self.crop_marks_padding), + Point(end_x_point, self.margin.height + (y + 1) * (self.card_size.height + self.padding) + - self.crop_marks_padding))) + + return crop_marks + + # TODO: Extract crop marks calculation from sheet class, + # think again about it in the future, maybe it is not the best idea @property def crop_marks(self) -> list[Line]: """Return the crop marks to be drawn in each page.""" - # TUNE: This is not manageable if self.__crop_marks is None: - crop_marks = [] - - for x in range(self.cards_per_page.width): - start_x_point = self.margin.width + x * (self.card_size.width + self.padding) - end_x_point = start_x_point + self.card_size.width - - crop_marks.append(Line( - Point(start_x_point, self.print_margin), - Point(start_x_point, self.margin.height - self.crop_marks_padding))) - crop_marks.append(Line( - Point(end_x_point, self.print_margin), - Point(end_x_point, self.margin.height - self.crop_marks_padding))) - if 2 * self.crop_marks_padding < self.padding: - for y in range(self.cards_per_page.height - 1): - crop_marks.append(Line( - Point(start_x_point, self.margin.height + (y + 1) * self.card_size.height - + y * self.padding + self.crop_marks_padding), - Point(start_x_point, self.margin.height + - (y + 1) * (self.card_size.height + self.padding) - self.crop_marks_padding))) - crop_marks.append(Line( - Point(end_x_point, self.margin.height + (y + 1) * self.card_size.height - + y * self.padding + self.crop_marks_padding), - Point(end_x_point, self.margin.height + (y + 1) * (self.card_size.height + self.padding) - - self.crop_marks_padding))) - crop_marks.append(Line( - Point(start_x_point, self.size.height - self.margin.height + self.crop_marks_padding), - Point(start_x_point, self.size.height - self.print_margin))) - crop_marks.append(Line( - Point(end_x_point, self.size.height - self.margin.height + self.crop_marks_padding), - Point(end_x_point, self.size.height - self.print_margin))) - - for y in range(self.cards_per_page.height): - start_y_point = self.margin.height + y * (self.card_size.height + self.padding) - end_y_point = start_y_point + self.card_size.height - - crop_marks.append(Line( - Point(self.print_margin, start_y_point), - Point(self.margin.width - self.crop_marks_padding, start_y_point))) - crop_marks.append(Line( - Point(self.print_margin, end_y_point), - Point(self.margin.width - self.crop_marks_padding, end_y_point))) - if 2 * self.crop_marks_padding < self.padding: - for x in range(self.cards_per_page.width - 1): - crop_marks.append(Line( - Point(self.margin.width + (x + 1) * self.card_size.width + x * self.padding - + self.crop_marks_padding, start_y_point), - Point(self.margin.width + (x + 1) * (self.card_size.width + self.padding) - - self.crop_marks_padding, start_y_point))) - crop_marks.append(Line( - Point(self.margin.width + (x + 1) * self.card_size.width + x * self.padding - + self.crop_marks_padding, end_y_point), - Point(self.margin.width + (x + 1) * (self.card_size.width + self.padding) - - self.crop_marks_padding, end_y_point))) - crop_marks.append(Line( - Point(self.size.width - self.margin.width + self.crop_marks_padding, start_y_point), - Point(self.size.width - self.print_margin, start_y_point))) - crop_marks.append(Line( - Point(self.size.width - self.margin.width + self.crop_marks_padding, end_y_point), - Point(self.size.width - self.print_margin, end_y_point))) - - self.__crop_marks = crop_marks + self.__crop_marks = ( + self._calculate_border_horizontal_crop_marks() + + self._calculate_middle_horizontal_crop_marks() + + self._calculate_border_vertical_crop_marks() + + self._calculate_middle_vertical_crop_marks() + ) return self.__crop_marks diff --git a/tests/test_measure.py b/tests/test_measure.py index 86c06c2..10555fe 100644 --- a/tests/test_measure.py +++ b/tests/test_measure.py @@ -1,6 +1,6 @@ import pytest -from cartuli.measure import Size, mm, A4, MINI_USA +from cartuli.measure import Line, Point, Size, mm, A4, MINI_USA def test_size(): @@ -13,3 +13,10 @@ def test_size(): Size.from_str("[3*mm, 4*mm]") == Size(3*mm, 4*mm) with pytest.raises(ValueError): Size.from_str("Size") + + +def test_line(): + a = Point(0, 0) + b = Point(1, 1) + + assert Line(a, b) == Line(b, a) diff --git a/tests/test_sheet.py b/tests/test_sheet.py index 278340e..31507de 100644 --- a/tests/test_sheet.py +++ b/tests/test_sheet.py @@ -132,61 +132,199 @@ def test_sheet_page_cards(random_image, random_card_image): assert not sheet.two_sided +def test_sheet_single_card_crop_marks(random_card_image): + sheet = Sheet(Card(random_card_image(size=A4/2)), size=A4, print_margin=3*mm, padding=4*mm, + crop_marks_padding=1*mm) + + print_margin = sheet.print_margin + crop_marks_padding = sheet.crop_marks_padding + sheet_size = sheet.size + card_size = sheet.card_size + margin = sheet.margin + + # V1 V2 + # | | + # H1- ---- -H3 + # | | + # |Card| + # | | + # H2- ---- -H4 + # | | + # V3 V4 + assert sorted(sheet._calculate_border_horizontal_crop_marks()) == sorted([ + # H1 + Line(Point(print_margin, margin.height), + Point(margin.width - crop_marks_padding, margin.height)), + # H2 + Line(Point(print_margin, margin.height + card_size.height), + Point(margin.width - crop_marks_padding, margin.height + card_size.height)), + # H3 + Line(Point(sheet_size.width - margin.width + crop_marks_padding, margin.height), + Point(sheet_size.width - print_margin, sheet.margin.height)), + # H4 + Line(Point(sheet_size.width - margin.width + crop_marks_padding, margin.height + card_size.height), + Point(sheet_size.width - print_margin, margin.height + card_size.height)), + ]) + assert sheet._calculate_middle_horizontal_crop_marks() == [] + assert sorted(sheet._calculate_border_vertical_crop_marks()) == sorted([ + # V1 + Line(Point(margin.width, print_margin), + Point(margin.width, margin.height - crop_marks_padding)), + # V2 + Line(Point(margin.width + card_size.width, print_margin), + Point(margin.width + card_size.width, margin.height - crop_marks_padding)), + # V3 + Line(Point(margin.width, sheet_size.height - margin.height + crop_marks_padding), + Point(margin.width, sheet_size.height - print_margin)), + # V4 + Line(Point(margin.width + card_size.width, sheet_size.height - margin.height + crop_marks_padding), + Point(margin.width + card_size.width, sheet_size.height - print_margin)), + ]) + assert sheet._calculate_middle_vertical_crop_marks() == [] + + def test_sheet_crop_marks(random_card_image): sheet = Sheet(Card(random_card_image(size=STANDARD)), size=A4, print_margin=3*mm, padding=4*mm, crop_marks_padding=1*mm) + # print_margin = sheet.print_margin + # padding = sheet.padding + # crop_marks_padding = sheet.crop_marks_padding + sheet_size = sheet.size + # card_size = sheet.card_size + # margin = sheet.margin + + # V1 V2 V3 V4 V5 V6 + # | | | | | | + # H1- ------ -H7-- ------ -H13- ------ -H19 + # | | | | | | + # | C1x1 | | C2x1 | | C3x1 | + # | | | | | | + # H2- ------ -H8-- ------ -H14- ------ -H20 + # | | | | | | + # V7 V8 V9 V10 V11 V12 + # | | | | | | + # H3- ------ -H9-- ------ -H15- ------ -H21 + # | | | | | | + # | C1x2 | | C2x2 | | C3x2 | + # | | | | | | + # H4- ------ -H10- ------ -H16- ------ -H22 + # | | | | | | + # V13 V14 V15 V16 V17 V18 + # | | | | | | + # H5- ------ -H11- ------ -H17- ------ -H23 + # | | | | | | + # | C1x3 | | C2x3 | | C3x3 | + # | | | | | | + # H6- ------ -H12- ------ -H18- ------ -H24 + # | | | | | | + # V19 V20 V21 V22 V23 V24 + # # Horizontal margin = 5.75 # Vertical margin = 12.5 - assert sorted(sheet.crop_marks) == sorted([ - Line(Point(5.75*mm, 3*mm), Point(5.75*mm, 11.5*mm)), - Line(Point(5.75*mm, 101.5*mm), Point(5.75*mm, 103.5*mm)), - Line(Point(5.75*mm, 193.5*mm), Point(5.75*mm, 195.5*mm)), - Line(Point(5.75*mm, A4.height - 11.5*mm), Point(5.75*mm, A4.height - 3*mm)), - Line(Point(69.25*mm, 3*mm), Point(69.25*mm, 11.5*mm)), - Line(Point(69.25*mm, 101.5*mm), Point(69.25*mm, 103.5*mm)), - Line(Point(69.25*mm, 193.5*mm), Point(69.25*mm, 195.5*mm)), - Line(Point(69.25*mm, A4.height - 11.5*mm), Point(69.25*mm, A4.height - 3*mm)), - Line(Point(73.25*mm, 3*mm), Point(73.25*mm, 11.5*mm)), - Line(Point(73.25*mm, 101.5*mm), Point(73.25*mm, 103.5*mm)), - Line(Point(73.25*mm, 193.5*mm), Point(73.25*mm, 195.5*mm)), - Line(Point(73.25*mm, A4.height - 11.5*mm), Point(73.25*mm, A4.height - 3*mm)), - Line(Point(136.75*mm, 3*mm), Point(136.75*mm, 11.5*mm)), - Line(Point(136.75*mm, 101.5*mm), Point(136.75*mm, 103.5*mm)), - Line(Point(136.75*mm, 193.5*mm), Point(136.75*mm, 195.5*mm)), - Line(Point(136.75*mm, A4.height - 11.5*mm), Point(136.75*mm, A4.height - 3*mm)), - Line(Point(140.75*mm, 3*mm), Point(140.75*mm, 11.5*mm)), - Line(Point(140.75*mm, 101.5*mm), Point(140.75*mm, 103.5*mm)), - Line(Point(140.75*mm, 193.5*mm), Point(140.75*mm, 195.5*mm)), - Line(Point(140.75*mm, A4.height - 11.5*mm), Point(140.75*mm, A4.height - 3*mm)), - Line(Point(204.25*mm, 3*mm), Point(204.25*mm, 11.5*mm)), - Line(Point(204.25*mm, 101.5*mm), Point(204.25*mm, 103.5*mm)), - Line(Point(204.25*mm, 193.5*mm), Point(204.25*mm, 195.5*mm)), - Line(Point(204.25*mm, A4.height - 11.5*mm), Point(204.25*mm, A4.height - 3*mm)), + assert sorted(sheet._calculate_border_horizontal_crop_marks()) == sorted([ + # H1 Line(Point(3*mm, 12.5*mm), Point(4.75*mm, 12.5*mm)), - Line(Point(70.25*mm, 12.5*mm), Point(72.25*mm, 12.5*mm)), - Line(Point(137.75*mm, 12.5*mm), Point(139.75*mm, 12.5*mm)), - Line(Point(A4.width - 4.75*mm, 12.5*mm), Point(A4.width - 3*mm, 12.5*mm)), + # H2 Line(Point(3*mm, 100.5*mm), Point(4.75*mm, 100.5*mm)), - Line(Point(70.25*mm, 100.5*mm), Point(72.25*mm, 100.5*mm)), - Line(Point(137.75*mm, 100.5*mm), Point(139.75*mm, 100.5*mm)), - Line(Point(A4.width - 4.75*mm, 100.5*mm), Point(A4.width - 3*mm, 100.5*mm)), + # H3 Line(Point(3*mm, 104.5*mm), Point(4.75*mm, 104.5*mm)), - Line(Point(70.25*mm, 104.5*mm), Point(72.25*mm, 104.5*mm)), - Line(Point(137.75*mm, 104.5*mm), Point(139.75*mm, 104.5*mm)), - Line(Point(A4.width - 4.75*mm, 104.5*mm), Point(A4.width - 3*mm, 104.5*mm)), + # H4 Line(Point(3*mm, 192.5*mm), Point(4.75*mm, 192.5*mm)), - Line(Point(70.25*mm, 192.5*mm), Point(72.25*mm, 192.5*mm)), - Line(Point(137.75*mm, 192.5*mm), Point(139.75*mm, 192.5*mm)), - Line(Point(A4.width - 4.75*mm, 192.5*mm), Point(A4.width - 3*mm, 192.5*mm)), + # H5 Line(Point(3*mm, 196.5*mm), Point(4.75*mm, 196.5*mm)), - Line(Point(70.25*mm, 196.5*mm), Point(72.25*mm, 196.5*mm)), - Line(Point(137.75*mm, 196.5*mm), Point(139.75*mm, 196.5*mm)), - Line(Point(A4.width - 4.75*mm, 196.5*mm), Point(A4.width - 3*mm, 196.5*mm)), + # H6 Line(Point(3*mm, 284.5*mm), Point(4.75*mm, 284.5*mm)), + # H19 + Line(Point(sheet_size.width - 4.75*mm, 12.5*mm), Point(sheet_size.width - 3*mm, 12.5*mm)), + # H20 + Line(Point(sheet_size.width - 4.75*mm, 100.5*mm), Point(sheet_size.width - 3*mm, 100.5*mm)), + # H21 + Line(Point(sheet_size.width - 4.75*mm, 104.5*mm), Point(sheet_size.width - 3*mm, 104.5*mm)), + # H22 + Line(Point(sheet_size.width - 4.75*mm, 192.5*mm), Point(sheet_size.width - 3*mm, 192.5*mm)), + # H23 + Line(Point(sheet_size.width - 4.75*mm, 196.5*mm), Point(sheet_size.width - 3*mm, 196.5*mm)), + # H24 + Line(Point(sheet_size.width - 4.75*mm, 284.5*mm), Point(sheet_size.width - 3*mm, 284.5*mm)) + ]) + assert sorted(sheet._calculate_middle_horizontal_crop_marks()) == sorted([ + # H7 + Line(Point(70.25*mm, 12.5*mm), Point(72.25*mm, 12.5*mm)), + # H8 + Line(Point(70.25*mm, 100.5*mm), Point(72.25*mm, 100.5*mm)), + # H9 + Line(Point(70.25*mm, 104.5*mm), Point(72.25*mm, 104.5*mm)), + # H10 + Line(Point(70.25*mm, 192.5*mm), Point(72.25*mm, 192.5*mm)), + # H11 + Line(Point(70.25*mm, 196.5*mm), Point(72.25*mm, 196.5*mm)), + # H12 Line(Point(70.25*mm, 284.5*mm), Point(72.25*mm, 284.5*mm)), + # H13 + Line(Point(137.75*mm, 12.5*mm), Point(139.75*mm, 12.5*mm)), + # H14 + Line(Point(137.75*mm, 100.5*mm), Point(139.75*mm, 100.5*mm)), + # H15 + Line(Point(137.75*mm, 104.5*mm), Point(139.75*mm, 104.5*mm)), + # H16 + Line(Point(137.75*mm, 192.5*mm), Point(139.75*mm, 192.5*mm)), + # H17 + Line(Point(137.75*mm, 196.5*mm), Point(139.75*mm, 196.5*mm)), + # H18 Line(Point(137.75*mm, 284.5*mm), Point(139.75*mm, 284.5*mm)), - Line(Point(A4.width - 4.75*mm, 284.5*mm), Point(A4.width - 3*mm, 284.5*mm)) + ]) + assert sorted(sheet._calculate_border_vertical_crop_marks()) == sorted([ + # V1 + Line(Point(5.75*mm, 3*mm), Point(5.75*mm, 11.5*mm)), + # V2 + Line(Point(69.25*mm, 3*mm), Point(69.25*mm, 11.5*mm)), + # V3 + Line(Point(73.25*mm, 3*mm), Point(73.25*mm, 11.5*mm)), + # V4 + Line(Point(136.75*mm, 3*mm), Point(136.75*mm, 11.5*mm)), + # V5 + Line(Point(140.75*mm, 3*mm), Point(140.75*mm, 11.5*mm)), + # V6 + Line(Point(204.25*mm, 3*mm), Point(204.25*mm, 11.5*mm)), + # V19 + Line(Point(5.75*mm, sheet_size.height - 11.5*mm), Point(5.75*mm, sheet_size.height - 3*mm)), + # V20 + Line(Point(69.25*mm, sheet_size.height - 11.5*mm), Point(69.25*mm, sheet_size.height - 3*mm)), + # V21 + Line(Point(73.25*mm, sheet_size.height - 11.5*mm), Point(73.25*mm, sheet_size.height - 3*mm)), + # V22 + Line(Point(136.75*mm, sheet_size.height - 11.5*mm), Point(136.75*mm, sheet_size.height - 3*mm)), + # V23 + Line(Point(140.75*mm, sheet_size.height - 11.5*mm), Point(140.75*mm, sheet_size.height - 3*mm)), + # V24 + Line(Point(204.25*mm, sheet_size.height - 11.5*mm), Point(204.25*mm, sheet_size.height - 3*mm)), + ]) + assert sorted(sheet._calculate_middle_vertical_crop_marks()) == sorted([ + # V7 + Line(Point(5.75*mm, 101.5*mm), Point(5.75*mm, 103.5*mm)), + # V8 + Line(Point(69.25*mm, 101.5*mm), Point(69.25*mm, 103.5*mm)), + # V9 + Line(Point(73.25*mm, 101.5*mm), Point(73.25*mm, 103.5*mm)), + # V10 + Line(Point(136.75*mm, 101.5*mm), Point(136.75*mm, 103.5*mm)), + # V11 + Line(Point(140.75*mm, 101.5*mm), Point(140.75*mm, 103.5*mm)), + # V12 + Line(Point(204.25*mm, 101.5*mm), Point(204.25*mm, 103.5*mm)), + # V13 + Line(Point(5.75*mm, 193.5*mm), Point(5.75*mm, 195.5*mm)), + # V14 + Line(Point(69.25*mm, 193.5*mm), Point(69.25*mm, 195.5*mm)), + # V15 + Line(Point(73.25*mm, 193.5*mm), Point(73.25*mm, 195.5*mm)), + # V16 + Line(Point(136.75*mm, 193.5*mm), Point(136.75*mm, 195.5*mm)), + # V17 + Line(Point(140.75*mm, 193.5*mm), Point(140.75*mm, 195.5*mm)), + # V18 + Line(Point(204.25*mm, 193.5*mm), Point(204.25*mm, 195.5*mm)), ])