【问题标题】:How to make route drawing more efficient?如何让路线绘制更高效?
【发布时间】:2011-10-03 17:58:15
【问题描述】:

这是我用来绘制路线的代码。当我有 1000 个点时,路线会严重减慢 ui。也许有人可以提供一个代码 sn-p 或一个链接来解释如何更有效地进行路线绘制?我知道解决这个问题的一种方法是缓存位图路径,但不知道该怎么做。

public class PathOverlay extends Overlay{

private GeoPoint startPoint;
private GeoPoint finishPoint;
private ArrayList<GeoPoint> pathPoints;
private Paint paint;
private Path path;
private Point pathStartPoint;
private Point pathEndPoint;

private float dx;
private float dy;


public PathOverlay(GeoPoint startPoint, GeoPoint finishPoint, ArrayList<GeoPoint> pathPoints, int color){
    this.startPoint = startPoint;
    this.finishPoint = finishPoint;
    this.pathPoints = pathPoints;
    this.paint = new Paint();
    this.paint.setAntiAlias(true);
    this.paint.setDither(true);
    this.paint.setColor(color);
    this.paint.setAlpha(150);
    this.paint.setStrokeWidth(4);
    this.paint.setStyle(Paint.Style.STROKE);
}

@Override
public void draw(Canvas overlayCanvas, MapView mapView, boolean shadow) {
    if(path == null) {
        path = getPath(mapView);
    } else {
        path = transformPath(mapView);
    }
    overlayCanvas.drawPath(path, paint);
    super.draw(overlayCanvas, mapView, shadow);
}

private Path getPath(MapView mapView) {
    Projection projection = mapView.getProjection();
    if(path == null) {
        path = new Path();
        path.setFillType(FillType.WINDING);
    } else {
        path.rewind();
    }
    Point point = new Point();
    pathStartPoint = new Point();
    pathEndPoint = new Point();

    projection.toPixels(startPoint, point);
    projection.toPixels(startPoint, pathStartPoint);
    path.moveTo(point.x, point.y);
    path.addCircle(point.x, point.y, (float) 2.0, Direction.CCW);
    if (pathPoints != null) {
        for(int i=0;i<pathPoints.size();i++) {
            projection.toPixels(pathPoints.get(i), point);
            path.lineTo(point.x, point.y);
        }
    }
    projection.toPixels(finishPoint, point);
    projection.toPixels(finishPoint, pathEndPoint);
    path.lineTo(point.x-5, point.y);
    path.addCircle(point.x-5, point.y, (float) 2.0, Direction.CCW);


    return path;
}

private Path transformPath(MapView mapView) {
    Projection projection = mapView.getProjection();

    Point sPoint = new Point();
    Point ePoint = new Point();
    projection.toPixels(startPoint, sPoint);
    projection.toPixels(finishPoint, ePoint);

    float sx = ((float)ePoint.x - (float)sPoint.x)/((float)pathEndPoint.x - (float)pathStartPoint.x);
    float sy = ((float)ePoint.y - (float)sPoint.y)/((float)pathEndPoint.y - (float)pathStartPoint.y);

    if(sx != 1.0 && sy != 1.0) {
        Log.i("PathOverlay", "resized");
        return getPath(mapView);
    } else {
        Log.i("PathOverlay", "moved");
        Matrix matrix = new Matrix();

        dx = (float)sPoint.x - (float)pathStartPoint.x;
        dy = (float)sPoint.y - (float)pathStartPoint.y;

        matrix.postTranslate(dx, dy);
        pathStartPoint = sPoint;
        pathEndPoint = ePoint;
        path.transform(matrix);

        return path;
    }
}

}

【问题讨论】:

标签: android path bitmap routes


【解决方案1】:

提高绘图速度的最佳方法是减少路径包含的点数。可能它们不是必需的 - 其中很多只是位于上一个和下一个之间,因此您可以通过以下方式过滤它们:

与前一点的最小距离(简单方法)

最小的轴承变化(有点困难,尽管Location 类和它的方法bearingTo() 应该会有所帮助。

【讨论】:

    【解决方案2】:

    您可以将路径绘制到透明的Bitmap 对象(无论您认为合适的大小 - 越大,路径的细节越好,但内存消耗也越高)。

    确保使用Bitmap.config.ARGB_8888 创建它以提高透明度。

    完成此操作后,您将使用两个矩形来显示Overlay 上的路径:

    • 用于确定路径的哪一部分可见的源矩形
    • 一个目标矩形,用于确定您希望在 Overlay 的画布上的哪个位置显示此路径。

    您将使用Canvas.drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint)

    应该不会太难,您已经完成了transformPath 方法中的大部分重要计算。

    添加:

    您实际上可以将绘制到位图的路径和重绘实际路径点结合起来。当用户在地图上移动或放大/缩小时使用上述技术,然后在用户放开屏幕时重绘路径。

    【讨论】:

    • 我想使用你的方法,但我发现了几个问题。如果我创建固定大小的位图并绘制更大的路径,则并非所有路径部分都将绘制到位图,因此如果移动地图,某些路径部分将不可见。如果我创建路径大小的位图,我可能会遇到需要大量内存来创建位图对象的问题,因此应用程序会被杀死。任何想法如何解决它?
    • 您可以缩小路径的大小。使用您的 dst 矩形将其放大。这将表现良好,但在更高的缩放级别可能会缺少细节,具体取决于位图的大小。如果您的路径不经常更改,此解决方案效果很好,否则您最好删除路径点。
    【解决方案3】:
    1. 你应该知道 draw() 方法绘制一个绘制周期大约 50 次。我不知道为什么,但你可以测试一下。这会降低性能。如果你必须绘制 1000 个对象,而 draw() 将每个对象绘制 30-50 个......它会变得非常非常笨拙...... 为避免这种情况,您应该创建一个缓存叠加层。此缓存将仅绘制所有对象一次,并拒绝其他绘制。

    2. 为了加快进程,请在低优先级的后台线程中绘制。

    3. 在多个点之间绘制一条线的最快方法是使用方法 Canvas.drawLines(float[] pts, int offset, int count, Paint paint)。 我已经测试了所有方法,这是android提供的最快的方法。

    【讨论】:

    • 1.您能否指定创建缓存覆盖将如何防止绘制运行超出需要? 2.如何在后台线程中绘制?我知道您可以使用 SurfaceView 在单独的线程中进行绘制,还是有其他方法?
    • 1.在位图中绘制。检查地图是否有任何变化(更改地图中心、更改缩放级别等)。如果有任何变化 - 重绘位图。如果没有,请在屏幕上绘制位图。 2. 我试图在 SurfaceView 中绘图,但什么也没发生。您可以创建一个线程类并在 UI 线程和后台线程之间创建一个通信模块。也请参见 HandlerThread 类。
    猜你喜欢
    • 2013-06-28
    • 1970-01-01
    • 2016-07-08
    • 2012-02-03
    • 2017-06-08
    • 2019-07-26
    • 1970-01-01
    • 1970-01-01
    • 2018-02-08
    相关资源
    最近更新 更多