// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.

#ifndef tools_sg_plotter
#define tools_sg_plotter

#include "../lina/vec2f"

#include "render_action"
#include "plottables"
#include "style"
#include "rep"
#include "colormap"
#include "noderef"
#include "atb_vertices"
#include "cube" //for lego
#include "matrix"
#include "normal"
#include "holder"
#include "tex_rect" //for plottable_img.

#include "axis"
#include "infos_box"
#include "legend"
#include "text"
#include "torche"
#include "ellipse"

#include "../data_axis"
#include "../hatcher"
#include "../clist_contour"
#include "../tess_contour"
#include "../lina/geom3"
#include "../spline"
#include "../rtausmef"

//#define INLIBS_SG_PLOTTER_TIMING
#ifdef INLIBS_SG_PLOTTER_TIMING
#include "../sys/atime"
#endif

#include <utility>

namespace tools {
namespace sg {

class plotter : public node {
  TOOLS_NODE(plotter,tools::sg::plotter,node)
private:
  static const std::string& s_infos_what_def() {
    static const std::string s_v("name entries mean rms fit_quality fit_ndf fit_parameters fit_errors");
    return s_v;
  }
  static float default_infos_margin() {return 0.005f;}
  static float default_title_box_width()    {return 0.3f;}
  static float default_title_box_height()   {return 0.05f;}
  static float default_title_box_x_margin() {return 0.01f;}
  static float default_title_box_y_margin() {return 0.005f;}
public:
  sf<float> width;          //PAW XSIZ
  sf<float> height;         //PAW YSIZ
  sf<float> left_margin;    //PAW XMGL
  sf<float> right_margin;   //PAW XMGR
  sf<float> bottom_margin;  //PAW YMGL
  sf<float> top_margin;     //PAW YMGU

  sf<float> depth;
  sf<float> down_margin;
  sf<float> up_margin;

  sf<bool> title_up;
  sf<float> title_to_axis;
  sf<float> title_height;
  sf<bool> title_automated;
  sf_enum<hjust> title_hjust;
  sf_string title; //output if title_automated.

  sf<bool> colormap_visible;
  enum colormap_axis_labeling_type {
    cells = 0,
    min_max
  };
  sf_enum<colormap_axis_labeling_type> colormap_axis_labeling;
  sf<bool> colormap_attached;
  sf<bool> colormap_axis_visible;

  // Wanted axes parameters.
  // They are not necessary realized on the sg::axis nodes.
  sf<bool> x_axis_enforced;
  sf<bool> x_axis_automated;
  sf<float> x_axis_min;
  sf<float> x_axis_max;
  sf<bool> x_axis_is_log;

  sf<bool> y_axis_enforced;
  sf<bool> y_axis_automated;
  sf<float> y_axis_min;
  sf<float> y_axis_max;
  sf<bool> y_axis_is_log;

  sf<bool> z_axis_enforced;
  sf<bool> z_axis_automated;
  sf<float> z_axis_min;
  sf<float> z_axis_max;
  sf<bool> z_axis_is_log;

  sf<float> value_top_margin;
  sf<float> value_bottom_margin;
  sf<bool> value_bins_with_entries;

  sf<float> infos_width; //in percent of width.
  sf<float> infos_x_margin; //in percent of width. From right.
  sf<float> infos_y_margin; //in percent of height. From top.
  sf_string infos_what;

  sf<float> title_box_width;    //in percent of width.
  sf<float> title_box_height;   //in percent of height.
  sf<float> title_box_x_margin; //in percent of width. From left.
  sf<float> title_box_y_margin; //in percent of height. From top.

  sf<bool> func2D_borders_visible;

  // used with shape xyz
  sf<float> theta;  //in degrees.
  sf<float> phi;    //in degrees.
  sf<float> tau;    //in degrees.

  ////////////////////////////////////////////////////////////////
  /// legend related :////////////////////////////////////////////
  ////////////////////////////////////////////////////////////////
  sf<bool> legends_automated;
  //sf<bool> legends_attached_to_infos;
  //if legends_attached_to_infos is false :
  //  legends_origin is used to place the legends. It is then
  //  the lower left corner of the box containing all legends.
  mf_vec<vec2f,float> legends_origin; //common origin of legend boxes.
  enum unit_type {
    unit_percent,
    unit_axis
  };
  mf_enum<unit_type> legends_origin_unit;
  mf_vec<vec2f,float> legends_size; //overall legend boxes size.
  mf_string legends_string;

  ////////////////////////////////////////////////////////////////
  ////////////////////////////////////////////////////////////////
  ////////////////////////////////////////////////////////////////

  sf<bool> shape_automated;

  enum shape_type {
    xy = 0,
    xyz
  };
  sf_enum<shape_type> shape;

  // used with xy shape :
  sf<float> xy_depth; //all is in z [0,xy_depth]

  sf<unsigned int> curve_number_of_points;

  sf<bool> data_light_on_automated;

  // for gopaw :
  sf<bool> primitives_enforced;
  sf<bool> inner_frame_enforced;
  // to be implemented :
  sf<bool> top_axis_visible;
  sf<bool> right_axis_visible;
  sf<bool> superpose_bins;
  //sf<bool> grid_visible;
  // For contours :
  sf<unsigned int> number_of_levels;
  mf<float> levels;
  //sf<bool> frozen;
  //sf<float> ttfScale;
  //sf<bool> wallEnforced;
  //sf<bool> gridEnforced;
  //SoMFString infos; //Output
  //SoMFString legend; //Output

public:
  virtual const desc_fields& node_desc_fields() const {
    TOOLS_FIELD_DESC_NODE_CLASS(tools::sg::plotter)
    static const desc_fields s_v(parent::node_desc_fields(),63, //WARNING : take care of count.

      TOOLS_ARG_FIELD_DESC(width),
      TOOLS_ARG_FIELD_DESC(height),
      TOOLS_ARG_FIELD_DESC(left_margin),
      TOOLS_ARG_FIELD_DESC(right_margin),
      TOOLS_ARG_FIELD_DESC(bottom_margin),
      TOOLS_ARG_FIELD_DESC(top_margin),
      TOOLS_ARG_FIELD_DESC(depth),
      TOOLS_ARG_FIELD_DESC(down_margin),
      TOOLS_ARG_FIELD_DESC(up_margin),
      TOOLS_ARG_FIELD_DESC(colormap_visible),  //10

      TOOLS_ARG_FIELD_DESC_ENUMS_BEG(colormap_axis_labeling,2)
        TOOLS_ARG_ENUM(cells),
        TOOLS_ARG_ENUM(min_max)
      TOOLS_ARG_FIELD_DESC_ENUMS_END,

      TOOLS_ARG_FIELD_DESC(colormap_attached),
      TOOLS_ARG_FIELD_DESC(colormap_axis_visible),

      TOOLS_ARG_FIELD_DESC(title_up),
      TOOLS_ARG_FIELD_DESC(title_to_axis),
      TOOLS_ARG_FIELD_DESC(title_height),
      TOOLS_ARG_FIELD_DESC(title_automated),

      TOOLS_ARG_FIELD_DESC_ENUMS_BEG(title_hjust,3)
        "left",left,
        "center",center,
        "right",right
      TOOLS_ARG_FIELD_DESC_ENUMS_END,

      TOOLS_ARG_FIELD_DESC(title),

      TOOLS_ARG_FIELD_DESC(x_axis_enforced),  //20
      TOOLS_ARG_FIELD_DESC(x_axis_automated),
      TOOLS_ARG_FIELD_DESC(x_axis_min),
      TOOLS_ARG_FIELD_DESC(x_axis_max),
      TOOLS_ARG_FIELD_DESC(x_axis_is_log),

      TOOLS_ARG_FIELD_DESC(y_axis_enforced),
      TOOLS_ARG_FIELD_DESC(y_axis_automated),
      TOOLS_ARG_FIELD_DESC(y_axis_min),
      TOOLS_ARG_FIELD_DESC(y_axis_max),
      TOOLS_ARG_FIELD_DESC(y_axis_is_log),

      TOOLS_ARG_FIELD_DESC(z_axis_enforced),  //30
      TOOLS_ARG_FIELD_DESC(z_axis_automated),
      TOOLS_ARG_FIELD_DESC(z_axis_min),
      TOOLS_ARG_FIELD_DESC(z_axis_max),
      TOOLS_ARG_FIELD_DESC(z_axis_is_log),

      TOOLS_ARG_FIELD_DESC(value_top_margin),
      TOOLS_ARG_FIELD_DESC(value_bottom_margin),
      TOOLS_ARG_FIELD_DESC(value_bins_with_entries),

      TOOLS_ARG_FIELD_DESC(infos_width),
      TOOLS_ARG_FIELD_DESC(infos_x_margin),
      TOOLS_ARG_FIELD_DESC(infos_y_margin), //40
      TOOLS_ARG_FIELD_DESC(infos_what),

      TOOLS_ARG_FIELD_DESC(func2D_borders_visible),
      TOOLS_ARG_FIELD_DESC(theta),
      TOOLS_ARG_FIELD_DESC(phi),
      TOOLS_ARG_FIELD_DESC(tau),

      TOOLS_ARG_FIELD_DESC(legends_automated),

      TOOLS_ARG_FIELD_DESC_ENUMS_BEG(legends_origin,2)
        "unit_percent",unit_percent,
        "unit_axis",unit_axis
      TOOLS_ARG_FIELD_DESC_ENUMS_END,

      TOOLS_ARG_FIELD_DESC(legends_origin_unit),
      TOOLS_ARG_FIELD_DESC(legends_size),
      TOOLS_ARG_FIELD_DESC(legends_string), //50

      TOOLS_ARG_FIELD_DESC(shape_automated),

      TOOLS_ARG_FIELD_DESC_ENUMS_BEG(shape,2)
        "xy",xy,
        "xyz",xyz
      TOOLS_ARG_FIELD_DESC_ENUMS_END,

      TOOLS_ARG_FIELD_DESC(xy_depth),
      TOOLS_ARG_FIELD_DESC(curve_number_of_points),

      TOOLS_ARG_FIELD_DESC(number_of_levels),
      TOOLS_ARG_FIELD_DESC(levels),

      TOOLS_ARG_FIELD_DESC(data_light_on_automated),

      TOOLS_ARG_FIELD_DESC(primitives_enforced),
      TOOLS_ARG_FIELD_DESC(inner_frame_enforced),

      TOOLS_ARG_FIELD_DESC(title_box_width), //60
      TOOLS_ARG_FIELD_DESC(title_box_height),
      TOOLS_ARG_FIELD_DESC(title_box_x_margin),
      TOOLS_ARG_FIELD_DESC(title_box_y_margin)   //63

    );
    return s_v;
  }
  virtual bool touched() {
    if(parent::touched()) return true;

    if(background_style().touched()) return true;
    if(title_style().touched()) return true;
    if(infos_style().touched()) return true;
    if(title_box_style().touched()) return true;
    if(inner_frame_style().touched()) return true;
    if(grid_style().touched()) return true;
    if(wall_style().touched()) return true;

   {tools_vforit(style,m_bins_style,it) {if((*it).touched()) return true;}}
   {tools_vforit(style,m_errors_style,it) {if((*it).touched()) return true;}}
   {tools_vforit(style,m_func_style,it) {if((*it).touched()) return true;}}
   {tools_vforit(style,m_points_style,it) {if((*it).touched()) return true;}}
   {tools_vforit(style,m_left_hatch_style,it) {if((*it).touched()) return true;}}
   {tools_vforit(style,m_right_hatch_style,it) {if((*it).touched()) return true;}}
   {tools_vforit(style,m_legend_style,it) {if((*it).touched()) return true;}}

    return false;
  }
  virtual void reset_touched() {
    parent::reset_touched();

    background_style().reset_touched();
    title_style().reset_touched();
    infos_style().reset_touched();
    title_box_style().reset_touched();
    inner_frame_style().reset_touched();
    grid_style().reset_touched();
    wall_style().reset_touched();

   {tools_vforit(style,m_bins_style,it) (*it).reset_touched();}
   {tools_vforit(style,m_errors_style,it) (*it).reset_touched();}
   {tools_vforit(style,m_func_style,it) (*it).reset_touched();}
   {tools_vforit(style,m_points_style,it) (*it).reset_touched();}
   {tools_vforit(style,m_left_hatch_style,it) (*it).reset_touched();}
   {tools_vforit(style,m_right_hatch_style,it) (*it).reset_touched();}
   {tools_vforit(style,m_legend_style,it) (*it).reset_touched();}
  }

private:
  void add_fields(){
    // if adding a field, look for reset_style(), set_from_style() and set_from_string()
    add_field(&width);
    add_field(&height);
    add_field(&left_margin);
    add_field(&right_margin);
    add_field(&bottom_margin);
    add_field(&top_margin);
    add_field(&depth);
    add_field(&down_margin);
    add_field(&up_margin);

    add_field(&title_up);
    add_field(&title_to_axis);
    add_field(&title_height);
    add_field(&title_automated);
    add_field(&title_hjust);
    add_field(&title);

    add_field(&x_axis_enforced);
    add_field(&x_axis_automated);
    add_field(&x_axis_min);
    add_field(&x_axis_max);
    add_field(&x_axis_is_log);

    add_field(&y_axis_enforced);
    add_field(&y_axis_automated);
    add_field(&y_axis_min);
    add_field(&y_axis_max);
    add_field(&y_axis_is_log);

    add_field(&z_axis_enforced);
    add_field(&z_axis_automated);
    add_field(&z_axis_min);
    add_field(&z_axis_max);
    add_field(&z_axis_is_log);

    add_field(&value_top_margin);
    add_field(&value_bottom_margin);
    add_field(&value_bins_with_entries);

    add_field(&infos_width);
    add_field(&infos_x_margin);
    add_field(&infos_y_margin);
    add_field(&infos_what);

    add_field(&title_box_width);
    add_field(&title_box_height);
    add_field(&title_box_x_margin);
    add_field(&title_box_y_margin);

    add_field(&func2D_borders_visible);
    add_field(&theta);
    add_field(&phi);
    add_field(&tau);

    add_field(&legends_automated);
    //add_field(&legends_attached_to_infos);
    add_field(&legends_origin);
    add_field(&legends_origin_unit);
    add_field(&legends_size);
    add_field(&legends_string);

    add_field(&shape_automated);
    add_field(&shape);

    add_field(&xy_depth);
    add_field(&curve_number_of_points);
    add_field(&number_of_levels);
    add_field(&levels);
    add_field(&data_light_on_automated);
    add_field(&primitives_enforced);
    add_field(&inner_frame_enforced);
  }
public: //style
  void copy_style(const plotter& a_from) {  //used in sg::plots.
    ////////////////////////////////////////////
    ////////////////////////////////////////////
    ////////////////////////////////////////////
    shape_automated = a_from.shape_automated;
    shape = a_from.shape;
    xy_depth = a_from.xy_depth;
    curve_number_of_points = a_from.curve_number_of_points;
    value_top_margin = a_from.value_top_margin;
    value_bottom_margin = a_from.value_bottom_margin;
    value_bins_with_entries = a_from.value_bins_with_entries;
    infos_what = a_from.infos_what;
    infos_width = a_from.infos_width;
    //infos height is automatic.
    infos_x_margin = a_from.infos_x_margin;
    infos_y_margin = a_from.infos_y_margin;

    title_box_width = a_from.title_box_width;
    title_box_height = a_from.title_box_height;
    title_box_x_margin = a_from.title_box_x_margin;
    title_box_y_margin = a_from.title_box_y_margin;

    legends_automated = a_from.legends_automated;
    title_automated = a_from.title_automated;
    title = a_from.title;
    title_up = a_from.title_up;
    title_hjust = a_from.title_hjust;

    colormap_visible = a_from.colormap_visible;
    colormap_axis_labeling = a_from.colormap_axis_labeling;
    colormap_attached = a_from.colormap_attached;
    colormap_axis_visible = a_from.colormap_axis_visible;

    number_of_levels = a_from.number_of_levels;
    levels  = a_from.levels;
    data_light_on_automated = a_from.data_light_on_automated;
    primitives_enforced = a_from.primitives_enforced;
    inner_frame_enforced = a_from.inner_frame_enforced;

    ////////////////////////////////////////////
    ////////////////////////////////////////////
    ////////////////////////////////////////////
    x_axis_enforced = a_from.x_axis_enforced;
    x_axis_automated = a_from.x_axis_automated;
    x_axis_min = a_from.x_axis_min;
    x_axis_max = a_from.x_axis_max;
    x_axis_is_log = a_from.x_axis_is_log;

    y_axis_enforced = a_from.y_axis_enforced;
    y_axis_automated = a_from.y_axis_automated;
    y_axis_min = a_from.y_axis_min;
    y_axis_max = a_from.y_axis_max;
    y_axis_is_log = a_from.y_axis_is_log;

    z_axis_enforced = a_from.z_axis_enforced;
    z_axis_automated = a_from.z_axis_automated;
    z_axis_min = a_from.z_axis_min;
    z_axis_max = a_from.z_axis_max;
    z_axis_is_log = a_from.z_axis_is_log;

    /*
    m_x_axis = a_from.m_x_axis;
    m_y_axis = a_from.m_y_axis;
    m_z_axis = a_from.m_z_axis;
    m_cmap_axis = a_from.m_cmap_axis;

    */
    ////////////////////////////////////////////
    ////////////////////////////////////////////
    ////////////////////////////////////////////

    m_background_style = a_from.m_background_style;
    m_title_style = a_from.m_title_style;
    m_infos_style = a_from.m_infos_style;
    m_title_box_style = a_from.m_title_box_style;
    m_inner_frame_style = a_from.m_inner_frame_style;
    m_grid_style = a_from.m_grid_style;
    m_wall_style = a_from.m_wall_style;

    m_bins_style = a_from.m_bins_style;
    m_errors_style = a_from.m_errors_style;
    m_func_style = a_from.m_func_style;
    m_points_style = a_from.m_points_style;
    m_left_hatch_style = a_from.m_left_hatch_style;
    m_right_hatch_style = a_from.m_right_hatch_style;
    m_legend_style = a_from.m_legend_style;
  }

  void reset_style(bool a_geom = false) {
    //reset fields that are considered as part of the style.

    //::printf("debug : tools::sg::plotter::reset_style :\n");

    shape_automated = true;
    shape = xy;

    xy_depth = 0.01f;
    curve_number_of_points = 100;
    ////////////////////////////////////////////
    value_top_margin = 0.1f; //percent.  // CERN-PAW seems to have 0.1F and CERN-ROOT 0.05F.
    value_bottom_margin = 0.0f; //percent.
    value_bins_with_entries = true; //gopaw uses false.

    infos_what = s_infos_what_def();
    infos_width = 0.3f;
    //infos height is automatic.
    infos_x_margin = default_infos_margin(); //percent of width
    infos_y_margin = default_infos_margin(); //percent of height

    title_box_width = default_title_box_width();
    title_box_height = default_title_box_height();
    title_box_x_margin = default_title_box_x_margin(); //percent of width
    title_box_y_margin = default_title_box_y_margin(); //percent of height

    legends_automated = true;

    ////////////////////////////////////////////

    if(a_geom) {
    float xfac = 1.0F/20.0F; //0.05
    float yfac = 1.0F/20.0F; //0.05

    // Take PAW defaults :
    float XSIZ = 20 * xfac;    //1     //page width
    float YSIZ = 20 * yfac;    //1     //page height
    float XMGL = 2 * xfac;     //0.1   //left x margin (to data frame).
    float XMGR = 2 * xfac;     //0.1   //right y margin (to data frame).
    float YMGL = 2 * yfac;     //0.1   //low y margin (to data frame).
    float YMGU = 2 * yfac;     //0.1   //up y margin (to data frame).
    // Axes :
    float VSIZ = 0.28F * yfac; //0.014 //tick label character size.
    float XVAL = 0.4F * xfac;  //0.02 //x distance of y tick label to data frame.
    float YVAL = 0.4F * yfac;  //0.02 //y distance of x tick label to data frame.
    float XTIC = 0.3F * yfac;  //0.015 //y length of X axis ticks.
    float YTIC = 0.3F * xfac;  //0.015 //x length of Y axis ticks.
    float XLAB = 1.4F * xfac;  //0.07  //x distance of y title to data frame.
    float YLAB = 0.8F * yfac;  //0.04  //y distance of x title to data frame.
    float ASIZ = 0.28F * yfac; //0.014 // axis title (label) character size.

    float YHTI = 1.2F * yfac;  //0.06  //y distance of title to x axis.
    float TSIZ = 0.28F * yfac; //0.014 //title character size

    float zfac = 1.0F/20.0F; //0.05
    float ZSIZ = 20 * zfac;    //1     //page depth
    float ZMGD = 2 * zfac;     //0.1   //low y margin (to data frame).
    float ZMGU = 2 * zfac;     //0.1   //up y margin (to data frame).

    // Data area :
    //float wData = XSIZ-XMGL-XMGR;
    //float hData = YSIZ-YMGL-YMGU;
    //float dData = ZSIZ-ZMGD-ZMGU;

    width = XSIZ;
    height = YSIZ;
    depth = ZSIZ;

    left_margin = XMGL;
    right_margin = XMGR;
    bottom_margin = YMGL;
    top_margin = YMGU;
    down_margin = ZMGD;
    up_margin = ZMGU;

    title_to_axis = YHTI;
    title_height = TSIZ;

    if(shape.value()==xy) {
      m_x_axis.tick_length.value(XTIC);
      m_x_axis.label_to_axis.value(YVAL);
      m_x_axis.label_height.value(VSIZ);
      m_x_axis.title_to_axis.value(YLAB);
      m_x_axis.title_height.value(ASIZ);

      m_y_axis.tick_length.value(YTIC);
      m_y_axis.label_to_axis.value(XVAL);
      m_y_axis.label_height.value(VSIZ);
      m_y_axis.title_to_axis.value(XLAB);
      m_y_axis.title_height.value(ASIZ);

      //set anyway z axis :
      //m_z_axis.tick_length.value(YTIC);
      //m_z_axis.label_to_axis.value(XVAL);
      //m_z_axis.label_height.value(VSIZ);
      //m_z_axis.title_to_axis.value(XLAB);
      //m_z_axis.title_height.value(ASIZ);

      m_cmap_axis.tick_length.value(YTIC);
      m_cmap_axis.label_to_axis.value(XVAL);
      m_cmap_axis.label_height.value(VSIZ);
      m_cmap_axis.title_to_axis.value(XLAB);
      m_cmap_axis.title_height.value(ASIZ);

    } else { //xyz
      m_x_axis.tick_length.value(XTIC);
      m_x_axis.label_to_axis.value(YVAL);
      m_x_axis.label_height.value(VSIZ);
      m_x_axis.title_to_axis.value(YLAB);
      m_x_axis.title_height.value(ASIZ);

      m_y_axis.tick_length.value(XTIC);
      m_y_axis.label_to_axis.value(YVAL);
      m_y_axis.label_height.value(VSIZ);
      m_y_axis.title_to_axis.value(YLAB);
      m_y_axis.title_height.value(ASIZ);

      m_z_axis.tick_length.value(YTIC);
      m_z_axis.label_to_axis.value(XVAL);
      m_z_axis.label_height.value(VSIZ);
      m_z_axis.title_to_axis.value(XLAB);
      m_z_axis.title_height.value(ASIZ);

      m_cmap_axis.tick_length.value(XTIC);
      m_cmap_axis.label_to_axis.value(YVAL);
      m_cmap_axis.label_height.value(VSIZ);
      m_cmap_axis.title_to_axis.value(YLAB);
      m_cmap_axis.title_height.value(ASIZ);

    }

    }

    title_automated = true;
    title.value().clear();
    title_up = true;
    title_hjust = center;

    ////////////////////////////////////////////
    colormap_visible = true;
    colormap_axis_labeling = cells;
    colormap_attached = true;
    colormap_axis_visible = true;

    ////////////////////////////////////////////
    x_axis_enforced = false;
    x_axis_automated = true;
    x_axis_min = 0;
    x_axis_max = 1;
    x_axis_is_log = false;

    y_axis_enforced = false;
    y_axis_automated = true;
    y_axis_min = 0;
    y_axis_max = 1;
    y_axis_is_log = false;

    z_axis_enforced = false;
    z_axis_automated = true;
    z_axis_min = 0;
    z_axis_max = 1;
    z_axis_is_log = false;

    m_x_axis.reset_style();
    m_y_axis.reset_style();
    m_z_axis.reset_style();

    ////////////////////////////////////////////
    ////////////////////////////////////////////
    ////////////////////////////////////////////
    number_of_levels = 10;
    levels.clear();
    data_light_on_automated = true;
    primitives_enforced = false;
    inner_frame_enforced = false;

    ////////////////////////////////////////////
    // setup styles :
    ////////////////////////////////////////////

    m_title_style = text_style();
    m_infos_style = text_style();
    m_title_box_style = text_style();
    m_background_style = style();
    m_wall_style = style();
    m_inner_frame_style = style();
    m_grid_style = style();

    m_title_style.color = colorf_black();
    m_title_style.font = font_hershey();
    m_title_style.font_modeling = font_filled;
    m_title_style.encoding = encoding_PAW();

    m_background_style.back_color = colorf_white();
    m_background_style.line_width = 0; //no border
    m_background_style.color = colorf_black(); //border

    m_inner_frame_style.color = colorf_black();
    m_inner_frame_style.line_pattern = line_solid;

    m_grid_style.color = colorf_black();
    m_grid_style.line_pattern = line_dashed;

    m_infos_style.font = font_hershey();
    m_infos_style.font_modeling = font_filled;
    m_infos_style.encoding = encoding_PAW();

    m_title_box_style.visible = false;
    m_title_box_style.font = font_hershey();
    m_title_box_style.font_modeling = font_filled;
    m_title_box_style.encoding = encoding_PAW();

   {tools_vforit(style,m_bins_style,it) {
      (*it) = style();
      (*it).modeling = modeling_top_lines();
      (*it).marker_size = 5; //for bins1D of profile.
    }}
   {tools_vforit(style,m_errors_style,it) {(*it) = style();(*it).visible = false;}}
   {tools_vforit(style,m_func_style,it) (*it) = style();}
   {tools_vforit(style,m_points_style,it) {
      (*it) = style();
      (*it).modeling = modeling_markers(); //for gopaw.
    }}
   {tools_vforit(style,m_left_hatch_style,it) {(*it) = style();(*it).visible = false;}}
   {tools_vforit(style,m_right_hatch_style,it) {(*it) = style();(*it).visible = false;}}
   {tools_vforit(style,m_legend_style,it) {(*it) = style();(*it).visible = false;}}

  }

  void gopaw_reset_style() {
   {tools_vforit(style,m_bins_style,it) {
      (*it) = style();
      (*it).modeling = modeling_top_lines();
      (*it).marker_size = 5; //for bins1D of profile.
    }}

   {tools_vforit(style,m_errors_style,it) {(*it) = style();(*it).visible = false;}}
   {tools_vforit(style,m_func_style,it) (*it) = style();}
   {tools_vforit(style,m_points_style,it) {
      (*it) = style();
      (*it).modeling = modeling_markers(); //for gopaw.
    }}
   {tools_vforit(style,m_left_hatch_style,it) {(*it) = style();(*it).visible = false;}}
   {tools_vforit(style,m_right_hatch_style,it) {(*it) = style();(*it).visible = false;}}
   {tools_vforit(style,m_legend_style,it) {(*it) = style();(*it).visible = false;}}
  }

  typedef std::pair<std::string,std::string> style_item_t;
  typedef std::vector<style_item_t> style_t;
  bool set_from_style(std::ostream& a_out,const style_t& a_style) {
    tools_vforcit(style_item_t,a_style,it) {
      const std::string& key = (*it).first;
      const std::string& sv = (*it).second;
      //::printf("debug : plotter::set_from_style : key \"%s\" \"%s\"\n",key.c_str(),sv.c_str());
      //if(key=="reset") {}
      if(key=="tag") {
        // key to find back <plotter_style>s.
        // see also :
        //   xml_style::load_plotter_style()
        //   xml_style::find_plotter_styles()


      //width,height,depth : could set from style (for exa for lego).
      } else if(key=="width") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        width = v;
      } else if(key=="height") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        height = v;
      } else if(key=="depth") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        depth = v;

      } else if(key=="left_margin") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        left_margin = v;
      } else if(key=="right_margin") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        right_margin = v;
      } else if(key=="bottom_margin") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        bottom_margin = v;
      } else if(key=="top_margin") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        top_margin = v;
      } else if(key=="down_margin") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        down_margin = v;
      } else if(key=="up_margin") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        up_margin = v;

      } else if(key=="title") {
        title = sv;
      } else if(key=="title_up") {
        bool v;
        if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
        title_up = v;
      } else if(key=="title_to_axis") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        title_to_axis = v;
      } else if(key=="title_height") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        title_height = v;
      } else if(key=="title_automated") {
        bool v;
        if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
        title_automated = v;
      } else if(key=="title_hjust") {
        hjust v;
        if(!shjust(sv,v))
          {style_failed(a_out,key,sv);return false;}
        title_hjust = v;

      } else if(key=="x_axis_enforced") {
        bool v;
        if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
        x_axis_enforced = v;
      } else if(key=="x_axis_automated") {
        bool v;
        if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
        x_axis_automated = v;
      } else if(key=="x_axis_min") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        x_axis_min = v;
      } else if(key=="x_axis_max") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        x_axis_max = v;
      } else if(key=="x_axis_is_log") {
        bool v;
        if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
        x_axis_is_log = v;

      } else if(key=="y_axis_enforced") {
        bool v;
        if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
        y_axis_enforced = v;
      } else if(key=="y_axis_automated") {
        bool v;
        if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
        y_axis_automated = v;
      } else if(key=="y_axis_min") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        y_axis_min = v;
      } else if(key=="y_axis_max") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        y_axis_max = v;
      } else if(key=="y_axis_is_log") {
        bool v;
        if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
        y_axis_is_log = v;

      } else if(key=="z_axis_enforced") {
        bool v;
        if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
        z_axis_enforced = v;
      } else if(key=="z_axis_automated") {
        bool v;
        if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
        z_axis_automated = v;
      } else if(key=="z_axis_min") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        z_axis_min = v;
      } else if(key=="z_axis_max") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        z_axis_max = v;
      } else if(key=="z_axis_is_log") {
        bool v;
        if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
        z_axis_is_log = v;

      } else if(key=="value_top_margin") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        value_top_margin = v;
      } else if(key=="value_bottom_margin") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        value_bottom_margin = v;
      } else if(key=="value_bins_with_entries") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        value_bins_with_entries = v;
      } else if(key=="infos_width") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        infos_width = v;
      } else if(key=="infos_x_margin") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        infos_x_margin = v;
      } else if(key=="infos_y_margin") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        infos_y_margin = v;

      } else if(key=="title_box_width") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        title_box_width = v;
      } else if(key=="title_box_height") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        title_box_height = v;
      } else if(key=="title_box_x_margin") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        title_box_x_margin = v;
      } else if(key=="title_box_y_margin") {
        float v;
        if(!to<float>(sv,v)) {style_failed(a_out,key,sv);return false;}
        title_box_y_margin = v;

      } else if(key=="infos_what") {
        infos_what = sv;

//      } else if(key=="legends_visible") {
//        bool v;
//        if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
//        legends_visible = v;
      } else if(key=="legends_automated") {
        bool v;
        if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
        legends_automated = v;
//    } else if(key=="legends_attached_to_infos") {
//      bool v;
//      if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
//      legends_attached_to_infos = v;
      } else if(key=="legends_origin") {
        vec2f v;
        if(!sto(sv,v)) {style_failed(a_out,key,sv);return false;}
        legends_origin.setValue(v);
      } else if(key=="legends_size") {
        vec2f v;
        if(!sto(sv,v)) {style_failed(a_out,key,sv);return false;}
        legends_size.setValue(v);
      } else if(key=="legends_origin_unit") {
        unit_type v;
        if(!sto(sv,v)) {style_failed(a_out,key,sv);return false;}
        legends_origin_unit.setValue(v);

      } else if(key=="shape_automated") {
        bool v;
        if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
        shape_automated = v;

      } else if(key=="shape") {
        if(sv=="xy") {
          shape = xy;
        } else if(sv=="xyz") {
          shape = xyz;
        } else {
          style_failed(a_out,key,sv);return false;
        }

      //legends_string
      //legends_color
      //legends_string mf_string
      //legends_color mf_vec<colorf,float>

      } else {
        a_out << "tools::sg::plotter::set_from_style : unknown key " << key << "." << std::endl;
      }
    }
    return true;
  }

protected:
  bool s2axis(const std::string& a_s,sg::axis*& a_axis) {
         if(a_s=="x_axis")        {a_axis = &(x_axis());return true;}
    else if(a_s=="y_axis")        {a_axis = &(y_axis());return true;}
    else if(a_s=="z_axis")        {a_axis = &(z_axis());return true;}
    else if(a_s=="colormap_axis") {a_axis = &(colormap_axis());return true;}
    else {
      a_axis = 0;
      return false;
    }
  }
public:
  bool set_from_string(std::ostream& a_out,cmaps_t& a_cmaps,const std::string& a_field,const std::string& a_value) {
    // see also plotter_style file.
    std::string::size_type pos = a_field.find('.');
    bool status = true;
    if(pos==std::string::npos) {
      style_t _style;
      _style.push_back(style_item_t(a_field,a_value));
      if(!set_from_style(a_out,_style)) status = false;
    } else {
      std::vector<std::string> _words;
      words(a_field,".",false,_words);
      if(_words.size()==2) {
        const std::string& word0 = _words[0];
        const std::string& word1 = _words[1];
        std::string _s = word1+" "+std::string(a_value);
        sg::axis* _axis = 0;
             if(word0=="background_style")  {if(!background_style().from_string(a_out,a_cmaps,_s)) status = false;}
        else if(word0=="title_style")       {if(!title_style().from_string(a_out,a_cmaps,_s)) status = false;}
        else if(word0=="infos_style")       {if(!infos_style().from_string(a_out,a_cmaps,_s)) status = false;}
        else if(word0=="title_box_style")   {if(!title_box_style().from_string(a_out,a_cmaps,_s)) status = false;}
        else if(word0=="inner_frame_style") {if(!inner_frame_style().from_string(a_out,a_cmaps,_s)) status = false;}
        else if(word0=="grid_style")        {if(!grid_style().from_string(a_out,a_cmaps,_s)) status = false;}
        else if(word0=="wall_style")        {if(!wall_style().from_string(a_out,a_cmaps,_s)) status = false;}
        else if(!s2axis(word0,_axis)) {
          a_out << "tools::sg::plotter::set_from_string : unexpected axis field " << word0 << "." << std::endl;
          status = false;
        } else {
          style_t _style;
          _style.push_back(style_item_t(word1,a_value));
          if(!_axis->set_from_style(a_out,_style)) status = false;
        }
      } else if(_words.size()==3) {
        const std::string& word0 = _words[0];
        const std::string& word1 = _words[1];
        const std::string& word2 = _words[2];
        sg::axis* _axis = 0;
        std::string _s = word2+" "+std::string(a_value);
        unsigned int index;
        bool to_status = to<unsigned int>(word1,index);
	if(word0=="bins_style") {
	  if(!to_status) {
            a_out << "tools::sg::plotter::set_from_string : bad string " << word1 << " for an index." << std::endl;
            status = false;
          } else {
            if(!bins_style(index).from_string(a_out,a_cmaps,_s)) status = false;
	  }
	} else if(word0=="errors_style") {
	  if(!to_status) {
            a_out << "tools::sg::plotter::set_from_string : bad string " << word1 << " for an index." << std::endl;
            status = false;
          } else {
            if(!errors_style(index).from_string(a_out,a_cmaps,_s)) status = false;
	  }
	} else if(word0=="func_style") {
	  if(!to_status) {
            a_out << "tools::sg::plotter::set_from_string : bad string " << word1 << " for an index." << std::endl;
            status = false;
          } else {
            if(!func_style(index).from_string(a_out,a_cmaps,_s)) status = false;
	  }
	} else if(word0=="points_style") {
	  if(!to_status) {
            a_out << "tools::sg::plotter::set_from_string : bad string " << word1 << " for an index." << std::endl;
            status = false;
          } else {
            if(!points_style(index).from_string(a_out,a_cmaps,_s)) status = false;
	  }
	} else if(word0=="left_hatch_style") {
	  if(!to_status) {
            a_out << "tools::sg::plotter::set_from_string : bad string " << word1 << " for an index." << std::endl;
            status = false;
          } else {
            if(!left_hatch_style(index).from_string(a_out,a_cmaps,_s)) status = false;
	  }
	} else if(word0=="right_hatch_style") {
	  if(!to_status) {
            a_out << "tools::sg::plotter::set_from_string : bad string " << word1 << " for an index." << std::endl;
            status = false;
          } else {
            if(!right_hatch_style(index).from_string(a_out,a_cmaps,_s)) status = false;
	  }
	} else if(word0=="legend_style") {
	  if(!to_status) {
            a_out << "tools::sg::plotter::set_from_string : bad string " << word1 << " for an index." << std::endl;
            status = false;
          } else {
            if(!legend_style(index).from_string(a_out,a_cmaps,_s)) status = false;
	  }
        } else if(!s2axis(word0,_axis)) {
          a_out << "tools::sg::plotter::set_from_string : unexpected axis field " << word0 << "." << std::endl;
          status = false;
        } else {
               if(word1=="line_style")   {if(!_axis->line_style().from_string(a_out,a_cmaps,_s)) status = false;}
          else if(word1=="ticks_style")  {if(!_axis->ticks_style().from_string(a_out,a_cmaps,_s)) status = false;}
          else if(word1=="labels_style") {if(!_axis->labels_style().from_string(a_out,a_cmaps,_s)) status = false;}
          else if(word1=="mag_style")    {if(!_axis->mag_style().from_string(a_out,a_cmaps,_s)) status = false;}
          else if(word1=="title_style")  {if(!_axis->title_style().from_string(a_out,a_cmaps,_s)) status = false;}
          else {
            a_out << "tools::sg::plotter::set_from_string : unexpected style field " << word1 << "." << std::endl;
            status = false;
          }
        }
      } else {
        a_out << "tools::sg::plotter::set_from_string : unexpected number of fields " << _words.size() << "." << std::endl;
        status = false;
      }
    }
    return status;
  }

  void set_encoding(const std::string& a_value) {
    title_style().encoding = a_value;
    infos_style().encoding = a_value;
    title_box_style().encoding = a_value;
    m_x_axis.set_encoding(a_value);
    m_y_axis.set_encoding(a_value);
    m_z_axis.set_encoding(a_value);
    m_cmap_axis.set_encoding(a_value);
  }
  void set_encoding_none() {set_encoding(encoding_none());}

  void print_available_customization(std::ostream& a_out) const {
    a_out << "plotter fields :" << std::endl;
   {const std::vector<field_desc>& fds = node_desc_fields();
    tools_vforcit(field_desc,fds,itd) {
      a_out << " " << (*itd).name() << ", class " << (*itd).cls() << std::endl;
    }}
    a_out << std::endl;

    a_out << "plotter data available styles :" << std::endl;
    a_out << " bins_style.<uint>, class style" << std::endl;
    a_out << " errors_style.<uint>, class style" << std::endl;
    a_out << " func_style.<uint>, class style" << std::endl;
    a_out << " points_style.<uint>, class style" << std::endl;
    a_out << " left_hatch_style.<uint>, class style" << std::endl;
    a_out << " right_hatch_style.<uint>, class style" << std::endl;
    a_out << " legend_style.<uint>, class style" << std::endl;
    a_out << std::endl;

    a_out << "plotter available styles :" << std::endl;
    a_out << " title_style, class text_style" << std::endl;
    a_out << " infos_style, class text_style" << std::endl;
    a_out << " title_box_style, class text_style" << std::endl;
    a_out << " background_style, class style" << std::endl;
    a_out << " inner_frame_style, class style" << std::endl;
    a_out << " grid_style, class style" << std::endl;
    a_out << " wall_style, class style" << std::endl;
    a_out << std::endl;

    a_out << "plotter available axes :" << std::endl;
    a_out << " x_axis" << std::endl;
    a_out << " y_axis" << std::endl;
    a_out << " z_axis" << std::endl;
    a_out << " colormap_axis" << std::endl;
    a_out << std::endl;

    a_out << "plotter axis available styles :" << std::endl;
    a_out << " title_style, class text_style" << std::endl;
    a_out << " labels_style, class text_style" << std::endl;
    a_out << " mag_style, class text_style" << std::endl;
    a_out << " line_style, class line_style" << std::endl;
    a_out << " ticks_style, class line_style" << std::endl;
    a_out << std::endl;

    a_out << "plotter style class fields :" << std::endl;
   {style _style;
    const std::vector<field_desc>& fds = _style.node_desc_fields();
    tools_vforcit(field_desc,fds,itd) {
      a_out << " " << (*itd).name() << ", class " << (*itd).cls() << std::endl;
    }}
    a_out << std::endl;

    a_out << "plotter text_style class fields :" << std::endl;
   {text_style _style;
    const std::vector<field_desc>& fds = _style.node_desc_fields();
    tools_vforcit(field_desc,fds,itd) {
      a_out << " " << (*itd).name() << ", class " << (*itd).cls() << std::endl;
    }}
    a_out << std::endl;

    a_out << "plotter line_style class fields :" << std::endl;
   {line_style _style;
    const std::vector<field_desc>& fds = _style.node_desc_fields();
    tools_vforcit(field_desc,fds,itd) {
      a_out << " " << (*itd).name() << ", class " << (*itd).cls() << std::endl;
    }}
    a_out << std::endl;
  }
