30#include <libdap/BaseType.h>
31#include <libdap/Float64.h>
32#include <libdap/Str.h>
33#include <libdap/Array.h>
34#include <libdap/Grid.h>
35#include <libdap/D4RValue.h>
37#include <libdap/Error.h>
38#include <libdap/DDS.h>
40#include <libdap/debug.h>
41#include <libdap/util.h>
45#include "LinearScaleFunction.h"
51string linear_scale_info =
52 string(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
53 +
"<function name=\"linear_scale\" version=\"1.0b1\" href=\"http://docs.opendap.org/index.php/Server_Side_Processing_Functions#linear_scale\">\n"
60static double string_to_double(
const char *val)
62 istringstream iss(val);
66 double abs_val = fabs(v);
67 if (abs_val > DODS_DBL_MAX || (abs_val != 0.0 && abs_val < DODS_DBL_MIN))
68 throw Error(malformed_expr,
string(
"Could not convert the string '") + val +
"' to a double.");
82static double get_attribute_double_value(BaseType *var, vector<string> &attributes)
86 AttrTable &attr = var->get_attr_table();
87 string attribute_value =
"";
89 vector<string>::iterator i = attributes.begin();
90 while (attribute_value ==
"" && i != attributes.end()) {
92 if (!values.empty()) values +=
", ";
93 attribute_value = attr.get_attr(*i++);
98 if (attribute_value.empty()) {
99 if (var->type() == dods_grid_c)
100 return get_attribute_double_value(
dynamic_cast<Grid&
>(*var).get_array(), attributes);
102 throw Error(malformed_expr,
103 string(
"No COARDS/CF '") + values.substr(0, values.size() - 2)
104 +
"' attribute was found for the variable '" + var->name() +
"'.");
107 return string_to_double(remove_quotes(attribute_value).c_str());
110static double get_attribute_double_value(BaseType *var,
const string &attribute)
112 AttrTable &attr = var->get_attr_table();
113 string attribute_value = attr.get_attr(attribute);
117 if (attribute_value.empty()) {
118 if (var->type() == dods_grid_c)
119 return get_attribute_double_value(
dynamic_cast<Grid&
>(*var).get_array(), attribute);
121 throw Error(malformed_expr,
122 string(
"No COARDS '") + attribute +
"' attribute was found for the variable '" + var->name()
126 return string_to_double(remove_quotes(attribute_value).c_str());
129static double get_y_intercept(BaseType *var)
131 vector<string> attributes;
132 attributes.push_back(
"add_offset");
133 attributes.push_back(
"add_off");
134 return get_attribute_double_value(var, attributes);
137static double get_slope(BaseType *var)
139 return get_attribute_double_value(var,
"scale_factor");
142static double get_missing_value(BaseType *var)
144 return get_attribute_double_value(var,
"missing_value");
147BaseType *function_linear_scale_worker(BaseType *bt,
double m,
double b,
double missing,
bool use_missing)
151 BaseType *dest =
nullptr;
153 if (bt->type() == dods_grid_c) {
155 Grid &source =
dynamic_cast<Grid&
>(*bt);
157 BESDEBUG(
"function",
"function_linear_scale_worker() - Grid send_p: " << source.send_p() << endl);
159 "function_linear_scale_worker() - Grid Array send_p: " << source.get_array()->send_p() << endl);
163 source.set_send_p(
true);
167 Array *a = source.get_array();
169 data = extract_double_array(a);
172 int length = a->length();
173 for (
int i = 0; i < length; ++i)
174 data[i] = data[i] * m + b;
179 Grid *result =
new Grid(source);
183 result->get_array()->add_var_nocopy(
new Float64(source.name()));
184 result->get_array()->set_value(data, length);
188 BESDEBUG(
"function",
"function_linear_scale_worker() - Grid send_p: " << source.send_p() << endl);
190 "function_linear_scale_worker() - Grid Array send_p: " << source.get_array()->send_p() << endl);
194 else if (bt->is_vector_type()) {
195 Array &source =
dynamic_cast<Array&
>(*bt);
198 if (source.get_parent() && source.get_parent()->type() == dods_grid_c) {
199 source.get_parent()->set_send_p(
true);
200 source.get_parent()->read();
205 data = extract_double_array(&source);
206 int length = source.length();
207 for (
int i = 0; i < length; ++i)
208 data[i] = data[i] * m + b;
210 Array *result =
new Array(source);
212 result->add_var_nocopy(
new Float64(source.name()));
213 result->set_value(data, length);
219 else if (bt->is_simple_type() && !(bt->type() == dods_str_c || bt->type() == dods_url_c)) {
220 double data = extract_double_value(bt);
221 if (!use_missing || !double_eq(data, missing)) data = data * m + b;
223 Float64 *fdest =
new Float64(bt->name());
225 fdest->set_value(data);
230 throw Error(malformed_expr,
"The linear_scale() function works only for numeric Grids, Arrays and scalars.");
248void function_dap2_linear_scale(
int argc, BaseType * argv[], DDS &, BaseType **btpp)
251 Str *response =
new Str(
"info");
252 response->set_value(linear_scale_info);
258 DBG(cerr <<
"argc = " << argc << endl);
259 if (!(argc == 1 || argc == 3 || argc == 4))
260 throw Error(malformed_expr,
261 "Wrong number of arguments to linear_scale(). See linear_scale() for more information");
264 bool use_missing =
false;
265 double m, b, missing = 0.0;
267 m = extract_double_value(argv[1]);
268 b = extract_double_value(argv[2]);
269 missing = extract_double_value(argv[3]);
272 else if (argc == 3) {
273 m = extract_double_value(argv[1]);
274 b = extract_double_value(argv[2]);
278 m = get_slope(argv[0]);
284 b = get_y_intercept(argv[0]);
294 missing = get_missing_value(argv[0]);
303 "function_dap2_linear_scale() - m: " << m <<
", b: " << b <<
", use_missing: " << use_missing <<
", missing: " << missing << endl);
305 *btpp = function_linear_scale_worker(argv[0], m, b, missing, use_missing);
320BaseType *function_dap4_linear_scale(D4RValueList *args, DMR &dmr)
322 BESDEBUG(
"function",
"function_dap4_linear_scale() BEGIN " << endl);
325 if (args == 0 || args->size() == 0) {
326 Str *response =
new Str(
"info");
327 response->set_value(linear_scale_info);
333 DBG(cerr <<
"args.size() = " << args.size() << endl);
334 if (!(args->size() == 1 || args->size() == 3 || args->size() == 4))
335 throw Error(malformed_expr,
336 "Wrong number of arguments to linear_scale(). See linear_scale() for more information");
339 bool use_missing =
false;
340 double m, b, missing = 0.0;
341 if (args->size() == 4) {
342 m = extract_double_value(args->get_rvalue(1)->value(dmr));
343 b = extract_double_value(args->get_rvalue(2)->value(dmr));
344 missing = extract_double_value(args->get_rvalue(3)->value(dmr));
347 else if (args->size() == 3) {
348 m = extract_double_value(args->get_rvalue(1)->value(dmr));
349 b = extract_double_value(args->get_rvalue(2)->value(dmr));
353 m = get_slope(args->get_rvalue(0)->value(dmr));
359 b = get_y_intercept(args->get_rvalue(0)->value(dmr));
369 missing = get_missing_value(args->get_rvalue(0)->value(dmr));
377 "function_dap4_linear_scale() - m: " << m <<
", b: " << b <<
", use_missing: " << use_missing <<
", missing: " << missing << endl);
379 BESDEBUG(
"function",
"function_dap4_linear_scale() END " << endl);
381 return function_linear_scale_worker(args->get_rvalue(0)->value(dmr), m, b, missing, use_missing);