Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Draw line between 2 points using scene shapenode and ui.Path()
-
Hello, this is my first post here - I’m new to Python and Pythonista. As I learn I’ve hit a strange issue with drawing paths I cannot work out.
I’ve been trying to draw a line between 2 points - a fixed point at the centre of the screen and a touched point on the screen - and whilst I can get nodes drawing on screen OK, the line itself is not in the right position. I’ve posted my code below to help replicate the issue.
It’s not in my code below, but I’ve also tried numerous workarounds such as rotating the node, changing anchor points dynamically and calculating the vector between the points, all of which would work in Swift SpriteKit (which I have years of experience with) but don’t seem to work here - the nodes just end up in seemingly random positions with no pattern I can discern.
Any pointers in the right direction would be very much appreciated - many thanks.
import ui from scene import * class MyScene (Scene): def setup(self): self.background_color = '#00006b' self.centre = Point(self.size.w/2, self.size.h/2) def update(self): pass def touch_began(self, touch): # Place dots in scene to test touch and centre points are correct dotA = Dot(location = self.centre) self.add_child(dotA) dotB = Dot(location = touch.location) self.add_child(dotB) # The issue: line is right length but never right position or angle # Draw line between the touched point and centre of the screen path = ui.Path() path.line_width = 4.0 path.move_to(self.centre.x, self.centre.y) path.line_to(touch.location.x, touch.location.y) line = ShapeNode() line.path = path line.position = (self.centre.x, self.centre.y) line.anchor_point = (0, 0) line.stroke_color = 'white' self.add_child(line) class Dot(ShapeNode): def __init__(self, *, location, **kwargs): circle = ui.Path.oval(0,0,20,20) super().__init__(circle, fill_color='white', **kwargs) self.position = (location.x, location.y) run(MyScene())
-
@inaccessiblerail in ui, y=0 at top but in scene, y=0 at bottom
the little modification here works for touchs at up-right of center, use it as first step to solve all 😀path.line_to(touch.location.x, ui.get_screen_size()[1] - touch.location.y)
-
@cvp Thanks, that’s a very helpful tip on the ui vs scene coordinates. I’ve worked out your screenshot for up right touches - I’ll work on the other parts of the screen now. Thanks for your help!
-
@inaccessiblerail I'm really sorry that I'm not able to help you better but I never use Scene.
I've remarked that if you touch at right,bottom of the center, the line starts from the correct x but with y = 0. I suppose that anchor_point or position is the reason but I can't help.
There are some guys in this forum who could help you but this is an holiday period 😢 -
This works
path.move_to(-dx,dy) path.line_to(-dx,dy) path.move_to(0,0) path.line_to(dx,-dy) line = ShapeNode() line.path = path line.position = (self.centre.x, self.centre.y) #line.anchor_point = (0, 0) # default = 0.5,0.5 line.stroke_color = 'white' self.add_child(line)
-
@cvp - that’s a tremendous help, many thanks.
For anyone who might want help with ui and scene path drawing when searching in the future, here’s the complete working code (when using the ‘new’ render loop not the classic render loop):
import ui from scene import * class MyScene (Scene): def setup(self): self.background_color = '#00006b' self.centre = Point(self.size.w/2, self.size.h/2) def update(self): pass def touch_began(self, touch): # Calculate vector between centre point and touched point dx = touch.location.x - self.centre.x dy = touch.location.y - self.centre.y # Draw path from centre point to touched point path = ui.Path() path.line_width = 4.0 path.move_to(-dx,dy) path.line_to(-dx,dy) path.move_to(0,0) path.line_to(dx,-dy) # Create line node from path line = ShapeNode() line.path = path line.position = (self.centre.x, self.centre.y) line.stroke_color = 'white' self.add_child(line) # Place dots at centre and touch points dotA = Dot(location = self.centre) self.add_child(dotA) dotB = Dot(location = touch.location) self.add_child(dotB) class Dot(ShapeNode): def __init__(self, *, location, **kwargs): circle = ui.Path.oval(0,0,20,20) super().__init__(circle, fill_color='white', **kwargs) self.position = (location.x, location.y) run(MyScene())