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