* Bug #11550 fixed - Closing the scope graph while running simulation led to a
[scilab.git] / scilab / modules / scicos_blocks / src / c / cmat3d.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 <stdlib.h>
14 #include <math.h>
15 #include <string.h>
16
17 #include "dynlib_scicos_blocks.h"
18 #include "scoUtils.h"
19
20 #include "MALLOC.h"
21 #include "core_math.h"
22 #include "elementary_functions.h"
23
24 #include "getGraphicObjectProperty.h"
25 #include "setGraphicObjectProperty.h"
26 #include "graphicObjectProperties.h"
27 #include "createGraphicObject.h"
28
29 #include "CurrentFigure.h"
30
31 #include "scicos_block4.h"
32 #include "scicos.h"
33
34 #include "localization.h"
35 #ifdef _MSC_VER
36 #include "strdup_windows.h"
37 #endif
38
39 #include "FigureList.h"
40 #include "BuildObjects.h"
41 #include "AxesModel.h"
42 /*****************************************************************************
43  * Internal container structure
44  ****************************************************************************/
45
46 /**
47  * Container structure
48  */
49 typedef struct
50 {
51     struct
52     {
53         char const* cachedFigureUID;
54         char *cachedAxeUID;
55         char *cachedPlot3dUID;
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  * Push the block data to the polyline
75  *
76  * \param data the data to push
77  *
78  */
79 static BOOL pushData(scicos_block * block, double *data);
80
81 /*****************************************************************************
82  * Graphics utils
83  ****************************************************************************/
84
85 /**
86  * Get (and allocate on demand) the figure associated with the block
87  * \param block the block
88  * \return a valid figure UID or NULL on error
89  */
90 static char const* getFigure(scicos_block * block);
91
92 /**
93  * Get (and allocate on demand) the axe associated with the input
94  *
95  * \param pFigureUID the parent figure UID
96  * \param block the block
97  * \return a valid axe UID or NULL on error
98  */
99 static char *getAxe(char const* pFigureUID, scicos_block * block);
100
101 /**
102  * Get (and allocate on demand) the plot3d
103  *
104  * \param pAxeUID the parent axe UID
105  * \param block the block
106  * \return a valid plot3d UID or NULL on error
107  */
108 static char *getPlot3d(char *pAxeUID, scicos_block * block);
109
110 /**
111  * Set the plot3d and axes bounds
112  *
113  * \param block the block
114  * \param pAxeUID the axe
115  * \param pPlot3dUID the plot3d
116  */
117 static BOOL setBounds(scicos_block * block, char *pAxeUID, char *pPlot3dUID);
118
119 /**
120  * Set the plot3d settings
121  *
122  * \param pPlot3dUID the plot3d
123  */
124 static BOOL setPlot3dSettings(char *pPlot3dUID);
125
126 /**
127  * Set the plot3d default values
128  *
129  * \param block the block
130  * \param pPlot3dUID the plot3d
131  */
132 static BOOL setDefaultValues(scicos_block * block, char *pPlot3dUID);
133
134 /*****************************************************************************
135  * Simulation function
136  ****************************************************************************/
137
138 /** \fn void cmatview(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 cmat3d(scicos_block * block, scicos_flag flag)
144 {
145     char const* pFigureUID;
146
147     double *u;
148     sco_data *sco;
149
150     BOOL result;
151
152     switch (flag)
153     {
154
155         case Initialization:
156             sco = getScoData(block);
157             if (sco == NULL)
158             {
159                 set_block_error(-5);
160                 break;
161             }
162             pFigureUID = getFigure(block);
163             if (pFigureUID == NULL)
164             {
165                 // allocation error
166                 set_block_error(-5);
167                 break;
168             }
169             break;
170
171         case StateUpdate:
172             pFigureUID = getFigure(block);
173             if (pFigureUID == NULL)
174             {
175                 // allocation error
176                 set_block_error(-5);
177                 break;
178             }
179
180             u = GetRealInPortPtrs(block, 1);
181
182             result = pushData(block, u);
183             if (result == FALSE)
184             {
185                 Coserror("%s: unable to push some data.", "cmatview");
186                 break;
187             }
188             break;
189
190         case Ending:
191             freeScoData(block);
192             break;
193
194         default:
195             break;
196     }
197 }
198
199 /*-------------------------------------------------------------------------*/
200
201 /*****************************************************************************
202  *
203  * Container management
204  *
205  ****************************************************************************/
206
207 static sco_data *getScoData(scicos_block * block)
208 {
209     sco_data *sco = (sco_data *) * (block->work);
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->scope.cachedFigureUID = NULL;
222         sco->scope.cachedAxeUID = NULL;
223         sco->scope.cachedPlot3dUID = NULL;
224
225         *(block->work) = sco;
226     }
227
228     return sco;
229
230     /*
231      * Error management (out of normal flow)
232      */
233
234 error_handler_sco:
235     // allocation error
236     set_block_error(-5);
237     return NULL;
238 }
239
240 static void freeScoData(scicos_block * block)
241 {
242     sco_data *sco = (sco_data *) * (block->work);
243
244     if (sco != NULL)
245     {
246         FREE(sco->scope.cachedAxeUID);
247         FREE(sco->scope.cachedPlot3dUID);
248
249
250         FREE(sco);
251         *(block->work) = NULL;
252     }
253 }
254
255 static BOOL pushData(scicos_block * block, double *data)
256 {
257     char const* pFigureUID;
258     char *pAxeUID;
259     char *pPlot3dUID;
260
261     BOOL result;
262
263     int m, n;
264
265     pFigureUID = getFigure(block);
266     pAxeUID = getAxe(pFigureUID, block);
267     pPlot3dUID = getPlot3d(pAxeUID, block);
268
269     m = GetInPortSize(block, 1, 1);
270     n = GetInPortSize(block, 1, 2);
271
272     result = setGraphicObjectProperty(pPlot3dUID, __GO_DATA_MODEL_Z__, data, jni_double_vector, m * n);
273
274     return result;
275 }
276
277 /*****************************************************************************
278  *
279  * Graphic utils
280  *
281  ****************************************************************************/
282
283 /*****************************************************************************
284  *
285  * Graphic
286  *
287  ****************************************************************************/
288 static char const* getFigure(scicos_block * block)
289 {
290     signed int figNum;
291     char const* pFigureUID = NULL;
292     char *pAxe = NULL;
293     int i__1 = 1;
294     sco_data *sco = (sco_data *) * (block->work);
295
296     // assert the sco is not NULL
297     if (sco == NULL)
298     {
299         return NULL;
300     }
301
302
303     // fast path for an existing object
304     if (sco->scope.cachedFigureUID != NULL)
305     {
306         return sco->scope.cachedFigureUID;
307     }
308
309     figNum = block->ipar[0];
310
311     // with a negative id, use the block number indexed from a constant.
312     if (figNum < 0)
313     {
314         figNum = 20000 + get_block_number();
315     }
316
317     pFigureUID = getFigureFromIndex(figNum);
318     // create on demand
319     if (pFigureUID == NULL)
320     {
321         pFigureUID = createNewFigureWithAxes();
322         setGraphicObjectProperty(pFigureUID, __GO_ID__, &figNum, jni_int, 1);
323
324         // the stored uid is a reference to the figure map, not to the current figure
325         pFigureUID = getFigureFromIndex(figNum);
326         sco->scope.cachedFigureUID = pFigureUID;
327
328         setGraphicObjectProperty(pFigureUID, __GO_COLORMAP__, block->rpar, jni_double_vector, block->ipar[2]);
329
330         // allocate the axes through the getter
331         pAxe = getAxe(pFigureUID, block);
332
333         /*
334          * Setup according to block settings
335          */
336         setLabel(pAxe, __GO_X_AXIS_LABEL__, "x");
337         setLabel(pAxe, __GO_Y_AXIS_LABEL__, "y");
338         setLabel(pAxe, __GO_Z_AXIS_LABEL__, "z");
339
340         setGraphicObjectProperty(pAxe, __GO_X_AXIS_VISIBLE__, &i__1, jni_bool, 1);
341         setGraphicObjectProperty(pAxe, __GO_Y_AXIS_VISIBLE__, &i__1, jni_bool, 1);
342         setGraphicObjectProperty(pAxe, __GO_Z_AXIS_VISIBLE__, &i__1, jni_bool, 1);
343     }
344
345     if (sco->scope.cachedFigureUID == NULL)
346     {
347         sco->scope.cachedFigureUID = pFigureUID;
348     }
349     return pFigureUID;
350 }
351
352 static char *getAxe(char const* pFigureUID, scicos_block * block)
353 {
354     char *pAxe;
355     int i__1 = 1;
356     sco_data *sco = (sco_data *) * (block->work);
357
358     // assert the sco is not NULL
359     if (sco == NULL)
360     {
361         return NULL;
362     }
363
364     // fast path for an existing object
365     if (sco->scope.cachedAxeUID != NULL)
366     {
367         return sco->scope.cachedAxeUID;
368     }
369
370     pAxe = findChildWithKindAt(pFigureUID, __GO_AXES__, 0);
371
372     /*
373      * Allocate if necessary
374      */
375     if (pAxe == NULL)
376     {
377         cloneAxesModel(pFigureUID);
378         pAxe = findChildWithKindAt(pFigureUID, __GO_AXES__, 0);
379     }
380
381     if (pAxe != NULL)
382     {
383         setGraphicObjectProperty(pAxe, __GO_BOX_TYPE__, &i__1, jni_int, 1);
384
385         getPlot3d(pAxe, block);
386     }
387
388     /*
389      * then cache with local storage
390      */
391     if (pAxe != NULL && sco->scope.cachedAxeUID == NULL)
392     {
393         sco->scope.cachedAxeUID = strdup(pAxe);
394         releaseGraphicObjectProperty(__GO_PARENT__, pAxe, jni_string, 1);
395     }
396     return sco->scope.cachedAxeUID;
397 }
398
399 static char *getPlot3d(char *pAxeUID, scicos_block * block)
400 {
401     char *pPlot3d;
402
403     sco_data *sco = (sco_data *) * (block->work);
404
405     // assert the sco is not NULL
406     if (sco == NULL)
407     {
408         return NULL;
409     }
410
411     // fast path for an existing object
412     if (sco->scope.cachedPlot3dUID != NULL)
413     {
414         return sco->scope.cachedPlot3dUID;
415     }
416
417     pPlot3d = findChildWithKindAt(pAxeUID, __GO_PLOT3D__, 0);
418
419     /*
420      * Allocate if necessary
421      */
422     if (pPlot3d == NULL)
423     {
424         pPlot3d = createGraphicObject(__GO_PLOT3D__);
425
426         if (pPlot3d != NULL)
427         {
428             createDataObject(pPlot3d, __GO_PLOT3D__);
429             setGraphicObjectRelationship(pAxeUID, pPlot3d);
430         }
431     }
432
433     /*
434      * Setup on first access
435      */
436     if (pPlot3d != NULL)
437     {
438
439         setBounds(block, pAxeUID, pPlot3d);
440         setPlot3dSettings(pPlot3d);
441         setDefaultValues(block, pPlot3d);
442
443         {
444             int iClipState = 1; //on
445             setGraphicObjectProperty(pPlot3d, __GO_CLIP_STATE__, &iClipState, jni_int, 1);
446         }
447     }
448
449     /*
450      * then cache with a local storage
451      */
452     if (pPlot3d != NULL && sco->scope.cachedPlot3dUID == NULL)
453     {
454         sco->scope.cachedPlot3dUID = strdup(pPlot3d);
455         releaseGraphicObjectProperty(__GO_PARENT__, pPlot3d, jni_string, 1);
456     }
457     return sco->scope.cachedPlot3dUID;
458 }
459
460 static BOOL setBounds(scicos_block * block, char *pAxeUID, char *pPlot3dUID)
461 {
462     BOOL result;
463
464     int gridSize[4];
465     double dataBounds[6];
466     double rotationAngle[2];
467
468     int m, n;
469     int colormapLen;
470
471     m = GetInPortSize(block, 1, 1);
472     n = GetInPortSize(block, 1, 2);
473
474     gridSize[0] = 1;
475     gridSize[1] = m;
476     gridSize[2] = 1;
477     gridSize[3] = n;
478
479     colormapLen = block->ipar[3];
480     if (colormapLen == 1)
481     {
482         dataBounds[0] = (double) 0;  // xMin
483         dataBounds[1] = (double) m;  // xMax
484         dataBounds[2] = (double) 0;  // yMin
485         dataBounds[3] = (double) n;  // yMax
486     }
487     else
488     {
489         dataBounds[0] = block->rpar[colormapLen + 0];   // xMin
490         dataBounds[1] = block->rpar[colormapLen + 1];   // xMax
491         dataBounds[2] = block->rpar[colormapLen + 2];   // yMin
492         dataBounds[3] = block->rpar[colormapLen + 3];   // yMax
493     }
494
495     dataBounds[4] = (double)block->ipar[0]; // zMin
496     dataBounds[5] = (double)block->ipar[1]; // zMax
497
498     rotationAngle[0] = 50;      // alpha
499     rotationAngle[1] = 280;     // theta
500
501     result = setGraphicObjectProperty(pPlot3dUID, __GO_DATA_MODEL_GRID_SIZE__, gridSize, jni_int_vector, 4);
502     result &= setGraphicObjectProperty(pAxeUID, __GO_DATA_BOUNDS__, dataBounds, jni_double_vector, 6);
503     result &= setGraphicObjectProperty(pAxeUID, __GO_ROTATION_ANGLES__, rotationAngle, jni_double_vector, 2);
504
505     return result;
506 }
507
508 static BOOL setPlot3dSettings(char *pPlot3dUID)
509 {
510     int i__1 = 1;
511     double d__1 = 1.0;
512     int i__2 = 2;
513     int i__4 = 4;
514
515     BOOL result = TRUE;
516
517     result &= setGraphicObjectProperty(pPlot3dUID, __GO_SURFACE_MODE__, &i__1, jni_bool, 1);
518     result &= setGraphicObjectProperty(pPlot3dUID, __GO_LINE_THICKNESS__, &d__1, jni_double, 1);
519
520     result &= setGraphicObjectProperty(pPlot3dUID, __GO_COLOR_MODE__, &i__2, jni_int, 1);
521     result &= setGraphicObjectProperty(pPlot3dUID, __GO_COLOR_FLAG__, &i__1, jni_int, 1);
522     result &= setGraphicObjectProperty(pPlot3dUID, __GO_HIDDEN_COLOR__, &i__4, jni_int, 1);
523
524     setGraphicObjectProperty(pPlot3dUID, __GO_CLIP_STATE__, &i__1, jni_int, 1);
525
526     return result;
527 }
528
529 static BOOL setDefaultValues(scicos_block * block, char *pPlot3dUID)
530 {
531     int m, n, len;
532     int i;
533     double *values;
534
535     BOOL result;
536
537     m = GetInPortSize(block, 1, 1);
538     n = GetInPortSize(block, 1, 2);
539
540     /*
541      * Share the same memory for 0 allocation (z) and incremented index (x and y)
542      */
543     values = (double *)CALLOC(m * n, sizeof(double));
544     if (values == NULL)
545     {
546         return FALSE;
547     }
548     result = setGraphicObjectProperty(pPlot3dUID, __GO_DATA_MODEL_Z__, values, jni_double_vector, m * n);
549
550     len = Max(m, n);
551     for (i = 1; i <= len; i++)
552     {
553         values[i] = (double) i;
554     }
555
556     result &= setGraphicObjectProperty(pPlot3dUID, __GO_DATA_MODEL_X__, values, jni_double_vector, m);
557     result &= setGraphicObjectProperty(pPlot3dUID, __GO_DATA_MODEL_Y__, values, jni_double_vector, n);
558
559     FREE(values);
560     return result;
561 }