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.undermouse=None
self.draw() 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 # draw all particles
def draw(self): def draw(self):
@ -61,7 +72,7 @@ class Painter(Widget):
# draw order: particles, then grids, then transparent particles # draw order: particles, then grids, then transparent particles
for particle in self.particles: for particle in self.particles:
particle.draw() particle.draw(self)
# draw grids # draw grids
for particle in self.particles: for particle in self.particles:
@ -69,8 +80,9 @@ class Painter(Widget):
self.draw_grid(particle.squares[0].pos,particle.grid) self.draw_grid(particle.squares[0].pos,particle.grid)
for particle in self.particles: 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): def draw_grid(self,pos,mesh):
# height offset due to status bar and command prompt # height offset due to status bar and command prompt
height_offset=self.app.status_bar.height+self.app.command_prompt.height 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): def on_touch_down(self,touch):
# only respond to touch in drawing area # only respond to touch in drawing area
if self.collide_point(*touch.pos): 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 # create new cross
if touch.button=="right": 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)): if not self.check_interaction_any(new,Point(0,0)):
# add to list # add to list
self.particles.append(new) self.particles.append(new)
@ -175,11 +190,11 @@ class Painter(Widget):
# select particle # select particle
if touch.button=="left": if touch.button=="left":
# find particle under touch # 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 # record relative position of click with respect to reference
if self.undermouse!=None: 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 # no modifiers
if self.modifiers==[]: if self.modifiers==[]:
@ -222,12 +237,16 @@ class Painter(Widget):
# respond to drag # respond to drag
def on_touch_move(self,touch): 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 # only respond to touch in drawing area
if self.collide_point(*touch.pos): if self.collide_point(*touch.pos):
# only move on left click # only move on left click
if touch.button=="left" and self.modifiers==[] and self.undermouse!=None: 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 # 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: for particle in self.selected:
particle.move(delta) particle.move(delta)

View File

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