dcooley / sfheaders

Build sf objects from R and Rcpp
https://dcooley.github.io/sfheaders/
Other
74 stars 5 forks source link

Create linestring without Z or M dimension #86

Closed agila5 closed 4 years ago

agila5 commented 4 years ago

Hi! First of all, thank you very much for working on this package, it's extremely useful.

I created this github issue since I have a question related to sfc_linestring function. Is it possible to define a new object without Z or M dimensions? For example:

# packages
library(sf)
#> Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1
library(sfheaders)

# create data
fake_data <- data.frame(
  x = rnorm(10), 
  y = rnorm(10), 
  ID = rep(c("A", "B"), each = 5)
)

fake_linestring <- sfc_linestring(fake_data, linestring_id = "ID")
fake_linestring
#> Geometry set for 2 features 
#> geometry type:  LINESTRING
#> dimension:      XY
#> bbox:           xmin: -2.316161 ymin: -1.11913 xmax: 1.734445 ymax: 1.06014
#> z_range:        zmin: NA zmax: NA
#> m_range:        mmin: NA mmax: NA
#> CRS:            NA
#> LINESTRING (0.4392517 0.3996995, -0.03385222 -0...
#> LINESTRING (0.4234799 -0.8409173, -0.3708309 -1...

Created on 2020-11-13 by the reprex package (v0.3.0)

I know that I can use st_zm after creating the object, but I would like to skip that step if possible. Thanks!

dcooley commented 4 years ago

Your example doesn't have Z or M dimensions. Or have I misunderstood your question?


Or are you referring to the z_range and m_range attributes? If so, this may be of interest

agila5 commented 4 years ago

Hi! I could have written the questions much better, but I was referring to the fact that the output object has a z_range and a m_range attribute (both c(NA, NA)) even if the input object doesn't have Z or M dimension. Hence, I was wondering if it's possible to create an object without z_range or m_range.

Or are you referring to the z_range and m_range attributes? If so, this may be of interest

I'm not 100% sure but, after reading that GH issue, I think that I could simply remove the z_range and m_range attributes, is that right?

dcooley commented 4 years ago

Yes that should still work for you

attr( fake_linestring, "z_range" ) <- NULL
attr( fake_linestring, "m_range" ) <- NULL

fake_linestring

# Geometry set for 2 features 
# geometry type:  LINESTRING
# dimension:      XY
# bbox:           xmin: -2.772747 ymin: -1.044071 xmax: 2.672171 ymax: 1.966581
# CRS:            NA
# LINESTRING (0.4554192 -0.05182977, -0.35838 1.9...
# LINESTRING (0.5933351 0.5489179, 0.8940883 -0.5...

But may I ask why you don't want those attributes?

Perhaps we could consider only adding them as attributes ONLY IF the Z and / or M dimensions exist.

ping @edzer - do you have any thoughts on updating the sfc object to only include z_range and m_range IFF they explictily are not NA ?

edzer commented 4 years ago

Isn't that the case right now?

> library(sf)
Linking to GEOS 3.8.1, GDAL 3.1.3, PROJ 7.1.1
> p = st_sfc(st_point(0:1))
> attributes(p)
$class
[1] "sfc_POINT" "sfc"      

$precision
[1] 0

$bbox
xmin ymin xmax ymax 
   0    1    0    1 

$crs
Coordinate Reference System: NA

$n_empty
[1] 0

> p = st_sfc(st_point(0:2))
> attributes(p)
$class
[1] "sfc_POINT" "sfc"      

$precision
[1] 0

$bbox
xmin ymin xmax ymax 
   0    1    0    1 

$z_range
zmin zmax 
   2    2 

$crs
Coordinate Reference System: NA

$n_empty
[1] 0

> p = st_sfc(st_point(0:3))
> attributes(p)
$class
[1] "sfc_POINT" "sfc"      

$precision
[1] 0

$bbox
xmin ymin xmax ymax 
   0    1    0    1 

$z_range
zmin zmax 
   2    2 

$m_range
mmin mmax 
   3    3 

$crs
Coordinate Reference System: NA

$n_empty
[1] 0
dcooley commented 4 years ago

oh yeah - you're absolutely right - thanks for clarifying.

Then I think, @agila5, I need to udpate sfheaders to align with this behaviour. So I'll get working on it.

dcooley commented 4 years ago

@agila5 in the development version you should now see this behaviour


remotes::install_github("dcooley/sfheaders")

library(sf)
#> Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1
library(sfheaders)

# create data
fake_data <- data.frame(
  x = rnorm(10), 
  y = rnorm(10), 
  ID = rep(c("A", "B"), each = 5)
)

# fake_linestring <- sfc_linestring(fake_data, linestring_id = "ID")
# fake_linestring
# Geometry set for 2 features 
# geometry type:  LINESTRING
# dimension:      XY
# bbox:           xmin: -2.67091 ymin: -2.172776 xmax: 1.768129 ymax: 2.043167
# CRS:            NA
# LINESTRING (-2.67091 -2.172776, 1.768129 0.4822...
# LINESTRING (1.11033 -0.9021552, 0.766239 0.2187...
agila5 commented 4 years ago

Thank you very much, it works perfectly.

But may I ask why you don't want those attributes?

I created an algorithm to modify LINESTRING data obtained from Open Street Map (see here if you want to read more details) and it didn't feel natural to return an XY object with missing Z/M range that will always be missing since the input data doesn't have Z or M dimensions.

dcooley commented 4 years ago

I see there's a lot going on in there!

If it helps in any way you might find sfheaders::sf_cast() functions quicker than the sf::st_cast() equivalent, and I also have sfheaders::sf_to_df() which is faster for non-point objects as Robin and I found out

agila5 commented 4 years ago

Thanks for the suggestions! That's only the first draft for the new function, I hope I will revise it in a few days since sfheaders::sf_cast() and sfheaders::sf_to_df() could be useful in the line -> points conversion.