This is an automated email from the ASF dual-hosted git repository.

kontinuation pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/sedona-db.git


The following commit(s) were added to refs/heads/main by this push:
     new 95c156d  chore: Add sedona-geo-traits-ext and sedona-geo-generic-alg 
to the workspace, eliminating geo, wkt and wkb forks (#203)
95c156d is described below

commit 95c156d507f9ce67dde1fd3ec6e1a196c70a39a6
Author: Kristin Cowalcijk <[email protected]>
AuthorDate: Fri Oct 10 22:49:57 2025 +0800

    chore: Add sedona-geo-traits-ext and sedona-geo-generic-alg to the 
workspace, eliminating geo, wkt and wkb forks (#203)
    
    This is the final step of the forked dependency elimination plan: 
https://github.com/apache/sedona-db/pull/165/files. sedona-geo-generic-alg will 
go live and replace the original wherobots/geo dependency. We also replace 
forked wkb and wkt dependencies with the latest release versions.
    
    This patch depends on https://github.com/wherobots/geo-index/pull/7 to 
resolve a geo version conflict.
    
    Remaining tasks:
    
    * geo-index will be the only forked dependency, and we are [submitting 
patches](https://github.com/kylebarron/geo-index/pull/141) to put the nearest 
neighbour search APIs needed by sedona-db to the upstream.
    * We need a released version of 
[georust/wkb](https://github.com/georust/wkb) before releasing 0.2.0.
---
 Cargo.lock                                        |  249 ++--
 Cargo.toml                                        |   26 +-
 c/sedona-geos/Cargo.toml                          |    9 +-
 c/sedona-geos/benches/wkb_to_geos.rs              |   77 ++
 c/sedona-geos/src/executor.rs                     |    4 +-
 c/sedona-geos/src/lib.rs                          |    1 +
 c/sedona-geos/src/wkb_to_geos.rs                  | 1335 +++++++++++++++++++++
 c/sedona-tg/benches/parse-wkb.rs                  |    8 +-
 rust/sedona-functions/src/st_geomfromwkt.rs       |   13 +-
 rust/sedona-geo-generic-alg/Cargo.toml            |   41 +-
 rust/sedona-geo-traits-ext/Cargo.toml             |   34 +-
 rust/sedona-geo/Cargo.toml                        |    4 +-
 rust/sedona-geo/src/centroid.rs                   |    4 +-
 rust/sedona-geo/src/st_area.rs                    |    2 +-
 rust/sedona-geo/src/st_centroid.rs                |    2 +-
 rust/sedona-geo/src/st_distance.rs                |    2 +-
 rust/sedona-geo/src/st_dwithin.rs                 |    2 +-
 rust/sedona-geo/src/st_intersection_aggr.rs       |   47 +-
 rust/sedona-geo/src/st_intersects.rs              |    2 +-
 rust/sedona-geo/src/st_length.rs                  |    2 +-
 rust/sedona-geo/src/st_perimeter.rs               |    2 +-
 rust/sedona-geo/src/st_union_aggr.rs              |   38 +-
 rust/sedona-geo/src/to_geo.rs                     |   68 +-
 rust/sedona-geometry/src/bounds.rs                |   10 +-
 rust/sedona-geometry/src/is_empty.rs              |   12 +-
 rust/sedona-geometry/src/wkb_factory.rs           |  102 +-
 rust/sedona-spatial-join/Cargo.toml               |    7 +-
 rust/sedona-spatial-join/src/index.rs             |    2 +-
 rust/sedona-spatial-join/src/operand_evaluator.rs |    2 +-
 rust/sedona-spatial-join/src/refine/geo.rs        |   26 +-
 rust/sedona-spatial-join/src/refine/geos.rs       |    3 +-
 rust/sedona-testing/src/create.rs                 |   10 +-
 rust/sedona-testing/src/datagen.rs                |   11 +-
 33 files changed, 1891 insertions(+), 266 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index d9a3c0a..ce037d7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -537,6 +537,17 @@ version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
 
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi 0.1.19",
+ "libc",
+ "winapi",
+]
+
 [[package]]
 name = "autocfg"
 version = "1.5.0"
@@ -2332,6 +2343,19 @@ dependencies = [
  "regex",
 ]
 
+[[package]]
+name = "env_logger"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
+dependencies = [
+ "atty",
+ "humantime 1.3.0",
+ "log",
+ "regex",
+ "termcolor",
+]
+
 [[package]]
 name = "env_logger"
 version = "0.11.8"
@@ -2578,9 +2602,9 @@ dependencies = [
 
 [[package]]
 name = "geo"
-version = "0.30.0"
+version = "0.31.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "4416397671d8997e9a3e7ad99714f4f00a22e9eaa9b966a5985d2194fc9e02e1"
+checksum = "2fc1a1678e54befc9b4bcab6cd43b8e7f834ae8ea121118b0fd8c42747675b4a"
 dependencies = [
  "earcutr",
  "float_next_after",
@@ -2594,48 +2618,21 @@ dependencies = [
  "spade",
 ]
 
-[[package]]
-name = "geo-generic-alg"
-version = "0.1.0"
-source = 
"git+https://github.com/wherobots/geo.git?branch=generic-alg#66ff85949a82549b0d28fb2d4fae01e3ea19ca83";
-dependencies = [
- "earcutr",
- "float_next_after",
- "geo-traits 0.2.0",
- "geo-traits-ext",
- "geo-types",
- "geographiclib-rs",
- "i_overlay",
- "log",
- "num-traits",
- "robust",
- "rstar",
- "spade",
-]
-
 [[package]]
 name = "geo-index"
 version = "0.3.1"
-source = 
"git+https://github.com/wherobots/geo-index.git?branch=main#6a03f0a2e3ba7ecfaacbf18019008449b8c93541";
+source = 
"git+https://github.com/wherobots/geo-index.git?branch=main#3213c162b1dfdac9effdef3083afc17261c9f6fc";
 dependencies = [
  "bytemuck",
  "float_next_after",
  "geo",
- "geo-traits 0.3.0",
+ "geo-traits",
  "geo-types",
  "num-traits",
  "thiserror 1.0.69",
  "tinyvec",
 ]
 
-[[package]]
-name = "geo-traits"
-version = "0.2.0"
-source = 
"git+https://github.com/wherobots/geo.git?branch=generic-alg#66ff85949a82549b0d28fb2d4fae01e3ea19ca83";
-dependencies = [
- "geo-types",
-]
-
 [[package]]
 name = "geo-traits"
 version = "0.3.0"
@@ -2645,18 +2642,6 @@ dependencies = [
  "geo-types",
 ]
 
-[[package]]
-name = "geo-traits-ext"
-version = "0.1.0"
-source = 
"git+https://github.com/wherobots/geo.git?branch=generic-alg#66ff85949a82549b0d28fb2d4fae01e3ea19ca83";
-dependencies = [
- "approx",
- "geo-traits 0.2.0",
- "geo-types",
- "num-traits",
- "serde",
-]
-
 [[package]]
 name = "geo-types"
 version = "0.7.17"
@@ -2825,6 +2810,15 @@ version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "hermit-abi"
 version = "0.5.2"
@@ -2917,6 +2911,15 @@ version = "1.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
 
+[[package]]
+name = "humantime"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
+dependencies = [
+ "quick-error",
+]
+
 [[package]]
 name = "humantime"
 version = "2.3.0"
@@ -2988,24 +2991,24 @@ dependencies = [
 
 [[package]]
 name = "i_float"
-version = "1.7.0"
+version = "1.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "85df3a416829bb955fdc2416c7b73680c8dcea8d731f2c7aa23e1042fe1b8343"
+checksum = "010025c2c532c8d82e42d0b8bb5184afa449fa6f06c709ea9adcb16c49ae405b"
 dependencies = [
- "serde",
+ "libm",
 ]
 
 [[package]]
 name = "i_key_sort"
-version = "0.2.0"
+version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "347c253b4748a1a28baf94c9ce133b6b166f08573157e05afe718812bc599fcd"
+checksum = "9190f86706ca38ac8add223b2aed8b1330002b5cdbbce28fb58b10914d38fc27"
 
 [[package]]
 name = "i_overlay"
-version = "2.0.5"
+version = "4.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "0542dfef184afdd42174a03dcc0625b6147fb73e1b974b1a08a2a42ac35cee49"
+checksum = "0fcccbd4e4274e0f80697f5fbc6540fdac533cce02f2081b328e68629cce24f9"
 dependencies = [
  "i_float",
  "i_key_sort",
@@ -3016,19 +3019,18 @@ dependencies = [
 
 [[package]]
 name = "i_shape"
-version = "1.7.0"
+version = "1.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "0a38f5a42678726718ff924f6d4a0e79b129776aeed298f71de4ceedbd091bce"
+checksum = "1ea154b742f7d43dae2897fcd5ead86bc7b5eefcedd305a7ebf9f69d44d61082"
 dependencies = [
  "i_float",
- "serde",
 ]
 
 [[package]]
 name = "i_tree"
-version = "0.8.3"
+version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "155181bc97d770181cf9477da51218a19ee92a8e5be642e796661aee2b601139"
+checksum = "35e6d558e6d4c7b82bc51d9c771e7a927862a161a7d87bf2b0541450e0e20915"
 
 [[package]]
 name = "iana-time-zone"
@@ -3222,7 +3224,7 @@ version = "0.4.16"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
 dependencies = [
- "hermit-abi",
+ "hermit-abi 0.5.2",
  "libc",
  "windows-sys 0.59.0",
 ]
@@ -3773,7 +3775,7 @@ dependencies = [
  "futures",
  "http 1.3.1",
  "http-body-util",
- "humantime",
+ "humantime 2.3.0",
  "hyper",
  "itertools 0.14.0",
  "md-5",
@@ -4028,6 +4030,16 @@ dependencies = [
  "zerocopy",
 ]
 
+[[package]]
+name = "pretty_env_logger"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d"
+dependencies = [
+ "env_logger 0.7.1",
+ "log",
+]
+
 [[package]]
 name = "prettyplease"
 version = "0.2.37"
@@ -4170,6 +4182,12 @@ version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "5a651516ddc9168ebd67b24afd085a718be02f8858fe406591b013d101ce2f40"
 
+[[package]]
+name = "quick-error"
+version = "1.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
+
 [[package]]
 name = "quick-xml"
 version = "0.38.3"
@@ -4319,6 +4337,16 @@ dependencies = [
  "getrandom 0.3.3",
 ]
 
+[[package]]
+name = "rand_distr"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31"
+dependencies = [
+ "num-traits",
+ "rand 0.8.5",
+]
+
 [[package]]
 name = "rayon"
 version = "1.11.0"
@@ -4769,7 +4797,7 @@ dependencies = [
  "datafusion-ffi",
  "dirs",
  "futures",
- "geo-traits 0.2.0",
+ "geo-traits",
  "geo-types",
  "object_store",
  "parking_lot",
@@ -4816,7 +4844,7 @@ dependencies = [
  "async-trait",
  "clap",
  "datafusion",
- "env_logger",
+ "env_logger 0.11.8",
  "futures",
  "libmimalloc-sys",
  "mimalloc",
@@ -4845,7 +4873,7 @@ dependencies = [
  "datafusion-common",
  "datafusion-expr",
  "datafusion-physical-expr",
- "geo-traits 0.2.0",
+ "geo-traits",
  "rstest",
  "sedona-common",
  "sedona-geometry",
@@ -4866,7 +4894,7 @@ dependencies = [
  "datafusion",
  "datafusion-common",
  "datafusion-expr",
- "geo-traits 0.2.0",
+ "geo-traits",
  "rstest",
  "sedona-common",
  "sedona-expr",
@@ -4876,7 +4904,7 @@ dependencies = [
  "serde_json",
  "tokio",
  "wkb",
- "wkt 0.13.0",
+ "wkt 0.14.0",
 ]
 
 [[package]]
@@ -4889,17 +4917,54 @@ dependencies = [
  "datafusion-common",
  "datafusion-expr",
  "geo",
- "geo-generic-alg",
- "geo-traits 0.2.0",
+ "geo-traits",
  "geo-types",
  "rstest",
  "sedona-expr",
  "sedona-functions",
+ "sedona-geo-generic-alg",
  "sedona-geometry",
  "sedona-schema",
  "sedona-testing",
  "wkb",
- "wkt 0.13.0",
+ "wkt 0.14.0",
+]
+
+[[package]]
+name = "sedona-geo-generic-alg"
+version = "0.2.0"
+dependencies = [
+ "approx",
+ "criterion",
+ "float_next_after",
+ "geo",
+ "geo-traits",
+ "geo-types",
+ "i_overlay",
+ "log",
+ "num-traits",
+ "pretty_env_logger",
+ "rand 0.8.5",
+ "rand_distr",
+ "robust",
+ "rstar",
+ "sedona-geo-traits-ext",
+ "sedona-testing",
+ "wkb",
+ "wkt 0.14.0",
+]
+
+[[package]]
+name = "sedona-geo-traits-ext"
+version = "0.2.0"
+dependencies = [
+ "byteorder",
+ "geo-traits",
+ "geo-types",
+ "num-traits",
+ "rstest",
+ "wkb",
+ "wkt 0.14.0",
 ]
 
 [[package]]
@@ -4927,7 +4992,7 @@ dependencies = [
 name = "sedona-geometry"
 version = "0.2.0"
 dependencies = [
- "geo-traits 0.2.0",
+ "geo-traits",
  "geo-types",
  "lru",
  "rstest",
@@ -4936,7 +5001,7 @@ dependencies = [
  "serde_with",
  "thiserror 2.0.17",
  "wkb",
- "wkt 0.13.0",
+ "wkt 0.14.0",
 ]
 
 [[package]]
@@ -4957,7 +5022,7 @@ dependencies = [
  "datafusion-physical-plan",
  "float_next_after",
  "futures",
- "geo-traits 0.2.0",
+ "geo-traits",
  "object_store",
  "parquet",
  "rstest",
@@ -4981,9 +5046,12 @@ version = "0.2.0"
 dependencies = [
  "arrow-array",
  "arrow-schema",
+ "byteorder",
  "criterion",
  "datafusion-common",
  "datafusion-expr",
+ "geo-traits",
+ "geo-types",
  "geos",
  "rstest",
  "sedona",
@@ -5006,7 +5074,7 @@ dependencies = [
  "criterion",
  "datafusion-common",
  "datafusion-expr",
- "geo-traits 0.2.0",
+ "geo-traits",
  "geo-types",
  "proj-sys",
  "rstest",
@@ -5071,10 +5139,9 @@ dependencies = [
  "datafusion-physical-plan",
  "float_next_after",
  "futures",
- "geo-generic-alg",
+ "geo",
  "geo-index",
- "geo-traits 0.2.0",
- "geo-traits-ext",
+ "geo-traits",
  "geo-types",
  "geos",
  "once_cell",
@@ -5085,6 +5152,8 @@ dependencies = [
  "sedona-expr",
  "sedona-functions",
  "sedona-geo",
+ "sedona-geo-generic-alg",
+ "sedona-geo-traits-ext",
  "sedona-geometry",
  "sedona-geos",
  "sedona-schema",
@@ -5092,7 +5161,7 @@ dependencies = [
  "sedona-tg",
  "tokio",
  "wkb",
- "wkt 0.13.0",
+ "wkt 0.14.0",
 ]
 
 [[package]]
@@ -5107,7 +5176,7 @@ dependencies = [
  "datafusion-expr",
  "datafusion-physical-expr",
  "geo",
- "geo-traits 0.2.0",
+ "geo-traits",
  "geo-types",
  "parquet",
  "rand 0.8.5",
@@ -5117,7 +5186,7 @@ dependencies = [
  "sedona-geometry",
  "sedona-schema",
  "wkb",
- "wkt 0.13.0",
+ "wkt 0.14.0",
 ]
 
 [[package]]
@@ -5520,6 +5589,15 @@ dependencies = [
  "windows-sys 0.61.2",
 ]
 
+[[package]]
+name = "termcolor"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
+dependencies = [
+ "winapi-util",
+]
+
 [[package]]
 name = "thiserror"
 version = "1.0.69"
@@ -6380,14 +6458,11 @@ checksum = 
"f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
 
 [[package]]
 name = "wkb"
-version = "0.8.0"
-source = 
"git+https://github.com/wherobots/wkb.git?branch=generic-alg#5496c33919e9193edcde6ccf7dd51a9093782277";
+version = "0.9.1"
+source = 
"git+https://github.com/georust/wkb.git?rev=130eb0c2b343bc9299aeafba6d34c2a6e53f3b6a#130eb0c2b343bc9299aeafba6d34c2a6e53f3b6a";
 dependencies = [
  "byteorder",
- "geo-traits 0.2.0",
- "geo-traits-ext",
- "geo-types",
- "geos",
+ "geo-traits",
  "num_enum",
  "thiserror 1.0.69",
 ]
@@ -6406,10 +6481,11 @@ dependencies = [
 
 [[package]]
 name = "wkt"
-version = "0.13.0"
-source = 
"git+https://github.com/wherobots/wkt.git?branch=generic-alg#ec26b050ec1718ee08e4d8a911e99f1039b60c8b";
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "efb2b923ccc882312e559ffaa832a055ba9d1ac0cc8e86b3e25453247e4b81d7"
 dependencies = [
- "geo-traits 0.2.0",
+ "geo-traits",
  "geo-types",
  "log",
  "num-traits",
@@ -6584,8 +6660,3 @@ dependencies = [
  "cc",
  "pkg-config",
 ]
-
-[[patch.unused]]
-name = "geo-types"
-version = "0.7.16"
-source = 
"git+https://github.com/wherobots/geo.git?branch=generic-alg#66ff85949a82549b0d28fb2d4fae01e3ea19ca83";
diff --git a/Cargo.toml b/Cargo.toml
index 1c36111..f314e53 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -22,6 +22,8 @@ members = [
     "c/sedona-s2geography",
     "c/sedona-tg",
     "r/sedonadb/src/rust",
+    "rust/sedona-geo-traits-ext",
+    "rust/sedona-geo-generic-alg",
     "rust/sedona-adbc",
     "rust/sedona-expr",
     "rust/sedona-functions",
@@ -65,6 +67,7 @@ arrow-json = { version = "55.1.0" }
 arrow-schema = { version = "55.1.0" }
 async-trait = { version = "0.1.87" }
 bytes = "1.10"
+byteorder = "1"
 chrono = { version = "0.4.38", default-features = false }
 comfy-table = { version = "7.0" }
 criterion = { version = "0.5", features = ["html_reports"] }
@@ -82,23 +85,21 @@ env_logger = "0.11"
 futures = { version = "0.3" }
 object_store = { version = "0.12.0", default-features = false }
 float_next_after = "1"
+num-traits = { version = "0.2", default-features = false, features = ["libm"] }
 mimalloc = { version = "0.1", default-features = false }
 libmimalloc-sys = { version = "0.1", default-features = false }
 once_cell = "1.20"
 
-geos = { version = "10.0.0", features = ["geo"] }
+geos = { version = "10.0.0", features = ["geo", "v3_10_0"] }
 
-# Use our own fork of georust/geo, which implements generic computational 
geometry algorithms for geo-traits
-geo-generic-alg = { git = "https://github.com/wherobots/geo.git";, branch = 
"generic-alg", package = "geo-generic-alg" }
-geo-types = "0.7.16"
-geo-traits = "0.2.0"
-geo-traits-ext = "0.1.0"
-geo = { version = "0.30.0" }
+geo-types = "0.7.17"
+geo-traits = "0.3.0"
+geo = "0.31.0"
 
 geo-index = { version = "0.3.1" }
 
-wkb = { version = "0.8.0", features = ["geos"] }
-wkt = "0.13.0"
+wkb = "0.9.1"
+wkt = "0.14.0"
 
 parking_lot = "0.12"
 parquet = { version = "55.1.0", default-features = false, features = [
@@ -129,9 +130,6 @@ datafusion-ffi = { git = 
"https://github.com/paleolimbot/datafusion.git";, branch
 datafusion-physical-expr = { git = 
"https://github.com/paleolimbot/datafusion.git";, branch = 
"local-49-with-patch", package = "datafusion-physical-expr" }
 datafusion-physical-plan = { git = 
"https://github.com/paleolimbot/datafusion.git";, branch = 
"local-49-with-patch", package = "datafusion-physical-plan" }
 
-geo-types = { git = "https://github.com/wherobots/geo.git";, branch = 
"generic-alg", package = "geo-types" }
-geo-traits = { git = "https://github.com/wherobots/geo.git";, branch = 
"generic-alg", package = "geo-traits" }
-geo-traits-ext = { git = "https://github.com/wherobots/geo.git";, branch = 
"generic-alg", package = "geo-traits-ext" }
+# TODO: remove them once changes we made to geo-index and wkb crates are 
merged to upstream and released
 geo-index = { git = "https://github.com/wherobots/geo-index.git";, branch = 
"main" }
-wkb = { git = "https://github.com/wherobots/wkb.git";, branch = "generic-alg" }
-wkt = { git = "https://github.com/wherobots/wkt.git";, branch = "generic-alg" }
+wkb = { git = "https://github.com/georust/wkb.git";, rev = 
"130eb0c2b343bc9299aeafba6d34c2a6e53f3b6a" }
diff --git a/c/sedona-geos/Cargo.toml b/c/sedona-geos/Cargo.toml
index f7de7ee..d92f076 100644
--- a/c/sedona-geos/Cargo.toml
+++ b/c/sedona-geos/Cargo.toml
@@ -31,6 +31,7 @@ criterion = { workspace = true }
 sedona = { path = "../../rust/sedona" }
 sedona-testing = { path = "../../rust/sedona-testing", features = 
["criterion"] }
 rstest = { workspace = true }
+geo-types = { workspace = true }
 
 [dependencies]
 arrow-schema = { workspace = true }
@@ -42,8 +43,14 @@ sedona-expr = { path = "../../rust/sedona-expr" }
 sedona-functions = { path = "../../rust/sedona-functions" }
 sedona-geometry = { path = "../../rust/sedona-geometry" }
 sedona-schema = { path = "../../rust/sedona-schema" }
-wkb = { workspace = true, features = ["geos"] }
+geo-traits = { workspace = true }
+wkb = { workspace = true }
+byteorder = { workspace = true }
 
 [[bench]]
 harness = false
 name = "geos-functions"
+
+[[bench]]
+harness = false
+name = "wkb_to_geos"
diff --git a/c/sedona-geos/benches/wkb_to_geos.rs 
b/c/sedona-geos/benches/wkb_to_geos.rs
new file mode 100644
index 0000000..cd2b9db
--- /dev/null
+++ b/c/sedona-geos/benches/wkb_to_geos.rs
@@ -0,0 +1,77 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+use criterion::{criterion_group, criterion_main};
+use geo_types::{LineString, Point};
+use sedona_geos::wkb_to_geos::GEOSWkbFactory;
+use wkb::Endianness;
+
+fn generate_wkb_linestring(num_points: usize, endianness: Endianness) -> 
Vec<u8> {
+    let mut points = Vec::new();
+    for i in 0..num_points {
+        points.push(Point::new(i as f64, i as f64));
+    }
+    let linestring = LineString::from(points);
+    let mut buffer = Vec::new();
+    wkb::writer::write_geometry(
+        &mut buffer,
+        &linestring,
+        &wkb::writer::WriteOptions { endianness },
+    )
+    .unwrap();
+    buffer
+}
+
+fn bench_parse(c: &mut criterion::Criterion) {
+    for num_points in [4, 10, 100, 500, 1000] {
+        for endianness in [Endianness::BigEndian, Endianness::LittleEndian] {
+            let wkb_buf = generate_wkb_linestring(num_points, endianness);
+            let wkb = wkb::reader::read_wkb(&wkb_buf).unwrap();
+            let endianness_name: &str = match endianness {
+                Endianness::BigEndian => "big endian",
+                Endianness::LittleEndian => "little endian",
+            };
+
+            c.bench_function(
+                &format!(
+                    "convert linestring containing {num_points} points using 
to_geos ({endianness_name})"
+                ),
+                |b| {
+                    let factory = GEOSWkbFactory::new();
+                    b.iter(|| {
+                        let g = factory.create(&wkb).unwrap();
+                        criterion::black_box(g);
+                    });
+                },
+            );
+
+            c.bench_function(
+                &format!(
+                    "convert linestring containing {num_points} points using 
geos wkb parser ({endianness_name})"
+                ),
+                |b| {
+                    b.iter(|| {
+                        let g = 
geos::Geometry::new_from_wkb(wkb.buf()).unwrap();
+                        criterion::black_box(g);
+                    });
+                },
+            );
+        }
+    }
+}
+
+criterion_group!(benches, bench_parse);
+criterion_main!(benches);
diff --git a/c/sedona-geos/src/executor.rs b/c/sedona-geos/src/executor.rs
index 3d806cc..5e8a021 100644
--- a/c/sedona-geos/src/executor.rs
+++ b/c/sedona-geos/src/executor.rs
@@ -17,13 +17,15 @@
 use datafusion_common::{DataFusionError, Result};
 use sedona_functions::executor::{GenericExecutor, GeometryFactory};
 
+use crate::wkb_to_geos::GEOSWkbFactory;
+
 /// A [GenericExecutor] that iterates over [geos::Geometry]
 pub type GeosExecutor<'a, 'b> = GenericExecutor<'a, 'b, GeosGeometryFactory, 
GeosGeometryFactory>;
 
 /// [GeometryFactory] implementation for iterating over [geos::Geometry]
 #[derive(Default)]
 pub struct GeosGeometryFactory {
-    inner: wkb::reader::to_geos::GEOSWkbFactory,
+    inner: GEOSWkbFactory,
 }
 
 impl GeometryFactory for GeosGeometryFactory {
diff --git a/c/sedona-geos/src/lib.rs b/c/sedona-geos/src/lib.rs
index 667bc82..74d57b9 100644
--- a/c/sedona-geos/src/lib.rs
+++ b/c/sedona-geos/src/lib.rs
@@ -27,3 +27,4 @@ mod st_convexhull;
 mod st_dwithin;
 mod st_length;
 mod st_perimeter;
+pub mod wkb_to_geos;
diff --git a/c/sedona-geos/src/wkb_to_geos.rs b/c/sedona-geos/src/wkb_to_geos.rs
new file mode 100644
index 0000000..9bd8350
--- /dev/null
+++ b/c/sedona-geos/src/wkb_to_geos.rs
@@ -0,0 +1,1335 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+use std::cell::RefCell;
+
+use byteorder::{BigEndian, ByteOrder, LittleEndian};
+use geo_traits::*;
+use geos::GResult;
+use wkb::{reader::*, Endianness};
+
+/// A factory for converting WKB to GEOS geometries.
+///
+/// This factory uses a scratch buffer to store intermediate coordinate data.
+/// The scratch buffer is reused for each conversion, which reduces memory 
allocation
+/// overhead.
+pub struct GEOSWkbFactory {
+    scratch: RefCell<Vec<f64>>,
+}
+
+impl Default for GEOSWkbFactory {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl GEOSWkbFactory {
+    /// Create a new GEOSWkbFactory.
+    pub fn new() -> Self {
+        Self {
+            scratch: RefCell::new(Vec::new()),
+        }
+    }
+
+    /// Create a GEOS geometry from a WKB.
+    pub fn create(&self, wkb: &Wkb) -> GResult<geos::Geometry> {
+        let scratch = &mut self.scratch.borrow_mut();
+        geometry_to_geos(scratch, wkb)
+    }
+}
+
+fn geometry_to_geos(scratch: &mut Vec<f64>, wkb: &Wkb) -> 
GResult<geos::Geometry> {
+    let geom = wkb.as_type();
+    match geom {
+        geo_traits::GeometryType::Point(p) => point_to_geos(scratch, p),
+        geo_traits::GeometryType::LineString(ls) => 
line_string_to_geos(scratch, ls),
+        geo_traits::GeometryType::Polygon(poly) => polygon_to_geos(scratch, 
poly),
+        geo_traits::GeometryType::MultiPoint(mp) => 
multi_point_to_geos(scratch, mp),
+        geo_traits::GeometryType::MultiLineString(mls) => 
multi_line_string_to_geos(scratch, mls),
+        geo_traits::GeometryType::MultiPolygon(mpoly) => 
multi_polygon_to_geos(scratch, mpoly),
+        geo_traits::GeometryType::GeometryCollection(gc) => {
+            geometry_collection_to_geos(scratch, gc)
+        }
+        _ => Err(geos::Error::ConversionError(
+            "Unsupported geometry type".to_string(),
+        )),
+    }
+}
+
+fn point_to_geos(scratch: &mut Vec<f64>, p: &Point) -> GResult<geos::Geometry> 
{
+    if p.is_empty() {
+        geos::Geometry::create_empty_point()
+    } else {
+        let coord_seq = create_coord_sequence_from_raw_parts(
+            p.coord_slice(),
+            p.dimension(),
+            p.byte_order(),
+            1,
+            scratch,
+        )?;
+        let point = geos::Geometry::create_point(coord_seq)?;
+        Ok(point)
+    }
+}
+
+fn line_string_to_geos(scratch: &mut Vec<f64>, ls: &LineString) -> 
GResult<geos::Geometry> {
+    let num_points = ls.num_coords();
+    if num_points == 0 {
+        geos::Geometry::create_empty_line_string()
+    } else {
+        let coord_seq = create_coord_sequence_from_raw_parts(
+            ls.coords_slice(),
+            ls.dimension(),
+            ls.byte_order(),
+            num_points,
+            scratch,
+        )?;
+        geos::Geometry::create_line_string(coord_seq)
+    }
+}
+
+fn polygon_to_geos(scratch: &mut Vec<f64>, poly: &Polygon) -> 
GResult<geos::Geometry> {
+    // Create exterior ring
+    let exterior = if let Some(ring) = poly.exterior() {
+        let coord_seq = create_coord_sequence_from_raw_parts(
+            ring.coords_slice(),
+            ring.dimension(),
+            ring.byte_order(),
+            ring.num_coords(),
+            scratch,
+        )?;
+        geos::Geometry::create_linear_ring(coord_seq)?
+    } else {
+        return geos::Geometry::create_empty_polygon();
+    };
+
+    // Create interior rings
+    let num_interiors = poly.num_interiors();
+    let mut interior_rings = Vec::with_capacity(num_interiors);
+    for i in 0..num_interiors {
+        let ring = poly.interior(i).unwrap();
+        let coord_seq = create_coord_sequence_from_raw_parts(
+            ring.coords_slice(),
+            ring.dimension(),
+            ring.byte_order(),
+            ring.num_coords(),
+            scratch,
+        )?;
+        let interior_ring = geos::Geometry::create_linear_ring(coord_seq)?;
+        interior_rings.push(interior_ring);
+    }
+
+    geos::Geometry::create_polygon(exterior, interior_rings)
+}
+
+fn multi_point_to_geos(scratch: &mut Vec<f64>, mp: &MultiPoint) -> 
GResult<geos::Geometry> {
+    let num_points = mp.num_points();
+    if num_points == 0 {
+        // Create an empty multi-point by creating a geometry collection with 
no geometries
+        
geos::Geometry::create_empty_collection(geos::GeometryTypes::MultiPoint)
+    } else {
+        let mut points = Vec::with_capacity(num_points);
+        for i in 0..num_points {
+            let point = unsafe { mp.point_unchecked(i) };
+            let geos_point = point_to_geos(scratch, &point)?;
+            points.push(geos_point);
+        }
+        geos::Geometry::create_multipoint(points)
+    }
+}
+
+fn multi_line_string_to_geos(
+    scratch: &mut Vec<f64>,
+    mls: &MultiLineString,
+) -> GResult<geos::Geometry> {
+    let num_line_strings = mls.num_line_strings();
+    if num_line_strings == 0 {
+        
geos::Geometry::create_empty_collection(geos::GeometryTypes::MultiLineString)
+    } else {
+        let mut line_strings = Vec::with_capacity(num_line_strings);
+        for i in 0..num_line_strings {
+            let ls = unsafe { mls.line_string_unchecked(i) };
+            let geos_line_string = line_string_to_geos(scratch, ls)?;
+            line_strings.push(geos_line_string);
+        }
+        geos::Geometry::create_multiline_string(line_strings)
+    }
+}
+
+fn multi_polygon_to_geos(scratch: &mut Vec<f64>, mpoly: &MultiPolygon) -> 
GResult<geos::Geometry> {
+    let num_polygons = mpoly.num_polygons();
+    if num_polygons == 0 {
+        
geos::Geometry::create_empty_collection(geos::GeometryTypes::MultiPolygon)
+    } else {
+        let mut polygons = Vec::with_capacity(num_polygons);
+        for i in 0..num_polygons {
+            let poly = unsafe { mpoly.polygon_unchecked(i) };
+            let geos_polygon = polygon_to_geos(scratch, poly)?;
+            polygons.push(geos_polygon);
+        }
+        geos::Geometry::create_multipolygon(polygons)
+    }
+}
+
+fn geometry_collection_to_geos(
+    scratch: &mut Vec<f64>,
+    gc: &GeometryCollection,
+) -> GResult<geos::Geometry> {
+    if gc.num_geometries() == 0 {
+        
geos::Geometry::create_empty_collection(geos::GeometryTypes::GeometryCollection)
+    } else {
+        let num_geometries = gc.num_geometries();
+        let mut geometries = Vec::with_capacity(num_geometries);
+        for i in 0..num_geometries {
+            let geom = gc.geometry(i).unwrap();
+            let geos_geom = geometry_to_geos(scratch, geom)?;
+            geometries.push(geos_geom);
+        }
+        geos::Geometry::create_geometry_collection(geometries)
+    }
+}
+
+const NATIVE_ENDIANNESS: Endianness = if cfg!(target_endian = "big") {
+    Endianness::BigEndian
+} else {
+    Endianness::LittleEndian
+};
+
+fn create_coord_sequence_from_raw_parts(
+    buf: &[u8],
+    dim: Dimension,
+    byte_order: Endianness,
+    num_coords: usize,
+    scratch: &mut Vec<f64>,
+) -> GResult<geos::CoordSeq> {
+    let (has_z, has_m, dim_size) = match dim {
+        Dimension::Xy => (false, false, 2),
+        Dimension::Xyz => (true, false, 3),
+        Dimension::Xym => (false, true, 3),
+        Dimension::Xyzm => (true, true, 4),
+    };
+    let num_ordinates = dim_size * num_coords;
+
+    // If the byte order matches native endianness, we can potentially use 
zero-copy
+    if byte_order == NATIVE_ENDIANNESS {
+        let ptr = buf.as_ptr();
+
+        // On platforms with unaligned memory access support, we can construct 
the coord seq
+        // directly from the raw parts without copying to the scratch buffer.
+        #[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
+        {
+            let coords_f64 =
+                unsafe { &*core::ptr::slice_from_raw_parts(ptr as *const f64, 
num_ordinates) };
+            geos::CoordSeq::new_from_buffer(coords_f64, num_coords, has_z, 
has_m)
+        }
+
+        // On platforms without unaligned memory access support, we need to 
copy the data to the
+        // scratch buffer to make sure the data is aligned.
+        #[cfg(not(any(target_arch = "aarch64", target_arch = "x86_64")))]
+        {
+            unsafe {
+                scratch.clear();
+                scratch.reserve(num_ordinates);
+                scratch.set_len(num_ordinates);
+                std::ptr::copy_nonoverlapping(
+                    ptr,
+                    scratch.as_mut_ptr() as *mut u8,
+                    num_ordinates * std::mem::size_of::<f64>(),
+                );
+                geos::CoordSeq::new_from_buffer(scratch.as_slice(), 
num_coords, has_z, has_m)
+            }
+        }
+    } else {
+        // Need to convert byte order
+        match byte_order {
+            Endianness::BigEndian => {
+                save_f64_to_scratch::<BigEndian>(scratch, buf, num_ordinates);
+            }
+            Endianness::LittleEndian => {
+                save_f64_to_scratch::<LittleEndian>(scratch, buf, 
num_ordinates);
+            }
+        }
+        geos::CoordSeq::new_from_buffer(scratch.as_slice(), num_coords, has_z, 
has_m)
+    }
+}
+
+fn save_f64_to_scratch<B: ByteOrder>(scratch: &mut Vec<f64>, buf: &[u8], 
num_ordinates: usize) {
+    scratch.clear();
+    scratch.reserve(num_ordinates);
+    // Safety: we have already reserved the capacity, so we can set the length 
safely.
+    // Justification: rewriting the loop to not use Vec::push makes it many 
times faster,
+    // since it eliminates several memory loads and stores for vector's length 
and capacity,
+    // and it enables the compiler to generate vectorized code.
+    #[allow(clippy::uninit_vec)]
+    unsafe {
+        scratch.set_len(num_ordinates);
+    }
+    assert!(num_ordinates * 8 <= buf.len());
+    for (i, tgt) in scratch.iter_mut().enumerate().take(num_ordinates) {
+        let offset = i * 8;
+        let value = B::read_f64(&buf[offset..]);
+        *tgt = value;
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use geo_types::{
+        line_string, point, polygon, Geometry, GeometryCollection, LineString, 
MultiLineString,
+        MultiPoint, MultiPolygon, Point, Polygon,
+    };
+    use geos::Geom;
+    use wkb::{
+        writer::{
+            write_geometry_collection, write_line_string, 
write_multi_line_string,
+            write_multi_point, write_multi_polygon, write_point, 
write_polygon, WriteOptions,
+        },
+        Endianness,
+    };
+
+    pub(super) fn point_2d() -> Point {
+        point!(
+            x: 0., y: 1.
+        )
+    }
+
+    pub(super) fn linestring_2d() -> LineString {
+        line_string![
+            (x: 0., y: 1.),
+            (x: 1., y: 2.)
+        ]
+    }
+
+    pub(super) fn polygon_2d() -> Polygon {
+        polygon![
+            (x: -111., y: 45.),
+            (x: -111., y: 41.),
+            (x: -104., y: 41.),
+            (x: -104., y: 45.),
+        ]
+    }
+
+    pub(super) fn polygon_2d_with_interior() -> Polygon {
+        polygon!(
+            exterior: [
+                (x: -111., y: 45.),
+                (x: -111., y: 41.),
+                (x: -104., y: 41.),
+                (x: -104., y: 45.),
+            ],
+            interiors: [
+                [
+                    (x: -110., y: 44.),
+                    (x: -110., y: 42.),
+                    (x: -105., y: 42.),
+                    (x: -105., y: 44.),
+                ],
+            ],
+        )
+    }
+
+    pub(super) fn multi_point_2d() -> MultiPoint {
+        MultiPoint::new(vec![
+            point!(
+                x: 0., y: 1.
+            ),
+            point!(
+                x: 1., y: 2.
+            ),
+        ])
+    }
+
+    pub(super) fn multi_line_string_2d() -> MultiLineString {
+        MultiLineString::new(vec![
+            line_string![
+                (x: -111., y: 45.),
+                (x: -111., y: 41.),
+                (x: -104., y: 41.),
+                (x: -104., y: 45.),
+            ],
+            line_string![
+                (x: -110., y: 44.),
+                (x: -110., y: 42.),
+                (x: -105., y: 42.),
+                (x: -105., y: 44.),
+            ],
+        ])
+    }
+
+    pub(super) fn multi_polygon_2d() -> MultiPolygon {
+        MultiPolygon::new(vec![
+            polygon![
+                (x: -111., y: 45.),
+                (x: -111., y: 41.),
+                (x: -104., y: 41.),
+                (x: -104., y: 45.),
+            ],
+            polygon!(
+                exterior: [
+                    (x: -111., y: 45.),
+                    (x: -111., y: 41.),
+                    (x: -104., y: 41.),
+                    (x: -104., y: 45.),
+                ],
+                interiors: [
+                    [
+                        (x: -110., y: 44.),
+                        (x: -110., y: 42.),
+                        (x: -105., y: 42.),
+                        (x: -105., y: 44.),
+                    ],
+                ],
+            ),
+        ])
+    }
+
+    pub(super) fn geometry_collection_2d() -> GeometryCollection {
+        GeometryCollection::new_from(vec![
+            Geometry::Point(point_2d()),
+            Geometry::LineString(linestring_2d()),
+            Geometry::Polygon(polygon_2d()),
+            Geometry::Polygon(polygon_2d_with_interior()),
+            Geometry::MultiPoint(multi_point_2d()),
+            Geometry::MultiLineString(multi_line_string_2d()),
+            Geometry::MultiPolygon(multi_polygon_2d()),
+        ])
+    }
+
+    fn test_geometry_conversion(geo_geom: &Geometry, endianness: Endianness) {
+        // Convert geo geometry to WKB
+        let mut buf = Vec::new();
+        let write_options = WriteOptions { endianness };
+        match geo_geom {
+            Geometry::Point(p) => write_point(&mut buf, p, 
&write_options).unwrap(),
+            Geometry::LineString(ls) => write_line_string(&mut buf, ls, 
&write_options).unwrap(),
+            Geometry::Polygon(p) => write_polygon(&mut buf, p, 
&write_options).unwrap(),
+            Geometry::MultiPoint(mp) => write_multi_point(&mut buf, mp, 
&write_options).unwrap(),
+            Geometry::MultiLineString(mls) => {
+                write_multi_line_string(&mut buf, mls, &write_options).unwrap()
+            }
+            Geometry::MultiPolygon(mp) => {
+                write_multi_polygon(&mut buf, mp, &write_options).unwrap()
+            }
+            Geometry::GeometryCollection(gc) => {
+                write_geometry_collection(&mut buf, gc, 
&write_options).unwrap()
+            }
+            Geometry::Line(_) => panic!("Line geometry not supported in 
tests"),
+            Geometry::Rect(_) => panic!("Rect geometry not supported in 
tests"),
+            Geometry::Triangle(_) => panic!("Triangle geometry not supported 
in tests"),
+        }
+
+        // Read WKB back
+        let wkb = wkb::reader::read_wkb(&buf).unwrap();
+
+        // Convert to GEOS using our ToGeos converter
+        let geos_geom = GEOSWkbFactory::new().create(&wkb).unwrap();
+
+        // Convert back to geo for comparison
+        let geo_from_geos: Geometry = geos_geom.try_into().unwrap();
+
+        // Compare the geometries
+        assert_eq!(*geo_geom, geo_from_geos);
+    }
+
+    #[test]
+    fn test_point_conversion() {
+        let point = point_2d();
+        let geo_geom = Geometry::Point(point);
+
+        test_geometry_conversion(&geo_geom, Endianness::LittleEndian);
+        test_geometry_conversion(&geo_geom, Endianness::BigEndian);
+    }
+
+    #[test]
+    fn test_empty_point_conversion() {
+        // Create an empty point by writing NaN coordinates
+        let mut buf = Vec::new();
+        buf.push(1); // Little endian
+        buf.extend_from_slice(&1u32.to_le_bytes()); // Point type
+        buf.extend_from_slice(&f64::NAN.to_le_bytes()); // x = NaN
+        buf.extend_from_slice(&f64::NAN.to_le_bytes()); // y = NaN
+
+        let wkb = read_wkb(&buf).unwrap();
+        let geos_geom = GEOSWkbFactory::new().create(&wkb).unwrap();
+
+        assert!(geos_geom.is_empty().unwrap());
+    }
+
+    #[test]
+    fn test_line_string_conversion() {
+        let line_string = linestring_2d();
+        let geo_geom = Geometry::LineString(line_string);
+
+        test_geometry_conversion(&geo_geom, Endianness::LittleEndian);
+        test_geometry_conversion(&geo_geom, Endianness::BigEndian);
+    }
+
+    #[test]
+    fn test_empty_line_string_conversion() {
+        let mut buf = Vec::new();
+        write_line_string(
+            &mut buf,
+            &LineString::new(vec![]),
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        )
+        .unwrap();
+
+        let wkb = read_wkb(&buf).unwrap();
+        let geos_geom = GEOSWkbFactory::new().create(&wkb).unwrap();
+
+        assert!(geos_geom.is_empty().unwrap());
+    }
+
+    #[test]
+    fn test_polygon_conversion() {
+        let polygon = polygon_2d();
+        let geo_geom = Geometry::Polygon(polygon);
+
+        test_geometry_conversion(&geo_geom, Endianness::LittleEndian);
+        test_geometry_conversion(&geo_geom, Endianness::BigEndian);
+    }
+
+    #[test]
+    fn test_polygon_with_interior_conversion() {
+        let polygon = polygon_2d_with_interior();
+        let geo_geom = Geometry::Polygon(polygon);
+
+        test_geometry_conversion(&geo_geom, Endianness::LittleEndian);
+        test_geometry_conversion(&geo_geom, Endianness::BigEndian);
+    }
+
+    #[test]
+    fn test_multi_point_conversion() {
+        let multi_point = multi_point_2d();
+        let geo_geom = Geometry::MultiPoint(multi_point);
+
+        test_geometry_conversion(&geo_geom, Endianness::LittleEndian);
+        test_geometry_conversion(&geo_geom, Endianness::BigEndian);
+    }
+
+    #[test]
+    fn test_empty_multi_point_conversion() {
+        let mut buf = Vec::new();
+        write_multi_point(
+            &mut buf,
+            &MultiPoint::new(vec![]),
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        )
+        .unwrap();
+
+        let wkb = read_wkb(&buf).unwrap();
+        let geos_geom = GEOSWkbFactory::new().create(&wkb).unwrap();
+
+        assert!(geos_geom.is_empty().unwrap());
+    }
+
+    #[test]
+    fn test_multi_line_string_conversion() {
+        let multi_line_string = multi_line_string_2d();
+        let geo_geom = Geometry::MultiLineString(multi_line_string);
+
+        test_geometry_conversion(&geo_geom, Endianness::LittleEndian);
+        test_geometry_conversion(&geo_geom, Endianness::BigEndian);
+    }
+
+    #[test]
+    fn test_empty_multi_line_string_conversion() {
+        let mut buf = Vec::new();
+        write_multi_line_string(
+            &mut buf,
+            &MultiLineString::new(vec![]),
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        )
+        .unwrap();
+
+        let wkb = read_wkb(&buf).unwrap();
+        let geos_geom = GEOSWkbFactory::new().create(&wkb).unwrap();
+
+        assert!(geos_geom.is_empty().unwrap());
+    }
+
+    #[test]
+    fn test_multi_polygon_conversion() {
+        let multi_polygon = multi_polygon_2d();
+        let geo_geom = Geometry::MultiPolygon(multi_polygon);
+
+        test_geometry_conversion(&geo_geom, Endianness::LittleEndian);
+        test_geometry_conversion(&geo_geom, Endianness::BigEndian);
+    }
+
+    #[test]
+    fn test_empty_multi_polygon_conversion() {
+        let mut buf = Vec::new();
+        write_multi_polygon(
+            &mut buf,
+            &MultiPolygon::new(vec![]),
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        )
+        .unwrap();
+
+        let wkb = read_wkb(&buf).unwrap();
+        let geos_geom = GEOSWkbFactory::new().create(&wkb).unwrap();
+
+        assert!(geos_geom.is_empty().unwrap());
+    }
+
+    #[test]
+    fn test_geometry_collection_conversion() {
+        let geometry_collection = geometry_collection_2d();
+        let geo_geom = Geometry::GeometryCollection(geometry_collection);
+
+        test_geometry_conversion(&geo_geom, Endianness::LittleEndian);
+        test_geometry_conversion(&geo_geom, Endianness::BigEndian);
+    }
+
+    #[test]
+    fn test_empty_geometry_collection_conversion() {
+        let mut buf = Vec::new();
+        write_geometry_collection(
+            &mut buf,
+            &GeometryCollection::new_from(vec![]),
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        )
+        .unwrap();
+
+        let wkb = read_wkb(&buf).unwrap();
+        let geos_geom = GEOSWkbFactory::new().create(&wkb).unwrap();
+
+        assert!(geos_geom.is_empty().unwrap());
+    }
+
+    #[test]
+    fn test_nested_geometry_collection() {
+        // Create a geometry collection containing other geometry collections
+        let inner_gc1 = GeometryCollection::new_from(vec![
+            Geometry::Point(point_2d()),
+            Geometry::LineString(linestring_2d()),
+        ]);
+
+        let inner_gc2 = GeometryCollection::new_from(vec![
+            Geometry::Polygon(polygon_2d()),
+            Geometry::MultiPoint(multi_point_2d()),
+        ]);
+
+        let outer_gc = GeometryCollection::new_from(vec![
+            Geometry::GeometryCollection(inner_gc1),
+            Geometry::GeometryCollection(inner_gc2),
+            Geometry::MultiLineString(multi_line_string_2d()),
+        ]);
+
+        let geo_geom = Geometry::GeometryCollection(outer_gc);
+
+        test_geometry_conversion(&geo_geom, Endianness::LittleEndian);
+        test_geometry_conversion(&geo_geom, Endianness::BigEndian);
+    }
+
+    #[test]
+    fn test_coordinate_precision() {
+        // Test with high precision coordinates
+        let high_precision_point = Point::new(123.456789012345, 
-98.765432109876);
+        let geo_geom = Geometry::Point(high_precision_point);
+
+        test_geometry_conversion(&geo_geom, Endianness::LittleEndian);
+        test_geometry_conversion(&geo_geom, Endianness::BigEndian);
+    }
+
+    #[test]
+    fn test_large_coordinates() {
+        // Test with very large coordinate values
+        let large_point = Point::new(1e10, -1e10);
+        let geo_geom = Geometry::Point(large_point);
+
+        test_geometry_conversion(&geo_geom, Endianness::LittleEndian);
+        test_geometry_conversion(&geo_geom, Endianness::BigEndian);
+    }
+
+    #[test]
+    fn test_negative_coordinates() {
+        // Test with negative coordinates
+        let negative_point = Point::new(-180.0, -90.0);
+        let geo_geom = Geometry::Point(negative_point);
+
+        test_geometry_conversion(&geo_geom, Endianness::LittleEndian);
+        test_geometry_conversion(&geo_geom, Endianness::BigEndian);
+    }
+
+    #[test]
+    fn test_zero_coordinates() {
+        // Test with zero coordinates
+        let zero_point = Point::new(0.0, 0.0);
+        let geo_geom = Geometry::Point(zero_point);
+
+        test_geometry_conversion(&geo_geom, Endianness::LittleEndian);
+        test_geometry_conversion(&geo_geom, Endianness::BigEndian);
+    }
+
+    #[test]
+    fn test_endianness_handling() {
+        let factory = GEOSWkbFactory::new();
+        // Test that both endianness variants work correctly
+        let point = point_2d();
+        let geo_geom = Geometry::Point(point);
+
+        // Test little endian
+        let mut buf_le = Vec::new();
+        write_point(
+            &mut buf_le,
+            &point_2d(),
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        )
+        .unwrap();
+        let wkb_le = read_wkb(&buf_le).unwrap();
+        let geos_geom_le = factory.create(&wkb_le).unwrap();
+        let geo_from_geos_le: Geometry = geos_geom_le.try_into().unwrap();
+
+        // Test big endian
+        let mut buf_be = Vec::new();
+        write_point(
+            &mut buf_be,
+            &point_2d(),
+            &WriteOptions {
+                endianness: Endianness::BigEndian,
+            },
+        )
+        .unwrap();
+        let wkb_be = read_wkb(&buf_be).unwrap();
+        let geos_geom_be = factory.create(&wkb_be).unwrap();
+        let geo_from_geos_be: Geometry = geos_geom_be.try_into().unwrap();
+
+        // Both should produce the same result
+        assert_eq!(geo_from_geos_le, geo_from_geos_be);
+        assert_eq!(geo_geom, geo_from_geos_le);
+    }
+
+    #[test]
+    fn test_xyz_dimension_handling() {
+        // Test XYZ dimension handling by manually creating WKB with XYZ 
coordinates
+        let mut buf = Vec::new();
+
+        // Write WKB header for LineString XYZ (type 1002)
+        buf.push(1); // Little endian
+        buf.extend_from_slice(&1002u32.to_le_bytes()); // LineString XYZ
+        buf.extend_from_slice(&2u32.to_le_bytes()); // 2 points
+
+        // Write XYZ coordinates: (0.0, 1.0, 10.0), (1.0, 2.0, 20.0)
+        buf.extend_from_slice(&0.0f64.to_le_bytes());
+        buf.extend_from_slice(&1.0f64.to_le_bytes());
+        buf.extend_from_slice(&10.0f64.to_le_bytes());
+        buf.extend_from_slice(&1.0f64.to_le_bytes());
+        buf.extend_from_slice(&2.0f64.to_le_bytes());
+        buf.extend_from_slice(&20.0f64.to_le_bytes());
+
+        let wkb = read_wkb(&buf).unwrap();
+        let geos_geom = GEOSWkbFactory::new().create(&wkb).unwrap();
+
+        // Verify the geometry was created successfully
+        assert!(!geos_geom.is_empty().unwrap());
+
+        // Verify coordinates by checking the WKT representation
+        let wkt = geos_geom.to_wkt().unwrap();
+        // Expected WKT for LineString with XYZ coordinates (0.0, 1.0, 10.0), 
(1.0, 2.0, 20.0)
+        let expected_wkt = "LINESTRING Z (0 1 10, 1 2 20)";
+        assert_eq!(wkt, expected_wkt);
+    }
+
+    #[test]
+    fn test_xym_dimension_handling() {
+        // Test XYM dimension handling by manually creating WKB with XYM 
coordinates
+        let mut buf = Vec::new();
+
+        // Write WKB header for LineString XYM (type 2002)
+        buf.push(1); // Little endian
+        buf.extend_from_slice(&2002u32.to_le_bytes()); // LineString XYM
+        buf.extend_from_slice(&2u32.to_le_bytes()); // 2 points
+
+        // Write XYM coordinates: (0.0, 1.0, 100.0), (1.0, 2.0, 200.0)
+        buf.extend_from_slice(&0.0f64.to_le_bytes());
+        buf.extend_from_slice(&1.0f64.to_le_bytes());
+        buf.extend_from_slice(&100.0f64.to_le_bytes());
+        buf.extend_from_slice(&1.0f64.to_le_bytes());
+        buf.extend_from_slice(&2.0f64.to_le_bytes());
+        buf.extend_from_slice(&200.0f64.to_le_bytes());
+
+        let wkb = read_wkb(&buf).unwrap();
+        let geos_geom = GEOSWkbFactory::new().create(&wkb).unwrap();
+
+        // Verify the geometry was created successfully
+        assert!(!geos_geom.is_empty().unwrap());
+
+        // Verify coordinates by checking the WKT representation
+        let wkt = geos_geom.to_wkt().unwrap();
+        // Expected WKT for LineString with XYM coordinates (0.0, 1.0, 100.0), 
(1.0, 2.0, 200.0)
+        let expected_wkt = "LINESTRING M (0 1 100, 1 2 200)";
+        assert_eq!(wkt, expected_wkt);
+    }
+
+    #[test]
+    fn test_xyzm_dimension_handling() {
+        // Test XYZM dimension handling by manually creating WKB with XYZM 
coordinates
+        let mut buf = Vec::new();
+
+        // Write WKB header for LineString XYZM (type 3002)
+        buf.push(1); // Little endian
+        buf.extend_from_slice(&3002u32.to_le_bytes()); // LineString XYZM
+        buf.extend_from_slice(&2u32.to_le_bytes()); // 2 points
+
+        // Write XYZM coordinates: (0.0, 1.0, 10.0, 100.0), (1.0, 2.0, 20.0, 
200.0)
+        buf.extend_from_slice(&0.0f64.to_le_bytes());
+        buf.extend_from_slice(&1.0f64.to_le_bytes());
+        buf.extend_from_slice(&10.0f64.to_le_bytes());
+        buf.extend_from_slice(&100.0f64.to_le_bytes());
+        buf.extend_from_slice(&1.0f64.to_le_bytes());
+        buf.extend_from_slice(&2.0f64.to_le_bytes());
+        buf.extend_from_slice(&20.0f64.to_le_bytes());
+        buf.extend_from_slice(&200.0f64.to_le_bytes());
+
+        let wkb = read_wkb(&buf).unwrap();
+        let geos_geom = GEOSWkbFactory::new().create(&wkb).unwrap();
+
+        // Verify the geometry was created successfully
+        assert!(!geos_geom.is_empty().unwrap());
+
+        // Verify coordinates by checking the WKT representation
+        let wkt = geos_geom.to_wkt().unwrap();
+        // Expected WKT for LineString with XYZM coordinates (0.0, 1.0, 10.0, 
100.0), (1.0, 2.0, 20.0, 200.0)
+        let expected_wkt = "LINESTRING ZM (0 1 10 100, 1 2 20 200)";
+        assert_eq!(wkt, expected_wkt);
+    }
+
+    #[test]
+    fn test_big_endian_xyz_dimension_handling() {
+        // Test XYZ dimension handling with big endian byte order
+        let mut buf = Vec::new();
+
+        // Write WKB header for LineString XYZ (type 1002) in big endian
+        buf.push(0); // Big endian
+        buf.extend_from_slice(&1002u32.to_be_bytes()); // LineString XYZ
+        buf.extend_from_slice(&2u32.to_be_bytes()); // 2 points
+
+        // Write XYZ coordinates in big endian: (0.0, 1.0, 10.0), (1.0, 2.0, 
20.0)
+        buf.extend_from_slice(&0.0f64.to_be_bytes());
+        buf.extend_from_slice(&1.0f64.to_be_bytes());
+        buf.extend_from_slice(&10.0f64.to_be_bytes());
+        buf.extend_from_slice(&1.0f64.to_be_bytes());
+        buf.extend_from_slice(&2.0f64.to_be_bytes());
+        buf.extend_from_slice(&20.0f64.to_be_bytes());
+
+        let wkb = read_wkb(&buf).unwrap();
+        let geos_geom = GEOSWkbFactory::new().create(&wkb).unwrap();
+
+        // Verify the geometry was created successfully
+        assert!(!geos_geom.is_empty().unwrap());
+
+        // Verify coordinates by checking the WKT representation
+        let wkt = geos_geom.to_wkt().unwrap();
+        // Expected WKT for LineString with XYZ coordinates (0.0, 1.0, 10.0), 
(1.0, 2.0, 20.0)
+        let expected_wkt = "LINESTRING Z (0 1 10, 1 2 20)";
+        assert_eq!(wkt, expected_wkt);
+    }
+
+    /// Represents a single WKB test case, holding the expected geometry type, 
Dimension,
+    /// the raw WKB bytes, and the WKT string.
+    /// This is the direct Rust equivalent of your C++ `WKBTestCase` struct, 
with WKT added.
+    #[derive(Debug, PartialEq, Clone)]
+    pub struct WkbTestCase {
+        pub dimension: Dimension,
+        pub wkb_bytes: Vec<u8>,
+        pub wkt_string: String, // Added WKT field
+    }
+
+    // You can then define your test cases as a `Vec<WkbTestCase>`
+    pub fn get_wkb_test_cases() -> Vec<WkbTestCase> {
+        vec![
+            // POINT EMPTY
+            WkbTestCase {
+                dimension: Dimension::Xy,
+                wkb_bytes: vec![
+                    0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0xf8, 0x7f,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f,
+                ],
+                wkt_string: "POINT EMPTY".to_string(),
+            },
+            // POINT (30 10)
+            WkbTestCase {
+                dimension: Dimension::Xy,
+                wkb_bytes: vec![
+                    0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x3e, 0x40,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40,
+                ],
+                wkt_string: "POINT (30 10)".to_string(),
+            },
+            // POINT Z (30 10 40)
+            WkbTestCase {
+                dimension: Dimension::Xyz,
+                wkb_bytes: vec![
+                    0x01, 0xe9, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x3e, 0x40,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x44, 0x40,
+                ],
+                wkt_string: "POINT Z (30 10 40)".to_string(),
+            },
+            // POINT M (30 10 300)
+            WkbTestCase {
+                dimension: Dimension::Xym,
+                wkb_bytes: vec![
+                    0x01, 0xd1, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x3e, 0x40,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0xc0, 0x72, 0x40,
+                ],
+                wkt_string: "POINT M (30 10 300)".to_string(),
+            },
+            // POINT ZM (30 10 40 300)
+            WkbTestCase {
+                dimension: Dimension::Xyzm,
+                wkb_bytes: vec![
+                    0x01, 0xb9, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x3e, 0x40,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 
0x72, 0x40,
+                ],
+                wkt_string: "POINT ZM (30 10 40 300)".to_string(),
+            },
+            // POINT (30 10) (big endian)
+            WkbTestCase {
+                dimension: Dimension::Xy,
+                wkb_bytes: vec![
+                    0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x3e, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x40, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                ],
+                wkt_string: "POINT (30 10)".to_string(), // WKT is 
endian-agnostic
+            },
+            // LINESTRING EMPTY
+            WkbTestCase {
+                dimension: Dimension::Xy,
+                wkb_bytes: vec![0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00],
+                wkt_string: "LINESTRING EMPTY".to_string(),
+            },
+            // LINESTRING (30 10, 10 30, 40 40)
+            WkbTestCase {
+                dimension: Dimension::Xy,
+                wkb_bytes: vec![
+                    0x01, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x24, 0x40, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 
0x40, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x44, 0x40,
+                ],
+                wkt_string: "LINESTRING (30 10, 10 30, 40 40)".to_string(),
+            },
+            // LINESTRING Z (30 10 40, 10 30 40, 40 40 80)
+            WkbTestCase {
+                dimension: Dimension::Xyz,
+                wkb_bytes: vec![
+                    0x01, 0xea, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 
0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 
0x00, 0x00,
+                    0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x44, 0x40,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 
0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00,
+                    0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 
0x40, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 
0x00, 0x00,
+                    0x00, 0x00, 0x54, 0x40
+                ],
+                wkt_string: "LINESTRING Z (30 10 40, 10 30 40, 40 40 
80)".to_string(),
+            },
+            // LINESTRING M (30 10 300, 10 30 300, 40 40 1600)
+            WkbTestCase {
+                dimension: Dimension::Xym,
+                wkb_bytes: vec![
+                    0x01, 0xd2, 0x07, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x24, 0x40, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 0x40, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 
0x40, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0xc0, 0x72, 0x40, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x44, 0x40,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x99, 0x40,
+                ],
+                wkt_string: "LINESTRING M (30 10 300, 10 30 300, 40 40 
1600)".to_string(),
+            },
+            // LINESTRING ZM (30 10 40 300, 10 30 40 300, 40 40 80 1600)
+            WkbTestCase {
+                dimension: Dimension::Xyzm,
+                wkb_bytes: vec![
+                    0x01, 0xba, 0x0b, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 
0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 
0x00, 0x00,
+                    0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x44, 0x40,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 0x40, 0x00, 
0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00,
+                    0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 
0x40, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 0x40, 0x00, 0x00, 
0x00, 0x00,
+                    0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x44,
+                    0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x40, 
0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x99, 0x40,
+                ],
+                wkt_string: "LINESTRING ZM (30 10 40 300, 10 30 40 300, 40 40 
80 1600)".to_string(),
+            },
+            // LINESTRING (30 10, 10 30, 40 40) (big endian)
+            WkbTestCase {
+                dimension: Dimension::Xy,
+                wkb_bytes: vec![
+                    0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 
0x40, 0x3e, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x40, 0x24, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x40,
+                    0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x3e, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x40, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x40, 0x44, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00,
+                ],
+                wkt_string: "LINESTRING (30 10, 10 30, 40 40)".to_string(),
+            },
+            // POLYGON EMPTY
+            WkbTestCase {
+                dimension: Dimension::Xy,
+                wkb_bytes: vec![0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00],
+                wkt_string: "POLYGON EMPTY".to_string(),
+            },
+            // POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))
+            WkbTestCase {
+                dimension: Dimension::Xy,
+                wkb_bytes: vec![
+                    0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x05, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x44, 0x40, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x34,
+                    0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x34, 0x40, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x24, 0x40,
+                ],
+                wkt_string: "POLYGON ((30 10, 40 40, 20 40, 10 20, 30 
10))".to_string(),
+            },
+            // POLYGON Z ((30 10 40, 40 40 80, 20 40 60, 10 20 30, 30 10 40))
+            WkbTestCase {
+                dimension: Dimension::Xyz,
+                wkb_bytes: vec![
+                    0x01, 0xeb, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x05, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x44, 0x40, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x44,
+                    0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x40, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x34, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x44, 0x40, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x40, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 
0x40, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x3e, 0x40,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x44, 0x40,
+                ],
+                wkt_string: "POLYGON Z ((30 10 40, 40 40 80, 20 40 60, 10 20 
30, 30 10 40))".to_string(),
+            },
+            // POLYGON M ((30 10 300, 40 40 1600, 20 40 800, 10 20 200, 30 10 
300))
+            WkbTestCase {
+                dimension: Dimension::Xym,
+                wkb_bytes: vec![
+                    0x01, 0xd3, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x05, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 
0x72, 0x40, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x44,
+                    0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x40, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x34, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x44, 0x40, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x40, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 
0x40, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x69, 0x40, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x3e, 0x40,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0xc0, 0x72, 0x40,
+                ],
+                wkt_string: "POLYGON M ((30 10 300, 40 40 1600, 20 40 800, 10 
20 200, 30 10 300))".to_string(),
+            },
+            // POLYGON ZM ((30 10 40 300, 40 40 80 1600, 20 40 60 800, 10 20 
30 200, 30
+            // 10 40 300))
+            WkbTestCase {
+                dimension: Dimension::Xyzm,
+                wkb_bytes: vec![
+                    0x01, 0xbb, 0x0b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x05, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x44, 0x40, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0xc0, 0x72, 0x40, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x44,
+                    0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x54, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x99, 0x40, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 
0x40, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x89, 0x40, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x24, 0x40,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x69, 0x40, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x24,
+                    0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0xc0, 0x72, 0x40,
+                ],
+                wkt_string: "POLYGON ZM ((30 10 40 300, 40 40 80 1600, 20 40 
60 800, 10 20 30 200, 30 10 40 300))".to_string(),
+            },
+            // MULTIPOINT EMPTY
+            WkbTestCase {
+                dimension: Dimension::Xy,
+                wkb_bytes: vec![0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00],
+                wkt_string: "MULTIPOINT EMPTY".to_string(),
+            },
+            // MULTIPOINT ((30 10))
+            WkbTestCase {
+                dimension: Dimension::Xy,
+                wkb_bytes: vec![
+                    0x01, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x01, 0x01, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x24, 0x40,
+                ],
+                wkt_string: "MULTIPOINT ((30 10))".to_string(),
+            },
+            // MULTIPOINT Z ((30 10 40))
+            WkbTestCase {
+                dimension: Dimension::Xyz,
+                wkb_bytes: vec![
+                    0x01, 0xec, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x01, 0xe9, 0x03, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x44, 0x40,
+                ],
+                wkt_string: "MULTIPOINT Z ((30 10 40))".to_string(),
+            },
+            // MULTIPOINT M ((30 10 300))
+            WkbTestCase {
+                dimension: Dimension::Xym,
+                wkb_bytes: vec![
+                    0x01, 0xd4, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x01, 0xd1, 0x07, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0xc0, 0x72, 0x40,
+                ],
+                wkt_string: "MULTIPOINT M ((30 10 300))".to_string(),
+            },
+            // MULTIPOINT ZM ((30 10 40 300))
+            WkbTestCase {
+                dimension: Dimension::Xyzm,
+                wkb_bytes: vec![
+                    0x01, 0xbc, 0x0b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x01, 0xb9, 0x0b, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x44, 0x40, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 0x40,
+                ],
+                wkt_string: "MULTIPOINT ZM ((30 10 40 300))".to_string(),
+            },
+            // MULTILINESTRING EMPTY
+            WkbTestCase {
+                dimension: Dimension::Xy,
+                wkb_bytes: vec![0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00],
+                wkt_string: "MULTILINESTRING EMPTY".to_string(),
+            },
+            // MULTILINESTRING ((30 10, 10 30, 40 40))
+            WkbTestCase {
+                dimension: Dimension::Xy,
+                wkb_bytes: vec![
+                    0x01, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x01, 0x02, 0x00, 0x00,
+                    0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x3e, 0x40,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x3e, 0x40, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x44,
+                    0x40,
+                ],
+                wkt_string: "MULTILINESTRING ((30 10, 10 30, 40 
40))".to_string(),
+            },
+            // MULTILINESTRING Z ((30 10 40, 10 30 40, 40 40 80))
+            WkbTestCase {
+                dimension: Dimension::Xyz,
+                wkb_bytes: vec![
+                    0x01, 0xed, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x01, 0xea, 0x03, 0x00,
+                    0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x3e, 0x40,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x24, 0x40, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x44,
+                    0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x54, 0x40,
+                ],
+                wkt_string: "MULTILINESTRING Z ((30 10 40, 10 30 40, 40 40 
80))".to_string(),
+            },
+            // MULTILINESTRING M ((30 10 300, 10 30 300, 40 40 1600))
+            WkbTestCase {
+                dimension: Dimension::Xym,
+                wkb_bytes: vec![
+                    0x01, 0xd5, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x01, 0xd2, 0x07, 0x00,
+                    0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x3e, 0x40,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0xc0, 0x72, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x24, 0x40, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 
0x00, 0x00, 0xc0, 0x72,
+                    0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x99, 0x40,
+                ],
+                wkt_string: "MULTILINESTRING M ((30 10 300, 10 30 300, 40 40 
1600))".to_string(),
+            },
+            // MULTILINESTRING ZM ((30 10 40 300, 10 30 40 300, 40 40 80 1600))
+            WkbTestCase {
+                dimension: Dimension::Xyzm,
+                wkb_bytes: vec![
+                    0x01, 0xbd, 0x0b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x01, 0xba, 0x0b, 0x00,
+                0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x3e, 0x40,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 
0x00, 0x00, 0x00,
+                0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 
0x40, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x3e,
+                0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 
0x00, 0x00, 0x00,
+                0x00, 0xc0, 0x72, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x44, 0x40, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00,
+                0x54, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x40
+                ],
+                wkt_string: "MULTILINESTRING ZM ((30 10 40 300, 10 30 40 300, 
40 40 80 1600))".to_string(),
+            },
+            // MULTIPOLYGON EMPTY
+            WkbTestCase {
+                dimension: Dimension::Xy,
+                wkb_bytes: vec![0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00],
+                wkt_string: "MULTIPOLYGON EMPTY".to_string(),
+            },
+            // MULTIPOLYGON (((30 10, 40 40, 20 40, 10 20, 30 10)))
+            WkbTestCase {
+                dimension: Dimension::Xy,
+                wkb_bytes: vec![
+                    0x01, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x01, 0x03, 0x00, 0x00,
+                    0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x24, 0x40, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 
0x40, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x24, 0x40,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x24, 0x40,
+                ],
+                wkt_string: "MULTIPOLYGON (((30 10, 40 40, 20 40, 10 20, 30 
10)))".to_string(),
+            },
+            // MULTIPOLYGON Z (((30 10 40, 40 40 80, 20 40 60, 10 20 30, 30 10 
40)))
+            WkbTestCase {
+                dimension: Dimension::Xyz,
+                wkb_bytes: vec![
+                    0x01, 0xee, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x01, 0xeb, 0x03, 0x00,
+                    0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x24, 0x40, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 
0x40, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x54, 0x40, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x34, 0x40,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x4e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x24, 0x40, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x3e,
+                    0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x44, 0x40,
+                ],
+                wkt_string: "MULTIPOLYGON Z (((30 10 40, 40 40 80, 20 40 60, 
10 20 30, 30 10 40)))".to_string(),
+            },
+            // MULTIPOLYGON M (((30 10 300, 40 40 1600, 20 40 800, 10 20 200, 
30 10 300)))
+            WkbTestCase {
+                dimension: Dimension::Xym,
+                wkb_bytes: vec![
+                    0x01, 0xd6, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x01, 0xd3, 0x07, 0x00,
+                    0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x24, 0x40, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 0x40, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 
0x40, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x99, 0x40, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x34, 0x40,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x89, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x24, 0x40, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x69,
+                    0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0xc0, 0x72, 0x40,
+                ],
+                wkt_string: "MULTIPOLYGON M (((30 10 300, 40 40 1600, 20 40 
800, 10 20 200, 30 10 300)))".to_string(),
+            },
+            // MULTIPOLYGON ZM (((30 10 40 300, 40 40 80 1600, 20 40 60 800, 
10 20 30 200, 30
+            // 10 40 300)))
+            WkbTestCase {
+                dimension: Dimension::Xyzm,
+                wkb_bytes: vec![
+                    0x01, 0xbe, 0x0b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x01, 0xbb, 0x0b, 0x00,
+                    0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x24, 0x40, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 
0x00, 0x00, 0x00, 0xc0,
+                    0x72, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 
0x40, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x54, 0x40,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x40, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x34, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x44, 0x40, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x4e, 0x40, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x89,
+                    0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x34, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x3e, 0x40, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x40, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
+                    0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 
0x40, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 
0x00, 0xc0, 0x72, 0x40,
+                ],
+                wkt_string: "MULTIPOLYGON ZM (((30 10 40 300, 40 40 80 1600, 
20 40 60 800, 10 20 30 200, 30 10 40 300)))".to_string(),
+            },
+            // GEOMETRYCOLLECTION EMPTY
+            WkbTestCase {
+                dimension: Dimension::Xy,
+                wkb_bytes: vec![0x01, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00],
+                wkt_string: "GEOMETRYCOLLECTION EMPTY".to_string(),
+            },
+            // GEOMETRYCOLLECTION (POINT (30 10))
+            WkbTestCase {
+                dimension: Dimension::Xy,
+                wkb_bytes: vec![
+                    0x01, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x01, 0x01, 0x00, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x24, 0x40,
+                ],
+                wkt_string: "GEOMETRYCOLLECTION (POINT (30 10))".to_string(),
+            },
+            // GEOMETRYCOLLECTION Z (POINT Z (30 10 40))
+            WkbTestCase {
+                dimension: Dimension::Xyz,
+                wkb_bytes: vec![
+                    0x01, 0xef, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x01, 0xe9, 0x03, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x44, 0x40,
+                ],
+                wkt_string: "GEOMETRYCOLLECTION Z (POINT Z (30 10 
40))".to_string(),
+            },
+            // GEOMETRYCOLLECTION M (POINT M (30 10 300))
+            WkbTestCase {
+                dimension: Dimension::Xym,
+                wkb_bytes: vec![
+                    0x01, 0xd7, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x01, 0xd1, 0x07, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0xc0, 0x72, 0x40,
+                ],
+                wkt_string: "GEOMETRYCOLLECTION M (POINT M (30 10 
300))".to_string(),
+            },
+            // GEOMETRYCOLLECTION ZM (POINT ZM (30 10 40 300))
+            WkbTestCase {
+                dimension: Dimension::Xyzm,
+                wkb_bytes: vec![
+                    0x01, 0xbf, 0x0b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
0x01, 0xb9, 0x0b, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 
0x00, 0x00, 0x00, 0x00,
+                    0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x44, 0x40, 0x00,
+                    0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 0x40,
+                ],
+                wkt_string: "GEOMETRYCOLLECTION ZM (POINT ZM (30 10 40 
300))".to_string(),
+            },
+        ]
+    }
+
+    #[test]
+    fn test_using_comprehensive_cases() {
+        let factory = GEOSWkbFactory::new();
+        let test_cases = get_wkb_test_cases();
+        for test_case in test_cases {
+            let wkb = read_wkb(&test_case.wkb_bytes).unwrap();
+            let geos_geom = factory.create(&wkb).unwrap();
+            let wkt_from_geos = geos_geom.to_wkt().unwrap();
+            assert_eq!(
+                wkt_from_geos, test_case.wkt_string,
+                "Failed for test case {}",
+                test_case.wkt_string
+            );
+        }
+    }
+}
diff --git a/c/sedona-tg/benches/parse-wkb.rs b/c/sedona-tg/benches/parse-wkb.rs
index 9632afe..79a920d 100644
--- a/c/sedona-tg/benches/parse-wkb.rs
+++ b/c/sedona-tg/benches/parse-wkb.rs
@@ -27,14 +27,18 @@ fn criterion_benchmark(c: &mut Criterion) {
     wkb::writer::write_geometry(
         &mut large_geom_wkb_big_endian,
         &large_geom,
-        wkb::Endianness::BigEndian,
+        &wkb::writer::WriteOptions {
+            endianness: wkb::Endianness::BigEndian,
+        },
     )
     .unwrap();
     let mut large_geom_wkb_little_endian = Vec::new();
     wkb::writer::write_geometry(
         &mut large_geom_wkb_little_endian,
         &large_geom,
-        wkb::Endianness::LittleEndian,
+        &wkb::writer::WriteOptions {
+            endianness: wkb::Endianness::LittleEndian,
+        },
     )
     .unwrap();
 
diff --git a/rust/sedona-functions/src/st_geomfromwkt.rs 
b/rust/sedona-functions/src/st_geomfromwkt.rs
index b35d628..558fbec 100644
--- a/rust/sedona-functions/src/st_geomfromwkt.rs
+++ b/rust/sedona-functions/src/st_geomfromwkt.rs
@@ -29,7 +29,8 @@ use sedona_schema::{
     datatypes::{SedonaType, WKB_GEOGRAPHY, WKB_GEOMETRY},
     matchers::ArgMatcher,
 };
-use wkb::writer::write_geometry;
+use wkb::writer::{write_geometry, WriteOptions};
+use wkb::Endianness;
 use wkt::Wkt;
 
 use crate::executor::WkbExecutor;
@@ -128,8 +129,14 @@ fn invoke_scalar(wkt_bytes: &str, builder: &mut 
BinaryBuilder) -> Result<()> {
     let geometry: Wkt<f64> = Wkt::from_str(wkt_bytes)
         .map_err(|err| DataFusionError::Internal(format!("WKT parse error: 
{err}")))?;
 
-    write_geometry(builder, &geometry, wkb::Endianness::LittleEndian)
-        .map_err(|err| DataFusionError::Internal(format!("WKB write error: 
{err}")))
+    write_geometry(
+        builder,
+        &geometry,
+        &WriteOptions {
+            endianness: Endianness::LittleEndian,
+        },
+    )
+    .map_err(|err| DataFusionError::Internal(format!("WKB write error: 
{err}")))
 }
 
 #[cfg(test)]
diff --git a/rust/sedona-geo-generic-alg/Cargo.toml 
b/rust/sedona-geo-generic-alg/Cargo.toml
index 666d42b..2cbcd36 100644
--- a/rust/sedona-geo-generic-alg/Cargo.toml
+++ b/rust/sedona-geo-generic-alg/Cargo.toml
@@ -16,40 +16,35 @@
 # under the License.
 [package]
 name = "sedona-geo-generic-alg"
-version = "0.2.0"
-authors = ["Apache Sedona <[email protected]>"]
-license = "Apache-2.0"
-homepage = "https://github.com/apache/sedona-db";
-repository = "https://github.com/apache/sedona-db";
-description = "geo algorithms refactored to work with sedona-geo-traits-ext"
-readme = "README.md"
-edition = "2021"
-
-[workspace]
+version.workspace = true
+homepage.workspace = true
+repository.workspace = true
+description.workspace = true
+readme.workspace = true
+edition.workspace = true
+rust-version.workspace = true
 
 [dependencies]
-float_next_after = "1"
-geo-traits = { version = "0.3.0" }
-geo-types = { version = "0.7.17", features = ["approx", "use-rstar_0_12"] }
+float_next_after = { workspace = true }
+geo-traits = { workspace = true }
+geo-types = { workspace = true, features = ["approx", "use-rstar_0_12"] }
 sedona-geo-traits-ext = { path = "../sedona-geo-traits-ext" }
 log = "0.4.11"
-num-traits = { version = "0.2", default-features = false, features = ["libm"] }
+num-traits = { workspace = true }
 robust = "1.1.0"
 rstar = "0.12.0"
 i_overlay = { version = "4.0.0, < 4.1.0", default-features = false }
 
 [dev-dependencies]
-approx = "0.5"
-criterion = { version = "0.5", features = ["html_reports"] }
+sedona-testing = { path = "../sedona-testing" }
+approx = { workspace = true }
+criterion = { workspace = true }
 pretty_env_logger = "0.4"
-rand = "0.8"
+rand = { workspace = true }
 rand_distr = "0.4.3"
-geo = "0.31.0"
-wkb = "0.9.1"
-wkt = "0.14.0"
-
-[patch.crates-io]
-wkb = { git = "https://github.com/georust/wkb.git";, rev = 
"130eb0c2b343bc9299aeafba6d34c2a6e53f3b6a" }
+geo = { workspace = true }
+wkb = { workspace = true }
+wkt = { workspace = true }
 
 [[bench]]
 name = "area"
diff --git a/rust/sedona-geo-traits-ext/Cargo.toml 
b/rust/sedona-geo-traits-ext/Cargo.toml
index 9a2a465..fb9a495 100644
--- a/rust/sedona-geo-traits-ext/Cargo.toml
+++ b/rust/sedona-geo-traits-ext/Cargo.toml
@@ -16,27 +16,21 @@
 # under the License.
 [package]
 name = "sedona-geo-traits-ext"
-version = "0.2.0"
-authors = ["Apache Sedona <[email protected]>"]
-license = "Apache-2.0"
-homepage = "https://github.com/apache/sedona-db";
-repository = "https://github.com/apache/sedona-db";
-description = "geo-traits extended for implementing generic algorithms"
-readme = "README.md"
-edition = "2021"
-
-[workspace]
+version.workspace = true
+homepage.workspace = true
+repository.workspace = true
+description.workspace = true
+readme.workspace = true
+edition.workspace = true
+rust-version.workspace = true
 
 [dependencies]
-geo-traits = "0.3.0"
-geo-types = "0.7.17"
-num-traits = { version = "0.2", default-features = false, features = ["libm"] }
-wkb = "0.9.1"
-byteorder = "1"
+geo-traits = { workspace = true }
+geo-types = { workspace = true }
+num-traits = { workspace = true }
+wkb = { workspace = true }
+byteorder ={ workspace = true }
 
 [dev-dependencies]
-wkt = "0.14.0"
-rstest = "0.24.0"
-
-[patch.crates-io]
-wkb = { git = "https://github.com/georust/wkb.git";, rev = 
"130eb0c2b343bc9299aeafba6d34c2a6e53f3b6a" }
+wkt = { workspace = true }
+rstest = { workspace = true }
diff --git a/rust/sedona-geo/Cargo.toml b/rust/sedona-geo/Cargo.toml
index f9c947a..df43918 100644
--- a/rust/sedona-geo/Cargo.toml
+++ b/rust/sedona-geo/Cargo.toml
@@ -32,7 +32,7 @@ criterion = { workspace = true }
 rstest = { workspace = true }
 sedona-geometry = { path = "../sedona-geometry" }
 sedona-schema = { path = "../sedona-schema" }
-sedona-testing = { path = "../sedona-testing", features = ["criterion"] }
+sedona-testing = { path = "../sedona-testing", features = ["criterion", "geo"] 
}
 wkt = { workspace = true }
 
 [dependencies]
@@ -40,7 +40,7 @@ arrow-schema = { workspace = true }
 arrow-array = { workspace = true }
 datafusion-common = { workspace = true }
 datafusion-expr = { workspace = true }
-geo-generic-alg = { workspace = true }
+sedona-geo-generic-alg = { path = "../sedona-geo-generic-alg" }
 geo-traits = { workspace = true, features = ["geo-types"] }
 geo-types = { workspace = true }
 geo = { workspace = true }
diff --git a/rust/sedona-geo/src/centroid.rs b/rust/sedona-geo/src/centroid.rs
index e7ab25f..ee74df1 100644
--- a/rust/sedona-geo/src/centroid.rs
+++ b/rust/sedona-geo/src/centroid.rs
@@ -17,11 +17,11 @@
 //! Centroid extraction functionality for WKB geometries
 
 use datafusion_common::{error::DataFusionError, Result};
-use geo_generic_alg::Centroid;
-use geo_generic_alg::HasDimensions;
 use geo_traits::CoordTrait;
 use geo_traits::GeometryTrait;
 use geo_traits::PointTrait;
+use sedona_geo_generic_alg::Centroid;
+use sedona_geo_generic_alg::HasDimensions;
 
 use crate::to_geo::item_to_geometry;
 
diff --git a/rust/sedona-geo/src/st_area.rs b/rust/sedona-geo/src/st_area.rs
index 8a274d5..5efd5f0 100644
--- a/rust/sedona-geo/src/st_area.rs
+++ b/rust/sedona-geo/src/st_area.rs
@@ -20,9 +20,9 @@ use arrow_array::builder::Float64Builder;
 use arrow_schema::DataType;
 use datafusion_common::error::Result;
 use datafusion_expr::ColumnarValue;
-use geo_generic_alg::Area;
 use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel};
 use sedona_functions::executor::WkbExecutor;
+use sedona_geo_generic_alg::Area;
 use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher};
 use wkb::reader::Wkb;
 
diff --git a/rust/sedona-geo/src/st_centroid.rs 
b/rust/sedona-geo/src/st_centroid.rs
index 31c3dd7..bc6b818 100644
--- a/rust/sedona-geo/src/st_centroid.rs
+++ b/rust/sedona-geo/src/st_centroid.rs
@@ -20,9 +20,9 @@ use std::sync::Arc;
 use arrow_array::builder::BinaryBuilder;
 use datafusion_common::{error::Result, exec_err};
 use datafusion_expr::ColumnarValue;
-use geo_generic_alg::Centroid;
 use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel};
 use sedona_functions::executor::WkbExecutor;
+use sedona_geo_generic_alg::Centroid;
 use sedona_geometry::is_empty::is_geometry_empty;
 use sedona_schema::{
     datatypes::{SedonaType, WKB_GEOMETRY},
diff --git a/rust/sedona-geo/src/st_distance.rs 
b/rust/sedona-geo/src/st_distance.rs
index 4900690..e2f48a1 100644
--- a/rust/sedona-geo/src/st_distance.rs
+++ b/rust/sedona-geo/src/st_distance.rs
@@ -20,9 +20,9 @@ use arrow_array::builder::Float64Builder;
 use arrow_schema::DataType;
 use datafusion_common::error::Result;
 use datafusion_expr::ColumnarValue;
-use geo_generic_alg::line_measures::DistanceExt;
 use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel};
 use sedona_functions::executor::WkbExecutor;
+use sedona_geo_generic_alg::line_measures::DistanceExt;
 use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher};
 use wkb::reader::Wkb;
 
diff --git a/rust/sedona-geo/src/st_dwithin.rs 
b/rust/sedona-geo/src/st_dwithin.rs
index 2ba3f5d..25e8bf2 100644
--- a/rust/sedona-geo/src/st_dwithin.rs
+++ b/rust/sedona-geo/src/st_dwithin.rs
@@ -20,9 +20,9 @@ use arrow_array::builder::BooleanBuilder;
 use arrow_schema::DataType;
 use datafusion_common::{cast::as_float64_array, error::Result};
 use datafusion_expr::ColumnarValue;
-use geo_generic_alg::line_measures::DistanceExt;
 use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel};
 use sedona_functions::executor::WkbExecutor;
+use sedona_geo_generic_alg::line_measures::DistanceExt;
 use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher};
 use wkb::reader::Wkb;
 
diff --git a/rust/sedona-geo/src/st_intersection_aggr.rs 
b/rust/sedona-geo/src/st_intersection_aggr.rs
index 446290f..b9cad44 100644
--- a/rust/sedona-geo/src/st_intersection_aggr.rs
+++ b/rust/sedona-geo/src/st_intersection_aggr.rs
@@ -31,9 +31,9 @@ use sedona_schema::{
     datatypes::{SedonaType, WKB_GEOMETRY},
     matchers::ArgMatcher,
 };
-use wkb::reader::Wkb;
 use wkb::writer::write_geometry;
 use wkb::Endianness;
+use wkb::{reader::Wkb, writer::WriteOptions};
 
 /// ST_Intersection_Aggr() implementation
 pub fn st_intersection_aggr_impl() -> SedonaAccumulatorRef {
@@ -133,7 +133,13 @@ impl IntersectionAccumulator {
 
     fn geometry_to_wkb(&self, geom: &geo::Geometry) -> Option<Vec<u8>> {
         let mut wkb_bytes = Vec::new();
-        match write_geometry(&mut wkb_bytes, geom, Endianness::LittleEndian) {
+        match write_geometry(
+            &mut wkb_bytes,
+            geom,
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        ) {
             Ok(_) => Some(wkb_bytes),
             Err(_) => None,
         }
@@ -223,7 +229,9 @@ mod test {
     use rstest::rstest;
     use sedona_functions::st_intersection_aggr::st_intersection_aggr_udf;
     use sedona_schema::datatypes::WKB_VIEW_GEOMETRY;
-    use sedona_testing::{compare::assert_scalar_equal_wkb_geometry, 
testers::AggregateUdfTester};
+    use sedona_testing::{
+        compare::assert_scalar_equal_wkb_geometry_topologically, 
testers::AggregateUdfTester,
+    };
 
     #[rstest]
     fn polygon_polygon_cases(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] 
sedona_type: SedonaType) {
@@ -238,16 +246,19 @@ mod test {
             vec![Some("POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))")],
             vec![Some("POLYGON((1 1, 3 1, 3 3, 1 3, 1 1))")],
         ];
-        assert_scalar_equal_wkb_geometry(
+        assert_scalar_equal_wkb_geometry_topologically(
             &tester.aggregate_wkt(batches).unwrap(),
             Some("MULTIPOLYGON(((1 1, 2 1, 2 2, 1 2, 1 1)))"),
         );
 
         // Empty input
-        
assert_scalar_equal_wkb_geometry(&tester.aggregate_wkt(vec![]).unwrap(), None);
+        assert_scalar_equal_wkb_geometry_topologically(
+            &tester.aggregate_wkt(vec![]).unwrap(),
+            None,
+        );
 
         // Single polygon input
-        assert_scalar_equal_wkb_geometry(
+        assert_scalar_equal_wkb_geometry_topologically(
             &tester
                 .aggregate_wkt(vec![vec![Some("POLYGON((0 0, 2 0, 2 2, 0 2, 0 
0))")]])
                 .unwrap(),
@@ -259,14 +270,17 @@ mod test {
             vec![Some("POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))")],
             vec![Some("POLYGON((2 2, 3 2, 3 3, 2 3, 2 2))")],
         ];
-        
assert_scalar_equal_wkb_geometry(&tester.aggregate_wkt(non_intersecting).unwrap(),
 None);
+        assert_scalar_equal_wkb_geometry_topologically(
+            &tester.aggregate_wkt(non_intersecting).unwrap(),
+            None,
+        );
 
         // Input with nulls
         let nulls_input = vec![
             vec![Some("POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))"), None],
             vec![Some("POLYGON((1 1, 3 1, 3 3, 1 3, 1 1))"), None],
         ];
-        assert_scalar_equal_wkb_geometry(
+        assert_scalar_equal_wkb_geometry_topologically(
             &tester.aggregate_wkt(nulls_input).unwrap(),
             Some("MULTIPOLYGON(((1 1, 2 1, 2 2, 1 2, 1 1)))"),
         );
@@ -276,7 +290,7 @@ mod test {
             vec![Some("POLYGON((0 0, 3 0, 3 3, 0 3, 0 0))")],
             vec![Some("POLYGON((1 1, 2 1, 2 2, 1 2, 1 1))")],
         ];
-        assert_scalar_equal_wkb_geometry(
+        assert_scalar_equal_wkb_geometry_topologically(
             &tester.aggregate_wkt(contained).unwrap(),
             Some("MULTIPOLYGON(((1 1, 2 1, 2 2, 1 2, 1 1)))"),
         );
@@ -298,7 +312,7 @@ mod test {
                 "MULTIPOLYGON(((1 1, 2 1, 2 2, 1 2, 1 1)), ((4 4, 5 4, 5 5, 4 
5, 4 4)))",
             )],
         ];
-        assert_scalar_equal_wkb_geometry(
+        assert_scalar_equal_wkb_geometry_topologically(
             &tester.aggregate_wkt(poly_and_multi).unwrap(),
             Some("MULTIPOLYGON(((1 1, 2 1, 2 2, 1 2, 1 1)))"),
         );
@@ -310,7 +324,7 @@ mod test {
                 "MULTIPOLYGON(((2 2, 3 2, 3 3, 2 3, 2 2)), ((4 4, 5 4, 5 5, 4 
5, 4 4)))",
             )],
         ];
-        assert_scalar_equal_wkb_geometry(
+        assert_scalar_equal_wkb_geometry_topologically(
             &tester.aggregate_wkt(poly_and_nonoverlap_multi).unwrap(),
             None,
         );
@@ -324,7 +338,7 @@ mod test {
                 "MULTIPOLYGON(((1 1, 2 1, 2 2, 1 2, 1 1)), ((11 11, 12 11, 12 
12, 11 12, 11 11)))",
             )],
         ];
-        assert_scalar_equal_wkb_geometry(
+        assert_scalar_equal_wkb_geometry_topologically(
             &tester.aggregate_wkt(multi_and_multi).unwrap(),
             Some("MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1)),((11 11,12 11,12 12,11 
12,11 11)))"),
         );
@@ -348,7 +362,7 @@ mod test {
                 "MULTIPOLYGON(((2 2, 5 2, 5 5, 2 5, 2 2)), ((9 9, 12 9, 12 12, 
9 12, 9 9)))",
             )],
         ];
