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