From a2e78f7dd3e4d343c7c2f775bc3b6d98154085b7 Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Wed, 17 Aug 2022 08:50:54 +0100 Subject: [PATCH] Switch a few places to using Tessellation instead of constructing an invalid Polygon only to render it. #951 --- abstutil/src/serde.rs | 1 - geom/src/polygon.rs | 19 +++---------- geom/src/stats.rs | 2 -- geom/src/tessellation.rs | 39 ++++++++++++++++++++++++--- map_model/src/objects/intersection.rs | 1 - widgetry/src/svg.rs | 4 +-- widgetry/src/widgets/fan_chart.rs | 6 ++--- widgetry/src/widgets/plots.rs | 6 ++--- 8 files changed, 47 insertions(+), 31 deletions(-) diff --git a/abstutil/src/serde.rs b/abstutil/src/serde.rs index d600b76fa7..f3677db2dd 100644 --- a/abstutil/src/serde.rs +++ b/abstutil/src/serde.rs @@ -1,6 +1,5 @@ use std::cmp::Ord; use std::collections::{BTreeMap, HashMap}; -use std::convert::TryFrom; use anyhow::Result; use serde::de::DeserializeOwned; diff --git a/geom/src/polygon.rs b/geom/src/polygon.rs index b0d69caf2a..ce95c32231 100644 --- a/geom/src/polygon.rs +++ b/geom/src/polygon.rs @@ -1,4 +1,3 @@ -use std::convert::TryFrom; use std::fmt; use anyhow::Result; @@ -35,7 +34,7 @@ impl Polygon { vertices.push(pt.x()); vertices.push(pt.y()); } - let indices = downsize(earcutr::earcut(&vertices, &Vec::new(), 2)); + let indices = crate::tessellation::downsize(earcutr::earcut(&vertices, &Vec::new(), 2)); Polygon { points: orig_pts, @@ -56,7 +55,7 @@ impl Polygon { }) .collect(); let (vertices, holes, dims) = earcutr::flatten(&geojson_style); - let indices = downsize(earcutr::earcut(&vertices, &holes, dims)); + let indices = crate::tessellation::downsize(earcutr::earcut(&vertices, &holes, dims)); Polygon { points: vertices @@ -90,7 +89,7 @@ impl Polygon { assert!(indices.len() % 3 == 0); Polygon { points, - indices: downsize(indices), + indices: crate::tessellation::downsize(indices), rings: None, } } @@ -671,15 +670,3 @@ fn from_multi(multi: geo::MultiPolygon) -> Vec { }) .collect() } - -fn downsize(input: Vec) -> Vec { - let mut output = Vec::new(); - for x in input { - if let Ok(x) = u16::try_from(x) { - output.push(x); - } else { - panic!("{} can't fit in u16, some polygon is too huge", x); - } - } - output -} diff --git a/geom/src/stats.rs b/geom/src/stats.rs index b22fb2032f..51af94188c 100644 --- a/geom/src/stats.rs +++ b/geom/src/stats.rs @@ -1,5 +1,3 @@ -use std::convert::TryFrom; - use serde::{Deserialize, Serialize}; use crate::{Distance, Duration}; diff --git a/geom/src/tessellation.rs b/geom/src/tessellation.rs index dd09b6162d..554ffee472 100644 --- a/geom/src/tessellation.rs +++ b/geom/src/tessellation.rs @@ -20,13 +20,34 @@ pub struct Triangle { impl From for Tessellation { fn from(polygon: Polygon) -> Self { - Self::new(polygon.points, polygon.indices) + Self { + points: polygon.points, + indices: polygon.indices, + } } } impl Tessellation { - pub fn new(points: Vec, indices: Vec) -> Self { - Tessellation { points, indices } + pub fn new(points: Vec, indices: Vec) -> Self { + Tessellation { + points, + indices: downsize(indices), + } + } + + /// The `points` are not necessarily a `Ring`, which has strict requirements about no duplicate + /// points. We can render various types of invalid polygon. + pub fn from_ring(points: Vec) -> Self { + assert!(points.len() >= 3); + + let mut vertices = Vec::new(); + for pt in &points { + vertices.push(pt.x()); + vertices.push(pt.y()); + } + let indices = downsize(earcutr::earcut(&vertices, &Vec::new(), 2)); + + Self { points, indices } } /// Returns (points, indices) for rendering @@ -115,3 +136,15 @@ impl Tessellation { } } } + +pub fn downsize(input: Vec) -> Vec { + let mut output = Vec::new(); + for x in input { + if let Ok(x) = u16::try_from(x) { + output.push(x); + } else { + panic!("{} can't fit in u16, some polygon is too huge", x); + } + } + output +} diff --git a/map_model/src/objects/intersection.rs b/map_model/src/objects/intersection.rs index 4422dbf6d5..f4db186f42 100644 --- a/map_model/src/objects/intersection.rs +++ b/map_model/src/objects/intersection.rs @@ -1,5 +1,4 @@ use std::collections::{BTreeMap, BTreeSet}; -use std::convert::TryFrom; use std::fmt; use serde::{Deserialize, Serialize}; diff --git a/widgetry/src/svg.rs b/widgetry/src/svg.rs index 6f3fe8b75f..603d04eeff 100644 --- a/widgetry/src/svg.rs +++ b/widgetry/src/svg.rs @@ -4,7 +4,7 @@ use lyon::tessellation; use lyon::tessellation::geometry_builder::{simple_builder, VertexBuffers}; use abstutil::VecMap; -use geom::{Bounds, Polygon, Pt2D}; +use geom::{Bounds, Pt2D, Tessellation}; use crate::{Color, Fill, GeomBatch, LinearGradient, Prerender}; @@ -99,7 +99,7 @@ pub(crate) fn add_svg_inner( for (color, mesh) in mesh_per_color.consume() { batch.push( color, - Polygon::precomputed( + Tessellation::new( mesh.vertices .into_iter() .map(|v| Pt2D::new(f64::from(v.x), f64::from(v.y))) diff --git a/widgetry/src/widgets/fan_chart.rs b/widgetry/src/widgets/fan_chart.rs index b111a3ab81..9c1e1ae68a 100644 --- a/widgetry/src/widgets/fan_chart.rs +++ b/widgetry/src/widgets/fan_chart.rs @@ -1,8 +1,8 @@ use std::collections::VecDeque; use geom::{ - Angle, Distance, Duration, HgramValue, Histogram, PolyLine, Polygon, Pt2D, Statistic, Time, - UnitFmt, + Angle, Distance, Duration, HgramValue, Histogram, PolyLine, Pt2D, Statistic, Tessellation, + Time, UnitFmt, }; use crate::widgets::plots::{make_legend, thick_lineseries, Axis, PlotOptions}; @@ -133,7 +133,7 @@ impl FanChart { p99.reverse(); band.extend(transform(p99)); band.push(band[0]); - batch.push(s.color.alpha(0.5), Polygon::buggy_new(band)); + batch.push(s.color.alpha(0.5), Tessellation::from_ring(band)); batch.push( s.color, diff --git a/widgetry/src/widgets/plots.rs b/widgetry/src/widgets/plots.rs index ec2194f8c8..f2c1310fc0 100644 --- a/widgetry/src/widgets/plots.rs +++ b/widgetry/src/widgets/plots.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use abstutil::prettyprint_usize; -use geom::{Circle, Distance, Duration, Percent, Polygon, Pt2D, Time, UnitFmt}; +use geom::{Circle, Distance, Duration, Percent, Pt2D, Tessellation, Time, UnitFmt}; use crate::{Color, EventCtx, GeomBatch, ScreenDims, TextExt, Toggle, Widget}; @@ -189,7 +189,7 @@ pub fn make_legend, Y: Axis>( } // TODO If this proves useful, lift to geom -pub fn thick_lineseries(pts: Vec, width: Distance) -> Polygon { +pub fn thick_lineseries(pts: Vec, width: Distance) -> Tessellation { use lyon::math::{point, Point}; use lyon::path::Path; use lyon::tessellation::geometry_builder::{BuffersBuilder, Positions, VertexBuffers}; @@ -215,7 +215,7 @@ pub fn thick_lineseries(pts: Vec, width: Distance) -> Polygon { &mut buffer, ) .unwrap(); - Polygon::precomputed( + Tessellation::new( geom.vertices .into_iter() .map(|v| Pt2D::new(f64::from(v.x), f64::from(v.y)))