-        assert_scalar_equal_wkb_geometry(
+        assert_scalar_equal_wkb_geometry_topologically(
             &tester.aggregate_wkt(multi_multi_case1).unwrap(),
             Some("MULTIPOLYGON(((2 2, 3 2, 3 3, 2 3, 2 2)))"),
         );
@@ -362,7 +376,10 @@ mod test {
                 "MULTIPOLYGON(((2 2, 3 2, 3 3, 2 3, 2 2)), ((7 7, 8 7, 8 8, 7 
8, 7 7)))",
             )],
         ];
-        
assert_scalar_equal_wkb_geometry(&tester.aggregate_wkt(multi_multi_case2).unwrap(),
 None);
+        assert_scalar_equal_wkb_geometry_topologically(
+            &tester.aggregate_wkt(multi_multi_case2).unwrap(),
+            None,
+        );
 
         // Test case 3: Three MultiPolygons intersection
         let multi_multi_case3 = vec![
@@ -376,7 +393,7 @@ mod test {
                 "MULTIPOLYGON(((3 3, 5 3, 5 5, 3 5, 3 3)), ((13 13, 15 13, 15 
15, 13 15, 13 13)))",
             )],
         ];
-        assert_scalar_equal_wkb_geometry(
+        assert_scalar_equal_wkb_geometry_topologically(
             &tester.aggregate_wkt(multi_multi_case3).unwrap(),
             Some("MULTIPOLYGON(((3 3,4 3,4 4,3 4,3 3)),((13 13,14 13,14 14,13 
14,13 13)))"),
         );
