Center logical coordinates (so that zooming in and out keeps center invariant)

This commit is contained in:
Ian Jauslin 2022-09-21 17:37:05 -04:00
parent 19838bc2a2
commit ec9f0018f7
2 changed files with 56 additions and 29 deletions

View File

@ -53,6 +53,17 @@ class Painter(Widget):
self.undermouse=None
self.draw()
# convert logical coordinates (normalized and centered) to the ones that are plotted
def pos_tocoord_x(self,x):
return self.width/2+x*Square_element.size
def pos_tocoord_y(self,y):
return self.height/2+y*Square_element.size
def coord_topos_x(self,x):
return (x-self.width/2)/Square_element.size
def coord_topos_y(self,y):
return (y-self.height/2)/Square_element.size
# draw all particles
def draw(self):
@ -61,7 +72,7 @@ class Painter(Widget):
# draw order: particles, then grids, then transparent particles
for particle in self.particles:
particle.draw()
particle.draw(self)
# draw grids
for particle in self.particles:
@ -69,8 +80,9 @@ class Painter(Widget):
self.draw_grid(particle.squares[0].pos,particle.grid)
for particle in self.particles:
particle.draw(alpha=0.5)
particle.draw(self,alpha=0.5)
# draw a grid around a particle
def draw_grid(self,pos,mesh):
# height offset due to status bar and command prompt
height_offset=self.app.status_bar.height+self.app.command_prompt.height
@ -156,10 +168,13 @@ class Painter(Widget):
def on_touch_down(self,touch):
# only respond to touch in drawing area
if self.collide_point(*touch.pos):
# convert to logical
touchx=self.coord_topos_x(touch.x)
touchy=self.coord_topos_y(touch.y)
# create new cross
if touch.button=="right":
new=Cross(touch.x/Square_element.size,touch.y/Square_element.size)
new=Cross(touchx,touchy)
if not self.check_interaction_any(new,Point(0,0)):
# add to list
self.particles.append(new)
@ -175,11 +190,11 @@ class Painter(Widget):
# select particle
if touch.button=="left":
# find particle under touch
self.undermouse=self.find_particle(Point(touch.x/Square_element.size,touch.y/Square_element.size))
self.undermouse=self.find_particle(Point(touchx,touchy))
# record relative position of click with respect to reference
if self.undermouse!=None:
self.offset=Point(touch.x/Square_element.size,touch.y/Square_element.size)-self.undermouse.squares[0].pos
self.offset=Point(touchx,touchy)-self.undermouse.squares[0].pos
# no modifiers
if self.modifiers==[]:
@ -222,12 +237,16 @@ class Painter(Widget):
# respond to drag
def on_touch_move(self,touch):
# convert to logical
touchx=self.coord_topos_x(touch.x)
touchy=self.coord_topos_y(touch.y)
# only respond to touch in drawing area
if self.collide_point(*touch.pos):
# only move on left click
if touch.button=="left" and self.modifiers==[] and self.undermouse!=None:
# attempted move determined by the relative position to the relative position of click within self.undermouse
delta=self.adjust_move(Point(touch.x/Square_element.size,touch.y/Square_element.size)-(self.offset+self.undermouse.squares[0].pos),0)
delta=self.adjust_move(Point(touchx,touchy)-(self.offset+self.undermouse.squares[0].pos),0)
for particle in self.selected:
particle.move(delta)

View File

