python_point_line_calss

2019年04月19日

首頁

 

 

Python user_defined Class Point

Python canvas Point自訂函數:Python學習日誌之三

                           

The  python Canvas widget provides graphics methods for Tkinter to  draw graphs and plots, create graphics editors, and implement various kinds of custom widgets.The purpose of canvas widget is used to display and edit graphs and other drawings.

If you are a python beginner like me or you are get used to vb6 or vb.net ,you may feel confused with some methods of python canvas. Hereafter I would like to share some user_defined function of class Point(2D,Point,3D will discuss the other day) which similar to vb6/vb.net.

    Python canvas畫布,並無直接提供畫點之工具,只能以畫圓之create_oval()畫圓代替,點直徑最小也要2 pixels,即create_oval(x,y,x+1,y+1),或create_line(x,y,x+1,y)不像vb6可以直接用Pset(x,y)。因此對用慣vb6vb nert,相當不習慣。如要將vb6畫圖程式改寫成python也很頭大。因為vb6只要在module中宣告如:

Public Type ptxy()

   x as double

   y as double

   str as string  ‘(備註用:如點號,及其他註記)

  

在主程式及其他專案下之function sub,只要宣告如 pt0 as ptxy, ptx as ptxy即可。為解決vb6畫圖程式改寫成python問題,所以今天在此就將個人之學習經驗與大家分享。首先我們需要自訂Point()函數,我們希望如要定義直線也能以Line(pt0,pt1)之型式出現,也就是x0=pt0.x, y0=pt0.y,  x1=pt1.x, y1=pt1.y。為達成此目的,我們可以定義Ptxy類別(class):

-----------------------------------------------------------

class Ptxy: # class Ptxy() is same as class Ptxy

    def __init__(self,x,y):

        self.x=x

        self.y=y  

 

    def ptxy(self):

    return self.x,self.y

-----------------------------------------------------------

 __init__(initialization)為初始化必要之宣告,或稱建構方法,有此宣告,就不能直接被呼叫引用,所以必須在class Ptxy下 另外定義ptxy(self)作為本尊或替身、分身,被用來呼叫引用。

(1)   此處init不能改用其他任意名稱。

(2)   self則可以改用其他名稱,如my,Day,MrDay等。

(3)   def ptxy(self)ptxy也可改以Ptxy,ptXY,ptxy,PTXY等取代。

(4)   class Ptxy涵蓋範圍下其他函數有以self為引數者,後面的函數可以引用較前者。這就是有self之特殊。

(5)   class Ptxy ptptlen(pt0,pt1)不能被其他與class Ptxy有關之函數(IspointInCircl()RotatePoint()) 應改用class line()linelen(line)。此可能是應因class Ptxy只定義一個點(ptxy)

,而class line是定義兩個點(pt0,pt1)。如硬要使用只能用ptptDist(pt0,pt1)

然後令x0=pt0.x,y0=pt1,x1=pt1.x,y1=pt1.yldist=math.sqrt((x1-x0)**2+(y1-y0)**2)

………。否則會出現NameError: name 'ptptlen' is not defined

(6)set_pixel(xi,yi)et_pixel(pti)等之座標均為canvas絕對座標。

 

class Ptxy中我們將討論到點之旋轉(Rotation of point) 、反射或鏡射(Reflection of point),為方便說明及檢視成果,我們另定義圓(圓心及半徑已知,至於三點圓會另外討論)之畫法以說明點之旋轉。程式內容,相關函數之實現(Implement)方法相當簡單,可以看圖說故事,套ㄧ句英文是self- explanation,所以就不多廢話。

 

 ‘---------------------------------------------------------------------

 

# -*- coding: utf-8 -*-

#author:day169

import math

import tkinter as tk

from PIL import Image

import PIL.ImageGrab

from ctypes import windll

root=tk.Tk()

root.title('My Window')

root.geometry('1000x1000')

 

canvas= tk.Canvas(root,width=800,height=800,bg='white')

canvas.place(x=100,y=100)

#canvas.pack()

global glxystr

glxystr="'x= 0 ', y= '0'"

lblxy = tk.Label( root,text=glxystr,bg='white')

lblxy.place(x=10,y=10,width=160)

