#![cfg_attr(not(feature = "std"), no_std)]
#![warn(missing_docs)]
#![deny(unsafe_code)]
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(not(feature = "std"))]
use alloc::format;
#[cfg(not(feature = "std"))]
use alloc::string::String;
pub mod area_of_use;
#[cfg(feature = "std")]
pub mod cache;
pub mod crs;
#[cfg(feature = "std")]
pub mod crs_identify;
#[cfg(feature = "std")]
pub mod crs_registry;
pub mod datum_transform;
pub mod epsg;
pub mod error;
#[cfg(feature = "std")]
pub mod geocentric;
pub mod geodesic;
pub mod geoid;
#[cfg(feature = "std")]
pub mod geoid_formats;
#[cfg(feature = "std")]
pub mod grid_shift;
pub mod operation_selection;
#[cfg(feature = "std")]
pub mod pipeline;
#[cfg(feature = "std")]
pub mod proj_string;
#[cfg(feature = "std")]
pub mod projections;
pub mod transform;
pub mod ups_projection;
pub mod wkt;
pub use area_of_use::{AreaOfUse, area_of_use_for_epsg};
#[cfg(feature = "std")]
pub use cache::{TransformerCache, TransformerKey};
pub use crs::{Crs, CrsSource};
#[cfg(feature = "std")]
pub use crs_identify::{
CrsFingerprint, fingerprint_from_proj, fingerprint_from_wkt, identify_epsg_from_proj,
identify_epsg_from_wkt,
};
pub use epsg::{CrsType, EpsgDefinition};
#[cfg(feature = "proj-db")]
pub use epsg::{ProjDb, ProjDbEntry, default_proj_db_paths, populate_from_proj_db};
#[cfg(feature = "std")]
pub use epsg::{available_epsg_codes, contains_epsg, lookup_epsg};
pub use error::{Error, Result};
#[cfg(feature = "std")]
pub use geocentric::{
EcefCoordinate, EcefTransformer, GeocentricCrs, GeocentricEllipsoid, ecef_to_geographic,
ecef_to_geographic_iterative, geographic_to_ecef, geographic_to_geographic_via_ecef,
};
pub use geodesic::{
GeodesicError, GeodesicParams, VincentyDirectResult, VincentyResult, haversine_distance_m,
vincenty_direct, vincenty_inverse, wgs84_direct, wgs84_haversine_m, wgs84_inverse,
};
#[cfg(feature = "std")]
pub use geoid::load_egm_grid;
pub use geoid::{
GeoidGrid, GeoidModel, VerticalDatumKind, classify_vertical_datum, synthetic_grid,
synthetic_height_m,
};
#[cfg(feature = "std")]
pub use geoid_formats::{
Egm96AsciiHeader, Egm2008BinaryHeader, load_geoid_auto, parse_egm96_ascii_file,
parse_egm96_ascii_header, parse_egm96_ascii_str, parse_egm2008_binary_25,
parse_egm2008_binary_25_file, parse_egm2008_binary_25_header,
};
#[cfg(feature = "std")]
pub use grid_shift::{
DHDN_TO_ETRS89, Helmert7Params, NAD27_TO_NAD83, NTF_TO_RGF93, NtV2Grid, OSGB36_TO_ETRS89,
dhdn_etrs89_helmert, helmert_3d, helmert_7param, nad27_nad83_poly, ostn15_approx, rgf93_approx,
};
pub use operation_selection::{
CandidateOperation, OperationRanking, area_coverage_fraction, operation_score, rank_operations,
select_best_operation,
};
#[cfg(feature = "std")]
pub use pipeline::{
EllipsoidParams, HelmertConvention, HelmertParams, HelmertRateParams, ParsedStep, Pipeline,
PipelineStep, ShiftDirection, StepKind, Unit, parse_pipeline,
};
#[cfg(feature = "std")]
pub use transform::{
AreaOfUseCheck, AreaOfUseWarning, AzimuthalEquidistant, CassineSoldner, EckertIV, EckertVI,
EquidistantConic, GaussKruger, Gnomonic, LambertAzimuthalEqualArea, LambertConformalConic,
Mollweide, Robinson, Sinusoidal, Transformer, TransverseMercator, transform_coordinate,
transform_epsg,
};
pub use transform::{BoundingBox, Coordinate, Coordinate3D};
pub use ups_projection::{
PolarStereographicParams, UpsCoordinate, UpsHemisphere, polar_stereo_w,
polar_stereographic_forward, polar_stereographic_inverse, ups_from_geographic,
ups_to_geographic, ups_zone_letter,
};
pub use wkt::{WktNode, WktParser, parse_wkt};
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub const NAME: &str = env!("CARGO_PKG_NAME");
pub fn info() -> String {
format!("{} v{}", NAME, VERSION)
}
#[cfg(test)]
#[allow(clippy::expect_used)]
mod tests {
use super::*;
#[test]
fn test_version_info() {
let info = info();
assert!(info.contains("oxigdal-proj"));
assert!(info.contains(env!("CARGO_PKG_VERSION")));
}
#[test]
fn test_basic_workflow() {
let wgs84 = Crs::wgs84();
let web_mercator = Crs::web_mercator();
let transformer = Transformer::new(wgs84, web_mercator);
assert!(transformer.is_ok());
let coord = Coordinate::from_lon_lat(0.0, 0.0);
let result = transformer.expect("should create").transform(&coord);
assert!(result.is_ok());
}
#[test]
fn test_epsg_lookup() {
let wgs84 = lookup_epsg(4326);
assert!(wgs84.is_ok());
assert!(contains_epsg(4326));
assert!(contains_epsg(3857));
assert!(!contains_epsg(99999));
let codes = available_epsg_codes();
assert!(!codes.is_empty());
}
#[test]
fn test_convenience_functions() {
let coord = Coordinate::from_lon_lat(0.0, 0.0);
let result = transform_epsg(&coord, 4326, 4326);
assert!(result.is_ok());
}
#[test]
fn test_bounding_box_workflow() {
let bbox = BoundingBox::new(0.0, 0.0, 10.0, 10.0);
assert!(bbox.is_ok());
let bbox = bbox.expect("valid bbox");
let transformer = Transformer::from_epsg(4326, 4326);
assert!(transformer.is_ok());
let result = transformer.expect("should create").transform_bbox(&bbox);
assert!(result.is_ok());
}
#[test]
fn test_wkt_parsing() {
let wkt = r#"GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563]]]"#;
let result = parse_wkt(wkt);
assert!(result.is_ok());
let node = result.expect("should parse");
assert_eq!(node.node_type, "GEOGCS");
}
#[test]
fn test_crs_creation_methods() {
let crs1 = Crs::from_epsg(4326);
assert!(crs1.is_ok());
let crs2 = Crs::from_proj("+proj=longlat +datum=WGS84 +no_defs");
assert!(crs2.is_ok());
let wkt = r#"GEOGCS["WGS 84"]"#;
let crs3 = Crs::from_wkt(wkt);
assert!(crs3.is_ok());
let crs4 = Crs::custom("My CRS", "+proj=longlat +datum=WGS84 +no_defs");
assert!(matches!(crs4.source(), CrsSource::Custom { .. }));
}
#[test]
fn test_coordinate_types() {
let coord_2d = Coordinate::new(10.0, 20.0);
assert_eq!(coord_2d.x, 10.0);
assert_eq!(coord_2d.y, 20.0);
let coord_3d = Coordinate3D::new(10.0, 20.0, 30.0);
assert_eq!(coord_3d.x, 10.0);
assert_eq!(coord_3d.y, 20.0);
assert_eq!(coord_3d.z, 30.0);
let coord_2d_from_3d = coord_3d.to_2d();
assert_eq!(coord_2d_from_3d.x, 10.0);
assert_eq!(coord_2d_from_3d.y, 20.0);
}
}