Buffer a polygon by offsetting each vertex outward.
(rings: &[Vec<[f64; 2]>], meters: f64, _segments: usize)
| 193 | |
| 194 | /// Buffer a polygon by offsetting each vertex outward. |
| 195 | fn buffer_polygon(rings: &[Vec<[f64; 2]>], meters: f64, _segments: usize) -> Geometry { |
| 196 | let mut new_rings = Vec::with_capacity(rings.len()); |
| 197 | |
| 198 | for (ring_idx, ring) in rings.iter().enumerate() { |
| 199 | if ring.len() < 3 { |
| 200 | new_rings.push(ring.clone()); |
| 201 | continue; |
| 202 | } |
| 203 | let is_exterior = ring_idx == 0; |
| 204 | // For exterior: expand outward. For holes: shrink inward. |
| 205 | let sign = if is_exterior { 1.0 } else { -1.0 }; |
| 206 | let offset_m = meters * sign; |
| 207 | |
| 208 | let mut new_ring = Vec::with_capacity(ring.len()); |
| 209 | let n = if ring.first() == ring.last() { |
| 210 | ring.len() - 1 |
| 211 | } else { |
| 212 | ring.len() |
| 213 | }; |
| 214 | |
| 215 | for i in 0..n { |
| 216 | let prev = ring[(i + n - 1) % n]; |
| 217 | let curr = ring[i]; |
| 218 | let next = ring[(i + 1) % n]; |
| 219 | |
| 220 | // Bisector direction (average of the two edge normals). |
| 221 | let n1 = edge_outward_normal(prev, curr); |
| 222 | let n2 = edge_outward_normal(curr, next); |
| 223 | let bisect = [(n1[0] + n2[0]) / 2.0, (n1[1] + n2[1]) / 2.0]; |
| 224 | let len = (bisect[0] * bisect[0] + bisect[1] * bisect[1]) |
| 225 | .sqrt() |
| 226 | .max(1e-12); |
| 227 | let unit = [bisect[0] / len, bisect[1] / len]; |
| 228 | |
| 229 | let dlat = offset_m / 110_540.0; |
| 230 | let dlng = offset_m / (111_320.0 * curr[1].to_radians().cos().max(0.001)); |
| 231 | |
| 232 | new_ring.push([curr[0] + unit[0] * dlng, curr[1] + unit[1] * dlat]); |
| 233 | } |
| 234 | |
| 235 | // Close. |
| 236 | if let Some(&first_pt) = new_ring.first() { |
| 237 | new_ring.push(first_pt); |
| 238 | } |
| 239 | new_rings.push(new_ring); |
| 240 | } |
| 241 | |
| 242 | Geometry::Polygon { |
| 243 | coordinates: new_rings, |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | /// Compute offset segments (left and right parallel lines at `meters` distance). |
| 248 | /// A pair of offset segments: (left_segment, right_segment). |