protected:
  void style_failed(std::ostream& a_out,const std::string& a_key,const std::string& a_value) {
    a_out << "tools::sg::plotter::set_from_style :"
          << " failed for key " << sout(a_key)
          << " and value " << sout(a_value) << "."
          << std::endl;
  }
public:
  virtual void render(render_action& a_action) {
    if(touched()) {
      update_sg(a_action.out());
      reset_touched();
    }
    m_group.render(a_action);
  }
  virtual void pick(pick_action& a_action) {
    if(touched()) {
      update_sg(a_action.out());
      reset_touched();
    }
    nodekit_pick(a_action,m_group,this);
  }
  virtual void search(search_action& a_action) {
    if(touched()) {
      update_sg(a_action.out());
      reset_touched();
    }
    node::search(a_action);
    if(a_action.done()) return;
    m_group.search(a_action);
  }
  virtual void bbox(bbox_action& a_action) {
    if(touched()) {
      update_sg(a_action.out());
      reset_touched();
    }
    m_group.bbox(a_action);
  }

  virtual bool write(write_action& a_action) {
    if(touched()) {
      update_sg(a_action.out());
      reset_touched();
    }
    //if(!write_fields(a_action)) return false;
    return m_group.write(a_action);
  }
public:
  plotter(const base_freetype& a_ttf)
  :parent()
  ,width(0)
  ,height(0)
  ,left_margin(0)
  ,right_margin(0)
  ,bottom_margin(0)
  ,top_margin(0)
  ,depth(0)
  ,down_margin(0)
  ,up_margin(0)

  ,title_up(true)
  ,title_to_axis(0) //set below.
  ,title_height(0)  //set below.
  ,title_automated(true)
  ,title_hjust(center)
  ,title("")

  ,colormap_visible(true)
  ,colormap_axis_labeling(cells)
  ,colormap_attached(true)
  ,colormap_axis_visible(true)

  ,x_axis_enforced(false)
  ,x_axis_automated(true)
  ,x_axis_min(0)
  ,x_axis_max(1)
  ,x_axis_is_log(false)
  ,y_axis_enforced(false)
  ,y_axis_automated(true)
  ,y_axis_min(0)
  ,y_axis_max(1)
  ,y_axis_is_log(false)
  ,z_axis_enforced(false)
  ,z_axis_automated(true)
  ,z_axis_min(0)
  ,z_axis_max(1)
  ,z_axis_is_log(false)

  ,value_top_margin(0.1f) //percent. // CERN-PAW seems to have 0.1F and CERN-ROOT 0.05F.
  ,value_bottom_margin(0.0f) //percent.
  ,value_bins_with_entries(true)

  ,infos_width(0.3f) //percent of width
  ,infos_x_margin(default_infos_margin()) //percent of width
  ,infos_y_margin(default_infos_margin()) //percent of height
  ,infos_what(s_infos_what_def())

  ,title_box_width(default_title_box_width())       //percent of width
  ,title_box_height(default_title_box_height())     //percent of height
  ,title_box_x_margin(default_title_box_x_margin()) //percent of width
  ,title_box_y_margin(default_title_box_y_margin()) //percent of height

  ,func2D_borders_visible(true)
  ,theta(30)
  ,phi(30)
  ,tau(-90)

  ,legends_automated(true)
  //,legends_attached_to_infos(true)
  // if legends_attached_to_infos is false and
  // unit_percent, legends_origin is the position
  // of the upper right corner of the legends
  // relative to the upper right corner of the plotter
  // with positive values going in reverse x,y axis.
  //,legends_origin(vec2f(0.01f,0.01f))
  //,legends_origin_unit(unit_percent)
  //,legends_size(vec2f(0.2f,0.16f))
  //legends_string

  ,shape_automated(true)
  ,shape(xy)

  ,xy_depth(0.01f)
  ,curve_number_of_points(100)
  ,data_light_on_automated(true)
  ,primitives_enforced(false)
  ,inner_frame_enforced(false)
  ,number_of_levels(10)
  ,levels()

  ,m_ttf(a_ttf)

  ,m_cmap_axis(a_ttf)
  ,m_x_axis(a_ttf)
  ,m_y_axis(a_ttf)
  ,m_z_axis(a_ttf)

  ,m_shape(xy)
  {
    m_cmaps[style_default_colormap::s_default()] = style_default_colormap(); //costly

    add_fields();
    reset_style(true);

    init_sg(); // skeleton of scene graph.
  }
  virtual ~plotter(){
    clear_plottables();
    clear_primitives();
    clear_cmaps();
  }
public:
  plotter(const plotter& a_from)
  :parent(a_from)
  ,width(a_from.width)
  ,height(a_from.height)
  ,left_margin(a_from.left_margin)
  ,right_margin(a_from.right_margin)
  ,bottom_margin(a_from.bottom_margin)
  ,top_margin(a_from.top_margin)
  ,depth(a_from.depth)
  ,down_margin(a_from.down_margin)
  ,up_margin(a_from.up_margin)

  ,title_up(a_from.title_up)
  ,title_to_axis(a_from.title_to_axis)
  ,title_height(a_from.title_height)
  ,title_automated(a_from.title_automated)
  ,title_hjust(a_from.title_hjust)
  ,title(a_from.title)

  ,colormap_visible(a_from.colormap_visible)
  ,colormap_axis_labeling(a_from.colormap_axis_labeling)
  ,colormap_attached(a_from.colormap_attached)
  ,colormap_axis_visible(a_from.colormap_axis_visible)

  ,x_axis_enforced(a_from.x_axis_enforced)
  ,x_axis_automated(a_from.x_axis_automated)
  ,x_axis_min(a_from.x_axis_min)
  ,x_axis_max(a_from.x_axis_max)
  ,x_axis_is_log(a_from.x_axis_is_log)
  ,y_axis_enforced(a_from.y_axis_enforced)
  ,y_axis_automated(a_from.y_axis_automated)
  ,y_axis_min(a_from.y_axis_min)
  ,y_axis_max(a_from.y_axis_max)
  ,y_axis_is_log(a_from.y_axis_is_log)
  ,z_axis_enforced(a_from.z_axis_enforced)
  ,z_axis_automated(a_from.z_axis_automated)
  ,z_axis_min(a_from.z_axis_min)
  ,z_axis_max(a_from.z_axis_max)
  ,z_axis_is_log(a_from.z_axis_is_log)
  ,value_top_margin(a_from.value_top_margin)
  ,value_bottom_margin(a_from.value_bottom_margin)
  ,value_bins_with_entries(a_from.value_bins_with_entries)

  ,infos_width(a_from.infos_width)
  ,infos_x_margin(a_from.infos_x_margin)
  ,infos_y_margin(a_from.infos_y_margin)
  ,infos_what(a_from.infos_what)

  ,title_box_width(a_from.title_box_width)
  ,title_box_height(a_from.title_box_height)
  ,title_box_x_margin(a_from.title_box_x_margin)
  ,title_box_y_margin(a_from.title_box_y_margin)

  ,func2D_borders_visible(a_from.func2D_borders_visible)
  ,theta(a_from.theta)
  ,phi(a_from.phi)
  ,tau(a_from.tau)

  ,legends_automated(a_from.legends_automated)
//,legends_attached_to_infos(a_from.legends_attached_to_infos)
  ,legends_origin(a_from.legends_origin)
  ,legends_origin_unit(a_from.legends_origin_unit)
  ,legends_size(a_from.legends_size)
  ,legends_string(a_from.legends_string)

  ,shape_automated(a_from.shape_automated)
  ,shape(a_from.shape)

  ,xy_depth(a_from.xy_depth)
  ,curve_number_of_points(a_from.curve_number_of_points)
  ,data_light_on_automated(a_from.data_light_on_automated)
  ,primitives_enforced(a_from.primitives_enforced)
  ,inner_frame_enforced(a_from.inner_frame_enforced)
  ,number_of_levels(a_from.number_of_levels)
  ,levels(a_from.levels)

  ,m_ttf(a_from.m_ttf)

  ,m_background_sep()

  ,m_cmap_axis(m_ttf)
  ,m_x_axis(m_ttf)
  ,m_y_axis(m_ttf)
  ,m_z_axis(m_ttf)

  ,m_etc_sep(a_from.m_etc_sep)

  ,m_shape(a_from.m_shape)

  ,m_bins_style(a_from.m_bins_style)
  ,m_errors_style(a_from.m_errors_style)
  ,m_func_style(a_from.m_func_style)
  ,m_points_style(a_from.m_points_style)
  ,m_left_hatch_style(a_from.m_left_hatch_style)
  ,m_right_hatch_style(a_from.m_right_hatch_style)
  ,m_legend_style(a_from.m_legend_style)

  ,m_title_style(a_from.m_title_style)
  ,m_infos_style(a_from.m_infos_style)
  ,m_title_box_style(a_from.m_title_box_style)
  ,m_background_style(a_from.m_background_style)
  ,m_wall_style(a_from.m_wall_style)
  ,m_inner_frame_style(a_from.m_inner_frame_style)
  ,m_grid_style(a_from.m_grid_style)
  ,m_cmaps(a_from.m_cmaps)
  {
    add_fields();

    // to copy axes styles :
    m_x_axis = a_from.m_x_axis;
    m_y_axis = a_from.m_y_axis;
    m_z_axis = a_from.m_z_axis;
    m_cmap_axis = a_from.m_cmap_axis;

    init_sg(); // skeleton of scene graph.

   {tools_vforcit(plottable*,a_from.m_plottables,it) {m_plottables.push_back((*it)->copy());}}
   {tools_vforcit(plotprim*,a_from.m_primitives,it) {m_primitives.push_back((*it)->copy());}}
  }
  plotter& operator=(const plotter& a_from){
    parent::operator=(a_from);
    if(&a_from==this) return *this;

    width = a_from.width;
    height = a_from.height;
    left_margin = a_from.left_margin;
    right_margin = a_from.right_margin;
    bottom_margin = a_from.bottom_margin;
    top_margin = a_from.top_margin;
    depth = a_from.depth;
    down_margin = a_from.down_margin;
    up_margin = a_from.up_margin;

    title_up = a_from.title_up;
    title_to_axis = a_from.title_to_axis;
    title_height = a_from.title_height;
    title_automated = a_from.title_automated;
    title_hjust = a_from.title_hjust;
    title = a_from.title;

    colormap_visible = a_from.colormap_visible;
    colormap_axis_labeling = a_from.colormap_axis_labeling;
    colormap_attached = a_from.colormap_attached;
    colormap_axis_visible = a_from.colormap_axis_visible;

    x_axis_enforced = a_from.x_axis_enforced;
    x_axis_automated = a_from.x_axis_automated;
    x_axis_min = a_from.x_axis_min;
    x_axis_max = a_from.x_axis_max;
    x_axis_is_log = a_from.x_axis_is_log;
    y_axis_enforced = a_from.y_axis_enforced;
    y_axis_automated = a_from.y_axis_automated;
    y_axis_min = a_from.y_axis_min;
    y_axis_max = a_from.y_axis_max;
    y_axis_is_log = a_from.y_axis_is_log;
    z_axis_enforced = a_from.z_axis_enforced;
    z_axis_automated = a_from.z_axis_automated;
    z_axis_min = a_from.z_axis_min;
    z_axis_max = a_from.z_axis_max;
    z_axis_is_log = a_from.z_axis_is_log;
    value_top_margin = a_from.value_top_margin;
    value_bottom_margin = a_from.value_bottom_margin;
    value_bins_with_entries = a_from.value_bins_with_entries;

    infos_width = a_from.infos_width;
    infos_x_margin = a_from.infos_x_margin;
    infos_y_margin = a_from.infos_y_margin;
    infos_what = a_from.infos_what;

    title_box_width = a_from.title_box_width;
    title_box_height = a_from.title_box_height;
    title_box_x_margin = a_from.title_box_x_margin;
    title_box_y_margin = a_from.title_box_y_margin;

    func2D_borders_visible = a_from.func2D_borders_visible;
    theta = a_from.theta;
    phi = a_from.phi;
    tau = a_from.tau;

    legends_automated = a_from.legends_automated;
  //legends_attached_to_infos = a_from.legends_attached_to_infos;
    legends_origin = a_from.legends_origin;
    legends_origin_unit = a_from.legends_origin_unit;
    legends_size = a_from.legends_size;
    legends_string = a_from.legends_string;

    shape_automated = a_from.shape_automated;
    shape = a_from.shape;

    xy_depth = a_from.xy_depth;
    curve_number_of_points = a_from.curve_number_of_points;
    number_of_levels = a_from.number_of_levels;
    levels = a_from.levels;
    data_light_on_automated = a_from.data_light_on_automated;
    primitives_enforced = a_from.primitives_enforced;
    inner_frame_enforced = a_from.inner_frame_enforced;

    m_etc_sep = a_from.m_etc_sep;

    m_bins_style = a_from.m_bins_style;
    m_errors_style = a_from.m_errors_style;
    m_func_style = a_from.m_func_style;
    m_points_style = a_from.m_points_style;
    m_left_hatch_style = a_from.m_left_hatch_style;
    m_right_hatch_style = a_from.m_right_hatch_style;
    m_legend_style = a_from.m_legend_style;

    m_title_style = a_from.m_title_style;
    m_infos_style = a_from.m_infos_style;
    m_title_box_style = a_from.m_title_box_style;
    m_background_style = a_from.m_background_style;
    m_wall_style = a_from.m_wall_style;
    m_inner_frame_style = a_from.m_inner_frame_style;
    m_grid_style = a_from.m_grid_style;

    // to copy axes styles :
    m_x_axis = a_from.m_x_axis;
    m_y_axis = a_from.m_y_axis;
    m_z_axis = a_from.m_z_axis;
    m_cmap_axis = a_from.m_cmap_axis;

    m_cmaps = a_from.m_cmaps;

    clear_plottables();
    clear_primitives();
    clear_todels();

   {tools_vforcit(plottable*,a_from.m_plottables,it) {m_plottables.push_back((*it)->copy());}}
   {tools_vforcit(plotprim*,a_from.m_primitives,it) {m_primitives.push_back((*it)->copy());}}

    return *this;
  }
public:
  size_t number_of_plottables() const {
    size_t number = 0;
    tools_vforcit(plottable*,m_plottables,it) {
      plottable* object = *it;
      if(!object) continue;
      if(!object->is_valid()) continue;
      // take into account all valid plottables, even the one without a representation.
      number++;
    }
    return number;
  }

#define TOOLS_SG_PLOTTER_NUMBER_OF(a__what) \
  size_t number_of_plotted_##a__what##s() const {\
    size_t number = 0;\
    tools_vforcit(plottable*,m_plottables,it) {\
      plottable* object = *it;\
      if(!object) continue;\
      if(!object->is_valid()) continue;\
      if(safe_cast<plottable,a__what>(*object)) number++;\
    }\
    return number;\
  }

  TOOLS_SG_PLOTTER_NUMBER_OF(bins1D)
  TOOLS_SG_PLOTTER_NUMBER_OF(bins2D)
  TOOLS_SG_PLOTTER_NUMBER_OF(points2D)
  TOOLS_SG_PLOTTER_NUMBER_OF(points3D)
  TOOLS_SG_PLOTTER_NUMBER_OF(func1D)
  TOOLS_SG_PLOTTER_NUMBER_OF(func2D)

#undef TOOLS_SG_PLOTTER_NUMBER_OF

  void plotted_object_names(std::vector<std::string>& a_names) const {
    a_names.clear();
    tools_vforcit(plottable*,m_plottables,it) {
      plottable* object = *it;
      if(!object) continue;
      if(!object->is_valid()) continue;
      // take into account all valid plottables, even the one without a representation.
      a_names.push_back(object->name());
    }
  }

public: //public
  const torche& data_light() const {return m_data_light;}
  torche& data_light() {return m_data_light;}

  matrix& tsf() {return m_tsf;}

  const separator& etc_sep() const {return m_etc_sep;}
  separator& etc_sep() {return m_etc_sep;}

  const std::vector<plottable*>& plottables() const {return m_plottables;}

  void add_plottable(plottable* a_p) {
    //WARNING : it takes ownership of a_p object.
    m_plottables.push_back(a_p);
    touch();
  }

  void prep_plottable(plottable* a_p) {
    //WARNING : it takes ownership of a_p object.
    m_plottables.insert(m_plottables.begin(),a_p);
    touch();
  }

  void transfer_plottables(std::vector<plottable*>& a_to) {
    a_to = m_plottables;
    m_plottables.clear(); //do not delete plottables !
    touch();
  }

  template <class T>
  bool remove_plottables() {
    bool found = false;
    std::vector<plottable*>::iterator it;
    for(it=m_plottables.begin();it!=m_plottables.end();) {
      plottable* object = *it;
      if(object && safe_cast<plottable,T>(*object)) {
        it = m_plottables.erase(it);
        delete object;
        found = true;
      } else {
        it++;
      }
    }
    if(found) touch();
    return found;
  }

  void add_primitive(plotprim* a_prim) {m_primitives.push_back(a_prim);touch();}

  void transfer_primitives(std::vector<plotprim*>& a_to) {
    a_to = m_primitives;
    m_primitives.clear(); //do not delete primitives !
    touch();
  }

  template <class T>
  void add_todel(T* a_obj) {
    m_todel_group.add(new sg::holder<T>(a_obj));
  }
  template <class T>
  void remove_todels(){
    remove_holders<T>(m_todel_group.children());
  }
  void transfer_todels(std::vector<node*>& a_to) { //used in sg::plots.
    m_todel_group.transfer(a_to);
  }
  void add_node_todel(node* a_node) { //used in sg::plots.
    m_todel_group.add(a_node);
  }

  void clear() {
    clear_plottables();
    clear_primitives();
    clear_todels();

    legends_string.clear();
    legends_origin_unit.clear();
    legends_origin.clear();
    legends_size.clear();

    //wallEnforced.setValue(false);
    //gridEnforced.setValue(false);
    primitives_enforced = false;
    inner_frame_enforced = false;

    //getEtcSeparator()->removeAllChildren();
    //getEtcDataSeparator()->removeAllChildren();
  }

  const sg::axis& x_axis() const {return m_x_axis;}
  sg::axis& x_axis() {return m_x_axis;}

  const sg::axis& y_axis() const {return m_y_axis;}
  sg::axis& y_axis() {return m_y_axis;}

  const sg::axis& z_axis() const {return m_z_axis;}
  sg::axis& z_axis() {return m_z_axis;}

  const sg::axis& colormap_axis() const {return m_cmap_axis;}
  sg::axis& colormap_axis() {return m_cmap_axis;}

  text_style& title_style() {return m_title_style;}
  style& background_style() {return m_background_style;}
  style& wall_style() {return m_wall_style;}
  style& inner_frame_style() {return m_inner_frame_style;}
  style& grid_style() {return m_grid_style;}
  text_style& infos_style() {return m_infos_style;}
  text_style& title_box_style() {return m_title_box_style;}

  style& bins_style(size_t a_index) {
    size_t sz = m_bins_style.size();
    if(a_index>=sz) {
      //012345 sz=6
      //         9 a_index wanted
      //      6789 loop
      for(size_t index=sz;index<=a_index;index++) {
        m_bins_style.push_back(style());
        m_bins_style.back().modeling = modeling_top_lines();
        m_bins_style.back().marker_size = 5; //for bins1D of profile.
      }
    }
    return m_bins_style[a_index];
  }

  style& errors_style(size_t a_index) {
    size_t sz = m_errors_style.size();
    if(a_index>=sz) {
      for(size_t index=sz;index<=a_index;index++) {
        m_errors_style.push_back(style());
        m_errors_style.back().visible = false;
      }
    }
    return m_errors_style[a_index];
  }

  style& func_style(size_t a_index) {
    size_t sz = m_func_style.size();
    if(a_index>=sz) {
      for(size_t index=sz;index<=a_index;index++) {
        m_func_style.push_back(style());
      }
    }
    return m_func_style[a_index];
  }

  style& points_style(size_t a_index) {
    size_t sz = m_points_style.size();
    if(a_index>=sz) {
      //012345 sz=6
      //         9 a_index wanted
      //      6789 loop
      for(size_t index=sz;index<=a_index;index++) {
        m_points_style.push_back(style());
        m_points_style.back().modeling = modeling_markers(); //for gopaw.
      }
    }
    return m_points_style[a_index];
  }

  style& left_hatch_style(size_t a_index) {
    size_t sz = m_left_hatch_style.size();
    if(a_index>=sz) {
      for(size_t index=sz;index<=a_index;index++) {
        m_left_hatch_style.push_back(style());
        m_left_hatch_style.back().visible = false;
      }
    }
    return m_left_hatch_style[a_index];
  }

  style& right_hatch_style(size_t a_index) {
    size_t sz = m_right_hatch_style.size();
    if(a_index>=sz) {
      for(size_t index=sz;index<=a_index;index++) {
        m_right_hatch_style.push_back(style());
        m_right_hatch_style.back().visible = false;
      }
    }
    return m_right_hatch_style[a_index];
  }

  style& legend_style(size_t a_index) {
    size_t sz = m_legend_style.size();
    if(a_index>=sz) {
      for(size_t index=sz;index<=a_index;index++) {
        m_legend_style.push_back(style());
      }
    }
    return m_legend_style[a_index];
  }

  void bins_modelings(size_t a_index,std::vector<std::string>& a_opts) {
    a_opts.clear();
    update_shape();
    if(m_shape==xy) {
      size_t ibins = 0;
      tools_vforcit(plottable*,m_plottables,it) {
        plottable* object = *it;
        if(!object) continue;
        if(bins1D* b1 = safe_cast<plottable,bins1D>(*object)) {
          //update_bins1D_xy
          if(a_index==ibins) {
            if(b1->is_profile()) {
              a_opts.push_back(modeling_points());
              a_opts.push_back(modeling_markers());
	      return;
            } else {
              a_opts.push_back(modeling_boxes());
              a_opts.push_back(modeling_wire_boxes());
              a_opts.push_back(modeling_bar_chart());
              a_opts.push_back(modeling_top_lines());
              a_opts.push_back(modeling_points());
              a_opts.push_back(modeling_markers());
              return;
            }
          }
          ibins++;
        } if(safe_cast<plottable,bins2D>(*object)) {
          //update_bins2D_xy
          if(a_index==ibins) {
            a_opts.push_back(modeling_curve());
            a_opts.push_back(modeling_filled_curve());
            a_opts.push_back(modeling_boxes());
            a_opts.push_back(modeling_wire_boxes());
            a_opts.push_back(modeling_solid());
            a_opts.push_back(modeling_points());
            return;
          }
          ibins++;
        }
      }
    }
  }

  bool xx_2_yy(const vec3f& a_pos,vec3f& a_out) const {
    // a_pos is in data frame NDC coordinates.
   {float XSIZ = width;
    float XMGL = left_margin;
    float XMGR = right_margin;
    float wData = XSIZ-XMGL-XMGR;
    a_out[0] = wData*a_pos[0];}

   {float YSIZ = height;
    float YMGL = bottom_margin;
    float YMGU = top_margin;
    float hData = YSIZ-YMGL-YMGU;
    a_out[1] = hData*a_pos[1];}

   {float ZSIZ = depth;
    float ZMGD = down_margin;
    float ZMGU = up_margin;
    float dData = ZSIZ-ZMGD-ZMGU;
    a_out[2] = dData*a_pos[2];}

    return true;
  }

  bool data_frame_2_vp(const vec3f& a_pos,vec3f& a_vp) const {
    // a_pos is in data frame NDC coordinates.
    // a_vp is in viewport/screen coordinates (in [0,1]).
   {float XSIZ = width;
    float XMGL = left_margin;
    float XMGR = right_margin;
    float wData = XSIZ-XMGL-XMGR;
    if(XSIZ==0.0F) {
      //SoDebugError::postInfo("tools::sg;:plotter::data_frame_2_vp","XSIZ is 0");
      return false;
    }
    a_vp[0] = (wData*a_pos[0] + XMGL)/XSIZ;}

   {float YSIZ = height;
    float YMGL = bottom_margin;
    float YMGU = top_margin;
    float hData = YSIZ-YMGL-YMGU;
    if(YSIZ==0.0F) {
      //SoDebugError::postInfo("tools::sg;:plotter::data_frame_2_vp","YSIZ is 0");
      return false;
    }
    a_vp[1] = (hData*a_pos[1] + YMGL)/YSIZ;}

   {float ZSIZ = depth;
    float ZMGD = down_margin;
    float ZMGU = up_margin;
    float dData = ZSIZ-ZMGD-ZMGU;
    if(ZSIZ==0.0F) {
      //SoDebugError::postInfo("tools::sg;:plotter::data_frame_2_vp","ZSIZ is 0");
      return false;
    }
    a_vp[2] = (dData*a_pos[2] + ZMGD)/ZSIZ;}

    return true;
  }

  bool vp_2_data_frame(const vec3f& a_vp,vec3f& a_pos) const {
    // a_vp is in viewport/screen coordinates (in [0,1]).
    // a_pos is in data frame NDC coordinates.

   {float XSIZ = width;
    float XMGL = left_margin;
    float XMGR = right_margin;
    float wData = XSIZ-XMGL-XMGR;
    if(wData==0.0F) {
      //SoDebugError::postInfo("tools::sg;:plotter::vp_2_data_frame","wData is 0");
      return false;
    }
    a_pos[0] = (a_vp[0]*XSIZ - XMGL)/wData;}

   {float YSIZ = height;
    float YMGL = bottom_margin;
    float YMGU = top_margin;
    float hData = YSIZ-YMGL-YMGU;
    if(hData==0.0F) {
      //SoDebugError::postInfo("tools::sg;:plotter::vp_2_data_frame","hData is 0");
      return false;
    }
    a_pos[1] = (a_vp[1]*YSIZ - YMGL)/hData;}

   {float ZSIZ = depth;
    float ZMGD = down_margin;
    float ZMGU = up_margin;
    float dData = ZSIZ-ZMGD-ZMGU;
    if(dData==0.0F) {
      //SoDebugError::postInfo("tools::sg;:plotter::vp_2_data_frame","dData is 0");
      return false;
    }
    a_pos[2] = (a_vp[2]*ZSIZ - ZMGD)/dData;}

    return true;
  }

  bool data_frame_2_axis(const vec3f& aDF,vec3f& a_pos) const {
    // aDF is in data area coordinates. In [0,1][0,1][0,1].
    // a_pos is in axes coordinates.

    // Assume that axes min,max,is_log are up to date.

   {float mn = m_x_axis.minimum_value;
    float mx = m_x_axis.maximum_value;
    bool lg = m_x_axis.is_log;
    if(lg) {
      mn = fpow(10,mn);
      mx = fpow(10,mx);
    }
    a_pos[0] = verify_log_inv(aDF[0],mn,mx-mn,lg);}

   {float mn = m_y_axis.minimum_value;
    float mx = m_y_axis.maximum_value;
    bool lg = m_y_axis.is_log;
    if(lg) {
      mn = fpow(10,mn);
      mx = fpow(10,mx);
    }
    a_pos[1] = verify_log_inv(aDF[1],mn,mx-mn,lg);}

   {float mn = m_z_axis.minimum_value;
    float mx = m_z_axis.maximum_value;
    bool lg = m_z_axis.is_log;
    if(lg) {
      mn = fpow(10,mn);
      mx = fpow(10,mx);
    }
    a_pos[2] = verify_log_inv(aDF[2],mn,mx-mn,lg);}

    return true;
  }

  bool axis_2_data_frame(const vec3f& a_pos,vec3f& aDF) const {
    // a_pos is in axes coordinates.
    // aDF in data area coordinate. In [0,1][0,1][0,1].

    // Assume that axes min,max,logScale are up to date.

   {float mn = m_x_axis.minimum_value;
    float mx = m_x_axis.maximum_value;
    if(mx==mn) {
      //SoDebugError::postInfo
      //  ("tools::sg;:plotter::axis_2_data_frame","x : mn (%g) == mx (%g)",mn,mx);
      return false;
    }
    bool lg = m_x_axis.is_log;
    if(lg) {
      if(mn<=0) {
        //SoDebugError::postInfo
        //  ("tools::sg;:plotter::axis_2_data_frame","x log but mn (%g) <=0",mn);
        return false;
      }
      if(mx<=0) {
        //SoDebugError::postInfo
        //  ("tools::sg;:plotter::axis_2_data_frame","x log but mx (%g) <=0",mx);
        return false;
      }
      mn = flog10(mn);
      mx = flog10(mx);
    }
    aDF[0] = verify_log(a_pos[0],mn,mx-mn,lg);}

   {float mn = m_y_axis.minimum_value;
    float mx = m_y_axis.maximum_value;
    if(mx==mn) {
      //SoDebugError::postInfo
      //  ("tools::sg;:plotter::axis_2_data_frame","y : mn (%g) == mx (%g)",mn,mx);
      return false;
    }
    bool lg = m_y_axis.is_log;
    if(lg) {
      if(mn<=0) {
        //SoDebugError::postInfo
        //  ("tools::sg;:plotter::axis_2_data_frame","y log but mn (%g) <=0",mn);
        return false;
      }
      if(mx<=0) {
        //SoDebugError::postInfo
        //  ("tools::sg;:plotter::axis_2_data_frame","y log but mx (%g) <=0",mx);
        return false;
      }
      mn = flog10(mn);
      mx = flog10(mx);
    }
    aDF[1] = verify_log(a_pos[1],mn,mx-mn,lg);}

   {float mn = m_z_axis.minimum_value;
    float mx = m_z_axis.maximum_value;
    if(mx==mn) {
      //SoDebugError::postInfo
      //  ("tools::sg;:plotter::axis_2_data_frame","z : mn (%g) == mx (%g)",mn,mx);
      return false;
    }
    bool lg = m_z_axis.is_log;
    if(lg) {
      if(mn<=0) {
        //SoDebugError::postInfo
        //  ("tools::sg;:plotter::axis_2_data_frame","z log but mn (%g) <=0",mn);
        return false;
      }
      if(mx<=0) {
        //SoDebugError::postInfo
        //  ("tools::sg;:plotter::axis_2_data_frame","z log but mx (%g) <=0",mx);
        return false;
      }
      mn = flog10(mn);
      mx = flog10(mx);
    }
    aDF[2] = verify_log(a_pos[2],mn,mx-mn,lg);}

    return true;
  }

  bool axis_2_vp(const vec3f& a_pos,vec3f& a_vp) const {
    // a_pos is in axes coordinates.
    // a_vp is in viewport/screen coordinates (in [0,1]).
    vec3f d; // In data area coordinate. In [0,1][0,1][0,1].
    if(!axis_2_data_frame(a_pos,d)) return false;
    return data_frame_2_vp(d,a_vp);
  }

  bool vp_2_axis(const vec3f& a_vp,vec3f& a_pos) const {
    // a_vp is in viewport/screen coordinates (in [0,1]).
    // a_pos is in axes coordinates.
    vec3f d; // In data area coordinate. In [0,1][0,1][0,1].
    if(!vp_2_data_frame(a_vp,d)) return false;
    return data_frame_2_axis(d,a_pos);
  }

public:
  void set_axes_modeling(const std::string& a_v){
    m_x_axis.modeling = a_v;
    m_y_axis.modeling = a_v;
    m_z_axis.modeling = a_v;
    m_cmap_axis.modeling = a_v;
  }

  void set_axes_color(const colorf& a_color){
    m_x_axis.line_style().color = a_color;
    m_x_axis.ticks_style().color = a_color;
    m_x_axis.labels_style().color = a_color;
    m_x_axis.title_style().color = a_color;
    m_x_axis.mag_style().color = a_color;

    m_y_axis.line_style().color = a_color;
    m_y_axis.ticks_style().color = a_color;
    m_y_axis.labels_style().color = a_color;
    m_y_axis.title_style().color = a_color;
    m_y_axis.mag_style().color = a_color;

    m_z_axis.line_style().color = a_color;
    m_z_axis.ticks_style().color = a_color;
    m_z_axis.labels_style().color = a_color;
    m_z_axis.title_style().color = a_color;
    m_z_axis.mag_style().color = a_color;

    m_cmap_axis.line_style().color = a_color;
    m_cmap_axis.ticks_style().color = a_color;
    m_cmap_axis.labels_style().color = a_color;
    m_cmap_axis.title_style().color = a_color;
    m_cmap_axis.mag_style().color = a_color;
  }

  void set_axes_text_scale(float a_v){
    m_x_axis.labels_style().scale = a_v;
    m_x_axis.title_style().scale = a_v;
    m_x_axis.mag_style().scale = a_v;

    m_y_axis.labels_style().scale = a_v;
    m_y_axis.title_style().scale = a_v;
    m_y_axis.mag_style().scale = a_v;

    m_z_axis.labels_style().scale = a_v;
    m_z_axis.title_style().scale = a_v;
    m_z_axis.mag_style().scale = a_v;

    m_cmap_axis.labels_style().scale = a_v;
    m_cmap_axis.title_style().scale = a_v;
    m_cmap_axis.mag_style().scale = a_v;
  }

  void set_axes_line_pattern(unsigned short a_v){
    m_x_axis.line_style().pattern = a_v;
    m_y_axis.line_style().pattern = a_v;
    m_z_axis.line_style().pattern = a_v;
    m_cmap_axis.line_style().pattern = a_v;
  }

  void set_axes_line_width(int a_v){
    m_x_axis.line_style().width = float(a_v);
    m_y_axis.line_style().width = float(a_v);
    m_z_axis.line_style().width = float(a_v);
    m_cmap_axis.line_style().width = float(a_v);

    m_x_axis.ticks_style().width = float(a_v);
    m_y_axis.ticks_style().width = float(a_v);
    m_z_axis.ticks_style().width = float(a_v);
    m_cmap_axis.ticks_style().width = float(a_v);
  }

  void set_axes_tick_length(float a_v){
    m_x_axis.tick_length = a_v;
    m_y_axis.tick_length = a_v;
    m_z_axis.tick_length = a_v;
    m_cmap_axis.tick_length = a_v;
  }

  void set_axes_title_height(float a_v){
    m_x_axis.title_height = a_v;
    m_y_axis.title_height = a_v;
    m_z_axis.title_height = a_v;
    m_cmap_axis.title_height = a_v;
  }

  void set_axes_label_height(float a_v){
    m_x_axis.label_height = a_v;
    m_y_axis.label_height = a_v;
    m_z_axis.label_height = a_v;
    m_cmap_axis.label_height = a_v;
  }

  void set_axes_font_modeling(font_modeling a_v){
    m_x_axis.labels_style().font_modeling = a_v;
    m_x_axis.title_style().font_modeling = a_v;
    m_x_axis.mag_style().font_modeling = a_v;

    m_y_axis.labels_style().font_modeling = a_v;
    m_y_axis.title_style().font_modeling = a_v;
    m_y_axis.mag_style().font_modeling = a_v;

    m_z_axis.labels_style().font_modeling = a_v;
    m_z_axis.title_style().font_modeling = a_v;
    m_z_axis.mag_style().font_modeling = a_v;

    m_cmap_axis.labels_style().font_modeling = a_v;
    m_cmap_axis.title_style().font_modeling = a_v;
    m_cmap_axis.mag_style().font_modeling = a_v;
  }

  void set_font_modeling(font_modeling a_v){
    set_axes_font_modeling(a_v);
    title_style().font_modeling = a_v;
    infos_style().font_modeling = a_v;
    title_box_style().font_modeling = a_v;
  }
protected:
  void init_sg(){

    m_group.add(new noderef(m_background_sep));
    m_group.add(new noderef(m_cmap_sep));
    m_group.add(new noderef(m_infos_title_sep));
    m_group.add(new noderef(m_infos_sep));
    m_group.add(new noderef(m_legend_sep));
    m_group.add(new noderef(m_title_box_sep));
    m_group.add(new noderef(m_tsf));
    m_group.add(new noderef(m_layout));
    m_group.add(new noderef(m_title_sep));
    m_group.add(new noderef(m_x_axis_sep));
    m_group.add(new noderef(m_y_axis_sep));
    m_group.add(new noderef(m_z_axis_sep));
    m_group.add(new noderef(m_grid_sep));
    m_group.add(new noderef(m_data_sep));
    m_group.add(new noderef(m_primitives_sep));

    m_cmap_sep.add(new noderef(m_cmap_matrix));
    m_cmap_sep.add(new noderef(m_cmap_cells_sep));
    m_cmap_sep.add(new noderef(m_cmap_axis_matrix));
    m_cmap_sep.add(new noderef(m_cmap_axis));

    m_x_axis_sep.add(new noderef(m_x_axis_matrix));
    m_x_axis_sep.add(new noderef(m_x_axis));

    m_y_axis_sep.add(new noderef(m_y_axis_matrix));
    m_y_axis_sep.add(new noderef(m_y_axis));

    m_z_axis_sep.add(new noderef(m_z_axis_matrix));
    m_z_axis_sep.add(new noderef(m_z_axis));

    m_data_sep.add(new noderef(m_data_light));
    m_data_sep.add(new noderef(m_data_matrix));

    m_data_sep.add(new noderef(m_bins_sep));
    m_data_sep.add(new noderef(m_errors_sep));
    m_data_sep.add(new noderef(m_func_sep));
    m_data_sep.add(new noderef(m_points_sep));
    m_data_sep.add(new noderef(m_inner_frame_sep));
    m_data_sep.add(new noderef(m_etc_sep));
  }

  void update_layout(){
    float XSIZ = width;
    float XMGL = left_margin;
    float XMGR = right_margin;
    float wData = XSIZ-XMGL-XMGR;

    float YSIZ = height;
    float YMGL = bottom_margin;
    float YMGU = top_margin;
    float hData = YSIZ-YMGL-YMGU;

    float ZSIZ = depth;
    float ZMGD = down_margin;
    float ZMGU = up_margin;
    float dData = ZSIZ-ZMGD-ZMGU;

   {mat4f& mtx = m_layout.mtx.value();
    mtx.set_identity();

    if(m_shape==xy) {
      // in rep primitives (0,0) is the lower left corner
      // of the data area square;
      mtx.mul_translate(-XSIZ/2+XMGL,-YSIZ/2+YMGL,0);

      if(data_light_on_automated.value()) m_data_light.on = false;
      vec3f dir(0,0,-1);
      m_data_light.direction = dir;

    } else { //xyz
      //printf("debug : update_layout : X : %g %g %g %g\n",
      //  XSIZ,XMGL,XMGR,wData);
      //printf("debug : update_layout : Y : %g %g %g %g\n",
      //  YSIZ,YMGL,YMGU,hData);

      // global transformation (to have a "lego" layout) :
      //  translate so that the center of the scene
      //  is the center of the data area cube;
      //  then rotate to have lego 3D layout.

      mtx.mul_rotate(1,0,0,theta*fdeg2rad());
      mtx.mul_rotate(0,1,0,phi*fdeg2rad());
      mtx.mul_rotate(1,0,0,tau*fdeg2rad());

      // To place as CERN-PAW default.
      // In CERN-PAW, it is the projection
      // which fits in the (XSIZ,XMGL,XMGR)/(YSIZ,YMGL,YMGU)
      // page setup.

      rotf r1(vec3f(1,0,0),theta * fdeg2rad());
      rotf r2(vec3f(0,1,0),phi * fdeg2rad());
      rotf r3(vec3f(1,0,0),tau * fdeg2rad());

      rotf r = r1*r2*r3;
      mat4f _m;
      r.value(_m);

      float xmn = -0.5F*wData;
      float ymn = -0.5F*hData;
      float zmn = -0.5F*dData;
      float xmx =  0.5F*wData;
      float ymx =  0.5F*hData;
      float zmx =  0.5F*dData;

      box3f _box;
      float x,y,z;
      // zmn face :
     {x = xmn;y = ymn;z = zmn;
      _m.mul_3f(x,y,z);
      _box.extend_by(x,y,z);}
     {x = xmx;y = ymn;z = zmn;
      _m.mul_3f(x,y,z);
      _box.extend_by(x,y,z);}
     {x = xmx;y = ymx;z = zmn;
      _m.mul_3f(x,y,z);
      _box.extend_by(x,y,z);}
     {x = xmn;y = ymx;z = zmn;
      _m.mul_3f(x,y,z);
      _box.extend_by(x,y,z);}

      // zmx face :
     {x = xmn;y = ymn;z = zmx;
      _m.mul_3f(x,y,z);
      _box.extend_by(x,y,z);}
     {x = xmx;y = ymn;z = zmx;
      _m.mul_3f(x,y,z);
      _box.extend_by(x,y,z);}
     {x = xmx;y = ymx;z = zmx;
      _m.mul_3f(x,y,z);
      _box.extend_by(x,y,z);}
     {x = xmn;y = ymx;z = zmx;
      _m.mul_3f(x,y,z);
      _box.extend_by(x,y,z);}

      float xfac = _box.mx()[0]-_box.mn()[0];
      float yfac = _box.mx()[1]-_box.mn()[1];
      float zfac = _box.mx()[2]-_box.mn()[2];

      //cube setup (driven by hData) :
      mtx.mul_scale(hData/xfac,hData/yfac,hData/zfac);

      mtx.mul_translate(-wData/2,-hData/2,-dData/2); //Applied first.

      if(data_light_on_automated.value()) m_data_light.on = true;
     {vec3f dir(1,-1,-10);
      float dx,dy,dz;dir.value(dx,dy,dz);
      mat4f inv;
      if(mtx.invert(inv)) {
        inv.mul_dir_3f(dx,dy,dz);
        m_data_light.direction = vec3f(dx,dy,dz);
      }}
    }}

   {mat4f& mtx = m_data_matrix.mtx.value();
    mtx.set_identity();
    if(m_shape==xy) {
      mtx.mul_scale(wData,hData,1); //z size decided with xy_depth
    } else if(m_shape==xyz) {
      mtx.mul_scale(wData,hData,dData);
    }}

  }

public:
  void update_sg(std::ostream& a_out) {

    update_shape();
    update_axes_data(a_out);

    update_background();
    update_layout();

    // roundtrip over plottables to check if they are valids. Done first.
    unsigned int nplottables = 0;
    unsigned int nbins = 0;
    unsigned int npoints = 0;
    unsigned int nfunc = 0;
   {tools_vforit(plottable*,m_plottables,it) {
      plottable* object = *it;
      if(!object) continue;
      if(!object->is_valid()) {
        *it = 0;
        delete object;
      } else {
        if(safe_cast<plottable,bins1D>(*object)) {
          nplottables++;
          nbins++;
        } else if(safe_cast<plottable,bins2D>(*object)) {
          nplottables++;
          nbins++;

        } else if(safe_cast<plottable,points2D>(*object)) {
          nplottables++;
          npoints++;
        } else if(safe_cast<plottable,points3D>(*object)) {
          nplottables++;
          npoints++;

        } else if(safe_cast<plottable,func1D>(*object)) {
          nplottables++;
          nfunc++;
        } else if(safe_cast<plottable,func2D>(*object)) {
          nplottables++;
          nfunc++;
        }
      }
    }}

    clear_cmaps();
    m_bins_cmaps.resize(nbins,0);
    m_points_cmaps.resize(npoints,0);
    m_func_cmaps.resize(nfunc,0);

    // even if !nplottables we continue.

    m_infos_title_sep.clear();
    m_infos_sep.clear();
    m_legend_strings.clear();

    bool superpose = false;
    /*uuuu
    bool superpose = superposeBins;
    if(superpose) {
      // Check compatibility of bins :
      if( (nbins1D<=0) || (m_shape!=XY) ) {
        superpose = false;
      } else {
        SbPlottableBins1D* bins = f_bins1DList[0];
        int xnbin = bins->getAxisNumberOfBins();
        float xmn = bins->get_axis_min();
        float xmx = bins->get_axis_max();
        superpose = true;
        for(int ibins=1;ibins<nbins1D;ibins++) {
          SbPlottableBins1D* binsloop = f_bins1DList[ibins];
          if( (xnbin!=binsloop->getAxisNumberOfBins()) ||
              (xmn!=binsloop->get_axis_min()) ||
              (xmx!=binsloop->get_axis_max()) ) {
            superpose = false;
            break;
          }
        }
        if(superpose) { //Compatible bins :
          if(y_axis_automated) {
            // Correct Y axis if XY shape and superposing bins.
            // Get min/max
            float bmin,bmax;
            getHeight(nbins1D-1,f_bins1DList,bins1DListSwMnMx,0,bmin,bmax);
            bmin = bmax;
            for(int ibin=1;ibin<xnbin;ibin++) {
              float mini,maxi;
              getHeight
                (nbins1D-1,f_bins1DList,bins1DListSwMnMx,ibin,mini,maxi);
              bmin = SbMinimum(bmin,maxi);
              bmax = SbMaximum(bmax,maxi);
            }
            f_yDataAxis.setMinimumValue(bmin);
            f_yDataAxis.setMaximumValue(bmax);
            f_yDataAxis.adjustAxis();
          }
        }
      }
    }*/

    float xmin =  m_x_axis_data.min_value();
    float xmax =  m_x_axis_data.max_value();
    bool xlog = m_x_axis_data.is_log();
    if(xlog) {
      if((xmin<=0) || (xmax<=0) ) {
        m_x_axis_data.adjust();
        xmin =  m_x_axis_data.min_value();
        xmax =  m_x_axis_data.max_value();
        // now should have reasonable values.
      }
      if((xmin<=0) || (xmax<=0) ) {
        xlog = false;
      } else {
        xmin = flog10(xmin);
        xmax = flog10(xmax);
      }
    }

    float ymin =  m_y_axis_data.min_value();
    float ymax =  m_y_axis_data.max_value();
    bool ylog = m_y_axis_data.is_log();
    if(ylog) {
      if((ymin<=0) || (ymax<=0) ) {
        m_y_axis_data.adjust();
        ymin = m_y_axis_data.min_value();
        ymax = m_y_axis_data.max_value();
        // now should have reasonable values.
      }
      if((ymin<=0) || (ymax<=0) ) {
        ylog = false;
      }else{
        ymin = flog10(ymin);
        ymax = flog10(ymax);
      }
    }

    float zmin =  m_z_axis_data.min_value();
    float zmax =  m_z_axis_data.max_value();
    bool zlog = m_z_axis_data.is_log();
    if(zlog) {
      if((zmin<=0) || (zmax<=0) ) {
        m_z_axis_data.adjust();
        zmin = m_z_axis_data.min_value();
        zmax = m_z_axis_data.max_value();
        // now should have reasonable values.
      }
      if((zmin<=0) || (zmax<=0) ) {
        zlog = false;
      }else{
        zmin = flog10(zmin);
        zmax = flog10(zmax);
      }
    }

    if(m_shape==xy) {
      if(xmin>=xmax) {
        DUMP_UPDATE_WHAT(a_out,"bad min/max x axes");
      }
      if(ymin>=ymax) {
        DUMP_UPDATE_WHAT(a_out,"bad min/max y axes");
      }
    } else if(m_shape==xyz) {
      if(xmin>=xmax) {
        DUMP_UPDATE_WHAT(a_out,"bad min/max x axes");
      }
      if(ymin>=ymax) {
        DUMP_UPDATE_WHAT(a_out,"bad min/max y axes");
      }
      if(zmin>=zmax) {
        DUMP_UPDATE_WHAT(a_out,"bad min/max z axes");
      }
    }

   {float XSIZ = width;
    float XMGL = left_margin;
    float XMGR = right_margin;
    float wData = XSIZ-XMGL-XMGR;

    float YSIZ = height;
    float YMGL = bottom_margin;
    float YMGU = top_margin;
    float hData = YSIZ-YMGL-YMGU;
    if(m_shape==xy) {
      if(wData<=0) {
        DUMP_UPDATE_WHAT(a_out,"null w data area");
      }
      if(hData<=0) {
        DUMP_UPDATE_WHAT(a_out,"null h data area");
      }
    } else if(m_shape==xyz) {
      float ZSIZ = depth;
      float ZMGD = down_margin;
      float ZMGU = up_margin;
      float dData = ZSIZ-ZMGD-ZMGU;
      if(wData<=0) {
        DUMP_UPDATE_WHAT(a_out,"null w data area");
      }
      if(hData<=0) {
        DUMP_UPDATE_WHAT(a_out,"null h data area");
      }
      if(dData<=0) {
        DUMP_UPDATE_WHAT(a_out,"null d data area");
      }
    }}

    float dx   = xmax - xmin;
    float dy   = ymax - ymin;
    float dz   = zmax - zmin;

    rep_box boxX(xmin,dx,xlog);
    rep_box boxY(ymin,dy,ylog);
    rep_box boxZ(zmin,dz,zlog);

    ////////////////////////////////////
    /// data : /////////////////////////
    ////////////////////////////////////
    if(m_shape==xy) {
      //a_out << "tools::sg::plotter::update_sg : shape xy :" << std::endl;

      // first data plane is at zz = _zoffset().

      float zz = 0;

      ////////////////////////////////////
      /// binss //////////////////////////
      ////////////////////////////////////

      //if(verbose) {
      //  SoDebugError::postInfo("tools::sg;:plotter::updateChildren",
      //  "%lu : XY : update bins",(unsigned long)this);
      //}

     {m_bins_sep.clear();
      m_errors_sep.clear();

      unsigned int ibins = 0; //used to get each bins style and colormap.
      //unsigned int ibins1D = 0;
      //unsigned int ibins2D = 0;
      tools_vforcit(plottable*,m_plottables,it) {
        plottable* object = *it;
        if(!object) continue;
        if(bins1D* b1 = safe_cast<plottable,bins1D>(*object)) {

          zz += _zoffset(); // ibins = 0 back (PAW convention).
          style* data_style = merge_bins_style(ibins,*object);
          style* _left_hatch_style = merge_left_hatch_style(ibins,*object);
          style* _right_hatch_style = merge_right_hatch_style(ibins,*object);
          style* error_style = merge_errors_style(ibins,*object);

          update_bins1D_xy(a_out,*b1,
                           *data_style,*_left_hatch_style,*_right_hatch_style,*error_style,ibins,
                           superpose,boxX,boxY,zz);

          if(legends_automated.value()) {
            m_legend_strings.push_back(object->legend());
            style& _style = legend_style(m_legend_strings.size()-1);
            _style.color = data_style->color;
            _style.marker_style = data_style->marker_style;
            _style.marker_size = data_style->marker_size;
          }

          delete data_style;
          delete _left_hatch_style;
          delete _right_hatch_style;
          delete error_style;
          ibins++;
          //ibins1D++;
        } if(bins2D* b2 = safe_cast<plottable,bins2D>(*object)) {
          //a_out << "tools::sg::plotter::update_sg : bins2D." << std::endl;
          zz += _zoffset(); // ibins = 0 back (PAW convention).
          style* data_style = merge_bins_style(ibins,*object);

          update_bins2D_xy(a_out,*b2,*data_style,ibins,boxX,boxY,boxZ,zz);

          if(legends_automated.value()) {
            m_legend_strings.push_back(object->legend());
            style& _style = legend_style(m_legend_strings.size()-1);
            _style.color = data_style->color;
            _style.marker_style = data_style->marker_style;
            _style.marker_size = data_style->marker_size;
          }

          delete data_style;
          ibins++;
        }
      }}

      ////////////////////////////////////
      /// funcs //////////////////////////
      ////////////////////////////////////

     {m_func_sep.clear();
      //zz = 0; // Functions in front.
      unsigned int ifunc = 0; //used to get each func style and colormap.
      tools_vforcit(plottable*,m_plottables,it) {
        plottable* object = *it;
        if(!object) continue;
        if(func1D* f1 = safe_cast<plottable,func1D>(*object)) {
          zz += _zoffset();
          style* data_style = merge_func_style(ifunc,*object);
          update_func1D_xy(a_out,*f1,*data_style,boxX,boxY,zz);
          if(legends_automated.value()) {
            m_legend_strings.push_back(object->legend());
            style& _style = legend_style(m_legend_strings.size()-1);
            _style.color = data_style->color;
            _style.marker_style = data_style->marker_style;
            _style.marker_size = data_style->marker_size;
          }
          delete data_style;
          ifunc++;
        } else if(func2D* f2 = safe_cast<plottable,func2D>(*object)) {
          zz += _zoffset();
          style* data_style = merge_func_style(ifunc,*object);
          update_func2D_xy(a_out,*f2,ifunc,*data_style,boxX,boxY,boxZ,zz);
          if(legends_automated.value()) {
            m_legend_strings.push_back(object->legend());
            style& _style = legend_style(m_legend_strings.size()-1);
            _style.color = data_style->color;
            _style.marker_style = data_style->marker_style;
            _style.marker_size = data_style->marker_size;
          }
          delete data_style;
          ifunc++;
        }
      }}

      ////////////////////////////////////
      /// pointss ////////////////////////
      ////////////////////////////////////
     {m_points_sep.clear();
      unsigned int ipoints = 0; //used to get each points style and colormap.
      tools_vforcit(plottable*,m_plottables,it) {
        plottable* object = *it;
        if(!object) continue;
        if(points2D* p2 = safe_cast<plottable,points2D>(*object)) {

          zz += _zoffset(); // ibins = 0 back (PAW convention).
          style* data_style = merge_points_style(ipoints,*object);
          update_points2D_xy(a_out,*p2,*data_style,boxX,boxY,zz);

          if(legends_automated.value()) {
            m_legend_strings.push_back(object->legend());
            style& _style = legend_style(m_legend_strings.size()-1);
            _style.color = data_style->color;
            _style.modeling = data_style->modeling;
            _style.marker_style = data_style->marker_style;
            _style.marker_size = data_style->marker_size;
            _style.point_size = data_style->point_size;
	  }

          delete data_style;
          ipoints++;
        }
      }}
    }

    if(m_shape==xyz) {

      ////////////////////////////////////
      /// binss //////////////////////////
      ////////////////////////////////////
     {m_bins_sep.clear();
      m_errors_sep.clear();
      unsigned int ibins = 0; //used to get each bins style and colormap.
      tools_vforcit(plottable*,m_plottables,it) {
        plottable* object = *it;
        if(!object) continue;
        if(safe_cast<plottable,bins1D>(*object)) {
          ibins++;
        } else if(bins2D* b2 = safe_cast<plottable,bins2D>(*object)) {
          style* data_style = merge_bins_style(ibins,*object);
          update_bins2D_xyz(a_out,*b2,ibins,*data_style,boxX,boxY,boxZ);
          delete data_style;
          ibins++;
        }
      }}

      ////////////////////////////////////
      /// funcs //////////////////////////
      ////////////////////////////////////

     {m_func_sep.clear();
      unsigned int ifunc = 0; //used to get each func style and colormap.
      tools_vforcit(plottable*,m_plottables,it) {
        plottable* object = *it;
        if(!object) continue;
        if(safe_cast<plottable,func1D>(*object)) {
          ifunc++;
        } else if(func2D* f2 = safe_cast<plottable,func2D>(*object)) {
          style* data_style = merge_func_style(ifunc,*object);
          update_func2D_xyz(a_out,*f2,ifunc,*data_style,boxX,boxY,boxZ);
          delete data_style;
          ifunc++;
        }
      }}

      ////////////////////////////////////
      /// pointss ////////////////////////
      ////////////////////////////////////
     {m_points_sep.clear();
      unsigned int ipoints = 0; //used to get each points style and colormap.
      tools_vforcit(plottable*,m_plottables,it) {
        plottable* object = *it;
        if(!object) continue;
        if(points3D* p3 = safe_cast<plottable,points3D>(*object)) {

          style* data_style = merge_points_style(ipoints,*object);
          update_points3D_xyz(a_out,*p3,*data_style,boxX,boxY,boxZ);

          if(legends_automated.value()) {
            m_legend_strings.push_back(object->legend());
            style& _style = legend_style(m_legend_strings.size()-1);
            _style.color = data_style->color;
            _style.modeling = data_style->modeling;
            _style.marker_style = data_style->marker_style;
            _style.marker_size = data_style->marker_size;
            _style.point_size = data_style->point_size;
	  }

          delete data_style;
          ipoints++;
        }
      }}
    }

    ////////////////////////////////////
    /// axes : /////////////////////////
    ////////////////////////////////////
    // done before update_legends() which needs
    // the x_axis min/max if legends_origin_unit
    // is unit_axis.

    // axes :
    if(m_shape==xy){
      if(x_axis_enforced.value()) {
        update_x_axis_2D();
        m_x_axis.minimum_value = x_axis_min.value();
        m_x_axis.maximum_value = x_axis_max.value();
        m_x_axis.is_log = x_axis_is_log.value();
        m_x_axis.update_sg(a_out); // So that the grid be correct.
        m_x_axis.reset_touched();
      } else {
	if(!nplottables) {
	  m_x_axis.width = 0;
	} else {
          update_x_axis_2D();
          update_axis(a_out,m_x_axis,m_x_axis_data);
	}
      }

      if(y_axis_enforced.value()) {
        update_y_axis_2D();
        m_y_axis.minimum_value = y_axis_min.value();
        m_y_axis.maximum_value = y_axis_max.value();
        m_y_axis.is_log = y_axis_is_log.value();
        m_y_axis.update_sg(a_out); // So that the grid be correct.
        m_y_axis.reset_touched();
      } else {
	if(!nplottables) {
	  m_y_axis.width = 0;
	} else {
          update_y_axis_2D();
          update_axis(a_out,m_y_axis,m_y_axis_data);
	}
      }

      if(z_axis_enforced.value()) {
        update_z_axis_2D();
        m_z_axis.minimum_value = z_axis_min.value();
        m_z_axis.maximum_value = z_axis_max.value();
        m_z_axis.is_log = z_axis_is_log.value();
        m_z_axis.update_sg(a_out); // So that the grid be correct.
        m_z_axis.reset_touched();
      } else {
	if(!nplottables) {
	  m_z_axis.width = 0;
	} else {
          update_z_axis_2D();
	}
      }
    }

    if(m_shape==xyz){
      if(x_axis_enforced.value()) {
        update_x_axis_3D();
        m_x_axis.minimum_value = x_axis_min.value();
        m_x_axis.maximum_value = x_axis_max.value();
        m_x_axis.is_log = x_axis_is_log.value();
        m_x_axis.update_sg(a_out); // So that the grid be correct.
        m_x_axis.reset_touched();
      } else {
	if(!nplottables) {
	  m_x_axis.width = 0;
	} else {
          update_x_axis_3D();
          update_axis(a_out,m_x_axis,m_x_axis_data);
	}
      }

      if(y_axis_enforced.value()) {
        update_y_axis_3D();
        m_y_axis.minimum_value = y_axis_min.value();
        m_y_axis.maximum_value = y_axis_max.value();
        m_y_axis.is_log = y_axis_is_log.value();
        m_y_axis.update_sg(a_out); // So that the grid be correct.
        m_y_axis.reset_touched();
      } else {
	if(!nplottables) {
	  m_y_axis.width = 0;
	} else {
          update_y_axis_3D();
          update_axis(a_out,m_y_axis,m_y_axis_data);
	}
      }

      if(z_axis_enforced.value()) {
        update_z_axis_3D();
        m_z_axis.minimum_value = z_axis_min.value();
        m_z_axis.maximum_value = z_axis_max.value();
        m_z_axis.is_log = z_axis_is_log.value();
        m_z_axis.update_sg(a_out); // So that the grid be correct.
        m_z_axis.reset_touched();
      } else {
	if(!nplottables) {
	  m_z_axis.width = 0;
	} else {
          update_z_axis_3D();
          update_axis(a_out,m_z_axis,m_z_axis_data);
	}
      }
    }

    if(nplottables) {
      // infos box is done before update_legends()
      // because legends may be placed relative to it.
      update_infos(a_out);
    }
    m_legend_sep.clear();

    if(!legends_automated) {
      m_legend_strings = legends_string.values();
    }
    update_legends(a_out);

    if(title_automated) {
      std::string _s;
      get_title(_s);
      title.value(_s);
      title.reset_touched(); //output field.
    }
    m_title_sep.clear();
    if(nplottables) update_title();

    m_title_box_sep.clear();
    if(nplottables) update_title_box();

    m_inner_frame_sep.clear();
    if(inner_frame_enforced.value() || nplottables) {
      if(m_shape==xy) {
        update_inner_frame_XY();
      } else {
        update_inner_frame_XYZ();
      }
    }

    m_grid_sep.clear();
    if(nplottables) {
      if(m_shape==xy) {
        update_grid_XY();
      } else {
        update_grid_XYZ();
      }
    }

    m_cmap_axis.width = 0;
    m_cmap_cells_sep.clear();
    if(m_bins_cmaps.size() && m_bins_cmaps[0] && m_bins_cmaps[0]->valn()) {     //major_bins
      update_cmap(a_out,*(m_bins_cmaps[0]));
    } else if(m_points_cmaps.size() && m_points_cmaps[0] && m_points_cmaps[0]->valn()) { //major_points
      update_cmap(a_out,*(m_points_cmaps[0]));
    } else if(m_func_cmaps.size() && m_func_cmaps[0] && m_func_cmaps[0]->valn()) { //major_func
      update_cmap(a_out,*(m_func_cmaps[0]));
    }

    update_primitives(a_out);
  }

  void get_value_axis_min_max(float a_Sw_mn,float a_Sw_mx,bool a_is_log,float& a_min,float& a_max,bool a_min_visible) {
    if(a_Sw_mn>a_Sw_mx) {
      a_min = 0;
      a_max = 0;
      return;
    }
    // a_Sw_mx >= a_Sw_mn.
    if(a_is_log && (a_Sw_mn<=0) ) { //let data_axis.adjust() do something.
      a_min = a_Sw_mn;
      a_max = a_Sw_mx;
      return;
    }
    float mn;
    if(a_is_log) {
      if(value_bottom_margin.value()!=0) {
        float log_Sw_mn = flog10(a_Sw_mn);
        float log_Sw_mx = flog10(a_Sw_mx);
        float log_mn = log_Sw_mn - (log_Sw_mx-log_Sw_mn)*value_bottom_margin;
        mn = fpow(10,log_mn);
      } else {
        mn = a_Sw_mn;
        if(a_min_visible) { // arrang so that the bin with a_Sw_mn be visible.
          float log_Sw_mn = flog10(a_Sw_mn);
          mn = fpow(10,log_Sw_mn)*(1.0f-0.4f);
        }
      }
    } else {
      if(value_bottom_margin.value()!=0) {
        mn = a_Sw_mn - (a_Sw_mx-a_Sw_mn)*value_bottom_margin;
      } else {
        if(a_min_visible) {
	  // Arrange so that the bin with a_Sw_mn (if not 0) be visible. (If 0, it will be anyway on the x axis) :
          if(a_Sw_mn>0) {
	    mn = 0; //PAW logic.
	  } else if(a_Sw_mn==0) {
	    mn = 0; //PAW logic. min bin will be anyway on x axis.
	  } else {
	    mn = a_Sw_mn; // min bin will be anyway on x axis.
	  }
	} else {
          mn = a_Sw_mn; //min bin will be on x axis.
	}
      }
    }
    a_min = mn;

    float mx;
    if(a_is_log) {
      if(value_top_margin.value()!=0) {
        float log_Sw_mn = flog10(a_Sw_mn);
        float log_Sw_mx = flog10(a_Sw_mx);
        float log_mx = log_Sw_mx + (log_Sw_mx-log_Sw_mn)*value_top_margin;
        mx = fpow(10,log_mx);
      } else {
        mx = a_Sw_mx; //max bin will be on top of frame (then not visible if same color).
      }
    } else {
      mx = a_Sw_mx + (a_Sw_mx-mn)*value_top_margin;
    //mx = a_Sw_mx + (a_Sw_mx-a_Sw_mn)*value_top_margin; //not compatible with gopaw.
    }
    a_max = mx;
  }

  void update_axes_data(std::ostream& a_out){
    m_x_axis_data.set_min_value(0);
    m_x_axis_data.set_max_value(0);
    m_x_axis_data.set_is_log(x_axis_is_log);

    m_y_axis_data.set_min_value(0);
    m_y_axis_data.set_max_value(0);
    m_y_axis_data.set_is_log(y_axis_is_log);

    m_z_axis_data.set_min_value(0);
    m_z_axis_data.set_max_value(0);
    m_z_axis_data.set_is_log(z_axis_is_log);

    if(!x_axis_automated) { //def = true
      m_x_axis_data.set_min_value(x_axis_min);
      m_x_axis_data.set_max_value(x_axis_max);
    }

    if(!y_axis_automated) {
      m_y_axis_data.set_min_value(y_axis_min);
      m_y_axis_data.set_max_value(y_axis_max);
    }

    if(!z_axis_automated) {
      m_z_axis_data.set_min_value(z_axis_min);
      m_z_axis_data.set_max_value(z_axis_max);
    }

    bins1D* b1;
    bins2D* b2;

    func1D* f1;
    func2D* f2;

    points2D* p2;
    points3D* p3;

    if(first_bins(b1,b2)) {

      if(b1) {

        if(x_axis_automated) {
          m_x_axis_data.set_min_value(b1->axis_min());
          m_x_axis_data.set_max_value(b1->axis_max());
        }

        if(y_axis_automated) {
        //::printf("debug : value %g %g %d : is log %d\n",
        //    value_bottom_margin.value(),value_top_margin.value(),value_bins_with_entries.value(),
        //    m_y_axis_data.is_log());
          float Sw_mn,Sw_mx;
          b1->bins_Sw_range(Sw_mn,Sw_mx,value_bins_with_entries.value());
        //::printf("debug : Sw %g %g\n",Sw_mn,Sw_mx);
          float mn,mx;
          get_value_axis_min_max(Sw_mn,Sw_mx,m_y_axis_data.is_log(),mn,mx,true);
        //::printf("debug : mn mx %g %g\n",mn,mx);
          m_y_axis_data.set_min_value(mn);
          m_y_axis_data.set_max_value(mx);

          m_y_axis_data.adjust();
        //::printf("debug : adjusted : mn mx %g %g\n",mn,mx);
        }

      } if(b2) {
        if(x_axis_automated) {
          m_x_axis_data.set_min_value(b2->x_axis_min());
          m_x_axis_data.set_max_value(b2->x_axis_max());
        }

        if(y_axis_automated) {
          m_y_axis_data.set_min_value(b2->y_axis_min());
          m_y_axis_data.set_max_value(b2->y_axis_max());
        }

        if(z_axis_automated) {
          float Sw_mn,Sw_mx;
          b2->bins_Sw_range(Sw_mn,Sw_mx,value_bins_with_entries.value());
          float mn,mx;
          get_value_axis_min_max(Sw_mn,Sw_mx,m_z_axis_data.is_log(),mn,mx,false);
          m_z_axis_data.set_min_value(mn);
          m_z_axis_data.set_max_value(mx);

          m_z_axis_data.adjust();
        }
      } /*else if(f_binsList[0]->getDimension()==3) {
        //FIXME : should do something.
      } else {
        // Unusual case.
      }*/

    } else if(first_points(p2,p3)) {
      if(p2) {
        if(x_axis_automated) {
          m_x_axis_data.set_min_value(p2->x_axis_min());
          m_x_axis_data.set_max_value(p2->x_axis_max());
        }
        if(y_axis_automated) {
          float ymn = p2->y_axis_min();
          float ymx = p2->y_axis_max();
          // For pawex22 ?
          //m_y_axis_data.set_min_value(ymn*1.1F);
          //m_y_axis_data.set_max_value(ymx*1.1F);
          m_y_axis_data.set_min_value(ymn);
          m_y_axis_data.set_max_value(ymx);
        }
      } else if(p3) {

        if(x_axis_automated) {
          m_x_axis_data.set_min_value(p3->x_axis_min());
          m_x_axis_data.set_max_value(p3->x_axis_max());
        }

        if(y_axis_automated) {
          m_y_axis_data.set_min_value(p3->y_axis_min());
          m_y_axis_data.set_max_value(p3->y_axis_max());
        }

        if(z_axis_automated) {
          m_z_axis_data.set_min_value(p3->z_axis_min());
          m_z_axis_data.set_max_value(p3->z_axis_max());
        }
      }

    } else if(first_func(f1,f2)) {

      if(f1) {

        if(x_axis_automated) {
          float xmn = f1->x_min();
          float xmx = f1->x_max();
          if(xmx<=xmn) {
            xmn = -1;
            xmx = 1;
          }
          m_x_axis_data.set_min_value(xmn);
          m_x_axis_data.set_max_value(xmx);
        }

        if(y_axis_automated) {
          float xmn = m_x_axis_data.min_value();
          float xmx = m_x_axis_data.max_value();
          unsigned int nstp = f1->x_steps();
          nstp = nstp <=0 ? curve_number_of_points.value(): nstp;

          float df = (xmx - xmn)/nstp;
          bool problem = false;
          float vmin;
          if(!f1->value(xmn,vmin)) problem = true;
          float vmax = vmin;
          for(unsigned int ibin=0;ibin<=nstp;ibin++) {
            float xx = xmn + ibin * df;
            float val;
            if(!f1->value(xx,val)) problem = true;
            vmax = mx<float>(vmax,val);
            vmin = mn<float>(vmin,val);
          }
          if(problem) {
            a_out << "tools::sg::plotter :"
                  << " problem when getting some function value."
                  << std::endl;
          }
          m_y_axis_data.set_min_value(vmin);
          m_y_axis_data.set_max_value(vmax);
          m_y_axis_data.adjust();
        }

      } else if(f2) {
        if(x_axis_automated) {
          float xmn = f2->x_min();
          float xmx = f2->x_max();
          if(xmx<=xmn) {
            xmn = -1;
            xmx = 1;
          }
          m_x_axis_data.set_min_value(xmn);
          m_x_axis_data.set_max_value(xmx);
        }

        if(y_axis_automated) {
          float ymn =  f2->y_min();
          float ymx =  f2->y_max();
          if(ymx<=ymn) {
            ymn = -1;
            ymx = 1;
          }
          m_y_axis_data.set_min_value(ymn);
          m_y_axis_data.set_max_value(ymx);
        }

        if(z_axis_automated) {

          float xmn = m_x_axis_data.min_value();
          float xmx = m_x_axis_data.max_value();
          int nx = f2->x_steps();
          nx = nx <=0 ? curve_number_of_points.value() : nx;

          float ymn = m_y_axis_data.min_value();
          float ymx = m_y_axis_data.max_value();
          int ny = f2->y_steps();
          ny = ny <=0 ? curve_number_of_points.value() : ny;

          float dfx = (xmx - xmn)/nx;
          float dfy = (ymx - ymn)/ny;

          bool problem = false;
          float vmin;
          if(!f2->value(xmn,ymn,vmin)) problem = true;
          float vmax = vmin;
          for(int jbin=ny-1;jbin>=0;jbin--) {
            for(int ibin=nx-1;ibin>=0;ibin--) {
              float xx = xmn + ibin * dfx;
              float yy = ymn + jbin * dfy;
              float val;
              if(!f2->value(xx,yy,val)) problem = true;
              vmin = mn<float>(vmin,val);
              vmax = mx<float>(vmax,val);
            }
          }
          if(problem) {
            a_out << "tools::sg::plotter :"
                  << " problem when getting some function value."
                  << std::endl;
          }
          m_z_axis_data.set_min_value(vmin);
          m_z_axis_data.set_max_value(vmax);
          m_z_axis_data.adjust();
        }
      }
    }
  }
  void update_shape(){
    m_shape = get_shape();
    //uuuu if(shapeAutomated) {
    //  shape.setValue(m_shape);
    //}
  }

  void update_axis(std::ostream& a_out,sg::axis& a_axis,data_axis& a_data){
    a_axis.minimum_value = a_data.min_value();
    a_axis.maximum_value = a_data.max_value();
    a_axis.is_log = a_data.is_log();
    a_axis.update_sg(a_out); // So that the grid be correct.
    a_axis.reset_touched();
  }

  void update_x_axis_2D(){
    float XSIZ = width;
    float XMGL = left_margin;
    float XMGR = right_margin;
    float wData = XSIZ-XMGL-XMGR;

    //m_x_axis.verbose.setValue(verbose);
    m_x_axis.tick_up = true;
    m_x_axis.width = wData;

   {text_style& style = m_x_axis.labels_style();
    if(!style.enforced.value()) { //gopaw may enforce style.
      style.x_orientation = vec3f(1,0,0);
      style.y_orientation = vec3f(0,1,0);
      style.hjust = center;
      style.vjust = top;
    }}

   {text_style& style = m_x_axis.title_style();
    style.x_orientation = vec3f(1,0,0);
    style.y_orientation = vec3f(0,1,0);
    style.hjust = m_x_axis.title_hjust;
    style.vjust = top;}

   {text_style& style = m_x_axis.mag_style();
    style.hjust = left;
    style.vjust = bottom;}

    m_x_axis_matrix.set_translate(0,0,_zaxis());
  }

  void update_y_axis_2D(){
    float YSIZ = height;
    float YMGL = bottom_margin;
    float YMGU = top_margin;
    float hData = YSIZ-YMGL-YMGU;

    //m_x_axis.verbose.setValue(verbose);
    m_y_axis.tick_up.value(true);
    m_y_axis.width.value(hData);

   {text_style& style = m_y_axis.labels_style();
    if(!style.enforced.value()) {
      style.x_orientation = vec3f(0,1,0);
      style.y_orientation = vec3f(1,0,0);
      style.hjust = right;
      style.vjust = middle;
    }}

   {text_style& style = m_y_axis.title_style();
    style.x_orientation = vec3f(1,0,0);
    style.y_orientation = vec3f(0,-1,0);
    style.hjust = m_y_axis.title_hjust;
    style.vjust = bottom;}

   {text_style& style = m_y_axis.mag_style();
    style.x_orientation = vec3f(0,1,0);
    style.y_orientation = vec3f(1,0,0);
    style.hjust = right;
    style.vjust = bottom;}

   {mat4f& mtx = m_y_axis_matrix.mtx.value();
    mtx.set_translate(0,0,_zaxis());
    mtx.mul_rotate(0,1,0,fpi());
    mtx.mul_rotate(0,0,1,fhalf_pi());}
  }

  void update_z_axis_2D(){
    m_z_axis.width = 0;
    m_z_axis_matrix.set_identity();
  }

  void update_x_axis_3D(){
    float XSIZ = width;
    float XMGL = left_margin;
    float XMGR = right_margin;
    float wData = XSIZ-XMGL-XMGR;

    //m_x_axis.verbose.setValue(verbose);
    m_x_axis.tick_up = false;
    m_x_axis.width = wData;

   {text_style& style = m_x_axis.labels_style();
    if(!style.enforced.value()) {
      //style->font_name = SbFont_Hershey; //Enforce Hershey.
      style.x_orientation = vec3f(1,0,0);
      style.y_orientation = vec3f(0,1,0);
      style.hjust = center;
      style.vjust = top;
    }}

   {text_style& style = m_x_axis.title_style();
    style.x_orientation = vec3f(1,0,0);
    style.y_orientation = vec3f(0,1,0);
    style.hjust = right;
    style.vjust = top;}

   //{text_style& style = m_x_axis.mag_style();
   // style.hjust = left;
   // style.vjust = bottom;}

    m_x_axis_matrix.set_rotate(1,0,0,fhalf_pi());

  }

  void update_y_axis_3D(){
    float YSIZ = height;
    float YMGL = bottom_margin;
    float YMGU = top_margin;
    float hData = YSIZ-YMGL-YMGU;

    //m_x_axis.verbose.setValue(verbose);
    m_y_axis.tick_up = false;
    m_y_axis.width = hData;

   {text_style& style = m_y_axis.labels_style();
    if(!style.enforced.value()) {
      //style->fontName.setValue(SbFont_Hershey); //Enforce Hershey.
      style.x_orientation = vec3f(-1,0,0);
      style.y_orientation = vec3f( 0,1,0);
      style.hjust = center;
      style.vjust = top;
    }}

   {text_style& style = m_y_axis.title_style();
    style.x_orientation = vec3f(-1,0,0);
    style.y_orientation = vec3f( 0,1,0);
    style.hjust = left;
    style.vjust = top;}

   //{text_style& style = m_y_axis.mag_style();
   // style.x_orientation = vec3f(0,1,0);
   // style.y_orientation = vec3f(1,0,0);
   // style.hjust = right;
   // style.vjust = bottom;}

   {mat4f& mtx = m_y_axis_matrix.mtx.value();
    mtx.set_rotate(0,1,0,fhalf_pi());
    mtx.mul_rotate(0,0,1,fhalf_pi());}
  }

  void update_z_axis_3D(){
    float ZSIZ = depth;
    float ZMGD = down_margin;
    float ZMGU = up_margin;
    float dData = ZSIZ-ZMGD-ZMGU;

    m_z_axis.tick_up = false;
    m_z_axis.width = dData;

   {text_style& style = m_z_axis.labels_style();
    if(!style.enforced.value()) {
      //style->fontName.setValue(SbFont_Hershey); //Enforce Hershey.
      style.x_orientation = vec3f(0,1,0);
      style.y_orientation = vec3f(1,0,0);
      style.hjust = right;
      style.vjust = middle;
    }}

   {text_style& style = m_z_axis.title_style();
    style.x_orientation = vec3f(0,1,0);
    style.y_orientation = vec3f(1,0,0);
    style.hjust = right;
    style.vjust = bottom;}

   //{text_style& style = m_z_axis.mag_style();
   // style.hjust = center;
   // style.vjust = bottom;}

   {mat4f& mtx = m_z_axis_matrix.mtx.value();
    mtx.set_translate(0,m_y_axis.width.value(),0);
    mtx.mul_rotate(0,0,1,-fhalf_pi());
    mtx.mul_rotate(0,1,0,-fhalf_pi());}

  }

  void update_cmap(std::ostream& a_out,const base_colormap& a_cmap){
    if(!colormap_visible.value()) return;

    size_t valn = a_cmap.valn();
    if(!valn) return;
    size_t coln = a_cmap.colorn();
    if(!coln) return;

    float XSIZ = width;
    float XMGL = left_margin;
    float XMGR = right_margin;
    float wData = XSIZ-XMGL-XMGR;

    float YSIZ = height;
    float YMGL = bottom_margin;
    float YMGU = top_margin;
    float hData = YSIZ-YMGL-YMGU;

    float hcmap = hData;

   {mat4f& mtx = m_cmap_matrix.mtx.value();
    if(m_shape==xy) {
      mtx = m_layout.mtx.value();
      mtx.mul_translate(0,0,_zgrid());
    } else {
      float ZSIZ = depth;
      float ZMGD = down_margin;
      float ZMGU = up_margin;
      float dData = ZSIZ-ZMGD-ZMGU;
      hcmap = dData;
      if(colormap_attached.value()) {
        mtx = m_layout.mtx.value();
        mtx.mul_rotate(1,0,0,90.0F*fdeg2rad());
      } else { //OpenPAW
        float zz = -depth*0.5f;
        mtx.set_translate(-XSIZ/2+XMGL,-YSIZ/2+YMGL,zz); //applied first
      }
    }}

    float w  = XMGR*0.3F;
    float xx = wData+XMGR*0.1F;
    float zz = 0;

    float yy = 0;
    float h = hcmap/float(coln);

    // colored cells :
   {m_cmap_cells_sep.clear();
    m_cmap_cells_sep.add(new normal);
    for(unsigned int index=0;index<coln;index++)        {
      rgba* mat = new rgba();
      mat->color = a_cmap.color(index);
      m_cmap_cells_sep.add(mat);

      vertices* vtxs = new vertices;
      vtxs->mode = gl::triangle_fan();
      m_cmap_cells_sep.add(vtxs);

      vtxs->add(xx      ,yy     ,zz);
      vtxs->add(xx + w  ,yy     ,zz);
      vtxs->add(xx + w  ,yy + h ,zz);
      vtxs->add(xx      ,yy + h ,zz);

      yy += h;
    }}

    // surrounding box :
   {rgba* mat = new rgba();
    mat->color = colorf_black();
    m_cmap_cells_sep.add(mat);

    draw_style* ds = new draw_style;
    ds->style = draw_lines;
    ds->line_pattern = line_solid;
    ds->line_width = 1;
    m_cmap_cells_sep.add(ds);

    vertices* vtxs = new vertices;
    vtxs->mode = gl::line_strip();
    m_cmap_cells_sep.add(vtxs);

    vtxs->add(xx      ,0     ,zz);
    vtxs->add(xx + w  ,0     ,zz);
    vtxs->add(xx + w  ,hcmap ,zz);
    vtxs->add(xx      ,hcmap ,zz);
    vtxs->add(xx      ,0     ,zz);}

    if(!colormap_axis_visible.value()) {
      m_cmap_axis.width = 0;
    } else {

    // right axis :
    mat4f& mtx = m_cmap_axis_matrix.mtx.value();
    mtx.set_identity();

    zz += _zoffset()*0.01f;

    if(safe_cast<base_colormap,by_value_colormap>(a_cmap)) {
      if(colormap_axis_labeling.value()==cells) {
        if((valn+1)==coln) { // <col> <num> <col> ... <num> <col>
          mtx.set_translate(xx+w,h,zz);
        } else {
          mtx.set_translate(xx+w,0,zz);
        }
      } else {
        mtx.set_translate(xx+w,0,zz);
      }
    } else { //grey_scale,grey_scale_inverse,violet_to_red
      mtx.set_translate(xx+w,0,zz);
    }

    mtx.mul_rotate(0,0,1,fhalf_pi());

    m_cmap_axis.title = "";
    m_cmap_axis.tick_up = true;
    //m_cmap_axis.label_to_axis = 0.01F;
    //m_cmap_axis.label_height = 0.10F;
    //m_cmap_axis.ttf_scale = 10.0F;

    if(safe_cast<base_colormap,by_value_colormap>(a_cmap)) {
      if(colormap_axis_labeling.value()==cells) {
        if((valn+1)==coln) { // <col> <num> <col> ... <num> <col>
          m_cmap_axis.width = hcmap-2*h;
          m_cmap_axis.modeling = tick_modeling_none();
          m_cmap_axis.tick_number = uint32(valn);
          m_cmap_axis.labels.clear();
          m_cmap_axis.coords.clear();
          for(unsigned int index=0;index<valn;index++)        {
            //FIXME : for the labels, have a "mag" logic similar to SoAxis.
            char tmp[32];
            snpf(tmp,sizeof(tmp),"%g",a_cmap.value(index));
            m_cmap_axis.labels.add(tmp);
            m_cmap_axis.coords.add(h*index);
          }
        } else if((coln+1)==valn) { // <num> <col> <num> ... <col> <num>
          m_cmap_axis.width = hcmap;
          m_cmap_axis.modeling = tick_modeling_none();
          m_cmap_axis.tick_number = uint32(valn);
          m_cmap_axis.labels.clear();
          m_cmap_axis.coords.clear();
          for(unsigned int index=0;index<valn;index++)        {
            //FIXME : for the labels, have a "mag" logic similar to SoAxis.
            char tmp[32];
            snpf(tmp,sizeof(tmp),"%g",a_cmap.value(index));
            m_cmap_axis.labels.add(tmp);
            m_cmap_axis.coords.add(h*index);
          }
        } else {
          a_out << "tools::sg::plotter::update_cmap :"
                << " inconsistent by value colormap."
                << std::endl;
        }
      } else {
        m_cmap_axis.modeling = tick_modeling_hippo();
        m_cmap_axis.width = hcmap;
        m_cmap_axis.minimum_value = a_cmap.value(0);
        m_cmap_axis.maximum_value = a_cmap.value(uint32(valn)-1);
      }
    } else { //grey_scale,grey_scale_inverse,violet_to_red
      m_cmap_axis.modeling = tick_modeling_hippo();
      m_cmap_axis.width = hcmap;
      m_cmap_axis.minimum_value = a_cmap.value(0);
      m_cmap_axis.maximum_value = a_cmap.value(uint32(valn)-1);
    }

   {text_style& style = m_cmap_axis.labels_style();
    style.x_orientation = vec3f(0,-1,0);
    style.y_orientation = vec3f(1,0,0);
    style.hjust = left;
    style.vjust = middle;}

   {text_style& style = m_cmap_axis.mag_style();
    style.hjust = center;
    style.vjust = bottom;}

    }//end axis
  }

  void update_primitives(std::ostream& a_out) {
//    if(primitives_enforced.value()) {
      m_primitives_sep.clear();
      tools_vforcit(plotprim*,m_primitives,it) {
        if(plottable_text* ptext = safe_cast<plotprim,plottable_text>(*(*it))) {
          update_primitive_text(*ptext);
        } else if(plottable_box* pbox = safe_cast<plotprim,plottable_box>(*(*it))) {
          update_primitive_box(a_out,*pbox);
        } else if(plottable_ellipse* pellipse = safe_cast<plotprim,plottable_ellipse>(*(*it))) {
          update_primitive_ellipse(a_out,*pellipse);
        } else if(plottable_img* pimg = safe_cast<plotprim,plottable_img>(*(*it))) {
          update_primitive_img(a_out,*pimg);
	}
      }
    //}
  }

protected: //vis bins
  void update_bins1D_xy(std::ostream& a_out,
                        const bins1D& a_bins,
                        const style& a_data_style,
                        const style& a_left_hatch_style,
                        const style& a_right_hatch_style,
                        const style& a_errors_style,
                        int a_index,
                      /*SoStyle& aGraphicStyle,
                        int aIndex1D,
                        const std::vector<SbPlottableBins1D*>& a_bins1DList,
                        const SbPList& a_bins1DListSwMnMx,*/
                        bool /*aSuperpose*/,
                        const rep_box& a_box_x,
                        const rep_box& a_box_y,
                        float a_zz){

    //char sid[128];
    //::sprintf(sid,"tools::sg::bins1D/0x%lx",
    //  (unsigned long)const_cast<bins1D*>(&a_bins));

  //bool hbe = a_bins.has_entries_per_bin();

    float bmin = 0;
    float bmax = 0;

    size_t xnbin = a_bins.bins();
    std::vector<rep_bin1D> bins(xnbin);
   {bool first = true;
    for(size_t ibin=0;ibin<xnbin;ibin++) {
    //if(hbe && (a_bins.bin_entries(size_t(ibin))<=0)) continue;
      float val = a_bins.bin_Sw(int(ibin));
      float xx = float(a_bins.bin_lower_edge(int(ibin)));
      float xe = float(a_bins.bin_upper_edge(int(ibin)));
      bins[ibin] = rep_bin1D(xx,xe,0,val);
      if(first) {
        first = false;
        bmin = val;
        bmax = val;
      } else {
        bmin = mn<float>(bmin,val);
        bmax = mx<float>(bmax,val);
      }
    }}

    //a_bins.bins_Sw_range(bmin,bmax,false);

    //modeling_profile could override errors_visible.
    bool errors_visible = a_errors_style.visible;

    if(a_data_style.visible) {

      painting_policy painting = a_data_style.painting;
      if(painting==painting_by_value) {
        m_bins_cmaps[a_index] = new by_value_colormap(a_out,m_cmaps,a_data_style.color_mapping);
      } else if( (painting==painting_grey_scale) ||
                 (painting==painting_grey_scale_inverse) ||
                 (painting==painting_violet_to_red) ){
       {float dbins = bmax-bmin;
        if(dbins!=0.0F) {
          for(size_t index=0;index<xnbin;index++) bins[index].m_ratio = (a_bins.bin_Sw(int(index))-bmin)/dbins;
        }}
        if(painting==painting_grey_scale) {
          m_bins_cmaps[a_index] = new grey_scale_colormap(bmin,bmax,50);
        } else if(painting==painting_grey_scale_inverse) {
          m_bins_cmaps[a_index] = new grey_scale_inverse_colormap(bmin,bmax,50);
        } else if(painting==painting_violet_to_red) {
          m_bins_cmaps[a_index] = new violet_to_red_colormap(bmin,bmax,50);
        }
      } else {
        m_bins_cmaps[a_index] = new const_colormap(a_data_style.color);
      }

      if(a_bins.is_profile()) {
        // enforce with a_data_style, a bins rep with :
        //  rep_bins1D_xy_points
        // AND :
        //  rep_errors_plus for bins rep.
        // NOTE : a_data_style.modeling not used for the moment.
        //printf("debug : bins is profile : modeling %s\n",a_data_style.modeling.value().c_str());

        style data_style = a_data_style;
        data_style.modeling = modeling_markers();
        rep_bins1D_xy_points(a_out,data_style,*(m_bins_cmaps[a_index]),bins,a_box_x,a_box_y,a_zz);

        std::vector<float> bars(xnbin);
        for(size_t ibin=0;ibin<xnbin;ibin++) bars[ibin] = a_bins.bin_error(int(ibin));

        rep_errors_plus_xy(a_out,a_data_style,bins,a_box_x,a_box_y,bars,a_zz+_zerrors());
        errors_visible = false;

      } else {

        const std::string& modeling = a_data_style.modeling;

        //bool one_node = false;
        //bool oneNode = false;
       //{int nlimit = aGraphicStyle.multiNodeLimit.value();
        //if(nlimit!=NoLimit) {
        //  oneNode = (xnbin>nlimit?true:false);
        //}}

        bool _bar_chart = false;

        //char sid_bin[128];
        //::sprintf(sid_bin,"SbBin1D/0x%lx",(unsigned long)&a_bins);

        if((modeling==modeling_points())||(modeling==modeling_markers())){
          //if(oneNode) {
          //  rep_bins1D_xy_points_one(binsNode,aGraphicStyle,
          //                       bins,a_box_x,a_box_y,a_zz,std::string(sid));
          //} else {
            rep_bins1D_xy_points(a_out,a_data_style,
                                 *(m_bins_cmaps[a_index]),
                                 bins,a_box_x,a_box_y,a_zz);
          //}
        } else if(modeling==modeling_boxes()) {
          //if(oneNode) {
          //  rep_bins1D_xy_boxes_one(binsNode,aGraphicStyle,
          //                      bins,a_box_x,a_box_y,a_zz,std::string(sid));
          //} else {
            rep_bins1D_xy_boxes(a_data_style,
                                *(m_bins_cmaps[a_index]),
                                bins,a_box_x,a_box_y,a_zz //,std::string(sid_bin)
                                );
          //}

        } else if(modeling==modeling_wire_boxes()) {
          //if(oneNode) {
          //  rep_bins1D_xy_wire_boxes_one(binsNode,aGraphicStyle,barChart,
          //                           bins,a_box_x,a_box_y,a_zz,std::string(sid));
          //} else {
            rep_bins1D_xy_wire_boxes(a_data_style,*(m_bins_cmaps[a_index]),bins,a_box_x,a_box_y,a_zz,false);
          //}
        } else if(modeling==modeling_bar_chart()) {
           _bar_chart = true;
          //if(oneNode) {
          //  rep_bins1D_xy_wire_boxes_one(binsNode,aGraphicStyle,barChart,
          //                           bins,a_box_x,a_box_y,a_zz,std::string(sid));
          //} else {
            rep_bins1D_xy_wire_boxes(a_data_style,*(m_bins_cmaps[a_index]),bins,a_box_x,a_box_y,a_zz,true);
          //}

        } else if(modeling==modeling_lines()){
          rep_bins1D_xy_lines_one(a_data_style,bins,a_box_x,a_box_y,a_zz/*,std::string(sid)*/);
        } else if(modeling==modeling_curve()){
          rep_bins1D_xy_curve_one(a_out,a_data_style,bins,a_box_x,a_box_y,a_zz/*,std::string(sid)*/);

        } else if(modeling==modeling_top_lines_boxes()) { //gopaw. pawex24, k_plus.
          style _style;_style.color = colorf_white();
          rep_bins1D_xy_boxes(_style,*(m_bins_cmaps[a_index]),bins,a_box_x,a_box_y,a_zz);
          rep_bins1D_xy_top_lines(a_data_style,*(m_bins_cmaps[a_index]),bins,a_box_x,a_box_y,a_zz+_zhatch());

        } else { //default modeling==modeling_top_lines()
          rep_bins1D_xy_top_lines(a_data_style,*(m_bins_cmaps[a_index]),bins,a_box_x,a_box_y,a_zz/*,std::string(sid_bin)*/);

        }

        hatching_policy hatching = a_data_style.hatching.value();
	//::printf("debug : bins1D %d hatching : %d\n",a_index,hatching);
        if(hatching!=hatching_none) {
          // WARNING : must come AFTER rep_bins1_xy.
          if((hatching==hatching_right)||((hatching==hatching_left_and_right))) {
            //if(oneNode) {
              //repHatch1D_xy_one(binsNode,aRightHatchStyle,barChart,bins,a_box_x,a_box_y,a_zz+_zhatch(),std::string(sid));
            //} else {
              rep_hatch1D_xy(a_right_hatch_style,bins,a_box_x,a_box_y,a_zz+_zhatch(),_bar_chart);
            //}
          }
          if((hatching==hatching_left)||((hatching==hatching_left_and_right))) {
            //if(oneNode) {
              //repHatch1D_xy_one(binsNode,aLeftHatchStyle,barChart,bins,a_box_x,a_box_y,a_zz+_zhatch(),std::string(sid));
            //} else {
              rep_hatch1D_xy(a_left_hatch_style,bins,a_box_x,a_box_y,a_zz+_zhatch(),_bar_chart);
            //}
          }
        }

      } //end !is_profile.
    } //end data_style visible

    // Errors :
    if(errors_visible) {
      std::vector<float> bars(xnbin);
      for(size_t ibin=0;ibin<xnbin;ibin++) bars[ibin] = a_bins.bin_error(int(ibin));
      const std::string& modeling = a_errors_style.modeling;
      if(modeling==modeling_plus()) {
        rep_errors_plus_xy(a_out,a_errors_style,bins,a_box_x,a_box_y,bars,a_zz+_zerrors());
      } else { //modeling_I()
        rep_errors_I_xy(a_out,a_errors_style,bins,a_box_x,a_box_y,bars,a_zz+_zerrors());
      }
    }

  }

  static bool bins2D_to_func(const bins2D& a_bins,float a_X,float a_Y,float& a_value){
    unsigned int xn = a_bins.x_bins();
    float xmn = a_bins.x_axis_min();
    float xmx = a_bins.x_axis_max();
    unsigned int yn = a_bins.y_bins();
    float ymn = a_bins.y_axis_min();
    float ymx = a_bins.y_axis_max();

    float dx = (xmx-xmn)/xn;
    float dy = (ymx-ymn)/yn;
    int ibin = (int)((a_X-xmn)/dx);
    int jbin = (int)((a_Y-ymn)/dy);

    if((ibin<0)||(ibin>=int(xn))) {a_value=0;return false;}
    if((jbin<0)||(jbin>=int(yn))) {a_value=0;return false;}

    float xx_0 = a_bins.bin_lower_edge_x(ibin);
    //float xe_0 = a_bins.bin_upper_edge_x(ibin);
    float xx_1 = a_bins.bin_lower_edge_x(ibin+1);
    //float xe_1 = a_bins.bin_upper_edge_x(ibin+1);

    float yy_0 = a_bins.bin_lower_edge_y(jbin);
    //float ye_0 = a_bins.bin_upper_edge_y(jbin);
    float yy_1 = a_bins.bin_lower_edge_y(jbin+1);
    //float ye_1 = a_bins.bin_upper_edge_y(jbin+1);

    float val1 = a_bins.bin_Sw(ibin,jbin);
    float val2 = a_bins.bin_Sw(ibin+1,jbin);
    //float val3 = a_bins.getBinSumOfWeights(ibin+1,jbin+1);
    float val4 = a_bins.bin_Sw(ibin,jbin+1);

    // Interpolate :
    vec3f p1(xx_0,yy_0,val1);
    vec3f p2(xx_1,yy_0,val2);
    //vec3f p3(xx_1,yy_1,val3);
    vec3f p4(xx_0,yy_1,val4);

    //FIXME : case of (x,y) in (p2,p3,p4)

    plane<vec3f> _plane(p1,p2,p4);
    vec3f pt;
    line<vec3f> _line(vec3f(a_X,a_Y,0),vec3f(a_X,a_Y,10));
    _plane.intersect(_line,pt);

    a_value = pt[2];
    return true;
  }

  typedef struct {
    const func2D* m_func2D;
    const bins2D* m_bins2D;
    double m_limits[4];
    double m_limits_in[4];
    bool m_problem;
  } SbFunc;

  static double bins2D_to_contour(double a_X,double a_Y,void* aData) {
    SbFunc* func =(SbFunc*)aData;
    if( (a_X<func->m_limits_in[0])||
        (a_X>func->m_limits_in[1])||
        (a_Y<func->m_limits_in[2])||
        (a_Y>func->m_limits_in[3])
      ) return -FLT_MAX;
    float value;
    if(!bins2D_to_func(*(func->m_bins2D),(float)a_X,(float)a_Y,value)) func->m_problem = true;
    return value;
  }

  static double log_bins2D_to_contour(double a_X,double a_Y,void* aData) {
    SbFunc* func =(SbFunc*)aData;
    if( (a_X<func->m_limits_in[0])||
        (a_X>func->m_limits_in[1])||
        (a_Y<func->m_limits_in[2])||
        (a_Y>func->m_limits_in[3])
      ) return -FLT_MAX;
    float value;
    if(!bins2D_to_func(*(func->m_bins2D),(float)a_X,(float)a_Y,value)) func->m_problem = true;
    return take_log(value);
  }

  void update_bins2D_xy(std::ostream& a_out,
                        const bins2D& a_bins,
                        const style& a_data_style,
                        int a_index,
                        const rep_box& a_box_x,
                        const rep_box& a_box_y,
                        const rep_box& a_box_z,
                        float a_zz){

    //a_out << "tools::sg::update_bins2D_xy : begin :" << std::endl;

    if(!a_data_style.visible) return;

    //a_out << "tools::sg::update_bins2D_xy : visible :" << std::endl;

    unsigned int xnbin = a_bins.x_bins();
    unsigned int ynbin = a_bins.y_bins();

    const std::string& modeling = a_data_style.modeling;

    if( (modeling==modeling_curve()) || (modeling==modeling_filled_curve()) ){

      a_out << "tools::sg::update_bins2D_xy : modeling_curve :" << std::endl;

      painting_policy painting = a_data_style.painting;

      float zmin = a_box_z.m_pos;
      float dz = a_box_z.m_width;
      bool zlog = a_box_z.m_log;

      float xmn =  m_x_axis_data.min_value();
      float xmx =  m_x_axis_data.max_value();
      float ymn =  m_y_axis_data.min_value();
      float ymx =  m_y_axis_data.max_value();

      clist_contour list_contour;
      //int nFir = 32;
      int nFir = 128;
      list_contour.set_first_grid(nFir,nFir); //Default : 32,32
      //int nSec = 256;
      int nSec = 512; //slower than 256
      list_contour.set_secondary_grid(nSec,nSec); //Default : 256,256.

      double limits[4];
      // User limits :
      limits[0] = xmn;
      limits[1] = xmx;
      limits[2] = ymn;
      limits[3] = ymx;

      SbFunc sbFunc;
      sbFunc.m_func2D = 0;
      sbFunc.m_problem = false;
      sbFunc.m_bins2D = &a_bins;
      sbFunc.m_limits_in[0] = limits[0];
      sbFunc.m_limits_in[1] = limits[1];
      sbFunc.m_limits_in[2] = limits[2];
      sbFunc.m_limits_in[3] = limits[3];

      // Extend the grid to have some borders in order to close contours :
      int n = nSec - 2 * 10;
      double dx = (limits[1]-limits[0]) /n;
      double dy = (limits[3]-limits[2]) /n;
      limits[0] = limits[0] - 10 * dx;
      limits[1] = limits[1] + 10 * dx;
      limits[2] = limits[2] - 10 * dy;
      limits[3] = limits[3] + 10 * dy;

      sbFunc.m_limits[0] = limits[0];
      sbFunc.m_limits[1] = limits[1];
      sbFunc.m_limits[2] = limits[2];
      sbFunc.m_limits[3] = limits[3];

      list_contour.set_limits(limits);

      if(levels.size()) {
        size_t zn = levels.size();
        std::vector<double> zs(zn);
        for(size_t zi=0;zi<zn;zi++) zs[zi] = levels[zi];
        list_contour.set_planes(zs);
      } else {
        unsigned int zn = number_of_levels.value();
        if(zn<=0) zn = 1;
        std::vector<double> zs(zn+1);
        float zmax = zmin + dz;
        double zd = (zmax-zmin)/zn;
        for(unsigned int zi=0;zi<=zn;zi++) zs[zi] = zmin + zi * zd;
        list_contour.set_planes(zs);
      }

      if(zlog)
        list_contour.set_field_fcn(log_bins2D_to_contour,(void*)&sbFunc);
      else
        list_contour.set_field_fcn(bins2D_to_contour,(void*)&sbFunc);

#ifdef INLIBS_SG_PLOTTER_TIMING
      atime _start = atime::now();
#endif
      list_contour.ccontour::generate();
#ifdef INLIBS_SG_PLOTTER_TIMING
      a_out << "tools::sg::update_bins2D_xy : contour generate elapsed " << atime::elapsed(_start) << "." << std::endl;
      _start = atime::now();
#endif

      if(!list_contour.compact_strips ()) {
        a_out << "tools::sg::plotter::updateBins2D_XY : clist_contour::compact_strips () : failure." << std::endl;
      } else {
#ifdef INLIBS_SG_PLOTTER_TIMING
        a_out << "tools::sg::update_bins2D_xy : contour compact strips elapsed " << atime::elapsed(_start) << "." << std::endl;
#endif
        if( (painting==painting_by_level) || (painting==painting_by_value) ){
          m_bins_cmaps[a_index] = new by_value_colormap(a_out,m_cmaps,a_data_style.color_mapping);
          //bool zlog = a_box_z.m_log;
          if(zlog) m_bins_cmaps[a_index]->set_PAW_coloring();
        } else {
          m_bins_cmaps[a_index] = new const_colormap(a_data_style.color);
        }

        if(modeling==modeling_filled_curve()) {
          rep_contour_xy_filled(a_out,a_data_style,
                                painting,*(m_bins_cmaps[a_index]),
                                list_contour,a_box_x,a_box_y,a_box_z,a_zz /*,std::string(sid.c_str())*/);
        } else {
          rep_contour_xy(a_out,a_data_style,
                         painting,*(m_bins_cmaps[a_index]),
                         list_contour,a_box_x,a_box_y,a_box_z,a_zz /*,std::string(sid.c_str())*/);
        }

      }

      if(sbFunc.m_problem) {
        a_out << "tools::sg::plotter::updateFunction_XY(SbPlottableFunction2D) : "
	      << "problem when getting some function value." << std::endl;
      }

    } else {

      bool hbe = a_bins.has_entries_per_bin();

      float bmin = 0;
      float bmax = 0;

      std::vector<rep_bin2D> bins;
     {bool first = true;
      for(int jbin=ynbin-1;jbin>=0;jbin--) {
        for(int ibin=xnbin-1;ibin>=0;ibin--) {
          if(hbe && (a_bins.bin_entries(ibin,jbin)<=0)) continue;

          float val = a_bins.bin_Sw(ibin,jbin);

          float xx = a_bins.bin_lower_edge_x(ibin);
          float xe = a_bins.bin_upper_edge_x(ibin);
          float yy = a_bins.bin_lower_edge_y(jbin);
          float ye = a_bins.bin_upper_edge_y(jbin);

          bins.push_back(rep_bin2D(xx,xe,yy,ye,val,ibin,jbin));

          if(first) {
            first = false;
            bmin = val;
            bmax = val;
          } else {
            bmin = mn<float>(bmin,val);
            bmax = mx<float>(bmax,val);
          }
        }
      }}
      size_t number = bins.size();

      //a_bins.bins_Sw_range(bmin,bmax,false);

      painting_policy painting = a_data_style.painting;
      if(painting==painting_by_value) {
        m_bins_cmaps[a_index] = new by_value_colormap(a_out,m_cmaps,a_data_style.color_mapping);
      } else if( (painting==painting_grey_scale) ||
                 (painting==painting_grey_scale_inverse) ||
                 (painting==painting_violet_to_red) ){
       {float dbins = bmax-bmin;
        if(dbins!=0.0F) {
          for(size_t index=0;index<number;index++) {
            bins[index].m_ratio = (bins[index].m_val-bmin)/dbins;
          }
        }}
        if(painting==painting_grey_scale) {
          m_bins_cmaps[a_index] = new grey_scale_colormap(bmin,bmax,50);
        } else if(painting==painting_grey_scale_inverse) {
          m_bins_cmaps[a_index] = new grey_scale_inverse_colormap(bmin,bmax,50);
        } else if(painting==painting_violet_to_red) {
          m_bins_cmaps[a_index] = new violet_to_red_colormap(bmin,bmax,50);
        }
      } else {
        m_bins_cmaps[a_index] = new const_colormap(a_data_style.color);
      }

      if(modeling==modeling_solid()) {
        //a_out << "tools::sg::update_bins2D_xy : modeling_solid :" << std::endl;

        rep_bins2D_xy_solid(a_data_style,*(m_bins_cmaps[a_index]),bins,a_box_x,a_box_y,a_zz);

      } else if(modeling==modeling_points()) {
        //a_out << "tools::sg::update_bins2D_xy : modeling_points :" << std::endl;
        rep_bins2D_xy_random_one(a_data_style,bins,a_box_x,a_box_y,bmin,bmax,a_zz/*,std::string(sid)*/);

      } else if(modeling==modeling_wire_boxes()) {
        //a_out << "tools::sg::update_bins2D_xy : modeling_wire_boxes :" << std::endl;

        // one node decision :
      /*bool oneNode = false;
       {int nlimit = aGraphicStyle.multiNodeLimit.value();
        if(nlimit!=NoLimit) {
          oneNode = (number>nlimit?true:false);
        }}*/

      /*if(oneNode) {
          rep_bins2D_xy_wire_box_one(a_data_style,bins,a_box_x,a_box_y,bmin,bmax,std::string(sid));
        } else {*/
          rep_bins2D_xy_wire_box(a_data_style,bins,a_box_x,a_box_y,bmin,bmax,a_zz/*,std::string(sid_bin)*/);
        //}

      } else if(modeling==modeling_texts()) {
        //a_out << "tools::sg::update_bins2D_xy : modeling_wire_texts :" << std::endl;

        // one node decision :
      //bool oneNode = false;
     //{int nlimit = aGraphicStyle.multiNodeLimit.value();
      // if(nlimit!=NoLimit) {
      //   oneNode = (number>nlimit?true:false);
      //}}

        //if(oneNode) {
        //  rep_bins2D_xy_text_one(binsNode,
        //                        aGraphicStyle,
        //                        bins,a_box_x,a_box_y,std::string(sid));
        //} else {
          rep_bins2D_xy_text(a_data_style,bins,a_box_x,a_box_y/*,std::string(sid_bin)*/);
       //}

      } else { //default rep modeling==modeling_boxes()
        //a_out << "tools::sg::update_bins2D_xy : modeling_<else> :" << std::endl;

        rep_bins2D_xy_box(a_data_style,bins,a_box_x,a_box_y,bmin,bmax,a_zz);

      }


    } //end if modeling

  }

  void update_func1D_xy(std::ostream& a_out,const func1D& a_func,
                        const style& a_style,const rep_box& a_box_x,const rep_box& a_box_y,float a_zz){

    //a_out << "debug : tools::sg::plotter::update_func1D_xy : modeling " << a_style.modeling.value() << " :" << std::endl;

    if(!a_style.visible) return;

    float xmn = m_x_axis_data.min_value();
    float xmx = m_x_axis_data.max_value();

    unsigned int nstp = a_func.x_steps();
    nstp = nstp <=0 ? curve_number_of_points.value() : nstp;

    float df = (xmx - xmn)/nstp;

    bool problem = false;
    std::vector<vec3f> points(nstp+1);
    for(unsigned int ibin=0;ibin<=nstp;ibin++) {
      float xx = xmn + ibin * df;
      float val;
      if(!a_func.value(xx,val)) problem = true;
      points[ibin].set_value(xx,val,a_zz);
    }
    if(problem) {
      a_out << "tools::sg::plotter::update_func1D_xy :"
            << " problem when getting some function value."
            << std::endl;
    }

    const std::string& modeling = a_style.modeling;

    if(modeling==modeling_points()){
      vertices* vtxs = new vertices;
      std::vector<float>& pts = vtxs->xyzs.values(); //npt*3
      clip_points_2D(points,a_box_x,a_box_y,pts);
      if(pts.size()) {
        //a_out << "debug : tools::sg::plotter::update_func1D_xy :"
        //      << " ptn " << pts.size()
        //      << std::endl;

        separator* sep = new separator;
        m_func_sep.add(sep);

        rgba* mat = new rgba();
        mat->color = a_style.color;
        sep->add(mat);

        draw_style* ds = new draw_style;
        ds->style = draw_points;
        ds->point_size = a_style.point_size;
        sep->add(ds);

        vtxs->mode = gl::points();
        sep->add(vtxs);
      } else {
        delete vtxs;
      }

    } else if(modeling==modeling_markers()){
      markers* _marks = new markers;
      std::vector<float>& pts = _marks->xyzs.values(); //npt*3
      clip_points_2D(points,a_box_x,a_box_y,pts);
      if(pts.size()) {
        //a_out << "debug : tools::sg::plotter::update_func1D_xy :"
        //      << " ptn " << pts.size()
        //      << std::endl;

        separator* sep = new separator;
        m_func_sep.add(sep);

        rgba* mat = new rgba();
        mat->color = a_style.color;
        sep->add(mat);

        _marks->size = a_style.marker_size;
        _marks->style = a_style.marker_style;
        sep->add(_marks);
      } else {
        delete _marks;
      }

    } else {

      vertices* vtxs = new vertices;
      std::vector<float>& pts = vtxs->xyzs.values(); //npt*3

      clip_polyline_2D(points,a_box_x,a_box_y,pts);
      if(pts.size()) {
        //a_out << "debug : tools::sg::plotter::update_func1D_xy : ptn " << pts.size() << std::endl;

        separator* sep = new separator;
        m_func_sep.add(sep);

        rgba* mat = new rgba();
        mat->color = a_style.color;
        sep->add(mat);

        draw_style* ds = new draw_style;
        ds->style = draw_lines;
        ds->line_pattern = a_style.line_pattern;
        ds->line_width = a_style.line_width;
        sep->add(ds);

        vtxs->mode = gl::line_strip();
        sep->add(vtxs);
      } else {
        delete vtxs;
      }
    }
  }

  static double function_to_contour(double a_X,double a_Y,void* aData) {
    SbFunc* func = (SbFunc*)aData;
    if( (a_X<func->m_limits_in[0])||
        (a_X>func->m_limits_in[1])||
        (a_Y<func->m_limits_in[2])||
        (a_Y>func->m_limits_in[3])
      ) return -FLT_MAX;
    float value;
    if(!func->m_func2D->value((float)a_X,(float)a_Y,value)) func->m_problem = true;
    return double(value);
  }
  static double log_function_to_contour(double a_X,double a_Y,void* aData) {
    SbFunc* func =(SbFunc*)aData;
    if( (a_X<func->m_limits_in[0])||
        (a_X>func->m_limits_in[1])||
        (a_Y<func->m_limits_in[2])||
        (a_Y>func->m_limits_in[3])
      ) return -FLT_MAX;
    float value;
    if(!func->m_func2D->value((float)a_X,(float)a_Y,value)) func->m_problem = true;
    return take_log(value);
  }

  void update_func2D_xy(std::ostream& a_out,const func2D& a_func,int a_index,style& a_data_style,
                        const rep_box& a_box_x,const rep_box& a_box_y,const rep_box& a_box_z,float a_zz){
    //a_out << "debug : tools::sg::plotter::update_func2D_xy(Function2D) : begin :" << std::endl;
    if(!a_data_style.visible.value()) return;

  //  std::string sid;
  // {std::string sp;
  //  if(!p2sx(&a_func,sp)){}
  //  sid = "SbFunction2D/"+sp;}

    const std::string& modeling = a_data_style.modeling.getValue();
    painting_policy painting = a_data_style.painting;

    if( (modeling==modeling_curve()) || (modeling==modeling_filled_curve()) ) {

      //a_out << "debug : tools::sg::plotter::update_func2D_xy(Function2D) : curve." << std::endl;

      float zmin = a_box_z.m_pos;
      float dz = a_box_z.m_width;
      bool zlog = a_box_z.m_log;

      float xmn = m_x_axis_data.min_value();
      float xmx = m_x_axis_data.max_value();
      float ymn = m_y_axis_data.min_value();
      float ymx = m_y_axis_data.max_value();

      clist_contour list_contour;
      //int nFir = 32;
      int nFir = 128;
      list_contour.set_first_grid(nFir,nFir); //Default : 32,32
      //int nSec = 256;
      int nSec = 512; //slower than 256
      list_contour.set_secondary_grid(nSec,nSec); //Default : 256,256.

      double limits[4];
      // User limits :
      limits[0] = xmn;
      limits[1] = xmx;
      limits[2] = ymn;
      limits[3] = ymx;

      SbFunc sbFunc;
      sbFunc.m_func2D = &a_func;
      sbFunc.m_problem = false;
      sbFunc.m_bins2D = 0;
      sbFunc.m_limits_in[0] = limits[0];
      sbFunc.m_limits_in[1] = limits[1];
      sbFunc.m_limits_in[2] = limits[2];
      sbFunc.m_limits_in[3] = limits[3];

      // Extend the grid to have some borders in order to close contours :
      int n = nSec - 2 * 10;
      double dx = (limits[1]-limits[0]) /n;
      double dy = (limits[3]-limits[2]) /n;
      limits[0] = limits[0] - 10 * dx;
      limits[1] = limits[1] + 10 * dx;
      limits[2] = limits[2] - 10 * dy;
      limits[3] = limits[3] + 10 * dy;

      sbFunc.m_limits[0] = limits[0];
      sbFunc.m_limits[1] = limits[1];
      sbFunc.m_limits[2] = limits[2];
      sbFunc.m_limits[3] = limits[3];

      list_contour.set_limits(limits);

      if(levels.getNum()) {
        size_t zn = levels.size();
        std::vector<double> zs(zn);
        for(size_t zi=0;zi<zn;zi++) zs[zi] = levels[zi];
        list_contour.set_planes(zs);
      } else {
        unsigned int zn = number_of_levels;
        if(zn<=0) zn = 1;
        std::vector<double> zs(zn+1);
        float zmax = zmin + dz;
        double zd = (zmax-zmin)/zn;
        for(unsigned int zi=0;zi<=zn;zi++) zs[zi] = zmin + zi * zd;
        list_contour.set_planes(zs);
      }

      if(zlog) {
        list_contour.set_field_fcn(log_function_to_contour,(void*)&sbFunc);
      } else {
        list_contour.set_field_fcn(function_to_contour,(void*)&sbFunc);
      }

#ifdef INLIBS_SG_PLOTTER_TIMING
      atime _start = atime::now();
#endif
      list_contour.ccontour::generate();

#ifdef INLIBS_SG_PLOTTER_TIMING
      a_out << "tools::sg::update_func2D_xy : contour generate elapsed " << atime::elapsed(_start) << "." << std::endl;
      _start = atime::now();
#endif

      if(!list_contour.compact_strips ()) {
        a_out << "tools::sg::plotter::update_func2D_xy : clist_contour::compact_strips () : failure." << std::endl;
      } else {
#ifdef INLIBS_SG_PLOTTER_TIMING
        a_out << "tools::sg::update_func2D_xy : contour compact strips elapsed " << atime::elapsed(_start) << "." << std::endl;
#endif
        if( (painting==painting_by_level) || (painting==painting_by_value) ){
          m_func_cmaps[a_index] = new by_value_colormap(a_out,m_cmaps,a_data_style.color_mapping.value());
          //bool zlog = a_box_z.m_log;
          if(zlog) m_func_cmaps[a_index]->set_PAW_coloring();
        } else {
          m_func_cmaps[a_index] = new const_colormap(a_data_style.color.value());
        }

        if(modeling==modeling_filled_curve()) {
          rep_contour_xy_filled(a_out,a_data_style,
                                painting,*(m_func_cmaps[a_index]),
                                list_contour,a_box_x,a_box_y,a_box_z,a_zz /*,std::string(sid.c_str())*/);
        } else {
          rep_contour_xy(a_out,a_data_style,
                         painting,*(m_func_cmaps[a_index]),
                         list_contour,a_box_x,a_box_y,a_box_z,a_zz /*,std::string(sid.c_str())*/);
        }
      }

      if(sbFunc.m_problem) {
        a_out << "tools::sg::plotter::update_func2D_xy : problem when getting some function value." << std::endl;
      }

  /*
    } else if(modeling==SbModeling_polygon) {

      int npoint = a_func.getNumberOfPoints();
      if(npoint) {

      std::vector<vec3f> points(npoint);
      std::vector<int> controls;
      for(int count=0;count<npoint;count++) {
        float xx,yy;
        bool isControl;
        a_func.getIthPoint(count,xx,yy,isControl);
        points[count] = vec3f(xx,yy,a_zz);
        if(isControl) controls.push_back(count);
      }
      //check closure :
      if((points.size()>=2) && (points[points.size()-1]!=points[0]) ) {
        points.push_back(points[0]);
      }

      project2D(points,a_box_x,a_box_y);

      bool editable = a_data_style.editable.getValue();
      if(!editable) {
        clip<float> clipper;
       {size_t ptn = points.size();
        for(size_t index=0;index<ptn;index++) clipper.add(points[index]);}

        plane<vec3f> plane_xy_bot(vec3f(0, 1,0),vec3f(0,0,0));
        plane<vec3f> plane_xy_top(vec3f(0,-1,0),vec3f(0,1,0));
        plane<vec3f> plane_yz_left (vec3f( 1, 0,0),vec3f(0,0,0));
        plane<vec3f> plane_yz_right(vec3f(-1, 0,0),vec3f(1,0,0));

        clipper.execute(plane_xy_bot);
        clipper.execute(plane_xy_top);
        clipper.execute(plane_yz_left);
        clipper.execute(plane_yz_right);

       {int n = clipper.getNumVertices();
        points.resize(n);
        for(int index=0;index<n;index++) {
          clipper.getVertex(index,points[index]);
        }}
        if((points.size()>=2) && (points[points.size()-1]!=points[0]) ) {
          points.push_back(points[0]);
        }
      }

      int ptn = points.size();
      if(ptn) {
      vec3f* pts = &(points[0]);

      SoSceneGraph* separator = new SoSceneGraph();
      separator->setString(sid.c_str());
      functionNode->addChild(separator);

      SoSeparator* sep = new SoSeparator;
      separator->addChild(sep);

      sep->addChild(fStyleCache->getFilled());
      sep->addChild(fStyleCache->getNormalBindingOverall());
      sep->addChild(fStyleCache->getNormalZ());
      sep->addChild(fStyleCache->getMaterial(a_data_style.color.getValue(),a_data_style.transparency.getValue()));

      SoCoordinate3* coordinate3 = new SoCoordinate3;
      coordinate3->point.setValues(0,ptn,pts);
      sep->addChild(coordinate3);

      SoFaceSet* faceSet = new SoFaceSet;
      faceSet->numVertices.set1Value(0,ptn);
      sep->addChild(faceSet);

      sep->addChild(fStyleCache->getLineStyle(SbLinePattern_solid,1));
      sep->addChild(fStyleCache->getMaterial(SbColor_black,0));

      //NOTE : we could simply add faceSet again !
      SoLineSet* lineSet = new SoLineSet;
      lineSet->numVertices.set1Value(0,ptn);
      sep->addChild(lineSet);

      if(editable) {
        SoSeparator* sep = new SoSeparator;
        separator->addChild(sep);

        float scale = 0.05F;

        for(int index=0;index<controls.size();index++) {
          int icontrol = controls[index];
          const vec3f& pt = pts[icontrol];

          SoSeparator* sp = new SoSeparator;
          sep->addChild(sp);

          SoTransform* tsf = new SoTransform();
          tsf->translation.setValue(pt);
          tsf->scaleFactor.setValue(scale,scale,scale);
          sp->addChild(tsf);

          SoPlotter_dragger* dragger =
            new SoPlotter_dragger(*coordinate3,icontrol,scale,*this,const_cast<SbPlottableFunction2D&>(a_func),a_box_x,a_box_y,a_zz);
          SoTools_setDraggerColor(*dragger,SbColor_red);
          sp->addChild(dragger);
        }
      }

      } //ptn
      } //npoint

  */
    } else {
      a_out << "tools::sg::plotter::update_func2D_xy :"
            << " modeling " << modeling
  	  << " does not apply on Functi  on2D in XY. Valid modelings ared curve, filled_curve and polygon."
	  << std::endl;
    }

  }

  void update_points2D_xy(std::ostream& a_out,const points2D& a_points,const style& a_style,
                          const rep_box& a_box_x,const rep_box& a_box_y,float a_zz) {

    //a_out << "debug : tools::sg::plotter::update_points2D_xy : modeling " << a_style.modeling.value() << std::endl;

    if(!a_style.visible) return;

    size_t number = a_points.points();
    if(!number) return;

    const std::string& modeling = a_style.modeling;

    if(modeling==modeling_lines()) {
      rep_points2D_xy_lines(a_style,a_points,a_box_x,a_box_y,a_zz);
    } else if(modeling==modeling_curve()) {
      rep_points2D_xy_curve(a_out,a_style,a_points,a_box_x,a_box_y,a_zz);
    } else {
      rep_points2D_xy_points(a_out,a_style,a_points,a_box_x,a_box_y,a_zz);
    }
  }

  void update_points3D_xyz(std::ostream& a_out,const points3D& a_points,const style& a_style,
                           const rep_box& a_box_x,const rep_box& a_box_y,const rep_box& a_box_z) {

    //a_out << "debug : tools::sg::plotter::update_points3D_xyz : modeling " << a_style.modeling.value() << std::endl;

    if(!a_style.visible) return;

    size_t number = a_points.points();
    if(!number) return;

    rep_points3D_xyz_points(a_out,a_style,a_points,a_box_x,a_box_y,a_box_z);
  }

  void get_title(std::string& a_s){
    a_s.clear();
    bins1D* b1;
    bins2D* b2;
    func1D* f1;
    func2D* f2;
    points2D* p2;
    points3D* p3;
    if(first_bins(b1,b2)) {
      if(b1) {
        a_s = b1->title();
      } else if(b2) {
        a_s = b2->title();
      }
    } else if(first_points(p2,p3)) {
      if(p2) {
        a_s = p2->title();
      } else if(p3) {
        a_s = p3->title();
      }
    } else if(first_func(f1,f2)) {
      if(f1) {
        a_s = f1->title();
      } if(f2) {
        a_s = f2->title();
      }
    }
  }

  void update_bins2D_xyz(std::ostream& a_out,const bins2D& a_bins,unsigned int a_index,const style& a_style,
                         const rep_box& a_box_x,const rep_box& a_box_y,const rep_box& a_box_z){
    //a_out << "tools::sg::update_bins2D_xyz : begin :" << std::endl;

    if(!a_style.visible) return;

    //a_out << "tools::sg::update_bins2D_xyz : visible :" << std::endl;

    unsigned int xnbin = a_bins.x_bins();
    unsigned int ynbin = a_bins.y_bins();
    if(!xnbin || !ynbin) return;

    const std::string& modeling = a_style.modeling;

    if(modeling==modeling_boxes()) {

      bool hbe = a_bins.has_entries_per_bin();

      float bmin = 0;
      float bmax = 0;

      std::vector<rep_bin2D> bins;
     {bool first = true;
      for(int jbin=ynbin-1;jbin>=0;jbin--) {
        for(int ibin=xnbin-1;ibin>=0;ibin--) {
          if(hbe && (a_bins.bin_entries(ibin,jbin)<=0)) continue;

          float val = a_bins.bin_Sw(ibin,jbin);

          float xx = a_bins.bin_lower_edge_x(ibin);
          float xe = a_bins.bin_upper_edge_x(ibin);
          float yy = a_bins.bin_lower_edge_y(jbin);
          float ye = a_bins.bin_upper_edge_y(jbin);

          bins.push_back(rep_bin2D(xx,xe,yy,ye,val,ibin,jbin));

          if(first) {
            first = false;
            bmin = val;
            bmax = val;
          } else {
            bmin = mn<float>(bmin,val);
            bmax = mx<float>(bmax,val);
          }
        }
      }}
      size_t number = bins.size();

      //a_bins.bins_Sw_range(bmin,bmax,false);

      painting_policy painting = a_style.painting;
      if(painting==painting_by_value) {
        m_bins_cmaps[a_index] = new by_value_colormap(a_out,m_cmaps,a_style.color_mapping);
      } else if( (painting==painting_grey_scale) ||
                 (painting==painting_grey_scale_inverse) ||
                 (painting==painting_violet_to_red) ){
       {float dbins = bmax-bmin;
        if(dbins!=0.0F) {
          for(size_t index=0;index<number;index++) {
            bins[index].m_ratio = (bins[index].m_val-bmin)/dbins;
          }
        }}
        if(painting==painting_grey_scale) {
          m_bins_cmaps[a_index] = new grey_scale_colormap(bmin,bmax,50);
        } else if(painting==painting_grey_scale_inverse) {
          m_bins_cmaps[a_index] = new grey_scale_inverse_colormap(bmin,bmax,50);
        } else if(painting==painting_violet_to_red) {
          m_bins_cmaps[a_index] = new violet_to_red_colormap(bmin,bmax,50);
        }
      } else {
        m_bins_cmaps[a_index] = new const_colormap(a_style.color);
      }

      rep_bins2D_xyz_box(a_style,*m_bins_cmaps[a_index],bins,a_box_x,a_box_y,a_box_z,bmin,bmax);

    } else if(modeling==modeling_curve()){ //gopaw

      float bmin = 0;
      float bmax = 0;

      std::vector<rep_top_face2D> faces((xnbin-1)*(ynbin-1));
     {bool first = true;
      size_t facei = 0;
      unsigned int xnbin_1 = xnbin-1;
      unsigned int ynbin_1 = ynbin-1;
      for(unsigned int jbin=0;jbin<ynbin_1;jbin++) {
        for(unsigned int ibin=0;ibin<xnbin_1;ibin++) {

          float xx_0 = a_bins.bin_lower_edge_x(ibin);
          float xe_0 = a_bins.bin_upper_edge_x(ibin);
          float xx_1 = a_bins.bin_lower_edge_x(ibin+1);
          float xe_1 = a_bins.bin_upper_edge_x(ibin+1);

          float yy_0 = a_bins.bin_lower_edge_y(jbin);
          float ye_0 = a_bins.bin_upper_edge_y(jbin);
          float yy_1 = a_bins.bin_lower_edge_y(jbin+1);
          float ye_1 = a_bins.bin_upper_edge_y(jbin+1);

          float xx = (xx_0+xe_0)/2;
          float xe = (xx_1+xe_1)/2;
          float yy = (yy_0+ye_0)/2;
          float ye = (yy_1+ye_1)/2;

          float val1 = a_bins.bin_Sw(ibin,jbin);
          float val2 = a_bins.bin_Sw(ibin+1,jbin);
          float val3 = a_bins.bin_Sw(ibin+1,jbin+1);
          float val4 = a_bins.bin_Sw(ibin,jbin+1);

          faces[facei] = rep_top_face2D(xx,xe,yy,ye,val1,val2,val3,val4);

          if(first) {
            first = false;
            bmin = val1;
            bmax = val1;
          } else {
            bmin = mn<float>(bmin,val1);
            bmax = mx<float>(bmax,val1);
          }

          facei++;
        }
      }}

      //a_bins.bins_Sw_range(bmin,bmax,false);

      painting_policy painting = a_style.painting;
      if((painting==painting_by_value)||(painting==painting_by_level)) {
        m_bins_cmaps[a_index] = new by_value_colormap(a_out,m_cmaps,a_style.color_mapping);
      } else {
        m_bins_cmaps[a_index] = new const_colormap(a_style.color);
      }

      if(painting==painting_by_level) { //gopaw
        rep_top_face2D_xyz_by_level(a_style,painting,*(m_bins_cmaps[a_index]),
                                    faces,a_box_x,a_box_y,a_box_z,
                                    bmin,bmax/*,SbString(sid.c_str())*/);
        //if(a_style.area_style.value()==area_edged) {
        //  style gs;
        //  gs.light_model = light_model_base_color();
        //  gs.line_width = 1;
        //  rep_top_face2D_xyz_line(gs,faces,a_box_x,a_box_y,a_box_z);
        //}

      } else {

        //bool oneNode = false;
       //{int nlimit = aGraphicStyle.multiNodeLimit.getValue();
        //if(nlimit!=NoLimit) {
        //oneNode = ((int)faces.size()>nlimit?true:false);
        //}}

        //if(oneNode) {
        //repTopFaces2D_xyz_one(binsNode,aGraphicStyle,faces,a_box_x,a_box_y,a_box_z,SbString(sid.c_str()));
        //} else {
        bool zlog = a_box_z.m_log;
        if(zlog) m_func_cmaps[a_index]->set_PAW_coloring();
        rep_top_face2D_xyz(m_bins_sep,a_style,*(m_bins_cmaps[a_index]),faces,a_box_x,a_box_y,a_box_z);

        if(a_style.area_style.value()==area_edged) {
          style gs;
          gs.light_model = light_model_base_color();
          gs.line_width = 1;
          rep_top_face2D_xyz_line(gs,faces,a_box_x,a_box_y,a_box_z/*,SbString(sid.c_str())*/);
        }

        if(painting==painting_uniform) { //gopaw SURF3 (s_SURF_CONT).

          base_colormap* cmap = new by_value_colormap(a_out,m_cmaps,a_style.color_mapping);
          if(cmap->colorn()<=0) {
            //a_out << "tools::sg::update_bins2D_xyz : bypass rep_contour_xy_filled." << std::endl;
            delete cmap;
          } else {
            //updateBins2D_XY(a_bins,aIndex,*gs,a_box_x,a_box_y,boxZ,1.1F);

            float zmin = a_box_z.m_pos;
            float dz = a_box_z.m_width;
            //bool zlog = a_box_z.m_log;

            float xmn =  m_x_axis_data.min_value();
            float xmx =  m_x_axis_data.max_value();
            float ymn =  m_y_axis_data.min_value();
            float ymx =  m_y_axis_data.max_value();

            clist_contour list_contour;
            //int nFir = 32;
            int nFir = 128;
            list_contour.set_first_grid(nFir,nFir); //Default : 32,32
            //int nSec = 256;
            int nSec = 512;
            list_contour.set_secondary_grid(nSec,nSec); //Default : 256,256.

            double limits[4];
            // User limits :
            limits[0] = xmn;
            limits[1] = xmx;
            limits[2] = ymn;
            limits[3] = ymx;

            SbFunc sbFunc;
            sbFunc.m_func2D = 0;
            sbFunc.m_problem = false;
            sbFunc.m_bins2D = &a_bins;
            sbFunc.m_limits_in[0] = limits[0];
            sbFunc.m_limits_in[1] = limits[1];
            sbFunc.m_limits_in[2] = limits[2];
            sbFunc.m_limits_in[3] = limits[3];

            // Extend the grid to have some borders in order to close contours :
            int n = nSec - 2 * 10;
            double dx = (limits[1]-limits[0]) /n;
            double dy = (limits[3]-limits[2]) /n;
            limits[0] = limits[0] - 10 * dx;
            limits[1] = limits[1] + 10 * dx;
            limits[2] = limits[2] - 10 * dy;
            limits[3] = limits[3] + 10 * dy;

            sbFunc.m_limits[0] = limits[0];
            sbFunc.m_limits[1] = limits[1];
            sbFunc.m_limits[2] = limits[2];
            sbFunc.m_limits[3] = limits[3];

            list_contour.set_limits(limits);

            //int zn = numberOfLevels.getValue();
            size_t zn = cmap->colorn();
            if(zn<=0) zn = 1;

            std::vector<double> zs(zn+1);
            float zmax = zmin + dz;
            double zd = (zmax-zmin)/zn;
            for(size_t zi=0;zi<=zn;zi++) zs[zi] = zmin + zi * zd;
            list_contour.set_planes(zs);

            if(zlog) list_contour.set_field_fcn(log_bins2D_to_contour,(void*)&sbFunc);
            else     list_contour.set_field_fcn(bins2D_to_contour,(void*)&sbFunc);

            list_contour.ccontour::generate();
            if(!list_contour.compact_strips ()) {
              a_out << "tools::sg::plotter::update_bins2D_xyz : clist_contour::compact_strips () : failure." << std::endl;
              delete cmap;
            } else {
              delete m_bins_cmaps[a_index];
              m_bins_cmaps[a_index] = cmap; //to visualize the cmap.

              matrix* transf = new matrix;
              //contour back is at ZZ - 0.01F;
              transf->set_translate(0,0,1.02F);
              transf->mul_scale(1,1,0.01F); //applied first.
	      m_bins_sep.add(transf);

              style gs;
              gs.light_model = light_model_base_color();
              //FIXME gs.transparency = 0.3F;

              float ZZ = 0.0F;

              rep_contour_xy_filled(a_out,gs,painting_by_level,*cmap,list_contour,
                                    a_box_x,a_box_y,a_box_z,ZZ/*,SbString(sid.c_str())*/);
            }
          }

        } //uniform

      }

    } //end if modeling

  }

  void update_func2D_xyz(std::ostream& a_out,
                         const func2D& a_func,
                         unsigned int a_index,
                         const style& a_style,
                         const rep_box& a_box_x,
                         const rep_box& a_box_y,
                         const rep_box& a_box_z){
    //a_out << "tools::sg::plotter::update_func2D_xyz : begin :" << std::endl;
    if(!a_style.visible) return;

    //a_out << "tools::sg::plotter::update_func2D_xyz : visible :" << std::endl;

    float xmn = m_x_axis_data.min_value();
    float xmx = m_x_axis_data.max_value();

    unsigned int nx = a_func.x_steps();
    nx = !nx?20:nx;

    float ymn = m_y_axis_data.min_value();
    float ymx = m_y_axis_data.max_value();

    unsigned int ny = a_func.y_steps();
    ny = !ny?20:ny;

    float dfx = (xmx - xmn)/nx;
    float dfy = (ymx - ymn)/ny;

    //printf("debug : nx %d ny %d\n",nx,ny);

    std::vector<rep_top_face2D> faces(nx*ny);
   {bool problem = false;
    unsigned int facei = 0;
    float* vprev = new float[2*nx];
    for(int jbin=ny-1;jbin>=0;jbin--) {
      float o1 = 0;
      float o4 = 0;
      for(int ibin=nx-1;ibin>=0;ibin--) {

        float xx = xmn + ibin * dfx;
        float yy = ymn + jbin * dfy;
        float xe = xx + dfx;
        float ye = yy + dfy;

        // Values at the corner :
        float val1;
        if(!a_func.value(xx,yy,val1)) problem = true;
        float val2;
        if(ibin==int(nx-1)) {
          if(!a_func.value(xe,yy,val2)) problem = true;
        } else {
          val2 = o1;
        }
        float val3,val4;
        if(jbin==int(ny-1)) {
          if(ibin==int(nx-1)) {
            if(!a_func.value(xe,ye,val3)) problem = true;
          } else {
            val3 = o4;
          }
          if(!a_func.value(xx,ye,val4)) problem = true;
        } else {
          val3 = vprev[2*ibin+1];
          val4 = vprev[2*ibin];
        }
        //printf("debug : %d %d : %g %g %g %g\n",
        //   ibin,jbin,
        //   val1,val2,val3,val4);
        vprev[2*ibin] = val1;
        vprev[2*ibin+1] = val2;
        o4 = val4;
        o1 = val1;

        faces[facei] = rep_top_face2D(xx,xe,yy,ye,val1,val2,val3,val4);
        facei++;
      }
    }
    delete [] vprev;
    if(problem) {
      a_out << "tools::sg::plotter::update_func2D_xyz :"
            << " problem when getting some function value."
            << std::endl;
    }}

    painting_policy painting = a_style.painting;

    if(painting==painting_by_value) {
      m_func_cmaps[a_index] = new by_value_colormap(a_out,m_cmaps,a_style.color_mapping);

    } else if( (painting==painting_grey_scale) ||
               (painting==painting_grey_scale_inverse) ||
               (painting==painting_violet_to_red) ){
      float vmin = faces[0].m_v1;
      float vmax = faces[0].m_v1;
      size_t number = faces.size();
      for(size_t index=0;index<number;index++) {
        float vmean  = faces[index].m_v1;
        vmean += faces[index].m_v2;
        vmean += faces[index].m_v3;
        vmean += faces[index].m_v4;
        vmean /= 4.0f;

        vmin = mn<float>(vmin,vmean);
        vmax = mx<float>(vmax,vmean);

        faces[index].m_ratio = vmean;
      }

     {float dbins = vmax-vmin;
      if(dbins!=0.0F) {
        for(size_t index=0;index<number;index++) {
          faces[index].m_ratio = (faces[index].m_ratio-vmin)/dbins;
        }
      }}

      if(painting==painting_grey_scale) {
        m_func_cmaps[a_index] = new grey_scale_colormap(vmin,vmax,50);
      } else if(painting==painting_grey_scale_inverse) {
        m_func_cmaps[a_index] = new grey_scale_inverse_colormap(vmin,vmax,50);
      } else if(painting==painting_violet_to_red) {
        m_func_cmaps[a_index] = new violet_to_red_colormap(vmin,vmax,50);
      }

    } else {
      m_func_cmaps[a_index] = new const_colormap(a_style.color);
    }

  // bool oneNode = false;
  //{int nlimit = a_data_style.multiNodeLimit.getValue();
  // if(nlimit!=NoLimit) {
  //   oneNode = ((int)faces.size()>nlimit?true:false);
  //}}

  //char sid[128];
  //::sprintf(sid,"SbFunction2D/0x%lx",(unsigned long)&a_func);

  //if(oneNode) {
  //  repTopFaces2D_xyz_one(functionNode,a_data_style,
  //                        faces,a_box_x,a_box_y,a_box_z,std::string(sid));
  //} else
    {
      bool zlog = a_box_z.m_log;
      if(zlog) m_func_cmaps[a_index]->set_PAW_coloring();
      rep_top_face2D_xyz(m_func_sep,a_style,*(m_func_cmaps[a_index]),faces,a_box_x,a_box_y,a_box_z);
    }

    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    float zmin = a_box_z.m_pos;
    float dz = a_box_z.m_width;
    bool zlog = a_box_z.m_log;

   if(func2D_borders_visible.value()) {
   // border X (Y=0)

   {separator* sep = new separator;
   {normal* nm = new normal;
    nm->vec = vec3f(0,-1,0);
    sep->add(nm);}
   {rgba* mat = new rgba();
    mat->color = colorf(0.6f,0.2f,0.2f); //brown
    sep->add(mat);}

    vertices* vtxs = new vertices;
    vtxs->mode = gl::triangle_fan();
    sep->add(vtxs);

    bool empty = true;
    bool problem = false;

   {float xx = xmn;
    float yy = ymn;
    xx = verify_log(xx,xmin,dx,xlog);
    yy = verify_log(yy,ymin,dy,ylog);
    vtxs->add(xx,yy,0);}

   {float xx = xmx;
    float yy = ymn;
    xx = verify_log(xx,xmin,dx,xlog);
    yy = verify_log(yy,ymin,dy,ylog);
    vtxs->add(xx,yy,0);}

   {float val;
   {if(!a_func.value(xmx,ymn,val)) problem = true;
    val = verify_log(val,zmin,dz,zlog);
    if(val<0) val = 0;
    if(val>1) val = 1;}
   {float xx = xmx;
    float yy = ymn;
    xx = verify_log(xx,xmin,dx,xlog);
    yy = verify_log(yy,ymin,dy,ylog);
    vtxs->add(xx,yy,val);}}

    for(int ibin=nx-1;ibin>=0;ibin--) {

      float xx = xmn + ibin * dfx;
      //float xe = xx + dfx;
      float yy = ymn;

      float val;
     {if(!a_func.value(xx,yy,val)) problem = true;
      val = verify_log(val,zmin,dz,zlog);
      if(val<0) val = 0;
      if(val>1) val = 1;}

      xx = verify_log(xx,xmin,dx,xlog);
      yy = verify_log(yy,ymin,dy,ylog);

      if((xx>=0)&&(xx<=1) && (yy>=0)&&(yy<=1) ) {

        vtxs->add(xx,yy,val);

        empty = false;
      }
    }
    if(empty) {
      delete sep;
    } else {
      m_func_sep.add(sep);
    }
    if(problem) {
      a_out << "tools::sg::plotter::update_func2D_xyz :"
            << " problem when getting some function value."
            << std::endl;
    }}

    // border Y (X=0)
   {separator* sep = new separator;
   {normal* nm = new normal;
    nm->vec = vec3f(-1,0,0);
    sep->add(nm);}
   {rgba* mat = new rgba();
    mat->color = colorf(0.6f,0.2f,0.2f); //brown
    sep->add(mat);}

    vertices* vtxs = new vertices;
    vtxs->mode = gl::triangle_fan();
    sep->add(vtxs);

   {float xx = xmn;
    float yy = ymx;
    xx = verify_log(xx,xmin,dx,xlog);
    yy = verify_log(yy,ymin,dy,ylog);
    vtxs->add(xx,yy,0);}

   {float xx = xmn;
    float yy = ymn;
    xx = verify_log(xx,xmin,dx,xlog);
    yy = verify_log(yy,ymin,dy,ylog);
    vtxs->add(xx,yy,0);}

    bool empty = true;
    bool problem = false;

    for(unsigned int jbin=0;jbin<ny;jbin++) {

      float xx = xmn;
      float yy = ymn + jbin * dfy;

      float val;
     {if(!a_func.value(xx,yy,val)) problem = true;
      val = verify_log(val,zmin,dz,zlog);
      if(val<0) val = 0;
      if(val>1) val = 1;}

      xx = verify_log(xx,xmin,dx,xlog);
      yy = verify_log(yy,ymin,dy,ylog);

      if((xx>=0)&&(xx<=1)   &&
         (yy>=0)&&(yy<=1)   ){

        vtxs->add(xx,yy,val);

        empty = false;

      }
    }

   {float val;
   {if(!a_func.value(xmn,ymx,val)) problem = true;
    val = verify_log(val,zmin,dz,zlog);
    if(val<0) val = 0;
    if(val>1) val = 1;}
   {float xx = xmn;
    float yy = ymx;
    xx = verify_log(xx,xmin,dx,xlog);
    yy = verify_log(yy,ymin,dy,ylog);
    vtxs->add(xx,yy,val);}}
    if(empty) {
      delete sep;
    } else {
      m_func_sep.add(sep);
    }
    if(problem) {
      a_out << "tools::sg::plotter::update_func2D_xyz :"
            << " problem when getting some function value."
            << std::endl;
    }}


    } //func2D_borders_visible

  }

  void update_title(){
    if(!m_title_style.visible) return;

    if(m_shape==xyz) return;

    if(title.value().empty()) return;

    // Use the XY layout transform to position the title.
    // (Else we would have to compensate the 3D rotation
    //  in order to bring the title at the right position
    //  without rotation).
    //titleNode->addChild(layout);

    rgba* mat = new rgba();
    mat->color = m_title_style.color;
    m_title_sep.add(mat);

    float text_size = title_height * m_title_style.scale;

    std::string font = m_title_style.font.value();

    if(font==font_hershey()) {
      draw_style* ds = new draw_style;
      ds->style = draw_lines;
      ds->line_pattern = m_title_style.line_pattern;
      ds->line_width = m_title_style.line_width;
      m_title_sep.add(ds);
    } else {
      m_title_sep.add(new normal);
    }

    float XSIZ = width;
    float XMGL = left_margin;
    float XMGR = right_margin;
    float wData = XSIZ-XMGL-XMGR;

    float YSIZ = height;
    float YMGL = bottom_margin;
    float YMGU = top_margin;
    float hData = YSIZ-YMGL-YMGU;

    float xx = wData/2;
    float yy = hData + title_to_axis;

    float zz = _zinfos();

    vjust vjust = bottom;
    if(!title_up) {
      yy = -title_to_axis;
      vjust = top;
    }

    //::printf("debug : %lu : %g %g : text_size : %g : %s\n",
    //  this,xx,yy,text_size,title.value().c_str());

    vec3f TX(1,0,0);
    vec3f TY(0,1,0);
    add_string(m_title_sep,
                       font,
                       m_title_style.font_modeling.value(),
                       m_title_style.encoding.value(),
                       m_title_style.smoothing,
                       title.value(),
                       xx,yy,zz, //vec
                       TX,TY,
                       text_size,
                       title_hjust,vjust,
                       m_ttf);
  }

  void update_title_box(){
    if(!m_title_box_style.visible) return;
    if(title.value().empty()) return;

    // same plane than infos, then in front of data and grid.
    float zz = _zinfos();
    if(m_shape==xyz) zz = depth*0.5f;

    float wbox = width*title_box_width;
    float hbox = height*title_box_height;

    float xmargin = width*title_box_x_margin;  //from left border
    float ymargin = height*title_box_y_margin; //from top border

    matrix* _tsf = new matrix;
   {float xx = -width*0.5f+wbox*0.5f+xmargin; //at left.
    float yy = height*0.5f-hbox*0.5F-ymargin; //at top.
    _tsf->set_translate(xx,yy,zz);
    _tsf->mul_scale(1,1,_zscale_text());}
    m_title_box_sep.add(_tsf);

    sg::text* title_box = new sg::text(m_ttf);
    title_box->width = wbox;
    title_box->height = hbox;
    title_box->back_area::color = m_title_box_style.back_color;
    title_box->color = m_title_box_style.color;
    title_box->font = m_title_box_style.font;
    title_box->font_modeling = m_title_box_style.font_modeling;
    title_box->encoding = m_title_box_style.encoding;
    title_box->line_width = m_title_box_style.line_width;
  //title_box->front_face = m_title_box_style.front_face;
    title_box->confine = true;
    title_box->back_area::shadow = m_title_box_style.back_shadow;

    title_box->strings.add(title.value());

    m_title_box_sep.add(title_box);
  }

  void get_infos(std::string& a_s){
    // return "[<key>\n<value>]\n".
    a_s.clear();
    const std::string&  opts = infos_what.value();
   {bins1D* b1;
    bins2D* b2;
    func1D* f1;
    func2D* f2;
    points2D* p2;
    points3D* p3;
    if(first_bins(b1,b2)) {
      if(b1) {
        b1->infos(opts,a_s);
      } else if(b2) {
        b2->infos(opts,a_s);
      }
    } else if(first_points(p2,p3)) {
      if(p2) {
        p2->infos(opts,a_s);
      } else if(p3) {
        p3->infos(opts,a_s);
      }
    } else if(first_func(f1,f2)) {
      if(f1) {
        f1->infos(opts,a_s);
      } if(f2) {
        f2->infos(opts,a_s);
      }
    }}
    //look for fit infos :
   {tools_vforcit(plottable*,m_plottables,it) {
      plottable* object = *it;
      if(!object) continue;
      if(object->cast(s_tools_sg_fit2plot())) {
        if(a_s.size()) a_s += "\n";
        std::string _s;
        object->infos(opts,_s);
        a_s += _s;
      }
    }}
  }

  matrix* get_infos_matrix() {
    if(m_infos_sep.empty()) return 0;
    return (matrix*)m_infos_sep[0]; //WARNING.
  }
  sg::infos_box* get_infos_node() {
    if(m_infos_sep.empty()) return 0;
    return (sg::infos_box*)m_infos_sep[1]; //WARNING.
  }

  void update_infos(std::ostream&){
    if(!m_infos_style.visible) return;

    std::string sinfos;
    get_infos(sinfos);
    std::vector<std::string> ws;
    words(sinfos,"\n",false,ws);
    size_t linen = ws.size()/2;

    float zz = _zinfos(); //xy
    if(m_shape==xyz) zz = depth*0.5f;

    float _height = height;
    if(m_shape==xyz) _height = depth;

    float wbox = width*infos_width;

    matrix* infos_title_tsf = 0;
    sg::text* infos_title_text = 0;

    std::string infos_title;
    if(m_infos_style.modeling==infos_modeling_ROOT()) {
      std::vector<std::string> _ws; //to rm "Name".
      for(size_t index=0;index<linen;index++) {
        const std::string& name = ws[2*index];
        const std::string& value = ws[2*index+1];
        if(name=="Name") {
          infos_title = value;
        } else {
	  _ws.push_back(name);
	  _ws.push_back(value);
	}
      }
      ws = std::move(_ws);
      linen = ws.size()/2;
    }

    if(infos_title.size()) {
      float hbox = _height*0.05f;

      matrix* _tsf = new matrix;
     {float xx = width*0.5f  - wbox*0.5f -  width*infos_x_margin;
      float yy = _height*0.5f - hbox*0.5F - _height*infos_y_margin;
      _tsf->mul_translate(xx,yy,zz);
      _tsf->mul_scale(1,1,_zscale_text());}
      //in case of having infos, the tsf is refined below.
      m_infos_title_sep.add(_tsf);

      // same params as title_box.
      sg::text* txt = new sg::text(m_ttf);
      txt->width = wbox;
      txt->height = hbox;
      txt->back_area::color = m_infos_style.back_color;
      txt->color = m_infos_style.color;
      txt->font = m_infos_style.font;
      txt->font_modeling = m_infos_style.font_modeling;
      txt->encoding = m_infos_style.encoding;
      txt->line_width = m_infos_style.line_width;
    //txt->front_face = m_infos_style.front_face;
      txt->confine = true;
      txt->back_area::shadow = m_infos_style.back_shadow;

      txt->hjust = center;

      txt->strings.add(infos_title);
      m_infos_title_sep.add(txt);

      // to refine height below.
      infos_title_tsf = _tsf;
      infos_title_text = txt;
    }

    if(sinfos.empty()) return;
    if(!linen) return;

    matrix* _tsf = new matrix;
    m_infos_sep.add(_tsf);

    sg::infos_box* infos = new sg::infos_box(m_ttf);
    infos->width = wbox;
    //infos->height is an output field, see below.
    infos->back_area::color = m_infos_style.back_color;
    infos->color = m_infos_style.color;
    infos->font = m_infos_style.font;
    infos->encoding = m_infos_style.encoding;
    infos->font_modeling = m_infos_style.font_modeling;
    infos->line_width = m_infos_style.line_width;
  //infos->front_face = m_infos_style.front_face;
    infos->back_area::shadow = m_infos_style.back_shadow;
    infos->border_line_width = m_infos_style.line_width;

   {for(size_t index=0;index<linen;index++) {
      const std::string& name = ws[2*index];
      const std::string& value = ws[2*index+1];
      infos->lstrings.add(name);
      infos->rstrings.add(value);
      //a_out << "debug : name " << sout(name)
      //      << " value " << sout(value) << std::endl;
    }}

    // enforce an infos::update_sg to get infos::height
    // to place the box.
    infos->update_sg();

    // if any, set infos_title height :
    float title_hbox = 0;
    if(infos_title_tsf && infos_title_text) {
      title_hbox = infos->height/linen;
      float xx = width*0.5f  - wbox*0.5f       - width*infos_x_margin;
      float yy = _height*0.5f - title_hbox*0.5F - _height*infos_y_margin;
      infos_title_tsf->set_identity();
      infos_title_tsf->mul_translate(xx,yy,zz);
      infos_title_tsf->mul_scale(1,1,_zscale_text());

      infos_title_text->height = title_hbox;
    }

    float hbox = infos->height;
   {float xx = width*0.5f  -wbox*0.5f -width*infos_x_margin;
    float yy = _height*0.5f -hbox*0.5F - _height*infos_y_margin;
    yy -= title_hbox;
    _tsf->set_translate(xx,yy,zz);
    _tsf->mul_scale(1,1,_zscale_text());}

    m_infos_sep.add(infos);
  }

