Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend the existing possibilities of writing ogr datasets. #31

Merged
merged 11 commits into from
Jan 17, 2017
53 changes: 53 additions & 0 deletions examples/read_write_ogr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
extern crate gdal;

use std::fs;
use std::path::Path;
use gdal::vector::*;
use gdal::spatial_ref::{SpatialRef, CoordTransform};

fn main() {
let mut dataset_a = Dataset::open(Path::new("fixtures/roads.geojson")).unwrap();
let layer_a = dataset_a.layer(0).unwrap();
let fields_defn = layer_a.defn().fields()
.map(|field| (field.name(), field.field_type(), field.width()))
.collect::<Vec<_>>();

// Create a new dataset :
fs::remove_file("/tmp/abcde.shp");
let drv = Driver::get("ESRI Shapefile").unwrap();
let mut ds = drv.create(Path::new("/tmp/abcde.shp")).unwrap();
let lyr = ds.create_layer().unwrap();

// Copy the origin layer shema to the destination layer :
for fd in &fields_defn {
let field_defn = FieldDefn::new(&fd.0, fd.1).unwrap();
field_defn.set_width(fd.2);
field_defn.add_to_layer(&lyr);
}

// Prepare the origin and destination spatial references objects :
let spatial_ref_src = SpatialRef::from_epsg(4326).unwrap();
let spatial_ref_dst = SpatialRef::from_epsg(3025).unwrap();

// And the feature used to actually transform the geometries :
let htransform = CoordTransform::new(&spatial_ref_src, &spatial_ref_dst).unwrap();

// Get the definition to use on each feature :
let defn = Defn::from_layer(&lyr);

for feature_a in layer_a.features() {
// Get the original geometry :
let geom = feature_a.geometry();
// Get a new transformed geometry :
let new_geom = geom.transform(&htransform).unwrap();
// Create the new feature, set its geometry :
let mut ft = Feature::new(&defn).unwrap();
ft.set_geometry(new_geom);
// copy each field value of the feature :
for fd in &fields_defn {
ft.set_field(&fd.0, &feature_a.field(&fd.0).unwrap()).unwrap();
}
// Add the feature to the layer :
ft.create(&lyr);
}
}
2 changes: 1 addition & 1 deletion examples/spatial_reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fn main() {
println!("Before transformation :\n{:?} {:?}", xs, ys);
htransform.transform_coord(xs, ys, &mut [0.0, 0.0]);
println!("After transformation :\n{:?} {:?}\n", xs, ys);
let mut geom = Geometry::from_wkt("POLYGON((23.43 37.58, 23.43 40.0, 25.29 40.0, 25.29 37.58, 23.43 37.58))").unwrap();
let geom = Geometry::from_wkt("POLYGON((23.43 37.58, 23.43 40.0, 25.29 40.0, 25.29 37.58, 23.43 37.58))").unwrap();
println!("Polygon before transformation:\n{:?}\n", geom.wkt().unwrap());
geom.transform(&htransform).unwrap();
println!("Polygon after transformation:\n{:?}\n", geom.wkt().unwrap());
Expand Down
99 changes: 99 additions & 0 deletions examples/write_ogr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
extern crate gdal;

use std::path::Path;
use std::fs;
use gdal::vector::{Defn, Driver, Feature, FieldDefn, Geometry, OGRFieldType, FieldValue};

fn main(){
/// Example 1, the detailed way :
{
fs::remove_file("/tmp/output1.geojson");
let drv = Driver::get("GeoJSON").unwrap();
let mut ds = drv.create(Path::new("/tmp/output1.geojson")).unwrap();

let lyr = ds.create_layer().unwrap();

let field_defn = FieldDefn::new("Name", OGRFieldType::OFTString).unwrap();
field_defn.set_width(80);
field_defn.add_to_layer(&lyr);

let field_defn = FieldDefn::new("Value", OGRFieldType::OFTReal).unwrap();
field_defn.add_to_layer(&lyr);

let defn = Defn::from_layer(&lyr);

// 1st feature :
let mut ft = Feature::new(&defn).unwrap();
ft.set_geometry(Geometry::from_wkt("POINT (45.21 21.76)").unwrap());
ft.set_field_string("Name", "Feature 1");
ft.set_field_double("Value", 45.78);
ft.create(&lyr);

// 2nd feature :
let mut ft = Feature::new(&defn).unwrap();
ft.set_geometry(Geometry::from_wkt("POINT (46.50 22.50)").unwrap());
ft.set_field_string("Name", "Feature 2");
ft.set_field_double("Value", 0.789);
ft.create(&lyr);

// Feature triggering an error due to a wrong field name :
let mut ft = Feature::new(&defn).unwrap();
ft.set_geometry(Geometry::from_wkt("POINT (46.50 22.50)").unwrap());
ft.set_field_string("Name", "Feature 2");
match ft.set_field_double("Values", 0.789) {
Ok(v) => v, Err(err) => println!("{:?}", err.to_string()),
};
ft.create(&lyr);
}

/// Example 2, same output, shortened way :
{
fs::remove_file("/tmp/output2.geojson");
let driver = Driver::get("GeoJSON").unwrap();
let mut ds = driver.create(Path::new("/tmp/output2.geojson")).unwrap();
let mut layer = ds.create_layer().unwrap();

layer.create_defn_fields(&[("Name", OGRFieldType::OFTString), ("Value", OGRFieldType::OFTReal)]);
// Shortcut for :
// let field_defn = FieldDefn::new("Name", OFT_STRING);
// field_defn.add_to_layer(&layer);
// let field_defn = FieldDefn::new("Value", OFT_REAL);
// field_defn.add_to_layer(&layer);

layer.create_feature_fields(
Geometry::from_wkt("POINT (45.21 21.76)").unwrap(),
&["Name", "Value"],
&[FieldValue::StringValue("Feature 1".to_string()), FieldValue::RealValue(45.78)]
).unwrap();

layer.create_feature_fields(
Geometry::from_wkt("POINT (46.50 22.50)").unwrap(),
&["Name", "Value"],
&[FieldValue::StringValue("Feature 2".to_string()), FieldValue::RealValue(0.789)]
).unwrap();

// Feature creation triggering an error due to a wrong field name :
match layer.create_feature_fields(
Geometry::from_wkt("POINT (46.50 22.50)").unwrap(),
&["Abcd", "Value"],
&[FieldValue::StringValue("Feature 2".to_string()), FieldValue::RealValue(0.789)]) {
Ok(v) => v,
Err(err) => println!("{:?}", err.to_string()),
};
// Shortcuts for :
// let defn = Defn::new_from_layer(&layer);
//
// let mut ft = Feature::new(&defn);
// ft.set_geometry(Geometry::from_wkt("POINT (45.21 21.76)").unwrap());
// ft.set_field("Name", OFT_STRING, "Feature 1");
// ft.set_field("Value", OFT_REAL, 45.78);
// ft.create(&lyr);
//
// let mut ft = Feature::new(&defn);
// ft.set_geometry(Geometry::from_wkt("POINT (46.50 22.50)").unwrap());
// ft.set_field("Name", OFT_STRING, "Feature 2");
// ft.set_field("Value", OFT_REAL, 0.789);
// ft.create(&lyr);
}

}
18 changes: 14 additions & 4 deletions gdal-sys/src/ogr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,25 @@ extern {
pub fn OGR_L_GetNextFeature(hLayer: *const c_void) -> *const c_void;
pub fn OGR_L_SetSpatialFilter(hLayer: *const c_void, hGeom: *const c_void);
pub fn OGR_L_CreateFeature(hLayer: *const c_void, hFeat: *const c_void) -> OGRErr;
pub fn OGR_L_CreateField(hLayer: *const c_void, hField: *const c_void, bApproxOK: c_int) -> OGRErr;
pub fn OGR_FD_GetFieldCount(hDefn: *const c_void) -> c_int;
pub fn OGR_FD_GetFieldDefn(hDefn: *const c_void, iField: c_int) -> *const c_void;
pub fn OGR_F_Create(hDefn: *const c_void) -> *const c_void;
pub fn OGR_F_GetFieldIndex(hFeat: *const c_void, pszName: *const c_char) -> c_int;
pub fn OGR_F_GetFieldDefnRef(hFeat: *const c_void, i: c_int) -> *const c_void;
pub fn OGR_F_GetFieldAsString(hFeat: *const c_void, iField: c_int) -> *const c_char;
pub fn OGR_F_GetFieldAsDouble(hFeat: *const c_void, iField: c_int) -> c_double;
pub fn OGR_F_GetFieldAsInteger(hFeat: *const c_void, iField: c_int) -> c_int;
pub fn OGR_F_GetGeometryRef(hFeat: *const c_void) -> *const c_void;
pub fn OGR_F_SetGeometry(hFeat: *const c_void, hGeom: *const c_void) -> OGRErr;
pub fn OGR_F_SetGeometryDirectly(hFeat: *const c_void, hGeom: *const c_void) -> OGRErr;
pub fn OGR_F_SetFieldString(hFeat: *const c_void, iField: c_int, pszValue: *const c_char) -> c_void;
pub fn OGR_F_SetFieldDouble(hFeat: *const c_void, iField: c_int, dfValue: c_double) -> c_void;
pub fn OGR_F_SetFieldInteger(hFeat: *const c_void, iField: c_int, nValue: c_int) -> c_void;
pub fn OGR_F_Destroy(hFeat: *const c_void);
pub fn OGR_G_CreateGeometry(eGeometryType: c_int) -> *const c_void;
pub fn OGR_G_CreateFromWkt(ppszData: &mut *const c_char, hSRS: *const c_void, phGeometry: &mut *const c_void) -> OGRErr;
pub fn OGR_G_Clone(OGRGeometryH: *const c_void) -> *const c_void;
pub fn OGR_G_GetGeometryType(hGeom: *const c_void) -> c_int;
pub fn OGR_G_GetPoint(hGeom: *const c_void, i: c_int, pdfX: &mut c_double, pdfY: &mut c_double, pdfZ: &mut c_double);
pub fn OGR_G_GetPointCount(hGeom: *const c_void) -> c_int;
Expand All @@ -41,14 +48,17 @@ extern {
pub fn OGR_G_TransformTo(hGeom: *const c_void, hSRS: *const c_void) -> OGRErr;
pub fn OGR_G_DestroyGeometry(hGeom: *mut c_void);
pub fn OGR_Fld_GetNameRef(hDefn: *const c_void) -> *const c_char;
pub fn OGR_Fld_GetType(hDefn: *const c_void) -> c_int;
pub fn OGR_Fld_GetType(hDefn: *const c_void) -> OGRFieldType;
pub fn OGR_Fld_Create(pszName: *const c_char, eType: OGRFieldType) -> *const c_void;
pub fn OGR_Fld_GetWidth(hDefn: *const c_void) -> c_int;
pub fn OGR_Fld_GetPrecision(hDefn: *const c_void) -> c_int;
pub fn OGR_Fld_SetWidth(hDefn: *const c_void, nNewWidth: c_int) -> c_void;
pub fn OGR_Fld_SetPrecision(hDefn: *const c_void, nNewPrecision: c_int) -> c_void;
pub fn OGR_Fld_Destroy(hDefn: *mut c_void) -> c_void;
pub fn OGRFree(ptr: *mut c_void);
pub fn VSIFree(ptr: *mut c_void);
}

pub const OFT_REAL: c_int = 2;
pub const OFT_STRING: c_int = 4;

pub const WKB_UNKNOWN: c_int = 0;
pub const WKB_POINT: c_int = 1;
pub const WKB_LINESTRING: c_int = 2;
Expand Down
25 changes: 23 additions & 2 deletions gdal-sys/src/ogr_enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#[allow(dead_code)]
#[repr(C)]
pub enum OGRErr {
OGRERR_NONE = 0,
OGRERR_NONE = 0,
OGRERR_NOT_ENOUGH_DATA = 1,
OGRERR_NOT_ENOUGH_MEMORY = 2,
OGRERR_UNSUPPORTED_GEOMETRY_TYPE = 3,
Expand All @@ -12,4 +12,25 @@ pub enum OGRErr {
OGRERR_UNSUPPORTED_SRS = 7,
OGRERR_INVALID_HANDLE = 8,
OGRERR_NON_EXISTING_FEATURE = 9
}
}

#[derive(Clone, Copy, Debug, PartialEq)]
#[allow(dead_code)]
#[repr(C)]
pub enum OGRFieldType {
OFTInteger = 0,
OFTIntegerList = 1,
OFTReal = 2,
OFTRealList = 3,
OFTString = 4,
OFTStringList = 5,
OFTWideString = 6,
OFTWideStringList = 7,
OFTBinary = 8,
OFTDate = 9,
OFTTime = 10,
OFTDateTime = 11,
OFTInteger64 = 12,
OFTInteger64List = 13,
OFTMaxType = 14
}
16 changes: 14 additions & 2 deletions src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use libc::{c_int};
use gdal_sys::cpl_error::CPLErr;
use gdal_sys::ogr_enums::OGRErr;
use gdal_sys::ogr_enums::{OGRErr, OGRFieldType};

// Create the Error, ErrorKind, ResultExt, and Result types
error_chain! {
Expand All @@ -16,11 +16,23 @@ error_chain! {
}
NullPointer(method_name: &'static str) {
description("GDAL method returned a NULL pointer.")
display("GDAL method '{}' returned a NULL pointer.", method_name)
display("GDAL method '{}' returned a NULL pointer.", method_name)
}
OgrError(err: OGRErr, method_name: &'static str) {
description("OGR error")
display("OGR method '{}' returned error: '{:?}'", method_name, err)
}
UnhandledFieldType(field_type: OGRFieldType, method_name: &'static str){
description("Unhandled field type")
display("Unhandled type {:?} on OGR method {}", field_type, method_name)
}
InvalidFieldName(field_name: String, method_name: &'static str){
description("Invalid field name error")
display("Invalid field name '{}' used on method {}", field_name, method_name)
}
UnlinkedGeometry(method_name: &'static str){
description("Unlinked Geometry")
display("Unlinked Geometry on method {}", method_name)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a more descriptive name for this error (maybe InvalidFieldType)?
Also i added the method name to the errors related to the GDAL FFI calls to enable users to look up methods in the GDAL API. I'm not sure if it is needed here.

}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//! for feature in layer.features() {
//! let highway_field = feature.field("highway").unwrap();
//! let geometry = feature.geometry();
//! println!("{} {}", highway_field.as_string(), geometry.wkt().unwrap());
//! println!("{} {}", highway_field.to_string().unwrap(), geometry.wkt().unwrap());
//! }
//! ```

Expand Down
4 changes: 2 additions & 2 deletions src/spatial_ref/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ fn transform_coordinates(){
fn transform_ogr_geometry(){
//let expected_value = "POLYGON ((5509543.150809700600803 1716062.191619219258428,5467122.000330002978444 1980151.204280239529908,5623571.028492723591626 2010213.310253676958382,5671834.921544363722205 1746968.078280254499987,5509543.150809700600803 1716062.191619219258428))";
let expected_value = "POLYGON ((5509543.15080969966948 1716062.191619222285226,5467122.000330002047122 1980151.204280242323875,5623571.028492721728981 2010213.31025367998518,5671834.921544362790883 1746968.078280256595463,5509543.15080969966948 1716062.191619222285226))";
let mut geom = Geometry::from_wkt("POLYGON((23.43 37.58, 23.43 40.0, 25.29 40.0, 25.29 37.58, 23.43 37.58))").unwrap();
let geom = Geometry::from_wkt("POLYGON((23.43 37.58, 23.43 40.0, 25.29 40.0, 25.29 37.58, 23.43 37.58))").unwrap();
let spatial_ref1 = SpatialRef::from_proj4("+proj=laea +lat_0=52 +lon_0=10 +x_0=4321000 +y_0=3210000 +ellps=GRS80 +units=m +no_defs").unwrap();
let spatial_ref2 = SpatialRef::from_wkt("GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",7030]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY[\"EPSG\",6326]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",8901]],UNIT[\"DMSH\",0.0174532925199433,AUTHORITY[\"EPSG\",9108]],AXIS[\"Lat\",NORTH],AXIS[\"Long\",EAST],AUTHORITY[\"EPSG\",4326]]").unwrap();
let htransform = CoordTransform::new(&spatial_ref2, &spatial_ref1).unwrap();
geom.transform(&htransform).unwrap();
geom.transform_inplace(&htransform).unwrap();
assert_eq!(expected_value, geom.wkt().unwrap());
}
20 changes: 20 additions & 0 deletions src/vector/defn.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use libc::{c_int, c_void};
use utils::_string;
use gdal_sys::ogr;
use vector::layer::Layer;
use gdal_major_object::MajorObject;
use gdal_sys::ogr_enums::OGRFieldType;

/// Layer definition
///
Expand All @@ -26,6 +29,11 @@ impl Defn {
total: total
};
}

pub fn from_layer(lyr: &Layer) -> Defn {
let c_defn = unsafe { ogr::OGR_L_GetLayerDefn(lyr.gdal_object_ptr())};
Defn {c_defn: c_defn}
}
}

pub struct FieldIterator<'a> {
Expand Down Expand Up @@ -66,4 +74,16 @@ impl<'a> Field<'a> {
let rv = unsafe { ogr::OGR_Fld_GetNameRef(self.c_field_defn) };
return _string(rv);
}

pub fn field_type(&'a self) -> OGRFieldType {
unsafe { ogr::OGR_Fld_GetType(self.c_field_defn) }
}

pub fn width(&'a self) -> i32 {
unsafe { ogr::OGR_Fld_GetWidth(self.c_field_defn) }
}

pub fn precision(&'a self) -> i32 {
unsafe { ogr::OGR_Fld_GetPrecision(self.c_field_defn) }
}
}
Loading