/
sfheaders.Rmd
191 lines (127 loc) · 4.41 KB
/
sfheaders.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
---
title: "sfheaders"
output: html_document
editor_options:
chunk_output_type: console
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
```{r sfheaers-setup}
## Detatch {sf} to remove 'print' methods
## because I want to show the underlying structure
##
## library(sf) will be called later
pkgload::unload("sf")
```
The design philosophy of `{sfheaders}` is to
1. **build** `{sf}` objects from vectors, matrices and data.frames
- without depending on the `{sf}` library
2. **expose** all C++ code through header files (hence the name, `sfheaders`)
It's intended that every operation you can do in R, you can also do in C++. I anticipate 99% of users will only need the R functions. But the C++ header files are there if you are building your own package with C++ code and would like to build `{sf}` objects directly in C++.
This package is not directly affiliated with the `{sf}` library, but every effort is made to keep it aligned and create valid `sf` objects.
## Building sf objects in R
The simplest use-case for `{sfheaders}` is best demonstrated with examples of building `sfg`, `sfc` and `sf` objects.
### Simple Feature Geometry - sfg
Here are examples showing
- a vector converted to `sfg_POINT`
- a matrix converted to `sfg_LINESTRING`
- a data.frame converted to `sfg_POLYGON`
```{r sfheaders-sfg_point}
v = c(1,1)
sfheaders::sfg_point(obj = v)
```
```{r sfheaders-sfg_linestring}
n = 8
m = matrix(1:n, ncol = 2)
sfheaders::sfg_linestring(obj = m)
```
```{r sfheaders-sfg_polygon}
n = 4
df = data.frame(
x = 1:n
, y = n:1
)
sfheaders::sfg_polygon(obj = df)
```
In these examples I have deliberately not used the print methods that come with the `{sf}` library, to show you the underlying structures of the objects. If I now load `{sf}`
```{r sfheaders-library-sf}
library(sf)
```
and create the `sfg_POLYGON` again, you'll see it's printed to the console as a regular `{sf}` object
```{r sfheaders-sfg_polygon_print}
sfheaders::sfg_polygon(obj = df)
```
### Simple Feature Collections - sfc
Reusing the objects `v`, `m`, and `df` we can also build `sfc` objects
```{r sfheaders-sfc_point}
sfheaders::sfc_point(obj = v)
```
```{r sfheaders-sfc_linestring}
sfheaders::sfc_linestring(obj = m)
```
```{r sfheaders-sfc_polygon}
sfheaders::sfc_polygon(obj = df)
```
### Simple Features - sf
And similarly, `sf` objects
```{r sfheaders-sfc_point}
sfheaders::sf_point(obj = v)
```
```{r sfheaders-sfc_linestring}
sfheaders::sf_linestring(obj = m)
```
```{r sfheaders-sfc_polygon}
sfheaders::sf_polygon(obj = df)
```
In each of these examples you'll notices the CRS (coordinate reference system) is not defined. If you plan on doing any calculations or geometric operations using `{sf}` functions you'll need to set this manually, for example
```{r sfheaders-crs}
sf <- sfheaders::sfg_polygon(obj = df)
sf::st_crs(sf) <- 4326 ## Web Mecarter (long/lat)
```
## Building sf objects in C++
To use the C++ API you need to link to both the `{sfheaders}` and `{geometries}` libraries.
If you're building a package you define these links in the `LinkingTo` section of the `DESCRIPTION` file. For example, this is the `LinkingTo` section of the [`{geojsonsf}`](https://github.com/SymbolixAU/geojsonsf/blob/master/DESCRIPTION) library.
```
LinkingTo:
geometries,
jsonify (>= 1.1.1),
rapidjsonr (>= 1.2.0),
Rcpp,
sfheaders (>= 0.2.2)
```
Now all the C++ headers in `{sfheaders}` will be available in your package, just define them as `#include` statements at the top of your code and away you go.
Here are the same examples as before, showing
- a vector converted to `sfg_POINT`
- a matrix converted to `sfg_LINESTRING`
- a data.frame converted to `sfg_POLYGON`
but written as C++ (through Rcpp)
```c++
#include "sfheaders/sfg/point/sfg_point.hpp"
#include "sfheaders/sfg/linestring/sfg_linestring.hpp"
#include "sfheaders/sfg/polygon/sfg_polygon.hpp"
//' Create Point
//'
//' builds an sfg_point object from a valid SEXP type
//'
//' [[Rcpp::export]]
SEXP create_point(SEXP x) {
return sfheaders::sfg::sfg_point( x );
}
//' Create Linestring
//'
//' builds an sfg_linestring object from a vaild SEXP type
//'
//' [[Rcpp::export]]
SEXP create_linestring(SEXP x) {
return sfheaders::sfg::sfg_linestring( x );
}
//' Create Polygon
//'
//' builds an sfg_polygon object from a vaild SEXP type
//'
//' [[Rcpp::export]]
SEXP create_polygon(SEXP x) {
return sfheaders::sfg::sfg_polygon( x );
}
```