Scicos blocks: use the new MVC graphic for scopes
[scilab.git] / scilab / modules / scicos_blocks / src / c / bouncexy.c
index d2107ee..61f9251 100644 (file)
-/*  Scicos
-*
-*  Copyright (C) INRIA - METALAU Project <scicos@inria.fr>
-*
-* This program is free software; you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation; either version 2 of the License, or
-* (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program; if not, write to the Free Software
-* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*
-* See the file ./license.txt
-*/
-/*--------------------------------------------------------------------------*/
-/**
-   \file bouncexy.c
-   \author Benoit Bayol
-   \version 1.0
-   \date September 2006 - January 2007
-   \brief BOUNCEXY has to be used with bounce_ball block
-   \see BOUNCEXY.sci in macros/scicos_blocks/Misc/
-*/
+/*
+ *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ *  Copyright (C) 2011 - DIGITEO - ClĂ©ment DAVID
+ *
+ *  This file must be used under the terms of the CeCILL.
+ *  This source file is licensed as described in the file COPYING, which
+ *  you should have received as part of this distribution.  The terms
+ *  are also available at
+ *  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
+ *
+ */
+
 #include <math.h>
-#include "scoMemoryScope.h"
-#include "scoWindowScope.h"
-#include "scoMisc.h"
-#include "scoGetProperty.h"
-#include "scoSetProperty.h"
+#ifndef M_PI
+#define M_PI           3.14159265358979323846
+#endif
+
+#include "dynlib_scicos_blocks.h"
+#include "scoUtils.h"
+
+#include "MALLOC.h"
+#include "elementary_functions.h"
+
+#include "getGraphicObjectProperty.h"
+#include "setGraphicObjectProperty.h"
+#include "graphicObjectProperties.h"
+#include "createGraphicObject.h"
+
+#include "CurrentFigure.h"
+
 #include "scicos_block4.h"
-#include "ObjectStructure.h"
-#include "DrawingBridge.h"
 #include "scicos.h"
-#include "scicos_malloc.h"
-#include "scicos_free.h"
-#include "MALLOC.h"
-#include "dynlib_scicos_blocks.h"
-#include "HandleManagement.h"
-/*--------------------------------------------------------------------------*/
-/** \fn bouncexy_draw(scicos_block * block, ScopeMemory ** pScopeMemory, int firstdraw)
-    \brief Function to draw or redraw the window
+
+#include "localization.h"
+#include "FigureList.h"
+#include "BuildObjects.h"
+#include "AxesModel.h"
+
+/*****************************************************************************
+ * Internal container structure
+ ****************************************************************************/
+
+/**
+ * Container structure
+ */
+typedef struct
+{
+    struct
+    {
+        double *ballsSize;
+        double **data;
+    } internal;
+
+    struct
+    {
+        char *cachedFigureUID;
+        char *cachedAxeUID;
+        char **cachedArcsUIDs;
+    } scope;
+} sco_data;
+
+/**
+ * Get (and allocate on demand) the internal data used on this scope
+ * \param block the block
+ * \return the scope data
+ */
+static sco_data *getScoData(scicos_block * block);
+
+/**
+ * Release any internal data
+ *
+ * \param block the block
+ */
+static void freeScoData(scicos_block * block);
+
+/**
+ * Append the data to the current data
+ *
+ * \param block the block
+ * \param x x data
+ * \param y y data
+ */
+static void appendData(scicos_block * block, double *x, double *y);
+
+/**
+ * Push the block data to the polyline
+ *
+ * \param block the block
+ * \param row the selected row
+ *
+ */
+static BOOL pushData(scicos_block * block, int row);
+
+/*****************************************************************************
+ * Graphics utils
+ ****************************************************************************/
+
+/**
+ * Get (and allocate on demand) the figure associated with the block
+ * \param block the block
+ * \return a valid figure UID or NULL on error
+ */
+static char *getFigure(scicos_block * block);
+
+/**
+ * Get (and allocate on demand) the axe associated with the input
+ *
+ * \param pFigureUID the parent figure UID
+ * \param block the block
+ * \param input the current input index (0-indexed)
+ * \return a valid axe UID or NULL on error
+ */
+static char *getAxe(char *pFigureUID, scicos_block * block);
+
+/**
+ * Get (and allocate on demand) the arc associated with the row
+ *
+ * \param pAxeUID the parent axe UID
+ * \param block the block
+ * \param row the current row index (0-indexed)
+ * \return a valid polyline UID or NULL on error
+ */
+static char *getArc(char *pAxeUID, scicos_block * block, int row);
+
+/**
+ * Set the bounds
+ *
+ * \param block the block
+ */
+static BOOL setBounds(scicos_block * block);
+
+/*****************************************************************************
+ * Simulation function
+ ****************************************************************************/
+
+/** \fn void bouncexy(scicos_block * block,int flag)
+    \brief the computational function
+    \param block A pointer to a scicos_block
+    \param flag An int which indicates the state of the block (init, update, ending)
 */
