* Bug #11550 fixed - Closing the scope graph while running simulation led to a
[scilab.git] / scilab / modules / scicos_blocks / src / c / cscopxy.c
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2011 - 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 <string.h>
14
15 #include "dynlib_scicos_blocks.h"
16 #include "scoUtils.h"
17
18 #include "MALLOC.h"
19 #include "elementary_functions.h"
20
21 #include "getGraphicObjectProperty.h"
22 #include "setGraphicObjectProperty.h"
23 #include "graphicObjectProperties.h"
24 #include "createGraphicObject.h"
25
26 #include "CurrentFigure.h"
27
28 #include "scicos_block4.h"
29 #include "scicos.h"
30
31 #include "localization.h"
32 #ifdef _MSC_VER
33 #include "strdup_windows.h"
34 #endif
35
36 #include "FigureList.h"
37 #include "BuildObjects.h"
38 #include "AxesModel.h"
39
40 /*****************************************************************************
41  * Internal container structure
42  ****************************************************************************/
43
44 /**
45  * Container structure
46  */
47 typedef struct
48 {
49     struct
50     {
51         int numberOfPoints;
52         int maxNumberOfPoints;
53         double ***data;
54     } internal;
55
56     struct
57     {
58         char const* cachedFigureUID;
59         char *cachedAxeUID;
60         char **cachedPolylinesUIDs;
61     } scope;
62 } sco_data;
63
64 /**
65  * Get (and allocate on demand) the internal data used on this scope
66  * \param block the block
67  * \return the scope data
68  */
69 static sco_data *getScoData(scicos_block * block);
70
71 /**
72  * Release any internal data
73  *
74  * \param block the block
75  */
76 static void freeScoData(scicos_block * block);
77
78 /**
79  * Append the data to the current data
80  *
81  * \param block the block
82  * \param x x data
83  * \param y y data
84  */
85 static void appendData(scicos_block * block, double *x, double *y);
86
87 /**
88  * Push the block data to the polyline
89  *
90  * \param block the block
91  * \param row the selected row
92  *
93  */
94 static BOOL pushData(scicos_block * block, int row);
95
96 /*****************************************************************************
97  * Graphics utils
98  ****************************************************************************/
99
100 /**
101  * Get (and allocate on demand) the figure associated with the block
102  * \param block the block
103  * \return a valid figure UID or NULL on error
104  */
105 static char const* getFigure(scicos_block * block);
106
107 /**
108  * Get (and allocate on demand) the axe associated with the input
109  *
110  * \param pFigureUID the parent figure UID
111  * \param block the block
112  * \param input the current input index (0-indexed)
113  * \return a valid axe UID or NULL on error
114  */
115 static char *getAxe(char const* pFigureUID, scicos_block * block);
116
117 /**
118  * Get (and allocate on demand) the polyline associated with the row
119  *
120  * \param pAxeUID the parent axe UID
121  * \param block the block
122  * \param row the current row index (0-indexed)
123  * \return a valid polyline UID or NULL on error
124  */
125 static char *getPolyline(char *pAxeUID, scicos_block * block, int row);
126
127 /**
128  * Set the polylines buffer size
129  *
130  * \param block the block
131  * \param maxNumberOfPoints the size of the buffer
132  */
133 static BOOL setPolylinesBuffers(scicos_block * block, int maxNumberOfPoints);
134
135 /**
136  * Set the polylines bounds
137  *
138  * \param block the block
139  */
140 static BOOL setPolylinesBounds(scicos_block * block);
141
142 /*****************************************************************************
143  * Simulation function
144  ****************************************************************************/
145
146 /** \fn void cmscope(scicos_block * block,int flag)
147     \brief the computational function
148     \param block A pointer to a scicos_block
149     \param flag An int which indicates the state of the block (init, update, ending)
150 */
151 SCICOS_BLOCKS_IMPEXP void cscopxy(scicos_block * block, scicos_flag flag)
152 {
153     char const* pFigureUID;
154     int j;
155     sco_data *sco;
156     BOOL result;
157
158     switch (flag)
159     {
160
161         case Initialization:
162             sco = getScoData(block);
163             if (sco == NULL)
164             {
165                 set_block_error(-5);
166             }
167             pFigureUID = getFigure(block);
168             if (pFigureUID == NULL)
169             {
170                 // allocation error
171                 set_block_error(-5);
172             }
173             break;
174
175         case StateUpdate:
176             pFigureUID = getFigure(block);
177             if (pFigureUID == NULL)
178             {
179                 // allocation error
180                 set_block_error(-5);
181                 break;
182             }
183
184             appendData(block, block->inptr[0], block->inptr[1]);
185             for (j = 0; j < block->insz[0]; j++)
186             {
187                 result = pushData(block, j);
188                 if (result == FALSE)
189                 {
190                     Coserror("%s: unable to push some data.", "cscopxy");
191                     break;
192                 }
193             }
194             break;
195
196         case Ending:
197             freeScoData(block);
198             break;
199
200         default:
201             break;
202     }
203 }
204
205 /*-------------------------------------------------------------------------*/
206
207 /*****************************************************************************
208  *
209  * Container management
210  *
211  ****************************************************************************/
212
213 static sco_data *getScoData(scicos_block * block)
214 {
215     sco_data *sco = (sco_data *) * (block->work);
216     int i, j, k, l;
217
218     if (sco == NULL)
219     {
220         /*
221          * Data allocation
222          */
223
224         sco = (sco_data *) MALLOC(sizeof(sco_data));
225         if (sco == NULL)
226             goto error_handler_sco;
227
228         sco->internal.numberOfPoints = 0;
229         sco->internal.maxNumberOfPoints = block->ipar[2];
230
231         sco->internal.data = (double ***)CALLOC(block->nin, sizeof(double **));
232         if (sco->internal.data == NULL)
233             goto error_handler_data;
234
235         for (i = 0; i < block->nin; i++)
236         {
237             sco->internal.data[i] = (double **)CALLOC(block->insz[i], sizeof(double *));
238             if (sco->internal.data[i] == NULL)
239                 goto error_handler_data_i;
240         }
241         for (i = 0; i < block->nin; i++)
242         {
243             for (j = 0; j < block->insz[i]; j++)
244             {
245                 sco->internal.data[i][j] = (double *)CALLOC(block->ipar[2], sizeof(double));
246
247                 if (sco->internal.data[i][j] == NULL)
248                     goto error_handler_data_ij;
249             }
250         }
251
252         sco->scope.cachedFigureUID = NULL;
253         sco->scope.cachedAxeUID = NULL;
254
255         sco->scope.cachedPolylinesUIDs = (char **)CALLOC(block->insz[0], sizeof(char **));
256
257         *(block->work) = sco;
258     }
259
260     return sco;
261
262     /*
263      * Error management (out of normal flow)
264      */
265
266 error_handler_data_ij:
267     for (k = 0; k < i; k++)
268     {
269         for (l = 0; l < j; l++)
270         {
271             FREE(sco->internal.data[k][l]);
272         }
273     }
274     i = block->nin - 1;
275 error_handler_data_i:
276     for (j = 0; j < i; j++)
277     {
278         FREE(sco->internal.data[i]);
279     }
280     FREE(sco->internal.data);
281 error_handler_data:
282     FREE(sco);
283 error_handler_sco:
284     // allocation error
285     set_block_error(-5);
286     return NULL;
287 }
288
289 static void freeScoData(scicos_block * block)
290 {
291     sco_data *sco = (sco_data *) * (block->work);
292     int i, j;
293
294     if (sco != NULL)
295     {
296         for (i = 0; i < block->nin; i++)
297         {
298             for (j = 0; j < block->insz[i]; j++)
299             {
300                 FREE(sco->internal.data[i][j]);
301             }
302             FREE(sco->internal.data[i]);
303         }
304
305         FREE(sco->internal.data);
306
307         for (i = 0; i < block->insz[0]; i++)
308         {
309             FREE(sco->scope.cachedPolylinesUIDs[i]);
310         }
311         FREE(sco->scope.cachedAxeUID);
312
313         FREE(sco);
314         *(block->work) = NULL;
315     }
316 }
317
318 static sco_data *reallocScoData(scicos_block * block, int numberOfPoints)
319 {
320     sco_data *sco = (sco_data *) * (block->work);
321     int i, j;
322
323     double *ptr;
324     int setLen;
325     int previousNumberOfPoints = sco->internal.maxNumberOfPoints;
326
327     for (i = 0; i < block->nin; i++)
328     {
329         for (j = 0; j < block->insz[i]; j++)
330         {
331             ptr = (double *)REALLOC(sco->internal.data[i][j], numberOfPoints * sizeof(double));
332             if (ptr == NULL)
333                 goto error_handler;
334
335             for (setLen = numberOfPoints - previousNumberOfPoints - 1; setLen >= 0; setLen--)
336             {
337                 ptr[previousNumberOfPoints + setLen] = ptr[previousNumberOfPoints - 1];
338             }
339             sco->internal.data[i][j] = ptr;
340         }
341     }
342
343     sco->internal.maxNumberOfPoints = numberOfPoints;
344     return sco;
345
346 error_handler:
347     freeScoData(block);
348     // allocation error
349     set_block_error(-5);
350     return NULL;
351 }
352
353 static void appendData(scicos_block * block, double *x, double *y)
354 {
355     int i;
356
357     sco_data *sco = (sco_data *) * (block->work);
358     int maxNumberOfPoints = sco->internal.maxNumberOfPoints;
359     int numberOfPoints = sco->internal.numberOfPoints;
360
361     /*
362      * Handle the case where the scope has more points than maxNumberOfPoints
363      */
364     if (sco != NULL && numberOfPoints >= maxNumberOfPoints)
365     {
366         // on a full scope, re-alloc
367         maxNumberOfPoints = maxNumberOfPoints + block->ipar[2];
368         sco = reallocScoData(block, maxNumberOfPoints);
369
370         // reconfigure related graphic objects
371         if (setPolylinesBuffers(block, maxNumberOfPoints) == FALSE)
372         {
373             set_block_error(-5);
374             freeScoData(block);
375             sco = NULL;
376         }
377     }
378
379     /*
380      * Update data
381      */
382     if (sco != NULL)
383     {
384         int setLen;
385
386         for (i = 0; i < block->insz[0]; i++)
387         {
388             for (setLen = maxNumberOfPoints - numberOfPoints - 1; setLen >= 0; setLen--)
389             {
390                 sco->internal.data[0][i][numberOfPoints + setLen] = x[i];
391                 sco->internal.data[1][i][numberOfPoints + setLen] = y[i];
392             }
393         }
394
395         sco->internal.numberOfPoints++;
396     }
397 }
398
399 static BOOL pushData(scicos_block * block, int row)
400 {
401     char const* pFigureUID;
402     char *pAxeUID;
403     char *pPolylineUID;
404
405     double *x;
406     double *y;
407     sco_data *sco;
408
409     BOOL result = TRUE;
410
411     pFigureUID = getFigure(block);
412     pAxeUID = getAxe(pFigureUID, block);
413     pPolylineUID = getPolyline(pAxeUID, block, row);
414
415     sco = getScoData(block);
416     if (sco == NULL)
417         return FALSE;
418
419     // select the right input and row
420     x = sco->internal.data[0][row];
421     y = sco->internal.data[1][row];
422
423     result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_X__, x, jni_double_vector, sco->internal.maxNumberOfPoints);
424     result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_Y__, y, jni_double_vector, sco->internal.maxNumberOfPoints);
425
426     return result;
427 }
428
429 /*****************************************************************************
430  *
431  * Graphic utils
432  *
433  ****************************************************************************/
434
435 /**
436  * Set properties on the figure.
437  *
438  * \param pFigureUID the figure uid
439  * \param block the current block
440  */
441 static void setFigureSettings(char const* pFigureUID, scicos_block * block)
442 {
443     int win_pos[2];
444     int win_dim[2];
445
446     int *ipar = block->ipar;
447
448     win_pos[0] = ipar[6];
449     win_pos[1] = ipar[7];
450     win_dim[0] = ipar[8];
451     win_dim[1] = ipar[9];
452
453     if (win_pos[0] > 0 && win_pos[1] > 0)
454     {
455         setGraphicObjectProperty(pFigureUID, __GO_POSITION__, &win_pos, jni_int_vector, 2);
456     }
457
458     if (win_dim[0] > 0 && win_dim[1] > 0)
459     {
460         setGraphicObjectProperty(pFigureUID, __GO_SIZE__, &win_dim, jni_int_vector, 2);
461     }
462 };
463
464 /*****************************************************************************
465  *
466  * Graphic
467  *
468  ****************************************************************************/
469
470 static char const* getFigure(scicos_block * block)
471 {
472     signed int figNum;
473     char const* pFigureUID = NULL;
474     char *pAxe = NULL;
475     int i__1 = 1;
476     sco_data *sco = (sco_data *) * (block->work);
477
478     // assert the sco is not NULL
479     if (sco == NULL)
480     {
481         return NULL;
482     }
483
484     // fast path for an existing object
485     if (sco->scope.cachedFigureUID != NULL)
486     {
487         return sco->scope.cachedFigureUID;
488     }
489
490     figNum = block->ipar[0];
491
492     // with a negative id, use the block number indexed from a constant.
493     if (figNum < 0)
494     {
495         figNum = 20000 + get_block_number();
496     }
497
498     pFigureUID = getFigureFromIndex(figNum);
499     // create on demand
500     if (pFigureUID == NULL)
501     {
502         pFigureUID = createNewFigureWithAxes();
503         setGraphicObjectProperty(pFigureUID, __GO_ID__, &figNum, jni_int, 1);
504
505         // the stored uid is a reference to the figure map, not to the current figure
506         pFigureUID = getFigureFromIndex(figNum);
507         sco->scope.cachedFigureUID = pFigureUID;
508
509         // set configured parameters
510         setFigureSettings(pFigureUID, block);
511
512         // allocate the axes through the getter
513         pAxe = getAxe(pFigureUID, block);
514
515         /*
516          * Setup according to block settings
517          */
518         setLabel(pAxe, __GO_X_AXIS_LABEL__, "x");
519         setLabel(pAxe, __GO_Y_AXIS_LABEL__, "y");
520
521         setGraphicObjectProperty(pAxe, __GO_X_AXIS_VISIBLE__, &i__1, jni_bool, 1);
522         setGraphicObjectProperty(pAxe, __GO_Y_AXIS_VISIBLE__, &i__1, jni_bool, 1);
523
524         setPolylinesBounds(block);
525     }
526
527     if (sco->scope.cachedFigureUID == NULL)
528     {
529         sco->scope.cachedFigureUID = pFigureUID;
530     }
531     return pFigureUID;
532 }
533
534 static char *getAxe(char const* pFigureUID, scicos_block * block)
535 {
536     char *pAxe;
537     int i;
538     sco_data *sco = (sco_data *) * (block->work);
539
540     // assert the sco is not NULL
541     if (sco == NULL)
542     {
543         return NULL;
544     }
545
546     // fast path for an existing object
547     if (sco->scope.cachedAxeUID != NULL)
548     {
549         return sco->scope.cachedAxeUID;
550     }
551
552     pAxe = findChildWithKindAt(pFigureUID, __GO_AXES__, 0);
553
554     /*
555      * Allocate if necessary
556      */
557     if (pAxe == NULL)
558     {
559         cloneAxesModel(pFigureUID);
560         pAxe = findChildWithKindAt(pFigureUID, __GO_AXES__, 0);
561     }
562
563     /*
564      * Setup on first access
565      */
566     if (pAxe != NULL)
567     {
568         // allocate the polylines through the getter
569         for (i = 0; i < block->insz[0]; i++)
570         {
571             getPolyline(pAxe, block, i);
572         }
573     }
574
575     /*
576      * then cache with local storage
577      */
578     if (pAxe != NULL && sco->scope.cachedAxeUID == NULL)
579     {
580         sco->scope.cachedAxeUID = strdup(pAxe);
581         releaseGraphicObjectProperty(__GO_PARENT__, pAxe, jni_string, 1);
582     }
583     return sco->scope.cachedAxeUID;
584 }
585
586 static char *getPolyline(char *pAxeUID, scicos_block * block, int row)
587 {
588     char *pPolyline;
589     double d__0 = 0.0;
590     BOOL b__true = TRUE;
591
592     int color;
593     int markSize;
594     double lineThickness;
595
596     sco_data *sco = (sco_data *) * (block->work);
597
598     // assert the sco is not NULL
599     if (sco == NULL)
600     {
601         return NULL;
602     }
603
604     // fast path for an existing object
605     if (sco->scope.cachedPolylinesUIDs != NULL && sco->scope.cachedPolylinesUIDs[row] != NULL)
606     {
607         return sco->scope.cachedPolylinesUIDs[row];
608     }
609
610     pPolyline = findChildWithKindAt(pAxeUID, __GO_POLYLINE__, row);
611
612     /*
613      * Allocate if necessary
614      */
615     if (pPolyline == NULL)
616     {
617         pPolyline = createGraphicObject(__GO_POLYLINE__);
618
619         if (pPolyline != NULL)
620         {
621             createDataObject(pPolyline, __GO_POLYLINE__);
622             setGraphicObjectRelationship(pAxeUID, pPolyline);
623
624         }
625     }
626
627     /*
628      * Setup on first access
629      */
630     if (pPolyline != NULL)
631     {
632         /*
633          * Default setup (will crash if removed)
634          */
635         {
636             int polylineSize[2] = { 1, block->ipar[2] };
637             setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_NUM_ELEMENTS_ARRAY__, polylineSize, jni_int_vector, 2);
638         }
639
640         setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_X__, &d__0, jni_double_vector, 1);
641         setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_Y__, &d__0, jni_double_vector, 1);
642
643         color = block->ipar[3];
644         markSize = block->ipar[4];
645         lineThickness = (double)markSize;
646         if (color > 0)
647         {
648             setGraphicObjectProperty(pPolyline, __GO_LINE_MODE__, &b__true, jni_bool, 1);
649
650             setGraphicObjectProperty(pPolyline, __GO_LINE_COLOR__, &color, jni_int, 1);
651             setGraphicObjectProperty(pPolyline, __GO_LINE_THICKNESS__, &lineThickness, jni_double, 1);
652         }
653         else
654         {
655             color = -color;
656             setGraphicObjectProperty(pPolyline, __GO_MARK_MODE__, &b__true, jni_bool, 1);
657
658             setGraphicObjectProperty(pPolyline, __GO_MARK_STYLE__, &color, jni_int, 1);
659             setGraphicObjectProperty(pPolyline, __GO_MARK_SIZE__, &markSize, jni_int, 1);
660         }
661
662         {
663             int iClipState = 1; //on
664             setGraphicObjectProperty(pPolyline, __GO_CLIP_STATE__, &iClipState, jni_int, 1);
665         }
666     }
667
668     /*
669      * then cache with local storage
670      */
671     if (pPolyline != NULL && sco->scope.cachedPolylinesUIDs != NULL && sco->scope.cachedPolylinesUIDs[row] == NULL)
672     {
673         sco->scope.cachedPolylinesUIDs[row] = strdup(pPolyline);
674         releaseGraphicObjectProperty(__GO_PARENT__, pPolyline, jni_string, 1);
675     }
676     return sco->scope.cachedPolylinesUIDs[row];
677 }
678
679 static BOOL setPolylinesBuffers(scicos_block * block, int maxNumberOfPoints)
680 {
681     int i;
682
683     char const* pFigureUID;
684     char *pAxeUID;
685     char *pPolylineUID;
686
687     BOOL result = TRUE;
688     int polylineSize[2] = { 1, maxNumberOfPoints };
689
690     pFigureUID = getFigure(block);
691     pAxeUID = getAxe(pFigureUID, block);
692
693     for (i = 0; i < block->insz[0]; i++)
694     {
695         pPolylineUID = getPolyline(pAxeUID, block, i);
696         result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_NUM_ELEMENTS_ARRAY__, polylineSize, jni_int_vector, 2);
697     }
698
699     return result;
700 }
701
702 static BOOL setPolylinesBounds(scicos_block * block)
703 {
704     char const* pFigureUID;
705     char *pAxeUID;
706
707     double dataBounds[6];
708
709     dataBounds[0] = block->rpar[0]; // xMin
710     dataBounds[1] = block->rpar[1]; // xMax
711     dataBounds[2] = block->rpar[2]; // yMin
712     dataBounds[3] = block->rpar[3]; // yMax
713     dataBounds[4] = -1.0;       // zMin
714     dataBounds[5] = 1.0;        // zMax
715
716     pFigureUID = getFigure(block);
717     pAxeUID = getAxe(pFigureUID, block);
718
719     return setGraphicObjectProperty(pAxeUID, __GO_DATA_BOUNDS__, dataBounds, jni_double_vector, 6);
720 }