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

functionpurpose in expression
containsTo check that one geometry is within another
bufferTo buffer the navaid geometry in order to use whitin the contain function
transformTo change from WGS84 to a projected coordinates system set in the map canvas appropriate for the area
aggregateI 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

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'

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.



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 @
valueThe value to set
This is the value the expression will replace the name for when it evaluates
expressionThe 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

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'

At the end this is how it looks, hopefully it provides some useful information for this and other cases


Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *