/*   EXTRAITS DE LA LICENCE
	Copyright CEA, contributeurs : Luc BILLARD et Damien
	CALISTE, laboratoire L_Sim, (2001-2005)
  
	Adresse mèl :
	BILLARD, non joignable par mèl ;
	CALISTE, damien P caliste AT cea P fr.

	Ce logiciel est un programme informatique servant à visualiser des
	structures atomiques dans un rendu pseudo-3D. 

	Ce logiciel est régi par la licence CeCILL soumise au droit français et
	respectant les principes de diffusion des logiciels libres. Vous pouvez
	utiliser, modifier et/ou redistribuer ce programme sous les conditions
	de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA 
	sur le site "http://www.cecill.info".

	Le fait que vous puissiez accéder à cet en-tête signifie que vous avez 
	pris connaissance de la licence CeCILL, et que vous en avez accepté les
	termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
*/

/*   LICENCE SUM UP
	Copyright CEA, contributors : Luc BILLARD et Damien
	CALISTE, laboratoire L_Sim, (2001-2005)

	E-mail address:
	BILLARD, not reachable any more ;
	CALISTE, damien P caliste AT cea P fr.

	This software is a computer program whose purpose is to visualize atomic
	configurations in 3D.

	This software is governed by the CeCILL  license under French law and
	abiding by the rules of distribution of free software.  You can  use, 
	modify and/ or redistribute the software under the terms of the CeCILL
	license as circulated by CEA, CNRS and INRIA at the following URL
	"http://www.cecill.info". 

	The fact that you are presently reading this means that you have had
	knowledge of the CeCILL license and that you accept its terms. You can
	find a copy of this licence shipped with this software at Documentation/licence.en.txt.
*/

#include "scale.h"

#include <string.h>

#include <GL/gl.h>
#include <GL/glu.h> 

#include <opengl.h>
#include <openGLFunctions/text.h>
#include <visu_tools.h>
#include <visu_configFile.h>
#include <openGLFunctions/objectList.h>
#include <coreTools/toolColor.h>
#include <coreTools/toolMatrix.h>

#include <math.h>

/**
 * SECTION:scale
 * @short_description: Draw an arrow with a label.
 *
 * This little extension is used to draw an arrow at a given position
 * displaying a given length.
 *
 * Since: 3.3
 */

/* Parameters & resources*/
/* This is a boolean to control is the axes is render or not. */
#define FLAG_RESOURCE_SCALE_USED   "scales_are_on"
#define DESC_RESOURCE_SCALE_USED   "Control if scales are drawn ; boolean (0 or 1)"
static gboolean defaultUsed = FALSE;

/* A resource to control the color used to render the lines of the Scale. */
#define FLAG_RESOURCE_SCALE_COLOR   "scales_color"
#define DESC_RESOURCE_SCALE_COLOR   "Define the color RGBA of all scales ; four floating point values (0. <= v <= 1.)"
static float _rgba[4] = {0.f, 0.f, 0.f, 1.f};

/* A resource to control the width to render the lines of the Scale. */
#define FLAG_RESOURCE_SCALE_LINE   "scales_line_width"
#define DESC_RESOURCE_SCALE_LINE   "Define the width of the lines of all scales ; one floating point value (1. <= v <= 10.)"
static float _width = 1.f;

/* A resource to control the width to render the lines of the Scale. */
#define FLAG_RESOURCE_SCALE_STIPPLE   "scales_line_stipple"
#define DESC_RESOURCE_SCALE_STIPPLE   "Define the stipple pattern of the lines of all scales ; one integer value (0 <= v <= 65535)"
static guint16 _stipple = 65535;

/* A resource to control the elements of a scale (origin, direction, length... */
#define FLAG_RESOURCE_SCALE_DEFINITION "scale_definition"
#define DESC_RESOURCE_SCALE_DEFINITION "Define the position, the direction, the length and the legend of a scale ; position[3] direction[3] length legend"
#define SCALE_LEGEND_DEFAULT _("Length: %6.2f")

/* Export function that is called by visu_module to write the
   values of resources to a file. */
static void exportResourcesScale(GString *data, VisuData *dataObj);

#define SCALE_AUTO_LEGEND "[auto]"

typedef struct _Arrow
{
  /* Definition of the scale. */
  float origin[3];
  float direction[3];
  float length;

  /* Characteristics. */
  gboolean drawn;
  gchar *legendPattern;
  GString *legend;
} Arrow;

struct _VisuGlExtScalePrivate
{
  /* Internal object gestion. */
  gboolean dispose_has_run;

  /* A list of arrows. */
  GList *arrows;
  guint iArr;
  float width;
  float rgba[4];
  guint16 stipple;

  /* Related objects. */
  VisuGlView *view;
  gulong view_signal;
};

enum
  {
    PROP_0,
    COLOR_PROP,
    WIDTH_PROP,
    STIPPLE_PROP,
    N_ARR_PROP,
    CUR_PROP,
    CUR_LENGTH_PROP,
    CUR_LBL_PROP,
    CUR_ORIG_X_PROP,
    CUR_ORIG_Y_PROP,
    CUR_ORIG_Z_PROP,
    CUR_DIR_X_PROP,
    CUR_DIR_Y_PROP,
    CUR_DIR_Z_PROP,
    N_PROP
  };
static GParamSpec *properties[N_PROP];

static VisuGlExtScale * defaultScale = NULL;

/* Object gestion methods. */
static void visu_gl_ext_lined_interface_init(VisuGlExtLinedInterface *iface);
static void scale_dispose (GObject* obj);
static void scale_finalize(GObject* obj);
static void scale_get_property(GObject* obj, guint property_id,
                               GValue *value, GParamSpec *pspec);
static void scale_set_property(GObject* obj, guint property_id,
                               const GValue *value, GParamSpec *pspec);
static void scale_rebuild (VisuGlExt *ext);
static void scale_draw(VisuGlExt *ext);
static gboolean scale_setGlView(VisuGlExt *ext, VisuGlView *view);

