PLplot
5.15.0
Toggle main menu visibility
Loading...
Searching...
No Matches
nncommon.c
Go to the documentation of this file.
1
//--------------------------------------------------------------------------
2
//
3
// File: nncommon.c
4
//
5
// Created: 04/08/2000
6
//
7
// Author: Pavel Sakov
8
// CSIRO Marine Research
9
//
10
// Purpose: Common stuff for NN interpolation library
11
//
12
// Description: None
13
//
14
// Revisions: 15/11/2002 PS: Changed name from "utils.c"
15
// 28/02/2003 PS: Modified points_read() to do the job without
16
// rewinding the file. This allows to read from stdin when
17
// necessary.
18
// 09/04/2003 PS: Modified points_read() to read from a
19
// file specified by name, not by handle.
20
// Modified: Andrew Ross 20/10/2008
21
// Change <= comparison in circle_contains() to use EPSILON
22
// to catch case where the point lies on the circle and there
23
// is floating point rounding error in the radii.
24
//
25
//--------------------------------------------------------------------------
26
27
#include <stdlib.h>
28
#include <stdio.h>
29
#include <stdarg.h>
30
#include <assert.h>
31
#include <math.h>
32
#include <limits.h>
33
#include <float.h>
34
#include <string.h>
35
#include <errno.h>
36
#include "
nan.h
"
37
#include "
delaunay.h
"
38
39
#define BUFSIZE 1024
40
41
#define EPSILON 1.0e-8
42
43
int
nn_verbose
= 0;
44
int
nn_test_vertice
= -1;
45
NN_RULE
nn_rule
=
SIBSON
;
46
47
#include "
version.h
"
48
49
void
nn_quit
(
const
char
* format, ... );
50
int
circle_build
(
circle
* c,
point
* p1,
point
* p2,
point
* p3 );
51
int
circle_contains
(
circle
* c,
point
* p );
52
53
void
nn_quit
(
const
char
* format, ... )
54
{
55
va_list args;
56
57
fflush( stdout );
// just in case, to have the exit message
58
// last
59
60
fprintf( stderr,
"error: nn: "
);
61
va_start( args, format );
62
vfprintf( stderr, format, args );
63
va_end( args );
64
65
exit( 1 );
66
}
67
68
int
circle_build
(
circle
* c,
point
* p1,
point
* p2,
point
* p3 )
69
{
70
double
x1sq = p1->
x
* p1->
x
;
71
double
x2sq = p2->
x
* p2->
x
;
72
double
x3sq = p3->
x
* p3->
x
;
73
double
y1sq = p1->
y
* p1->
y
;
74
double
y2sq = p2->
y
* p2->
y
;
75
double
y3sq = p3->
y
* p3->
y
;
76
double
t1 = x3sq - x2sq + y3sq - y2sq;
77
double
t2 = x1sq - x3sq + y1sq - y3sq;
78
double
t3 = x2sq - x1sq + y2sq - y1sq;
79
double
D = ( p1->
x
* ( p2->
y
- p3->
y
) + p2->
x
* ( p3->
y
- p1->
y
) + p3->
x
* ( p1->
y
- p2->
y
) ) * 2.0;
80
81
if
( D == 0.0 )
82
return
0;
83
84
c->
x
= ( p1->
y
* t1 + p2->
y
* t2 + p3->
y
* t3 ) / D;
85
c->
y
= -( p1->
x
* t1 + p2->
x
* t2 + p3->
x
* t3 ) / D;
86
c->
r
= hypot( c->
x
- p1->
x
, c->
y
- p1->
y
);
87
88
return
1;
89
}
90
91
// This procedure has taken it final shape after a number of tries. The problem
92
// was to have the calculated and stored radii being the same if (x,y) is
93
// exactly on the circle border (i.e. not to use FCPU extended precision in
94
// the radius calculation). This may have little effect in practice but was
95
// important in some tests when both input and output data were placed
96
// in rectangular grid nodes.
97
//
98
int
circle_contains
(
circle
* c,
point
* p )
99
{
100
return
hypot( c->
x
- p->
x
, c->
y
- p->
y
) <= c->
r
* ( 1.0 +
EPSILON
);
101
}
102
103
// Smoothes the input point array by averaging the input x,y and z values
104
// for each cell within virtual rectangular nx by ny grid. The corners of the
105
// grid are created from min and max values of the input array. It also frees
106
// the original array and returns results and new dimension via original
107
// data and size pointers.
108
//
109
// @param pn Pointer to number of points (input/output)
110
// @param ppoints Pointer to array of points (input/output) [*pn]
111
// @param nx Number of x nodes in decimation
112
// @param ny Number of y nodes in decimation
113
//
114
void
points_thin
(
int
* pn,
point
** ppoints,
int
nx,
int
ny )
115
{
116
int
n = *pn;
117
point
* points = *ppoints;
118
double
xmin = DBL_MAX;
119
double
xmax = -DBL_MAX;
120
double
ymin = DBL_MAX;
121
double
ymax = -DBL_MAX;
122
int
nxy = nx * ny;
123
double
* sumx = calloc( (
size_t
) nxy,
sizeof
(
double
) );
124
double
* sumy = calloc( (
size_t
) nxy,
sizeof
(
double
) );
125
double
* sumz = calloc( (
size_t
) nxy,
sizeof
(
double
) );
126
int
* count = calloc( (
size_t
) nxy,
sizeof
(
int
) );
127
double
stepx = 0.0;
128
double
stepy = 0.0;
129
int
nnew = 0;
130
point
* pointsnew = NULL;
131
int
i, j, ii;
132
133
if
(
nn_verbose
)
134
fprintf( stderr,
"thinned: %d points -> "
, *pn );
135
136
if
( nx < 1 || ny < 1 )
137
{
138
free( points );
139
*ppoints = NULL;
140
*pn = 0;
141
if
(
nn_verbose
)
142
fprintf( stderr,
"0 points"
);
143
free( sumx );
144
free( sumy );
145
free( sumz );
146
free( count );
147
return
;
148
}
149
150
for
( ii = 0; ii < n; ++ii )
151
{
152
point
* p = &points[ii];
153
154
if
( p->
x
< xmin )
155
xmin = p->
x
;
156
if
( p->
x
> xmax )
157
xmax = p->
x
;
158
if
( p->
y
< ymin )
159
ymin = p->
y
;
160
if
( p->
y
> ymax )
161
ymax = p->
y
;
162
}
163
164
stepx = ( nx > 1 ) ? ( xmax - xmin ) / nx : 0.0;
165
stepy = ( ny > 1 ) ? ( ymax - ymin ) / ny : 0.0;
166
167
for
( ii = 0; ii < n; ++ii )
168
{
169
point
* p = &points[ii];
170
int
index;
171
172
//
173
// Following is the portion of the code which really depends on the
174
// floating point particulars. Do not be surprised if different
175
// compilers/options give different results here.
176
//
177
i = ( nx == 1 ) ? 0 : (int) ( ( p->
x
- xmin ) / stepx );
178
j = ( ny == 1 ) ? 0 : (int) ( ( p->
y
- ymin ) / stepy );
179
180
if
( i == nx )
181
i--;
182
if
( j == ny )
183
j--;
184
index = i + j * nx;
185
sumx[index] += p->
x
;
186
sumy[index] += p->
y
;
187
sumz[index] += p->
z
;
188
count[index]++;
189
}
190
191
for
( j = 0; j < ny; ++j )
192
{
193
for
( i = 0; i < nx; ++i )
194
{
195
int
index = i + j * nx;
196
197
if
( count[index] > 0 )
198
nnew++;
199
}
200
}
201
202
pointsnew = malloc( (
size_t
) nnew *
sizeof
(
point
) );
203
204
ii = 0;
205
for
( j = 0; j < ny; ++j )
206
{
207
for
( i = 0; i < nx; ++i )
208
{
209
int
index = i + j * nx;
210
int
nn = count[index];
211
212
if
( nn > 0 )
213
{
214
point
* p = &pointsnew[ii];
215
216
p->
x
= sumx[index] / nn;
217
p->
y
= sumy[index] / nn;
218
p->
z
= sumz[index] / nn;
219
ii++;
220
}
221
}
222
}
223
224
if
(
nn_verbose
)
225
fprintf( stderr,
"%d points\n"
, nnew );
226
227
free( sumx );
228
free( sumy );
229
free( sumz );
230
free( count );
231
232
free( points );
233
*ppoints = pointsnew;
234
*pn = nnew;
235
}
236
237
// Generates rectangular grid nx by ny using min and max x and y values from
238
// the input point array. Allocates space for the output point array, be sure
239
// to free it when necessary!
240
//
241
// @param n Number of points
242
// @param points Array of points [n]
243
// @param nx Number of x nodes
244
// @param ny Number of y nodes
245
// @param zoom Zoom coefficient
246
// @param nout Pointer to number of output points
247
// @param pout Pointer to array of output points [*nout]
248
//
249
void
points_generate1
(
int
nin,
point
pin[],
int
nx,
int
ny,
double
zoom,
int
* nout,
point
** pout )
250
{
251
double
xmin = DBL_MAX;
252
double
xmax = -DBL_MAX;
253
double
ymin = DBL_MAX;
254
double
ymax = -DBL_MAX;
255
double
stepx, stepy;
256
double
x0, xx, yy;
257
int
i, j, ii;
258
259
if
( nx < 1 || ny < 1 )
260
{
261
*pout = NULL;
262
*nout = 0;
263
return
;
264
}
265
266
for
( ii = 0; ii < nin; ++ii )
267
{
268
point
* p = &pin[ii];
269
270
if
( p->
x
< xmin )
271
xmin = p->
x
;
272
if
( p->
x
> xmax )
273
xmax = p->
x
;
274
if
( p->
y
< ymin )
275
ymin = p->
y
;
276
if
( p->
y
> ymax )
277
ymax = p->
y
;
278
}
279
280
if
( isnan( zoom ) || zoom <= 0.0 )
281
zoom = 1.0;
282
283
if
( zoom != 1.0 )
284
{
285
double
xdiff2 = ( xmax - xmin ) / 2.0;
286
double
ydiff2 = ( ymax - ymin ) / 2.0;
287
double
xav = ( xmax + xmin ) / 2.0;
288
double
yav = ( ymax + ymin ) / 2.0;
289
290
xmin = xav - xdiff2 * zoom;
291
xmax = xav + xdiff2 * zoom;
292
ymin = yav - ydiff2 * zoom;
293
ymax = yav + ydiff2 * zoom;
294
}
295
296
*nout = nx * ny;
297
*pout = malloc( (
size_t
) ( *nout ) *
sizeof
(
point
) );
298
299
stepx = ( nx > 1 ) ? ( xmax - xmin ) / ( nx - 1 ) : 0.0;
300
stepy = ( ny > 1 ) ? ( ymax - ymin ) / ( ny - 1 ) : 0.0;
301
x0 = ( nx > 1 ) ? xmin : ( xmin + xmax ) / 2.0;
302
yy = ( ny > 1 ) ? ymin : ( ymin + ymax ) / 2.0;
303
304
ii = 0;
305
for
( j = 0; j < ny; ++j )
306
{
307
xx = x0;
308
for
( i = 0; i < nx; ++i )
309
{
310
point
* p = &( *pout )[ii];
311
312
p->
x
= xx;
313
p->
y
= yy;
314
xx += stepx;
315
ii++;
316
}
317
yy += stepy;
318
}
319
}
320
321
// Generates rectangular grid nx by ny using specified min and max x and y
322
// values. Allocates space for the output point array, be sure to free it
323
// when necessary!
324
//
325
// @param xmin Min x value
326
// @param xmax Max x value
327
// @param ymin Min y value
328
// @param ymax Max y value
329
// @param nx Number of x nodes
330
// @param ny Number of y nodes
331
// @param nout Pointer to number of output points
332
// @param pout Pointer to array of output points [*nout]
333
//
334
void
points_generate2
(
double
xmin,
double
xmax,
double
ymin,
double
ymax,
int
nx,
int
ny,
int
* nout,
point
** pout )
335
{
336
double
stepx, stepy;
337
double
x0, xx, yy;
338
int
i, j, ii;
339
340
if
( nx < 1 || ny < 1 )
341
{
342
*pout = NULL;
343
*nout = 0;
344
return
;
345
}
346
347
*nout = nx * ny;
348
*pout = malloc( (
size_t
) ( *nout ) *
sizeof
(
point
) );
349
350
stepx = ( nx > 1 ) ? ( xmax - xmin ) / ( nx - 1 ) : 0.0;
351
stepy = ( ny > 1 ) ? ( ymax - ymin ) / ( ny - 1 ) : 0.0;
352
x0 = ( nx > 1 ) ? xmin : ( xmin + xmax ) / 2.0;
353
yy = ( ny > 1 ) ? ymin : ( ymin + ymax ) / 2.0;
354
355
ii = 0;
356
for
( j = 0; j < ny; ++j )
357
{
358
xx = x0;
359
for
( i = 0; i < nx; ++i )
360
{
361
point
* p = &( *pout )[ii];
362
363
p->
x
= xx;
364
p->
y
= yy;
365
xx += stepx;
366
ii++;
367
}
368
yy += stepy;
369
}
370
}
371
372
static
int
str2double
(
char
* token,
double
*
value
)
373
{
374
char
* end = NULL;
375
376
if
( token == NULL )
377
{
378
*
value
=
NaN
;
379
return
0;
380
}
381
382
*
value
= strtod( token, &end );
383
384
if
( end == token )
385
{
386
*
value
=
NaN
;
387
return
0;
388
}
389
390
return
1;
391
}
392
393
#define NALLOCATED_START 1024
394
395
// Reads array of points from a columnar file.
396
//
397
// @param fname File name (can be "stdin" for standard input)
398
// @param dim Number of dimensions (must be 2 or 3)
399
// @param n Pointer to number of points (output)
400
// @param points Pointer to array of points [*n] (output) (to be freed)
401
//
402
void
points_read
(
char
* fname,
int
dim,
int
* n,
point
** points )
403
{
404
FILE * f = NULL;
405
int
nallocated =
NALLOCATED_START
;
406
char
buf
[
BUFSIZE
];
407
char
seps[] =
" ,;\t"
;
408
char
* token;
409
410
if
( dim < 2 || dim > 3 )
411
{
412
*n = 0;
413
*points = NULL;
414
return
;
415
}
416
417
if
( fname == NULL )
418
f = stdin;
419
else
420
{
421
if
( strcmp( fname,
"stdin"
) == 0 || strcmp( fname,
"-"
) == 0 )
422
f = stdin;
423
else
424
{
425
f = fopen( fname,
"r"
);
426
if
( f == NULL )
427
nn_quit
(
"%s: %s\n"
, fname, strerror( errno ) );
428
}
429
}
430
431
*points = malloc( (
size_t
) nallocated *
sizeof
(
point
) );
432
*n = 0;
433
while
( fgets(
buf
,
BUFSIZE
, f ) != NULL )
434
{
435
point
* p;
436
437
if
( *n == nallocated )
438
{
439
nallocated *= 2;
440
*points = realloc( *points, (
size_t
) nallocated *
sizeof
(
point
) );
441
}
442
443
p = &( *points )[*n];
444
445
if
(
buf
[0] ==
'#'
)
446
continue
;
447
if
( ( token = strtok(
buf
, seps ) ) == NULL )
448
continue
;
449
if
( !
str2double
( token, &p->
x
) )
450
continue
;
451
if
( ( token = strtok( NULL, seps ) ) == NULL )
452
continue
;
453
if
( !
str2double
( token, &p->
y
) )
454
continue
;
455
if
( dim == 2 )
456
p->
z
=
NaN
;
457
else
458
{
459
if
( ( token = strtok( NULL, seps ) ) == NULL )
460
continue
;
461
if
( !
str2double
( token, &p->
z
) )
462
continue
;
463
}
464
( *n )++;
465
}
466
467
if
( *n == 0 )
468
{
469
free( *points );
470
*points = NULL;
471
}
472
else
473
*points = realloc( *points, (
size_t
) ( *n ) *
sizeof
(
point
) );
474
475
if
( f != stdin )
476
if
( fclose( f ) != 0 )
477
nn_quit
(
"%s: %s\n"
, fname, strerror( errno ) );
478
}
479
480
//* Scales Y coordinate so that the resulting set fits into square:
481
//** xmax - xmin = ymax - ymin
482
//*
483
//* @param n Number of points
484
//* @param points The points to scale
485
//* @return Y axis compression coefficient
486
//
487
double
points_scaletosquare
(
int
n,
point
* points )
488
{
489
double
xmin, ymin, xmax, ymax;
490
double
k;
491
int
i;
492
493
if
( n <= 0 )
494
return
NaN
;
495
496
xmin = xmax = points[0].
x
;
497
ymin = ymax = points[0].
y
;
498
499
for
( i = 1; i < n; ++i )
500
{
501
point
* p = &points[i];
502
503
if
( p->
x
< xmin )
504
xmin = p->
x
;
505
else
if
( p->
x
> xmax )
506
xmax = p->
x
;
507
if
( p->
y
< ymin )
508
ymin = p->
y
;
509
else
if
( p->
y
> ymax )
510
ymax = p->
y
;
511
}
512
513
if
( xmin == xmax || ymin == ymax )
514
return
NaN
;
515
else
516
k = ( ymax - ymin ) / ( xmax - xmin );
517
518
for
( i = 0; i < n; ++i )
519
points[i].y /= k;
520
521
return
k;
522
}
523
524
//* Compresses Y domain by a given multiple.
525
//
526
// @param n Number of points
527
// @param points The points to scale
528
// @param Y axis compression coefficient as returned by points_scaletosquare()
529
//
530
void
points_scale
(
int
n,
point
* points,
double
k )
531
{
532
int
i;
533
534
for
( i = 0; i < n; ++i )
535
points[i].y /= k;
536
}
NaN
#define NaN
Definition
csa/nan.h:62
delaunay.h
nan.h
version.h
NN_RULE
NN_RULE
Definition
nn.h:23
SIBSON
@ SIBSON
Definition
nn.h:23
nn_test_vertice
int nn_test_vertice
Definition
nncommon.c:44
nn_verbose
int nn_verbose
Definition
nncommon.c:43
EPSILON
#define EPSILON
Definition
nncommon.c:41
points_generate2
void points_generate2(double xmin, double xmax, double ymin, double ymax, int nx, int ny, int *nout, point **pout)
Definition
nncommon.c:334
points_scale
void points_scale(int n, point *points, double k)
Definition
nncommon.c:530
nn_rule
NN_RULE nn_rule
Definition
nncommon.c:45
points_scaletosquare
double points_scaletosquare(int n, point *points)
Definition
nncommon.c:487
points_read
void points_read(char *fname, int dim, int *n, point **points)
Definition
nncommon.c:402
circle_build
int circle_build(circle *c, point *p1, point *p2, point *p3)
Definition
nncommon.c:68
circle_contains
int circle_contains(circle *c, point *p)
Definition
nncommon.c:98
points_thin
void points_thin(int *pn, point **ppoints, int nx, int ny)
Definition
nncommon.c:114
NALLOCATED_START
#define NALLOCATED_START
Definition
nncommon.c:393
points_generate1
void points_generate1(int nin, point pin[], int nx, int ny, double zoom, int *nout, point **pout)
Definition
nncommon.c:249
str2double
static int str2double(char *token, double *value)
Definition
nncommon.c:372
nn_quit
void nn_quit(const char *format,...)
Definition
nncommon.c:53
BUFSIZE
#define BUFSIZE
Definition
nncommon.c:39
value
static PLFLT value(double n1, double n2, double hue)
Definition
plctrl.c:1219
circle
Definition
delaunay.h:34
circle::x
double x
Definition
delaunay.h:35
circle::r
double r
Definition
delaunay.h:37
circle::y
double y
Definition
delaunay.h:36
point
Definition
csa.h:30
point::y
double y
Definition
csa.h:32
point::x
double x
Definition
csa.h:31
point::z
double z
Definition
csa.h:33
buf
static char buf[200]
Definition
tclAPI.c:873
lib
nn
nncommon.c
Generated on
for PLplot by
1.17.0