Files
geant4/source/externals/g4tools/include/tools/sg/text_hershey
T
2025-12-05 08:54:02 +01:00

641 lines
16 KiB
Plaintext

// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_sg_text_hershey
#define tools_sg_text_hershey
#include "base_text"
#include "enums"
#include "strings"
#include "render_action"
#include "pick_action"
#include "bbox_action"
#include "gstos"
#include "sf_string"
#include "../hershey"
#include "../lina/box_3f"
#include "../mnmx"
namespace tools {
namespace sg {
class hchar {
public:
hchar()
:m_char(0)
,m_font(sg::latin)
,m_y_move(none)
,m_back(false)
,m_bar(false)
,m_cr(false)
{
}
virtual ~hchar(){
}
public:
hchar(const hchar& aFrom)
:m_char(aFrom.m_char)
,m_font(aFrom.m_font)
,m_y_move(aFrom.m_y_move)
,m_back(aFrom.m_back)
,m_bar(aFrom.m_bar)
,m_cr(aFrom.m_cr)
{
}
hchar& operator=(const hchar& aFrom) {
m_char = aFrom.m_char;
m_font = aFrom.m_font;
m_y_move = aFrom.m_y_move;
m_back = aFrom.m_back;
m_bar = aFrom.m_bar;
m_cr = aFrom.m_cr;
return *this;
}
public:
enum e_move {
none,
up,
down
};
public:
char m_char;
font_type m_font;
e_move m_y_move;
bool m_back;
bool m_bar;
bool m_cr;
};
class text_hershey : public base_text, public gstos {
public:
TOOLS_NODE(text_hershey,tools::sg::text_hershey,base_text)
public:
sf_string encoding;
sf_enum<font_type> font;
public:
virtual const desc_fields& node_desc_fields() const {
TOOLS_FIELD_DESC_NODE_CLASS(tools::sg::text_hershey)
static const desc_fields s_v(parent::node_desc_fields(),2, //WARNING : take care of count.
TOOLS_ARG_FIELD_DESC(encoding),
TOOLS_ARG_FIELD_DESC(font)
);
return s_v;
}
private:
void add_fields(){
add_field(&encoding);
add_field(&font);
}
protected: //gstos
virtual unsigned int create_gsto(std::ostream&,sg::render_manager& a_mgr) {
std::vector<float> gsto_data;
{size_t npts = m_segs.size()/2; //2 coords
size_t ngsto = npts*3; //3 coords.
size_t sz = gsto_data.size();
gsto_data.resize(sz+ngsto);
float* pxyz = gsto_data.data()+sz;
const float* data = m_segs.data();
gl::cvt_2to3(npts,data,pxyz);}
m_gsto_sz = gsto_data.size();
if(gsto_data.empty()) return 0;
return a_mgr.create_gsto_from_data(gsto_data);
}
public:
virtual void render(render_action& a_action) {
if(touched()) {
update_sg();
reset_touched();
}
const state& state = a_action.state();
if(state.m_use_gsto) {
unsigned int _id = get_gsto_id(a_action.out(),a_action.render_manager());
if(_id) {
a_action.begin_gsto(_id);
a_action.draw_gsto_v(gl::lines(),m_gsto_sz/3,0);
a_action.end_gsto();
return;
} else { //!_id
// use immediate rendering.
}
} else {
clean_gstos(&a_action.render_manager());
}
// immediate rendering :
a_action.draw_vertex_array_xy(gl::lines(),m_segs);
}
virtual void pick(pick_action& a_action) {
if(touched()) {
update_sg();
reset_touched();
}
a_action.add__lines_xy(*this,m_segs,true);
}
virtual void bbox(bbox_action& a_action) {
if(touched()) {
update_sg();
reset_touched();
}
float x,y;
std::vector<float>::const_iterator it;
for(it=m_segs.begin();it!=m_segs.end();) {
x = *it;it++;
y = *it;it++;
a_action.add_one_point(x,y,0);
}
}
public:
text_hershey()
:parent()
,encoding(encoding_none())
,font(sg::latin)
,m_gsto_sz(0)
{
add_fields();
}
virtual ~text_hershey(){}
public:
text_hershey(const text_hershey& a_from)
:parent(a_from)
,gstos(a_from)
,encoding(a_from.encoding)
,font(a_from.font)
,m_gsto_sz(0)
{
add_fields();
}
text_hershey& operator=(const text_hershey& a_from){
parent::operator=(a_from);
gstos::operator=(a_from);
encoding = a_from.encoding;
font = a_from.font;
return *this;
}
public: //sg::base_text :
virtual void get_bounds(float a_height,
float& a_mn_x,float& a_mn_y,float& a_mn_z,
float& a_mx_x,float& a_mx_y,float& a_mx_z) const {
get_bounds(a_height,encoding.value(),font.value(),
strings.values(),
a_mn_x,a_mn_y,a_mn_z,
a_mx_x,a_mx_y,a_mx_z);
}
virtual float ascent(float a_height) const {
// '/' seems to be the char with the max ascent.
// NOTE : If 'A', the ascent = height.value().
float mn_x,mn_y,mn_z;
float mx_x,mx_y,mx_z;
get_char_bound('/',sg::latin,a_height,false,
mn_x,mn_y,mn_z,
mx_x,mx_y,mx_z);
return mx_y;
}
virtual float y_advance(float a_height) const {
float HEIGHT = a_height;
return 2 * HEIGHT; //Y_ADVANCE
}
public:
virtual float descent(float a_height) const {return _descent(a_height);}
virtual bool truncate(const std::string& a_string,float a_height,float a_cut_width,std::string& a_out) const {
return _truncate(a_string,a_height,font.value(),a_cut_width,a_out);
}
public:
static void get_bounds(float a_height,
const std::string& a_encoding,
font_type a_font,
const std::vector<std::string>& a_ss,
float& a_mn_x,float& a_mn_y,float& a_mn_z,
float& a_mx_x,float& a_mx_y,float& a_mx_z){
if(a_ss.size()) {
float HEIGHT = a_height;
float Y_ADVANCE = 2 * HEIGHT;
float width = 0;
float Y = 0;
std::vector<float> dummy;
tools_vforcit(std::string,a_ss,it) {
float XL = 0;
string_segs(false,*it,a_height,a_encoding,a_font,XL,Y,dummy,false);
Y -= Y_ADVANCE;
width = max_of<float>(width,XL);
}
a_mn_x = 0;
a_mn_y = -Y_ADVANCE*(a_ss.size()-1)-_descent(a_height);
a_mn_z = 0;
a_mx_x = width;
a_mx_y = HEIGHT;
a_mx_z = 0;
} else {
box_3f_make_empty(a_mn_x,a_mn_y,a_mn_z,a_mx_x,a_mx_y,a_mx_z);
}
}
static void get_bounds(float a_height,
const std::string& a_encoding,
font_type a_font,
const std::string& a_s,
float& a_mn_x,float& a_mn_y,float& a_mn_z,
float& a_mx_x,float& a_mx_y,float& a_mx_z){
float HEIGHT = a_height;
float Y_ADVANCE = 2 * HEIGHT;
float width = 0;
float Y = 0;
std::vector<float> dummy;
float XL = 0;
string_segs(false,a_s,a_height,a_encoding,a_font,XL,Y,dummy,false);
Y -= Y_ADVANCE;
width = max_of<float>(width,XL);
a_mn_x = 0;
a_mn_y = -_descent(a_height);
a_mn_z = 0;
a_mx_x = width;
a_mx_y = HEIGHT;
a_mx_z = 0;
}
protected:
void update_sg() {
clean_gstos();
m_segs.clear();
get_segments(m_segs);
}
void get_segments(std::vector<float>& a_segs) const {
float Y = 0;
if( (vjust.value()==sg::middle) ||
(vjust.value()==sg::top) ){
float mn_x,mn_y,mn_z;
float mx_x,mx_y,mx_z;
get_bounds(height.value(),mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
float szy = mx_y - mn_y;
if(vjust.value()==sg::middle) {
Y -= 0.5F * szy;
} else if(vjust.value()==sg::top) {
Y -= szy;
}
}
float HEIGHT = height.value();
float Y_ADVANCE = 2 * HEIGHT;
const std::string& encod = encoding.value();
const std::vector<std::string>& ss = strings.values();
tools_vforcit(std::string,ss,it) {
float X = 0;
if( (hjust.value()==sg::center) ||
(hjust.value()==sg::right) ){
float mn_x,mn_y,mn_z;
float mx_x,mx_y,mx_z;
get_bounds(height,encoding.value(),font,*it,
mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
float szx = mx_x - mn_x;
if(hjust.value()==sg::center) {
X -= 0.5F * szx;
} else if(hjust.value()==sg::right) {
X -= szx;
}
}
string_segs(true,*it,HEIGHT,encod,font.value(),X,Y,a_segs,true);
Y -= Y_ADVANCE;
}
}
protected:
static float _descent(float a_height) {
// '/' seems to be the char with the max descent.
float mn_x,mn_y,mn_z;
float mx_x,mx_y,mx_z;
get_char_bound('/',sg::latin,a_height,false,
mn_x,mn_y,mn_z,
mx_x,mx_y,mx_z);
return -mn_y; //return then a positive number.
}
static bool _truncate(const std::string& a_string,
float a_height,
font_type a_font,float a_cut_width,
std::string& a_out) {
//It does not take into account encoding.
a_out.clear();
float width = 0;
const unsigned int mx_poly = 4;
const unsigned int mx_point = 160;
int max_point[mx_poly];
float xp[mx_point];
float yp[mx_point];
for(auto it = a_string.cbegin(); it != a_string.cend(); ++it) {
float cwidth;
int number;
if (a_font==sg::greek) {
hershey::greek_char_points(*it,a_height,number,max_point,xp,yp,cwidth);
} else if (a_font==sg::special) {
hershey::special_char_points(*it,a_height,number,max_point,xp,yp,cwidth);
} else {
hershey::latin_char_points(*it,a_height,number,max_point,xp,yp,cwidth);
}
float advance = cwidth + a_height * 0.01F;
if((width+cwidth)>=a_cut_width) return true;
a_out += *it;
width += advance;
}
return true;
}
static void get_char_bound(char a_char,
font_type a_font,
float a_scale,bool a_bar,
float& a_mn_x,float& a_mn_y,float& a_mn_z,
float& a_mx_x,float& a_mx_y,float& a_mx_z){
box_3f_make_empty(a_mn_x,a_mn_y,a_mn_z,a_mx_x,a_mx_y,a_mx_z);
const unsigned int mx_poly = 4;
const unsigned int mx_point = 160;
int max_point[mx_poly];
float xp[mx_point];
float yp[mx_point];
int number;
float width;
if (a_font==sg::greek) {
hershey::greek_char_points(a_char,a_scale,number,max_point,xp,yp,width);
} else if (a_font==sg::special) {
hershey::special_char_points(a_char,a_scale,number,max_point,xp,yp,width);
} else {
hershey::latin_char_points(a_char,a_scale,number,max_point,xp,yp,width);
}
float ymax = 0;
int ipoint = 0;
for (int ipoly=0;ipoly<number;ipoly++) {
int pointn = max_point[ipoly];
if(pointn>0) {
for(int count=0;count<pointn-1;count++) {
ymax = max_of<float>(ymax,yp[ipoint]);
box_3f_extend_by(a_mn_x,a_mn_y,a_mn_z,a_mx_x,a_mx_y,a_mx_z,xp[ipoint],yp[ipoint],0);
ymax = max_of<float>(ymax,yp[ipoint+1]);
box_3f_extend_by(a_mn_x,a_mn_y,a_mn_z,a_mx_x,a_mx_y,a_mx_z,xp[ipoint+1],yp[ipoint+1],0);
ipoint ++;
}
ipoint ++;
}
}
if(a_bar) { //Draw a bar on top of the character.
float xbar = 0;
float ybar = ymax * 1.3F;
box_3f_extend_by(a_mn_x,a_mn_y,a_mn_z,a_mx_x,a_mx_y,a_mx_z,xbar,ybar,0);
box_3f_extend_by(a_mn_x,a_mn_y,a_mn_z,a_mx_x,a_mx_y,a_mx_z,xbar+width,ybar,0);
}
}
static void string_segs(
bool aGEN_POINTS // false = advance only.
,const std::string& a_string
,float a_height
,const std::string& a_encoding
,font_type a_font
,float& aX
,float& aY
,std::vector<float>& a_segs
,bool a_fill_segs
){
float oldX = 0;
float HEIGHT = a_height;
bool encod_PAW = (a_encoding==encoding_PAW()?true:false);
sencoded sed;
if(encod_PAW) decode_PAW(a_string,sed);
else decode_plain(a_string,sed);
tools_vforcit(hchar,sed,it) {
const hchar& hc = *it;
font_type hershey_font = hc.m_font;
if(encod_PAW) {
hershey_font = hc.m_font;
} else {
hershey_font = a_font;
}
float scale = HEIGHT;
float ymove = 0;
if(hc.m_y_move==hchar::up) {
scale = HEIGHT*0.6F;
ymove = HEIGHT*0.6F;
} else if(hc.m_y_move==hchar::down) {
scale = HEIGHT*0.6F;
ymove = -HEIGHT*0.6F;
}
if(hc.m_back) aX = oldX;
oldX = aX;
//FIXME : bar
aY += ymove;
float advance = char_segs(aGEN_POINTS,hc.m_char,hershey_font,scale,hc.m_bar,aX,aY,a_segs,a_fill_segs) + HEIGHT * 0.01F;
aX += advance;
aY -= ymove;
}
}
static float char_segs(
bool aGEN_POINTS // false = advance only.
,char a_char
,font_type a_font
,float a_scale
,bool aBar
,float aX
,float aY
,std::vector<float>& a_segs
,bool a_fill_segs
){
const unsigned int mx_poly = 8;
const unsigned int mx_point = 160;
int max_point[mx_poly];
float xp[mx_point];
float yp[mx_point];
int number;
float width;
if (a_font==sg::greek) {
hershey::greek_char_points(a_char,a_scale,number,max_point,xp,yp,width);
} else if (a_font==sg::special) {
hershey::special_char_points(a_char,a_scale,number,max_point,xp,yp,width);
} else {
hershey::latin_char_points(a_char,a_scale,number,max_point,xp,yp,width);
}
if(!aGEN_POINTS) return width;
float ymax = 0;
int ipoint = 0;
int pointn;
for (int ipoly=0;ipoly<number;ipoly++) {
pointn = max_point[ipoly];
if(pointn>0) {
for(int count=0;count<pointn-1;count++) {
ymax = max_of<float>(ymax,yp[ipoint]);
if(a_fill_segs) {
a_segs.push_back(aX+xp[ipoint]);
a_segs.push_back(aY+yp[ipoint]);
}
ymax = max_of<float>(ymax,yp[ipoint+1]);
if(a_fill_segs) {
a_segs.push_back(aX+xp[ipoint+1]);
a_segs.push_back(aY+yp[ipoint+1]);
}
ipoint ++;
}
ipoint ++;
}
}
if(aBar) { //Draw a bar on top of the character.
float xbar = 0;
float ybar = ymax * 1.3F;
if(a_fill_segs) {
a_segs.push_back(aX+xbar);
a_segs.push_back(aY+ybar);
a_segs.push_back(aX+xbar+width);
a_segs.push_back(aY+ybar);
}
}
return width;
}
typedef std::vector<hchar> sencoded;
static void decode_plain(const std::string& a_s,sencoded& a_sed){
a_sed.clear();
for(auto it = a_s.cbegin(); it != a_s.cend(); ++it) {
hchar hc;
hc.m_char = *it;
a_sed.push_back(hc);
}
if(a_sed.size()) a_sed[a_sed.size()-1].m_cr = true;
}
///////////////////////////////////////////////////////////////////////////
/// PAW encoding //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// PAW control characters :
// [ go to greek (roman = default)
// ] end of greek
// " go to special
// # end of special
// ! go to normal level of script
// ^ go to superscript
// ? go to subscript
// & backscpace one charachter
// < go to lower case
// > go to upper case (default)
// Extension :
// | draw a bar over one character
// Found in PAW manual Version 1.14 (July 1992), page 178, 180.
///////////////////////////////////////////////////////////////////////////
static void decode_PAW(const std::string& a_s,sencoded& a_sed){
a_sed.clear();
font_type hershey_font = sg::latin;
hchar::e_move move = hchar::none;
bool back = false;
bool bar = false;
//bool upper = true; //to be done.
for(auto it = a_s.cbegin(); it != a_s.cend(); ++it) {
char c = *it;
// Control characters :
if(c=='[') {
hershey_font = sg::greek;
continue;
} else if(c==']') {
hershey_font = sg::latin;
continue;
} else if(c=='"') {
hershey_font = sg::special;
continue;
} else if(c=='#') {
hershey_font = sg::latin;
continue;
} else if(c=='!') {
move = hchar::none;
continue;
} else if(c=='^') {
move = hchar::up;
continue;
} else if(c=='?') {
move = hchar::down;
continue;
} else if(c=='&') {
back = true;
continue;
} else if(c=='<') {
//upper = false;
continue;
} else if(c=='>') {
//upper = true;
continue;
}
hchar hc;
hc.m_y_move = move;
hc.m_back = back;
hc.m_bar = bar;
hc.m_font = hershey_font;
hc.m_char = c;
a_sed.push_back(hc);
back = false;
bar = false;
}
if(a_sed.size()) a_sed[a_sed.size()-1].m_cr = true;
}
protected:
std::vector<float> m_segs; //list of [begin,end]
size_t m_gsto_sz;
};
}}
#endif