/* * pen_arrow.cc -- ePiX::pen_arrow class * * This file is part of ePiX, a C++ library for creating high-quality * figures in LaTeX * * Version 1.2.0-2 * Last Change: September 26, 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 // for arrow shaft cropping #include "pairs.h" #include "affine.h" #include "screen_mask.h" #include "length.h" #include "edge_data.h" #include "Color.h" #include "arrow_style.h" #include "label_style.h" #include "marker_style.h" // for bbox marker #include "format.h" #include "picture_data.h" #include "picture.h" #include "tile.h" #include "pen_arrow.h" namespace ePiX { pen_arrow::pen_arrow(const pair& tail, const pair& head, const pen_data& line, const pen_data& base, double scale, double sin_th, bool head_seen) : m_shaft(tail, head, true), m_line(line), m_base(base), m_scale(scale), m_shorten(sin_th), m_head_seen(head_seen), m_style(the_arrowhead_style()) { } pen_arrow* pen_arrow::clone() const { return new pen_arrow(*this); } pen_arrow& pen_arrow::map_by(const affine& f) { m_shaft = edge2d(f(m_shaft.tail()), f(m_shaft.head()), m_shaft.is_seen()); return *this; } pen_arrow& pen_arrow::crop_to(const screen_mask& M) { // update head visibility; never re-mark as visible if (M.crops(m_shaft.head())) m_head_seen = false; // screen masks are convex, so we're cropped iff an end is cropped if (M.crops(m_shaft.head()) || M.crops(m_shaft.tail())) { std::list shaft; shaft.push_back(m_shaft); M.crop_path(shaft); // search for visible segment; will find no more than one bool still_seen(false); for (std::list::const_iterator ep = shaft.begin(); ep != shaft.end(); ++ep) if ((*ep).is_seen()) { still_seen = true; m_shaft = *ep; } if (!still_seen) { m_head_seen = false; m_shaft.seen(false); } } return *this; } bool pen_arrow::is_empty() const { return !(m_head_seen && m_shaft.is_seen()) || m_line.color().is_unset(); } /* * * 1: base, 2: foot, 3: tip, 4: ear_right, 5: ear_left * 5 ... ......... ..... .........1 2.....3 ......... ..... ... 4 * <-height-> * * <--> inset (fraction of height) * */ std::string pen_arrow::print_to(const format& fmt, const std::string& len) const { if (is_empty()) return ""; // else std::stringstream obuf; if (m_shaft.tail() == m_shaft.head()) // draw a ddot { label_state my_state(the_label_style()); my_state.text_color(m_line.color()); obuf << fmt.print_mark(m_shaft.tail(), pair(0,0), DDOT, the_mark_size(), my_state, len); } else { const pair head(m_shaft.head()); const double stretch(length("1pt").to(len).magnitude()); pair dir(head - m_shaft.tail()); double dist(norm(dir)); const pair unit_dir((stretch/dist)*dir); const pair unit_perp(J(unit_dir)); const double wd(m_scale*m_style.width()); const double ht(m_style.ratio()*wd*m_shorten); const pair base(head - ht*unit_dir); const pair foot(head - (1-m_style.inset())*ht*unit_dir); const pair ear_left(base + wd*unit_perp); const pair ear_right(base - wd*unit_perp); std::list bd; bd.push_back(edge2d(foot, ear_right, true)); bd.push_back(edge2d(ear_right, head, true)); bd.push_back(edge2d(head, ear_left, true)); bd.push_back(edge2d(ear_left, foot, true)); obuf << fmt.print_fill(bd, pair(0,0), m_line.color(), m_line, len); } return obuf.str(); } void pen_arrow::add_to_pallet() const { if (!is_empty()) the_picture().add_to_pallet(m_line.color()) .add_to_pallet(m_base.color()); } } // end of namespace