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.slow_pool.get().await?;
37
38 let result = plant_layer::heatmap(
39 map_id,
40 query_params.plant_layer_id,
41 query_params.shade_layer_id,
42 query_params.hydrology_layer_id,
43 query_params.soil_layer_id,
44 query_params.plant_id,
45 query_params.date.unwrap_or_else(|| Utc::now().date_naive()),
46 &mut conn,
47 )
48 .await?;
49
50 let heatmap_colors = application_settings::get_heatmap_colors(&mut conn).await?;
51 let buffer = matrix_to_image(&result, heatmap_colors)?;
52
53 Ok(buffer)
54}
55
56#[allow(
58 clippy::cast_possible_truncation, clippy::indexing_slicing, clippy::cast_sign_loss )]
62fn matrix_to_image(
63 matrix: &[Vec<(HeatmapColor, f32)>],
64 colors: HeatmapColors,
65) -> Result<Vec<u8>, ServiceError> {
66 let (width, height) = (matrix[0].len(), matrix.len());
67 let mut imgbuf = ImageBuffer::new(width as u32, height as u32);
68
69 let (red, orange, green, black) = colors;
70
71 for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
72 let (color, relevance) = &matrix[y as usize][x as usize];
73 let alpha = (relevance * 255.0) as u8;
74
75 *pixel = match color {
76 HeatmapColor::Red => Rgba([red.0, red.1, red.2, alpha]),
77 HeatmapColor::Orange => Rgba([orange.0, orange.1, orange.2, alpha]),
78 HeatmapColor::Green => Rgba([green.0, green.1, green.2, alpha]),
79 HeatmapColor::Black => Rgba([black.0, black.1, black.2, alpha]),
80 };
81 }
82
83 let mut buffer: Vec<u8> = Vec::new();
84 imgbuf
85 .write_to(&mut Cursor::new(&mut buffer), image::ImageOutputFormat::Png)
86 .map_err(|err| ServiceError::new(StatusCode::INTERNAL_SERVER_ERROR, &err.to_string()))?;
87 Ok(buffer)
88}
89
90pub async fn find_relations(
96 search_query: RelationSearchParameters,
97 pool: &SharedPool,
98) -> Result<RelationsDto, ServiceError> {
99 let mut conn = pool.get().await?;
100 let result = plant_layer::find_relations(search_query, &mut conn).await?;
101 Ok(result)
102}