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