2014-01-29 34 views
2

我需要繪製成千上萬,未來可能成千上萬個簡單的2D對象(圓形,矩形,一些填充,標記...)到一個小部件。如何快速繪製10000+ 2D圖形對象?

在同一個程序中,我需要GUI小部件(按鈕,文本輸入,複選框)。

我用C++和Python試用了Gtk,Qt和SDL。第一個結果是預料之中的:C++和Python顯示相同的性能,因爲它們在後端調用相同的C或C++例程。

第二個結果是沒有一個庫有很大的不同。數字:22500矩形(150 * 150)需要大約一秒鐘來更新。由於(a)新的數據,即更多的矩形,和(b)用戶交互,即縮放,平移等等,將會不斷地向上調整,第二種方法需要很長的時間!

什麼是更快的方法。小例子非常感謝。 Python和C++很好。其他庫應該很容易在Linux上訪問和安裝。

也許我只是做錯了。

ps。我不張貼我的測試代碼,因爲我不想偏見答案。我不希望被糾正了我的代碼,我想這樣做的最快方法...

編輯:

好吧,我會增加我的GTK測試:

#!/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() 

而SDL實驗:

#!/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() 

Qt的試驗是由我的同事這樣做,我沒有代碼現在...

+1

所以,你要我們從地上爬起來爲你的代碼呢?如果您包含一些代碼,您獲得答案的可能性將大大增加。 – IanAuld

+2

你認爲OpenGL? –

+0

@IanAuld:好的... – steffen

回答

0

看起來你正在繪製每一個對象,無論它是否在可視區域。您是否考慮過存儲每個對象的位置數組,然後在繪製之前測試每個對象以確定它是否位於屏幕的可視區域中?

我做了一個快速和骯髒的測試,嘗試一下(代碼可以是乾淨多了,我敢肯定),這是更爲敏感圖紙只有什麼是可見:

首先,我創建了一些變量來確定可見邊界(你會更新的界限,每次移動和縮放的窗口大小調整等發生):

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

抽獎活動,我檢查如果位置繪製前boundry內。我還整理了您的循環以提高效率,您可以在相同的迭代中繪製和添加文本。即使使用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)