/* * 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 * 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 #include #include #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::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 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 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