animate Kivy Bezier curve with custom width ? (a bit silly question)

Question:

update: After discussing with others, I decided that it is a bit silly question. I wanted to animate Bezier curve with changed width, but it has no width property. with Line Bezier, I can change width, but then can’t animate.


I can’t change witdh of Bezier curve like Line.
here is the code:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import *

class MyLayout(Widget):
    def __init__(self):
        super(MyLayout, self).__init__()
        with self.canvas:
            self.L=Bezier(points=[200,450,500,300,600,150],width=12)
            self.k=Line  (bezier=[100,350,400,200,500,50 ],width=12)

class MyApp(App):
    def __init__(self):
        super(MyApp, self).__init__()
    def build(self):
        return MyLayout()

if __name__=="__main__":
    MyApp().run()

and outupt:
MyApp

the problem is,

the upper curve isn’t width=12.

I think that’s because Kivy’s Bezier Class has no attribute width cuz when I do it on kv lang, it gives me AttributeError: 'kivy.graphics.vertex_instructions.Bezier' object has no attribute 'width'. Well, why not using Line with bezier ? I want to use Animation on it and when I try to on Line with bezier, I get AttributeError: attribute 'bezier' of 'kivy.graphics.vertex_instructions.Line' objects is not readable.

so the question,

how can I change width of Bezier. if it is not possible, is there any way like finding the y of cruve (or ys) for given x so I can put Ellipse on these points and resize them to simulate width ?

thanks and pardon my english

Asked By: FLAW

||

Answers:

The Bezier has no width property, but the Line does. So you can animate that width. An easy way to do that is by animating a NumericProperty that holds the width. Here is a modified version of your code that does that:

from kivy.animation import Animation
from kivy.app import App
from kivy.clock import Clock
from kivy.properties import NumericProperty
from kivy.uix.widget import Widget
from kivy.graphics import *

class MyLayout(Widget):
    line_width = NumericProperty(12)
    def __init__(self):
        super(MyLayout, self).__init__()
        with self.canvas:
            self.L=Bezier(points=[200,450,500,300,600,150],width=self.line_width)
            self.k=Line  (bezier=[100,350,400,200,500,50 ],width=self.line_width)

    def on_line_width(self, instance, new_width):
        self.k.width = new_width

class MyApp(App):

    def build(self):
        Clock.schedule_once(self.anim)
        return MyLayout()

    def anim(self, dt):
        a = Animation(line_width=3)
        a.start(self.root)

if __name__=="__main__":
    MyApp().run()

If you build the Line in kv, then you don’t even need the on_line_width() method since kivy will do the binding for you.

Answered By: John Anderson

The line can use bezier:, example:

Line:
    bezier:[n1,n2,n3,n4]
    width:3

This is a Line, not a Bezier, but you get the same result…

One example:

from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.boxlayout import BoxLayout

posicao=[]
class Draw(BoxLayout):
    def __init__(self, **kwargs):
        super(Draw, self).__init__(**kwargs)
    
    def on_touch_down(self,touch):
        posicao.append(touch.pos)
        
    def on_touch_up(self,touch):
        posicao.clear()
        
    def on_touch_move(self,touch):
        Line = Builder.load_string(
"""
FloatLayout:
    canvas:
        Color:
            rgba:11,.1,1,1
        Line:
            points: {pos}
            width:14
""".format(pos=(touch.pos, posicao[0])))
        self.add_widget(Line)
        posicao.clear()
        posicao.append(touch.pos)
        
class Code(App):
    def build(self):
        return Draw()
        
if __name__ == '__main__':
    Code().run()

Or:

from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.graphics import *

posi = []

Builder.load_string(
"""
<Draw>:
    
""")
class Draw(BoxLayout):
    def __init__(self, **kwargs):
        super(Draw, self).__init__(**kwargs)
    
    def on_touch_down(self,touch):
        posi.clear()
        posi.append(touch.pos)
        
    def on_touch_up(self,touch):
        posi.clear()
        
    def on_touch_move(self,touch):
        with self.canvas:
            Line(points=[posi[0], touch.pos],width=14)
        posi.clear()
        posi.append(touch.pos)
            
class Code(App):
    def build(self):
        return Draw()
        
if __name__ == '__main__':
    Code().run()
Answered By: Heitor Tasso
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.