GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/unrrdu/2op.c Lines: 19 53 35.8 %
Date: 2017-05-26 Branches: 1 40 2.5 %

Line Branch Exec Source
1
/*
2
  Teem: Tools to process and visualize scientific data and images             .
3
  Copyright (C) 2013, 2012, 2011, 2010, 2009  University of Chicago
4
  Copyright (C) 2008, 2007, 2006, 2005  Gordon Kindlmann
5
  Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998  University of Utah
6
7
  This library is free software; you can redistribute it and/or
8
  modify it under the terms of the GNU Lesser General Public License
9
  (LGPL) as published by the Free Software Foundation; either
10
  version 2.1 of the License, or (at your option) any later version.
11
  The terms of redistributing and/or modifying this software also
12
  include exceptions to the LGPL that facilitate static linking.
13
14
  This library is distributed in the hope that it will be useful,
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
  Lesser General Public License for more details.
18
19
  You should have received a copy of the GNU Lesser General Public License
20
  along with this library; if not, write to Free Software Foundation, Inc.,
21
  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
*/
23
24
#include "unrrdu.h"
25
#include "privateUnrrdu.h"
26
27
#define INFO "Binary operation on two nrrds, or on a nrrd and a constant"
28
static const char *_unrrdu_2opInfoL =
29
(INFO
30
 ". Either the first or second operand can be a float constant, "
31
 "but not both.  Use \"-\" for an operand to signify "
32
 "a nrrd to be read from stdin (a pipe).  Note, however, "
33
 "that \"-\" can probably only be used once (reliably).\n "
34
 "* Uses nrrdArithIterBinaryOp or (with -w) nrrdArithIterBinaryOpSelect");
35
36
int
37
unrrdu_2opMain(int argc, const char **argv, const char *me,
38
               hestParm *hparm) {
39
2
  hestOpt *opt = NULL;
40
1
  char *out, *err, *seedS;
41
1
  NrrdIter *in1, *in2;
42
  Nrrd *nout, *ntmp=NULL;
43
1
  int op, type, E, pret, which;
44
  airArray *mop;
45
1
  unsigned int seed;
46
47
1
  hestOptAdd(&opt, NULL, "operator", airTypeEnum, 1, 1, &op, NULL,
48
             "Binary operator. Possibilities include:\n "
49
             "\b\bo \"+\", \"-\", \"x\", \"/\": "
50
             "add, subtract, multiply, divide\n "
51
             "\b\bo \"+c\", \"-c\", \"xc\": add, subtract, multiply, with "
52
             "clamping to range of output, in case its integral\n "
53
             "\b\bo \"^\": exponentiation (pow)\n "
54
             "\b\bo \"spow\": signed exponentiation: sgn(x)pow(abs(x),p)\n "
55
             "\b\bo \"fpow\": like spow but with curves flipped\n "
56
             "\b\bo \"%\": integer modulo\n "
57
             "\b\bo \"fmod\": same as fmod() in C\n "
58
             "\b\bo \"atan2\": same as atan2() in C\n "
59
             "\b\bo \"min\", \"max\": minimum, maximum\n "
60
             "\b\bo \"lt\", \"lte\", \"gt\", \"gte\": same as C's <, <=, >, <=\n "
61
             "\b\bo \"eq\", \"neq\": same as C's == and !=\n "
62
             "\b\bo \"comp\": -1, 0, or 1 if 1st value is less than, "
63
             "equal to, or greater than 2nd value\n "
64
             "\b\bo \"if\": if 1st value is non-zero, use it, "
65
             "else use 2nd value\n "
66
             "\b\bo \"exists\": if 1st value exists, use it, "
67
             "else use 2nd value\n "
68
             "\b\bo \"nrand\": scale unit-stdv Gaussian noise by 2nd value "
69
             "and add to first value\n "
70
             "\b\bo \"rrand\": sample Rician distribution with 1st value "
71
             "for \"true\" mean, and 2nd value for sigma",
72
1
             NULL, nrrdBinaryOp);
73
1
  hestOptAdd(&opt, NULL, "in1", airTypeOther, 1, 1, &in1, NULL,
74
             "First input.  Can be a single value or a nrrd.",
75
1
             NULL, NULL, nrrdHestIter);
76
1
  hestOptAdd(&opt, NULL, "in2", airTypeOther, 1, 1, &in2, NULL,
77
             "Second input.  Can be a single value or a nrrd.",
78
1
             NULL, NULL, nrrdHestIter);
79
1
  hestOptAdd(&opt, "s,seed", "seed", airTypeString, 1, 1, &seedS, "",
80
             "seed value for RNG for nrand, so that you "
81
             "can get repeatable results between runs, or, "
82
             "by not using this option, the RNG seeding will be "
83
             "based on the current time");
84
1
  hestOptAdd(&opt, "t,type", "type", airTypeOther, 1, 1, &type, "default",
85
             "type to convert all INPUT nrrds to, prior to "
86
             "doing operation, useful for doing, for instance, the difference "
87
             "between two unsigned char nrrds.  This will also determine "
88
             "output type. By default (not using this option), the types of "
89
             "the input nrrds are left unchanged.",
90
             NULL, NULL, &unrrduHestMaybeTypeCB);
91
1
  hestOptAdd(&opt, "w,which", "arg", airTypeInt, 1, 1, &which, "-1",
92
             "Which argument (0 or 1) should be used to determine the "
93
             "shape of the output nrrd. By default (not using this option), "
94
             "the first non-constant argument is used. ");
95
1
  OPT_ADD_NOUT(out, "output nrrd");
96
97
1
  mop = airMopNew();
98
1
  airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways);
