1 /* math2.c --- 2ary math funcs
2  *
3  * Copyright: 1990, N. Dessipris
4  *
5  * Author: Nicos Dessipris
6  * Written on: 02/05/1990
7  * Modified on:
8  * 10/12/93 JC
9  *	- now reports total number of x/0, rather than each one.
10  * 1/2/95 JC
11  *	- rewritten for PIO with im_wrapone()
12  *	- incorrect complex code removed
13  *	- /0 reporting removed for ease of programming
14  * 15/4/97 JC
15  *	- return( 0 ) missing, oops!
16  * 6/7/98 JC
17  *	- _vec form added
18  * 30/8/09
19  * 	- gtkdoc
20  * 	- tiny cleanups
21  * 20/9/09
22  * 	- im_powtra() adapated to make math2.c
23  * 12/11/11
24  * 	- redone as a class
25  * 17/7/12
26  * 	- wopconst was broken
27  * 20/10/21 indus
28  * 	- add atan2
29  */
30 
31 /*
32 
33     Copyright (C) 1991-2005 The National Gallery
34 
35     This library is free software; you can redistribute it and/or
36     modify it under the terms of the GNU Lesser General Public
37     License as published by the Free Software Foundation; either
38     version 2.1 of the License, or (at your option) any later version.
39 
40     This library is distributed in the hope that it will be useful,
41     but WITHOUT ANY WARRANTY; without even the implied warranty of
42     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
43     Lesser General Public License for more details.
44 
45     You should have received a copy of the GNU Lesser General Public
46     License along with this library; if not, write to the Free Software
47     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
48     02110-1301  USA
49 
50  */
51 
52 /*
53 
54     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
55 
56  */
57 
58 /*
59 #define DEBUG
60  */
61 
62 #ifdef HAVE_CONFIG_H
63 #include <config.h>
64 #endif /*HAVE_CONFIG_H*/
65 #include <vips/intl.h>
66 
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <math.h>
70 
71 #include <vips/vips.h>
72 
73 #include "binary.h"
74 #include "unaryconst.h"
75 
76 typedef struct _VipsMath2 {
77 	VipsBinary parent_instance;
78 
79 	VipsOperationMath2 math2;
80 
81 } VipsMath2;
82 
83 typedef VipsBinaryClass VipsMath2Class;
84 
85 G_DEFINE_TYPE( VipsMath2, vips_math2, VIPS_TYPE_BINARY );
86 
87 static int
vips_math2_build(VipsObject * object)88 vips_math2_build( VipsObject *object )
89 {
90 	VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
91 	VipsBinary *binary = (VipsBinary *) object;
92 
93 	if( binary->left &&
94 		vips_check_noncomplex( class->nickname, binary->left ) )
95 		return( -1 );
96 	if( binary->right &&
97 		vips_check_noncomplex( class->nickname, binary->right ) )
98 		return( -1 );
99 
100 	if( VIPS_OBJECT_CLASS( vips_math2_parent_class )->build( object ) )
101 		return( -1 );
102 
103 	return( 0 );
104 }
105 
106 #define LOOP( IN, OUT, OP ) { \
107 	IN * restrict p1 = (IN *) in[0]; \
108 	IN * restrict p2 = (IN *) in[1]; \
109 	OUT * restrict q = (OUT *) out; \
110 	\
111 	for( x = 0; x < sz; x++ ) \
112 		OP( q[x], p1[x], p2[x] ); \
113 }
114 
115 #define SWITCH( L, OP ) \
116 	switch( vips_image_get_format( im ) ) { \
117 	case VIPS_FORMAT_UCHAR: \
118 		L( unsigned char, float, OP ); break; \
119 	case VIPS_FORMAT_CHAR: \
120 		L( signed char, float, OP ); break; \
121 	case VIPS_FORMAT_USHORT: \
122 		L( unsigned short, float, OP ); break; \
123 	case VIPS_FORMAT_SHORT: \
124 		L( signed short, float, OP ); break; \
125 	case VIPS_FORMAT_UINT: \
126 		L( unsigned int, float, OP ); break; \
127 	case VIPS_FORMAT_INT: \
128 		L( signed int, float, OP ); break; \
129 	case VIPS_FORMAT_FLOAT: \
130 		L( float, float, OP ); break; \
131 	case VIPS_FORMAT_DOUBLE: \
132 		L( double, double, OP ); break;\
133  	\
134 	default: \
135 		g_assert_not_reached(); \
136 	}
137 
138 #define POW( Y, X, E ) { \
139 	double left = (double) (X); \
140 	double right = (double) (E); \
141 	\
142 	/* Special case for **-1 and **0.5, since they are so common. Also \
143 	 * watch for /0. \
144 	 */ \
145 	(Y) = (left == 0.0) \
146 		? 0.0 \
147 		: (right == -1) \
148 			? 1.0 / left \
149 			: (right == 0.5) \
150 				? sqrt( left ) \
151 				: pow( left, right ); \
152 }
153 
154 #define WOP( Y, X, E ) POW( Y, E, X )
155 
156 #ifdef HAVE_ATAN2
157 #define ATAN2( Y, L, R ) { \
158 	double left = (double) (L); \
159 	double right = (double) (R); \
160 	\
161 	(Y) = VIPS_DEG( atan2( left, right ) ); \
162 	if( (Y) < 0.0 ) \
163 		(Y) += 360; \
164 }
165 #else
166 #define ATAN2( Y, L, R ) { \
167 	double left = (double) (L); \
168 	double right = (double) (R); \
169 	\
170 	(Y) = vips_col_ab2h( left, right ); \
171 }
172 #endif
173 
174 static void
vips_math2_buffer(VipsArithmetic * arithmetic,VipsPel * out,VipsPel ** in,int width)175 vips_math2_buffer( VipsArithmetic *arithmetic,
176 	VipsPel *out, VipsPel **in, int width )
177 {
178 	VipsMath2 *math2 = (VipsMath2 *) arithmetic;
179 	VipsImage *im = arithmetic->ready[0];
180 	const int sz = width * vips_image_get_bands( im );
181 
182 	int x;
183 
184 	switch( math2->math2 ) {
185 	case VIPS_OPERATION_MATH2_POW: 	SWITCH( LOOP, POW ); break;
186 	case VIPS_OPERATION_MATH2_WOP: 	SWITCH( LOOP, WOP ); break;
187 	case VIPS_OPERATION_MATH2_ATAN2: 	SWITCH( LOOP, ATAN2 ); break;
188 
189         default:
190 		g_assert_not_reached();
191         }
192 }
193 
194 /* Save a bit of typing.
195  */
196 #define UC VIPS_FORMAT_UCHAR
197 #define C VIPS_FORMAT_CHAR
198 #define US VIPS_FORMAT_USHORT
199 #define S VIPS_FORMAT_SHORT
200 #define UI VIPS_FORMAT_UINT
201 #define I VIPS_FORMAT_INT
202 #define F VIPS_FORMAT_FLOAT
203 #define X VIPS_FORMAT_COMPLEX
204 #define D VIPS_FORMAT_DOUBLE
205 #define DX VIPS_FORMAT_DPCOMPLEX
206 
207 /* Type promotion for math2. Keep in sync with math2_buffer() above.
208  */
209 static int vips_math2_format_table[10] = {
210 /* UC  C   US  S   UI  I   F   X   D   DX */
211    F,  F,  F,  F,  F,  F,  F,  X,  D,  DX
212 };
213 
214 static void
vips_math2_class_init(VipsMath2Class * class)215 vips_math2_class_init( VipsMath2Class *class )
216 {
217 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
218 	VipsObjectClass *object_class = (VipsObjectClass *) class;
219 	VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS( class );
220 
221 	gobject_class->set_property = vips_object_set_property;
222 	gobject_class->get_property = vips_object_get_property;
223 
224 	object_class->nickname = "math2";
225 	object_class->description = _( "binary math operations" );
226 	object_class->build = vips_math2_build;
227 
228 	aclass->process_line = vips_math2_buffer;
229 
230 	vips_arithmetic_set_format_table( aclass, vips_math2_format_table );
231 
232 	VIPS_ARG_ENUM( class, "math2", 200,
233 		_( "Operation" ),
234 		_( "math to perform" ),
235 		VIPS_ARGUMENT_REQUIRED_INPUT,
236 		G_STRUCT_OFFSET( VipsMath2, math2 ),
237 		VIPS_TYPE_OPERATION_MATH2, VIPS_OPERATION_MATH2_POW );
238 }
239 
240 static void
vips_math2_init(VipsMath2 * math2)241 vips_math2_init( VipsMath2 *math2 )
242 {
243 }
244 
245 static int
vips_math2v(VipsImage * left,VipsImage * right,VipsImage ** out,VipsOperationMath2 math2,va_list ap)246 vips_math2v( VipsImage *left, VipsImage *right, VipsImage **out,
247 	VipsOperationMath2 math2, va_list ap )
248 {
249 	return( vips_call_split( "math2", ap, left, right, out, math2 ) );
250 }
251 
252 /**
253  * vips_math2:
254  * @left: left-hand input #VipsImage
255  * @right: right-hand input #VipsImage
256  * @out: (out): output #VipsImage
257  * @math2: math operation to perform
258  * @...: %NULL-terminated list of optional named arguments
259  *
260  * This operation calculates a 2-ary maths operation on a pair of images
261  * and writes the result to @out. The images may have any
262  * non-complex format. @out is float except in the case that either of @left
263  * or @right are double, in which case @out is also double.
264  *
265  * It detects division by zero, setting those pixels to zero in the output.
266  * Beware: it does this silently!
267  *
268  * If the images differ in size, the smaller image is enlarged to match the
269  * larger by adding zero pixels along the bottom and right.
270  *
271  * If the number of bands differs, one of the images
272  * must have one band. In this case, an n-band image is formed from the
273  * one-band image by joining n copies of the one-band image together, and then
274  * the two n-band images are operated upon.
275  *
276  * The two input images are cast up to the smallest common format (see table
277  * Smallest common format in
278  * <link linkend="libvips-arithmetic">arithmetic</link>), and that format is the
279  * result type.
280  *
281  * See also: vips_math2_const().
282  *
283  * Returns: 0 on success, -1 on error
284  */
285 int
vips_math2(VipsImage * left,VipsImage * right,VipsImage ** out,VipsOperationMath2 math2,...)286 vips_math2( VipsImage *left, VipsImage *right, VipsImage **out,
287 	VipsOperationMath2 math2, ... )
288 {
289 	va_list ap;
290 	int result;
291 
292 	va_start( ap, math2 );
293 	result = vips_math2v( left, right, out, math2, ap );
294 	va_end( ap );
295 
296 	return( result );
297 }
298 
299 /**
300  * vips_pow:
301  * @left: left-hand input #VipsImage
302  * @right: right-hand input #VipsImage
303  * @out: (out): output #VipsImage
304  * @...: %NULL-terminated list of optional named arguments
305  *
306  * Perform #VIPS_OPERATION_MATH2_POW on a pair of images. See
307  * vips_math2().
308  *
309  * Returns: 0 on success, -1 on error
310  */
311 int
vips_pow(VipsImage * left,VipsImage * right,VipsImage ** out,...)312 vips_pow( VipsImage *left, VipsImage *right, VipsImage **out, ... )
313 {
314 	va_list ap;
315 	int result;
316 
317 	va_start( ap, out );
318 	result = vips_math2v( left, right, out, VIPS_OPERATION_MATH2_POW, ap );
319 	va_end( ap );
320 
321 	return( result );
322 }
323 
324 /**
325  * vips_wop:
326  * @left: left-hand input #VipsImage
327  * @right: right-hand input #VipsImage
328  * @out: (out): output #VipsImage
329  * @...: %NULL-terminated list of optional named arguments
330  *
331  * Perform #VIPS_OPERATION_MATH2_WOP on a pair of images. See
332  * vips_math2().
333  *
334  * Returns: 0 on success, -1 on error
335  */
336 int
vips_wop(VipsImage * left,VipsImage * right,VipsImage ** out,...)337 vips_wop( VipsImage *left, VipsImage *right, VipsImage **out, ... )
338 {
339 	va_list ap;
340 	int result;
341 
342 	va_start( ap, out );
343 	result = vips_math2v( left, right, out, VIPS_OPERATION_MATH2_WOP, ap );
344 	va_end( ap );
345 
346 	return( result );
347 }
348 
349 /**
350  * vips_atan2:
351  * @left: left-hand input #VipsImage
352  * @right: right-hand input #VipsImage
353  * @out: (out): output #VipsImage
354  * @...: %NULL-terminated list of optional named arguments
355  *
356  * Perform #VIPS_OPERATION_MATH2_ATAN2 on a pair of images. See
357  * vips_math2().
358  *
359  * Returns: 0 on success, -1 on error
360  */
361 int
vips_atan2(VipsImage * left,VipsImage * right,VipsImage ** out,...)362 vips_atan2( VipsImage *left, VipsImage *right, VipsImage **out, ... )
363 {
364 	va_list ap;
365 	int result;
366 
367 	va_start( ap, out );
368 	result = vips_math2v( left, right, out, VIPS_OPERATION_MATH2_ATAN2, ap );
369 	va_end( ap );
370 
371 	return( result );
372 }
373 
374 
375 typedef struct _VipsMath2Const {
376 	VipsUnaryConst parent_instance;
377 
378 	VipsOperationMath2 math2;
379 
380 } VipsMath2Const;
381 
382 typedef VipsUnaryConstClass VipsMath2ConstClass;
383 
384 G_DEFINE_TYPE( VipsMath2Const,
385 	vips_math2_const, VIPS_TYPE_UNARY_CONST );
386 
387 static int
vips_math2_const_build(VipsObject * object)388 vips_math2_const_build( VipsObject *object )
389 {
390 	VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
391 	VipsUnary *unary = (VipsUnary *) object;
392 
393 	if( unary->in &&
394 		vips_check_noncomplex( class->nickname, unary->in ) )
395 		return( -1 );
396 
397 	if( VIPS_OBJECT_CLASS( vips_math2_const_parent_class )->
398 		build( object ) )
399 		return( -1 );
400 
401 	return( 0 );
402 }
403 
404 #define LOOPC( IN, OUT, OP ) { \
405 	IN * restrict p = (IN *) in[0]; \
406 	OUT * restrict q = (OUT *) out; \
407 	double * restrict c = uconst->c_double; \
408 	\
409 	for( i = 0, x = 0; x < width; x++ ) \
410 		for( b = 0; b < bands; b++, i++ ) \
411 			OP( q[i], p[i], c[b] ); \
412 }
413 
414 static void
vips_math2_const_buffer(VipsArithmetic * arithmetic,VipsPel * out,VipsPel ** in,int width)415 vips_math2_const_buffer( VipsArithmetic *arithmetic,
416 	VipsPel *out, VipsPel **in, int width )
417 {
418 	VipsUnaryConst *uconst = (VipsUnaryConst *) arithmetic;
419 	VipsMath2Const *math2 = (VipsMath2Const *) arithmetic;
420 	VipsImage *im = arithmetic->ready[0];
421 	int bands = im->Bands;
422 
423 	int i, x, b;
424 
425 	switch( math2->math2 ) {
426 	case VIPS_OPERATION_MATH2_POW:
427 		SWITCH( LOOPC, POW );
428 		break;
429 
430 	case VIPS_OPERATION_MATH2_WOP:
431 		SWITCH( LOOPC, WOP );
432 		break;
433 
434 	case VIPS_OPERATION_MATH2_ATAN2:
435 		SWITCH( LOOPC, ATAN2 );
436 		break;
437 
438         default:
439 		g_assert_not_reached();
440 		break;
441         }
442 }
443 
444 static void
vips_math2_const_class_init(VipsMath2ConstClass * class)445 vips_math2_const_class_init( VipsMath2ConstClass *class )
446 {
447 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
448 	VipsObjectClass *object_class = (VipsObjectClass *) class;
449 	VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS( class );
450 
451 	gobject_class->set_property = vips_object_set_property;
452 	gobject_class->get_property = vips_object_get_property;
453 
454 	object_class->nickname = "math2_const";
455 	object_class->description =
456 		_( "binary math operations with a constant" );
457 	object_class->build = vips_math2_const_build;
458 
459 	aclass->process_line = vips_math2_const_buffer;
460 
461 	vips_arithmetic_set_format_table( aclass, vips_math2_format_table );
462 
463 	VIPS_ARG_ENUM( class, "math2", 200,
464 		_( "Operation" ),
465 		_( "math to perform" ),
466 		VIPS_ARGUMENT_REQUIRED_INPUT,
467 		G_STRUCT_OFFSET( VipsMath2Const, math2 ),
468 		VIPS_TYPE_OPERATION_MATH2, VIPS_OPERATION_MATH2_POW );
469 }
470 
471 static void
vips_math2_const_init(VipsMath2Const * math2_const)472 vips_math2_const_init( VipsMath2Const *math2_const )
473 {
474 }
475 
476 static int
vips_math2_constv(VipsImage * in,VipsImage ** out,VipsOperationMath2 math2,const double * c,int n,va_list ap)477 vips_math2_constv( VipsImage *in, VipsImage **out,
478 	VipsOperationMath2 math2, const double *c, int n, va_list ap )
479 {
480 	VipsArea *area_c;
481 	double *array;
482 	int result;
483 	int i;
484 
485 	area_c = vips_area_new_array( G_TYPE_DOUBLE, sizeof( double ), n );
486 	array = (double *) area_c->data;
487 	for( i = 0; i < n; i++ )
488 		array[i] = c[i];
489 
490 	result = vips_call_split( "math2_const", ap, in, out, math2, area_c );
491 
492 	vips_area_unref( area_c );
493 
494 	return( result );
495 }
496 
497 /**
498  * vips_math2_const: (method)
499  * @in: input image
500  * @out: (out): output image
501  * @math2: math operation to perform
502  * @c: (array length=n): array of constants
503  * @n: number of constants in @c
504  * @...: %NULL-terminated list of optional named arguments
505  *
506  * This operation calculates various 2-ary maths operations on an image and
507  * an array of constants and writes the result to @out.
508  * The image may have any
509  * non-complex format. @out is float except in the case that @in
510  * is double, in which case @out is also double.
511  *
512  * It detects division by zero, setting those pixels to zero in the output.
513  * Beware: it does this silently!
514  *
515  * If the array of constants has just one element, that constant is used for
516  * all image bands. If the array has more than one element and they have
517  * the same number of elements as there are bands in the image, then
518  * one array element is used for each band. If the arrays have more than one
519  * element and the image only has a single band, the result is a many-band
520  * image where each band corresponds to one array element.
521  *
522  * See also: vips_math2(), vips_math().
523  *
524  * Returns: 0 on success, -1 on error
525  */
526 int
vips_math2_const(VipsImage * in,VipsImage ** out,VipsOperationMath2 math2,const double * c,int n,...)527 vips_math2_const( VipsImage *in, VipsImage **out,
528 	VipsOperationMath2 math2, const double *c, int n, ... )
529 {
530 	va_list ap;
531 	int result;
532 
533 	va_start( ap, n );
534 	result = vips_math2_constv( in, out, math2, c, n, ap );
535 	va_end( ap );
536 
537 	return( result );
538 }
539 
540 /**
541  * vips_pow_const: (method)
542  * @in: left-hand input #VipsImage
543  * @out: (out): output #VipsImage
544  * @c: (array length=n): array of constants
545  * @n: number of constants in @c
546  * @...: %NULL-terminated list of optional named arguments
547  *
548  * Perform #VIPS_OPERATION_MATH2_POW on an image and a constant. See
549  * vips_math2_const().
550  *
551  * Returns: 0 on success, -1 on error
552  */
553 int
vips_pow_const(VipsImage * in,VipsImage ** out,const double * c,int n,...)554 vips_pow_const( VipsImage *in, VipsImage **out, const double *c, int n, ... )
555 {
556 	va_list ap;
557 	int result;
558 
559 	va_start( ap, n );
560 	result = vips_math2_constv( in, out,
561 		VIPS_OPERATION_MATH2_POW, c, n, ap );
562 	va_end( ap );
563 
564 	return( result );
565 }
566 
567 /**
568  * vips_wop_const: (method)
569  * @in: left-hand input #VipsImage
570  * @out: (out): output #VipsImage
571  * @c: (array length=n): array of constants
572  * @n: number of constants in @c
573  * @...: %NULL-terminated list of optional named arguments
574  *
575  * Perform #VIPS_OPERATION_MATH2_WOP on an image and a constant. See
576  * vips_math2_const().
577  *
578  * Returns: 0 on success, -1 on error
579  */
580 int
vips_wop_const(VipsImage * in,VipsImage ** out,const double * c,int n,...)581 vips_wop_const( VipsImage *in, VipsImage **out, const double *c, int n, ... )
582 {
583 	va_list ap;
584 	int result;
585 
586 	va_start( ap, n );
587 	result = vips_math2_constv( in, out,
588 		VIPS_OPERATION_MATH2_WOP, c, n, ap );
589 	va_end( ap );
590 
591 	return( result );
592 }
593 
594 /**
595  * vips_atan2_const: (method)
596  * @in: left-hand input #VipsImage
597  * @out: (out): output #VipsImage
598  * @c: (array length=n): array of constants
599  * @n: number of constants in @c
600  * @...: %NULL-terminated list of optional named arguments
601  *
602  * Perform #VIPS_OPERATION_MATH2_ATAN2 on an image and a constant. See
603  * vips_math2_const().
604  *
605  * Returns: 0 on success, -1 on error
606  */
607 int
vips_atan2_const(VipsImage * in,VipsImage ** out,const double * c,int n,...)608 vips_atan2_const( VipsImage *in, VipsImage **out, const double *c, int n, ... )
609 {
610 	va_list ap;
611 	int result;
612 
613 	va_start( ap, n );
614 	result = vips_math2_constv( in, out,
615 		VIPS_OPERATION_MATH2_ATAN2, c, n, ap );
616 	va_end( ap );
617 
618 	return( result );
619 }
620 
621 /**
622  * vips_math2_const1: (method)
623  * @in: input image
624  * @out: (out): output image
625  * @math2: math operation to perform
626  * @c: constant
627  * @...: %NULL-terminated list of optional named arguments
628  *
629  * This operation calculates various 2-ary maths operations on an image and
630  * a constant. See vips_math2_const().
631  *
632  * Returns: 0 on success, -1 on error
633  */
634 int
vips_math2_const1(VipsImage * in,VipsImage ** out,VipsOperationMath2 math2,double c,...)635 vips_math2_const1( VipsImage *in, VipsImage **out,
636 	VipsOperationMath2 math2, double c, ... )
637 {
638 	va_list ap;
639 	int result;
640 
641 	va_start( ap, c );
642 	result = vips_math2_constv( in, out, math2, &c, 1, ap );
643 	va_end( ap );
644 
645 	return( result );
646 }
647 
648 /**
649  * vips_pow_const1: (method)
650  * @in: left-hand input #VipsImage
651  * @out: (out): output #VipsImage
652  * @c: constant
653  * @...: %NULL-terminated list of optional named arguments
654  *
655  * Perform #VIPS_OPERATION_MATH2_POW on an image and a constant. See
656  * vips_math2_const().
657  *
658  * Returns: 0 on success, -1 on error
659  */
660 int
vips_pow_const1(VipsImage * in,VipsImage ** out,double c,...)661 vips_pow_const1( VipsImage *in, VipsImage **out, double c, ... )
662 {
663 	va_list ap;
664 	int result;
665 
666 	va_start( ap, c );
667 	result = vips_math2_constv( in, out,
668 		VIPS_OPERATION_MATH2_POW, &c, 1, ap );
669 	va_end( ap );
670 
671 	return( result );
672 }
673 
674 /**
675  * vips_wop_const1: (method)
676  * @in: left-hand input #VipsImage
677  * @out: (out): output #VipsImage
678  * @c: constant
679  * @...: %NULL-terminated list of optional named arguments
680  *
681  * Perform #VIPS_OPERATION_MATH2_WOP on an image and a constant. See
682  * vips_math2_const().
683  *
684  * Returns: 0 on success, -1 on error
685  */
686 int
vips_wop_const1(VipsImage * in,VipsImage ** out,double c,...)687 vips_wop_const1( VipsImage *in, VipsImage **out, double c, ... )
688 {
689 	va_list ap;
690 	int result;
691 
692 	va_start( ap, c );
693 	result = vips_math2_constv( in, out,
694 		VIPS_OPERATION_MATH2_WOP, &c, 1, ap );
695 	va_end( ap );
696 
697 	return( result );
698 }
699 
700 /**
701  * vips_atan2_const1: (method)
702  * @in: left-hand input #VipsImage
703  * @out: (out): output #VipsImage
704  * @c: constant
705  * @...: %NULL-terminated list of optional named arguments
706  *
707  * Perform #VIPS_OPERATION_MATH2_ATAN2 on an image and a constant. See
708  * vips_math2_const().
709  *
710  * Returns: 0 on success, -1 on error
711  */
712 int
vips_atan2_const1(VipsImage * in,VipsImage ** out,double c,...)713 vips_atan2_const1( VipsImage *in, VipsImage **out, double c, ... )
714 {
715 	va_list ap;
716 	int result;
717 
718 	va_start( ap, c );
719 	result = vips_math2_constv( in, out,
720 		VIPS_OPERATION_MATH2_ATAN2, &c, 1, ap );
721 	va_end( ap );
722 
723 	return( result );
724 }
725