diff --git a/rust/sedona-geo/src/st_intersects.rs 
b/rust/sedona-geo/src/st_intersects.rs
index 9fac6ed..8c624fd 100644
--- a/rust/sedona-geo/src/st_intersects.rs
+++ b/rust/sedona-geo/src/st_intersects.rs
@@ -20,9 +20,9 @@ use arrow_array::builder::BooleanBuilder;
 use arrow_schema::DataType;
 use datafusion_common::error::Result;
 use datafusion_expr::ColumnarValue;
-use geo_generic_alg::Intersects;
 use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel};
 use sedona_functions::executor::WkbExecutor;
+use sedona_geo_generic_alg::Intersects;
 use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher};
 use wkb::reader::Wkb;
 
diff --git a/rust/sedona-geo/src/st_length.rs b/rust/sedona-geo/src/st_length.rs
index 0ab4461..21b2be1 100644
--- a/rust/sedona-geo/src/st_length.rs
+++ b/rust/sedona-geo/src/st_length.rs
@@ -21,9 +21,9 @@ use arrow_array::builder::Float64Builder;
 use arrow_schema::DataType;
 use datafusion_common::error::Result;
 use datafusion_expr::ColumnarValue;
-use geo_generic_alg::algorithm::{line_measures::Euclidean, 
LengthMeasurableExt};
 use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel};
 use sedona_functions::executor::WkbExecutor;
