busstoptaktik / geodesy

Rust geodesy
Apache License 2.0
66 stars 6 forks source link

Help with Coordinate Conversion in Rust Geodesy (RG) #119

Closed pbroboto closed 1 month ago

pbroboto commented 1 month ago

Hi,

I’m a beginner in Rust and currently exploring Rust Geodesy (RG). I have some prior experience using PROJ via Pyproj and have worked on Android projects using Dart/Flutter with my compiled PROJ source for ARM architecture. Now, I’m testing a few pieces of Rust code and could use your help.

Here’s my code:

use geodesy::prelude::*;

fn main() -> Result<(), Box<Error>> {
    let mut context = Minimal::new();
    let tm100_7 = context.op("tmerc lon_0=100.7 lat_0=0 k_0=1.0 x_0=500000 y_0=0 ellps=WGS84")?;
    let ne1 = Coor2D::raw(501261.22032610676, 1521088.326792507);
    let ne2 = Coor2D::raw(499315.16759512835, 1685050.54257971);
    let mut coor = [ne1, ne2];
    context.apply(tm100_7, Inv, &mut coor)?;
    println!("{:#?}", coor);
    Ok(())
}

The result will output:


[
    Coor2D(
        [
            1.7577500966210504,
            0.2400462188897853,
        ],
    ),
    Coor2D(
        [
            1.7574352994459437,
            0.26591009639328894,
        ],
    ),
]```
I expected to get the result in degree  but I got it in radians and not like the RG example. What I doing wrong? Please suggest me. Thanks.
pbroboto commented 1 month ago

Apologies for my previous confusion—I didn’t fully read the documentation. I managed to solve the issue by using the geo:in parameter in the transformation definition. Here’s the working code:

use geodesy::prelude::*;

fn main() -> Result<(), Box<Error>> {
    let mut context = Minimal::new();
    let tm100_7 = context.op("geo:in | tmerc lon_0=100.7 lat_0=0 k_0=1.0 x_0=500000 y_0=0 ellps=WGS84")?;
    let ne1 = Coor2D::raw(501261.22032610676, 1521088.326792507);
    let ne2 = Coor2D::raw(499315.16759512835, 1685050.54257971);
    let mut coor = [ne1, ne2];
    context.apply(tm100_7, Inv, &mut coor)?;
    println!("{:#?}", coor);
    Ok(())
}

The output is now in degrees, as expected:

[
    Coor2D(
        [
            13.753635230458237,
            100.71166197509885,
        ],
    ),
    Coor2D(
        [
            15.23552625325235,
            100.6936254255626,
        ],
    ),
]

Thanks for providing such a great library for Rust! I’ve also successfully compiled RG for an embedded system on the ESP32.

busstoptaktik commented 1 month ago

Thanks for providing such a great library for Rust!

You're welcome - glad to hear it's of use to you!

I’ve also successfully compiled RG for an embedded system on the ESP32.

That's awesome! Did you have to modify anything to get it to compile?

pbroboto commented 1 month ago

Hi,

I’m using WSL2 on Windows and followed the instructions from this tutorial. However, I encountered an issue with the crate dirs-sys-0.4.1. Here’s part of the error message I’m seeing:

   Compiling futures-util v0.3.30
   Compiling clap_builder v4.5.18
   Compiling nb v0.1.3
   Compiling option-ext v0.2.0
   Compiling const_format v0.2.33
   Compiling void v1.0.2
   Compiling enumset v1.1.5
   Compiling critical-section v1.1.3
   Compiling embedded-hal v0.2.7
   Compiling dirs-sys v0.4.1
   Compiling embedded-hal-nb v1.0.0
error[E0425]: cannot find value `_SC_GETPW_R_SIZE_MAX` in crate `libc`
  --> /home/pbrobo/.cargo/registry/src/index.crates.io-6f17d22bba15001f/dirs-sys-0.4.1/src/lib.rs:45:45
   |
45 |         let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) {
   |                                             ^^^^^^^^^^^^^^^^^^^^ not found in `libc`

For more information about this error, try `rustc --explain E0425`.
error: could not compile `dirs-sys` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...

I searched for _SC_GETPW_R_SIZE_MAX and found that it’s a "suggested initial value for the size of the password entry buffer" and typically set to 70.

pub const _SC_GETPW_R_SIZE_MAX: c_int = 70;

I temporarily replaced the constant with the value 70, and the compilation succeeded:

-       let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) {
+       let amt = match libc::sysconf(70) {

The compilation now works. Below is my Rust code that tests Rust Geodesy (RG):

use geodesy::prelude::*;

fn main() -> Result<(), Box<Error>> {
    // It is necessary to call this function once. Otherwise some patches to the runtime
    // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
    esp_idf_svc::sys::link_patches();

    // Bind the log crate to the ESP Logging facilities
    esp_idf_svc::log::EspLogger::initialize_default();

    log::info!("Hello, Rust Geodesy!");
    let mut context = Minimal::new();
    // Test Pipeline of RG
    println!("Test inverse pipeline: ");
    let ne1 = Coor2D::raw(685063.5075, 1521137.2111);
    let ne2 = Coor2D::raw(681899.5402, 1685083.1436);
    let coor1 = [ne1, ne2];
    println!("From grid coordinates of UTM zone 47: ");
    println!("{:#?}", coor1);

    let op = context
    .op("inv tmerc lon_0=100.7 lat_0=0 k_0=1.0 x_0=500000 y_0=0 ellps=WGS84 | utm zone=47 ellips=WGS84 ")?;
    let mut coor2: [Coor2D; 2] = coor1.clone();
    context.apply(op, Inv, &mut coor2)?;
    println!("To grid coordinates of TM @CM=100.7 K0=1.0:");
    println!("{:#?}", coor2);

    println!("Test forward pipeline: ");
    println!("From grid coordinates of TM @CM=100.7 K0=1.0:");
    let coor3: [Coor2D; 2] = coor2.clone();
    println!("{:#?}", coor3);
    let mut coor4: [Coor2D; 2] = coor3.clone();
    context.apply(op, Fwd, &mut coor4)?;
    println!("To grid coordinates of UTM zone 47:");
    println!("{:#?}", coor4);
    Ok(())
}

Here is the result:

pbrobo@pbrworkstation:~/esp/rust-esp/test_geodesy$ cargo run
    Finished `dev` profile [optimized + debuginfo] target(s) in 0.69s
     Running `espflash flash --monitor target/xtensa-esp32-espidf/debug/test_geodesy`
[2024-10-02T11:52:43Z INFO ] Serial port: '/dev/ttyUSB0'
[2024-10-02T11:52:43Z INFO ] Connecting...
[2024-10-02T11:52:44Z INFO ] Using flash stub
Chip type:         esp32 (revision v3.1)
Crystal frequency: 40 MHz
Flash size:        4MB
Features:          WiFi, BT, Dual Core, 240MHz, Coding Scheme None
MAC address:       88:13:bf:07:b8:98
App/part. size:    853,328/4,128,768 bytes, 20.67%
[2024-10-02T11:52:45Z INFO ] Segment at address '0x1000' has not changed, skipping write
[2024-10-02T11:52:45Z INFO ] Segment at address '0x8000' has not changed, skipping write
[00:00:40] [========================================]     435/435     0x10000
[2024-10-02T11:53:30Z INFO ] Flashing has completed!
Commands:
    CTRL+R    Reset chip
    CTRL+C    Exit

ets Jul 29 2019 12:21:46

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:7104
load:0x40078000,len:15576
load:0x40080400,len:4
0x40080400 - _invalid_pc_placeholder
    at ??:??
ho 8 tail 4 room 4
load:0x40080404,len:3876
entry 0x4008064c
I (31) boot: ESP-IDF v5.1-beta1-378-gea5e0ff298-dirt 2nd stage bootloader
I (31) boot: compile time Jun  7 2023 07:48:23
I (33) boot: Multicore bootloader
I (37) boot: chip revision: v3.1
I (41) boot.esp32: SPI Speed      : 40MHz
I (46) boot.esp32: SPI Mode       : DIO
I (50) boot.esp32: SPI Flash Size : 4MB
I (55) boot: Enabling RNG early entropy source...
I (60) boot: Partition Table:
I (64) boot: ## Label            Usage          Type ST Offset   Length
I (71) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (79) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (86) boot:  2 factory          factory app      00 00 00010000 003f0000
I (94) boot: End of partition table
I (98) esp_image: segment 0: paddr=00010020 vaddr=3f400020 size=34f90h (216976) map
I (185) esp_image: segment 1: paddr=00044fb8 vaddr=3ffb0000 size=02158h (  8536) load
I (188) esp_image: segment 2: paddr=00047118 vaddr=40080000 size=08f00h ( 36608) load
I (206) esp_image: segment 3: paddr=00050020 vaddr=400d0020 size=8d55ch (578908) map
I (415) esp_image: segment 4: paddr=000dd584 vaddr=40088f00 size=02fa4h ( 12196) load
I (426) boot: Loaded app from partition at offset 0x10000
I (426) boot: Disabling RNG early entropy source...
I (438) cpu_start: Multicore app
I (447) cpu_start: Pro cpu start user code
I (447) cpu_start: cpu freq: 160000000 Hz
I (447) cpu_start: Application information:
I (450) cpu_start: Project name:     libespidf
I (455) cpu_start: App version:      1
I (459) cpu_start: Compile time:     Oct  2 2024 18:15:32
I (465) cpu_start: ELF file SHA256:  000000000...
I (471) cpu_start: ESP-IDF:          v5.2.2
I (476) cpu_start: Min chip rev:     v0.0
I (480) cpu_start: Max chip rev:     v3.99
I (485) cpu_start: Chip rev:         v3.1
I (490) heap_init: Initializing. RAM available for dynamic allocation:
I (497) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (503) heap_init: At 3FFB2AC0 len 0002D540 (181 KiB): DRAM
I (509) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (516) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (522) heap_init: At 4008BEA4 len 0001415C (80 KiB): IRAM
I (530) spi_flash: detected chip: generic
I (533) spi_flash: flash io: dio
W (537) pcnt(legacy): legacy driver is deprecated, please migrate to `driver/pulse_cnt.h`
W (546) timer_group: legacy driver is deprecated, please migrate to `driver/gptimer.h`
I (555) main_task: Started on CPU0
I (565) main_task: Calling app_main()
I (565) test_geodesy: Hello, Rust Geodesy!
Test inverse pipeline:
From grid coordinates of UTM zone 47:
[
    Coor2D(
        [
            685063.5075,
            1521137.2111,
        ],
    ),
    Coor2D(
        [
            681899.5402,
            1685083.1436,
        ],
    ),
]
To grid coordinates of TM @CM=100.7 K0=1.0:
[
    Coor2D(
        [
            501261.2203195006,
            1521088.3268045,
        ],
    ),
    Coor2D(
        [
            499315.16763403936,
            1685050.5426394003,
        ],
    ),
]
Test forward pipeline:
From grid coordinates of TM @CM=100.7 K0=1.0:
[
    Coor2D(
        [
            501261.2203195006,
            1521088.3268045,
        ],
    ),
    Coor2D(
        [
            499315.16763403936,
            1685050.5426394003,
        ],
    ),
]
To grid coordinates of UTM zone 47:
[
    Coor2D(
        [
            685063.5075000018,
            1521137.2111,
        ],
    ),
    Coor2D(
        [
            681899.5402000027,
            1685083.1436000003,
        ],
    ),
]
I (735) main_task: Returned from app_main()

I also attempted to compile PROJ from georust/proj, but I was unsuccessful.