move along cross
This commit is contained in:
parent
6851e1ab32
commit
a5caeec29a
96
cross.py
96
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 (rel<math.ceil(rel)-1e-11 and newrel>math.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 newrel<math.floor(rel)-1e-11 and math.floor(rel)!=0):
|
||||
# in open corner
|
||||
if rel<math.floor(rel)+1e-11:
|
||||
candidate.y=math.floor(rel)-1+self.pos.y
|
||||
else:
|
||||
candidate.y=math.floor(rel)+self.pos.y
|
||||
return candidate
|
||||
# move when stuck in the y direction
|
||||
def move_stuck_y(self,newpos,pos):
|
||||
# only move in x direction
|
||||
candidate=Point(newpos.x,pos.y)
|
||||
# do not move past corners
|
||||
rel=pos.x-self.pos.x
|
||||
newrel=newpos.x-self.pos.x
|
||||
if newpos.x>pos.x:
|
||||
if self.check_interaction(candidate)==False or (rel<math.ceil(rel)-1e-11 and newrel>math.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<math.floor(rel)-1e-11 and math.floor(rel)!=0):
|
||||
# in open corner
|
||||
if rel<math.floor(rel)+1e-11:
|
||||
candidate.x=math.floor(rel)-1+self.pos.x
|
||||
else:
|
||||
candidate.x=math.floor(rel)+self.pos.x
|
||||
return candidate
|
||||
|
||||
|
||||
|
||||
# L_infinity distance rescalled by 3 in the x direction
|
||||
def cross_distx(x,y):
|
||||
@ -181,8 +265,16 @@ class Cross_painter(Widget):
|
||||
if other!=cross:
|
||||
# move would make cross overlap with other
|
||||
if other.check_interaction(newpos)==False:
|
||||
# stick to the cross
|
||||
return other.move_on_line_to_stick(cross.pos,newpos-cross.pos)
|
||||
# check if cross is stuck to other
|
||||
if cross.stuckto==other:
|
||||
# move along other while remaining stuck
|
||||
return other.move_along(newpos,cross.pos)
|
||||
else:
|
||||
# stick to the cross
|
||||
cross.stuckto=other
|
||||
return other.move_on_line_to_stick(cross.pos,newpos-cross.pos)
|
||||
# reset stuckto if move is allowed
|
||||
cross.stuckto=None
|
||||
return newpos
|
||||
|
||||
# check that a cross can be added at position
|
||||
|
Loading…
Reference in New Issue
Block a user