klayout/src/db/dbHershey.h

315 lines
7.8 KiB
C++

/*
KLayout Layout Viewer
Copyright (C) 2006-2017 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef HDR_dbHershey
#define HDR_dbHershey
#include "dbEdge.h"
#include "dbBox.h"
#include "dbHersheyFont.h"
#include "dbCommon.h"
#include <vector>
namespace db {
struct HersheyFont;
DB_PUBLIC int hershey_font_width (unsigned int f);
DB_PUBLIC int hershey_font_height (unsigned int f);
DB_PUBLIC db::DBox hershey_text_box (const std::string &s, unsigned int f);
DB_PUBLIC void hershey_justify (const std::string &s, unsigned int f, db::DBox bx, HAlign halign, VAlign valign, std::vector<db::DPoint> &linestarts);
DB_PUBLIC std::vector<std::string> hershey_font_names ();
DB_PUBLIC size_t hershey_count_edges (const std::string &s, unsigned int f);
class DB_PUBLIC basic_hershey_edge_iterator
{
public:
basic_hershey_edge_iterator (const std::string &s, unsigned int f, const std::vector<db::DPoint> &line_starts);
bool at_end () const;
db::DEdge get ();
void inc ();
private:
bool m_new_char;
unsigned int m_line;
std::string m_string;
unsigned int m_edge, m_edge_end;
unsigned int m_index, m_end;
std::vector<db::DPoint> m_linestarts;
db::DPoint m_pos;
db::DVector m_delta;
HersheyFont *m_fp;
};
template <class C>
class DB_PUBLIC hershey_edge_iterator
: private basic_hershey_edge_iterator
{
public:
typedef C coord_type;
typedef db::coord_traits<C> coord_traits;
/**
* @brief Standard constructor of the hershey edge iterator
*/
hershey_edge_iterator (const std::string &s, unsigned int f, const std::vector<db::DPoint> &line_starts, double scale)
: basic_hershey_edge_iterator (s, f, line_starts),
m_scale (scale)
{
// .. nothing yet.
}
/**
* @brief Test if there are more edges
*
* @return true, if there are more edges to deliver
*/
bool
at_end () const
{
return basic_hershey_edge_iterator::at_end ();
}
/**
* @brief Deliver the current edge
*
* @return The current edge
*/
edge<C> operator* ()
{
db::DEdge e = basic_hershey_edge_iterator::get ();
return edge<C> (point<C> (coord_traits::rounded (e.p1 ().x () * m_scale), coord_traits::rounded (e.p1 ().y () * m_scale)),
point<C> (coord_traits::rounded (e.p2 ().x () * m_scale), coord_traits::rounded (e.p2 ().y () * m_scale)));
}
/**
* @brief Increment operator
*
* Increment the iterator. Must not be called, if at_end() is true.
*/
hershey_edge_iterator &
operator++ ()
{
basic_hershey_edge_iterator::inc ();
return *this;
}
private:
double m_scale;
};
/**
* @brief A hershey text class
*/
template <class C>
struct DB_PUBLIC hershey
{
typedef C coord_type;
typedef db::coord_traits<C> coord_traits;
typedef hershey_edge_iterator<C> edge_iterator;
/**
* @brief Default constructor
*
* Creates a text object with an empty text
*/
hershey ()
: m_string (),
m_font (DefaultFont),
m_scale (1.0)
{
// .. nothing yet ..
}
/**
* @brief Standard constructor
*
* @param s The text
*/
hershey (const std::string &s, Font f)
: m_string (s),
m_font (f),
m_scale (1.0)
{
// .. nothing yet ..
}
/**
* @brief Scale the text
*
* @param s The scaling factor
*/
void scale (double s)
{
m_scale *= s;
}
/**
* @brief Obtain the current scaling factor
*/
double scale_factor () const
{
return m_scale;
}
/**
* @brief Obtain the size of the text
*
* @return The bounding box of the text with the scaling applied
*/
box<C> bbox () const
{
db::DBox b = hershey_text_box (m_string, m_font);
db::point<C> p1 (coord_traits::rounded (b.p1 ().x () / m_scale), coord_traits::rounded (b.p1 ().y () / m_scale));
db::point<C> p2 (coord_traits::rounded (b.p2 ().x () / m_scale), coord_traits::rounded (b.p2 ().y () / m_scale));
return box<C> (p1, p2);
}
/**
* @brief Position the text at the given point
*
* @param p The lower left point of the first characters
*/
void position (const point<C> &p)
{
m_linestarts.clear ();
m_linestarts.push_back (db::DPoint (coord_traits::rounded (p.x () / m_scale), coord_traits::rounded (p.y () / m_scale)));
}
/**
* @brief Justify the text within a given bbox
*
* @param b The target box
* @param halign The horizontal alignment mode
* @param valign The vertical alignment mode
* @param scale true, if the text should be scaled to fit into the box
* @param margin The amount of margin to leave around the text when scale = true and the box is a "real" box
*
* If the target box is degenerated (width or height is 0) it specifies the
* height or width of the "M" character instead of the whole text.
*/
void justify (const box<C> &b, HAlign halign, VAlign valign, bool scale = true, double margin = 0.1)
{
m_linestarts.clear ();
if (m_string.size () > 0) {
if (! scale) {
db::DPoint p1 (b.p1 ().x () / m_scale, b.p1 ().y () / m_scale);
db::DPoint p2 (b.p2 ().x () / m_scale, b.p2 ().y () / m_scale);
hershey_justify (m_string, m_font, db::DBox (p1, p2), halign, valign, m_linestarts);
} else {
if (b.width () > 0 && b.height () > 0) {
db::DBox tbx (hershey_text_box (m_string, m_font));
double fx = double (b.width ()) / double (tbx.width ());
double fy = double (b.height ()) / double (tbx.height ());
double f = std::min (fx, fy);
m_scale = f * (1.0 - 2.0 * margin);
} else if (b.width () > 0) {
m_scale = double (b.width ()) / double (hershey_font_width (m_font));
} else if (b.height () > 0) {
m_scale = double (b.height ()) / double (hershey_font_height (m_font));
}
if (m_scale > 1e-6) {
db::DPoint p1 (b.p1 ().x () / m_scale, b.p1 ().y () / m_scale);
db::DPoint p2 (b.p2 ().x () / m_scale, b.p2 ().y () / m_scale);
hershey_justify (m_string, m_font, db::DBox (p1, p2), halign, valign, m_linestarts);
}
}
}
}
/**
* @brief Count edges required
*
* @return The number of edges required to display this string
*/
size_t count_edges () const
{
return hershey_count_edges (m_string, m_font);
}
/**
* @brief Edge iterator
*
* @return The edge iterator delivering all edges of the text in the
* text object
*/
hershey_edge_iterator<C> begin_edges () const
{
return hershey_edge_iterator<C> (m_string, (unsigned int) m_font, m_linestarts, m_scale);
}
/**
* @brief Get font names
*
* The font names are provided as a vector in the order they are
* defined in the enum Font. This means, the index can be cast to
* the enum rendering the font enum.
*
* @return a vector with the font names.
*/
static std::vector<std::string> font_names ()
{
return hershey_font_names ();
}
private:
std::string m_string;
Font m_font;
double m_scale;
std::vector <db::DPoint> m_linestarts;
};
/**
* @brief Standard typedef for db::Coord
*/
typedef db::hershey<db::Coord> Hershey;
/**
* @brief Standard typedef for db::DCoord
*/
typedef db::hershey<db::DCoord> DHershey;
}
#endif