+use sedona_geo_generic_alg::algorithm::{line_measures::Euclidean, 
LengthMeasurableExt};
 use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher};
 use wkb::reader::Wkb;
 
diff --git a/rust/sedona-geo/src/st_perimeter.rs 
b/rust/sedona-geo/src/st_perimeter.rs
index ad5ffbc..11111b6 100644
--- a/rust/sedona-geo/src/st_perimeter.rs
+++ b/rust/sedona-geo/src/st_perimeter.rs
@@ -21,9 +21,9 @@ use arrow_array::builder::Float64Builder;
 use arrow_schema::DataType;
 use datafusion_common::error::Result;
 use datafusion_expr::ColumnarValue;
-use geo_generic_alg::algorithm::{line_measures::Euclidean, 
LengthMeasurableExt};
 use sedona_expr::scalar_udf::{ScalarKernelRef, SedonaScalarKernel};
 use sedona_functions::executor::WkbExecutor;
+use sedona_geo_generic_alg::algorithm::{line_measures::Euclidean, 
LengthMeasurableExt};
 use sedona_schema::{datatypes::SedonaType, matchers::ArgMatcher};
 use wkb::reader::Wkb;
 
diff --git a/rust/sedona-geo/src/st_union_aggr.rs 
b/rust/sedona-geo/src/st_union_aggr.rs
index 1260de5..2462e48 100644
--- a/rust/sedona-geo/src/st_union_aggr.rs
+++ b/rust/sedona-geo/src/st_union_aggr.rs
@@ -31,9 +31,9 @@ use sedona_schema::{
     datatypes::{SedonaType, WKB_GEOMETRY},
     matchers::ArgMatcher,
 };