class Ptxy: # class Ptxy() is same as class Ptxy

    def __init__(self,x,y) :

        self.x=x

        self.y=y   #return self.x, self.y --->do'nt work不能直接呼叫 return self.x, self.y

           

    def Ptxy(self): #note here we can use ptxy or Ptxy,PTXY,pTxy,此處可用與class Ptxy相同名稱也可以用 ptxy ,PTXY,PTxy同價

        return self.x,self.y #return self.x, self.y work

def get_pixel(pti):  #coordinate pti is canvas relative to root widget

    dc = windll.user32.GetDC(0)

    xroot=pti.x

    yroot=pti.y

    #rgb = windll.gdi32.GetPixel(dc,event.x_root,event.y_root)

    rgb = windll.gdi32.GetPixel(dc,xroot,yroot)

    r = rgb & 0xff

    g = (rgb >> 8) & 0xff

    b = (rgb >> 16) & 0xff

    print (r,g,b)

    return r,g,b

   

def ptMoveto(ptOrg,xmove,ymove):

    xmoveto=ptOrg.x+xmove

    ymoveto=ptOrg.y+ymove

    ptmove=Ptxy(xmoveto,ymoveto)

    return ptmove

       

def ptCopyto(ptorg,xmove,ymove):

    xmoveto=ptorg.x+xmove

    ymoveto=ptorg.y+ymove

    ptcopyto=Ptxy(xmoveto,ymoveto)

    return ptorg,ptcopyto   

    #--------------------------------

