2014-05-14 4 views
0

안녕하세요. SurfaceView를 사용하여 들어오는 신호의 실시간 그래프를 플로팅하는 중입니다. 샘플링 속도는 128Hz이고 목표 그래프 새로 고침 빈도는 50Zh입니다.SurfaceView 캔버스를 지운 후에 고스트 그리기를 피하는 방법

점들은 실시간으로 제대로 그려집니다.

내가 path.computeBounds 전화 각 세그먼트 경로() 를 사용하여 몇 가지 포인트의 세그먼트의 데이터를 플롯() 나는 holder.lockCanvas (RECT)를 호출하고 경로를 그리는 데 사용할 구형 영역을 얻을 수 있습니다. rect를 사용하면 깜박임을 방지하고 CPU 사용량을 줄일 수 있습니다.

그래프가 끝나면 전체 캔버스를 잠그고 배경을 지우고 그래프 프레임을 그린 다음 플로팅을 계속합니다. 나는이 이중 버퍼링/더러운 지역의 사용으로 인한 것으로 판단

ghost image

:

문제는 각각의 새로운 "페이지"의 시작 부분에 내가 마지막 페이지에서 고스트 이미지를 얻을 수 있다는 것입니다 플로팅 할 때.

이 문제에 대한 해결책을 찾았지만이 유형의 응용 프로그램에는 적합하지 않습니다. 어떤 도움이라도 대환영입니다.

감사 장 - 피에르

코드는 다음과 같습니다

private void draw() { 
    Point point = null; 
    Canvas canvas = null; 
    Path path = new Path(); 
    ArrayList<Point> pointArray; 
    float oldX = -1; 
    boolean setToClear = false; 
    boolean isNewSegment = false; 

    if (samplesInQueue == 0) { 
     return; 
    } 

    pointArray = new ArrayList<Point>((int) samplesInQueue); 

    for (int i = 0; i < samplesInQueue; i++) { 
     // take a peek at the point without retrieving it from the point 
     // queue 
     point = Points.peek(); 
     // check if first point of segment is the start of a page 
     if (i == 0) { 
      if (lastSegmentEndPoint != null) { 
       if (point.x < lastSegmentEndPoint.x) { 
        // yes then we will need to clear the screen now 
        isNewSegment = true; 
       } 
      } else { 
       // yes then we will need to clear the screen now 
       isNewSegment = true; 
      } 
     } 

     if (point != null) { 
      if (point.x > oldX) { 
       // put consecutive points in the path point array 
       point = Points.poll(); 
       samplesInQueue--; 
       pointArray.add(point); 
       oldX = point.x; 
      } else { 
       // we have a wrap around, stop and indicate we need to clear 
       // the screen on the next pass 
       if (!isNewSegment) { 
        setToClear = true; 
       } 
       break; 
      } 
     } 
    } 

    // no points, return 
    if (pointArray.size() == 0) { 
     return; 
    } 

    // fill the path 
    for (int i = 0; i < pointArray.size(); i++) { 
     Point p = pointArray.get(i); 

     if (i == 0) { 
      if (lastSegmentEndPoint != null) { 
       if (p.x >= lastSegmentEndPoint.x) { 
        // if we have the end of the last segment, move to it 
        // and line to the new point 
        path.moveTo(lastSegmentEndPoint.x, lastSegmentEndPoint.y); 
        path.lineTo(p.x, p.y); 
       } else { 
        // otherwise just line to the new point 
        path.moveTo(p.x, p.y); 
       } 
      } else { 
       path.moveTo(p.x, p.y); 
      } 
     } else { 
      path.lineTo(p.x, p.y); 
     } 
    } 

    if (clear || isNewSegment) { 
     if (clear) { 
      clear = false; 
     } 
     // we need to clear, lock the whole canvas 
     canvas = holder.lockCanvas(); 
     // draw the graph frame/scales 
     drawGraphFrame = true; 
     drawGraphFrame(canvas); 
    } else { 
     // just draw the path 
     RectF bounds = new RectF(); 
     Rect dirty = new Rect(); 
     // calculate path bounds 
     path.computeBounds(bounds, true); 

     int extra = 0; 
     dirty.left = (int) java.lang.Math.floor(bounds.left - extra); 
     dirty.top = (int) java.lang.Math.floor(bounds.top - extra); 
     dirty.right = (int) java.lang.Math.round(bounds.right + 0.5); 
     dirty.bottom = (int) java.lang.Math.round(bounds.bottom + 0.5); 

     // just lock what is needed to plot the path 
     canvas = holder.lockCanvas(dirty); 
    } 

    // draw the path 
    canvas.drawPath(path, linePaint); 

    // unlock the canvas 
    holder.unlockCanvasAndPost(canvas); 

    // remember last segment end point 
    lastSegmentEndPoint = pointArray.get(pointArray.size() - 1); 

    // set clear flag for next pass 
    if (setToClear) { 
     clear = true; 
    } 
} 