static gboolean _setRGB(VisuGlExtLined *scale, float rgb[4], int mask);
static gboolean _setLineWidth(VisuGlExtLined *scale, float width);
static gboolean _setLineStipple(VisuGlExtLined *scale, guint16 stipple);
static float*   _getRGB(const VisuGlExtLined *scale);
static float    _getLineWidth(const VisuGlExtLined *scale);
static guint16  _getLineStipple(const VisuGlExtLined *scale);

/* Local methods. */
static void _freeArrow(Arrow *arr);
static void _drawArrow(Arrow *arr, guint nlat);

/* Local callbacks */
static void onScaleParametersChange(VisuGlExtScale *scale);
static void onEntryUsed(VisuGlExtScale *scale, VisuConfigFileEntry *entry, VisuConfigFile *obj);
static void onEntryColor(VisuGlExtScale *scale, VisuConfigFileEntry *entry, VisuConfigFile *obj);
static void onEntryWidth(VisuGlExtScale *scale, VisuConfigFileEntry *entry, VisuConfigFile *obj);
static void onEntryStipple(VisuGlExtScale *scale, VisuConfigFileEntry *entry, VisuConfigFile *obj);

G_DEFINE_TYPE_WITH_CODE(VisuGlExtScale, visu_gl_ext_scale, VISU_TYPE_GL_EXT,
                        G_ADD_PRIVATE(VisuGlExtScale)
                        G_IMPLEMENT_INTERFACE(VISU_TYPE_GL_EXT_LINED,
                                              visu_gl_ext_lined_interface_init))

static void visu_gl_ext_lined_interface_init(VisuGlExtLinedInterface *iface)
{
  iface->get_width   = _getLineWidth;
  iface->set_width   = _setLineWidth;
  iface->get_stipple = _getLineStipple;
  iface->set_stipple = _setLineStipple;
  iface->get_rgba    = _getRGB;
  iface->set_rgba    = _setRGB;
}
static void visu_gl_ext_scale_class_init(VisuGlExtScaleClass *klass)
{
  float rgColor[2] = {0.f, 1.f};
  float rgWidth[2] = {0.f, 10.f};
  VisuConfigFileEntry *resourceEntry;

  DBG_fprintf(stderr, "Scale: creating the class of the object.\n");

  /* Connect freeing methods. */
  G_OBJECT_CLASS(klass)->dispose  = scale_dispose;
  G_OBJECT_CLASS(klass)->finalize = scale_finalize;
  G_OBJECT_CLASS(klass)->set_property = scale_set_property;
  G_OBJECT_CLASS(klass)->get_property = scale_get_property;
  VISU_GL_EXT_CLASS(klass)->rebuild = scale_rebuild;
  VISU_GL_EXT_CLASS(klass)->draw = scale_draw;
  VISU_GL_EXT_CLASS(klass)->setGlView = scale_setGlView;

  /* Create the entries in config files. */
  DBG_fprintf(stderr," - create entries for config file.\n");
  resourceEntry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_RESOURCE,
                                                   FLAG_RESOURCE_SCALE_USED,
                                                   DESC_RESOURCE_SCALE_USED,
                                                   &defaultUsed, FALSE);
  visu_config_file_entry_setVersion(resourceEntry, 3.3f);
  resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE,
                                                      FLAG_RESOURCE_SCALE_COLOR,
                                                      DESC_RESOURCE_SCALE_COLOR,
                                                      4, _rgba, rgColor, FALSE);
  visu_config_file_entry_setVersion(resourceEntry, 3.3f);
  resourceEntry = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE,
                                                      FLAG_RESOURCE_SCALE_LINE,
                                                      DESC_RESOURCE_SCALE_LINE,
                                                      1, &_width, rgWidth, FALSE);
  visu_config_file_entry_setVersion(resourceEntry, 3.3f);
  resourceEntry = visu_config_file_addTokenizedEntry(VISU_CONFIG_FILE_RESOURCE,
                                                     FLAG_RESOURCE_SCALE_DEFINITION,
                                                     DESC_RESOURCE_SCALE_DEFINITION,
                                                     FALSE);
  visu_config_file_entry_setVersion(resourceEntry, 3.3f);
  resourceEntry = visu_config_file_addStippleArrayEntry(VISU_CONFIG_FILE_RESOURCE,
                                                        FLAG_RESOURCE_SCALE_STIPPLE,
                                                        DESC_RESOURCE_SCALE_STIPPLE,
                                                        1, &_stipple);
  visu_config_file_entry_setVersion(resourceEntry, 3.4f);
  visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE,
				   exportResourcesScale);

  /**
   * VisuGlExtScale::color:
   *
   * Store the color of the scale.
   *
   * Since: 3.8
   */
  g_object_class_override_property(G_OBJECT_CLASS(klass), COLOR_PROP, "color");
  /**
   * VisuGlExtScale::width:
   *
   * Store the line width of the scale.
   *
   * Since: 3.8
   */
  g_object_class_override_property(G_OBJECT_CLASS(klass), WIDTH_PROP, "width");
  /**
   * VisuGlExtScale::stipple:
   *
   * Store the line stipple pattern of the scale.
   *
   * Since: 3.8
   */
  g_object_class_override_property(G_OBJECT_CLASS(klass), STIPPLE_PROP, "stipple");
  /**
   * VisuGlExtScale::n-arrows:
   *
   * Store the number of arrows.
   *
   * Since: 3.8
   */
  properties[N_ARR_PROP] = g_param_spec_uint("n-arrows", "number of arrows",
                                           "number of stored arrows",
                                           0, G_MAXUINT, 0,
                                           G_PARAM_READABLE);
  g_object_class_install_property(G_OBJECT_CLASS(klass), N_ARR_PROP,
				  properties[N_ARR_PROP]);
  /**
   * VisuGlExtScale::current:
   *
   * Store the id of the current arrow.
   *
   * Since: 3.8
   */
  properties[CUR_PROP] = g_param_spec_uint("current", "current arrow",
                                               "id of the current arrow",
                                               0, G_MAXUINT, 0,
                                               G_PARAM_READWRITE);
  g_object_class_install_property(G_OBJECT_CLASS(klass), CUR_PROP,
				  properties[CUR_PROP]);
  /**
   * VisuGlExtScale::current-length:
   *
   * Store the length of the current arrow.
   *
   * Since: 3.8
   */
  properties[CUR_LENGTH_PROP] = g_param_spec_float("current-length",
                                                   "current arrow length",
                                                   "length of the current arrow",
                                                   0.f, G_MAXFLOAT, 0.f,
                                                   G_PARAM_READWRITE);
  g_object_class_install_property(G_OBJECT_CLASS(klass), CUR_LENGTH_PROP,
				  properties[CUR_LENGTH_PROP]);
  /**
   * VisuGlExtScale::current-label:
   *
   * Store the label of the current arrow.
   *
   * Since: 3.8
   */
  properties[CUR_LBL_PROP] = g_param_spec_string("current-label",
                                                 "current arrow label",
                                                 "label of the current arrow",
                                                 "", G_PARAM_READWRITE);
  g_object_class_install_property(G_OBJECT_CLASS(klass), CUR_LBL_PROP,
				  properties[CUR_LBL_PROP]);
  /**
   * VisuGlExtScale::current-origin-x:
   *
   * Store the origin[x] of the current arrow.
   *
   * Since: 3.8
   */
  properties[CUR_ORIG_X_PROP] = g_param_spec_float("current-origin-x",
                                                   "current arrow origin",
                                                   "origin of the current arrow",
                                                   -G_MAXFLOAT, G_MAXFLOAT, 0.,
                                                   G_PARAM_READWRITE);
  g_object_class_install_property(G_OBJECT_CLASS(klass), CUR_ORIG_X_PROP,
				  properties[CUR_ORIG_X_PROP]);
  /**
   * VisuGlExtScale::current-origin-y:
   *
   * Store the origin[y] of the current arrow.
   *
   * Since: 3.8
   */
  properties[CUR_ORIG_Y_PROP] = g_param_spec_float("current-origin-y",
                                                   "current arrow origin",
                                                   "origin of the current arrow",
                                                   -G_MAXFLOAT, G_MAXFLOAT, 0.,
                                                   G_PARAM_READWRITE);
  g_object_class_install_property(G_OBJECT_CLASS(klass), CUR_ORIG_Y_PROP,
				  properties[CUR_ORIG_Y_PROP]);
  /**
   * VisuGlExtScale::current-origin-z:
   *
   * Store the origin[z] of the current arrow.
   *
   * Since: 3.8
   */
  properties[CUR_ORIG_Z_PROP] = g_param_spec_float("current-origin-z",
                                                   "current arrow origin",
                                                   "origin of the current arrow",
                                                   -G_MAXFLOAT, G_MAXFLOAT, 0.,
                                                   G_PARAM_READWRITE);
  g_object_class_install_property(G_OBJECT_CLASS(klass), CUR_ORIG_Z_PROP,
				  properties[CUR_ORIG_Z_PROP]);
  /**
   * VisuGlExtScale::current-orientation-x:
   *
   * Store the orientation[x] of the current arrow.
   *
   * Since: 3.8
   */
  properties[CUR_DIR_X_PROP] = g_param_spec_float("current-orientation-x",
                                                   "current arrow orientation",
                                                   "orientation of the current arrow",
                                                   -G_MAXFLOAT, G_MAXFLOAT, 0.,
                                                   G_PARAM_READWRITE);
  g_object_class_install_property(G_OBJECT_CLASS(klass), CUR_DIR_X_PROP,
				  properties[CUR_DIR_X_PROP]);
  /**
   * VisuGlExtScale::current-orientation-y:
   *
   * Store the orientation[y] of the current arrow.
   *
   * Since: 3.8
   */
  properties[CUR_DIR_Y_PROP] = g_param_spec_float("current-orientation-y",
                                                   "current arrow orientation",
                                                   "orientation of the current arrow",
                                                   -G_MAXFLOAT, G_MAXFLOAT, 0.,
                                                   G_PARAM_READWRITE);
  g_object_class_install_property(G_OBJECT_CLASS(klass), CUR_DIR_Y_PROP,
				  properties[CUR_DIR_Y_PROP]);
  /**
   * VisuGlExtScale::current-orientation-z:
   *
   * Store the orientation[z] of the current arrow.
   *
   * Since: 3.8
   */
  properties[CUR_DIR_Z_PROP] = g_param_spec_float("current-orientation-z",
                                                   "current arrow orientation",
                                                   "orientation of the current arrow",
                                                   -G_MAXFLOAT, G_MAXFLOAT, 0.,
                                                   G_PARAM_READWRITE);
  g_object_class_install_property(G_OBJECT_CLASS(klass), CUR_DIR_Z_PROP,
				  properties[CUR_DIR_Z_PROP]);
}

static void visu_gl_ext_scale_init(VisuGlExtScale *obj)
{
  DBG_fprintf(stderr, "Scale: creating a new scale (%p).\n", (gpointer)obj);
  obj->priv = visu_gl_ext_scale_get_instance_private(obj);
  obj->priv->dispose_has_run = FALSE;
  obj->priv->arrows          = (GList*)0;
  obj->priv->iArr            = 0;
  obj->priv->view            = (VisuGlView*)0;
  obj->priv->view_signal     = 0;
  obj->priv->width = _width;
  obj->priv->rgba[0] = _rgba[0];
  obj->priv->rgba[1] = _rgba[1];
  obj->priv->rgba[2] = _rgba[2];
  obj->priv->rgba[3] = _rgba[3];
  obj->priv->stipple = _stipple;

  g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_SCALE_USED,
                          G_CALLBACK(onEntryUsed), (gpointer)obj, G_CONNECT_SWAPPED);
  g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_SCALE_COLOR,
                          G_CALLBACK(onEntryColor), (gpointer)obj, G_CONNECT_SWAPPED);
  g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_SCALE_LINE,
                          G_CALLBACK(onEntryWidth), (gpointer)obj, G_CONNECT_SWAPPED);
  g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_SCALE_STIPPLE,
                          G_CALLBACK(onEntryStipple), (gpointer)obj, G_CONNECT_SWAPPED);

  if (!defaultScale)
    defaultScale = obj;
}

/* This method can be called several times.
   It should unref all of its reference to
   GObjects. */