-use wkb::reader::Wkb;
 use wkb::writer::write_geometry;
 use wkb::Endianness;
+use wkb::{reader::Wkb, writer::WriteOptions};
 
 /// ST_Union_Aggr() implementation
 pub fn st_union_aggr_impl() -> SedonaAccumulatorRef {
@@ -127,7 +127,13 @@ impl UnionAccumulator {
 
     fn geometry_to_wkb(&self, geom: &geo::Geometry) -> Option<Vec<u8>> {
         let mut wkb_bytes = Vec::new();
-        match write_geometry(&mut wkb_bytes, geom, Endianness::LittleEndian) {
+        match write_geometry(
+            &mut wkb_bytes,
+            geom,
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        ) {
             Ok(_) => Some(wkb_bytes),
             Err(_) => None,
         }
@@ -217,7 +223,9 @@ mod test {
     use rstest::rstest;
     use sedona_functions::st_union_aggr::st_union_aggr_udf;
     use sedona_schema::datatypes::WKB_VIEW_GEOMETRY;
-    use sedona_testing::{compare::assert_scalar_equal_wkb_geometry, 
testers::AggregateUdfTester};
+    use sedona_testing::{
+        compare::assert_scalar_equal_wkb_geometry_topologically, 
testers::AggregateUdfTester,
+    };
 
     #[rstest]
     fn polygon_polygon_cases(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] 
sedona_type: SedonaType) {
@@ -233,16 +241,16 @@ mod test {
             vec![Some("POLYGON((1 1, 3 1, 3 3, 1 3, 1 1))")],
         ];
 
-        assert_scalar_equal_wkb_geometry(
+        assert_scalar_equal_wkb_geometry_topologically(
             &tester.aggregate_wkt(batches).unwrap(),
             Some("MULTIPOLYGON(((0 0, 2 0, 2 1, 3 1, 3 3, 1 3, 1 2, 0 2, 0 
0)))"),
         );
 
         // Empty input
-        assert_scalar_equal_wkb_geometry(&tester.aggregate(&vec![]).unwrap(), 
None);
+        
assert_scalar_equal_wkb_geometry_topologically(&tester.aggregate(&vec![]).unwrap(),
 None);
 
         // Single polygon input
-        assert_scalar_equal_wkb_geometry(
+        assert_scalar_equal_wkb_geometry_topologically(
             &tester
                 .aggregate_wkt(vec![vec![Some("POLYGON((0 0, 2 0, 2 2, 0 2, 0 
0))")]])
                 .unwrap(),
@@ -254,7 +262,7 @@ mod test {
             vec![Some("POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))")],
             vec![Some("POLYGON((2 2, 3 2, 3 3, 2 3, 2 2))")],
         ];
-        assert_scalar_equal_wkb_geometry(
+        assert_scalar_equal_wkb_geometry_topologically(
             &tester.aggregate_wkt(non_intersecting).unwrap(),
             Some("MULTIPOLYGON(((0 0, 1 0, 1 1, 0 1, 0 0)),((2 2, 3 2, 3 3, 2 
3, 2 2)))"),
         );
@@ -264,7 +272,7 @@ mod test {
             vec![Some("POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))"), None],
             vec![Some("POLYGON((1 1, 3 1, 3 3, 1 3, 1 1))"), None],
         ];
-        assert_scalar_equal_wkb_geometry(
+        assert_scalar_equal_wkb_geometry_topologically(
             &tester.aggregate_wkt(nulls_input).unwrap(),
             Some("MULTIPOLYGON(((0 0, 2 0, 2 1, 3 1, 3 3, 1 3, 1 2, 0 2, 0 
0)))"),
         );
@@ -274,7 +282,7 @@ mod test {
             vec![Some("POLYGON((0 0, 3 0, 3 3, 0 3, 0 0))")],
             vec![Some("POLYGON((1 1, 2 1, 2 2, 1 2, 1 1))")],
         ];
-        assert_scalar_equal_wkb_geometry(
+        assert_scalar_equal_wkb_geometry_topologically(
             &tester.aggregate_wkt(contained).unwrap(),
             Some("MULTIPOLYGON(((0 0, 3 0, 3 3, 0 3, 0 0)))"),
         );
@@ -296,7 +304,7 @@ mod test {
                 "MULTIPOLYGON(((1 1, 2 1, 2 2, 1 2, 1 1)), ((4 4, 5 4, 5 5, 4 
5, 4 4)))",
             )],
         ];
-        assert_scalar_equal_wkb_geometry(
+        assert_scalar_equal_wkb_geometry_topologically(
             &tester.aggregate_wkt(poly_and_multi).unwrap(),
             Some("MULTIPOLYGON(((0 0, 3 0, 3 3, 0 3, 0 0)),((4 4, 5 4, 5 5, 4 
5, 4 4)))"),
         );
@@ -308,7 +316,7 @@ mod test {
                 "MULTIPOLYGON(((2 2, 3 2, 3 3, 2 3, 2 2)), ((4 4, 5 4, 5 5, 4 
5, 4 4)))",
             )],
         ];
