Scicos blocks: use the new MVC graphic for scopes
[scilab.git] / scilab / modules / scicos_blocks / src / c / canimxy3d.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 "dynlib_scicos_blocks.h"
14 #include "scoUtils.h"
15
16 #include "MALLOC.h"
17 #include "elementary_functions.h"
18
19 #include "getGraphicObjectProperty.h"
20 #include "setGraphicObjectProperty.h"
21 #include "graphicObjectProperties.h"
22 #include "createGraphicObject.h"
23
24 #include "CurrentFigure.h"
25
26 #include "scicos_block4.h"
27 #include "scicos.h"
28
29 #include "localization.h"
30
31 #include "FigureList.h"
32 #include "BuildObjects.h"
33 #include "AxesModel.h"
34
35 #include <string.h>
36
37 /*****************************************************************************
38  * Internal container structure
39  ****************************************************************************/
40
41 /**
42  * Container structure
43  */
44 typedef struct
45 {
46     struct
47     {
48         int numberOfPoints;
49         int maxNumberOfPoints;
50         double ***data;
51     } internal;
52
53     struct
54     {
55         char *cachedFigureUID;
56         char *cachedAxeUID;
57         char **cachedPolylinesUIDs;
58     } scope;
59 } sco_data;
60
61 /**
62  * Get (and allocate on demand) the internal data used on this scope
63  * \param block the block
64  * \return the scope data
65  */
66 static sco_data *getScoData(scicos_block * block);
67
68 /**
69  * Release any internal data
70  *
71  * \param block the block
72  */
73 static void freeScoData(scicos_block * block);
74
75 /**
76  * Append the data to the current data
77  *
78  * \param block the block
79  * \param x x data
80  * \param y y data
81  * \param z z data
82  */
83 static void appendData(scicos_block * block, double *x, double *y, double *z);
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 polyline 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 *getPolyline(char *pAxeUID, scicos_block * block, int row);
124
125 /**
126  * Set the polylines bounds
127  *
128  * \param block the block
129  */
130 static BOOL setPolylinesBounds(scicos_block * block);
131
132 /*****************************************************************************
133  * Simulation function
134  ****************************************************************************/
135
136 /** \fn void cmscope(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 canimxy3d(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], (double *)block->inptr[2]);
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.", "cscopxy3d");
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, k, l;
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.numberOfPoints = 0;
215         sco->internal.maxNumberOfPoints = block->ipar[2];
216
217         sco->internal.data = (double ***)CALLOC(block->nin, sizeof(double **));
218         if (sco->internal.data == NULL)
219             goto error_handler_data;
220
221         for (i = 0; i < block->nin; i++)
222         {
223             sco->internal.data[i] = (double **)CALLOC(block->insz[i], sizeof(double *));
224             if (sco->internal.data[i] == NULL)
225                 goto error_handler_data_i;
226         }
227         for (i = 0; i < block->nin; i++)
228         {
229             for (j = 0; j < block->insz[i]; j++)
230             {
231                 sco->internal.data[i][j] = (double *)CALLOC(block->ipar[2], sizeof(double));
232
233                 if (sco->internal.data[i][j] == NULL)
234                     goto error_handler_data_ij;
235             }
236         }
237
238         sco->scope.cachedFigureUID = NULL;
239         sco->scope.cachedAxeUID = NULL;
240
241         sco->scope.cachedPolylinesUIDs = (char **)CALLOC(block->insz[0], sizeof(char **));
242
243         *(block->work) = sco;
244     }
245
246     return sco;
247
248     /*
249      * Error management (out of normal flow)
250      */
251
252 error_handler_data_ij:
253     for (k = 0; k < i; k++)
254     {
255         for (l = 0; l < j; l++)
256         {
257             FREE(sco->internal.data[k][l]);
258         }
259     }
260     i = block->nin - 1;
261 error_handler_data_i:
262     for (j = 0; j < i; j++)
263     {
264         FREE(sco->internal.data[i]);
265     }
266     FREE(sco->internal.data);
267 error_handler_data:
268     FREE(sco);
269 error_handler_sco:
270     // allocation error
271     set_block_error(-5);
272     return NULL;
273 }
274
275 static void freeScoData(scicos_block * block)
276 {
277     sco_data *sco = (sco_data *) * (block->work);
278     int i, j;
279
280     if (sco != NULL)
281     {
282         for (i = 0; i < block->nin; i++)
283         {
284             for (j = 0; j < block->insz[i]; j++)
285             {
286                 FREE(sco->internal.data[i][j]);
287             }
288             FREE(sco->internal.data[i]);
289         }
290
291         FREE(sco->internal.data);
292
293 //      Commented due to the C++ allocation
294 //      see http://bugzilla.scilab.org/show_bug.cgi?id=9747
295 //      FREE(sco->scope.cachedFigureUID);
296 //      sco->scope.cachedFigureUID = NULL;
297 //      for (i=0; i<block->nin; i++) {
298 //          for (j=0; j<block->insz[i]; j++) {
299 //              FREE(sco->scope.cachedPolylinesUIDs[i][j]);
300 //              sco->scope.cachedPolylinesUIDs[i][j] = NULL;
301 //          }
302 //          FREE(sco->scope.cachedAxeUID[i]);
303 //          sco->scope.cachedAxeUID[i] = NULL;
304 //      }
305
306         FREE(sco);
307     }
308 }
309
310 static void appendData(scicos_block * block, double *x, double *y, double *z)
311 {
312     int i;
313
314     sco_data *sco = (sco_data *) * (block->work);
315     int maxNumberOfPoints = sco->internal.maxNumberOfPoints;
316     int numberOfPoints = sco->internal.numberOfPoints;
317
318     /*
319      * Handle the case where the scope has more points than maxNumberOfPoints
320      */
321     if (sco != NULL && numberOfPoints >= maxNumberOfPoints)
322     {
323         unsigned int setLen = (unsigned int)maxNumberOfPoints - 1;
324
325         // on a full scope, push data
326         for (i = 0; i < block->insz[0]; i++)
327         {
328             sco->internal.data[0][i][setLen] = x[i];
329             memmove(sco->internal.data[0][i], &sco->internal.data[0][i][1], setLen * sizeof(double));
330
331             sco->internal.data[1][i][setLen] = y[i];
332             memmove(sco->internal.data[1][i], &sco->internal.data[1][i][1], setLen * sizeof(double));
333
334             sco->internal.data[2][i][setLen] = z[i];
335             memmove(sco->internal.data[2][i], &sco->internal.data[2][i][1], setLen * sizeof(double));
336         }
337
338         // then return
339         return;
340     }
341
342     /*
343      * Update data
344      */
345     if (sco != NULL)
346     {
347         int setLen;
348
349         for (i = 0; i < block->insz[0]; i++)
350         {
351             for (setLen = maxNumberOfPoints - numberOfPoints; setLen >= 0; setLen--)
352             {
353                 sco->internal.data[0][i][numberOfPoints + setLen] = x[i];
354                 sco->internal.data[1][i][numberOfPoints + setLen] = y[i];
355                 sco->internal.data[2][i][numberOfPoints + setLen] = z[i];
356             }
357         }
358
359         sco->internal.numberOfPoints++;
360     }
361 }
362
363 static BOOL pushData(scicos_block * block, int row)
364 {
365     char *pFigureUID;
366     char *pAxeUID;
367     char *pPolylineUID;
368
369     double *x;
370     double *y;
371     double *z;
372     sco_data *sco;
373
374     BOOL result = TRUE;
375
376     pFigureUID = getFigure(block);
377     pAxeUID = getAxe(pFigureUID, block);
378     pPolylineUID = getPolyline(pAxeUID, block, row);
379
380     sco = getScoData(block);
381     if (sco == NULL)
382         return FALSE;
383
384     // select the right input and row
385     x = sco->internal.data[0][row];
386     y = sco->internal.data[1][row];
387     z = sco->internal.data[2][row];
388
389     result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_X__, x, jni_double_vector, sco->internal.maxNumberOfPoints);
390     result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_Y__, y, jni_double_vector, sco->internal.maxNumberOfPoints);
391     result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_Z__, z, jni_double_vector, sco->internal.maxNumberOfPoints);
392
393     return result;
394 }
395
396 /*****************************************************************************
397  *
398  * Graphic utils
399  *
400  ****************************************************************************/
401
402 /**
403  * Set properties on the figure.
404  *
405  * \param pFigureUID the figure uid
406  * \param block the current block
407  */
408 static void setFigureSettings(char *pFigureUID, scicos_block * block)
409 {
410     int win_pos[2];
411     int win_dim[2];
412
413     int *ipar = block->ipar;
414     int nipar = block->nipar;
415
416     win_pos[0] = ipar[nipar - 5];
417     win_pos[1] = ipar[nipar - 4];
418     win_dim[0] = ipar[nipar - 3];
419     win_dim[1] = ipar[nipar - 2];
420
421     setGraphicObjectProperty(pFigureUID, __GO_POSITION__, &win_pos, jni_int_vector, 2);
422     setGraphicObjectProperty(pFigureUID, __GO_SIZE__, &win_dim, jni_int_vector, 2);
423 };
424
425 /*****************************************************************************
426  *
427  * Graphic
428  *
429  ****************************************************************************/
430
431 static char *getFigure(scicos_block * block)
432 {
433     signed int figNum;
434     char *pFigureUID = NULL;
435     char *pAxe = NULL;
436     static const int i__1 = 1;
437     sco_data *sco = (sco_data *) * (block->work);
438
439     // fast path for an existing object
440     if (sco->scope.cachedFigureUID != NULL)
441     {
442         return sco->scope.cachedFigureUID;
443     }
444
445     figNum = block->ipar[0];
446
447     // with a negative id, use the block number indexed from a constant.
448     if (figNum < 0)
449     {
450         figNum = 20000 + get_block_number();
451     }
452
453     pFigureUID = getFigureFromIndex(figNum);
454     // create on demand
455     if (pFigureUID == NULL)
456     {
457         pFigureUID = createNewFigureWithAxes();
458         setGraphicObjectProperty(pFigureUID, __GO_ID__, &figNum, jni_int, 1);
459
460         // set configured parameters
461         setFigureSettings(pFigureUID, block);
462         sco->scope.cachedFigureUID = pFigureUID;
463
464         // allocate the axes through the getter
465         pAxe = getAxe(pFigureUID, block);
466
467         /*
468          * Setup according to block settings
469          */
470         setLabel(pAxe, __GO_X_AXIS_LABEL__, "x");
471         setLabel(pAxe, __GO_Y_AXIS_LABEL__, "y");
472         setLabel(pAxe, __GO_Z_AXIS_LABEL__, "z");
473
474         setGraphicObjectProperty(pAxe, __GO_X_AXIS_VISIBLE__, &i__1, jni_bool, 1);
475         setGraphicObjectProperty(pAxe, __GO_Y_AXIS_VISIBLE__, &i__1, jni_bool, 1);
476         setGraphicObjectProperty(pAxe, __GO_Z_AXIS_VISIBLE__, &i__1, jni_bool, 1);
477
478         setPolylinesBounds(block);
479     }
480
481     if (sco->scope.cachedFigureUID == NULL)
482     {
483         sco->scope.cachedFigureUID = pFigureUID;
484     }
485     return pFigureUID;
486 }
487
488 static char *getAxe(char *pFigureUID, scicos_block * block)
489 {
490     char *pAxe;
491     int i;
492     sco_data *sco = (sco_data *) * (block->work);
493
494     // fast path for an existing object
495     if (sco->scope.cachedAxeUID != NULL)
496     {
497         return sco->scope.cachedAxeUID;
498     }
499
500     pAxe = findChildWithKindAt(pFigureUID, __GO_AXES__, 0);
501
502     /*
503      * Allocate if necessary
504      */
505     if (pAxe == NULL)
506     {
507         pAxe = cloneGraphicObject(getAxesModel());
508
509         if (pAxe != NULL)
510         {
511             setGraphicObjectRelationship(pFigureUID, pAxe);
512
513             // allocate the polylines through the getter
514             for (i = 0; i < block->insz[0]; i++)
515             {
516                 getPolyline(pAxe, block, i);
517             }
518         }
519     }
520
521     if (sco->scope.cachedAxeUID == NULL)
522     {
523         sco->scope.cachedAxeUID = pAxe;
524     }
525     return pAxe;
526 }
527
528 static char *getPolyline(char *pAxeUID, scicos_block * block, int row)
529 {
530     char *pPolyline;
531     static double d__0 = 0.0;
532     static int i__1 = 1;
533     static BOOL b__true = TRUE;
534
535     int color;
536     int markSize;
537     double lineThickness;
538
539     sco_data *sco = (sco_data *) * (block->work);
540
541     // fast path for an existing object
542     if (sco->scope.cachedPolylinesUIDs != NULL && sco->scope.cachedPolylinesUIDs[row] != NULL)
543     {
544         return sco->scope.cachedPolylinesUIDs[row];
545     }
546
547     pPolyline = findChildWithKindAt(pAxeUID, __GO_POLYLINE__, row);
548
549     /*
550      * Allocate if necessary
551      */
552     if (pPolyline == NULL)
553     {
554         pPolyline = createGraphicObject(__GO_POLYLINE__);
555
556         if (pPolyline != NULL)
557         {
558             createDataObject(pPolyline, __GO_POLYLINE__);
559             setGraphicObjectRelationship(pAxeUID, pPolyline);
560
561             /*
562              * Default setup (will crash if removed)
563              */
564             {
565                 int polylineSize[2] = { 1, block->ipar[2] };
566                 setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_NUM_ELEMENTS_ARRAY__, polylineSize, jni_int_vector, 2);
567             }
568
569             setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_X__, &d__0, jni_double_vector, 1);
570             setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_Y__, &d__0, jni_double_vector, 1);
571             setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_Z__, &d__0, jni_double_vector, 1);
572
573             color = block->ipar[3 + row];
574             markSize = block->ipar[3 + block->ipar[1] + row];
575             lineThickness = (double)markSize;
576             if (color > 0)
577             {
578                 setGraphicObjectProperty(pPolyline, __GO_LINE_MODE__, &b__true, jni_bool, 1);
579
580                 setGraphicObjectProperty(pPolyline, __GO_LINE_COLOR__, &color, jni_int, 1);
581                 setGraphicObjectProperty(pPolyline, __GO_LINE_THICKNESS__, &lineThickness, jni_double, 1);
582             }
583             else
584             {
585                 color = -color;
586                 setGraphicObjectProperty(pPolyline, __GO_MARK_MODE__, &b__true, jni_bool, 1);
587
588                 setGraphicObjectProperty(pPolyline, __GO_MARK_STYLE__, &color, jni_int, 1);
589                 setGraphicObjectProperty(pPolyline, __GO_MARK_SIZE__, &markSize, jni_int, 1);
590             }
591         }
592     }
593
594     if (sco->scope.cachedPolylinesUIDs != NULL)
595     {
596         sco->scope.cachedPolylinesUIDs[row] = pPolyline;
597     }
598     return pPolyline;
599 }
600
601 static BOOL setPolylinesBounds(scicos_block * block)
602 {
603     char *pFigureUID;
604     char *pAxeUID;
605
606     BOOL result;
607     double dataBounds[6];
608     double rotationAngle[2];
609
610     dataBounds[0] = block->rpar[0]; // xMin
611     dataBounds[1] = block->rpar[1]; // xMax
612     dataBounds[2] = block->rpar[2]; // yMin
613     dataBounds[3] = block->rpar[3]; // yMax
614     dataBounds[4] = block->rpar[4]; // zMin
615     dataBounds[5] = block->rpar[5]; // zMax
616
617     rotationAngle[0] = block->rpar[6];  // alpha
618     rotationAngle[1] = block->rpar[7];  // theta
619
620     pFigureUID = getFigure(block);
621     pAxeUID = getAxe(pFigureUID, block);
622
623     result = setGraphicObjectProperty(pAxeUID, __GO_DATA_BOUNDS__, dataBounds, jni_double_vector, 6);
624     result &= setGraphicObjectProperty(pAxeUID, __GO_ROTATION_ANGLES__, rotationAngle, jni_double_vector, 2);
625
626     return result;
627 }