use hephaestus::backend::vello::VelloRenderer;
use hephaestus::color::{rgb8, Color};
use hephaestus::composition::{Composition, Patch, Span};
use hephaestus::geometry::Size;
use hephaestus::plot::chrome::axis::{Axis, AxisPlacement, PolarRing};
use hephaestus::plot::projection::{PolarProjection, Projection};
use hephaestus::plot::{scale, Plot, PlotComposition, PointGeom, RectGeom};
use hephaestus::scene::SceneBuilder;
use hephaestus::Renderer;
fn comp() -> Composition {
Composition::empty(1, 1).place(1, 1, Span::cell(), Patch::new("panel"))
}
fn main() {
let (w, h) = (700u32, 700u32);
let dpi = 96.0;
let inner_projection = Projection::Polar(
PolarProjection::full_circle()
.outer_radius(0.45)
.fit_to_bbox(false),
);
let outer_top_projection = Projection::Polar(
PolarProjection::full_circle()
.theta_range(165.0_f64.to_radians(), 15.0_f64.to_radians())
.inner_radius(0.55)
.fit_to_bbox(false),
);
let outer_bottom_projection = Projection::Polar(
PolarProjection::full_circle()
.theta_range(-15.0_f64.to_radians(), -165.0_f64.to_radians())
.inner_radius(0.55)
.fit_to_bbox(false),
);
let n_inner = 60;
let inner_theta: Vec<f64> = (0..n_inner).map(|i| i as f64 / n_inner as f64).collect();
let inner_radius: Vec<f64> = (0..n_inner)
.map(|i| 0.35 + 0.6 * ((i as f64 * 0.137).sin() * 0.5 + 0.5))
.collect();
let inner_color = rgb8(60, 120, 200);
let top_n = 12;
let top_x_a: Vec<f64> = (0..top_n)
.map(|i| (i as f64 - 0.4) / top_n as f64)
.collect();
let top_x_b: Vec<f64> = (0..top_n)
.map(|i| (i as f64 + 0.4) / top_n as f64)
.collect();
let top_inner: Vec<f64> = (0..top_n).map(|_| 0.0_f64).collect();
let top_outer: Vec<f64> = (0..top_n)
.map(|i| 0.35 + 0.6 * ((i as f64 * 0.5).sin() * 0.5 + 0.5))
.collect();
let top_color = rgb8(180, 80, 100);
let bot_n = 30;
let bot_theta: Vec<f64> = (0..bot_n).map(|i| i as f64 / (bot_n - 1) as f64).collect();
let bot_radius: Vec<f64> = (0..bot_n)
.map(|i| 0.2 + 0.7 * ((i as f64 * 0.21).cos() * 0.5 + 0.5))
.collect();
let bot_color = rgb8(80, 170, 80);
let mut view = PlotComposition::new(&comp())
.add_scale("theta_unit", scale::continuous(0.0..=1.0))
.add_scale("radius_unit", scale::continuous(0.0..=1.0));
let mut p_inner = Plot::new(&comp(), "panel")
.projection(inner_projection)
.bind("x", "theta_unit")
.bind("y", "radius_unit");
p_inner.add_geom(
PointGeom::builder()
.set("x", inner_theta)
.set("y", inner_radius)
.set("fill", inner_color)
.set("size", 5.0_f64)
.build(),
);
p_inner.add_axis(Axis::rail(
"radius_unit",
AxisPlacement::PolarRadius { theta_frac: 0.0 },
));
view.attach_plot(p_inner);
let mut p_top = Plot::new(&comp(), "panel")
.projection(outer_top_projection)
.bind("x", "theta_unit")
.bind("x2", "theta_unit")
.bind("y", "radius_unit")
.bind("y2", "radius_unit");
p_top.add_geom(
RectGeom::builder()
.set("x", top_x_a)
.set("x2", top_x_b)
.set("y", top_inner)
.set("y2", top_outer)
.set("fill", top_color)
.build(),
);
p_top.add_axis(Axis::rail(
"theta_unit",
AxisPlacement::PolarAngular(PolarRing::Outer),
));
view.attach_plot(p_top);
let mut p_bot = Plot::new(&comp(), "panel")
.projection(outer_bottom_projection)
.bind("x", "theta_unit")
.bind("y", "radius_unit");
p_bot.add_geom(
PointGeom::builder()
.set("x", bot_theta)
.set("y", bot_radius)
.set("fill", bot_color)
.set("size", 6.0_f64)
.build(),
);
p_bot.add_axis(Axis::rail(
"theta_unit",
AxisPlacement::PolarAngular(PolarRing::Outer),
));
view.attach_plot(p_bot);
let issues = view.validate();
if !issues.is_empty() {
panic!("validate() reported issues: {issues:?}");
}
let mut renderer = VelloRenderer::new().expect("vello renderer init");
let bg: Color = rgb8(248, 248, 252);
{
let scene = renderer.scene();
scene.clear();
view.render(scene, Size::new(w as f64, h as f64), dpi);
}
let mut pixels = vec![0u8; (w * h * 4) as usize];
renderer
.render_to_buffer(w, h, bg, &mut pixels)
.expect("render");
let path = std::env::current_dir()
.unwrap()
.join("examples/polar_nested.png");
hephaestus::image::write_png(&path, w, h, &pixels).expect("write png");
println!("wrote {}", path.display());
}