[Qgis-developer] Force canvas to predefined scales : help needed to improve a script

Nathan Woodrow madmanwoo at gmail.com
Fri Apr 17 05:40:42 PDT 2015


And here is a different way using just functions:

(https://gist.github.com/mdouchin/72a09b629a5557c1dc1c#comment-1435388)

def forcedScale(*scales):
    replayed = False

    def setScale(scale ):
        iface.mapCanvas().scaleChanged.disconnect(setScale)

        print "initial scale: %s" % scale

        targetScale = min(
            scales,
            key=lambda x:abs(x-scale)
        )
        if targetScale == scale:
            return

        print "zoom to %s" % targetScale
        iface.mapCanvas().zoomScale( targetScale )
        iface.mapCanvas().scaleChanged.connect(setScale)

    # pre-defined scales
    predefinedScales = [
        5000,
        10000,
        25000,
        50000,
        100000,
        250000,
        500000
    ]

    # avoid loop

    iface.mapCanvas().scaleChanged.connect(setScale)

    if not scales:
        scales = predefinedScales

On Fri, 17 Apr 2015 at 22:34 kimaidou <kimaidou at gmail.com> wrote:

> More pythonesque Nathan, thanks !
>
> 2015-04-17 14:32 GMT+02:00 Nathan Woodrow <madmanwoo at gmail.com>:
>
>> def __init__( self, *predefinedScales ):
>> and you can do this
>>
>> forcedScale(25000, 50000, 100000)
>>
>> On Fri, 17 Apr 2015 at 22:30 kimaidou <kimaidou at gmail.com> wrote:
>>
>>> Hi all,
>>>
>>> Improve version here:
>>> https://gist.github.com/mdouchin/72a09b629a5557c1dc1c
>>>
>>> with:
>>>
>>> * "replayed" variable to avoid probable infinite loop, thanks to Hugo's
>>> proposal
>>>
>>> * you can now initialize the method with a python list of scales you
>>> want to force canvas to:
>>>
>>> fs =  fs = forcedScale( [25000, 50000, 100000 ] )
>>>
>>> Cheers,
>>> Michaël
>>>
>>> 2015-04-17 12:27 GMT+02:00 kimaidou <kimaidou at gmail.com>:
>>>
>>>> Hi Hugo,
>>>>
>>>> Thanks for the anwser. I used some "print scale" and "print
>>>> targetScale" in my script to check the behavious, and I did not have any
>>>> "infinite loop" or strange behaviour with it. It seems the related QGIS
>>>> code is armed against this risks.
>>>>
>>>> This python script was only a prototype, and I will surely have a look
>>>> at the cpp classes and propose a PR to add this option in QGIS core.
>>>>
>>>> Michaël
>>>>
>>>> 2015-04-17 11:26 GMT+02:00 Hugo Mercier <hugo.mercier at oslandia.com>:
>>>>
>>>>> Hi,
>>>>>
>>>>> Le 17/04/2015 10:46, kimaidou a écrit :
>>>>> > Hi QGIS !
>>>>> >
>>>>> > I would like to be able in QGIS to force the canvas scales to some
>>>>> > predefined ones. Since we now have project scales (and QGIS
>>>>> pre-defined
>>>>> > scales) in the scale selector, we could use them, and add a simple
>>>>> > checkbox near the combobox "Stick to predefined scales".
>>>>> >
>>>>> > The aim is to force the canvas to render only at these scales. For
>>>>> > example, if I use the rectangle zoom tool, and I should go toe
>>>>> 1/56003,
>>>>> > I would instead land on 1/50000 , the closest pre-defined scale.
>>>>>
>>>>> That would be nice to have it in the core. I already had to do
>>>>> something
>>>>> similar with a plugin.
>>>>>
>>>>> >
>>>>> > I made a little python script as a proof of concept to illustrate it
>>>>> :
>>>>> > http://paste.debian.net/167247/
>>>>> >
>>>>> > In this script, I hard coded the scales, but oviously we should get
>>>>> them
>>>>> > from the project properties.
>>>>> >
>>>>> > I have a question regarding my script. Since I use the
>>>>> > QgsMapCanvas::scaleChanged signal, I assume the rendering is done
>>>>> twice
>>>>> > ? Once the "normal" way, and once again after I use the
>>>>> > QgsMapCanvas::zoomScale method after calculating the new target
>>>>> scale.
>>>>> >
>>>>> > Any idea for improving it ? I assume I would have to disconnect one
>>>>> (not
>>>>> > found yet) signal/slot, then set the scale and reconnect this
>>>>> > signal/slot afterwards ?
>>>>>
>>>>> QObject::blockSignals might be of help here. But in this case, you
>>>>> don't
>>>>> want to block all signals, only yours.
>>>>>
>>>>> I guess your solution would work.
>>>>> You can also use a flag in your callback, something like :
>>>>>
>>>>>     def setScale( self, scale ):
>>>>>         if self.reentrant:
>>>>>                 return
>>>>>
>>>>>         targetScale = min(
>>>>>             self.predefinedScales,
>>>>>             key=lambda x:abs(x-scale)
>>>>>         )
>>>>>         self.reentrant = True
>>>>>         self.mc.zoomScale( targetScale )
>>>>>         self.reentrant = False
>>>>>
>>>>> _______________________________________________
>>>>> Qgis-developer mailing list
>>>>> Qgis-developer at lists.osgeo.org
>>>>> http://lists.osgeo.org/mailman/listinfo/qgis-developer
>>>>>
>>>>
>>>>
>>> _______________________________________________
>>> Qgis-developer mailing list
>>> Qgis-developer at lists.osgeo.org
>>> http://lists.osgeo.org/mailman/listinfo/qgis-developer
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osgeo.org/pipermail/qgis-developer/attachments/20150417/c273c4a1/attachment-0001.html>


More information about the Qgis-developer mailing list