38 static char rcsid[]
not_used = {
"$Id: ce_functions.cc 25066 2011-11-30 18:39:37Z jimg $" };
50 #undef FUNCTION_DAP // undef so the dap() function always returns an error;
86 double w32strtod(
const char *,
char **);
102 inline bool double_eq(
double lhs,
double rhs,
double epsilon = 1.0e-5)
105 return (lhs - rhs) < ((lhs + rhs) / epsilon);
107 return (rhs - lhs) < ((lhs + rhs) / epsilon);
124 "The CE Evaluator built an argument list where some constants held no values.");
126 string s =
dynamic_cast<Str&
> (*arg).
value();
128 DBG(cerr <<
"s: " << s << endl);
133 template<
class T>
static void set_array_using_double_helper(Array * a,
double *src,
int src_len)
135 T *values =
new T[src_len];
136 for (
int i = 0; i < src_len; ++i)
137 values[i] = (T) src[i];
140 a->val2buf(values,
true);
142 a->set_value(values, src_len);
170 throw InternalErr(__FILE__, __LINE__,
"The function requires a DAP numeric-type array argument.");
176 if (dest->
length() != src_len)
180 "The source and destination array sizes don't match (" +
long_to_string(src_len) +
" versus "
189 set_array_using_double_helper<dods_byte> (dest, src, src_len);
192 set_array_using_double_helper<dods_uint16> (dest, src, src_len);
195 set_array_using_double_helper<dods_int16> (dest, src, src_len);
198 set_array_using_double_helper<dods_uint32> (dest, src, src_len);
201 set_array_using_double_helper<dods_int32> (dest, src, src_len);
204 set_array_using_double_helper<dods_float32> (dest, src, src_len);
207 set_array_using_double_helper<dods_float64> (dest, src, src_len);
211 "The argument list built by the CE parser contained an unsupported numeric type.");
218 template<
class T>
static double *extract_double_array_helper(Array * a)
220 int length = a->length();
222 T *b =
new T[length];
225 double *dest =
new double[length];
226 for (
int i = 0; i < length; ++i)
227 dest[i] = (
double) b[i];
245 throw InternalErr(__FILE__, __LINE__,
string(
"The Array '") + a->
name() +
"'does not contain values.");
253 return extract_double_array_helper<dods_byte> (a);
255 return extract_double_array_helper<dods_uint16> (a);
257 return extract_double_array_helper<dods_int16> (a);
259 return extract_double_array_helper<dods_uint32> (a);
261 return extract_double_array_helper<dods_int32> (a);
263 return extract_double_array_helper<dods_float32> (a);
265 return extract_double_array_helper<dods_float64> (a);
268 "The argument list built by the CE parser contained an unsupported numeric type.");
287 "The CE Evaluator built an argument list where some constants held no values.");
293 switch (arg->
type()) {
295 return (
double) (
dynamic_cast<Byte&
> (*arg).
value());
297 return (
double) (
dynamic_cast<UInt16&
> (*arg).
value());
299 return (
double) (
dynamic_cast<Int16&
> (*arg).
value());
301 return (
double) (
dynamic_cast<UInt32&
> (*arg).
value());
303 return (
double) (
dynamic_cast<Int32&
> (*arg).
value());
305 return (
double) (
dynamic_cast<Float32&
> (*arg).
value());
310 "The argument list built by the CE parser contained an unsupported numeric type.");
324 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
326 <function name=\"geogrid\" version=\"1.2\"/>\
327 <function name=\"grid\" version=\"1.0\"/>\
328 <function name=\"linear_scale\" version=\"1.0b1\"/>\
329 <function name=\"version\" version=\"1.0\"/>\
330 <function name=\"dap\" version=\"1.0\"/>\
335 Str *response =
new Str(
"version");
346 throw Error(
"The 'dap' function must be called with a version number.\n\
347 see http://docs.opendap.org/index.php/Server_Side_Processing_Functions#dap");
351 dds.set_dap_version(pv);
354 "The 'dap' function is not supported in lieu of Constraint expression 'keywords.'\n\
355 see http://docs.opendap.org/index.php/Server_Side_Processing_Functions#keywords");
359 static void parse_gse_expression(gse_arg * arg, BaseType * expr)
364 bool status =
gse_parse((
void *) arg) == 0;
370 static void apply_grid_selection_expr(Grid * grid, GSEClause * clause)
374 Grid::Map_iter map_i = grid->map_begin();
375 while (map_i != grid->map_end() && (*map_i)->name() != clause->get_map_name())
378 if (map_i == grid->map_end())
380 "The map vector '" + clause->get_map_name() +
"' is not in the grid '" + grid->name() +
"'.");
383 Array::Dim_iter grid_dim = (grid->get_array()->dim_begin() + (map_i - grid->map_begin()));
385 Array *map =
dynamic_cast<Array *
> ((*map_i));
387 throw InternalErr(__FILE__, __LINE__,
"Expected an Array");
388 int start = max(map->dimension_start(map->dim_begin()), clause->get_start());
389 int stop = min(map->dimension_stop(map->dim_begin()), clause->get_stop());
393 msg <<
"The expressions passed to grid() do not result in an inclusive \n" <<
"subset of '"
394 << clause->get_map_name() <<
"'. The map's values range " <<
"from " << clause->get_map_min_value()
395 <<
" to " << clause->get_map_max_value() <<
".";
399 DBG(cerr <<
"Setting constraint on " << map->name()
400 <<
"[" << start <<
":" << stop <<
"]" << endl);
403 map->add_constraint(map->dim_begin(), start, 1, stop);
404 grid->get_array()->add_constraint(grid_dim, start, 1, stop);
407 static void apply_grid_selection_expressions(Grid * grid, vector<GSEClause *> clauses)
409 vector<GSEClause *>::iterator clause_i = clauses.begin();
410 while (clause_i != clauses.end())
411 apply_grid_selection_expr(grid, *clause_i++);
413 grid->set_read_p(
false);
454 DBG(cerr <<
"Entering function_grid..." << endl);
458 string(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
459 +
"<function name=\"grid\" version=\"1.0\" href=\"http://docs.opendap.org/index.php/Server_Side_Processing_Functions#grid\">\n"
463 Str *response =
new Str(
"info");
469 Grid *original_grid =
dynamic_cast<Grid *
> (argv[0]);
476 Grid *l_grid =
dynamic_cast<Grid *
> (btp);
479 throw InternalErr(__FILE__, __LINE__,
"Expected a Grid.");
482 DBG(cerr <<
"grid: past initialization code" << endl);
492 (*i++)->set_send_p(
true);
495 DBG(cerr <<
"grid: past map read" << endl);
501 vector<GSEClause *> clauses;
503 for (
int i = 1; i < argc; ++i) {
504 parse_gse_expression(arg, argv[i]);
510 apply_grid_selection_expressions(l_grid, clauses);
512 DBG(cerr <<
"grid: past gse application" << endl);
560 string(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
561 +
"<function name=\"geogrid\" version=\"1.2\" href=\"http://docs.opendap.org/index.php/Server_Side_Processing_Functions#geogrid\">\n"
565 Str *response =
new Str(
"version");
580 if (argc < 1 || !(l_grid = dynamic_cast<Grid *> (argv[0]->ptr_duplicate())))
586 "Wrong number of arguments to geogrid() (expected at least 5 args). See geogrid() for more information.");
588 bool grid_lat_lon_form;
591 if (!(l_lat = dynamic_cast<Array *> (argv[1])))
592 grid_lat_lon_form =
false;
593 else if (!(l_lon = dynamic_cast<Array *> (argv[2])))
595 "When using the Grid, Lat, Lon form of geogrid() both the lat and lon maps must be given (lon map missing)!");
597 grid_lat_lon_form =
true;
599 if (grid_lat_lon_form && argc < 7)
601 "Wrong number of arguments to geogrid() (expected at least 7 args). See geogrid() for more information.");
620 (*i++)->set_send_p(
true);
627 DBG(cerr <<
"geogrid: past map read" << endl);
631 int min_arg_count = (grid_lat_lon_form) ? 7 : 5;
632 if (argc > min_arg_count) {
635 vector<GSEClause *> clauses;
637 for (
int i = min_arg_count; i < argc; ++i) {
638 parse_gse_expression(arg, argv[i]);
644 apply_grid_selection_expressions(l_grid, clauses);
654 int box_index_offset = (grid_lat_lon_form) ? 3 : 1;
660 DBG(cerr <<
"geogrid: past bounding box set" << endl);
664 DBG(cerr <<
"geogrid: past apply constraint" << endl);
672 }
catch (exception & e) {
673 throw InternalErr(
string(
"A C++ exception was thrown from inside geogrid(): ") + e.what());
682 static double string_to_double(
const char *val)
689 double v = w32strtod(val, &ptr);
691 double v = strtod(val, &ptr);
694 if ((v == 0.0 && (val == ptr || errno == HUGE_VAL || errno == ERANGE)) || *ptr !=
'\0') {
695 throw Error(
malformed_expr,
string(
"Could not convert the string '") + val +
"' to a double.");
698 double abs_val = fabs(v);
700 throw Error(
malformed_expr,
string(
"Could not convert the string '") + val +
"' to a double.");
714 static double get_attribute_double_value(BaseType *var, vector<string> &attributes)
718 AttrTable &attr = var->get_attr_table();
719 string attribute_value =
"";
721 vector<string>::iterator i = attributes.begin();
722 while (attribute_value ==
"" && i != attributes.end()) {
726 attribute_value = attr.get_attr(*i++);
731 if (attribute_value.empty()) {
733 return get_attribute_double_value(dynamic_cast<Grid&> (*var).get_array(), attributes);
737 string(
"No COARDS/CF '") + values.substr(0, values.length() - 2)
738 +
"' attribute was found for the variable '" + var->name() +
"'.");
741 return string_to_double(
remove_quotes(attribute_value).c_str());
744 static double get_attribute_double_value(BaseType *var,
const string &attribute)
746 AttrTable &attr = var->get_attr_table();
747 string attribute_value = attr.get_attr(attribute);
751 if (attribute_value.empty()) {
753 return get_attribute_double_value(dynamic_cast<Grid&> (*var).get_array(), attribute);
756 string(
"No COARDS '") + attribute +
"' attribute was found for the variable '" + var->name() +
"'.");
759 return string_to_double(
remove_quotes(attribute_value).c_str());
762 static double get_y_intercept(BaseType *var)
764 vector<string> attributes;
765 attributes.push_back(
"add_offset");
766 attributes.push_back(
"add_off");
767 return get_attribute_double_value(var, attributes);
770 static double get_slope(BaseType *var)
772 return get_attribute_double_value(var,
"scale_factor");
775 static double get_missing_value(BaseType *var)
777 return get_attribute_double_value(var,
"missing_value");
796 string(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
797 +
"<function name=\"linear_scale\" version=\"1.0b1\" href=\"http://docs.opendap.org/index.php/Server_Side_Processing_Functions#linear_scale\">\n"
801 Str *response =
new Str(
"info");
808 DBG(cerr <<
"argc = " << argc << endl);
809 if (!(argc == 1 || argc == 3 || argc == 4))
811 "Wrong number of arguments to linear_scale(). See linear_scale() for more information");
814 bool use_missing =
false;
815 double m, b, missing = 0.0;
822 else if (argc == 3) {
828 m = get_slope(argv[0]);
834 b = get_y_intercept(argv[0]);
843 missing = get_missing_value(argv[0]);
850 DBG(cerr <<
"m: " << m <<
", b: " << b << endl);
DBG(cerr <<
"use_missing: " << use_missing <<
", missing: " << missing << endl);
857 Array &source = *
dynamic_cast<Grid&
> (*argv[0]).get_array();
861 int length = source.
length();
864 DBG2(cerr <<
"data[" << i <<
"]: " << data[i] << endl);
865 if (!use_missing || !
double_eq(data[i], missing))
866 data[i] = data[i] * m + b;
867 DBG2(cerr <<
" >> data[" << i <<
"]: " << data[i] << endl);
875 source.
val2buf(static_cast<void*>(data),
false);
883 else if (argv[0]->is_vector_type()) {
884 Array &source =
dynamic_cast<Array&
> (*argv[0]);
894 int length = source.
length();
897 if (!use_missing || !
double_eq(data[i], missing))
898 data[i] = data[i] * m + b;
905 source.
val2buf(static_cast<void*> (data),
false);
912 else if (argv[0]->is_simple_type() && !(argv[0]->type() ==
dods_str_c || argv[0]->type() ==
dods_url_c)) {
914 if (!use_missing || !
double_eq(data, missing))
917 dest =
new Float64(argv[0]->name());
919 dest->
val2buf(static_cast<void*> (&data));
923 throw Error(
malformed_expr,
"The linear_scale() function works only for numeric Grids, Arrays and scalars.");
952 string(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") +
953 "<function name=\"geoarray\" version=\"0.9b1\" href=\"http://docs.opendap.org/index.php/Server_Side_Processing_Functions#geoarray\">\n" +
957 Str *response =
new Str(
"version");
958 response->set_value(info);
963 DBG(cerr <<
"argc = " << argc << endl);
964 if (!(argc == 5 || argc == 9 || argc == 11))
965 throw Error(
malformed_expr,
"Wrong number of arguments to geoarray(). See geoarray() for more information.");
968 Array *l_array = dynamic_cast < Array * >(argv[0]->ptr_duplicate());
970 throw Error(
malformed_expr,
"The first argument to geoarray() must be an Array variable!");
982 ArrayGeoConstraint agc(l_array);
984 agc.set_bounding_box(bb_left, bb_top, bb_right, bb_bottom);
986 agc.apply_constraint_to_data();
987 *btpp = agc.get_constrained_array();
996 ArrayGeoConstraint agc (l_array, var_left, var_top, var_right, var_bottom);
998 agc.set_bounding_box(bb_left, bb_top, bb_right, bb_bottom);
1000 agc.apply_constraint_to_data();
1001 *btpp = agc.get_constrained_array();
1012 ArrayGeoConstraint agc(l_array,
1013 var_left, var_top, var_right, var_bottom,
1016 agc.set_bounding_box(bb_left, bb_top, bb_right, bb_bottom);
1018 agc.apply_constraint_to_data();
1019 *btpp = agc.get_constrained_array();
1024 throw InternalErr(__FILE__, __LINE__,
"Wrong number of args to geoarray.");
1030 catch (exception & e) {
1033 (
"A C++ exception was thrown from inside geoarray(): ")
1038 throw InternalErr(__FILE__, __LINE__,
"Impossible condition in geoarray.");