32#include <libdap/BaseType.h>
33#include <libdap/Int32.h>
34#include <libdap/Str.h>
35#include <libdap/Array.h>
36#include <libdap/Structure.h>
38#include <libdap/D4RValue.h>
39#include <libdap/Error.h>
40#include <libdap/debug.h>
41#include <libdap/util.h>
42#include <libdap/ServerFunctionsList.h>
46#include "BBoxFunction.h"
54#define UNWIND_BBOX_CODE 1
61unique_ptr<Array> bbox_helper(
double min_value,
double max_value, Array* the_array)
64 vector<double> the_values;
65 extract_double_array(the_array, the_values);
68 unsigned int rank = the_array->dimensions();
69 unique_ptr<Array> response = roi_bbox_build_empty_bbox(rank, the_array->name());
73 unsigned int X = the_array->dimension_size(the_array->dim_begin());
74 bool found_start =
false;
75 unsigned int start = 0;
76 for (
unsigned int i = 0; i < X && !found_start; ++i) {
77 if (the_values[i] >= min_value && the_values[i] <= max_value) {
84 ostringstream oss(
"In function bbox(): No values between ", std::ios::ate);
85 oss << min_value <<
" and " << max_value <<
" were found in the array '" << the_array->name() <<
"'";
86 throw Error(oss.str());
88 bool found_stop =
false;
89 unsigned int stop = X - 1;
90 for (
int i = X - 1; i >= 0 && !found_stop; --i) {
91 if (the_values[i] >= min_value && the_values[i] <= max_value) {
92 stop = (
unsigned int) (i);
97 if (!found_stop)
throw InternalErr(__FILE__, __LINE__,
"In BBoxFunction: Found start but not stop.");
99 Structure*
slice = roi_bbox_build_slice(start, stop, the_array->dimension_name(the_array->dim_begin()));
100 response->set_vec_nocopy(0,
slice);
105 Array::Dim_iter rows = the_array->dim_begin(), cols = the_array->dim_begin() + 1;
106 unsigned int Y = the_array->dimension_size(rows);
107 unsigned int X = the_array->dimension_size(cols);
108 unsigned int x_start = X - 1;
109 unsigned int y_start = 0;
110 bool found_y_start =
false;
112 for (
unsigned int j = 0; j < Y; ++j) {
113 bool found_x_start =
false;
114 for (
unsigned int i = 0; i < X && !found_x_start; ++i) {
115 unsigned int ind = j * X + i;
116 if (the_values[ind] >= min_value && the_values[ind] <= max_value) {
117 x_start = min(i, x_start);
118 found_x_start =
true;
119 if (!found_y_start) {
121 found_y_start =
true;
127 if (!found_y_start) {
128 ostringstream oss(
"In function bbox(): No values between ", std::ios::ate);
129 oss << min_value <<
" and " << max_value <<
" were found in the array '" << the_array->name() <<
"'";
130 throw Error(oss.str());
132 unsigned int x_stop = 0;
133 unsigned int y_stop = 0;
134 bool found_y_stop =
false;
136 for (
int j = Y - 1; j >= (int) (y_start); --j) {
137 bool found_x_stop =
false;
138 for (
int i = X - 1; i >= 0 && !found_x_stop; --i) {
139 unsigned int ind = j * X + i;
140 if (the_values[ind] >= min_value && the_values[ind] <= max_value) {
141 x_stop = max((
unsigned int) (i), x_stop);
151 if (!found_y_stop)
throw InternalErr(__FILE__, __LINE__,
"In BBoxFunction: Found start but not stop.");
153 response->set_vec_nocopy(0, roi_bbox_build_slice(y_start, y_stop, the_array->dimension_name(rows)));
154 response->set_vec_nocopy(1, roi_bbox_build_slice(x_start, x_stop, the_array->dimension_name(cols)));
158 Odometer::shape shape(rank);
160 for (Array::Dim_iter i = the_array->dim_begin(), e = the_array->dim_end(); i != e; ++i) {
161 shape.at(j++) = the_array->dimension_size(i);
164 Odometer::shape indices(rank);
165 Odometer::shape min = shape;
166 Odometer::shape max(rank, 0);
169 if (the_values[odometer.offset()] >= min_value && the_values[odometer.offset()] <= max_value) {
171 odometer.indices(indices);
172 Odometer::shape::iterator m = min.begin();
173 Odometer::shape::iterator x = max.begin();
174 for (Odometer::shape::iterator i = indices.begin(), e = indices.end(); i != e; ++i, ++m, ++x) {
175 if (*i < *m) *m = *i;
177 if (*i > *x) *x = *i;
180 }
while (odometer.next() != odometer.end());
184 if (min[0] == shape[0]) {
185 ostringstream oss(
"In function bbox(): No values between ", std::ios::ate);
186 oss << min_value <<
" and " << max_value <<
" were found in the array '" << the_array->name() <<
"'";
187 throw Error(oss.str());
189 Odometer::shape::iterator m = min.begin();
190 Odometer::shape::iterator x = max.begin();
191 Array::Dim_iter d = the_array->dim_begin();
192 for (
unsigned int i = 0; i < rank; ++i, ++m, ++x, ++d) {
193 response->set_vec_nocopy(i, roi_bbox_build_slice(*m, *x, the_array->dimension_name(d)));
199 response->set_read_p(
true);
200 response->set_send_p(
true);
229function_dap2_bbox(
int argc, BaseType *argv[], DDS &, BaseType **btpp)
231 const string wrong_args =
"Wrong number of arguments to bbox(). Expected an Array and minimum and maximum values (3 arguments)";
235 throw Error(malformed_expr, wrong_args);
240 throw Error(malformed_expr, wrong_args);
243 if (argv[0] && argv[0]->type() != dods_array_c)
244 throw Error(
"In function bbox(): Expected argument 1 to be an Array.");
245 if (!argv[0]->var()->is_simple_type() || argv[0]->var()->type() == dods_str_c || argv[0]->var()->type() == dods_url_c)
246 throw Error(
"In function bbox(): Expected argument 1 to be an Array of numeric types.");
249 Array *the_array =
static_cast<Array*
>(argv[0]);
250 BESDEBUG(
"bbox",
"the_array: " << the_array->name() <<
": " << (
void*)the_array << endl);
254 the_array->set_read_p(
true);
256 double min_value = extract_double_value(argv[1]);
257 double max_value = extract_double_value(argv[2]);
260 unique_ptr<Array> response = bbox_helper(min_value, max_value, the_array);
262 *btpp = response.release();
277BaseType *function_dap4_bbox(D4RValueList * , DMR & )
279 throw Error(malformed_expr,
"Not yet implemented for DAP4 functions.");