// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef tools_sg_valop2sg #define tools_sg_valop2sg #include "bbox_action" #include "strings" #include "separator" #include "matrix" #include "vertices" #include "base_freetype" #include "mnmx" #include "../valop" #include "../smath" namespace tools { class valop2sg : public virtual valop_visitor { public: virtual bool binary(unsigned int a_type,const valop& a_1,const valop& a_2) { sg::separator* sep = new sg::separator; sg::separator* sep1 = new sg::separator; sep->add(sep1); sg::matrix* tsf1 = new sg::matrix; sep1->add(tsf1); vec3f mn1,mx1; {valop2sg v(m_out,*sep1,m_ttf); if(!v.visit(a_1)) { delete sep; return false; } mnmx(m_out,*sep1,mn1,mx1);} sg::separator* op_sep = new sg::separator; sep->add(op_sep); sg::matrix* op_tsf = new sg::matrix; op_sep->add(op_tsf); sg::separator* sep2 = new sg::separator; sep->add(sep2); sg::matrix* tsf2 = new sg::matrix; sep2->add(tsf2); vec3f mn2,mx2; {valop2sg v(m_out,*sep2,m_ttf); if(!v.visit(a_2)) { delete sep; return false; } mnmx(m_out,*sep2,mn2,mx2);} if((a_type==valop::ADD) || (a_type==valop::SUB) || (a_type==valop::MUL) || (a_type==valop::EQUAL) ){ sg::base_freetype* tft = sg::base_freetype::create(m_ttf); if(a_type==valop::ADD) unichar2sg(0x0002B,*tft); // + else if(a_type==valop::SUB) unichar2sg(0x02212,*tft); else if(a_type==valop::MUL) unichar2sg(0x02A2F,*tft); // x else if(a_type==valop::EQUAL) unichar2sg(0x0003D,*tft); // = op_sep->add(tft); vec3f omn,omx; mnmx(m_out,*tft,omn,omx); float odx = omx[0]-omn[0]; float xmargin = odx*0.1f; op_tsf->mul_translate(-omn[0]+mx1[0]+xmargin,0,0); tsf2->mul_translate(-mn2[0]+mx1[0]+xmargin+odx+xmargin,0,0); } else if( (a_type==valop::ASIDE) || (a_type==valop::NVMUL) ){ float xspace = (mx1[0]-mn1[0])*0.1f; tsf2->mul_translate(-mn2[0]+mx1[0]+xspace,0,0); } else if(a_type==valop::DIV) { // the bar : sg::vertices* vtcs = new sg::vertices; op_sep->add(vtcs); float w2 = 0.5f; float h = 0.101f; vtcs->add(-w2,0,0); vtcs->add( w2,0,0); vtcs->add( w2,h,0); vtcs->add(-w2,h,0); if(m_wf) { vtcs->mode = gl::line_strip(); vtcs->add(-w2,0,0); } else { vtcs->mode = gl::triangle_fan(); } float ymargin = h; float osx = max_of(mx1[0]-mn1[0],mx2[0]-mn2[0]); osx *= 1.1f; op_tsf->mul_scale(osx,1,1); //put a_1 symbol in the middle of the bar. //put a_1 symbol on top of the bar (with an ymargin). float dx1 = -(mn1[0]+mx1[0])*0.5f; float dy1 = -mn1[1]+h+ymargin; tsf1->mul_translate(dx1,dy1,0); //put a_2 symbol in the middle of the bar. //put a_2 symbol under the bar (with an ymargin). float dx2 = -(mn2[0]+mx2[0])*0.5f; float dy2 = -mx2[1]-ymargin; tsf2->mul_translate(dx2,dy2,0); } else if(a_type==valop::SUPS) { if(mx2[0]==mn2[0]) { delete sep; return false; } float s2 = 0.5f*(mx1[0]-mn1[0])/(mx2[0]-mn2[0]); //half a_1 horiz size. tsf2->set_scale(s2,s2,1); mnmx(m_out,*sep2,mn2,mx2); float xshift = (mx1[0]-mn1[0])*0.1f; float dx2 = -mn2[0]+mx1[0]+xshift; float yshift = (mx1[1]-mn1[1])*0.3f; float dy2 = -mn2[1]+mx1[1]-yshift; tsf2->set_translate(dx2,dy2,0); tsf2->mul_scale(s2,s2,1); //applied first } else if(a_type==valop::SUBS) { if(mx2[0]==mn2[0]) { delete sep; return false; } float s2 = 0.5f*(mx1[0]-mn1[0])/(mx2[0]-mn2[0]); //half a_1 horiz size. tsf2->set_scale(s2,s2,1); mnmx(m_out,*sep2,mn2,mx2); float xshift = (mx1[0]-mn1[0])*0.1f; float dx2 = -mn2[0]+mx1[0]+xshift; float yshift = (mx1[1]-mn1[1])*0.3f; float dy2 = -mn2[1]-yshift; tsf2->set_translate(dx2,dy2,0); tsf2->mul_scale(s2,s2,1); //applied first } else { delete sep; return false; } m_group.add(sep); return true; } virtual bool unary(unsigned int a_type,const valop& a_1) { if(a_type==valop::MINUS) { sg::separator* sep = new sg::separator; sg::separator* sep1 = new sg::separator; sep->add(sep1); sg::matrix* tsf1 = new sg::matrix; sep1->add(tsf1); vec3f mn1,mx1; {valop2sg v(m_out,*sep1,m_ttf); if(!v.visit(a_1)) { delete sep; return false; } mnmx(m_out,*sep1,mn1,mx1);} m_group.add(sep); //////////////////////////////////////////////////////// /// minus symbol /////////////////////////////////////// //////////////////////////////////////////////////////// sg::separator* op_sep = new sg::separator; sep->add(op_sep); sg::base_freetype* tft = sg::base_freetype::create(m_ttf); unichar2sg(0x0002D,*tft); op_sep->add(tft); vec3f omn,omx; mnmx(m_out,*tft,omn,omx); float odx = omx[0]-omn[0]; float xmargin = odx*0.1f; //push a_1 at right of minus symbol tsf1->mul_translate(-mn1[0]+omx[0]+xmargin,0,0); return true; } else { return false; } } virtual bool variable(unsigned int a_type,const value& a_var) { sg::base_freetype* tft = sg::base_freetype::create(m_ttf); if(a_type==valop::SYMBOL) { if(rcmp(a_var.get_string(),s_psi())) { unichar2sg(0x003C8,*tft); m_group.add(tft); return true; } else if(rcmp(a_var.get_string(),s_gamma())) { unichar2sg(0x003B3,*tft); m_group.add(tft); return true; } else if(rcmp(a_var.get_string(),s_mu())) { unichar2sg(0x003BC,*tft); m_group.add(tft); return true; } else if(rcmp(a_var.get_string(),s_upper_delta())) { unichar2sg(0x02206,*tft); m_group.add(tft); return true; } else if(rcmp(a_var.get_string(),s_partial_derivative())){ unichar2sg(0x02202,*tft); //d ronde m_group.add(tft); return true; } else if(rcmp(a_var.get_string(),s_h_bar())){ unichar2sg(0x0210F,*tft); m_group.add(tft); return true; } } else if(a_type==valop::REAL){ s2sg(value::to_string(a_var),*tft); m_group.add(tft); return true; } else if(a_type==valop::STRING){ if(a_var.type()==value::STRING){ s2sg(a_var.get_string(),*tft); m_group.add(tft); return true; } else { m_out << "valop2sg::variable :" << " expected a value::STRING." << " Got " << a_var.stype() << "." << std::endl; } } delete tft; return false; } virtual bool option(const valop& a_node) { sg::base_freetype* tft = sg::base_freetype::create(m_ttf); s2sg(a_node.m_name,*tft); m_group.add(tft); return true; } virtual bool func_1(const valop& a_f,const valop& a_1) { if(rcmp(a_f.m_function->name(),s_sqrt())) { sg::separator* sep = new sg::separator; sg::separator* sep1 = new sg::separator; sep->add(sep1); vec3f mn1,mx1; {valop2sg v(m_out,*sep1,m_ttf); if(!v.visit(a_1)) { delete sep; return false; } mnmx(m_out,*sep1,mn1,mx1);} m_group.add(sep); //////////////////////////////////////////////////////// /// sqrt symbol //////////////////////////////////////// //////////////////////////////////////////////////////// sg::separator* op_sep = new sg::separator; sep->add(op_sep); sg::matrix* op_tsf = new sg::matrix; op_sep->add(op_tsf); sg::base_freetype* tft = sg::base_freetype::create(m_ttf); unichar2sg(0x0221A,*tft); op_sep->add(tft); vec3f omn,omx; mnmx(m_out,*tft,omn,omx); // upper bar : sg::vertices* vtcs = new sg::vertices; op_sep->add(vtcs); float dx = 0.05f; //to cover the top of the sqrt symbol. float w = mx1[0]-mn1[0]; w *= 1.05f; float h = 0.09f; vtcs->add(omx[0]-dx ,omx[1]-h,0); vtcs->add(omx[0]+w ,omx[1]-h,0); vtcs->add(omx[0]+w ,omx[1] ,0); vtcs->add(omx[0]-dx ,omx[1] ,0); if(m_wf) { vtcs->mode = gl::line_strip(); vtcs->add(omx[0]-dx ,omx[1]-h,0); } else { vtcs->mode = gl::triangle_fan(); } float xmargin = 0; //push sqrt-symbol at left of a_1 //scale sqrt-symbol to match a_1 y height. //y translate sqrt-symbol so that a_1 is under the bar : float osy = (mx1[1]-mn1[1])/(omx[1]-omn[1]); float ody = -omn[1]*osy + mn1[1]; osy *= 1.2f; op_tsf->mul_translate(-omx[0]+mn1[0]-xmargin,ody,0); //second op_tsf->mul_scale(1,osy,1); //first return true; } else { // generic case : (rep of a_1) sg::separator* sep = new sg::separator; sg::separator* sep1 = new sg::separator; sep->add(sep1); vec3f mn1,mx1; {valop2sg v(m_out,*sep1,m_ttf); if(!v.visit(a_1)) { delete sep; return false; } mnmx(m_out,*sep1,mn1,mx1);} m_group.add(sep); //////////////////////////////////////////////////////// /// left func symbol : ( ///////////// //////////////////////////////////////////////////////// {sg::separator* op_sep = new sg::separator; sep->add(op_sep); sg::matrix* op_tsf = new sg::matrix; op_sep->add(op_tsf); sg::base_freetype* tft = sg::base_freetype::create(m_ttf); //TTNODE* tft = new TTNODE(); s2sg(a_f.m_function->name(),*tft); tft->unitext[0].push_back(0x00028); // ( op_sep->add(tft); vec3f omn,omx; mnmx(m_out,*tft,omn,omx); //push func-symbol at left of a_1 : float xmargin = 0; op_tsf->mul_translate(-omx[0]+mn1[0]-xmargin,0,0); } //end left op //////////////////////////////////////////////////////// /// right func symbol : ) ///////////// //////////////////////////////////////////////////////// {sg::separator* op_sep = new sg::separator; sep->add(op_sep); sg::matrix* op_tsf = new sg::matrix; op_sep->add(op_tsf); sg::base_freetype* tft = sg::base_freetype::create(m_ttf); unichar2sg(0x00029,*tft); op_sep->add(tft); vec3f omn,omx; mnmx(m_out,*tft,omn,omx); //push func-symbol at right of a_1 : float xmargin = 0; op_tsf->mul_translate(-omn[0]+mx1[0]+xmargin,0,0); } //end right op return true; } } virtual bool func_2(const valop& a_f,const valop& a_1,const valop& a_2) { if(rcmp(a_f.m_function->name(),s_pow())) { sg::separator* sep = new sg::separator; sg::separator* sep1 = new sg::separator; sep->add(sep1); sg::matrix* tsf1 = new sg::matrix; sep1->add(tsf1); vec3f mn1,mx1; {valop2sg v(m_out,*sep1,m_ttf); if(!v.visit(a_1)) { delete sep; return false; } mnmx(m_out,*sep1,mn1,mx1);} sg::separator* sep2 = new sg::separator; sep->add(sep2); sg::matrix* tsf2 = new sg::matrix; sep2->add(tsf2); vec3f mn2,mx2; {valop2sg v(m_out,*sep2,m_ttf); if(!v.visit(a_2)) { delete sep; return false; } mnmx(m_out,*sep2,mn2,mx2);} float s2 = 0.5f*(mx1[0]-mn1[0])/(mx2[0]-mn2[0]); //half a_1 horiz size. if(mx2[0]==mn2[0]) { delete sep; return false; } tsf2->set_scale(s2,s2,1); mnmx(m_out,*sep2,mn2,mx2); float xshift = (mx1[0]-mn1[0])*0.1f; float dx2 = -mn2[0]+mx1[0]+xshift; float yshift = (mx1[1]-mn1[1])*0.3f; float dy2 = -mn2[1]+mx1[1]-yshift; tsf2->set_identity(); tsf2->mul_translate(dx2,dy2,0); tsf2->mul_scale(s2,s2,1); //applied first m_group.add(sep); return true; } else { // generic case : (rep of a_1, rep of a_2) sg::separator* sep = new sg::separator; sg::separator* sep1 = new sg::separator; sep->add(sep1); vec3f mn1,mx1; {valop2sg v(m_out,*sep1,m_ttf); if(!v.visit(a_1)) { delete sep; return false; } mnmx(m_out,*sep1,mn1,mx1);} sg::separator* sep2 = new sg::separator; sep->add(sep2); sg::matrix* tsf2 = new sg::matrix; sep2->add(tsf2); vec3f mn2,mx2; {valop2sg v(m_out,*sep2,m_ttf); if(!v.visit(a_2)) { delete sep; return false; } mnmx(m_out,*sep2,mn2,mx2);} m_group.add(sep); //////////////////////////////////////////////////////// /// left func symbol : ( ///////////// //////////////////////////////////////////////////////// {sg::separator* op_sep = new sg::separator; sep->add(op_sep); sg::matrix* op_tsf = new sg::matrix; op_sep->add(op_tsf); sg::base_freetype* tft = sg::base_freetype::create(m_ttf); s2sg(a_f.m_function->name(),*tft); tft->unitext[0].push_back(0x00028); // ( op_sep->add(tft); vec3f omn,omx; mnmx(m_out,*tft,omn,omx); //push func-symbol at left of a_1 : float xmargin = 0; op_tsf->mul_translate(-omx[0]+mn1[0]-xmargin,0,0); } //end left op //////////////////////////////////////////////////////// /// , ///////////// //////////////////////////////////////////////////////// float xend2 = 0; {sg::separator* op_sep = new sg::separator; sep->add(op_sep); sg::matrix* op_tsf = new sg::matrix; op_sep->add(op_tsf); sg::base_freetype* tft = sg::base_freetype::create(m_ttf); unichar2sg(0x0002C,*tft); // , op_sep->add(tft); vec3f omn,omx; mnmx(m_out,*tft,omn,omx); //push comma-symbol at right of a_1 : float odx = omx[0]-omn[0]; float xmargin = odx*0.1f; op_tsf->mul_translate(-omn[0]+mx1[0]+xmargin,0,0); float xendcomma = mx1[0]+xmargin+(omx[0]-omn[0]); tsf2->mul_translate(-mn2[0]+xendcomma+xmargin,0,0); xend2 = xendcomma+(mx2[0]-mn2[0]); } //end comma //////////////////////////////////////////////////////// /// right func symbol : ) ///////////// //////////////////////////////////////////////////////// {sg::separator* op_sep = new sg::separator; sep->add(op_sep); sg::matrix* op_tsf = new sg::matrix; op_sep->add(op_tsf); sg::base_freetype* tft = sg::base_freetype::create(m_ttf); unichar2sg(0x00029,*tft); op_sep->add(tft); vec3f omn,omx; mnmx(m_out,*tft,omn,omx); //push ")" at right of a_2 : float xmargin = 0; op_tsf->mul_translate(-omn[0]+xend2+xmargin,0,0); } //end right op return true; } } virtual bool func_3(const valop&,const valop&,const valop&,const valop&) { return false; } virtual bool func_4(const valop&,const valop&,const valop&,const valop&,const valop&) { return false; } virtual bool func_5(const valop&,const valop&,const valop&,const valop&,const valop&,const valop&) { return false; } virtual bool func_6(const valop&,const valop&,const valop&,const valop&,const valop&,const valop&,const valop&) { return false; } public: valop2sg(std::ostream& a_out, sg::group& a_group, const sg::base_freetype& a_ttf) :m_out(a_out) ,m_group(a_group) //,m_wf(true) ,m_wf(false) ,m_ttf(a_ttf) {} virtual ~valop2sg() {} public: valop2sg(const valop2sg& a_from) :valop_visitor(a_from) ,m_out(a_from.m_out) ,m_group(a_from.m_group) ,m_wf(a_from.m_wf) ,m_ttf(a_from.m_ttf) {} valop2sg& operator=(const valop2sg& a_from){ m_wf = a_from.m_wf; return *this; } protected: typedef unsigned int unichar; unichar char2stix(char a_c) { if(a_c=='-') return 0x0002D; if(a_c=='.') return 0x0002E; if(a_c=='0') return 0x00030; if(a_c=='1') return 0x00031; if(a_c=='2') return 0x00032; if(a_c=='3') return 0x00033; if(a_c=='4') return 0x00034; if(a_c=='5') return 0x00035; if(a_c=='6') return 0x00036; if(a_c=='7') return 0x00037; if(a_c=='8') return 0x00038; if(a_c=='9') return 0x00039; if(a_c=='A') return 0x00041; if(a_c=='B') return 0x00042; if(a_c=='C') return 0x00043; if(a_c=='D') return 0x00044; if(a_c=='E') return 0x00045; if(a_c=='F') return 0x00046; if(a_c=='G') return 0x00047; if(a_c=='H') return 0x00048; if(a_c=='I') return 0x00049; if(a_c=='J') return 0x0004A; if(a_c=='K') return 0x0004B; if(a_c=='L') return 0x0004C; if(a_c=='M') return 0x0004D; if(a_c=='N') return 0x0004E; if(a_c=='O') return 0x0004F; if(a_c=='P') return 0x00050; if(a_c=='Q') return 0x00051; if(a_c=='R') return 0x00052; if(a_c=='S') return 0x00053; if(a_c=='T') return 0x00054; if(a_c=='U') return 0x00055; if(a_c=='V') return 0x00056; if(a_c=='W') return 0x00057; if(a_c=='X') return 0x00058; if(a_c=='Y') return 0x00059; if(a_c=='Z') return 0x0005A; if(a_c=='a') return 0x00061; if(a_c=='b') return 0x00062; if(a_c=='c') return 0x00063; if(a_c=='d') return 0x00064; if(a_c=='e') return 0x00065; if(a_c=='f') return 0x00066; if(a_c=='g') return 0x00067; if(a_c=='h') return 0x00068; if(a_c=='i') return 0x00069; if(a_c=='j') return 0x0006A; if(a_c=='k') return 0x0006B; if(a_c=='l') return 0x0006C; if(a_c=='m') return 0x0006D; if(a_c=='n') return 0x0006E; if(a_c=='o') return 0x0006F; if(a_c=='p') return 0x00070; if(a_c=='q') return 0x00071; if(a_c=='r') return 0x00072; if(a_c=='s') return 0x00073; if(a_c=='t') return 0x00074; if(a_c=='u') return 0x00075; if(a_c=='v') return 0x00076; if(a_c=='w') return 0x00077; if(a_c=='x') return 0x00078; if(a_c=='y') return 0x00079; if(a_c=='z') return 0x0007A; if(a_c=='_') return 0x0005F; return 0x0003F; //? } void unichar2sg(unichar a_unichar,sg::base_freetype& a_node){ if(m_wf) a_node.modeling = sg::font_outline; a_node.font = sg::font_stixgeneral_otf(); std::vector line; line.push_back(a_unichar); a_node.unitext.add(line); } void s2sg(const std::string& a_s,sg::base_freetype& a_node){ if(m_wf) a_node.modeling = sg::font_outline; //else font_filled, font_pixmap. a_node.font = sg::font_stixgeneral_otf(); std::vector line; for(auto it = a_s.cbegin(); it != a_s.cend(); ++it) line.push_back(char2stix(*it)); a_node.unitext.add(line); } protected: std::ostream& m_out; sg::group& m_group; bool m_wf; const sg::base_freetype& m_ttf; }; } #endif