I have derived a class from QgsMapCanvasItem for drawing circle of some radius at a given latitude and longitude. In my paint function I am using QPainter to draw the circle as

void paint (QPainter* painter){
 painter->drawEllipse(center, radius, radius);

void updatePosition(){
   center = toCanvasCoordinates(center_lat_lon);

The circle is drawing properly and its position is getting updated whenever the events like panning, zoom in, zoom out are happening. My problem is, whenever I am zooming in or zomming out, radius is not changing accordingly. Also I want to update my radius according to the projection system ( say WGS84 ). Any help is greatly appreciated.

2 Answers 2


A different approach might work better - especially considering zooming and CRS:

  1. In code (you might want to use Python instead of C++), create a memory layer. The memory layer can have a CRS assigned.
  2. Then create a circle feature in that memory layer. It will use the CRS units (meters, feet, degree, ...).

If you want just a circle and no ellipse, just use buffer code, e.g.

vpoly = QgsVectorLayer("Polygon", "pointbuffer", "memory")
feature = QgsFeature()
feature.setGeometry( QgsGeometry.fromPoint(QgsPoint(3517601,5406205)).buffer(10000,5))
provider = vpoly.dataProvider()
provider.addFeatures( [feature] )

Here is some Python code I am using for drawing QgsHighlight circles around point features:

def circle_geometry(self, pt, radius=0, segments=0, mapunits=False):
    Draw a circle at a canvas point

    :type pt: qgis.core.QgsPoint
    :param pt: canvas point, in layer crs
    :type radius: float
    :param radius: cicle radius, considered to be in layer units
    :type segments: int
    :param segments: number of segments usually divisible by 8, e.g. 32
    :type mapunits: bool
    :param mapunits: whether the radius should be considered in map units
    :return: QgsGeometry of type QGis.Polygon
    if not radius:
        radius = self.circleradius  # default of 5 for this project
    if not mapunits:
        ctx = self.canvas.mapRenderer().rendererContext()
        # as mm (converted to map pixels, then to map units)
        radius *= ctx.scaleFactor() * ctx.mapToPixel().mapUnitsPerPixel()
    if not segments:
        segments = self.circlesegments  # usually divisible by 8, e.g. 32
    pts = []
    for i in range(segments):
        theta = i * (2.0 * math.pi / segments)
        p = QgsPoint(pt.x() + radius * math.cos(theta),
                     pt.y() + radius * math.sin(theta))
    return QgsGeometry.fromPolygon([pts])

While these circles are temporary, erased after a canvas refresh in my case, and not the C++ code you are looking for in your QgsMapCanvasItem subclass, you can see how QgsRendererContext is used to determine what the radius would be given the current map scale.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.