The main server, and probably only repository in this org.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

86 lines
2.1 KiB

package huecolor
// NOT IN USE. Gamuts just made things worse.
import "math"
type gamutPoint [2]float64
// A ColorGamut is a subset of a color space, and is used to constrain colors.
type ColorGamut struct {
R gamutPoint
G gamutPoint
B gamutPoint
}
var (
// HueGamut is the recommended gamut for hue bulbs
HueGamut = ColorGamut{gamutPoint{0.675, 0.322}, gamutPoint{0.4091, 0.518}, gamutPoint{0.167, 0.04}}
// FancyGamut is for LivingColors, Iris, and other fancy bulbs
FancyGamut = ColorGamut{gamutPoint{0.704, 0.296}, gamutPoint{0.2151, 0.7106}, gamutPoint{0.138, 0.08}}
// DefaultGamut is for non-Hue stuff.
DefaultGamut = ColorGamut{gamutPoint{0.9961, 0.0001}, gamutPoint{0.0001, 0.9961}, gamutPoint{0.0001, 0.0001}}
)
// Closest gets the closest point on the color gamut's edges. This function will always return a point
// on an edge, even if `(x, y)` is inside of it.
func (g *ColorGamut) Closest(x, y float64) (x2, y2 float64) {
p := gamutPoint{x, y}
pRG := closestToLine(g.R, g.G, p)
pGB := closestToLine(g.G, g.B, p)
pBR := closestToLine(g.B, g.R, p)
dRG := distance(p, pRG)
dGB := distance(p, pGB)
dBR := distance(p, pBR)
closest := pRG
closestDistance := dRG
if dGB < closestDistance {
closest = pGB
closestDistance = dGB
}
if dBR < closestDistance {
closest = pBR
closestDistance = dBR
}
return closest[0], closest[1]
}
// Contains retunrs true if the gamut contains the color.
func (g *ColorGamut) Contains(x, y float64) bool {
pt := gamutPoint{x, y}
b1 := sign(pt, g.R, g.G) < 0
b2 := sign(pt, g.G, g.B) < 0
b3 := sign(pt, g.B, g.R) < 0
return ((b1 == b2) && (b2 == b3))
}
func distance(p1, p2 gamutPoint) float64 {
dx := p1[0] - p2[0]
dy := p1[1] - p2[1]
return math.Sqrt(dx*dx + dy*dy)
}
func closestToLine(a, b, p gamutPoint) gamutPoint {
ap := gamutPoint{p[0] - a[0], p[1] - a[1]}
ab := gamutPoint{b[0] - a[0], b[1] - a[1]}
t := (ap[0]*ab[0] + ap[1]*ab[1]) / (ab[0]*ab[0] + ap[0]*ap[0])
if t < 0 {
t = 0
} else if t > 1 {
t = 1
}
return gamutPoint{a[0] + t*ab[0], a[1] + t*ab[1]}
}
func sign(p1, p2, p3 gamutPoint) float64 {
return (p1[0]-p3[0])*(p2[1]-p3[1]) - (p2[0]-p3[0])*(p1[1]-p3[1])
}