/*
  void update_legends(std::ostream& a_out){
    if(!legends_visible) return;

    if(m_legend_strings.empty()) return;
    if(m_legend_colors.size()!=m_legend_strings.size()) return;

    //m_legend_sep contains :
    //   one global mtx
    //   one sep per legend.

   {matrix* _tsf = new matrix;
    m_legend_sep.add(_tsf);

    float zz = _zinfos();

    //set legends layout :
    if(legends_attached_to_infos) {
      _tsf->set_translate(0,0,zz);
    } else {
      if(legends_origin_unit==unit_axis) {

        // legends_origin is in axes coordinates.
        float x = legends_origin.value()[0];
        float y = legends_origin.value()[1];

        vec3f pos;
        if(!axis_2_vp(vec3f(x,y,0),pos)) {
          //SoDebugError::postInfo("SoPlotterRegion::updateChildren",
   	    //		             "failed for %g %g.",x,y);
        } else {
          //pos is in NDC of [0,width][0,height].

          float xx = width  * (-0.5f+pos[0]);
          float yy = height * (-0.5f+pos[1]);

          _tsf->set_translate(xx,yy,zz);

        }

      } else { //unit_percent
        // legends_origin is
        // the UR corner of legend region relative
        // to UR of plotter region.
        float xur = legends_origin.value()[0];
        float yur = legends_origin.value()[1];

        vec2f ur(1-xur,1-yur);

        float w = legends_size.value()[0];
        float h = legends_size.value()[1];

        float x = ur[0]-w;
        float y = ur[1]-h;

        float xx = width  * (x-0.5f);
        float yy = height * (y-0.5f);

        _tsf->set_translate(xx,yy,zz);

      }
    }}

    size_t number = m_legend_strings.size();
    for(size_t index=0;index<number;index++) {

      separator* sep = new separator;
      m_legend_sep.add(sep);

      matrix* _tsf = new matrix;
      sep->add(_tsf);

      //sg::text* text = new sg::text;
      legend* text = new legend(m_ttf);
      //text->confine = true;
      text->strings.add(m_legend_strings[index]);
      sep->add(text);
      text->color = m_legend_colors[index];

      if(legends_attached_to_infos) {
        // global tsf should be the identity.

        // legend box geometry and placement is relative
        // to the infos box placement and geometry :
        if(m_infos_style.visible) {
          sg::infos_box* inode = get_infos_node();
          if(!inode) {delete sep;return;}
          matrix* imtx = get_infos_matrix();
          if(!imtx) {delete sep;return;}

          float wbox = inode->width;
          float hbox = inode->height/number;

          text->width = wbox;
          text->height = hbox;

          _tsf->mtx = imtx->mtx;

          float xx = width*0.5f-wbox*0.5f;

          float yy = height*0.5f-inode->height-hbox*0.5f-hbox*index;

          _tsf->set_translate(xx,yy,0);

        } else {
          float wbox = width  * legends_size.value()[0];
          float hbox = (height * legends_size.value()[1])/number;

          text->width = wbox;
          text->height = hbox;

          float xx = width*0.5f-wbox*0.5f - width*infos_x_margin;
          float yy = height*0.5f-hbox*0.5F - height*infos_y_margin;

          yy -= hbox*index;

          _tsf->set_translate(xx,yy,0);
        }

      } else {

        //legends_size is in NDC of [0,width][0,height].
        float w = width  * legends_size.value()[0];
        float h = height * legends_size.value()[1];

        text->width = w;
        text->height = h/number;

        float xx = w * 0.5f;
        float yy = text->height * 0.5f;
        yy += text->height*(number-index-1);

        _tsf->set_translate(xx,yy,0);

      }
      _tsf->mul_scale(1,1,_zscale_text());

    }
  }
*/

  void update_legends(std::ostream& a_out) {
    //::printf("debug : update_legends : begin\n");
    if(m_legend_strings.empty()) return;
    if(m_legend_strings.size()!=legends_origin.size()) return;
    if(legends_size.size()!=legends_origin.size()) return;
    if(legends_origin_unit.size()!=legends_origin.size()) return;

    float zz = _zinfos();

   {matrix* _tsf = new matrix;
    _tsf->mul_scale(1,1,_zscale_text());
    m_legend_sep.add(_tsf);}

    size_t number = m_legend_strings.size();
    //::printf("debug : update_legends : 001 %lu\n",number);
    for(size_t index=0;index<number;index++) {
      const style& _style = legend_style(index);
      if(!_style.visible) continue;
      //::printf("debug : update_legends : 002 %lu |%s|\n",index,m_legend_strings[index].c_str());

      separator* sep = new separator;
      m_legend_sep.add(sep);

      matrix* _tsf = new matrix;
      sep->add(_tsf);

      //sg::text* text = new sg::text;
      legend* text = new legend(m_ttf);
      text->font = _style.font;
      text->font_modeling = _style.font_modeling;
      text->encoding = _style.encoding;
      text->strings.add(m_legend_strings[index]);
      text->color = _style.color;
      text->marker_style = _style.marker_style;
      text->marker_size = _style.marker_size;
      text->back_visible = false;
      sep->add(text);

      //legends_size is in NDC of [0,width][0,height].
      float w = width  * legends_size[index][0];
      float h = height * legends_size[index][1];
      text->width = w;
      text->height = h;

      float xxx = w * 0.5f;
      float yyy = h * 0.5f;

      if(legends_origin_unit[index]==unit_axis) {

        // legends_origin is in axes coordinates.
        float x = legends_origin[index][0];
        float y = legends_origin[index][1];

        vec3f pos;
        if(!axis_2_vp(vec3f(x,y,0),pos)) {
          a_out << "tools::sg::plotter::update_legends : axis_2_vp() failed for x=" << x << ", y=" << y << "." << std::endl;
        } else {
          //pos is in NDC of [0,width][0,height].
          float xx = width  * (-0.5f+pos[0]);
          float yy = height * (-0.5f+pos[1]);
          _tsf->set_translate(xx,yy,zz);
        }

      } else { //unit_percent
        // legends_origin is
        // the UR corner of legend region relative
        // to UR of plotter region.
        float xur = legends_origin[index][0];
        float yur = legends_origin[index][1];

        vec2f ur(1-xur,1-yur);

        float x =  width*ur[0] - w;
        float y = height*ur[1] - h;

        float xx =  -width*0.5f + x;
        float yy = -height*0.5f + y;

        _tsf->set_translate(xx,yy,zz);
      }

      _tsf->mul_translate(xxx,yyy,0); //applied first.

    }
  }

  void update_background(){
    m_background_sep.clear();
    if(!m_background_style.visible) return;

    matrix* _tsf = new matrix;
    m_background_sep.add(_tsf);

    float w2 = width*0.5F;
    float h2 = height*0.5F;

    float zz = 0; //in xy, then before first data plane at _zoffset()
    if(m_shape==xyz) zz = -depth*0.5f;

   {rgba* mat = new rgba();
    if(m_background_style.line_width) { //there is a border.
      mat->color = m_background_style.color; //then border color !
    } else {
      mat->color = m_background_style.back_color;
    }
    m_background_sep.add(mat);

    m_background_sep.add(new normal);

    vertices* vtxs = new vertices;
    vtxs->mode = gl::triangle_fan();
    m_background_sep.add(vtxs);

    vtxs->add(-w2,-h2,zz);
    vtxs->add( w2,-h2,zz);
    vtxs->add( w2, h2,zz);
    vtxs->add(-w2, h2,zz);}

    if(m_background_style.line_width) { //border
      //WARNING : line_width should be in percent of width.

      //NOTE : border is done by drawing a front smaller polygon.

      rgba* mat = new rgba();
      mat->color = m_background_style.back_color; //yes,yes !
      m_background_sep.add(mat);

      vertices* vtxs = new vertices;
      vtxs->mode = gl::triangle_fan();
      m_background_sep.add(vtxs);

      //float d = width*0.005;
      float d = width*m_background_style.line_width;

      zz += _zoffset()*0.5f;

      vtxs->add(-w2+d,-h2+d,zz);
      vtxs->add( w2-d,-h2+d,zz);
      vtxs->add( w2-d, h2-d,zz);
      vtxs->add(-w2+d, h2-d,zz);
    }

  }

  void update_inner_frame_XY(){
    if(!m_inner_frame_style.visible) return;

    rgba* mat = new rgba();
    mat->color = m_inner_frame_style.color;
    m_inner_frame_sep.add(mat);

    draw_style* ds = new draw_style;
    ds->style = draw_lines;
    ds->line_pattern = m_inner_frame_style.line_pattern;
    ds->line_width = m_inner_frame_style.line_width;
    m_inner_frame_sep.add(ds);

    vertices* vtxs = new vertices;
    vtxs->mode = gl::line_strip();
    m_inner_frame_sep.add(vtxs);

    float zz = _zgrid();

    vtxs->add(0,0,zz);
    vtxs->add(1,0,zz);
    vtxs->add(1,1,zz);
    vtxs->add(0,1,zz);
    vtxs->add(0,0,zz);
  }

  void update_inner_frame_XYZ(){
    if(!m_inner_frame_style.visible) return;

    rgba* mat = new rgba();
    mat->color = m_inner_frame_style.color;
    m_inner_frame_sep.add(mat);

    draw_style* ds = new draw_style;
    ds->style = draw_lines;
    ds->line_pattern = m_inner_frame_style.line_pattern;
    ds->line_width = m_inner_frame_style.line_width;
    m_inner_frame_sep.add(ds);

    vertices* ls = new vertices;
    ls->mode = gl::lines();
    m_inner_frame_sep.add(ls);

    // z bottom :
    ls->add(0,0,0);ls->add(1,0,0);
    ls->add(1,0,0);ls->add(1,1,0);
    ls->add(1,1,0);ls->add(0,1,0);
    ls->add(0,1,0);ls->add(0,0,0);

    // z top :
    ls->add(0,0,1);ls->add(1,0,1);
    ls->add(1,0,1);ls->add(1,1,1);
    ls->add(1,1,1);ls->add(0,1,1);
    ls->add(0,1,1);ls->add(0,0,1);

    // sides along z :
    ls->add(0,0,0);ls->add(0,0,1);
    ls->add(1,0,0);ls->add(1,0,1);
    ls->add(1,1,0);ls->add(1,1,1);
    ls->add(0,1,0);ls->add(0,1,1);
  }

  void update_grid_XY(){
    if(!m_grid_style.visible) return;

    unsigned int number = m_x_axis.tick_number + m_y_axis.tick_number;
    if(number<=0) return;

    bool draw_vertical = true;
    bool draw_horizontal = true;
    if(m_grid_style.options.value()=="vertical") draw_horizontal = false;
    if(m_grid_style.options.value()=="horizontal") draw_vertical = false;

    rgba* mat = new rgba();
    mat->color = m_grid_style.color;
    m_grid_sep.add(mat);

    draw_style* ds = new draw_style;
    ds->style = draw_lines;
    ds->line_pattern = line_solid;
    ds->line_width = m_grid_style.line_width;
    m_grid_sep.add(ds);

    float zz = _zgrid();

    vertices* vtxs = new vertices;
    vtxs->mode = gl::lines();
    m_grid_sep.add(vtxs);

    std::vector<float>& pts = vtxs->xyzs.values();

    bool is_solid = m_grid_style.line_pattern.value()==line_solid;

    if(draw_vertical) {
      float _width = m_y_axis.width;
      float xx;
     {size_t _number = m_x_axis.coords.size();
      if(is_solid) {
        pts.reserve(_number*6);
        for(size_t count=0;count<_number;count++) {
          xx = m_x_axis.coords[count];
          vtxs->add(xx, 0    ,zz);
          vtxs->add(xx, _width,zz);
        }
      } else {
        pts.reserve(_number*100*6);
        for(size_t count=0;count<_number;count++) {
          xx = m_x_axis.coords[count];
          vtxs->add_dashed_line(xx,0,zz,xx,_width,zz,100);
        }
      }}
      if(m_x_axis.is_log) {
        size_t _number = m_x_axis.sub_coords.size();
        if(is_solid) {
          pts.reserve(_number*6);
          for(size_t count=0;count<_number;count++) {
            xx = m_x_axis.sub_coords[count];
            vtxs->add(xx, 0    ,zz);
            vtxs->add(xx,_width,zz);
          }
        } else {
          pts.reserve(_number*100*6);
          for(size_t count=0;count<_number;count++) {
            xx = m_x_axis.sub_coords[count];
            vtxs->add_dashed_line(xx,0,zz,xx,_width,zz,100);
          }
        }
      }
    }

    if(draw_horizontal) {
      float _width = m_x_axis.width;
      float yy;
     {size_t _number = m_y_axis.coords.size();
      if(is_solid) {
        pts.reserve(_number*6);
        for(size_t count=0;count<_number;count++) {
          yy = m_y_axis.coords[count];
          vtxs->add(0,yy    ,zz);
          vtxs->add(_width,yy,zz);
        }
      } else {
        pts.reserve(_number*100*6);
        for(size_t count=0;count<_number;count++) {
          yy = m_y_axis.coords[count];
          vtxs->add_dashed_line(0,yy,zz,_width,yy,zz,100);
        }
      }}
      if(m_y_axis.is_log) {
        size_t _number = m_y_axis.sub_coords.size();
        if(is_solid) {
          pts.reserve(_number*6);
          for(size_t count=0;count<_number;count++) {
            yy = m_y_axis.sub_coords[count];
            vtxs->add(0,yy,    zz);
            vtxs->add(_width,yy,zz);
          }
        } else {
          pts.reserve(_number*100*6);
          for(size_t count=0;count<_number;count++) {
            yy = m_y_axis.sub_coords[count];
            vtxs->add_dashed_line(0,yy,zz,_width,yy,zz,100);
          }
        }
      }
    }

  }

  void update_grid_XYZ(){
    if(!m_grid_style.visible) return;

    rgba* mat = new rgba();
    mat->color = m_grid_style.color;
    m_grid_sep.add(mat);

    draw_style* ds = new draw_style;
    ds->style = draw_lines;
    ds->line_pattern = m_grid_style.line_pattern;
    ds->line_width = m_grid_style.line_width;
    m_grid_sep.add(ds);

/*
    vertices* vtxs = new vertices;
    vtxs->mode = gl::line_strip();
    m_grid_sep.add(vtxs);

    float z = 0.5F;

    vtxs->add(0,0,z);
    vtxs->add(1,0,z);
    vtxs->add(1,1,z);
    vtxs->add(0,1,z);
    vtxs->add(0,0,z);
*/
/*
  int ntick = m_z_axis.tickNumber;
  if(ntick<=0) return;

  SoSeparator* sep = (SoSeparator*)gridSeparator.value();

  sep->addChild(fStyleCache->getMaterial
               (style->color.value(),
                style->transparency.value()));

  sep->addChild(getLineStyle(*style));

  vec3f* points = new vec3f[4 * ntick];
  int pos = 0;
  for(int count=0;count<ntick;count++) {
    float xe = m_x_axis.width.value();
    float ye = m_y_axis.width.value();
    float zz = m_z_axis.coords[count];
    LIST_SET(points,pos,0 ,ye,zz);pos++;
    LIST_SET(points,pos,xe,ye,zz);pos++;
    LIST_SET(points,pos,xe,ye,zz);pos++;
    LIST_SET(points,pos,xe,0 ,zz);pos++;
  }
  if(pos>0) {
    SoCoordinate3* coordinate3 = new SoCoordinate3;
    int32_t pointn = pos;
    coordinate3->point.setValues(0,pointn,points);
    sep->addChild(coordinate3);

    SoLineSet* lineSet = new SoLineSet;
    int segmentn = pointn/2;
    int32_t* vertices = new int32_t[segmentn];
    for (int count=0;count<segmentn;count++) vertices[count] = 2;
    lineSet->numVertices.setValues(0,segmentn,vertices);
    delete [] vertices;
    sep->addChild(lineSet);
  }

  delete [] points;
*/
  }

