maplibre-rs/maplibre/src/tessellation/zero_tessellator.rs
2022-04-22 21:16:35 +02:00

196 lines
5.5 KiB
Rust

use bytemuck::Pod;
use geozero::{FeatureProcessor, GeomProcessor, PropertyProcessor};
use lyon::geom;
use lyon::geom::point;
use lyon::lyon_tessellation::VertexBuffers;
use lyon::path::path::Builder;
use lyon::path::Path;
use lyon::tessellation::geometry_builder::MaxIndex;
use lyon::tessellation::{
BuffersBuilder, FillOptions, FillRule, FillTessellator, StrokeOptions, StrokeTessellator,
};
use std::cell::RefCell;
use crate::render::ShaderVertex;
use crate::tessellation::{VertexConstructor, DEFAULT_TOLERANCE};
type GeoResult<T> = geozero::error::Result<T>;
pub struct ZeroTessellator<I: std::ops::Add + From<lyon::tessellation::VertexId> + MaxIndex> {
path_builder: RefCell<Builder>,
path_open: bool,
is_point: bool,
pub buffer: VertexBuffers<ShaderVertex, I>,
pub feature_indices: Vec<u32>,
current_index: usize,
}
impl<I: std::ops::Add + From<lyon::tessellation::VertexId> + MaxIndex> Default
for ZeroTessellator<I>
{
fn default() -> Self {
Self {
path_builder: RefCell::new(Path::builder()),
buffer: VertexBuffers::new(),
feature_indices: Vec::new(),
current_index: 0,
path_open: false,
is_point: false,
}
}
}
impl<I: std::ops::Add + From<lyon::tessellation::VertexId> + MaxIndex> ZeroTessellator<I> {
fn update_feature_indices(&mut self) {
let next_index = self.buffer.indices.len();
let indices = (next_index - self.current_index) as u32;
self.feature_indices.push(indices);
self.current_index = next_index;
}
fn tessellate_strokes(&mut self) {
let path_builder = self.path_builder.replace(Path::builder());
StrokeTessellator::new()
.tessellate_path(
&path_builder.build(),
&StrokeOptions::tolerance(DEFAULT_TOLERANCE),
&mut BuffersBuilder::new(&mut self.buffer, VertexConstructor {}),
)
.unwrap();
}
fn end(&mut self, close: bool) {
if self.path_open {
self.path_builder.borrow_mut().end(close);
self.path_open = false;
}
}
fn tessellate_fill(&mut self) {
let path_builder = self.path_builder.replace(Path::builder());
FillTessellator::new()
.tessellate_path(
&path_builder.build(),
&FillOptions::tolerance(DEFAULT_TOLERANCE).with_fill_rule(FillRule::NonZero),
&mut BuffersBuilder::new(&mut self.buffer, VertexConstructor {}),
)
.unwrap();
}
}
impl<I: std::ops::Add + From<lyon::tessellation::VertexId> + MaxIndex> GeomProcessor
for ZeroTessellator<I>
{
fn xy(&mut self, x: f64, y: f64, idx: usize) -> GeoResult<()> {
// log::info!("xy");
if self.is_point {
// log::info!("point");
} else if !self.path_open {
self.path_builder
.borrow_mut()
.begin(geom::point(x as f32, y as f32));
self.path_open = true;
} else {
self.path_builder
.borrow_mut()
.line_to(geom::point(x as f32, y as f32));
}
Ok(())
}
fn point_begin(&mut self, _idx: usize) -> GeoResult<()> {
// log::info!("point_begin");
self.is_point = true;
Ok(())
}
fn point_end(&mut self, _idx: usize) -> GeoResult<()> {
// log::info!("point_end");
self.is_point = false;
Ok(())
}
fn multipoint_begin(&mut self, _size: usize, _idx: usize) -> GeoResult<()> {
// log::info!("multipoint_begin");
Ok(())
}
fn multipoint_end(&mut self, _idx: usize) -> GeoResult<()> {
// log::info!("multipoint_end");
Ok(())
}
fn linestring_begin(&mut self, _tagged: bool, _size: usize, _idx: usize) -> GeoResult<()> {
// log::info!("linestring_begin");
Ok(())
}
fn linestring_end(&mut self, tagged: bool, _idx: usize) -> GeoResult<()> {
// log::info!("linestring_end");
self.end(false);
if tagged {
self.tessellate_strokes();
}
Ok(())
}
fn multilinestring_begin(&mut self, _size: usize, _idx: usize) -> GeoResult<()> {
// log::info!("multilinestring_begin");
Ok(())
}
fn multilinestring_end(&mut self, _idx: usize) -> GeoResult<()> {
// log::info!("multilinestring_end");
self.tessellate_strokes();
Ok(())
}
fn polygon_begin(&mut self, _tagged: bool, _size: usize, _idx: usize) -> GeoResult<()> {
// log::info!("polygon_begin");
Ok(())
}
fn polygon_end(&mut self, tagged: bool, _idx: usize) -> GeoResult<()> {
// log::info!("polygon_end");
self.end(true);
if tagged {
self.tessellate_fill();
}
Ok(())
}
fn multipolygon_begin(&mut self, size: usize, idx: usize) -> GeoResult<()> {
// log::info!("multipolygon_begin");
Ok(())
}
fn multipolygon_end(&mut self, _idx: usize) -> GeoResult<()> {
// log::info!("multipolygon_end");
self.tessellate_fill();
Ok(())
}
}
impl<I: std::ops::Add + From<lyon::tessellation::VertexId> + MaxIndex> PropertyProcessor
for ZeroTessellator<I>
{
}
impl<I: std::ops::Add + From<lyon::tessellation::VertexId> + MaxIndex> FeatureProcessor
for ZeroTessellator<I>
{
fn feature_end(&mut self, _idx: u64) -> geozero::error::Result<()> {
self.update_feature_indices();
Ok(())
}
}