/* * markers.cc -- ePiX axes, grids, markers, and labels * * This file is part of ePiX, a C++ library for creating high-quality * figures in LaTeX * * Version 1.1.19 * Last Change: September 17, 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 "constants.h" #include "triples.h" #include "length.h" #include "functions.h" #include "path.h" #include "curves.h" #include "screen.h" #include "picture.h" #include "label_data.h" #include "markers.h" namespace ePiX { static void __epix_label(const P& base, const P& offset, const std::string& lbl, epix_label_posn POSN, bool masked) { label_data val(base, offset, lbl); if (masked) { // get mask color Color my_mask(the_label_style().mask_color()); if (my_mask.is_unset()) my_mask = White(); val.mask_color(my_mask); } else // !masked val.mask_color(Neutral()); val.align_to(POSN).draw(); } // label -- put POSN-aligned string // at Cartesian position translated by true points. void label(const P& base, const P& offset, const std::string& lbl, epix_label_posn POSN) { __epix_label(base, offset, lbl, POSN, the_label_style().is_masked()); } // mask color comes from global style, falls back to White() void masklabel(const P& base, const P& offset, const std::string& lbl, epix_label_posn POSN) { __epix_label(base, offset, lbl, POSN, true); } void label(const P& base, const P& offset, const std::string& lbl) { __epix_label(base, offset, lbl, none, the_label_style().is_masked()); } void masklabel(const P& base, const P& offset, const std::string& lbl) { __epix_label(base, offset, lbl, none, true); } // centered labels void label(const P& base, const std::string& lbl) { __epix_label(base, P(0,0), lbl, c, the_label_style().is_masked()); } void masklabel(const P& base, const std::string& lbl) { __epix_label(base, P(0,0), lbl, c, true); } // Marker aliases void marker(const P& arg, epix_mark_type TYPE) { label_data(arg, TYPE).draw(); } // Markers with labels void circ(const P& posn, const P& offset, const std::string& label_text, epix_label_posn POSN) { if (label_text != "") label(posn, offset, label_text, POSN); label_data mk(posn, CIRC); mk.draw(); } void ring(const P& posn, const P& offset, const std::string& label_text, epix_label_posn POSN) { if (label_text != "") label(posn, offset, label_text, POSN); label_data mk(posn, RING); mk.draw(); } void spot(const P& posn, const P& offset, const std::string& label_text, epix_label_posn POSN) { if (label_text != "") label(posn, offset, label_text, POSN); label_data mk(posn, SPOT); mk.draw(); } void dot(const P& posn, const P& offset, const std::string& label_text, epix_label_posn POSN) { if (label_text != "") label(posn, offset, label_text, POSN); label_data mk(posn, DOT); mk.draw(); } void ddot(const P& posn, const P& offset, const std::string& label_text, epix_label_posn POSN) { if (label_text != "") label(posn, offset, label_text, POSN); label_data mk(posn, DDOT); mk.draw(); } void box(const P& posn, const P& offset, const std::string& label_text, epix_label_posn POSN) { if (label_text != "") label(posn, offset, label_text, POSN); label_data mk(posn, BOX); mk.draw(); } void bbox(const P& posn, const P& offset, const std::string& label_text, epix_label_posn POSN) { if (label_text != "") label(posn, offset, label_text, POSN); label_data mk(posn, BBOX); mk.draw(); } // Axis ticks (h_tick = tall, thin rectangle, for a *horizontal* axis) void h_axis_tick(const P& arg, epix_label_posn POSN) { label_data mk(arg, HTICK, POSN); mk.draw(); } void v_axis_tick(const P& arg, epix_label_posn POSN) { label_data mk(arg, VTICK, POSN); mk.draw(); } //// Curve-like elements // arrow with label void arrow(const P& tail, const P& head, const P& offset, const std::string& label_text, epix_label_posn POSN, double scale) { arrow(tail, head, scale); label(tail, offset, label_text, POSN); } // fixed-size elements void right_angle(const P& loc, P leg1, P leg2, double scale) { const double norm1(norm(leg1)); const double norm2(norm(leg2)); if (norm1 < EPIX_EPSILON || norm2 < EPIX_EPSILON) return; //else const double mult(pt_to_screen(scale)); leg1 *= mult/norm1; leg2 *= mult/norm2; path bd; bd.pt(loc + leg1).pt(loc + leg1 + leg2).pt(loc + leg2); bd.draw(); } // the *acute* angle void arc_measure(const P& loc, P leg1, P leg2, const P& offset, const std::string& text, epix_label_posn align, double scale) { const double norm1(norm(leg1)); const double norm2(norm(leg2)); if (norm1 < EPIX_EPSILON || norm2 < EPIX_EPSILON) return; //else normalize leg1 *= 1.0/norm1; leg2 *= 1.0/norm2; // check for parllelity P perp(leg1*leg2); const double norm3(norm(perp)); if (norm3 < EPIX_EPSILON) return; // else get small angle const double th(Acos(leg1|leg2)); perp *= 1.0/norm3; leg1 *= pt_to_screen(scale); perp *= leg1; // perp to leg1 in plane of legs ellipse(loc, leg1, perp, 0, th); if (text != "") label(loc + Cos(0.5*th)*leg1 + Sin(0.5*th)*perp, offset, text, align); } void arc_measure(const P& loc, P leg1, P leg2, double scale) { arc_measure(loc, leg1, leg2, P(0,0), "", none, scale); } void axis_break(const P& tail, const P& head, double scale) { const P midpt(0.5*(head+tail)); P dir((head-tail)%E_3); // project to (x1,x2)-plane if (norm(dir) < EPIX_EPSILON) return; // else dir *= pt_to_screen(0.25*scale)/norm(dir); // zag is scale pt long path bd; bd.pt(tail).pt(midpt-2*dir).pt(midpt-dir+1.5*J(dir)) .pt(midpt+dir-1.5*J(dir)).pt(midpt+2*dir).pt(head); bd.draw(); } void h_error_bar(const P& loc, double err, epix_mark_type mk, double ht) { const P dy(0, pt_to_screen(0.5*ht)); const P bot(loc - P(err,0)); const P top(loc + P(err,0)); line(bot, top); line(bot - dy, bot + dy); line(top - dy, top + dy); marker(loc, mk); } void v_error_bar(const P& loc, double err, epix_mark_type mk, double wd) { const P dx(pt_to_screen(0.5*wd), 0); const P bot(loc - P(0,err)); const P top(loc + P(0,err)); line(bot, top); line(bot - dx, bot + dx); line(top - dx, top + dx); marker(loc, mk); } } // end of namespace