Борьба с простым 1D панорамированием и масштабированием - PullRequest
0 голосов
/ 01 марта 2020

Я хочу реализовать панорамирование и масштабирование с использованием текущей позиции мыши. Мой вариант использования особенно прост, учитывая, что я хочу реализовать его только по оси X.

Я попробовал несколько подходов, последний из которых обсуждался здесь:

Масштабирование графика, основанная на текущем положении мыши

Но безрезультатно, масштабирование и панорамирование не работают правильно и плавно на нескольких этапах.

Суть проблемы должна составлять ie в как я выполняю преобразования в методах on_mouse_wheel и scr2obj и obj2scr.

import numpy as np
import math
from vispy import app, gloo, visuals
from vispy.visuals.transforms import STTransform

# Number of displayed lines
x_size = 50

# window size
canvas_size = (800, 600)

# launch app
app.Application(backend_name='PyQt5')

# define texture
tex = np.c_[(np.ones(shape=(1, x_size, 1)),np.zeros(shape=(1, x_size, 1)),np.zeros(shape=(1, x_size, 1)),np.random.uniform(size=(1, x_size, 1)))]

class Canvas(app.Canvas):
    def __init__(self):
        # housekeeping
        app.Canvas.__init__(self, title='Use your wheel to zoom!', keys='interactive', vsync=True, autoswap=True)
        gloo.set_viewport(0, 0, *self.physical_size)

        # translate and scale 1d texture to full screen
        self.heatmap = visuals.ImageVisual(data=tex, method='subdivide',interpolation='nearest')
        s = (1 / (self.size[0]*self.heatmap.size[0] / (self.size[0]*2)), 100)
        self.heatmap.transform = STTransform(scale=s, translate=(-1,-1))

        self.translate = 0.
        self.scale = 1.

        # track time
        self._timer = app.Timer('auto', connect=self.on_timer, start=True)

        # housekeeping
        gloo.set_state(clear_color='black', blend=True, blend_func=('src_alpha', 'one_minus_src_alpha'))
        self.show()

    def scr2obj(self, x):
        res = (x - self.translate) / self.scale
        return res

    def obj2scr(self, x):
        res = self.translate + (x * self.scale)
        return res

    def on_mouse_wheel(self, event):
        #get new mouse pos
        mx = self._normalize(event.pos)[0]

        # translation of new mouse pos to world
        mx0 = self.scr2obj(mx)

        #apply zoom
        dx = np.sign(event.delta[1]) * 0.05
        self.scale = self.scale * math.exp(1.0 * dx)

        #now compute new screen based on already translated position and new zoom
        mx0 = self.obj2scr(mx0)

        #update
        self.translate = self.translate + (mx-mx0)


    def on_resize(self, event):
        vp = (0, 0, event.physical_size[0], event.physical_size[1])
        self.context.set_viewport(*vp)


    def on_timer(self, event):
        #reset trnasform
        self.heatmap.transform._scale = np.array([1 / (self.size[0]*self.heatmap.size[0] / (self.size[0]*2)),2.,1.,1.])#np.ones(4, dtype=np.float32)
        self.heatmap.transform._translate = np.array([-1., -1. , 0., 0.])
        #scale and translate to mouse pos
        self.heatmap.transform.zoom(zoom=self.scale, center=self.translate)
        #send to the shader
        self.update()

    def on_draw(self, event):
        gloo.clear(color='black', depth=True)
        self.heatmap.draw()

    def _normalize(self, x):
        w = float(self.size[0])
        return x / (w / 2.) - 1


if __name__ == '__main__':
    c = Canvas()
    app.run()
...