Home > other >  How do I calculate the true length of a set of sf line segments that contains elevation values?
How do I calculate the true length of a set of sf line segments that contains elevation values?

Time:06-01

I'm trying to calculate the true length of each multilinestring that contains elevation data.

Here's my code:

library(sf)
#Linking to GEOS 3.10.2, GDAL 3.4.2, PROJ 9.0.0; sf_use_s2() is TRUE

# Data creation
s1 <- st_multilinestring(list(rbind(c(0,3,1), c(0,4,1))))
s2 <- st_multilinestring(list(rbind(c(0,4,1), c(1,5,4))))
s3 <- st_multilinestring(list(rbind(c(1,5,4), c(2,5,6))))
s4 <- st_multilinestring(list(rbind(c(2,5,6), c(2.5,5,12))))
s5 <- st_multilinestring(list(rbind(c(2.5,5,12), c(4,7,4))))
s6 <- st_multilinestring(list(rbind(c(4,7,4), c(4.5,7,3))))
s7 <- st_multilinestring(list(rbind(c(4.5,7,3), c(5,7,3))))

sf_ml <- st_sf(section = 1,
               geometry=st_sfc(list(s1,s2,s3,s4,s5,s6,s7)),
               crs = 4326)
plot(sf_ml)

plot(sf_ml

However, when using the st_length() it prompts that it is dropping the Z coordinate. Thus, I'm thinking that it is not using the elevation values.

st_length(sf_ml)
# st_as_s2(): dropping Z and/or M coordinate
#Units: [m]
#[1] 111195.10 157010.41 110771.96  55385.98 277435.26  55183.13  55183.13

And if I don't use S2, I'm getting a different set of values.

sf_use_s2(F)
#Spherical geometry (s2) switched off

st_length(sf_ml)
#Units: [m]
#[1] 110578.44 156665.64 110898.70  55449.35 276575.59  55247.61  55247.61

If I don't use S2, does st_length() make use of the elevation values? Or am I using the wrong R package for this?

Thanks in advance.

CodePudding user response:

The st_length calculation does use the Z values when working with lat-long data.

Let's create a single feature that is 1m along and 1m up. I'll do this in a UK projected system and convert to lat-long in a bit.

> g1 = st_multilinestring(list(rbind(c(0,1,2),c(0,2,3))))
> sd = st_sf(geometry=st_sfc(g1), crs=27700)

st_length ignores the Z, silently, and gives a 1m length:

> st_length(sd)
1 [m]

This is independent of s2 status, of course, because we are in a cartesian coordinate system:

> sf_use_s2(TRUE)
> st_length(sd)
1 [m]
> sf_use_s2(FALSE)
Spherical geometry (s2) switched off
> st_length(sd)
1 [m]

Now transform to 4326 and see:

> sdg = st_transform(sd, 4326)
> sf_use_s2(TRUE)
Spherical geometry (s2) switched on
> st_length(sdg)
st_as_s2(): dropping Z and/or M coordinate
0.9981138 [m]

This has dropped the Z and returned a distance a bit less than 1m because of the transformation. Now without s2:

> sf_use_s2(FALSE)
Spherical geometry (s2) switched off
> st_length(sdg)
1.413078 [m]

This is approximately sqrt(2), which is the 3d distance including the Z of this line - but there must have been some conversion back to meters to return a distance of meters (and treat the Z coord as being in meters). This is mentioned in the details of ?st_length and will be using a spherical distance - maybe it computes that for the X-Y distance and then combines with the Z distance via Pythagoras theorem.

So I conclude by observation:

  • For projected cartesian coordinates, st_length silently ignores Z
  • For lat-long coordinates with s2 enabled, st_length noisily drops Z
  • For lat-long coordinates with s2 disables, st_length computes 3d distance using Z
  •  Tags:  
  • r sf
  • Related