<div>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:</div><div><br></div><div> # First, get the layer-coords version of the bounding box:</div>
<div> def pixelToCrsBox(self, theClickBox, theCanvas, theLayer):</div><div> """</div><div> Takes a bbox in pixel coords, converts it to a bbox in layer coords.</div><div><br></div><div> Args:</div>
<div> The bbox that needs to be converted.</div><div> The current canvas.</div><div> The current layer.</div><div> Returns:</div><div> The converted bbox.</div><div> Raises:</div>
<div> None</div><div> """</div><div> # converts from screen to map canvas crs</div><div> myMapToPixel = theCanvas.getCoordinateTransform()</div><div> myX1 = theClickBox.xMinimum()</div>
<div> myY1 = theClickBox.yMinimum()</div><div> myPoint1 = myMapToPixel.toMapCoordinates(myX1, myY1)</div><div><br></div><div> myX2 = theClickBox.xMaximum()</div><div> myY2 = theClickBox.yMaximum()</div>
<div> myPoint2 = myMapToPixel.toMapCoordinates(myX2, myY2)</div><div><br></div><div> myRectangle = QgsRectangle(myPoint1, myPoint2)</div><div><br></div><div> # converts the click box from canvas crs to the layer's CRS</div>
<div> myCanvasCrs = theCanvas.mapRenderer().destinationCrs()</div><div> myLayerCrs = theLayer.crs()</div><div> myTransform = QgsCoordinateTransform(myCanvasCrs, myLayerCrs)</div><div> myExtent = myTransform.transform(myRectangle)</div>
<div> return myExtent</div><div><br></div><div> # Next, get the first feature in the layer using the extents computed above</div><div> # (returned as myExtent, but fed to this function as theExtent).</div><div>
def getFirstFeature(self, theLayer, theExtent):</div><div> """</div><div> Gets the first feature within the bbox in the active layer.</div><div><br></div><div> Args:</div><div> The current layer.</div>
<div> The converted bbox.</div><div> Returns:</div><div> A feature.</div><div> Raises:</div><div> Exception if data could not be loaded.</div><div> """</div>
<div><br></div><div> myProvider = theLayer.dataProvider()</div><div> if myProvider is None:</div><div> msg = ('Could not obtain data provider from '</div><div> 'layer "%s"' % theLayer.source())</div>
<div> raise Exception(msg)</div><div><br></div><div> #myLayerExtent = theLayer.extent()</div><div> myAttributes = myProvider.attributeIndexes()</div><div> myFetchGeometryFlag = True</div><div>
myUseIntersectFlag = True</div><div><br></div><div> mySelection = myProvider.select(myAttributes,</div><div> theExtent, myFetchGeometryFlag, myUseIntersectFlag)</div><div> print ('SELECTED: %s' % mySelection)</div>
<div> myFeature = myProvider.nextFeature(mySelection)</div><div> return myFeature</div><div><br></div><div><br></div><div><br></div><div><br></div><div>To test this, I have these functions:</div><div><br></div>
<div> def prepareTestCanvas(self):</div><div> """</div><div> Sets parameters for a test canvas.</div><div> """</div><div> loadLayers()</div><div> setCanvasCrs(4326, True)</div>
<div> canvas.zoomToFullExtent()</div><div><br></div><div> def testPixelToCrsBox(self):</div><div> """</div><div> Tests that a bbox in pixel coords is converted to map coords</div><div>
"""</div><div> self.prepareTestCanvas()</div><div> myPoint = QgsPoint(40, 15)</div><div> myBox = self.bucketFill.getClickBbox(myPoint)</div><div> myLayer = self.bucketFill.getActiveVectorLayer()</div>
<div> myRectangle = self.bucketFill.pixelToCrsBox(myBox, canvas, myLayer)</div><div> myExpectedBox = QgsRectangle(106.758705784, -6.13591899755,</div><div> 106.761696484, -6.1329282975)</div>
<div> myMessage = ('Bounding box was incorrect.\n'</div><div> 'Received values %s\n'</div><div> 'Expected values %s' % (</div><div> str('%s, %s, %s, %s' % (</div>
<div> myRectangle.xMinimum(), myRectangle.yMinimum(),</div><div> myRectangle.xMaximum(), myRectangle.yMaximum()</div><div> )),</div><div> str('%s, %s, %s, %s' % (</div>
<div> myExpectedBox.xMinimum(), myExpectedBox.yMinimum(),</div><div> myExpectedBox.xMaximum(), myExpectedBox.yMaximum()</div><div> )),</div><div> ))</div><div> assert (</div>
<div> round(myRectangle.xMinimum(), 9) ==</div><div> round(myExpectedBox.xMinimum(), 9) and</div><div> round(myRectangle.xMaximum(), 9) ==</div><div> round(myExpectedBox.xMaximum(), 9) and</div>
<div> round(myRectangle.yMinimum(), 9) ==</div><div> round(myExpectedBox.yMinimum(), 9) and</div><div> round(myRectangle.yMaximum(), 9) ==</div><div> round(myExpectedBox.yMaximum(), 9)), myMessage</div>
<div><br></div><div> def testGetFirstFeature(self):</div><div> """</div><div> Tests that a feature is returned.</div><div> """</div><div> self.prepareTestCanvas()</div>
<div> myLayer = self.bucketFill.getActiveVectorLayer()</div><div> myTestBox = QgsRectangle(106.758705784, -6.13591899755,</div><div> 106.761696484, -6.1329282975)</div><div> myFeature = self.bucketFill.getFirstFeature(myLayer, myTestBox)</div>
<div> print myFeature</div><div> myMessage = ('Returned object was not a feature.')</div><div> assert myFeature.type() == QgsFeature, myMessage</div><div><br></div><div>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.</div>
<div><br></div><div>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).</div>
<div><br></div><div>So my theory is that the coordinates are transformed incorrectly. What am I doing wrong?</div>