// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* // ** Copyright UCAR (c) 1990 - 2016 // ** University Corporation for Atmospheric Research (UCAR) // ** National Center for Atmospheric Research (NCAR) // ** Boulder, Colorado, USA // ** BSD licence applies - redistribution and use in source and binary // ** forms, with or without modification, are permitted provided that // ** the following conditions are met: // ** 1) If the software is modified to produce derivative works, // ** such modified software should be clearly marked, so as not // ** to confuse it with the version available from UCAR. // ** 2) Redistributions of source code must retain the above copyright // ** notice, this list of conditions and the following disclaimer. // ** 3) Redistributions in binary form must reproduce the above copyright // ** notice, this list of conditions and the following disclaimer in the // ** documentation and/or other materials provided with the distribution. // ** 4) Neither the name of UCAR nor the names of its contributors, // ** if any, may be used to endorse or promote products derived from // ** this software without specific prior written permission. // ** DISCLAIMER: THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS // ** OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED // ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* ///////////////////////////////////////////////////////////// // BdryPolyline // // C++ wrapper for boundary polyline data. // // Nancy Rehak, RAP, NCAR // POBox 3000, Boulder, CO, USA // // March 2005 ////////////////////////////////////////////////////////////// #include #include #include #include #include using namespace std; // constructor BdryPolyline::BdryPolyline(const int num_secs_extrap, const string &label) : _numSecsExtrap(num_secs_extrap), _label(label), _numSpare(0) { } // destructor BdryPolyline::~BdryPolyline() { } /************************************************************************ * assemble() - Load up the given buffer from the object. Handles byte * swapping. * * Returns true on success, false on failure. */ bool BdryPolyline::assemble(MemBuf &mem_buf) const { BDRY_spdb_polyline_t spdb_polyline; memset(&spdb_polyline, 0, sizeof(BDRY_spdb_polyline_t)); spdb_polyline.num_pts = _points.size(); spdb_polyline.num_secs = _numSecsExtrap; for (int i=0; i<_numSpare; ++i) { spdb_polyline.spare[i] = _spare[i]; } STRcopy(spdb_polyline.object_label, _label.c_str(), BDRY_LABEL_LEN); _polylineToBE(spdb_polyline); mem_buf.add((void *)&spdb_polyline, sizeof(BDRY_spdb_polyline_t) - sizeof(BDRY_spdb_point_t)); /* * Add each of the points in the polyline to the buffer. */ vector< BdryPoint >::const_iterator point; for (point = _points.begin(); point != _points.end(); ++point) point->assemble(mem_buf); return true; } /************************************************************************ * disassemble() - Disassembles a buffer, sets the object values. Handles * byte swapping. * * Returns true on success, false on failure. */ bool BdryPolyline::disassemble(char *&buf, int &len) { static const string method_name = "BdryPolyline::disassemble()"; int polyline_size = sizeof(BDRY_spdb_polyline_t) - sizeof(BDRY_spdb_point_t); if (polyline_size > len) { cerr << "ERROR: " << method_name << endl; cerr << "Incoming buffer too small for product" << endl; return false; } BDRY_spdb_polyline_t *spdb_polyline = (BDRY_spdb_polyline_t *)buf; _polylineFromBE(*spdb_polyline); _numSecsExtrap = spdb_polyline->num_secs; _label = spdb_polyline->object_label; for (int i=0; ispare[i]; if (_spare[i] != 0) { _numSpare = i+1; } } buf += polyline_size; len -= polyline_size; for (int j = 0; j < spdb_polyline->num_pts; j++) { BdryPoint point; if (!point.disassemble(buf, len)) return false; _points.push_back(point); } /* endfor - j */ return true; } /************************************************************************ * extrapolate(): Extrapolate the polyline using simple extrapolation of * each point in the boundary using the given speed (in m/s) * and direction. * * Note: This method updates the polyline in place with the resulting * extrapolation locations. */ void BdryPolyline::extrapolate(const int extrap_secs, const double speed, const double direction) { /* * Calculate the distance each point will move in the * given extrapolation time. Note that the detection * speed is given in m/s and extrapolation time is given * in seconds. */ double extrap_km = (speed * extrap_secs) / 1000.0; /* * Now extrapolate each point in the polyline. */ vector< BdryPoint >::iterator point; for (point = _points.begin(); point != _points.end(); ++point) { double extrap_lat, extrap_lon; Pjg::latlonPlusRTheta(point->getLat(), point->getLon(), extrap_km, direction, extrap_lat, extrap_lon); point->setLocation(extrap_lat, extrap_lon); } /* endfor - point */ return; } /************************************************************************ * extrapPointMotion(): Extrapolate the polyline using the motion vectors * associated with each point on the polyline. * * Note: This method updates the polyline in place with the resulting * extrapolation locations. */ void BdryPolyline::extrapPointMotion(const int extrap_secs) { // Extrapolate each point in the polyline vector< BdryPoint >::iterator point; for (point = _points.begin(); point != _points.end(); ++point) { double ucomp = point->getUComp(); double vcomp = point->getVComp(); // If the values of u and v are valid, move the point accordingly. // If the values are not valid, do not move the point at all, i.e. // do nothing. if (ucomp != BDRY_VALUE_UNKNOWN && vcomp != BDRY_VALUE_UNKNOWN) { // Find the speed and direction of the boundary at this // point. Note that speed is in m/s and direction is // in radar degrees. double bdry_pt_speed, bdry_pt_dir; _uv2SpeedDir(ucomp, vcomp, bdry_pt_speed, bdry_pt_dir); // Calculate the distance the point will move in the // given extrapolation time. double extrap_km = (bdry_pt_speed * extrap_secs) / 1000.0; double extrap_lat, extrap_lon; Pjg::latlonPlusRTheta(point->getLat(), point->getLon(), extrap_km, bdry_pt_dir, extrap_lat, extrap_lon); point->setLocation(extrap_lat, extrap_lon); } /* endif */ } /* endfor - point */ return; } /************************************************************************ * print(): Print the boundary polyline to the given stream. */ void BdryPolyline::print(FILE *stream, const bool print_points) const { fprintf(stream, "\nBoundary Polyline:\n"); fprintf(stream, "\n"); fprintf(stream, " num_pts = %d\n", (int) _points.size()); fprintf(stream, " num_secs = %d\n", _numSecsExtrap); fprintf(stream, " object_label = <%s>\n", _label.c_str()); if (print_points) { vector< BdryPoint >::const_iterator point; for (point = _points.begin(); point != _points.end(); ++point) { point->print(stream); fprintf(stream, "\n"); } } } void BdryPolyline::print(ostream &stream, const bool print_points) const { stream << endl; stream << "Boundary Polyline:" << endl; stream << endl; stream << " num_pts = " << _points.size() << endl; stream << " num_secs = " << _numSecsExtrap << endl; stream << " object_label = <" << _label << ">" << endl; if (print_points) { vector< BdryPoint >::const_iterator point; for (point = _points.begin(); point != _points.end(); ++point) { point->print(stream); stream << endl; } } } /************************************************************************ * STATIC ROUTINES ************************************************************************/ /************************************************************************ * _polylineFromBE(): Convert a boundary polyline structure from big-endian * format to native format. */ void BdryPolyline::_polylineFromBE(BDRY_spdb_polyline_t &polyline) { polyline.num_pts = BE_to_si32(polyline.num_pts); polyline.num_secs = BE_to_si32(polyline.num_secs); BE_to_array_32(polyline.spare, sizeof(polyline.spare)); /* object_label is okay */ return; } /************************************************************************ * _polylineToBE(): Convert a boundary polyline structure from native * format to big-endian format. */ void BdryPolyline::_polylineToBE(BDRY_spdb_polyline_t &polyline) { polyline.num_pts = BE_from_si32(polyline.num_pts); polyline.num_secs = BE_from_si32(polyline.num_secs); BE_from_array_32(polyline.spare, sizeof(polyline.spare)); /* object_label is okay */ return; } /************************************************************************ * _uv2SpeedDir(): Convert U/V values to speed and direction clockwise * from true north (i.e. radar coordinates). * * Note: u and v can be in any speed units, direction is returned in * degrees and speed is returned in the same units as u and v. */ void BdryPolyline::_uv2SpeedDir(const double u, const double v, double &speed, double &direction) { double dir_rad; // Get the direction of the wind vector. // wind dir = inv tan(v/u) (in polar coordinates) // Check special cases first. if (u == 0.0) { if (v == 0.0) dir_rad = 0.0; else if (v < 0) dir_rad = PI * -1/2.0; else dir_rad = PI/2.0; } else if (v == 0.0) { if (u < 0) dir_rad = PI; else dir_rad = 0.0; } else { dir_rad = atan2(v, u); } // Convert to degrees. // 1 radian = (180/pi) degrees direction = dir_rad * RAD_TO_DEG; // Convert polar to "radar" coordinates. direction = 90.0 - direction; // Put in range [0.0, 360) while (direction < 0.0) direction += 360.0; // Get the speed of the wind vector. // wind speed = sqrt(u^2 + v^2) speed = sqrt(u*u + v*v); }