static void scale_dispose(GObject* obj)
{
  DBG_fprintf(stderr, "Scale: dispose object %p.\n", (gpointer)obj);

  if (VISU_GL_EXT_SCALE(obj)->priv->dispose_has_run)
    return;

  VISU_GL_EXT_SCALE(obj)->priv->dispose_has_run = TRUE;
  /* Chain up to the parent class */
  G_OBJECT_CLASS(visu_gl_ext_scale_parent_class)->dispose(obj);
}
/* This method is called once only. */
static void scale_finalize(GObject* obj)
{
  VisuGlExtScale *scale = VISU_GL_EXT_SCALE(obj);
  GList *lst;

  g_return_if_fail(obj);

  DBG_fprintf(stderr, "Scale: finalize object %p.\n", (gpointer)obj);

  /* Free my memory. */
  for (lst = scale->priv->arrows; lst; lst = g_list_next(lst))
    _freeArrow((Arrow*)lst->data);
  g_list_free(scale->priv->arrows);
  scale_setGlView(VISU_GL_EXT(scale), (VisuGlView*)0);

  /* Chain up to the parent class */
  G_OBJECT_CLASS(visu_gl_ext_scale_parent_class)->finalize(obj);
}
static void scale_get_property(GObject* obj, guint property_id,
                               GValue *value, GParamSpec *pspec)
{
  const gchar *lbl;
  float *arr;
  VisuGlExtScale *self = VISU_GL_EXT_SCALE(obj);

  DBG_fprintf(stderr, "Extension Scale: get property '%s' -> ",
	      g_param_spec_get_name(pspec));
  switch (property_id)
    {
    case COLOR_PROP:
      g_value_take_boxed(value, tool_color_new(self->priv->rgba));
      DBG_fprintf(stderr, "%gx%gx%g.\n", self->priv->rgba[0], self->priv->rgba[1], self->priv->rgba[2]);
      break;
    case WIDTH_PROP:
      g_value_set_float(value, self->priv->width);
      DBG_fprintf(stderr, "%g.\n", self->priv->width);
      break;
    case STIPPLE_PROP:
      g_value_set_uint(value, (guint)self->priv->stipple);
      DBG_fprintf(stderr, "%d.\n", (guint)self->priv->stipple);
      break;
    case N_ARR_PROP:
      g_value_set_uint(value, g_list_length(self->priv->arrows));
      DBG_fprintf(stderr, "%d.\n", g_list_length(self->priv->arrows));
      break;
    case CUR_PROP:
      g_value_set_uint(value, (guint)self->priv->iArr);
      DBG_fprintf(stderr, "%d.\n", (guint)self->priv->iArr);
      break;
    case CUR_LENGTH_PROP:
      g_value_set_float(value, visu_gl_ext_scale_getLength(self, self->priv->iArr));
      DBG_fprintf(stderr, "%g.\n", g_value_get_float(value));
      break;
    case CUR_LBL_PROP:
      lbl = visu_gl_ext_scale_getLegend(self, self->priv->iArr);
      if (lbl)
        g_value_set_string(value, lbl);
      else
        g_value_set_static_string(value, "");
      DBG_fprintf(stderr, "%s.\n", g_value_get_string(value));
      break;
    case CUR_ORIG_X_PROP:
    case CUR_ORIG_Y_PROP:
    case CUR_ORIG_Z_PROP:
      arr = visu_gl_ext_scale_getOrigin(self, self->priv->iArr);
      g_value_set_float(value, (arr) ? arr[property_id - CUR_ORIG_X_PROP] : 0.f);
      DBG_fprintf(stderr, "%g.\n", g_value_get_float(value));
      break;
    case CUR_DIR_X_PROP:
    case CUR_DIR_Y_PROP:
    case CUR_DIR_Z_PROP:
      arr = visu_gl_ext_scale_getOrientation(self, self->priv->iArr);
      g_value_set_float(value, (arr) ? arr[property_id - CUR_DIR_X_PROP] : 0.f);
      DBG_fprintf(stderr, "%g.\n", g_value_get_float(value));
      break;
    default:
      /* We don't have any other property... */
      G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
      break;
    }
}
static void scale_set_property(GObject* obj, guint property_id,
                               const GValue *value, GParamSpec *pspec)
{
  ToolColor *color;
  float arr[3];
  VisuGlExtScale *self = VISU_GL_EXT_SCALE(obj);
  gint mask[3] = {TOOL_XYZ_MASK_X, TOOL_XYZ_MASK_Y, TOOL_XYZ_MASK_Z };

  DBG_fprintf(stderr, "Extension Scale: set property '%s' -> ",
	      g_param_spec_get_name(pspec));
  switch (property_id)
    {
    case COLOR_PROP:
      color = (ToolColor*)g_value_get_boxed(value);
      _setRGB((VisuGlExtLined*)self, color->rgba, TOOL_COLOR_MASK_RGBA);
      DBG_fprintf(stderr, "%gx%gx%g.\n", self->priv->rgba[0], self->priv->rgba[1], self->priv->rgba[2]);
      break;
    case WIDTH_PROP:
      _setLineWidth((VisuGlExtLined*)self, g_value_get_float(value));
      DBG_fprintf(stderr, "%g.\n", self->priv->width);
      break;
    case STIPPLE_PROP:
      _setLineStipple((VisuGlExtLined*)self, (guint16)g_value_get_uint(value));
      DBG_fprintf(stderr, "%d.\n", (guint)self->priv->stipple);
      break;
    case CUR_PROP:
      self->priv->iArr = g_value_get_uint(value);
      DBG_fprintf(stderr, "%d.\n", (guint)self->priv->iArr);
      break;
    case CUR_LENGTH_PROP:
      visu_gl_ext_scale_setLength(self, self->priv->iArr, g_value_get_float(value));
      DBG_fprintf(stderr, "%g.\n", g_value_get_float(value));
      break;
    case CUR_LBL_PROP:
      visu_gl_ext_scale_setLegend(self, self->priv->iArr, g_value_get_string(value));
      DBG_fprintf(stderr, "%s.\n", g_value_get_string(value));
      break;
    case CUR_ORIG_X_PROP:
    case CUR_ORIG_Y_PROP:
    case CUR_ORIG_Z_PROP:
      arr[property_id - CUR_ORIG_X_PROP] = g_value_get_float(value);
      visu_gl_ext_scale_setOrigin(self, self->priv->iArr,
                                  arr, mask[property_id - CUR_ORIG_X_PROP]);
      DBG_fprintf(stderr, "%g.\n", arr[property_id - CUR_ORIG_X_PROP]);
      break;
    case CUR_DIR_X_PROP:
    case CUR_DIR_Y_PROP:
    case CUR_DIR_Z_PROP:
      arr[property_id - CUR_DIR_X_PROP] = g_value_get_float(value);
      visu_gl_ext_scale_setOrientation(self, self->priv->iArr,
                                       arr, mask[property_id - CUR_DIR_X_PROP]);
      DBG_fprintf(stderr, "%g.\n", arr[property_id - CUR_DIR_X_PROP]);
      break;
    default:
      /* We don't have any other property... */
      G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
      break;
    }
}

