diff --git a/main.py b/main.py index b780f44..d34b69f 100644 --- a/main.py +++ b/main.py @@ -55,7 +55,7 @@ class Cross_painter(Widget): self.selected.selected=False # find cross under touch - self.selected=self.find_cross((touch.x,touch.y)) + self.selected=self.find_cross(Point(touch.x,touch.y)) # select if self.selected!=None: self.selected.selected=True @@ -65,8 +65,7 @@ class Cross_painter(Widget): def on_touch_move(self,touch): # only move on left click if touch.button=="left" and self.selected!=None: - #self.selected.pos=self.check_move((touch.x,touch.y),self.selected) - self.selected.setpos(touch.x,touch.y) + self.selected.pos=self.check_move(Point(touch.x,touch.y),self.selected) # redraw self.canvas.clear() self.draw() @@ -85,7 +84,9 @@ class Cross_painter(Widget): for other in self.crosses: # do not compare a cross to itself if other!=cross: - return newpos + if other.check_interaction(newpos)==False: + # stick to the cross + return other.move_on_line_to_stick(cross.pos,newpos-cross.pos) return newpos # check that a cross can be added at position @@ -105,6 +106,11 @@ class Cross(): self.color=kwargs.get("color",(0,0,1)) self.selected=False + # set position + def setpos(self,x,y): + self.pos.x=x + self.pos.y=y + def draw(self): # fill #if not self.selected: @@ -137,8 +143,50 @@ class Cross(): def check_interaction(self,pos): return ((pos-self.pos)/self.size).int()**2>=5 - # find position along a line that comes in contact with the line - #def move_on_line_to_stick(self,x,v): + # find position along a line that comes in contact with the line going through pos in direction v + def move_on_line_to_stick(self,pos,v): + # relative to cross + return self.move_on_line_to_stick_relative((pos-self.pos)/self.size,v/self.size)*self.size+self.pos + def move_on_line_to_stick_relative(self,x,v): + + # if x is in the right quadrant + if abs(x.y)<=x.x: + # find all stuck positions on lines + stuck=[] + + # check intersections with vertical lines + if v.x!=0: + for i in range(1,4): + # candidate + y=Point(i,x.y+(i-x.x)*v.y/v.x) + # check that it is in the right range + if abs(y.y)<=4-i and abs(y.y)>=3-i: + stuck.append(y) + # check intersections with horizontal lines + if v.y!=0: + for i in [-3,-2,-1,1,2,3]: + # candidate + y=Point(x.x+(i-x.y)*v.x/v.y,i) + # check that it is in the right range + if y.x<=4-abs(i) and y.x>=3-abs(i): + stuck.append(y) + + return x.closest(stuck) + + # reflect other quadrants to the right one + # top quadrant + elif abs(x.x)<=x.y: + closest=self.move_on_line_to_stick_relative(Point(x.y,x.x),Point(v.y,v.x)) + return Point(closest.y,closest.x) + # bottom quadrant + elif abs(x.x)<=-x.y: + closest=self.move_on_line_to_stick_relative(Point(-x.y,x.x),Point(-v.y,v.x)) + return Point(closest.y,-closest.x) + # left quadrant + else: + closest=self.move_on_line_to_stick_relative(Point(-x.x,x.y),Point(-v.x,v.y)) + return Point(-closest.x,closest.y) + class Point: def __init__(self,x,y): @@ -172,10 +220,15 @@ class Point: def int(self): return Point(int(self.x),int(self.y)) - # set position - def setpos(self,x,y): - self.x=x - self.y=y + # find the closest among a list of points + def closest(self,points): + dist=math.inf + closest=None + for point in points: + if (self-point)**2