backend/service/
plant_layer.rs1use std::io::Cursor;
4
5use actix_http::StatusCode;
6use chrono::Utc;
7use image::{ImageBuffer, Rgba};
8
9use crate::{
10 config::data::SharedPool,
11 error::ServiceError,
12 model::{
13 dto::{HeatMapQueryParams, RelationSearchParameters, RelationsDto},
14 entity::plant_layer,
15 r#enum::heatmap_color::HeatmapColor,
16 },
17 service::application_settings,
18};
19
20use super::application_settings::HeatmapColors;
21
22pub async fn heatmap(
32 map_id: i32,
33 query_params: HeatMapQueryParams,
34 pool: &SharedPool,
35) -> Result<Vec<u8>, ServiceError> {
36 let mut conn = pool.get().await?;
37 let result = plant_layer::heatmap(
38 map_id,
39 query_params.plant_layer_id,
40 query_params.shade_layer_id,
41 query_params.hydrology_layer_id,
42 query_params.soil_layer_id,
43 query_params.plant_id,
44 query_params.date.unwrap_or_else(|| Utc::now().date_naive()),
45 &mut conn,
46 )
47 .await?;
48
49 let heatmap_colors = application_settings::get_heatmap_colors(&mut conn).await?;
50 let buffer = matrix_to_image(&result, heatmap_colors)?;
51
52 Ok(buffer)
53}
54
55#[allow(
57 clippy::cast_possible_truncation, clippy::indexing_slicing, clippy::cast_sign_loss )]
61fn matrix_to_image(
62 matrix: &[Vec<(HeatmapColor, f32)>],
63 colors: HeatmapColors,
64) -> Result<Vec<u8>, ServiceError> {
65 let (width, height) = (matrix[0].len(), matrix.len());
66 let mut imgbuf = ImageBuffer::new(width as u32, height as u32);
67
68 let (red, orange, green, black) = colors;
69
70 for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
71 let (color, relevance) = &matrix[y as usize][x as usize];
72 let alpha = (relevance * 255.0) as u8;
73
74 *pixel = match color {
75 HeatmapColor::Red => Rgba([red.0, red.1, red.2, alpha]),
76 HeatmapColor::Orange => Rgba([orange.0, orange.1, orange.2, alpha]),
77 HeatmapColor::Green => Rgba([green.0, green.1, green.2, alpha]),
78 HeatmapColor::Black => Rgba([black.0, black.1, black.2, alpha]),
79 };
80 }
81
82 let mut buffer: Vec<u8> = Vec::new();
83 imgbuf
84 .write_to(&mut Cursor::new(&mut buffer), image::ImageOutputFormat::Png)
85 .map_err(|err| ServiceError::new(StatusCode::INTERNAL_SERVER_ERROR, &err.to_string()))?;
86 Ok(buffer)
87}
88
89pub async fn find_relations(
95 search_query: RelationSearchParameters,
96 pool: &SharedPool,
97) -> Result<RelationsDto, ServiceError> {
98 let mut conn = pool.get().await?;
99 let result = plant_layer::find_relations(search_query, &mut conn).await?;
100 Ok(result)
101}