@ -18,7 +18,7 @@ class Polyomino():
self.grid=kwargs.get("grid",0)
# draw function
def draw(self,**kwargs):
def draw(self,painter,**kwargs):
alpha=kwargs.get("alpha",1)
# set color
if not self.selected:
@ -29,22 +29,26 @@ class Polyomino():
Color(r/2,g/2,b/2,alpha)
for square in self.squares:
Rectangle(pos=((square.pos.x-0.5)*square.size,(square.pos.y-0.5)*square.size),size=(square.size,square.size))
Rectangle(pos=(painter.pos_tocoord_x(square.pos.x-0.5),painter.pos_tocoord_y(square.pos.y-0.5)),size=(square.size,square.size))
# draw boundary
self.stroke()
self.stroke(painter)
# draw boundary (override for connected polyominos)
def stroke(self):
def stroke(self,painter):
# convert to graphical coordinates
coordx=painter.pos_tocoord_x(square.pos.x)
coordy=painter.pos_tocoord_y(square.pos.y)
# white
Color(1,1,1)
for square in self.squares:
Line(points=(
*((square.pos.x-0.5)*square.size,(square.pos.y-0.5)*square.size),
*((square.pos.x-0.5)*square.size,(square.pos.y+0.5)*square.size),
*((square.pos.x+0.5)*square.size,(square.pos.y+0.5)*square.size),
*((square.pos.x+0.5)*square.size,(square.pos.y-0.5)*square.size),
*((square.pos.x-0.5)*square.size,(square.pos.y-0.5)*square.size)
*(coordx-0.5*square.size,coordy-0.5*square.size),
*(coordx-0.5*square.size,coordy+0.5*square.size),
*(coordx+0.5*square.size,coordy+0.5*square.size),
*(coordx+0.5*square.size,coordy-0.5*square.size),
*(coordx-0.5*square.size,coordy-0.5*square.size)
))
# move by delta
@ -84,22 +88,26 @@ class Cross(Polyomino):
])
# redefine stroke to avoid lines between touching squares
def stroke(self):
def stroke(self,painter):
# convert to graphical coordinates
coordx=painter.pos_tocoord_x(self.squares[0].pos.x)
coordy=painter.pos_tocoord_y(self.squares[0].pos.y)
Color(1,1,1)
Line(points=(
*((self.squares[0].pos.x-0.5)*Square_element.size,(self.squares[0].pos.y-0.5)*Square_element.size),
*((self.squares[0].pos.x-0.5)*Square_element.size,(self.squares[0].pos.y-1.5)*Square_element.size),
*((self.squares[0].pos.x+0.5)*Square_element.size,(self.squares[0].pos.y-1.5)*Square_element.size),
*((self.squares[0].pos.x+0.5)*Square_element.size,(self.squares[0].pos.y-0.5)*Square_element.size),
*((self.squares[0].pos.x+1.5)*Square_element.size,(self.squares[0].pos.y-0.5)*Square_element.size),
*((self.squares[0].pos.x+1.5)*Square_element.size,(self.squares[0].pos.y+0.5)*Square_element.size),
*((self.squares[0].pos.x+0.5)*Square_element.size,(self.squares[0].pos.y+0.5)*Square_element.size),
*((self.squares[0].pos.x+0.5)*Square_element.size,(self.squares[0].pos.y+1.5)*Square_element.size),
*((self.squares[0].pos.x-0.5)*Square_element.size,(self.squares[0].pos.y+1.5)*Square_element.size),
*((self.squares[0].pos.x-0.5)*Square_element.size,(self.squares[0].pos.y+0.5)*Square_element.size),
*((self.squares[0].pos.x-1.5)*Square_element.size,(self.squares[0].pos.y+0.5)*Square_element.size),
*((self.squares[0].pos.x-1.5)*Square_element.size,(self.squares[0].pos.y-0.5)*Square_element.size),
*((self.squares[0].pos.x-0.5)*Square_element.size,(self.squares[0].pos.y-0.5)*Square_element.size),
*(coordx-0.5*Square_element.size,coordy-0.5*Square_element.size),
*(coordx-0.5*Square_element.size,coordy-1.5*Square_element.size),
*(coordx+0.5*Square_element.size,coordy-1.5*Square_element.size),
*(coordx+0.5*Square_element.size,coordy-0.5*Square_element.size),
*(coordx+1.5*Square_element.size,coordy-0.5*Square_element.size),
*(coordx+1.5*Square_element.size,coordy+0.5*Square_element.size),
*(coordx+0.5*Square_element.size,coordy+0.5*Square_element.size),
*(coordx+0.5*Square_element.size,coordy+1.5*Square_element.size),
*(coordx-0.5*Square_element.size,coordy+1.5*Square_element.size),
*(coordx-0.5*Square_element.size,coordy+0.5*Square_element.size),
*(coordx-1.5*Square_element.size,coordy+0.5*Square_element.size),
*(coordx-1.5*Square_element.size,coordy-0.5*Square_element.size),
*(coordx-0.5*Square_element.size,coordy-0.5*Square_element.size),
))