diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 09dba2d..4988888 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,6 @@ +0.6.0 + - tests + - fix area drawing 0.5.0 - tests - fix page drawing diff --git a/gfxlcd/drawing/area.py b/gfxlcd/drawing/area.py index 418a84b..c2ab129 100644 --- a/gfxlcd/drawing/area.py +++ b/gfxlcd/drawing/area.py @@ -32,48 +32,40 @@ class Area(Pixel): for _ in itertools.repeat(None, length): self.driver.data(color, None) - def _calculate_steps(self, length, step, required_length): - """calculate lineparts - helper""" - steps = [length for _ in range(0, step)] - if step * length < required_length: - for idx in range(0, required_length - step * length): - steps[idx] += 1 - - return steps - def draw_line(self, pos_x1, pos_y1, pos_x2, pos_y2): """draw diagonal line""" width = abs(pos_x2 - pos_x1) height = abs(pos_y2 - pos_y1) if pos_x1 == pos_x2: - steps = [height] + steps = [height+1] horizontal = False offset_x = offset_y = 0 elif pos_y1 == pos_y2: - steps = [width] + steps = [width+1] horizontal = True offset_x = offset_y = 0 elif width > height: + width += 1 if pos_x2 < pos_x1: pos_x1, pos_x2 = pos_x2, pos_x1 pos_y1, pos_y2 = pos_y2, pos_y1 offset_y = 1 if pos_y2 > pos_y1 else -1 offset_x = 1 if pos_x2 > pos_x1 else -1 horizontal = True - step = height - length = width / step - steps = self._calculate_steps(length, step, width) - + step = height + 1 + length = width // step + steps = self._calculate_line_steps(length, step, width) else: + height += 1 if pos_y2 < pos_y1: pos_x1, pos_x2 = pos_x2, pos_x1 pos_y1, pos_y2 = pos_y2, pos_y1 offset_y = 1 if pos_y2 > pos_y1 else -1 offset_x = 1 if pos_x2 > pos_x1 else -1 horizontal = False - step = width - length = height / step - steps = self._calculate_steps(length, step, height) + step = width + 1 + length = height // step + steps = self._calculate_line_steps(length, step, height) delta_y = 0 delta_x = 0 diff --git a/gfxlcd/drawing/page.py b/gfxlcd/drawing/page.py index d5720ee..0e7f54e 100644 --- a/gfxlcd/drawing/page.py +++ b/gfxlcd/drawing/page.py @@ -18,37 +18,6 @@ class Page(Pixel, metaclass=abc.ABCMeta): self.buffer[pos_x][pos_y//8] |= 1 << (pos_y % 8) self.flush() - def _calculate_steps(self, length, step, required_length): - """calculate lineparts - helper""" - steps = [length for _ in range(0, step)] - if step * length < required_length: - offset = len(steps) // 2 - rest = required_length - step * length - steps_even = True if len(steps) & 1 == 0 else False - rest_even = True if rest & 1 == 0 else False - appendix = 0 - for idx in range(0, rest): - steps[offset + appendix] += 1 - if steps_even: - appendix = self._calculate_appendix(appendix) - elif idx > 0 and rest_even: - appendix = self._calculate_appendix(appendix) - elif not rest_even: - appendix = self._calculate_appendix(appendix) - - return steps - - def _calculate_appendix(self, appendix): - """calculate appendix during drawing a line""" - if appendix == 0: - appendix = -1 - elif appendix < 0: - appendix *= -1 - else: - appendix = (appendix + 1) * -1 - - return appendix - def draw_line(self, pos_x1, pos_y1, pos_x2, pos_y2): """draw diagonal line""" width = abs(pos_x2 - pos_x1) @@ -71,7 +40,7 @@ class Page(Pixel, metaclass=abc.ABCMeta): horizontal = True step = height + 1 length = width // step - steps = self._calculate_steps(length, step, width) + steps = self._calculate_line_steps(length, step, width) else: height += 1 if pos_y2 < pos_y1: @@ -82,7 +51,7 @@ class Page(Pixel, metaclass=abc.ABCMeta): horizontal = False step = width + 1 length = height // step - steps = self._calculate_steps(length, step, height) + steps = self._calculate_line_steps(length, step, height) delta_y = 0 delta_x = 0 for idx, step in enumerate(steps): diff --git a/gfxlcd/drawing/pixel.py b/gfxlcd/drawing/pixel.py index a3a7339..e54f6cc 100644 --- a/gfxlcd/drawing/pixel.py +++ b/gfxlcd/drawing/pixel.py @@ -104,3 +104,34 @@ class Pixel(object): else: offset_x -= 1 err -= 2*offset_x + 1 + + def _calculate_line_steps(self, length, step, required_length): + """calculate lineparts - helper""" + steps = [length for _ in range(0, step)] + if step * length < required_length: + offset = len(steps) // 2 + rest = required_length - step * length + steps_even = True if len(steps) & 1 == 0 else False + rest_even = True if rest & 1 == 0 else False + appendix = 0 + for idx in range(0, rest): + steps[offset + appendix] += 1 + if steps_even: + appendix = self._calculate_line_appendix(appendix) + elif idx > 0 and rest_even: + appendix = self._calculate_line_appendix(appendix) + elif not rest_even: + appendix = self._calculate_line_appendix(appendix) + + return steps + + def _calculate_line_appendix(self, appendix): + """calculate appendix during drawing a line""" + if appendix == 0: + appendix = -1 + elif appendix < 0: + appendix *= -1 + else: + appendix = (appendix + 1) * -1 + + return appendix diff --git a/gfxlcd/driver/null/area_driver.py b/gfxlcd/driver/null/area_driver.py new file mode 100644 index 0000000..a27be79 --- /dev/null +++ b/gfxlcd/driver/null/area_driver.py @@ -0,0 +1,50 @@ +"""Area driver """ +import time +from gfxlcd.abstract.driver import Driver + + +class AreaDriver(Driver): + """Null communication driver""" + def __init__(self, width, height): + self.height = height + self.width = width + self.buffer = [[0] * self.height for x in range(self.width)] + self.area = { + 'start_x': 0, + 'start_y': 0, + 'end_x': width, + 'end_y': height + } + self.pointer = (0, 0) + + def init(self): + """initialize pins""" + pass + + def reset(self): + """reset a display""" + pass + + def cmd(self, data, enable): + """send command to display""" + pass + + def data(self, data, enable): + """send data to display""" + app_x, app_y = self.pointer + self.buffer[self.area['start_x'] + app_x][self.area['start_y'] + app_y] = data + self._inc_pointer() + + def _inc_pointer(self): + app_x, app_y = self.pointer + app_x += 1 + if self.area['start_x'] + app_x > self.area['end_x']: + app_x = 0 + app_y += 1 + + if self.area['start_y'] + app_y > self.area['end_y']: + app_x = 0 + app_y = 0 + + self.pointer = (app_x, app_y) + diff --git a/gfxlcd/driver/null/null_area.py b/gfxlcd/driver/null/null_area.py new file mode 100644 index 0000000..dfd1ca6 --- /dev/null +++ b/gfxlcd/driver/null/null_area.py @@ -0,0 +1,36 @@ +"""Null Area test chip driver""" +from gfxlcd.drawing.area import Area +from gfxlcd.abstract.chip import Chip + + +class NullArea(Area, Chip): + """Test chip driver for area drawing""" + def __init__(self, width, height, driver, auto_flush=True): + Chip.__init__(self, width, height, driver, auto_flush) + Area.__init__(self, driver) + self.rotation = 0 + + def _converted_background_color(self): + """dummy background color""" + return 2 + + def _converted_color(self): + """dummy color""" + return 1 + + def init(self): + """init display""" + self.driver.init() + Area.init(self) + Chip.init(self) + self.driver.reset() + + def _set_area(self, pos_x1, pos_y1, pos_x2, pos_y2): + """set area to work on""" + self.driver.area = { + 'start_x': pos_x1, + 'start_y': pos_y1, + 'end_x': pos_x2, + 'end_y': pos_y2 + } + self.driver.pointer = (0, 0) diff --git a/gfxlcd/driver/null/null_page.py b/gfxlcd/driver/null/null_page.py index 7915153..dbf83c4 100644 --- a/gfxlcd/driver/null/null_page.py +++ b/gfxlcd/driver/null/null_page.py @@ -1,4 +1,4 @@ -"""Null Page test chip drover""" +"""Null Page test chip driver""" from gfxlcd.drawing.page import Page from gfxlcd.abstract.chip import Chip diff --git a/gfxlcd/tests/test_area_drawing.py b/gfxlcd/tests/test_area_drawing.py new file mode 100644 index 0000000..8b37f5b --- /dev/null +++ b/gfxlcd/tests/test_area_drawing.py @@ -0,0 +1,272 @@ +import sys +from nose.tools import assert_equal +sys.path.append("../../") +from gfxlcd.driver.null.null_area import NullArea +from gfxlcd.driver.null.area_driver import AreaDriver + + +class TestPageDrawing(object): + def setUp(self): + self.drv = AreaDriver(10, 16) + self.lcd = NullArea(10, 16, self.drv, False) + self.lcd.init() + + def get_buffer(self): + return [[0] * 16 for x in range(10)] + + def test_has_correct_size(self): + assert_equal(self.lcd.width, 10) + assert_equal(self.lcd.height, 16) + + def test_empty_buffer_after_init(self): + assert_equal(self.drv.buffer, self.get_buffer()) + + def test_draw_pixel(self): + self.lcd.draw_pixel(1, 1) + buffer = self.get_buffer() + buffer[1][1] = 1 + assert_equal(self.drv.buffer, buffer) + + def test_draw_two_pixel(self): + self.lcd.draw_pixel(1, 1) + self.lcd.draw_pixel(2, 2) + buffer = self.get_buffer() + buffer[1][1] = 1 + buffer[2][2] = 1 + assert_equal(self.drv.buffer, buffer) + + def test_draw_horizontal_line(self): + self.lcd.draw_line(1, 1, 8, 1) + buffer = self.get_buffer() + buffer[1][1] = 1 + buffer[2][1] = 1 + buffer[3][1] = 1 + buffer[4][1] = 1 + buffer[5][1] = 1 + buffer[6][1] = 1 + buffer[7][1] = 1 + buffer[8][1] = 1 + assert_equal(self.drv.buffer, buffer) + + def test_draw_vertical_line(self): + self.lcd.draw_line(1, 1, 1, 14) + buffer = self.get_buffer() + buffer[1][1] = 1 + buffer[1][2] = 1 + buffer[1][3] = 1 + buffer[1][4] = 1 + buffer[1][5] = 1 + buffer[1][6] = 1 + buffer[1][7] = 1 + buffer[1][8] = 1 + buffer[1][9] = 1 + buffer[1][10] = 1 + buffer[1][11] = 1 + buffer[1][12] = 1 + buffer[1][13] = 1 + buffer[1][14] = 1 + assert_equal(self.drv.buffer, buffer) + + def test_draw_overlapping_lines(self): + self.lcd.draw_line(1, 1, 8, 1) + self.lcd.draw_line(1, 1, 1, 14) + buffer = self.get_buffer() + buffer[1][1] = 1 + buffer[2][1] = 1 + buffer[3][1] = 1 + buffer[4][1] = 1 + buffer[5][1] = 1 + buffer[6][1] = 1 + buffer[7][1] = 1 + buffer[8][1] = 1 + buffer[1][1] = 1 + buffer[1][2] = 1 + buffer[1][3] = 1 + buffer[1][4] = 1 + buffer[1][5] = 1 + buffer[1][6] = 1 + buffer[1][7] = 1 + buffer[1][8] = 1 + buffer[1][9] = 1 + buffer[1][10] = 1 + buffer[1][11] = 1 + buffer[1][12] = 1 + buffer[1][13] = 1 + buffer[1][14] = 1 + assert_equal(self.drv.buffer, buffer) + + def test_draw_diagonal_line(self): + self.lcd.draw_line(0, 0, 9, 1) + buffer = self.get_buffer() + buffer[0][0] = 1 + buffer[1][0] = 1 + buffer[2][0] = 1 + buffer[3][0] = 1 + buffer[4][0] = 1 + buffer[5][1] = 1 + buffer[6][1] = 1 + buffer[7][1] = 1 + buffer[8][1] = 1 + buffer[9][1] = 1 + assert_equal(self.drv.buffer, buffer) + + def test_draw_diagonal_line_even_steps(self): + self.lcd.draw_line(0, 0, 9, 15) + buffer = self.get_buffer() + buffer[0][0] = 1 + buffer[1][1] = 1 + buffer[2][2] = 1 + buffer[2][3] = 1 + buffer[3][4] = 1 + buffer[3][5] = 1 + buffer[4][6] = 1 + buffer[4][7] = 1 + buffer[5][8] = 1 + buffer[5][9] = 1 + buffer[6][10] = 1 + buffer[6][11] = 1 + buffer[7][12] = 1 + buffer[7][13] = 1 + buffer[8][14] = 1 + buffer[9][15] = 1 + assert_equal(self.drv.buffer, buffer) + + def test_draw_diagonal_line_even_steps_even_rest(self): + self.lcd.draw_line(0, 0, 9, 5) + buffer = self.get_buffer() + buffer[0][0] = 1 + buffer[1][1] = 1 + buffer[2][1] = 1 + buffer[3][2] = 1 + buffer[4][2] = 1 + buffer[5][3] = 1 + buffer[6][3] = 1 + buffer[7][4] = 1 + buffer[8][4] = 1 + buffer[9][5] = 1 + assert_equal(self.drv.buffer, buffer) + + def test_draw_diagonal_line_odd_steps_even_rest(self): + self.lcd.draw_line(0, 0, 9, 6) + buffer = self.get_buffer() + buffer[0][0] = 1 + buffer[1][1] = 1 + buffer[2][2] = 1 + buffer[3][2] = 1 + buffer[4][3] = 1 + buffer[5][3] = 1 + buffer[6][4] = 1 + buffer[7][4] = 1 + buffer[8][5] = 1 + buffer[9][6] = 1 + assert_equal(self.drv.buffer, buffer) + + def test_draw_diagonal_line_even_steps_odd_rest(self): + self.lcd.draw_line(0, 0, 8, 6) + buffer = self.get_buffer() + buffer[0][0] = 1 + buffer[1][1] = 1 + buffer[2][2] = 1 + buffer[3][3] = 1 + buffer[4][3] = 1 + buffer[5][3] = 1 + buffer[6][4] = 1 + buffer[7][5] = 1 + buffer[8][6] = 1 + assert_equal(self.drv.buffer, buffer) + + def test_draw_rect(self): + self.lcd.draw_rect(2, 2, 7, 11) + buffer = self.get_buffer() + buffer[2][2] = 1 + buffer[2][3] = 1 + buffer[2][4] = 1 + buffer[2][5] = 1 + buffer[2][6] = 1 + buffer[2][7] = 1 + buffer[2][8] = 1 + buffer[2][9] = 1 + buffer[2][10] = 1 + buffer[2][11] = 1 + buffer[7][2] = 1 + buffer[7][3] = 1 + buffer[7][4] = 1 + buffer[7][5] = 1 + buffer[7][6] = 1 + buffer[7][7] = 1 + buffer[7][8] = 1 + buffer[7][9] = 1 + buffer[7][10] = 1 + buffer[7][11] = 1 + + buffer[3][2] = 1 + buffer[4][2] = 1 + buffer[5][2] = 1 + buffer[6][2] = 1 + buffer[3][11] = 1 + buffer[4][11] = 1 + buffer[5][11] = 1 + buffer[6][11] = 1 + assert_equal(self.drv.buffer, buffer) + + def test_fill_rect(self): + self.lcd.fill_rect(2, 2, 7, 11) + buffer = self.get_buffer() + for x in range(6): + for y in range(10): + buffer[2+x][2+y] = 2 + assert_equal(self.drv.buffer, buffer) + + def test_draw_circle(self): + self.lcd.draw_circle(5, 8, 3) + buffer = self.get_buffer() + buffer[2][7] = 1 + buffer[2][8] = 1 + buffer[2][9] = 1 + buffer[3][6] = 1 + buffer[3][7] = 1 + buffer[3][9] = 1 + buffer[3][10] = 1 + buffer[4][5] = 1 + buffer[4][6] = 1 + buffer[4][10] = 1 + buffer[4][11] = 1 + buffer[5][5] = 1 + buffer[5][11] = 1 + buffer[6][5] = 1 + buffer[6][6] = 1 + buffer[7][6] = 1 + buffer[7][7] = 1 + buffer[8][7] = 1 + buffer[8][8] = 1 + buffer[8][9] = 1 + buffer[7][9] = 1 + buffer[7][10] = 1 + buffer[6][10] = 1 + buffer[6][11] = 1 + assert_equal(self.drv.buffer, buffer) + + def test_draw_arc(self): + self.lcd.draw_arc(5, 8, 3, 90, 270) + buffer = self.get_buffer() + buffer[2][7] = 1 + buffer[2][8] = 1 + buffer[2][9] = 1 + buffer[3][6] = 1 + buffer[3][7] = 1 + buffer[3][9] = 1 + buffer[3][10] = 1 + buffer[4][5] = 1 + buffer[4][6] = 1 + buffer[4][10] = 1 + buffer[4][11] = 1 + buffer[5][5] = 1 + buffer[5][11] = 1 + assert_equal(self.drv.buffer, buffer) + + def draw_buffer(self, buffer): + for y in range(self.lcd.height): + row = "" + for x in range(self.lcd.width): + row += str(buffer[x][y]) + print (row) diff --git a/gfxlcd/tests/test_page_drawing.py b/gfxlcd/tests/test_page_drawing.py index ad825de..98abfe1 100644 --- a/gfxlcd/tests/test_page_drawing.py +++ b/gfxlcd/tests/test_page_drawing.py @@ -7,7 +7,6 @@ from gfxlcd.driver.null.null_page import NullPage class TestPageDrawing(object): def setUp(self): self.lcd = NullPage(10, 16, None, False) - self.buffer = [[0] * (16 // 8) for x in range(10)] self.lcd.init() def get_buffer(self): @@ -18,7 +17,7 @@ class TestPageDrawing(object): assert_equal(self.lcd.height, 16) def test_empty_buffer_after_init(self): - assert_equal(self.lcd.buffer, self.buffer) + assert_equal(self.lcd.buffer, self.get_buffer()) def test_draw_pixel(self): self.lcd.draw_pixel(1, 1) @@ -104,7 +103,6 @@ class TestPageDrawing(object): buffer[7][1] = 16+32 buffer[8][1] = 64 buffer[9][1] = 128 - self.draw_buffer(self.lcd.buffer) assert_equal(self.lcd.buffer, buffer) def test_draw_diagonal_line_even_steps_even_rest(self): @@ -120,7 +118,6 @@ class TestPageDrawing(object): buffer[7][0] = 16 buffer[8][0] = 16 buffer[9][0] = 32 - assert_equal(self.lcd.buffer, buffer) def test_draw_diagonal_line_odd_steps_even_rest(self): @@ -136,23 +133,38 @@ class TestPageDrawing(object): buffer[7][0] = 16 buffer[8][0] = 32 buffer[9][0] = 64 - assert_equal(self.lcd.buffer, buffer) def test_draw_diagonal_line_even_steps_odd_rest(self): - self.lcd.draw_line(0, 0, 9, 6) + self.lcd.draw_line(0, 0, 8, 6) buffer = self.get_buffer() buffer[0][0] = 1 buffer[1][0] = 2 buffer[2][0] = 4 - buffer[3][0] = 4 + buffer[3][0] = 8 buffer[4][0] = 8 buffer[5][0] = 8 buffer[6][0] = 16 - buffer[7][0] = 16 - buffer[8][0] = 32 - buffer[9][0] = 64 + buffer[7][0] = 32 + buffer[8][0] = 64 + assert_equal(self.lcd.buffer, buffer) + def test_draw_rect(self): + self.lcd.draw_rect(2, 2, 7, 11) + buffer = self.get_buffer() + buffer[2][0] = 4+8+16+32+64+128 + buffer[3][0] = 4 + buffer[4][0] = 4 + buffer[5][0] = 4 + buffer[6][0] = 4 + buffer[7][0] = 4+8+16+32+64+128 + + buffer[2][1] = 1+2+4+8 + buffer[3][1] = 8 + buffer[4][1] = 8 + buffer[5][1] = 8 + buffer[6][1] = 8 + buffer[7][1] = 1+2+4+8 assert_equal(self.lcd.buffer, buffer) def test_fill_rect(self): @@ -202,7 +214,6 @@ class TestPageDrawing(object): buffer[3][1] = 2+4 buffer[4][1] = 4+8 buffer[5][1] = 8 - self.draw_buffer(self.lcd.buffer) assert_equal(self.lcd.buffer, buffer) def draw_buffer(self, buffer): diff --git a/setup.py b/setup.py index a5e5a46..52f6792 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ def read(*paths): setup( name='gfxlcd', - version='0.4.0', + version='0.6.0', description='gfxlcd is a handler for graphical lcds: ILI9328, SSD1306, NJU6450, touch panel: AD7843 @ Raspberry Pi.', keywords=[ 'gfxlcd', 'raspberry pi' ,'ili9328' ,'ssd1306', 'nju6450', 'lcd', 'graphical lcd', 'touch panel', 'ad7843',