use crate::cli::{Args, resolve_color_with_alpha};
use crate::data_array::to_f64_vec;
use crate::mask::PixelMask;
use crate::params::*;
use crate::pipeline::ProcessedData;
use crate::rotation::{CoordSystem, ViewTransform};
use image::Rgba;
use std::str::FromStr;
pub fn create_pixel_mask(
args: &Args,
data: &ProcessedData,
verbose: bool,
) -> Result<Option<PixelMask>, String> {
let map_f64 = to_f64_vec(&data.map);
if let Some(mask_below) = args.mask_below {
if verbose {
println!("Creating value-range mask (below: {})", mask_below);
}
let fill_color = crate::mask::parse_maskfill_color(&args.maskfill_color);
let coord = args
.mask_coord
.as_ref()
.and_then(|s| CoordSystem::from_str(s).ok())
.unwrap_or(data.meta.coord);
return Ok(Some(PixelMask::from_value_range(
&map_f64,
args.mask_below,
args.mask_above,
data.meta.nside,
fill_color,
coord,
)));
}
if let Some(mask_above) = args.mask_above {
if verbose {
println!("Creating value-range mask (above: {})", mask_above);
}
let fill_color = crate::mask::parse_maskfill_color(&args.maskfill_color);
let coord = args
.mask_coord
.as_ref()
.and_then(|s| CoordSystem::from_str(s).ok())
.unwrap_or(data.meta.coord);
return Ok(Some(PixelMask::from_value_range(
&map_f64,
args.mask_below,
args.mask_above,
data.meta.nside,
fill_color,
coord,
)));
}
if let Some(ref mask_file) = args.mask_file {
if verbose {
println!("Loading mask from {}", mask_file);
}
let fill_color = crate::mask::parse_maskfill_color(&args.maskfill_color);
let coord = args
.mask_coord
.as_ref()
.and_then(|s| CoordSystem::from_str(s).ok());
match PixelMask::from_fits_file(mask_file, fill_color, coord) {
Ok(mask) => {
if let Some(warning) = mask.warn_coord_mismatch(data.meta.coord, verbose) {
eprintln!("{}", warning);
}
return Ok(Some(mask));
}
Err(e) => {
eprintln!("Warning: Failed to load mask: {}", e);
return Ok(None);
}
}
}
Ok(None)
}
pub fn resolve_overlay_color(args: &Args) -> Result<Rgba<u8>, String> {
if args.grat_coord_overlay.is_some() {
resolve_color_with_alpha(&args.grat_overlay_color, 200)
.map_err(|e| format!("Invalid overlay color format: {}", e))
} else {
Ok(Rgba([255, 255, 0, 0]))
}
}
pub fn resolve_graticule_coord(args: &Args, data_coord: CoordSystem) -> Option<CoordSystem> {
if !args.graticule {
return None;
}
if let Some(ref s) = args.grat_coord {
CoordSystem::from_str(s).ok()
} else {
Some(match data_coord {
CoordSystem::E => CoordSystem::E,
CoordSystem::G => CoordSystem::G,
CoordSystem::C => CoordSystem::C,
})
}
}
pub fn parse_overlay_coord(overlay_str: &str) -> CoordSystem {
CoordSystem::from_str(overlay_str)
.unwrap_or_else(|e| panic!("Invalid overlay coordinate system: {}", e))
}
pub fn build_mollweide_params<'a>(
args: &'a Args,
data: &'a ProcessedData,
config: &'a crate::cli::PlotConfig,
view: &'a ViewTransform,
mask: Option<PixelMask>,
) -> Result<MollweideParams<'a>, String> {
let grat_coord = resolve_graticule_coord(args, data.meta.coord);
let grat_overlay = args
.grat_coord_overlay
.as_ref()
.map(|s| parse_overlay_coord(s));
let overlay_color = resolve_overlay_color(args)?;
Ok(MollweideParams {
plot: PlotData {
map: to_f64_vec(&data.map),
width: args.width,
filename: args.get_output_filename(),
pdf_backend: args.pdf_backend.clone(),
},
scale: ScaleParams {
minv: args.min,
maxv: args.max,
gamma: args.gamma,
scale: config.scale,
neg_mode: config.neg_mode,
},
color: ColorParams {
cmap: config.colormap,
bad_color: config.bad_color_rgba,
bg_color: config.bg_color_rgba,
},
display: DisplayParams {
show_colorbar: !args.no_cbar && !args.fast_render,
transparent: args.transparent,
draw_border: !args.no_border,
latex_rendering: config.latex_rendering,
units: config.units.clone(),
extend: args
.extend
.parse()
.map_err(|_| "Invalid extend option".to_string())?,
tick_direction: args
.tick_direction
.parse()
.map_err(|_| "Invalid tick direction option".to_string())?,
tick_font_size: args.tick_font_size,
units_font_size: args.units_font_size,
rlabel: args.rlabel.clone(),
llabel: args.llabel.clone(),
label_font_size: args.label_font_size,
mask: mask.clone(),
title: args.title.clone(),
show_title: !args.no_title && !args.fast_render,
scale_text: !args.no_scale_text && !args.no_text && !args.fast_render,
},
graticule: GraticuleParams {
show_graticule: args.graticule && !args.fast_render,
grat_coord,
grat_overlay,
overlay_color,
show_labels: args.grat_labels,
dpar_deg: args.grat_par,
dmer_deg: args.grat_mer,
},
meta: data.meta,
view,
})
}
pub fn build_gnomonic_params<'a>(
args: &'a Args,
data: &'a ProcessedData,
config: &'a crate::cli::PlotConfig,
view: &'a ViewTransform,
mask: Option<PixelMask>,
) -> Result<GnomonicParams<'a>, String> {
let lon = args.lon.unwrap_or(0.0);
let lat = args.lat.unwrap_or(0.0);
let fov = args.fov;
let res = args.res;
let grat_overlay = args
.grat_coord_overlay
.as_ref()
.map(|s| parse_overlay_coord(s));
let overlay_color = resolve_overlay_color(args)?;
Ok(GnomonicParams {
plot: PlotData {
map: to_f64_vec(&data.map),
width: args.width,
filename: args.get_output_filename(),
pdf_backend: args.pdf_backend.clone(),
},
scale: ScaleParams {
minv: args.min,
maxv: args.max,
gamma: args.gamma,
scale: config.scale,
neg_mode: config.neg_mode,
},
color: ColorParams {
cmap: config.colormap,
bad_color: config.bad_color_rgba,
bg_color: config.bg_color_rgba,
},
display: DisplayParams {
show_colorbar: !args.no_cbar && !args.fast_render,
transparent: args.transparent,
draw_border: false,
latex_rendering: config.latex_rendering,
units: config.units.clone(),
extend: args
.extend
.parse()
.map_err(|_| "Invalid extend option".to_string())?,
tick_direction: args
.tick_direction
.parse()
.map_err(|_| "Invalid tick direction option".to_string())?,
tick_font_size: args.tick_font_size,
units_font_size: args.units_font_size,
rlabel: args.rlabel.clone(),
llabel: args.llabel.clone(),
label_font_size: args.label_font_size,
mask: mask.clone(),
title: args.title.clone(),
show_title: !args.no_title && !args.no_text && !args.fast_render,
scale_text: !args.no_scale_text && !args.no_text && !args.fast_render,
},
graticule: GraticuleParams {
show_graticule: args.local_graticule && !args.fast_render,
grat_coord: None,
grat_overlay,
overlay_color,
show_labels: false,
dpar_deg: args.local_grat_dlon,
dmer_deg: args.local_grat_dlat,
},
meta: data.meta,
view,
lon_deg: lon,
lat_deg: lat,
fov_arcmin: fov,
resolution_arcmin: res,
roll_deg: args.roll,
grat_line_width: args.grat_line_width,
show_gnomonic_text: !args.no_text,
})
}
pub fn build_hammer_params<'a>(
args: &'a Args,
data: &'a ProcessedData,
config: &'a crate::cli::PlotConfig,
view: &'a ViewTransform,
mask: Option<PixelMask>,
) -> Result<HammerParams<'a>, String> {
let grat_coord = resolve_graticule_coord(args, data.meta.coord);
let grat_overlay = args
.grat_coord_overlay
.as_ref()
.map(|s| parse_overlay_coord(s));
let overlay_color = resolve_overlay_color(args)?;
Ok(HammerParams {
plot: PlotData {
map: to_f64_vec(&data.map),
width: args.width,
filename: args.get_output_filename(),
pdf_backend: args.pdf_backend.clone(),
},
scale: ScaleParams {
minv: args.min,
maxv: args.max,
gamma: args.gamma,
scale: config.scale,
neg_mode: config.neg_mode,
},
color: ColorParams {
cmap: config.colormap,
bad_color: config.bad_color_rgba,
bg_color: config.bg_color_rgba,
},
display: DisplayParams {
show_colorbar: !args.no_cbar && !args.fast_render,
transparent: args.transparent,
draw_border: !args.no_border,
latex_rendering: config.latex_rendering,
units: config.units.clone(),
extend: args
.extend
.parse()
.map_err(|_| "Invalid extend option".to_string())?,
tick_direction: args
.tick_direction
.parse()
.map_err(|_| "Invalid tick direction option".to_string())?,
tick_font_size: args.tick_font_size,
units_font_size: args.units_font_size,
rlabel: args.rlabel.clone(),
llabel: args.llabel.clone(),
label_font_size: args.label_font_size,
mask: mask.clone(),
title: args.title.clone(),
show_title: !args.no_title && !args.no_text && !args.fast_render,
scale_text: !args.no_scale_text && !args.no_text && !args.fast_render,
},
graticule: GraticuleParams {
show_graticule: args.graticule && !args.fast_render,
grat_coord,
grat_overlay,
overlay_color,
show_labels: args.grat_labels,
dpar_deg: args.grat_par,
dmer_deg: args.grat_mer,
},
meta: data.meta,
view,
})
}