protected: //rep
  ////////////////////////////////////////////////////////////////////////////
  // reps xy /////////////////////////////////////////////////////////////////
  ////////////////////////////////////////////////////////////////////////////
  void rep_bins1D_xy_top_lines(const style& a_style,
                               const base_colormap& a_cmap,
                               const std::vector<rep_bin1D>& a_bins,
                               const rep_box& a_box_x,
                               const rep_box& a_box_y,
                               float a_zz/*,
                               const std::string& aID*/){
    painting_policy painting = a_style.painting;

    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    float y0 = 0;
    y0 = verify_log(y0,ymin,dy,ylog);
    if(y0<0) y0 = 0;
    if(y0>1) y0 = 1;

    separator* _sep = new separator();

    draw_style* ds = new draw_style;
    ds->style = draw_lines;
    ds->line_pattern = a_style.line_pattern;
    ds->line_width = a_style.line_width;
    _sep->add(ds);

    bool empty = true;
    colorf clr;

    float yp = 0;
    size_t xnbin = a_bins.size();
    for(size_t index=0;index<xnbin;index++) {
      float xx = a_bins[index].m_x_min;
      float xe = a_bins[index].m_x_max;
      float y = a_bins[index].m_val;

      float val = a_bins[index].m_val;

      xx = verify_log(xx,xmin,dx,xlog);
      xe = verify_log(xe,xmin,dx,xlog);
      y = verify_log(y,ymin,dy,ylog);

      // Clipping :
      if(xe<0) continue;
      if(xx>1) continue;
      if(xx<0) xx = 0;
      if(xe>1) xe = 1;
      if(y<0) y = 0;
      if(y>1) y = 1;

      separator* sep = new separator();
      _sep->add(sep);

    /*uuu
      a_bins[index].fSeparator = sep;

     {char s[128];
      //::sprintf(s,"%d",index);
      sep->setInfos(s);
      //::sprintf(s,"/0x%lx",(unsigned long)sep->getInfos());
      std::string sid = aID;
      sid += std::string(s);
      sep->setString(sid);}*/

      if(painting==painting_by_value) {
        a_cmap.get_color(val,clr);
      } else if( (painting==painting_grey_scale) ||
                 (painting==painting_grey_scale_inverse) ||
                 (painting==painting_violet_to_red) ){
        a_cmap.get_color(a_bins[index].m_ratio,clr);
      } else {
        clr = a_style.color;
      }

      rgba* mat = new rgba();
      mat->color = clr;
      sep->add(mat);

      vertices* vtxs = new vertices;
      vtxs->mode = gl::line_strip();
      sep->add(vtxs);

      vtxs->add(xx,yp,a_zz);
      vtxs->add(xx,y,a_zz);
      vtxs->add(xe,y,a_zz);
      if(index==xnbin-1){
        vtxs->add(xe,y0,a_zz);
      }

      empty = false;
      yp = y;
    }

    if(empty) {
      delete _sep;
    } else {
      m_bins_sep.add(_sep);
    }
  }

  void rep_bins1D_xy_points(std::ostream& a_out,
                            const style& a_style,
                            const base_colormap& a_cmap,
                            const std::vector<rep_bin1D>& a_bins,
                            const rep_box& a_box_x,
                            const rep_box& a_box_y,
                            float a_zz/*,
                            const std::string& aID*/){
    //::printf("debug : tools::sg::plotter::rep_bins1D_xy_points : begin\n");
    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    painting_policy painting = a_style.painting;

    separator* _sep = new separator();

    if(a_style.modeling==modeling_points()) {
      draw_style* ds = new draw_style;
      ds->style = draw_points;
      ds->point_size = a_style.point_size;
      _sep->add(ds);
    }

    bool empty = true;
    colorf clr;
    size_t xnbin = a_bins.size();
    for(size_t index=0;index<xnbin;index++) {
      float x = (a_bins[index].m_x_min + a_bins[index].m_x_max)/2;
      float y = a_bins[index].m_val;
      float val = a_bins[index].m_val;

      x = verify_log(x,xmin,dx,xlog);
      y = verify_log(y,ymin,dy,ylog);

      if((x<0)||(x>1)||(y<0)||(y>1)) continue;

      //::printf("debug : tools::sg::plotter::rep_bins1D_xy_points : x %g, y %g, val %g\n",x,y,val);

      separator* sep = new separator();
      _sep->add(sep);

      //a_bins[index].fSeparator = sep;

     //{char s[128];
     // ::sprintf(s,"%d",index);
     // sep->setInfos(s);
     // ::sprintf(s,"/0x%lx",(unsigned long)sep->getInfos());
     // std::string sid = aID;
     // sid += std::string(s);
     // sep->setString(sid);}

      if(painting==painting_by_value) {
        a_cmap.get_color(val,clr);
      } else if( (painting==painting_grey_scale) ||
                 (painting==painting_grey_scale_inverse) ||
                 (painting==painting_violet_to_red) ){
        a_cmap.get_color(a_bins[index].m_ratio,clr);
      } else {
        clr = a_style.color;
      }

      rgba* mat = new rgba();
      mat->color = clr;
      sep->add(mat);

      if(a_style.modeling==modeling_points()) {
        vertices* vtxs = new vertices;
        vtxs->mode = gl::points();
        vtxs->add(x,y,a_zz);
        sep->add(vtxs);
      } else if(a_style.modeling==modeling_markers()) {
        markers* _marks = new markers;
        _marks->size = a_style.marker_size;
        _marks->style = a_style.marker_style;
        _marks->add(x,y,a_zz);
        sep->add(_marks);
      } else {
        a_out << "tools::sg::plotter::rep_bins1D_xy_points :"
              << " bad modeling style " << tools::sout(a_style.modeling) << std::endl;
        delete _sep;
        return;
      }

      empty = false;
    }

    if(empty) {
      delete _sep;
    } else {
      m_bins_sep.add(_sep);
    }
  }

  void rep_bins1D_xy_boxes(const style& a_style,
                           const base_colormap& a_cmap,
                           const std::vector<rep_bin1D>& a_bins,
                           const rep_box& a_box_x,
                           const rep_box& a_box_y,
                           float a_zz //,const std::string& aID
                               ){
    painting_policy painting = a_style.painting;

    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    separator* _sep = new separator();

    _sep->add(new normal);

    bool empty = true;
    colorf clr;

    tools_vforcit(rep_bin1D,a_bins,it) {
      const rep_bin1D& rbin = *it;

      float xx = rbin.m_x_min;
      float xe = rbin.m_x_max;
      float yy = rbin.m_v_min;
      float ye = rbin.m_val;
      if(ye<yy) {
        yy = rbin.m_val;
        ye = rbin.m_v_min;
      }

      float val = rbin.m_val;

      xx = verify_log(xx,xmin,dx,xlog);
      xe = verify_log(xe,xmin,dx,xlog);
      yy = verify_log(yy,ymin,dy,ylog);
      ye = verify_log(ye,ymin,dy,ylog);

      // Clipping :
      if(xx>1) continue;
      if(xe<0) continue;
      if(xx<0) xx = 0;
      if(xe>1) xe = 1;
      if(yy>1) continue;
      if(ye<0) continue;
      if(yy<0) yy = 0;
      if(ye>1) ye = 1;

      //FIXME if(ye<=yy) continue; //Else we shall have a tessellation error.

      separator* sep = new separator();
      _sep->add(sep);

    //a_bins[index].fSeparator = sep;
    //{char s[128];
    //::sprintf(s,"%d",index);
    //sep->setInfos(s);
    //::sprintf(s,"/0x%lx",(unsigned long)sep->getInfos());
    //std::string sid = aID;
    //sid += std::string(s);
    //sep->setString(sid);}

      if(painting==painting_by_value) {
        a_cmap.get_color(val,clr);
      } else if( (painting==painting_grey_scale) ||
                 (painting==painting_grey_scale_inverse) ||
                 (painting==painting_violet_to_red) ){
        a_cmap.get_color(rbin.m_ratio,clr);
      } else {
        clr = a_style.color;
      }

      rgba* mat = new rgba();
      mat->color = clr;
      sep->add(mat);

      vertices* vtxs = new vertices;
      vtxs->mode = gl::triangle_fan();
      sep->add(vtxs);

      vtxs->add(xx,yy,a_zz);
      vtxs->add(xe,yy,a_zz);
      vtxs->add(xe,ye,a_zz);
      vtxs->add(xx,ye,a_zz);

      empty = false;
    }

    if(empty) {
      delete _sep;
    } else {
      m_bins_sep.add(_sep);
    }
  }

  void rep_bins1D_xy_wire_boxes(const style& a_style,
                                const base_colormap& a_cmap,
                                const std::vector<rep_bin1D>& a_bins,
                                const rep_box& a_box_x,const rep_box& a_box_y,
                                float a_zz,
                                bool a_bar_chart/*,
                                const std::string& aID*/){

    painting_policy painting = a_style.painting;

    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    separator* _sep = new separator();

    bool empty = true;
    colorf clr;

    tools_vforcit(rep_bin1D,a_bins,it) {
      const rep_bin1D& rbin = *it;

      float xx = rbin.m_x_min;
      float xe = rbin.m_x_max;
      float yy = rbin.m_v_min;
      float ye = rbin.m_val;
      if(ye<yy) {
        yy = rbin.m_val;
        ye = rbin.m_v_min;
      }

      float val = rbin.m_val;

      if(a_bar_chart) {
        bar_chart(a_style.bar_offset.value(),
                  a_style.bar_width.value(),xx,xe);
      }

      xx = verify_log(xx,xmin,dx,xlog);
      xe = verify_log(xe,xmin,dx,xlog);
      yy = verify_log(yy,ymin,dy,ylog);
      ye = verify_log(ye,ymin,dy,ylog);

      // Clipping :
      if(xx>1) continue;
      if(xe<0) continue;
      if(xx<0) xx = 0;
      if(xe>1) xe = 1;
      if(yy>1) continue;
      if(ye<0) continue;
      if(yy<0) yy = 0;
      if(ye>1) ye = 1;

      separator* sep = new separator();
      _sep->add(sep);

   //{char s[128];
    //::sprintf(s,"%d",index);
    //sep->setInfos(s);
    //::sprintf(s,"/0x%lx",(unsigned long)sep->getInfos());
    //std::string sid = aID;
    //sid += std::string(s);
    //sep->setString(sid);}

      if(painting==painting_by_value) {
        a_cmap.get_color(val,clr);
      } else if( (painting==painting_grey_scale) ||
                 (painting==painting_grey_scale_inverse) ||
                 (painting==painting_violet_to_red) ){
        a_cmap.get_color(rbin.m_ratio,clr);
      } else {
        clr = a_style.color;
      }

      rgba* mat = new rgba();
      mat->color = clr;
      sep->add(mat);

      vertices* vtxs = new vertices;
      vtxs->mode = gl::line_strip();
      sep->add(vtxs);

      vtxs->add(xx,yy,a_zz);
      vtxs->add(xe,yy,a_zz);
      vtxs->add(xe,ye,a_zz);
      vtxs->add(xx,ye,a_zz);
      vtxs->add(xx,yy,a_zz);

      empty = false;
    }

    if(empty) {
      delete _sep;
    } else {
      m_bins_sep.add(_sep);
    }
  }

  void rep_bins1D_xy_lines_one(const style& a_style,const std::vector<rep_bin1D>& a_bins,
                               const rep_box& a_box_x,const rep_box& a_box_y,float a_zz/*,const SbString& aID*/) {
    // Draw lines connecting top middle of bins.

    //::printf("debug : rep_bins2D_lines_one\n");

    size_t xnbin = a_bins.size();
    std::vector<vec3f> points(xnbin);
    for(size_t index=0;index<xnbin;index++) {
      float x = (a_bins[index].m_x_min + a_bins[index].m_x_max)/2;
      float y = a_bins[index].m_val;
      points[index] = vec3f(x,y,a_zz);
    }

    vertices* vtxs = new vertices;
    std::vector<float>& pts = vtxs->xyzs.values(); //npt*3

    clip_polyline_2D(points,a_box_x,a_box_y,pts);
    if(pts.size()) {
      sg::separator* separator = new sg::separator;
      //separator->setString(aID);

      rgba* mat = new rgba();
      mat->color = a_style.color;
      separator->add(mat);

      draw_style* ds = new draw_style;
      ds->style = draw_lines;
      ds->line_pattern = a_style.line_pattern;
      ds->line_width = a_style.line_width;
      separator->add(ds);

      vtxs->mode = gl::line_strip();
      separator->add(vtxs);

      m_bins_sep.add(separator);
    } else {
      delete vtxs;
    }
  }

  void rep_bins1D_xy_curve_one(std::ostream& a_out,const style& a_style,const std::vector<rep_bin1D>& a_bins,
                               const rep_box& a_box_x,const rep_box& a_box_y,float a_zz/*,const SbString& aID*/){
    //::printf("debug : rep_bins1D_curve_one\n");

    size_t number = a_bins.size();
    if(!number) return;

    double* xs = new double[number];
    double* ys = new double[number];
    float x,y;
    for(size_t index=0;index<number;index++) {
      x = (a_bins[index].m_x_min + a_bins[index].m_x_max)/2;
      y = a_bins[index].m_val;
      xs[index] = x;ys[index] = y;
    }
    spline::cubic _spline(a_out,number,xs,ys);
  //spline::quintic _spline(a_out,number,xs,ys);
    delete [] xs;delete [] ys;

    float xmn = m_x_axis_data.min_value();
    float xmx = m_x_axis_data.max_value();
    unsigned int nstp = curve_number_of_points;
    float step = (xmx - xmn)/nstp;
    std::vector<vec3f> points(nstp+1);
    for(unsigned int ibin=0;ibin<=nstp;ibin++) {
      float xx = xmn + ibin * step;
      double val = _spline.eval(xx);
      points[ibin].set_value(xx,float(val),a_zz);
    }

    vertices* vtxs = new vertices;
    std::vector<float>& pts = vtxs->xyzs.values(); //npt*3

    clip_polyline_2D(points,a_box_x,a_box_y,pts);
    if(pts.size()) {
      sg::separator* separator = new sg::separator;
      //separator->setString(aID);

      rgba* mat = new rgba();
      mat->color = a_style.color;
      separator->add(mat);

      draw_style* ds = new draw_style;
      ds->style = draw_lines;
      ds->line_pattern = a_style.line_pattern;
      ds->line_width = a_style.line_width;
      separator->add(ds);

      vtxs->mode = gl::line_strip();
      separator->add(vtxs);

      m_bins_sep.add(separator);
    } else {
      delete vtxs;
    }

  }


  void rep_bins2D_xy_box(const style& a_style,const std::vector<rep_bin2D>& a_bins,
                         const rep_box& a_box_x,const rep_box& a_box_y,float a_bmin,float a_bmax,float a_zz) {
    // Draw box of size proportionnal to bin value.

    //std::cout << "debug : tools::sg::plotter::rep_bins2D_xy_box" << std::endl;

    separator* _sep = new separator();

    _sep->add(new normal);

    rgba* mat = new rgba();
    mat->color = a_style.color;
    _sep->add(mat);

    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    bool empty = true;
    float range = a_bmax - a_bmin;

    tools_vforcit(rep_bin2D,a_bins,it) {
      const rep_bin2D& rbin = *it;

      float xx = rbin.m_x_min;
      float xe = rbin.m_x_max;
      float yy = rbin.m_y_min;
      float ye = rbin.m_y_max;
      float val = rbin.m_val;

      float xsize,ysize;
      if(range>0) {
        // If val = bmax, the box maps the cell.
        xsize = (val - a_bmin) * (xe - xx) / range;
        ysize = (val - a_bmin) * (ye - yy) / range;
      } else {
        //If range is 0. ; then all bins that have
        // entries have same values. Draw box xdbin * ydbin.
        xsize = xe - xx;
        ysize = ye - yy;
      }

      xx = xx + ((xe-xx) - xsize)/2;
      xe = xx + xsize;
      yy = yy + ((ye-yy) - ysize)/2;
      ye = yy + ysize;

      xx = verify_log(xx ,xmin,dx  ,xlog);
      xe = verify_log(xe ,xmin,dx  ,xlog);
      yy = verify_log(yy ,ymin,dy  ,ylog);
      ye = verify_log(ye ,ymin,dy  ,ylog);

      // Clipping :
      if(xx>1) continue;
      if(xe<0) continue;
      if(xx<0) xx = 0;
      if(xe>1) xe = 1;
      if(yy>1) continue;
      if(ye<0) continue;
      if(yy<0) yy = 0;
      if(ye>1) ye = 1;

      //sg::separator* sep = new separator();
      //_sep->add(sep);

   /*{char s[128];
      //::sprintf(s,"%d %d",rbin.fI,rbin.fJ);
      sep->setInfos(s);
      //::sprintf(s,"/0x%lx",(unsigned long)sep->getInfos());
      std::string sid = aID;
      sid += std::string(s);
      sep->setString(sid);}*/

      vertices* vtxs = new vertices;
      vtxs->mode = gl::triangle_fan();
      //sep->add(vtxs);
      _sep->add(vtxs);

      vtxs->add(xx,yy,a_zz);
      vtxs->add(xe,yy,a_zz);
      vtxs->add(xe,ye,a_zz);
      vtxs->add(xx,ye,a_zz);

      empty = false;
    }

    if(empty) {
      delete _sep;
    } else {
      m_bins_sep.add(_sep);
    }
  }

  void rep_bins2D_xy_wire_box(const style& a_style,
                              const std::vector<rep_bin2D>& a_bins,
			      const rep_box& a_box_x,const rep_box& a_box_y,
			      float a_bmin,float a_bmax,float a_zz
                              /*,const SbString& aID*/){
    // Draw box of size proportionnal to bin value.

    sg::separator* separator = new sg::separator;

    rgba* mat = new rgba();
    mat->color = a_style.color;
    separator->add(mat);

    draw_style* ds = new draw_style;
    ds->style = draw_lines;
    ds->line_pattern = a_style.line_pattern;
    ds->line_width = a_style.line_width;
    separator->add(ds);

    vertices* vtxs = new vertices;
    vtxs->mode = gl::lines();
    separator->add(vtxs);

    bool empty = true;

    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    float range = a_bmax - a_bmin;
    size_t number = a_bins.size();
    for(size_t index=0;index<number;index++) {

      float xx = a_bins[index].m_x_min;
      float xe = a_bins[index].m_x_max;
      float yy = a_bins[index].m_y_min;
      float ye = a_bins[index].m_y_max;
      float val = a_bins[index].m_val;

      float xsize,ysize;
      if(range>0) {
        // If val = bmax, the box maps the cell.
        xsize = (val - a_bmin) * (xe - xx) / range;
        ysize = (val - a_bmin) * (ye - yy) / range;
      } else {
        //If range is 0. ; then all bins that have
        // entries have same values. Draw box xdbin * ydbin.
        xsize = xe - xx;
        ysize = ye - yy;
      }

      xx = xx + ((xe-xx) - xsize)/2;
      xe = xx + xsize;
      yy = yy + ((ye-yy) - ysize)/2;
      ye = yy + ysize;

      xx = verify_log(xx ,xmin,dx  ,xlog);
      xe = verify_log(xe ,xmin,dx  ,xlog);
      yy = verify_log(yy ,ymin,dy  ,ylog);
      ye = verify_log(ye ,ymin,dy  ,ylog);

      // Clipping :
      if(xx>1) continue;
      if(xe<0) continue;
      if(xx<0) xx = 0;
      if(xe>1) xe = 1;
      if(yy>1) continue;
      if(ye<0) continue;
      if(yy<0) yy = 0;
      if(ye>1) ye = 1;

      //::printf("debug : zzzzuu : %g %g %g %g\n",xx,xe,yy,ye);

     //{char s[128];
     // ::sprintf(s,"%d %d",a_bins[index].fI,a_bins[index].fJ);
     // sep->setInfos(s);}
     //{std::string sp;
     // if(!p2sx(sep->getInfos(),sp)){}
     // std::string sid(aID.getString());
     // sid += "/"+sp;
     // sep->setString(sid.c_str());}

    //vertices* vtxs = new vertices;
    //vtxs->mode = gl::line_strip();
    //separator->add(vtxs);
    //vtxs->add(xx,yy,a_zz);
    //vtxs->add(xe,yy,a_zz);
    //vtxs->add(xe,ye,a_zz);
    //vtxs->add(xx,ye,a_zz);
    //vtxs->add(xx,yy,a_zz);

      vtxs->add(xx,yy,a_zz);
      vtxs->add(xe,yy,a_zz);

      vtxs->add(xe,yy,a_zz);
      vtxs->add(xe,ye,a_zz);

      vtxs->add(xe,ye,a_zz);
      vtxs->add(xx,ye,a_zz);

      vtxs->add(xx,ye,a_zz);
      vtxs->add(xx,yy,a_zz);

      empty = false;
    }

    if(empty) {
      delete separator;
    } else {
      m_bins_sep.add(separator);
    }
  }

  void rep_bins2D_xy_solid(const style& a_style,const base_colormap& a_cmap,const std::vector<rep_bin2D>& a_bins,
                           const rep_box& a_box_x,const rep_box& a_box_y,float a_zz) {
    painting_policy painting = a_style.painting;

    separator* _sep = new separator();

    _sep->add(new normal);

    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    bool empty = true;
    colorf clr;

    tools_vforcit(rep_bin2D,a_bins,it) {
      const rep_bin2D& rbin = *it;

      float xx = rbin.m_x_min;
      float xe = rbin.m_x_max;
      float yy = rbin.m_y_min;
      float ye = rbin.m_y_max;
      float val = rbin.m_val;

      xx = verify_log(xx ,xmin,dx  ,xlog);
      xe = verify_log(xe ,xmin,dx  ,xlog);
      yy = verify_log(yy ,ymin,dy  ,ylog);
      ye = verify_log(ye ,ymin,dy  ,ylog);

      // Clipping :
      if(xx>1) continue;
      if(xe<0) continue;
      if(xx<0) xx = 0;
      if(xe>1) xe = 1;
      if(yy>1) continue;
      if(ye<0) continue;
      if(yy<0) yy = 0;
      if(ye>1) ye = 1;

      if(painting==painting_by_value) {
        a_cmap.get_color(val,clr);
      } else if( (painting==painting_grey_scale) ||
                 (painting==painting_grey_scale_inverse) ||
                 (painting==painting_violet_to_red) ){
        a_cmap.get_color(rbin.m_ratio,clr);
      } else {
        clr = a_style.color;
      }

      rgba* mat = new rgba();
      mat->color = clr;
      _sep->add(mat);

      vertices* vtxs = new vertices;
      vtxs->mode = gl::triangle_fan();
      //sep->add(vtxs);
      _sep->add(vtxs);

      vtxs->add(xx,yy,a_zz);
      vtxs->add(xe,yy,a_zz);
      vtxs->add(xe,ye,a_zz);
      vtxs->add(xx,ye,a_zz);

      empty = false;
    }

    if(empty) {
      delete _sep;
    } else {
      m_bins_sep.add(_sep);
    }
  }

  void rep_bins2D_xy_random_one(const style& a_style,const std::vector<rep_bin2D>& a_bins,
                                const rep_box& a_box_x,const rep_box& a_box_y,float a_bmin,float a_bmax,float a_zz
                                /*,const SbString& aID*/){
    //::printf("debug : rep_bins2D_xy_random_one\n");

    sg::separator* separator = new sg::separator;

    rgba* mat = new rgba();
    mat->color = a_style.color;
    separator->add(mat);

    draw_style* ds = new draw_style;
    ds->style = draw_points;
    ds->point_size = a_style.point_size;
    separator->add(ds);

    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    //  Draw for each bins a number of random
    // points proportiannal to bins range.

    float range = a_bmax - a_bmin;

    bool empty = true;

    size_t number = a_bins.size();
    for(size_t index=0;index<number;index++) {

      float xx = a_bins[index].m_x_min;
      float xe = a_bins[index].m_x_max;
      float yy = a_bins[index].m_y_min;
      float ye = a_bins[index].m_y_max;
      float val = a_bins[index].m_val;

      // If range is 0. ; then all bins that have entries
      // have same values. Draw one point.

      int nmin = 1;
      int nmax = 50;
      int npt = range>0. ? (int)((val - a_bmin)*(nmax-nmin)/range + nmin):1;
      if(npt>0) {
        vertices* vtxs = new vertices;
        vtxs->mode = gl::points();
        separator->add(vtxs);

        float xdbin = xe - xx;
        float ydbin = ye - yy;
        for(int count=0;count<npt;count++) {
          float xxx = xx + xdbin * m_rtausmef.shoot();
          float yyy = yy + ydbin * m_rtausmef.shoot();
          xxx = verify_log(xxx ,xmin,dx  ,xlog);
          yyy = verify_log(yyy ,ymin,dy  ,ylog);
          if((xxx>=0)&&(xxx<=1)  &&
             (yyy>=0)&&(yyy<=1)  ) {
            vtxs->add(xxx,yyy,a_zz);
            empty = false;
          }
        }
      }

    }//end for

    if(empty) {
      delete separator;
    } else {
      m_bins_sep.add(separator);
    }
  }

  void rep_bins2D_xy_text(
   const style& //a_style
  ,const std::vector<rep_bin2D>& //a_bins
  ,const rep_box& //a_box_x
  ,const rep_box& //a_box_y
  //,const SbString& aID
  ){
    //Draw box and text for number of entries.
    ::printf("debug : rep_bins2D_xy_text : dummy\n");

  /*
    sg::separator* separator = new sg::separator;

    //bool drawWireBoxe = false;

    bool empty = true;

    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    vec3f points[5];

    for(unsigned int index=0;index<a_bins.size();index++) {

      float xx = a_bins[index].m_x_min;
      float xe = a_bins[index].m_x_max;
      float yy = a_bins[index].m_y_min;
      float ye = a_bins[index].m_y_max;
      float val = a_bins[index].m_val;

      int ival = (int)val;
      if(ival==0) continue;

      xx = VerifyLog(xx ,xmin,dx  ,xlog);
      xe = VerifyLog(xe ,xmin,dx  ,xlog);
      yy = VerifyLog(yy ,ymin,dy  ,ylog);
      ye = VerifyLog(ye ,ymin,dy  ,ylog);

      // Clipping :
      if(xx>1) continue;
      if(xe<0) continue;
      if(xx<0) xx = 0;
      if(xe>1) xe = 1;
      if(yy>1) continue;
      if(ye<0) continue;
      if(yy<0) yy = 0;
      if(ye>1) ye = 1;

      char sval[32];
      //::sprintf (sval,"%d",ival);
      SbString sbval(sval);
      int charn = sbval.getLength();
      if(charn<=0) continue;

      SoSceneGraph* sep = new SoSceneGraph;
      separator->addChild(sep);

     {char s[128];
      //::sprintf(s,"%d %d",a_bins[index].fI,a_bins[index].fJ);
      sep->setInfos(s);}
     {std::string sp;
      if(!p2sx(sep->getInfos(),sp)){}
      std::string sid(aID.getString());
      sid += "/"+sp;
      sep->setString(sid.c_str());}

      SoMaterial* material =
        fStyleCache->getMaterial(a_style.color.getValue(),
                                 a_style.transparency.getValue());
      sep->addChild(material);

      sep->addChild(getLineStyle(a_style));

      float dx = xe-xx;
      float dy = ye-yy;

      if(drawWireBoxe) {
        LIST_SET(points,0,xx,yy,0);
        LIST_SET(points,1,xe,yy,0);
        LIST_SET(points,2,xe,ye,0);
        LIST_SET(points,3,xx,ye,0);
        LIST_SET(points,4,xx,yy,0);
        coordIndex[0] = icoord + 0;
        coordIndex[1] = icoord + 1;
        coordIndex[2] = icoord + 2;
        coordIndex[3] = icoord + 3;
        coordIndex[4] = icoord + 4;
        coordIndex[5] = SO_END_LINE_INDEX;

        coordinate3->point.setValues(icoord,5,points);
        icoord += 5;

        SoIndexedLineSet* lineSet = new SoIndexedLineSet;
        lineSet->coordIndex.setValues(0,6,coordIndex);
        sep->addChild(lineSet);
      }

      float x = xx + 0.1F * dx;
      float y = yy + 0.1F * dy;
      float z = 0;
      float w = dx * 0.5F;
      float h = dy * 0.5F;

      SoTransform* transform = new SoTransform;
      transform->scaleFactor.setValue(vec3f(w/charn,h,1));
      transform->translation.setValue(x,y,z);
      sep->addChild(transform);

      SoTextHershey* text = new SoTextHershey;
      text->string.setValue(sbval);
      sep->addChild (text);

      empty = false;
    }

    if(empty) {
      delete separator;
    } else {
      m_bins_sep.add(separator);
    }
  */
  }

  void rep_contour_xy(std::ostream& a_out,const style& a_style,painting_policy a_painting,
                      const base_colormap& a_cmap,clist_contour& a_contour,
		      const rep_box& a_box_x,const rep_box& a_box_y,const rep_box& a_box_z,float a_zz
                      /*,const std::string& aID*/){
    //a_out << "debug : rep_contour_xy :" << std::endl;

    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    float zmin = a_box_z.m_pos;
    float dz = a_box_z.m_width;
    //bool zlog = a_box_z.m_log;

    sg::separator* separator = new sg::separator;
    //separator->setString(aID);

    draw_style* ds = new draw_style;
    ds->style.value(draw_lines);
    ds->line_pattern.value(a_style.line_pattern);
    ds->line_width.value(a_style.line_width);
    separator->add(ds);

    atb_vertices* vtxs = new atb_vertices;
    vtxs->mode = gl::lines(); //segments
    separator->add(vtxs);

    bool empty = true;

    for (unsigned int i=0;i<a_contour.get_number_of_planes();i++)  {
      cline_strip_list* pStripList = a_contour.get_lines(i);
      if(!pStripList) {
        a_out << "tools::sg;:plotter::rep_contour_xy : problem with contour." << std::endl;
        delete separator;
        return;
      }

      //If zlog true, zz is already in log.
      float val = (float)a_contour.get_plane(i);
      float zz = val;

      zz = verify_log(zz,zmin,dz,false);
      if(zz>1) continue;
      if(zz<0) continue;

      colorf _color;
      if(a_painting==painting_by_value) {
        a_cmap.get_color(val,_color);
      } else if(a_painting==painting_by_level) {
        size_t icol = a_cmap.colorn() ? (i % a_cmap.colorn()) :0;
        _color = a_cmap.color(icol);
      } else {
        _color = a_style.color;
      }

      tools_lforcit(cline_strip*,*pStripList,pos) {
        cline_strip* pStrip = (*pos);
        if(!pStrip) {
          a_out << "tools::sg;:plotter::rep_contour_xy : problem with contour." << std::endl;
          delete separator;
          return;
        }
        if (pStrip->empty()) continue;

        //// putting point at start and end of strip
        //// retreiving index
        //unsigned int index=pStrip->front();
        //double xb=a_contour.get_xi(index);
        //double yb=a_contour.get_yi(index);
        //// retreiving index
        ////glColor4f(0,0,1,.8f);
        //index=pStrip->back();
        //double xe=a_contour.get_xi(index);
        //double ye=a_contour.get_yi(index);

        bool first = true;
        float xprev = 0;
        float yprev = 0;
        float xx,yy;

        tools_lforcit(unsigned int,*pStrip,pos2) {
          xx = (float)a_contour.get_xi(*pos2);
          yy = (float)a_contour.get_yi(*pos2);
          xx = verify_log(xx,xmin,dx,xlog);
          yy = verify_log(yy,ymin,dy,ylog);
          if(
              (xx<0) || (xx>1) ||
              (yy<0) || (yy>1)
            ) {
            // Throw away this strip :
          }
	  if(first) {
	    first = false;
	  } else {
            vtxs->add(xprev,yprev,a_zz+zz);
            vtxs->add(xx,yy,a_zz+zz);
            vtxs->add_color(_color);
            vtxs->add_color(_color);
	  }
          xprev = xx;
          yprev = yy;

          empty = false;
      }
    }

    }

    if(empty) {
      delete separator;
    } else {
      m_bins_sep.add(separator);
    }
  }

  void rep_contour_xy_filled(std::ostream& a_out,const style& a_style,painting_policy a_painting,
                             const base_colormap& a_cmap,clist_contour& a_contour,
			     const rep_box& a_box_x,const rep_box& a_box_y,const rep_box& a_box_z,float a_zz
                             /*,const std::string& aID*/){
    //a_out << "debug : rep_contour_xy_filled :" << std::endl;

    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    float zmin = a_box_z.m_pos;
    float dz = a_box_z.m_width;
    //bool zlog = a_box_z.m_log;

    sg::separator* separator = new sg::separator;
    //separator->setString(aID);

    vec3f AB,BC,vcross;

    {// Draw background :
      sg::separator* sep = new sg::separator;
      separator->add(sep);

      float zz = a_zz - 0.01F;

      colorf _color;
      if(a_cmap.colorn()) {
        _color = a_cmap.color(0);
      } else {
        _color = a_style.color;
      }

      rgba* mat = new rgba();
      mat->color = _color;
      sep->add(mat);

      float xx = xmin;
      float xe = xmin+dx;
      float yy = ymin;
      float ye = ymin+dy;

      xx = verify_log(xx,xmin,dx,xlog);
      xe = verify_log(xe,xmin,dx,xlog);
      yy = verify_log(yy,ymin,dy,ylog);
      ye = verify_log(ye,ymin,dy,ylog);

      vertices* vtxs = new vertices;
      vtxs->mode = gl::triangle_fan();
      vtxs->add(xx,yy,zz);
      vtxs->add(xe,yy,zz);
      vtxs->add(xe,ye,zz);
      vtxs->add(xx,ye,zz);
      sep->add(vtxs);

    } // End background.

    bool empty = true;

    for (unsigned int i=0;i<a_contour.get_number_of_planes();i++)  {

      cline_strip_list* pStripList = a_contour.get_lines(i);
      if(!pStripList) {
        a_out << "tools::sg;:plotter::rep_contour_xy_filled : problem with contour." << std::endl;
        delete separator;
        return;
      }

      sg::separator* sep = new sg::separator;
      separator->add(sep);

      //If zlog true, zz is already in log.
      float val = (float)a_contour.get_plane(i);
      float zz = val;

      zz = verify_log(zz,zmin,dz,false);
      if(zz>1) continue;
      if(zz<0) continue;

      std::vector< std::vector<vec3f> > contourVector;

      tools_lforcit(cline_strip*,*pStripList,pos) {
        cline_strip* pStrip = (*pos);
        if(pStrip->size() >2) {
          std::vector<vec3f> v;
          for (cline_strip::iterator pos2=pStrip->begin();pos2 != pStrip->end();pos2++) {
            unsigned int index=(*pos2);
            float xx = (float)a_contour.get_xi(index);
            float yy = (float)a_contour.get_yi(index);
            xx = verify_log(xx,xmin,dx,xlog);
            yy = verify_log(yy,ymin,dy,ylog);
            v.push_back(vec3f(xx,yy,a_zz+zz));
          }
          contourVector.push_back(std::move(v));
        }
      }

      std::vector<tess_triangle> tris;
      tess_contour tessContour(a_out,tris); //we pass a ref to tris.
      tessContour.getFilledArea(contourVector);
      if(!tris.size()) continue;

      colorf _color;
      if(a_painting==painting_by_value) {
        a_cmap.get_color(val,_color);
      } else if(a_painting==painting_by_level) {
        int icol = a_cmap.colorn() ? (i % a_cmap.colorn()) :0;
        _color = a_cmap.color(icol);
      } else {
        _color = a_style.color;
      }

      atb_vertices* vtxs = new atb_vertices; //PAW_C/color.kumac. It needs back face.
      vtxs->mode = gl::triangles();
      sep->add(vtxs);

      for(size_t itri=0;itri<tris.size();itri++) {
        tess_triangle& tri = tris[itri];
	AB.set_value((float)(tri.pointB[0]-tri.pointA[0]),
                     (float)(tri.pointB[1]-tri.pointA[1]),
                     (float)(tri.pointB[2]-tri.pointA[2]));
        BC.set_value((float)(tri.pointC[0]-tri.pointB[0]),
                     (float)(tri.pointC[1]-tri.pointB[1]),
                     (float)(tri.pointC[2]-tri.pointB[2]));
        AB.cross(BC,vcross);
	if(vcross.z()>=0) {
          vtxs->add((float)tri.pointA[0],(float)tri.pointA[1],(float)tri.pointA[2]);
          vtxs->add((float)tri.pointB[0],(float)tri.pointB[1],(float)tri.pointB[2]);
          vtxs->add((float)tri.pointC[0],(float)tri.pointC[1],(float)tri.pointC[2]);
	} else {
          vtxs->add((float)tri.pointA[0],(float)tri.pointA[1],(float)tri.pointA[2]);
          vtxs->add((float)tri.pointC[0],(float)tri.pointC[1],(float)tri.pointC[2]);
          vtxs->add((float)tri.pointB[0],(float)tri.pointB[1],(float)tri.pointB[2]);
	}
        vtxs->add_color(_color);
        vtxs->add_color(_color);
        vtxs->add_color(_color);
      }

      empty = false;

    }

    if(empty) {
      delete separator;
    } else {
      m_bins_sep.add(separator);
    }
  }

  void rep_errors_plus_xy(std::ostream& /*a_out*/,const style& a_style,const std::vector<rep_bin1D>& a_bins,
                          const rep_box& a_box_x,const rep_box& a_box_y,const std::vector<float>& a_bars,float aZ) {
    //a_out << "debug : rep_erros_plus_xy : begin :" << std::endl;
    separator* _sep = new separator();
    //_sep->setString(aID);

    rgba* mat = new rgba();
    mat->color = a_style.color;
    _sep->add(mat);

    draw_style* ds = new draw_style;
    ds->style.value(draw_lines);
    ds->line_pattern.value(a_style.line_pattern);
    ds->line_width.value(a_style.line_width);
    _sep->add(ds);

    vertices* vtxs = new vertices;
    vtxs->mode = gl::lines();
    _sep->add(vtxs);

    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    size_t xnbin = a_bins.size();

    for(size_t index=0;index<xnbin;index++) {

      //Need all bins modeled for fitting.

      float val = a_bins[index].m_val;
      float bar_height = a_bars[index];

      float bar_min = val - bar_height/2;
      float bar_max = val + bar_height/2;

      float xx = a_bins[index].m_x_min;
      float xe = a_bins[index].m_x_max;

      xx = verify_log(xx,xmin,dx,xlog);
      xe = verify_log(xe,xmin,dx,xlog);
      val = verify_log(val,ymin,dy,ylog);

      bar_min = verify_log(bar_min,ymin,dy,ylog);
      bar_max = verify_log(bar_max,ymin,dy,ylog);

      if(xe<0) continue;
      if(xx>1) continue;
      if(xx<0) xx = 0;
      if(xe>1) xe = 1;
      //if(val<0) val = 0;
      //if(val>1) val = 1;

      float ex = (xe+xx)/2;
      //if( (ex >=0)&&(ex <=1) ) { //FIXME : have to clip

      float edx = 0.3F * (xe-xx);

      if((val>=0)&&(val<=1)) {
        vtxs->add(ex-edx,val,aZ);
        vtxs->add(ex+edx,val,aZ);
      }

      if(bar_min >1)  {
        // do nothing
      } else  if(bar_max <0)  {
        // do nothing
      } else  if(bar_min <0) {
        if(bar_max >1) {
          vtxs->add(ex,0,aZ);
          vtxs->add(ex,1,aZ);
        } else {
          vtxs->add(ex,0,aZ);
          vtxs->add(ex,bar_max,aZ);
        }
      } else  if(bar_max >1) {
        vtxs->add(ex,bar_min,aZ);
        vtxs->add(ex,1,aZ);
      } else {
        vtxs->add(ex    ,bar_min,aZ);
        vtxs->add(ex    ,bar_max,aZ);
      }

    }

    if(vtxs->number()) {
      m_errors_sep.add(_sep);
    } else {
      delete _sep;
    }
  }

  void rep_errors_I_xy(std::ostream& /*a_out*/,const style& a_style,const std::vector<rep_bin1D>& a_bins,
                       const rep_box& a_box_x,const rep_box& a_box_y,const std::vector<float>& a_bars,float aZ){
    //a_out << "debug : rep_erros_I_xy : begin :" << std::endl;
    separator* _sep = new separator();
    //_sep->setString(aID);

    rgba* mat = new rgba();
    mat->color = a_style.color;
    _sep->add(mat);

    draw_style* ds = new draw_style;
    ds->style.value(draw_lines);
    ds->line_pattern.value(a_style.line_pattern);
    ds->line_width.value(a_style.line_width);
    _sep->add(ds);

    vertices* vtxs = new vertices;
    vtxs->mode = gl::lines();
    _sep->add(vtxs);

    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    size_t xnbin = a_bins.size();

    for(size_t index=0;index<xnbin;index++) {

      //Need all bins modeled for fitting.

      float val = a_bins[index].m_val;
      float bar_height = a_bars[index];

      float bar_min = val - bar_height/2;
      float bar_max = val + bar_height/2;

      float xx = a_bins[index].m_x_min;
      float xe = a_bins[index].m_x_max;

      xx = verify_log(xx,xmin,dx,xlog);
      xe = verify_log(xe,xmin,dx,xlog);
      val = verify_log(val,ymin,dy,ylog);

      bar_min = verify_log(bar_min,ymin,dy,ylog);
      bar_max = verify_log(bar_max,ymin,dy,ylog);

      if(xe<0) continue;
      if(xx>1) continue;
      if(xx<0) xx = 0;
      if(xe>1) xe = 1;
      if(val<0) val = 0;
      if(val>1) val = 1;

      float ex = (xe+xx)/2;
      //if( (ex >=0)&&(ex <=1) ) { //FIXME : have to clip

      float edx = 0.3F * (xe-xx);

      if(bar_min >1)  {
        // do nothing
      } else  if(bar_max <0)  {
        // do nothing
      } else  if(bar_min <0) {
        if(bar_max >1) {
          vtxs->add(ex,0,aZ);
          vtxs->add(ex,1,aZ);
        } else {
          vtxs->add(ex,0,aZ);
          vtxs->add(ex,bar_max,aZ);
          vtxs->add(ex-edx,bar_max,aZ);
          vtxs->add(ex+edx,bar_max,aZ);
        }
      } else  if(bar_max >1) {
        vtxs->add(ex-edx,bar_min,aZ);
        vtxs->add(ex+edx,bar_min,aZ);
        vtxs->add(ex,bar_min,aZ);
        vtxs->add(ex,1,aZ);
      } else {
        vtxs->add(ex-edx,bar_min,aZ);
        vtxs->add(ex+edx,bar_min,aZ);
        vtxs->add(ex    ,bar_min,aZ);
        vtxs->add(ex    ,bar_max,aZ);
        vtxs->add(ex-edx,bar_max,aZ);
        vtxs->add(ex+edx,bar_max,aZ);
      }

    }

    if(vtxs->number()) {
      m_errors_sep.add(_sep);
    } else {
      delete _sep;
    }
  }

  void rep_hatch1D_xy(const style& a_style,
                      const std::vector<rep_bin1D>& a_bins,
		      const rep_box& a_box_x,const rep_box& a_box_y,float a_zz,
		      bool a_bar_chart){
    //printf("debug : tools::sg;:plotter::repHatch1D_xy : zz %g barchart %d sw %g\n",a_zz,aBarChart,a_style.stripWidth.getValue());

    separator* _sep = new separator;

    rgba* mat = new rgba();
    mat->color = a_style.color;
    _sep->add(mat);

    draw_style* ds = new draw_style;
    if(a_style.strip_width.value()==0) {
      ds->style = draw_lines;
      ds->line_pattern = line_solid;
      ds->line_width = a_style.line_width;
    } else {
      ds->style = draw_filled;
      //ds->cull_face = true;
    }
    _sep->add(ds);

    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    bool empty = true;

    vec3f points[5];
    size_t xnbin = a_bins.size();
    for(size_t index=0;index<xnbin;index++) {
      float xx = a_bins[index].m_x_min;
      float xe = a_bins[index].m_x_max;
      float yy = a_bins[index].m_v_min;
      float ye = a_bins[index].m_val;
      if(ye<yy) {
        yy = a_bins[index].m_val;
        ye = a_bins[index].m_v_min;
      }

      if(a_bar_chart) bar_chart(a_style.bar_offset.value(),a_style.bar_width.value(),xx,xe);

      xx = verify_log(xx,xmin,dx,xlog);
      xe = verify_log(xe,xmin,dx,xlog);
      yy = verify_log(yy,ymin,dy,ylog);
      ye = verify_log(ye,ymin,dy,ylog);

      // Clipping :
      if(xx>1) continue;
      if(xe<0) continue;
      if(xx<0) xx = 0;
      if(xe>1) xe = 1;
      if(yy>1) continue;
      if(ye<0) continue;
      if(yy<0) yy = 0;
      if(ye>1) ye = 1;

      points[0].set_value(xx,yy,a_zz);
      points[1].set_value(xe,yy,a_zz);
      points[2].set_value(xe,ye,a_zz);
      points[3].set_value(xx,ye,a_zz);
      points[4].set_value(xx,yy,a_zz);

      //FIXME : have picking a hatch picks also the bin.

      hatcher _hatcher;
      _hatcher.set_offset_point(vec3f(0,0,a_zz));
      _hatcher.set_angle(a_style.angle.value());
      _hatcher.set_spacing(a_style.spacing.value());
      if(!_hatcher.set_strip_width(a_style.strip_width.value())) {}

      bool res = _hatcher.check_polyline(points,4);
      if(res) res = _hatcher.compute_polyline(points,4);

      size_t numPoints = _hatcher.points().size();
      size_t numVertices = _hatcher.vertices().size();
      if((res) && numPoints && numVertices) {

          const std::vector<vec3f>& _points = _hatcher.points();

          if(a_style.strip_width.value()==0) {

            size_t ipt = 0;
	    tools_vforcit(unsigned int,_hatcher.vertices(),itv) {
              vertices* vtxs = new vertices;
              vtxs->mode = gl::line_strip();
              for(size_t _index=0;_index<(*itv);_index++) {
                vtxs->add(_points[ipt]);
		ipt++;
       	      }
              _sep->add(vtxs);
              empty = false;
	    }

          } else {
            size_t ipt = 0;
	    tools_vforcit(unsigned int,_hatcher.vertices(),itv) {
              vertices* vtxs = new vertices;
              vtxs->mode = gl::triangle_fan();
              for(size_t _index=0;_index<(*itv);_index++) {
                vtxs->add(_points[ipt]);
		ipt++;
       	      }
              _sep->add(vtxs);
              empty = false;
	    }
	  }

      }
    }
    if(empty) {
      delete _sep;
    } else {
      m_bins_sep.add(_sep);
    }
  }

  void rep_points2D_xy_lines(const style& a_style,const points2D& a_points,
                             const rep_box& a_box_x,const rep_box& a_box_y,float a_zz){
    //::printf("debug : rep_points2D_xy_lines\n");
    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    separator* _sep = new separator();

    rgba* mat = new rgba();
    mat->color = a_style.color;
    _sep->add(mat);

    draw_style* ds = new draw_style;
    ds->style.value(draw_lines);
    ds->line_pattern.value(a_style.line_pattern);
    ds->line_width.value(a_style.line_width);
    _sep->add(ds);

    vertices* vtxs = new vertices;
    vtxs->mode = gl::line_strip();
    _sep->add(vtxs);

    bool empty = true;

    float x,y;
    unsigned int number = a_points.points();
    for(unsigned int index=0;index<number;index++) {
      a_points.ith_point(index,x,y);
      x = verify_log(x,xmin,dx,xlog);
      y = verify_log(y,ymin,dy,ylog);
      if((x<0)||(x>1)||(y<0)||(y>1)) continue;
      vtxs->add(x,y,a_zz);
      empty = false;
    }

    if(empty) {
      delete _sep;
    } else {
      m_points_sep.add(_sep);
    }
  }

  void rep_points2D_xy_curve(std::ostream& a_out,const style& a_style,const points2D& a_points,
                             const rep_box& a_box_x,const rep_box& a_box_y,float a_zz){
    //::printf("debug : rep_points2D_xy_curve\n");
    unsigned int number = a_points.points();
    if(!number) return;

    double* xs = new double[number];
    double* ys = new double[number];
    float x,y;
   {for(unsigned int index=0;index<number;index++) {
      a_points.ith_point(index,x,y);
      xs[index] = x;ys[index] = y;
    }}
    spline::cubic _spline(a_out,number,xs,ys);
  //spline::quintic _spline(a_out,number,xs,ys);
    delete [] xs;delete [] ys;

    float xmn = m_x_axis_data.min_value();
    float xmx = m_x_axis_data.max_value();
    unsigned int nstp = curve_number_of_points;
    float step = (xmx - xmn)/nstp;
    std::vector<vec3f> points(nstp+1);
    for(unsigned int ibin=0;ibin<=nstp;ibin++) {
      float xx = xmn + ibin * step;
      double val = _spline.eval(xx);
      points[ibin].set_value(xx,float(val),a_zz);
    }

    vertices* vtxs = new vertices;
    std::vector<float>& pts = vtxs->xyzs.values(); //npt*3

    clip_polyline_2D(points,a_box_x,a_box_y,pts);
    if(pts.size()) {
      sg::separator* separator = new sg::separator;
      //separator->setString(aID);

      rgba* mat = new rgba();
      mat->color = a_style.color;
      separator->add(mat);

      draw_style* ds = new draw_style;
      ds->style = draw_lines;
      ds->line_pattern = a_style.line_pattern;
      ds->line_width = a_style.line_width;
      separator->add(ds);

      vtxs->mode = gl::line_strip();
      separator->add(vtxs);

      m_points_sep.add(separator);
    } else {
      delete vtxs;
    }

  }

  void rep_points2D_xy_points(std::ostream& a_out,
                              const style& a_style,const points2D& a_points,
                              const rep_box& a_box_x,const rep_box& a_box_y,float a_zz) {
    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    separator* _sep = new separator();

    rgba* mat = new rgba();
    mat->color = a_style.color;
    _sep->add(mat);

    mf<float>* _xyzs = 0;

    if(a_style.modeling==modeling_markers()) {
      markers* _marks = new markers;
      _marks->size = a_style.marker_size;
      _marks->style = a_style.marker_style;
      _xyzs = &(_marks->xyzs);
      _sep->add(_marks);

    } else if(a_style.modeling==modeling_points()) {
      draw_style* ds = new draw_style;
      ds->style = draw_points;
      ds->point_size = a_style.point_size;
      _sep->add(ds);

      vertices* vtxs = new vertices;
      vtxs->mode = gl::points();
      _xyzs = &(vtxs->xyzs);
      _sep->add(vtxs);
    } else {
      a_out << "tools::sg::plotter::rep_points2D_xy_points :"
            << " bad modeling style " << tools::sout(a_style.modeling) << std::endl;
      delete _sep;
      return;
    }

    float x,y;

    // first round trip to get number of floats :
    size_t npts = 0;
   {unsigned int number = a_points.points();
    for(unsigned int index=0;index<number;index++) {
      a_points.ith_point(index,x,y);
      //float val = a_bins[index].m_val;
      x = verify_log(x,xmin,dx,xlog);
      y = verify_log(y,ymin,dy,ylog);
      if((x<0)||(x>1)||(y<0)||(y>1)) continue;
      npts += 3;
    }}

    _xyzs->values().resize(npts);
    size_t xyz_pos = 0;

    bool empty = true;

   {unsigned int number = a_points.points();
    for(unsigned int index=0;index<number;index++) {
      a_points.ith_point(index,x,y);
      //float val = a_bins[index].m_val;
      x = verify_log(x,xmin,dx,xlog);
      y = verify_log(y,ymin,dy,ylog);
      if((x<0)||(x>1)||(y<0)||(y>1)) continue;
      _xyzs->add_allocated(xyz_pos,x,y,a_zz);
      empty = false;
    }}

    if(empty) {
      delete _sep;
    } else {
      m_points_sep.add(_sep);
    }
  }

  void rep_points3D_xyz_points(std::ostream& a_out,
                               const style& a_style,const points3D& a_points,
                               const rep_box& a_box_x,const rep_box& a_box_y,const rep_box& a_box_z) {
    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    float zmin = a_box_z.m_pos;
    float dz = a_box_z.m_width;
    bool zlog = a_box_z.m_log;

    separator* _sep = new separator();

    rgba* mat = new rgba();
    mat->color = a_style.color;
    _sep->add(mat);

    mf<float>* _xyzs = 0;

    if(a_style.modeling==modeling_markers()) {
      markers* _marks = new markers;
      _marks->size = a_style.marker_size;
      _marks->style = a_style.marker_style;
      _xyzs = &(_marks->xyzs);
      _sep->add(_marks);

    } else if(a_style.modeling==modeling_points()) {
      draw_style* ds = new draw_style;
      ds->style = draw_points;
      ds->point_size = a_style.point_size;
      _sep->add(ds);

      vertices* vtxs = new vertices;
      vtxs->mode = gl::points();
      _xyzs = &(vtxs->xyzs);
      _sep->add(vtxs);
    } else {
      a_out << "tools::sg::plotter::rep_points3D_xy_points :"
            << " bad modeling style " << tools::sout(a_style.modeling) << std::endl;
      delete _sep;
      return;
    }

    float x,y,z;

    // first round trip to get number of floats :
    size_t npts = 0;
   {unsigned int number = a_points.points();
    for(unsigned int index=0;index<number;index++) {
      a_points.ith_point(index,x,y,z);
      //float val = a_bins[index].m_val;
      x = verify_log(x,xmin,dx,xlog);
      y = verify_log(y,ymin,dy,ylog);
      z = verify_log(z,zmin,dz,zlog);
      if((x<0)||(x>1)||(y<0)||(y>1)||(z<0)||(z>1)) continue;
      npts += 3;
    }}

    _xyzs->values().resize(npts);
    size_t xyz_pos = 0;

    bool empty = true;

   {unsigned int number = a_points.points();
    for(unsigned int index=0;index<number;index++) {
      a_points.ith_point(index,x,y,z);
      //float val = a_bins[index].m_val;
      x = verify_log(x,xmin,dx,xlog);
      y = verify_log(y,ymin,dy,ylog);
      z = verify_log(z,zmin,dz,zlog);
      if((x<0)||(x>1)||(y<0)||(y>1)||(z<0)||(z>1)) continue;
      _xyzs->add_allocated(xyz_pos,x,y,z);
      empty = false;
    }}

    if(empty) {
      delete _sep;
    } else {
      m_points_sep.add(_sep);
    }
  }

  void rep_bins2D_xyz_box(const style& a_style,const base_colormap& a_cmap,const std::vector<rep_bin2D>& a_bins,
                          const rep_box& a_box_x,const rep_box& a_box_y,const rep_box& a_box_z,float a_bmin,float /*a_bmax*/){
    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    float zmin = a_box_z.m_pos;
    float dz = a_box_z.m_width;
    bool zlog = a_box_z.m_log;

    painting_policy painting = a_style.painting;

    separator* _sep = new separator();

    bool empty = true;
    //float range = a_bmax - a_bmin;
    colorf clr;

    tools_vforcit(rep_bin2D,a_bins,it) {
      const rep_bin2D& rbin = *it;

      float xx = rbin.m_x_min;
      float xe = rbin.m_x_max;
      float yy = rbin.m_y_min;
      float ye = rbin.m_y_max;
      float val = rbin.m_val;
      float zz = a_bmin;
      float ze = val;

      xx = verify_log(xx ,xmin,dx  ,xlog);
      xe = verify_log(xe ,xmin,dx  ,xlog);
      yy = verify_log(yy ,ymin,dy  ,ylog);
      ye = verify_log(ye ,ymin,dy  ,ylog);
      zz = verify_log(zz ,zmin,dz  ,zlog);
      ze = verify_log(ze ,zmin,dz  ,zlog);

      // Clipping :
      if(xx>1) continue;
      if(xe<0) continue;
      if(xx<0) xx = 0;
      if(xe>1) xe = 1;

      if(yy>1) continue;
      if(ye<0) continue;
      if(yy<0) yy = 0;
      if(ye>1) ye = 1;

      if(zz>1) continue;
      if(ze<0) continue;
      if(zz<0) zz = 0;
      if(ze>1) ze = 1;

      if(yy>=ye) continue;
      if(xx>=xe) continue;
      if(zz>=ze) continue;

      separator* sep = new separator();
      _sep->add(sep);

      if(painting==painting_by_value) {
        a_cmap.get_color(val,clr);
      } else if( (painting==painting_grey_scale) ||
                 (painting==painting_grey_scale_inverse) ||
                 (painting==painting_violet_to_red) ){
        a_cmap.get_color(rbin.m_ratio,clr);
      } else {
        clr = a_style.color;
      }

      rgba* mat = new rgba();
      mat->color = clr;
      sep->add(mat);

   /*{char s[128];
      //::sprintf(s,"%d %d",rbin.fI,rbin.fJ);
      sep->setInfos(s);
      //::sprintf(s,"/0x%lx",(unsigned long)sep->getInfos());
      std::string sid = aID;
      sid += std::string(s);
      sep->setString(sid);}*/

      float sx = xe-xx;
      float sy = ye-yy;
      float sz = ze-zz;

      matrix* _tsf = new matrix;
      _tsf->set_translate(xx+sx/2,yy+sy/2,sz/2);
      sep->add(_tsf);

      cube* _cube = new cube;
      _cube->width = sx;
      _cube->height = sy;
      _cube->depth = sz;
      sep->add(_cube);

      empty = false;
    }

    if(empty) {
      delete _sep;
    } else {
      m_bins_sep.add(_sep);
    }
  }

  void rep_top_face2D_xyz(separator& a_sep,const style& a_style,const base_colormap& a_cmap,
                          const std::vector<rep_top_face2D>& a_faces,
			  const rep_box& a_box_x,const rep_box& a_box_y,const rep_box& a_box_z) {
    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    float zmin = a_box_z.m_pos;
    float dz = a_box_z.m_width;
    bool zlog = a_box_z.m_log;

    bool empty = true;

    painting_policy painting = a_style.painting;

    separator* _sep = new separator();

    //draw_style* ds = new draw_style;
    //ds->style = draw_filled;
    //ds->cull_face = true;
    //_sep->add(ds);

    atb_vertices* vtxs = new atb_vertices;
    vtxs->mode = gl::triangles();
    vtxs->do_back = true;
    vtxs->epsilon = 1e-6f;
    _sep->add(vtxs);

    colorf clr;
    vec3f nm;

    size_t number = a_faces.size();
    for(size_t index=0;index<number;index++) {
      float xx = a_faces[index].m_x_min;
      float xe = a_faces[index].m_x_max;
      float yy = a_faces[index].m_y_min;
      float ye = a_faces[index].m_y_max;
      float val1 = a_faces[index].m_v1;
      float val2 = a_faces[index].m_v2;
      float val3 = a_faces[index].m_v3;
      float val4 = a_faces[index].m_v4;

      float val = val1;

      val1 = verify_log(val1,zmin,dz,zlog);
      val2 = verify_log(val2,zmin,dz,zlog);
      val3 = verify_log(val3,zmin,dz,zlog);
      val4 = verify_log(val4,zmin,dz,zlog);
      xx = verify_log(xx,xmin,dx,xlog);
      xe = verify_log(xe,xmin,dx,xlog);
      yy = verify_log(yy,ymin,dy,ylog);
      ye = verify_log(ye,ymin,dy,ylog);

      if(val1<0) val1 = 0;
      if(val1>1) val1 = 1;

      if(val2<0) val2 = 0;
      if(val2>1) val2 = 1;

      if(val3<0) val3 = 0;
      if(val3>1) val3 = 1;

      if(val4<0) val4 = 0;
      if(val4>1) val4 = 1;

      if((xx>=0)&&(xx<=1)   &&
         (xe>=0)&&(xe<=1)   &&
         (yy>=0)&&(yy<=1)   &&
         (ye>=0)&&(ye<=1)  ) {

        if(painting==painting_by_value) {
          float v = (zlog?take_log(val):val);
          a_cmap.get_color(v,clr);
        } else if( (painting==painting_grey_scale) ||
                   (painting==painting_grey_scale_inverse) ||
                   (painting==painting_violet_to_red) ){
          a_cmap.get_color(a_faces[index].m_ratio,clr);
        } else {
          clr = a_style.color;
        }

        //if(a_style.area_style.getValue()==SoStyle::EDGED) { //OpenPAW.
        //}

        //////////////////////////////////////
        //////////////////////////////////////
        vtxs->add(xx,ye,val4);
        vtxs->add(xx,yy,val1);
        vtxs->add(xe,yy,val2);

        vtxs->add_color(clr);
        vtxs->add_color(clr);
        vtxs->add_color(clr);

        direction(xx,ye,val4,
                  xx,yy,val1,
                  xe,yy,val2,nm);
        nm.normalize();
        vtxs->add_normal(nm[0],nm[1],nm[2]);
        vtxs->add_normal(nm[0],nm[1],nm[2]);
        vtxs->add_normal(nm[0],nm[1],nm[2]);

        //////////////////////////////////////
        //////////////////////////////////////
        vtxs->add(xe,yy,val2);
        vtxs->add(xe,ye,val3);
        vtxs->add(xx,ye,val4);

        vtxs->add_rgba(clr[0],clr[1],clr[2],clr[3]);
        vtxs->add_rgba(clr[0],clr[1],clr[2],clr[3]);
        vtxs->add_rgba(clr[0],clr[1],clr[2],clr[3]);

        direction(xe,yy,val2,
                  xe,ye,val3,
                  xx,ye,val4,nm);
        nm.normalize();
        vtxs->add_normal(nm[0],nm[1],nm[2]);
        vtxs->add_normal(nm[0],nm[1],nm[2]);
        vtxs->add_normal(nm[0],nm[1],nm[2]);

        empty = false;
      }
    }
    if(empty) {
      delete _sep;
    } else {
      a_sep.add(_sep);
    }
  }

  void rep_top_face2D_xyz_line(const style& /*a_style*/,const std::vector<rep_top_face2D>& a_top_faces,
                               const rep_box& a_box_x,const rep_box& a_box_y,const rep_box& a_box_z/*,const SbString& aID*/){
    //::printf("debug : rep_top_face2D_xyz_line\n");

    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    float zmin = a_box_z.m_pos;
    float dz = a_box_z.m_width;
    bool zlog = a_box_z.m_log;

    sg::separator* separator = new sg::separator;
    bool empty = true;

    rgba* mat = new rgba();
    mat->color = colorf_black();
    separator->add(mat);

    draw_style* ds = new draw_style;
    ds->style = draw_lines;
    ds->line_pattern = line_solid;
    ds->line_width = 1;
    separator->add(ds);

    vertices* vtxs = new vertices;
    vtxs->mode = gl::lines();
    separator->add(vtxs);

    float zepsilon = 0.02f; //for pawex9.kumac top-left and bottom-right.

    size_t number = a_top_faces.size();
    for(size_t index=0;index<number;index++) {
      float xx = a_top_faces[index].m_x_min;
      float xe = a_top_faces[index].m_x_max;
      float yy = a_top_faces[index].m_y_min;
      float ye = a_top_faces[index].m_y_max;
      float val1 = a_top_faces[index].m_v1;
      float val2 = a_top_faces[index].m_v2;
      float val3 = a_top_faces[index].m_v3;
      float val4 = a_top_faces[index].m_v4;

      //float val = val1;

      val1 = verify_log(val1,zmin,dz,zlog);
      val2 = verify_log(val2,zmin,dz,zlog);
      val3 = verify_log(val3,zmin,dz,zlog);
      val4 = verify_log(val4,zmin,dz,zlog);
      xx = verify_log(xx,xmin,dx,xlog);
      xe = verify_log(xe,xmin,dx,xlog);
      yy = verify_log(yy,ymin,dy,ylog);
      ye = verify_log(ye,ymin,dy,ylog);

      if(val1<0) val1 = 0;
      if(val1>1) val1 = 1;

      if(val2<0) val2 = 0;
      if(val2>1) val2 = 1;

      if(val3<0) val3 = 0;
      if(val3>1) val3 = 1;

      if(val4<0) val4 = 0;
      if(val4>1) val4 = 1;

      if((xx>=0)&&(xx<=1)   &&
         (xe>=0)&&(xe<=1)   &&
         (yy>=0)&&(yy<=1)   &&
         (ye>=0)&&(ye<=1)  ) {

        vtxs->add(xx,ye,val4+zepsilon);
        vtxs->add(xx,yy,val1+zepsilon);

        vtxs->add(xx,yy,val1+zepsilon);
        vtxs->add(xe,yy,val2+zepsilon);

        vtxs->add(xe,yy,val2+zepsilon);
        vtxs->add(xe,ye,val3+zepsilon);

        vtxs->add(xe,ye,val3+zepsilon);
        vtxs->add(xx,ye,val4+zepsilon);

        empty = false;

      }
    }
    if(empty) {
      delete separator;
    } else {
      m_bins_sep.add(separator);
    }
  }

  void rep_top_face2D_xyz_by_level(const style& /*a_style*/,painting_policy /*a_painting*/,const base_colormap& a_cmap,
                                   const std::vector<rep_top_face2D>& a_top_faces,
                                   const rep_box& a_box_x,const rep_box& a_box_y,const rep_box& a_box_z,
                                   float a_bmin,float a_bmax/*,const SbString& aID*/){
    //::printf("debug : rep_top_face2D_xyz_by_level\n");

    size_t ncol = a_cmap.colorn();
    if(!ncol) return;

    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    float zmin = a_box_z.m_pos;
    float dz = a_box_z.m_width;
    bool zlog = a_box_z.m_log;

    float zz = a_bmin;
    zz = verify_log(zz,zmin,dz,zlog);
    float zmx = a_bmax;
    zmx = verify_log(zmx,zmin,dz,zlog);

    bool empty = true;

    sg::separator* separator = new sg::separator;
    //separator->setString(aID);

    atb_vertices* tris = new atb_vertices;
    tris->mode = gl::triangles();
    tris->do_back = true;
    tris->epsilon = 1e-6f;
    separator->add(tris);

    colorf _color;
    vec3f _point;

    float d_z = (zmx-zz)/ncol;

    size_t number = a_top_faces.size();

    for(size_t icol=0;icol<ncol;icol++) {

      //sg::separator* sep = new sg::separator;
      //bool sep_empty = true;

      _color = a_cmap.color(icol);

      for(size_t index=0;index<number;index++) {
        float xx = a_top_faces[index].m_x_min;
        float xe = a_top_faces[index].m_x_max;
        float yy = a_top_faces[index].m_y_min;
        float ye = a_top_faces[index].m_y_max;
        float val1 = a_top_faces[index].m_v1;
        float val2 = a_top_faces[index].m_v2;
        float val3 = a_top_faces[index].m_v3;
        float val4 = a_top_faces[index].m_v4;

        //float val = val1;

        val1 = verify_log(val1,zmin,dz,zlog);
        val2 = verify_log(val2,zmin,dz,zlog);
        val3 = verify_log(val3,zmin,dz,zlog);
        val4 = verify_log(val4,zmin,dz,zlog);
        xx = verify_log(xx,xmin,dx,xlog);
        xe = verify_log(xe,xmin,dx,xlog);
        yy = verify_log(yy,ymin,dy,ylog);
        ye = verify_log(ye,ymin,dy,ylog);

        if(val1<0) val1 = 0;
        if(val1>1) val1 = 1;

        if(val2<0) val2 = 0;
        if(val2>1) val2 = 1;

        if(val3<0) val3 = 0;
        if(val3>1) val3 = 1;

        if(val4<0) val4 = 0;
        if(val4>1) val4 = 1;

        if((xx>=0)&&(xx<=1)   &&
           (xe>=0)&&(xe<=1)   &&
           (yy>=0)&&(yy<=1)   &&
           (ye>=0)&&(ye<=1)  ) {

          //////////////////////////////////////
          //////////////////////////////////////
         {clip<vec3f> clipper;
          clipper.add(vec3f(xx,ye,val4));
          clipper.add(vec3f(xx,yy,val1));
          clipper.add(vec3f(xe,yy,val2));
          //val[n] had been z normalized.
          float z1 = zz+d_z*icol;
          float z2 = z1+d_z;
          plane<vec3f> plane_z_bot(vec3f(0,0,1),vec3f(0,0,z1));
          plane<vec3f> plane_z_top(vec3f(0,0,-1),vec3f(0,0,z2));
          clipper.execute(plane_z_bot);
          clipper.execute(plane_z_top);

          const std::vector<vec3f>& result = clipper.result();
          if(result.size()) {
            plane<vec3f> plane1(vec3f(xx,ye,val4),vec3f(xx,yy,val1),vec3f(xe,yy,val2));
            if(result.size()==3) {
              tools_vforcit(vec3f,result,it) {
                tris->add(*it);
                tris->add_color(_color);
                tris->add_normal(plane1.normal());
              }
            } else {
              atb_vertices* vtxs = new atb_vertices; //FIXME : ouch! optimize.
              vtxs->mode = gl::triangle_fan();
              vtxs->do_back = true;
              vtxs->epsilon = 1e-6f;
              separator->add(vtxs);
              tools_vforcit(vec3f,result,it) {
                vtxs->add(*it);
                vtxs->add_color(_color);
                vtxs->add_normal(plane1.normal());
              }
    	  }
            empty = false;
            //sep_empty = false;
          }}

          //////////////////////////////////////
          //////////////////////////////////////
         {clip<vec3f> clipper;
          clipper.add(vec3f(xe,yy,val2));
          clipper.add(vec3f(xe,ye,val3));
          clipper.add(vec3f(xx,ye,val4));
          //val[n] had been z normalized.
          float z1 = zz+d_z*icol;
          float z2 = z1+d_z;
          plane<vec3f> plane_z_bot(vec3f(0,0,1),vec3f(0,0,z1));
          plane<vec3f> plane_z_top(vec3f(0,0,-1),vec3f(0,0,z2));
          clipper.execute(plane_z_bot);
          clipper.execute(plane_z_top);

          const std::vector<vec3f>& result = clipper.result();
          if(result.size()) {
            plane<vec3f> plane2(vec3f(xe,yy,val2),vec3f(xe,ye,val3),vec3f(xx,ye,val4));
            if(result.size()==3) {
              tools_vforcit(vec3f,result,it) {
                tris->add(*it);
                tris->add_color(_color);
                tris->add_normal(plane2.normal());
              }
            } else {
              atb_vertices* vtxs = new atb_vertices; //FIXME : ouch! optimize.
              vtxs->mode = gl::triangle_fan();
              vtxs->do_back = true;
              vtxs->epsilon = 1e-6f;
              separator->add(vtxs);
              tools_vforcit(vec3f,result,it) {
                vtxs->add(*it);
                vtxs->add_color(_color);
                vtxs->add_normal(plane2.normal());
              }
            }
            empty = false;
            //sep_empty = false;
          }}
        }

      } //index faces

      //if(sep_empty) {
      //  delete sep;
      //} else {
      //  separator->add(sep);
      //}

    } //icol

    if(empty) {
      delete separator;
    } else {
      m_bins_sep.add(separator);
    }
  }

  // for OpenPAW /GRAPHICS/PRIMITIVES/TEXT
  // for OpenPAW /GRAPHICS/PRIMITIVES/ITX
  void update_primitive_text(const plottable_text& a_obj){
    if(a_obj.m_TEXT.empty()) return;

    float z = xy_depth.value()*1.1F;

    vec3f pos;
    axis_2_data_frame(vec3f(a_obj.m_X,a_obj.m_Y,z),pos); //FIXME return FALSE
    xx_2_yy(pos,pos);

    separator* sep = new separator;

    rgba* mat = new rgba();
    mat->color = a_obj.m_TXCI;
    sep->add(mat);

    matrix* _tsf = new matrix;
    _tsf->set_translate(pos);
    _tsf->mul_rotate(0,0,1,a_obj.m_ANGLE*fpi()/180.0f);
    _tsf->mul_scale(a_obj.m_SCALE,a_obj.m_SCALE,1);
    sep->add(_tsf);

    //SIZE is in page coordinate YSIZ.
    //float YSIZ = height.value();
    //if(YSIZ<=0) YSIZ = 1;

    //::printf("debug : tools::sg::plotter::update_primitive_text : %s : X %g Y %g : SCALE %g SIZE %g : pos %g %g %g\n",
    //    a_obj.m_TEXT.c_str(),a_obj.m_X,a_obj.m_Y,a_obj.m_SCALE,a_obj.m_SIZE,
    //    pos[0],pos[1],pos[2]);

    if(a_obj.m_text_mode==plottable_text::text_enforce_width) {  // not tested yet.

      vec3f pos2;
      axis_2_data_frame(vec3f(a_obj.m_X+a_obj.m_SIZE,a_obj.m_Y,z),pos2);  //m_SIZE is taken as text width in this text_mode.
      xx_2_yy(pos2,pos2);

      float _width = pos2.x()-pos.x();

      text* _text = new text(m_ttf);
      _text->enforce_front_width = true;  //it will set _text->width, height.
      _text->front_width = _width;
      _text->back_visible = false;

      _text->encoding = encoding_PAW();
      _text->strings.add(a_obj.m_TEXT);
      _text->line_width = a_obj.m_line_width;
      _text->font = a_obj.m_FONT;
      _text->font_modeling = a_obj.m_font_modeling;

      if(a_obj.m_HJUST=='R') {
        _text->hjust = right;
      } else if(a_obj.m_HJUST=='C') {
        _text->hjust = center;
      } else {
        _text->hjust = left;
      }
      if(a_obj.m_VJUST=='T') {
        _text->vjust = top;
      } else if(a_obj.m_VJUST=='M') {
        _text->vjust = middle;
      } else {
        _text->vjust = bottom;
      }

      sep->add(_text);

    } else if(a_obj.m_text_mode==plottable_text::text_enforce_height) { // for EsbRootView neard, fard 2D plot.

      vec3f pos2;
      axis_2_data_frame(vec3f(a_obj.m_X,a_obj.m_Y+a_obj.m_SIZE,z),pos2);  //m_SIZE is taken as text height in this text_mode.
      xx_2_yy(pos2,pos2);

      float _height = pos2.y()-pos.y();

      text* _text = new text(m_ttf);
      _text->enforce_front_height = true;  //it will set _text->width, height.
      _text->front_height = _height;
      _text->back_visible = false;  //if true, we should adapt back_area::width, height to inside text size.

      _text->encoding = encoding_PAW();
      _text->strings.add(a_obj.m_TEXT);
      _text->line_width = a_obj.m_line_width;
      _text->font = a_obj.m_FONT;
      _text->font_modeling = a_obj.m_font_modeling;

      if(a_obj.m_HJUST=='R') {
        _text->hjust = right;
      } else if(a_obj.m_HJUST=='C') {
        _text->hjust = center;
      } else {
        _text->hjust = left;
      }
      if(a_obj.m_VJUST=='T') {
        _text->vjust = top;
      } else if(a_obj.m_VJUST=='M') {
        _text->vjust = middle;
      } else {
        _text->vjust = bottom;
      }

      sep->add(_text);

    } else { //text_as_it (for gopaw/pagpri.cpp).
      _tsf->mul_scale(a_obj.m_SIZE,a_obj.m_SIZE,1);

      if(a_obj.m_FONT==font_hershey()) {
        //::printf("debug : tools::sg::plotter::update_primitive_text : hershey\n");
        draw_style* ds = new draw_style;
        ds->style = draw_lines;
        ds->line_pattern = line_solid;
        ds->line_width = a_obj.m_line_width;
        //ds->line_pattern = m_title_style.line_pattern;
        //ds->line_width = m_title_style.line_width;
        sep->add(ds);

        text_hershey* text = new text_hershey;
        text->encoding = encoding_PAW();
        text->strings.add(a_obj.m_TEXT);
        if(a_obj.m_HJUST=='R') {
          text->hjust = right;
        } else if(a_obj.m_HJUST=='C') {
          text->hjust = center;
        } else {
          text->hjust = left;
        }
        if(a_obj.m_VJUST=='T') {
          text->vjust = top;
        } else if(a_obj.m_VJUST=='M') {
          text->vjust = middle;
        } else {
          text->vjust = bottom;
        }
        sep->add(text);

      } else {
        //::printf("debug : tools::sg::plotter::update_primitive_text : freetype\n");
        base_freetype* text = base_freetype::create(m_ttf);

        text->font = a_obj.m_FONT;
        if(a_obj.m_HJUST=='R') {
          text->hjust = right;
        } else if(a_obj.m_HJUST=='C') {
          text->hjust = center;
        } else {
          text->hjust = left;
        }
        if(a_obj.m_VJUST=='T') {
          text->vjust = top;
        } else if(a_obj.m_VJUST=='M') {
          text->vjust = middle;
        } else {
          text->vjust = bottom;
        }

        text->modeling = a_obj.m_font_modeling;

        //text->encoding = encoding_PAW()
        //text->smooting = a_obj.m_SMOOTHING;
        //text->hinting = a_obj.m_HINTING;
        text->strings.add(a_obj.m_TEXT);
        //text->hjust.value(a_hjust);
        //text->vjust.value(a_vjust);

        sep->add(text);
      }

    } //text_mode.

    m_primitives_sep.add(sep);
  }

  // for OpenPAW /GRAPHICS/PRIMITIVES/BOX
  void PAW_hatch(int aHTYP,hatching_policy& a_policy,float& a_spacing,float& a_angle_right,float& a_angle_left) {
    // PAW hatching encoding (paw.pdf 1.14(1992) p 174) :

    a_policy = hatching_none;
    a_spacing = 0;
    a_angle_right = 0;
    a_angle_left = 0;

    int code = aHTYP;
    if(code==0) return;

    // From PAW FAQ web page.
    // special code from code [1,25]
    if(code==1) {
      a_policy = hatching_left_and_right;
      a_spacing = 0.04F;
      a_angle_right = 3.0F*fpi()/4.0F;
      a_angle_left = fpi()/4.0F;
      return;
    } else if(code==2) {
      a_policy = hatching_left_and_right;
      a_spacing = 0.08F;
      a_angle_right = 3.0F*fpi()/4.0F;
      a_angle_left = fpi()/4.0F;
      return;
    } else if(code==3) {
      a_policy = hatching_left_and_right;
      a_spacing = 1.6f*0.07F; //cooking
      a_angle_right = 3.0F*fpi()/4.0F;
      a_angle_left = fpi()/4.0F;
      return;
    } else if(code==4) {
      code = 354;
    } else if(code==5) {
      code = 345;
    } else if(code==6) {
      code = 359;
    } else if(code==7) {
      code = 350;
    } else if(code<=25) {
      //FIXME : seems to be done with patterns.
      a_policy = hatching_none;
      return;
    } else if(code<=99) {
      //FIXME
      a_policy = hatching_none;
      return;
    }

    //code >=100

    // code = ijk

    int i = code / 100;
    int j = (code - i * 100)/10;
    int k = code - i * 100 - j * 10;

    // j-hatching on rightHatchStyle :
    // k-hatching on leftHatchStyle :

    if((j==5)&&(k==5))
      a_policy = hatching_none;
    else if((j!=5)&&(k==5))
      a_policy = hatching_right;
    else if((j==5)&&(k!=5))
      a_policy = hatching_left;
    else if((j!=5)&&(k!=5))
      a_policy = hatching_left_and_right;

    unsigned int NY = 1;

    a_spacing = float(NY) * float(i) * 0.07F; //cooking

    if(j!=5) {
      float angle = float(j==4?45:j*10);
      angle = 180.0F - angle;
      angle *= fpi() / 180.0F;

      a_angle_right = angle;
    }

    if(k!=5) {
      float angle = float(k==4?45:k*10);
      angle *= fpi() / 180.0F;
      a_angle_left = angle;
    }

  }

  void rep_box_hatch(separator& a_parent,float a_spacing,float a_angle,float a_strip_width,
                     float xx,float yy,float xe,float ye,float a_zz){

    //printf("debug : SoPlotter::repHatch1D_xy : zz %g\n",a_zz);
    sg::separator* separator = new sg::separator;

    bool empty = true;

    vec3f points[5];

    points[0].set_value(xx,yy,a_zz);
    points[1].set_value(xe,yy,a_zz);
    points[2].set_value(xe,ye,a_zz);
    points[3].set_value(xx,ye,a_zz);
    points[4].set_value(xx,yy,a_zz);

    //We can have multiple hatching for a bins ; have a separator :
    hatcher _hatcher;
    _hatcher.set_offset_point(vec3f(0,0,a_zz));
    _hatcher.set_angle(a_angle);
    _hatcher.set_spacing(a_spacing);
    if(!_hatcher.set_strip_width(a_strip_width)) {}

    bool res = _hatcher.check_polyline(points,4);
    if(res) res = _hatcher.compute_polyline(points,4);

    size_t numPoints = _hatcher.points().size();
    size_t numVertices = _hatcher.vertices().size();
    if((res) && numPoints && numVertices) {

      const std::vector<vec3f>& _points = _hatcher.points();

      if(a_strip_width==0) {
        size_t ipt = 0;
        tools_vforcit(unsigned int,_hatcher.vertices(),itv) {
          vertices* vtxs = new vertices;
          vtxs->mode = gl::line_strip();
          for(size_t index=0;index<(*itv);index++) {
            vtxs->add(_points[ipt]);
            ipt++;
         	}
          separator->add(vtxs);
          empty = false;
        }

      } else {
        size_t ipt = 0;
        tools_vforcit(unsigned int,_hatcher.vertices(),itv) {
          vertices* vtxs = new vertices;
          vtxs->mode = gl::triangle_fan();
          for(size_t index=0;index<(*itv);index++) {
            vtxs->add(_points[ipt]);
            ipt++;
          }
          separator->add(vtxs);
          empty = false;
        }
      }

      empty = false;
    }

    if(empty) {
      delete separator;
    } else {
      a_parent.add(separator);
    }
  }

  void update_primitive_box(std::ostream& a_out,const plottable_box& a_obj){

    float z = xy_depth.value()*1.1F;

    vec3f pos1;
    axis_2_data_frame(vec3f(a_obj.m_X1,a_obj.m_Y1,z),pos1);
    xx_2_yy(pos1,pos1);

    vec3f pos2;
    axis_2_data_frame(vec3f(a_obj.m_X2,a_obj.m_Y2,z),pos2);
    xx_2_yy(pos2,pos2);

    z = pos1[2];

//    ::printf("debug : tools::sg::plotter::update_primitive_box : FAIS %d : %g %g %g : %g %g %g\n",a_obj.m_FAIS,
//        pos1.x(),pos1.y(),pos1.z(),pos2.x(),pos2.y(),pos2.z());

    if(a_obj.m_FAIS==plottable_box::HOLLOW) {

      separator* sep = new separator;

      rgba* mat = new rgba();
      mat->color = a_obj.m_PLCI;
      sep->add(mat);

      draw_style* ds = new draw_style;
      ds->style = draw_lines;
      ds->line_pattern = line_solid;
      ds->line_width = a_obj.m_LWID;
      sep->add(ds);

      vertices* vtxs = new vertices;
      vtxs->mode = gl::line_strip();
      sep->add(vtxs);

      vtxs->add(pos1[0],pos1[1],z);
      vtxs->add(pos2[0],pos1[1],z);
      vtxs->add(pos2[0],pos2[1],z);
      vtxs->add(pos1[0],pos2[1],z);
      vtxs->add(pos1[0],pos1[1],z);

      m_primitives_sep.add(sep);

    } else if(a_obj.m_FAIS==plottable_box::SOLID) {
      separator* sep = new separator;

      rgba* mat = new rgba();
      mat->color = a_obj.m_FACI;
      sep->add(mat);

      draw_style* ds = new draw_style;
      ds->style = draw_filled;
      sep->add(ds);

      vertices* vtxs = new vertices;
      vtxs->mode = gl::triangle_fan();
      sep->add(vtxs);

      vtxs->add(pos1[0],pos1[1],z);
      vtxs->add(pos2[0],pos1[1],z);
      vtxs->add(pos2[0],pos2[1],z);
      vtxs->add(pos1[0],pos2[1],z);

      m_primitives_sep.add(sep);

    } else if(a_obj.m_FAIS==plottable_box::HATCHED) {

     {separator* sep = new separator;

      rgba* mat = new rgba();
      mat->color = a_obj.m_FACI;
      sep->add(mat);

      hatching_policy hatching;
      float spacing;
      float angle_right;
      float angle_left;
      PAW_hatch(a_obj.m_FASI,hatching,spacing,angle_right,angle_left);
      float stripWidth = 0;

      if((hatching==hatching_right)||((hatching==hatching_left_and_right))) {
        rep_box_hatch(*sep,spacing,angle_right,stripWidth,pos1[0],pos1[1],pos2[0],pos2[1],z);
      }
      if((hatching==hatching_left)||((hatching==hatching_left_and_right))) {
        rep_box_hatch(*sep,spacing,angle_left,stripWidth,pos1[0],pos1[1],pos2[0],pos2[1],z);
      }

      if(hatching==hatching_none) {
        draw_style* ds = new draw_style;
        ds->style = draw_filled;
        sep->add(ds);
        vertices* vtxs = new vertices;
        vtxs->mode = gl::triangle_fan();
        sep->add(vtxs);
        vtxs->add(pos1[0],pos1[1],z);
        vtxs->add(pos2[0],pos1[1],z);
        vtxs->add(pos2[0],pos2[1],z);
        vtxs->add(pos1[0],pos2[1],z);
      }

      m_primitives_sep.add(sep);}

      if(a_obj.m_BORD) {
        separator* sep = new separator;
        rgba* mat = new rgba();
        mat->color = a_obj.m_PLCI;
        sep->add(mat);

        draw_style* ds = new draw_style;
        ds->style = draw_lines;
        ds->line_pattern = line_solid;
        ds->line_width = 1;
        sep->add(ds);

        vertices* vtxs = new vertices;
        vtxs->mode = gl::line_strip();
        sep->add(vtxs);

        z *= 1.01F;
        vtxs->add(pos1[0],pos1[1],z);
        vtxs->add(pos2[0],pos1[1],z);
        vtxs->add(pos2[0],pos2[1],z);
        vtxs->add(pos1[0],pos2[1],z);
        vtxs->add(pos1[0],pos1[1],z);

        m_primitives_sep.add(sep);
      }

    } else if(a_obj.m_FAIS==plottable_box::PATTERN) {
      a_out << "tools::sg::plotter::update_plottable_box FAIS PATTERN not yet handled." << std::endl;
    }

  }

  void update_primitive_ellipse(std::ostream& a_out,const plottable_ellipse& a_obj){

    float z = xy_depth.value()*1.1F;

    vec3f pos;
    axis_2_data_frame(vec3f(a_obj.m_X,a_obj.m_Y,z),pos);
    xx_2_yy(pos,pos);

    vec3f pos2;
    axis_2_data_frame(vec3f(a_obj.m_X+a_obj.m_R1,a_obj.m_Y+a_obj.m_R2,z),pos2);
    xx_2_yy(pos2,pos2);

    float rx = pos2[0]-pos[0];
    float ry = pos2[1]-pos[1];

    z = pos[2];

    //::printf("debug : tools::sg::plotter::update_primitive_ellipse : FAIS %d : %g %g %g : %g %g\n",a_obj.m_FAIS,
    //         pos.x(),pos.y(),pos.z(),rx,ry);

    if(a_obj.m_FAIS==plottable_ellipse::HOLLOW) {

      separator* sep = new separator;

      matrix* _tsf = new matrix;
      _tsf->set_translate(pos);
      sep->add(_tsf);

      rgba* mat = new rgba();
      mat->color = a_obj.m_PLCI;
      sep->add(mat);

      draw_style* ds = new draw_style;
      ds->style = draw_lines;
      ds->line_pattern = line_solid;
      ds->line_width = a_obj.m_LWID;
      sep->add(ds);

      ellipse* _ellipse = new ellipse;
      _ellipse->rx = rx;
      _ellipse->ry = ry;
      sep->add(_ellipse);

      m_primitives_sep.add(sep);

/*
    } else if(a_obj.m_FAIS==plottable_ellipse::SOLID) {
      separator* sep = new separator;

      rgba* mat = new rgba();
      mat->color = a_obj.m_FACI;
      sep->add(mat);

      draw_style* ds = new draw_style;
      ds->style = draw_filled;
      sep->add(ds);

      vertices* vtxs = new vertices;
      vtxs->mode = gl::triangle_fan();
      sep->add(vtxs);

      vtxs->add(pos1[0],pos1[1],z);
      vtxs->add(pos2[0],pos1[1],z);
      vtxs->add(pos2[0],pos2[1],z);
      vtxs->add(pos1[0],pos2[1],z);

      m_primitives_sep.add(sep);

    } else if(a_obj.m_FAIS==plottable_ellipse::HATCHED) {

     {separator* sep = new separator;

      rgba* mat = new rgba();
      mat->color = a_obj.m_FACI;
      sep->add(mat);

      hatching_policy hatching;
      float spacing;
      float angle_right;
      float angle_left;
      PAW_hatch(a_obj.m_FASI,hatching,spacing,angle_right,angle_left);
      float stripWidth = 0;

      if((hatching==hatching_right)||((hatching==hatching_left_and_right))) {
        rep_box_hatch(*sep,spacing,angle_right,stripWidth,pos1[0],pos1[1],pos2[0],pos2[1],z);
      }
      if((hatching==hatching_left)||((hatching==hatching_left_and_right))) {
        rep_box_hatch(*sep,spacing,angle_left,stripWidth,pos1[0],pos1[1],pos2[0],pos2[1],z);
      }

      if(hatching==hatching_none) {
        draw_style* ds = new draw_style;
        ds->style = draw_filled;
        sep->add(ds);
        vertices* vtxs = new vertices;
        vtxs->mode = gl::triangle_fan();
        sep->add(vtxs);
        vtxs->add(pos1[0],pos1[1],z);
        vtxs->add(pos2[0],pos1[1],z);
        vtxs->add(pos2[0],pos2[1],z);
        vtxs->add(pos1[0],pos2[1],z);
      }

      m_primitives_sep.add(sep);}

      if(a_obj.m_BORD) {
        separator* sep = new separator;
        rgba* mat = new rgba();
        mat->color = a_obj.m_PLCI;
        sep->add(mat);

        draw_style* ds = new draw_style;
        ds->style = draw_lines;
        ds->line_pattern = line_solid;
        ds->line_width = 1;
        sep->add(ds);

        vertices* vtxs = new vertices;
        vtxs->mode = gl::line_strip();
        sep->add(vtxs);

        z *= 1.01F;
        vtxs->add(pos1[0],pos1[1],z);
        vtxs->add(pos2[0],pos1[1],z);
        vtxs->add(pos2[0],pos2[1],z);
        vtxs->add(pos1[0],pos2[1],z);
        vtxs->add(pos1[0],pos1[1],z);

        m_primitives_sep.add(sep);
      }

    } else if(a_obj.m_FAIS==plottable_ellipse::PATTERN) {
      a_out << "tools::sg::plotter::update_plottable_box FAIS PATTERN not yet handled." << std::endl;
*/
    } else {
      a_out << "tools::sg::plotter::update_plottable_box FAIS " << a_obj.m_FAIS << " not yet handled." << std::endl;
    }

  }

  void update_primitive_img(std::ostream& /*a_out*/,const plottable_img& a_obj){

    float z = xy_depth.value()*1.1F;

    vec3f pos;
    axis_2_data_frame(vec3f(a_obj.m_X,a_obj.m_Y,z),pos);
    xx_2_yy(pos,pos);   //pos = center of image in axes coordinates.
    z = pos[2];

    vec3f top;
    axis_2_data_frame(vec3f(0,a_obj.m_Y+a_obj.m_HEIGHT*0.5f,0),top);
    xx_2_yy(top,top);  //top = (o,y-top)  of image in axes coordinates.
    float scale = 2.0f*(top[1]-pos[1]);
    //float scale = a_obj.m_HEIGHT; //m_HEIGHT is then in page coordinate YSIZ.

    const img<byte>& img = a_obj.m_img;

  //::printf("debug : tools::sg::plotter::update_primitive_img : %d %d %d : %g %g %g : %g : %g %g\n",
  //    img.width(),img.height(),img.bpp(),
  //    pos.x(),pos.y(),pos.z(),a_obj.m_HEIGHT,a_obj.m_THETA,a_obj.m_PHI);

    separator* sep = new separator;

    rgba* mat = new rgba();
    mat->color = colorf_white();
    sep->add(mat);

    normal* nm = new normal;
    sep->add(nm);

    matrix* _tsf = new matrix;
    _tsf->set_translate(pos);
    _tsf->mul_rotate(0,1,0,a_obj.m_THETA*fpi()/180.0f);
    _tsf->mul_rotate(0,0,1,a_obj.m_PHI*fpi()/180.0f);
    _tsf->mul_scale(scale,scale,1);
    sep->add(_tsf);

    tex_rect* _img = new tex_rect();
    _img->img = img;
    sep->add(_img);

    m_primitives_sep.add(sep);

  }

