ropod7 / pyboard_drive

23 stars 11 forks source link

drawLine() implementation proposal #5

Closed mchobby closed 8 years ago

mchobby commented 8 years ago

Hi Roman,

I did work a bit on drawLine() and I can propose the following former version. It draw a line from coordonate x,y to coordonate x1,y1 . This would be nice for charting.

Note: see further the most recent code proposal :-)

def drawLine( self, x,y,x1,y1, color ):
    if x==x1:
        self.drawVline( x, y if y<=y1 else y1, abs(y1-y), color )
    elif y==y1:
        self.drawHline( x if x<=x1 else x1, y, abs(x-x1), color )
    else:
        # assume positive range for x 
        if x1 < x:
            x,x1 = x1,x
            y,y1 = y1,y
        r = (y1-y) / (x1-x)
        # draw the line
        for i in range( x1-x+1 ):
            self.drawPixel( x+i, math.trunc(y+(r*i)), color )

=== sample ====

# work great
from lcd import *                                                           
l = LCD( rate=21000000 )                                                    
l.drawLine( 20, 155, 121, 31, RED )                                         
l.drawLine( 121, 155, 20, 31, GREEN )                                       
l.drawLine( 20,31, 121, 31, BLUE )                                          
l.drawLine( 121,155, 20,155, ORANGE )                                       
l.drawLine( 121,31, 121,155, YELLOW ) 
l.drawLine( 20,155, 20,31, CYAN )

==== sample 2 ====

from lcd import *                                                           
l = LCD( rate=21000000 )    
# Work great                                                
for i in range( 0, 320, 8 ):
    l.drawLine( 0,0, 240, i, CYAN )
# ratio bug to fix 
for i in range( 0, 240, 8 ):
    l.drawLine( 0,0, i, 320, MAGENTA )

Kind regards, Dominique

mchobby commented 8 years ago

Here a fixed version for drawLine()

    # Todo: support border > 1
    def drawLine(self, x,y,x1,y1, color ):
        if x==x1:
            self.drawVline( x, y if y<=y1 else y1, abs(y1-y), color )
        elif y==y1:
            self.drawHline( x if x<=x1 else x1, y, abs(x-x1), color )
        else:
            if x1 < x:
              x,x1 = x1,x
              y,y1 = y1,y
            r = (y1-y)/(x1-x)
            for i in range( x1-x+1 ):
                if (r<=1) or (i==0): # first always point, draw point for low ratio
                    self.drawPixel( x+i, math.trunc(y+(r*i)), color )
                else:
                    self.drawVline( x+i, math.trunc(y+(r*i)-r), math.trunc(r), color ) 

This second proposal fix the bug in the sample 2 (see previous sample) However, some lines are thick (the CYAN lines of sample 2) because r is < 1 and some other are thin (the MAGENTA lines in sample 2) because r > 1.

I do prefer the thin line because it is nicer on the screen ( thick line does overcharge the screen ). I will made a last proposal with r kept > 1. Keeping r > 1 will also improve the line drawing (because it draws less pixels).

mchobby commented 8 years ago

Here a final revision of drawLine() allow graphic drawing with ease.

    # Todo: support border > 1
    def drawLine(self, x,y,x1,y1, color ):
        if x==x1:
            self.drawVline( x, y if y<=y1 else y1, abs(y1-y), color )
        elif y==y1:
            self.drawHline( x if x<=x1 else x1, y, abs(x-x1), color )
        else:
            # keep positive range for x
            if x1 < x:
              x,x1 = x1,x
              y,y1 = y1,y
            r = (y1-y)/(x1-x)
            # select ratio > 1 for fast drawing (and thin line)
            if abs(r) >= 1:
                for i in range( x1-x+1 ):
                    if (i==0): # first always a point
                        self.drawPixel( x+i, math.trunc(y+(r*i)), color )
                    else:
                        # r may be negative when drawing to wrong way > Fix it when drawing
                        self.drawVline( x+i, math.trunc(y+(r*i)-r)+(0 if r>0 else math.trunc(r)), abs(math.trunc(r)), color )
            else:
                # keep positive range for y
                if y1 < y:
                    x,x1 = x1,x
                    y,y1 = y1,y
                # invert the ratio (should be close of r = 1/r)
                r = (x1-x)/(y1-y)
                for i in range( y1-y+1 ):
                    if( i== 0): # starting point is always a point
                        self.drawPixel( math.trunc(x+(r*i)), y+i, color )
                    else:
                        # r may be negative when drawing the wrong way > fix it to draw positive
                        self.drawHline( math.trunc(x+(r*i)-r)+(0 if r>0 else math.trunc(r)), y+i, abs(math.trunc(r)), color )
mchobby commented 8 years ago

Here another sample: This one draws a sinus on the screen with drawLine()

from lcd import *
from math import sin, trunc, radians

l = LCD( rate=21000000 )
# Draw axis
l.drawLine( 0,0, 240, 0, CYAN )
l.drawLine( 120, 0, 120, 320, CYAN )

# Draw a sinus plot (in the height of the screen)
previous=None
for degree in range(0,320):
    # screen x axis = SIN, screen y axis = degrees
    point = ( trunc(120+sin(radians(degree))*120) , degree ) 
    if previous != None:
        l.drawLine( previous[0], previous[1], point[0], point[1], YELLOW )
    previous = point 
ropod7 commented 8 years ago

I will try it soon. Thanks. I am away from my machine now.

mchobby commented 8 years ago

Here the pictures corresponding to the 3 samples/test code provided in this proposal thread. Enjoy Dominique

micropython-ili9341-exemples-60 micropython-ili9341-exemples-61 micropython-ili9341-exemples-62

ropod7 commented 8 years ago

Cool stuff! What about speed, is it as in circle drawing?

ropod7 commented 8 years ago

Sorry for my delays. It is added into driver. Cool.

I will try to understand it and will try to add some thickness feature soon.