sdc/
reader.rs

1//! Read points from an .sdc file.
2
3use std::fs::File;
4use std::iter::IntoIterator;
5use std::io::{BufReader, Read};
6use std::path::Path;
7use std::str;
8
9use byteorder;
10use byteorder::{LittleEndian, ReadBytesExt};
11
12use error::Error;
13use point::{Point, TargetType};
14use result::Result;
15
16/// An object for readings .sdc points.
17///
18/// We don't just read them all into memory right away since .sdc files can be quite big.
19#[derive(Debug)]
20pub struct Reader<R: Read> {
21    reader: R,
22    version: Version,
23    header_information: Vec<u8>,
24}
25
26/// The sdc file version.
27#[derive(Clone, Copy, Debug)]
28pub struct Version {
29    /// The sdc major version.
30    pub major: u16,
31    /// The sdc minor version.
32    pub minor: u16,
33}
34
35impl Reader<BufReader<File>> {
36    /// Creates a new reader for a path.
37    ///
38    /// # Examples
39    ///
40    /// ```
41    /// use sdc::reader::Reader;
42    /// let reader = Reader::from_path("data/4-points-5.0.sdc").unwrap();
43    /// ```
44    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Reader<BufReader<File>>> {
45        let reader = BufReader::new(try!(File::open(path)));
46        Reader::new(reader)
47    }
48}
49
50impl<R: Read> Reader<R> {
51    /// Creates a new reader, consuimg a `Read`.
52    ///
53    /// # Examples
54    ///
55    /// ```
56    /// use std::fs::File;
57    /// use sdc::reader::Reader;
58    /// let file = File::open("data/4-points-5.0.sdc").unwrap();
59    /// let reader = Reader::new(file);
60    /// ```
61    pub fn new(mut reader: R) -> Result<Reader<R>> {
62        let header_size = try!(reader.read_u32::<LittleEndian>());
63        let major = try!(reader.read_u16::<LittleEndian>());
64        if major != 5 {
65            return Err(Error::InvalidMajorVersion(major));
66        }
67        let minor = try!(reader.read_u16::<LittleEndian>());
68        let header_information_size = header_size - 8;
69        let mut header_information = Vec::with_capacity(header_information_size as usize);
70        if try!(reader.by_ref()
71                      .take(header_information_size as u64)
72                      .read_to_end(&mut header_information)) !=
73           header_information_size as usize {
74            return Err(Error::InvalidHeaderInformation);
75        }
76        Ok(Reader {
77            reader: reader,
78            version: Version { major: major, minor: minor, },
79            header_information: header_information,
80        })
81    }
82
83    /// Reads the next point from the underlying `Read`.
84    ///
85    /// # Examples
86    ///
87    /// ```
88    /// use sdc::reader::Reader;
89    /// let mut reader = Reader::from_path("data/4-points-5.0.sdc").unwrap();
90    /// let point = reader.next_point();
91    /// ```
92    pub fn next_point(&mut self) -> Result<Option<Point>> {
93        // Technically we should just check the first byte instead of the first four, but the work
94        // required to do that doesn't seem worth it at the moment.
95        let time = match self.reader.read_f64::<LittleEndian>() {
96            Ok(time) => time,
97            Err(byteorder::Error::UnexpectedEOF) => return Ok(None),
98            Err(err) => return Err(Error::from(err)),
99        };
100        let range = try!(self.reader.read_f32::<LittleEndian>());
101        let theta = try!(self.reader.read_f32::<LittleEndian>());
102        let x = try!(self.reader.read_f32::<LittleEndian>());
103        let y = try!(self.reader.read_f32::<LittleEndian>());
104        let z = try!(self.reader.read_f32::<LittleEndian>());
105        let amplitude = try!(self.reader.read_u16::<LittleEndian>());
106        let width = try!(self.reader.read_u16::<LittleEndian>());
107        let target_type = try!(TargetType::from_u8(try!(self.reader.read_u8())));
108        let target = try!(self.reader.read_u8());
109        let num_target = try!(self.reader.read_u8());
110        let rg_index = try!(self.reader.read_u16::<LittleEndian>());
111        let channel_desc_byte = try!(self.reader.read_u8());
112        let mut class_id = None;
113        let mut rho = None;
114        let mut reflectance = None;
115        if self.version.major >= 5 && self.version.minor >= 2 {
116            class_id = Some(try!(self.reader.read_u8()));
117        }
118        // These 5.3 and 5.4 reads are untested, since I don't have a real-world sample file yet.
119        if self.version.major >= 5 && self.version.minor >= 3 {
120            rho = Some(try!(self.reader.read_f32::<LittleEndian>()));
121        }
122        if self.version.major >= 5 && self.version.minor >= 4 {
123            reflectance = Some(try!(self.reader.read_i16::<LittleEndian>()));
124        }
125        Ok(Some(Point {
126            time: time,
127            range: range,
128            theta: theta,
129            x: x,
130            y: y,
131            z: z,
132            amplitude: amplitude,
133            width: width,
134            target_type: target_type,
135            target: target,
136            num_target: num_target,
137            rg_index: rg_index,
138            facet_number: channel_desc_byte & 0x3,
139            high_channel: (channel_desc_byte & 0b01000000) == 0b01000000,
140            class_id: class_id,
141            rho: rho,
142            reflectance: reflectance
143        }))
144    }
145
146    /// Returns this file's version as a `(u16, u16)`.
147    ///
148    /// # Examples
149    ///
150    /// ```
151    /// use sdc::reader::{Reader, Version};
152    /// let reader = Reader::from_path("data/4-points-5.0.sdc").unwrap();
153    /// let Version { major, minor } = reader.version();
154    /// ```
155    pub fn version(&self) -> Version {
156        self.version
157    }
158
159    /// Returns this file's header information, or an error if it is not valid ASCII.
160    ///
161    /// # Examples
162    ///
163    /// ```
164    /// use sdc::reader::Reader;
165    /// let reader = Reader::from_path("data/4-points-5.0.sdc").unwrap();
166    /// let header_information = reader.header_information_as_str();
167    /// ```
168    pub fn header_information_as_str(&self) -> Result<&str> {
169        str::from_utf8(&self.header_information[..]).map_err(|e| Error::from(e))
170    }
171}
172
173impl<R: Read> IntoIterator for Reader<R> {
174    type Item = Point;
175    type IntoIter = PointIterator<R>;
176    fn into_iter(self) -> Self::IntoIter {
177        PointIterator { reader: self }
178    }
179}
180
181/// An iterator over a reader's points.
182#[derive(Debug)]
183pub struct PointIterator<R: Read> {
184    reader: Reader<R>,
185}
186
187impl<R: Read> Iterator for PointIterator<R> {
188    type Item = Point;
189    fn next(&mut self) -> Option<Self::Item> {
190        self.reader.next_point().unwrap()
191    }
192}
193
194#[cfg(test)]
195mod tests {
196    use super::*;
197
198    #[test]
199    fn read_points() {
200        let reader = Reader::from_path("data/4-points-5.0.sdc").unwrap();
201        let points: Vec<_> = reader.into_iter().collect();
202        assert_eq!(4, points.len());
203    }
204
205    #[test]
206    fn read_52() {
207        let reader = Reader::from_path("data/4-points-5.2.sdc").unwrap();
208        let points: Vec<_> = reader.into_iter().collect();
209        assert_eq!(4, points.len());
210        assert_eq!(4, points[0].class_id.unwrap());
211    }
212}