Skip to content

Commit eec087b

Browse files
authored
Merge pull request #8 from hakolao/feature-f32
Feature f32
2 parents 0dcef6a + e6fdde7 commit eec087b

File tree

9 files changed

+130
-89
lines changed

9 files changed

+130
-89
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ serde_json = "^1.0"
2525

2626
[features]
2727
geojson = ["dep:geojson", "dep:serde_json"]
28+
f32 = []
2829

2930
[package.metadata.docs.rs]
3031
all-features = true

examples/ex.rs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
1-
use contour::ContourBuilder;
1+
use contour::{ContourBuilder, Float};
22
use geojson::{FeatureCollection, GeoJson};
33
use std::fs::File;
44
use std::io::{BufWriter, Write};
55

66
fn main() {
77
let pot_pop_fr = include_str!("../tests/fixtures/pot_pop_fr.json");
88
let raw_data: serde_json::Value = serde_json::from_str(pot_pop_fr).unwrap();
9-
let matrix: Vec<f64> = raw_data["data"]
9+
let matrix: Vec<Float> = raw_data["data"]
1010
.as_array()
1111
.unwrap()
1212
.iter()
13-
.map(|x| x.as_f64().unwrap())
13+
.map(|x| {
14+
#[cfg(not(feature = "f32"))]
15+
{
16+
x.as_f64().unwrap()
17+
}
18+
#[cfg(feature = "f32")]
19+
{
20+
x.as_f64().unwrap() as f32
21+
}
22+
})
1423
.collect();
1524
let h = raw_data["height"].as_u64().unwrap() as u32;
1625
let w = raw_data["width"].as_u64().unwrap() as u32;
@@ -51,11 +60,20 @@ fn main() {
5160

5261
let volcano = include_str!("../tests/fixtures/volcano.json");
5362
let raw_data: serde_json::Value = serde_json::from_str(volcano).unwrap();
54-
let matrix: Vec<f64> = raw_data["data"]
63+
let matrix: Vec<Float> = raw_data["data"]
5564
.as_array()
5665
.unwrap()
5766
.iter()
58-
.map(|x| x.as_f64().unwrap())
67+
.map(|x| {
68+
#[cfg(not(feature = "f32"))]
69+
{
70+
x.as_f64().unwrap()
71+
}
72+
#[cfg(feature = "f32")]
73+
{
74+
x.as_f64().unwrap() as f32
75+
}
76+
})
5977
.collect();
6078
let h = raw_data["height"].as_u64().unwrap() as u32;
6179
let w = raw_data["width"].as_u64().unwrap() as u32;

src/area.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use crate::Pt;
1+
use crate::{Float, Pt};
22

3-
pub fn area(ring: &[Pt]) -> f64 {
3+
pub fn area(ring: &[Pt]) -> Float {
44
let mut i = 0;
55
let n = ring.len() - 1;
66
let mut area = ring[n - 1].y * ring[0].x - ring[n - 1].x * ring[0].y;
@@ -51,7 +51,7 @@ fn ring_contains(ring: &[Pt], point: &Pt) -> i32 {
5151

5252
fn segment_contains(a: &Pt, b: &Pt, c: &Pt) -> bool {
5353
if collinear(a, b, c) {
54-
if (a.x - b.x).abs() < std::f64::EPSILON {
54+
if (a.x - b.x).abs() < Float::EPSILON {
5555
within(a.y, c.y, b.y)
5656
} else {
5757
within(a.x, c.x, b.x)
@@ -62,9 +62,9 @@ fn segment_contains(a: &Pt, b: &Pt, c: &Pt) -> bool {
6262
}
6363

6464
fn collinear(a: &Pt, b: &Pt, c: &Pt) -> bool {
65-
((b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y)).abs() < std::f64::EPSILON
65+
((b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y)).abs() < Float::EPSILON
6666
}
6767

68-
fn within(p: f64, q: f64, r: f64) -> bool {
68+
fn within(p: Float, q: Float, r: Float) -> bool {
6969
p <= q && q <= r || r <= q && q <= p
7070
}

src/band.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,32 @@
1+
use crate::Float;
12
use geo_types::MultiPolygon;
23

34
/// An isoband has the geometry and min / max values of a contour ring, built by [`ContourBuilder`].
45
#[derive(Debug, Clone)]
56
pub struct Band {
6-
pub(crate) geometry: MultiPolygon,
7-
pub(crate) min_v: f64,
8-
pub(crate) max_v: f64,
7+
pub(crate) geometry: MultiPolygon<Float>,
8+
pub(crate) min_v: Float,
9+
pub(crate) max_v: Float,
910
}
1011

1112
impl Band {
1213
/// Borrow the [`MultiPolygon`](geo_types::MultiPolygon) geometry of this contour.
13-
pub fn geometry(&self) -> &MultiPolygon {
14+
pub fn geometry(&self) -> &MultiPolygon<Float> {
1415
&self.geometry
1516
}
1617

1718
/// Get the owned polygons and thresholds (min and max) of this band.
18-
pub fn into_inner(self) -> (MultiPolygon, f64, f64) {
19+
pub fn into_inner(self) -> (MultiPolygon<Float>, Float, Float) {
1920
(self.geometry, self.min_v, self.max_v)
2021
}
2122

2223
/// Get the minimum value used to construct this band.
23-
pub fn min_v(&self) -> f64 {
24+
pub fn min_v(&self) -> Float {
2425
self.min_v
2526
}
2627

2728
/// Get the maximum value used to construct this band.
28-
pub fn max_v(&self) -> f64 {
29+
pub fn max_v(&self) -> Float {
2930
self.max_v
3031
}
3132

src/contour.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
1+
use crate::Float;
12
use geo_types::MultiPolygon;
23

34
/// A contour has the geometry and threshold of a contour ring, built by [`ContourBuilder`].
45
#[derive(Debug, Clone)]
56
pub struct Contour {
6-
pub(crate) geometry: MultiPolygon,
7-
pub(crate) threshold: f64,
7+
pub(crate) geometry: MultiPolygon<Float>,
8+
pub(crate) threshold: Float,
89
}
910

1011
impl Contour {
1112
/// Borrow the [`MultiPolygon`](geo_types::MultiPolygon) geometry of this contour.
12-
pub fn geometry(&self) -> &MultiPolygon {
13+
pub fn geometry(&self) -> &MultiPolygon<Float> {
1314
&self.geometry
1415
}
1516

1617
/// Get the owned polygons and threshold of this contour.
17-
pub fn into_inner(self) -> (MultiPolygon, f64) {
18+
pub fn into_inner(self) -> (MultiPolygon<Float>, Float) {
1819
(self.geometry, self.threshold)
1920
}
2021

2122
/// Get the threshold used to construct this contour.
22-
pub fn threshold(&self) -> f64 {
23+
pub fn threshold(&self) -> Float {
2324
self.threshold
2425
}
2526

src/contourbuilder.rs

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::area::{area, contains};
22
use crate::error::{new_error, ErrorKind, Result};
33
use crate::isoringbuilder::IsoRingBuilder;
4-
use crate::{Band, Contour, Line, Ring};
4+
use crate::{Band, Contour, Float, Line, Ring};
55
use geo_types::{LineString, MultiLineString, MultiPolygon, Polygon};
66
use rustc_hash::FxHashMap;
77

@@ -18,13 +18,13 @@ pub struct ContourBuilder {
1818
/// Whether to smooth the contours
1919
smooth: bool,
2020
/// The horizontal coordinate for the origin of the grid.
21-
x_origin: f64,
21+
x_origin: Float,
2222
/// The vertical coordinate for the origin of the grid.
23-
y_origin: f64,
23+
y_origin: Float,
2424
/// The horizontal step for the grid
25-
x_step: f64,
25+
x_step: Float,
2626
/// The vertical step for the grid
27-
y_step: f64,
27+
y_step: Float,
2828
}
2929

3030
impl ContourBuilder {
@@ -43,38 +43,38 @@ impl ContourBuilder {
4343
dx,
4444
dy,
4545
smooth,
46-
x_origin: 0f64,
47-
y_origin: 0f64,
48-
x_step: 1f64,
49-
y_step: 1f64,
46+
x_origin: 0.,
47+
y_origin: 0.,
48+
x_step: 1.,
49+
y_step: 1.,
5050
}
5151
}
5252

5353
/// Sets the x origin of the grid.
54-
pub fn x_origin(mut self, x_origin: impl Into<f64>) -> Self {
54+
pub fn x_origin(mut self, x_origin: impl Into<Float>) -> Self {
5555
self.x_origin = x_origin.into();
5656
self
5757
}
5858

5959
/// Sets the y origin of the grid.
60-
pub fn y_origin(mut self, y_origin: impl Into<f64>) -> Self {
60+
pub fn y_origin(mut self, y_origin: impl Into<Float>) -> Self {
6161
self.y_origin = y_origin.into();
6262
self
6363
}
6464

6565
/// Sets the x step of the grid.
66-
pub fn x_step(mut self, x_step: impl Into<f64>) -> Self {
66+
pub fn x_step(mut self, x_step: impl Into<Float>) -> Self {
6767
self.x_step = x_step.into();
6868
self
6969
}
7070

7171
/// Sets the y step of the grid.
72-
pub fn y_step(mut self, y_step: impl Into<f64>) -> Self {
72+
pub fn y_step(mut self, y_step: impl Into<Float>) -> Self {
7373
self.y_step = y_step.into();
7474
self
7575
}
7676

77-
fn smoooth_linear(&self, ring: &mut Ring, values: &[f64], value: f64) {
77+
fn smoooth_linear(&self, ring: &mut Ring, values: &[Float], value: Float) {
7878
let dx = self.dx;
7979
let dy = self.dy;
8080
let len_values = values.len();
@@ -89,11 +89,11 @@ impl ContourBuilder {
8989
let ix = (yt * dx + xt) as usize;
9090
if ix < len_values {
9191
let v1 = values[ix];
92-
if x > 0.0 && x < (dx as f64) && (xt as f64 - x).abs() < std::f64::EPSILON {
92+
if x > 0.0 && x < (dx as Float) && (xt as Float - x).abs() < Float::EPSILON {
9393
v0 = values[(yt * dx + xt - 1) as usize];
9494
point.x = x + (value - v0) / (v1 - v0) - 0.5;
9595
}
96-
if y > 0.0 && y < (dy as f64) && (yt as f64 - y).abs() < std::f64::EPSILON {
96+
if y > 0.0 && y < (dy as Float) && (yt as Float - y).abs() < Float::EPSILON {
9797
v0 = values[((yt - 1) * dx + xt) as usize];
9898
point.y = y + (value - v0) / (v1 - v0) - 0.5;
9999
}
@@ -111,7 +111,7 @@ impl ContourBuilder {
111111
///
112112
/// * `values` - The slice of values to be used.
113113
/// * `thresholds` - The slice of thresholds values to be used.
114-
pub fn lines(&self, values: &[f64], thresholds: &[f64]) -> Result<Vec<Line>> {
114+
pub fn lines(&self, values: &[Float], thresholds: &[Float]) -> Result<Vec<Line>> {
115115
if values.len() as u32 != self.dx * self.dy {
116116
return Err(new_error(ErrorKind::BadDimension));
117117
}
@@ -122,7 +122,12 @@ impl ContourBuilder {
122122
.collect()
123123
}
124124

125-
fn line(&self, values: &[f64], threshold: f64, isoring: &mut IsoRingBuilder) -> Result<Line> {
125+
fn line(
126+
&self,
127+
values: &[Float],
128+
threshold: Float,
129+
isoring: &mut IsoRingBuilder,
130+
) -> Result<Line> {
126131
let mut result = isoring.compute(values, threshold)?;
127132
let mut linestrings = Vec::new();
128133

@@ -132,8 +137,8 @@ impl ContourBuilder {
132137
self.smoooth_linear(&mut ring, values, threshold);
133138
}
134139
// Compute the polygon coordinates according to the grid properties if needed
135-
if (self.x_origin, self.y_origin) != (0f64, 0f64)
136-
|| (self.x_step, self.y_step) != (1f64, 1f64)
140+
if (self.x_origin, self.y_origin) != (0.0, 0.0)
141+
|| (self.x_step, self.y_step) != (1.0, 1.0)
137142
{
138143
ring.iter_mut().for_each(|point| {
139144
point.x = point.x * self.x_step + self.x_origin;
@@ -143,7 +148,7 @@ impl ContourBuilder {
143148
linestrings.push(LineString(ring));
144149
});
145150
Ok(Line {
146-
geometry: MultiLineString(linestrings),
151+
geometry: MultiLineString::<Float>(linestrings),
147152
threshold,
148153
})
149154
}
@@ -157,7 +162,7 @@ impl ContourBuilder {
157162
///
158163
/// * `values` - The slice of values to be used.
159164
/// * `thresholds` - The slice of thresholds values to be used.
160-
pub fn contours(&self, values: &[f64], thresholds: &[f64]) -> Result<Vec<Contour>> {
165+
pub fn contours(&self, values: &[Float], thresholds: &[Float]) -> Result<Vec<Contour>> {
161166
if values.len() as u32 != self.dx * self.dy {
162167
return Err(new_error(ErrorKind::BadDimension));
163168
}
@@ -170,8 +175,8 @@ impl ContourBuilder {
170175

171176
fn contour(
172177
&self,
173-
values: &[f64],
174-
threshold: f64,
178+
values: &[Float],
179+
threshold: Float,
175180
isoring: &mut IsoRingBuilder,
176181
) -> Result<Contour> {
177182
let (mut polygons, mut holes) = (Vec::new(), Vec::new());
@@ -183,16 +188,16 @@ impl ContourBuilder {
183188
self.smoooth_linear(&mut ring, values, threshold);
184189
}
185190
// Compute the polygon coordinates according to the grid properties if needed
186-
if (self.x_origin, self.y_origin) != (0f64, 0f64)
187-
|| (self.x_step, self.y_step) != (1f64, 1f64)
191+
if (self.x_origin, self.y_origin) != (0.0, 0.0)
192+
|| (self.x_step, self.y_step) != (1.0, 1.0)
188193
{
189194
ring.iter_mut().for_each(|point| {
190195
point.x = point.x * self.x_step + self.x_origin;
191196
point.y = point.y * self.y_step + self.y_origin;
192197
});
193198
}
194199
if area(&ring) > 0.0 {
195-
polygons.push(Polygon::new(LineString::new(ring), vec![]))
200+
polygons.push(Polygon::<Float>::new(LineString::new(ring), vec![]))
196201
} else {
197202
holes.push(LineString::new(ring));
198203
}
@@ -208,7 +213,7 @@ impl ContourBuilder {
208213
});
209214

210215
Ok(Contour {
211-
geometry: MultiPolygon(polygons),
216+
geometry: MultiPolygon::<Float>(polygons),
212217
threshold,
213218
})
214219
}
@@ -223,7 +228,7 @@ impl ContourBuilder {
223228
/// * `values` - The slice of values to be used.
224229
/// * `thresholds` - The slice of thresholds values to be used
225230
/// (have to be equal to or greater than 2).
226-
pub fn isobands(&self, values: &[f64], thresholds: &[f64]) -> Result<Vec<Band>> {
231+
pub fn isobands(&self, values: &[Float], thresholds: &[Float]) -> Result<Vec<Band>> {
227232
// We will compute rings as previously, but we will
228233
// iterate over the contours in pairs and use the paths from the lower threshold
229234
// and the path from the upper threshold to create the isoband.
@@ -249,8 +254,8 @@ impl ContourBuilder {
249254
}
250255
ring.dedup();
251256
// Compute the polygon coordinates according to the grid properties if needed
252-
if (self.x_origin, self.y_origin) != (0f64, 0f64)
253-
|| (self.x_step, self.y_step) != (1f64, 1f64)
257+
if (self.x_origin, self.y_origin) != (0.0, 0.0)
258+
|| (self.x_step, self.y_step) != (1.0, 1.0)
254259
{
255260
ring.iter_mut().for_each(|point| {
256261
point.x = point.x * self.x_step + self.x_origin;
@@ -263,7 +268,7 @@ impl ContourBuilder {
263268
.collect::<Vec<Ring>>();
264269
Ok((rings, *threshold))
265270
})
266-
.collect::<Result<Vec<(Vec<Ring>, f64)>>>()?;
271+
.collect::<Result<Vec<(Vec<Ring>, Float)>>>()?;
267272

268273
// We now have the rings for each isolines for all the given thresholds,
269274
// we can iterate over them in pairs to compute the isobands.
@@ -304,12 +309,12 @@ impl ContourBuilder {
304309
enclosed_by_n.insert(i, enclosed_by_j);
305310
}
306311

307-
let mut polygons: Vec<Polygon<f64>> = Vec::new();
308-
let mut interior_rings: Vec<LineString<f64>> = Vec::new();
312+
let mut polygons: Vec<Polygon<Float>> = Vec::new();
313+
let mut interior_rings: Vec<LineString<Float>> = Vec::new();
309314

310315
for (i, (ring, _)) in rings_and_area.into_iter().enumerate() {
311316
if *enclosed_by_n.get(&i).unwrap() % 2 == 0 {
312-
polygons.push(Polygon::new(ring.into(), vec![]));
317+
polygons.push(Polygon::<Float>::new(ring.into(), vec![]));
313318
} else {
314319
interior_rings.push(ring.into());
315320
}
@@ -326,7 +331,7 @@ impl ContourBuilder {
326331
polygons.reverse();
327332

328333
bands.push(Band {
329-
geometry: MultiPolygon(polygons),
334+
geometry: MultiPolygon::<Float>(polygons),
330335
min_v: *min_v,
331336
max_v: *max_v,
332337
});

0 commit comments

Comments
 (0)