PageRenderTime 100ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/plug-ins/selection-to-path/spline.c

https://gitlab.com/marcelosabino/gimp
C | 233 lines | 137 code | 57 blank | 39 comment | 16 complexity | 1b50c6c043394b5ed44ed7ff69d9d6fa MD5 | raw file
  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 3, 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, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "config.h"
  19. #include <assert.h>
  20. #include <glib.h>
  21. #include "global.h"
  22. #include "bounding-box.h"
  23. #include "spline.h"
  24. #include "vector.h"
  25. /* Return a new spline structure, initialized with (recognizable)
  26. garbage. */
  27. spline_type
  28. new_spline (void)
  29. {
  30. real_coordinate_type coord = { -100.0, -100.0 };
  31. spline_type spline;
  32. START_POINT (spline)
  33. = CONTROL1 (spline)
  34. = CONTROL2 (spline)
  35. = END_POINT (spline)
  36. = coord;
  37. SPLINE_DEGREE (spline) = -1;
  38. SPLINE_LINEARITY (spline) = 0;
  39. return spline;
  40. }
  41. /* Print a spline in human-readable form. */
  42. void
  43. print_spline (FILE *f, spline_type s)
  44. {
  45. if (SPLINE_DEGREE (s) == LINEAR)
  46. fprintf (f, "(%.3f,%.3f)--(%.3f,%.3f).\n",
  47. START_POINT (s).x, START_POINT (s).y,
  48. END_POINT (s).x, END_POINT (s).y);
  49. else if (SPLINE_DEGREE (s) == CUBIC)
  50. fprintf (f, "(%.3f,%.3f)..ctrls(%.3f,%.3f)&(%.3f,%.3f)..(%.3f,%.3f).\n",
  51. START_POINT (s).x, START_POINT (s).y,
  52. CONTROL1 (s).x, CONTROL1 (s).y,
  53. CONTROL2 (s).x, CONTROL2 (s).y,
  54. END_POINT (s).x, END_POINT (s).y);
  55. else
  56. {
  57. /* FATAL1 ("print_spline: strange degree (%d)", SPLINE_DEGREE (s)); */
  58. }
  59. }
  60. /* Evaluate the spline S at a given T value. This is an implementation
  61. of de Casteljau's algorithm. See Schneider's thesis (reference in
  62. ../limn/README), p.37. The variable names are taken from there. */
  63. real_coordinate_type
  64. evaluate_spline (spline_type s, real t)
  65. {
  66. spline_type V[4]; /* We need degree+1 splines, but assert degree <= 3. */
  67. unsigned i, j;
  68. real one_minus_t = 1.0 - t;
  69. polynomial_degree degree = SPLINE_DEGREE (s);
  70. for (i = 0; i <= degree; i++)
  71. V[0].v[i] = s.v[i];
  72. for (j = 1; j <= degree; j++)
  73. for (i = 0; i <= degree - j; i++)
  74. {
  75. #if defined (__GNUC__)
  76. real_coordinate_type t1 = Pmult_scalar (V[j - 1].v[i], one_minus_t);
  77. real_coordinate_type t2 = Pmult_scalar (V[j - 1].v[i + 1], t);
  78. V[j].v[i] = Padd (t1, t2);
  79. #else
  80. /* HB: the above is really nice, but is there any other compiler
  81. * supporting this ??
  82. */
  83. real_coordinate_type t1;
  84. real_coordinate_type t2;
  85. t1.x = V[j - 1].v[i].x * one_minus_t;
  86. t1.y = V[j - 1].v[i].y * one_minus_t;
  87. t2.x = V[j - 1].v[i + 1].x * t;
  88. t2.y = V[j - 1].v[i + 1].y * t;
  89. V[j].v[i].x = t1.x + t2.x;
  90. V[j].v[i].y = t1.y + t2.y;
  91. #endif
  92. }
  93. return V[degree].v[0];
  94. }
  95. /* Return a new, empty, spline list. */
  96. spline_list_type *
  97. new_spline_list (void)
  98. {
  99. spline_list_type *answer = g_new (spline_list_type, 1);
  100. SPLINE_LIST_DATA (*answer) = NULL;
  101. SPLINE_LIST_LENGTH (*answer) = 0;
  102. return answer;
  103. }
  104. /* Return a new spline list with SPLINE as the first element. */
  105. spline_list_type *
  106. init_spline_list (spline_type spline)
  107. {
  108. spline_list_type *answer = g_new (spline_list_type, 1);
  109. SPLINE_LIST_DATA (*answer) = g_new (spline_type, 1);
  110. SPLINE_LIST_ELT (*answer, 0) = spline;
  111. SPLINE_LIST_LENGTH (*answer) = 1;
  112. return answer;
  113. }
  114. /* Free the storage in a spline list. We don't have to free the
  115. elements, since they are arrays in automatic storage. And we don't
  116. want to free the list if it was empty. */
  117. void
  118. free_spline_list (spline_list_type *spline_list)
  119. {
  120. if (SPLINE_LIST_DATA (*spline_list) != NULL)
  121. safe_free ((address *) &(SPLINE_LIST_DATA (*spline_list)));
  122. }
  123. /* Append the spline S to the list SPLINE_LIST. */
  124. void
  125. append_spline (spline_list_type *l, spline_type s)
  126. {
  127. assert (l != NULL);
  128. SPLINE_LIST_LENGTH (*l)++;
  129. SPLINE_LIST_DATA (*l) = g_realloc (SPLINE_LIST_DATA (*l),
  130. SPLINE_LIST_LENGTH (*l) * sizeof (spline_type));
  131. LAST_SPLINE_LIST_ELT (*l) = s;
  132. }
  133. /* Tack the elements in the list S2 onto the end of S1.
  134. S2 is not changed. */
  135. void
  136. concat_spline_lists (spline_list_type *s1, spline_list_type s2)
  137. {
  138. unsigned this_spline;
  139. unsigned new_length;
  140. assert (s1 != NULL);
  141. new_length = SPLINE_LIST_LENGTH (*s1) + SPLINE_LIST_LENGTH (s2);
  142. SPLINE_LIST_DATA (*s1) = g_realloc(SPLINE_LIST_DATA (*s1),new_length * sizeof(spline_type));
  143. for (this_spline = 0; this_spline < SPLINE_LIST_LENGTH (s2); this_spline++)
  144. SPLINE_LIST_ELT (*s1, SPLINE_LIST_LENGTH (*s1)++)
  145. = SPLINE_LIST_ELT (s2, this_spline);
  146. }
  147. /* Return a new, empty, spline list array. */
  148. spline_list_array_type
  149. new_spline_list_array (void)
  150. {
  151. spline_list_array_type answer;
  152. SPLINE_LIST_ARRAY_DATA (answer) = NULL;
  153. SPLINE_LIST_ARRAY_LENGTH (answer) = 0;
  154. return answer;
  155. }
  156. /* Free the storage in a spline list array. We don't
  157. want to free the list if it is empty. */
  158. void
  159. free_spline_list_array (spline_list_array_type *spline_list_array)
  160. {
  161. unsigned this_list;
  162. for (this_list = 0;
  163. this_list < SPLINE_LIST_ARRAY_LENGTH (*spline_list_array);
  164. this_list++)
  165. free_spline_list (&SPLINE_LIST_ARRAY_ELT (*spline_list_array, this_list));
  166. if (SPLINE_LIST_ARRAY_DATA (*spline_list_array) != NULL)
  167. safe_free ((address *) &(SPLINE_LIST_ARRAY_DATA (*spline_list_array)));
  168. }
  169. /* Append the spline S to the list SPLINE_LIST_ARRAY. */
  170. void
  171. append_spline_list (spline_list_array_type *l, spline_list_type s)
  172. {
  173. SPLINE_LIST_ARRAY_LENGTH (*l)++;
  174. SPLINE_LIST_ARRAY_DATA (*l) = g_realloc(SPLINE_LIST_ARRAY_DATA (*l),(SPLINE_LIST_ARRAY_LENGTH (*l))*sizeof(spline_list_type));
  175. LAST_SPLINE_LIST_ARRAY_ELT (*l) = s;
  176. }