/**
 * visu_gl_ext_scale_new:
 * @name: (allow-none): a name for the #VisuGlExt.
 *
 * Create a new arrow set without any elements. Add arrows with visu_gl_ext_scale_add().
 *
 * Returns: a newly created #VisuGlExtScale object.
 *
 * Since: 3.3
 */
VisuGlExtScale* visu_gl_ext_scale_new(const gchar *name)
{
  char *name_ = "Scale";
  char *description = _("Draw scales in the rendering area.");
  VisuGlExt *scale;

  scale = VISU_GL_EXT(g_object_new(VISU_TYPE_GL_EXT_SCALE,
                                      "name", (name)?name:name_, "label", _(name),
                                      "description", description,
                                      "nGlObj", 1, "saveState", TRUE, NULL));

  return VISU_GL_EXT_SCALE(scale);
}
static gboolean scale_setGlView(VisuGlExt *ext, VisuGlView *view)
{
  VisuGlExtScalePrivate *priv = VISU_GL_EXT_SCALE(ext)->priv;

  if (view == priv->view)
    return FALSE;

  if (priv->view)
    {
      g_signal_handler_disconnect(G_OBJECT(priv->view), priv->view_signal);
      g_clear_object(&priv->view);
    }
  if (view)
    {
      priv->view = g_object_ref(view);
      priv->view_signal =
        g_signal_connect_swapped(G_OBJECT(view), "notify",
                                 G_CALLBACK(onScaleParametersChange), (gpointer)ext);
    }

  visu_gl_ext_setDirty(ext, TRUE);
  return TRUE;
}
/**
 * visu_gl_ext_scale_add:
 * @scale: the #VisuGlExtScale object to add to.
 * @origin: (array fixed-size=3): the origin ;
 * @orientation: (array fixed-size=3): the orientation in cartesian coordinates ;
 * @length: the length of the arrow ;
 * @legend: (allow-none): the text going with the arrow (can be NULL).
 *
 * Create a new arrow pointing somewhere in the box with a label.
 * If @legend is NULL, then the label will be the value of the length.
 *
 * Since: 3.7
 *
 * Returns: the id of the newly added arrow.
 */
guint visu_gl_ext_scale_add(VisuGlExtScale *scale, float origin[3], float orientation[3],
                            float length, const gchar *legend)
{
  Arrow *arr;

  g_return_val_if_fail(length > 0.f && VISU_IS_GL_EXT_SCALE(scale), 0);

  arr = g_malloc(sizeof(Arrow));
  arr->drawn     = TRUE;
  arr->origin[0] = origin[0];
  arr->origin[1] = origin[1];
  arr->origin[2] = origin[2];
  arr->direction[0] = orientation[0];
  arr->direction[1] = orientation[1];
  arr->direction[2] = orientation[2];
  arr->length = length;
  if (legend && strcmp(legend, SCALE_AUTO_LEGEND))
    arr->legendPattern = g_strdup(legend);
  else
    arr->legendPattern = (gchar*)0;
  arr->legend = g_string_new("");
  if (arr->legendPattern)
    g_string_assign(arr->legend, arr->legendPattern);
  else
    g_string_printf(arr->legend, SCALE_LEGEND_DEFAULT, arr->length);
  scale->priv->arrows = g_list_append(scale->priv->arrows, arr);

  if (scale->priv->iArr == g_list_length(scale->priv->arrows) - 1)
    {
      g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_LENGTH_PROP]);
      g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_LBL_PROP]);
      g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_ORIG_X_PROP]);
      g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_ORIG_Y_PROP]);
      g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_ORIG_Z_PROP]);
      g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_DIR_X_PROP]);
      g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_DIR_Y_PROP]);
      g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_DIR_Z_PROP]);
    }
  g_object_notify_by_pspec(G_OBJECT(scale), properties[N_ARR_PROP]);

  return g_list_length(scale->priv->arrows) - 1;
}

static void _freeArrow(Arrow *arr)
{
  if (arr->legendPattern)
    g_free(arr->legendPattern);
  g_string_free(arr->legend, TRUE);
  g_free(arr);
}

static gboolean _setRGB(VisuGlExtLined *scale, float rgba[4], int mask)
{
  VisuGlExtScalePrivate *self;
  g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), FALSE);
  self = VISU_GL_EXT_SCALE(scale)->priv;
  
  if (mask & TOOL_COLOR_MASK_R)
    self->rgba[0] = rgba[0];
  if (mask & TOOL_COLOR_MASK_G)
    self->rgba[1] = rgba[1];
  if (mask & TOOL_COLOR_MASK_B)
    self->rgba[2] = rgba[2];

  visu_gl_ext_setDirty(VISU_GL_EXT(scale), TRUE);
  return TRUE;
}
static gboolean _setLineWidth(VisuGlExtLined *scale, float width)
{
  VisuGlExtScalePrivate *self;
  g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), FALSE);
  self = VISU_GL_EXT_SCALE(scale)->priv;
  
  self->width = width;

  visu_gl_ext_setDirty(VISU_GL_EXT(scale), TRUE);
  return TRUE;
}
static gboolean _setLineStipple(VisuGlExtLined *scale, guint16 stipple)
{
  VisuGlExtScalePrivate *self;
  g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), FALSE);
  self = VISU_GL_EXT_SCALE(scale)->priv;

  self->stipple = stipple;

  visu_gl_ext_setDirty(VISU_GL_EXT(scale), TRUE);
  return TRUE;
}

