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