Sometimes when we are working with maps we get symbols that overlap and we need to figure out a way to be able to show both symbols if that is a requirement, in this case I will offset the symbol based on an expression to figure out if it is within a certain distance from the other symbol which in this case are in two different layers, one which is for airports/heliports and the other which is used for the ground based navigation aids used by aircraft.
In QGIS we can apply an offset to symbols but in that case it will apply the offset to all the symbols irrespective if this is actually required or not
In this case we really want to be sure only those symbols which may overlap are to be moved, so what we can do is to use an expression instead, for this particular case I used the following expression, since my data is in WGS84 I need to do a transformation from that to a projected coordinate system in order to apply a distance which I wanted it to be 2.5 Nautical Miles. There needs to be a transformation from 2.5 NM to the projection units which is meters that is why the value is multiplied by 1852
In this expression we are going to use the following functions
function | purpose in expression |
contains | To check that one geometry is within another |
buffer | To buffer the navaid geometry in order to use whitin the contain function |
transform | To change from WGS84 to a projected coordinates system set in the map canvas appropriate for the area |
aggregate | I have found that with this function you can access geometries of a second layer, do not know if this is the best way but it works. I will use this to get the airport layer and then check against the navaid layer |
CASE WHEN
contains(buffer(transform(aggregate(layer:='AirportHeliport_cdb14b2e_594a_4432_be9e_a0f6ba88440e', aggregate:='collect', expression:=$geometry),@wgs, @project_crs ),2.5*1852),transform($geometry,@wgs,@project_crs))
THEN '-1,1'
ELSE '0.0,0.0'
END
The case when the expression is true (buffer of the airport contains the navaid) will then cause a displacement of the navaid symbol by -1,1 (x,y), if not there will be no displacement. Notice that in the expression above there are some repetitive values and this could get a bit cumbersome if it needs to provide a more complex transformation, an alternative to that is to use with_variable option.
with_variable(name,value,expression)
Explanation
Arguments | Explanation |
name | The name of the variable to set This is the name you will use in your expression to call any value set, in my tests it accepts either strings or numbers although probably would be a better idea to stick to strings. Also when you use it in the expression it will normally be used with @ before the name but I also tested and name works when in quotes without needing to add @. Seems there is no check on this to prevent not using @ |
value | The value to set This is the value the expression will replace the name for when it evaluates |
expression | The expression for which the variable will be available You can write any expression you like here and include the name of your variable to be used |
Same expression but now using the variables which can allow to change the value of that particular variable just once at the start instead of scanning the expression to possible locations
with_variable('wgs','EPSG:4326',
CASE WHEN
contains(buffer(transform(aggregate(layer:='AirportHeliport_cdb14b2e_594a_4432_be9e_a0f6ba88440e', aggregate:='collect', expression:=$geometry),@wgs, @project_crs ),2.5*1852),transform($geometry,@wgs,@project_crs))
THEN '-1,1'
ELSE '0.0,0.0'
END
)
At the end this is how it looks, hopefully it provides some useful information for this and other cases
0 Comments