/* Get methods. */
static float* _getRGB(const VisuGlExtLined *scale)
{
  g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), (float*)0);
  return ((VisuGlExtScale*)scale)->priv->rgba;
}
static float _getLineWidth(const VisuGlExtLined *scale)
{
  g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), 0.f);
  return ((VisuGlExtScale*)scale)->priv->width;
}
static guint16 _getLineStipple(const VisuGlExtLined *scale)
{
  g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), 0);
  return ((VisuGlExtScale*)scale)->priv->stipple;
}


/**
 * visu_gl_ext_scale_getNArrows:
 * @scale: the #VisuGlExtScale to poll.
 *
 * A #VisuGlExtScale is characterised by a set of arrows.
 *
 * Since: 3.7
 *
 * Returns: the number of stored arrows.
 */
guint visu_gl_ext_scale_getNArrows(VisuGlExtScale *scale)
{
  g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), 0);

  return g_list_length(scale->priv->arrows);
}
static Arrow* _ensureOneArrow(VisuGlExtScale *scale, guint i)
{
  GList *lst;
  float origin[3] = { 0.f, 0.f, 0.f };
  float orientation[3] = { 1.f, 0.f, 0.f };

  lst = g_list_nth(scale->priv->arrows, i);
  if (!lst && i == 0 && g_list_length(scale->priv->arrows) == 0)
    {
      visu_gl_ext_scale_add(scale, origin, orientation, 5.f, (const gchar*)0);
      lst = scale->priv->arrows;
    }
  g_return_val_if_fail(lst, (Arrow*)0);
  return (Arrow*)lst->data;
}
/**
 * visu_gl_ext_scale_getLength:
 * @scale: the #VisuGlExtScale to poll.
 * @i: the ith arrow.
 *
 * A #VisuGlExtScale is characterised by its length.
 *
 * Since: 3.3
 *
 * Returns: a positive floating point value or a negative value if @i
 * is not in the arrow list.
 */
float visu_gl_ext_scale_getLength(VisuGlExtScale *scale, guint i)
{
  GList *lst;

  g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), -1.f);

  lst = g_list_nth(scale->priv->arrows, i);
  return (lst) ? ((Arrow*)lst->data)->length : -1.f;
}
/**
 * visu_gl_ext_scale_getOrigin:
 * @scale: the #VisuGlExtScale to poll.
 * @i: the ith arrow.
 *
 * A #VisuGlExtScale is characterised by its origin in cartesian coordinates.
 *
 * Since: 3.3
 *
 * Returns: (array fixed-size=3) (transfer none) (allow-none): three
 * floating point values.
 */
float* visu_gl_ext_scale_getOrigin(VisuGlExtScale *scale, guint i)
{
  GList *lst;

  g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), (float*)0);

  lst = g_list_nth(scale->priv->arrows, i);
  if (lst)
    return ((Arrow*)lst->data)->origin;
  else
    return (float*)0;
}
/**
 * visu_gl_ext_scale_getOrientation:
 * @scale: the #VisuGlExtScale to poll.
 * @i: the ith arrow.
 *
 * A #VisuGlExtScale is characterised by its orientation in cartesian coordinates.
 *
 * Since: 3.3
 *
 * Returns: (array fixed-size=3) (transfer none) (allow-none): three
 * floating point values.
 */
float* visu_gl_ext_scale_getOrientation(VisuGlExtScale *scale, guint i)
{
  GList *lst;

  g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), (float*)0);

  lst = g_list_nth(scale->priv->arrows, i);
  if (lst)
    return ((Arrow*)lst->data)->direction;
  else
    return (float*)0;
}
/**
 * visu_gl_ext_scale_getLegend:
 * @scale: the #VisuGlExtScale to poll.
 * @i: the ith arrow.
 *
 * A #VisuGlExtScale can have a legend. This is not actualy the string printed
 * on screen but the one used to generate it.
 *
 * Since: 3.3
 *
 * Returns: (allow-none): a string (private, do not free it).
 */
const gchar* visu_gl_ext_scale_getLegend(VisuGlExtScale *scale, guint i)
{
  GList *lst;

  g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), (const gchar*)0);

  lst = g_list_nth(scale->priv->arrows, i);
  if (lst)
    return ((Arrow*)lst->data)->legendPattern;
  else
    return (const gchar*)0;
}

/**
 * visu_gl_ext_scale_setOrigin:
 * @scale: the #VisuGlExtScale to modify ;
 * @i: the ith arrow ;
 * @xyz: (array fixed-size=3): a vector in cartesian coordinates ;
 * @mask: relevant values in @xyz, see #TOOL_XYZ_MASK_X...
 *
 * Routine that changes the origin of the scale.
 *
 * Since: 3.3
 *
 * Returns: TRUE if the origin was actually changed.
 */
gboolean visu_gl_ext_scale_setOrigin(VisuGlExtScale *scale, guint i,
                                     float xyz[3], int mask)
{
  Arrow *arr;
  gboolean difference;

  g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), FALSE);

  arr = _ensureOneArrow(scale, i);
  if (!arr)
    return FALSE;

  difference = FALSE;
  g_object_freeze_notify(G_OBJECT(scale));
  if (mask & TOOL_XYZ_MASK_X && arr->origin[0] != xyz[0])
    {
      arr->origin[0] = xyz[0];
      difference = TRUE;
      g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_ORIG_X_PROP]);
    }
  if (mask & TOOL_XYZ_MASK_Y && arr->origin[1] != xyz[1])
    {
      arr->origin[1] = xyz[1];
      difference = TRUE;
      g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_ORIG_Y_PROP]);
    }
  if (mask & TOOL_XYZ_MASK_Z && arr->origin[2] != xyz[2])
    {
      arr->origin[2] = xyz[2];
      difference = TRUE;
      g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_ORIG_Z_PROP]);
    }
  if (difference)
    visu_gl_ext_setDirty(VISU_GL_EXT(scale), TRUE);
  g_object_thaw_notify(G_OBJECT(scale));

  return difference;
}

