diff --git a/cross.py b/cross.py index 8f5518a..2d7e397 100644 --- a/cross.py +++ b/cross.py @@ -1,8 +1,10 @@ import math +import sys from kivy.graphics import Color,Line,Rectangle from kivy.uix.widget import Widget from point import Point +from tools import isint_nonzero,sgn class Cross(): # size of central square @@ -12,6 +14,7 @@ class Cross(): self.pos=Point(x,y) self.color=kwargs.get("color",(0,0,1)) self.selected=False + self.stuckto=None # set position def setpos(self,x,y): @@ -89,6 +92,87 @@ class Cross(): closest=self.move_on_line_to_stick_relative(Point(-x.x,x.y),Point(-v.x,v.y)) return Point(-closest.x,closest.y) + # move along edge of cross while remaining stuck + def move_along(self,newpos,pos): + rel=pos-self.pos + # check if the particle is stuck in the x direction + if isint_nonzero(rel.x): + # check y direction + if isint_nonzero(rel.y): + # in corner + # two types of corners: |x|_1=3 or |x|_1=4 + if abs(rel.x)+abs(rel.y)<3.5: + if sgn(newpos.y-pos.y)==sgn(rel.y): + # stuck in x direction + return self.move_stuck_x(newpos,pos) + elif sgn(newpos.x-pos.x)==sgn(rel.x): + # stuck in y direction + return self.move_stuck_y(newpos,pos) + else: + if sgn(newpos.y-pos.y)==-sgn(rel.y): + # stuck in x direction + return self.move_stuck_x(newpos,pos) + elif sgn(newpos.x-pos.x)==-sgn(rel.x): + # stuck in y direction + return self.move_stuck_y(newpos,pos) + # stuck in both directions + return pos + else: + # stuck in x direction + return self.move_stuck_x(newpos,pos) + elif isint_nonzero(rel.y): + # stuck in y direction + return self.move_stuck_y(newpos,pos) + # this should never happen + else: + print("error: stuck particle has non-integer relative position: (",rel.x,",",rel.y,")",file=sys.stderr) + exit(-1) + # move when stuck in the x direction + def move_stuck_x(self,newpos,pos): + # only move in y direction + candidate=Point(pos.x,newpos.y) + # do not move past corners + rel=pos.y-self.pos.y + newrel=newpos.y-self.pos.y + if newpos.y>pos.y: + if self.check_interaction(candidate)==False or (relmath.ceil(rel)+1e-11 and math.ceil(rel)!=0): + # in open corner + if rel>math.ceil(rel)-1e-11: + candidate.y=math.ceil(rel)+1+self.pos.y + else: + candidate.y=math.ceil(rel)+self.pos.y + else: + if self.check_interaction(candidate)==False or (rel>math.floor(rel)+1e-11 and newrelpos.x: + if self.check_interaction(candidate)==False or (relmath.ceil(rel)+1e-11 and math.ceil(rel)!=0): + # in open corner + if rel>math.ceil(rel)-1e-11: + candidate.x=math.ceil(rel)+1+self.pos.x + else: + candidate.x=math.ceil(rel)+self.pos.x + else: + if self.check_interaction(candidate)==False or (rel>math.floor(rel)+1e-11 and newrel=0: return 1 return -1 + +# check whether a number is an integer (with tolerance) +def isint_nonzero(x): + if abs(x)<1e-11: + return False + return abs(round(x)-x)<1e-11