libdap++  Updated for version 3.8.2
ce_functions.cc
Go to the documentation of this file.
1 // -*- mode: c++; c-basic-offset:4 -*-
2 
3 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
4 // Access Protocol.
5 
6 // Copyright (c) 2002,2003 OPeNDAP, Inc.
7 // Author: James Gallagher <jgallagher@opendap.org>
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
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
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 //
23 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24 
25 // (c) COPYRIGHT URI/MIT 1999
26 // Please read the full copyright statement in the file COPYRIGHT_URI.
27 //
28 // Authors:
29 // jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
30 
31 
32 // These functions are used by the CE evaluator
33 //
34 // 1/15/99 jhrg
35 
36 #include "config.h"
37 
38 static char rcsid[]not_used =
39 { "$Id: ce_functions.cc 23551 2010-09-13 21:00:46Z jimg $"
40 };
41 
42 #include <limits.h>
43 
44 #include <cstdlib> // used by strtod()
45 #include <cerrno>
46 #include <cmath>
47 #include <iostream>
48 #include <vector>
49 #include <algorithm>
50 
51 //#define DODS_DEBUG
52 
53 #include "BaseType.h"
54 #include "Byte.h"
55 #include "Int16.h"
56 #include "UInt16.h"
57 #include "Int32.h"
58 #include "UInt32.h"
59 #include "Float32.h"
60 #include "Float64.h"
61 #include "Str.h"
62 #include "Url.h"
63 #include "Array.h"
64 #include "Structure.h"
65 #include "Sequence.h"
66 #include "Grid.h"
67 #include "Error.h"
68 #include "RValue.h"
69 
70 #include "GSEClause.h"
71 #include "GridGeoConstraint.h"
72 #include "ArrayGeoConstraint.h"
73 
74 #include "ce_functions.h"
75 #include "gse_parser.h"
76 #include "gse.tab.hh"
77 #include "debug.h"
78 #include "util.h"
79 
80 // We wrapped VC++ 6.x strtod() to account for a short coming
81 // in that function in regards to "NaN". I don't know if this
82 // still applies in more recent versions of that product.
83 // ROM - 12/2007
84 #ifdef WIN32
85 #include <limits>
86 double w32strtod(const char *, char **);
87 #endif
88 
89 using namespace std;
90 
91 int gse_parse(void *arg);
92 void gse_restart(FILE * in);
93 
94 // Glue routines declared in gse.lex
95 void gse_switch_to_buffer(void *new_buffer);
96 void gse_delete_buffer(void *buffer);
97 void *gse_string(const char *yy_str);
98 
99 namespace libdap {
100 
102 inline bool double_eq(double lhs, double rhs, double epsilon = 1.0e-5)
103 {
104  if (lhs > rhs)
105  return (lhs - rhs) < ((lhs + rhs) / epsilon);
106  else
107  return (rhs - lhs) < ((lhs + rhs) / epsilon);
108 }
109 
118 {
119  if (arg->type() != dods_str_c)
120  throw Error(malformed_expr,
121  "The function requires a DAP string argument.");
122 
123  if (!arg->read_p())
124  throw InternalErr(__FILE__, __LINE__,
125  "The CE Evaluator built an argument list where some constants held no values.");
126 
127  string s = dynamic_cast<Str&>(*arg).value();
128 
129  DBG(cerr << "s: " << s << endl);
130 
131  return s;
132 }
133 template<class T> static void set_array_using_double_helper(Array * a,
134  double *src, int src_len)
135 {
136  T *values = new T[src_len];
137  for (int i = 0; i < src_len; ++i)
138  values[i] = (T) src[i];
139 
140 #ifdef VAL2BUF
141  a->val2buf(values, true);
142 #else
143  a->set_value(values, src_len);
144 #endif
145 
146  delete[]values;
147 }
148 
166 void set_array_using_double(Array * dest, double *src, int src_len)
167 {
168  // Simple types are Byte, ..., Float64, String and Url.
169  if ((dest->type() == dods_array_c && !dest->var()->is_simple_type())
170  || dest->var()->type() == dods_str_c
171  || dest->var()->type() == dods_url_c)
172  throw InternalErr(__FILE__, __LINE__,
173  "The function requires a DAP numeric-type array argument.");
174 
175  // Test sizes. Note that Array::length() takes any constraint into account
176  // when it returns the length. Even if this was removed, the 'helper'
177  // function this uses calls Vector::val2buf() which uses Vector::width()
178  // which in turn uses length().
179  if (dest->length() != src_len)
180  throw InternalErr(__FILE__, __LINE__,
181  "The source and destination array sizes don't match ("
182  + long_to_string(src_len) + " versus "
183  + long_to_string(dest->length()) + ").");
184 
185  // The types of arguments that the CE Parser will build for numeric
186  // constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
187  // Expanded to work for any numeric type so it can be used for more than
188  // just arguments.
189  switch (dest->var()->type()) {
190  case dods_byte_c:
191  set_array_using_double_helper<dods_byte>(dest, src, src_len);
192  break;
193  case dods_uint16_c:
194  set_array_using_double_helper<dods_uint16>(dest, src, src_len);
195  break;
196  case dods_int16_c:
197  set_array_using_double_helper<dods_int16>(dest, src, src_len);
198  break;
199  case dods_uint32_c:
200  set_array_using_double_helper<dods_uint32>(dest, src, src_len);
201  break;
202  case dods_int32_c:
203  set_array_using_double_helper<dods_int32>(dest, src, src_len);
204  break;
205  case dods_float32_c:
206  set_array_using_double_helper<dods_float32>(dest, src, src_len);
207  break;
208  case dods_float64_c:
209  set_array_using_double_helper<dods_float64>(dest, src, src_len);
210  break;
211  default:
212  throw InternalErr(__FILE__, __LINE__,
213  "The argument list built by the CE parser contained an unsupported numeric type.");
214  }
215 
216  // Set the read_p property.
217  dest->set_read_p(true);
218 }
219 
220 template<class T> static double *extract_double_array_helper(Array * a)
221 {
222  int length = a->length();
223 
224  T *b = new T[length];
225  a->value(b);
226 
227  double *dest = new double[length];
228  for (int i = 0; i < length; ++i)
229  dest[i] = (double) b[i];
230  delete[]b;
231 
232  return dest;
233 }
234 
240 {
241  // Simple types are Byte, ..., Float64, String and Url.
242  if ((a->type() == dods_array_c && !a->var()->is_simple_type())
243  || a->var()->type() == dods_str_c || a->var()->type() == dods_url_c)
244  throw Error(malformed_expr,
245  "The function requires a DAP numeric-type array argument.");
246 
247  if (!a->read_p())
248  throw InternalErr(__FILE__, __LINE__,
249  string("The Array '") + a->name() +
250  "'does not contain values.");
251 
252  // The types of arguments that the CE Parser will build for numeric
253  // constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
254  // Expanded to work for any numeric type so it can be used for more than
255  // just arguments.
256  switch (a->var()->type()) {
257  case dods_byte_c:
258  return extract_double_array_helper<dods_byte>(a);
259  case dods_uint16_c:
260  return extract_double_array_helper<dods_uint16>(a);
261  case dods_int16_c:
262  return extract_double_array_helper<dods_int16>(a);
263  case dods_uint32_c:
264  return extract_double_array_helper<dods_uint32>(a);
265  case dods_int32_c:
266  return extract_double_array_helper<dods_int32>(a);
267  case dods_float32_c:
268  return extract_double_array_helper<dods_float32>(a);
269  case dods_float64_c:
270  return extract_double_array_helper<dods_float64>(a);
271  default:
272  throw InternalErr(__FILE__, __LINE__,
273  "The argument list built by the CE parser contained an unsupported numeric type.");
274  }
275 }
276 
285 {
286  // Simple types are Byte, ..., Float64, String and Url.
287  if (!arg->is_simple_type() || arg->type() == dods_str_c || arg->type()
288  == dods_url_c)
289  throw Error(malformed_expr,
290  "The function requires a DAP numeric-type argument.");
291 
292  if (!arg->read_p())
293  throw InternalErr(__FILE__, __LINE__,
294  "The CE Evaluator built an argument list where some constants held no values.");
295 
296  // The types of arguments that the CE Parser will build for numeric
297  // constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
298  // Expanded to work for any numeric type so it can be used for more than
299  // just arguments.
300  switch (arg->type()) {
301  case dods_byte_c:
302  return (double)(dynamic_cast<Byte&>(*arg).value());
303  case dods_uint16_c:
304  return (double)(dynamic_cast<UInt16&>(*arg).value());
305  case dods_int16_c:
306  return (double)(dynamic_cast<Int16&>(*arg).value());
307  case dods_uint32_c:
308  return (double)(dynamic_cast<UInt32&>(*arg).value());
309  case dods_int32_c:
310  return (double)(dynamic_cast<Int32&>(*arg).value());
311  case dods_float32_c:
312  return (double)(dynamic_cast<Float32&>(*arg).value());
313  case dods_float64_c:
314  return dynamic_cast<Float64&>(*arg).value();
315  default:
316  throw InternalErr(__FILE__, __LINE__,
317  "The argument list built by the CE parser contained an unsupported numeric type.");
318  }
319 }
320 
323 void
324 function_version(int, BaseType *[], DDS &, BaseType **btpp)
325 {
326  string
327  xml_value =
328  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
329  <functions>\
330  <function name=\"geogrid\" version=\"1.2\"/>\
331  <function name=\"grid\" version=\"1.0\"/>\
332  <function name=\"linear_scale\" version=\"1.0b1\"/>\
333  <function name=\"version\" version=\"1.0\"/>\
334  </functions>";
335 
336  // <function name=\"geoarray\" version=\"0.9b1\"/>
337 
338  Str *response = new Str("version");
339 
340  response->set_value(xml_value);
341  *btpp = response;
342  return;
343 }
344 
345 static void parse_gse_expression(gse_arg * arg, BaseType * expr)
346 {
347  gse_restart(0); // Restart the scanner.
348  void *cls = gse_string(extract_string_argument(expr).c_str());
349  // gse_switch_to_buffer(cls); // Get set to scan the string.
350  bool status = gse_parse((void *) arg) == 0;
351  gse_delete_buffer(cls);
352  if (!status)
353  throw Error(malformed_expr, "Error parsing grid selection.");
354 }
355 
356 static void apply_grid_selection_expr(Grid * grid, GSEClause * clause)
357 {
358  // Basic plan: For each map, look at each clause and set start and stop
359  // to be the intersection of the ranges in those clauses.
360  Grid::Map_iter map_i = grid->map_begin();
361  while (map_i != grid->map_end() && (*map_i)->name() != clause->get_map_name())
362  ++map_i;
363 
364  if (map_i == grid->map_end())
365  throw Error(malformed_expr,"The map vector '" + clause->get_map_name()
366  + "' is not in the grid '" + grid->name() + "'.");
367 
368  // Use pointer arith & the rule that map order must match array dim order
369  Array::Dim_iter grid_dim = (grid->get_array()->dim_begin() + (map_i - grid->map_begin()));
370 
371  Array *map = dynamic_cast < Array * >((*map_i));
372  if (!map)
373  throw InternalErr(__FILE__, __LINE__, "Expected an Array");
374  int start = max(map->dimension_start(map->dim_begin()), clause->get_start());
375  int stop = min(map->dimension_stop(map->dim_begin()), clause->get_stop());
376 
377  if (start > stop) {
378  ostringstream msg;
379  msg
380  << "The expressions passed to grid() do not result in an inclusive \n"
381  << "subset of '" << clause->get_map_name()
382  << "'. The map's values range " << "from "
383  << clause->get_map_min_value() << " to "
384  << clause->get_map_max_value() << ".";
385  throw Error(malformed_expr,msg.str());
386  }
387 
388  DBG(cerr << "Setting constraint on " << map->name()
389  << "[" << start << ":" << stop << "]" << endl);
390 
391  // Stride is always one.
392  map->add_constraint(map->dim_begin(), start, 1, stop);
393  grid->get_array()->add_constraint(grid_dim, start, 1, stop);
394 }
395 
396 static void apply_grid_selection_expressions(Grid * grid,
397  vector < GSEClause * >clauses)
398 {
399  vector < GSEClause * >::iterator clause_i = clauses.begin();
400  while (clause_i != clauses.end())
401  apply_grid_selection_expr(grid, *clause_i++);
402 
403  grid->set_read_p(false);
404 }
405 
442 void
443 function_grid(int argc, BaseType * argv[], DDS &, BaseType **btpp)
444 {
445  DBG(cerr << "Entering function_grid..." << endl);
446 
447  string info =
448  string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") +
449  "<function name=\"grid\" version=\"1.0\" href=\"http://docs.opendap.org/index.php/Server_Side_Processing_Functions#grid\">\n" +
450  "</function>\n";
451 
452  if (argc == 0) {
453  Str *response = new Str("info");
454  response->set_value(info);
455  *btpp = response;
456  return;
457  }
458 
459  Grid *original_grid = dynamic_cast < Grid * >(argv[0]);
460  if (!original_grid)
461  throw Error(malformed_expr,"The first argument to grid() must be a Grid variable!");
462 
463  // Duplicate the grid; DODSFilter::send_data() will delete the variable
464  // after serializing it.
465  Grid *l_grid = dynamic_cast < Grid * >(original_grid->ptr_duplicate());
466  if (!l_grid)
467  throw InternalErr(__FILE__, __LINE__, "Expected a Grid.");
468 
469  DBG(cerr << "grid: past initialization code" << endl);
470 
471  // Read the maps. Do this before calling parse_gse_expression(). Avoid
472  // reading the array until the constraints have been applied because it
473  // might be really large.
474 
475  // This version makes sure to set the send_p flags which is needed for
476  // the hdf4 handler (and is what should be done in general).
477  Grid::Map_iter i = l_grid->map_begin();
478  while (i != l_grid->map_end())
479  (*i++)->set_send_p(true);
480  l_grid->read();
481 
482  DBG(cerr << "grid: past map read" << endl);
483 
484  // argv[1..n] holds strings; each are little expressions to be parsed.
485  // When each expression is parsed, the parser makes a new instance of
486  // GSEClause. GSEClause checks to make sure the named map really exists
487  // in the Grid and that the range of values given makes sense.
488  vector < GSEClause * > clauses;
489  gse_arg *arg = new gse_arg(l_grid);
490  for (int i = 1; i < argc; ++i) {
491  parse_gse_expression(arg, argv[i]);
492  clauses.push_back(arg->get_gsec());
493  }
494  delete arg;
495  arg = 0;
496 
497  apply_grid_selection_expressions(l_grid, clauses);
498 
499  DBG(cerr << "grid: past gse application" << endl);
500 
501  l_grid->get_array()->set_send_p(true);
502 
503  l_grid->read();
504 
505  *btpp = l_grid;
506  return;
507 }
508 
544 void
545 function_geogrid(int argc, BaseType * argv[], DDS &, BaseType **btpp)
546 {
547  string info =
548  string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") +
549  "<function name=\"geogrid\" version=\"1.2\" href=\"http://docs.opendap.org/index.php/Server_Side_Processing_Functions#geogrid\">\n"+
550  "</function>";
551 
552  if (argc == 0) {
553  Str *response = new Str("version");
554  response->set_value(info);
555  *btpp = response;
556  return ;
557  }
558 
559  // There are two main forms of this function, one that takes a Grid and one
560  // that takes a Grid and two Arrays. The latter provides a way to explicitly
561  // tell the function which maps contain lat and lon data. The remaining
562  // arguments are the same for both versions, although that includes a
563  // varying argument list.
564 
565  // Look at the types of the first three arguments to determine which of the
566  // two forms were used to call this function.
567  Grid *l_grid = 0;
568  if (argc < 1 || !(l_grid = dynamic_cast < Grid * >(argv[0]->ptr_duplicate())))
569  throw Error(malformed_expr,"The first argument to geogrid() must be a Grid variable!");
570 
571  // Both forms require at least this many args
572  if (argc < 5)
573  throw Error(malformed_expr,"Wrong number of arguments to geogrid() (expected at least 5 args). See geogrid() for more information.");
574 
575  bool grid_lat_lon_form;
576  Array *l_lat = 0;
577  Array *l_lon = 0;
578  if (!(l_lat = dynamic_cast < Array * >(argv[1]))) //->ptr_duplicate())))
579  grid_lat_lon_form = false;
580  else if (!(l_lon = dynamic_cast < Array * >(argv[2]))) //->ptr_duplicate())))
581  throw Error(malformed_expr,"When using the Grid, Lat, Lon form of geogrid() both the lat and lon maps must be given (lon map missing)!");
582  else
583  grid_lat_lon_form = true;
584 
585  if (grid_lat_lon_form && argc < 7)
586  throw Error(malformed_expr,"Wrong number of arguments to geogrid() (expected at least 7 args). See geogrid() for more information.");
587 
588 #if 0
589  Grid *l_grid = dynamic_cast < Grid * >(argv[0]->ptr_duplicate());
590  if (!l_grid)
591  throw Error(malformed_expr,"The first argument to geogrid() must be a Grid variable!");
592 #endif
593  // Read the maps. Do this before calling parse_gse_expression(). Avoid
594  // reading the array until the constraints have been applied because it
595  // might be really large.
596  //
597  // Trick: Some handlers build Grids from a combination of Array
598  // variables and attributes. Those handlers (e.g., hdf4) use the send_p
599  // property to determine which parts of the Grid to read *but they can
600  // only read the maps from within Grid::read(), not the map's read()*.
601  // Since the Grid's array does not have send_p set, it will not be read
602  // by the call below to Grid::read().
603  Grid::Map_iter i = l_grid->map_begin();
604  while (i != l_grid->map_end())
605  (*i++)->set_send_p(true);
606 
607  l_grid->read();
608  // Calling read() above sets the read_p flag for the entire grid; clear it
609  // for the grid's array so that later on the code will be sure to read it
610  // under all circumstances.
611  l_grid->get_array()->set_read_p(false);
612  DBG(cerr << "geogrid: past map read" << endl);
613 
614  // Look for Grid Selection Expressions tacked onto the end of the BB
615  // specification. If there are any, evaluate them before evaluating the BB.
616  int min_arg_count = (grid_lat_lon_form) ? 7 : 5;
617  if (argc > min_arg_count) {
618  // argv[5..n] holds strings; each are little Grid Selection Expressions
619  // to be parsed and evaluated.
620  vector < GSEClause * > clauses;
621  gse_arg *arg = new gse_arg(l_grid);
622  for (int i = min_arg_count; i < argc; ++i) {
623  parse_gse_expression(arg, argv[i]);
624  clauses.push_back(arg->get_gsec());
625  }
626  delete arg;
627  arg = 0;
628 
629  apply_grid_selection_expressions(l_grid, clauses);
630  }
631 
632  try {
633  // Build a GeoConstraint object. If there are no longitude/latitude
634  // maps then this constructor throws Error.
635  GridGeoConstraint gc(l_grid);
636 
637  // This sets the bounding box and modifies the maps to match the
638  // notation of the box (0/359 or -180/179)
639  int box_index_offset = (grid_lat_lon_form) ? 3 : 1;
640  double top = extract_double_value(argv[box_index_offset]);
641  double left = extract_double_value(argv[box_index_offset + 1]);
642  double bottom = extract_double_value(argv[box_index_offset + 2]);
643  double right = extract_double_value(argv[box_index_offset + 3]);
644  gc.set_bounding_box(top, left, bottom, right);
645  DBG(cerr << "geogrid: past bounding box set" << endl);
646 
647  // This also reads all of the data into the grid variable
649  DBG(cerr << "geogrid: past apply constraint" << endl);
650 
651  // In this function the l_grid pointer is the same as the pointer returned
652  // by this call. The caller of the function must free the pointer.
653  *btpp = gc.get_constrained_grid();
654  return;
655  }
656  catch (Error &e) {
657  throw e;
658  }
659  catch (exception & e) {
660  throw
661  InternalErr(string
662  ("A C++ exception was thrown from inside geogrid(): ")
663  + e.what());
664  }
665 }
666 
667 // These static functions could be moved to a class that provides a more
668 // general interface for COARDS/CF someday. Assume each BaseType comes bundled
669 // with an attribute table.
670 
671 // This was ripped from parser-util.cc
672 static double string_to_double(const char *val)
673 {
674  char *ptr;
675  errno = 0;
676  // Clear previous value. 5/21/2001 jhrg
677 
678 #ifdef WIN32
679  double v = w32strtod(val, &ptr);
680 #else
681  double v = strtod(val, &ptr);
682 #endif
683 
684  if ((v == 0.0 && (val == ptr || errno == HUGE_VAL || errno == ERANGE))
685  || *ptr != '\0') {
686  throw Error(malformed_expr,string("Could not convert the string '") + val + "' to a double.");
687  }
688 
689  double abs_val = fabs(v);
690  if (abs_val > DODS_DBL_MAX || (abs_val != 0.0 && abs_val < DODS_DBL_MIN))
691  throw Error(malformed_expr,string("Could not convert the string '") + val + "' to a double.");
692 
693  return v;
694 }
695 
705 static double get_attribute_double_value(BaseType *var,
706  vector<string> &attributes)
707 {
708  // This code also builds a list of the attribute values that have been
709  // passed in but not found so that an informative message can be returned.
710  AttrTable &attr = var->get_attr_table();
711  string attribute_value = "";
712  string values = "";
713  vector<string>::iterator i = attributes.begin();
714  while (attribute_value == "" && i != attributes.end()) {
715  values += *i;
716  if (!values.empty())
717  values += ", ";
718  attribute_value = attr.get_attr(*i++);
719  }
720 
721  // If the value string is empty, then look at the grid's array (if it's a
722  // grid) or throw an Error.
723  if (attribute_value.empty()) {
724  if (var->type() == dods_grid_c)
725  return get_attribute_double_value(dynamic_cast<Grid&>(*var).get_array(), attributes);
726  else
727  throw Error(malformed_expr,string("No COARDS/CF '") + values.substr(0, values.length() - 2)
728  + "' attribute was found for the variable '"
729  + var->name() + "'.");
730  }
731 
732  return string_to_double(remove_quotes(attribute_value).c_str());
733 }
734 
735 static double get_attribute_double_value(BaseType *var, const string &attribute)
736 {
737  AttrTable &attr = var->get_attr_table();
738  string attribute_value = attr.get_attr(attribute);
739 
740  // If the value string is empty, then look at the grid's array (if it's a
741  // grid or throw an Error.
742  if (attribute_value.empty()) {
743  if (var->type() == dods_grid_c)
744  return get_attribute_double_value(dynamic_cast<Grid&>(*var).get_array(), attribute);
745  else
746  throw Error(malformed_expr,string("No COARDS '") + attribute
747  + "' attribute was found for the variable '"
748  + var->name() + "'.");
749  }
750 
751  return string_to_double(remove_quotes(attribute_value).c_str());
752 }
753 
754 static double get_y_intercept(BaseType *var)
755 {
756  vector<string> attributes;
757  attributes.push_back("add_offset");
758  attributes.push_back("add_off");
759  return get_attribute_double_value(var, attributes);
760 }
761 
762 static double get_slope(BaseType *var)
763 {
764  return get_attribute_double_value(var, "scale_factor");
765 }
766 
767 static double get_missing_value(BaseType *var)
768 {
769  return get_attribute_double_value(var, "missing_value");
770 }
771 
784 void
785 function_linear_scale(int argc, BaseType * argv[], DDS &, BaseType **btpp)
786 {
787  string info =
788  string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") +
789  "<function name=\"linear_scale\" version=\"1.0b1\" href=\"http://docs.opendap.org/index.php/Server_Side_Processing_Functions#linear_scale\">\n" +
790  "</function>";
791 
792  if (argc == 0) {
793  Str *response = new Str("info");
794  response->set_value(info);
795  *btpp = response;
796  return;
797  }
798 
799  // Check for 1 or 3 arguments: 1 --> use attributes; 3 --> m & b supplied
800  DBG(cerr << "argc = " << argc << endl);
801  if (!(argc == 1 || argc == 3 || argc == 4))
802  throw Error(malformed_expr,"Wrong number of arguments to linear_scale(). See linear_scale() for more information");
803 
804  // Get m & b
805  bool use_missing = false;
806  double m, b, missing = 0.0;
807  if (argc == 4) {
808  m = extract_double_value(argv[1]);
809  b = extract_double_value(argv[2]);
810  missing = extract_double_value(argv[3]);
811  use_missing = true;
812  } else if (argc == 3) {
813  m = extract_double_value(argv[1]);
814  b = extract_double_value(argv[2]);
815  use_missing = false;
816  } else {
817  m = get_slope(argv[0]);
818 
819  // This is really a hack; on a fair number of datasets, the y intercept
820  // is not given and is assumed to be 0. Here the function looks and
821  // catches the error if a y intercept is not found.
822  try {
823  b = get_y_intercept(argv[0]);
824  }
825  catch (Error &e) {
826  b = 0.0;
827  }
828 
829  // This is not the best plan; the get_missing_value() function should
830  // do something other than throw, but to do that would require mayor
831  // surgery on get_attribute_double_value().
832  try {
833  missing = get_missing_value(argv[0]);
834  use_missing = true;
835  }
836  catch (Error &e) {
837  use_missing = false;
838  }
839  }
840 
841  DBG(cerr << "m: " << m << ", b: " << b << endl);DBG(cerr << "use_missing: " << use_missing << ", missing: " << missing << endl);
842 
843  // Read the data, scale and return the result. Must replace the new data
844  // in a constructor (i.e., Array part of a Grid).
845  BaseType *dest = 0;
846  double *data;
847  if (argv[0]->type() == dods_grid_c) {
848  Array &source = *dynamic_cast<Grid&>(*argv[0]).get_array();
849  source.set_send_p(true);
850  source.read();
851  data = extract_double_array(&source);
852  int length = source.length();
853  int i = 0;
854  while (i < length) {
855  DBG2(cerr << "data[" << i << "]: " << data[i] << endl);
856  if (!use_missing || !double_eq(data[i], missing))
857  data[i] = data[i] * m + b;
858  DBG2(cerr << " >> data[" << i << "]: " << data[i] << endl);
859  ++i;
860  }
861 
862  // Vector::add_var will delete the existing 'template' variable
863  Float64 *temp_f = new Float64(source.name());
864  source.add_var(temp_f);
865 #ifdef VAL2BUF
866  source.val2buf(static_cast<void*>(data), false);
867 #else
868  source.set_value(data, i);
869 #endif
870  delete [] data; // val2buf copies.
871  delete temp_f; // add_var copies and then adds.
872  dest = argv[0];
873  } else if (argv[0]->is_vector_type()) {
874  Array &source = dynamic_cast<Array&>(*argv[0]);
875  source.set_send_p(true);
876  // If the array is really a map, make sure to read using the Grid
877  // because of the HDF4 handler's odd behavior WRT dimensions.
878  if (source.get_parent() && source.get_parent()->type() == dods_grid_c)
879  source.get_parent()->read();
880  else
881  source.read();
882 
883  data = extract_double_array(&source);
884  int length = source.length();
885  int i = 0;
886  while (i < length) {
887  if (!use_missing || !double_eq(data[i], missing))
888  data[i] = data[i] * m + b;
889  ++i;
890  }
891 
892  Float64 *temp_f = new Float64(source.name());
893  source.add_var(temp_f);
894 
895  source.val2buf(static_cast<void*>(data), false);
896 
897  delete [] data; // val2buf copies.
898  delete temp_f; // add_var copies and then adds.
899 
900  dest = argv[0];
901  } else if (argv[0]->is_simple_type() && !(argv[0]->type() == dods_str_c
902  || argv[0]->type() == dods_url_c)) {
903  double data = extract_double_value(argv[0]);
904  if (!use_missing || !double_eq(data, missing))
905  data = data * m + b;
906 
907  dest = new Float64(argv[0]->name());
908 
909  dest->val2buf(static_cast<void*>(&data));
910 
911  } else {
912  throw Error(malformed_expr,"The linear_scale() function works only for numeric Grids, Arrays and scalars.");
913  }
914 
915  *btpp = dest;
916  return;
917 }
918 
919 #if 0
920 
936 void
937 function_geoarray(int argc, BaseType * argv[], DDS &, BaseType **btpp)
938 {
939  string info =
940  string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") +
941  "<function name=\"geoarray\" version=\"0.9b1\" href=\"http://docs.opendap.org/index.php/Server_Side_Processing_Functions#geoarray\">\n" +
942  "</function>";
943 
944  if (argc == 0) {
945  Str *response = new Str("version");
946  response->set_value(info);
947  *btpp = response;
948  return;
949  }
950 
951  DBG(cerr << "argc = " << argc << endl);
952  if (!(argc == 5 || argc == 9 || argc == 11))
953  throw Error(malformed_expr,"Wrong number of arguments to geoarray(). See geoarray() for more information.");
954 
955  // Check the Array (and dup because the caller will free the variable).
956  Array *l_array = dynamic_cast < Array * >(argv[0]->ptr_duplicate());
957  if (!l_array)
958  throw Error(malformed_expr,"The first argument to geoarray() must be an Array variable!");
959 
960  try {
961 
962  // Read the bounding box and variable extents from the params
963  double bb_top = extract_double_value(argv[1]);
964  double bb_left = extract_double_value(argv[2]);
965  double bb_bottom = extract_double_value(argv[3]);
966  double bb_right = extract_double_value(argv[4]);
967 
968  switch (argc) {
969  case 5: {
970  ArrayGeoConstraint agc(l_array);
971 
972  agc.set_bounding_box(bb_left, bb_top, bb_right, bb_bottom);
973  // This also reads all of the data into the grid variable
975  *btpp = agc.get_constrained_array();
976  return;
977  break;
978  }
979  case 9: {
980  double var_top = extract_double_value(argv[5]);
981  double var_left = extract_double_value(argv[6]);
982  double var_bottom = extract_double_value(argv[7]);
983  double var_right = extract_double_value(argv[8]);
984  ArrayGeoConstraint agc (l_array, var_left, var_top, var_right, var_bottom);
985 
986  agc.set_bounding_box(bb_left, bb_top, bb_right, bb_bottom);
987  // This also reads all of the data into the grid variable
989  *btpp = agc.get_constrained_array();
990  return;
991  break;
992  }
993  case 11: {
994  double var_top = extract_double_value(argv[5]);
995  double var_left = extract_double_value(argv[6]);
996  double var_bottom = extract_double_value(argv[7]);
997  double var_right = extract_double_value(argv[8]);
998  string projection = extract_string_argument(argv[9]);
999  string datum = extract_string_argument(argv[10]);
1000  ArrayGeoConstraint agc(l_array,
1001  var_left, var_top, var_right, var_bottom,
1002  projection, datum);
1003 
1004  agc.set_bounding_box(bb_left, bb_top, bb_right, bb_bottom);
1005  // This also reads all of the data into the grid variable
1007  *btpp = agc.get_constrained_array();
1008  return;
1009  break;
1010  }
1011  default:
1012  throw InternalErr(__FILE__, __LINE__, "Wrong number of args to geoarray.");
1013  }
1014  }
1015  catch (Error & e) {
1016  throw e;
1017  }
1018  catch (exception & e) {
1019  throw
1020  InternalErr(string
1021  ("A C++ exception was thrown from inside geoarray(): ")
1022  + e.what());
1023 
1024  }
1025 
1026  throw InternalErr(__FILE__, __LINE__, "Impossible condition in geoarray.");
1027 }
1028 #endif
1029 
1031 {
1032  ce.add_function("grid", function_grid);
1033  ce.add_function("geogrid", function_geogrid);
1034  ce.add_function("linear_scale", function_linear_scale);
1035 #if 0
1036  ce.add_function("geoarray", function_geoarray);
1037 #endif
1038  ce.add_function("version", function_version);
1039 }
1040 
1041 } // namespace libdap
virtual bool read()
Read data into a local buffer.
Definition: BaseType.cc:790
void gse_delete_buffer(void *buffer)
virtual void add_constraint(Dim_iter i, int start, int stride, int stop)
Adds a constraint to an Array dimension.
Definition: Array.cc:313
virtual bool read_p()
Has this variable been read?
Definition: BaseType.cc:444
string name() const
Returns the name of the class instance.
Definition: BaseType.cc:210
void gse_restart(FILE *in)
#define DODS_DBL_MIN
Definition: dods-limits.h:59
void add_var(BaseType *v, Part p=nil)
Add the BaseType pointer to this constructor type instance.
Definition: Array.cc:176
Contains the attributes for a dataset.
Definition: AttrTable.h:146
#define not_used
Definition: config.h:521
#define malformed_expr
Definition: Error.h:64
Holds an unsigned 16-bit integer.
Definition: UInt16.h:59
virtual void set_read_p(bool state)
Indicates that the data is ready to send.
Definition: Vector.cc:358
virtual BaseType * get_parent()
Definition: BaseType.cc:655
void * gse_string(const char *yy_str)
void register_functions(ConstraintEvaluator &ce)
string extract_string_argument(BaseType *arg)
virtual string get_attr(const string &name, unsigned int i=0)
Definition: AttrTable.cc:799
virtual dods_byte value() const
Definition: Byte.cc:210
GSEClause * get_gsec()
Definition: gse_parser.h:62
#define DODS_DBL_MAX
Definition: dods-limits.h:57
void function_geoarray(int argc, BaseType *argv[], DDS &dds, BaseType **btpp)
Map_iter map_end()
Definition: Grid.cc:547
void set_bounding_box(double top, double left, double bottom, double right)
virtual dods_float64 value() const
Definition: Float64.cc:193
Holds a 32-bit floating point value.
Definition: Float32.h:61
#define DBG2(x)
Definition: debug.h:73
string get_map_max_value() const
Get the maximum map vector value.
Definition: GSEClause.cc:343
void function_linear_scale(int argc, BaseType *argv[], DDS &, BaseType **btpp)
int get_stop() const
Get the stopping index of the clause&#39;s map variable as constrained by this clause.
Definition: GSEClause.cc:314
A class for software fault reporting.
Definition: InternalErr.h:64
virtual BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=0)
Definition: Vector.cc:383
Holds character string data.
Definition: Str.h:64
Map_iter map_begin()
Returns an iterator referencing the first Map vector.
Definition: Grid.cc:539
void set_array_using_double(Array *dest, double *src, int src_len)
#define DBG(x)
Definition: debug.h:58
double * extract_double_array(Array *a)
virtual BaseType * ptr_duplicate()
Definition: Grid.cc:121
Holds a 16-bit signed integer value.
Definition: Int16.h:59
void function_grid(int argc, BaseType *argv[], DDS &, BaseType **btpp)
Type type() const
Returns the type of the class instance.
Definition: BaseType.cc:238
std::vector< dimension >::iterator Dim_iter
Definition: Array.h:152
virtual void set_read_p(bool state)
Sets the value of the read_p property.
Definition: Grid.cc:180
string get_map_min_value() const
Get the minimum map vector value.
Definition: GSEClause.cc:333
virtual void value(dods_byte *b) const
Get a copy of the data held by this variable. Read data from this variable&#39;s internal storage and loa...
Definition: Vector.cc:1457
Holds the Grid data type.
Definition: Grid.h:123
void gse_switch_to_buffer(void *new_buffer)
virtual unsigned int val2buf(void *val, bool reuse=false)
Reads data into the Vector buffer.
Definition: Vector.cc:848
virtual bool set_value(const string &value)
Definition: Str.cc:224
Array * get_array()
Returns the Grid Array. This method returns the array using an Array*, so no cast is required...
Definition: Grid.cc:528
std::vector< BaseType * >::iterator Map_iter
Definition: Grid.h:140
double extract_double_value(BaseType *arg)
virtual unsigned int val2buf(void *val, bool reuse=false)=0
Loads class data.
virtual BaseType * ptr_duplicate()=0
virtual int dimension_stop(Dim_iter i, bool constrained=false)
Return the stop index of the constraint.
Definition: Array.cc:447
string long_to_string(long val, int base)
Definition: util.cc:440
Evaluate a constraint expression.
virtual dods_int32 value() const
Definition: Int32.cc:190
virtual void set_send_p(bool state)
Indicates that the data is ready to send.
Definition: Vector.cc:346
virtual int dimension_start(Dim_iter i, bool constrained=false)
Return the start index of a dimension.
Definition: Array.cc:423
void function_version(int, BaseType *[], DDS &, BaseType **btpp)
int get_start() const
Get the starting index of the clause&#39;s map variable as constrained by this clause.
Definition: GSEClause.cc:297
virtual AttrTable & get_attr_table()
Definition: BaseType.cc:531
string remove_quotes(const string &s)
Definition: util.cc:380
void add_function(const string &name, bool_func f)
Add a boolean function to the list.
virtual dods_uint16 value() const
Definition: UInt16.cc:181
The basic data type for the DODS DAP types.
Definition: BaseType.h:190
virtual Grid * get_constrained_grid() const
void function_geogrid(int argc, BaseType *argv[], DDS &, BaseType **btpp)
Dim_iter dim_begin()
Definition: Array.cc:340
virtual string value() const
Definition: Str.cc:235
Holds a 64-bit (double precision) floating point value.
Definition: Float64.h:62
virtual int length() const
Definition: Vector.cc:524
Holds a single byte.
Definition: Byte.h:63
virtual dods_float32 value() const
Definition: Float32.cc:201
virtual dods_uint32 value() const
Definition: UInt32.cc:183
virtual bool is_simple_type()
Returns true if the instance is a numeric, string or URL type variable.
Definition: BaseType.cc:295
int gse_parse(void *arg)
virtual bool set_value(dods_byte *val, int sz)
set the value of a byte array
Definition: Vector.cc:1272
A class for error processing.
Definition: Error.h:90
Holds a 32-bit unsigned integer.
Definition: UInt32.h:61
virtual Array * get_constrained_array() const
A multidimensional array of identical data types.
Definition: Array.h:101
bool double_eq(double lhs, double rhs, double epsilon=1.0e-5)
string get_map_name() const
Get the name of the map variable constrained by this clause.
Definition: GSEClause.cc:288
Holds a 32-bit signed integer.
Definition: Int32.h:62
virtual void apply_constraint_to_data()
virtual dods_int16 value() const
Definition: Int16.cc:179