protected: //etc
  // background is at z = 0.
  // last z items are text in infos, legend boxes that should be at xy_depth().

  float _zoffset() const {
    // first data plane is at _zoffset.
    // last one at m_plottables.size()*_zoffset = xy_depth.value()-_zoffset().
    return xy_depth.value()/(float(m_plottables.size())+1.0f);
  }
  float _zaxis() const {return _zoffset();}
  float _zgrid() const {return xy_depth.value()-_zoffset()*0.5f;}
  float _ztext() const {return 0.01f;} //if text back is visible else 0. (sf<float> zfront ?)
  float _zscale_text() const {return _zoffset()*0.4f/_ztext();} //title and infos boxes thickness.
  float _zinfos() const {return xy_depth.value()-_zoffset()*0.4f;} //in front _zgrid
  float _zhatch() const {return _zoffset()*0.25f;}
  float _zerrors() const {return _zoffset()*0.5f;}

  //static void LIST_SET(vec3f a_list[],unsigned int a_index,float x,float y,float z) {a_list[a_index].set_value(x,y,z);}

  static float take_log(float a_x){
    if(a_x<=0) {
      return -FLT_MAX;
    } else {
      return flog10(a_x);
    }
  }

  static float verify_log(float a_val,float a_min,float a_dx,bool a_log){
    if(a_log) {
      if(a_val>0.0F) {
        return (flog10(a_val) - a_min)/a_dx;
      } else { // Return a negative large number :
        //return -FLT_MAX;
        return -100;
      }
    } else {
      // Simple protection against value that could exceed a float :
      if(a_val>(a_min+100.0F * a_dx)) return 100;
      if(a_val<(a_min-100.0F * a_dx)) return -100;
      // Rescale :
      return (a_val - a_min)/a_dx;
    }
  }

  static float verify_log_inv(float a_val,float a_min,float a_dx,bool a_log){
   if(a_log) {
      return fpow(10,a_val*a_dx+a_min);
    } else {
      return a_val*a_dx+a_min;
    }
  }

  style* merge_bins_style(unsigned int a_index,plottable&) {
    style& _style = bins_style(a_index);
    //uuu merge with a_p.infos().
    return new style(_style);
  }

  style* merge_left_hatch_style(unsigned int a_index,plottable&) {
    style& _style = left_hatch_style(a_index);
    //uuu merge with a_p.infos().
    return new style(_style);
  }

  style* merge_right_hatch_style(unsigned int a_index,plottable&) {
    style& _style = right_hatch_style(a_index);
    //uuu merge with a_p.infos().
    return new style(_style);
  }

  style* merge_errors_style(unsigned int a_index,plottable&) {
    style& _style = errors_style(a_index);
    //uuu merge with a_p.infos().
    return new style(_style);
  }

  style* merge_func_style(unsigned int a_index,plottable&) {
    style& _style = func_style(a_index);
    //uuu merge with a_p.infos().
    return new style(_style);
  }

  style* merge_points_style(unsigned int a_index,plottable&) {
    style& _style = points_style(a_index);
    //uuu merge with a_p.infos().
    return new style(_style);
  }