/**
 * visu_gl_ext_scale_setOrientation:
 * @scale: the #VisuGlExtScale to modify ;
 * @i: the ith arrow ;
 * @xyz: (array fixed-size=3): a vector in cartesian coordinates ;
 * @mask: relevant values in @xyz, see #TOOL_XYZ_MASK_X...
 *
 * Routine that changes the direction of the scale.
 *
 * Since: 3.3
 *
 * Returns: TRUE if the orientation was actually changed.
 */
gboolean visu_gl_ext_scale_setOrientation(VisuGlExtScale *scale, guint i,
                                          float xyz[3], int mask)
{
  Arrow *arr;
  gboolean difference;

  g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), FALSE);

  arr = _ensureOneArrow(scale, i);
  if (!arr)
    return FALSE;

  difference = FALSE;
  g_object_freeze_notify(G_OBJECT(scale));
  if (mask & TOOL_XYZ_MASK_X && arr->direction[0] != xyz[0])
    {
      arr->direction[0] = xyz[0];
      difference = TRUE;
      g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_ORIG_X_PROP]);
    }
  if (mask & TOOL_XYZ_MASK_Y && arr->direction[1] != xyz[1])
    {
      arr->direction[1] = xyz[1];
      difference = TRUE;
      g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_ORIG_Y_PROP]);
    }
  if (mask & TOOL_XYZ_MASK_Z && arr->direction[2] != xyz[2])
    {
      arr->direction[2] = xyz[2];
      difference = TRUE;
      g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_ORIG_Z_PROP]);
    }
  if (difference)
    visu_gl_ext_setDirty(VISU_GL_EXT(scale), TRUE);
  g_object_thaw_notify(G_OBJECT(scale));

  return difference;
}
static void _updateLbl(Arrow *arr)
{
  g_return_if_fail(arr);

  if (arr->legendPattern)
    g_string_assign(arr->legend, arr->legendPattern);
  else
    g_string_printf(arr->legend, SCALE_LEGEND_DEFAULT, arr->length);
}
/**
 * visu_gl_ext_scale_setLength:
 * @scale: the #VisuGlExtScale to modify ;
 * @i: the ith arrow ;
 * @lg: a positive length.
 *
 * Routine that changes the length of the scale. If @i is zero and
 * @scale has currently no arrow, a default one is created.
 *
 * Since: 3.3
 *
 * Returns: TRUE if the length was actually changed.
 */
gboolean visu_gl_ext_scale_setLength(VisuGlExtScale *scale, guint i, float lg)
{
  Arrow *arr;

  g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), FALSE);

  arr = _ensureOneArrow(scale, i);
  if (!arr || lg == arr->length)
    return FALSE;

  arr->length = lg;
  _updateLbl(arr);

  visu_gl_ext_setDirty(VISU_GL_EXT(scale), TRUE);
  g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_LENGTH_PROP]);
  return TRUE;
}
/**
 * visu_gl_ext_scale_setLegend:
 * @scale: the #VisuGlExtScale to modify ;
 * @i: the ith arrow ;
 * @value: (allow-none): a string (can be NULL).
 *
 * Routine that changes the legend of the scale. If @value is NULL
 * then the length of the scale is printed.
 *
 * Since: 3.3
 *
 * Returns: TRUE if the legend was actually changed.
 */
gboolean visu_gl_ext_scale_setLegend(VisuGlExtScale *scale, guint i, const gchar *value)
{
  Arrow *arr;

  g_return_val_if_fail(VISU_IS_GL_EXT_SCALE(scale), FALSE);

  arr = _ensureOneArrow(scale, i);
  if (!arr)
    return FALSE;
  
  g_free(arr->legendPattern);

  if (value && *g_strstrip((gchar*)value))
    arr->legendPattern = g_strdup(value);
  else
    arr->legendPattern = (gchar*)0;
  _updateLbl(arr);

  visu_gl_ext_setDirty(VISU_GL_EXT(scale), TRUE);
  g_object_notify_by_pspec(G_OBJECT(scale), properties[CUR_LBL_PROP]);
  return TRUE;
}

/****************/
/* Private part */
/****************/

static void scale_rebuild(VisuGlExt *ext)
{
  visu_gl_text_rebuildFontList();
  visu_gl_ext_setDirty(ext, TRUE);
  scale_draw(ext);
}
static void onScaleParametersChange(VisuGlExtScale *scale)
{
  visu_gl_ext_setDirty(VISU_GL_EXT(scale), TRUE);
}
static void onEntryUsed(VisuGlExtScale *scale, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_)
{
  visu_gl_ext_setActive(VISU_GL_EXT(scale), defaultUsed);
}
static void onEntryColor(VisuGlExtScale *scale, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_)
{
  visu_gl_ext_lined_setRGBA(VISU_GL_EXT_LINED(scale), _rgba, TOOL_COLOR_MASK_RGBA);
}
static void onEntryWidth(VisuGlExtScale *scale, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_)
{
  visu_gl_ext_lined_setWidth(VISU_GL_EXT_LINED(scale), _width);
}
static void onEntryStipple(VisuGlExtScale *scale, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_)
{
  visu_gl_ext_lined_setStipple(VISU_GL_EXT_LINED(scale), _stipple);
}

/**
 * visu_gl_ext_scale_draw:
 * @scale: the #VisuGlExtScale object to draw.
 *
 * This method creates a compile list that draw all arrow of a scale.
 *
 * Since: 3.3
 */
