diff --git a/src/algorithm/boundingbox.rs b/src/algorithm/boundingbox.rs index 7718b9432..8bada9a6b 100644 --- a/src/algorithm/boundingbox.rs +++ b/src/algorithm/boundingbox.rs @@ -93,7 +93,8 @@ impl BoundingBox for LineString /// Return the BoundingBox for a LineString /// fn bbox(&self) -> Self::Output { - get_bbox(&self.0) + // TODO this should return a Bbox + get_bbox(self.points()) } } @@ -106,7 +107,7 @@ impl BoundingBox for MultiLineString /// Return the BoundingBox for a MultiLineString /// fn bbox(&self) -> Self::Output { - get_bbox(self.0.iter().flat_map(|line| line.0.iter())) + get_bbox(self.0.iter().flat_map(|line| line.points().iter())) } } @@ -133,7 +134,7 @@ impl BoundingBox for MultiPolygon /// Return the BoundingBox for a MultiPolygon /// fn bbox(&self) -> Self::Output { - get_bbox(self.0.iter().flat_map(|poly| (poly.exterior).0.iter())) + get_bbox(self.0.iter().flat_map(|poly| poly.exterior.points().iter())) } } diff --git a/src/algorithm/centroid.rs b/src/algorithm/centroid.rs index fc3f1ec5b..a00904e83 100644 --- a/src/algorithm/centroid.rs +++ b/src/algorithm/centroid.rs @@ -73,23 +73,15 @@ impl Centroid for LineString // The Centroid of a LineString is the mean of the middle of the segment // weighted by the length of the segments. fn centroid(&self) -> Self::Output { - if self.0.is_empty() { - return None; - } - if self.0.len() == 1 { - Some(self.0[0].clone()) - } else { - let mut sum_x = T::zero(); - let mut sum_y = T::zero(); - let mut total_length = T::zero(); - for line in self.lines() { - let segment_len = line.length(); - let (x1, y1, x2, y2) = (line.start.x(), line.start.y(), line.end.x(), line.end.y()); - total_length = total_length + segment_len; - sum_x = sum_x + segment_len * ((x1 + x2) / (T::one() + T::one())); - sum_y = sum_y + segment_len * ((y1 + y2) / (T::one() + T::one())); - } - Some(Point::new(sum_x / total_length, sum_y / total_length)) + let mut sum_x = T::zero(); + let mut sum_y = T::zero(); + let mut total_length = T::zero(); + for line in self.lines() { + let segment_len = line.length(); + let (x1, y1, x2, y2) = (line.start.x(), line.start.y(), line.end.x(), line.end.y()); + total_length = total_length + segment_len; + sum_x = sum_x + segment_len * ((x1 + x2) / (T::one() + T::one())); + sum_y = sum_y + segment_len * ((y1 + y2) / (T::one() + T::one())); } Some(Point::new(sum_x / total_length, sum_y / total_length)) } @@ -110,34 +102,24 @@ impl Centroid for Polygon // See here for a formula: http://math.stackexchange.com/a/623849 // See here for detail on alternative methods: https://fotino.me/calculating-centroids/ fn centroid(&self) -> Self::Output { - let linestring = &self.exterior; - let vect = &linestring.0; - if vect.is_empty() { - return None; - } - if vect.len() == 1 { - Some(Point::new(vect[0].x(), vect[0].y())) - } else { - let external_centroid = simple_polygon_centroid(&self.exterior).unwrap(); - if !self.interiors.is_empty() { - let external_area = simple_polygon_area(&self.exterior).abs(); - // accumulate interior Polygons - let (totals_x, totals_y, internal_area) = - self.interiors - .iter() - .map(|ring| { - let area = simple_polygon_area(ring).abs(); - let centroid = simple_polygon_centroid(ring).unwrap(); - ((centroid.x() * area), (centroid.y() * area), area) - }) - .fold((T::zero(), T::zero(), T::zero()), - |accum, val| (accum.0 + val.0, accum.1 + val.1, accum.2 + val.2)); - return Some(Point::new(((external_centroid.x() * external_area) - totals_x) / - (external_area - internal_area), - ((external_centroid.y() * external_area) - totals_y) / - (external_area - internal_area))); - } - Some(external_centroid) + let external_centroid = simple_polygon_centroid(&self.exterior).unwrap(); + if !self.interiors.is_empty() { + let external_area = simple_polygon_area(&self.exterior).abs(); + // accumulate interior Polygons + let (totals_x, totals_y, internal_area) = + self.interiors + .iter() + .map(|ring| { + let area = simple_polygon_area(ring).abs(); + let centroid = simple_polygon_centroid(ring).unwrap(); + ((centroid.x() * area), (centroid.y() * area), area) + }) + .fold((T::zero(), T::zero(), T::zero()), + |accum, val| (accum.0 + val.0, accum.1 + val.1, accum.2 + val.2)); + return Some(Point::new(((external_centroid.x() * external_area) - totals_x) / + (external_area - internal_area), + ((external_centroid.y() * external_area) - totals_y) / + (external_area - internal_area))); } Some(external_centroid) } diff --git a/src/algorithm/contains.rs b/src/algorithm/contains.rs index 639bb344b..78adc2d04 100644 --- a/src/algorithm/contains.rs +++ b/src/algorithm/contains.rs @@ -44,16 +44,8 @@ impl Contains> for LineString where T: Float { fn contains(&self, p: &Point) -> bool { - // LineString without points - if self.0.is_empty() { - return false; - } - // LineString with one point equal p - if self.0.len() == 1 { - return self.0[0].contains(p); - } // check if point is a vertex - if self.0.contains(p) { + if self.points().contains(p) { return true; } for line in self.lines() { @@ -142,10 +134,6 @@ fn get_position(p: &Point, linestring: &LineString) -> PositionPoint // ?updated-min=2011-01-01T00:00:00-06:00&updated-max=2012-01-01T00:00:00-06:00&max-results=19 // Return the position of the point relative to a linestring - // LineString without points - if linestring.0.is_empty() { - return PositionPoint::Outside; - } // Point is on linestring if linestring.contains(p) { return PositionPoint::OnBoundary; @@ -223,7 +211,7 @@ impl Contains> for Polygon { fn contains(&self, linestring: &LineString) -> bool { // All LineString points must be inside the Polygon - if linestring.0.iter().all(|point| self.contains(point)) { + if linestring.points().iter().all(|point| self.contains(point)) { // The Polygon interior is allowed to intersect with the LineString // but the Polygon's rings are not !self.interiors.iter().any(|ring| ring.intersects(linestring)) diff --git a/src/algorithm/distance.rs b/src/algorithm/distance.rs index 2e8a3dc77..9580bd209 100644 --- a/src/algorithm/distance.rs +++ b/src/algorithm/distance.rs @@ -156,7 +156,7 @@ impl Distance> for Point // get exterior ring let exterior = &polygon.exterior; // No need to continue if the polygon contains the point, or is zero-length - if polygon.contains(self) || exterior.0.is_empty() { + if polygon.contains(self) { return T::zero(); } // minimum priority queue diff --git a/src/algorithm/intersects.rs b/src/algorithm/intersects.rs index d2acb5395..208d2f640 100644 --- a/src/algorithm/intersects.rs +++ b/src/algorithm/intersects.rs @@ -133,9 +133,6 @@ impl Intersects> for LineString { // See: https://github.com/brandonxiang/geojson-python-utils/blob/33b4c00c6cf27921fb296052d0c0341bd6ca1af2/geojson_utils.py fn intersects(&self, linestring: &LineString) -> bool { - if self.0.is_empty() || linestring.0.is_empty() { - return false; - } for a in self.lines() { for b in linestring.lines() { let u_b = (b.end.y() - b.start.y()) * (a.end.x() - a.start.x()) - diff --git a/src/algorithm/rotate.rs b/src/algorithm/rotate.rs index 5fbf7a291..515fa9590 100644 --- a/src/algorithm/rotate.rs +++ b/src/algorithm/rotate.rs @@ -134,15 +134,6 @@ where } } -impl RotatePoint for LineString - where T: Float -{ - /// Rotate the LineString about a point by the given number of degrees - fn rotate_around_point(&self, angle: T, point: &Point) -> Self { - unsafe { LineString::new_unchecked(rotation_matrix(angle, point, &self.points())) } - } -} - impl Rotate for Polygon where T: Float + FromPrimitive, @@ -155,11 +146,13 @@ where true => self.centroid().unwrap(), }; Polygon::new( - LineString(rotation_matrix(angle, ¢roid, &self.exterior.0)), + // TODO: can this be unchecked + LineString::new(rotation_matrix(angle, ¢roid, self.exterior.points())).unwrap(), self.interiors .iter() .map(|ring| { - LineString(rotation_matrix(angle, ¢roid, &ring.0)) + // TODO: can this be unchecked + LineString::new(rotation_matrix(angle, ¢roid, ring.points())).unwrap() }) .collect(), ) diff --git a/src/algorithm/simplifyvw.rs b/src/algorithm/simplifyvw.rs index eaaf4115b..1044e7d1b 100644 --- a/src/algorithm/simplifyvw.rs +++ b/src/algorithm/simplifyvw.rs @@ -207,11 +207,11 @@ where } } // Simplify shell - rings.push(visvalingam_preserve(geomtype, &exterior.0, epsilon, &mut tree)); + rings.push(visvalingam_preserve(geomtype, exterior.points(), epsilon, &mut tree)); // Simplify interior rings, if any if let Some(interior_rings) = interiors { for ring in interior_rings { - rings.push(visvalingam_preserve(geomtype, &ring.0, epsilon, &mut tree)) + rings.push(visvalingam_preserve(geomtype, ring.points(), epsilon, &mut tree)) } } rings @@ -370,11 +370,11 @@ where let point_a = orig[triangle.left]; let point_b = orig[triangle.current]; let point_c = orig[triangle.right]; - let bbox = LineString(vec![ + let bbox = unsafe { LineString::new_unchecked(vec![ orig[triangle.left], orig[triangle.current], orig[triangle.right], - ]).bbox() + ]) }.bbox() .unwrap(); let br = Point::new(bbox.xmin, bbox.ymin); let tl = Point::new(bbox.xmax, bbox.ymax); @@ -500,7 +500,8 @@ where geomtype: GeomType::Line, }; let mut simplified = vwp_wrapper(>, &self, None, epsilon); - LineString(simplified.pop().unwrap()) + // can this be unchecked? + LineString::new(simplified.pop().unwrap()).unwrap() } } @@ -529,8 +530,9 @@ where geomtype: GeomType::Ring, }; let mut simplified = vwp_wrapper(>, &self.exterior, Some(&self.interiors), epsilon); - let exterior = LineString(simplified.remove(0)); - let interiors = simplified.into_iter().map(LineString).collect(); + // todo: can these be unchecked? + let exterior = LineString::new(simplified.remove(0)).unwrap(); + let interiors = simplified.into_iter().map(|l| LineString::new(l).unwrap()).collect(); Polygon::new(exterior, interiors) } }