-        assert_scalar_equal_wkb_geometry(
+        assert_scalar_equal_wkb_geometry_topologically(
             &tester.aggregate_wkt(poly_and_nonoverlap_multi).unwrap(),
             Some("MULTIPOLYGON(((0 0, 1 0, 1 1, 0 1, 0 0)),((2 2, 3 2, 3 3, 2 
3, 2 2)),((4 4, 5 4, 5 5, 4 5, 4 4)))"),
         );
@@ -322,7 +330,7 @@ mod test {
                 "MULTIPOLYGON(((1 1, 2 1, 2 2, 1 2, 1 1)), ((11 11, 13 11, 13 
13, 11 13, 11 11)))",
             )],
         ];
-        assert_scalar_equal_wkb_geometry(
+        assert_scalar_equal_wkb_geometry_topologically(
             &tester.aggregate_wkt(multi_and_multi).unwrap(),
             Some("MULTIPOLYGON(((0 0, 3 0, 3 3, 0 3, 0 0)),((10 10, 12 10, 12 
11, 13 11, 13 13, 11 13, 11 12, 10 12, 10 10)))"),
         );
@@ -346,7 +354,7 @@ mod test {
                 "MULTIPOLYGON(((2 2, 5 2, 5 5, 2 5, 2 2)), ((7 7, 10 7, 10 10, 
7 10, 7 7)))",
             )],
         ];