def get_pixel_colorw(i_x, i_y):# i_x, i_y are absolute coordinateare of  widget canvas絕對座標

      import win32gui

      i_desktop_window_id = win32gui.GetDesktopWindow()

      i_desktop_window_dc = win32gui.GetWindowDC(i_desktop_window_id)

      long_colour = win32gui.GetPixel(i_desktop_window_dc, i_x, i_y)

      i_colour = int(long_colour)

      return (i_colour & 0xff), ((i_colour >> 8) & 0xff), ((i_colour >> 16) & 0xff

     

def get_pixel_color(i_x, i_y):# i_x, i_y are absolute coordinateare of  widget canvas絕對座標

      import PIL.ImageGrab

      print('get color',PIL.ImageGrab.grab().load()[i_x, i_y])

      return PIL.ImageGrab.grab().load()[i_x, i_y]

    print(get_pixel_color(0,0))

 

def get_pixel_colour(pti):#ptiis point absolute coordinateare of  widget canvas絕對座標

    #import PIL.ImageGrab

    print('int(pti.x),int(pti.y)',int(pti.x),int(pti.y))

    color=PIL.ImageGrab.grab().load()[int(pti.x),int(pti.y)]

    print('int(pti.x),int(pti.y)',int(pti.x),int(pti.y),color)

    return color # return rgb(r,g,b)

   

def get_pixel_colourA(i_x, i_y):#i_x, i_y are absolute coordinateare of  widget canvas絕對座標

    #import PIL.ImageGrab

    color=PIL.ImageGrab.grab().load()[i_x, i_y]

    return color  # return rgb(r,g,b)

    #print (get_pixel_colour(0, 0))

def set_pixel_color(pti,rgbIn):

    rgbuse=from_rgb(rgbIn)

    print("rgb",rgbIn,rgbuse)

    id=canvas.create_line(pti.x,pti.y,pti.x+1,pti.y,fill=rgbuse)

    stri=canvas.coords(id)

    print("id,stri",id,stri)

    print('strii[0]',stri[0])

    color=PIL.ImageGrab.grab().load()[int(stri[0]),int(stri[1])]

    print('color in set_pixel,stri[0],stri[1]',int(stri[0]),int(stri[1]),color)

    return id  

class line():

    def __init__(self,pt0,pt1) :

        self.pt0=pt0

        self.pt1=pt1

    def line(self): #callabl for both in main() and other function建議使用

        return self.pt0,self.pt1

def linelen(Linet):

   

    ldist=math.sqrt((Linet.pt1.x-Linet.pt0.x)**2+(Linet.pt1.y-Linet.pt0.y)**2)

    return ldist

def ptptDist(pt0,pt1): # can be called both by main() and other function,ptptDist可以在主程式及其他函數使

    x0=pt0.x

    y0=pt0.y

    x1=pt1.x

    y1=pt1.y

    ldist=math.sqrt((x1-x0)**2+(y1-y0)**2)

    return ldist

  

def ptptLen(pt0,pt1):# callabe in main() only,只能在主程式使用

    try:

        ldist=math.sqrt((pt1.x-pt0.x)**2+(pt1.y-pt0.y)**2)

        print ('ldist=',ldist)

    except:

        x0=pt0.x

        y0=pt0.y

        x1=pt1.x

        y1=pt1.y

        ldist=math.sqrt((x1-x0)**2+(y1-y0)**2)

    return ldist

    

def ptsLen(pts): # callabe in main() only,只能在主程式使用

    ldist=math.sqrt((pts[1].x-pts[0].x)**2+(pts[1].y-pts[0].y)**2)   

    return ldist       

 #------------------------------------------------------------------------------------------      

def IspointInCircle(pttest,ptCirBox0,ptCirBox1,radi): #herafter are exclude within class Ptxy,do'nt indent,不縮排

    x=(ptCirBox0.x+ptCirBox1.x)/2 

    y=(ptCirBox0.y+ptCirBox1.y)/2

    #不能直接使用 ptcen.x=(ptCirBox0.x+ptCirBox1.x)/2 & ptcen.y=(ptCirBox0.y+ptCirBox1.y)/2

    ptcen=Ptxy(x,y)

    linet=line(pttest,ptcen)

    #ltpt=math.sqrt((pttest.x-ptcen.x)**2+(pttest.y-ptcen.y)**2)

    ltpt=linelen(linet)

    ltpt=ptptDist(pttest,ptcen)

    if ltpt< radi:

        return True

    else:

        return False

   

   

def RotatePoint(ptBerot,ptPivot,angrot ): # rotation a point

    #print('ptBerot.x,ptBerot.y,ptPivot.x,ptPivot.y',ptBerot.x,ptBerot.y,ptPivot.x,ptPivot.y)

    #radt=math.sqrt((ptBerot.x-ptPivot.x)**2+(ptBerot.y-ptPivot.y)**2)#ptptlen(ptBerot,ptPivot)

    #radt=ptclass.Ptptlen(ptBerot,ptPivot)

    #pts=[]

    #pts.append(ptBerot)

    #pts.append(ptPivot)

    #radt=ptslen(pts)

    radt=ptptDist(ptBerot,ptPivot)

    angorg=math.atan2((ptBerot.y-ptPivot.y),(ptBerot.x-ptPivot.x))

    angrot=math.radians(angrot)+angorg

    xrot=ptPivot.x+radt*math.cos(angrot)

    yrot=ptPivot.y+radt*math.sin(angrot)

    ptrotAft=Ptxy(xrot,yrot)

    return ptrotAft

def Ptverticaltoline(referPt,basePt0,basePt1) :#已知線外一點求垂線座標垂足點

    #print('in= ',referPtX, referPtY,basePt0x,basePt0y,basePt1x,basePt1y)

    Ax = basePt0.x

    Ay = basePt0.y

    Bx = basePt1.x

    By = basePt1.y

    px = referPt.x

    py = referPt.y

    #print('Ax,Ay,Bx,By,px,py',Ax,Ay,Bx,By,px,py)

    vAB_x = Bx - Ax

    vAB_y = By - Ay

    Ldist = math.sqrt(vAB_x ** 2 + vAB_y ** 2)

    #print('Ldist',Ldist)

    if Ldist >= 0.000001:

        uAB_x = vAB_x / Ldist   #'單位向量 uabx分量

        uAB_y = vAB_y / Ldist   #'單位向量 uaby分量

        #print('uAB_x,uAB_y',uAB_x,uAB_y)

        vPA_x = px - Ax

        #print('vPA_x',vPA_x)

        vPA_y = py - Ay

        #print('vPA_y',vPA_y)

        t = uAB_x * vPA_x + uAB_y * vPA_y

        ptvertX = Ax + t * uAB_x

        ptvertY = Ay + t * uAB_y

        ptvert=Ptxy(ptvertX,ptvertY)

        return  ptvert

   

def ReflctPoint(referPt,basePt0,basePt1) :#點反射或鏡射

    #print('in= ',referPtX, referPtY,basePt0x,basePt0y,basePt1x,basePt1y)

    Ax = basePt0.x

    Ay = basePt0.y

    Bx = basePt1.x

    By = basePt1.y

    px = referPt.x

    py = referPt.y

    #print('Ax,Ay,Bx,By,px,py',Ax,Ay,Bx,By,px,py)

    vAB_x = Bx - Ax

    vAB_y = By - Ay

    Ldist = math.sqrt(vAB_x ** 2 + vAB_y ** 2)

    #print('Ldist',Ldist)

    if Ldist >= 0.000001:

        uAB_x = vAB_x / Ldist   #'單位向量 uabx分量

        uAB_y = vAB_y / Ldist   #'單位向量 uaby分量

        #print('uAB_x,uAB_y',uAB_x,uAB_y)

        vPA_x = px - Ax

        #print('vPA_x',vPA_x)

        vPA_y = py - Ay

        #print('vPA_y',vPA_y)

        t = uAB_x * vPA_x + uAB_y * vPA_y

        ptvertX = Ax + t * uAB_x

        ptvertY = Ay + t * uAB_y

        ptvert=Ptxy(ptvertX,ptvertY)

        l1=math.sqrt((Ax-ptvertX)**2+(Ay-ptvertY)**2)

        l2=math.sqrt((Bx-ptvertX)**2+(By-ptvertY)**2)

        lt=math.sqrt((Ax-Bx)**2+(Ay-By)**2)

        if abs(lt-l1-l2)<=0.001:

            lvert=math.sqrt((referPt.x-ptvertX)**2+(referPt.y-ptvertY)**2)

            Xreflect=2*ptvertX-px

            Yreflect=2*ptvertY-py

            ptreflect=Ptxy(Xreflect,Yreflect)

            return ptreflect

         

def circleDraw(ptcen,ptonArc,npt=36,angbeg=0,angend=360):

    canvas.create_line(ptonArc.x,ptonArc.y,ptcen.x,ptcen.y)

    rad=ptptDist(ptonArc,ptcen)

    xpts=[]

    ypts=[]

    angdel=(angend-angbeg)/npt

    angdel=math.radians(angdel)

    for i in range(npt):

        xtpt=ptcen.x+rad*math.cos(angdel*i)

        ytpt=ptcen.y+rad*math.sin(angdel*i)

        xpts.append(xtpt)

        ypts.append(ytpt)

    if abs(360.0-angend-angbeg)<=0.01 :

        xpts.append(xpts[0])

        ypts.append(ypts[0])

    lines=[]

    print(len(xpts))

    for i in range(len(xpts)-1):

        lines += [(xpts[i],ypts[i],xpts[i+1],ypts[i+1])]

    canvas.create_line(lines,fill='red'

    return xpts,ypts

def from_rgb(rgbin):

    return ("#%02x%02x%02x" %  rgbin)

def CursorMove(event):

    x,y= event.x, event.y

    global glxystr

    glxystr=('x= ',x ,' y= ',y)

    lblxy.config(text=glxystr)

canvas.bind('<B1-Motion>',CursorMove) 

def CursorDown(event):

    x,y=event.x,event.y

    dc = windll.user32.GetDC(0) # get handler

    rgb = windll.gdi32.GetPixel(dc,event.x_root,event.y_root)

    print('x,y,event.x_root,event.y_root',x,y,event.x_root,event.y_root)

   

    r = rgb & 0xff

    g = (rgb >> 8) & 0xff

    b = (rgb >> 16) & 0xff

    print (r,g,b)

    pti=Ptxy(event.x_root,event.y_root)

    colr=get_pixel_colour(pti)

    print('colr in mousedown',colr)

    return r,g,b

canvas.bind('<Button-1>', CursorDown)    

#canvas.bind('<B1-Motion>',CursorMove)  

def main():

    ptb0=Ptxy(4,6)

    ptb1=Ptxy(7,9)

    pttest=Ptxy(3,3)

    print('ptb0.x,ptb0.y',ptb0.x,ptb0.y)

    print('ptb1.x,ptb1.y',ptb1.x,ptb1.y)

    bolans=IspointInCircle(pttest,ptb0,ptb1,5)

    print('bolans',bolans)

    pt0=Ptxy(4,6)#ptb0 # copy ptb0 to pt0

    pt1=Ptxy(7,9)#ptb1

    linet=line(pt0,pt1)

    ldist=linelen(linet) #呼叫引用class line中之linelen()

    """

    #??????????????????????????????????/'

    ldist=ptptlen(pt0,pt1)  #NameError: name 'ptptlen' is not defined

    #?????????????????????????????????????????

    """

    print('ldist=',ldist)

    pt0Base=Ptxy(50,50)

    ptmove=ptMoveto(pt0Base,50,50)

    canvas.create_oval(ptmove.x-9,ptmove.y-9,ptmove.x+9,ptmove.y+9,fill='gold')

   

    ptorg,ptcopy=ptCopyto(pt0Base,150,148)

    canvas.create_oval(ptcopy.x-10,ptcopy.y-10,ptcopy.x+10,ptcopy.y+10,fill='red')

    pt1Base=Ptxy(450,450)

    ptPivot=Ptxy(300,400)

    angrot=45

    ptBerot=Ptxy(100,150)

    ptOrg=ptBerot

    canvas.create_line(pt0Base.x,pt0Base.y,pt1Base.x,pt1Base.y,fill='blue',width=3)

    col=get_pixel_color(49,46)

    print('col 49,46',col)

    colw=get_pixel_colorw(49,46)

    print('col 49,46w',colw)

    print('get_pixel_color(0,0)',get_pixel_color(0,0))

    canvas.create_oval(pt0Base.x-5,pt0Base.y-5,pt0Base.x+5,pt0Base.y+5,fill='blue')

    canvas.create_rectangle(ptPivot.x-5,ptPivot.y-5,ptPivot.x+5,ptPivot.y+5,fill='red',activefill='green')

    canvas.create_text(ptPivot.x+5,ptPivot.y+5,text='pivot')

    canvas.create_oval(ptOrg.x-5,ptOrg.y-5,ptOrg.x+5,ptOrg.y+5,fill='gold')

    canvas.create_oval(ptBerot.x-5,ptBerot.y-5,ptBerot.x+5,ptBerot.y+5,fill='cyan')

    canvas.create_text(ptBerot.x+5,ptBerot.y+5,text='ptbeRot& ptbeRefct')

    ptrot=RotatePoint(ptBerot,ptPivot,angrot)

    canvas.create_rectangle(ptrot.x-5,ptrot.y-5,ptrot.x+5,ptrot.y+5,fill='green',activefill='red')

    canvas.create_text(ptrot.x+5,ptrot.y+5,text='ptaftRot')

    ptreflct= ReflctPoint(ptOrg,pt0Base,pt1Base)

    canvas.create_rectangle(ptreflct.x-5,ptreflct.y-5,ptreflct.x+5,ptreflct.y+5)

    canvas.create_text(ptreflct.x+5,ptreflct.y+5,text='ptaftRefl')

    canvas.create_line(ptOrg.x,ptOrg.y,ptreflct.x,ptreflct.y,fill='gold',width=3)

    ptcen=ptPivot

    xpts=[]

    ypts=[]

    xpts,ypts=circleDraw(ptcen,ptBerot)

    pti=Ptxy(400,300)

    rgbin=(250,0,0)

    id=set_pixel_color(pti,rgbin)

    print('id=',id)

   

    pts=[]

    pts.append(pt0Base)

    pts.append(pt1Base)

    ldist= ptsLen(pts)

    print('lpts= ',ldist)

   

if __name__ == '__main__':

    main()

 

canvas.mainloop()



Output:

1

2

3

4

  Line 63

    print(get_pixel_color(0,0))

                              ^

IndentationError: unindent does not match any outer indentation level

 

 

 

 

Name(您的大名)
E_MAIL(您的電子信箱)
Comment or Suggestion(您想反應的狀況,建議,或諮詢事項)
首頁


 

 

 

 

首頁 | python_user_defined_stipple_pattern | python_user_defined_ellipse_calss(2) | python_point_line_calss | python_user_defined_splines | python_user_defined_function_Ellipse | lon_lattoxy

上次修改此網站的日期: 2019年03月23日