Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
ptwXY_methods.c
Go to the documentation of this file.
1/*
2# <<BEGIN-copyright>>
3# Copyright 2019, Lawrence Livermore National Security, LLC.
4# This file is part of the gidiplus package (https://github.com/LLNL/gidiplus).
5# gidiplus is licensed under the MIT license (see https://opensource.org/licenses/MIT).
6# SPDX-License-Identifier: MIT
7# <<END-copyright>>
8*/
9
10#include <math.h>
11#include <float.h>
12
13#include "ptwXY.h"
14
15static nfu_status ptwXY_clip2( statusMessageReporting *smr, ptwXYPoints *ptwXY1, double y, double x1, double y1, double x2, double y2 );
16static double ptwXY_thicken_linear_dx( int sectionSubdivideMax, double dDomainMax, double x1, double x2 );
17static nfu_status ptwXY_thin2( statusMessageReporting *smr, ptwXYPoints *thinned, char *thin, double accuracy, int64_t i1, int64_t i2 );
18/*
19************************************************************
20*/
21nfu_status ptwXY_clip( statusMessageReporting *smr, ptwXYPoints *ptwXY1, double rangeMin, double rangeMax ) {
22/*
23 This function acts oddly for xy = [ [ 1, 0 ], [ 3, -2 ], [ 4, 1 ] ] and rangeMin = 0.2, why???????
24 This function probably only works for linear, linear interpolation (mainly because of ptwXY_clip2).
25*/
26 int64_t i, j, n;
27 double x2, y2, _rangeMin, _rangeMax;
28 ptwXYPoints *clipped;
29 ptwXYPoint *points;
30
31 if( ptwXY_simpleCoalescePoints( smr, ptwXY1 ) != nfu_Okay ) {
33 return( ptwXY1->status );
34 }
35
37 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_otherInterpolation, "Other interpolation not allowed." );
38 return( nfu_otherInterpolation );
39 }
40 n = ptwXY1->length;
41 if( n > 0 ) {
42 i = 0;
43 if( ptwXY_range( smr, ptwXY1, &_rangeMin, &_rangeMax ) != nfu_Okay ) {
45 return( nfu_Error );
46 }
47 if( _rangeMax < rangeMin ) i = 1;
48 if( _rangeMin > rangeMax ) i = 1;
49 if( i == 1 ) {
50 if( ptwXY_clear( smr, ptwXY1 ) != nfu_Okay ) smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_Error, "Via." );
51 return( ptwXY1->status );
52 }
53 }
54 if( n == 1 ) {
55 y2 = ptwXY1->points[0].y;
56 if( y2 < rangeMin ) {
57 ptwXY1->points[0].y = rangeMin; }
58 else if( y2 > rangeMax ) {
59 ptwXY1->points[0].y = rangeMax;
60 } }
61 else if( n > 1 ) {
62 if( ( clipped = ptwXY_new( smr, ptwXY1->interpolation, ptwXY1->interpolationString,
63 ptwXY1->biSectionMax, ptwXY1->accuracy, n, 10, ptwXY1->userFlag ) ) == NULL ) {
65 return( ptwXY1->status );
66 }
67 for( i = 0; i < n; i++ ) {
68 x2 = ptwXY1->points[i].x;
69 y2 = ptwXY1->points[i].y;
70 if( y2 < rangeMin ) {
71 if( i > 0 ) {
72 points = ptwXY_getPointAtIndex_Unsafely( clipped, clipped->length - 1 );
73 if( points->y > rangeMin ) {
74 if( ptwXY_clip2( smr, clipped, rangeMin, points->x, points->y, x2, y2 ) != nfu_Okay ) goto Err;
75 }
76 }
77 if( ptwXY_setValueAtX( smr, clipped, x2, rangeMin ) != nfu_Okay ) goto Err;
78 j = i;
79 for( i++; i < n; i++ ) if( !( ptwXY1->points[i].y < rangeMin ) ) break;
80 if( i < n ) {
81 x2 = ptwXY1->points[i].x;
82 y2 = ptwXY1->points[i].y;
83 if( ptwXY_clip2( smr, clipped, rangeMin, ptwXY1->points[i-1].x, ptwXY1->points[i-1].y, x2, y2 ) != nfu_Okay ) goto Err;
84 if( y2 > rangeMax ) {
85 if( ptwXY_clip2( smr, clipped, rangeMax, ptwXY1->points[i-1].x, ptwXY1->points[i-1].y, x2, y2 ) != nfu_Okay ) goto Err;
86 } }
87 else if( j != n - 1 ) {
88 if( ptwXY_setValueAtX( smr, clipped, ptwXY1->points[n - 1].x, rangeMin ) != nfu_Okay ) goto Err;
89 }
90 i--; }
91 else if( y2 > rangeMax ) {
92 if( i > 0 ) {
93 points = ptwXY_getPointAtIndex_Unsafely( clipped, clipped->length - 1 );
94 if( points->y < rangeMax ) {
95 if( ptwXY_clip2( smr, clipped, rangeMax, points->x, points->y, x2, y2 ) != nfu_Okay ) goto Err;
96 }
97 }
98 if( ptwXY_setValueAtX( smr, clipped, x2, rangeMax ) != nfu_Okay ) goto Err;
99 j = i;
100 for( i++; i < n; i++ ) if( !( ptwXY1->points[i].y > rangeMax ) ) break;
101 if( i < n ) {
102 x2 = ptwXY1->points[i].x;
103 y2 = ptwXY1->points[i].y;
104 if( ptwXY_clip2( smr, clipped, rangeMax, ptwXY1->points[i-1].x, ptwXY1->points[i-1].y, x2, y2 ) != nfu_Okay ) goto Err;
105 if( y2 < rangeMin ) {
106 if( ptwXY_clip2( smr, clipped, rangeMin, ptwXY1->points[i-1].x, ptwXY1->points[i-1].y, x2, y2 ) != nfu_Okay ) goto Err;
107 } }
108 else if( j != n - 1 ) {
109 if( ptwXY_setValueAtX( smr, clipped, ptwXY1->points[n - 1].x, rangeMax ) != nfu_Okay ) goto Err;
110 }
111 i--; }
112 else {
113 if( ptwXY_setValueAtX( smr, clipped, x2, y2 ) != nfu_Okay ) goto Err;
114 }
115 }
116 if( ptwXY_simpleCoalescePoints( smr, clipped ) != nfu_Okay ) goto Err;
117 ptwXY1->length = clipped->length; /* The squeamish may want to skip the next few lines. */
118 clipped->length = n;
119 n = ptwXY1->allocatedSize;
120 ptwXY1->allocatedSize = clipped->allocatedSize;
121 clipped->allocatedSize = n;
122 points = clipped->points;
123 clipped->points = ptwXY1->points;
124 ptwXY1->points = points;
125 ptwXY_free( clipped );
126 }
127
128 return( ptwXY1->status );
129
130Err:
132 ptwXY_free( clipped );
133 return( ptwXY1->status );
134}
135/*
136************************************************************
137*/
138static nfu_status ptwXY_clip2( statusMessageReporting *smr, ptwXYPoints *clipped, double y, double x1, double y1, double x2, double y2 ) {
139
140 double x;
141
142 x = ( y - y1 ) * ( x2 - x1 ) / ( y2 - y1 ) + x1;
143 if( x <= x1 ) {
144 x = x1; }
145 else if( x >= x2 ) {
146 x = x1; }
147 else {
148 ptwXY_setValueAtX( smr, clipped, x, y );
149 }
150 return( clipped->status );
151}
152/*
153************************************************************
154*/
155nfu_status ptwXY_thicken( statusMessageReporting *smr, ptwXYPoints *ptwXY1, int sectionSubdivideMax,
156 double dDomainMax, double fDomainMax ) {
157
158 double x1, x2 = 0., y1, y2 = 0., fx = 1.1, x, dx, dxp, lfx, y; /* fx initialized so compilers want complain. */
159 int64_t i, notFirstPass = 0;
160 int nfx, nDone, doLinear;
161
162 if( ptwXY1->interpolation == ptwXY_interpolationOther ) {
163 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_otherInterpolation, "Other interpolation not allowed." );
164 return( nfu_otherInterpolation );
165 }
166 if( ( sectionSubdivideMax < 1 ) || ( dDomainMax < 0. ) || ( fDomainMax < 1. ) ) {
168 "ptwXY_thicken: One or more of the following not satisfied: sectionSubdivideMax = %d > 0, dDomainMax = %e >= 0.0, fDomainMax = %e >= 1.0",
169 sectionSubdivideMax, dDomainMax, fDomainMax );
170 return( nfu_badInput );
171 }
172 if( sectionSubdivideMax > ptwXY_sectionSubdivideMax ) sectionSubdivideMax = ptwXY_sectionSubdivideMax;
173 if( ptwXY_simpleCoalescePoints( smr, ptwXY1 ) != nfu_Okay ) {
175 return( ptwXY1->status );
176 }
177 for( i = ptwXY1->length - 1; i >= 0; i-- ) {
178 x1 = ptwXY1->points[i].x;
179 y1 = ptwXY1->points[i].y;
180 if( notFirstPass ) {
181 dx = ptwXY_thicken_linear_dx( sectionSubdivideMax, dDomainMax, x1, x2 );
182
183 if( x1 == 0. ) {
184 doLinear = 1; }
185 else {
186 fx = x2 / x1;
187 if( fx > 0. ) {
188 lfx = log( fx );
189 if( fDomainMax == 1. ) {
190 nfx = sectionSubdivideMax; }
191 else {
192 nfx = ( (int) ( lfx / log( fDomainMax ) ) ) + 1;
193 if( nfx > sectionSubdivideMax ) nfx = sectionSubdivideMax;
194 }
195 if( nfx > 0 ) fx = exp( lfx / nfx );
196 doLinear = 0;
197 if( dx < ( fx - 1 ) * x1 ) doLinear = 1; }
198 else {
199 doLinear = 1;
200 }
201 }
202 x = x1;
203 dxp = dx;
204 nDone = 0;
205 while( 1 ) {
206 if( doLinear ) {
207 x += dx; }
208 else {
209 dx = ptwXY_thicken_linear_dx( sectionSubdivideMax - nDone, dDomainMax, x, x2 );
210 if( dx <= ( fx - 1 ) * x ) {
211 dxp = dx;
212 doLinear = 1;
213 continue;
214 }
215 dxp = ( fx - 1. ) * x;
216 x *= fx;
217 }
218 if( ( x2 - x ) < 0.05 * fabs( dxp ) ) break;
219 if( ( ptwXY1->status = ptwXY_interpolatePoint( smr, ptwXY1->interpolation, x, &y, x1, y1, x2, y2 ) ) != nfu_Okay ) {
221 return( ptwXY1->status );
222 }
223 if( ( ptwXY1->status = ptwXY_setValueAtX( smr, ptwXY1, x, y ) ) != nfu_Okay ) {
225 return( ptwXY1->status );
226 }
227 nDone++;
228 }
229 }
230 notFirstPass = 1;
231 x2 = x1;
232 y2 = y1;
233 }
234 return( ptwXY1->status );
235}
236/*
237************************************************************
238*/
239static double ptwXY_thicken_linear_dx( int sectionSubdivideMax, double dDomainMax, double x1, double x2 ) {
240
241 int ndx;
242 double dx = x2 - x1, dndx;
243
244 if( dDomainMax == 0. ) {
245 dx = ( x2 - x1 ) / sectionSubdivideMax; }
246 else {
247 dndx = dx / dDomainMax;
248 ndx = (int) dndx;
249 if( ( dndx - ndx ) > 1e-6 ) ndx++;
250 if( ndx > sectionSubdivideMax ) ndx = sectionSubdivideMax;
251 if( ndx > 0 ) dx /= ndx;
252 }
253
254 return( dx );
255}
256/*
257************************************************************
258*/
259ptwXYPoints *ptwXY_thin( statusMessageReporting *smr, ptwXYPoints *ptwXY1, double accuracy ) {
260
261 int64_t i, j, length = ptwXY1->length;
262 ptwXYPoints *thinned = NULL;
263 double y1, y2, y3, accuracyNew;
264 char *thin = NULL;
265
266 if( length < 3 ) { /* Logic below requires at least 2 points. */
267 if( ( thinned = ptwXY_clone( smr, ptwXY1 ) ) == NULL )
269 return( thinned );
270 }
271
272 if( ptwXY_simpleCoalescePoints( smr, ptwXY1 ) != nfu_Okay ) {
274 return( NULL );
275 }
276
277 if( ptwXY1->interpolation == ptwXY_interpolationOther ) {
278 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_otherInterpolation, "Other interpolation not allowed." );
279 return( NULL );
280 }
281
282 accuracy = ptwXY_limitAccuracy( accuracy );
283 accuracyNew = accuracy;
284 if( accuracyNew < ptwXY1->accuracy ) accuracyNew = ptwXY1->accuracy;
285 if( ( thinned = ptwXY_new( smr, ptwXY1->interpolation, ptwXY1->interpolationString,
286 ptwXY1->biSectionMax, accuracyNew, length, ptwXY1->overflowLength, ptwXY1->userFlag ) ) == NULL ) {
288 return( NULL );
289 }
290
291 thinned->points[0] = ptwXY1->points[0]; /* This sections removes middle point if surrounding points have the same y-value. */
292 y1 = ptwXY1->points[0].y;
293 y2 = ptwXY1->points[1].y;
294 for( i = 2, j = 1; i < length; i++ ) {
295 y3 = ptwXY1->points[i].y;
296 if( ( y1 != y2 ) || ( y2 != y3 ) ) {
297 thinned->points[j++] = ptwXY1->points[i - 1];
298 y1 = y2;
299 y2 = y3;
300 }
301 }
302 thinned->points[j++] = ptwXY1->points[length - 1];
303
304 if( ptwXY1->interpolation != ptwXY_interpolationFlat ) { /* Now call ptwXY_thin2 for more thinning. */
305 length = thinned->length = j;
306 if( ( thin = (char *) smr_malloc2( smr, (size_t) length, 1, "thin" ) ) == NULL ) goto Err2;
307 if( ptwXY_thin2( smr, thinned, thin, accuracy, 0, length - 1 ) != nfu_Okay ) goto Err1;
308 for( j = 1; j < length; j++ ) if( thin[j] != 0 ) break;
309 for( i = j + 1; i < length; i++ ) {
310 if( thin[i] == 0 ) {
311 thinned->points[j] = thinned->points[i];
312 j++;
313 }
314 }
315 smr_freeMemory2( thin );
316 }
317 thinned->length = j;
318
319 return( thinned );
320
321Err1:
323Err2:
324 ptwXY_free( thinned );
325 if( thin != NULL ) smr_freeMemory2( thin );
326 return( NULL );
327}
328/*
329************************************************************
330*/
331static nfu_status ptwXY_thin2( statusMessageReporting *smr, ptwXYPoints *thinned, char *thin, double accuracy, int64_t i1, int64_t i2 ) {
332
333 int64_t i, iMax = 0;
334 double y, s, dRange, dRangeMax = 0., dRangeR, dRangeRMax = 0;
335 double x1 = thinned->points[i1].x, y1 = thinned->points[i1].y, x2 = thinned->points[i2].x, y2 = thinned->points[i2].y;
336 nfu_status status = nfu_Okay;
337
338 if( i1 + 1 >= i2 ) return( nfu_Okay );
339 for( i = i1 + 1; i < i2; i++ ) {
340 if( ( thinned->status = ptwXY_interpolatePoint( smr, thinned->interpolation, thinned->points[i].x, &y, x1, y1, x2, y2 ) ) != nfu_Okay ) {
342 return( thinned->status );
343 }
344 s = 0.5 * ( fabs( y ) + fabs( thinned->points[i].y ) );
345 dRange = fabs( y - thinned->points[i].y );
346 dRangeR = 0;
347 if( s != 0 ) dRangeR = dRange / s;
348 if( ( dRangeR > dRangeRMax ) || ( ( dRangeR >= 0.9999 * dRangeRMax ) && ( dRange > dRangeMax ) ) ) {
349 iMax = i; /* The choice of 0.9999 is not exact science. */
350 if( dRange > dRangeMax ) dRangeMax = dRange;
351 if( dRangeR > dRangeRMax ) dRangeRMax = dRangeR;
352 }
353 }
354 if( dRangeRMax < accuracy ) {
355 for( i = i1 + 1; i < i2; i++ ) thin[i] = 1; }
356 else {
357 if( ( status = ptwXY_thin2( smr, thinned, thin, accuracy, i1, iMax ) ) != nfu_Okay ) return( status );
358 status = ptwXY_thin2( smr, thinned, thin, accuracy, iMax, i2 );
359 }
360 return( status );
361}
362/*
363************************************************************
364*/
366/*
367* Thins domain points that are closer the '0.5 * (x[i+1] + x[i]) * epsilon'.
368*/
369 int64_t i1, i2, length = ptwXY1->length, lengthm1 = length - 1, thinnedLength = 0;
370 ptwXYPoint *points;
371 ptwXYPoints *thinned = NULL;
372 double x1, x2, x3, dx, y2, half_epsilon = 0.5 * epsilon;
373
374 if( ptwXY1->interpolation == ptwXY_interpolationFlat ) {
375 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_invalidInterpolation, "Flat interpolation not allowed." );
376 return( NULL );
377 }
378
379 if( ptwXY1->interpolation == ptwXY_interpolationOther ) {
380 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_otherInterpolation, "Other interpolation not allowed." );
381 return( NULL );
382 }
383
384 if( ptwXY_simpleCoalescePoints( smr, ptwXY1 ) != nfu_Okay ) {
386 return( NULL );
387 }
388
389 if( length > 1 ) {
390 if( ( ptwXY1->points[length-1].x - ptwXY1->points[0].x ) < half_epsilon * ( fabs( ptwXY1->points[0].x ) + fabs( ptwXY1->points[0].x ) ) ) {
391 smr_setReportError2( smr, nfu_SMR_libraryID, nfu_Error, "Domain (%.17e, %.17e) is less than epsilon = %.17e.",
392 ptwXY1->points[0].x, ptwXY1->points[length-1].x, epsilon );
393 return( NULL );
394 }
395 }
396
397 if( ( length <= 2 ) || ( epsilon < 2 * DBL_EPSILON ) ) {
398 if( ( thinned = ptwXY_clone( smr, ptwXY1 ) ) == NULL ) smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_Error, "Via." );
399 return( thinned );
400 }
401
402 if( ( thinned = ptwXY_new( smr, ptwXY1->interpolation, ptwXY1->interpolationString, ptwXY1->biSectionMax, ptwXY1->accuracy,
403 length, ptwXY1->overflowAllocatedSize, ptwXY1->userFlag ) ) == NULL ) {
405 return( NULL );
406 }
407
408 points = thinned->points;
409 *points = ptwXY1->points[0];
410 ++points;
411 ++thinnedLength;
412 x1 = ptwXY1->points[0].x;
413 x2 = x3 = x1; /* To stop some compilers from printing a warning. */
414 for( i1 = 1; i1 < lengthm1; i1 = i2 ) {
415 for( i2 = i1; i2 < length; ++i2 ) { /* Find next x3 that is epsilon * ( x1 + x2 ) / 2 above x1. */
416 x3 = ptwXY1->points[i2].x;
417 if( ( x3 - x1 ) >= half_epsilon * ( fabs( x1 ) + fabs( x3 ) ) ) break;
418 x2 = x3;
419 }
420 if( i1 == i2 ) {
421 y2 = ptwXY1->points[i2].y;
422 x2 = x3; }
423 else {
424 if( ( x3 - x1 ) > ( epsilon * ( fabs( x1 ) + fabs( x3 ) ) ) ) {
425 dx = fabs( x2 * epsilon );
426 x2 = x1 + dx;
427 if( ptwXY_getValueAtX( smr, ptwXY1, x2, &y2 ) != nfu_Okay ) {
429 ptwXY_free( thinned );
430 return( NULL );
431 }
432 --i2; }
433 else {
434 if( i2 == length ) break;
435 x2 = x3;
436 y2 = ptwXY1->points[i2].y;
437 }
438 }
439 points->x = x2;
440 points->y = y2;
441 ++points;
442 ++thinnedLength;
443 x1 = x2;
444 ++i2;
445 }
446
447 x3 = ptwXY1->points[lengthm1].x;
448 x2 = thinned->points[thinnedLength-1].x;
449 if( ( x3 - x2 ) < ( half_epsilon * ( fabs( x2 ) + fabs( x3 ) ) ) ) {
450 --points;
451 --thinnedLength;
452 x1 = thinned->points[thinnedLength-1].x;
453 if( ( x3 - x1 ) > ( epsilon * ( fabs( x1 ) + fabs( x2 ) ) ) ) {
454 dx = fabs( x3 * epsilon );
455 x2 = x3 - dx;
456 if( ptwXY_getValueAtX( smr, ptwXY1, x2, &y2 ) != nfu_Okay ) {
458 ptwXY_free( thinned );
459 return( NULL );
460 }
461 points->x = x2;
462 points->y = y2;
463 ++points;
464 ++thinnedLength;
465 }
466 }
467 points->x = x3;
468 points->y = ptwXY1->points[lengthm1].y;
469 ++thinnedLength;
470 thinned->length = thinnedLength;
471
472 return( thinned );
473}
474/*
475************************************************************
476*/
478/*
479c Remove extra zeros at beginning and end.
480*/
481 int64_t i, i1, i2;
482
483 if( ptwXY->status != nfu_Okay ) {
484 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_badSelf, "Invalid destination." );
485 return( ptwXY->status );
486 }
487
488 if( ptwXY_simpleCoalescePoints( smr, ptwXY ) != nfu_Okay ) {
490 return( ptwXY->status );
491 }
492
493 for( i1 = 0; i1 < ptwXY->length; i1++ ) {
494 if( ptwXY->points[i1].y != 0 ) break;
495 }
496 if( i1 > 0 ) i1--;
497 for( i2 = ptwXY->length - 1; i2 >= 0; i2-- ) {
498 if( ptwXY->points[i2].y != 0 ) break;
499 }
500 i2++;
501 if( i2 < ptwXY->length ) i2++;
502 if( i2 > i1 ) {
503 if( i1 > 0 ) {
504 for( i = i1; i < i2; i++ ) ptwXY->points[i - i1] = ptwXY->points[i];
505 }
506 ptwXY->length = i2 - i1; }
507 else if( i2 < i1 ) { /* Remove all zeros between endpoints. */
508 ptwXY->points[1] = ptwXY->points[ptwXY->length - 1];
509 ptwXY->length = 2;
510 }
511
512 return( nfu_Okay );
513}
514/*
515************************************************************
516*/
517ptwXYPoints *ptwXY_union( statusMessageReporting *smr, ptwXYPoints *ptwXY1, ptwXYPoints *ptwXY2, int unionOptions ) {
518
519 int64_t overflowSize, i, i1 = 0, i2 = 0, n1 = ptwXY1->length, n2 = ptwXY2->length, length;
520 int fillWithFirst = unionOptions & ptwXY_union_fill, trim = unionOptions & ptwXY_union_trim;
521 ptwXYPoints *n;
522 double x1 = 0., x2 = 0., y1 = 0., y2 = 0., y, biSectionMax, accuracy;
523/*
524* Many other routines use the fact that ptwXY_union calls ptwXY_coalescePoints for ptwXY1 and ptwXY2 so do not change it.
525*/
526 if( ptwXY_simpleCoalescePoints( smr, ptwXY1 ) != nfu_Okay ) {
528 return( NULL );
529 }
530 if( ptwXY_simpleCoalescePoints( smr, ptwXY2 ) != nfu_Okay ) {
532 return( NULL );
533 }
534
535 if( ptwXY1->interpolation == ptwXY_interpolationOther ) {
536 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_otherInterpolation, "Other interpolation not allowed for source1." );
537 return( NULL );
538 }
539 if( ptwXY2->interpolation == ptwXY_interpolationOther ) {
540 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_otherInterpolation, "Other interpolation not allowed for source2." );
541 return( NULL );
542 }
543
544 if( ( n1 == 1 ) || ( n2 == 1 ) ) {
546 "Too few point in one of the sources: len( source1 ) = %d, len( source2 ) = %d", (int) n1, (int) n2 );
547 return( NULL );
548 }
549 if( trim ) {
550 if( n1 > 0 ) {
551 if( n2 > 0 ) {
552 if( ptwXY1->points[0].x < ptwXY2->points[0].x ) {
553 while( i1 < n1 ) {
554 if( ptwXY1->points[i1].x >= ptwXY2->points[0].x ) break;
555 if( fillWithFirst ) {
556 if( i1 < ( ptwXY1->length - 1 ) ) {
557 x1 = ptwXY1->points[i1].x;
558 y1 = ptwXY1->points[i1].y;
559 x2 = ptwXY1->points[i1+1].x;
560 y2 = ptwXY1->points[i1+1].y;
561 }
562 }
563 i1++;
564 } }
565 else {
566 while( i2 < n2 ) {
567 if( ptwXY2->points[i2].x >= ptwXY1->points[0].x ) break;
568 i2++;
569 }
570 }
571 if( ptwXY1->points[n1-1].x > ptwXY2->points[n2-1].x ) {
572 while( i1 < n1 ) {
573 if( ptwXY1->points[n1-1].x <= ptwXY2->points[n2-1].x ) break;
574 n1--;
575 } }
576 else {
577 while( i2 < n2 ) {
578 if( ptwXY2->points[n2-1].x <= ptwXY1->points[n1-1].x ) break;
579 n2--;
580 }
581 } }
582 else {
583 n1 = 0;
584 } }
585 else {
586 n2 = 0;
587 }
588 }
589 overflowSize = ptwXY1->overflowAllocatedSize;
590 if( overflowSize < ptwXY2->overflowAllocatedSize ) overflowSize = ptwXY2->overflowAllocatedSize;
591 length = ( n1 - i1 ) + ( n2 - i2 );
592 if( length == 0 ) length = ptwXY_minimumSize;
593 biSectionMax = ptwXY1->biSectionMax;
594 if( biSectionMax < ptwXY2->biSectionMax ) biSectionMax = ptwXY2->biSectionMax;
595 accuracy = ptwXY1->accuracy;
596 if( accuracy < ptwXY2->accuracy ) accuracy = ptwXY2->accuracy;
597 n = ptwXY_new( smr, ptwXY1->interpolation, NULL, biSectionMax, accuracy, length, overflowSize, ptwXY1->userFlag );
598 if( n == NULL ) {
600 return( NULL );
601 }
602
603 for( i = 0; ( i1 < n1 ) && ( i2 < n2 ); i++ ) {
604 y = 0.;
605 if( ptwXY1->points[i1].x <= ptwXY2->points[i2].x ) {
606 n->points[i].x = ptwXY1->points[i1].x;
607 if( fillWithFirst ) {
608 y = ptwXY1->points[i1].y;
609 if( i1 < ( ptwXY1->length - 1 ) ) {
610 x1 = ptwXY1->points[i1].x;
611 y1 = ptwXY1->points[i1].y;
612 x2 = ptwXY1->points[i1+1].x;
613 y2 = ptwXY1->points[i1+1].y; }
614 else {
615 y1 = 0.;
616 y2 = 0.;
617 }
618 }
619 if( ptwXY1->points[i1].x == ptwXY2->points[i2].x ) i2++;
620 i1++; }
621 else {
622 n->points[i].x = ptwXY2->points[i2].x;
623 if( fillWithFirst && ( ( y1 != 0. ) || ( y2 != 0. ) ) ) {
624 if( ptwXY_interpolatePoint( smr, ptwXY1->interpolation, ptwXY2->points[i2].x, &y, x1, y1, x2, y2 ) != nfu_Okay ) {
626 ptwXY_free( n );
627 return( NULL );
628 }
629 }
630 i2++;
631 }
632 n->points[i].y = y;
633 }
634
635 y = 0.;
636 for( ; i1 < n1; i1++, i++ ) {
637 n->points[i].x = ptwXY1->points[i1].x;
638 if( fillWithFirst ) y = ptwXY1->points[i1].y;
639 n->points[i].y = y;
640 }
641 for( ; i2 < n2; i2++, i++ ) {
642 n->points[i].x = ptwXY2->points[i2].x;
643 if( fillWithFirst && trim && ( n->points[i].x <= x2 ) ) {
644 if( ptwXY_interpolatePoint( smr, ptwXY1->interpolation, n->points[i].x, &y, x1, y1, x2, y2 ) != nfu_Okay ) {
646 ptwXY_free( n );
647 return( NULL );
648 }
649 }
650 n->points[i].y = y;
651 }
652 n->length = i;
653
654 if( unionOptions & ptwXY_union_mergeClosePoints ) {
655 if( ptwXY_mergeClosePoints( smr, n, 4 * DBL_EPSILON ) != nfu_Okay ) {
657 ptwXY_free( n );
658 return( NULL );
659 }
660 }
661 return( n );
662}
663/*
664************************************************************
665*/
666nfu_status ptwXY_scaleOffsetXAndY( statusMessageReporting *smr, ptwXYPoints *ptwXY, double xScale, double xOffset,
667 double yScale, double yOffset ) {
668
669 int64_t i1, length = ptwXY->length;
670 ptwXYPoint *p1;
671 nfu_status status;
672
673 if( ptwXY->status != nfu_Okay ) {
674 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_badSelf, "Invalid destination." );
675 return( ptwXY->status );
676 }
677
678 if( xScale == 0 ) {
679 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_XNotAscending, "xScale is 0 that will cause a non-ascending domain." );
680 return( ptwXY->status = nfu_XNotAscending );
681 }
682
683 if( ( status = ptwXY_simpleCoalescePoints( smr, ptwXY ) ) != nfu_Okay ) {
685 return( status );
686 }
687
688 for( i1 = 0, p1 = ptwXY->points; i1 < length; i1++, p1++ ) {
689 p1->x = xScale * p1->x + xOffset;
690 p1->y = yScale * p1->y + yOffset;
691 }
692
693 if( xScale < 0 ) {
694 int64_t length_2 = length / 2;
695 ptwXYPoint tmp, *p2;
696
697 for( i1 = 0, p1 = ptwXY->points, p2 = &(ptwXY->points[length-1]); i1 < length_2; i1++ ) {
698 tmp = *p1;
699 *p1 = *p2;
700 *p2 = tmp;
701 }
702 }
703
704 return( ptwXY->status );
705}
706/*
707************************************************************
708*/
710 int skipLastPoint ) {
711/*
712 This function only modifies ptwXY over the domain defined by offsetXY via the equation ptwXY = offsetXY + slopeXY * ptwXY.
713 slopeXY must have the same domain as offsetXY. If skipLastPoint is non-zero, the last point modified is reverted by to its
714 origial value. This allows one to call this function multiple times with abutting domains for the offset and slope without
715 getting weird jumps at the boundaries. For example, suppose ptwXY is initially defined to be 1 in the domain [0,10]. Let,
716 ptwXY have the points [ [ 0, 1 ], [ 5, 1 ], [ 10, 1 ] ]. Calling this function with an offset and slope with the points
717 [ [ 0, 0 ], [ 5, 0 ] ] and [ 0, 2 ], [ 5, 2 ], respectively would return ptwXY as [ [ 0, 2 ], [ 5, 2 ], [ 10, 1 ] ]
718 if skipLastPoint is 0 and [ [ 0, 2 ], [ 5, 1 ], [ 10, 1 ] ] otherwise. Now calling the returned ptwXYPoints instances with an
719 offset and slope with the points [ [ 5, 0 ], [ 10, 0 ] ] and [ 5, 2 ], [ 10, 2 ], respectively would return ptwXY as
720 [ [ 0, 2 ], [ 5, 4 ], [ 10, 2 ] ] and [ [ 0, 2 ], [ 5, 2 ], [ 10, 2 ] ], respectively.
721*/
722
723 int64_t i1;
724 ptwXYPoint *p1;
725 nfu_status status1, status2;
726 double offsetXYMin, offsetXYMax, slopeXYMin, slopeXYMax, domainMin, domainMax, domainMinXY, domainMaxXY;
727 ptwXYPoints *ptwXY2 = NULL, *offsetXY2 = NULL, *slopeXY2 = NULL;
728 ptwXYPoints *mulXY = NULL, *addXY = NULL;
729
730 if( ptwXY_simpleCoalescePoints( smr, ptwXY ) != nfu_Okay ) {
732 return( ptwXY->status );
733 }
734
735 status1 = ptwXY_domainMin( smr, offsetXY, &offsetXYMin ); /* Also verifies that offsetXY has no issues. */
736 if( ( status1 != nfu_Okay ) && ( status1 != nfu_empty ) ) {
738 return( status1 );
739 }
740 ptwXY_domainMax( smr, offsetXY, &offsetXYMax ); /* If ptwXY_domainMin succeeded, this will succeed. */
741
742 status2 = ptwXY_domainMin( smr, slopeXY, &slopeXYMin );
743 if( ( status2 != nfu_Okay ) && ( status2 != nfu_empty ) ) {
745 return( status2 );
746 }
747 ptwXY_domainMax( smr, slopeXY, &slopeXYMax );
748
749 if( ( status1 == nfu_empty ) && ( status2 == nfu_empty ) ) return( nfu_Okay );
750
751 if( ( offsetXYMin != slopeXYMin ) || ( offsetXYMax != slopeXYMax ) ) {
752 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_domainsNotMutual, "Offset and slope do not have the same domain." );
753 return( ptwXY->status = nfu_domainsNotMutual );
754 }
755
756 if( ptwXY->length == 0 ) return( nfu_Okay );
757
758 ptwXY_domainMin( smr, ptwXY, &domainMinXY );
759 ptwXY_domainMax( smr, ptwXY, &domainMaxXY );
760
761 if( ( domainMinXY >= offsetXYMax ) || ( domainMaxXY <= offsetXYMin ) ) return( nfu_Okay );
762
763 domainMin = ( domainMinXY > offsetXYMin ? domainMinXY : offsetXYMin );
764 domainMax = ( domainMaxXY < offsetXYMax ? domainMaxXY : offsetXYMax );
765
766 if( ( domainMinXY == offsetXYMin ) && ( domainMaxXY == offsetXYMax ) ) {
767 ptwXY2 = ptwXY;
768 offsetXY2 = offsetXY;
769 slopeXY2 = slopeXY; }
770 else {
771 if( ( ptwXY2 = ptwXY_domainSlice( smr, ptwXY, domainMin, domainMax, 0, 1 ) ) == NULL ) {
773 goto Err;
774 }
775
776 if( ( offsetXY2 = ptwXY_domainSlice( smr, offsetXY, domainMin, domainMax, 0, 1 ) ) == NULL ) {
778 goto Err;
779 }
780
781 if( ( slopeXY2 = ptwXY_domainSlice( smr, slopeXY, domainMin, domainMax, 0, 1 ) ) == NULL ) {
783 goto Err;
784 }
785 }
786
787 if( ( mulXY = ptwXY_mul2_ptwXY( smr, ptwXY2, slopeXY2 ) ) == NULL ) {
789 goto Err;
790 }
791 if( ( addXY = ptwXY_mul2_ptwXY( smr, mulXY, offsetXY2 ) ) == NULL ) {
793 goto Err;
794 }
795 if( skipLastPoint != 0 ) addXY->points[addXY->length-1].y = ptwXY2->points[ptwXY2->length-1].y;
796
797 if( domainMin > domainMinXY ) {
798 for( i1 = 0, p1 = ptwXY2->points; i1 < ptwXY2->length; i1++, p1++ ) {
799 if( p1->x >= domainMin ) break;
800 if( ptwXY_setValueAtX( smr, addXY, p1->x, p1->y ) != nfu_Okay ) goto Err;
801 }
802 }
803
804 if( domainMax < domainMaxXY ) {
805 for( i1 = 0, p1 = ptwXY2->points; i1 < ptwXY2->length; i1++, p1++ ) if( p1->x > domainMax ) break;
806 for( ; i1 < ptwXY2->length; i1++, p1++ ) {
807 if( ptwXY_setValueAtX( smr, addXY, p1->x, p1->y ) != nfu_Okay ) goto Err;
808 }
809 }
810
811 ptwXY_copy( smr, ptwXY, addXY );
812
813TheEnd:
814 if( offsetXY2 != offsetXY ) ptwXY_free( offsetXY2 );
815 if( slopeXY2 != slopeXY ) ptwXY_free( slopeXY2 );
816 if( ptwXY2 != ptwXY ) ptwXY_free( ptwXY2 );
817 ptwXY_free( mulXY );
818 ptwXY_free( addXY );
819
820 return( ptwXY->status );
821
822Err:
823 ptwXY->status = nfu_Error;
824 goto TheEnd;
825}
G4double epsilon(G4double density, G4double temperature)
@ nfu_domainsNotMutual
@ nfu_XNotAscending
@ nfu_invalidInterpolation
@ nfu_Okay
@ nfu_badSelf
@ nfu_tooFewPoints
@ nfu_badInput
@ nfu_Error
@ nfu_empty
@ nfu_otherInterpolation
enum nfu_status_e nfu_status
int nfu_SMR_libraryID
ptwXYPoints * ptwXY_domainSlice(statusMessageReporting *smr, ptwXYPoints *ptwXY, double domainMin, double domainMax, int64_t secondarySize, int fill)
Definition ptwXY_core.c:422
nfu_status ptwXY_setValueAtX(statusMessageReporting *smr, ptwXYPoints *ptwXY, double x, double y)
double ptwXY_limitAccuracy(double accuracy)
Definition ptwXY_misc.c:28
ptwXYPoints * ptwXY_clone(statusMessageReporting *smr, ptwXYPoints *ptwXY)
Definition ptwXY_core.c:302
nfu_status ptwXY_range(statusMessageReporting *smr, ptwXYPoints *ptwXY, double *rangeMin, double *rangeMax)
@ ptwXY_interpolationFlat
Definition ptwXY.h:38
@ ptwXY_interpolationOther
Definition ptwXY.h:38
ptwXYPoints * ptwXY_mul2_ptwXY(statusMessageReporting *smr, ptwXYPoints *ptwXY1, ptwXYPoints *ptwXY2)
struct ptwXYPoints_s ptwXYPoints
#define ptwXY_union_trim
Definition ptwXY.h:35
nfu_status ptwXY_clear(statusMessageReporting *smr, ptwXYPoints *ptwXY)
Definition ptwXY_core.c:743
#define ptwXY_minimumSize
Definition ptwXY.h:23
nfu_status ptwXY_interpolatePoint(statusMessageReporting *smr, ptwXY_interpolation interpolation, double x, double *y, double x1, double y1, double x2, double y2)
#define ptwXY_union_fill
Definition ptwXY.h:34
ptwXYPoints * ptwXY_new(statusMessageReporting *smr, ptwXY_interpolation interpolation, char const *interpolationString, double biSectionMax, double accuracy, int64_t primarySize, int64_t secondarySize, int userFlag)
Definition ptwXY_core.c:28
#define ptwXY_sectionSubdivideMax
Definition ptwXY.h:27
nfu_status ptwXY_copy(statusMessageReporting *smr, ptwXYPoints *dest, ptwXYPoints *src)
Definition ptwXY_core.c:171
#define ptwXY_union_mergeClosePoints
Definition ptwXY.h:36
struct ptwXYPoint_s ptwXYPoint
nfu_status ptwXY_mergeClosePoints(statusMessageReporting *smr, ptwXYPoints *ptwXY, double epsilon)
ptwXYPoints * ptwXY_free(ptwXYPoints *ptwXY)
Definition ptwXY_core.c:782
ptwXYPoint * ptwXY_getPointAtIndex_Unsafely(ptwXYPoints const *ptwXY, int64_t index)
nfu_status ptwXY_domainMax(statusMessageReporting *smr, ptwXYPoints *ptwXY, double *value)
nfu_status ptwXY_getValueAtX(statusMessageReporting *smr, ptwXYPoints *ptwXY, double x, double *y)
nfu_status ptwXY_simpleCoalescePoints(statusMessageReporting *smr, ptwXYPoints *ptwXY)
Definition ptwXY_core.c:734
nfu_status ptwXY_domainMin(statusMessageReporting *smr, ptwXYPoints *ptwXY, double *value)
nfu_status ptwXY_trim(statusMessageReporting *smr, ptwXYPoints *ptwXY)
nfu_status ptwXY_scaleOffsetXAndY(statusMessageReporting *smr, ptwXYPoints *ptwXY, double xScale, double xOffset, double yScale, double yOffset)
nfu_status ptwXY_scaleAndOffsetDomainWith_ptwXYs(statusMessageReporting *smr, ptwXYPoints *ptwXY, ptwXYPoints *offsetXY, ptwXYPoints *slopeXY, int skipLastPoint)
nfu_status ptwXY_clip(statusMessageReporting *smr, ptwXYPoints *ptwXY1, double rangeMin, double rangeMax)
ptwXYPoints * ptwXY_thinDomain(statusMessageReporting *smr, ptwXYPoints *ptwXY1, double epsilon)
ptwXYPoints * ptwXY_thin(statusMessageReporting *smr, ptwXYPoints *ptwXY1, double accuracy)
nfu_status ptwXY_thicken(statusMessageReporting *smr, ptwXYPoints *ptwXY1, int sectionSubdivideMax, double dDomainMax, double fDomainMax)
ptwXYPoints * ptwXY_union(statusMessageReporting *smr, ptwXYPoints *ptwXY1, ptwXYPoints *ptwXY2, int unionOptions)
#define smr_setReportError2(smr, libraryID, code, fmt,...)
#define smr_setReportError2p(smr, libraryID, code, fmt)
#define smr_freeMemory2(p)
#define smr_malloc2(smr, size, zero, forItem)
double y
Definition ptwXY.h:64
double x
Definition ptwXY.h:64
int userFlag
Definition ptwXY.h:83
ptwXYPoint * points
Definition ptwXY.h:93
ptwXY_interpolation interpolation
Definition ptwXY.h:81
double biSectionMax
Definition ptwXY.h:84
double accuracy
Definition ptwXY.h:85
int64_t length
Definition ptwXY.h:87
int64_t overflowLength
Definition ptwXY.h:89
int64_t overflowAllocatedSize
Definition ptwXY.h:90
nfu_status status
Definition ptwXY.h:80
int64_t allocatedSize
Definition ptwXY.h:88
char const * interpolationString
Definition ptwXY.h:82
#define DBL_EPSILON
Definition templates.hh:66