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 //a_out << "debug : tools::axis::update_sg :" << std::endl;
0348
0349 if(width<=0) {
0350 m_line_sep.clear();
0351 m_ticks_sep.clear();
0352 m_labels_sep.clear();
0353 m_mag_sep.clear();
0354 m_title_sep.clear();
0355 return;
0356 }
0357
0358 // line scene graph :
0359 m_line_sep.clear();
0360 if(m_line_style.visible) {
0361 rgba* mat = new rgba();
0362 mat->color = m_line_style.color;
0363 m_line_sep.add(mat);
0364
0365 draw_style* ds = new draw_style;
0366 ds->style = draw_lines;
0367 ds->line_pattern = m_line_style.pattern;
0368 ds->line_width = m_line_style.width;
0369 m_line_sep.add(ds);
0370
0371 vertices* vtxs = new vertices;
0372 vtxs->mode = gl::line_strip();
0373 vtxs->add(0,0,0);
0374 vtxs->add(width,0,0);
0375 m_line_sep.add(vtxs);
0376 }
0377
0378 // ticks scene graph :
0379 if(modeling==tick_modeling_none()) {
0380 } else if(modeling==tick_modeling_hplot()) {
0381 compute_ticks_HPLOT(a_out);
0382 } else {
0383 compute_ticks_hippo();
0384 }
0385
0386 m_ticks_sep.clear();
0387 if(m_ticks_style.visible) {
0388
0389 vertices* vtxs = new vertices;
0390 vtxs->mode = gl::lines();
0391
0392 if(modeling==tick_modeling_hplot()) {
0393
0394 size_t num = m_sub_ticks.size()/4;
0395 size_t pos = 0;
0396 for(size_t index=0;index<num;index++) {
0397 float bx = m_sub_ticks[pos];pos++;
0398 float by = m_sub_ticks[pos];pos++;
0399 float ex = m_sub_ticks[pos];pos++;
0400 float ey = m_sub_ticks[pos];pos++;
0401 if(tick_up) {
0402 vtxs->add(bx,by,0);
0403 vtxs->add(ex,ey,0);
0404 } else {
0405 vtxs->add(bx,-by,0);
0406 vtxs->add(ex,-ey,0);
0407 }
0408 }
0409
0410 } else {
0411
0412 float yy = tick_up ? tick_length.value():-tick_length.value();
0413 for(unsigned int index=0;index<tick_number;index++) {
0414 float xx = coords.values()[index];
0415 vtxs->add(xx,0,0);
0416 vtxs->add(xx,yy,0);
0417 }
0418 }
0419
0420 if(vtxs->number()) {
0421
0422 rgba* mat = new rgba();
0423 mat->color = m_ticks_style.color;
0424 m_ticks_sep.add(mat);
0425
0426 draw_style* ds = new draw_style;
0427 ds->style = draw_lines;
0428 ds->line_pattern = m_ticks_style.pattern;
0429 ds->line_width = m_ticks_style.width;
0430 m_ticks_sep.add(ds);
0431
0432 m_ticks_sep.add(vtxs);
0433 } else {
0434 delete vtxs;
0435 }
0436
0437 }
0438
0439 // labels scene graph :
0440 m_labels_sep.clear();
0441 if(m_labels_style.visible && tick_number ) {
0442 m_labels_seps.clear();
0443 m_labels_xs.clear();
0444 m_labels_mtxs.clear();
0445
0446 rgba* mat = new rgba();
0447 mat->color = m_labels_style.color;
0448 m_labels_sep.add(mat);
0449
0450 float text_size = label_height*m_labels_style.scale;
0451 std::string font = m_labels_style.font.value();
0452
0453 if(font==font_hershey()) {
0454 draw_style* ds = new draw_style;
0455 ds->style = draw_lines;
0456 ds->line_pattern = m_labels_style.line_pattern;
0457 ds->line_width = m_labels_style.line_width;
0458 m_labels_sep.add(ds);
0459 } else {
0460 m_labels_sep.add(new normal);
0461 }
0462
0463 vec3f X = m_labels_style.x_orientation.value();
0464 vec3f Y = m_labels_style.y_orientation.value();
0465 X.normalize();
0466 Y.normalize();
0467 vec3f Z;X.cross(Y,Z);
0468 Z.cross(X,Y);
0469 mat4f scale_rot(X.v0(),Y.v0(),Z.v0(),0, //first row
0470 X.v1(),Y.v1(),Z.v1(),0,
0471 X.v2(),Y.v2(),Z.v2(),0,
0472 0,0,0,1);
0473 scale_rot.mul_scale(text_size,text_size,1);
0474
0475 bool bin_center = (m_labels_style.options.value()=="center"?true:false); //gopaw.
0476
0477 vec3f vec;float xx;
0478 {unsigned int number = tick_number;
0479 for(unsigned int index=0;index<number;index++) {
0480
0481 if(bin_center) { //label at the center of the bin :
0482 if(index==(number-1)) continue;
0483 xx = 0.5f*(coords.values()[index]+coords.values()[index+1]);
0484 } else { // label on tick :
0485 xx = coords.values()[index];
0486 }
0487
0488 vec.set_value(xx,-label_to_axis,0);
0489 vec += m_labels_style.translation.value();
0490
0491 separator* sep = new separator;
0492 m_labels_sep.add(sep);
0493
0494 matrix* _tsf =
0495 add_string_opt(*sep,
0496 font,
0497 m_labels_style.font_modeling.value(),
0498 m_labels_style.encoding.value(),
0499 m_labels_style.smoothing,
0500 labels.values()[index],
0501 vec[0],vec[1],vec[2],
0502 scale_rot,
0503 m_labels_style.hjust,
0504 m_labels_style.vjust,
0505 m_ttf);
0506 if(_tsf) {
0507 m_labels_seps.push_back(sep);
0508 m_labels_xs.push_back(xx);
0509 m_labels_mtxs.push_back(_tsf);
0510 }
0511 }}
0512
0513 if(labels_no_overlap_automated.value()) avoid_labels_overlap(a_out);
0514 m_labels_seps.clear();
0515 m_labels_xs.clear();
0516 m_labels_mtxs.clear();
0517 }
0518
0519 m_mag_sep.clear();
0520 if( magnitude.value() && m_mag_style.visible) {
0521 rgba* mat = new rgba();
0522 mat->color = m_mag_style.color;
0523 m_mag_sep.add(mat);
0524
0525 char string[64];
0526 if(magnitude>=0)
0527 snpf(string,sizeof(string),"x10+%d",magnitude.value());
0528 else
0529 snpf(string,sizeof(string),"x10-%d",::abs(magnitude));
0530
0531 vec3f vec(width*1.03f,0,0);
0532 vec += m_mag_style.translation.value();
0533
0534 float text_size = label_height*0.8f * m_mag_style.scale;
0535 std::string font = m_mag_style.font.value();
0536
0537 if(font==font_hershey()) {
0538 draw_style* ds = new draw_style;
0539 ds->style = draw_lines;
0540 ds->line_pattern = m_mag_style.line_pattern;
0541 ds->line_width = m_mag_style.line_width;
0542 m_mag_sep.add(ds);
0543 }
0544
0545 add_string(m_mag_sep,
0546 font,
0547 m_mag_style.font_modeling.value(),
0548 m_mag_style.encoding.value(),
0549 m_mag_style.smoothing,
0550 string,
0551 vec[0],vec[1],vec[2],
0552 m_mag_style.x_orientation.value(),
0553 m_mag_style.y_orientation.value(),
0554 text_size,
0555 m_mag_style.hjust,
0556 m_mag_style.vjust,
0557 m_ttf);
0558 }
0559
0560 // title scene graph :if(update_title) {
0561 m_title_sep.clear();
0562 if(title.value().size() && m_title_style.visible) {
0563 rgba* mat = new rgba();
0564 mat->color = m_title_style.color;
0565 m_title_sep.add(mat);
0566
0567 float text_size = title_height*m_title_style.scale;
0568 std::string font = m_title_style.font.value();
0569
0570 if(font==font_hershey()) {
0571 draw_style* ds = new draw_style;
0572 ds->style = draw_lines;
0573 ds->line_pattern = m_title_style.line_pattern;
0574 ds->line_width = m_title_style.line_width;
0575 m_title_sep.add(ds);
0576 } else {
0577 m_title_sep.add(new normal);
0578 }
0579
0580 float xx = 0; //left
0581 if(title_hjust==center) {
0582 xx = width/2;
0583 } else if(title_hjust==right) {
0584 xx = width;
0585 }
0586
0587 vec3f vec(xx,-title_to_axis,0);
0588 vec += m_title_style.translation.value();
0589
0590 //std::cout << "debug : axis : update_title :"
0591 // << " pos : " << vec[0] << " " << vec[1] << " " << vec[2]
0592 // << std::endl;
0593
0594 add_string(m_title_sep,
0595 font,
0596 m_title_style.font_modeling.value(),
0597 m_title_style.encoding.value(),
0598 m_title_style.smoothing,
0599 title.value(),
0600 vec[0],vec[1],vec[2],
0601 m_title_style.x_orientation.value(),
0602 m_title_style.y_orientation.value(),
0603 text_size,
0604 m_title_style.hjust,
0605 m_title_style.vjust,
0606 m_ttf);
0607 }
0608
0609 }
0610
0611 public: //style
0612 void reset_style(bool a_geom = false) {
0613 //reset fields that are considered as part of the style.
0614
0615 ////////////////////////////////////////////
0616 // we do not touch :
0617 ////////////////////////////////////////////
0618 //width
0619 //minimum_value
0620 //maximum_value
0621 //labels_enforced
0622 //tick_number
0623 //magnitude
0624 //time_labels
0625 //time_format
0626 //time_offset
0627 //time_offset_is_GMT
0628 //labels
0629 //values
0630 //coords
0631 //sub_coords
0632
0633 ////////////////////////////////////////////
0634 divisions = 510;
0635 modeling = tick_modeling_hippo();
0636 tick_up = true;
0637 is_log = false;
0638 title.value().clear();
0639
0640 labels_no_overlap_automated = true;
0641 labels_gap = 0.02f;
0642
0643 if(a_geom) {
0644 ////////////////////////////////////////////
0645 // Take PAW default :
0646 float YSIZ = 20; //page height
0647 float YMGL = 2; //low y margin (to data frame).
0648 float YMGU = 2; //up y margin (to data frame).
0649 float VSIZ = 0.28F; //tick label character size.
0650 float YVAL = 0.4F; //y distance of x tick label to data frame.
0651 float XTIC = 0.3F; //y length of X axis ticks.
0652 float YLAB = 0.8F; //y distance of x title to data frame.
0653 float ASIZ = 0.28F; // axis title (label) character size.
0654
0655 float hData = YSIZ-YMGL-YMGU;
0656
0657 // To map data space to width :
0658 float to1 = width/hData;
0659
0660 float vsiz = VSIZ * to1; //0.0175F
0661 float yval = YVAL * to1; //0.025F
0662 float xtic = XTIC * to1; //0.01875F
0663 float ylab = YLAB * to1; //0.05F
0664 float asiz = ASIZ * to1; //0.0175F
0665
0666 //sf
0667 tick_length = xtic;
0668 label_to_axis = yval;
0669 label_height = vsiz;
0670
0671 // The axis title is the PAW axis label.
0672 // It is right justified at the end of axis
0673 // (at end right for XY_X, at end top for XY_Y)
0674 title_to_axis = ylab;
0675 title_height = asiz;
0676 }
0677
0678 title_hjust = right;
0679
0680 ////////////////////////////////////////////
0681 // setup styles :
0682 m_line_style = line_style();
0683 m_ticks_style = line_style();
0684 m_labels_style = text_style();
0685 m_mag_style = text_style();
0686 m_title_style = text_style();
0687
0688 m_line_style.color = colorf_black();
0689 m_ticks_style.color = colorf_black();
0690
0691 m_labels_style.color = colorf_black();
0692 m_labels_style.font = font_hershey();
0693 m_labels_style.encoding = encoding_PAW();
0694
0695 m_mag_style.color = colorf_black();
0696 m_mag_style.font = font_hershey();
0697 m_mag_style.encoding = encoding_PAW();
0698
0699 m_title_style.color = colorf_black();
0700 m_title_style.font = font_hershey();
0701 m_title_style.encoding = encoding_PAW();
0702 }
0703
0704 typedef std::pair<std::string,std::string> style_item_t;
0705 typedef std::vector<style_item_t> style_t;
0706 bool set_from_style(std::ostream& a_out,const style_t& a_style) {
0707 style_t::const_iterator it;
0708 for(it=a_style.begin();it!=a_style.end();++it) {
0709 const std::string& key = (*it).first;
0710 const std::string& sv = (*it).second;
0711 //::printf("debug : axis::set_from_style : key \"%s\" \"%s\"\n",key.c_str(),sv.c_str());
0712 //if(key=="reset") {}
0713
0714 // not part of style :
0715 //width
0716 //minimum_value
0717 //maximum_value
0718 //labels_enforced
0719 //tick_number
0720 //magnitude
0721 //title
0722 //time_labels
0723 //time_format
0724 //time_offset
0725 //time_offset_is_GMT
0726 //labels
0727 //values
0728 //coords
0729 //sub_coords
0730
0731 if(key=="divisions") {
0732 unsigned int v;
0733 if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
0734 divisions = v;
0735 } else if(key=="modeling") {
0736 modeling = sv;
0737 } else if(key=="is_log") {
0738 bool v;
0739 if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
0740 is_log = v;
0741
0742 } else if(key=="tick_up") {
0743 bool v;
0744 if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
0745 tick_up = v;
0746 } else if(key=="tick_length") {
0747 float v;
0748 if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
0749 tick_length = v;
0750
0751 } else if(key=="title") {
0752 title = sv;
0753 } else if(key=="title_to_axis") {
0754 float v;
0755 if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
0756 title_to_axis = v;
0757 } else if(key=="title_height") {
0758 float v;
0759 if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
0760 title_height = v;
0761 } else if(key=="title_hjust") {
0762 hjust v;
0763 if(!shjust(sv,v))
0764 {style_failed(a_out,key,sv);return false;}
0765 title_hjust = v;
0766
0767 } else if(key=="label_to_axis") {
0768 float v;
0769 if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
0770 label_to_axis = v;
0771 } else if(key=="label_height") {
0772 float v;
0773 if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
0774 label_height = v;
0775
0776 } else if(key=="labels_no_overlap_automated") {
0777 bool v;
0778 if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
0779 labels_no_overlap_automated = v;
0780 } else if(key=="labels_gap") {
0781 float v;
0782 if(!to(sv,v)) {style_failed(a_out,key,sv);return false;}
0783 labels_gap = v;
0784
0785 } else {
0786 a_out << "axis::set_from_style :"
0787 << " unknown key " << key << "."
0788 << std::endl;
0789 }
0790 }
0791 return true;
0792 }
0793
0794 void set_encoding(const std::string& a_value) {
0795 labels_style().encoding = a_value;
0796 mag_style().encoding = a_value;
0797 title_style().encoding = a_value;
0798 }
0799 protected:
0800 float get_overlap(std::ostream& a_out,bool& a_overlap) {
0801 a_overlap = false;
0802 std::vector<float> x_mins;
0803 std::vector<float> x_maxs;
0804 {size_t index = 0;
0805 bbox_action _action(a_out);
0806 tools_vforcit(separator*,m_labels_seps,it) {
0807 _action.reset();
0808 (*it)->bbox(_action);
0809 if(_action.end()) {
0810 float dx,dy,dz;
0811 if(_action.box().get_size(dx,dy,dz)) {
0812 if(dx>0) {
0813 x_mins.push_back(m_labels_xs[index]-dx*0.5f);
0814 x_maxs.push_back(m_labels_xs[index]+dx*0.5f);
0815 }
0816 }
0817 }
0818 index++;
0819 }}
0820 float dx_overlap = 0;
0821 {size_t number = x_mins.size();
0822 for(size_t index=1;index<number;index++) {
0823 float dx = x_mins[index]-x_maxs[index-1];
0824 if(dx<0) {
0825 a_overlap = true;
0826 dx_overlap = mx(dx_overlap,-dx);
0827 }
0828 }}
0829 return dx_overlap;
0830 }
0831 void avoid_labels_overlap(std::ostream& a_out) {
0832 bool overlap;
0833 float first_scale = 1;
0834 float first_overlap = get_overlap(a_out,overlap);
0835 if(overlap) {
0836 float second_scale = 1.1f; // greater than one to be sure to overlap again.
0837 {tools_vforcit(matrix*,m_labels_mtxs,it) {
0838 (*it)->mul_scale(second_scale,second_scale,1);
0839 }}
0840 float second_overlap = get_overlap(a_out,overlap);
0841 if(overlap) {
0842 // first_overlap = a*first_scale+b
0843 // second_overlap = a*second_scale+b
0844 float a = (second_overlap-first_overlap)/(second_scale-first_scale);
0845 float b = first_overlap-a*first_scale;
0846 //float wanted_scale = -b/a; //zero overlap.
0847 float wanted_gap = width.value()*labels_gap.value();
0848 float wanted_scale = (-wanted_gap-b)/a;
0849 if(wanted_scale<=0) wanted_scale = 1; // this if() should not happen.
0850 wanted_scale /= second_scale;
0851 {tools_vforcit(matrix*,m_labels_mtxs,it) {
0852 (*it)->mul_scale(wanted_scale,wanted_scale,1);
0853 }}
0854 } else { //it should not happen.
0855 tools_vforcit(matrix*,m_labels_mtxs,it) {
0856 (*it)->mul_scale(1.0f/second_scale,1.0f/second_scale,1);
0857 }
0858 }
0859 }
0860 }
0861
0862 static void style_failed(std::ostream& a_out,
0863 const std::string& a_key,
0864 const std::string& a_value) {
0865 a_out << "axis::set_from_style :"
0866 << " failed for key " << sout(a_key)
0867 << " and value " << sout(a_value) << "."
0868 << std::endl;
0869 }
0870 protected:
0871 //////////////////////////////////////////////////////////////////////////
0872 /// Hippodraw tick modeling //////////////////////////////////////////////
0873 //////////////////////////////////////////////////////////////////////////
0874 void compute_ticks_hippo() {
0875 // input fields :
0876 // minimum_value
0877 // maximum_value
0878 // is_log
0879 // output fields :
0880 // values
0881 // coords
0882 // sub_coords
0883 // labels (if labels_enforced is false)
0884 // tick_number
0885
0886
0887 float mn = minimum_value;
0888 float mx = maximum_value;
0889
0890 bool a_is_log = is_log;
0891 if(a_is_log) {
0892 if((mn<=0) || (mx<=0) ) a_is_log = false;
0893 }
0894
0895 float magxxx,y,yr,startTick,tickSize;
0896 float pmag;
0897 char pstr[10] = "";
0898 char tmp[10];
0899
0900 unsigned int tick_num = 0;
0901 std::vector<float> tick_values;
0902 std::vector<std::string> tick_labels;
0903
0904 // need include <float.h> which does not exist on some system
0905 //NUM_FUZZ DBL_EPSILON*4
0906 float NUM_FUZZ = 0.01f;
0907
0908 if (mn >= mx) {
0909 if(tick_number) {
0910 tick_number.value(0);
0911 values.clear();
0912 coords.clear();
0913 sub_coords.clear();
0914 labels.clear();
0915 }
0916 if(magnitude.value()) magnitude.value(0);
0917 m_sub_ticks.clear();
0918 return;
0919 }
0920
0921 if (!a_is_log) {
0922
0923 tickSize = calculate_ticks_hippo(mx-mn,magxxx);
0924 startTick = fceil( mn / tickSize) * tickSize;
0925
0926 if (ffabs(magxxx) <= 3)
0927 pmag = 0.0;
0928 else
0929 pmag = startTick != 0.0 ? ffloor(flog10(ffabs(startTick))) : magxxx;
0930
0931 snpf(pstr,sizeof(pstr),"%%1.%df",(int)max_of<float>((pmag-magxxx),0.0));
0932
0933 y = startTick;
0934 while (y <= mx*(1.0+NUM_FUZZ)) {
0935
0936 yr = ffloor(y/fpow(10,magxxx) + 0.5F);
0937
0938 snpf(tmp,sizeof(tmp),pstr,yr*fpow(10,magxxx-pmag));
0939
0940 {float val = yr * fpow(10.0,magxxx);
0941 if((val>=mn)&&(val<=mx)) { //G.Barrand : add this test.
0942 tick_values.push_back(val);
0943 tick_labels.push_back(tmp);
0944 tick_num++;
0945 }}
0946
0947 y += tickSize;
0948 }
0949 if (ffabs(magxxx) <= 3.0) magxxx = 0.0;
0950
0951 } else {
0952
0953 if (mn <= 0) {
0954 if(tick_number) {
0955 tick_number.value(0);
0956 values.clear();
0957 coords.clear();
0958 sub_coords.clear();
0959 labels.clear();
0960 }
0961 if(magnitude.value()) magnitude.value(0);
0962 m_sub_ticks.clear();
0963 return;
0964 }
0965
0966 int nLogTicks;
0967 float logTicks[5];
0968 float magStep;
0969
0970 float maghigh = fceil(flog10(mx));
0971 float maglow = ffloor(flog10(mn));
0972 float magrng = maghigh - maglow;
0973
0974 if (magrng <=3) {
0975 nLogTicks = 3;
0976 logTicks[0] = 1.0;
0977 logTicks[1] = 2.0;
0978 logTicks[2] = 5.0;
0979 magStep = 1.0;
0980 } else {
0981 nLogTicks = 1;
0982 logTicks[0] = 1.0;
0983 magStep = magrng <= 7 ? 1.0F : 2.0F;
0984 }
0985
0986 pmag = (nLogTicks == 3 && (ffabs(maglow)>3 || ffabs(maghigh)>3)) ?
0987 maglow : 0;
0988
0989 magxxx = maglow;
0990 int i = 0;
0991 while ((y=logTicks[i]*fpow(10,magxxx)) < mx*(1+NUM_FUZZ)) {
0992 if (y >= mn) {
0993
0994 // be careful: there is a bug in the NeXT (s)printf
0995 // routine when you do, eg. printf("%1.0g",0.01);
0996 if ((magxxx-pmag) > 4 || (magxxx-pmag) < -3) {
0997 ::strcpy(pstr,"%1.0e");
0998 } else {
0999 snpf(pstr,sizeof(pstr),
1000 "%%1.%df",(int)((magxxx-pmag)>0?0.:-(magxxx-pmag)));
1001 }
1002 snpf(tmp,sizeof(tmp),pstr,y*fpow(10.0,-pmag));
1003
1004 {float val = flog10(y);
1005 if((val>=flog10(mn))&&(val<=flog10(mx))) { //G.Barrand : add this if
1006 tick_values.push_back(val);
1007 tick_labels.push_back(tmp);
1008 tick_num++;
1009 }}
1010
1011 }
1012
1013 i++;
1014 if (i>=nLogTicks) {
1015 i = 0;
1016 magxxx += magStep;
1017 }
1018 }
1019
1020 mn = flog10(mn);
1021 mx = flog10(mx);
1022 }
1023
1024 float range = mx - mn;
1025
1026 // it is assumes that tick_values are ordered min to max.
1027 tick_number.value(tick_num);
1028 values.clear();
1029 coords.clear();
1030 for(unsigned int index=0;index<tick_num;index++) {
1031 float val = tick_values[index];
1032 float coord = width * (val-mn)/range;
1033 values.add(val);
1034 coords.add(coord);
1035 }
1036
1037 if(labels_enforced) {
1038 size_t n = labels.size();
1039 if(tick_num>n) {
1040 for(size_t index=n;index<tick_num;index++) labels.add("");
1041 }
1042 } else {
1043 labels = tick_labels;
1044 }
1045
1046 magnitude.value((int)pmag);
1047
1048 sub_coords.clear();
1049 m_sub_ticks.clear();
1050 }
1051
1052 static float calculate_ticks_hippo(float aSize,float& a_mag) {
1053 unsigned int MIN_TICKS = 4;
1054
1055 if (aSize <= 0.0) {
1056 //printf ("CalculateTicks : bad value \n");
1057 aSize = ffabs(aSize);
1058 if (aSize == 0.0) aSize = 1.0;
1059 }
1060
1061 a_mag = ffloor(flog10(aSize));
1062 if (aSize/fpow(10.0,a_mag) < MIN_TICKS) (a_mag)--;
1063
1064 // now fit the max number of ticks into this range
1065
1066 float tickSize;
1067 int tickIndex;
1068 static const float goodTicks[] = {10.0, 5.0, 4.0, 2.0, 1.0};
1069 for(tickIndex = 0;
1070 aSize/(tickSize=goodTicks[tickIndex]*fpow(10.0,a_mag))<MIN_TICKS;
1071 tickIndex++){}
1072
1073 if (tickIndex == 0) a_mag++;
1074
1075 return tickSize;
1076 }
1077
1078 ////////////////////////////////////////////////////////////////////////////
1079 /// HPLOT tick modeling ////////////////////////////////////////////////////
1080 ////////////////////////////////////////////////////////////////////////////
1081 ////////////////////////////////////////////////////////////////////////////
1082 void compute_ticks_HPLOT(std::ostream& a_out) {
1083 // Controlled by fields :
1084 // minimum_value
1085 // maximum_value
1086 // divisions
1087 // is_log
1088 // Set value on fields :
1089 // values
1090 // coords
1091 // labels (if labels_enforced is false)
1092 // tick_number
1093
1094 float mn = minimum_value;
1095 float mx = maximum_value;
1096
1097 bool a_is_log = is_log;
1098 if(a_is_log) {
1099 if((mn<=0) || (mx<=0) ) a_is_log = false;
1100 }
1101
1102 // Use hplot::axis to get the ticks and subticks positions
1103 // and the labels text.
1104
1105 double xmin = 0;
1106 double ymin = 0;
1107 double xmax = width;
1108 double ymax = 0;
1109
1110 double gridlength = 0;
1111 std::string chopt;
1112 if(a_is_log) chopt += "G";
1113
1114 std::vector<float> linesGrid;
1115 std::vector<hplot::_text> texts;
1116
1117 hplot::axis sbAxisHPLOT(a_out);
1118
1119 chopt += "S";
1120 sbAxisHPLOT.set_tick_size(tick_length/width.value());
1121
1122 if(time_labels.value()) {
1123 chopt += "t";
1124 sbAxisHPLOT.set_time_format(time_format.value());
1125 sbAxisHPLOT.set_time_offset(time_offset,
1126 time_offset_is_GMT);
1127 }
1128
1129 // Get ticks :
1130 {double wmin = mn;
1131 double wmax = mx;
1132 int ndiv = divisions;
1133 sbAxisHPLOT.set_title("");
1134 sbAxisHPLOT.paint(xmin,ymin,xmax,ymax,
1135 wmin,wmax,ndiv, //Modified
1136 chopt,gridlength,false,
1137 m_sub_ticks,linesGrid,texts);}
1138
1139 if(a_is_log) {
1140 mn = flog10(mn);
1141 mx = flog10(mx);
1142 }
1143
1144 float range = mx - mn;
1145
1146 size_t tick_num = texts.size();
1147
1148 // HPLOT stores the magnitude on the last label :
1149 magnitude.value(0);
1150 if(tick_num) {
1151 int pmag;
1152 if(::sscanf(texts[tick_num-1].fString.c_str(),"x10^%d!",&pmag)==1) {
1153 magnitude.value(pmag);
1154 tick_num--;
1155 }
1156 }
1157
1158 tick_number.value(uint32(tick_num));
1159 values.clear();
1160 coords.clear();
1161 for(size_t index=0;index<tick_num;index++) {
1162 float coord = (float)texts[index].fX;
1163 //NOTE : are we sure that val is in [mn,mx]
1164 float val = (coord/width.value()) * range + mn;
1165 coords.add(coord);
1166 values.add(val);
1167 }
1168
1169 if(labels_enforced) {
1170 size_t n = labels.size();
1171 if(tick_num>n) {
1172 for(size_t index=n;index<tick_num;index++) labels.add("");
1173 }
1174 } else {
1175 labels.clear();
1176 for(size_t index=0;index<tick_num;index++) {
1177 labels.add(texts[index].fString);
1178 }
1179 }
1180
1181 {sub_coords.clear();
1182 size_t num = m_sub_ticks.size()/4;
1183 size_t pos = 0;
1184 for(size_t index=0;index<num;index++) {
1185 float coord = m_sub_ticks[pos];
1186 pos += 4;
1187 bool found = false;
1188 for(size_t i=0;i<tick_num;i++) {
1189 if((float)texts[i].fX==coord) {
1190 found = true;
1191 break;
1192 }
1193 }
1194 if(!found) { //not a main tick
1195 sub_coords.add(coord);
1196 }
1197 }}
1198 }
1199
1200 protected:
1201 const base_freetype& m_ttf;
1202
1203 group m_group;
1204
1205 separator m_line_sep;
1206 separator m_ticks_sep;
1207 separator m_labels_sep;
1208 separator m_mag_sep;
1209 separator m_title_sep;
1210
1211 sg::line_style m_line_style;
1212 sg::line_style m_ticks_style;
1213 text_style m_labels_style;
1214 text_style m_mag_style;
1215 text_style m_title_style;
1216
1217 std::vector<float> m_sub_ticks; //n*(2+2)
1218
1219 std::vector<separator*> m_labels_seps;
1220 std::vector<float> m_labels_xs;
1221 std::vector<matrix*> m_labels_mtxs;
1222 };
1223
1224 }}
1225
1226 #endif