Back to home page

EIC code displayed by LXR

 
 

    


Warning, /include/Geant4/tools/sg/axis is written in an unsupported language. File is not indexed.

0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003 
0004 #ifndef tools_sg_axis
0005 #define tools_sg_axis
0006 
0007 #include "node"
0008 #include "line_style"
0009 #include "text_style"
0010 #include "enums"
0011 #include "noderef"
0012 #include "vertices"
0013 #include "draw_style"
0014 #include "rgba"
0015 #include "normal"
0016 #include "separator"
0017 #include "tools"
0018 #include "nodekit"
0019 
0020 #include "../lina/vec3f"
0021 #include "../mnmx"
0022 #include "../hplot"
0023 
0024 #include <cstdio> //sprintf
0025 #include <cstring> //strcpy
0026 
0027 namespace tools {
0028 namespace sg {
0029 
0030 class axis : public node {
0031 public:
0032   TOOLS_NODE(axis,tools::sg::axis,node)
0033 public:
0034   sf<float> width;
0035   sf<float> minimum_value;
0036   sf<float> maximum_value;
0037   sf<unsigned int> divisions;
0038   sf_string modeling; //hippo, hplot
0039   sf<bool> is_log;
0040   // If modeling is hippo or hplot,
0041   // labels_enforced true let labels be an input field.
0042   sf<bool> labels_enforced;
0043   sf<bool> tick_up;
0044   sf<float> tick_length;
0045 
0046   // NOTE : if modeling is none,the below are input fields.
0047   //        If modeling is hippo or hplot, the below are output field
0048   //        (filled by compute_ticks).
0049   sf<unsigned int> tick_number; //output
0050   mf_string labels;       //output
0051   mf<float> values;       //output //in [minimumValue,maximumValue]
0052   mf<float> coords;       //output //in [0,width]
0053   mf<float> sub_coords;   //output
0054   sf<int> magnitude;      //output
0055 
0056   sf_string title;
0057   sf<float> title_to_axis;
0058   sf<float> title_height;
0059   sf_enum<hjust> title_hjust;
0060 
0061   sf<float> label_to_axis;
0062   sf<float> label_height;
0063 
0064   sf<bool>  labels_no_overlap_automated;
0065   sf<float> labels_gap; //in percent of width.
0066 
0067   // time labels only in hplot modeling for the moment.
0068   sf<bool> time_labels;
0069   sf_string time_format;
0070   sf<double> time_offset;
0071   sf<bool> time_offset_is_GMT;
0072 public:
0073   virtual const desc_fields& node_desc_fields() const {
0074     TOOLS_FIELD_DESC_NODE_CLASS(tools::sg::axis)
0075     static const desc_fields s_v(parent::node_desc_fields(),27, //WARNING : take care of count.
0076       TOOLS_ARG_FIELD_DESC(width),
0077       TOOLS_ARG_FIELD_DESC(minimum_value),
0078       TOOLS_ARG_FIELD_DESC(maximum_value),
0079       TOOLS_ARG_FIELD_DESC(divisions),
0080       TOOLS_ARG_FIELD_DESC(modeling),
0081       TOOLS_ARG_FIELD_DESC(is_log),
0082       TOOLS_ARG_FIELD_DESC(labels_enforced),
0083       TOOLS_ARG_FIELD_DESC(tick_up),
0084       TOOLS_ARG_FIELD_DESC(tick_length),
0085       TOOLS_ARG_FIELD_DESC(tick_number),
0086       TOOLS_ARG_FIELD_DESC(labels),
0087       TOOLS_ARG_FIELD_DESC(values),
0088       TOOLS_ARG_FIELD_DESC(coords),
0089       TOOLS_ARG_FIELD_DESC(sub_coords),
0090       TOOLS_ARG_FIELD_DESC(magnitude),
0091       TOOLS_ARG_FIELD_DESC(title),
0092       TOOLS_ARG_FIELD_DESC(title_to_axis),
0093       TOOLS_ARG_FIELD_DESC(title_height),
0094       TOOLS_ARG_FIELD_DESC(title_hjust),
0095       TOOLS_ARG_FIELD_DESC(label_to_axis),
0096       TOOLS_ARG_FIELD_DESC(label_height),
0097       TOOLS_ARG_FIELD_DESC(labels_no_overlap_automated),
0098       TOOLS_ARG_FIELD_DESC(labels_gap),
0099 
0100       TOOLS_ARG_FIELD_DESC(time_labels),
0101       TOOLS_ARG_FIELD_DESC(time_format),
0102       TOOLS_ARG_FIELD_DESC(time_offset),
0103       TOOLS_ARG_FIELD_DESC(time_offset_is_GMT)
0104     );
0105     return s_v;
0106   }
0107   virtual bool touched() {
0108     if(parent::touched()) return true;
0109     if(line_style().touched()) return true;
0110     if(ticks_style().touched()) return true;
0111     if(labels_style().touched()) return true;
0112     if(mag_style().touched()) return true;
0113     if(title_style().touched()) return true;
0114     return false;
0115   }
0116   virtual void reset_touched() {
0117     parent::reset_touched();
0118     line_style().reset_touched();
0119     ticks_style().reset_touched();
0120     labels_style().reset_touched();
0121     mag_style().reset_touched();
0122     title_style().reset_touched();
0123   }
0124 private:
0125   void add_fields(){
0126     // if adding a field, look for reset_style() and set_from_style()
0127     add_field(&width);
0128     add_field(&minimum_value);
0129     add_field(&maximum_value);
0130     add_field(&divisions);
0131     add_field(&modeling);
0132     add_field(&is_log);
0133     add_field(&labels_enforced);
0134     add_field(&tick_up);
0135     add_field(&tick_length);
0136     add_field(&tick_number);
0137     add_field(&labels);
0138     add_field(&values);
0139     add_field(&coords);
0140     add_field(&sub_coords);
0141     add_field(&magnitude);
0142     add_field(&title);
0143     add_field(&title_to_axis);
0144     add_field(&title_height);
0145     add_field(&title_hjust);
0146     add_field(&label_to_axis);
0147     add_field(&label_height);
0148     add_field(&labels_no_overlap_automated);
0149     add_field(&labels_gap);
0150 
0151     add_field(&time_labels);
0152     add_field(&time_format);
0153     add_field(&time_offset);
0154     add_field(&time_offset_is_GMT);
0155   }
0156   void init_sg(){
0157     m_group.add(new noderef(m_line_sep));
0158     m_group.add(new noderef(m_ticks_sep));
0159     m_group.add(new noderef(m_labels_sep));
0160     m_group.add(new noderef(m_mag_sep));
0161     m_group.add(new noderef(m_title_sep));
0162   }
0163 public:
0164   virtual void render(render_action& a_action) {
0165     if(touched()) {
0166       update_sg(a_action.out());
0167       reset_touched();
0168     }
0169     m_group.render(a_action);
0170   }
0171   virtual void pick(pick_action& a_action) {
0172     if(touched()) {
0173       update_sg(a_action.out());
0174       reset_touched();
0175     }
0176     //m_group.pick(a_action);
0177     nodekit_pick(a_action,m_group,this);
0178   }
0179   virtual void search(search_action& a_action) {
0180     if(touched()) {
0181       update_sg(a_action.out());
0182       reset_touched();
0183     }
0184     parent::search(a_action);
0185     if(a_action.done()) return;
0186     m_group.search(a_action);
0187   }
0188   virtual void bbox(bbox_action& a_action) {
0189     if(touched()) {
0190       update_sg(a_action.out());
0191       reset_touched();
0192     }
0193     m_group.bbox(a_action);
0194   }
0195 
0196   virtual bool write(write_action& a_action) {
0197     //FIXME : this method should not be needed !
0198     //        But m_[line,ticks,labels,mag,title]_style not written !
0199 
0200     if(touched()) {
0201       update_sg(a_action.out());
0202       reset_touched();
0203     }
0204     //if(!write_fields(a_action)) return false;
0205     return m_group.write(a_action);
0206   }
0207 public:
0208   axis(const base_freetype& a_ttf)
0209   :parent()
0210   ,width(1)
0211   ,minimum_value(0)
0212   ,maximum_value(1)
0213   ,divisions(510)
0214   ,modeling(tick_modeling_hippo())
0215   ,is_log(false)
0216   ,labels_enforced(false)
0217   ,tick_up(true)
0218   ,tick_length(0)
0219 
0220   ,tick_number(0)
0221   ,magnitude(0)
0222 
0223   ,title("")
0224   ,title_to_axis(0)   //inited below
0225   ,title_height(0)    //inited below
0226   ,title_hjust(right)
0227 
0228   ,label_to_axis(0) //inited below
0229   ,label_height(0)  //inited below
0230 
0231   ,labels_no_overlap_automated(true)
0232   ,labels_gap(0.02f)
0233 
0234   ,time_labels(false)
0235   ,time_format("%H:%M:%S")
0236   ,time_offset(0) //UTC_time_1970_01_01__00_00_00
0237   ,time_offset_is_GMT(false)
0238 
0239   ,m_ttf(a_ttf)
0240   {
0241     add_fields();
0242 
0243     init_sg();
0244 
0245     reset_style(true);
0246   }
0247   virtual ~axis(){}
0248 public:
0249   axis(const axis& a_from)
0250   :parent(a_from)
0251   ,width(a_from.width)
0252   ,minimum_value(a_from.minimum_value)
0253   ,maximum_value(a_from.maximum_value)
0254   ,divisions(a_from.divisions)
0255   ,modeling(a_from.modeling)
0256   ,is_log(a_from.is_log)
0257   ,labels_enforced(a_from.labels_enforced)
0258   ,tick_up(a_from.tick_up)
0259   ,tick_length(a_from.tick_length)
0260 
0261   ,tick_number(a_from.tick_number)
0262   ,magnitude(a_from.magnitude)
0263 
0264   ,title(a_from.title)
0265   ,title_to_axis(a_from.title_to_axis)
0266   ,title_height(a_from.title_height)
0267   ,title_hjust(a_from.title_hjust)
0268 
0269   ,label_to_axis(a_from.label_to_axis)
0270   ,label_height(a_from.label_height)
0271 
0272   ,labels_no_overlap_automated(a_from.labels_no_overlap_automated)
0273   ,labels_gap(a_from.labels_gap)
0274 
0275   ,time_labels(a_from.time_labels)
0276   ,time_format(a_from.time_format)
0277   ,time_offset(a_from.time_offset)
0278   ,time_offset_is_GMT(a_from.time_offset_is_GMT)
0279 
0280   ,m_ttf(a_from.m_ttf)
0281 
0282   ,m_line_style(a_from.m_line_style)
0283   ,m_ticks_style(a_from.m_ticks_style)
0284   ,m_labels_style(a_from.m_labels_style)
0285   ,m_mag_style(a_from.m_mag_style)
0286   ,m_title_style(a_from.m_title_style)
0287   {
0288     add_fields();
0289     init_sg();
0290   }
0291   axis& operator=(const axis& a_from){
0292     parent::operator=(a_from);
0293 
0294     width = a_from.width;
0295     minimum_value = a_from.minimum_value;
0296     maximum_value = a_from.maximum_value;
0297     divisions = a_from.divisions;
0298     modeling = a_from.modeling;
0299     is_log = a_from.is_log;
0300     labels_enforced = a_from.labels_enforced;
0301     tick_up = a_from.tick_up;
0302     tick_length = a_from.tick_length;
0303 
0304     tick_number = a_from.tick_number;
0305     magnitude = a_from.magnitude;
0306 
0307     title = a_from.title;
0308     title_to_axis = a_from.title_to_axis;
0309     title_height = a_from.title_height;
0310     title_hjust = a_from.title_hjust;
0311 
0312     label_to_axis = a_from.label_to_axis;
0313     label_height = a_from.label_height;
0314 
0315     labels_no_overlap_automated = a_from.labels_no_overlap_automated;
0316     labels_gap = a_from.labels_gap;
0317 
0318     time_labels = a_from.time_labels;
0319     time_format = a_from.time_format;
0320     time_offset = a_from.time_offset;
0321     time_offset_is_GMT = a_from.time_offset_is_GMT;
0322 
0323     m_line_style = a_from.m_line_style;
0324     m_ticks_style = a_from.m_ticks_style;
0325     m_labels_style = a_from.m_labels_style;
0326     m_mag_style = a_from.m_mag_style;
0327     m_title_style = a_from.m_title_style;
0328 
0329     return *this;
0330   }
0331 public:
0332   sg::line_style& line_style() {return m_line_style;}
0333   sg::line_style& ticks_style() {return m_ticks_style;}
0334   text_style& labels_style() {return m_labels_style;}
0335   text_style& title_style() {return m_title_style;}
0336   text_style& mag_style() {return m_mag_style;}
0337 
0338   void set_color(const colorf& a_color){
0339     m_line_style.color = a_color;
0340     m_ticks_style.color = a_color;
0341     m_labels_style.color = a_color;
0342     m_title_style.color = a_color;
0343     m_mag_style.color = a_color;
0344   }
0345 public:
0346   void update_sg(std::ostream& a_out) {
0347     if(width<=0) {
0348       m_line_sep.clear();
0349       m_ticks_sep.clear();
0350       m_labels_sep.clear();
0351       m_mag_sep.clear();
0352       m_title_sep.clear();
0353       return;
0354     }
0355 
0356     // line scene graph :
0357     m_line_sep.clear();
0358     if(m_line_style.visible) {
0359       rgba* mat = new rgba();
0360       mat->color = m_line_style.color;
0361       m_line_sep.add(mat);
0362 
0363       draw_style* ds = new draw_style;
0364       ds->style = draw_lines;
0365       ds->line_pattern = m_line_style.pattern;
0366       ds->line_width = m_line_style.width;
0367       m_line_sep.add(ds);
0368 
0369       vertices* vtxs = new vertices;
0370       vtxs->mode = gl::line_strip();
0371       vtxs->add(0,0,0);
0372       vtxs->add(width,0,0);
0373       m_line_sep.add(vtxs);
0374     }
0375 
0376     // ticks scene graph :
0377     if(modeling==tick_modeling_none()) {
0378     } else if(modeling==tick_modeling_hplot()) {
0379       compute_ticks_HPLOT(a_out);
0380     } else {
0381       compute_ticks_hippo();
0382     }
0383 
0384     m_ticks_sep.clear();
0385     if(m_ticks_style.visible) {
0386 
0387       vertices* vtxs = new vertices;
0388       vtxs->mode = gl::lines();
0389 
0390       if(modeling==tick_modeling_hplot()) {
0391 
0392         size_t num = m_sub_ticks.size()/4;
0393         size_t pos = 0;
0394         for(size_t index=0;index<num;index++) {
0395           float bx = m_sub_ticks[pos];pos++;
0396           float by = m_sub_ticks[pos];pos++;
0397           float ex = m_sub_ticks[pos];pos++;
0398           float ey = m_sub_ticks[pos];pos++;
0399           if(tick_up) {
0400             vtxs->add(bx,by,0);
0401             vtxs->add(ex,ey,0);
0402           } else {
0403             vtxs->add(bx,-by,0);
0404             vtxs->add(ex,-ey,0);
0405           }
0406         }
0407 
0408       } else {
0409 
0410         float yy = tick_up ? tick_length.value():-tick_length.value();
0411         for(unsigned int index=0;index<tick_number;index++) {
0412           float xx = coords.values()[index];
0413           vtxs->add(xx,0,0);
0414           vtxs->add(xx,yy,0);
0415         }
0416       }
0417 
0418       if(vtxs->number()) {
0419 
0420         rgba* mat = new rgba();
0421         mat->color = m_ticks_style.color;
0422         m_ticks_sep.add(mat);
0423 
0424         draw_style* ds = new draw_style;
0425         ds->style = draw_lines;
0426         ds->line_pattern = m_ticks_style.pattern;
0427         ds->line_width = m_ticks_style.width;
0428         m_ticks_sep.add(ds);
0429 
0430         m_ticks_sep.add(vtxs);
0431       } else {
0432         delete vtxs;
0433       }
0434 
0435     }
0436 
0437     // labels scene graph :
0438     m_labels_sep.clear();
0439     if(m_labels_style.visible && tick_number ) {
0440       m_labels_seps.clear();
0441       m_labels_xs.clear();
0442       m_labels_mtxs.clear();
0443 
0444       rgba* mat = new rgba();
0445       mat->color = m_labels_style.color;
0446       m_labels_sep.add(mat);
0447 
0448       float text_size = label_height*m_labels_style.scale;
0449       std::string font = m_labels_style.font.value();
0450 
0451       if(font==font_hershey()) {
0452         draw_style* ds = new draw_style;
0453         ds->style = draw_lines;
0454         ds->line_pattern = m_labels_style.line_pattern;
0455         ds->line_width = m_labels_style.line_width;
0456         m_labels_sep.add(ds);
0457       } else {
0458         m_labels_sep.add(new normal);
0459       }
0460 
0461       vec3f X = m_labels_style.x_orientation.value();
0462       vec3f Y = m_labels_style.y_orientation.value();
0463       X.normalize();
0464       Y.normalize();
0465       vec3f Z;X.cross(Y,Z);
0466       Z.cross(X,Y);
0467       mat4f scale_rot(X.v0(),Y.v0(),Z.v0(),0, //first row
0468                       X.v1(),Y.v1(),Z.v1(),0,
0469                       X.v2(),Y.v2(),Z.v2(),0,
0470                       0,0,0,1);
0471       scale_rot.mul_scale(text_size,text_size,1);
0472 
0473       bool bin_center = (m_labels_style.options.value()=="center"?true:false); //gopaw.
0474 
0475       vec3f vec;float xx;
0476      {unsigned int number = tick_number;
0477       for(unsigned int index=0;index<number;index++) {
0478 
0479         if(bin_center) { //label at the center of the bin :
0480           if(index==(number-1)) continue;
0481           xx = 0.5f*(coords.values()[index]+coords.values()[index+1]);
0482         } else { // label on tick :
0483           xx = coords.values()[index];
0484         }
0485 
0486         vec.set_value(xx,-label_to_axis,0);
0487         vec += m_labels_style.translation.value();
0488 
0489         separator* sep = new separator;
0490         m_labels_sep.add(sep);
0491 
0492         matrix* _tsf =
0493           add_string_opt(*sep,
0494                          font,
0495                          m_labels_style.font_modeling.value(),
0496                          m_labels_style.encoding.value(),
0497                          m_labels_style.smoothing,
0498                          labels.values()[index],
0499                          vec[0],vec[1],vec[2],
0500                          scale_rot,
0501                          m_labels_style.hjust,
0502                          m_labels_style.vjust,
0503                          m_ttf);
0504         if(_tsf) {
0505           m_labels_seps.push_back(sep);
0506           m_labels_xs.push_back(xx);
0507           m_labels_mtxs.push_back(_tsf);
0508         }
0509       }}
0510 
0511       if(labels_no_overlap_automated.value()) avoid_labels_overlap(a_out);
0512       m_labels_seps.clear();
0513       m_labels_xs.clear();
0514       m_labels_mtxs.clear();
0515     }
0516 
0517     m_mag_sep.clear();
0518     if( magnitude.value() && m_mag_style.visible) {
0519       rgba* mat = new rgba();
0520       mat->color = m_mag_style.color;
0521       m_mag_sep.add(mat);
0522 
0523       char string[64];
0524       if(magnitude>=0)
0525         snpf(string,sizeof(string),"x10+%d",magnitude.value());
0526       else
0527         snpf(string,sizeof(string),"x10-%d",::abs(magnitude));
0528 
0529       vec3f vec(width*1.03f,0,0);
0530       vec += m_mag_style.translation.value();
0531 
0532       float text_size = label_height*0.8f * m_mag_style.scale;
0533       std::string font = m_mag_style.font.value();
0534 
0535       if(font==font_hershey()) {
0536         draw_style* ds = new draw_style;
0537         ds->style = draw_lines;
0538         ds->line_pattern = m_mag_style.line_pattern;
0539         ds->line_width = m_mag_style.line_width;
0540         m_mag_sep.add(ds);
0541       }
0542 
0543       add_string(m_mag_sep,
0544                          font,
0545                          m_mag_style.font_modeling.value(),
0546                          m_mag_style.encoding.value(),
0547                          m_mag_style.smoothing,
0548                          string,
0549                          vec[0],vec[1],vec[2],
0550                          m_mag_style.x_orientation.value(),
0551                          m_mag_style.y_orientation.value(),
0552                          text_size,
0553                          m_mag_style.hjust,
0554                          m_mag_style.vjust,
0555                          m_ttf);
0556     }
0557 
0558     // title scene graph :if(update_title) {
0559     m_title_sep.clear();
0560     if(title.value().size() && m_title_style.visible) {
0561       rgba* mat = new rgba();
0562       mat->color = m_title_style.color;
0563       m_title_sep.add(mat);
0564 
0565       float text_size = title_height*m_title_style.scale;
0566       std::string font = m_title_style.font.value();
0567 
0568       if(font==font_hershey()) {
0569         draw_style* ds = new draw_style;
0570         ds->style = draw_lines;
0571         ds->line_pattern = m_title_style.line_pattern;
0572         ds->line_width = m_title_style.line_width;
0573         m_title_sep.add(ds);
0574       } else {
0575         m_title_sep.add(new normal);
0576       }
0577 
0578       float xx = 0; //left
0579       if(title_hjust==center) {
0580          xx = width/2;
0581       } else if(title_hjust==right) {
0582          xx = width;
0583       }
0584 
0585       vec3f vec(xx,-title_to_axis,0);
0586       vec += m_title_style.translation.value();
0587 
0588       add_string(m_title_sep,
0589                          font,
0590                          m_title_style.font_modeling.value(),
0591                          m_title_style.encoding.value(),
0592                          m_title_style.smoothing,
0593                          title.value(),
0594                          vec[0],vec[1],vec[2],
0595                          m_title_style.x_orientation.value(),
0596                          m_title_style.y_orientation.value(),
0597                          text_size,
0598                          m_title_style.hjust,
0599                          m_title_style.vjust,
0600                          m_ttf);
0601     }
0602 
0603   }
0604 
0605 public: //style
0606   void reset_style(bool a_geom = false) {
0607     //reset fields that are considered as part of the style.
0608 
0609     ////////////////////////////////////////////
0610     // we do not touch :
0611     ////////////////////////////////////////////
0612     //width
0613     //minimum_value
0614     //maximum_value
0615     //labels_enforced
0616     //tick_number
0617     //magnitude
0618     //time_labels
0619     //time_format
0620     //time_offset
0621     //time_offset_is_GMT
0622     //labels
0623     //values
0624     //coords
0625     //sub_coords
0626 
0627     ////////////////////////////////////////////
0628     divisions = 510;
0629     modeling = tick_modeling_hippo();
0630     tick_up = true;
0631     is_log = false;
0632     title.value().clear();
0633 
0634     labels_no_overlap_automated = true;
0635     labels_gap = 0.02f;
0636 
0637     if(a_geom) {
0638     ////////////////////////////////////////////
0639     // Take PAW default :
0640     float YSIZ = 20; //page height
0641     float YMGL = 2;  //low y margin (to data frame).
0642     float YMGU = 2;  //up y margin (to data frame).
0643     float VSIZ = 0.28F; //tick label character size.
0644     float YVAL = 0.4F;  //y distance of x tick label to data frame.
0645     float XTIC = 0.3F;  //y length of X axis ticks.
0646     float YLAB = 0.8F; //y distance of x title to data frame.
0647     float ASIZ = 0.28F; // axis title (label) character size.
0648 
0649     float hData = YSIZ-YMGL-YMGU;
0650 
0651     // To map data space to width :
0652     float to1 = width/hData;
0653 
0654     float vsiz = VSIZ * to1; //0.0175F
0655     float yval = YVAL * to1; //0.025F
0656     float xtic = XTIC * to1; //0.01875F
0657     float ylab = YLAB * to1; //0.05F
0658     float asiz = ASIZ * to1; //0.0175F
0659 
0660     //sf
0661     tick_length = xtic;
0662     label_to_axis = yval;
0663     label_height = vsiz;
0664 
0665     // The axis title is the PAW axis label.
0666     // It is right justified at the end of axis
0667     // (at end right for XY_X, at end top for XY_Y)
0668     title_to_axis = ylab;
0669     title_height = asiz;
0670     }
0671 
0672     title_hjust = right;
0673 
0674     ////////////////////////////////////////////
0675     // setup styles :
0676     m_line_style = line_style();
0677     m_ticks_style = line_style();
0678     m_labels_style = text_style();
0679     m_mag_style = text_style();
0680     m_title_style = text_style();
0681 
0682     m_line_style.color = colorf_black();
0683     m_ticks_style.color = colorf_black();
0684 
0685     m_labels_style.color = colorf_black();
0686     m_labels_style.font = font_hershey();
0687     m_labels_style.encoding = encoding_PAW();
0688 
0689     m_mag_style.color = colorf_black();
0690     m_mag_style.font = font_hershey();
0691     m_mag_style.encoding = encoding_PAW();
0692 
0693     m_title_style.color = colorf_black();
0694     m_title_style.font = font_hershey();
0695     m_title_style.encoding = encoding_PAW();
0696   }
0697 
0698   typedef std::pair<std::string,std::string> style_item_t;
0699   typedef std::vector<style_item_t> style_t;
0700   bool set_from_style(std::ostream& a_out,const style_t& a_style) {
0701     style_t::const_iterator it;
0702     for(it=a_style.begin();it!=a_style.end();++it) {
0703       const std::string& key = (*it).first;
0704       const std::string& sv = (*it).second;
0705 
0706       // not part of style :
0707       //width
0708       //minimum_value
0709       //maximum_value
0710       //labels_enforced
0711       //tick_number
0712       //magnitude
0713       //title
0714       //time_labels
0715       //time_format
0716       //time_offset
0717       //time_offset_is_GMT
0718       //labels
0719       //values
0720       //coords
0721       //sub_coords
0722 
0723       if(key=="divisions") {
0724         unsigned int v;
0725         if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
0726         divisions = v;
0727       } else if(key=="modeling") {
0728         modeling = sv;
0729       } else if(key=="is_log") {
0730         bool v;
0731         if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
0732         is_log = v;
0733 
0734       } else if(key=="tick_up") {
0735         bool v;
0736         if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
0737         tick_up = v;
0738       } else if(key=="tick_length") {
0739         float v;
0740         if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
0741         tick_length = v;
0742 
0743       } else if(key=="title") {
0744         title = sv;
0745       } else if(key=="title_to_axis") {
0746         float v;
0747         if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
0748         title_to_axis = v;
0749       } else if(key=="title_height") {
0750         float v;
0751         if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
0752         title_height = v;
0753       } else if(key=="title_hjust") {
0754         hjust v;
0755         if(!shjust(sv,v))
0756           {style_failed(a_out,key,sv);return false;}
0757         title_hjust = v;
0758 
0759       } else if(key=="label_to_axis") {
0760         float v;
0761         if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
0762         label_to_axis = v;
0763       } else if(key=="label_height") {
0764         float v;
0765         if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
0766         label_height = v;
0767 
0768       } else if(key=="labels_no_overlap_automated") {
0769         bool v;
0770         if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
0771         labels_no_overlap_automated = v;
0772       } else if(key=="labels_gap") {
0773         float v;
0774         if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
0775         labels_gap = v;
0776 
0777       } else {
0778         a_out << "axis::set_from_style :"
0779               << " unknown key " << key << "."
0780               << std::endl;
0781       }
0782     }
0783     return true;
0784   }
0785 
0786   void set_encoding(const std::string& a_value) {
0787     labels_style().encoding = a_value;
0788     mag_style().encoding = a_value;
0789     title_style().encoding = a_value;
0790   }
0791 protected:
0792   float get_overlap(std::ostream& a_out,bool& a_overlap) {
0793     a_overlap = false;
0794     std::vector<float> x_mins;
0795     std::vector<float> x_maxs;
0796    {size_t index = 0;
0797     bbox_action _action(a_out);
0798     tools_vforcit(separator*,m_labels_seps,it) {
0799       _action.reset();
0800       (*it)->bbox(_action);
0801       if(_action.end()) {
0802         float dx,dy,dz;
0803         if(_action.box().get_size(dx,dy,dz)) {
0804           if(dx>0) {
0805             x_mins.push_back(m_labels_xs[index]-dx*0.5f);
0806             x_maxs.push_back(m_labels_xs[index]+dx*0.5f);
0807           }
0808         }
0809       }
0810       index++;
0811     }}
0812     float dx_overlap = 0;
0813    {size_t number = x_mins.size();
0814     for(size_t index=1;index<number;index++) {
0815       float dx = x_mins[index]-x_maxs[index-1];
0816       if(dx<0) {
0817         a_overlap = true;
0818         dx_overlap = max_of(dx_overlap,-dx);
0819       }
0820     }}
0821     return dx_overlap;
0822   }
0823   void avoid_labels_overlap(std::ostream& a_out) {
0824     bool overlap;
0825     float first_scale = 1;
0826     float first_overlap = get_overlap(a_out,overlap);
0827     if(overlap) {
0828       float second_scale = 1.1f; // greater than one to be sure to overlap again.
0829      {tools_vforcit(matrix*,m_labels_mtxs,it) {
0830         (*it)->mul_scale(second_scale,second_scale,1);
0831       }}
0832       float second_overlap = get_overlap(a_out,overlap);
0833       if(overlap) {
0834         // first_overlap  = a*first_scale+b
0835         // second_overlap = a*second_scale+b
0836         float a = (second_overlap-first_overlap)/(second_scale-first_scale);
0837         float b = first_overlap-a*first_scale;
0838       //float wanted_scale = -b/a; //zero overlap.
0839         float wanted_gap = width.value()*labels_gap.value();
0840         float wanted_scale = (a==0.0f) ? 1 : (-wanted_gap-b)/a; //a==0.0f should not happen.
0841         if(wanted_scale<=0) wanted_scale = 1; // this if() should not happen.
0842         wanted_scale /= second_scale;
0843        {tools_vforcit(matrix*,m_labels_mtxs,it) {
0844           (*it)->mul_scale(wanted_scale,wanted_scale,1);
0845         }}
0846       } else { //it should not happen.
0847         tools_vforcit(matrix*,m_labels_mtxs,it) {
0848           (*it)->mul_scale(1.0f/second_scale,1.0f/second_scale,1);
0849         }
0850       }
0851     }
0852   }
0853 
0854   static void style_failed(std::ostream& a_out,
0855                            const std::string& a_key,
0856                            const std::string& a_value) {
0857     a_out << "axis::set_from_style :"
0858           << " failed for key " << sout(a_key)
0859           << " and value " << sout(a_value) << "."
0860           << std::endl;
0861   }
0862 protected:
0863   //////////////////////////////////////////////////////////////////////////
0864   /// Hippodraw tick modeling //////////////////////////////////////////////
0865   //////////////////////////////////////////////////////////////////////////
0866   void compute_ticks_hippo() {
0867     //  input fields :
0868     //    minimum_value
0869     //    maximum_value
0870     //    is_log
0871     //  output fields :
0872     //    values
0873     //    coords
0874     //    sub_coords
0875     //    labels (if labels_enforced is false)
0876     //    tick_number
0877 
0878 
0879     float mn = minimum_value;
0880     float mx = maximum_value;
0881 
0882     bool a_is_log = is_log;
0883     if(a_is_log) {
0884       if((mn<=0) || (mx<=0) ) a_is_log = false;
0885     }
0886 
0887     float magxxx,y,yr,startTick,tickSize;
0888     float pmag;
0889     char pstr[10] = "";
0890     char tmp[10];
0891 
0892     unsigned int tick_num = 0;
0893     std::vector<float> tick_values;
0894     std::vector<std::string> tick_labels;
0895 
0896     // need include <float.h> which does not exist on some system
0897     //NUM_FUZZ DBL_EPSILON*4
0898     float NUM_FUZZ = 0.01f;
0899 
0900     if (mn >= mx) {
0901       if(tick_number) {
0902         tick_number.value(0);
0903         values.clear();
0904         coords.clear();
0905         sub_coords.clear();
0906         labels.clear();
0907       }
0908       if(magnitude.value()) magnitude.value(0);
0909       m_sub_ticks.clear();
0910       return;
0911     }
0912 
0913     if (!a_is_log) {
0914 
0915       tickSize  = calculate_ticks_hippo(mx-mn,magxxx);
0916       startTick = fceil( mn / tickSize) * tickSize;
0917 
0918       if (ffabs(magxxx) <= 3)
0919         pmag = 0.0;
0920       else
0921         pmag = startTick != 0.0 ? ffloor(flog10(ffabs(startTick))) : magxxx;
0922 
0923       snpf(pstr,sizeof(pstr),"%%1.%df",(int)max_of<float>((pmag-magxxx),0.0));
0924 
0925       y = startTick;
0926       while (y <= mx*(1.0+NUM_FUZZ)) {
0927 
0928         yr = ffloor(y/fpow(10,magxxx) + 0.5F);
0929 
0930         snpf(tmp,sizeof(tmp),pstr,yr*fpow(10,magxxx-pmag));
0931 
0932        {float val = yr * fpow(10.0,magxxx);
0933         if((val>=mn)&&(val<=mx)) { //G.Barrand : add this test.
0934           tick_values.push_back(val);
0935           tick_labels.push_back(tmp);
0936           tick_num++;
0937         }}
0938 
0939         y += tickSize;
0940       }
0941       if (ffabs(magxxx) <= 3.0) magxxx = 0.0;
0942 
0943     }  else {
0944 
0945       if (mn <= 0) {
0946         if(tick_number) {
0947           tick_number.value(0);
0948           values.clear();
0949           coords.clear();
0950           sub_coords.clear();
0951           labels.clear();
0952         }
0953         if(magnitude.value()) magnitude.value(0);
0954         m_sub_ticks.clear();
0955         return;
0956       }
0957 
0958       int nLogTicks;
0959       float logTicks[5];
0960       float magStep;
0961 
0962       float maghigh = fceil(flog10(mx));
0963       float maglow  = ffloor(flog10(mn));
0964       float magrng  = maghigh - maglow;
0965 
0966       if (magrng <=3) {
0967         nLogTicks   = 3;
0968         logTicks[0] = 1.0;
0969         logTicks[1] = 2.0;
0970         logTicks[2] = 5.0;
0971         magStep     = 1.0;
0972       } else {
0973         nLogTicks   = 1;
0974         logTicks[0] = 1.0;
0975         magStep     = magrng <= 7 ? 1.0F : 2.0F;
0976       }
0977 
0978       pmag = (nLogTicks == 3 && (ffabs(maglow)>3 || ffabs(maghigh)>3)) ?
0979         maglow : 0;
0980 
0981       magxxx = maglow;
0982       int i = 0;
0983       while ((y=logTicks[i]*fpow(10,magxxx)) < mx*(1+NUM_FUZZ)) {
0984         if (y >= mn) {
0985 
0986           // be careful: there is a bug in the NeXT (s)printf
0987           //   routine when you do, eg. printf("%1.0g",0.01);
0988           if ((magxxx-pmag) > 4 || (magxxx-pmag) < -3) {
0989             ::strcpy(pstr,"%1.0e");
0990           } else {
0991             snpf(pstr,sizeof(pstr),
0992                  "%%1.%df",(int)((magxxx-pmag)>0?0.:-(magxxx-pmag)));
0993           }
0994           snpf(tmp,sizeof(tmp),pstr,y*fpow(10.0,-pmag));
0995 
0996          {float val = flog10(y);
0997           if((val>=flog10(mn))&&(val<=flog10(mx))) { //G.Barrand : add this if
0998             tick_values.push_back(val);
0999             tick_labels.push_back(tmp);
1000             tick_num++;
1001           }}
1002 
1003         }
1004 
1005         i++;
1006         if (i>=nLogTicks)        {
1007           i = 0;
1008           magxxx += magStep;
1009         }
1010       }
1011 
1012       mn = flog10(mn);
1013       mx = flog10(mx);
1014     }
1015 
1016     float range = mx - mn;
1017 
1018     // it is assumes that tick_values are ordered min to max.
1019     tick_number.value(tick_num);
1020     values.clear();
1021     coords.clear();
1022     for(unsigned int index=0;index<tick_num;index++) {
1023       float val = tick_values[index];
1024       float coord = width * (val-mn)/range;
1025       values.add(val);
1026       coords.add(coord);
1027     }
1028 
1029     if(labels_enforced) {
1030       size_t n = labels.size();
1031       if(tick_num>n) {
1032         for(size_t index=n;index<tick_num;index++) labels.add("");
1033       }
1034     } else {
1035       labels = tick_labels;
1036     }
1037 
1038     magnitude.value((int)pmag);
1039 
1040     sub_coords.clear();
1041     m_sub_ticks.clear();
1042   }
1043 
1044   static float calculate_ticks_hippo(float aSize,float& a_mag) {
1045     unsigned int MIN_TICKS = 4;
1046 
1047     if (aSize <= 0.0) {
1048       //printf ("CalculateTicks : bad value \n");
1049       aSize = ffabs(aSize);
1050       if (aSize == 0.0) aSize = 1.0;
1051     }
1052 
1053     a_mag = ffloor(flog10(aSize));
1054     if (aSize/fpow(10.0,a_mag) < MIN_TICKS) (a_mag)--;
1055 
1056     // now fit the max number of ticks into this range
1057 
1058     float  tickSize;
1059     int tickIndex;
1060     static const float goodTicks[] = {10.0, 5.0, 4.0, 2.0, 1.0};
1061     for(tickIndex = 0;
1062        aSize/(tickSize=goodTicks[tickIndex]*fpow(10.0,a_mag))<MIN_TICKS;
1063         tickIndex++){}
1064 
1065     if (tickIndex == 0) a_mag++;
1066 
1067     return tickSize;
1068   }
1069 
1070   ////////////////////////////////////////////////////////////////////////////
1071   /// HPLOT tick modeling ////////////////////////////////////////////////////
1072   ////////////////////////////////////////////////////////////////////////////
1073   ////////////////////////////////////////////////////////////////////////////
1074   void compute_ticks_HPLOT(std::ostream& a_out) {
1075     //  Controlled by fields :
1076     //    minimum_value
1077     //    maximum_value
1078     //    divisions
1079     //    is_log
1080     //  Set value on fields :
1081     //    values
1082     //    coords
1083     //    labels (if labels_enforced is false)
1084     //    tick_number
1085 
1086     float mn = minimum_value;
1087     float mx = maximum_value;
1088 
1089     bool a_is_log = is_log;
1090     if(a_is_log) {
1091       if((mn<=0) || (mx<=0) ) a_is_log = false;
1092     }
1093 
1094     // Use hplot::axis to get the ticks and subticks positions
1095     // and the labels text.
1096 
1097     double xmin = 0;
1098     double ymin = 0;
1099     double xmax = width;
1100     double ymax = 0;
1101 
1102     double gridlength = 0;
1103     std::string chopt;
1104     if(a_is_log) chopt += "G";
1105 
1106     std::vector<float> linesGrid;
1107     std::vector<hplot::_text> texts;
1108 
1109     hplot::axis sbAxisHPLOT(a_out);
1110 
1111     chopt += "S";
1112     sbAxisHPLOT.set_tick_size(tick_length/width.value());
1113 
1114     if(time_labels.value()) {
1115       chopt += "t";
1116       sbAxisHPLOT.set_time_format(time_format.value());
1117       sbAxisHPLOT.set_time_offset(time_offset,
1118                                   time_offset_is_GMT);
1119     }
1120 
1121     // Get ticks :
1122    {double wmin = mn;
1123     double wmax = mx;
1124     int ndiv = divisions;
1125     sbAxisHPLOT.set_title("");
1126     sbAxisHPLOT.paint(xmin,ymin,xmax,ymax,
1127                       wmin,wmax,ndiv, //Modified
1128                       chopt,gridlength,false,
1129                       m_sub_ticks,linesGrid,texts);}
1130 
1131     if(a_is_log) {
1132       mn = flog10(mn);
1133       mx = flog10(mx);
1134     }
1135 
1136     float range = mx - mn;
1137 
1138     size_t tick_num = texts.size();
1139 
1140     // HPLOT stores the magnitude on the last label :
1141     magnitude.value(0);
1142     if(tick_num) {
1143       int pmag;
1144       if(::sscanf(texts[tick_num-1].fString.c_str(),"x10^%d!",&pmag)==1) {
1145         magnitude.value(pmag);
1146         tick_num--;
1147       }
1148     }
1149 
1150     tick_number.value(uint32(tick_num));
1151     values.clear();
1152     coords.clear();
1153     for(size_t index=0;index<tick_num;index++) {
1154       float coord = (float)texts[index].fX;
1155       //NOTE : are we sure that val is in [mn,mx]
1156       float val = (coord/width.value()) * range + mn;
1157       coords.add(coord);
1158       values.add(val);
1159     }
1160 
1161     if(labels_enforced) {
1162       size_t n = labels.size();
1163       if(tick_num>n) {
1164         for(size_t index=n;index<tick_num;index++) labels.add("");
1165       }
1166     } else {
1167       labels.clear();
1168       for(size_t index=0;index<tick_num;index++) {
1169         labels.add(texts[index].fString);
1170       }
1171     }
1172 
1173    {sub_coords.clear();
1174     size_t num = m_sub_ticks.size()/4;
1175     size_t pos = 0;
1176     for(size_t index=0;index<num;index++) {
1177       float coord = m_sub_ticks[pos];
1178       pos += 4;
1179       bool found = false;
1180       for(size_t i=0;i<tick_num;i++) {
1181         if((float)texts[i].fX==coord) {
1182           found = true;
1183           break;
1184         }
1185       }
1186       if(!found) { //not a main tick
1187         sub_coords.add(coord);
1188       }
1189     }}
1190   }
1191 
1192 protected:
1193   const base_freetype& m_ttf;
1194 
1195   group m_group;
1196 
1197   separator m_line_sep;
1198   separator m_ticks_sep;
1199   separator m_labels_sep;
1200   separator m_mag_sep;
1201   separator m_title_sep;
1202 
1203   sg::line_style m_line_style;
1204   sg::line_style m_ticks_style;
1205   text_style m_labels_style;
1206   text_style m_mag_style;
1207   text_style m_title_style;
1208 
1209   std::vector<float> m_sub_ticks; //n*(2+2)
1210 
1211   std::vector<separator*> m_labels_seps;
1212   std::vector<float> m_labels_xs;
1213   std::vector<matrix*> m_labels_mtxs;
1214 };
1215 
1216 }}
1217 
1218 #endif