aboutsummaryrefslogtreecommitdiff
path: root/pkg/images/imutil/src/t_imarith.x
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
commitfa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch)
treebdda434976bc09c864f2e4fa6f16ba1952b1e555 /pkg/images/imutil/src/t_imarith.x
downloadiraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz
Initial commit
Diffstat (limited to 'pkg/images/imutil/src/t_imarith.x')
-rw-r--r--pkg/images/imutil/src/t_imarith.x489
1 files changed, 489 insertions, 0 deletions
diff --git a/pkg/images/imutil/src/t_imarith.x b/pkg/images/imutil/src/t_imarith.x
new file mode 100644
index 00000000..6d5f6105
--- /dev/null
+++ b/pkg/images/imutil/src/t_imarith.x
@@ -0,0 +1,489 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include <error.h>
+include <lexnum.h>
+
+define ADD 1 # Opcodes.
+define SUB 2
+define MUL 3
+define DIV 4
+define MIN 5
+define MAX 6
+
+# T_IMARITH -- Simple image arithmetic.
+#
+# For each pixel in each image compute:
+#
+# operand1 op operand2 = result
+#
+# Do the operations as efficiently as possible. Allow operand1 or operand2
+# to be a constant. Allow resultant image to have the same name as an
+# operand image. Allow lists for the operands and the results.
+# Allow one of the operands to have extra dimensions but require that the
+# common dimensions are of the same length.
+
+procedure t_imarith ()
+
+int list1 # Operand1 list
+int list2 # Operand2 list
+int list3 # Result list
+int op # Operator
+bool verbose # Verbose option
+bool noact # Noact option
+double c1 # Constant for operand1
+double c2 # Constant for operand2
+double divzero # Zero divide replacement
+int pixtype # Output pixel datatype
+int calctype # Datatype for calculations
+
+int i, j, pixtype1, pixtype2
+short sc1, sc2, sdz
+int hlist
+double dval1, dval2
+pointer im1, im2, im3
+pointer sp, operand1, operand2, result, imtemp
+pointer opstr, dtstr, field, title, hparams
+
+int imtopenp(), imtgetim(), imtlen(), imofnlu(), imgnfn()
+double clgetd(), imgetd()
+bool clgetb(), streq()
+int clgwrd()
+int gctod(), lexnum()
+pointer immap()
+errchk immap, imgetd, imputd
+
+begin
+ # Allocate memory for strings.
+ call smark (sp)
+ call salloc (operand1, SZ_FNAME, TY_CHAR)
+ call salloc (operand2, SZ_FNAME, TY_CHAR)
+ call salloc (result, SZ_FNAME, TY_CHAR)
+ call salloc (imtemp, SZ_FNAME, TY_CHAR)
+ call salloc (opstr, SZ_FNAME, TY_CHAR)
+ call salloc (dtstr, SZ_FNAME, TY_CHAR)
+ call salloc (field, SZ_FNAME, TY_CHAR)
+ call salloc (title, SZ_IMTITLE, TY_CHAR)
+ call salloc (hparams, SZ_LINE, TY_CHAR)
+
+ # Get the operands and the operator.
+ list1 = imtopenp ("operand1")
+ op = clgwrd ("op", Memc[opstr], SZ_FNAME, ",+,-,*,/,min,max,")
+ list2 = imtopenp ("operand2")
+ list3 = imtopenp ("result")
+
+ # Get the rest of the options.
+ call clgstr ("hparams", Memc[hparams], SZ_LINE)
+ verbose = clgetb ("verbose")
+ noact = clgetb ("noact")
+ if (op == DIV)
+ divzero = clgetd ("divzero")
+
+ # Check the number of elements.
+ if (((imtlen (list1) != 1) && (imtlen (list1) != imtlen (list3))) ||
+ ((imtlen (list2) != 1) && (imtlen (list2) != imtlen (list3)))) {
+ call imtclose (list1)
+ call imtclose (list2)
+ call imtclose (list3)
+ call error (1, "Wrong number of elements in the operand lists")
+ }
+
+ # Do each operation.
+ while (imtgetim (list3, Memc[result], SZ_FNAME) != EOF) {
+ if (imtgetim (list1, Memc[imtemp], SZ_FNAME) != EOF)
+ call strcpy (Memc[imtemp], Memc[operand1], SZ_FNAME)
+ if (imtgetim (list2, Memc[imtemp], SZ_FNAME) != EOF)
+ call strcpy (Memc[imtemp], Memc[operand2], SZ_FNAME)
+
+ # Image sections in the output are not allowed.
+ call imgsection (Memc[result], Memc[field], SZ_FNAME)
+ if (Memc[field] != EOS) {
+ call eprintf (
+ "imarith: image sections in the output are not allowed (%s)\n")
+ call pargstr (Memc[result])
+ next
+ }
+
+ # To allow purely numeric file names first test if the operand
+ # is a file. If it is not then attempt to interpret the operand
+ # as a numerical constant. Otherwise it is an error.
+ iferr {
+ im1 = immap (Memc[operand1], READ_ONLY, 0)
+ pixtype1 = IM_PIXTYPE(im1)
+ } then {
+ i = 1
+ j = gctod (Memc[operand1], i, c1)
+ if ((Memc[operand1+i-1]!=EOS) && (Memc[operand1+i-1]!=' ')) {
+ call eprintf ("%s is not an image or a number\n")
+ call pargstr (Memc[operand1])
+ next
+ }
+
+ i = 1
+ pixtype1 = lexnum (Memc[operand1], i, j)
+ switch (pixtype1) {
+ case LEX_REAL:
+ pixtype1 = TY_REAL
+ default:
+ pixtype1 = TY_SHORT
+ }
+ im1 = NULL
+ }
+
+ iferr {
+ im2 = immap (Memc[operand2], READ_ONLY, 0)
+ pixtype2 = IM_PIXTYPE(im2)
+ } then {
+ i = 1
+ j = gctod (Memc[operand2], i, c2)
+ if ((Memc[operand2+i-1]!=EOS) && (Memc[operand2+i-1]!=' ')) {
+ call eprintf ("%s is not an image or a number\n")
+ call pargstr (Memc[operand2])
+ if (im1 != NULL)
+ call imunmap (im1)
+ next
+ }
+
+ i = 1
+ pixtype2 = lexnum (Memc[operand2], i, j)
+ switch (pixtype2) {
+ case LEX_REAL:
+ pixtype2 = TY_REAL
+ default:
+ pixtype2 = TY_SHORT
+ }
+ im2 = NULL
+ }
+
+ # Determine the output pixel datatype and calculation datatype.
+ call ima_set (pixtype1, pixtype2, op, pixtype, calctype)
+
+ # If verbose or noact print the operation.
+ if (verbose || noact) {
+ call printf ("IMARITH:\n Operation = %s\n")
+ call pargstr (Memc[opstr])
+ call printf (" Operand1 = %s\n Operand2 = %s\n")
+ call pargstr (Memc[operand1])
+ call pargstr (Memc[operand2])
+ call printf (" Result = %s\n Result pixel type = %s\n")
+ call pargstr (Memc[result])
+ call dtstring (pixtype, Memc[dtstr], SZ_FNAME)
+ call pargstr (Memc[dtstr])
+ call printf (" Calculation type = %s\n")
+ call dtstring (calctype, Memc[dtstr], SZ_FNAME)
+ call pargstr (Memc[dtstr])
+ if (op == DIV) {
+ call printf (
+ " Replacement value for division by zero = %g\n")
+ call pargd (divzero)
+ }
+ }
+
+ # Do the operation if the no act switch is not set.
+ if (!noact) {
+ # Check the two operands have the same dimension lengths
+ # over the same dimensions.
+ if ((im1 != NULL) && (im2 != NULL)) {
+ j = OK
+ do i = 1, min (IM_NDIM (im1), IM_NDIM (im2))
+ if (IM_LEN (im1, i) != IM_LEN (im2, i))
+ j = ERR
+ if (j == ERR) {
+ call imunmap (im1)
+ call imunmap (im2)
+ call eprintf (
+ "Input images have different dimensions\n")
+ next
+ }
+ }
+
+ # Create a temporary output image as a copy of one of the
+ # operand images (the one with the highest dimension).
+ # This allows the resultant image to have
+ # the same name as one of the operand images.
+ if ((im1 != NULL) && (im2 != NULL)) {
+ call xt_mkimtemp (Memc[operand1], Memc[result],
+ Memc[imtemp], SZ_FNAME)
+ if (streq (Memc[result], Memc[imtemp]))
+ call xt_mkimtemp (Memc[operand2], Memc[result],
+ Memc[imtemp], SZ_FNAME)
+ if (IM_NDIM(im1) >= IM_NDIM(im2))
+ im3 = immap (Memc[result], NEW_COPY, im1)
+ else
+ im3 = immap (Memc[result], NEW_COPY, im2)
+ } else if (im1 != NULL) {
+ call xt_mkimtemp (Memc[operand1], Memc[result],
+ Memc[imtemp], SZ_FNAME)
+ im3 = immap (Memc[result], NEW_COPY, im1)
+ } else if (im2 != NULL) {
+ call xt_mkimtemp (Memc[operand2], Memc[result],
+ Memc[imtemp], SZ_FNAME)
+ im3 = immap (Memc[result], NEW_COPY, im2)
+ } else
+ call error (0, "No operand images")
+
+ # Set the result image title and pixel datatype.
+ call clgstr ("title", Memc[title], SZ_IMTITLE)
+ if (Memc[title] != EOS)
+ call strcpy (Memc[title], IM_TITLE (im3), SZ_IMTITLE)
+ IM_PIXTYPE (im3) = pixtype
+
+ # Call the appropriate procedure to do the arithmetic
+ # efficiently.
+ switch (calctype) {
+ case TY_SHORT:
+ sc1 = c1
+ sc2 = c2
+ switch (op) {
+ case ADD:
+ call ima_adds (im1, im2, im3, sc1, sc2)
+ case SUB:
+ call ima_subs (im1, im2, im3, sc1, sc2)
+ case MUL:
+ call ima_muls (im1, im2, im3, sc1, sc2)
+ case DIV:
+ sdz = divzero
+ call ima_divs (im1, im2, im3, sc1, sc2, sdz)
+ case MIN:
+ call ima_mins (im1, im2, im3, sc1, sc2)
+ case MAX:
+ call ima_maxs (im1, im2, im3, sc1, sc2)
+ }
+ case TY_INT:
+ switch (op) {
+ case ADD:
+ call ima_addi (im1, im2, im3, int (c1), int (c2))
+ case SUB:
+ call ima_subi (im1, im2, im3, int (c1), int (c2))
+ case MUL:
+ call ima_muli (im1, im2, im3, int (c1), int (c2))
+ case DIV:
+ call ima_divi (im1, im2, im3, int (c1), int (c2),
+ int (divzero))
+ case MIN:
+ call ima_mini (im1, im2, im3, int (c1), int (c2))
+ case MAX:
+ call ima_maxi (im1, im2, im3, int (c1), int (c2))
+ }
+ case TY_LONG:
+ switch (op) {
+ case ADD:
+ call ima_addl (im1, im2, im3, long (c1), long (c2))
+ case SUB:
+ call ima_subl (im1, im2, im3, long (c1), long (c2))
+ case MUL:
+ call ima_mull (im1, im2, im3, long (c1), long (c2))
+ case DIV:
+ call ima_divl (im1, im2, im3, long (c1), long (c2),
+ long (divzero))
+ case MIN:
+ call ima_minl (im1, im2, im3, long (c1), long (c2))
+ case MAX:
+ call ima_maxl (im1, im2, im3, long (c1), long (c2))
+ }
+ case TY_REAL:
+ switch (op) {
+ case ADD:
+ call ima_addr (im1, im2, im3, real (c1), real (c2))
+ case SUB:
+ call ima_subr (im1, im2, im3, real (c1), real (c2))
+ case MUL:
+ call ima_mulr (im1, im2, im3, real (c1), real (c2))
+ case DIV:
+ call ima_divr (im1, im2, im3, real (c1), real (c2),
+ real (divzero))
+ case MIN:
+ call ima_minr (im1, im2, im3, real (c1), real (c2))
+ case MAX:
+ call ima_maxr (im1, im2, im3, real (c1), real (c2))
+ }
+ case TY_DOUBLE:
+ switch (op) {
+ case ADD:
+ call ima_addd (im1, im2, im3, double(c1), double(c2))
+ case SUB:
+ call ima_subd (im1, im2, im3, double(c1), double(c2))
+ case MUL:
+ call ima_muld (im1, im2, im3, double(c1), double(c2))
+ case DIV:
+ call ima_divd (im1, im2, im3, double(c1), double(c2),
+ double(divzero))
+ case MIN:
+ call ima_mind (im1, im2, im3, double(c1), double(c2))
+ case MAX:
+ call ima_maxd (im1, im2, im3, double(c1), double(c2))
+ }
+ }
+
+ # Do the header parameters.
+ iferr {
+ ifnoerr (dval1 = imgetd (im3, "CCDMEAN"))
+ call imdelf (im3, "CCDMEAN")
+
+ hlist = imofnlu (im3, Memc[hparams])
+ while (imgnfn (hlist, Memc[field], SZ_FNAME) != EOF) {
+ if (im1 != NULL)
+ dval1 = imgetd (im1, Memc[field])
+ else
+ dval1 = c1
+ if (im2 != NULL)
+ dval2 = imgetd (im2, Memc[field])
+ else
+ dval2 = c2
+
+ switch (op) {
+ case ADD:
+ call imputd (im3, Memc[field], dval1 + dval2)
+ case SUB:
+ call imputd (im3, Memc[field], dval1 - dval2)
+ case MUL:
+ call imputd (im3, Memc[field], dval1 * dval2)
+ case DIV:
+ if (dval2 == 0.) {
+ call eprintf (
+ "WARNING: Division by zero in header keyword (%s)\n")
+ call pargstr (Memc[field])
+ } else
+ call imputd (im3, Memc[field], dval1 / dval2)
+ case MIN:
+ call imputd (im3, Memc[field], min (dval1, dval2))
+ case MAX:
+ call imputd (im3, Memc[field], max (dval1, dval2))
+ }
+ }
+ call imcfnl (hlist)
+ } then
+ call erract (EA_WARN)
+ }
+
+ # Unmap images and release the temporary output image.
+ if (im1 != NULL)
+ call imunmap (im1)
+ if (im2 != NULL)
+ call imunmap (im2)
+ if (!noact) {
+ call imunmap (im3)
+ call xt_delimtemp (Memc[result], Memc[imtemp])
+ }
+ }
+
+ call imtclose (list1)
+ call imtclose (list2)
+ call imtclose (list3)
+ call sfree (sp)
+end
+
+
+# IMA_SET -- Determine the output image pixel type and the calculation
+# datatype. The default pixel types are based on the highest arithmetic
+# precendence of the input images or constants. Division requires
+# a minimum of real.
+
+procedure ima_set (pixtype1, pixtype2, op, pixtype, calctype)
+
+int pixtype1 # Pixel datatype of operand 1
+int pixtype2 # Pixel datatype of operand 2
+int pixtype # Pixel datatype of resultant image
+int op # Operation
+int calctype # Pixel datatype for calculations
+
+char line[1]
+int max_type
+
+begin
+ # Determine maximum precedence datatype.
+ switch (pixtype1) {
+ case TY_SHORT:
+ if (op == DIV)
+ max_type = TY_REAL
+ else if (pixtype2 == TY_USHORT)
+ max_type = TY_LONG
+ else
+ max_type = pixtype2
+ case TY_USHORT:
+ if (op == DIV)
+ max_type = TY_REAL
+ else if ((pixtype2 == TY_SHORT) || (pixtype2 == TY_USHORT))
+ max_type = TY_LONG
+ else
+ max_type = pixtype2
+ case TY_INT:
+ if (op == DIV)
+ max_type = TY_REAL
+ else if ((pixtype2 == TY_SHORT) || (pixtype2 == TY_USHORT))
+ max_type = pixtype1
+ else
+ max_type = pixtype2
+ case TY_LONG:
+ if (op == DIV)
+ max_type = TY_REAL
+ else if ((pixtype2 == TY_SHORT) || (pixtype2 == TY_USHORT) ||
+ (pixtype2 == TY_INT))
+ max_type = pixtype1
+ else
+ max_type = pixtype2
+ case TY_REAL:
+ if (pixtype2 == TY_DOUBLE)
+ max_type = pixtype2
+ else
+ max_type = pixtype1
+ case TY_DOUBLE:
+ max_type = pixtype1
+ }
+
+ # Set calculation datatype.
+ call clgstr ("calctype", line, 1)
+ switch (line[1]) {
+ case '1':
+ if (pixtype1 == TY_USHORT)
+ calctype = TY_LONG
+ else
+ calctype = pixtype1
+ case '2':
+ if (pixtype2 == TY_USHORT)
+ calctype = TY_LONG
+ else
+ calctype = pixtype2
+ case EOS:
+ calctype = max_type
+ case 's':
+ calctype = TY_SHORT
+ case 'u':
+ calctype = TY_LONG
+ case 'i':
+ calctype = TY_INT
+ case 'l':
+ calctype = TY_LONG
+ case 'r':
+ calctype = TY_REAL
+ case 'd':
+ calctype = TY_DOUBLE
+ default:
+ call error (6, "Unrecognized datatype")
+ }
+
+ # Set output pixel datatype.
+ call clgstr ("pixtype", line, 1)
+ switch (line[1]) {
+ case '1':
+ pixtype = pixtype1
+ case '2':
+ pixtype = pixtype2
+ case EOS:
+ pixtype = calctype
+ case 's':
+ pixtype = TY_SHORT
+ case 'u':
+ pixtype = TY_USHORT
+ case 'i':
+ pixtype = TY_INT
+ case 'l':
+ pixtype = TY_LONG
+ case 'r':
+ pixtype = TY_REAL
+ case 'd':
+ pixtype = TY_DOUBLE
+ default:
+ call error (6, "Unrecognized dataype")
+ }
+end