그리기 프레임/명확한 그래프 코드 귀하의 문제는 매우 정직하고 .. 당신은 새로운 부분을 잠금입니다

private void drawGraphFrame(Canvas canvas) { 

    if (!drawGraphFrame) { 
     return; 
    } 

    if (canvas == null) { 
     Log.e(TAG, "trying to draw on a null canvas"); 
     return; 
    } 

    drawGraphFrame = false; 

    // clear the graph 
    canvas.drawColor(Color.BLACK, Mode.CLEAR); 

    // draw the graph frame 
    canvas.drawLine(leftMargin, topMargin, leftMargin, mCanvasHeight - bottomMargin, framePaint); 
    canvas.drawLine(leftMargin, mCanvasHeight - bottomMargin, mCanvasWidth - rightMargin, mCanvasHeight 
      - bottomMargin, framePaint); 

    // more drawing 
} 

답변

0

새 경로가 다루는 캔버스의 그래서 가장 좋은 방법은 당신의 경로와 더러운 렉의 사적인 멤버를 만드는 것입니다. 그런 다음 그리기 메서드를 시작할 때 경로의 현재 경계 (이전 경계)를 더러운 rect에 넣습니다. 이제 path.rewind();를 호출하십시오. 경로 수정을 시작하십시오. 새로운 경계를 가진 더러운 직사각형에 결합을 한 후에. 이제 너의 더러운 렉은 오래되고 새로운 렉들을 덮는다. 그래서 당신의 명료 함은 옛 길을 제거 할 것입니다. 또한 rect 및 path의 경우 초당 100 개 이상의 객체를 할당하지 않으므로 오버 헤드가 줄어 듭니다. 이제 오실로스코프를 그릴 때부터 구 경계를 뷰의 너비 부분으로 조정하려고 할 것입니다. 귀하의 새 부분이 커버하는 동일한 금액.

희망 사항이 해결되었습니다.

+0

감사합니다. Simon. 이 경우에는 실제로 작동하지 않습니다. rewind()는 이전 점이 유지 된 이후 경로가 커지게합니다. 이로 인해 성능은 몇 백 포인트가 지나면 빠르게 떨어집니다. 이것이 내가 한 번에 몇 가지 점을 그리는 이유입니다. 또한, 귀하의 마지막 진술 (오실로 스코프)에서, 나는 이것이 내 코드에서 끝나는 것 같아요, rect는 필요한 영역만을 다루고 있습니다. 어쩌면 당신이 의미하는 바를 이해하지 못했을 수도 있습니다. –

0

내 간단한 대답은 캔버스를 지울 때마다 clear_holder() 함수를 사용하는 것입니다. 홀더를 비워 두는 것이 3 번 명확 해지기 때문에 3 줄을 3 줄 복사하여 붙여 넣습니다.

홀더를 비운 후에 원하는 새 것을 그려야합니다!

link이 소스 코드를 제공합니다!

private void clear_holder(SurfaceHolder holder){ 
     Canvas c = holder.lockCanvas(); 
     c.drawColor(0, PorterDuff.Mode.CLEAR); 
     holder.unlockCanvasAndPost(c); 
     c = holder.lockCanvas(); 
     c.drawColor(0, PorterDuff.Mode.CLEAR); 
     holder.unlockCanvasAndPost(c); 
     c = holder.lockCanvas(); 
     c.drawColor(0, PorterDuff.Mode.CLEAR); 
     holder.unlockCanvasAndPost(c); 
    } 
0

캔버스를 비우는 것처럼 보입니다. 이중 버퍼링 문제가 아닙니다. 재사용 된 경로와 관련이 있다고 생각합니다.

새 페이지를 시작할 때 다음 줄을 추가하십시오.

path.reset();