import type { ColorAlleles, Hsv, Rgb } from './types'; export function clampByte(value: number): number { return Math.max(0, Math.min(255, Math.trunc(value))); } export function hsvToRgb(hueDeg: number, saturation: number, value: number): Rgb { const h = (((hueDeg % 360) + 360) % 360) / 60; const c = value * saturation; const x = c * (1 - Math.abs((h % 2) - 1)); const m = value - c; let r = 0; let g = 0; let b = 0; if (h < 1) { r = c; g = x; } else if (h < 2) { r = x; g = c; } else if (h < 3) { g = c; b = x; } else if (h < 4) { g = x; b = c; } else if (h < 5) { r = x; b = c; } else { r = c; b = x; } return [ clampByte((r + m) * 255), clampByte((g + m) * 255), clampByte((b + m) * 255), ]; } export function rgbToHsv(rgb: Rgb): Hsv { const [r, g, b] = rgb.map((channel) => channel / 255) as Rgb; const max = Math.max(r, g, b); const min = Math.min(r, g, b); const delta = max - min; let hue = 0; if (delta !== 0) { if (max === r) { hue = 60 * (((g - b) / delta) % 6); } else if (max === g) { hue = 60 * ((b - r) / delta + 2); } else { hue = 60 * ((r - g) / delta + 4); } } return [((hue % 360) + 360) % 360, max === 0 ? 0 : delta / max, max]; } export function expressedRgbFromAlleles(hsvAlleles: ColorAlleles): Rgb { const hue = (hsvAlleles.Hue[0] + hsvAlleles.Hue[1]) / 2; const saturation = (hsvAlleles.Saturation[0] + hsvAlleles.Saturation[1]) / 2; const value = (hsvAlleles.Value[0] + hsvAlleles.Value[1]) / 2; return hsvToRgb(hue, saturation, value); } export function derivePlantColor(budRgb: Rgb, leafRgb: Rgb): Rgb { const bud = rgbToHsv(budRgb); const leaf = rgbToHsv(leafRgb); return hsvToRgb( (bud[0] + leaf[0]) / 2, (bud[1] + leaf[1]) / 2, (bud[2] + leaf[2]) / 2 ); } export function hueFromRgb(rgb: Rgb): number { return Math.round(rgbToHsv(rgb)[0] * 10) / 10; } export function vibrance(rgb: Rgb): number { const [red, green, blue] = rgb; return Math.round(((Math.max(red, green, blue) - Math.min(red, green, blue)) / 255) * 1000) / 10; } export function colorFamily(hue: number): string { if (hue < 15 || hue >= 330) return 'red'; if (hue < 40) return 'orange'; if (hue < 70) return 'yellow'; if (hue < 160) return 'green'; if (hue < 200) return 'cyan'; if (hue < 260) return 'blue'; if (hue < 290) return 'purple'; return 'magenta'; }