|
# This will make the QGIS use a world projection and then move the center |
|
# of the CRS sequentially to create a spinning globe effect |
|
import os |
|
from PyQt5.QtGui import QImage, QPainter |
|
from PyQt5.QtCore import QEasingCurve |
|
os.system('rm /tmp/globe*') |
|
# Make this a big number while testing e.g. 19 |
|
# small number e.g. 1 will make for a smooth animation |
|
longitude_increments = -1 |
|
image_counter = 1 |
|
# Keep the scales the same if you dont want it to zoom in an out |
|
max_scale = 58589836 |
|
min_scale = 1830932 |
|
|
|
def render_image(name): |
|
size = iface.mapCanvas().size() |
|
image = QImage(size, QImage.Format_RGB32) |
|
|
|
painter = QPainter(image) |
|
settings = iface.mapCanvas().mapSettings() |
|
|
|
# You can fine tune the settings here for different |
|
# dpi, extent, antialiasing... |
|
# Just make sure the size of the target image matches |
|
|
|
job = QgsMapRendererCustomPainterJob(settings, painter) |
|
job.renderSynchronously() |
|
painter.end() |
|
image.save(name) |
|
|
|
# See https://doc.qt.io/qt-5/qeasingcurve.html#Type-enum |
|
# For the full list of available easings |
|
map_easing = QEasingCurve(QEasingCurve.InBounce) |
|
zoom_easing = QEasingCurve(QEasingCurve.InQuad) |
|
|
|
for i in range(360, 0, longitude_increments): |
|
longitude = i - 180 |
|
# Get latitude_factor as but scaled between 0 - 180 |
|
latitude_factor = i / 2 |
|
# Scale latitude_factor to a positive number from 0 to 1 for use in the easing function |
|
# we invert the result so the flight starts at the equator rather than the poles |
|
latitude_easing_factor = 1 - (latitude_factor / 180) |
|
# Multiply j by the easing of y_value to create a nice wobbly effect |
|
# as the earth rotates |
|
latitude = (latitude_factor * map_easing.valueForProgress(latitude_easing_factor) - 90) |
|
definition = ( |
|
'+proj=ortho +lat_0=%f +lon_0=%f +x_0=0 +y_0=0 +ellps=sphere +units=m +no_defs' % (latitude, longitude)) |
|
crs = QgsCoordinateReferenceSystem() |
|
crs.createFromProj(definition) |
|
iface.mapCanvas().setDestinationCrs(crs) |
|
|
|
# Now use easings for zoom level too |
|
zoom_easing_factor = zoom_easing.valueForProgress(latitude_easing_factor) |
|
scale = ((max_scale - min_scale) * zoom_easing_factor) + min_scale |
|
print('Longitude: %f Latitude: %f Latitude Easing Factor: %f Zoom Easing Factor %f Zoom Scale: %f' % |
|
(longitude, latitude, latitude_easing_factor, zoom_easing_factor, scale)) |
|
if zoom_easing_factor == 1: |
|
iface.mapCanvas().zoomToFullExtent() |
|
else: |
|
iface.mapCanvas().zoomScale(scale) |
|
name = ('/tmp/globe-%03d.png' % image_counter) |
|
render_image(name) |
|
image_counter += 1 |
|
|
|
# Now generate the GIF. If this fails try run the call from the command line |
|
# and check the path to convert (provided by ImageMagick) is correct... |
|
# delay of 3.33 makes the output around 30fps |
|
os.system('/usr/bin/convert -delay 3.33 -loop 0 /tmp/globe-*.png /tmp/globe.gif') |
|
# Now do a second pass with image magick to resize and compress the gif as much as possible. |
|
# The remap option basically takes the first image as a reference inmage for the colour palette |
|
# Depending on you cartography you may also want to bump up the colors param to increase palette size |
|
# and of course adjust the scale factor to the ultimate image size you want |
|
os.system('/usr/bin/convert /tmp/globe.gif -coalesce -scale 600x600 -fuzz 2% +dither -remap /tmp/globe.gif[20] +dither -colors 14 -layers Optimize /tmp/globe_small.gif') |
|
# Also we will make a video of the scene - useful for cases where you have a larger colour |
|
# pallette and gif will not hack it |
|
# Pad option is to deal with cases where ffmpeg complains because the h or w of the image |
|
# is an odd number of pixels. |
|
# :color=white pads the video with white pixels. Change to black if needed. |
|
#os.system('ffmpeg -framerate 30 -pattern_type glob -i "/tmp/globe-*.png" -vf "pad=ceil(iw/2)*2:ceil(ih/2)*2:color=white" -c:v libx264 -pix_fmt yuv420p /tmp/globe.mp4') |
Latest doodles (still definately a work in progress):
globe.mp4