/*
  text_style* merge_legend_style(unsigned int a_index,plottable& a_p) {
    if(a_index>=m_legend_style.size()) return new text_style();
    return new text_style(m_legend_style[a_index]);
    //uuu merge with a_p.infos().
  }
*/

  shape_type get_shape() const {
    if(!shape_automated) return shape.value();

    // Guess XY or XYZ shape :
  /*if(f_binsList.size()) { // major bins compells shape type.
      if(f_binsList[0]->getDimension()==1) {
        return XY;
      } else if(f_binsList[0]->getDimension()==2) {
        return XY; //lego is not the default.
      } else {
        return XYZ;
      }
    } else if(f_pointsList.size()) { // major points compells shape type.
      if(f_pointsList[0]->getDimension()==1) { //?
        return XY;
      } else if(f_pointsList[0]->getDimension()==2) {
        return XY;
      } else {
        return XYZ;
      }
    } else if(f_functionList.size()) { // major function compell shape type.
      if(f_functionList[0]->getDimension()==1) {
        return XY;
      } else {
        return XYZ;
      }
    } else*/ {
      return xy; //Default.
    }
  }

  void clear_plottables() {
    //unsigned int objn = m_plottables.size();
   {std::vector<plottable*>::iterator it;
    for(it=m_plottables.begin();it!=m_plottables.end();++it) delete *it;
    m_plottables.clear();}

    /*
    if(objn) {
      // If a title (logScale) had been given on some axis,
      // it is probably no more pertinent for further data.
      if(xAxisEnforced.value()==false)  {
        m_x_axis.title.setValue("");
        xAxisLogScale.setValue(false);
      }
      if(yAxisEnforced.value()==false)  {
        m_y_axis.title.setValue("");
        yAxisLogScale.setValue(false);
      }
      if(zAxisEnforced.value()==false)  {
        m_z_axis.title.setValue("");
        zAxisLogScale.setValue(false);
      }
    }
    */

    touch();
  }
  void clear_primitives() {
   {std::vector<plotprim*>::iterator it;
    for(it=m_primitives.begin();it!=m_primitives.end();++it) delete *it;
    m_primitives.clear();}
    touch();
  }

  void clear_todels() {m_todel_group.clear();}

  bool first_bins(bins1D*& a_1,bins2D*& a_2) const {
    tools_vforcit(plottable*,m_plottables,it) {
      plottable* object = *it;
      if(!object) continue;
      if(bins1D* b1 = safe_cast<plottable,bins1D>(*object)) {
        a_1 = b1;
        a_2 = 0;
        return true;
      } else if(bins2D* b2 = safe_cast<plottable,bins2D>(*object)) {
        a_1 = 0;
        a_2 = b2;
        return true;
      }
    }
    a_1 = 0;
    a_2 = 0;
    return false;
  }

  bool first_func(func1D*& a_1,func2D*& a_2) const {
    tools_vforcit(plottable*,m_plottables,it) {
      plottable* object = *it;
      if(!object) continue;
      if(func1D* f1 = safe_cast<plottable,func1D>(*object)) {
        a_1 = f1;
        a_2 = 0;
        return true;
      } else if(func2D* f2 = safe_cast<plottable,func2D>(*object)) {
        a_1 = 0;
        a_2 = f2;
        return true;
      }
    }
    a_1 = 0;
    a_2 = 0;
    return false;
  }

  bool first_points(points2D*& a_2,points3D*& a_3) const {
    tools_vforcit(plottable*,m_plottables,it) {
      plottable* object = *it;
      if(!object) continue;
      if(points2D* p2 = safe_cast<plottable,points2D>(*object)) {
        a_2 = p2;
        a_3 = 0;
        return true;
      } else if(points3D* p3 = safe_cast<plottable,points3D>(*object)) {
        a_2 = 0;
        a_3 = p3;
        return true;
      }
    }
    a_2 = 0;
    a_3 = 0;
    return false;
  }

  void clear_sg() {
    m_bins_sep.clear();
    m_errors_sep.clear();
    m_func_sep.clear();
    m_points_sep.clear();
  }

  void DUMP_UPDATE_WHAT(std::ostream&,const std::string&) {}
/*
  void DUMP_UPDATE_WHAT(std::ostream& a_out,const std::string& a_msg) {
    a_out << "tools::sg::plotter :"
          << " " << a_msg
          << std::endl;
  }
*/

  static void add_pt(std::vector<float>& a_pts,float a_x,float a_y,float a_z){
    a_pts.push_back(a_x);
    a_pts.push_back(a_y);
    a_pts.push_back(a_z);
  }

  static void clip_points_2D(const std::vector<vec3f>& a_points,
                             const rep_box& a_box_x,const rep_box& a_box_y,std::vector<float>& a_pts) {
    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    a_pts.clear();

    float xx,yy,zz;
    tools_vforcit(vec3f,a_points,it) {
      const vec3f& _point = *it;
      xx = _point[0];
      yy = _point[1];
      zz = _point[2];
      xx = verify_log(xx,xmin,dx,xlog);
      yy = verify_log(yy,ymin,dy,ylog);
      if((xx>=0)&&(xx<=1)&&(yy>=0)&&(yy<=1)) add_pt(a_pts,xx,yy,zz);
    }
  }

  static void clip_polyline_2D(const std::vector<vec3f>& a_points,
                               const rep_box& a_box_x,const rep_box& a_box_y,std::vector<float>& a_pts) {
    //  Clip line in a_box_x, a_box_y.

    //NOTE : it is not a general algorithm.
    //       It is assumed that a_points are ordered with increasing x.
    //       And the algorithm clips against up and bottom BoxY lines.
    //       (Use clip<float> for a more general algorithm ?)

    float xmin = a_box_x.m_pos;
    float dx = a_box_x.m_width;
    bool xlog = a_box_x.m_log;

    float ymin = a_box_y.m_pos;
    float dy = a_box_y.m_width;
    bool ylog = a_box_y.m_log;

    a_pts.clear();

    float xprev = 0;
    float yprev = 0;

   {unsigned int index = 0;
    std::vector<vec3f>::const_iterator it;
    for(it=a_points.begin();it!=a_points.end();++it,index++) {
      const vec3f& _point = *it;
      float xx = _point[0];
      float yy = _point[1];
      float zz = _point[2];
      //add_pt(a_pts,xx,yy,zz);continue; //debug
      xx = verify_log(xx,xmin,dx,xlog);
      yy = verify_log(yy,ymin,dy,ylog);
      if((xx>=0)&&(xx<=1) ) {
        if(yy>1) {
          if(index==0) {
            add_pt(a_pts,xx,1,zz);
          } else {
            if(yprev>1) {
              add_pt(a_pts,xx,1,zz);
            } else if(yprev<0) {
              float a = (yy - yprev)/(xx - xprev);
              float b = yy - a * xx;
              add_pt(a_pts,-b/a,0,zz);
              add_pt(a_pts,(1 - b)/a,1,zz);
              add_pt(a_pts,xx,1,zz);
            } else {
              float a = (yy - yprev)/(xx - xprev);
              float b = yy - a * xx;
              add_pt(a_pts,(1 - b)/a,1,zz);
              add_pt(a_pts,xx,1,zz);
            }
          }
        } else if (yy < 0) {
          if(index==0) {
            add_pt(a_pts,xx,0,zz);
          } else {
            if(yprev<0) {
              add_pt(a_pts,xx,0,zz);
            } else if(yprev>1) {
              float a = (yy - yprev)/(xx - xprev);
              float b = yy - a * xx;
              add_pt(a_pts,(1 - b)/a,1,zz);
              add_pt(a_pts,-b/a,0,zz);
              add_pt(a_pts,xx,0,zz);
            } else {
              float a = (yy - yprev)/(xx - xprev);
              float b = yy - a * xx;
              add_pt(a_pts,-b/a,0,zz);
              add_pt(a_pts,xx,0,zz);
             }
          }
        } else {
          if(index==0) {
            add_pt(a_pts,xx,yy,zz);
          } else if( (yprev>1) || (yprev<0) ) {
            // interpolate :
            float a = (yy - yprev)/(xx - xprev);
            float b = yy - a * xx;
            if(yprev>1) {
              add_pt(a_pts,(1 - b)/a,1,zz);
            } else {
              add_pt(a_pts,-b/a,0,zz);
            }
            add_pt(a_pts,xx,yy,zz);
          } else {
            add_pt(a_pts,xx,yy,zz);
          }
        }
      }
      xprev = xx;
      yprev = yy;
    }}
  }

  bool sto(const std::string& a_s,vec2f& a_v) {
    std::vector<std::string> ws;
    words(a_s," ",false,ws);
    if(ws.size()!=2) return false;
    float x = 0;
    if(!to<float>(ws[0],x)) return false;
    float y = 0;
    if(!to<float>(ws[1],x)) return false;
    a_v.set_value(x,y);
    return true;
  }

  bool sto(const std::string& a_s,unit_type& a_v) {
    if(a_s=="percent") {a_v = unit_percent;return true;}
    else if(a_s=="axis") {a_v = unit_axis;return true;}
    return false;
  }

  void clear_cmaps() {
   {std::vector<base_colormap*>::iterator it;
    for(it=m_bins_cmaps.begin();it!=m_bins_cmaps.end();++it) delete *it;
    m_bins_cmaps.clear();}

   {std::vector<base_colormap*>::iterator it;
    for(it=m_points_cmaps.begin();it!=m_points_cmaps.end();++it) delete *it;
    m_points_cmaps.clear();}

   {std::vector<base_colormap*>::iterator it;
    for(it=m_func_cmaps.begin();it!=m_func_cmaps.end();++it) delete *it;
    m_func_cmaps.clear();}
  }

  void bar_chart(float a_bar_offset,float a_bar_width,
                 float& a_beg,float& a_end){
    float xe = (a_end - a_beg)*a_bar_offset;
    float xw = (a_end - a_beg)*a_bar_width;
    a_end = a_beg + xe + xw;
    a_beg = a_beg + xe;
  }

protected:
  const base_freetype& m_ttf;
protected: //fields for skeleton.
  group m_group;

  separator m_background_sep;

  separator m_cmap_sep;
  matrix m_cmap_matrix;
  separator m_cmap_cells_sep;
  matrix m_cmap_axis_matrix;
  sg::axis m_cmap_axis;

  separator m_infos_title_sep;
  separator m_infos_sep;
  separator m_legend_sep;
  separator m_title_box_sep;

  matrix m_tsf;
  matrix m_layout;

  separator m_title_sep;

  separator m_x_axis_sep;
  matrix m_x_axis_matrix;
  sg::axis m_x_axis;

  separator m_y_axis_sep;
  matrix m_y_axis_matrix;
  sg::axis m_y_axis;

  separator m_z_axis_sep;
  matrix m_z_axis_matrix;
  sg::axis m_z_axis;

  separator m_grid_sep;

  separator m_data_sep;
  torche m_data_light;
  matrix m_data_matrix;
  separator m_bins_sep;
  separator m_errors_sep;
  separator m_func_sep;
  separator m_points_sep;
  separator m_inner_frame_sep;
  separator m_primitives_sep;
  separator m_etc_sep;

protected: //fields
  shape_type m_shape;

  data_axis m_x_axis_data;
  data_axis m_y_axis_data;
  data_axis m_z_axis_data;

  std::vector<plottable*> m_plottables; //it has ownership.

  std::vector<style> m_bins_style;
  std::vector<style> m_errors_style;
  std::vector<style> m_func_style;
  std::vector<style> m_points_style;
  std::vector<style> m_left_hatch_style;
  std::vector<style> m_right_hatch_style;
  std::vector<style> m_legend_style;

  text_style m_title_style;
  text_style m_infos_style;
  text_style m_title_box_style;
  style m_background_style;
  style m_wall_style; //for gopaw.
  style m_inner_frame_style;
  style m_grid_style;

protected:
  std::vector<std::string> m_legend_strings;

  std::vector<base_colormap*> m_bins_cmaps;
  std::vector<base_colormap*> m_points_cmaps;
  std::vector<base_colormap*> m_func_cmaps;

  group m_todel_group;
  std::vector<plotprim*> m_primitives;
  cmaps_t m_cmaps;
  rtausmef m_rtausmef;
};

}}

#endif
