Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

I need to convert the pixel coordinates of a bounding box to the same CRS being used by an existing layer. Here's the relevant code so far:

# First, get the layer-coords version of the bounding box:
def pixelToCrsBox(self, theClickBox, theCanvas, theLayer):
    Takes a bbox in pixel coords, converts it to a bbox in layer coords.

        The bbox that needs to be converted.
        The current canvas.
        The current layer.
        The converted bbox.
    # converts from screen to map canvas crs
    myMapToPixel = theCanvas.getCoordinateTransform()
    myX1 = theClickBox.xMinimum()
    myY1 = theClickBox.yMinimum()
    myPoint1 = myMapToPixel.toMapCoordinates(myX1, myY1)

    myX2 = theClickBox.xMaximum()
    myY2 = theClickBox.yMaximum()
    myPoint2 = myMapToPixel.toMapCoordinates(myX2, myY2)

    myRectangle = QgsRectangle(myPoint1, myPoint2)

    # converts the click box from canvas crs to the layer's CRS
    myCanvasCrs = theCanvas.mapRenderer().destinationCrs()
    myLayerCrs = theLayer.crs()
    myTransform = QgsCoordinateTransform(myCanvasCrs, myLayerCrs)
    myExtent = myTransform.transform(myRectangle)
    return myExtent

# Next, get the first feature in the layer using the extents computed above
# (returned as myExtent, but fed to this function as theExtent).
def getFirstFeature(self, theLayer, theExtent):
    Gets the first feature within the bbox in the active layer.

        The current layer.
        The converted bbox.
        A feature.
        Exception if data could not be loaded.

    myProvider = theLayer.dataProvider()
    if myProvider is None:
        msg = ('Could not obtain data provider from '
           'layer "%s"' % theLayer.source())
        raise Exception(msg)

    #myLayerExtent = theLayer.extent()
    myAttributes = myProvider.attributeIndexes()
    myFetchGeometryFlag = True
    myUseIntersectFlag = True

    mySelection = myProvider.select(myAttributes,
                  theExtent, myFetchGeometryFlag, myUseIntersectFlag)
    print ('SELECTED: %s' % mySelection)
    myFeature = myProvider.nextFeature(mySelection)
    return myFeature

To test this, I have these functions:

def prepareTestCanvas(self):
    Sets parameters for a test canvas.
    setCanvasCrs(4326, True)

def testPixelToCrsBox(self):
    Tests that a bbox in pixel coords is converted to map coords
    myPoint = QgsPoint(40, 15)
    myBox = self.bucketFill.getClickBbox(myPoint)
    myLayer = self.bucketFill.getActiveVectorLayer()
    myRectangle = self.bucketFill.pixelToCrsBox(myBox, canvas, myLayer)
    myExpectedBox = QgsRectangle(106.758705784, -6.13591899755,
                                 106.761696484, -6.1329282975)
    myMessage = ('Bounding box was incorrect.\n'
        'Received values %s\n'
        'Expected values %s' % (
        str('%s, %s, %s, %s' % (
            myRectangle.xMinimum(), myRectangle.yMinimum(),
            myRectangle.xMaximum(), myRectangle.yMaximum()
        str('%s, %s, %s, %s' % (
            myExpectedBox.xMinimum(), myExpectedBox.yMinimum(),
            myExpectedBox.xMaximum(), myExpectedBox.yMaximum()
    assert (
        round(myRectangle.xMinimum(), 9) ==
        round(myExpectedBox.xMinimum(), 9) and
        round(myRectangle.xMaximum(), 9) ==
        round(myExpectedBox.xMaximum(), 9) and
        round(myRectangle.yMinimum(), 9) ==
        round(myExpectedBox.yMinimum(), 9) and
        round(myRectangle.yMaximum(), 9) ==
        round(myExpectedBox.yMaximum(), 9)), myMessage

def testGetFirstFeature(self):
    Tests that a feature is returned.
    myLayer = self.bucketFill.getActiveVectorLayer()
    myTestBox = QgsRectangle(106.758705784, -6.13591899755,
                             106.761696484, -6.1329282975)
    myFeature = self.bucketFill.getFirstFeature(myLayer, myTestBox)
    print myFeature
    myMessage = ('Returned object was not a feature.')
    assert myFeature.type() == QgsFeature, myMessage

However, the coordinates are not in the right place when they are returned in the layer CRS. They're supposed to hit the feature I'm trying to select, but they don't.

The coordinates that get returned (same as those in the test) are way off base, and it shouldn't be possible to click there if the canvas is zoomed to the layer extents (there are no other features in the test layer).

So my theory is that the coordinates are transformed incorrectly. What am I doing wrong?

share|improve this question

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.