예제 #1
0
class FractalCanvas(Canvas):
    @property
    def fragment_shader(self):
        replacements = {
            '#define FUNCTION(z) (VECTOR2(0.0, 0.0))':
            f'#define FUNCTION(z) ({self.functions[self.function_index].function_gl})',
            '#define DERIVATIVE(z) (VECTOR2(1.0, 0.0))':
            f'#define DERIVATIVE(z) ({self.functions[self.function_index].derivative_gl})',
            '#define ROOTS (VECTOR2[](VECTOR2(0.0, 0.0)))':
            f'#define ROOTS (VECTOR2[]({self.functions[self.function_index].roots_gl}))'
        }
        return re.compile('|'.join(
            re.escape(key) for key in replacements.keys())).sub(
                lambda match: replacements[match.group(0)],
                self.fragment_shader_template)

    @property
    def function_info(self):
        return f'f(z)  = {self.functions[self.function_index].function_py.replace(" ** ", "^").replace("*", "·")}\n' + \
               f'f\'(z) = {self.functions[self.function_index].derivative_py.replace(" ** ", "^").replace("*", "·")}'

    @property
    def pixel_to_complex_transform(self):
        return array([[
            self.scale / self.size[0], 0.0, self.center[0] - 0.5 * self.scale
        ],
                      [
                          0.0, -self.scale / self.size[0],
                          0.5 * self.size[1] / self.size[0] * self.scale +
                          self.center[1]
                      ], [0.0, 0.0, 1.0]])

    @property
    def complex_to_pixel_transform(self):
        return inv(self.pixel_to_complex_transform)

    # noinspection PyShadowingNames
    def __init__(self, vertex_shader, fragment_shader_template, functions,
                 *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.vertex_shader = vertex_shader
        self.fragment_shader_template = fragment_shader_template
        self.functions = functions
        self.function_index = 0

        self.program = Program(self.vertex_shader, self.fragment_shader)
        self.program['position'] = [(-1.0, -1.0), (-1.0, 1.0), (1.0, 1.0),
                                    (-1.0, -1.0), (1.0, 1.0), (1.0, -1.0)]
        self.program['resolution'] = self.size
        self.center = array([0.0, 0.0])
        self.program['center'] = array(
            [*unpack_double(self.center[0]), *unpack_double(self.center[1])])
        self.center_min, self.center_max = array([-10.0,
                                                  -10.0]), array([10.0, 10.0])
        self.scale = 2.5
        self.program['scale'] = unpack_double(self.scale)
        self.scale_min, self.scale_max = 10.0**-10.0, 10.0**2.0

        self.line = LinePlotVisual(array([[-10, -10]]), color='white')
        self.position_text = TextVisual('',
                                        color='white',
                                        font_size=10,
                                        anchor_x='right',
                                        anchor_y='top')
        self.iterations_text = TextVisual('',
                                          color='white',
                                          font_size=10,
                                          anchor_x='left',
                                          anchor_y='top')
        self.info_text = TextVisual(self.function_info,
                                    pos=(5, 5),
                                    color='white',
                                    font_size=10,
                                    anchor_x='left',
                                    anchor_y='bottom')

        if use_app().backend_name == 'PyQt5':
            self._backend.leaveEvent = self.on_mouse_exit

        self.timer = Timer(connect=self.update, start=True)
        self.show()

    def on_draw(self, event):
        self.program.draw()
        self.line.draw()
        self.position_text.draw()
        self.iterations_text.draw()
        self.info_text.draw()

    def on_resize(self, event):
        self.program['resolution'] = self.size
        self.line.transforms.configure(canvas=self,
                                       viewport=(0, 0, *self.size))
        self.position_text.transforms.configure(canvas=self,
                                                viewport=(0, 0, *self.size))
        self.iterations_text.transforms.configure(canvas=self,
                                                  viewport=(0, 0, *self.size))
        self.info_text.transforms.configure(canvas=self,
                                            viewport=(0, 0, *self.size))

    def on_mouse_exit(self, event):
        self.on_mouse_handler('mouse_exit', event)

    def on_mouse_move(self, event):
        self.on_mouse_handler('mouse_move', event)

    def on_mouse_release(self, event):
        self.on_mouse_handler('mouse_release', event)

    def on_mouse_wheel(self, event):
        self.on_mouse_handler('mouse_wheel', event)

    def on_mouse_handler(self, event_type, event):
        if event_type == 'mouse_move' or event_type == 'mouse_wheel':
            if event.type == 'mouse_wheel':
                self.zoom(0.9 if event.delta[1] > 0.0 else 1.0 / 0.9,
                          event.pos)

            self.newton_method(event.pos)

            if event.is_dragging and event.buttons[0] == 1:
                new_position_complex = dot(
                    self.pixel_to_complex_transform,
                    array([[event.pos[0]], [event.pos[1]], [1.0]]))
                old_position_complex = dot(
                    self.pixel_to_complex_transform,
                    array([[event.last_event.pos[0]],
                           [event.last_event.pos[1]], [1.0]]))
                self.translate((new_position_complex -
                                old_position_complex)[:2].flatten())
        elif event_type == 'mouse_release':
            if event.last_event.is_dragging:
                return

            old_function_index = self.function_index
            self.function_index = (self.function_index +
                                   (1 if event.button == 1 else
                                    (-1 if event.button == 2 else 0))) % len(
                                        self.functions)
            new_function_index = self.function_index

            if new_function_index != old_function_index:
                self.program.set_shaders(vert=self.vertex_shader,
                                         frag=self.fragment_shader)
                self.newton_method(event.pos)
                self.info_text.text = self.function_info

        elif event_type == 'mouse_exit':
            self.line.set_data(array([[-10, -10]]))
            self.position_text.pos = (0, 0)
            self.iterations_text.pos = (0, 0)

    def newton_method(self, position_pixel):
        position_complex = dot(
            self.pixel_to_complex_transform,
            array([[position_pixel[0]], [position_pixel[1]], [1.0]]))
        z_0 = complex(*position_complex[:2].flatten())
        z_n, iterations = newton_method(
            z=z_0,
            function_string=self.functions[self.function_index].function_py,
            derivative_string=self.functions[
                self.function_index].derivative_py)

        # noinspection PyTypeChecker
        self.line.set_data(array([
            dot(self.complex_to_pixel_transform,
                array([[z[0]], [z[1]], [1.0]]))[:2].flatten() for z in z_n
        ]),
                           edge_width=0)
        self.position_text.text = '{:.3e}\n{:.3e}'.format(
            *position_complex[:2].flatten())
        self.position_text.pos = position_pixel + array([-5, -5])
        self.iterations_text.text = f'\n{iterations}'
        self.iterations_text.pos = dot(
            self.complex_to_pixel_transform,
            array([[z_n[-1][0]], [z_n[-1][1]], [1.0]]))[:2].flatten() + array(
                [5, -5])

    def translate(self, delta_complex):
        self.center = clip(self.center - delta_complex, self.center_min,
                           self.center_max)
        self.program['center'] = array(
            [*unpack_double(self.center[0]), *unpack_double(self.center[1])])

    def zoom(self, factor, position_pixel):
        old_position_complex = dot(
            self.pixel_to_complex_transform,
            array([[position_pixel[0]], [position_pixel[1]], [1.0]]))
        self.scale = clip(self.scale * factor, self.scale_min, self.scale_max)
        self.program['scale'] = unpack_double(self.scale)
        new_position_complex = dot(
            self.pixel_to_complex_transform,
            array([[position_pixel[0]], [position_pixel[1]], [1.0]]))
        self.translate(
            (new_position_complex - old_position_complex)[:2].flatten())
예제 #2
0
class Canvas(app.Canvas):
    def __init__(self):
        app.Canvas.__init__(self,
                            size=(512, 512),
                            title='Particle Renderer',
                            keys='interactive')

        # enable geometry shader
        gloo.gl.use_gl('gl+')

        # load and compile shader
        with open('shader/particleRenderer.frag', 'r') as file:
            fragmentString = file.read()

        with open('shader/particleRenderer.geom', 'r') as file:
            geomString = file.read()

        with open('shader/particleRenderer.vert', 'r') as file:
            vertexString = file.read()

        self.program = Program()
        self.program.set_shaders(vertexString, fragmentString, geomString,
                                 True)

        ######################################
        # settings

        # when changing near/far or fov you have to call resetProjection() for the changes to take effect
        # everything closer to the camera than near ot further away than far will not be drawn
        self.nearDistance = 0.1
        self.farDistance = 20
        self.fov = 45.0  # field of view in degree

        # initial camera position
        # call resetCamera or press "R" to go the initial position
        self.initialCamPosition = glm.vec3(3, 3, 3)
        self.initialCamTarget = glm.vec3(0, 0, 0)

        # you can change settings of the camera yourself with self.cam.xxx = yyy
        # you can also move the camera by calling setPosition / setTarget and
        # thereby predefine an animation (eg for videos/talks)
        # you can also change the camera control mode 1 = fly camera, 0 = trackball camera
        self.cam = Camera(1, self.initialCamPosition, self.initialCamTarget)
        # the CameraInputHandler links the camera to keybiard and mouse input, you can also change keybindings there
        self.camInputHandler = CameraInputHandler(self.cam)

        # // positions where spheres are rendered
        self.program['input_position'] = [(0, 0, 0), (1, 1, 1), (1, 1, -1),
                                          (1, -1, 1), (1, -1, -1), (-1, 1, 1),
                                          (-1, 1, -1), (-1, -1, 1),
                                          (-1, -1, -1)]

        # vector field for color
        # self.program['input_vector'] =
        # scalar field, used for color in color mode 3
        self.program['input_scalar'] = np.array(
            [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9], dtype=np.float32)
        # radius per particle, set self.program['enableSizePerParticle']  = True to enable
        self.program['input_radius'] = [[0.15], [0.1], [0.2], [0.1], [0.2],
                                        [0.05], [0.1], [0.15], [0.1]]

        # size
        self.program[
            'enableSizePerParticle'] = False  # enable this and set a size for each particle above
        self.program[
            'sphereRadius'] = 0.15  # radius of the spheres if "size per particle" is disabled

        # background
        gloo.set_state(clear_color=(0.30, 0.30, 0.35,
                                    1.00))  # background color

        # transfer function / color
        self.program[
            'colorMode'] = 3  # 1: color by vector field direction, 2: color by vector field magnitude, 3: color by scalar field, 0: constant color
        self.program['defaultColor'] = (1, 1, 1
                                        )  # particle color in color mode 0
        self.program[
            'lowerBound'] = 0.0  # lowest value of scalar field / vector field magnitude
        self.program[
            'upperBound'] = 1.0  # lowest value of scalar field / vector field magnitude
        self.program[
            'customTransferFunc'] = True  # set to true to use a custom transfer function
        # Transfer function uses a 1D Texture.
        # Provide 1D list of colors (r,g,b) as the textures data attribute, colors will be evenly spread over
        # the range [lowerBound,upperBound]. Meaning particles where the scalar is equal to lowerBound will
        # have the first specified color, the one with a scalar equal to lowerBound will have the last. Values that
        # lie in between the colors are interpolated linearly
        self.program['transferFunc'] = gloo.Texture1D(
            format='rgba',
            interpolation='linear',
            internalformat='rgba8',
            data=cm.viridis(range(256)).astype(np.float32))
        # sphere look
        self.program['brightness'] = 1  # additional brightness control
        self.program[
            'materialAlpha'] = 1.0  # set lower than one to make spheres
        self.program['materialShininess'] = 4.0  # material shininess
        self.program[
            'useTexture'] = False  # use the below texture for coloring (will be tinted according to set color)
        # provide a numpy array of shaper (x,y,3) for rgb pixels of the 2d image
        self.program['colorTexture'] = gloo.Texture2D(
            format='rgb',
            interpolation='linear',
            internalformat='rgb8',
            data=_checkerboard().astype(np.float32))
        self.program[
            'uvUpY'] = False  # rotates texture by 90 degrees so that sphere poles are along the Y axis

        # light settings
        self.program['lightPosition'] = (500, 500, 1000
                                         )  # position of the ligth
        self.program['lightDiffuse'] = (0.4, 0.4, 0.4
                                        )  # diffuse color of the light
        self.program['lightSpecular'] = (0.3, 0.3, 0.3
                                         )  # specular color of the light
        self.program['ambientLight'] = (0.1, 0.1, 0.1)  # ambient light color
        self.program[
            'lightInViewSpace'] = True  # should the light move around with the camera?

        # settings for flat shading
        self.program[
            'renderFlatDisks'] = False  # render flat discs instead of spheres
        self.program[
            'flatFalloff'] = False  # when using flat discs, enable this darken the edges

        # settings for additional depth cues
        self.program[
            'enableEdgeHighlights'] = False  # add black edge around the particles for better depth perception

        # style of blending
        self.useAdditiveBlending(False)

        # orientation helper
        self.enableOrientationIndicator = True  # enable / disable orientation indicator in the lower left
        self.enableOriginIndicator = True  # enable / disable orientation indicator at the origin
        self.originIndicatorSize = 1.0  # change size of the origin indicator

        # other
        self.program[
            'spriteScale'] = 1.1  # increase this if spheres appear to have cut off edges

        ############################################

        # setup orientation indicator

        # load and compile shader
        with open('shader/oriIndicator.frag', 'r') as file:
            oriFragmentString = file.read()

        with open('shader/oriIndicator.vert', 'r') as file:
            oriVertexString = file.read()

        self._oriProgram = Program(oriVertexString, oriFragmentString)
        self._oriProgram['input_position'] = [(0, 0, 0), (1, 0, 0), (0, 0, 0),
                                              (0, 1, 0), (0, 0, 0), (0, 0, 1)]

        # model matrix
        model = np.eye(4, dtype=np.float32)
        self.program['model'] = model

        # camera and view matrix
        self.program['view'] = self.cam.viewMatrix

        # projection matrix
        self._projection = glm.mat4(1.0)
        self._oriProjection = glm.mat4(1.0)
        self.resetProjection()

        # timing
        self._lastTime = time.time()

        # show window
        self.show()

    def resetCamera(self):
        self.cam.setPosition(self.initialCamPosition, True)
        self.cam.setTarget(self.initialCamTarget, True)

    def useAdditiveBlending(self, enable):
        if enable:
            gloo.set_blend_func('one', 'one')
            gloo.set_blend_equation('func_add')
            gloo.set_state(depth_test=False, blend=True)
        else:
            gloo.set_state(depth_test=True, blend=False)

    def on_mouse_move(self, event):
        self.camInputHandler.on_mouse_move(event)

    def on_key_press(self, event):
        if event.key == 'R':
            self.resetCamera()
            event.handled = True
        else:
            self.camInputHandler.on_key_pressed(event)

    def on_key_release(self, event):
        self.camInputHandler.on_key_released(event)

    def on_mouse_wheel(self, event):
        self.camInputHandler.on_mouse_wheel(event)

    def _drawOrientationIndicator(self):
        gloo.set_state(line_width=5)
        # we want the rotation of the camera but not the translation
        view = glm.inverse(
            glm.mat4_cast(self.cam._currentTransform.orientation))
        view = glm.scale(view, glm.vec3(0.25))
        self._oriProgram['projection'] = self._oriProjection
        self._oriProgram['view'] = view
        self._oriProgram.draw('lines')

    def _drawOriginIndicator(self):
        gloo.set_state(line_width=2)
        self._oriProgram['projection'] = self._projection
        self._oriProgram['view'] = glm.scale(
            self.cam.viewMatrix, glm.vec3(self.originIndicatorSize))
        self._oriProgram.draw('lines')

    def on_draw(self, event):
        # clear window content
        gloo.clear(color=True, depth=True)

        # calculate dt (time since last frame)
        newTime = time.time()
        dt = newTime - self._lastTime
        self._lastTime = newTime

        # update camera and view matrix
        self.camInputHandler.on_draw(dt)
        self.cam.update(dt)
        self.program['view'] = self.cam.viewMatrix

        # draw particles
        self.program.draw('points')

        # draw orientation indicator
        if self.enableOrientationIndicator:
            self._drawOrientationIndicator()
        if self.enableOriginIndicator:
            self._drawOriginIndicator()

        # update window content
        self.update()

    def on_resize(self, event):
        self.resetProjection()

    def resetProjection(self):
        # calculate projection
        gloo.set_viewport(0, 0, *self.physical_size)
        aspect = self.size[0] / float(self.size[1])
        self._projection = perspective(self.fov, aspect, self.nearDistance,
                                       self.farDistance)
        self.program['projection'] = self._projection

        # calculate projection for the orientation indicator in the lower left
        orthoScale = 1 / 500
        orthoProjection = glm.ortho(-self.size[0] * orthoScale,
                                    self.size[0] * orthoScale,
                                    -self.size[1] * orthoScale,
                                    self.size[1] * orthoScale)
        self._oriProjection = glm.translate(
            orthoProjection,
            glm.vec3(-self.size[0] * orthoScale + 0.28,
                     -self.size[1] * orthoScale + 0.28, 0))
예제 #3
0
파일: Map2D.py 프로젝트: udde/pybuildings
class Map2D(app.Canvas):
    def __init__(self, data_handler, parent):

        app.Canvas.__init__(self,
                            size=(512, 512),
                            title='map',
                            keys='interactive')

        self.__parent__ = parent
        self.__data_handler = data_handler

        ##read building data
        ##fetch single building
        #building1 = self.__sh.get_single_at_id(1595) #nya
        #building2 = self.__sh.get_single_at_id(1999) #stryk
        #building3 = self.__sh.get_single_at_id(1886) #strykbrada
        #building4 = self.__sh.get_single_at_id(1722) #Gula vid bron
        #building5 = self.__sh.get_single_at_id(1723) #
        ##and its vertices
        #verts1 = building1.gl_ready_vertices()
        #verts2 = building2.gl_ready_vertices()
        #verts3 = building3.gl_ready_vertices()
        #verts4 = building4.gl_ready_vertices()
        #verts5 = building5.gl_ready_vertices()

        self.all_buildings = self.__data_handler.get_all_buildings()

        all_pos = self.all_buildings[0].gl_ready_vertices()

        for building in self.all_buildings[1:]:
            all_pos = np.vstack((all_pos, building.gl_ready_vertices()))

        abets = self.__data_handler.get_single_at_id(1886)
        abets = abets.gl_ready_vertices()

        #Problem: 977, 1061, 1342(tva stora hal), 1389(hal), 1393(hal), 1434(hal), 1327(rese)
        #Error 1072, 1327(rese). 1472(?!?!?), 1504(!?!?!)
        #for j in range(100000):
        #    for i in range(1503, 1504):
        #print("----------------\n----------------",i)
        #all_pos = all_buildings[i].gl_ready_vertices()

        self.translate_by = np.mean(abets[:], 0)
        self.scale = 1.0

        all_pos = (all_pos - self.translate_by) * self.scale

        allverts = np.zeros(len(all_pos), [('position', np.float32, 2)])
        allverts['position'] = all_pos

        self.selectedverts = np.zeros(len(abets),
                                      [('position', np.float32, 2)])
        self.selectedverts['position'] = (abets -
                                          self.translate_by) * self.scale

        self.vertices = VertexBuffer(allverts)
        self.selectedvertices = VertexBuffer(self.selectedverts)
        #self.indices = IndexBuffer(I)

        # Build program
        self.program = Program(vertex, fragment)
        self.program.bind(self.vertices)

        self.cam2 = Cam3D.Camera([0, 0, 250], [0, 0, 0], [0, 1, 0],
                                 45.0,
                                 self.size[0] / float(self.size[1]),
                                 0.001,
                                 10000.0,
                                 is_2d=True)

        # Build view, model, projection & normal
        self.program['model'] = np.eye(
            4, dtype=np.float32)  #models are at palce from beginnings?
        self.program['model'] = np.transpose(vut.rotx(-10))

        self.program['view'] = self.cam2.view

        projection = perspective(45.0, self.size[0] / float(self.size[1]), 1.0,
                                 1000.0)
        self.program['projection'] = projection

        self.phi, self.theta = 0, 0

        gloo.set_state(clear_color=(0.70, 0.70, 0.7, 1.00), depth_test=True)
        self.set_selected([1999])
        self.activate_zoom()
        self.timer = app.Timer('auto', self.on_timer, start=True)

        self.show()

    def set_selected(self, ids):

        #building = self.__data_handler.get_single_at_id(id)
        #verts2 = building.gl_ready_vertices()

        self.selectedverts = np.zeros(0, [('position', np.float32, 2)])

        for id in ids:
            building = self.__data_handler.get_single_at_id(id)
            verts = building.gl_ready_vertices()
            data = np.zeros(len(verts), [('position', np.float32, 2)])
            data['position'] = (verts - self.translate_by) * self.scale
            self.selectedverts = np.concatenate([self.selectedverts, data])

        #self.selectedverts['position'] = (verts2 - self.translate_by) * self.scale
        self.selectedvertices = VertexBuffer(self.selectedverts)

        selected_pos = np.mean(self.all_buildings[id].points,
                               0) - self.translate_by
        self.cam2.translate_to(selected_pos)
        self.program['view'] = self.cam2.view

        self.update()

    def on_mouse_press(self, event):

        if event.button == 1:

            self.cam2.is_move = True
            self.cam2.is_rotate = False

        if event.button == 2:

            self.cam2.is_move = False
            self.cam2.is_rotate = True

        self.cam2.prev_mouse_pos = event.pos

    def on_mouse_release(self, event):

        self.cam2.is_move = False
        self.cam2.is_rotate = False

    def on_mouse_move(self, event):

        if self.cam2.is_move:

            self.cam2.translate2d(-1 * np.array(
                event.pos - self.cam2.prev_mouse_pos, dtype=np.float32))
            self.program['view'] = self.cam2.view
            self.update()

        elif self.cam2.is_rotate:

            self.cam2.rotx(-1 * np.array(
                (event.pos - self.cam2.prev_mouse_pos))[1:2])
            self.cam2.roty(-1 * np.array(
                (event.pos - self.cam2.prev_mouse_pos))[0:1])
            self.program['view'] = self.cam2.view
            self.update()

        self.cam2.prev_mouse_pos = event.pos

    def on_mouse_wheel(self, event):

        self.cam2.scale(event.delta[1])
        self.program['view'] = self.cam2.view
        self.update()

    def on_draw(self, event):

        gloo.clear(color=True, depth=True)

        self.program.set_shaders(vertex, fragment_active)
        self.program.bind(self.selectedvertices)
        self.program.draw('triangles')

        self.program.set_shaders(vertex, fragment)
        self.program.bind(self.vertices)
        self.program.draw('triangles')

    def on_resize(self, event):

        self.activate_zoom()

    def activate_zoom(self):

        gloo.set_viewport(0, 0, *self.physical_size)
        projection = perspective(45.0, self.size[0] / float(self.size[1]), 1.0,
                                 10000.0)
        self.program['projection'] = projection
        self.update()

    def on_timer(self, event):

        self.update()

    def on_resize(self, event):

        self.activate_zoom()

    def on_key_press(self, event):

        modifiers = [key.name for key in event.modifiers]
        print('Key pressed - text: %r, key: %s, modifiers: %r' %
              (event.text, event.key.name, modifiers))

    def on_key_release(self, event):

        modifiers = [key.name for key in event.modifiers]
        print('Key released - text: %r, key: %s, modifiers: %r' %
              (event.text, event.key.name, modifiers))