/********************************************************************** * $Id: PrecisionModel.cpp,v 1.28.2.1 2005/05/23 18:41:51 strk Exp $ * * GEOS - Geometry Engine Open Source * http://geos.refractions.net * * Copyright (C) 2001-2002 Vivid Solutions Inc. * * This is free software; you can redistribute and/or modify it under * the terms of the GNU Lesser General Public Licence as published * by the Free Software Foundation. * See the COPYING file for more information. * ********************************************************************** * $Log: PrecisionModel.cpp,v $ * Revision 1.28.2.1 2005/05/23 18:41:51 strk * Replaced sprintf uses with ostringstream * * Revision 1.28 2004/07/21 09:55:24 strk * CoordinateSequence::atLeastNCoordinatesOrNothing definition fix. * Documentation fixes. * * Revision 1.27 2004/07/12 15:42:03 strk * Fixed maximumPreciseValue scope * * Revision 1.26 2004/07/05 14:23:03 strk * More documentation cleanups. * * Revision 1.25 2004/07/03 12:51:37 strk * Documentation cleanups for DoxyGen. * * Revision 1.24 2004/07/02 13:28:26 strk * Fixed all #include lines to reflect headers layout change. * Added client application build tips in README. * * Revision 1.23 2004/05/28 18:16:01 ybychkov * Changed rounding method to make compilable with VC++ * * Revision 1.22 2004/05/21 13:39:31 strk * ::makePrecise make use of nearbyint() now, to be compatible with JTS * * Revision 1.21 2004/05/19 19:39:05 ybychkov * Changed rounding method to make compilable with VC++ * * Revision 1.20 2004/05/17 10:45:58 strk * Fixed bogus FIXED coordinate rounding * * Revision 1.19 2004/04/16 07:42:06 strk * PrecisionModel::Type made an enum instead of a Type. * * Revision 1.18 2004/04/14 09:38:10 strk * PrecisionModel(double newScale) missed to set the scale * * Revision 1.17 2004/03/31 07:50:37 ybychkov * "geom" partially upgraded to JTS 1.4 * * Revision 1.16 2003/11/12 17:15:05 strk * made sure PrecisionModel scale is never 0 * * Revision 1.15 2003/11/07 01:23:42 pramsey * Add standard CVS headers licence notices and copyrights to all cpp and h * files. * * Revision 1.14 2003/10/11 01:56:08 strk * * Code base padded with 'const' keywords ;) * * Revision 1.13 2003/10/09 10:10:05 strk * Throw an exception if scale is 0. Added Log entry. * **********************************************************************/ #include #include #include namespace geos { const double PrecisionModel::maximumPreciseValue=9007199254740992.0; /* * \brief Implementation of rint() for Visual C++ */ static double rint_vc(double val) { double n; double f=fabs(modf(val,&n)); if (val>=0) { if (f<0.5) { return floor(val); } else if (f>0.5) { return ceil(val); } else { return(floor(n/2)==n/2)?n:n+1.0; } } else { if (f<0.5) { return ceil(val); } else if (f>0.5) { return floor(val); } else { return(floor(n/2)==n/2)?n:n-1.0; } } } /** * Rounds an numeric value to the PrecisionModel grid. */ double PrecisionModel::makePrecise(double val) const { if (modelType==FLOATING_SINGLE) { float floatSingleVal = (float) val; return (double) floatSingleVal; } if (modelType == FIXED) { //double d=val*scale; //double me=((d >= 0.0) ? floor(d+0.5)/scale : - floor(-d+0.5)/scale); // double ret = nearbyint(val*scale)/scale; double ret = rint_vc(val*scale)/scale; return ret; } // modelType == FLOATING - no rounding necessary return val; } /** * Rounds given Coordinate to the PrecisionModel grid. */ void PrecisionModel::makePrecise(Coordinate *coord) const { // optimization for full precision if (modelType==FLOATING) return; coord->x=makePrecise(coord->x); coord->y=makePrecise(coord->y); } /** * Creates a PrecisionModel with a default precision * of FLOATING. */ PrecisionModel::PrecisionModel(){ modelType=FLOATING; scale=1.0; } /** * Creates a PrecisionModel that specifies * an explicit precision model type. * If the model type is FIXED the scale factor will default to 1. * * @param modelType the type of the precision model */ PrecisionModel::PrecisionModel(Type nModelType){ modelType=nModelType; if (modelType==FIXED){ setScale(1.0); } } /* * Creates a PrecisionModel that specifies Fixed precision. * Fixed-precision coordinates are represented as precise internal coordinates, * which are rounded to the grid defined by the scale factor. * * @param scale amount by which to multiply a coordinate after subtracting * the offset, to obtain a precise coordinate * @param offsetX not used. * @param offsetY not used. * * @deprecated offsets are no longer supported, * since internal representation is rounded floating point */ PrecisionModel::PrecisionModel(double newScale, double newOffsetX, double newOffsetY) //throw(IllegalArgumentException *) { modelType = FIXED; setScale(newScale); } /* * Creates a PrecisionModel that specifies Fixed precision. * Fixed-precision coordinates are represented as precise internal coordinates, * which are rounded to the grid defined by the scale factor. * *@param scale amount by which to multiply a coordinate after subtracting * the offset, to obtain a precise coordinate */ PrecisionModel::PrecisionModel(double newScale) //throw (IllegalArgumentException *) { modelType=FIXED; setScale(newScale); } PrecisionModel::PrecisionModel(const PrecisionModel &pm) { modelType = pm.modelType; scale = pm.scale; } /** * Tests whether the precision model supports floating point * @return true if the precision model supports floating point */ bool PrecisionModel::isFloating() const { return (modelType == FLOATING || modelType == FLOATING_SINGLE); } /** * Returns the maximum number of significant digits provided by this * precision model. * Intended for use by routines which need to print out precise values. * * @return the maximum number of decimal places provided by this precision model */ int PrecisionModel::getMaximumSignificantDigits() const { int maxSigDigits = 16; if (modelType == FLOATING) { maxSigDigits = 16; } else if (modelType == FLOATING_SINGLE) { maxSigDigits = 6; } else if (modelType == FIXED) { maxSigDigits = 1 + (int)ceil((double)log(getScale())/(double)log(10.0)); } return maxSigDigits; } /** * Gets the type of this PrecisionModel * @return the type of this PrecisionModel */ PrecisionModel::Type PrecisionModel::getType() const { return modelType; } /** * Returns the multiplying factor used to obtain a precise coordinate. * This method is private because PrecisionModel is intended to * be an immutable (value) type. * *@return the amount by which to multiply a coordinate after subtracting * the offset */ double PrecisionModel::getScale() const { return scale; } /** * Sets the multiplying factor used to obtain a precise coordinate. * This method is private because PrecisionModel is intended to * be an immutable (value) type. * */ void PrecisionModel::setScale(double newScale) { if ( newScale == 0 ) throw new IllegalArgumentException("PrecisionModel scale cannot be 0"); scale=fabs(newScale); } /* * Returns the x-offset used to obtain a precise coordinate. * * @return the amount by which to subtract the x-coordinate before * multiplying by the scale * @deprecated Offsets are no longer used */ double PrecisionModel::getOffsetX() const { return 0; } /* * Returns the y-offset used to obtain a precise coordinate. * * @return the amount by which to subtract the y-coordinate before * multiplying by the scale * @deprecated Offsets are no longer used */ double PrecisionModel::getOffsetY() const { return 0; } /* * Sets internal to the precise representation of external. * * @param external the original coordinate * @param internal the coordinate whose values will be changed to the * precise representation of external * @deprecated use makePrecise instead */ void PrecisionModel::toInternal (const Coordinate& external, Coordinate* internal) const { if (isFloating()) { internal->x = external.x; internal->y = external.y; } else { internal->x=makePrecise(external.x); internal->y=makePrecise(external.y); } internal->z = external.z; } /* * Returns the precise representation of external. * *@param external the original coordinate *@return the coordinate whose values will be changed to the precise * representation of external * @deprecated use makePrecise instead */ Coordinate* PrecisionModel::toInternal(const Coordinate& external) const { Coordinate* internal=new Coordinate(external); makePrecise(internal); return internal; } /* * Returns the external representation of internal. * *@param internal the original coordinate *@return the coordinate whose values will be changed to the * external representation of internal * @deprecated no longer needed, since internal representation is same as external representation */ Coordinate* PrecisionModel::toExternal(const Coordinate& internal) const { Coordinate* external=new Coordinate(internal); return external; } /* * Sets external to the external representation of * internal. * *@param internal the original coordinate *@param external the coordinate whose values will be changed to the * external representation of internal * @deprecated no longer needed, since internal representation is same * as external representation */ void PrecisionModel::toExternal(const Coordinate& internal, Coordinate* external) const { external->x = internal.x; external->y = internal.y; } string PrecisionModel::toString() const { ostringstream s; if (modelType == FLOATING) { s<<"Floating"; } else if (modelType == FLOATING_SINGLE) { s<<"Floating-Single"; } else if (modelType == FIXED) { s<<"Fixed (Scale="<PrecisionModel with which this PrecisionModel * is being compared *@return a negative integer, zero, or a positive integer as this PrecisionModel * is less than, equal to, or greater than the specified PrecisionModel */ int PrecisionModel::compareTo(const PrecisionModel *other) const { int sigDigits=getMaximumSignificantDigits(); int otherSigDigits=other->getMaximumSignificantDigits(); return sigDigitsmodelType==FLOATING) return 0; //if (modelType==FLOATING && other->modelType!=FLOATING) return 1; //if (modelType!=FLOATING && other->modelType==FLOATING) return -1; //if (modelType==FIXED && other->modelType==FIXED) { // if (scale>other->scale) // return 1; // else if (scalescale) // return -1; // else // return 0; //} //Assert::shouldNeverReachHere("Unknown Precision Model type encountered"); //return 0; } }