gsfunc3.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. /* Copyright (C) 1997, 2000 Aladdin Enterprises. All rights reserved.
  2. This file is part of AFPL Ghostscript.
  3. AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or
  4. distributor accepts any responsibility for the consequences of using it, or
  5. for whether it serves any particular purpose or works at all, unless he or
  6. she says so in writing. Refer to the Aladdin Free Public License (the
  7. "License") for full details.
  8. Every copy of AFPL Ghostscript must include a copy of the License, normally
  9. in a plain ASCII text file named PUBLIC. The License grants you the right
  10. to copy, modify and redistribute AFPL Ghostscript, but only under certain
  11. conditions described in the License. Among other things, the License
  12. requires that the copyright notice and this notice be preserved on all
  13. copies.
  14. */
  15. /*$Id: gsfunc3.c,v 1.4 2000/09/19 19:00:28 lpd Exp $ */
  16. /* Implementation of LL3 Functions */
  17. #include "math_.h"
  18. #include "gx.h"
  19. #include "gserrors.h"
  20. #include "gsfunc3.h"
  21. #include "gsparam.h"
  22. #include "gxfunc.h"
  23. /* ---------------- Utilities ---------------- */
  24. #define MASK1 ((uint)(~0) / 3)
  25. /*
  26. * Free an array of subsidiary Functions. Note that this may be called
  27. * before the Functions array has been fully initialized. Note also that
  28. * its argument conforms to the Functions array in the parameter structure,
  29. * but it (necessarily) deconstifies it.
  30. */
  31. private void
  32. fn_free_functions(const gs_function_t *const * Functions, int count,
  33. gs_memory_t * mem)
  34. {
  35. int i;
  36. for (i = count; --i >= 0;)
  37. if (Functions[i])
  38. gs_function_free((gs_function_t *)Functions[i], true, mem);
  39. gs_free_const_object(mem, Functions, "Functions");
  40. }
  41. /* ---------------- Exponential Interpolation functions ---------------- */
  42. typedef struct gs_function_ElIn_s {
  43. gs_function_head_t head;
  44. gs_function_ElIn_params_t params;
  45. } gs_function_ElIn_t;
  46. private_st_function_ElIn();
  47. /* Evaluate an Exponential Interpolation function. */
  48. private int
  49. fn_ElIn_evaluate(const gs_function_t * pfn_common, const float *in, float *out)
  50. {
  51. const gs_function_ElIn_t *const pfn =
  52. (const gs_function_ElIn_t *)pfn_common;
  53. double arg = in[0], raised;
  54. int i;
  55. if (arg < pfn->params.Domain[0])
  56. arg = pfn->params.Domain[0];
  57. else if (arg > pfn->params.Domain[1])
  58. arg = pfn->params.Domain[1];
  59. raised = pow(arg, pfn->params.N);
  60. for (i = 0; i < pfn->params.n; ++i) {
  61. float v0 = (pfn->params.C0 == 0 ? 0.0 : pfn->params.C0[i]);
  62. float v1 = (pfn->params.C1 == 0 ? 1.0 : pfn->params.C1[i]);
  63. double value = v0 + raised * (v1 - v0);
  64. if (pfn->params.Range) {
  65. float r0 = pfn->params.Range[2 * i],
  66. r1 = pfn->params.Range[2 * i + 1];
  67. if (value < r0)
  68. value = r0;
  69. else if (value > r1)
  70. value = r1;
  71. }
  72. out[i] = value;
  73. if_debug3('~', "[~]ElIn %g => [%d]%g\n", arg, i, out[i]);
  74. }
  75. return 0;
  76. }
  77. /* Test whether an Exponential function is monotonic. (They always are.) */
  78. private int
  79. fn_ElIn_is_monotonic(const gs_function_t * pfn_common,
  80. const float *lower, const float *upper,
  81. gs_function_effort_t effort)
  82. {
  83. const gs_function_ElIn_t *const pfn =
  84. (const gs_function_ElIn_t *)pfn_common;
  85. int i, result;
  86. if (lower[0] > pfn->params.Domain[1] ||
  87. upper[0] < pfn->params.Domain[0]
  88. )
  89. return_error(gs_error_rangecheck);
  90. for (i = 0, result = 0; i < pfn->params.n; ++i) {
  91. double diff =
  92. (pfn->params.C1 == 0 ? 1.0 : pfn->params.C1[i]) -
  93. (pfn->params.C0 == 0 ? 0.0 : pfn->params.C0[i]);
  94. if (pfn->params.N < 0)
  95. diff = -diff;
  96. else if (pfn->params.N == 0)
  97. diff = 0;
  98. result |=
  99. (diff < 0 ? FN_MONOTONIC_DECREASING :
  100. diff > 0 ? FN_MONOTONIC_INCREASING :
  101. FN_MONOTONIC_DECREASING | FN_MONOTONIC_INCREASING) <<
  102. (2 * i);
  103. }
  104. return result;
  105. }
  106. /* Write Exponential Interpolation function parameters on a parameter list. */
  107. private int
  108. fn_ElIn_get_params(const gs_function_t *pfn_common, gs_param_list *plist)
  109. {
  110. const gs_function_ElIn_t *const pfn =
  111. (const gs_function_ElIn_t *)pfn_common;
  112. int ecode = fn_common_get_params(pfn_common, plist);
  113. int code;
  114. if (pfn->params.C0) {
  115. if ((code = param_write_float_values(plist, "C0", pfn->params.C0,
  116. pfn->params.n, false)) < 0)
  117. ecode = code;
  118. }
  119. if (pfn->params.C1) {
  120. if ((code = param_write_float_values(plist, "C1", pfn->params.C1,
  121. pfn->params.n, false)) < 0)
  122. ecode = code;
  123. }
  124. if ((code = param_write_float(plist, "N", &pfn->params.N)) < 0)
  125. ecode = code;
  126. return ecode;
  127. }
  128. /* Free the parameters of an Exponential Interpolation function. */
  129. void
  130. gs_function_ElIn_free_params(gs_function_ElIn_params_t * params,
  131. gs_memory_t * mem)
  132. {
  133. gs_free_const_object(mem, params->C1, "C1");
  134. gs_free_const_object(mem, params->C0, "C0");
  135. fn_common_free_params((gs_function_params_t *) params, mem);
  136. }
  137. /* Allocate and initialize an Exponential Interpolation function. */
  138. int
  139. gs_function_ElIn_init(gs_function_t ** ppfn,
  140. const gs_function_ElIn_params_t * params,
  141. gs_memory_t * mem)
  142. {
  143. static const gs_function_head_t function_ElIn_head = {
  144. function_type_ExponentialInterpolation,
  145. {
  146. (fn_evaluate_proc_t) fn_ElIn_evaluate,
  147. (fn_is_monotonic_proc_t) fn_ElIn_is_monotonic,
  148. gs_function_get_info_default,
  149. (fn_get_params_proc_t) fn_ElIn_get_params,
  150. (fn_free_params_proc_t) gs_function_ElIn_free_params,
  151. fn_common_free
  152. }
  153. };
  154. int code;
  155. *ppfn = 0; /* in case of error */
  156. code = fn_check_mnDR((const gs_function_params_t *)params, 1, params->n);
  157. if (code < 0)
  158. return code;
  159. if ((params->C0 == 0 || params->C1 == 0) && params->n != 1)
  160. return_error(gs_error_rangecheck);
  161. if (params->N != floor(params->N)) {
  162. /* Non-integral exponent, all inputs must be non-negative. */
  163. if (params->Domain[0] < 0)
  164. return_error(gs_error_rangecheck);
  165. }
  166. if (params->N < 0) {
  167. /* Negative exponent, input must not be zero. */
  168. if (params->Domain[0] <= 0 && params->Domain[1] >= 0)
  169. return_error(gs_error_rangecheck);
  170. } {
  171. gs_function_ElIn_t *pfn =
  172. gs_alloc_struct(mem, gs_function_ElIn_t, &st_function_ElIn,
  173. "gs_function_ElIn_init");
  174. if (pfn == 0)
  175. return_error(gs_error_VMerror);
  176. pfn->params = *params;
  177. pfn->params.m = 1;
  178. pfn->head = function_ElIn_head;
  179. pfn->head.is_monotonic =
  180. fn_domain_is_monotonic((gs_function_t *)pfn, EFFORT_MODERATE);
  181. *ppfn = (gs_function_t *) pfn;
  182. }
  183. return 0;
  184. }
  185. /* ---------------- 1-Input Stitching functions ---------------- */
  186. typedef struct gs_function_1ItSg_s {
  187. gs_function_head_t head;
  188. gs_function_1ItSg_params_t params;
  189. } gs_function_1ItSg_t;
  190. private_st_function_1ItSg();
  191. /* Evaluate a 1-Input Stitching function. */
  192. private int
  193. fn_1ItSg_evaluate(const gs_function_t * pfn_common, const float *in, float *out)
  194. {
  195. const gs_function_1ItSg_t *const pfn =
  196. (const gs_function_1ItSg_t *)pfn_common;
  197. float arg = in[0], b0, b1, e0, encoded;
  198. int k = pfn->params.k;
  199. int i;
  200. if (arg < pfn->params.Domain[0]) {
  201. arg = pfn->params.Domain[0];
  202. i = 0;
  203. } else if (arg > pfn->params.Domain[1]) {
  204. arg = pfn->params.Domain[1];
  205. i = k - 1;
  206. } else {
  207. for (i = 0; i < k - 1; ++i)
  208. if (arg <= pfn->params.Bounds[i])
  209. break;
  210. }
  211. b0 = (i == 0 ? pfn->params.Domain[0] : pfn->params.Bounds[i - 1]);
  212. b1 = (i == k - 1 ? pfn->params.Domain[1] : pfn->params.Bounds[i]);
  213. e0 = pfn->params.Encode[2 * i];
  214. encoded =
  215. (arg - b0) * (pfn->params.Encode[2 * i + 1] - e0) / (b1 - b0) + e0;
  216. if_debug3('~', "[~]1ItSg %g in %d => %g\n", arg, i, encoded);
  217. return gs_function_evaluate(pfn->params.Functions[i], &encoded, out);
  218. }
  219. /* Test whether a 1-Input Stitching function is monotonic. */
  220. private int
  221. fn_1ItSg_is_monotonic(const gs_function_t * pfn_common,
  222. const float *lower, const float *upper,
  223. gs_function_effort_t effort)
  224. {
  225. const gs_function_1ItSg_t *const pfn =
  226. (const gs_function_1ItSg_t *)pfn_common;
  227. float v0 = lower[0], v1 = upper[0];
  228. float d0 = pfn->params.Domain[0], d1 = pfn->params.Domain[1];
  229. int k = pfn->params.k;
  230. int i;
  231. int result = 0;
  232. if (v0 > d1 || v1 < d0)
  233. return_error(gs_error_rangecheck);
  234. if (v0 < d0)
  235. v0 = d0;
  236. if (v1 > d1)
  237. v1 = d1;
  238. for (i = 0; i < pfn->params.k; ++i) {
  239. float b0 = (i == 0 ? d0 : pfn->params.Bounds[i - 1]);
  240. float b1 = (i == k - 1 ? d1 : pfn->params.Bounds[i]);
  241. float e0, e1;
  242. float w0, w1;
  243. int code;
  244. if (v0 >= b1 || v1 <= b0)
  245. continue;
  246. e0 = pfn->params.Encode[2 * i];
  247. e1 = pfn->params.Encode[2 * i + 1];
  248. w0 = (max(v0, b0) - b0) * (e1 - e0) / (b1 - b0) + e0;
  249. w1 = (min(v1, b1) - b0) * (e1 - e0) / (b1 - b0) + e0;
  250. /* Note that w0 > w1 is now possible if e0 > e1. */
  251. if (w0 > w1) {
  252. code = gs_function_is_monotonic(pfn->params.Functions[i],
  253. &w1, &w0, effort);
  254. if (code <= 0)
  255. return code;
  256. /* Swap the INCREASING and DECREASING flags. */
  257. code = ((code & MASK1) << 1) | ((code & (MASK1 << 1)) >> 1);
  258. } else {
  259. code = gs_function_is_monotonic(pfn->params.Functions[i],
  260. &w0, &w1, effort);
  261. if (code <= 0)
  262. return code;
  263. }
  264. if (result == 0)
  265. result = code;
  266. else {
  267. result &= code;
  268. /* Check that result is still monotonic in every position. */
  269. code = result | ((result & MASK1) << 1) |
  270. ((result & (MASK1 << 1)) >> 1);
  271. if (code != (1 << (2 * pfn->params.n)) - 1)
  272. return 0;
  273. }
  274. }
  275. return result;
  276. }
  277. /* Return 1-Input Stitching function information. */
  278. private void
  279. fn_1ItSg_get_info(const gs_function_t *pfn_common, gs_function_info_t *pfi)
  280. {
  281. const gs_function_1ItSg_t *const pfn =
  282. (const gs_function_1ItSg_t *)pfn_common;
  283. gs_function_get_info_default(pfn_common, pfi);
  284. pfi->Functions = pfn->params.Functions;
  285. pfi->num_Functions = pfn->params.k;
  286. }
  287. /* Write 1-Input Stitching function parameters on a parameter list. */
  288. private int
  289. fn_1ItSg_get_params(const gs_function_t *pfn_common, gs_param_list *plist)
  290. {
  291. const gs_function_1ItSg_t *const pfn =
  292. (const gs_function_1ItSg_t *)pfn_common;
  293. int ecode = fn_common_get_params(pfn_common, plist);
  294. int code;
  295. if ((code = param_write_float_values(plist, "Bounds", pfn->params.Bounds,
  296. pfn->params.k - 1, false)) < 0)
  297. ecode = code;
  298. if ((code = param_write_float_values(plist, "Encode", pfn->params.Encode,
  299. 2 * pfn->params.k, false)) < 0)
  300. ecode = code;
  301. return ecode;
  302. }
  303. /* Free the parameters of a 1-Input Stitching function. */
  304. void
  305. gs_function_1ItSg_free_params(gs_function_1ItSg_params_t * params,
  306. gs_memory_t * mem)
  307. {
  308. gs_free_const_object(mem, params->Encode, "Encode");
  309. gs_free_const_object(mem, params->Bounds, "Bounds");
  310. fn_free_functions(params->Functions, params->k, mem);
  311. fn_common_free_params((gs_function_params_t *) params, mem);
  312. }
  313. /* Allocate and initialize a 1-Input Stitching function. */
  314. int
  315. gs_function_1ItSg_init(gs_function_t ** ppfn,
  316. const gs_function_1ItSg_params_t * params, gs_memory_t * mem)
  317. {
  318. static const gs_function_head_t function_1ItSg_head = {
  319. function_type_1InputStitching,
  320. {
  321. (fn_evaluate_proc_t) fn_1ItSg_evaluate,
  322. (fn_is_monotonic_proc_t) fn_1ItSg_is_monotonic,
  323. (fn_get_info_proc_t) fn_1ItSg_get_info,
  324. (fn_get_params_proc_t) fn_1ItSg_get_params,
  325. (fn_free_params_proc_t) gs_function_1ItSg_free_params,
  326. fn_common_free
  327. }
  328. };
  329. int n = (params->Range == 0 ? 0 : params->n);
  330. float prev = params->Domain[0];
  331. int i;
  332. *ppfn = 0; /* in case of error */
  333. for (i = 0; i < params->k; ++i) {
  334. const gs_function_t *psubfn = params->Functions[i];
  335. if (psubfn->params.m != 1)
  336. return_error(gs_error_rangecheck);
  337. if (n == 0)
  338. n = psubfn->params.n;
  339. else if (psubfn->params.n != n)
  340. return_error(gs_error_rangecheck);
  341. /* There are only k - 1 Bounds, not k. */
  342. if (i < params->k - 1) {
  343. if (params->Bounds[i] <= prev)
  344. return_error(gs_error_rangecheck);
  345. prev = params->Bounds[i];
  346. }
  347. }
  348. if (params->Domain[1] < prev)
  349. return_error(gs_error_rangecheck);
  350. fn_check_mnDR((const gs_function_params_t *)params, 1, n);
  351. {
  352. gs_function_1ItSg_t *pfn =
  353. gs_alloc_struct(mem, gs_function_1ItSg_t, &st_function_1ItSg,
  354. "gs_function_1ItSg_init");
  355. if (pfn == 0)
  356. return_error(gs_error_VMerror);
  357. pfn->params = *params;
  358. pfn->params.m = 1;
  359. pfn->params.n = n;
  360. pfn->head = function_1ItSg_head;
  361. pfn->head.is_monotonic =
  362. fn_domain_is_monotonic((gs_function_t *)pfn, EFFORT_MODERATE);
  363. *ppfn = (gs_function_t *) pfn;
  364. }
  365. return 0;
  366. }
  367. /* ---------------- Arrayed Output functions ---------------- */
  368. typedef struct gs_function_AdOt_s {
  369. gs_function_head_t head;
  370. gs_function_AdOt_params_t params;
  371. } gs_function_AdOt_t;
  372. private_st_function_AdOt();
  373. /* Evaluate an Arrayed Output function. */
  374. private int
  375. fn_AdOt_evaluate(const gs_function_t * pfn_common, const float *in, float *out)
  376. {
  377. const gs_function_AdOt_t *const pfn =
  378. (const gs_function_AdOt_t *)pfn_common;
  379. int i;
  380. for (i = 0; i < pfn->params.n; ++i) {
  381. int code =
  382. gs_function_evaluate(pfn->params.Functions[i], in, out + i);
  383. if (code < 0)
  384. return code;
  385. }
  386. return 0;
  387. }
  388. /* Test whether an Arrayed Output function is monotonic. */
  389. private int
  390. fn_AdOt_is_monotonic(const gs_function_t * pfn_common,
  391. const float *lower, const float *upper,
  392. gs_function_effort_t effort)
  393. {
  394. const gs_function_AdOt_t *const pfn =
  395. (const gs_function_AdOt_t *)pfn_common;
  396. int i, result;
  397. for (i = 0, result = 0; i < pfn->params.n; ++i) {
  398. int code =
  399. gs_function_is_monotonic(pfn->params.Functions[i], lower, upper,
  400. effort);
  401. if (code <= 0)
  402. return code;
  403. result |= code << (2 * i);
  404. }
  405. return result;
  406. }
  407. /* Free the parameters of an Arrayed Output function. */
  408. void
  409. gs_function_AdOt_free_params(gs_function_AdOt_params_t * params,
  410. gs_memory_t * mem)
  411. {
  412. fn_free_functions(params->Functions, params->n, mem);
  413. fn_common_free_params((gs_function_params_t *) params, mem);
  414. }
  415. /* Allocate and initialize an Arrayed Output function. */
  416. int
  417. gs_function_AdOt_init(gs_function_t ** ppfn,
  418. const gs_function_AdOt_params_t * params, gs_memory_t * mem)
  419. {
  420. static const gs_function_head_t function_AdOt_head = {
  421. function_type_ArrayedOutput,
  422. {
  423. (fn_evaluate_proc_t) fn_AdOt_evaluate,
  424. (fn_is_monotonic_proc_t) fn_AdOt_is_monotonic,
  425. gs_function_get_info_default, /****** WRONG ******/
  426. fn_common_get_params, /****** WHAT TO DO ABOUT THIS? ******/
  427. (fn_free_params_proc_t) gs_function_AdOt_free_params,
  428. fn_common_free
  429. }
  430. };
  431. int m = params->m, n = params->n;
  432. int i;
  433. int is_monotonic = 0; /* initialize to pacify compiler */
  434. *ppfn = 0; /* in case of error */
  435. if (m <= 0 || n <= 0)
  436. return_error(gs_error_rangecheck);
  437. for (i = 0; i < n; ++i) {
  438. const gs_function_t *psubfn = params->Functions[i];
  439. int sub_mono;
  440. if (psubfn->params.m != m || psubfn->params.n != 1)
  441. return_error(gs_error_rangecheck);
  442. sub_mono = fn_domain_is_monotonic(psubfn, EFFORT_MODERATE);
  443. if (i == 0 || sub_mono < 0)
  444. is_monotonic = sub_mono;
  445. else if (is_monotonic >= 0)
  446. is_monotonic &= sub_mono;
  447. }
  448. {
  449. gs_function_AdOt_t *pfn =
  450. gs_alloc_struct(mem, gs_function_AdOt_t, &st_function_AdOt,
  451. "gs_function_AdOt_init");
  452. if (pfn == 0)
  453. return_error(gs_error_VMerror);
  454. pfn->params = *params;
  455. pfn->params.Domain = 0;
  456. pfn->params.Range = 0;
  457. pfn->head = function_AdOt_head;
  458. pfn->head.is_monotonic = is_monotonic;
  459. *ppfn = (gs_function_t *) pfn;
  460. }
  461. return 0;
  462. }