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