// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef tools_sg_axis #define tools_sg_axis #include "node" #include "line_style" #include "text_style" #include "enums" #include "noderef" #include "vertices" #include "draw_style" #include "rgba" #include "normal" #include "separator" #include "tools" #include "nodekit" #include "../lina/vec3f" #include "../mnmx" #include "../hplot" #include //sprintf #include //strcpy namespace tools { namespace sg { class axis : public node { public: TOOLS_NODE(axis,tools::sg::axis,node) public: sf width; sf minimum_value; sf maximum_value; sf divisions; sf_string modeling; //hippo, hplot sf is_log; // If modeling is hippo or hplot, // labels_enforced true let labels be an input field. sf labels_enforced; sf tick_up; sf tick_length; // NOTE : if modeling is none,the below are input fields. // If modeling is hippo or hplot, the below are output field // (filled by compute_ticks). sf tick_number; //output mf_string labels; //output mf values; //output //in [minimumValue,maximumValue] mf coords; //output //in [0,width] mf sub_coords; //output sf magnitude; //output sf_string title; sf title_to_axis; sf title_height; sf_enum title_hjust; sf label_to_axis; sf label_height; sf labels_no_overlap_automated; sf labels_gap; //in percent of width. // time labels only in hplot modeling for the moment. sf time_labels; sf_string time_format; sf time_offset; sf time_offset_is_GMT; public: virtual const desc_fields& node_desc_fields() const { TOOLS_FIELD_DESC_NODE_CLASS(tools::sg::axis) static const desc_fields s_v(parent::node_desc_fields(),27, //WARNING : take care of count. TOOLS_ARG_FIELD_DESC(width), TOOLS_ARG_FIELD_DESC(minimum_value), TOOLS_ARG_FIELD_DESC(maximum_value), TOOLS_ARG_FIELD_DESC(divisions), TOOLS_ARG_FIELD_DESC(modeling), TOOLS_ARG_FIELD_DESC(is_log), TOOLS_ARG_FIELD_DESC(labels_enforced), TOOLS_ARG_FIELD_DESC(tick_up), TOOLS_ARG_FIELD_DESC(tick_length), TOOLS_ARG_FIELD_DESC(tick_number), TOOLS_ARG_FIELD_DESC(labels), TOOLS_ARG_FIELD_DESC(values), TOOLS_ARG_FIELD_DESC(coords), TOOLS_ARG_FIELD_DESC(sub_coords), TOOLS_ARG_FIELD_DESC(magnitude), TOOLS_ARG_FIELD_DESC(title), TOOLS_ARG_FIELD_DESC(title_to_axis), TOOLS_ARG_FIELD_DESC(title_height), TOOLS_ARG_FIELD_DESC(title_hjust), TOOLS_ARG_FIELD_DESC(label_to_axis), TOOLS_ARG_FIELD_DESC(label_height), TOOLS_ARG_FIELD_DESC(labels_no_overlap_automated), TOOLS_ARG_FIELD_DESC(labels_gap), TOOLS_ARG_FIELD_DESC(time_labels), TOOLS_ARG_FIELD_DESC(time_format), TOOLS_ARG_FIELD_DESC(time_offset), TOOLS_ARG_FIELD_DESC(time_offset_is_GMT) ); return s_v; } virtual bool touched() { if(parent::touched()) return true; if(line_style().touched()) return true; if(ticks_style().touched()) return true; if(labels_style().touched()) return true; if(mag_style().touched()) return true; if(title_style().touched()) return true; return false; } virtual void reset_touched() { parent::reset_touched(); line_style().reset_touched(); ticks_style().reset_touched(); labels_style().reset_touched(); mag_style().reset_touched(); title_style().reset_touched(); } private: void add_fields(){ // if adding a field, look for reset_style() and set_from_style() add_field(&width); add_field(&minimum_value); add_field(&maximum_value); add_field(&divisions); add_field(&modeling); add_field(&is_log); add_field(&labels_enforced); add_field(&tick_up); add_field(&tick_length); add_field(&tick_number); add_field(&labels); add_field(&values); add_field(&coords); add_field(&sub_coords); add_field(&magnitude); add_field(&title); add_field(&title_to_axis); add_field(&title_height); add_field(&title_hjust); add_field(&label_to_axis); add_field(&label_height); add_field(&labels_no_overlap_automated); add_field(&labels_gap); add_field(&time_labels); add_field(&time_format); add_field(&time_offset); add_field(&time_offset_is_GMT); } void init_sg(){ m_group.add(new noderef(m_line_sep)); m_group.add(new noderef(m_ticks_sep)); m_group.add(new noderef(m_labels_sep)); m_group.add(new noderef(m_mag_sep)); m_group.add(new noderef(m_title_sep)); } 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(); } //m_group.pick(a_action); nodekit_pick(a_action,m_group,this); } virtual void search(search_action& a_action) { if(touched()) { update_sg(a_action.out()); reset_touched(); } parent::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) { //FIXME : this method should not be needed ! // But m_[line,ticks,labels,mag,title]_style not written ! if(touched()) { update_sg(a_action.out()); reset_touched(); } //if(!write_fields(a_action)) return false; return m_group.write(a_action); } public: axis(const base_freetype& a_ttf) :parent() ,width(1) ,minimum_value(0) ,maximum_value(1) ,divisions(510) ,modeling(tick_modeling_hippo()) ,is_log(false) ,labels_enforced(false) ,tick_up(true) ,tick_length(0) ,tick_number(0) ,magnitude(0) ,title("") ,title_to_axis(0) //inited below ,title_height(0) //inited below ,title_hjust(right) ,label_to_axis(0) //inited below ,label_height(0) //inited below ,labels_no_overlap_automated(true) ,labels_gap(0.02f) ,time_labels(false) ,time_format("%H:%M:%S") ,time_offset(0) //UTC_time_1970_01_01__00_00_00 ,time_offset_is_GMT(false) ,m_ttf(a_ttf) { add_fields(); init_sg(); reset_style(true); } virtual ~axis(){} public: axis(const axis& a_from) :parent(a_from) ,width(a_from.width) ,minimum_value(a_from.minimum_value) ,maximum_value(a_from.maximum_value) ,divisions(a_from.divisions) ,modeling(a_from.modeling) ,is_log(a_from.is_log) ,labels_enforced(a_from.labels_enforced) ,tick_up(a_from.tick_up) ,tick_length(a_from.tick_length) ,tick_number(a_from.tick_number) ,magnitude(a_from.magnitude) ,title(a_from.title) ,title_to_axis(a_from.title_to_axis) ,title_height(a_from.title_height) ,title_hjust(a_from.title_hjust) ,label_to_axis(a_from.label_to_axis) ,label_height(a_from.label_height) ,labels_no_overlap_automated(a_from.labels_no_overlap_automated) ,labels_gap(a_from.labels_gap) ,time_labels(a_from.time_labels) ,time_format(a_from.time_format) ,time_offset(a_from.time_offset) ,time_offset_is_GMT(a_from.time_offset_is_GMT) ,m_ttf(a_from.m_ttf) ,m_line_style(a_from.m_line_style) ,m_ticks_style(a_from.m_ticks_style) ,m_labels_style(a_from.m_labels_style) ,m_mag_style(a_from.m_mag_style) ,m_title_style(a_from.m_title_style) { add_fields(); init_sg(); } axis& operator=(const axis& a_from){ parent::operator=(a_from); width = a_from.width; minimum_value = a_from.minimum_value; maximum_value = a_from.maximum_value; divisions = a_from.divisions; modeling = a_from.modeling; is_log = a_from.is_log; labels_enforced = a_from.labels_enforced; tick_up = a_from.tick_up; tick_length = a_from.tick_length; tick_number = a_from.tick_number; magnitude = a_from.magnitude; title = a_from.title; title_to_axis = a_from.title_to_axis; title_height = a_from.title_height; title_hjust = a_from.title_hjust; label_to_axis = a_from.label_to_axis; label_height = a_from.label_height; labels_no_overlap_automated = a_from.labels_no_overlap_automated; labels_gap = a_from.labels_gap; time_labels = a_from.time_labels; time_format = a_from.time_format; time_offset = a_from.time_offset; time_offset_is_GMT = a_from.time_offset_is_GMT; m_line_style = a_from.m_line_style; m_ticks_style = a_from.m_ticks_style; m_labels_style = a_from.m_labels_style; m_mag_style = a_from.m_mag_style; m_title_style = a_from.m_title_style; return *this; } public: sg::line_style& line_style() {return m_line_style;} sg::line_style& ticks_style() {return m_ticks_style;} text_style& labels_style() {return m_labels_style;} text_style& title_style() {return m_title_style;} text_style& mag_style() {return m_mag_style;} void set_color(const colorf& a_color){ m_line_style.color = a_color; m_ticks_style.color = a_color; m_labels_style.color = a_color; m_title_style.color = a_color; m_mag_style.color = a_color; } public: void update_sg(std::ostream& a_out) { if(width<=0) { m_line_sep.clear(); m_ticks_sep.clear(); m_labels_sep.clear(); m_mag_sep.clear(); m_title_sep.clear(); return; } // line scene graph : m_line_sep.clear(); if(m_line_style.visible) { rgba* mat = new rgba(); mat->color = m_line_style.color; m_line_sep.add(mat); draw_style* ds = new draw_style; ds->style = draw_lines; ds->line_pattern = m_line_style.pattern; ds->line_width = m_line_style.width; m_line_sep.add(ds); vertices* vtxs = new vertices; vtxs->mode = gl::line_strip(); vtxs->add(0,0,0); vtxs->add(width,0,0); m_line_sep.add(vtxs); } // ticks scene graph : if(modeling==tick_modeling_none()) { } else if(modeling==tick_modeling_hplot()) { compute_ticks_HPLOT(a_out); } else { compute_ticks_hippo(); } m_ticks_sep.clear(); if(m_ticks_style.visible) { vertices* vtxs = new vertices; vtxs->mode = gl::lines(); if(modeling==tick_modeling_hplot()) { size_t num = m_sub_ticks.size()/4; size_t pos = 0; for(size_t index=0;indexadd(bx,by,0); vtxs->add(ex,ey,0); } else { vtxs->add(bx,-by,0); vtxs->add(ex,-ey,0); } } } else { float yy = tick_up ? tick_length.value():-tick_length.value(); for(unsigned int index=0;indexadd(xx,0,0); vtxs->add(xx,yy,0); } } if(vtxs->number()) { rgba* mat = new rgba(); mat->color = m_ticks_style.color; m_ticks_sep.add(mat); draw_style* ds = new draw_style; ds->style = draw_lines; ds->line_pattern = m_ticks_style.pattern; ds->line_width = m_ticks_style.width; m_ticks_sep.add(ds); m_ticks_sep.add(vtxs); } else { delete vtxs; } } // labels scene graph : m_labels_sep.clear(); if(m_labels_style.visible && tick_number ) { m_labels_seps.clear(); m_labels_xs.clear(); m_labels_mtxs.clear(); rgba* mat = new rgba(); mat->color = m_labels_style.color; m_labels_sep.add(mat); float text_size = label_height*m_labels_style.scale; std::string font = m_labels_style.font.value(); if(font==font_hershey()) { draw_style* ds = new draw_style; ds->style = draw_lines; ds->line_pattern = m_labels_style.line_pattern; ds->line_width = m_labels_style.line_width; m_labels_sep.add(ds); } else { m_labels_sep.add(new normal); } vec3f X = m_labels_style.x_orientation.value(); vec3f Y = m_labels_style.y_orientation.value(); X.normalize(); Y.normalize(); vec3f Z;X.cross(Y,Z); Z.cross(X,Y); mat4f scale_rot(X.v0(),Y.v0(),Z.v0(),0, //first row X.v1(),Y.v1(),Z.v1(),0, X.v2(),Y.v2(),Z.v2(),0, 0,0,0,1); scale_rot.mul_scale(text_size,text_size,1); bool bin_center = (m_labels_style.options.value()=="center"?true:false); //gopaw. vec3f vec;float xx; {unsigned int number = tick_number; for(unsigned int index=0;indexcolor = m_mag_style.color; m_mag_sep.add(mat); char string[64]; if(magnitude>=0) snpf(string,sizeof(string),"x10+%d",magnitude.value()); else snpf(string,sizeof(string),"x10-%d",::abs(magnitude)); vec3f vec(width*1.03f,0,0); vec += m_mag_style.translation.value(); float text_size = label_height*0.8f * m_mag_style.scale; std::string font = m_mag_style.font.value(); if(font==font_hershey()) { draw_style* ds = new draw_style; ds->style = draw_lines; ds->line_pattern = m_mag_style.line_pattern; ds->line_width = m_mag_style.line_width; m_mag_sep.add(ds); } add_string(m_mag_sep, font, m_mag_style.font_modeling.value(), m_mag_style.encoding.value(), m_mag_style.smoothing, string, vec[0],vec[1],vec[2], m_mag_style.x_orientation.value(), m_mag_style.y_orientation.value(), text_size, m_mag_style.hjust, m_mag_style.vjust, m_ttf); } // title scene graph :if(update_title) { m_title_sep.clear(); if(title.value().size() && m_title_style.visible) { 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 xx = 0; //left if(title_hjust==center) { xx = width/2; } else if(title_hjust==right) { xx = width; } vec3f vec(xx,-title_to_axis,0); vec += m_title_style.translation.value(); add_string(m_title_sep, font, m_title_style.font_modeling.value(), m_title_style.encoding.value(), m_title_style.smoothing, title.value(), vec[0],vec[1],vec[2], m_title_style.x_orientation.value(), m_title_style.y_orientation.value(), text_size, m_title_style.hjust, m_title_style.vjust, m_ttf); } } public: //style void reset_style(bool a_geom = false) { //reset fields that are considered as part of the style. //////////////////////////////////////////// // we do not touch : //////////////////////////////////////////// //width //minimum_value //maximum_value //labels_enforced //tick_number //magnitude //time_labels //time_format //time_offset //time_offset_is_GMT //labels //values //coords //sub_coords //////////////////////////////////////////// divisions = 510; modeling = tick_modeling_hippo(); tick_up = true; is_log = false; title.value().clear(); labels_no_overlap_automated = true; labels_gap = 0.02f; if(a_geom) { //////////////////////////////////////////// // Take PAW default : float YSIZ = 20; //page height float YMGL = 2; //low y margin (to data frame). float YMGU = 2; //up y margin (to data frame). float VSIZ = 0.28F; //tick label character size. float YVAL = 0.4F; //y distance of x tick label to data frame. float XTIC = 0.3F; //y length of X axis ticks. float YLAB = 0.8F; //y distance of x title to data frame. float ASIZ = 0.28F; // axis title (label) character size. float hData = YSIZ-YMGL-YMGU; // To map data space to width : float to1 = width/hData; float vsiz = VSIZ * to1; //0.0175F float yval = YVAL * to1; //0.025F float xtic = XTIC * to1; //0.01875F float ylab = YLAB * to1; //0.05F float asiz = ASIZ * to1; //0.0175F //sf tick_length = xtic; label_to_axis = yval; label_height = vsiz; // The axis title is the PAW axis label. // It is right justified at the end of axis // (at end right for XY_X, at end top for XY_Y) title_to_axis = ylab; title_height = asiz; } title_hjust = right; //////////////////////////////////////////// // setup styles : m_line_style = line_style(); m_ticks_style = line_style(); m_labels_style = text_style(); m_mag_style = text_style(); m_title_style = text_style(); m_line_style.color = colorf_black(); m_ticks_style.color = colorf_black(); m_labels_style.color = colorf_black(); m_labels_style.font = font_hershey(); m_labels_style.encoding = encoding_PAW(); m_mag_style.color = colorf_black(); m_mag_style.font = font_hershey(); m_mag_style.encoding = encoding_PAW(); m_title_style.color = colorf_black(); m_title_style.font = font_hershey(); m_title_style.encoding = encoding_PAW(); } typedef std::pair style_item_t; typedef std::vector style_t; bool set_from_style(std::ostream& a_out,const style_t& a_style) { style_t::const_iterator it; for(it=a_style.begin();it!=a_style.end();++it) { const std::string& key = (*it).first; const std::string& sv = (*it).second; // not part of style : //width //minimum_value //maximum_value //labels_enforced //tick_number //magnitude //title //time_labels //time_format //time_offset //time_offset_is_GMT //labels //values //coords //sub_coords if(key=="divisions") { unsigned int v; if(!to(sv,v)) {style_failed(a_out,key,sv);return false;} divisions = v; } else if(key=="modeling") { modeling = sv; } else if(key=="is_log") { bool v; if(!to(sv,v)) {style_failed(a_out,key,sv);return false;} is_log = v; } else if(key=="tick_up") { bool v; if(!to(sv,v)) {style_failed(a_out,key,sv);return false;} tick_up = v; } else if(key=="tick_length") { float v; if(!to(sv,v)) {style_failed(a_out,key,sv);return false;} tick_length = v; } else if(key=="title") { title = sv; } else if(key=="title_to_axis") { float v; if(!to(sv,v)) {style_failed(a_out,key,sv);return false;} title_to_axis = v; } else if(key=="title_height") { float v; if(!to(sv,v)) {style_failed(a_out,key,sv);return false;} title_height = 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=="label_to_axis") { float v; if(!to(sv,v)) {style_failed(a_out,key,sv);return false;} label_to_axis = v; } else if(key=="label_height") { float v; if(!to(sv,v)) {style_failed(a_out,key,sv);return false;} label_height = v; } else if(key=="labels_no_overlap_automated") { bool v; if(!to(sv,v)) {style_failed(a_out,key,sv);return false;} labels_no_overlap_automated = v; } else if(key=="labels_gap") { float v; if(!to(sv,v)) {style_failed(a_out,key,sv);return false;} labels_gap = v; } else { a_out << "axis::set_from_style :" << " unknown key " << key << "." << std::endl; } } return true; } void set_encoding(const std::string& a_value) { labels_style().encoding = a_value; mag_style().encoding = a_value; title_style().encoding = a_value; } protected: float get_overlap(std::ostream& a_out,bool& a_overlap) { a_overlap = false; std::vector x_mins; std::vector x_maxs; {size_t index = 0; bbox_action _action(a_out); tools_vforcit(separator*,m_labels_seps,it) { _action.reset(); (*it)->bbox(_action); if(_action.end()) { float dx,dy,dz; if(_action.box().get_size(dx,dy,dz)) { if(dx>0) { x_mins.push_back(m_labels_xs[index]-dx*0.5f); x_maxs.push_back(m_labels_xs[index]+dx*0.5f); } } } index++; }} float dx_overlap = 0; {size_t number = x_mins.size(); for(size_t index=1;indexmul_scale(second_scale,second_scale,1); }} float second_overlap = get_overlap(a_out,overlap); if(overlap) { // first_overlap = a*first_scale+b // second_overlap = a*second_scale+b float a = (second_overlap-first_overlap)/(second_scale-first_scale); float b = first_overlap-a*first_scale; //float wanted_scale = -b/a; //zero overlap. float wanted_gap = width.value()*labels_gap.value(); float wanted_scale = (a==0.0f) ? 1 : (-wanted_gap-b)/a; //a==0.0f should not happen. if(wanted_scale<=0) wanted_scale = 1; // this if() should not happen. wanted_scale /= second_scale; {tools_vforcit(matrix*,m_labels_mtxs,it) { (*it)->mul_scale(wanted_scale,wanted_scale,1); }} } else { //it should not happen. tools_vforcit(matrix*,m_labels_mtxs,it) { (*it)->mul_scale(1.0f/second_scale,1.0f/second_scale,1); } } } } static void style_failed(std::ostream& a_out, const std::string& a_key, const std::string& a_value) { a_out << "axis::set_from_style :" << " failed for key " << sout(a_key) << " and value " << sout(a_value) << "." << std::endl; } protected: ////////////////////////////////////////////////////////////////////////// /// Hippodraw tick modeling ////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void compute_ticks_hippo() { // input fields : // minimum_value // maximum_value // is_log // output fields : // values // coords // sub_coords // labels (if labels_enforced is false) // tick_number float mn = minimum_value; float mx = maximum_value; bool a_is_log = is_log; if(a_is_log) { if((mn<=0) || (mx<=0) ) a_is_log = false; } float magxxx,y,yr,startTick,tickSize; float pmag; char pstr[10] = ""; char tmp[10]; unsigned int tick_num = 0; std::vector tick_values; std::vector tick_labels; // need include which does not exist on some system //NUM_FUZZ DBL_EPSILON*4 float NUM_FUZZ = 0.01f; if (mn >= mx) { if(tick_number) { tick_number.value(0); values.clear(); coords.clear(); sub_coords.clear(); labels.clear(); } if(magnitude.value()) magnitude.value(0); m_sub_ticks.clear(); return; } if (!a_is_log) { tickSize = calculate_ticks_hippo(mx-mn,magxxx); startTick = fceil( mn / tickSize) * tickSize; if (ffabs(magxxx) <= 3) pmag = 0.0; else pmag = startTick != 0.0 ? ffloor(flog10(ffabs(startTick))) : magxxx; snpf(pstr,sizeof(pstr),"%%1.%df",(int)max_of((pmag-magxxx),0.0)); y = startTick; while (y <= mx*(1.0+NUM_FUZZ)) { yr = ffloor(y/fpow(10,magxxx) + 0.5F); snpf(tmp,sizeof(tmp),pstr,yr*fpow(10,magxxx-pmag)); {float val = yr * fpow(10.0,magxxx); if((val>=mn)&&(val<=mx)) { //G.Barrand : add this test. tick_values.push_back(val); tick_labels.push_back(tmp); tick_num++; }} y += tickSize; } if (ffabs(magxxx) <= 3.0) magxxx = 0.0; } else { if (mn <= 0) { if(tick_number) { tick_number.value(0); values.clear(); coords.clear(); sub_coords.clear(); labels.clear(); } if(magnitude.value()) magnitude.value(0); m_sub_ticks.clear(); return; } int nLogTicks; float logTicks[5]; float magStep; float maghigh = fceil(flog10(mx)); float maglow = ffloor(flog10(mn)); float magrng = maghigh - maglow; if (magrng <=3) { nLogTicks = 3; logTicks[0] = 1.0; logTicks[1] = 2.0; logTicks[2] = 5.0; magStep = 1.0; } else { nLogTicks = 1; logTicks[0] = 1.0; magStep = magrng <= 7 ? 1.0F : 2.0F; } pmag = (nLogTicks == 3 && (ffabs(maglow)>3 || ffabs(maghigh)>3)) ? maglow : 0; magxxx = maglow; int i = 0; while ((y=logTicks[i]*fpow(10,magxxx)) < mx*(1+NUM_FUZZ)) { if (y >= mn) { // be careful: there is a bug in the NeXT (s)printf // routine when you do, eg. printf("%1.0g",0.01); if ((magxxx-pmag) > 4 || (magxxx-pmag) < -3) { ::strcpy(pstr,"%1.0e"); } else { snpf(pstr,sizeof(pstr), "%%1.%df",(int)((magxxx-pmag)>0?0.:-(magxxx-pmag))); } snpf(tmp,sizeof(tmp),pstr,y*fpow(10.0,-pmag)); {float val = flog10(y); if((val>=flog10(mn))&&(val<=flog10(mx))) { //G.Barrand : add this if tick_values.push_back(val); tick_labels.push_back(tmp); tick_num++; }} } i++; if (i>=nLogTicks) { i = 0; magxxx += magStep; } } mn = flog10(mn); mx = flog10(mx); } float range = mx - mn; // it is assumes that tick_values are ordered min to max. tick_number.value(tick_num); values.clear(); coords.clear(); for(unsigned int index=0;indexn) { for(size_t index=n;index linesGrid; std::vector texts; hplot::axis sbAxisHPLOT(a_out); chopt += "S"; sbAxisHPLOT.set_tick_size(tick_length/width.value()); if(time_labels.value()) { chopt += "t"; sbAxisHPLOT.set_time_format(time_format.value()); sbAxisHPLOT.set_time_offset(time_offset, time_offset_is_GMT); } // Get ticks : {double wmin = mn; double wmax = mx; int ndiv = divisions; sbAxisHPLOT.set_title(""); sbAxisHPLOT.paint(xmin,ymin,xmax,ymax, wmin,wmax,ndiv, //Modified chopt,gridlength,false, m_sub_ticks,linesGrid,texts);} if(a_is_log) { mn = flog10(mn); mx = flog10(mx); } float range = mx - mn; size_t tick_num = texts.size(); // HPLOT stores the magnitude on the last label : magnitude.value(0); if(tick_num) { int pmag; if(::sscanf(texts[tick_num-1].fString.c_str(),"x10^%d!",&pmag)==1) { magnitude.value(pmag); tick_num--; } } tick_number.value(uint32(tick_num)); values.clear(); coords.clear(); for(size_t index=0;indexn) { for(size_t index=n;index m_sub_ticks; //n*(2+2) std::vector m_labels_seps; std::vector m_labels_xs; std::vector m_labels_mtxs; }; }} #endif