@@ -146,6 +146,216 @@ Example: [`odjitter`](https://github.com/dabreegster/odjitter/blob/98a7a6e03bc54
146146 res = sf :: read_sf(output_path )
147147```
148148
149+ ## Loose coupling
150+
151+ Example: [ ` qgisprocess ` R package] ( https://github.com/r-spatial/qgisprocess/blob/702358e5849b38a9ce8550ee0f8b465c902d59d4/R/qgis-run.R#L26-L53 )
152+
153+ ``` r
154+ qgis_run <- function (args = character (), ... , env = qgis_env(), path = qgis_path()) {
155+ if (is.null(path )) {
156+ message(
157+ " The filepath of 'qgis_process' is not present in the package cache, " ,
158+ " so the package is not well configured.\n " ,
159+ " Restart R and reload the package; run `qgis_configure()` if needed.\n " ,
160+ " For now, will try to fix it on the fly, but some functionality may not work.\n "
161+ )
162+ path <- qgis_path(query = TRUE , quiet = FALSE )
163+ # typically the version will also be missing, so fixing that as well:
164+ if (is.null(qgisprocess_cache $ version )) {
165+ invisible (qgis_version(query = TRUE , quiet = FALSE ))
166+ }
167+ }
168+ # workaround for running Windows batch files where arguments have spaces
169+ # see https://github.com/r-lib/processx/issues/301
170+ if (is_windows()) {
171+ withr :: with_envvar(
172+ env ,
173+ processx :: run(" cmd.exe" , c(" /c" , " call" , path , args ), ... ),
174+ )
175+ } else {
176+ withr :: with_envvar(
177+ env ,
178+ processx :: run(path , args , ... )
179+ )
180+ }
181+ }
182+ ```
183+
184+ ## Tight coupling 1
185+
186+ Source: [ ` geoarrow-c ` ] ( https://github.com/geoarrow/geoarrow-c/blob/main/python/geoarrow-c/src/geoarrow/c/_lib.pyx#L1-L22 )
187+
188+ ``` py
189+
190+
191+ # cython: language_level = 3
192+ # cython: linetrace=True
193+
194+
195+ """ Low-level geoarrow Python bindings."""
196+
197+
198+ from libc.stdint cimport uint8_t, int32_t, int64_t, uintptr_t
199+ from cpython cimport Py_buffer, PyObject
200+ from libcpp cimport bool
201+ from libcpp.string cimport string
202+
203+
204+ cdef extern from " geoarrow_type.h" :
205+ struct ArrowSchema:
206+ const char* format
207+ const char* name
208+ const char* metadata
209+ int64_t flags
210+ int64_t n_children
211+ ArrowSchema** children
212+ ArrowSchema* dictionary
213+ void (* release)(ArrowSchema* )
214+ void* private_data
215+ ```
216+
217+ ## Tight coupling 2
218+
219+ Source: [ ` geoarrow-rs ` ] ( https://github.com/geoarrow/geoarrow-rs/blob/db06a8bf4b591b38fc164c29be86c630108751f6/python/pyo3-geoarrow/src/data_type.rs#L1-L29 )
220+
221+ ``` rust
222+ use crate :: error :: {PyGeoArrowError , PyGeoArrowResult };
223+ use crate :: {PyCoordType , PyDimension };
224+
225+
226+ use geoarrow :: array :: CoordType ;
227+ use geoarrow :: datatypes :: {Dimension , GeoDataType };
228+ use pyo3 :: exceptions :: PyValueError ;
229+ use pyo3 :: intern;
230+ use pyo3 :: prelude :: * ;
231+ use pyo3 :: types :: {PyCapsule , PyType };
232+ use pyo3_arrow :: ffi :: to_schema_pycapsule;
233+ use pyo3_arrow :: PyField ;
234+
235+
236+ #[pyclass(module = " geoarrow.rust.core._rust" , name = " GeometryType" , subclass)]
237+ pub struct PyGeometryType (pub (crate ) GeoDataType );
238+
239+
240+ impl PyGeometryType {
241+ pub fn new (data_type : GeoDataType ) -> Self {
242+ Self (data_type )
243+ }
244+
245+
246+ /// Import from a raw Arrow C Schema capsules
247+ pub fn from_arrow_pycapsule (capsule : & Bound <PyCapsule >) -> PyGeoArrowResult <Self > {
248+ PyField :: from_arrow_pycapsule (capsule )? . try_into ()
249+ }
250+
251+
252+ pub fn into_inner (self ) -> GeoDataType {
253+ self . 0
254+ }
255+ }
256+ ```
257+
258+ ## Tight coupling 3
259+
260+ Source: [ ` RcppExports.R ` in ` sf ` ] ( https://github.com/r-spatial/sf/blob/35f5f8be44e1923d242a489b51d7c58b8397a2a9/R/RcppExports.R#L212-L218 )
261+
262+ ``` r
263+ CPL_geos_union <- function (sfc , by_feature = FALSE , is_coverage = FALSE ) {
264+ .Call(`_sf_CPL_geos_union` , sfc , by_feature , is_coverage )
265+ }
266+
267+
268+ CPL_geos_snap <- function (sfc0 , sfc1 , tolerance ) {
269+ .Call(`_sf_CPL_geos_snap` , sfc0 , sfc1 , tolerance )
270+ }
271+ ```
272+
273+ ## Tight coupling 4
274+
275+ <!-- https://github.com/paleolimbot/geos/blob/HEAD/R/geos-unary-geometry.R#L153-L169 -->
276+
277+ Source: [ ` geos-unary-geometry.R ` in ` geos ` ] ( https://github.com/paleolimbot/geos/blob/HEAD/R/geos-unary-geometry.R#L153-L169 )
278+
279+ ``` r
280+ # ' @rdname geos_centroid
281+ # ' @export
282+ geos_unary_union <- function (geom ) {
283+ geom <- sanitize_geos_geometry(geom )
284+ new_geos_geometry(.Call(geos_c_unary_union , geom ), crs = attr(geom , " crs" , exact = TRUE ))
285+ }
286+
287+
288+ # ' @rdname geos_centroid
289+ # ' @export
290+ geos_unary_union_prec <- function (geom , grid_size ) {
291+ geom <- sanitize_geos_geometry(geom )
292+ recycled <- recycle_common(list (geom , sanitize_double(grid_size )))
293+ new_geos_geometry(
294+ .Call(geos_c_unary_union_prec , recycled [[1 ]], recycled [[2 ]]),
295+ crs = attr(geom , " crs" , exact = TRUE )
296+ )
297+ }
298+ ```
299+
300+ ## Tight coupling 5
301+
302+ <!-- https://github.com/JuliaGeo/LibGEOS.jl/blob/91f69c04843f02a995c5df54b0186891534a2ef4/src/geos_functions.jl#L712-L726 -->
303+
304+ Source: [ ` geos_functions.jl ` in ` LibGEOS.jl ` ] ( https://github.com/JuliaGeo/LibGEOS.jl/blob/91f69c04843f02a995c5df54b0186891534a2ef4/src/geos_functions.jl#L712-L726 )
305+
306+ ``` julia
307+ function union (obj1:: Geometry , obj2:: Geometry , context:: GEOSContext = get_context (obj1))
308+ result = GEOSUnion_r (context, obj1, obj2)
309+ if result == C_NULL
310+ error (" LibGEOS: Error in GEOSUnion" )
311+ end
312+ geomFromGEOS (result, context)
313+ end
314+
315+
316+ function unaryUnion (obj:: Geometry , context:: GEOSContext = get_context (obj))
317+ result = GEOSUnaryUnion_r (context, obj)
318+ if result == C_NULL
319+ error (" LibGEOS: Error in GEOSUnaryUnion" )
320+ end
321+ geomFromGEOS (result, context)
322+ end
323+ ```
324+
325+ ## Project environments
326+
327+ ``` bash
328+ pixi init test-project --format pyproject
329+ ```
330+
331+ ```
332+ ✔ Initialized project in ~/test-project
333+ ```
334+
335+ ``` bash
336+ cd test-project
337+ pixi add geopandas
338+ pixi add --pypi --feature test pytest
339+ pixi install
340+ ```
341+
342+ ```
343+ ✔ Added pytest
344+ Added these as pypi-dependencies.
345+ Added these only for feature: test
346+ ```
347+
348+ Cross-language support (source: [ pixi.sh] ( https://pixi.sh/latest/ide_integration/r_studio/ ) )
349+
350+ ``` bash
351+ pixi add r-ggplot2
352+ ```
353+ Although some issues according to my tests (see [ prefix-dev/pixi #2066 ] ( https://github.com/prefix-dev/pixi/issues/2066 ) )
354+
355+ ## Containerisation
356+
357+
358+
149359
150360# Publishing
151361
0 commit comments