static void scale_draw(VisuGlExt *ext)
{
  GList *tmpLst;
  int nlat;
  float radius = 0.3;
  VisuGlExtScale *scale;

  g_return_if_fail(VISU_IS_GL_EXT_SCALE(ext));
  scale = VISU_GL_EXT_SCALE(ext);

  /* Nothing to draw; */
  if(!scale->priv->view) return;

  DBG_fprintf(stderr, "Extension Scale: creating scales.\n");

  visu_gl_text_initFontList();
  nlat = visu_gl_view_getDetailLevel(scale->priv->view, radius);
  
  glDeleteLists(visu_gl_ext_getGlList(VISU_GL_EXT(scale)), 1);
  visu_gl_ext_startDrawing(ext);

  /* Deactivate light and fog. */
  glDisable(GL_LIGHTING);
  glDisable(GL_FOG);

  glLineWidth(scale->priv->width);
  glColor4fv(scale->priv->rgba);
  if (scale->priv->stipple != 65535)
    {
      glEnable(GL_LINE_STIPPLE);
      glLineStipple(1, scale->priv->stipple);
    }

  for (tmpLst = scale->priv->arrows; tmpLst; tmpLst = g_list_next(tmpLst))
    _drawArrow((Arrow*)tmpLst->data, nlat);

  if (scale->priv->stipple != 65535)
    glDisable(GL_LINE_STIPPLE);

  visu_gl_ext_completeDrawing(ext);
}
/* fonction qui dessine la legende*/
static void _drawArrow(Arrow *arr, guint nlat)
{
  float x2,y2,z2, norm;
  float angles[3]; /*declaration des tableaux angles et coordonnÃ©es a 3 cellules*/
  float coord[3], u, v, s;
  float radius = 0.3 * (0.25f * log(_width) + 1.f);
  float tl = 1.f;
  GLUquadricObj *obj;
  float modelView[16];

  obj = gluNewQuadric();

  norm = (arr->length - tl) / sqrt(arr->direction[0] * arr->direction[0] +
                                   arr->direction[1] * arr->direction[1] +
                                   arr->direction[2] * arr->direction[2]);
  x2 = arr->origin[0] + arr->direction[0] * norm;
  y2 = arr->origin[1] + arr->direction[1] * norm;
  z2 = arr->origin[2] + arr->direction[2] * norm;

  coord[0] = x2 - arr->origin[0];
  coord[1] = y2 - arr->origin[1];
  coord[2] = z2 - arr->origin[2];

  tool_matrix_cartesianToSpherical(angles, coord);

  glPushMatrix();
  glTranslated(arr->origin[0], arr->origin[1], arr->origin[2]);
  glRotated(angles[2], 0., 0., 1.);
  glRotated(angles[1], 0., 1., 0.);
  glTranslated(0., 0., angles[0]);
  gluCylinder(obj, radius, 0., tl, nlat, 1);
  glRotated(180., 1., 0., 0.);
  gluDisk(obj, 0, radius, nlat, 1);
  glPopMatrix();

  glBegin (GL_LINES);
  glVertex3fv(arr->origin);
  glVertex3f(x2, y2, z2);
  glEnd();

  glGetFloatv(GL_MODELVIEW_MATRIX, modelView);
  v = -(coord[0] * modelView[0] + coord[1] * modelView[4] + coord[2] * modelView[8]);
  u = +(coord[0] * modelView[1] + coord[1] * modelView[5] + coord[2] * modelView[9]);
  s = (v < 0.f)?0.25f:0.75f;
  if (v > 0.f)
    {
      u *= -1.f;
      v *= -1.f;
    }
  coord[0] = arr->origin[0] + s * arr->direction[0] * norm;
  coord[1] = arr->origin[1] + s * arr->direction[1] * norm;
  coord[2] = arr->origin[2] + s * arr->direction[2] * norm;
  norm = 1.f / sqrt(u * u + v * v) * radius * 2.f;
  coord[0] += (u * modelView[0] + v * modelView[1]) * norm;
  coord[1] += (u * modelView[4] + v * modelView[5]) * norm;
  coord[2] += (u * modelView[8] + v * modelView[9]) * norm;
  glRasterPos3fv(coord);
  visu_gl_text_drawChars(arr->legend->str, VISU_GL_TEXT_NORMAL);

  gluDeleteQuadric(obj);
}

/* Parameters & resources*/
/* Export function that is called by visu_module to write the
   values of resources to a file. */
static void exportResourcesScale(GString *data,
                                 VisuData *dataObj _U_)
{
  GList *tmpLst;
  Arrow *arr;
  gchar *legend;

  if (!defaultScale)
    return;

  visu_config_file_exportComment(data, DESC_RESOURCE_SCALE_USED);
  visu_config_file_exportEntry(data, FLAG_RESOURCE_SCALE_USED, NULL,
                               "%d", visu_gl_ext_getActive(VISU_GL_EXT(defaultScale)));

  visu_config_file_exportComment(data, DESC_RESOURCE_SCALE_COLOR);
  visu_config_file_exportEntry(data, FLAG_RESOURCE_SCALE_COLOR, NULL,
                               "%4.3f %4.3f %4.3f %4.3f",
                               defaultScale->priv->rgba[0], defaultScale->priv->rgba[1],
                               defaultScale->priv->rgba[2], defaultScale->priv->rgba[3]);

  visu_config_file_exportComment(data, DESC_RESOURCE_SCALE_LINE);
  visu_config_file_exportEntry(data, FLAG_RESOURCE_SCALE_LINE, NULL,
                               "%4.0f", defaultScale->priv->width);

  visu_config_file_exportComment(data, DESC_RESOURCE_SCALE_STIPPLE);
  visu_config_file_exportEntry(data, FLAG_RESOURCE_SCALE_STIPPLE, NULL,
                               "%d", defaultScale->priv->stipple);

  visu_config_file_exportComment(data, DESC_RESOURCE_SCALE_DEFINITION);
  for (tmpLst = defaultScale->priv->arrows; tmpLst; tmpLst = g_list_next(tmpLst))
    {
      arr = (Arrow*)tmpLst->data;
      if (arr->legendPattern)
	legend = arr->legendPattern;
      else
	legend = SCALE_AUTO_LEGEND;
      visu_config_file_exportEntry(data, FLAG_RESOURCE_SCALE_DEFINITION, NULL,
                                   "%g %g %g  %g %g %g  %g  %s",
                                   arr->origin[0], arr->origin[1], arr->origin[2],
                                   arr->direction[0], arr->direction[1],
                                   arr->direction[2], arr->length, legend);
    }
  visu_config_file_exportComment(data, "");
}
