2014-01-29 2 views
2

장래에 수십만 개의 간단한 2 차원 객체 (원, 사각형, 일부 채워진 라벨, 레이블 ...)를 위젯에 가져와야합니다.10000+ 2D 그래픽 객체를 빠르게 그리는 방법은 무엇입니까?

동일한 프로그램에서 GUI 위젯 (버튼, 텍스트 입력, 체크 박스)이 필요합니다.

Gtk, Qt 및 SDL을 C++ 및 Python과 함께 사용해 보았습니다. 첫 번째 결과가 예상됩니다. C++과 Python은 백엔드에서 동일한 C 또는 C++ 루틴을 호출 할 때 동일한 성능을 나타냅니다.

두 번째 결과는 라이브러리 중 큰 차이점이 없다는 것입니다. 숫자 : 22500 개의 직사각형 (150 * 150)은 업데이트하는 데 약 1 초가 필요했습니다. (a) 새로운 데이터, 즉 더 많은 직사각형 및 (b) 사용자 상호 작용, 즉 확대/축소, 패닝 (panning) 등으로 인해 일정한 상향 조정이있을 것이므로, 두 번째 방법은 길다!

더 빠른 방법은 무엇입니까? 작은 예가 대단히 감사합니다. 파이썬과 C++이 좋습니다. 다른 라이브러리는 Linux에서 쉽게 액세스하고 설치할 수 있어야합니다.

어쩌면 내가 잘못하고있을 수도 있습니다.

ps. 나는 답을 편향시키고 싶지 않기 때문에 테스트 코드를 게시하지 않을 것이다.

#!/bin/env python2 

import gtk 
import gobject 
import gtk.gdk 

class GraphWidget(gtk.DrawingArea): 
    __gsignals__ = { 
     'expose-event': 'override', 
     'clicked' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, gtk.gdk.Event)) 
     } 

    def __init__(self,window): 
     gtk.DrawingArea.__init__(self) 
     #self.win = window 
     self.zoom_ratio = 1.0 
     self.dx = 40 
     self.dy = 40 

    def do_expose_event(self, event): 
     cr = self.window.cairo_create() 
     cr.set_source_rgba(1.0, 0.9, 0.8, 1.0) 
     cr.paint() 

     cr.translate(self.dx, self.dy) 
     cr.scale(self.zoom_ratio,self.zoom_ratio) 

     self.draw(cr) 

    def draw(self, cr): 
     n = 150 
     cr.set_source_rgba(0.,1.,1.,1.0) 
     for i in range(n): 
      for j in range(n): 
       cr.arc(i*30, j*30, 10, 0, 6.2832) 

       cr.close_path() 
       cr.fill() 

     cr.set_source_rgba(0.,0.,1.,1.0) 
     for i in range(n): 
      for j in range(n): 
       cr.arc(i*30, j*30, 10, 0, 6.2832) 
       cr.move_to(i*30-10, j*30) 
       cr.show_text("hu") 
       cr.stroke() 

    def on_zoom(self, zoom_factor): 
     self.zoom_ratio *= zoom_factor 
     self.queue_draw() 

    def on_translate(self,dx,dy): 
     self.dx += dx 
     self.dy += dy 
     self.queue_draw() 

class TestWindow(gtk.Window): 
    def __init__(self): 
     gtk.Window.__init__(self) 

     self.widget = GraphWidget(self) 

     self.add(self.widget) 

     self.show_all() 

     # connect key press events 

     self.connect('key-press-event', self.on_key_press_event) 
     self.connect('destroy', gtk.main_quit) 

     self.widget.queue_draw() 

    def on_key_press_event(self, widget, event): 

     if event.keyval == gtk.keysyms.space and not (event.state & gtk.gdk.CONTROL_MASK): 
      self.on_run(widget) 
      return True 
     elif event.keyval == gtk.keysyms.r: 
      self.on_refresh(widget) 
      return True 
     elif event.keyval == gtk.keysyms.Left: 
      self.widget.on_translate(-100, 0) 
     elif event.keyval == gtk.keysyms.Right: 
      self.widget.on_translate(100, 0) 
     elif event.keyval == gtk.keysyms.Up: 
      self.widget.on_translate(0, -100) 
     elif event.keyval == gtk.keysyms.Down: 
      self.widget.on_translate(0, 100) 
     elif event.keyval == gtk.keysyms.Page_Down: 
      self.widget.on_zoom(0.7) 
     elif event.keyval == gtk.keysyms.Page_Up: 
      self.widget.on_zoom(1.3) 

if __name__ == '__main__': 
    win = TestWindow() 
    gtk.main() 
:

좋아, 내 GTK 테스트를 추가합니다 : 그리고

편집 ... 내가 할 수있는 가장 빠른 방법으로 원하는, 내 코드가 수정되고 싶지 않아

그리고 SDL 실험 : Qt는 테스트 그래서 지금 코드가없는 나의 동료에 의해 수행되었다

#!/usr/bin/env python 

import sdl2 
import sdl2.ext as sdl2ext 

dx = 0 
dy = 0 
zoom_factor = 1. 
n_objects = 150 

sdl2ext.init() 

window = sdl2ext.Window('hallo', 
         size=(800, 600), 
         flags= sdl2.SDL_WINDOW_RESIZABLE) 
