// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* // ** 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. // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* ///////////////////////////////////////////////////////////// // Bdry.cc // // C++ wrapper for generic polyline/polygon data. // // Nancy Rehak, RAP, NCAR // POBox 3000, Boulder, CO, USA // // March 2005 ////////////////////////////////////////////////////////////// #include #include #include #include #include using namespace std; /* * Define values used for parsing the input file. */ #define PRODUCT_KEY "PRODUCT " #define GENERATE_TIME_KEY "GENERATE_TIME" #define PRODUCT_TIME_KEY "PRODUCT_TIME" #define PRODUCT_DESC_KEY "PRODUCT_DESCRIPTION" #define PRODUCT_MOTION_KEY "PRODUCT_MOTION" #define DETECTION_ATTR_KEY "DETECTION_ATTR" #define POLYLINE_KEY "POLYLINE" /* * Define values used for parsing data type */ #define MASK1 255 #define MASK2 65280 #define MASK3 16711935 #define SUBTYPE_BIAS 99 /* * Define tables for converting input line values to structure * values. */ const Bdry::parse_table_t Bdry::Type_table[] = { { "BDT", BDRY_TYPE_BDRY_TRUTH }, { "BDM", BDRY_TYPE_BDRY_MIGFA }, { "BDC", BDRY_TYPE_BDRY_COLIDE }, { "ANI", BDRY_TYPE_COMB_NC_ISSUE }, { "ANV", BDRY_TYPE_COMB_NC_VALID }, { "AXI", BDRY_TYPE_EXTRAP_ISSUE_ANW }, { "AXV", BDRY_TYPE_EXTRAP_VALID_ANW }, { "FGI", BDRY_TYPE_FIRST_GUESS_ISSUE }, { "FGV", BDRY_TYPE_FIRST_GUESS_VALID }, { "MMI", BDRY_TYPE_MINMAX_NC_ISSUE }, { "MMV", BDRY_TYPE_MINMAX_NC_VALID } }; const int Bdry::Type_table_size = sizeof(Bdry::Type_table) / sizeof(Bdry::parse_table_t); const Bdry::parse_table_t Bdry::Subtype_table[] = { { "ALL", BDRY_SUBTYPE_ALL } }; const int Bdry::Subtype_table_size = sizeof(Bdry::Subtype_table) / sizeof(Bdry::parse_table_t); const Bdry::parse_table_t Bdry::Line_type_table[] = { { "COMBINED_LINE", BDRY_LINE_TYPE_COMBINED }, { "EXTRAPOLATED_LINE", BDRY_LINE_TYPE_EXTRAPOLATED }, { "SHEAR_LINE", BDRY_LINE_TYPE_SHEAR }, { "THIN_LINE", BDRY_LINE_TYPE_THIN }, { "EMPTY_LINE", BDRY_LINE_TYPE_EMPTY }, { "GENERIC_LINE", BDRY_LINE_TYPE_GENERIC} }; const int Bdry::Line_type_table_size = sizeof(Bdry::Line_type_table) / sizeof(Bdry::parse_table_t); const string Bdry::UNKNOWN_VALUE_STRING = "unknown value"; /************************************************************************ * Constructors */ Bdry::Bdry() { clear(); } Bdry::Bdry(const time_t &data_time, const int extrap_seconds, const time_t &expire_time, const std::string &typeString, const std::string subtypeString, const int sequence, const int linetype, const int id, const std::string &description, const double motion_direction, const double motion_speed, const double quality, const double qual_thresh) { clear(); _type = _typeString2Type(typeString.c_str()); _subtype = _subtypeString2Subtype(subtypeString.c_str()); // _subtype_sring = subtypeString; // _line_type_string = typeString; _sequenceNum = sequence; _groupId = 0; _generateTime = time(NULL); _dataTime = data_time; _forecastTime = data_time + extrap_seconds; _expireTime = expire_time; _lineType = linetype; _bdryId = id; _motionDirection = motion_direction; _motionSpeed = motion_speed; _lineQualityValue = quality; _lineQualityThreshold = qual_thresh; _description = description; } /************************************************************************ * Destructor */ Bdry::~Bdry() { } /************************************************************************ * clear() - Clear out all of the information in this boundary. */ void Bdry::clear() { _numSpareFloat = 0; } /************************************************************************ * disassemble() - Disassembles a buffer, sets the object values. Handles * byte swapping. * * Returns true on success, false on failure. */ bool Bdry::disassemble(const void *buf, int len) { static const string method_name = "Bdry::disassemble()"; char *spdb_ptr = (char *)buf; BDRY_spdb_product_t *spdb_product = (BDRY_spdb_product_t *)spdb_ptr; int product_size = sizeof(BDRY_spdb_product_t) - sizeof(BDRY_spdb_polyline_t); if (product_size > len) { cerr << "ERROR: " << method_name << endl; cerr << "Incoming buffer too small for product" << endl; return false; } _spdbProductFromBE(*spdb_product); /* * Make sure to clear out the current information. */ clear(); /* * Update the high level boundary information. */ _type = spdb_product->type; _subtype = spdb_product->subtype; _sequenceNum = spdb_product->sequence_num; _groupId = spdb_product->group_id; _generateTime = spdb_product->generate_time; _dataTime = spdb_product->data_time; _forecastTime = spdb_product->forecast_time; _expireTime = spdb_product->expire_time; _lineType = spdb_product->line_type; _bdryId = spdb_product->bdry_id; _motionDirection = spdb_product->motion_direction; _motionSpeed = spdb_product->motion_speed; _lineQualityValue = spdb_product->line_quality_value; _lineQualityThreshold = spdb_product->line_quality_thresh; _description = spdb_product->desc; for (int i=0; ispare_float[i]; if (_spare_float[i] != 0.0) { _numSpareFloat = i+1; } } /* * Now create each polyline. */ spdb_ptr += product_size; int spdb_len = len - product_size; for (int i = 0; i < spdb_product->num_polylines; i++) { BdryPolyline polyline; if (!polyline.disassemble(spdb_ptr, spdb_len)) return false; _polylines.push_back(polyline); } /* endfor - i */ return true; } /************************************************************************ * assemble() - Load up the buffer from the object. Handles byte swapping. * * Returns true on success, false on failure. */ bool Bdry::assemble() { // Initialize the buffer _memBuf.reset(); // load the product information /* * Put the main product information into the buffer. */ BDRY_spdb_product_t spdb_product; memset(&spdb_product, 0, sizeof(spdb_product)); spdb_product.type = _type; spdb_product.subtype = _subtype; spdb_product.sequence_num = _sequenceNum; spdb_product.group_id = _groupId; spdb_product.generate_time = _generateTime.utime(); spdb_product.data_time = _dataTime.utime(); spdb_product.forecast_time = _forecastTime.utime(); spdb_product.expire_time = _expireTime.utime(); spdb_product.line_type = _lineType; spdb_product.bdry_id = _bdryId; spdb_product.num_polylines = _polylines.size(); spdb_product.motion_direction = _motionDirection; spdb_product.motion_speed = _motionSpeed; spdb_product.line_quality_value = _lineQualityValue; spdb_product.line_quality_thresh = _lineQualityThreshold; STRcopy(spdb_product.type_string, _type2String(_type).c_str(), BDRY_TYPE_LEN); STRcopy(spdb_product.subtype_string, _subtype2String(_subtype).c_str(), BDRY_TYPE_LEN); STRcopy(spdb_product.line_type_string, _lineType2String(_lineType).c_str(), BDRY_LINE_TYPE_LEN); STRcopy(spdb_product.desc, _description.c_str(), BDRY_DESC_LEN); for (int i=0; i<_numSpareFloat; ++i) { spdb_product.spare_float[i] = _spare_float[i]; } _spdbProductToBE(spdb_product); _memBuf.add((void *)&spdb_product, sizeof(BDRY_spdb_product_t) - sizeof(BDRY_spdb_polyline_t)); /* * Now add each of the polylines to the buffer. */ vector< BdryPolyline >::const_iterator polyline; for (polyline = _polylines.begin(); polyline != _polylines.end(); ++polyline) polyline->assemble(_memBuf); return true; } void Bdry::addSpareFloat(const fl32 v) { if (_numSpareFloat >= BDRY_SPARE_FLOAT_LEN) { // give a warning here return; } _spare_float[_numSpareFloat++] = v; } /************************************************************************ * init(): Initializes the Boundary basd on the SIO shape information read * in from an ASCII file. * * Returns true on success, false on failure. */ void Bdry::init(const SIO_shape_data_t &shape) { /* * Update the main product information */ _type = _typeString2Type(shape.type); _subtype = _subtypeString2Subtype(shape.sub_type); _sequenceNum = shape.sequence_number; _groupId = shape.group_id; _generateTime = shape.gen_time; _dataTime = shape.data_time; _forecastTime = shape.valid_time; _expireTime = shape.expire_time; _lineType = _lineTypeString2LineType(shape.line_type); _motionDirection = shape.motion_dir; _motionSpeed = shape.motion_speed; _lineQualityValue = shape.qual_value; _lineQualityThreshold = shape.qual_thresh; _description = shape.description; _bdryId = atoi(_description.c_str()); /* * Update the data for each of the polylines. */ for (int obj = 0; obj < shape.num_objects; obj++) { BdryPolyline polyline(shape.P[obj].nseconds, shape.P[obj].object_label); for (int pt = 0; pt < shape.P[obj].npoints; pt++) { BdryPoint point(shape.P[obj].lat[pt], shape.P[obj].lon[pt]); if (shape.P[obj].u_comp == NULL) point.setUComp(BDRY_VALUE_UNKNOWN); else if (shape.P[obj].u_comp[pt] == SIO_MISSING_UV) point.setUComp(BDRY_VALUE_UNKNOWN); else point.setUComp(shape.P[obj].u_comp[pt]); if (shape.P[obj].v_comp == NULL) point.setVComp(BDRY_VALUE_UNKNOWN); else if (shape.P[obj].v_comp[pt] == SIO_MISSING_UV) point.setVComp(BDRY_VALUE_UNKNOWN); else point.setVComp(shape.P[obj].v_comp[pt]); if (shape.P[obj].value == NULL) point.setSteeringFlow(0); else point.setSteeringFlow(shape.P[obj].value[pt]); polyline.addPoint(point); } /* endfor - pt */ } /* endfor - obj */ } /************************************************************************ * print(): Print the boundary to the given stream. */ void Bdry::print(FILE *stream, const bool print_points) const { fprintf(stream, "\nBoundary Product:\n"); fprintf(stream, "\n"); fprintf(stream, " type = %d\n", _type); fprintf(stream, " subtype = %d\n", _subtype); fprintf(stream, " sequence_num = %d\n", _sequenceNum); fprintf(stream, " group_id = %d\n", _groupId); fprintf(stream, " generate_time = %s\n", _generateTime.dtime()); fprintf(stream, " data_time = %s\n", _dataTime.dtime()); fprintf(stream, " forecast_time = %s\n", _forecastTime.dtime()); fprintf(stream, " expire_time = %s\n", _expireTime.dtime()); fprintf(stream, " line_type = %d\n", _lineType); fprintf(stream, " bdry_id = %d\n", _bdryId); fprintf(stream, " num_polylines = %d\n", (int) _polylines.size()); fprintf(stream, " motion_direction = %f\n", _motionDirection); fprintf(stream, " motion_speed = %f\n", _motionSpeed); fprintf(stream, " line_quality_value = %f\n", _lineQualityValue); fprintf(stream, " line_quality_thresh = %f\n", _lineQualityThreshold); fprintf(stream, " type_string = <%s>\n", _type2String(_type).c_str()); fprintf(stream, " subtype_string = <%s>\n", _subtype2String(_subtype).c_str()); fprintf(stream, " line_type_string = <%s>\n", _lineType2String(_lineType).c_str()); fprintf(stream, " desc = <%s>\n", _description.c_str()); vector< BdryPolyline >::const_iterator polyline; for (polyline = _polylines.begin(); polyline!= _polylines.end(); ++polyline) polyline->print(stream, print_points); } void Bdry::print(ostream &stream, const bool print_points) const { stream << endl; stream << "Boundary Product:" << endl; stream << endl; stream << " type = " << _type << endl; stream << " subtype = " << _subtype << endl; stream << " sequence_num = " << _sequenceNum << endl; stream << " group_id = " << _groupId << endl; stream << " generate_time = " << _generateTime << endl; stream << " data_time = " << _dataTime << endl; stream << " forecast_time = " << _forecastTime << endl; stream << " expire_time = " << _expireTime << endl; stream << " line_type = " << _lineType << endl; stream << " bdry_id = " << _bdryId << endl; stream << " num_polylines = " << _polylines.size() << endl; stream << " motion_direction = " << _motionDirection << endl; stream << " motion_speed = " << _motionSpeed << endl; stream << " line_quality_value = " << _lineQualityValue << endl; stream << " line_quality_thresh = " << _lineQualityThreshold << endl; stream << " type_string = <" << _type2String(_type) << ">" << endl; stream << " subtype_string = <" << _subtype2String(_subtype) << ">" << endl; stream << " line_type_string = <" << _lineType2String(_lineType) << ">" << endl; stream << " desc = <" << _description << ">" << endl; vector< BdryPolyline >::const_iterator polyline; for (polyline = _polylines.begin(); polyline != _polylines.end(); ++polyline) polyline->print(stream, print_points); } /************************************************************************ * toSIOShape(): Converts the boundary into the internal SIO shape structure. * * Returns a pointer to memory allocated by this routine that should be * freed by the calling routine. Returns NULL if there is an error. */ SIO_shape_data_t *Bdry::toSIOShape() { /* * Allocate space for the returned structure. */ SIO_shape_data_t *shape = (SIO_shape_data_t *)umalloc(sizeof(SIO_shape_data_t)); /* * Update the main shape structure. */ shape->type = STRdup(_type2String(_type).c_str()); shape->sub_type = STRdup(_subtype2String(_subtype).c_str()); shape->sequence_number = _sequenceNum; shape->group_id = _groupId; shape->gen_time = _generateTime.utime(); shape->data_time = _dataTime.utime(); shape->valid_time = _forecastTime.utime(); shape->expire_time = _expireTime.utime(); STRcopy(shape->description, _description.c_str(), SIO_LABEL_LEN); shape->motion_dir = _motionDirection; shape->motion_speed = _motionSpeed; shape->line_type = STRdup(_lineType2String(_lineType).c_str()); shape->qual_value = _lineQualityValue; shape->qual_thresh = _lineQualityThreshold; shape->num_objects = _polylines.size(); /* * Allocate space for the object structures. */ shape->P = (SIO_polyline_object_t *)umalloc(shape->num_objects * sizeof(SIO_polyline_object_t)); /* * Update the data for each of the objects. */ for (int obj = 0; obj < shape->num_objects; obj++) { SIO_polyline_object_t *object = &(shape->P[obj]); STRcopy(object->object_label, _polylines[obj].getLabel().c_str(), SIO_LABEL_LEN); object->nseconds = _polylines[obj].getNumSecsExtrap(); /* * Allocate space for the point arrays */ const vector< BdryPoint > points = _polylines[obj].getPoints(); object->npoints = points.size(); object->lat = (float *)umalloc(object->npoints * sizeof(float)); object->lon = (float *)umalloc(object->npoints * sizeof(float)); object->u_comp = (float *)umalloc(object->npoints * sizeof(float)); object->v_comp = (float *)umalloc(object->npoints * sizeof(float)); object->value = (float *)umalloc(object->npoints * sizeof(float)); /* * Set the point array values. */ for (int pt = 0; pt < object->npoints; pt++) { object->lat[pt] = points[pt].getLat(); object->lon[pt] = points[pt].getLon(); object->u_comp[pt] = points[pt].getUComp(); object->v_comp[pt] = points[pt].getVComp(); object->value[pt] = points[pt].getSteeringFlow(); } /* endfor - pt */ } /* endfor - obj */ return(shape); } /************************************************************************ * spdb2PjgDirection(): Converts the SPDB direction value to the * value used by PJG routines. * * Colide stores the direction using cartesian coordinates where * 0 degrees is along the X axis and degrees increase counter- * clockwise. PJG uses map coordinates, where 0 degrees is * north and degrees increase clockwise. Both give the angle we are * moving TO. */ double Bdry::spdb2PjgDirection(const double spdb_direction) { double pjg_direction; pjg_direction = 90.0 - spdb_direction; while (pjg_direction < 0.0) pjg_direction += 360.0; while (pjg_direction >= 360.0) pjg_direction -= 360.0; return pjg_direction; } /************************************************************************ * getSpdbDataType(): Sets data type so that first 8 bits (from lowest * order bit to highest order bit) are the * boundary type, the next 8 bits are the subtype * and the last 8 bits are the forecast period. * A constant value is subtracted from the subtype * to ensure the value will fit in the 8 bits given * to it. */ si32 Bdry::getSpdbDataType() const { int forecast_period = _forecastTime.utime() - _dataTime.utime(); int word = 0; si32 data_type = 0; word = forecast_period; word <<= 16; data_type = ((data_type) | word); word = _subtype - SUBTYPE_BIAS; word <<= 8; data_type = ((data_type) | word); word = _type; data_type = ((data_type) | word); return data_type; } /************************************************************************ * parseDataType(): Parses the data type field into type, subtype * and forecast period, assuming that the data type * was created such that the first 8 bits (from * lowest order bit to highest order bit) are the * boundary type, the next 8 bits are the subtype * and the last 8 bits are the forecast period. * A constant value is added back to the subtype * since it should have been subtracted off in * the creation of the data type to ensure that the * subtype value would fit into the 8 bits assigned * to it. */ void Bdry::parseDataType(const si32 data_type) { _type = (MASK1 & data_type); _subtype = ((MASK2 & data_type) >> 8) + SUBTYPE_BIAS; int forecast_period = (MASK3 & data_type) >> 16; _forecastTime = _dataTime + forecast_period; } /************************************************************************ * STATIC ROUTINES ************************************************************************/ /************************************************************************ * _convertParseValue(): Convert a string value read in from the input * file into the corresponding integer value using * the given parse table. */ int Bdry::_convertParseValue(const char *string, const parse_table_t *parse_table, const int parse_table_size) { for (int i = 0; i < parse_table_size; i++) if (STRequal_exact(string, parse_table[i].parse_string)) return parse_table[i].parse_value; return BDRY_VALUE_UNKNOWN; } /************************************************************************ * _convertStringValue(): Convert an integer value into the corresponding * string using the given parse table. */ string Bdry::_convertStringValue(const int parse_value, const parse_table_t *parse_table, const int parse_table_size) { for (int i = 0; i < parse_table_size; i++) if (parse_table[i].parse_value == parse_value) return parse_table[i].parse_string; return UNKNOWN_VALUE_STRING; } /************************************************************************ * _getExtrapolatedProdType(): Parse the product type line to see if * it's an extrapolated product. */ int Bdry::_getExtrapolatedProdType(const char *type_string) { int prod_type; switch(type_string[0]) { case 'E' : prod_type = BDRY_TYPE_EXTRAP_ISSUE_MIGFA; break; case 'V' : prod_type = BDRY_TYPE_EXTRAP_VALID; break; case 'X' : prod_type = BDRY_TYPE_EXTRAP_ISS_COLIDE; break; default : return(BDRY_VALUE_UNKNOWN); } /* endswitch */ return prod_type; } /************************************************************************ * _getExtrapolatedProdTypeString(): Convert an extrapolated product type * to a string. */ string Bdry::_getExtrapolatedProdTypeString(const int prod_type) { switch(prod_type) { case BDRY_TYPE_EXTRAP_ISSUE_MIGFA : return "E"; case BDRY_TYPE_EXTRAP_VALID : return "V"; case BDRY_TYPE_EXTRAP_ISS_COLIDE : return "X"; default : return UNKNOWN_VALUE_STRING; } /* endswitch */ } /************************************************************************ * _lineType2String(): Converts the line type value to a string. */ string Bdry::_lineType2String(const int line_type) { return(_convertStringValue(line_type, Line_type_table, Line_type_table_size)); } /************************************************************************ * _lineTypeString2LineType(): Returns the integer line type * for a given line type string. */ int Bdry::_lineTypeString2LineType(const char *line_type_string) { return(_convertParseValue(line_type_string, Line_type_table, Line_type_table_size)); } int Bdry::_lineTypeString2LineType(const string &line_type_string) { return(_lineTypeString2LineType(line_type_string.c_str())); } /************************************************************************ * _spdbProductFromBE(): Convert a boundary product from big-endian * format to native format. */ void Bdry::_spdbProductFromBE(BDRY_spdb_product_t &prod) { prod.type = BE_to_si32(prod.type); prod.subtype = BE_to_si32(prod.subtype); prod.sequence_num = BE_to_si32(prod.sequence_num); prod.group_id = BE_to_si32(prod.group_id); prod.generate_time = BE_to_si32(prod.generate_time); prod.data_time = BE_to_si32(prod.data_time); prod.forecast_time = BE_to_si32(prod.forecast_time); prod.expire_time = BE_to_si32(prod.expire_time); prod.line_type = BE_to_si32(prod.line_type); prod.bdry_id = BE_to_si32(prod.bdry_id); prod.num_polylines = BE_to_si32(prod.num_polylines); BE_to_array_32(prod.spare_int, BDRY_SPARE_INT_LEN * sizeof(si32)); BE_to_array_32(&prod.motion_direction, 4); BE_to_array_32(&prod.motion_speed, 4); BE_to_array_32(&prod.line_quality_value, 4); BE_to_array_32(&prod.line_quality_thresh, 4); BE_to_array_32(prod.spare_float, BDRY_SPARE_FLOAT_LEN * sizeof(fl32)); /* type_string is okay */ /* subtype_string is okay */ /* line_type_string is okay */ /* desc is okay */ } /************************************************************************ * _spdbProductToBE(): Convert a boundary product from native format * to big-endian format. */ void Bdry::_spdbProductToBE(BDRY_spdb_product_t &prod) { prod.type = BE_from_si32(prod.type); prod.subtype = BE_from_si32(prod.subtype); prod.sequence_num = BE_from_si32(prod.sequence_num); prod.group_id = BE_from_si32(prod.group_id); prod.generate_time = BE_from_si32(prod.generate_time); prod.data_time = BE_from_si32(prod.data_time); prod.forecast_time = BE_from_si32(prod.forecast_time); prod.expire_time = BE_from_si32(prod.expire_time); prod.line_type = BE_from_si32(prod.line_type); prod.bdry_id = BE_from_si32(prod.bdry_id); prod.num_polylines = BE_from_si32(prod.num_polylines); BE_from_array_32(prod.spare_int, BDRY_SPARE_INT_LEN * sizeof(si32)); BE_from_array_32(&prod.motion_direction, 4); BE_from_array_32(&prod.motion_speed, 4); BE_from_array_32(&prod.line_quality_value, 4); BE_from_array_32(&prod.line_quality_thresh, 4); BE_from_array_32(prod.spare_float, BDRY_SPARE_FLOAT_LEN * sizeof(fl32)); /* type_string is okay */ /* subtype_string is okay */ /* line_type_string is okay */ /* desc is okay */ return; } /************************************************************************ * _subtype2String(): Convert the given subtype to a string. */ string Bdry::_subtype2String(const int subtype) { return(_convertStringValue(subtype, Subtype_table, Subtype_table_size)); } /************************************************************************ * _subtypeString2Subtype(): Returns the integer subtype for a * given subtype string. */ int Bdry::_subtypeString2Subtype(const char *subtype_string) { return(_convertParseValue(subtype_string, Subtype_table, Subtype_table_size)); } /************************************************************************ * _type2String(): Returns the string associated with a given boundary * type. */ string Bdry::_type2String(const int type) { string type_string = _convertStringValue(type, Type_table, Type_table_size); if (type_string == UNKNOWN_VALUE_STRING) type_string = _getExtrapolatedProdTypeString(type); return type_string; } /************************************************************************ * _typeString2Type(): Returns the integer type for a given type * string. */ int Bdry::_typeString2Type(const char *type_string) { int type = _convertParseValue(type_string, Type_table, Type_table_size); if (type == -1) type = _getExtrapolatedProdType(type_string); return type; }