GfxLCD tests and fixes – page drawing

We need tests for GfxLCD and we need it now! But this is a driver so what can we test? W can and must test all drawing functions. We have two algorithms the page and the area. Let’ begin with page one.
We can mock a chip class in such way that it won’t use a driver and all drawing would go to a buffer and we always can check if buffer looks as we want.

Null page chip

First, let’s write a NullPage chip driver. It should be relatively easy because true driver works on the buffer. So we have all required bricks.
Tests for initialization, pixel_drawing, horizontal|vertical line drawing, fill_rect, draw_circle, draw_arc are green.
But diagonal line shows bugs just as I thought 🙂
First, we have wrong steps calculation. We divide values as floats, not ints. And it is hard to draw a half of pixel 😀
The second bug was with losing 1 point in every direction. Why? Because when we start at 0 and draw to 9 we should have 10 pixels but 9 – 0 = 9 🙂 Adding one fixes the problem.
The third is a problem with symmetry. Our algorithm divides a diagonal line into smaller horizontal or vertical lines. When we divide and have a rest we must add this rest to some sublines. We were doing it by adding 1 to sublines starting from first. But this creates such effect:

#_________
#_________
_#________
_#________
__#_______
__#_______
___#______
___#______
____#_____
____#_____
_____#____
_____#____
______#___
_______#__
________#_
_________#

Look at the beginning and the end. What can we do with it?
I think it is better to add rest from the middle to the sides.
We have four cases, even or odd steps and even or odd rest. But we can make two from it.
The simplest case is with even steps. We just need to add offsets (starting middle): 0, -1, 1, -2, 2, -3, 3… same for odd rest.
And other case for odd steps and odd rest is [0, 0, -1, +1 …].
We can now refactor function:

 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

With this we have a nice line:

#_________
_#________
__#_______
__#_______
___#______
___#______
____#_____
____#_____
_____#____
_____#____
______#___
______#___
_______#__
_______#__
________#_
_________#

Summary

We have tests for all drawing that works on a page. We had problems with line drawing but all is fixed.

And drawing a line is not so simple as it looks 🙂

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s