I'm writing a C++ application using QGIS API and I would like to improve the performance.
I want to render 5 layers:
- one raster layer using gdal to load Bing/Google Map tiles
- 4 custom QgsMapLayer (using plugin layer type) to draw different lines/polygons/points in WGS84.
For now, each of these layer is added to the MapCanvas, using:
QgsMapLayerRegistry::instance()->addMapLayer(customLayer);
QList myLayerSet;
myLayerSet.append(QgsMapCanvasLayer(cutomLayer,TRUE));
setLayerSet(myLayerSet);
On the canvas, I can have map tools, like panning, zoom in/out. I use custom layers because I want to easily decorate lines and polygons, using QPainter. This works, and I'm able to display what i want, where i want (using coordinate transforms from WGS84 to pseudo mercator).
My problem is: one of my custom layers draws a GPS point with some circles around it. This layer is refreshed every second. To refresh my layer, I use the canvas->refresh()
, but that refreshes all other layers as well, and by consequence, the GDAL layer. This takes a lot of time and it's not necessary.
I have read some posts here mentioning the use of layer->setImageCache()
, or by sub-classing QgsMapCanvasItem. Unfortunately, none of theses solutions works as I expect. setImageCache
apparently doesn't work at all, or I don't know how to use it properly.
Sub-classing QgsMapCanvasItem allows me to implement the layers that need frequent refresh, and refresh them without refresh Raster Layer but:
- when panning the map, drawn objects don't follow the map (as a rubberBand can).
- when i use zoom in/out, the selection rectangle erase what was drawn on my canvasItem, without triggering a redraw.
I don't see how to do that, even if this subject seems relatively common.
Am i on the right way or is there a better way?
EDIT :
thanks to Nathan, my problem is resolved, and i confirm that custom QgsMapCanvasItem is the solution to independently refresh some layers.
just keep in mind to use toCanvasCoordinates(), and implement boundingRect() properly.
Answer
Using QgsMapCanvasItem
is the way to go here as you will not have to refresh the canvas. You just have to make sure your implementation is correct.
Here is a basic example (taken from https://github.com/DMS-Aus/Roam/blob/master/src/roam/gps_action.py)
class GPSMarker(QgsMapCanvasItem):
def __init__(self, canvas):
QgsMapCanvasItem.__init__(self, canvas)
self.canvas = canvas
self.size = 24
self.map_pos = QgsPoint(0.0, 0.0)
self.svgrender = QSvgRenderer(":/icons/gps_marker")
def setSize(self, size):
self.size = size
def paint(self, painter, xxx, xxx2):
self.setPos(self.toCanvasCoordinates(self.map_pos))
halfSize = self.size / 2.0
self.svgrender.render(painter, QRectF(0 - halfSize, 0 - halfSize, self.size, self.size ) )
def boundingRect(self):
halfSize = self.size / 2.0
return QRectF(-halfSize, -halfSize, 2.0 * halfSize, 2.0 * halfSize)
def setCenter(self, map_pos):
self.map_pos = map_pos
self.setPos(self.toCanvasCoordinates(self.map_pos))
def updatePosition(self):
self.setCenter(self.map_pos)
No comments:
Post a Comment