fa50d077b7e5d9daa931c21f34b6f880cbf2286f
[scilab.git] / scilab / modules / scicos_blocks / src / c / canimxy.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 bounds
129  *
130  * \param block the block
131  */
132 static BOOL setPolylinesBounds(scicos_block * block);
133
134 /*****************************************************************************
135  * Simulation function
136  ****************************************************************************/
137
138 /** \fn void cmscope(scicos_block * block,int flag)
139     \brief the computational function
140     \param block A pointer to a scicos_block
141     \param flag An int which indicates the state of the block (init, update, ending)
142 */
143 SCICOS_BLOCKS_IMPEXP void canimxy(scicos_block * block, scicos_flag flag)
144 {
145     char const* pFigureUID;
146     sco_data *sco;
147
148     int j;
149     BOOL result;
150
151     switch (flag)
152     {
153
154         case Initialization:
155             sco = getScoData(block);
156             if (sco == NULL)
157             {
158                 set_block_error(-5);
159             }
160             pFigureUID = getFigure(block);
161             if (pFigureUID == NULL)
162             {
163                 // allocation error
164                 set_block_error(-5);
165             }
166             break;
167
168         case StateUpdate:
169             pFigureUID = getFigure(block);
170             if (pFigureUID == NULL)
171             {
172                 // allocation error
173                 set_block_error(-5);
174                 break;
175             }
176
177             appendData(block, block->inptr[0], block->inptr[1]);
178             for (j = 0; j < block->insz[0]; j++)
179             {
180                 result = pushData(block, j);
181                 if (result == FALSE)
182                 {
183                     Coserror("%s: unable to push some data.", "cscopxy");
184                     break;
185                 }
186             }
187             break;
188
189         case Ending:
190             freeScoData(block);
191             break;
192
193         default:
194             break;
195     }
196 }
197
198 /*-------------------------------------------------------------------------*/
199
200 /*****************************************************************************
201  *
202  * Container management
203  *
204  ****************************************************************************/
205
206 static sco_data *getScoData(scicos_block * block)
207 {
208     sco_data *sco = (sco_data *) * (block->work);
209     int i, j, k, l;
210
211     if (sco == NULL)
212     {
213         /*
214          * Data allocation
215          */
216
217         sco = (sco_data *) MALLOC(sizeof(sco_data));
218         if (sco == NULL)
219             goto error_handler_sco;
220
221         sco->internal.numberOfPoints = 0;
222         sco->internal.maxNumberOfPoints = block->ipar[2];
223
224         sco->internal.data = (double ***)CALLOC(block->nin, sizeof(double **));
225         if (sco->internal.data == NULL)
226             goto error_handler_data;
227
228         for (i = 0; i < block->nin; i++)
229         {
230             sco->internal.data[i] = (double **)CALLOC(block->insz[i], sizeof(double *));
231             if (sco->internal.data[i] == NULL)
232                 goto error_handler_data_i;
233         }
234         for (i = 0; i < block->nin; i++)
235         {
236             for (j = 0; j < block->insz[i]; j++)
237             {
238                 sco->internal.data[i][j] = (double *)CALLOC(block->ipar[2], sizeof(double));
239
240                 if (sco->internal.data[i][j] == NULL)
241                     goto error_handler_data_ij;
242             }
243         }
244
245         sco->scope.cachedFigureUID = NULL;
246         sco->scope.cachedAxeUID = NULL;
247
248         sco->scope.cachedPolylinesUIDs = (char **)CALLOC(block->insz[0], sizeof(char **));
249
250         *(block->work) = sco;
251     }
252
253     return sco;
254
255     /*
256      * Error management (out of normal flow)
257      */
258
259 error_handler_data_ij:
260     for (k = 0; k < i; k++)
261     {
262         for (l = 0; l < j; l++)
263         {
264             FREE(sco->internal.data[k][l]);
265         }
266     }
267     i = block->nin - 1;
268 error_handler_data_i:
269     for (j = 0; j < i; j++)
270     {
271         FREE(sco->internal.data[i]);
272     }
273     FREE(sco->internal.data);
274 error_handler_data:
275     FREE(sco);
276 error_handler_sco:
277     // allocation error
278     set_block_error(-5);
279     return NULL;
280 }
281
282 static void freeScoData(scicos_block * block)
283 {
284     sco_data *sco = (sco_data *) * (block->work);
285     int i, j;
286
287     if (sco != NULL)
288     {
289         for (i = 0; i < block->nin; i++)
290         {
291             for (j = 0; j < block->insz[i]; j++)
292             {
293                 FREE(sco->internal.data[i][j]);
294             }
295             FREE(sco->internal.data[i]);
296         }
297
298         FREE(sco->internal.data);
299
300         for (i = 0; i < block->insz[0]; i++)
301         {
302             FREE(sco->scope.cachedPolylinesUIDs[i]);
303             sco->scope.cachedPolylinesUIDs[i] = NULL;
304         }
305         FREE(sco->scope.cachedAxeUID);
306         sco->scope.cachedAxeUID = NULL;
307
308         FREE(sco);
309     }
310 }
311
312 static void appendData(scicos_block * block, double *x, double *y)
313 {
314     int i;
315
316     sco_data *sco = (sco_data *) * (block->work);
317     int maxNumberOfPoints = sco->internal.maxNumberOfPoints;
318     int numberOfPoints = sco->internal.numberOfPoints;
319
320     /*
321      * Handle the case where the scope has more points than maxNumberOfPoints
322      */
323     if (sco != NULL && numberOfPoints >= maxNumberOfPoints)
324     {
325         unsigned int setLen = (unsigned int)maxNumberOfPoints - 1;
326
327         // on a full scope, push data
328         for (i = 0; i < block->insz[0]; i++)
329         {
330             memmove(sco->internal.data[0][i], &sco->internal.data[0][i][1], setLen * sizeof(double));
331             sco->internal.data[0][i][setLen] = x[i];
332
333             memmove(sco->internal.data[1][i], &sco->internal.data[1][i][1], setLen * sizeof(double));
334             sco->internal.data[1][i][setLen] = y[i];
335         }
336
337         // then return
338         return;
339     }
340
341     /*
342      * Update data
343      */
344     if (sco != NULL)
345     {
346         int setLen;
347
348         for (i = 0; i < block->insz[0]; i++)
349         {
350             for (setLen = maxNumberOfPoints - numberOfPoints - 1; setLen >= 0; setLen--)
351             {
352                 sco->internal.data[0][i][numberOfPoints + setLen] = x[i];
353                 sco->internal.data[1][i][numberOfPoints + setLen] = y[i];
354             }
355         }
356
357         sco->internal.numberOfPoints++;
358     }
359 }
360
361 static BOOL pushData(scicos_block * block, int row)
362 {
363     char const* pFigureUID;
364     char *pAxeUID;
365     char *pPolylineUID;
366
367     double *x;
368     double *y;
369     sco_data *sco;
370
371     BOOL result = TRUE;
372
373     pFigureUID = getFigure(block);
374     pAxeUID = getAxe(pFigureUID, block);
375     pPolylineUID = getPolyline(pAxeUID, block, row);
376
377     sco = getScoData(block);
378     if (sco == NULL)
379         return FALSE;
380
381     // select the right input and row
382     x = sco->internal.data[0][row];
383     y = sco->internal.data[1][row];
384
385     result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_X__, x, jni_double_vector, sco->internal.maxNumberOfPoints);
386     result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_Y__, y, jni_double_vector, sco->internal.maxNumberOfPoints);
387
388     return result;
389 }
390
391 /*****************************************************************************
392  *
393  * Graphic utils
394  *
395  ****************************************************************************/
396
397 /**
398  * Set properties on the figure.
399  *
400  * \param pFigureUID the figure uid
401  * \param block the current block
402  */
403 static void setFigureSettings(char const* pFigureUID, scicos_block * block)
404 {
405     int win_pos[2];
406     int win_dim[2];
407
408     int *ipar = block->ipar;
409
410     win_pos[0] = ipar[6];
411     win_pos[1] = ipar[7];
412     win_dim[0] = ipar[8];
413     win_dim[1] = ipar[9];
414
415     if (win_pos[0] > 0 && win_pos[1] > 0)
416     {
417         setGraphicObjectProperty(pFigureUID, __GO_POSITION__, &win_pos, jni_int_vector, 2);
418     }
419
420     if (win_dim[0] > 0 && win_dim[1] > 0)
421     {
422         setGraphicObjectProperty(pFigureUID, __GO_SIZE__, &win_dim, jni_int_vector, 2);
423     }
424 };
425
426 /*****************************************************************************
427  *
428  * Graphic
429  *
430  ****************************************************************************/
431
432 static char const* getFigure(scicos_block * block)
433 {
434     signed int figNum;
435     char const* pFigureUID = NULL;
436     char *pAxe = NULL;
437     int i__1 = 1;
438     sco_data *sco = (sco_data *) * (block->work);
439
440     // fast path for an existing object
441     if (sco->scope.cachedFigureUID != NULL)
442     {
443         return sco->scope.cachedFigureUID;
444     }
445
446     figNum = block->ipar[0];
447
448     // with a negative id, use the block number indexed from a constant.
449     if (figNum < 0)
450     {
451         figNum = 20000 + get_block_number();
452     }
453
454     pFigureUID = getFigureFromIndex(figNum);
455     // create on demand
456     if (pFigureUID == NULL)
457     {
458         pFigureUID = createNewFigureWithAxes();
459         setGraphicObjectProperty(pFigureUID, __GO_ID__, &figNum, jni_int, 1);
460
461         // the stored uid is a reference to the figure map, not to the current figure
462         pFigureUID = getFigureFromIndex(figNum);
463         sco->scope.cachedFigureUID = pFigureUID;
464
465         // set configured parameters
466         setFigureSettings(pFigureUID, block);
467
468         // allocate the axes through the getter
469         pAxe = getAxe(pFigureUID, block);
470
471         /*
472          * Setup according to block settings
473          */
474         setLabel(pAxe, __GO_X_AXIS_LABEL__, "x");
475         setLabel(pAxe, __GO_Y_AXIS_LABEL__, "y");
476
477         setGraphicObjectProperty(pAxe, __GO_X_AXIS_VISIBLE__, &i__1, jni_bool, 1);
478         setGraphicObjectProperty(pAxe, __GO_Y_AXIS_VISIBLE__, &i__1, jni_bool, 1);
479
480         setPolylinesBounds(block);
481     }
482
483     if (sco->scope.cachedFigureUID == NULL)
484     {
485         sco->scope.cachedFigureUID = pFigureUID;
486     }
487     return pFigureUID;
488 }
489
490 static char *getAxe(char const* pFigureUID, scicos_block * block)
491 {
492     char *pAxe;
493     int i;
494     sco_data *sco = (sco_data *) * (block->work);
495
496     // fast path for an existing object
497     if (sco->scope.cachedAxeUID != NULL)
498     {
499         return sco->scope.cachedAxeUID;
500     }
501
502     pAxe = findChildWithKindAt(pFigureUID, __GO_AXES__, 0);
503
504     /*
505      * Allocate if necessary
506      */
507     if (pAxe == NULL)
508     {
509         cloneAxesModel(pFigureUID);
510         pAxe = findChildWithKindAt(pFigureUID, __GO_AXES__, 0);
511     }
512
513     /*
514      * Setup on first access
515      */
516     if (pAxe != NULL)
517     {
518         // allocate the polylines through the getter
519         for (i = 0; i < block->insz[0]; i++)
520         {
521             getPolyline(pAxe, block, i);
522         }
523     }
524
525     /*
526      * then cache with a local storage
527      */
528     if (pAxe != NULL && sco->scope.cachedAxeUID == NULL)
529     {
530         sco->scope.cachedAxeUID = strdup(pAxe);
531         releaseGraphicObjectProperty(__GO_PARENT__, pAxe, jni_string, 1);
532     }
533     return sco->scope.cachedAxeUID;
534 }
535
536 static char *getPolyline(char *pAxeUID, scicos_block * block, int row)
537 {
538     char *pPolyline;
539     double d__0 = 0.0;
540     BOOL b__true = TRUE;
541
542     int color;
543     int markSize;
544     double lineThickness;
545
546     sco_data *sco = (sco_data *) * (block->work);
547
548     // fast path for an existing object
549     if (sco->scope.cachedPolylinesUIDs != NULL && sco->scope.cachedPolylinesUIDs[row] != NULL)
550     {
551         return sco->scope.cachedPolylinesUIDs[row];
552     }
553
554     pPolyline = findChildWithKindAt(pAxeUID, __GO_POLYLINE__, row);
555
556     /*
557      * Allocate if necessary
558      */
559     if (pPolyline == NULL)
560     {
561         pPolyline = createGraphicObject(__GO_POLYLINE__);
562
563         if (pPolyline != NULL)
564         {
565             createDataObject(pPolyline, __GO_POLYLINE__);
566             setGraphicObjectRelationship(pAxeUID, pPolyline);
567
568         }
569     }
570
571     /*
572      * Setup on first access
573      */
574     if (pPolyline != NULL)
575     {
576         /*
577          * Default setup (will crash if removed)
578          */
579         {
580             int polylineSize[2] = { 1, block->ipar[2] };
581             setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_NUM_ELEMENTS_ARRAY__, polylineSize, jni_int_vector, 2);
582         }
583
584         setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_X__, &d__0, jni_double_vector, 1);
585         setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_Y__, &d__0, jni_double_vector, 1);
586
587         color = block->ipar[3];
588         markSize = block->ipar[4];
589         lineThickness = (double)markSize;
590         if (color > 0)
591         {
592             setGraphicObjectProperty(pPolyline, __GO_LINE_MODE__, &b__true, jni_bool, 1);
593
594             setGraphicObjectProperty(pPolyline, __GO_LINE_COLOR__, &color, jni_int, 1);
595             setGraphicObjectProperty(pPolyline, __GO_LINE_THICKNESS__, &lineThickness, jni_double, 1);
596         }
597         else
598         {
599             color = -color;
600             setGraphicObjectProperty(pPolyline, __GO_MARK_MODE__, &b__true, jni_bool, 1);
601
602             setGraphicObjectProperty(pPolyline, __GO_MARK_STYLE__, &color, jni_int, 1);
603             setGraphicObjectProperty(pPolyline, __GO_MARK_SIZE__, &markSize, jni_int, 1);
604         }
605
606         {
607             int iClipState = 1; //on
608             setGraphicObjectProperty(pPolyline, __GO_CLIP_STATE__, &iClipState, jni_int, 1);
609         }
610     }
611
612     /*
613      * then cache with a local storage
614      */
615     if (pPolyline != NULL && sco->scope.cachedPolylinesUIDs != NULL && sco->scope.cachedPolylinesUIDs[row] == NULL)
616     {
617         sco->scope.cachedPolylinesUIDs[row] = strdup(pPolyline);
618         releaseGraphicObjectProperty(__GO_PARENT__, pPolyline, jni_string, 1);
619     }
620     return sco->scope.cachedPolylinesUIDs[row];
621 }
622
623 static BOOL setPolylinesBounds(scicos_block * block)
624 {
625     char const* pFigureUID;
626     char *pAxeUID;
627
628     double dataBounds[6];
629
630     dataBounds[0] = block->rpar[0]; // xMin
631     dataBounds[1] = block->rpar[1]; // xMax
632     dataBounds[2] = block->rpar[2]; // yMin
633     dataBounds[3] = block->rpar[3]; // yMax
634     dataBounds[4] = -1.0;       // zMin
635     dataBounds[5] = 1.0;        // zMax
636
637     pFigureUID = getFigure(block);
638     pAxeUID = getAxe(pFigureUID, block);
639
640     return setGraphicObjectProperty(pAxeUID, __GO_DATA_BOUNDS__, dataBounds, jni_double_vector, 6);
641 }