public static ColorBlock Fit(ColorSet colors, Options options, bool isBC1) { int count = colors.Count; Vector3[] points = colors.Points; double[] weights = colors.Weights; // compute the principle component Vector3 principle = ComputePrincipleComponent(count, points, weights); // get the min and max range as the codebook endpoints Vector3 start = new Vector3(); Vector3 end = new Vector3(); if( count > 0 ) { double min, max; // compute the range start = end = points[0]; min = max = Vector3.Dot(points[0], principle); for( int i = 1; i < count; ++i ) { double val = Vector3.Dot(points[i], principle); if( val < min ) { start = points[i]; min = val; } else if( val > max ) { end = points[i]; max = val; } } } // clamp the output to [0, 1] start = Vector3.Clamp(start, 0.0, 1.0); end = Vector3.Clamp(end, 0.0, 1.0); // clamp to the grid and save Vector3 grid = new Vector3(31.0, 63.0, 31.0); Vector3 gridrcp = Vector3.Reciprocal(grid); Vector3 half = new Vector3(0.5); start = Truncate(grid * start + half) * gridrcp; end = Truncate(grid * end + half) * gridrcp; // create a codebook Vector3[] codes = new Vector3[4]; codes[0] = start; codes[1] = end; codes[2] = (2.0 / 3.0) * start + (1.0 / 3.0) * end; codes[3] = (1.0 / 3.0) * start + (2.0 / 3.0) * end; // match each point to the closest code int[] closest = new int[16]; double error = 0.0f; for( int i = 0; i < count; ++i ) { // find the closest code double dist = double.MaxValue; int idx = 0; for( int j = 0; j < 4; ++j ) { double d = (options.Metric * (points[i] - codes[j])).MagnitudeSquared; if( d < dist ) { dist = d; idx = j; } } // save the index closest[i] = idx; // accumulate the error error += dist; } // remap the indices int[] indices = new int[16]; colors.RemapIndices(closest, indices); return new ColorBlock(new Color(start.X, start.Y, start.Z), new Color(end.X, end.Y, end.Z), indices); }
public static ColorBlock Fit(ColorSet colors, Options options, bool isBC1) { int count = colors.Count; Vector3[] points = colors.Points; double[] weights = colors.Weights; // compute the principle component Vector3 principle = ComputePrincipleComponent(count, points, weights); // get the min and max range as the codebook endpoints Vector3 start = new Vector3(); Vector3 end = new Vector3(); if (count > 0) { double min, max; // compute the range start = end = points[0]; min = max = Vector3.Dot(points[0], principle); for (int i = 1; i < count; ++i) { double val = Vector3.Dot(points[i], principle); if (val < min) { start = points[i]; min = val; } else if (val > max) { end = points[i]; max = val; } } } // clamp the output to [0, 1] start = Vector3.Clamp(start, 0.0, 1.0); end = Vector3.Clamp(end, 0.0, 1.0); // clamp to the grid and save Vector3 grid = new Vector3(31.0, 63.0, 31.0); Vector3 gridrcp = Vector3.Reciprocal(grid); Vector3 half = new Vector3(0.5); start = Truncate(grid * start + half) * gridrcp; end = Truncate(grid * end + half) * gridrcp; // create a codebook Vector3[] codes = new Vector3[4]; codes[0] = start; codes[1] = end; codes[2] = (2.0 / 3.0) * start + (1.0 / 3.0) * end; codes[3] = (1.0 / 3.0) * start + (2.0 / 3.0) * end; // match each point to the closest code int[] closest = new int[16]; double error = 0.0f; for (int i = 0; i < count; ++i) { // find the closest code double dist = double.MaxValue; int idx = 0; for (int j = 0; j < 4; ++j) { double d = (options.Metric * (points[i] - codes[j])).MagnitudeSquared; if (d < dist) { dist = d; idx = j; } } // save the index closest[i] = idx; // accumulate the error error += dist; } // remap the indices int[] indices = new int[16]; colors.RemapIndices(closest, indices); return(new ColorBlock(new Color(start.X, start.Y, start.Z), new Color(end.X, end.Y, end.Z), indices)); }