-        assert_scalar_equal_wkb_geometry(
+        assert_scalar_equal_wkb_geometry_topologically(
             &tester.aggregate_wkt(multi_multi_case1).unwrap(),
             Some("MULTIPOLYGON(((0 0, 3 0, 3 2, 5 2, 5 5, 2 5, 2 3, 0 3, 0 
0)),((5 5, 8 5, 8 7, 10 7, 10 10, 7 10, 7 8, 5 8, 5 5)))"),
         );
@@ -360,7 +368,7 @@ mod test {
                 "MULTIPOLYGON(((2 2, 3 2, 3 3, 2 3, 2 2)), ((7 7, 8 7, 8 8, 7 
8, 7 7)))",
             )],
         ];
-        assert_scalar_equal_wkb_geometry(
+        assert_scalar_equal_wkb_geometry_topologically(
             &tester.aggregate_wkt(multi_multi_case2).unwrap(),
             Some("MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((2 2,3 2,3 3,2 3,2 
2)),((5 5,6 5,6 6,5 6,5 5)),((7 7,8 7,8 8,7 8,7 7)))"),
         );
@@ -371,7 +379,7 @@ mod test {
             vec![Some("MULTIPOLYGON(((3 3, 7 3, 7 7, 3 7, 3 3)), ((13 13, 17 
13, 17 17, 13 17, 13 13)))")],
             vec![Some("MULTIPOLYGON(((6 6, 10 6, 10 10, 6 10, 6 6)), ((16 16, 
20 16, 20 20, 16 20, 16 16)))")],
         ];
-        assert_scalar_equal_wkb_geometry(
+        assert_scalar_equal_wkb_geometry_topologically(
             &tester.aggregate_wkt(multi_multi_case3).unwrap(),
             Some("MULTIPOLYGON(((0 0, 4 0, 4 3, 7 3, 7 6, 10 6, 10 10, 6 10, 6 
7, 3 7, 3 4, 0 4, 0 0)),((10 10, 14 10, 14 13, 17 13, 17 16, 20 16, 20 20, 16 
20, 16 17, 13 17, 13 14, 10 14, 10 10)))"),
         );
diff --git a/rust/sedona-geo/src/to_geo.rs b/rust/sedona-geo/src/to_geo.rs
index 56a9217..a440112 100644
--- a/rust/sedona-geo/src/to_geo.rs
+++ b/rust/sedona-geo/src/to_geo.rs
@@ -69,8 +69,10 @@ pub fn item_to_geometry(geo: impl GeometryTrait<T = f64>) -> 
Result<Geometry> {
 }
 
 // GeometryCollection causes issues because it has a recursive definition and 
