// This file provides functions for sorting colors.package colorfulimport ()// An element represents a single element of a set. It is used to// implement a disjoint-set forest.type element struct { parent *element// Parent element rank int// Rank (approximate depth) of the subtree with this element as root}// newElement creates a singleton set and returns its sole element.func newElement() *element { := &element{} .parent = return}// find returns an arbitrary element of a set when invoked on any element of// the set, The important feature is that it returns the same value when// invoked on any element of the set. Consequently, it can be used to test if// two elements belong to the same set.func ( *element) () *element {for .parent != { .parent = .parent.parent = .parent }return}// union establishes the union of two sets when given an element from each set.// Afterwards, the original sets no longer exist as separate entities.func union(, *element) {// Ensure the two elements aren't already part of the same union. := .find() := .find()if == {return }// Create a union by making the shorter tree point to the root of the // larger tree.switch {case .rank < .rank: .parent = case .rank > .rank: .parent = default: .parent = .rank++ }}// An edgeIdxs describes an edge in a graph or tree. The vertices in the edge// are indexes into a list of Color values.type edgeIdxs [2]int// An edgeDistance is a map from an edge (pair of indices) to a distance// between the two vertices.type edgeDistance map[edgeIdxs]float64// allToAllDistancesCIEDE2000 computes the CIEDE2000 distance between each pair of// colors. It returns a map from a pair of indices (u, v) with u < v to a// distance.func allToAllDistancesCIEDE2000( []Color) edgeDistance { := len() := make(edgeDistance, *)for := 0; < -1; ++ {for := + 1; < ; ++ { [edgeIdxs{, }] = [].DistanceCIEDE2000([]) } }return}// sortEdges sorts all edges in a distance map by increasing vertex distance.func sortEdges( edgeDistance) []edgeIdxs { := make([]edgeIdxs, 0, len())for := range { = append(, ) }sort.Slice(, func(, int) bool {return [[]] < [[]] })return}// minSpanTree computes a minimum spanning tree from a vertex count and a// distance-sorted edge list. It returns the subset of edges that belong to// the tree, including both (u, v) and (v, u) for each edge.func minSpanTree( int, []edgeIdxs) map[edgeIdxs]struct{} {// Start with each vertex in its own set. := make([]*element, )for := range { [] = newElement() }// Run Kruskal's algorithm to construct a minimal spanning tree. := make(map[edgeIdxs]struct{}, )for , := range { , := [0], [1]if [].find() == [].find() {continue// Same set: edge would introduce a cycle. } [] = struct{}{} [edgeIdxs{, }] = struct{}{}union([], []) }return}// traverseMST walks a minimum spanning tree in prefix order.func traverseMST( map[edgeIdxs]struct{}, int) []int {// Compute a list of neighbors for each vertex. := make(map[int][]int, len())for := range { , := [0], [1] [] = append([], ) }for , := range {sort.Ints()copy([], ) }// Walk the tree from a given vertex. := make([]int, 0, len()) := make(map[int]bool, len())varfunc(int) = func( int) {// Visit the starting vertex. = append(, ) [] = true// Recursively visit each child in turn.for , := range [] {if ![] { () } } } ()return}// Sorted sorts a list of Color values. Sorting is not a well-defined operation// for colors so the intention here primarily is to order colors so that the// transition from one to the next is fairly smooth.func ( []Color) []Color {// Do nothing in trivial cases. := make([]Color, len())iflen() < 2 {copy(, )return }// Compute the distance from each color to every other color. := allToAllDistancesCIEDE2000()// Produce a list of edges in increasing order of the distance between // their vertices. := sortEdges()// Construct a minimum spanning tree from the list of edges. := minSpanTree(len(), )// Find the darkest color in the list.varColorvarint// Index of darkest color := math.MaxFloat64// Lightness of darkest color (distance from black)for , := range { := .DistanceCIEDE2000()if < { = = } }// Traverse the tree starting from the darkest color. := traverseMST(, )// Convert the index list to a list of colors, overwriting the input.for , := range { [] = [] }return}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.