99
100
2
  USAGE(_unrrdu_2opInfoL);
101
  PARSE();
102
  airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways);
103
104
  nout = nrrdNew();
105
  airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways);
106
107
  /*
108
  fprintf(stderr, "%s: op = %d\n", me, op);
109
  fprintf(stderr, "%s: in1->left = %d, in2->left = %d\n", me,
110
          (int)(in1->left), (int)(in2->left));
111
  */
112
  if (nrrdTypeDefault != type) {
113
    /* they wanted to convert nrrds to some other type first */
114
    E = 0;
115
    if (in1->ownNrrd) {
116
      if (!E) E |= nrrdConvert(ntmp=nrrdNew(), in1->ownNrrd, type);
117
      if (!E) nrrdIterSetOwnNrrd(in1, ntmp);
118
    }
119
    if (in2->ownNrrd) {
120
      if (!E) E |= nrrdConvert(ntmp=nrrdNew(), in2->ownNrrd, type);
121
      if (!E) nrrdIterSetOwnNrrd(in2, ntmp);
122
    }
123
    if (E) {
124
      airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
125
      fprintf(stderr, "%s: error converting input nrrd(s):\n%s", me, err);
126
      airMopError(mop);
127
      return 1;
128
    }
129
    /* this will still leave a nrrd in the NrrdIter for nrrdIterNix()
130
       (called by hestParseFree() called be airMopOkay()) to clear up */
131
  }
132
  /*
133
  ** Used to only deal with RNG seed for particular op:
134
  **   if (nrrdBinaryOpNormalRandScaleAdd == op) {
135
  ** but then when nrrdBinaryOpRicianRand was added, then the seed wasn't being
136
  ** used ==> BUG.  To be more future proof, we try to parse and use seed
137
  ** whenever a non-empty string is given, and end up *ALWAYS* calling
138
  ** airSrandMT, even for operations that have nothing to do with random
139
  ** numbers.  Could also have a new array that indicates if an op involves
140
  ** the RNG, but this would add rarely-needed complexity
141
  */
142
  if (airStrlen(seedS)) {
143
    if (1 != sscanf(seedS, "%u", &seed)) {
144
      fprintf(stderr, "%s: couldn't parse seed \"%s\" as uint\n", me, seedS);
145
      airMopError(mop);
146
      return 1;
147
    } else {
148
      airSrandMT(seed);
149
    }
150
  } else {
151
    /* got no request for specific seed */
152
    airSrandMT(AIR_CAST(unsigned int, airTime()));
153
  }
154
  if (-1 == which
155
      ? nrrdArithIterBinaryOp(nout, op, in1, in2)
156
      : nrrdArithIterBinaryOpSelect(nout, op, in1, in2,
157
                                    AIR_CAST(unsigned int, which))) {
158
    airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
159
    fprintf(stderr, "%s: error doing binary operation:\n%s", me, err);
160
    airMopError(mop);
161
    return 1;
162
  }
163
164
  SAVE(out, nout, NULL);
165
166
  airMopOkay(mop);
167
  return 0;
168
1
}
169
170
UNRRDU_CMD(2op, INFO);