summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2015-10-16 11:57:17 +0100
committerRichard Hughes <richard@hughsie.com>2015-10-16 11:59:34 +0100
commit6c3a8185bb09d5cab4a1821be43c26a5a42cffe5 (patch)
treec133a6ced6c25fab43c9432622d3b5fb2a07a796
parentea20f28db7b672793012b398a219d907b3da02d9 (diff)
downloadcolord-6c3a8185bb09d5cab4a1821be43c26a5a42cffe5.tar.gz
libcolord: Add cd_spectrum_set_wavelength_cal()
This allows us to have a non-linear relationship between pixel index and wavelength value.
-rw-r--r--lib/colord/cd-spectrum.c101
-rw-r--r--lib/colord/cd-spectrum.h8
-rw-r--r--lib/colord/cd-test-private.c45
3 files changed, 143 insertions, 11 deletions
diff --git a/lib/colord/cd-spectrum.c b/lib/colord/cd-spectrum.c
index 29e7dc2..52c07fa 100644
--- a/lib/colord/cd-spectrum.c
+++ b/lib/colord/cd-spectrum.c
@@ -42,6 +42,7 @@ struct _CdSpectrum {
gdouble start;
gdouble end;
gdouble norm;
+ gdouble wavelength_cal[3];
GArray *data;
};
@@ -69,6 +70,8 @@ cd_spectrum_dup (const CdSpectrum *spectrum)
tmp = cd_spectrum_get_value_raw (spectrum, i);
cd_spectrum_add_value (dest, tmp);
}
+ for (i = 0; i < 3; i++)
+ dest->wavelength_cal[i] = spectrum->wavelength_cal[i];
return dest;
}
@@ -196,20 +199,27 @@ cd_spectrum_get_value_raw (const CdSpectrum *spectrum, guint idx)
gdouble
cd_spectrum_get_wavelength (const CdSpectrum *spectrum, guint idx)
{
- gdouble step;
- guint number_points;
-
g_return_val_if_fail (spectrum != NULL, -1.0f);
- /* if we used cd_spectrum_size_new() and there is no data we can infer
- * the wavelenth based on the declared initial size */
- if (spectrum->reserved_size > 0)
- number_points = spectrum->reserved_size;
- else
- number_points = spectrum->data->len;
+ /* fall back to the old method */
+ if (spectrum->wavelength_cal[0] < 0) {
+ gdouble step;
+ guint number_points;
+ /* if we used cd_spectrum_size_new() and there is no data we can infer
+ * the wavelenth based on the declared initial size */
+ if (spectrum->reserved_size > 0)
+ number_points = spectrum->reserved_size;
+ else
+ number_points = spectrum->data->len;
+ step = (spectrum->end - spectrum->start) / (number_points - 1);
+ return spectrum->start + (step * (gdouble) idx);
+ }
- step = (spectrum->end - spectrum->start) / (number_points - 1);
- return spectrum->start + (step * (gdouble) idx);
+ /* use wavelength_cal to work out wavelength */
+ return spectrum->start +
+ spectrum->wavelength_cal[0] * (gdouble) idx +
+ spectrum->wavelength_cal[1] * pow (idx, 2) +
+ spectrum->wavelength_cal[2] * pow (idx, 3);
}
/**
@@ -352,6 +362,7 @@ cd_spectrum_new (void)
spectrum = g_slice_new0 (CdSpectrum);
spectrum->norm = 1.f;
spectrum->data = g_array_new (FALSE, FALSE, sizeof (gdouble));
+ spectrum->wavelength_cal[0] = -1.f;
return spectrum;
}
@@ -373,6 +384,7 @@ cd_spectrum_sized_new (guint reserved_size)
spectrum->norm = 1.f;
spectrum->reserved_size = reserved_size;
spectrum->data = g_array_sized_new (FALSE, FALSE, sizeof (gdouble), reserved_size);
+ spectrum->wavelength_cal[0] = -1.f;
return spectrum;
}
@@ -510,12 +522,25 @@ cd_spectrum_set_start (CdSpectrum *spectrum, gdouble start)
*
* Set the end value of the spectal data in nm.
*
+ * If there is already spectral data, the wavelength calibration will
+ * also be set automatically.
+ *
* Since: 1.1.6
**/
void
cd_spectrum_set_end (CdSpectrum *spectrum, gdouble end)
{
g_return_if_fail (spectrum != NULL);
+
+ /* calculate the calibration co-efficients */
+ if (spectrum->data->len > 1) {
+ spectrum->wavelength_cal[0] = (end - spectrum->start) /
+ (spectrum->data->len - 1);
+ spectrum->wavelength_cal[1] = 0.f;
+ spectrum->wavelength_cal[2] = 0.f;
+ }
+
+ /* set this for later */
spectrum->end = end;
}
@@ -723,6 +748,8 @@ cd_spectrum_subtract (CdSpectrum *s1, CdSpectrum *s2)
s->id = g_strdup_printf ("%s-%s", s1->id, s2->id);
s->start = s1->start;
s->end = s1->end;
+ for (i = 0; i < 3; i++)
+ s->wavelength_cal[i] = s1->wavelength_cal[i];
for (i = 0; i < s1->data->len; i++) {
gdouble tmp;
tmp = cd_spectrum_get_value (s1, i) - cd_spectrum_get_value (s2, i);
@@ -796,3 +823,55 @@ cd_spectrum_to_string (CdSpectrum *spectrum, guint max_width, guint max_height)
/* success */
return g_string_free (str, FALSE);
}
+
+/**
+ * cd_spectrum_set_wavelength_cal:
+ * @spectrum: a #CdSpectrum instance
+ * @c1: the 1st coefficient
+ * @c2: the 2nd coefficient
+ * @c3: the 3rd coefficient
+ *
+ * Sets the calibration coefficients used to map pixel indexes to
+ * wavelengths.
+ *
+ * This function will set the 'end' wavelength automatically,
+ * potentially overwriting the value set by cd_spectrum_set_end().
+ *
+ * Since: 1.3.1
+ **/
+void
+cd_spectrum_set_wavelength_cal (CdSpectrum *spectrum,
+ gdouble c1, gdouble c2, gdouble c3)
+{
+ spectrum->wavelength_cal[0] = c1;
+ spectrum->wavelength_cal[1] = c2;
+ spectrum->wavelength_cal[2] = c3;
+
+ /* recalculate the end wavelength */
+ spectrum->end = cd_spectrum_get_wavelength (spectrum,
+ cd_spectrum_get_size (spectrum) - 1);
+}
+
+/**
+ * cd_spectrum_get_wavelength_cal:
+ * @spectrum: a #CdSpectrum instance
+ * @c1: the 1st coefficient
+ * @c2: the 2nd coefficient
+ * @c3: the 3rd coefficient
+ *
+ * Gets the calibration coefficients used to map pixel indexes to
+ * wavelengths.
+ *
+ * Since: 1.3.1
+ **/
+void
+cd_spectrum_get_wavelength_cal (CdSpectrum *spectrum,
+ gdouble *c1, gdouble *c2, gdouble *c3)
+{
+ if (c1 != NULL)
+ *c1 = spectrum->wavelength_cal[0];
+ if (c2 != NULL)
+ *c2 = spectrum->wavelength_cal[1];
+ if (c3 != NULL)
+ *c3 = spectrum->wavelength_cal[2];
+}
diff --git a/lib/colord/cd-spectrum.h b/lib/colord/cd-spectrum.h
index ac6755a..816fc77 100644
--- a/lib/colord/cd-spectrum.h
+++ b/lib/colord/cd-spectrum.h
@@ -88,6 +88,14 @@ void cd_spectrum_set_value (CdSpectrum *spectrum,
gdouble data);
void cd_spectrum_add_value (CdSpectrum *spectrum,
gdouble data);
+void cd_spectrum_set_wavelength_cal (CdSpectrum *spectrum,
+ gdouble c1,
+ gdouble c2,
+ gdouble c3);
+void cd_spectrum_get_wavelength_cal (CdSpectrum *spectrum,
+ gdouble *c1,
+ gdouble *c2,
+ gdouble *c3);
CdSpectrum *cd_spectrum_multiply (CdSpectrum *s1,
CdSpectrum *s2,
gdouble resolution);
diff --git a/lib/colord/cd-test-private.c b/lib/colord/cd-test-private.c
index 617c9d6..efc4ffa 100644
--- a/lib/colord/cd-test-private.c
+++ b/lib/colord/cd-test-private.c
@@ -303,6 +303,50 @@ colord_spectrum_func (void)
}
static void
+colord_spect_cx_func (void)
+{
+ gdouble tmp;
+ g_autoptr(CdSpectrum) sp = NULL;
+
+ /* create test spectrum */
+ sp = cd_spectrum_new ();
+ cd_spectrum_set_start (sp, 100);
+ cd_spectrum_set_end (sp, 200);
+ g_assert_cmpfloat (fabs (cd_spectrum_get_end (sp) - 200.f), <, 0.001);
+
+ /* we don't calculate the coefficients with no data */
+ cd_spectrum_get_wavelength_cal (sp, &tmp, NULL, NULL);
+ g_assert_cmpfloat (fabs (tmp - -1.f), <, 0.001);
+
+ /* try again, this time with data added first */
+ cd_spectrum_add_value (sp, 1.f);
+ cd_spectrum_add_value (sp, 2.f);
+ cd_spectrum_add_value (sp, 3.f);
+ cd_spectrum_set_end (sp, 200);
+ cd_spectrum_get_wavelength_cal (sp, &tmp, NULL, NULL);
+ g_assert_cmpfloat (fabs (tmp - 50.f), <, 0.001);
+
+ /* test with linear polynomials */
+ g_assert_cmpfloat (fabs (cd_spectrum_get_end (sp) - 200.f), <, 0.001);
+ tmp = cd_spectrum_get_wavelength (sp, 0);
+ g_assert_cmpfloat (fabs (tmp - 100), <, 0.001);
+ tmp = cd_spectrum_get_wavelength (sp, 1);
+ g_assert_cmpfloat (fabs (tmp - 150), <, 0.001);
+ tmp = cd_spectrum_get_wavelength (sp, 2);
+ g_assert_cmpfloat (fabs (tmp - 200), <, 0.001);
+
+ /* test with 3rd order polynomials */
+ cd_spectrum_set_wavelength_cal (sp, 100.1f, 1.1f, 0.1f);
+ g_assert_cmpfloat (fabs (cd_spectrum_get_end (sp) - 305.3999f), <, 0.01);
+ tmp = cd_spectrum_get_wavelength (sp, 0);
+ g_assert_cmpfloat (fabs (tmp - 100), <, 0.001);
+ tmp = cd_spectrum_get_wavelength (sp, 1);
+ g_assert_cmpfloat (fabs (tmp - 201.2999), <, 0.01);
+ tmp = cd_spectrum_get_wavelength (sp, 2);
+ g_assert_cmpfloat (fabs (tmp - 305.3999), <, 0.01);
+}
+
+static void
colord_it8_spect_func (void)
{
CdIt8 *it8;
@@ -2251,6 +2295,7 @@ main (int argc, char **argv)
g_test_add_func ("/colord/spectrum", colord_spectrum_func);
g_test_add_func ("/colord/spectrum{planckian}", colord_spectrum_planckian_func);
g_test_add_func ("/colord/spectrum{subtract}", colord_spectrum_subtract_func);
+ g_test_add_func ("/colord/spectrum{cx}", colord_spect_cx_func);
g_test_add_func ("/colord/edid", colord_edid_func);
g_test_add_func ("/colord/transform", colord_transform_func);
g_test_add_func ("/colord/icc", colord_icc_func);