2

I need to triangulate fire observation bearings from multiple fire towers or points at known locations.

The towers are known points on the map. Fire patrol officers may also provide an observation from a known point. The observer provides a bearing on the fire and a distance estimate. The distance is not that important if I have a bearing from another observer.

I want to draw a line on the bearing from each observation point (obviously the fire towers are fixed points on my map) to ascertain the position of the fire.

The feature I require is to draw the line on the bearing and keep it on the map so I can draw the bearing from the other tower or observer. It would be good if I could then save that for future reference (evidence). How do I do this in QGIS?

6
  • Do you have a table (for example excel) with bearing and observation coordinates? The coordinates are in lat, long?
    – Bera
    Commented Dec 11, 2023 at 7:32
  • 2
    Sounds straightforward enough but the details mostly depend on the format of your data. I'd suggest you share a sample. Commented Dec 11, 2023 at 11:36
  • 1
    This help? gis.stackexchange.com/questions/447021/…
    – John
    Commented Dec 11, 2023 at 14:16
  • Tower 1 is at following coodinate GDA94, MGA Zone 55478639,5276640
    – Forestaus
    Commented Dec 12, 2023 at 0:28
  • Tower 2 is at GDA94, MGA Zone 55 496927,5256292
    – Forestaus
    Commented Dec 12, 2023 at 0:29

1 Answer 1

8

A stepwise approach to get the coordinates. First I show how to create the lines, and afterwards how to get the coordinates of the points where they cross. To imitate a real-world example, the lines do not cross exactly at the same point.

Final stage: a medium point (probable fire location) with mean coordinates is created, based on all the bearings (black/red dotted lines) from the fire stations (blue points):

enter image description here

And here is your use case with the two coordinates in EPSG:28355 and bearings you provided; instead of field name distance, I used a reasonable value of 25000 [m] instead. The red dot shows the (probable) location of the fire:

enter image description here


1. Create lines from Towers

First, use the following expression to create lines from the fire towers, based on attribute fields distance and bearing:

make_line (
    $geometry, 
    project (
        $geometry,
        distance,
        radians (bearing)
    )
)

Here you can see the black line, created with the expression above. The red dotted line is an extended version of the line, using the function extend(), to get an intersection with the other lines even if one of the lines is too short:

enter image description here


2. Create crossing points

In a second step, create the points where the line from one fire tower crosses the lines of the other fire towers, using this expression:

collect_geometries(
    array_foreach (
        overlay_nearest (
            @layer,
            extend (
                make_line (
                    $geometry, 
                    project ($geometry, distance,radians (bearing))
                ), 
                0,
                1000
            ),
            limit:=9 -- max number of towers to consider
        ),
        intersection (
            extend (
                make_line (
                    $geometry, 
                    project ($geometry, distance,radians (bearing))
                ), 
                0,
                1000
            ),
            @element
        )
    )
)

Red points = possible fire locations, created with the expression above: enter image description here


3. Calculate coordinates

Third step: get the coordinates of the intersection points using the following expression. the coordinates are automatically converted from the layer CRS used to WGS84 (lat/lon) coordinates:

array_to_string (
    array_foreach (
        overlay_nearest (
            @layer,
            extend (
                make_line (
                    $geometry, 
                    project ($geometry, distance, radians (bearing))
                ), 
                0,
                1000
            ),
            limit:=10 -- max number of neighboring points to consider
        ),
        with_variable(
            'fire',
            transform (
                intersection (
                    extend (
                        make_line (
                            $geometry, 
                            project ($geometry, distance, radians (bearing))
                        ),
                        0,
                        1000
                    ),
                    @element
                ),
                @layer_crs,
                'EPSG:4326'
            ),
            round (x(@fire),5)  || ';'  ||  round (y(@fire),5)  -- coordinates rounded to 5 decimals
        )
    )
)

Lat/Lon coordinate values created with the expression:

enter image description here


4. Create the point with the mean coordinates

To automatically create the mean coordinates of all the crossing points from each fire tower (and thus the most probable point where the fire is), use this expression:

with_variable(
    'create_coord',
    '
    array_mean (
        array_agg (
            array_mean(
                array_foreach (
                    overlay_nearest (
                        @layer,
                        extend (
                            make_line (
                                $geometry, 
                                project ($geometry, distance, radians (bearing))
                            ), 
                            0,
                            1000
                        ),
                        limit:=10 -- max number of neighboring points to consider
                    ),
                    with_variable(
                        ''fire'',
                        transform (
                            intersection (
                                extend (
                                    make_line (
                                        $geometry, 
                                        project ($geometry, distance, radians (bearing))
                                    ),
                                    0,
                                    1000
                                ),
                                @element
                            ),
                            @layer_crs,
                            ''EPSG:4326''
                        ),
                        ll(@fire)  
                    )
                ))))
    ',
    eval(replace (@create_coord,'ll','x'))  || ';'  || eval(replace (@create_coord,'ll','y')))

Creating the point with the mean coordinates of all the intersection points (red dot, expression below) and the coordinate values with the expression above:

enter image description here

To create the red dot with the mean coordinates:

with_variable(
    'create_coord',
    '
    array_mean (
        array_agg (
            array_mean(
                array_foreach (
                    overlay_nearest (
                        @layer,
                        extend (
                            make_line (
                                $geometry, 
                                project ($geometry, distance, radians (bearing))
                            ), 
                            0,
                            1000
                        ),
                        limit:=10 -- max number of neighboring points to consider
                    ),
                    with_variable(
                        ''fire'',
                        transform (
                            intersection (
                                extend (
                                    make_line (
                                        $geometry, 
                                        project ($geometry, distance, radians (bearing))
                                    ),
                                    0,
                                    1000
                                ),
                                @element
                            ),
                            @layer_crs,
                            ''EPSG:4326''
                        ),
                        latlon(@fire)  
                    )
                ))))
    ',
    transform (
        make_point (
            eval(replace (@create_coord,'latlon','x')) , 
            eval(replace (@create_coord,'latlon','y'))
        ),
        'EPSG:4326',
        @layer_crs
    )
)
1
  • 3
    Such an impressive answer. Thank you :)
    – Taras
    Commented Dec 17, 2023 at 8:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.