window.show() 

renderer = sdl2ext.RenderContext(window) 
renderer.color = sdl2ext.Color(255,155,25) 

def draw(): 
    renderer.clear() 
    for i in xrange(n_objects): 
     for j in xrange(n_objects): 
      renderer.fill([int((i*30+dx)*zoom_factor), 
          int((j*30+dy)*zoom_factor), 
          int(20*zoom_factor), 
          int(20*zoom_factor)], 
          sdl2ext.Color(255,25,55)) 
      renderer.draw_rect([int((i*30+dx)*zoom_factor), 
           int((j*30+dy)*zoom_factor), 
           int(20*zoom_factor), 
           int(20*zoom_factor)], 
           sdl2ext.Color(255,255,255)) 

    renderer.present() 

draw() 

running = True 
while running: 
    for e in sdl2ext.get_events(): 
     if e.type == sdl2.SDL_QUIT: 
      running = False 
      break 
     if e.type == sdl2.SDL_KEYDOWN: 
      if e.key.keysym.sym == sdl2.SDLK_ESCAPE: 
       running = False 
       break 
      elif e.key.keysym.sym == sdl2.SDLK_RIGHT: 
       dx += 50 
       draw() 
      elif e.key.keysym.sym == sdl2.SDLK_LEFT: 
       dx -= 50 
       draw() 
      elif e.key.keysym.sym == sdl2.SDLK_UP: 
       dy += 50 
       draw() 
      elif e.key.keysym.sym == sdl2.SDLK_DOWN: 
       dy -= 50 
       draw() 
      elif e.key.keysym.sym == sdl2.SDLK_PAGEUP: 
       zoom_factor *= 1.2 
       draw() 
      elif e.key.keysym.sym == sdl2.SDLK_PAGEDOWN: 
       zoom_factor /= 1.2 
       draw() 

...

+1

그래서 당신은 우리가 지상에서 당신이 원하는 코드를? 코드를 포함 시키면 답을 얻을 확률이 급격히 증가합니다. – IanAuld

+2

OpenGL을 고려해 보셨습니까? –

+0

@IanAuld : Ok ... – steffen

답변

0

볼 수있는 영역에 있는지 여부에 관계없이 모든 단일 개체를 그리는 것처럼 보입니다. 각 객체의 위치 배열을 저장하는 것을 고려한 다음 그리기 전에 화면의 가시 영역에 있는지 확인하기 위해 각각을 테스트 해 보셨습니까?

나는 (코드, 나는 확신 많은 청소기 수) 그것을 밖으로 시도 할 수있는 신속하고 더러운 테스트를했고, 그것을 볼 수 있어요 것만 훨씬 더 반응 도면의 :

첫째는 내가 결정하는 몇 가지 변수를 생성 위치를 그리기 전에 boundry 내에 있으면 내가 확인하고있어, 추첨 이벤트에서

boundX = [-60, 160] 
boundY = [-60, 160] 

: 눈에 보이는 경계 (당신은 경계마다 이동 및 확대, 창 크기 조정 등의 일을 업데이트). 또한 루프를 통합하여 효율성을 높이고 같은 반복에서 텍스트를 그리고 추가 할 수 있습니다. n = 50000으로 이것을 테스트하는 것조차 이전보다 더 반응 적입니다.

def draw(self, cr): 
    n = 150 

    for i in range(n): 
     if min(boundX) < i * 30 < max(boundX): 
      for j in range(n): 
       if min(boundY) < j * 30 < max(boundY): 
        cr.set_source_rgba(0.,1.,1.,1.0) 
        cr.arc(i*30, j*30, 10, 0, 6.2832) 

        cr.close_path() 
        cr.fill() 

        cr.set_source_rgba(0.,0.,1.,1.0) 
        cr.arc(i*30, j*30, 10, 0, 6.2832) 
        cr.move_to(i*30-10, j*30) 
        cr.show_text("hu") 
        cr.stroke() 

그리고 누르기 이벤트에

, 그냥 증가 및 위젯이 번역되고있는만큼 boundry을 감소 :

def on_key_press_event(self, widget, event): 

    if event.keyval == gtk.keysyms.space and not (event.state & gtk.gdk.CONTROL_MASK): 
     self.on_run(widget) 
     return True 
    elif event.keyval == gtk.keysyms.r: 
     self.on_refresh(widget) 
     return True 
    elif event.keyval == gtk.keysyms.Left: 
     boundX[0] += 100 
     boundX[1] += 100 
     self.widget.on_translate(-100, 0) 
    elif event.keyval == gtk.keysyms.Right: 
     boundX[0] -= 100 
     boundX[1] -= 100 
     self.widget.on_translate(100, 0) 
    elif event.keyval == gtk.keysyms.Up: 
     boundY[0] += 100 
     boundY[1] += 100 
     self.widget.on_translate(0, -100) 
    elif event.keyval == gtk.keysyms.Down: 
     boundY[0] -= 100 
     boundY[1] -= 100 
     self.widget.on_translate(0, 100) 
    elif event.keyval == gtk.keysyms.Page_Down: 
     self.widget.on_zoom(0.7) 
    elif event.keyval == gtk.keysyms.Page_Up: 
     self.widget.on_zoom(1.3) 
관련 문제