3a0e6d3d222f32c8cf341a2d90efa8486c5a75d5
[scilab.git] / scilab / modules / scicos_blocks / src / c / bouncexy.c
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2012 - Scilab Enterprises - Clement DAVID
4  *
5  *  This file must be used under the terms of the CeCILL.
6  *  This source file is licensed as described in the file COPYING, which
7  *  you should have received as part of this distribution.  The terms
8  *  are also available at
9  *  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12
13 #include <math.h>
14 #ifndef M_PI
15 #define M_PI           3.14159265358979323846
16 #endif
17 #include <string.h>
18
19 #include "dynlib_scicos_blocks.h"
20 #include "scoUtils.h"
21
22 #include "MALLOC.h"
23 #include "elementary_functions.h"
24
25 #include "setGraphicObjectProperty.h"
26 #include "getGraphicObjectProperty.h"
27 #include "graphicObjectProperties.h"
28 #include "createGraphicObject.h"
29
30 #include "CurrentFigure.h"
31
32 #include "scicos_block4.h"
33 #include "scicos.h"
34
35 #include "localization.h"
36 #ifdef _MSC_VER
37 #include "strdup_windows.h"
38 #endif
39
40 #include "FigureList.h"
41 #include "BuildObjects.h"
42 #include "AxesModel.h"
43
44 /*****************************************************************************
45  * Internal container structure
46  ****************************************************************************/
47
48 /**
49  * Container structure
50  */
51 typedef struct
52 {
53     struct
54     {
55         double *ballsSize;
56         double **data;
57     } internal;
58
59     struct
60     {
61         char const* cachedFigureUID;
62         char *cachedAxeUID;
63         char **cachedArcsUIDs;
64     } scope;
65 } sco_data;
66
67 /**
68  * Get (and allocate on demand) the internal data used on this scope
69  * \param block the block
70  * \return the scope data
71  */
72 static sco_data *getScoData(scicos_block * block);
73
74 /**
75  * Release any internal data
76  *
77  * \param block the block
78  */
79 static void freeScoData(scicos_block * block);
80
81 /**
82  * Append the data to the current data
83  *
84  * \param block the block
85  * \param x x data
86  * \param y y data
87  */
88 static void appendData(scicos_block * block, double *x, double *y);
89
90 /**
91  * Push the block data to the polyline
92  *
93  * \param block the block
94  * \param row the selected row
95  *
96  */
97 static BOOL pushData(scicos_block * block, int row);
98
99 /*****************************************************************************
100  * Graphics utils
101  ****************************************************************************/
102
103 /**
104  * Get (and allocate on demand) the figure associated with the block
105  * \param block the block
106  * \return a valid figure UID or NULL on error
107  */
108 static char const* getFigure(scicos_block * block);
109
110 /**
111  * Get (and allocate on demand) the axe associated with the input
112  *
113  * \param pFigureUID the parent figure UID
114  * \param block the block
115  * \param input the current input index (0-indexed)
116  * \return a valid axe UID or NULL on error
117  */
118 static char *getAxe(char const* pFigureUID, scicos_block * block);
119
120 /**
121  * Get (and allocate on demand) the arc associated with the row
122  *
123  * \param pAxeUID the parent axe UID
124  * \param block the block
125  * \param row the current row index (0-indexed)
126  * \return a valid polyline UID or NULL on error
127  */
128 static char *getArc(char *pAxeUID, scicos_block * block, int row);
129
130 /**
131  * Set the bounds
132  *
133  * \param block the block
134  */
135 static BOOL setBounds(scicos_block * block);
136
137 /*****************************************************************************
138  * Simulation function
139  ****************************************************************************/
140
141 /** \fn void bouncexy(scicos_block * block,int flag)
142     \brief the computational function
143     \param block A pointer to a scicos_block
144     \param flag An int which indicates the state of the block (init, update, ending)
145 */
146 SCICOS_BLOCKS_IMPEXP void bouncexy(scicos_block * block, scicos_flag flag)
147 {
148     char const* pFigureUID;
149
150     sco_data *sco;
151
152     int j;
153     BOOL result;
154
155     switch (flag)
156     {
157
158         case Initialization:
159             sco = getScoData(block);
160             if (sco == NULL)
161             {
162                 set_block_error(-5);
163             }
164             pFigureUID = getFigure(block);
165             if (pFigureUID == NULL)
166             {
167                 // allocation error
168                 set_block_error(-5);
169             }
170             break;
171
172         case StateUpdate:
173             pFigureUID = getFigure(block);
174             if (pFigureUID == NULL)
175             {
176                 // allocation error
177                 set_block_error(-5);
178                 break;
179             }
180
181             appendData(block, (double *)block->inptr[0], (double *)block->inptr[1]);
182             for (j = 0; j < block->insz[0]; j++)
183             {
184                 result = pushData(block, j);
185                 if (result == FALSE)
186                 {
187                     Coserror("%s: unable to push some data.", "bouncexy");
188                     break;
189                 }
190             }
191             break;
192
193         case Ending:
194             freeScoData(block);
195             break;
196
197         default:
198             break;
199     }
200 }
201
202 /*-------------------------------------------------------------------------*/
203
204 /*****************************************************************************
205  *
206  * Container management
207  *
208  ****************************************************************************/
209
210 static sco_data *getScoData(scicos_block * block)
211 {
212     sco_data *sco = (sco_data *) * (block->work);
213     int i, j;
214
215     if (sco == NULL)
216     {
217         /*
218          * Data allocation
219          */
220
221         sco = (sco_data *) MALLOC(sizeof(sco_data));
222         if (sco == NULL)
223             goto error_handler_sco;
224
225         sco->internal.ballsSize = (double *)CALLOC(block->insz[0], sizeof(double));
226         if (sco->internal.ballsSize == NULL)
227             goto error_handler_ballsSize;
228         for (i = 0; i < block->insz[0]; i++)
229         {
230             sco->internal.ballsSize[i] = block->z[6 * i + 2];
231         }
232
233         sco->internal.data = (double **)CALLOC(block->insz[0], sizeof(double *));
234         if (sco->internal.data == NULL)
235             goto error_handler_data;
236
237         for (i = 0; i < block->insz[0]; i++)
238         {
239             sco->internal.data[i] = (double *)CALLOC(3, sizeof(double));
240             if (sco->internal.data[i] == NULL)
241                 goto error_handler_data_i;
242         }
243
244         sco->scope.cachedFigureUID = NULL;
245         sco->scope.cachedAxeUID = NULL;
246
247         sco->scope.cachedArcsUIDs = (char **)CALLOC(block->insz[0], sizeof(char *));
248
249         *(block->work) = sco;
250     }
251
252     return sco;
253
254     /*
255      * Error management (out of normal flow)
256      */
257
258 error_handler_data_i:
259     for (j = 0; j < i; j++)
260     {
261         FREE(sco->internal.data[i]);
262     }
263     FREE(sco->internal.data);
264 error_handler_data:
265     FREE(sco->internal.ballsSize);
266 error_handler_ballsSize:
267     FREE(sco);
268 error_handler_sco:
269     // allocation error
270     set_block_error(-5);
271     return NULL;
272 }
273
274 static void freeScoData(scicos_block * block)
275 {
276     sco_data *sco = (sco_data *) * (block->work);
277     int i;
278
279     if (sco != NULL)
280     {
281         for (i = 0; i < block->insz[0]; i++)
282         {
283             FREE(sco->internal.data[i]);
284         }
285
286         FREE(sco->internal.data);
287         FREE(sco->internal.ballsSize);
288
289         for (i = 0; i < block->insz[0]; i++)
290         {
291             FREE(sco->scope.cachedArcsUIDs[i]);
292             sco->scope.cachedArcsUIDs[i] = NULL;
293         }
294         FREE(sco->scope.cachedAxeUID);
295         sco->scope.cachedAxeUID = NULL;
296
297         FREE(sco);
298     }
299 }
300
301 static void appendData(scicos_block * block, double *x, double *y)
302 {
303     int i;
304     double *upperLeftPoint;
305     double ballSize;
306     sco_data *sco = (sco_data *) * (block->work);
307
308     /*
309      * Update data
310      */
311     if (sco != NULL)
312     {
313         for (i = 0; i < block->insz[0]; i++)
314         {
315             upperLeftPoint = sco->internal.data[i];
316             ballSize = sco->internal.ballsSize[i];
317
318             upperLeftPoint[0] = x[i] - (ballSize / 2);  // x
319             upperLeftPoint[1] = y[i] + (ballSize / 2);  // y
320             upperLeftPoint[2] = 0;  // z
321         }
322     }
323 }
324
325 static BOOL pushData(scicos_block * block, int row)
326 {
327     char const* pFigureUID;
328     char *pAxeUID;
329     char *pArcUID;
330
331     double *upperLeftPoint;
332     sco_data *sco;
333
334     pFigureUID = getFigure(block);
335     pAxeUID = getAxe(pFigureUID, block);
336     pArcUID = getArc(pAxeUID, block, row);
337
338     sco = getScoData(block);
339     if (sco == NULL)
340         return FALSE;
341
342     upperLeftPoint = sco->internal.data[row];
343     return setGraphicObjectProperty(pArcUID, __GO_UPPER_LEFT_POINT__, upperLeftPoint, jni_double_vector, 3);
344 }
345
346 /*****************************************************************************
347  *
348  * Graphic utils
349  *
350  ****************************************************************************/
351
352 /*****************************************************************************
353  *
354  * Graphic
355  *
356  ****************************************************************************/
357
358 static char const* getFigure(scicos_block * block)
359 {
360     signed int figNum;
361     char const* pFigureUID = NULL;
362     char *pAxe = NULL;
363     int i__1 = 1;
364     BOOL b_true = TRUE;
365
366     sco_data *sco = (sco_data *) * (block->work);
367
368     // fast path for an existing object
369     if (sco->scope.cachedFigureUID != NULL)
370     {
371         return sco->scope.cachedFigureUID;
372     }
373
374     figNum = block->ipar[0];
375
376     // with a negative id, use the block number indexed from a constant.
377     if (figNum < 0)
378     {
379         figNum = 20000 + get_block_number();
380     }
381
382     pFigureUID = getFigureFromIndex(figNum);
383     // create on demand
384     if (pFigureUID == NULL)
385     {
386         pFigureUID = createNewFigureWithAxes();
387         setGraphicObjectProperty(pFigureUID, __GO_ID__, &figNum, jni_int, 1);
388
389         // the stored uid is a reference to the figure map, not to the current figure
390         pFigureUID = getFigureFromIndex(figNum);
391         sco->scope.cachedFigureUID = pFigureUID;
392
393         // allocate the axes through the getter
394         pAxe = getAxe(pFigureUID, block);
395
396         /*
397          * Setup according to block settings
398          */
399         setGraphicObjectProperty(pAxe, __GO_BOX_TYPE__, &i__1, jni_int, 1);
400         setGraphicObjectProperty(pAxe, __GO_ISOVIEW__, &b_true, jni_bool, 1);
401
402         setBounds(block);
403     }
404
405     if (sco->scope.cachedFigureUID == NULL)
406     {
407         sco->scope.cachedFigureUID = pFigureUID;
408     }
409     return pFigureUID;
410 }
411
412 static char *getAxe(char const* pFigureUID, scicos_block * block)
413 {
414     char *pAxe;
415     int i;
416
417     sco_data *sco = (sco_data *) * (block->work);
418
419     // fast path for an existing object
420     if (sco->scope.cachedAxeUID != NULL)
421     {
422         return sco->scope.cachedAxeUID;
423     }
424
425     pAxe = findChildWithKindAt(pFigureUID, __GO_AXES__, 0);
426
427     /*
428      * Allocate if necessary
429      */
430     if (pAxe == NULL)
431     {
432         cloneAxesModel(pFigureUID);
433         pAxe = findChildWithKindAt(pFigureUID, __GO_AXES__, 0);
434     }
435
436     /*
437      * Setup on first access
438      */
439     if (pAxe != NULL)
440     {
441         // allocate the polylines through the getter
442         for (i = 0; i < block->insz[0]; i++)
443         {
444             getArc(pAxe, block, i);
445         }
446     }
447
448     /*
449      * then cache with local storage
450      */
451     if (pAxe != NULL && sco->scope.cachedAxeUID == NULL)
452     {
453         sco->scope.cachedAxeUID = strdup(pAxe);
454         releaseGraphicObjectProperty(__GO_PARENT__, pAxe, jni_string, 1);
455     }
456     return sco->scope.cachedAxeUID;
457 }
458
459 static char *getArc(char *pAxeUID, scicos_block * block, int row)
460 {
461     static double d__0 = 0.0;
462     static double d__2PI = 2 * M_PI;
463     static BOOL b__true = TRUE;
464
465     char *pArc;
466     int color;
467
468     sco_data *sco = (sco_data *) * (block->work);
469
470     // fast path for an existing object
471     if (sco->scope.cachedArcsUIDs != NULL && sco->scope.cachedArcsUIDs[row] != NULL)
472     {
473         return sco->scope.cachedArcsUIDs[row];
474     }
475
476     pArc = findChildWithKindAt(pAxeUID, __GO_ARC__, row);
477
478     /*
479      * Allocate if necessary
480      */
481     if (pArc == NULL)
482     {
483         pArc = createGraphicObject(__GO_ARC__);
484
485         if (pArc != NULL)
486         {
487             createDataObject(pArc, __GO_ARC__);
488             setGraphicObjectRelationship(pAxeUID, pArc);
489         }
490     }
491
492     /*
493      * Setup on first access
494      */
495     if (pArc != NULL)
496     {
497         setGraphicObjectProperty(pArc, __GO_START_ANGLE__, &d__0, jni_double, 1);
498         setGraphicObjectProperty(pArc, __GO_END_ANGLE__, &d__2PI, jni_double, 1);
499
500         color = block->ipar[2 + row];
501         setGraphicObjectProperty(pArc, __GO_BACKGROUND__, &color, jni_int, 1);
502
503         setGraphicObjectProperty(pArc, __GO_WIDTH__, &sco->internal.ballsSize[row], jni_double, 1);
504         setGraphicObjectProperty(pArc, __GO_HEIGHT__, &sco->internal.ballsSize[row], jni_double, 1);
505
506         setGraphicObjectProperty(pArc, __GO_FILL_MODE__, &b__true, jni_bool, 1);
507
508         {
509             int iClipState = 1; //on
510             setGraphicObjectProperty(pArc, __GO_CLIP_STATE__, &iClipState, jni_int, 1);
511         }
512     }
513
514     /*
515      * then cache with local storage
516      */
517     if (pArc != NULL && sco->scope.cachedArcsUIDs != NULL && sco->scope.cachedArcsUIDs[row] == NULL)
518     {
519         sco->scope.cachedArcsUIDs[row] = strdup(pArc);
520         releaseGraphicObjectProperty(__GO_PARENT__, pArc, jni_string, 1);
521     }
522     return sco->scope.cachedArcsUIDs[row];
523 }
524
525 static BOOL setBounds(scicos_block * block)
526 {
527     char const* pFigureUID;
528     char *pAxeUID;
529
530     double dataBounds[6];
531
532     dataBounds[0] = block->rpar[0]; // xMin
533     dataBounds[1] = block->rpar[1]; // xMax
534     dataBounds[2] = block->rpar[2]; // yMin
535     dataBounds[3] = block->rpar[3]; // yMax
536     dataBounds[4] = -1.0;       // zMin
537     dataBounds[5] = 1.0;        // zMax
538
539     pFigureUID = getFigure(block);
540     pAxeUID = getAxe(pFigureUID, block);
541
542     return setGraphicObjectProperty(pAxeUID, __GO_DATA_BOUNDS__, dataBounds, jni_double_vector, 6);
543 }