libgimpprint API Reference: src/main/sequence.c Source File

Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

# src/main/sequence.c

Go to the documentation of this file.

    00001 /*
    00002  * "$Id: sequence_8c-source.html,v 1.1.1.2 2004/12/22 23:49:12 jlovell Exp $"
    00003  *
    00004  *   Sequence data type.  This type is designed to be derived from by
    00005  *   the curve and dither matrix types.
    00006  *
    00007  *   Copyright 2002-2003 Robert Krawitz (rlk@alum.mit.edu)
    00008  *   Copyright 2003      Roger Leigh (rleigh@debian.org)
    00009  *
    00010  *   This program is free software; you can redistribute it and/or modify it
    00011  *   under the terms of the GNU General Public License as published by the Free
    00012  *   Software Foundation; either version 2 of the License, or (at your option)
    00013  *   any later version.
    00014  *
    00015  *   This program is distributed in the hope that it will be useful, but
    00016  *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    00017  *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    00018  *   for more details.
    00019  *
    00020  *   You should have received a copy of the GNU General Public License
    00021  *   along with this program; if not, write to the Free Software
    00022  *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    00023  */
    00024
    00025 #ifdef HAVE_CONFIG_H
    00026 #include <config.h>
    00027 #endif
    00028 #include <gimp-print/gimp-print.h>
    00029 #include <gimp-print/sequence.h>
    00030 #include "gimp-print-internal.h"
    00031 #include <gimp-print/gimp-print-intl-internal.h>
    00032 #include <math.h>
    00033 #ifdef sun
    00034 #include <ieeefp.h>
    00035 #endif
    00036 #include <string.h>
    00037 #include <stdlib.h>
    00038 #include <limits.h>
    00039 #include <errno.h>
    00040 #include <ctype.h>
    00041
    00042 struct stp_sequence
    00043 {
    00044   int recompute_range; /* Do we need to recompute the min and max? */
    00045   double blo;          /* Lower bound */
    00046   double bhi;          /* Upper bound */
    00047   double rlo;          /* Lower range limit */
    00048   double rhi;          /* Upper range limit */
    00049   size_t size;         /* Number of points */
    00050   double *data;        /* Array of doubles */
    00051   float *float_data;   /* Data converted to other form */
    00052   long *long_data;
    00053   unsigned long *ulong_data;
    00054   int *int_data;
    00055   unsigned *uint_data;
    00056   short *short_data;
    00057   unsigned short *ushort_data;
    00058 };
    00059
    00060 /*
    00061  * We could do more sanity checks here if we want.
    00062  */
    00063 static inline void
    00064 check_sequence(const stp_sequence_t *v)
    00065 {
    00066   if (v == NULL)
    00067     {
    00068       stp_erprintf("Null stp_sequence_t! Please report this bug.\n");
    00069       stp_abort();
    00070     }
    00071 }
    00072
    00073 static void
    00074 sequence_ctor(stp_sequence_t *sequence)
    00075 {
    00076   sequence->rlo = sequence->blo = 0.0;
    00077   sequence->rhi = sequence->bhi = 1.0;
    00078   sequence->recompute_range = 1;
    00079   sequence->size = 0;
    00080   sequence->data = NULL;
    00081 }
    00082
    00083 stp_sequence_t *
    00084 stp_sequence_create(void)
    00085 {
    00086   stp_sequence_t *ret;
    00087   ret = stp_zalloc(sizeof(stp_sequence_t));
    00088   sequence_ctor(ret);
    00089   return ret;
    00090 }
    00091
    00092 static void
    00093 invalidate_auxilliary_data(stp_sequence_t *sequence)
    00094 {
    00095   STP_SAFE_FREE(sequence->float_data);
    00096   STP_SAFE_FREE(sequence->long_data);
    00097   STP_SAFE_FREE(sequence->ulong_data);
    00098   STP_SAFE_FREE(sequence->int_data);
    00099   STP_SAFE_FREE(sequence->uint_data);
    00100   STP_SAFE_FREE(sequence->short_data);
    00101   STP_SAFE_FREE(sequence->ushort_data);
    00102 }
    00103
    00104 static void
    00105 sequence_dtor(stp_sequence_t *sequence)
    00106 {
    00107   invalidate_auxilliary_data(sequence);
    00108   if (sequence->data)
    00109     stp_free(sequence->data);
    00110   memset(sequence, 0, sizeof(stp_sequence_t));
    00111 }
    00112
    00113 void
    00114 stp_sequence_destroy(stp_sequence_t *sequence)
    00115 {
    00116   check_sequence(sequence);
    00117   sequence_dtor(sequence);
    00118   stp_free(sequence);
    00119 }
    00120
    00121 void
    00122 stp_sequence_copy(stp_sequence_t *dest, const stp_sequence_t *source)
    00123 {
    00124   check_sequence(dest);
    00125   check_sequence(source);
    00126
    00127   dest->recompute_range = source->recompute_range;
    00128   dest->blo = source->blo;
    00129   dest->bhi = source->bhi;
    00130   dest->rlo = source->rlo;
    00131   dest->rhi = source->rhi;
    00132   dest->size = source->size;
    00133   dest->data = stp_zalloc(sizeof(double) * source->size);
    00134   memcpy(dest->data, source->data, (sizeof(double) * source->size));
    00135 }
    00136
    00137 stp_sequence_t *
    00138 stp_sequence_create_copy(const stp_sequence_t *sequence)
    00139 {
    00140   stp_sequence_t *ret;
    00141   check_sequence(sequence);
    00142   ret = stp_sequence_create();
    00143   stp_sequence_copy(ret, sequence);
    00144   return ret;
    00145 }
    00146
    00147 int
    00148 stp_sequence_set_bounds(stp_sequence_t *sequence, double low, double high)
    00149 {
    00150   check_sequence(sequence);
    00151   if (low > high)
    00152     return 0;
    00153   sequence->rlo = sequence->blo = low;
    00154   sequence->rhi = sequence->bhi = high;
    00155   sequence->recompute_range = 1;
    00156   return 1;
    00157 }
    00158
    00159 void
    00160 stp_sequence_get_bounds(const stp_sequence_t *sequence,
    00161                         double *low, double *high)
    00162 {
    00163   check_sequence(sequence);
    00164   *low = sequence->blo;
    00165   *high = sequence->bhi;
    00166 }
    00167
    00168
    00169 /*
    00170  * Find the minimum and maximum points on the curve.
    00171  */
    00172 static void
    00173 scan_sequence_range(stp_sequence_t *sequence)
    00174 {
    00175   int i;
    00176   sequence->rlo = sequence->bhi;
    00177   sequence->rhi = sequence->blo;
    00178   if (sequence->size)
    00179     for (i = 0; i < sequence->size; i++)
    00180       {
    00181         if (sequence->data[i] < sequence->rlo)
    00182           sequence->rlo = sequence->data[i];
    00183         if (sequence->data[i] > sequence->rhi)
    00184           sequence->rhi = sequence->data[i];
    00185       }
    00186   sequence->recompute_range = 0; /* Don't recompute unless the data changes */
    00187 }
    00188
    00189 void
    00190 stp_sequence_get_range(const stp_sequence_t *sequence,
    00191                        double *low, double *high)
    00192 {
    00193   if (sequence->recompute_range) /* Don't recompute the range if we don't
    00194                                need to. */
    00195     scan_sequence_range((stp_sequence_t *) sequence);
    00196   *low = sequence->rlo;
    00197   *high = sequence->rhi;
    00198 }
    00199
    00200
    00201 int
    00202 stp_sequence_set_size(stp_sequence_t *sequence, size_t size)
    00203 {
    00204   check_sequence(sequence);
    00205   if (sequence->data) /* Free old data */
    00206     {
    00207       stp_free(sequence->data);
    00208       sequence->data = NULL;
    00209     }
    00210   sequence->size = size;
    00211   sequence->recompute_range = 1; /* Always recompute on change */
    00212   if (size == 0)
    00213     return 1;
    00214   invalidate_auxilliary_data(sequence);
    00215   sequence->data = stp_zalloc(sizeof(double) * size);
    00216   return 1;
    00217 }
    00218
    00219
    00220 size_t
    00221 stp_sequence_get_size(const stp_sequence_t *sequence)
    00222 {
    00223   check_sequence(sequence);
    00224   return sequence->size;
    00225 }
    00226
    00227
    00228
    00229 int
    00230 stp_sequence_set_data(stp_sequence_t *sequence,
    00231                       size_t size, const double *data)
    00232 {
    00233   check_sequence(sequence);
    00234   sequence->size = size;
    00235   if (sequence->data)
    00236     stp_free(sequence->data);
    00237   sequence->data = stp_zalloc(sizeof(double) * size);
    00238   memcpy(sequence->data, data, (sizeof(double) * size));
    00239   invalidate_auxilliary_data(sequence);
    00240   sequence->recompute_range = 1;
    00241   return 1;
    00242 }
    00243
    00244 int
    00245 stp_sequence_set_subrange(stp_sequence_t *sequence, size_t where,
    00246                           size_t size, const double *data)
    00247 {
    00248   check_sequence(sequence);
    00249   if (where + size > sequence->size) /* Exceeds data size */
    00250     return 0;
    00251   memcpy(sequence->data+where, data, (sizeof(double) * size));
    00252   invalidate_auxilliary_data(sequence);
    00253   sequence->recompute_range = 1;
    00254   return 1;
    00255 }
    00256
    00257
    00258 void
    00259 stp_sequence_get_data(const stp_sequence_t *sequence, size_t *size,
    00260                       const double **data)
    00261 {
    00262   check_sequence(sequence);
    00263   *size = sequence->size;
    00264   *data = sequence->data;
    00265 }
    00266
    00267
    00268 int
    00269 stp_sequence_set_point(stp_sequence_t *sequence, size_t where,
    00270                        double data)
    00271 {
    00272   check_sequence(sequence);
    00273
    00274   if (where >= sequence->size || ! finite(data) ||
    00275       data < sequence->blo || data > sequence->bhi)
    00276     return 0;
    00277
    00278   if (sequence->recompute_range == 0 && (data < sequence->rlo ||
    00279                                          data > sequence->rhi ||
    00280                                          sequence->data[where] == sequence->rhi ||
    00281                                          sequence->data[where] == sequence->rlo))
    00282     sequence->recompute_range = 1;
    00283
    00284   sequence->data[where] = data;
    00285   invalidate_auxilliary_data(sequence);
    00286   return 1;
    00287 }
    00288
    00289 int
    00290 stp_sequence_get_point(const stp_sequence_t *sequence, size_t where,
    00291                        double *data)
    00292 {
    00293   check_sequence(sequence);
    00294
    00295   if (where >= sequence->size)
    00296     return 0;
    00297   *data = sequence->data[where];
    00298   return 1;
    00299 }
    00300
    00301 stp_sequence_t *
    00302 stp_sequence_create_from_xmltree(stp_mxml_node_t *da)
    00303 {
    00304   const char *stmp;
    00305   stp_sequence_t *ret = NULL;
    00306   size_t point_count;
    00307   double low, high;
    00308   int i;
    00309
    00310   ret = stp_sequence_create();
    00311
    00312   /* Get curve point count */
    00313   stmp = stp_mxmlElementGetAttr(da, "count");
    00314   if (stmp)
    00315     {
    00316       point_count = (size_t) stp_xmlstrtoul(stmp);
    00317       if ((stp_xmlstrtol(stmp)) < 0)
    00318         {
    00319           stp_erprintf("stp_sequence_create_from_xmltree: \"count\" is less than zero\n");
    00320           goto error;
    00321         }
    00322     }
    00323   else
    00324     {
    00325       stp_erprintf("stp_sequence_create_from_xmltree: \"count\" missing\n");
    00326       goto error;
    00327     }
    00328   /* Get lower bound */
    00329   stmp = stp_mxmlElementGetAttr(da, "lower-bound");
    00330   if (stmp)
    00331     {
    00332       low = stp_xmlstrtod(stmp);
    00333     }
    00334   else
    00335     {
    00336       stp_erprintf("stp_sequence_create_from_xmltree: \"lower-bound\" missing\n");
    00337       goto error;
    00338     }
    00339   /* Get upper bound */
    00340   stmp = stp_mxmlElementGetAttr(da, "upper-bound");
    00341   if (stmp)
    00342     {
    00343       high = stp_xmlstrtod(stmp);
    00344     }
    00345   else
    00346     {
    00347       stp_erprintf("stp_sequence_create_from_xmltree: \"upper-bound\" missing\n");
    00348       goto error;
    00349     }
    00350
    00351   stp_deprintf(STP_DBG_XML,
    00352                "stp_sequence_create_from_xmltree: stp_sequence_set_size: %d\n",
    00353                point_count);
    00354   stp_sequence_set_size(ret, point_count);
    00355   stp_sequence_set_bounds(ret, low, high);
    00356
    00357   /* Now read in the data points */
    00358   if (point_count)
    00359     {
    00360       stp_mxml_node_t *child = da->child;
    00361       i = 0;
    00362       while (child && i < point_count)
    00363         {
    00364           if (child->type == STP_MXML_TEXT)
    00365             {
    00366               char *endptr;
    00367               double tmpval = strtod(child->value.text.string, &endptr);
    00368               if (endptr == child->value.text.string)
    00369                 {
    00370                   stp_erprintf
    00371                     ("stp_sequence_create_from_xmltree: bad data %s\n",
    00372                      child->value.text.string);
    00373                   goto error;
    00374                 }
    00375               if (! finite(tmpval)
    00376                   || ( tmpval == 0 && errno == ERANGE )
    00377                   || tmpval < low
    00378                   || tmpval > high)
    00379                 {
    00380                   stp_erprintf("stp_sequence_create_from_xmltree: "
    00381                                "read aborted: datum out of bounds: "
    00382                                "%g (require %g <= x <= %g), n = %d\n",
    00383                                tmpval, low, high, i);
    00384                   goto error;
    00385                 }
    00386               /* Datum was valid, so now add to the sequence */
    00387               stp_sequence_set_point(ret, i, tmpval);
    00388               i++;
    00389               child = child->next;
    00390             }
    00391         }
    00392       if (i < point_count)
    00393         {
    00394           stp_erprintf("stp_sequence_create_from_xmltree: "
    00395                        "read aborted: too little data "
    00396                        "(n=%d, needed %d)\n", i, point_count);
    00397           goto error;
    00398         }
    00399     }
    00400
    00401   return ret;
    00402
    00403  error:
    00404   stp_erprintf("stp_sequence_create_from_xmltree: error during sequence read\n");
    00405   if (ret)
    00406     stp_sequence_destroy(ret);
    00407   return NULL;
    00408 }
    00409
    00410 stp_mxml_node_t *
    00411 stp_xmltree_create_from_sequence(const stp_sequence_t *seq)   /* The sequence */
    00412 {
    00413   size_t pointcount;
    00414   double low;
    00415   double high;
    00416
    00417   char *count;
    00418   char *lower_bound;
    00419   char *upper_bound;
    00420
    00421   stp_mxml_node_t *seqnode;
    00422
    00423   int i;                 /* loop counter */
    00424
    00425   pointcount = stp_sequence_get_size(seq);
    00426   stp_sequence_get_bounds(seq, &low, &high);
    00427
    00428   /* should count be of greater precision? */
    00429   stp_asprintf(&count, "%lu", (unsigned long) pointcount);
    00430   stp_asprintf(&lower_bound, "%g", low);
    00431   stp_asprintf(&upper_bound, "%g", high);
    00432
    00433   seqnode = stp_mxmlNewElement(NULL, "sequence");
    00434   (void) stp_mxmlElementSetAttr(seqnode, "count", count);
    00435   (void) stp_mxmlElementSetAttr(seqnode, "lower-bound", lower_bound);
    00436   (void) stp_mxmlElementSetAttr(seqnode, "upper-bound", upper_bound);
    00437
    00438   stp_free(count);
    00439   stp_free(lower_bound);
    00440   stp_free(upper_bound);
    00441
    00442   /* Write the curve points into the node content */
    00443   if (pointcount) /* Is there any data to write? */
    00444     {
    00445       for (i = 0; i < pointcount; i++)
    00446         {
    00447           double dval;
    00448           char *sval;
    00449
    00450           if ((stp_sequence_get_point(seq, i, &dval)) != 1)
    00451             goto error;
    00452
    00453           stp_asprintf(&sval, "%g", dval);
    00454           stp_mxmlNewText(seqnode, 1, sval);
    00455           stp_free(sval);
    00456       }
    00457     }
    00458   return seqnode;
    00459
    00460  error:
    00461   if (seqnode)
    00462     stp_mxmlDelete(seqnode);
    00463   return NULL;
    00464 }
    00465
    00466
    00467 /* "Overloaded" functions */
    00468
    00469 #define DEFINE_DATA_SETTER(t, name)                                          \
    00470 int                                                                          \
    00471 stp_sequence_set_##name##_data(stp_sequence_t *sequence,                     \
    00472                                size_t count, const t *data)                  \
    00473 {                                                                            \
    00474   int i;                                                                     \
    00475   check_sequence(sequence);                                                          \
    00476   if (count < 2)                                                             \
    00477     return 0;                                                                \
    00478                                                                              \
    00479   /* Validate the data before we commit to it. */                            \
    00480   for (i = 0; i < count; i++)                                                \
    00481     if (! finite(data[i]) ||                                                 \
    00482         data[i] < sequence->blo ||                                           \
    00483         data[i] > sequence->bhi)                                             \
    00484       return 0;                                                              \
    00485   stp_sequence_set_size(sequence, count);                                    \
    00486   for (i = 0; i < count; i++)                                                \
    00487     stp_sequence_set_point(sequence, i, (double) data[i]);                   \
    00488   return 1;                                                                  \
    00489 }
    00490
    00491 DEFINE_DATA_SETTER(float, float)
    00492 DEFINE_DATA_SETTER(long, long)
    00493 DEFINE_DATA_SETTER(unsigned long, ulong)
    00494 DEFINE_DATA_SETTER(int, int)
    00495 DEFINE_DATA_SETTER(unsigned int, uint)
    00496 DEFINE_DATA_SETTER(short, short)
    00497 DEFINE_DATA_SETTER(unsigned short, ushort)
    00498
    00499
    00500 #define DEFINE_DATA_ACCESSOR(t, lb, ub, name)                                \
    00501 const t *                                                                    \
    00502 stp_sequence_get_##name##_data(const stp_sequence_t *sequence, size_t *count) \
    00503 {                                                                            \
    00504   int i;                                                                     \
    00505   if (sequence->blo < (double) lb || sequence->bhi > (double) ub)            \
    00506     return NULL;                                                             \
    00507   if (!sequence->name##_data)                                                \
    00508     {                                                                        \
    00509       ((stp_sequence_t *)sequence)->name##_data = stp_zalloc(sizeof(t) * sequence->size);            \
    00510       for (i = 0; i < sequence->size; i++)                                   \
    00511         ((stp_sequence_t *)sequence)->name##_data[i] = (t) sequence->data[i];                \
    00512     }                                                                        \
    00513   *count = sequence->size;                                                   \
    00514   return sequence->name##_data;                                              \
    00515 }
    00516
    00517 #ifndef HUGE_VALF /* ISO constant, from <math.h> */
    00518 #define HUGE_VALF 3.402823466E+38F
    00519 #endif
    00520
    00521 DEFINE_DATA_ACCESSOR(float, -HUGE_VALF, HUGE_VALF, float)
    00522 DEFINE_DATA_ACCESSOR(long, LONG_MIN, LONG_MAX, long)
    00523 DEFINE_DATA_ACCESSOR(unsigned long, 0, ULONG_MAX, ulong)
    00524 DEFINE_DATA_ACCESSOR(int, INT_MIN, INT_MAX, int)
    00525 DEFINE_DATA_ACCESSOR(unsigned int, 0, UINT_MAX, uint)
    00526 DEFINE_DATA_ACCESSOR(short, SHRT_MIN, SHRT_MAX, short)
    00527 DEFINE_DATA_ACCESSOR(unsigned short, 0, USHRT_MAX, ushort)