2015-10-14 7 views
0

Я пытаюсь реализовать представление графического чертежа в OSX с использованием фреймворка Cocoa и Quartz с использованием NSBezierPath и добавлять/удалять точки данных, когда я иду.CALayer drawinContext, называемый @ 60fps, но просматривающий графику обновления @ 1fps

Выполнение этого действия в drawRect работало нормально, так как график часто обновлялся, но затем я столкнулся с проблемой производительности, когда мне нужно увеличить общий набор данных/частоту дискретизации.

Я решил перейти к drawLayer: inContext: но, когда функция вызывается со скоростью 60 кадров в секунду, представление не обновляет график при вызове функции и вместо этого обновляется со скоростью 1fps.

Что я здесь делаю неправильно?

class CustomDrawLayer: CALayer { 


convenience init(view: NSView, drawsAsynchronously : Bool = false) { 
    self.init() 
    self.bounds = view.bounds 
    self.anchorPoint = CGPointZero 
    self.opaque = false 
    self.frame = view.frame 
    self.drawsAsynchronously = drawsAsynchronously 

    //  for multiple draws in hosting view 
    //  self.delegate = self 

} 

override func actionForLayer(layer: CALayer, forKey event: String) -> CAAction? { 
    return nil 
}} 

override func drawLayer(layer: CALayer, inContext ctx: CGContext) { 

    if layer == self.layer { 
     Swift.print("axes drawing") 
     graphBounds.origin = self.frame.origin 
     graphAxes.drawAxesInRect(graphBounds, axeOrigin: plotOrigin, xPointsToShow: CGFloat(totalSecondsToDisplay), yPointsToShow: CGFloat(totalChannelsToDisplay)) 
    } 

    if layer == self.board { 
     Swift.print(1/NSDate().timeIntervalSinceDate(fpsTimer)) 
     fpsTimer = NSDate() 
     drawPointsInGraph(graphAxes, context: ctx) 

    } 
} 

    func drawPointsInGraph(axes: AxesDrawer, context: CGContext) 
    { 
      color.set() 

      var x : CGFloat = 0 
      var y : CGFloat = 0 

      for var channel = 0; channel < Int(totalChannelsToDisplay); channel++ { 

       path.removeAllPoints() 

       var visibleIndex = (dirtyRect.origin.x - axes.position.x)/(axes.pointsPerUnit.x/samplingRate) 
       if visibleIndex < 2 { 
        visibleIndex = 2 
       } 
       for var counter = Int(visibleIndex); counter < dataStream![channel].count; counter++ { 

        if dataStream![channel][counter] == 0 { 
         if path.elementCount > 0 { 
          path.stroke() 
         } 

         break 
        } 


        let position = axes.position 
        let ppY = axes.pointsPerUnit.y 
        let ppX = axes.pointsPerUnit.x 

        let channelYLocation = CGFloat(channel) 

        x = position.x + CGFloat(counter-1) * (ppX/samplingRate) 
        y = ((channelYLocation * ppY) + position.y) + (dataStream![channel][counter-1] * (ppY)) 
        path.moveToPoint(CGPoint(x: align(x), y: align(y))) 

        x = position.x + CGFloat(counter) * (ppX/samplingRate) 
        y = ((channelYLocation * ppY) + position.y) + (dataStream![channel][counter] * (ppY)) 


        path.lineToPoint(CGPoint(x: align(x), y: align(y))) 




        if x > (axes.position.x + axes.bounds.width) * 0.9 { 

         graphAxes.forwardStep = 5 
         dirtyRect = graphBounds 

         for var c = 0; c < Int(totalChannelsToDisplay); c++ { 
          for var i = 0; i < Int(samplingRate) * graphAxes.forwardStep; i++ 
          { 
           dataStream![c][i] = 0 
          } 

         } 

         return 
        } 


       } 



       path.stroke() 

     } 

     if inLiveResize { 
      dirtyRect = graphBounds 
     } else { 
      dirtyRect.origin.x = x 
      dirtyRect.origin.y = bounds.minY 
      dirtyRect.size.width = 10 
      dirtyRect.size.height = bounds.height 
     } 


    } 

ответ

1

Это невероятно редко, что вы должны когда-либо назвать функцию с частотой 60 Гц. Ни в коем случае нельзя пытаться вызвать функцию рисования при 60 Гц; что никогда не имеет смысла в какао. Если вы действительно имеете в виду «на интервал обновления экрана», см. CADisplayLink, который специально создан, чтобы вы могли рисовать на интервале обновления экрана. Это может быть медленнее 60 Гц. Если вы попытаетесь нарисовать ровно на 60 Гц, вы можете выйти из синхронизации и вызвать удары в анимации. Но это действительно предназначено только для таких вещей, как видео в реальном времени. Если это то, что у вас есть, то это инструмент, но на самом деле это не так.

Это немного сложно понять ваш код. Неясно, куда входит ваш 60fps. Но я предполагаю, что вы пытаетесь сделать, это оживить рисование графика. Если это так, как отмечает Mark F, см. CAShapeLayer. Он имеет встроенную автоматическую анимацию пути и определенно то, что вы хотите. Он автоматически обрабатывает тайминги и синхронизацию с обновлением экрана и оптимизацией графического процессора, а также множество других вещей, которые вы не должны пытаться работать.

Даже если CAShapeLayer не то, что вы хотите, вы должны смотреть на Core Animation, который предназначен для работы с вами, чтобы оживить значения и перерисовать по мере необходимости. Он автоматически будет обрабатывать ваш слой на нескольких ядрах, например, что значительно улучшит производительность. Подробнее об этом см. Animating Custom Layer Properties.

1

Если нужен ваш путь будет сделан вывод, что часто, проверьте CAShapeLayer, где вы можете просто изменить свойство пути. Это будет аппаратное ускорение и намного быстрее, чем drawRect или drawLayer.