0 ベクタパス作成ツール 1

とりあえず出来た( ´∀`)

  • ベクタパス作成ツール
  • 前に作ったベジェ操作ウィジェットの発展型で、割とうまく出来た
    ポイント追加と端点操作が自由に出来てデータの保存・読込も出来る
import sys , os , pickle
from PyQt5.QtWidgets import QApplication, QWidget,QMessageBox,QMenu,QAction
from PyQt5.QtCore import QPointF ,QRectF ,Qt
from PyQt5.QtGui import QPainterPath ,QPainter ,QPen,QCursor

class makepath(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('hogetta')
        self.setGeometry( 500, 50 , 500 , 500 )
        self.setMouseTracking (True)  
        self.plist=[]
        self.plist.append( QPointF(10,250) )  # start point
        self.plist.append( QPointF(100,100) )  #
        self.plist.append( QPointF(300,200) )  #
        self.plist.append( QPointF(490,250) )  #
        self.a = QPointF(4,4) # Tolerance in detecting point
        self.pselected = -1             # selected point
        self.pmove = 0                  # move flag
        self.drawp=0                    # selected start point
        self.isclosed=0                 # closed flag

        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect( self.custommenu )

        self.show()

    def custommenu(self):
        menu=QMenu(self)
        action = QAction('Add Point', self)
        action.triggered.connect(self.addpoint)
        menu.addAction(action)

        action = QAction('Close Path', self)
        action.triggered.connect(self.closepath)
        menu.addAction(action)
        action = QAction('Open Path', self)
        action.triggered.connect(self.openpath)
        menu.addAction(action)

        action = QAction('Save Path', self)
        action.triggered.connect(self.topickle)
        menu.addAction(action)
        action = QAction('Load Path', self)
        action.triggered.connect(self.frompickle)
        menu.addAction(action)

        menu.exec_(QCursor.pos ())   

    def addpoint(self): # ctrl + click
        e=self.mapFromGlobal( QCursor.pos() )
        p = QPointF( (e.x() - self.plist[-1].x())/3 , (e.y() - self.plist[-1].y())/3 )
        self.plist.append( self.plist[-1] + p ) 
        self.plist.append( self.plist[-1] + p ) 
        self.plist.append( self.plist[-1] + p )  # new start point
        self.update()

    def closepath(self):
        self.plist[-1] = self.plist[0]
        self.isclosed=1      # set close flag
        self.update()
    def openpath(self):
        self.isclosed=0      # set close flag

    def topickle(self):
        fname=os.path.join(os.path.dirname(__file__) , 'hoge')
        with open( fname, 'wb') as f :
            pickle.dump( self.plist ,f)
    def frompickle(self):
        fname=os.path.join(os.path.dirname(__file__) , 'hoge')
        with open( fname, 'rb') as f :
            self.plist=pickle.load( f)
        self.update()

    def mouseMoveEvent(self ,e):
        if self.pmove :  # Dorag ing
            if self.isclosed and self.pselected==0 :
                self.plist[-1]=e.pos()
            if e. modifiers().__eq__(Qt.ShiftModifier): # shift
                if self.drawp > self.pselected :
                    self.plist[self.drawp+1]=self.plist[self.drawp]+(self.plist[self.drawp]-self.plist[self.pselected])
                elif self.drawp < self.pselected :
                    self.plist[self.drawp-1]=self.plist[self.drawp]+(self.plist[self.drawp]-self.plist[self.pselected])
                else:
                    self.plist[self.drawp+1] += ( e.pos() - self.plist[self.pselected])
                    self.plist[self.drawp-1] += ( e.pos() - self.plist[self.pselected])
            self.plist[self.pselected] = e.pos()
            self.update()
        else:            # non Dorag ing
            self.pselected = -1
            rc = QRectF ( e.pos() - self.a , e.pos() + self.a )
            for i,l in enumerate( self.plist) :
                if rc.contains( l ) :
                    self.pselected = i
                    self.drawp = int( (i+1) / 3 )*3  # selected start point
                    self.update()
                    self.setWindowTitle('dawp {} selected {}'.format(self.drawp,self.pselected))
                    break

    def mousePressEvent(self ,e):
        if e. modifiers().__eq__(Qt.ControlModifier): # ctrl 
            self.addpoint()
        elif self.pselected != -1 :
            self.pmove = True

    def mouseReleaseEvent(self ,e):
        self.pmove = False
        self.pselected = -1

    def paintEvent (self,e):
        # 与えられたパラメータでパスを作成した後でパスをドローする→ mousemove に移したい
        path = QPainterPath( self.plist[0] )
        for i in range (1, len(self.plist) ,3):
            path.cubicTo( self.plist[i] , self.plist[i+1] , self.plist[i+2] )

        painter= QPainter()
        painter.begin(self) 

        painter.setPen( QPen( Qt.black , 2, style=Qt.SolidLine ) )
        painter.drawPath(path)
        for i in range( 0 , len(self.plist)-3 , 3 ) :             # draw all start point
            painter.drawRect( QRectF(QPointF(self.plist[i]-self.a) , 
                QPointF(self.plist[i] + self.a) ))

        painter.setPen( QPen( Qt.red , 2, style=Qt.DotLine ) )
        painter.drawRect( QRectF(QPointF(self.plist[self.drawp]-self.a) , 
            QPointF(self.plist[self.drawp] + self.a) ))

        if self.drawp==0:
            painter.drawLine( self.plist[self.drawp] , self.plist[self.drawp+1] ) 
            painter.drawRect( QRectF(QPointF(self.plist[self.drawp+1]-self.a) , 
                QPointF(self.plist[self.drawp+1] + self.a) ))
            painter.drawLine( self.plist[-1] , self.plist[-2] )
            painter.drawRect( QRectF(QPointF(self.plist[self.drawp-2]-self.a) , 
                QPointF(self.plist[self.drawp-2] + self.a) ))
        elif self.drawp== len(self.plist)-1 :
            painter.drawLine( self.plist[self.drawp] , self.plist[self.drawp-1] )   #  sub
            painter.drawRect( QRectF(QPointF(self.plist[self.drawp-1]-self.a) , 
                QPointF(self.plist[self.drawp-1] + self.a) ))
        else :
            painter.drawLine( self.plist[self.drawp] , self.plist[self.drawp-1] )  
            painter.drawLine( self.plist[self.drawp] , self.plist[self.drawp+1] )  
            painter.drawRect( QRectF(QPointF(self.plist[self.drawp+1]-self.a) , 
                QPointF(self.plist[self.drawp+1] + self.a) ))
            painter.drawRect( QRectF(QPointF(self.plist[self.drawp-1]-self.a) , 
                QPointF(self.plist[self.drawp-1] + self.a) ))

        if self.pselected != -1 :
            painter.setPen( QPen( Qt.blue , 2, style=Qt.DotLine ) )
            painter.drawRect( QRectF(QPointF(self.plist[self.pselected]-self.a) , 
                QPointF(self.plist[self.pselected] + self.a) ))

        painter.end() 

if __name__ == "__main__":
    app = QApplication(sys.argv)
    ex = makepath()
    sys.exit(app.exec_())
  • パスは全てcubu、ベジェに統一した
  • コントロールポイントはシフトキーでシンメトリに動く。基点はシフトキーで二つのコントロールポイントと平行に動く
    ただし始点と終点の動作はすっきりしてない
    この部分は今後の仕様も含めてしっかり考えた方が良いのかもしれない
  • 描画ルーチンがゴテゴテしてる、分岐が多すぎ、もっとすっきりさせたい
  • picklesのデータ保存は凄く簡単だったが、データに名前はつけれないんだろうか?
  • パスの派生クラスを作れば複数パスを並列して処理できそうだが??
  • 現在のポイント追加は常に終点に加える形だが、途中に追加できるようにしたい
    ベジェの演算が必要になるんだろうか???

--> PyQt でベクターオブジェクト作成ツールを作る # もくじ

0

メモを他の人に見せる

このメモを見せたい人に、このURL(今開いているページのURLです)を教えてあげてください

コメント(0)

  • someone

  • someone