summaryrefslogtreecommitdiff
path: root/graphics/epix/screen_data.cc
diff options
context:
space:
mode:
Diffstat (limited to 'graphics/epix/screen_data.cc')
-rw-r--r--graphics/epix/screen_data.cc572
1 files changed, 572 insertions, 0 deletions
diff --git a/graphics/epix/screen_data.cc b/graphics/epix/screen_data.cc
new file mode 100644
index 0000000000..02eac318b5
--- /dev/null
+++ b/graphics/epix/screen_data.cc
@@ -0,0 +1,572 @@
+/*
+ * screen_data.cc -- ePiX::screen class implementation
+ *
+ * This file is part of ePiX, a C++ library for creating high-quality
+ * figures in LaTeX
+ *
+ * Version 1.2.1
+ * Last Change: September 28, 2007
+ */
+
+/*
+ * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ * Andrew D. Hwang <rot 13 nujnat at zngupf dot ubylpebff dot rqh>
+ * Department of Mathematics and Computer Science
+ * College of the Holy Cross
+ * Worcester, MA, 01610-2395, USA
+ */
+
+/*
+ * ePiX 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.
+ *
+ * ePiX 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 ePiX; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <list>
+#include <algorithm>
+#include <sstream>
+
+#include "camera.h"
+
+#include "pairs.h"
+
+#include "functions.h"
+
+#include "Color.h"
+
+#include "utils.h"
+
+#include "tile.h"
+
+#include "pen_line.h"
+#include "pen_fill.h"
+
+#include "affine.h"
+#include "mask_ellipse.h"
+#include "mask_rectangle.h"
+#include "mask_diamond.h"
+
+#include "format.h"
+
+// #include "screen_mask.h"
+#include "screen_data.h"
+
+namespace ePiX {
+
+ typedef std::list<tile*>::const_iterator Tp;
+
+ // constructor
+ screen_data::screen_data(const pair& arg1, const pair& arg2)
+ : m_bl(pair(min(arg1.x1(), arg2.x1()), min(arg1.x2(), arg2.x2()))),
+ m_tr(pair(max(arg1.x1(), arg2.x1()), max(arg1.x2(), arg2.x2()))),
+ m_mask(new mask_rectangle(m_bl, m_tr)),
+ m_border(new pen_line()),
+ m_backing(new pen_fill()),
+ m_crop(false) { }
+
+ // copy constructor
+ screen_data::screen_data(const screen_data& scr)
+ : m_bl(scr.m_bl),
+ m_tr(scr.m_tr),
+ m_mask(scr.m_mask->clone()),
+ m_border(scr.m_border->clone()),
+ m_backing(scr.m_backing->clone()),
+ m_crop(scr.m_crop)
+ {
+ for(Tp p=scr.m_tiles.begin(); p!= scr.m_tiles.end(); ++p)
+ add_tile(*p);
+ }
+
+ // copy assignment
+ screen_data& screen_data::operator= (const screen_data& scr)
+ {
+ if (this != &scr)
+ {
+ // copy scr's tiles before freeing ours
+ std::list<tile*> tmp;
+ for(Tp p=scr.m_tiles.begin(); p!= scr.m_tiles.end(); ++p)
+ add_tile(*p);
+
+ screen_mask* tmp_mask(scr.m_mask->clone());
+
+ pen_line* tmp_border(scr.m_border->clone());
+ pen_fill* tmp_backing(scr.m_backing->clone());
+
+ // okay, safe to muck with our data
+ m_bl = scr.m_bl;
+ m_tr = scr.m_tr;
+
+ delete m_mask;
+ m_mask = tmp_mask;
+
+ delete m_border;
+ m_border = tmp_border;
+
+ delete m_backing;
+ m_backing = tmp_backing;
+
+ for (Tp p=m_tiles.begin(); p!=m_tiles.end(); ++p)
+ delete *p;
+
+ swap(m_tiles, tmp);
+
+ m_crop = scr.m_crop;
+ }
+ return *this;
+ } // end of copy assignment
+
+
+ screen_data::~screen_data()
+ {
+ delete m_mask;
+ delete m_border;
+ delete m_backing;
+
+ for(Tp p=m_tiles.begin(); p!= m_tiles.end(); ++p)
+ delete *p;
+ }
+
+ screen_data* screen_data::clone() const
+ {
+ return new screen_data(*this);
+ }
+
+
+ // superimpose a layer by affine scaling
+ // map child to inset (inset defaults to m_mask)
+ screen_data& screen_data::paste(const screen_data& child,
+ const screen_mask& inset)
+ {
+ if (this != &child)
+ {
+ const double h_sc(inset.h_size()/child.h_size());
+ const double v_sc(inset.v_size()/child.v_size());
+
+ const pair tmp00(inset.bl() - (child.bl() & pair(h_sc, v_sc)));
+
+ affine af(tmp00 + pair(h_sc, 0), tmp00 + pair(0, v_sc), tmp00);
+
+ // backing
+ if (!child.m_backing->is_empty())
+ {
+ // child is const, so must copy tile
+ pen_fill* temp(child.m_backing->clone());
+ add_tile(temp->map_by(af));
+ }
+
+ // tiles
+ for(Tp p=child.m_tiles.begin(); p!= child.m_tiles.end(); ++p)
+ {
+ tile* temp((*p)->clone());
+ add_tile(temp->map_by(af));
+ }
+
+ // border
+ if (!child.m_border->is_empty())
+ {
+ pen_line* temp(child.m_border->clone());
+ add_tile(temp->map_by(af));
+ }
+ }
+
+ return *this;
+ } // end of paste(child, inset)
+
+
+ screen_data& screen_data::paste(const screen_data& child)
+ {
+ if (this != &child)
+ {
+ const double h_sc(h_size()/child.h_size());
+ const double v_sc(v_size()/child.v_size());
+
+ const pair tmp00(bl() - (child.bl() & pair(h_sc, v_sc)));
+
+ affine af(tmp00 + pair(h_sc, 0), tmp00 + pair(0, v_sc), tmp00);
+
+ // backing
+ if (!child.m_backing->is_empty())
+ {
+ // child is const, so must copy tile
+ pen_fill* temp(child.m_backing->clone());
+
+ add_tile(temp->map_by(af));
+ }
+
+ // tiles
+ for(Tp p=child.m_tiles.begin(); p!= child.m_tiles.end(); ++p)
+ {
+ tile* temp((*p)->clone());
+ add_tile(temp->map_by(af));
+ }
+
+ // border
+ if (!child.m_border->is_empty())
+ {
+ pen_line* temp(child.m_border->clone());
+ add_tile(temp->map_by(af));
+ }
+ }
+
+ return *this;
+ }
+
+ screen_data& screen_data::clear()
+ {
+ delete m_border;
+ m_border = new pen_line();
+
+ m_tiles.clear();
+
+ delete m_backing;
+ m_backing = new pen_fill();
+
+ m_crop = false;
+ return *this;
+ }
+
+ screen_data& screen_data::crop_to(const screen_mask& mask)
+ {
+ std::list<tile*> visibles;
+
+ if (!m_border->is_empty())
+ m_border->crop_to(mask);
+
+ if (!m_backing->is_empty())
+ m_backing->crop_to(mask);
+
+ for (Tp curr=m_tiles.begin(); curr!=m_tiles.end(); ++curr)
+ {
+ (*curr)->crop_to(mask);
+
+ if (!(*curr)->is_empty())
+ visibles.push_back(*curr);
+ }
+
+ swap(m_tiles, visibles);
+ return *this;
+ }
+
+ screen_data& screen_data::crop()
+ {
+ return crop_to(*m_mask);
+ }
+
+
+ screen_data& screen_data::set_mask(const screen_mask& mask)
+ {
+ delete m_mask;
+ m_mask = mask.clone();
+
+ return *this;
+ }
+
+ screen_data& screen_data::set_crop(bool arg)
+ {
+ m_crop = arg;
+ return *this;
+ }
+
+ screen_data screen_data::extract(const pair& arg1, const pair& arg2) const
+ {
+ screen_data value(arg1, arg2);
+ value.set_crop(true);
+
+ for (Tp curr=m_tiles.begin(); curr!=m_tiles.end(); ++curr)
+ value.add_tile(*curr);
+
+ return value;
+ }
+
+ screen_data screen_data::extract_diamond(const pair& arg1,
+ const pair& arg2) const
+ {
+ screen_data value(arg1, arg2);
+
+ value.set_mask(mask_diamond(arg1, arg2)).set_crop(true);
+
+ for (Tp curr=m_tiles.begin(); curr!=m_tiles.end(); ++curr)
+ value.add_tile(*curr);
+
+ return value;
+ }
+
+ screen_data screen_data::extract_ellipse(const pair& arg1,
+ const pair& arg2) const
+ {
+ screen_data value(arg1, arg2);
+
+ value.set_mask(mask_ellipse(arg1, arg2)).set_crop(true);
+
+ for (Tp curr=m_tiles.begin(); curr!=m_tiles.end(); ++curr)
+ value.add_tile(*curr);
+
+ return value;
+ }
+
+
+ screen_data& screen_data::border(const Color& col, const std::string& len)
+ {
+ delete m_border;
+ m_border = new pen_line(m_mask->border(cam()(col), len));
+ m_crop = true;
+
+ return *this;
+ }
+
+
+ screen_data& screen_data::backing(const Color& col)
+ {
+ delete m_backing;
+ m_backing = new pen_fill(m_mask->backing(cam()(col)));
+ m_crop = true;
+
+ return *this;
+ }
+
+
+ screen_data& screen_data::border()
+ {
+ delete m_border;
+ m_border = new pen_line(m_mask->border());
+ m_crop = true;
+
+ return *this;
+ }
+
+
+ screen_data& screen_data::backing()
+ {
+ delete m_backing;
+ m_backing = new pen_fill(m_mask->backing());
+ m_crop = true;
+
+ return *this;
+ }
+
+ // screen cropping done in these two functions
+ void screen_data::add_tile(const tile& T)
+ {
+ tile* tmp(T.clone());
+ if (m_crop)
+ tmp->crop_to(*m_mask);
+
+ if (!tmp->is_empty())
+ m_tiles.push_back(tmp);
+ }
+
+ void screen_data::add_tile(tile* Tp)
+ {
+ tile* tmp(Tp->clone());
+ if (m_crop)
+ tmp->crop_to(*m_mask);
+
+ if (!tmp->is_empty())
+ m_tiles.push_back(tmp);
+ }
+
+
+ // affine operations on contents (not border, backing)
+ void screen_data::apply(const affine& af)
+ {
+ for (Tp curr=m_tiles.begin(); curr!=m_tiles.end(); ++curr)
+ (*curr)->map_by(af);
+ }
+
+ void screen_data::shift(const pair& arg)
+ {
+ affine af;
+ af.shift(arg);
+ apply(af);
+ }
+
+ // rotate by theta about ctr
+ void screen_data::rotate(double theta, const pair& ctr)
+ {
+ affine af;
+ af.rotate(theta, ctr);
+ apply(af);
+ }
+
+ // reflect in angle-theta line through ctr
+ void screen_data::reflect(double theta, const pair& ctr)
+ {
+ affine af;
+ af.reflect(theta, ctr);
+ apply(af);
+ }
+
+ // scale coord direction(s) fixing ctr
+ void screen_data::h_scale(double sc, const pair& ctr)
+ {
+ affine af;
+ af.h_scale(sc, ctr);
+ apply(af);
+ }
+
+ void screen_data::v_scale(double sc, const pair& ctr)
+ {
+ affine af;
+ af.v_scale(sc, ctr);
+ apply(af);
+ }
+
+ void screen_data::scale(double sc, const pair& ctr)
+ {
+ affine af;
+ af.scale(sc, ctr);
+ apply(af);
+ }
+
+ // shear, fixing ctr, e.g. h_shear(sc) : (x,y) -> (x+sc*y, y)
+ void screen_data::h_shear(double sc, const pair& ctr)
+ {
+ affine af;
+ af.h_shear(sc, ctr);
+ apply(af);
+ }
+
+ void screen_data::v_shear(double sc, const pair& ctr)
+ {
+ affine af;
+ af.v_shear(sc, ctr);
+ apply(af);
+ }
+
+
+ pair screen_data::tr() const
+ {
+ return m_tr;
+ }
+
+ pair screen_data::tl() const
+ {
+ return pair(m_bl.x1(), m_tr.x2());
+ }
+
+ pair screen_data::bl() const
+ {
+ return m_bl;
+ }
+
+ pair screen_data::br() const
+ {
+ return pair(m_tr.x1(), m_bl.x2());
+ }
+
+
+ pair screen_data::t() const
+ {
+ return pair(0.5*(m_bl.x1() + m_tr.x1()), m_tr.x2());
+ }
+
+ pair screen_data::b() const
+ {
+ return pair(0.5*(m_bl.x1() + m_tr.x1()), m_bl.x2());
+ }
+
+ pair screen_data::l() const
+ {
+ return pair(m_bl.x1(), 0.5*(m_bl.x2() + m_tr.x2()));
+ }
+
+ pair screen_data::r() const
+ {
+ return pair(m_tr.x1(), 0.5*(m_bl.x2() + m_tr.x2()));
+ }
+
+ pair screen_data::c() const
+ {
+ return pair(0.5*(m_bl.x1() + m_tr.x1()), 0.5*(m_bl.x2() + m_tr.x2()));
+ }
+
+
+ double screen_data::h_min() const
+ {
+ return m_bl.x1();
+ }
+
+ double screen_data::h_max() const
+ {
+ return m_tr.x1();
+ }
+
+ double screen_data::h_size() const
+ {
+ return m_tr.x1() - m_bl.x1();
+ }
+
+ double screen_data::h_avg() const
+ {
+ return 0.5*(m_bl.x1() + m_tr.x1());
+ }
+
+
+ double screen_data::v_min() const
+ {
+ return m_bl.x2();
+ }
+
+ double screen_data::v_max() const
+ {
+ return m_tr.x2();
+ }
+
+ double screen_data::v_size() const
+ {
+ return m_tr.x2() - m_bl.x2();
+ }
+
+ double screen_data::v_avg() const
+ {
+ return 0.5*(m_bl.x2() + m_tr.x2());
+ }
+
+ std::string screen_data::print_to(const format& fmt, const length& len,
+ bool wrap) const
+ {
+ std::ostringstream obuf;
+
+ if (wrap)
+ {
+ obuf << fmt.start_picture(tr()-bl(), bl());
+ fmt.reset_state(); // ensures drawing attribs set properly below
+ }
+
+ if (!m_backing->is_empty())
+ {
+ m_backing->add_to_pallet();
+
+ obuf << m_backing->print_to(fmt, len.units());
+ }
+
+ for (Tp curr = m_tiles.begin(); curr != m_tiles.end(); ++curr)
+ {
+ (*curr)->add_to_pallet();
+
+ obuf << (*curr)->print_to(fmt, len.units());
+ }
+
+ if (!m_border->is_empty())
+ {
+ m_border->add_to_pallet();
+
+ obuf << m_border->print_to(fmt, len.units());
+ }
+
+ if (wrap)
+ obuf << fmt.end_picture();
+
+ return obuf.str();
+ } // end of print_to()
+
+} // end of namespace