Implement interaction between squares of different sizes
This commit is contained in:
parent
b9be36b4e0
commit
5835c9003c
@ -348,8 +348,14 @@ class Painter(Widget):
|
|||||||
def check_interaction_unselected_element(self,element,offset):
|
def check_interaction_unselected_element(self,element,offset):
|
||||||
for particle in self.unselected:
|
for particle in self.unselected:
|
||||||
for square in particle.squares:
|
for square in particle.squares:
|
||||||
if square.check_interaction(element.pos+offset):
|
# add offset
|
||||||
|
element.pos+=offset
|
||||||
|
if square.check_interaction(element):
|
||||||
|
# reset offset
|
||||||
|
element.pos-=offset
|
||||||
return True
|
return True
|
||||||
|
# reset offset
|
||||||
|
element.pos-=offset
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@ -387,16 +393,21 @@ class Painter(Widget):
|
|||||||
for other in self.unselected:
|
for other in self.unselected:
|
||||||
for obstacle in other.squares:
|
for obstacle in other.squares:
|
||||||
# move would make element overlap with obstacle
|
# move would make element overlap with obstacle
|
||||||
if obstacle.check_interaction(element.pos+delta):
|
element.pos+=delta
|
||||||
|
if obstacle.check_interaction(element):
|
||||||
|
element.pos-=delta
|
||||||
accept_newpos=False
|
accept_newpos=False
|
||||||
# check if particle already touches obstacle
|
# check if particle already touches obstacle
|
||||||
if obstacle.check_touch(element.pos):
|
if obstacle.check_touch(element):
|
||||||
# move along obstacle while remaining stuck
|
# move along obstacle while remaining stuck
|
||||||
newdelta=obstacle.move_along(delta,element.pos)
|
newdelta=obstacle.move_along(delta,element)
|
||||||
else:
|
else:
|
||||||
newdelta=obstacle.move_on_line_to_stick(element.pos,delta)
|
newdelta=obstacle.move_on_line_to_stick(element,delta)
|
||||||
if not self.check_interaction_unselected_element(element,newdelta):
|
if not self.check_interaction_unselected_element(element,newdelta):
|
||||||
return newdelta
|
return newdelta
|
||||||
|
else:
|
||||||
|
# reset offset
|
||||||
|
element.pos-=delta
|
||||||
if accept_newpos:
|
if accept_newpos:
|
||||||
return delta
|
return delta
|
||||||
else:
|
else:
|
||||||
|
@ -29,7 +29,7 @@ class Polyomino():
|
|||||||
Color(r/2,g/2,b/2,alpha)
|
Color(r/2,g/2,b/2,alpha)
|
||||||
|
|
||||||
for square in self.squares:
|
for square in self.squares:
|
||||||
Rectangle(pos=(painter.pos_tocoord_x(square.pos.x-0.5),painter.pos_tocoord_y(square.pos.y-0.5)),size=(square.size*painter.base_size,square.size*painter.base_size))
|
Rectangle(pos=(painter.pos_tocoord_x(square.pos.x-0.5*square.size),painter.pos_tocoord_y(square.pos.y-0.5*square.size)),size=(square.size*painter.base_size,square.size*painter.base_size))
|
||||||
|
|
||||||
# draw boundary
|
# draw boundary
|
||||||
self.stroke(painter)
|
self.stroke(painter)
|
||||||
@ -67,8 +67,14 @@ class Polyomino():
|
|||||||
def check_interaction(self,candidate,offset):
|
def check_interaction(self,candidate,offset):
|
||||||
for square1 in self.squares:
|
for square1 in self.squares:
|
||||||
for square2 in candidate.squares:
|
for square2 in candidate.squares:
|
||||||
if square1.check_interaction(square2.pos+offset):
|
# add offset
|
||||||
|
square2.pos+=offset
|
||||||
|
if square1.check_interaction(square2):
|
||||||
|
# reset offset
|
||||||
|
square2.pos-=offset
|
||||||
return True
|
return True
|
||||||
|
# reset offset
|
||||||
|
square2.pos-=offset
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# square
|
# square
|
||||||
@ -125,38 +131,39 @@ class Square_element():
|
|||||||
self.pos.y=y
|
self.pos.y=y
|
||||||
|
|
||||||
|
|
||||||
# check whether a square at pos interacts with square
|
# check whether an element interacts with square
|
||||||
def check_interaction(self,pos):
|
def check_interaction(self,element):
|
||||||
return l_infinity(pos-self.pos)<self.size
|
|
||||||
|
|
||||||
# check whether a square at position pos is touching self
|
|
||||||
def check_touch(self,pos):
|
|
||||||
# allow for error
|
# allow for error
|
||||||
if in_interval(l_infinity(pos-self.pos),self.size-1e-11,self.size+1e-11):
|
return l_infinity(element.pos-self.pos)<(self.size+element.size)/2-1e-11
|
||||||
|
|
||||||
|
# check whether an element is touching self
|
||||||
|
def check_touch(self,element):
|
||||||
|
# allow for error
|
||||||
|
if in_interval(l_infinity(element.pos-self.pos),(self.size+element.size)/2-1e-11,(self.size+element.size)/2+1e-11):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# find position along a line that comes in contact with the line going through pos in direction v
|
# find position along a line that comes in contact with the line going through element.pos in direction v
|
||||||
def move_on_line_to_stick(self,pos,v):
|
def move_on_line_to_stick(self,element,v):
|
||||||
# compute intersections with four lines making up square
|
# compute intersections with four lines making up square
|
||||||
if v.x!=0:
|
if v.x!=0:
|
||||||
if v.y!=0:
|
if v.y!=0:
|
||||||
intersections=[\
|
intersections=[\
|
||||||
Point(self.pos.x+self.size,pos.y+v.y/v.x*(self.pos.x+self.size-pos.x)),\
|
Point(self.pos.x+(self.size+element.size)/2,element.pos.y+v.y/v.x*(self.pos.x+(self.size+element.size)/2-element.pos.x)),\
|
||||||
Point(self.pos.x-self.size,pos.y+v.y/v.x*(self.pos.x-self.size-pos.x)),\
|
Point(self.pos.x-(self.size+element.size)/2,element.pos.y+v.y/v.x*(self.pos.x-(self.size+element.size)/2-element.pos.x)),\
|
||||||
Point(pos.x+v.x/v.y*(self.pos.y+self.size-pos.y),self.pos.y+self.size),\
|
Point(element.pos.x+v.x/v.y*(self.pos.y+(self.size+element.size)/2-element.pos.y),self.pos.y+(self.size+element.size)/2),\
|
||||||
Point(pos.x+v.x/v.y*(self.pos.y-self.size-pos.y),self.pos.y-self.size)\
|
Point(element.pos.x+v.x/v.y*(self.pos.y-(self.size+element.size)/2-element.pos.y),self.pos.y-(self.size+element.size)/2)\
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
intersections=[\
|
intersections=[\
|
||||||
Point(self.pos.x+self.size,pos.y+v.y/v.x*(self.pos.x+self.size-pos.x)),\
|
Point(self.pos.x+(self.size+element.size)/2,element.pos.y+v.y/v.x*(self.pos.x+(self.size+element.size)/2-element.pos.x)),\
|
||||||
Point(self.pos.x-self.size,pos.y+v.y/v.x*(self.pos.x-self.size-pos.x))
|
Point(self.pos.x-(self.size+element.size)/2,element.pos.y+v.y/v.x*(self.pos.x-(self.size+element.size)/2-element.pos.x))
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
if v.y!=0:
|
if v.y!=0:
|
||||||
intersections=[\
|
intersections=[\
|
||||||
Point(pos.x+v.x/v.y*(self.pos.y+self.size-pos.y),self.pos.y+self.size),\
|
Point(element.pos.x+v.x/v.y*(self.pos.y+(self.size+element.size)/2-element.pos.y),self.pos.y+(self.size+element.size)/2),\
|
||||||
Point(pos.x+v.x/v.y*(self.pos.y-self.size-pos.y),self.pos.y-self.size)\
|
Point(element.pos.x+v.x/v.y*(self.pos.y-(self.size+element.size)/2-element.pos.y),self.pos.y-(self.size+element.size)/2)\
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
print("error: move_on_line_to_stick called with v=0, please file a bug report with the developer",file=sys.stderr)
|
print("error: move_on_line_to_stick called with v=0, please file a bug report with the developer",file=sys.stderr)
|
||||||
@ -167,72 +174,72 @@ class Square_element():
|
|||||||
dist=math.inf
|
dist=math.inf
|
||||||
for i in range(0,len(intersections)):
|
for i in range(0,len(intersections)):
|
||||||
# check that it is on square
|
# check that it is on square
|
||||||
if abs(intersections[i].x-self.pos.x)<=self.size+1e-11 and abs(intersections[i].y-self.pos.y)<=self.size+1e-11:
|
if abs(intersections[i].x-self.pos.x)<=(self.size+element.size)/2+1e-11 and abs(intersections[i].y-self.pos.y)<=(self.size+element.size)/2+1e-11:
|
||||||
if (intersections[i]-pos)**2<dist:
|
if (intersections[i]-element.pos)**2<dist:
|
||||||
closest=intersections[i]
|
closest=intersections[i]
|
||||||
dist=(intersections[i]-pos)**2
|
dist=(intersections[i]-element.pos)**2
|
||||||
|
|
||||||
if closest==None:
|
if closest==None:
|
||||||
print("error: cannot move particle at (",pos.x,",",pos.y,") to the boundary of (",self.pos.x,",",self.pos.y,") in direction (",v.x,",",v.y,")",file=sys.stderr)
|
print("error: cannot move particle at (",pos.x,",",pos.y,") to the boundary of (",self.pos.x,",",self.pos.y,") in direction (",v.x,",",v.y,")",file=sys.stderr)
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
# return difference to pos
|
# return difference to pos
|
||||||
return closest-pos
|
return closest-element.pos
|
||||||
|
|
||||||
# move along edge of square
|
# move along edge of square
|
||||||
def move_along(self,delta,pos):
|
def move_along(self,delta,element):
|
||||||
rel=pos-self.pos
|
rel=element.pos-self.pos
|
||||||
# check if the particle is stuck in the x direction
|
# check if the particle is stuck in the x direction
|
||||||
if isint_nonzero(rel.x/self.size):
|
if isint_nonzero(rel.x/((self.size+element.size)/2)):
|
||||||
# check y direction
|
# check y direction
|
||||||
if isint_nonzero(rel.y/self.size):
|
if isint_nonzero(rel.y/((self.size+element.size)/2)):
|
||||||
# in corner
|
# in corner
|
||||||
if sgn(delta.y)==-sgn(rel.y):
|
if sgn(delta.y)==-sgn(rel.y):
|
||||||
# stuck in x direction
|
# stuck in x direction
|
||||||
return self.move_stuck_x(delta,pos)
|
return self.move_stuck_x(delta,element)
|
||||||
elif sgn(delta.x)==-sgn(rel.x):
|
elif sgn(delta.x)==-sgn(rel.x):
|
||||||
# stuck in y direction
|
# stuck in y direction
|
||||||
return self.move_stuck_y(delta,pos)
|
return self.move_stuck_y(delta,element)
|
||||||
# stuck in both directions
|
# stuck in both directions
|
||||||
return pos
|
return element.pos
|
||||||
else:
|
else:
|
||||||
# stuck in x direction
|
# stuck in x direction
|
||||||
return self.move_stuck_x(delta,pos)
|
return self.move_stuck_x(delta,element)
|
||||||
elif isint_nonzero(rel.y/self.size):
|
elif isint_nonzero(rel.y/((self.size+element.size)/2)):
|
||||||
# stuck in y direction
|
# stuck in y direction
|
||||||
return self.move_stuck_y(delta,pos)
|
return self.move_stuck_y(delta,element)
|
||||||
# this should never happen
|
# this should never happen
|
||||||
else:
|
else:
|
||||||
print("error: stuck particle has non-integer relative position: (",rel.x,",",rel.y,")",file=sys.stderr)
|
print("error: stuck particle has non-integer relative position: (",rel.x,",",rel.y,")",file=sys.stderr)
|
||||||
exit(-1)
|
exit(-1)
|
||||||
# move when stuck in the x direction
|
# move when stuck in the x direction
|
||||||
def move_stuck_x(self,delta,pos):
|
def move_stuck_x(self,delta,element):
|
||||||
# only move in y direction
|
# only move in y direction
|
||||||
candidate=Point(0,delta.y)
|
candidate=Point(0,delta.y)
|
||||||
# do not move past corners
|
# do not move past corners
|
||||||
rel=pos.y-self.pos.y
|
rel=element.pos.y-self.pos.y
|
||||||
if delta.y>0:
|
if delta.y>0:
|
||||||
if rel<math.ceil(rel/self.size)*self.size-1e-11 and delta.y+rel>math.ceil(rel/self.size)*self.size+1e-11 and math.ceil(rel/self.size)*self.size!=0:
|
if rel<math.ceil(rel/((self.size+element.size)/2))*((self.size+element.size)/2)-1e-11 and delta.y+rel>math.ceil(rel/((self.size+element.size)/2))*((self.size+element.size)/2)+1e-11 and math.ceil(rel/((self.size+element.size)/2))*((self.size+element.size)/2)!=0:
|
||||||
# stick to corner
|
# stick to corner
|
||||||
candidate.y=math.ceil(rel/self.size)*self.size+self.pos.y-pos.y
|
candidate.y=math.ceil(rel/((self.size+element.size)/2))*((self.size+element.size)/2)+self.pos.y-element.pos.y
|
||||||
else:
|
else:
|
||||||
if rel>math.floor(rel/self.size)*self.size+1e-11 and delta.y+rel<math.floor(rel/self.size)*self.size-1e-11 and math.floor(rel/self.size)*self.size!=0:
|
if rel>math.floor(rel/((self.size+element.size)/2))*((self.size+element.size)/2)+1e-11 and delta.y+rel<math.floor(rel/((self.size+element.size)/2))*((self.size+element.size)/2)-1e-11 and math.floor(rel/((self.size+element.size)/2))*((self.size+element.size)/2)!=0:
|
||||||
# stick to corner
|
# stick to corner
|
||||||
candidate.y=math.floor(rel)+self.pos.y-pos.y
|
candidate.y=math.floor(rel/((self.size+element.size)/2))*((self.size+element.size)/2)+self.pos.y-element.pos.y
|
||||||
return candidate
|
return candidate
|
||||||
# move when stuck in the y direction
|
# move when stuck in the y direction
|
||||||
def move_stuck_y(self,delta,pos):
|
def move_stuck_y(self,delta,element):
|
||||||
# onlx move in x direction
|
# onlx move in x direction
|
||||||
candidate=Point(delta.x,0)
|
candidate=Point(delta.x,0)
|
||||||
# do not move past corners
|
# do not move past corners
|
||||||
rel=pos.x-self.pos.x
|
rel=element.pos.x-self.pos.x
|
||||||
if delta.x>0:
|
if delta.x>0:
|
||||||
if rel<math.ceil(rel/self.size)*self.size-1e-11 and delta.x+rel>math.ceil(rel/self.size)*self.size+1e-11 and math.ceil(rel/self.size)*self.size!=0:
|
if rel<math.ceil(rel/((self.size+element.size)/2))*((self.size+element.size)/2)-1e-11 and delta.x+rel>math.ceil(rel/((self.size+element.size)/2))*((self.size+element.size)/2)+1e-11 and math.ceil(rel/((self.size+element.size)/2))*((self.size+element.size)/2)!=0:
|
||||||
# stick to corner
|
# stick to corner
|
||||||
candidate.x=math.ceil(rel/self.size)*self.size+self.pos.x-pos.x
|
candidate.x=math.ceil(rel/((self.size+element.size)/2))*((self.size+element.size)/2)+self.pos.x-element.pos.x
|
||||||
else:
|
else:
|
||||||
if rel>math.floor(rel/self.size)*self.size+1e-11 and delta.x+rel<math.floor(rel/self.size)*self.size-1e-11 and math.floor(rel/self.size)*self.size!=0:
|
if rel>math.floor(rel/((self.size+element.size)/2))*((self.size+element.size)/2)+1e-11 and delta.x+rel<math.floor(rel/((self.size+element.size)/2))*((self.size+element.size)/2)-1e-11 and math.floor(rel/((self.size+element.size)/2))*((self.size+element.size)/2)!=0:
|
||||||
# stick to corner
|
# stick to corner
|
||||||
candidate.x=math.floor(rel/self.size)*self.size+self.pos.x-pos.x
|
candidate.x=math.floor(rel/((self.size+element.size)/2))*((self.size+element.size)/2)+self.pos.x-element.pos.x
|
||||||
return candidate
|
return candidate
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user