shapelib/
shape.rs

1//! shape
2//!
3//! to control publication imported modules
4//!
5//! # Requirements
6//!
7//! - ./shapelib/include/shapefil.h
8//! - ./shapelib/lib/shapelib_i.lib
9//! - ./shapelib/bin/shapelib.dll
10//!
11//! - ./include/bridge.hpp
12//! - ./src/bridge.cpp
13//!
14
15#![allow(unused)]
16// #![allow(unused_imports)]
17// #![allow(unused_attributes)]
18#![allow(non_snake_case)]
19#![allow(non_camel_case_types)]
20#![allow(non_upper_case_globals)]
21
22mod cshapefil;
23use cshapefil::*;
24
25mod cppbridge;
26pub use cppbridge::{ShapeC, c};
27
28use std::error::Error;
29use std::collections::BTreeMap;
30use asciiz::u8z;
31use encoding_rs;
32
33/// trait Drop
34impl Drop for ShapeC {
35  /// dispose
36  fn drop(&mut self) {
37    unsafe { self.dispose(); }
38  }
39}
40
41/// get pref and city from PPNNN assume JCODE
42pub fn get_pref_city(s: &str) -> Result<(i32, i32), Box<dyn Error>> {
43  if s.len() < 5 { return Err(format!("expect PPNNN but '{}'", s).into()); }
44  let pref = i32::from_str_radix(&s[0..2], 10)?; // s[0..2].parse::<i32>()?;
45  let city = i32::from_str_radix(&s[2..5], 10)?; // s[2..5].parse::<i32>()?;
46  Ok((pref, city))
47}
48
49/// get value of a[i] (a as *mut type)
50#[macro_export]
51macro_rules! ptr_array {
52  ($a: expr, $i: expr) => {
53    std::slice::from_raw_parts($a, $i as usize + 1)[$i as usize]
54  };
55}
56pub use ptr_array;
57
58/// create String from u8z (as u8 vector)
59pub fn u8zs(b: Vec<u8>) -> Result<String, Box<dyn Error>> {
60  let l = b.iter().position(|&c| c == 0).ok_or("not terminated by null")?;
61  Ok(String::from_utf8(b[0..l].to_vec())?)
62}
63
64/// create String from i8z (as *const i8)
65pub fn i8zs(b: *const i8, enc: &str) -> Result<String, Box<dyn Error>> {
66unsafe {
67  let mut l: usize = 0;
68  loop {
69    let c = std::slice::from_raw_parts((b as usize + l) as *const i8, 1);
70    if c[0] == 0 as i8 { break; }
71    l += 1;
72  }
73  let s = std::slice::from_raw_parts(b as *const u8, l);
74  match enc {
75  "cp932" => {
76    let (cow, enc_used, had_errors) = encoding_rs::SHIFT_JIS.decode(s);
77    Ok(cow.into_owned()) // Ok(String::from_utf8((&cow[..]).into())?)
78  },
79  _ => Ok(String::from_utf8(s.to_vec())?)
80  }
81}
82}
83
84/// V4d
85pub type V4d = [f64; 4];
86
87/// Pt2d
88#[derive(Debug)]
89pub struct Pt2d {
90  /// x
91  pub x: f64,
92  /// y
93  pub y: f64
94}
95
96/// Bounds4d
97pub type Bounds4d = Vec<V4d>;
98
99/// Contour2d
100pub type Contour2d = Vec<Pt2d>;
101
102/// Contours2d
103pub type Contours2d = Vec<Contour2d>;
104
105/// ShpContours
106pub type ShpContours = BTreeMap<i32, Contours2d>;
107
108/// StrFields
109pub type StrFields = Vec<String>;
110
111/// RecFields
112pub type RecFields = BTreeMap<i32, StrFields>;
113
114/// ShpContoursInf
115#[derive(Debug)]
116pub struct ShpContoursInf {
117  /// shp
118  pub shp: ShpContours,
119  /// rec
120  pub rec: RecFields,
121  /// minmax
122  pub minmax: Bounds4d
123}
124
125/// ShpContoursInf
126impl ShpContoursInf {
127  /// constructor
128  pub fn new() -> Result<ShpContoursInf, Box<dyn Error>> {
129    Ok(ShpContoursInf{
130      shp: vec![].into_iter().collect(),
131      rec: vec![].into_iter().collect(),
132      minmax: vec![[0.0; 4], [0.0; 4]]})
133  }
134}
135
136/// ShapeF
137#[derive(Debug)]
138pub struct ShapeF {
139  /// fname
140  pub fname: String,
141  /// enc
142  pub enc: String,
143  /// h_shp
144  pub h_shp: *mut SHPInfo,
145  /// h_dbf
146  pub h_dbf: *mut DBFInfo,
147  /// valid
148  pub valid: bool
149}
150
151/// ShapeF
152impl ShapeF {
153  /// constructor
154  pub fn new(fname: &str, enc: &str) -> Result<ShapeF, Box<dyn Error>> {
155    let mut shp = ShapeF{fname: fname.to_string(), enc: enc.to_string(),
156      h_shp: 0 as *mut SHPInfo, h_dbf: 0 as *mut DBFInfo, valid: false};
157    let fnz = u8z::U8zBuf::from_u8array(fname.as_bytes());
158    let opt = u8z::U8zBuf::from_u8array(b"rb");
159unsafe {
160    shp.h_shp = SHPOpen(fnz.as_i8p(), opt.as_i8p());
161    shp.h_dbf = DBFOpen(fnz.as_i8p(), opt.as_i8p());
162}
163    if shp.h_shp == 0 as *mut SHPInfo || shp.h_dbf == 0 as *mut DBFInfo {
164      return Err("ShapeF is not initialized".into());
165    }
166    shp.valid = true;
167    Ok(shp)
168  }
169
170  /// dispose
171  pub fn dispose(&mut self) {
172    if self.h_dbf != 0 as *mut DBFInfo {
173unsafe {
174      DBFClose(self.h_dbf);
175}
176      self.h_dbf = 0 as *mut DBFInfo;
177    }
178    if self.h_shp != 0 as *mut SHPInfo {
179unsafe {
180      SHPClose(self.h_shp);
181}
182      self.h_shp = 0 as *mut SHPInfo;
183    }
184    self.valid = false;
185  }
186
187  /// disp_record_inf
188  pub fn disp_record_inf(&self) -> Result<(), Box<dyn Error>> {
189    println!("SHP: {:?}, DBF: {:?}", self.h_shp, self.h_dbf);
190    if !self.valid { return Err("ShapeF is not valid".into()); }
191unsafe {
192    let records = DBFGetRecordCount(self.h_dbf);
193    let fields = DBFGetFieldCount(self.h_dbf);
194    println!("DBF: records: {}, fields: {}", records, fields);
195    for fld in 0..fields {
196      let mut name = vec![0u8; 12];
197      let mut fwd = (0i32, 0i32); // fw fd
198      let ft = DBFGetFieldInfo(self.h_dbf, fld,
199        &mut name[0] as *mut u8 as *mut i8, &mut fwd.0, &mut fwd.1);
200      println!(" fld: {} {:?} [{}] {} {}", fld, ft, u8zs(name)?, fwd.0, fwd.1);
201    }
202}
203    Ok(())
204  }
205
206  /// get_shape
207  pub fn get_shp_contours(&self, ignore: bool) ->
208    Result<ShpContoursInf, Box<dyn Error>> {
209    if !self.valid { return Err("ShapeF is not valid".into()); }
210    let mut sci = ShpContoursInf::new()?;
211    let mut entities = 0i32;
212    let mut shape_type = 0i32;
213unsafe {
214    SHPGetInfo(self.h_shp, &mut entities, &mut shape_type,
215      &mut sci.minmax[0][0], &mut sci.minmax[1][0]);
216}
217/*
218    println!("SHP: entities: {}, shapeType: {}", entities, shape_type);
219    println!("minBound X:{:11.6}, Y:{:11.6}, Z:{:11.6}, M:{:11.6}",
220      sci.minmax[0][0], sci.minmax[0][1], sci.minmax[0][2], sci.minmax[0][3]);
221    println!("maxBound X:{:11.6}, Y:{:11.6}, Z:{:11.6}, M:{:11.6}",
222      sci.minmax[1][0], sci.minmax[1][1], sci.minmax[1][2], sci.minmax[1][3]);
223*/
224    for i in 0..entities {
225unsafe {
226      let p_shape = SHPReadObject(self.h_shp, i);
227      if p_shape == 0 as *mut tagSHPObject {
228        println!("error ReadObject at {}", i);
229        continue;
230      }
231      let shape = *p_shape;
232      if shape.nSHPType != SHPT_POLYGON as i32 {
233        println!("{} not POLYGON at {}\x07", shape.nSHPType, i);
234      }
235      // SHPComputeExtents(shape); // recompute the extenst
236      // SHPRewindObject(self.h_shp, shape); // if necessary
237      let id: i32 = shape.nShapeId;
238      let parts: i32 = shape.nParts;
239      let vertices: i32 = shape.nVertices;
240//      println!("[{:4}]{:4}:{:3}:{:6}", i, id, parts, vertices); // 0-1906
241      if parts == 0 { println!("parts==0 at {}\x07", i); }
242
243      let fields = DBFGetFieldCount(self.h_dbf);
244      let p = DBFIsRecordDeleted(self.h_dbf, id); // DBFMarkRecordDeleted(...);
245      if p != 0 {
246        println!("no record DBF[{}]\x07", id);
247      } else {
248        // needless free
249        // DBFRead[Integer|Double|String]Attribute(self.h_dbf, id, f);
250        // DBFIsAttributeNULL(self.h_dbf, id, f);
251        // DBFGetNativeFieldType(self.h_dbf, f);
252        let mut flds = Vec::<String>::with_capacity(fields as usize);
253        for j in 0..fields {
254          let p_i8zs = DBFReadStringAttribute(self.h_dbf, id, j);
255          flds.push(i8zs(p_i8zs, self.enc.as_str())?);
256//          println!("-[{}]-[{}]", j, flds[j as usize].as_str());
257        }
258        let (pref, city) = match get_pref_city(flds[0].as_str()) {
259        Err(e) => { if !ignore { println!("{} at {}\x07", e, i) }; (0, 0) },
260        Ok(r) => r
261        };
262/*
263  if pref != 26 { SHPDestroyObject(p_shape); continue; } // 26 1177-1212
264  if city != 343 { SHPDestroyObject(p_shape); continue; } // 343 1204 etc
265  print!("{:4}:", id);
266  for j in 0..fields { print!(" [{}]", flds[j as usize]); }
267  for j in 0..4 {
268    print!(" {:9.4}", DBFReadDoubleAttribute(self.h_dbf, id, j + 7));
269  }
270  println!("");
271*/
272        sci.rec.insert(id, flds); // always create new <k, StrFields> of rec
273      }
274      let mut contours = Vec::<Contour2d>::with_capacity(parts as usize);
275      for n in 0..parts {
276//  print!(" {:3}[", n);
277        let typ: i32 = ptr_array!(shape.panPartType, n);
278        let vi_s: usize = ptr_array!(shape.panPartStart, n) as usize; // (i32)
279        let vi_e: usize = if n == parts - 1 { vertices }
280          else { ptr_array!(shape.panPartStart, n + 1) } as usize; // (i32)
281        let mut contour = Vec::<Pt2d>::with_capacity(vi_e - vi_s); // Contour2d
282        for vi in vi_s..vi_e {
283          let x: f64 = ptr_array!(shape.padfX, vi);
284          let y: f64 = ptr_array!(shape.padfY, vi);
285          let z: f64 = ptr_array!(shape.padfZ, vi);
286          let m: f64 = ptr_array!(shape.padfM, vi); // 0 if not provided
287//  print!(" ({:7.2} {:7.2})", x, y);
288          contour.push(Pt2d{x: x, y: y});
289        }
290        contours.push(contour);
291//  println!("]");
292      }
293      sci.shp.insert(id, contours); // always create new <k, Contours2d> of shp
294      SHPDestroyObject(p_shape); // SHPDestroyShape() in API manual
295}
296    }
297  // forget leak into_raw from_raw
298    Ok(sci)
299  }
300}
301
302/// trait Drop
303impl Drop for ShapeF {
304  /// dispose
305  fn drop(&mut self) {
306    self.dispose();
307  }
308}