-SCICOS_BLOCKS_IMPEXP void bouncexy_draw(scicos_block * block, ScopeMemory ** pScopeMemory, int firstdraw)
+SCICOS_BLOCKS_IMPEXP void bouncexy(scicos_block * block, scicos_flag flag)
+{
+    char *pFigureUID;
+
+    sco_data *sco;
+
+    int j;
+    BOOL result;
+
+    switch (flag)
+    {
+
+    case Initialization:
+        sco = getScoData(block);
+        if (sco == NULL)
+        {
+            set_block_error(-5);
+        }
+        pFigureUID = getFigure(block);
+        if (pFigureUID == NULL)
+        {
+            // allocation error
+            set_block_error(-5);
+        }
+        break;
+
+    case StateUpdate:
+        pFigureUID = getFigure(block);
+
+        appendData(block, (double *)block->inptr[0], (double *)block->inptr[1]);
+        for (j = 0; j < block->insz[0]; j++)
+        {
+            result = pushData(block, j);
+            if (result == FALSE)
+            {
+                Coserror("%s: unable to push some data.", "bouncexy");
+                break;
+            }
+        }
+        break;
+
+    case Ending:
+        freeScoData(block);
+        break;
+
+    default:
+        break;
+    }
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*****************************************************************************
+ *
+ * Container management
+ *
+ ****************************************************************************/
+
+static sco_data *getScoData(scicos_block * block)
+{
+    sco_data *sco = (sco_data *) * (block->work);
+    int i, j;
+
+    if (sco == NULL)
+    {
+        /*
+         * Data allocation
+         */
+
+        sco = (sco_data *) MALLOC(sizeof(sco_data));
+        if (sco == NULL)
+            goto error_handler_sco;
+
+        sco->internal.ballsSize = (double *)CALLOC(block->nin, sizeof(double));
+        if (sco->internal.ballsSize == NULL)
+            goto error_handler_ballsSize;
+        for (i = 0; i < block->insz[0]; i++)
+        {
+            sco->internal.ballsSize[i] = block->z[6 * i + 2];
+        }
+
+        sco->internal.data = (double **)CALLOC(block->insz[0], sizeof(double *));
+        if (sco->internal.data == NULL)
+            goto error_handler_data;
+
+        for (i = 0; i < block->insz[0]; i++)
+        {
+            sco->internal.data[i] = (double *)CALLOC(3, sizeof(double));
+            if (sco->internal.data[i] == NULL)
+                goto error_handler_data_i;
+        }
+
+        sco->scope.cachedFigureUID = NULL;
+        sco->scope.cachedAxeUID = NULL;
+
+        sco->scope.cachedArcsUIDs = (char **)CALLOC(block->insz[0], sizeof(char *));
+
+        *(block->work) = sco;
+    }
+
+    return sco;
+
+    /*
+     * Error management (out of normal flow)
+     */
+
+error_handler_data_i:
+    for (j = 0; j < i; j++)
+    {
+        FREE(sco->internal.data[i]);
+    }
+    FREE(sco->internal.data);
+error_handler_data:
+    FREE(sco->internal.ballsSize);
+error_handler_ballsSize:
+    FREE(sco);
+error_handler_sco:
+    // allocation error
+    set_block_error(-5);
+    return NULL;
+}
+
+static void freeScoData(scicos_block * block)
 {
-  scoGraphicalObject pAxes;
-  scoGraphicalObject pTemp;
-  double * z = NULL;
-  double *rpar = NULL;
-  int *ipar = NULL, nipar = 0;
-  int i = 0,j = 0;
-  int dimension = 0;
-  double ymin = 0., ymax = 0., xmin = 0., xmax = 0.;
-  int win = 0;
-  int number_of_subwin = 0;
-  int number_of_curves_by_subwin = 0;
-  int * colors = NULL;
-  int imode = 0;
-  double * size_balls = NULL;
-  double radius_max;
-
-  /*Retrieving Parameters*/
-  rpar = GetRparPtrs(block);
-  ipar = GetIparPtrs(block);
-  nipar = GetNipar(block);
-  win = ipar[0];
-  if (win == -1)
-    {
-      win = 20000 + get_block_number() ;
+    sco_data *sco = (sco_data *) * (block->work);
+    int i;
+
+    if (sco != NULL)
+    {
+        for (i = 0; i < block->insz[0]; i++)
+        {
+            FREE(sco->internal.data[i]);
+        }
+
+        FREE(sco->internal.data);
+        FREE(sco->internal.ballsSize);
+
+//      Commented due to the C++ allocation
+//      see http://bugzilla.scilab.org/show_bug.cgi?id=9747
+//      FREE(sco->scope.cachedFigureUID);
+//      sco->scope.cachedFigureUID = NULL;
+//      for (i=0; i<block->nin; i++) {
+//          for (j=0; j<block->insz[i]; j++) {
+//              FREE(sco->scope.cachedArcsUIDs[i][j]);
+//              sco->scope.cachedArcsUIDs[i][j] = NULL;
+//          }
+//          FREE(sco->scope.cachedAxeUID[i]);
+//          sco->scope.cachedAxeUID[i] = NULL;
+//      }
+
+        FREE(sco);
     }
-  dimension = 2;
-  imode = ipar[1];
-  number_of_curves_by_subwin = GetInPortRows(block,1);
-  radius_max = 0;
-  size_balls = (double*)scicos_malloc(number_of_curves_by_subwin*sizeof(double));
-  z = GetDstate(block);
-  for(i = 0 ; i < number_of_curves_by_subwin ; i++)
-    {
-      size_balls[i] = z[6*i+2];
-      if(radius_max < size_balls[i])
-       {
-         radius_max = size_balls[i];
-       }
+}
+
+static void appendData(scicos_block * block, double *x, double *y)
+{
+    int i;
+    double *upperLeftPoint;
+    double ballSize;
+    sco_data *sco = (sco_data *) * (block->work);
+
+    /*
+     * Update data
+     */
+    if (sco != NULL)
+    {
+        for (i = 0; i < block->insz[0]; i++)
+        {
+            upperLeftPoint = sco->internal.data[i];
+            ballSize = sco->internal.ballsSize[i];
+
+            upperLeftPoint[0] = x[i] - (ballSize / 2);  // x
+            upperLeftPoint[1] = y[i] + (ballSize / 2);  // y
+            upperLeftPoint[2] = 0;  // z
+        }
     }
-  number_of_subwin = 1;
-  xmin = rpar[0];
-  xmax = rpar[1];
-  ymin = rpar[2];
-  ymax = rpar[3];
-  colors = (int*)scicos_malloc(number_of_curves_by_subwin*sizeof(int));
-  for(i = 0 ; i < number_of_curves_by_subwin ; i++)
-    {
-      colors[i] = ipar[i+2];
+}
+
+static BOOL pushData(scicos_block * block, int row)
+{
+    char *pFigureUID;
+    char *pAxeUID;
+    char *pArcUID;
+
+    double *upperLeftPoint;
+    sco_data *sco;
+
+    pFigureUID = getFigure(block);
+    pAxeUID = getAxe(pFigureUID, block);
+    pArcUID = getArc(pAxeUID, block, row);
+
+    sco = getScoData(block);
+    if (sco == NULL)
+        return FALSE;
+
+    upperLeftPoint = sco->internal.data[row];
+    return setGraphicObjectProperty(pArcUID, __GO_UPPER_LEFT_POINT__, upperLeftPoint, jni_double_vector, 3);
+}
+
+/*****************************************************************************
+ *
+ * Graphic utils
+ *
+ ****************************************************************************/
+
+/*****************************************************************************
+ *
+ * Graphic
+ *
+ ****************************************************************************/
+
+static char *getFigure(scicos_block * block)
+{
+    signed int figNum;
+    char *pFigureUID = NULL;
+    char *pAxe = NULL;
+    sco_data *sco = (sco_data *) * (block->work);
+
+    // fast path for an existing object
+    if (sco->scope.cachedFigureUID != NULL)
+    {
+        return sco->scope.cachedFigureUID;
     }
-  if(firstdraw == 1)
+
+    figNum = block->ipar[0];
+
+    // with a negative id, use the block number indexed from a constant.
+    if (figNum < 0)
     {
-      /*Allocating memory*/
-      scoInitScopeMemory(block->work,pScopeMemory, number_of_subwin, &number_of_curves_by_subwin);
+        figNum = 20000 + get_block_number();
     }
-  /*Creating the Scope*/
-  scoInitOfWindow(*pScopeMemory, dimension, win, NULL, NULL, &xmin, &xmax, &ymin, &ymax, NULL, NULL);
-  if(scoGetScopeActivation(*pScopeMemory) == 1)
+
+    pFigureUID = getFigureFromIndex(figNum);
+    // create on demand
+    if (pFigureUID == NULL)
     {
-  pTemp = scoGetPointerScopeWindow(*pScopeMemory);
-  pAxes = scoGetPointerAxes(*pScopeMemory,0);
+        pFigureUID = createNewFigureWithAxes();
+        setGraphicObjectProperty(pFigureUID, __GO_ID__, &figNum, jni_int, 1);
 
-  pSUBWIN_FEATURE(pAxes)->isoview = TRUE;
+        sco->scope.cachedFigureUID = pFigureUID;
 
-  (pSUBWIN_FEATURE(pAxes)->axes).axes_visible[0] = FALSE;
-  (pSUBWIN_FEATURE(pAxes)->axes).axes_visible[1] = FALSE;
+        // allocate the axes through the getter
+        pAxe = getAxe(pFigureUID, block);
 
-  //** sciSetIsBoxed(pAxes, FALSE); //** obsolete in Scilab 5
-  sciSetBoxType(pAxes,BT_ON);
+        /*
+         * Setup according to block settings
+         */
+        setLabel(pAxe, __GO_X_AXIS_LABEL__, "x");
+        setLabel(pAxe, __GO_Y_AXIS_LABEL__, "y");
 
+        setBounds(block);
+    }
 
-  for(j = 0 ; j < number_of_curves_by_subwin ; j++)
+    if (sco->scope.cachedFigureUID == NULL)
     {
-      scoAddSphereForShortDraw(*pScopeMemory, 0, j, size_balls[j], colors[j]);
+        sco->scope.cachedFigureUID = pFigureUID;
     }
-  scoAddRectangleForLongDraw(*pScopeMemory,0,0,xmin,(ymax-fabs(ymin)),fabs(xmax-xmin),fabs(ymax-ymin));
-  sciDrawObj(scoGetPointerLongDraw(*pScopeMemory,0,0));
+    return pFigureUID;
+}
+
+static char *getAxe(char *pFigureUID, scicos_block * block)
+{
+    char *pAxe;
+    int i;
+
+    sco_data *sco = (sco_data *) * (block->work);
+
+    // fast path for an existing object
+    if (sco->scope.cachedAxeUID != NULL)
+    {
+        return sco->scope.cachedAxeUID;
+    }
+
+    pAxe = findChildWithKindAt(pFigureUID, __GO_AXES__, 0);
+
+    /*
+     * Allocate if necessary
+     */
+    if (pAxe == NULL)
+    {
+        pAxe = cloneGraphicObject(getAxesModel());
+
+        if (pAxe != NULL)
+        {
+            setGraphicObjectRelationship(pFigureUID, pAxe);
+
+            // allocate the polylines through the getter
+            for (i = 0; i < block->insz[0]; i++)
+            {
+                getArc(pAxe, block, i);
+            }
+        }
     }
-  scicos_free(colors);
-  scicos_free(size_balls);
 
+    sco->scope.cachedAxeUID = pAxe;
+    return pAxe;
 }
-/*--------------------------------------------------------------------------*/
-/** \fn void bouncexy(scicos_block * block,int flag)
-    \brief the computational function
-    \param block A pointer to a scicos_block
-    \param flag An int which indicates the state of the block (init, update, ending)
-*/
-SCICOS_BLOCKS_IMPEXP void bouncexy(scicos_block * block,int flag)
+
+static char *getArc(char *pAxeUID, scicos_block * block, int row)
 {
-  ScopeMemory * pScopeMemory = NULL;
-  scoGraphicalObject pShortDraw;
-  double * z = NULL;
-  double t = 0.;
-  int i = 0;
-  double * u1 = NULL, *u2 = NULL;
-  double * size_balls = NULL;
-  switch(flag)
+    static double d__0 = 0.0;
+    static double d__2PI = 2 * M_PI;
+
+    char *pArc;
+    int color;
+
+    sco_data *sco = (sco_data *) * (block->work);
+
+    // fast path for an existing object
+    if (sco->scope.cachedArcsUIDs != NULL && sco->scope.cachedArcsUIDs[row] != NULL)
     {
-    case Initialization:
-      {
-       bouncexy_draw(block,&pScopeMemory,1);
-       break;
-      }
-    case StateUpdate:
-      {
-       /*Retreiving Scope in the block->work*/
-       scoRetrieveScopeMemory(block->work,&pScopeMemory);
-       if(scoGetScopeActivation(pScopeMemory) == 1)
-         {
-           t = get_scicos_time();
-       /*If window has been destroyed we recreate it*/
-       if(scoGetPointerScopeWindow(pScopeMemory) == NULL)
-         {
-           bouncexy_draw(block,&pScopeMemory,0);
-         }
-
-       //Cannot be factorized depends of the scope
-       size_balls = (double*)scicos_malloc(scoGetNumberOfCurvesBySubwin(pScopeMemory,0)*sizeof(double));
-       z = GetDstate(block);
-       for(i = 0 ; i < scoGetNumberOfCurvesBySubwin(pScopeMemory,0) ; i++)
-         {
-           size_balls[i] = z[6*i+2];
-         }
-       u1 = GetRealInPortPtrs(block,1);
-       u2 = GetRealInPortPtrs(block,2);
-       for (i = 0 ; i < scoGetNumberOfCurvesBySubwin(pScopeMemory,0) ; i++)
-         {
-           pShortDraw  = scoGetPointerShortDraw(pScopeMemory,0,i);
-           //** pLongDraw  = scoGetPointerLongDraw(pScopeMemory,0,i);
-           pARC_FEATURE(pShortDraw)->x = u1[i]-size_balls[i]/2;
-           pARC_FEATURE(pShortDraw)->y = u2[i]+size_balls[i]/2;
-            forceRedraw(pShortDraw); //** force the redraw of each ball
-         }
-
-       sciSetUsedWindow(scoGetWindowID(pScopeMemory));
-       sciDrawObj(scoGetPointerScopeWindow(pScopeMemory));
-        scicos_free(size_balls);
-         }
-       break;
-      }
+        return sco->scope.cachedArcsUIDs[row];
+    }
 
-    case Ending:
-      {
-       scoRetrieveScopeMemory(block->work, &pScopeMemory);
-       if(scoGetScopeActivation(pScopeMemory) == 1)
-         {
-           sciSetUsedWindow(scoGetWindowID(pScopeMemory));
-           pShortDraw = sciGetCurrentFigure();
-           pFIGURE_FEATURE(pShortDraw)->user_data = NULL;
-           pFIGURE_FEATURE(pShortDraw)->size_of_user_data = 0;
-         }
-       scoFreeScopeMemory(block->work, &pScopeMemory);
-       break;
-      }
+    pArc = findChildWithKindAt(pAxeUID, __GO_ARC__, row);
+
+    /*
+     * Allocate if necessary
+     */
+    if (pArc == NULL)
+    {
+        pArc = createGraphicObject(__GO_ARC__);
+
+        if (pArc != NULL)
+        {
+            createDataObject(pArc, __GO_ARC__);
+            setGraphicObjectRelationship(pAxeUID, pArc);
+
+            /*
+             * Default setup
+             */
+            setGraphicObjectProperty(pArc, __GO_START_ANGLE__, &d__0, jni_double, 1);
+            setGraphicObjectProperty(pArc, __GO_END_ANGLE__, &d__2PI, jni_double, 1);
+
+            color = block->ipar[2 + row];
+            setGraphicObjectProperty(pArc, __GO_BACKGROUND__, &color, jni_int, 1);
+
+            setGraphicObjectProperty(pArc, __GO_WIDTH__, &sco->internal.ballsSize[row], jni_double, 1);
+            setGraphicObjectProperty(pArc, __GO_HEIGHT__, &sco->internal.ballsSize[row], jni_double, 1);
+        }
+    }
+
+    if (sco->scope.cachedArcsUIDs != NULL)
+    {
+        sco->scope.cachedArcsUIDs[row] = pArc;
     }
+    return pArc;
+}
+
+static BOOL setBounds(scicos_block * block)
+{
+    char *pFigureUID;
+    char *pAxeUID;
+
+    double dataBounds[6];
+
+    dataBounds[0] = block->rpar[0]; // xMin
+    dataBounds[1] = block->rpar[1]; // xMax
+    dataBounds[2] = block->rpar[2]; // yMin
+    dataBounds[3] = block->rpar[3]; // yMax
+    dataBounds[4] = -1.0;       // zMin
+    dataBounds[5] = 1.0;        // zMax
+
+    pFigureUID = getFigure(block);
+    pAxeUID = getAxe(pFigureUID, block);
+
+    return setGraphicObjectProperty(pAxeUID, __GO_DATA_BOUNDS__, dataBounds, jni_double_vector, 6);
 }
-/*--------------------------------------------------------------------------*/