private/Find-WtwContrastColor.ps1
|
function Find-WtwContrastColor { <# .SYNOPSIS Pick a color maximally distant from all currently assigned colors. #> param( [PSObject] $Colors, [string] $ExcludeKey # Don't count this key's current color as "in use" ) # Collect assigned colors, remembering the excluded key's current color $assigned = @() $excludedColor = $null foreach ($prop in $Colors.assignments.PSObject.Properties) { if ($ExcludeKey -and $prop.Name -eq $ExcludeKey) { $excludedColor = $prop.Value continue } $assigned += $prop.Value } if ($assigned.Count -eq 0 -and -not $excludedColor) { # Nothing assigned at all — pick randomly from palette $cands = @($Colors.palette) return $cands | Get-Random } # Use assigned colors + excluded color as repulsion points # (excluded color: we want distance from it so "random" gives something visibly different) $repulsionSet = @($assigned) if ($excludedColor) { $repulsionSet += $excludedColor } # Use a loop instead of pipeline to avoid array unrolling $assignedRgb = @() foreach ($hex in $repulsionSet) { $assignedRgb += , (ConvertTo-WtwRgbArray $hex) } # Candidates: full palette + generated hue samples for broader coverage $candidates = @() foreach ($c in @($Colors.palette)) { $candidates += $c } # Generate 72 evenly-spaced hues at two saturation/lightness levels for ($h = 0; $h -lt 360; $h += 5) { $candidates += Convert-HslToHex $h 0.75 0.45 $candidates += Convert-HslToHex $h 0.90 0.55 } # Remove the excluded key's current color from candidates so "random" always gives a new color if ($excludedColor) { $excludedLower = $excludedColor.ToLower() $candidates = $candidates | Where-Object { $_.ToLower() -ne $excludedLower } } # Score each candidate: minimum perceptual distance to any assigned color $scored = @() foreach ($c in $candidates) { $rgb = ConvertTo-WtwRgbArray $c $minDist = [double]::MaxValue foreach ($a in $assignedRgb) { $d = Get-PerceptualDistance $rgb $a if ($d -lt $minDist) { $minDist = $d } } $scored += @{ Color = $c; Score = $minDist } } # Sort descending by score $scored = $scored | Sort-Object Score -Descending # Take top 15 and pick one at random $poolSize = [math]::Min(15, $scored.Count) if ($poolSize -gt 0) { $pool = $scored[0..($poolSize - 1)] $picked = $pool | Get-Random return $picked.Color } return $null } |