move along cross
This commit is contained in:
		
							
								
								
									
										92
									
								
								cross.py
									
									
									
									
									
								
							
							
						
						
									
										92
									
								
								cross.py
									
									
									
									
									
								
							| @@ -1,8 +1,10 @@ | |||||||
| import math | import math | ||||||
|  | import sys | ||||||
| from kivy.graphics import Color,Line,Rectangle | from kivy.graphics import Color,Line,Rectangle | ||||||
| from kivy.uix.widget import Widget | from kivy.uix.widget import Widget | ||||||
|  |  | ||||||
| from point import Point | from point import Point | ||||||
|  | from tools import isint_nonzero,sgn | ||||||
|  |  | ||||||
| class Cross(): | class Cross(): | ||||||
|     # size of central square |     # size of central square | ||||||
| @@ -12,6 +14,7 @@ class Cross(): | |||||||
|         self.pos=Point(x,y) |         self.pos=Point(x,y) | ||||||
|         self.color=kwargs.get("color",(0,0,1)) |         self.color=kwargs.get("color",(0,0,1)) | ||||||
|         self.selected=False |         self.selected=False | ||||||
|  |         self.stuckto=None | ||||||
|  |  | ||||||
|     # set position |     # set position | ||||||
|     def setpos(self,x,y): |     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)) |             closest=self.move_on_line_to_stick_relative(Point(-x.x,x.y),Point(-v.x,v.y)) | ||||||
|             return Point(-closest.x,closest.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 | # L_infinity distance rescalled by 3 in the x direction | ||||||
| def cross_distx(x,y): | def cross_distx(x,y): | ||||||
| @@ -181,8 +265,16 @@ class Cross_painter(Widget): | |||||||
|             if other!=cross: |             if other!=cross: | ||||||
|                 # move would make cross overlap with other |                 # move would make cross overlap with other | ||||||
|                 if other.check_interaction(newpos)==False: |                 if other.check_interaction(newpos)==False: | ||||||
|  |                     # 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 |                         # stick to the cross | ||||||
|  |                         cross.stuckto=other | ||||||
|                         return other.move_on_line_to_stick(cross.pos,newpos-cross.pos) |                         return other.move_on_line_to_stick(cross.pos,newpos-cross.pos) | ||||||
|  |         # reset stuckto if move is allowed | ||||||
|  |         cross.stuckto=None | ||||||
|         return newpos |         return newpos | ||||||
|  |  | ||||||
|     # check that a cross can be added at position |     # check that a cross can be added at position | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user