won't work
-// with cargo run --release. Thus, we need our own version of this that limits 
the
-// recursion supported in a GeometryCollection.
+// with cargo run --release. Thus, we need our own version of this that works 
around this
+// problem by processing GeometryCollection using a free function instead of 
relying
+// on trait resolver.
+// See also https://github.com/geoarrow/geoarrow-rs/pull/956.
 fn to_geometry(item: impl GeometryTrait<T = f64>) -> Option<Geometry> {
     match item.as_type() {
         Point(geom) => geom.try_to_point().map(Geometry::Point),
@@ -79,35 +81,38 @@ fn to_geometry(item: impl GeometryTrait<T = f64>) -> 
Option<Geometry> {
         MultiPoint(geom) => 
geom.try_to_multi_point().map(Geometry::MultiPoint),
         MultiLineString(geom) => 
Some(Geometry::MultiLineString(geom.to_multi_line_string())),
         MultiPolygon(geom) => 
Some(Geometry::MultiPolygon(geom.to_multi_polygon())),
-        GeometryCollection(geom) => {
-            let geometries = geom
-                .geometries()
-                .filter_map(|child| match child.as_type() {
-                    Point(geom) => geom.try_to_point().map(Geometry::Point),
-                    LineString(geom) => 
Some(Geometry::LineString(geom.to_line_string())),
-                    Polygon(geom) => 
Some(Geometry::Polygon(geom.to_polygon())),
-                    MultiPoint(geom) => 
geom.try_to_multi_point().map(Geometry::MultiPoint),
-                    MultiLineString(geom) => {
-                        
Some(Geometry::MultiLineString(geom.to_multi_line_string()))
-                    }
-                    MultiPolygon(geom) => 
Some(Geometry::MultiPolygon(geom.to_multi_polygon())),
-                    _ => None,
-                })
-                .collect::<Vec<_>>();
-
-            // If any child conversions failed, also return None
-            if geometries.len() != geom.num_geometries() {
-                return None;
-            }
-
-            Some(Geometry::GeometryCollection(geo_types::GeometryCollection(
-                geometries,
-            )))
-        }
+        GeometryCollection(geom) => geometry_collection_to_geometry(geom),
         _ => None,
     }
 }
 
+fn geometry_collection_to_geometry<GC: GeometryCollectionTrait<T = f64>>(
+    geom: &GC,
+) -> Option<Geometry> {
+    let geometries = geom
+        .geometries()
+        .filter_map(|child| match child.as_type() {
+            Point(geom) => geom.try_to_point().map(Geometry::Point),
+            LineString(geom) => 
Some(Geometry::LineString(geom.to_line_string())),
+            Polygon(geom) => Some(Geometry::Polygon(geom.to_polygon())),
+            MultiPoint(geom) => 
geom.try_to_multi_point().map(Geometry::MultiPoint),
+            MultiLineString(geom) => 
Some(Geometry::MultiLineString(geom.to_multi_line_string())),
+            MultiPolygon(geom) => 
Some(Geometry::MultiPolygon(geom.to_multi_polygon())),
+            GeometryCollection(geom) => geometry_collection_to_geometry(geom),
+            _ => None,
+        })
+        .collect::<Vec<_>>();
+
+    // If any child conversions failed, also return None
+    if geometries.len() != geom.num_geometries() {
+        return None;
+    }
+
+    Some(Geometry::GeometryCollection(geo_types::GeometryCollection(
+        geometries,
+    )))
+}
+
 #[cfg(test)]
 mod tests {
     use datafusion_expr::ColumnarValue;
@@ -126,11 +131,6 @@ mod tests {
         let err = item_to_geometry(unsupported).unwrap_err();
         assert!(err.message().starts_with("geo kernel implementation"));
 
-        let unsupported =
-            Wkt::from_str("GEOMETRYCOLLECTION (GEOMETRYCOLLECTION(POINT (1 
2)))").unwrap();
-        let err = item_to_geometry(unsupported).unwrap_err();
-        assert!(err.message().starts_with("geo kernel implementation"));
-
         let unsupported = Wkt::from_str("GEOMETRYCOLLECTION (POINT 
EMPTY)").unwrap();
         let err = item_to_geometry(unsupported).unwrap_err();
         assert!(err.message().starts_with("geo kernel implementation"));
@@ -145,7 +145,8 @@ mod tests {
             "MULTIPOINT (1 2, 3 4)",
             "MULTILINESTRING ((1 2, 3 4))",
             "MULTIPOLYGON (((0 0, 1 0, 0 1, 0 0)))",
-            "GEOMETRYCOLLECTION(POINT (1 2))"
+            "GEOMETRYCOLLECTION(POINT (1 2))",
+            "GEOMETRYCOLLECTION (GEOMETRYCOLLECTION(POINT (1 2)))"
         )]
         wkt_value: &str,
     ) {
@@ -163,6 +164,7 @@ mod tests {
             Some("MULTILINESTRING ((1 2, 3 4))"),
             Some("MULTIPOLYGON (((0 0, 1 0, 0 1, 0 0)))"),
             Some("GEOMETRYCOLLECTION(POINT (1 2))"),
+            Some("GEOMETRYCOLLECTION (GEOMETRYCOLLECTION(POINT (1 2)))"),
             None,
         ];
         let args = vec![ColumnarValue::Array(create_array_storage(
diff --git a/rust/sedona-geometry/src/bounds.rs 
b/rust/sedona-geometry/src/bounds.rs
index 0f50040..e918d44 100644
--- a/rust/sedona-geometry/src/bounds.rs
+++ b/rust/sedona-geometry/src/bounds.rs
@@ -223,6 +223,7 @@ mod test {
     use super::*;
     use rstest::rstest;
     use std::{iter::zip, str::FromStr};
+    use wkb::{writer::WriteOptions, Endianness};
     use wkt::Wkt;
 
     pub fn wkt_bounds_xy(wkt_value: &str) -> Result<BoundingBox, 
SedonaGeometryError> {
@@ -441,7 +442,14 @@ mod test {
     fn test_wkb_bounds_xy() {
         let wkt: Wkt = Wkt::from_str("POINT (0 1)").unwrap();
         let mut out = Vec::new();
-        wkb::writer::write_geometry(&mut out, &wkt, 
wkb::Endianness::LittleEndian).unwrap();
+        wkb::writer::write_geometry(
+            &mut out,
+            &wkt,
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        )
+        .unwrap();
         assert_eq!(
             wkb_bounds_xy(&out).unwrap(),
             BoundingBox::xy((0, 0), (1, 1))
diff --git a/rust/sedona-geometry/src/is_empty.rs 
b/rust/sedona-geometry/src/is_empty.rs
index ad3f7d5..444b3d9 100644
--- a/rust/sedona-geometry/src/is_empty.rs
+++ b/rust/sedona-geometry/src/is_empty.rs
@@ -51,13 +51,21 @@ mod tests {
     use super::*;
     use std::str::FromStr;
     use wkb::reader::read_wkb;
-    use wkb::writer::write_geometry;
+    use wkb::writer::{write_geometry, WriteOptions};
+    use wkb::Endianness;
     use wkt::Wkt;
 
     fn create_wkb_bytes_from_wkt(wkt_str: &str) -> Vec<u8> {
         let wkt: Wkt = Wkt::from_str(wkt_str).unwrap();
         let mut wkb_bytes = vec![];
-        write_geometry(&mut wkb_bytes, &wkt, 
wkb::Endianness::LittleEndian).unwrap();
+        write_geometry(
+            &mut wkb_bytes,
+            &wkt,
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        )
+        .unwrap();
         wkb_bytes
     }
 
diff --git a/rust/sedona-geometry/src/wkb_factory.rs 
b/rust/sedona-geometry/src/wkb_factory.rs
index efa9f09..000788f 100644
--- a/rust/sedona-geometry/src/wkb_factory.rs
+++ b/rust/sedona-geometry/src/wkb_factory.rs
@@ -469,7 +469,8 @@ fn count_to_u32(count: usize) -> Result<u32, 
SedonaGeometryError> {
 mod test {
     use std::str::FromStr;
     use wkb::reader::read_wkb;
-    use wkb::writer::write_geometry;
+    use wkb::writer::{write_geometry, WriteOptions};
+    use wkb::Endianness;
     use wkt::Wkt;
 
     use super::*;
@@ -478,7 +479,14 @@ mod test {
     fn test_wkb_point() {
         let wkt: Wkt = Wkt::from_str("POINT (0 1)").unwrap();
         let mut wkb = vec![];
-        write_geometry(&mut wkb, &wkt, wkb::Endianness::LittleEndian).unwrap();
+        write_geometry(
+            &mut wkb,
+            &wkt,
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        )
+        .unwrap();
         assert_eq!(wkb_point((0.0, 1.0)).unwrap(), wkb);
     }
 
@@ -533,12 +541,26 @@ mod test {
     fn test_wkb_linestring() {
         let wkt: Wkt = Wkt::from_str("LINESTRING EMPTY").unwrap();
         let mut wkb = vec![];
-        write_geometry(&mut wkb, &wkt, wkb::Endianness::LittleEndian).unwrap();
+        write_geometry(
+            &mut wkb,
+            &wkt,
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        )
+        .unwrap();
         assert_eq!(wkb_linestring([].into_iter()).unwrap(), wkb);
 
         let wkt: Wkt = Wkt::from_str("LINESTRING (0 1, 2 3)").unwrap();
         let mut wkb = vec![];
-        write_geometry(&mut wkb, &wkt, wkb::Endianness::LittleEndian).unwrap();
+        write_geometry(
+            &mut wkb,
+            &wkt,
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        )
+        .unwrap();
         assert_eq!(
             wkb_linestring([(0.0, 1.0), (2.0, 3.0)].into_iter()).unwrap(),
             wkb
@@ -584,12 +606,26 @@ mod test {
     fn test_wkb_multilinestring() {
         let wkt: Wkt = Wkt::from_str("MULTILINESTRING EMPTY").unwrap();
         let mut wkb = vec![];
-        write_geometry(&mut wkb, &wkt, wkb::Endianness::LittleEndian).unwrap();
+        write_geometry(
+            &mut wkb,
+            &wkt,
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        )
+        .unwrap();
         assert_eq!(wkb_multilinestring([].into_iter()).unwrap(), wkb);
 
         let wkt: Wkt = Wkt::from_str("MULTILINESTRING ((0 0, 1 1, 2 2), (3 3, 
4 4))").unwrap();
         let mut wkb = vec![];
-        write_geometry(&mut wkb, &wkt, wkb::Endianness::LittleEndian).unwrap();
+        write_geometry(
+            &mut wkb,
+            &wkt,
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        )
+        .unwrap();
 
         let linestrings = vec![
             vec![(0.0, 0.0), (1.0, 1.0), (2.0, 2.0)],
@@ -603,12 +639,26 @@ mod test {
     fn test_wkb_polygon() {
         let wkt: Wkt = Wkt::from_str("POLYGON EMPTY").unwrap();
         let mut wkb = vec![];
-        write_geometry(&mut wkb, &wkt, wkb::Endianness::LittleEndian).unwrap();
+        write_geometry(
+            &mut wkb,
+            &wkt,
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        )
+        .unwrap();
         assert_eq!(wkb_polygon([].into_iter()).unwrap(), wkb);
 
         let wkt: Wkt = Wkt::from_str("POLYGON ((0 0, 1 0, 0 1, 0 
0))").unwrap();
         let mut wkb = vec![];
-        write_geometry(&mut wkb, &wkt, wkb::Endianness::LittleEndian).unwrap();
+        write_geometry(
+            &mut wkb,
+            &wkt,
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        )
+        .unwrap();
         assert_eq!(
             wkb_polygon([(0.0, 0.0), (1.0, 0.0), (0.0, 1.0), (0.0, 
0.0)].into_iter()).unwrap(),
             wkb
@@ -697,13 +747,27 @@ mod test {
     fn test_wkb_multipolygon() {
         let wkt: Wkt = Wkt::from_str("MULTIPOLYGON EMPTY").unwrap();
         let mut wkb = vec![];
-        write_geometry(&mut wkb, &wkt, wkb::Endianness::LittleEndian).unwrap();
+        write_geometry(
+            &mut wkb,
+            &wkt,
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        )
+        .unwrap();
         assert_eq!(wkb_multipolygon([].into_iter()).unwrap(), wkb);
 
         let wkt: Wkt =
             Wkt::from_str("MULTIPOLYGON (((0 0, 1 0, 0 1, 0 0)), ((2 2, 3 2, 2 
3, 2 2)))").unwrap();
         let mut wkb = vec![];
-        write_geometry(&mut wkb, &wkt, wkb::Endianness::LittleEndian).unwrap();
+        write_geometry(
+            &mut wkb,
+            &wkt,
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        )
+        .unwrap();
 
         let polygons = vec![
             vec![(0.0, 0.0), (1.0, 0.0), (0.0, 1.0), (0.0, 0.0)],
@@ -717,12 +781,26 @@ mod test {
     fn test_wkb_multipoint() {
         let wkt: Wkt = Wkt::from_str("MULTIPOINT EMPTY").unwrap();
         let mut wkb = vec![];
-        write_geometry(&mut wkb, &wkt, wkb::Endianness::LittleEndian).unwrap();
+        write_geometry(
+            &mut wkb,
+            &wkt,
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        )
+        .unwrap();
         assert_eq!(wkb_multipoint([].into_iter()).unwrap(), wkb);
 
         let wkt: Wkt = Wkt::from_str("MULTIPOINT ((0 0), (1 1))").unwrap();
         let mut wkb = vec![];
-        write_geometry(&mut wkb, &wkt, wkb::Endianness::LittleEndian).unwrap();
+        write_geometry(
+            &mut wkb,
+            &wkt,
+            &WriteOptions {
+                endianness: Endianness::LittleEndian,
+            },
+        )
+        .unwrap();
 
         let points = vec![(0.0, 0.0), (1.0, 1.0)];
         assert_eq!(wkb_multipoint(points.into_iter()).unwrap(), wkb);
diff --git a/rust/sedona-spatial-join/Cargo.toml 
b/rust/sedona-spatial-join/Cargo.toml
index 4720b86..d103714 100644
--- a/rust/sedona-spatial-join/Cargo.toml
+++ b/rust/sedona-spatial-join/Cargo.toml
@@ -44,9 +44,10 @@ datafusion-common-runtime = { workspace = true }
 futures = { workspace = true }
 once_cell = { workspace = true }
 parking_lot = { workspace = true }
-geo-generic-alg = { workspace = true }
+geo = { workspace = true }
+sedona-geo-generic-alg = { path = "../sedona-geo-generic-alg" }
 geo-traits = { workspace = true, features = ["geo-types"] }
-geo-traits-ext = { workspace = true }
+sedona-geo-traits-ext = { path = "../sedona-geo-traits-ext" }
 geo-types = { workspace = true }
 sedona-common = { path = "../sedona-common" }
 sedona-expr = { path = "../sedona-expr" }
@@ -55,6 +56,7 @@ sedona-geo = { path = "../sedona-geo" }
 sedona-geometry = { path = "../sedona-geometry" }
 sedona-schema = { path = "../sedona-schema" }
 sedona-tg = { path = "../../c/sedona-tg" }
+sedona-geos = { path = "../../c/sedona-geos" }
 wkb = { workspace = true }
 geo-index = { workspace = true }
 geos = { workspace = true }
@@ -66,5 +68,4 @@ rstest = { workspace = true }
 sedona-testing = { path = "../sedona-testing" }
 wkt = { workspace = true }
 tokio = { workspace = true, features = ["macros"] }
-sedona-geos = { path = "../../c/sedona-geos" }
 rand = { workspace = true }
diff --git a/rust/sedona-spatial-join/src/index.rs 
b/rust/sedona-spatial-join/src/index.rs
index 9c5f447..4e95527 100644
--- a/rust/sedona-spatial-join/src/index.rs
+++ b/rust/sedona-spatial-join/src/index.rs
@@ -587,7 +587,7 @@ impl SpatialIndex {
                 let max_distance = distances_with_indices[k_idx].0;
 
                 // For tie-breakers, create spatial envelope around probe 
centroid and use rtree.search()
-                use geo_generic_alg::algorithm::Centroid;
+                use sedona_geo_generic_alg::algorithm::Centroid;
                 let probe_centroid = 
probe_geom.centroid().unwrap_or(Point::new(0.0, 0.0));
                 let probe_x = probe_centroid.x() as f32;
                 let probe_y = probe_centroid.y() as f32;
diff --git a/rust/sedona-spatial-join/src/operand_evaluator.rs 
b/rust/sedona-spatial-join/src/operand_evaluator.rs
index 56dca64..114d430 100644
--- a/rust/sedona-spatial-join/src/operand_evaluator.rs
+++ b/rust/sedona-spatial-join/src/operand_evaluator.rs
@@ -25,10 +25,10 @@ use datafusion_common::{
 use datafusion_expr::ColumnarValue;
 use datafusion_physical_expr::PhysicalExpr;
 use float_next_after::NextAfter;
-use geo_generic_alg::BoundingRect;
 use geo_index::rtree::util::f64_box_to_f32;
 use geo_types::{coord, Rect};
 use sedona_functions::executor::IterGeo;
+use sedona_geo_generic_alg::BoundingRect;
 use sedona_schema::datatypes::SedonaType;
 use wkb::reader::Wkb;
 
diff --git a/rust/sedona-spatial-join/src/refine/geo.rs 
b/rust/sedona-spatial-join/src/refine/geo.rs
index 3b555e7..5d13b5e 100644
--- a/rust/sedona-spatial-join/src/refine/geo.rs
+++ b/rust/sedona-spatial-join/src/refine/geo.rs
@@ -17,12 +17,11 @@
 use std::sync::{Arc, OnceLock};
 
 use datafusion_common::Result;
-use geo_generic_alg::{
-    line_measures::DistanceExt, Contains, Distance, Euclidean, Intersects, 
Relate, Within,
-};
+use geo::{Contains, Relate, Within};
 use sedona_common::{sedona_internal_err, ExecutionMode, SpatialJoinOptions};
 use sedona_expr::statistics::GeoStatistics;
 use sedona_geo::to_geo::item_to_geometry;
+use sedona_geo_generic_alg::{line_measures::DistanceExt, Intersects};
 use wkb::reader::Wkb;
 
 use crate::{
@@ -136,7 +135,7 @@ impl GeoRefiner {
             Ok(geom) => geom,
             Err(_) => return Ok(Vec::new()),
         };
-        let probe_geom = geo_generic_alg::PreparedGeometry::from(probe_geom);
+        let probe_geom = geo::PreparedGeometry::from(probe_geom);
 
         for index_result in index_query_results {
             if self.evaluator.evaluate_prepare_probe(
@@ -204,7 +203,7 @@ trait GeoPredicateEvaluator: Send + Sync {
     fn evaluate_prepare_probe(
         &self,
         build: &Wkb,
-        probe: &geo_generic_alg::PreparedGeometry<'static, 
geo_types::Geometry>,
+        probe: &geo::PreparedGeometry<'static, geo_types::Geometry>,
         distance: Option<f64>,
     ) -> Result<bool>;
 }
@@ -237,7 +236,7 @@ impl GeoPredicateEvaluator for GeoIntersects {
     fn evaluate_prepare_probe(
         &self,
         build: &Wkb,
-        probe: &geo_generic_alg::PreparedGeometry<'static, 
geo_types::Geometry>,
+        probe: &geo::PreparedGeometry<'static, geo_types::Geometry>,
         _distance: Option<f64>,
     ) -> Result<bool> {
         let build_geom = match item_to_geometry(build) {
@@ -266,7 +265,7 @@ impl GeoPredicateEvaluator for GeoContains {
     fn evaluate_prepare_probe(
         &self,
         build: &Wkb,
-        probe: &geo_generic_alg::PreparedGeometry<'static, 
geo_types::Geometry>,
+        probe: &geo::PreparedGeometry<'static, geo_types::Geometry>,
         _distance: Option<f64>,
     ) -> Result<bool> {
         let build_geom = match item_to_geometry(build) {
@@ -295,7 +294,7 @@ impl GeoPredicateEvaluator for GeoWithin {
     fn evaluate_prepare_probe(
         &self,
         build: &Wkb,
-        probe: &geo_generic_alg::PreparedGeometry<'static, 
geo_types::Geometry>,
+        probe: &geo::PreparedGeometry<'static, geo_types::Geometry>,
         _distance: Option<f64>,
     ) -> Result<bool> {
         let build_geom = match item_to_geometry(build) {
@@ -320,18 +319,13 @@ impl GeoPredicateEvaluator for GeoDistance {
     fn evaluate_prepare_probe(
         &self,
         build: &Wkb,
-        probe: &geo_generic_alg::PreparedGeometry<'static, 
geo_types::Geometry>,
+        probe: &geo::PreparedGeometry<'static, geo_types::Geometry>,
         distance: Option<f64>,
     ) -> Result<bool> {
         let Some(distance) = distance else {
             return Ok(false);
         };
-        let build_geom = match item_to_geometry(build) {
-            Ok(geom) => geom,
-            Err(_) => return Ok(false),
-        };
-        let euc = Euclidean;
-        let dist = euc.distance(&build_geom, probe.geometry());
+        let dist = build.distance_ext(probe.geometry());
         Ok(dist <= distance)
     }
 }
@@ -358,7 +352,7 @@ macro_rules! impl_relate_evaluator {
             fn evaluate_prepare_probe(
                 &self,
                 build: &Wkb,
-                probe: &geo_generic_alg::PreparedGeometry<'static, 
geo_types::Geometry>,
+                probe: &geo::PreparedGeometry<'static, geo_types::Geometry>,
                 _distance: Option<f64>,
             ) -> Result<bool> {
                 let build_geom = match item_to_geometry(build) {
diff --git a/rust/sedona-spatial-join/src/refine/geos.rs 
b/rust/sedona-spatial-join/src/refine/geos.rs
index b6570b7..9b4bc29 100644
--- a/rust/sedona-spatial-join/src/refine/geos.rs
+++ b/rust/sedona-spatial-join/src/refine/geos.rs
@@ -24,7 +24,8 @@ use geos::{Geom, PreparedGeometry};
 use parking_lot::Mutex;
 use sedona_common::{sedona_internal_err, ExecutionMode, SpatialJoinOptions};
 use sedona_expr::statistics::GeoStatistics;
-use wkb::reader::{to_geos::GEOSWkbFactory, Wkb};
+use sedona_geos::wkb_to_geos::GEOSWkbFactory;
+use wkb::reader::Wkb;
 
 use crate::{
     index::IndexQueryResult,
diff --git a/rust/sedona-testing/src/create.rs 
b/rust/sedona-testing/src/create.rs
index fd5410a..9d785d6 100644
--- a/rust/sedona-testing/src/create.rs
+++ b/rust/sedona-testing/src/create.rs
@@ -20,6 +20,7 @@ use arrow_array::{ArrayRef, BinaryArray, BinaryViewArray};
 use datafusion_common::ScalarValue;
 use datafusion_expr::ColumnarValue;
 use sedona_schema::datatypes::SedonaType;
+use wkb::{writer::WriteOptions, Endianness};
 use wkt::Wkt;
 
 /// Create a [`ColumnarValue`] array from a sequence of WKT literals
@@ -86,7 +87,14 @@ where
 pub fn make_wkb(wkt_value: &str) -> Vec<u8> {
     let geom = Wkt::<f64>::from_str(wkt_value).unwrap();
     let mut out: Vec<u8> = vec![];
-    wkb::writer::write_geometry(&mut out, &geom, Default::default()).unwrap();
+    wkb::writer::write_geometry(
+        &mut out,
+        &geom,
+        &WriteOptions {
+            endianness: Endianness::LittleEndian,
+        },
+    )
+    .unwrap();
     out
 }
 
diff --git a/rust/sedona-testing/src/datagen.rs 
b/rust/sedona-testing/src/datagen.rs
index 4fb73c2..4481860 100644
--- a/rust/sedona-testing/src/datagen.rs
+++ b/rust/sedona-testing/src/datagen.rs
@@ -40,6 +40,8 @@ use sedona_geometry::types::GeometryTypeId;
 use sedona_schema::datatypes::{SedonaType, WKB_GEOMETRY};
 use std::f64::consts::PI;
 use std::sync::Arc;
+use wkb::writer::WriteOptions;
+use wkb::Endianness;
 
 /// Builder for generating test data partitions with random geometries.
 ///
@@ -502,7 +504,14 @@ fn generate_random_wkb<R: rand::Rng>(rng: &mut R, options: 
&RandomGeometryOption
 
     // Convert geometry to WKB
     let mut out: Vec<u8> = vec![];
-    wkb::writer::write_geometry(&mut out, &geometry, 
Default::default()).unwrap();
+    wkb::writer::write_geometry(
+        &mut out,
+        &geometry,
+        &WriteOptions {
+            endianness: Endianness::LittleEndian,
+        },
+    )
+    .unwrap();
     out
 }
 

Reply via email to