{"id":1277,"date":"2019-07-05T23:21:13","date_gmt":"2019-07-05T21:21:13","guid":{"rendered":"https:\/\/hannes.enjoys.it\/blog\/?p=1277"},"modified":"2019-07-05T23:22:04","modified_gmt":"2019-07-05T21:22:04","slug":"anaglyph-3d-contour-lines","status":"publish","type":"post","link":"https:\/\/hannes.enjoys.it\/blog\/2019\/07\/anaglyph-3d-contour-lines\/","title":{"rendered":"Anaglyph 3D contour lines"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">A <a href=\"https:\/\/twitter.com\/spatialillusion\/status\/1146744362459701248\">slight misunderstanding about a weird pattern<\/a> I posted to Twitter earlier made me wonder how easy it might be to present elevation data with real depth &#8482; as anaglyph 3D in QGIS. Anaglyph 3D, you know, those red and cyan glasses that rarely ever worked.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You might remember my post on <a href=\"https:\/\/hannes.enjoys.it\/blog\/2018\/12\/fake-chromatic-aberration-and-dynamic-label-shadows-in-qgis\/\">fake chromatic aberration and dynamic label shadows in QGIS<\/a> some months ago. Maybe with some small adjustments of the technique&#8230;?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Wikipedia has an detailed <a href=\"https:\/\/en.wikipedia.org\/wiki\/Anaglyph_3D\">article on the topic<\/a> if you are interested. It boils down to: One eye gets to see not the red but the cyan stuff. The other sees the red but not the cyan. By copying, coloring and shifting elements left-right increasingly the human vision gets tricked into seeing fake depth.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Got your anaglyph glasses? Oogled some images you found online to get in the mood? Excellent, let&#8217;s go!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Get some DEM data.<\/strong> I used a <a href=\"https:\/\/community.codeforhamburg.org\/t\/digitales-hohenmodell-hamburg-dgm-106\">10 meter DEM of Hamburg<\/a> and a <a href=\"https:\/\/www.geodatenzentrum.de\/geodaten\/gdz_rahmen.gdz_div?gdz_spr=deu&amp;gdz_akt_zeile=5&amp;gdz_anz_zeile=1&amp;gdz_unt_zeile=3&amp;gdz_user_id=0\">200 meter DEM of Germany<\/a> for testing. Make sure both your data and your project\/canvas CRS match or you have a hard time with the math.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"807\" height=\"822\" src=\"https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/hamburg-dgm10-hillshade.png\" alt=\"\" class=\"wp-image-1278\" srcset=\"https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/hamburg-dgm10-hillshade.png 807w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/hamburg-dgm10-hillshade-295x300.png 295w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/hamburg-dgm10-hillshade-768x782.png 768w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/hamburg-dgm10-hillshade-624x636.png 624w\" sizes=\"auto, (max-width: 807px) 100vw, 807px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Extract contours at a reasonable interval.<\/strong> What&#8217;s reasonable depends on your data. I used an interval of 5 meters for the 10 meter DEM as Hamburg is rather flat (which you will NOT see here).<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"807\" height=\"822\" src=\"https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/hamburg-dgm10-contours-5m.png\" alt=\"\" class=\"wp-image-1279\" srcset=\"https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/hamburg-dgm10-contours-5m.png 807w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/hamburg-dgm10-contours-5m-295x300.png 295w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/hamburg-dgm10-contours-5m-768x782.png 768w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/hamburg-dgm10-contours-5m-624x636.png 624w\" sizes=\"auto, (max-width: 807px) 100vw, 807px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">You may want to simplify or smooth this.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now it&#8217;s time to zoom in, because the effect only works if the line density is appropriately light.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"806\" height=\"570\" src=\"https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-dgm10-contours-5m.png\" alt=\"\" class=\"wp-image-1284\" srcset=\"https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-dgm10-contours-5m.png 806w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-dgm10-contours-5m-300x212.png 300w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-dgm10-contours-5m-768x543.png 768w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-dgm10-contours-5m-624x441.png 624w\" sizes=\"auto, (max-width: 806px) 100vw, 806px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Now we need to duplicate those, color them and move them left and right.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Change the symbol layer of your contours to a Geometry Generator.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s use that first layer for the left, red part. So <strong>change the color to red.<\/strong> Use a red that vanishes when you look through your left (red) eye but is clearly visible through the right (cyan) eye. The exact color depends on your glasses.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Set the Geometry Generator to LineString.<\/strong> I will now explain an intermediate step so if you just want the result, scroll a bit.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">translate(\n  $geometry,\n  -  -- there is a minus here!\n  (\n    x_max(@map_extent) - x(centroid($geometry))\n  )\n  \/100  -- magic scale value\u2026\n  ,\n  0  -- no translation in y\n)<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This moves each contour line to the left for a value that increases with the geometry&#8217;s distance to the right side. Since we don&#8217;t want to move the geometries too far, a magic scale factor needs to be added and adjusted according to your coordinate values.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">(Yes, that is a bug right here (centroid is a bad metric and some of the contours are huge geometries) but hey it works well enough. Segmentizing could fix this. Or just extract the vertices, that looks cool too TODO imagelink)<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"806\" height=\"570\" src=\"https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-dgm10-contours-5m-anaglyph-red.png\" alt=\"\" class=\"wp-image-1286\" srcset=\"https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-dgm10-contours-5m-anaglyph-red.png 806w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-dgm10-contours-5m-anaglyph-red-300x212.png 300w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-dgm10-contours-5m-anaglyph-red-768x543.png 768w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-dgm10-contours-5m-anaglyph-red-624x441.png 624w\" sizes=\"auto, (max-width: 806px) 100vw, 806px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">For the right, cyan side we need to add another Geometry Generator symbol layer, color it in cyan (so that you can only see it through your left eye) and do the geometry expression the other way around:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">translate(\n  $geometry,\n  (\n    x(centroid($geometry))-x_min(@map_extent)\n  )\n  \/100  -- magic scale value\u2026\n  ,\n  0  -- no translation in y\n)<\/pre>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"806\" height=\"570\" src=\"https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-dgm10-contours-5m-anaglyph-redcyan-1.png\" alt=\"\" class=\"wp-image-1288\" srcset=\"https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-dgm10-contours-5m-anaglyph-redcyan-1.png 806w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-dgm10-contours-5m-anaglyph-redcyan-1-300x212.png 300w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-dgm10-contours-5m-anaglyph-redcyan-1-768x543.png 768w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-dgm10-contours-5m-anaglyph-redcyan-1-624x441.png 624w\" sizes=\"auto, (max-width: 806px) 100vw, 806px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Cool! But this is lacking a certain depth, don&#8217;t you think? We need to scale the amount of horizontal shift by the elevation value of the contour lines. And then we also need to adjust the magic scale value again because reasons.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For the red symbol layer:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">translate(\n  $geometry,\n  -- move to the LEFT\n  -- scaled by the distance to the RIGHT side of the map\n  -- scaled by the elevation\n\n  -- minus so it goes to the left\n  -\n  \"ELEV\" -- the attribute field with the elevation values\n  *\n  (x_max(@map_extent)-x(centroid($geometry)))\n  \n  -- MAGIC scale value according to CRS and whatever\n  \/10000\n  ,\n  -- no change for y\n  0\n)<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For the cyan symbol layer:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">translate(\n  $geometry,\n  -- move to the RIGHT\n  -- scaled by the distance to the LEFT side of the map\n  -- scaled by the elevation\n \n  \"ELEV\" -- the attribute field with the elevation values\n  *\n  (x(centroid($geometry))-x_min(@map_extent))\n  \n  -- MAGIC scale value according to CRS and whatever\n  \/10000\n  ,\n  -- no change for y\n  0\n)<\/pre>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"806\" height=\"570\" src=\"https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-dgm10-contours-5m-anaglyph-redcyan-elev.png\" alt=\"\" class=\"wp-image-1292\" srcset=\"https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-dgm10-contours-5m-anaglyph-redcyan-elev.png 806w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-dgm10-contours-5m-anaglyph-redcyan-elev-300x212.png 300w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-dgm10-contours-5m-anaglyph-redcyan-elev-768x543.png 768w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-dgm10-contours-5m-anaglyph-redcyan-elev-624x441.png 624w\" sizes=\"auto, (max-width: 806px) 100vw, 806px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">That&#8217;s it!<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"748\" src=\"https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/harz.png\" alt=\"\" class=\"wp-image-1294\" srcset=\"https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/harz.png 800w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/harz-300x281.png 300w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/harz-768x718.png 768w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/harz-624x583.png 624w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"480\" src=\"https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/alpen.png\" alt=\"\" class=\"wp-image-1295\" srcset=\"https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/alpen.png 800w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/alpen-300x180.png 300w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/alpen-768x461.png 768w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/alpen-624x374.png 624w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"799\" height=\"420\" src=\"https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-points.png\" alt=\"\" class=\"wp-image-1297\" srcset=\"https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-points.png 799w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-points-300x158.png 300w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-points-768x404.png 768w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/blankenese-points-624x328.png 624w\" sizes=\"auto, (max-width: 799px) 100vw, 799px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"400\" src=\"https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/harburg.png\" alt=\"\" class=\"wp-image-1293\" srcset=\"https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/harburg.png 800w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/harburg-300x150.png 300w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/harburg-768x384.png 768w, https:\/\/hannes.enjoys.it\/blog\/wp-content\/uploads\/harburg-624x312.png 624w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Now, who is going to do <a href=\"https:\/\/en.wikipedia.org\/wiki\/Autostereogram\">Autostereograms<\/a>? Also check out <a href=\"http:\/\/elasticterrain.xyz\"><a href=\"http:\/\/elasticterrain.xyz\">http:\/\/elasticterrain.xyz<\/a><\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A slight misunderstanding about a weird pattern I posted to Twitter earlier made me wonder how easy it might be to present elevation data with real depth &#8482; as anaglyph 3D in QGIS. Anaglyph 3D, you know, those red and cyan glasses that rarely ever worked. You might remember my post on fake chromatic aberration [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9,31],"tags":[],"class_list":["post-1277","post","type-post","status-publish","format-standard","hentry","category-cartography","category-qgis"],"_links":{"self":[{"href":"https:\/\/hannes.enjoys.it\/blog\/wp-json\/wp\/v2\/posts\/1277","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hannes.enjoys.it\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hannes.enjoys.it\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hannes.enjoys.it\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/hannes.enjoys.it\/blog\/wp-json\/wp\/v2\/comments?post=1277"}],"version-history":[{"count":7,"href":"https:\/\/hannes.enjoys.it\/blog\/wp-json\/wp\/v2\/posts\/1277\/revisions"}],"predecessor-version":[{"id":1298,"href":"https:\/\/hannes.enjoys.it\/blog\/wp-json\/wp\/v2\/posts\/1277\/revisions\/1298"}],"wp:attachment":[{"href":"https:\/\/hannes.enjoys.it\/blog\/wp-json\/wp\/v2\/media?parent=1277"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hannes.enjoys.it\/blog\/wp-json\/wp\/v2\/categories?post=1277"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hannes.enjoys.it\/blog\/wp-json\/wp\/v2\/tags?post=1277"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}