home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / sel2path / spline.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-29  |  6.2 KB  |  231 lines

  1. /* spline.c: spline and spline list (represented as arrays) manipulation.
  2.  
  3. Copyright (C) 1992 Free Software Foundation, Inc.
  4.  
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9.  
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include <assert.h>
  20.  
  21. #include <glib.h>
  22.  
  23. #include "global.h"
  24. #include "bounding-box.h"
  25. #include "spline.h"
  26. #include "vector.h"
  27.  
  28. /* Return a new spline structure, initialized with (recognizable)
  29.    garbage.  */ 
  30.  
  31. spline_type
  32. new_spline ()
  33. {
  34.   real_coordinate_type coord = { -100.0, -100.0 };
  35.   spline_type spline;
  36.  
  37.   START_POINT (spline)
  38.     = CONTROL1 (spline)
  39.     = CONTROL2 (spline)
  40.     = END_POINT (spline)
  41.     = coord;
  42.   SPLINE_DEGREE (spline) = -1;
  43.  
  44.   return spline;
  45. }
  46.  
  47.  
  48. /* Print a spline in human-readable form.  */
  49.  
  50. void
  51. print_spline (FILE *f, spline_type s)
  52. {
  53.   if (SPLINE_DEGREE (s) == LINEAR)
  54.     fprintf (f, "(%.3f,%.3f)--(%.3f,%.3f).\n",
  55.                 START_POINT (s).x, START_POINT (s).y,
  56.                 END_POINT (s).x, END_POINT (s).y);
  57.  
  58.   else if (SPLINE_DEGREE (s) == CUBIC)
  59.     fprintf (f, "(%.3f,%.3f)..ctrls(%.3f,%.3f)&(%.3f,%.3f)..(%.3f,%.3f).\n",
  60.                 START_POINT (s).x, START_POINT (s).y,
  61.                 CONTROL1 (s).x, CONTROL1 (s).y,
  62.                 CONTROL2 (s).x, CONTROL2 (s).y,
  63.                 END_POINT (s).x, END_POINT (s).y);
  64.  
  65.   else
  66.     {
  67. /*       FATAL1 ("print_spline: strange degree (%d)", SPLINE_DEGREE (s)); */
  68.     }
  69. }
  70.  
  71. /* Evaluate the spline S at a given T value.  This is an implementation
  72.    of de Casteljau's algorithm.  See Schneider's thesis (reference in
  73.    ../limn/README), p.37.  The variable names are taken from there.  */
  74.  
  75. real_coordinate_type
  76. evaluate_spline (spline_type s, real t)
  77. {
  78.   spline_type V[4];    /* We need degree+1 splines, but assert degree <= 3.  */
  79.   unsigned i, j;
  80.   real one_minus_t = 1.0 - t;
  81.   polynomial_degree degree = SPLINE_DEGREE (s);
  82.  
  83.   for (i = 0; i <= degree; i++)
  84.     V[0].v[i] = s.v[i];
  85.  
  86.   for (j = 1; j <= degree; j++)
  87.     for (i = 0; i <= degree - j; i++)
  88.       {
  89. #if defined (__GNUC__)
  90.         real_coordinate_type t1 = Pmult_scalar (V[j - 1].v[i], one_minus_t);
  91.         real_coordinate_type t2 = Pmult_scalar (V[j - 1].v[i + 1], t);
  92.         V[j].v[i] = Padd (t1, t2);
  93. #else
  94.     /* HB: the above is really nice, but is there any other compiler
  95.      * supporting this ??
  96.      */
  97.         real_coordinate_type t1;
  98.         real_coordinate_type t2;
  99.         t1.x = V[j - 1].v[i].x * one_minus_t;
  100.         t1.y = V[j - 1].v[i].y * one_minus_t;
  101.         t2.x = V[j - 1].v[i + 1].x * t;
  102.         t2.y = V[j - 1].v[i + 1].y * t;
  103.         V[j].v[i].x = t1.x + t2.x;
  104.         V[j].v[i].y = t1.y + t2.y;
  105. #endif
  106.       }
  107.  
  108.   return V[degree].v[0];
  109. }
  110.  
  111.  
  112.  
  113. /* Return a new, empty, spline list.  */
  114.  
  115. spline_list_type *
  116. new_spline_list ()
  117. {
  118.   spline_list_type *answer = g_new (spline_list_type, 1);
  119.  
  120.   SPLINE_LIST_DATA (*answer) = NULL;
  121.   SPLINE_LIST_LENGTH (*answer) = 0;
  122.  
  123.   return answer;
  124. }
  125.  
  126.  
  127. /* Return a new spline list with SPLINE as the first element.  */
  128.  
  129. spline_list_type *
  130. init_spline_list (spline_type spline)
  131. {
  132.   spline_list_type *answer = g_new (spline_list_type, 1);
  133.  
  134.   SPLINE_LIST_DATA (*answer) = g_new (spline_type, 1);
  135.   SPLINE_LIST_ELT (*answer, 0) = spline;
  136.   SPLINE_LIST_LENGTH (*answer) = 1;
  137.  
  138.   return answer;
  139. }
  140.  
  141.  
  142. /* Free the storage in a spline list.  We don't have to free the
  143.    elements, since they are arrays in automatic storage.  And we don't
  144.    want to free the list if it was empty.  */
  145.  
  146. void
  147. free_spline_list (spline_list_type *spline_list)
  148. {
  149.   if (SPLINE_LIST_DATA (*spline_list) != NULL)
  150.     safe_free ((address *) &(SPLINE_LIST_DATA (*spline_list)));
  151. }
  152.  
  153.  
  154. /* Append the spline S to the list SPLINE_LIST.  */
  155.  
  156. void
  157. append_spline (spline_list_type *l, spline_type s)
  158. {
  159.   assert (l != NULL);
  160.   
  161.   SPLINE_LIST_LENGTH (*l)++;
  162.   SPLINE_LIST_DATA (*l) = g_realloc (SPLINE_LIST_DATA (*l),
  163.                                SPLINE_LIST_LENGTH (*l) * sizeof (spline_type));
  164.   LAST_SPLINE_LIST_ELT (*l) = s;
  165. }
  166.  
  167.  
  168. /* Tack the elements in the list S2 onto the end of S1.
  169.    S2 is not changed.  */
  170.  
  171. void
  172. concat_spline_lists (spline_list_type *s1, spline_list_type s2)
  173. {
  174.   unsigned this_spline;
  175.   unsigned new_length;
  176.  
  177.   assert (s1 != NULL);
  178.  
  179.   new_length = SPLINE_LIST_LENGTH (*s1) + SPLINE_LIST_LENGTH (s2);
  180.  
  181.   SPLINE_LIST_DATA (*s1) = g_realloc(SPLINE_LIST_DATA (*s1),new_length * sizeof(spline_type));
  182.  
  183.   for (this_spline = 0; this_spline < SPLINE_LIST_LENGTH (s2); this_spline++)
  184.     SPLINE_LIST_ELT (*s1, SPLINE_LIST_LENGTH (*s1)++)
  185.       = SPLINE_LIST_ELT (s2, this_spline);
  186. }
  187.  
  188.  
  189. /* Return a new, empty, spline list array.  */
  190.  
  191. spline_list_array_type
  192. new_spline_list_array ()
  193. {
  194.   spline_list_array_type answer;
  195.  
  196.   SPLINE_LIST_ARRAY_DATA (answer) = NULL;
  197.   SPLINE_LIST_ARRAY_LENGTH (answer) = 0;
  198.  
  199.   return answer;
  200. }
  201.  
  202.  
  203. /* Free the storage in a spline list array.  We don't
  204.    want to free the list if it is empty.  */
  205.  
  206. void
  207. free_spline_list_array (spline_list_array_type *spline_list_array)
  208. {
  209.   unsigned this_list;
  210.  
  211.   for (this_list = 0;
  212.        this_list < SPLINE_LIST_ARRAY_LENGTH (*spline_list_array);
  213.        this_list++) 
  214.     free_spline_list (&SPLINE_LIST_ARRAY_ELT (*spline_list_array, this_list));
  215.  
  216.   if (SPLINE_LIST_ARRAY_DATA (*spline_list_array) != NULL)
  217.     safe_free ((address *) &(SPLINE_LIST_ARRAY_DATA (*spline_list_array)));
  218. }
  219.  
  220.  
  221. /* Append the spline S to the list SPLINE_LIST_ARRAY.  */
  222.  
  223. void
  224. append_spline_list (spline_list_array_type *l, spline_list_type s)
  225. {
  226.   SPLINE_LIST_ARRAY_LENGTH (*l)++;
  227.   
  228.   SPLINE_LIST_ARRAY_DATA (*l) = g_realloc(SPLINE_LIST_ARRAY_DATA (*l),(SPLINE_LIST_ARRAY_LENGTH (*l))*sizeof(spline_list_type));
  229.   LAST_SPLINE_LIST_ARRAY_ELT (*l) = s;
  230. }
  231.