1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/* ---- includes ----------------------------------------------------------- */
18
19#include "b_TensorEm/RBFMap2D.h"
20#include "b_BasicEm/Math.h"
21#include "b_BasicEm/Memory.h"
22#include "b_BasicEm/Functions.h"
23
24/* ------------------------------------------------------------------------- */
25
26/* ========================================================================= */
27/*                                                                           */
28/* ---- \ghd{ auxiliary functions } ---------------------------------------- */
29/*                                                                           */
30/* ========================================================================= */
31
32/* ------------------------------------------------------------------------- */
33
34/* ========================================================================= */
35/*                                                                           */
36/* ---- \ghd{ constructor / destructor } ----------------------------------- */
37/*                                                                           */
38/* ========================================================================= */
39
40/* ------------------------------------------------------------------------- */
41
42void bts_RBFMap2D_init( struct bbs_Context* cpA,
43					    struct bts_RBFMap2D* ptrA )
44{
45	ptrA->RBFTypeE = bts_RBF_LINEAR;
46	bts_Cluster2D_init( cpA, &ptrA->srcClusterE );
47	bts_Cluster2D_init( cpA, &ptrA->rbfCoeffClusterE );
48	ptrA->altTypeE = bts_ALT_LINEAR;
49	bts_Flt16Alt2D_init( &ptrA->altE );
50
51	ptrA->altOnlyE = FALSE;
52
53	bts_Int32Mat_init( cpA, &ptrA->matE );
54	bts_Int32Mat_init( cpA, &ptrA->tempMatE );
55	bbs_Int32Arr_init( cpA, &ptrA->inVecE );
56	bbs_Int32Arr_init( cpA, &ptrA->outVecE );
57	bbs_Int32Arr_init( cpA, &ptrA->tempVecE );
58}
59
60/* ------------------------------------------------------------------------- */
61
62void bts_RBFMap2D_exit( struct bbs_Context* cpA,
63					    struct bts_RBFMap2D* ptrA )
64{
65	ptrA->RBFTypeE = bts_RBF_LINEAR;
66	bts_Cluster2D_exit( cpA, &ptrA->srcClusterE );
67	bts_Cluster2D_exit( cpA, &ptrA->rbfCoeffClusterE );
68	ptrA->altTypeE = bts_ALT_LINEAR;
69	bts_Flt16Alt2D_exit( &ptrA->altE );
70
71	ptrA->altOnlyE = FALSE;
72
73	bts_Int32Mat_exit( cpA, &ptrA->matE );
74	bts_Int32Mat_exit( cpA, &ptrA->tempMatE );
75	bbs_Int32Arr_exit( cpA, &ptrA->inVecE );
76	bbs_Int32Arr_exit( cpA, &ptrA->outVecE );
77	bbs_Int32Arr_exit( cpA, &ptrA->tempVecE );
78}
79
80/* ------------------------------------------------------------------------- */
81
82/* ========================================================================= */
83/*                                                                           */
84/* ---- \ghd{ operators } -------------------------------------------------- */
85/*                                                                           */
86/* ========================================================================= */
87
88/* ------------------------------------------------------------------------- */
89
90void bts_RBFMap2D_copy( struct bbs_Context* cpA,
91					    struct bts_RBFMap2D* ptrA,
92						const struct bts_RBFMap2D* srcPtrA )
93{
94	ptrA->RBFTypeE = srcPtrA->RBFTypeE;
95	bts_Cluster2D_copy( cpA, &ptrA->srcClusterE, &srcPtrA->srcClusterE );
96	bts_Cluster2D_copy( cpA, &ptrA->rbfCoeffClusterE, &srcPtrA->rbfCoeffClusterE );
97	ptrA->altTypeE = srcPtrA->altTypeE;
98	bts_Flt16Alt2D_copy( &ptrA->altE, &srcPtrA->altE );
99}
100
101/* ------------------------------------------------------------------------- */
102
103flag bts_RBFMap2D_equal( struct bbs_Context* cpA,
104						 const struct bts_RBFMap2D* ptrA,
105						 const struct bts_RBFMap2D* srcPtrA )
106{
107	if( ptrA->RBFTypeE != srcPtrA->RBFTypeE ) return FALSE;
108	if( ! bts_Cluster2D_equal( cpA, &ptrA->srcClusterE, &srcPtrA->srcClusterE ) ) return FALSE;
109	if( ! bts_Cluster2D_equal( cpA, &ptrA->rbfCoeffClusterE, &srcPtrA->rbfCoeffClusterE ) ) return FALSE;
110	if( ptrA->altTypeE != srcPtrA->altTypeE ) return FALSE;
111	if( ! bts_Flt16Alt2D_equal( &ptrA->altE, &srcPtrA->altE ) ) return FALSE;
112	return TRUE;
113}
114
115/* ------------------------------------------------------------------------- */
116
117/* ========================================================================= */
118/*                                                                           */
119/* ---- \ghd{ query functions } -------------------------------------------- */
120/*                                                                           */
121/* ========================================================================= */
122
123/* ------------------------------------------------------------------------- */
124
125/* ========================================================================= */
126/*                                                                           */
127/* ---- \ghd{ modify functions } ------------------------------------------- */
128/*                                                                           */
129/* ========================================================================= */
130
131/* ------------------------------------------------------------------------- */
132
133void bts_RBFMap2D_create( struct bbs_Context* cpA,
134						  struct bts_RBFMap2D* ptrA,
135						  uint32 sizeA,
136				          struct bbs_MemSeg* mspA )
137{
138	if( bbs_Context_error( cpA ) ) return;
139	bts_Cluster2D_create( cpA, &ptrA->srcClusterE, sizeA, mspA );
140	bts_Cluster2D_create( cpA, &ptrA->rbfCoeffClusterE, sizeA, mspA );
141
142	bts_Int32Mat_create( cpA, &ptrA->matE, sizeA, mspA );
143	bts_Int32Mat_create( cpA, &ptrA->tempMatE, sizeA, mspA );
144	bbs_Int32Arr_create( cpA, &ptrA->inVecE, sizeA, mspA );
145	bbs_Int32Arr_create( cpA, &ptrA->outVecE, sizeA, mspA );
146	bbs_Int32Arr_create( cpA, &ptrA->tempVecE, sizeA, mspA );
147}
148
149/* ------------------------------------------------------------------------- */
150
151void bts_RBFMap2D_compute( struct bbs_Context* cpA,
152						   struct bts_RBFMap2D* ptrA,
153						   const struct bts_Cluster2D* srcPtrA,
154						   const struct bts_Cluster2D* dstPtrA )
155{
156	const uint32 sizeL = srcPtrA->sizeE;
157	int32 bbp_internalL = 15;
158	int32 bbp_rbfCoeffL = 12;
159
160	int32 internalShiftL = bbp_internalL - srcPtrA->bbpE;
161	int32 rbfCoeffShiftL;
162
163	uint32 iL, jL;
164
165	if( dstPtrA->sizeE != srcPtrA->sizeE )
166	{
167		bbs_ERROR2( "void bts_RBFMap2D_compute( ... ): size mismatch, src cluster has size %d,"
168			"but dst cluster has size %d\n", srcPtrA->sizeE, dstPtrA->sizeE );
169		return;
170	}
171
172	ptrA->altOnlyE = FALSE;
173
174	/* if bbp of src cluster should be larger than bbp_internal, use it instead */
175	if( internalShiftL < 0 )
176	{
177		internalShiftL = 0;
178		bbp_internalL = srcPtrA->bbpE;
179	}
180
181	/* also checks for sizeL > allocated size */
182	bts_Cluster2D_size( cpA, &ptrA->rbfCoeffClusterE, sizeL );
183
184	/* set rbf coefficients to 0 in case they don't get computed */
185	for( iL =0; iL < sizeL; iL++ )
186	{
187		ptrA->rbfCoeffClusterE.vecArrE[ iL ].xE = 0;
188		ptrA->rbfCoeffClusterE.vecArrE[ iL ].yE = 0;
189	}
190
191	/* 1. Compute rigid transformation: if cluster size == 0 returns identity */
192	ptrA->altE = bts_Cluster2D_alt( cpA, srcPtrA, dstPtrA, ptrA->altTypeE );
193
194	/* if cluster size is less than 3 affine trafo covers whole transformation */
195	if( sizeL < 3 )
196	{
197		bts_Cluster2D_copy( cpA, &ptrA->srcClusterE, srcPtrA );
198		ptrA->altOnlyE = TRUE;
199		return;
200	}
201
202	/* 2. Compute RBF trafo */
203	ptrA->matE.widthE = sizeL;
204	ptrA->tempMatE.widthE = sizeL;
205
206	/* Set up linear matrix to invert */
207	switch( ptrA->RBFTypeE )
208	{
209		case bts_RBF_IDENTITY:
210		{
211			return;
212		}
213
214		case bts_RBF_LINEAR:
215		{
216			/* ||r|| */
217			for( iL = 0; iL < sizeL; iL++ )
218			{
219				struct bts_Int16Vec2D vec0L = srcPtrA->vecArrE[ iL ];
220				int32* ptrL = ptrA->matE.arrE.arrPtrE + iL * sizeL;
221
222				/* set diagonal elements having null distance */
223				*( ptrL + iL ) = 0;
224
225				for( jL = 0; jL < iL; jL++ )	/* use symmetry */
226				{
227					int32 normL = 0;
228					struct bts_Int16Vec2D vecL = srcPtrA->vecArrE[ jL ];
229					vecL.xE -= vec0L.xE;
230					vecL.yE -= vec0L.yE;
231					normL = bts_Int16Vec2D_norm( &vecL );
232					*ptrL++ = normL << internalShiftL;
233				}
234			}
235		}
236		break;
237
238		/* Add a new RBF type here */
239
240		default:
241		{
242			bbs_ERROR1( "void bts_RBFMap2D_compute( ... ): RBFType %d is not handled\n", ptrA->RBFTypeE );
243			return;
244		}
245	}
246
247	/* use symmetry: set symmetric elements in matrix */
248	for( iL = 0; iL < sizeL; iL++ )
249	{
250		int32* basePtrL = ptrA->matE.arrE.arrPtrE;
251		uint32 jL;
252		for( jL = iL + 1; jL < sizeL; jL++ )
253		{
254			*( basePtrL + iL * sizeL + jL ) = *( basePtrL + jL * sizeL + iL );
255		}
256	}
257
258	/* Precompute alt transformed cluster, srcClusterE will be restored at the end */
259	bts_Cluster2D_copy( cpA, &ptrA->srcClusterE, srcPtrA );
260	bts_Cluster2D_transformBbp( cpA, &ptrA->srcClusterE, ptrA->altE, dstPtrA->bbpE );
261
262	bbs_Int32Arr_size( cpA, &ptrA->inVecE, sizeL );
263	bbs_Int32Arr_size( cpA, &ptrA->outVecE, sizeL );
264	bbs_Int32Arr_size( cpA, &ptrA->tempVecE, sizeL );
265
266	{
267		flag successL;
268
269		/* compute right side vector of linear system to be solved, for x */
270		int32* inPtrL = ptrA->inVecE.arrPtrE;
271		struct bts_Int16Vec2D* dstVecL = dstPtrA->vecArrE;
272		struct bts_Int16Vec2D* altVecL = ptrA->srcClusterE.vecArrE;
273
274		int32 shiftL = srcPtrA->bbpE - ptrA->srcClusterE.bbpE + internalShiftL;
275		if( shiftL >= 0 )
276		{
277			for( iL = 0; iL < sizeL; iL++ ) inPtrL[ iL ] = ( int32 )( dstVecL[ iL ].xE - altVecL[ iL ].xE ) << shiftL;
278		}
279		else
280		{
281			for( iL = 0; iL < sizeL; iL++ ) inPtrL[ iL ] = ( ( ( int32 )( dstVecL[ iL ].xE - altVecL[ iL ].xE ) >> ( ( -shiftL ) - 1 ) ) + 1 ) >> 1;
282		}
283
284		/* solve linear system in x */
285		successL = bts_Int32Mat_solve(  cpA,
286			                            ptrA->matE.arrE.arrPtrE,
287										sizeL,
288										ptrA->inVecE.arrPtrE,
289										ptrA->outVecE.arrPtrE,
290										bbp_internalL,
291										ptrA->tempMatE.arrE.arrPtrE,
292										ptrA->tempVecE.arrPtrE );
293
294		/* no error condition here! system must be failsafe */
295		if( !successL ) ptrA->altOnlyE = TRUE;
296
297		/* store rbf coefficients, x component */
298		rbfCoeffShiftL = bbp_internalL - bbp_rbfCoeffL;
299		for( iL = 0; iL < sizeL; iL++ )
300		{
301			int32 rbfCoeffL = ptrA->outVecE.arrPtrE[ iL ] >> rbfCoeffShiftL;
302			if( rbfCoeffL < -32768 || rbfCoeffL > 32767 ) ptrA->altOnlyE = TRUE; /* check for overflow */
303			ptrA->rbfCoeffClusterE.vecArrE[ iL ].xE = rbfCoeffL;
304		}
305
306
307		/* compute right side vector of linear system to be solved, for y */
308		if( shiftL >= 0 )
309		{
310			for( iL = 0; iL < sizeL; iL++ ) inPtrL[ iL ] = ( int32 )( dstVecL[ iL ].yE - altVecL[ iL ].yE ) << shiftL;
311		}
312		else
313		{
314			for( iL = 0; iL < sizeL; iL++ ) inPtrL[ iL ] = ( ( ( int32 )( dstVecL[ iL ].yE - altVecL[ iL ].yE ) >> ( ( -shiftL ) - 1 ) ) + 1 ) >> 1;
315		}
316
317		/* solve linear system in y */
318		successL = bts_Int32Mat_solve(  cpA,
319			                            ptrA->matE.arrE.arrPtrE,
320										sizeL,
321										ptrA->inVecE.arrPtrE,
322										ptrA->outVecE.arrPtrE,
323										bbp_internalL,
324										ptrA->tempMatE.arrE.arrPtrE,
325										ptrA->tempVecE.arrPtrE );
326		if( !successL )
327		{
328			/* no error condition here! system must be failsafe */
329			ptrA->altOnlyE = TRUE;
330		}
331
332		/* store rbf coefficients, y component */
333		for( iL = 0; iL < sizeL; iL++ )
334		{
335			int32 rbfCoeffL = ptrA->outVecE.arrPtrE[ iL ] >> rbfCoeffShiftL;
336			if( rbfCoeffL < -32768 || rbfCoeffL > 32767 ) ptrA->altOnlyE = TRUE; /* check for overflow */
337			ptrA->rbfCoeffClusterE.vecArrE[ iL ].yE = rbfCoeffL;
338		}
339
340		/* set bbp of coeff cluster */
341		ptrA->rbfCoeffClusterE.bbpE = bbp_rbfCoeffL;
342	}
343
344	/** after having used srcClusterE for temporary storage of the alt src cluster,
345		restore the orig src cluster as needed for the RBF trafo */
346	bts_Cluster2D_copy( cpA, &ptrA->srcClusterE, srcPtrA );
347}
348
349/* ------------------------------------------------------------------------- */
350
351/* ========================================================================= */
352/*                                                                           */
353/* ---- \ghd{ I/O } -------------------------------------------------------- */
354/*                                                                           */
355/* ========================================================================= */
356
357/* ------------------------------------------------------------------------- */
358
359uint32 bts_RBFMap2D_memSize( struct bbs_Context* cpA,
360							 const struct bts_RBFMap2D *ptrA )
361{
362	return  bbs_SIZEOF16( uint32 )
363		  + bbs_SIZEOF16( uint32 ) /* version */
364		  + bbs_SIZEOF16( ptrA->RBFTypeE )
365		  + bts_Cluster2D_memSize( cpA, &ptrA->srcClusterE )
366		  + bts_Cluster2D_memSize( cpA, &ptrA->rbfCoeffClusterE )
367		  + bbs_SIZEOF16( ptrA->altTypeE )
368		  + bts_Flt16Alt2D_memSize( cpA, &ptrA->altE );
369}
370
371/* ------------------------------------------------------------------------- */
372
373uint32 bts_RBFMap2D_memWrite( struct bbs_Context* cpA,
374							  const struct bts_RBFMap2D* ptrA,
375							  uint16* memPtrA )
376{
377	uint32 memSizeL = bts_RBFMap2D_memSize( cpA, ptrA );
378	memPtrA += bbs_memWrite32( &memSizeL, memPtrA );
379	memPtrA += bbs_memWriteUInt32( bts_IRBFMAP2D_VERSION, memPtrA );
380	memPtrA += bbs_memWrite32( &ptrA->RBFTypeE, memPtrA );
381	memPtrA += bts_Cluster2D_memWrite( cpA, &ptrA->srcClusterE, memPtrA );
382	memPtrA += bts_Cluster2D_memWrite( cpA, &ptrA->rbfCoeffClusterE, memPtrA );
383	memPtrA += bbs_memWrite32( &ptrA->altTypeE, memPtrA );
384	memPtrA += bts_Flt16Alt2D_memWrite( cpA, &ptrA->altE, memPtrA );
385	return memSizeL;
386}
387
388/* ------------------------------------------------------------------------- */
389
390uint32 bts_RBFMap2D_memRead( struct bbs_Context* cpA,
391							 struct bts_RBFMap2D* ptrA,
392							 const uint16* memPtrA,
393				             struct bbs_MemSeg* mspA )
394{
395	uint32 memSizeL, versionL;
396	if( bbs_Context_error( cpA ) ) return 0;
397	memPtrA += bbs_memRead32( &memSizeL, memPtrA );
398	memPtrA += bbs_memReadVersion32( cpA, &versionL, bts_IRBFMAP2D_VERSION, memPtrA );
399	memPtrA += bbs_memRead32( &ptrA->RBFTypeE, memPtrA );
400	memPtrA += bts_Cluster2D_memRead( cpA, &ptrA->srcClusterE, memPtrA, mspA );
401	memPtrA += bts_Cluster2D_memRead( cpA, &ptrA->rbfCoeffClusterE, memPtrA, mspA );
402	memPtrA += bbs_memRead32( &ptrA->altTypeE, memPtrA );
403	memPtrA += bts_Flt16Alt2D_memRead( cpA, &ptrA->altE, memPtrA );
404
405	bts_Int32Mat_create( cpA, &ptrA->matE, ptrA->srcClusterE.sizeE, mspA );
406	bts_Int32Mat_create( cpA, &ptrA->tempMatE, ptrA->srcClusterE.sizeE, mspA );
407
408	if( memSizeL != bts_RBFMap2D_memSize( cpA, ptrA ) )
409	{
410		bbs_ERR0( bbs_ERR_CORRUPT_DATA, "uint32 bts_RBFMap2D_memRead( ... ): size mismatch\n" );
411		return 0;
412	}
413	return memSizeL;
414}
415
416/* ------------------------------------------------------------------------- */
417
418/* ========================================================================= */
419/*                                                                           */
420/* ---- \ghd{ exec functions } --------------------------------------------- */
421/*                                                                           */
422/* ========================================================================= */
423
424/* ------------------------------------------------------------------------- */
425/**	R, A are rbf and A affine linear transformations
426 *	T( x ) = R( x ) + A( x )
427 */
428struct bts_Flt16Vec2D bts_RBFMap2D_mapVector( struct bbs_Context* cpA,
429											  const struct bts_RBFMap2D* ptrA,
430											  struct bts_Flt16Vec2D vecA )
431{
432	const uint32 sizeL = ptrA->srcClusterE.sizeE;
433	const int32 bbp_internalL = ptrA->rbfCoeffClusterE.bbpE;
434	uint32 iL;
435	int32 shL;
436
437	int32 outXL;
438	int32 outYL;
439	int32 outBbpL;
440
441	/* 1. Compute rigid transformation, i.e. A( x ) */
442	struct bts_Flt16Vec2D altVecL = bts_Flt16Alt2D_mapFlt( &ptrA->altE, &vecA );
443
444	/* compute output on 32 bit here to prevent temporary overflows (j.s.) */
445	outXL   = altVecL.xE;
446	outYL   = altVecL.yE;
447	outBbpL = altVecL.bbpE;
448
449	/* if bbp was altered, change it back to bbp of vecA ( det A is always close to 1 here ) */
450	shL = vecA.bbpE - outBbpL;
451	if( shL > 0 )
452	{
453		outXL <<= shL;
454		outYL <<= shL;
455	}
456	else if( shL < 0 )
457	{
458		outXL = ( ( outXL >> ( -shL - 1 ) ) + 1 ) >> 1;
459		outYL = ( ( outYL >> ( -shL - 1 ) ) + 1 ) >> 1;
460	}
461	outBbpL = vecA.bbpE;
462
463	/* stop here if rbf coefficients could not be computed  */
464	if( ptrA->altOnlyE )
465	{
466		return bts_Flt16Vec2D_create32( outXL, outYL, outBbpL );
467	}
468
469	/* 2. Compute RBF transformation, i.e. R( x ) depending on type */
470	switch( ptrA->RBFTypeE )
471    {
472		case bts_RBF_IDENTITY:
473		break;
474
475        case bts_RBF_LINEAR:
476        {
477			int32 xSumL = 0;
478			int32 ySumL = 0;
479			int32 internalShiftL = bbp_internalL - ptrA->srcClusterE.bbpE;
480
481			/* first adapt vecA to bbp of srcCluster */
482			int32 xL = vecA.xE;
483			int32 yL = vecA.yE;
484			int32 shiftL = ptrA->srcClusterE.bbpE - vecA.bbpE;
485			if( shiftL > 0 )
486			{
487				xL <<= shiftL;
488				yL <<= shiftL;
489			}
490			else if( shiftL < 0 )
491			{
492				xL = ( ( xL >> ( -shiftL - 1 ) ) + 1 ) >> 1;
493				yL = ( ( yL >> ( -shiftL - 1 ) ) + 1 ) >> 1;
494			}
495
496			shiftL = ptrA->srcClusterE.bbpE;
497
498            for( iL = 0; iL < sizeL; iL++ )
499            {
500				struct bts_Int16Vec2D vecL = ptrA->srcClusterE.vecArrE[ iL ];
501				int32 normL = 0;
502				vecL.xE -= xL;
503				vecL.yE -= yL;
504				normL = bts_Int16Vec2D_norm( &vecL );
505
506/* printf( "iL = %d, norm = %d\n", iL, normL ); */
507
508				xSumL += ( normL * ptrA->rbfCoeffClusterE.vecArrE[ iL ].xE ) >> shiftL;
509				ySumL += ( normL * ptrA->rbfCoeffClusterE.vecArrE[ iL ].yE ) >> shiftL;
510
511/* printf( "iL = %d, xSumL = %d, ySumL = %d\n", iL, xSumL, ySumL ); */
512
513            }
514
515			xSumL >>= internalShiftL;
516			ySumL >>= internalShiftL;
517
518			/* change bbp of result back to bbp of vecA */
519		/*	shiftL = vecA.bbpE - ptrA->srcClusterE.bbpE - internalShiftL; */
520			shiftL = vecA.bbpE - ptrA->srcClusterE.bbpE;
521			if( shiftL > 0 )
522			{
523				xSumL <<= shiftL;
524				ySumL <<= shiftL;
525			}
526			else if( shiftL < 0 )
527			{
528				xSumL = ( ( xSumL >> ( -shiftL - 1 ) ) + 1 ) >> 1;
529				ySumL = ( ( ySumL >> ( -shiftL - 1 ) ) + 1 ) >> 1;
530			}
531
532			/* add rbf part to already computed alt part */
533			outXL += xSumL;
534			outYL += ySumL;
535        }
536        break;
537
538		/* Add a new RBF type here */
539
540		default:
541		{
542			bbs_ERROR1( "struct bts_Flt16Vec2D bts_RBFMap2D_mapVector( ... ): "
543				"RBFType %d is not handled\n", ptrA->RBFTypeE );
544			return bts_Flt16Vec2D_create32( outXL, outYL, outBbpL );
545		}
546	}
547
548	return bts_Flt16Vec2D_create32( outXL, outYL, outBbpL );
549}
550
551/* ------------------------------------------------------------------------- */
552
553void bts_RBFMap2D_mapCluster( struct bbs_Context* cpA,
554							  const struct bts_RBFMap2D* ptrA,
555							  const struct bts_Cluster2D* srcPtrA,
556							  struct bts_Cluster2D* dstPtrA,
557							  int32 dstBbpA )
558{
559	if( dstPtrA->sizeE != srcPtrA->sizeE )
560	{
561		/* resizing of clusters is allowed as long as allocated size is not exceeded */
562		bts_Cluster2D_size( cpA, dstPtrA, srcPtrA->sizeE );
563	}
564
565	{
566		uint32 iL;
567		int16 bbpL = srcPtrA->bbpE;
568
569		dstPtrA->bbpE = dstBbpA;
570
571		for( iL = 0; iL < srcPtrA->sizeE; iL++ )
572		{
573			struct bts_Int16Vec2D vecL = srcPtrA->vecArrE[ iL ];
574			struct bts_Flt16Vec2D srcVecL = bts_Flt16Vec2D_create16( vecL.xE, vecL.yE, bbpL );
575			struct bts_Flt16Vec2D dstVecL = bts_RBFMap2D_mapVector( cpA, ptrA, srcVecL );
576			dstPtrA->vecArrE[ iL ].xE = bbs_convertS32( dstVecL.xE, dstVecL.bbpE, dstBbpA );
577			dstPtrA->vecArrE[ iL ].yE = bbs_convertS32( dstVecL.yE, dstVecL.bbpE, dstBbpA );
578		}
579	}
580}
581
582/* ------------------------------------------------------------------------- */
583
584/* ========================================================================= */
585
586