File: PrecisionModel.cpp

package info (click to toggle)
geos 2.1.1-2
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 4,784 kB
  • ctags: 3,505
  • sloc: cpp: 24,991; sh: 8,431; xml: 6,597; makefile: 401; python: 77
file content (400 lines) | stat: -rw-r--r-- 11,836 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
/**********************************************************************
 * $Id: PrecisionModel.cpp,v 1.28 2004/07/21 09:55:24 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  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 <geos/geom.h>
#include <geos/util.h>
#include <stdio.h>

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 <code>PrecisionModel</code> with a default precision
* of FLOATING.
*/
PrecisionModel::PrecisionModel(){
	modelType=FLOATING;
	scale=1.0;
}

/**
* Creates a <code>PrecisionModel</code> 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 <code>PrecisionModel</code> 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 <code>PrecisionModel</code> 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 <code>true</code> 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 <code>internal</code> to the precise representation of <code>external</code>.
 *
 * @param external the original coordinate
 * @param internal the coordinate whose values will be changed to the
 *                 precise representation of <code>external</code>
 * @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 <code>external</code>.
 *
 *@param  external  the original coordinate
 *@return           the coordinate whose values will be changed to the precise
 *      representation of <code>external</code>
 * @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 <code>internal</code>.
 *
 *@param  internal  the original coordinate
 *@return           the coordinate whose values will be changed to the
 *      external representation of <code>internal</code>
 * @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 <code>external</code> to the external representation of
 * <code>internal</code>.
 *
 *@param  internal  the original coordinate
 *@param  external  the coordinate whose values will be changed to the
 *      external representation of <code>internal</code>
 * @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 {
	string result("");
	char buffer[255];
	result="UNKNOWN";
  	if (modelType == FLOATING) {
  		result = "Floating";
  	} else if (modelType == FLOATING_SINGLE) {
  		result = "Floating-Single";
  	} else if (modelType == FIXED) {
		sprintf(buffer,"Fixed (Scale=%g)",getScale());
		result="";
		result.append(buffer);
		result.append("");
    }
	return result;
}

PrecisionModel::~PrecisionModel(){}

bool operator==(const PrecisionModel a, const PrecisionModel b) {
	return a.isFloating() == b.isFloating() &&
			a.getScale() == b.getScale();
}

/**
*  Compares this {@link PrecisionModel} object with the specified object for order.
* A PrecisionModel is greater than another if it provides greater precision.
* The comparison is based on the value returned by the
* {@link getMaximumSignificantDigits) method.
* This comparison is not strictly accurate when comparing floating precision models
* to fixed models; however, it is correct when both models are either floating or fixed.
*
*@param  o  the <code>PrecisionModel</code> with which this <code>PrecisionModel</code>
*      is being compared
*@return    a negative integer, zero, or a positive integer as this <code>PrecisionModel</code>
*      is less than, equal to, or greater than the specified <code>PrecisionModel</code>
*/
int PrecisionModel::compareTo(const PrecisionModel *other) const {
	int sigDigits=getMaximumSignificantDigits();
	int otherSigDigits=other->getMaximumSignificantDigits();
	return sigDigits<otherSigDigits? -1: (sigDigits==otherSigDigits? 0:1);
	//if (modelType==FLOATING && other->modelType==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 (scale<other->scale)
	//		return -1;
	//	else
	//		return 0;
	//}
	//Assert::shouldNeverReachHere("Unknown Precision Model type encountered");
	//return 0;
}
}