1 /* 2 * markers.cc -- ePiX axes, grids, markers, and labels 3 * 4 * This file is part of ePiX, a C++ library for creating high-quality 5 * figures in LaTeX 6 * 7 * Version 1.1.19 8 * Last Change: September 17, 2007 9 */ 10 11 /* 12 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 13 * Andrew D. Hwang <rot 13 nujnat at zngupf dot ubylpebff dot rqh> 14 * Department of Mathematics and Computer Science 15 * College of the Holy Cross 16 * Worcester, MA, 01610-2395, USA 17 */ 18 19 /* 20 * ePiX is free software; you can redistribute it and/or modify it 21 * under the terms of the GNU General Public License as published by 22 * the Free Software Foundation; either version 2 of the License, or 23 * (at your option) any later version. 24 * 25 * ePiX is distributed in the hope that it will be useful, but WITHOUT 26 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 27 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 28 * License for more details. 29 * 30 * You should have received a copy of the GNU General Public License 31 * along with ePiX; if not, write to the Free Software Foundation, Inc., 32 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 33 */ 34 35 #include "constants.h" 36 37 #include "triples.h" 38 #include "length.h" 39 40 #include "functions.h" 41 42 #include "path.h" 43 #include "curves.h" 44 #include "screen.h" 45 #include "picture.h" 46 47 #include "label_data.h" 48 #include "markers.h" 49 50 namespace ePiX { 51 __epix_label(const P & base,const P & offset,const std::string & lbl,epix_label_posn POSN,bool masked)52 static void __epix_label(const P& base, const P& offset, 53 const std::string& lbl, 54 epix_label_posn POSN, bool masked) 55 { 56 label_data val(base, offset, lbl); 57 58 if (masked) 59 { 60 // get mask color 61 Color my_mask(the_label_style().mask_color()); 62 63 if (my_mask.is_unset()) 64 my_mask = White(); 65 66 val.mask_color(my_mask); 67 } 68 69 else // !masked 70 val.mask_color(Neutral()); 71 72 val.align_to(POSN).draw(); 73 } 74 75 // label -- put POSN-aligned string <label_text> 76 // at Cartesian position <base> translated by <offset> true points. label(const P & base,const P & offset,const std::string & lbl,epix_label_posn POSN)77 void label(const P& base, const P& offset, const std::string& lbl, 78 epix_label_posn POSN) 79 { 80 __epix_label(base, offset, lbl, POSN, the_label_style().is_masked()); 81 } 82 83 // mask color comes from global style, falls back to White() masklabel(const P & base,const P & offset,const std::string & lbl,epix_label_posn POSN)84 void masklabel(const P& base, const P& offset, const std::string& lbl, 85 epix_label_posn POSN) 86 { 87 __epix_label(base, offset, lbl, POSN, true); 88 } 89 label(const P & base,const P & offset,const std::string & lbl)90 void label(const P& base, const P& offset, const std::string& lbl) 91 { 92 __epix_label(base, offset, lbl, none, the_label_style().is_masked()); 93 } 94 masklabel(const P & base,const P & offset,const std::string & lbl)95 void masklabel(const P& base, const P& offset, const std::string& lbl) 96 { 97 __epix_label(base, offset, lbl, none, true); 98 } 99 100 // centered labels label(const P & base,const std::string & lbl)101 void label(const P& base, const std::string& lbl) 102 { 103 __epix_label(base, P(0,0), lbl, c, the_label_style().is_masked()); 104 } 105 masklabel(const P & base,const std::string & lbl)106 void masklabel(const P& base, const std::string& lbl) 107 { 108 __epix_label(base, P(0,0), lbl, c, true); 109 } 110 111 // Marker aliases marker(const P & arg,epix_mark_type TYPE)112 void marker(const P& arg, epix_mark_type TYPE) 113 { 114 label_data(arg, TYPE).draw(); 115 } 116 117 // Markers with labels circ(const P & posn,const P & offset,const std::string & label_text,epix_label_posn POSN)118 void circ(const P& posn, const P& offset, const std::string& label_text, 119 epix_label_posn POSN) 120 { 121 if (label_text != "") 122 label(posn, offset, label_text, POSN); 123 label_data mk(posn, CIRC); 124 mk.draw(); 125 } 126 ring(const P & posn,const P & offset,const std::string & label_text,epix_label_posn POSN)127 void ring(const P& posn, const P& offset, const std::string& label_text, 128 epix_label_posn POSN) 129 { 130 if (label_text != "") 131 label(posn, offset, label_text, POSN); 132 label_data mk(posn, RING); 133 mk.draw(); 134 } 135 spot(const P & posn,const P & offset,const std::string & label_text,epix_label_posn POSN)136 void spot(const P& posn, const P& offset, const std::string& label_text, 137 epix_label_posn POSN) 138 { 139 if (label_text != "") 140 label(posn, offset, label_text, POSN); 141 label_data mk(posn, SPOT); 142 mk.draw(); 143 } 144 dot(const P & posn,const P & offset,const std::string & label_text,epix_label_posn POSN)145 void dot(const P& posn, const P& offset, const std::string& label_text, 146 epix_label_posn POSN) 147 { 148 if (label_text != "") 149 label(posn, offset, label_text, POSN); 150 label_data mk(posn, DOT); 151 mk.draw(); 152 } 153 ddot(const P & posn,const P & offset,const std::string & label_text,epix_label_posn POSN)154 void ddot(const P& posn, const P& offset, const std::string& label_text, 155 epix_label_posn POSN) 156 { 157 if (label_text != "") 158 label(posn, offset, label_text, POSN); 159 label_data mk(posn, DDOT); 160 mk.draw(); 161 } 162 box(const P & posn,const P & offset,const std::string & label_text,epix_label_posn POSN)163 void box(const P& posn, const P& offset, const std::string& label_text, 164 epix_label_posn POSN) 165 { 166 if (label_text != "") 167 label(posn, offset, label_text, POSN); 168 label_data mk(posn, BOX); 169 mk.draw(); 170 } 171 bbox(const P & posn,const P & offset,const std::string & label_text,epix_label_posn POSN)172 void bbox(const P& posn, const P& offset, const std::string& label_text, 173 epix_label_posn POSN) 174 { 175 if (label_text != "") 176 label(posn, offset, label_text, POSN); 177 label_data mk(posn, BBOX); 178 mk.draw(); 179 } 180 181 // Axis ticks (h_tick = tall, thin rectangle, for a *horizontal* axis) h_axis_tick(const P & arg,epix_label_posn POSN)182 void h_axis_tick(const P& arg, epix_label_posn POSN) 183 { 184 label_data mk(arg, HTICK, POSN); 185 mk.draw(); 186 } 187 v_axis_tick(const P & arg,epix_label_posn POSN)188 void v_axis_tick(const P& arg, epix_label_posn POSN) 189 { 190 label_data mk(arg, VTICK, POSN); 191 mk.draw(); 192 } 193 194 195 //// Curve-like elements 196 // arrow with label arrow(const P & tail,const P & head,const P & offset,const std::string & label_text,epix_label_posn POSN,double scale)197 void arrow(const P& tail, const P& head, const P& offset, 198 const std::string& label_text, 199 epix_label_posn POSN, double scale) 200 { 201 arrow(tail, head, scale); 202 label(tail, offset, label_text, POSN); 203 } 204 205 // fixed-size elements right_angle(const P & loc,P leg1,P leg2,double scale)206 void right_angle(const P& loc, P leg1, P leg2, double scale) 207 { 208 const double norm1(norm(leg1)); 209 const double norm2(norm(leg2)); 210 211 if (norm1 < EPIX_EPSILON || norm2 < EPIX_EPSILON) 212 return; 213 214 //else 215 const double mult(pt_to_screen(scale)); 216 leg1 *= mult/norm1; 217 leg2 *= mult/norm2; 218 219 path bd; 220 bd.pt(loc + leg1).pt(loc + leg1 + leg2).pt(loc + leg2); 221 bd.draw(); 222 } 223 224 // the *acute* angle arc_measure(const P & loc,P leg1,P leg2,const P & offset,const std::string & text,epix_label_posn align,double scale)225 void arc_measure(const P& loc, P leg1, P leg2, const P& offset, 226 const std::string& text, epix_label_posn align, 227 double scale) 228 { 229 const double norm1(norm(leg1)); 230 const double norm2(norm(leg2)); 231 232 if (norm1 < EPIX_EPSILON || norm2 < EPIX_EPSILON) 233 return; 234 235 //else normalize 236 leg1 *= 1.0/norm1; 237 leg2 *= 1.0/norm2; 238 239 // check for parllelity 240 P perp(leg1*leg2); 241 const double norm3(norm(perp)); 242 243 if (norm3 < EPIX_EPSILON) 244 return; 245 246 // else get small angle 247 const double th(Acos(leg1|leg2)); 248 249 perp *= 1.0/norm3; 250 leg1 *= pt_to_screen(scale); 251 252 perp *= leg1; // perp to leg1 in plane of legs 253 254 ellipse(loc, leg1, perp, 0, th); 255 256 if (text != "") 257 label(loc + Cos(0.5*th)*leg1 + Sin(0.5*th)*perp, offset, 258 text, align); 259 } 260 arc_measure(const P & loc,P leg1,P leg2,double scale)261 void arc_measure(const P& loc, P leg1, P leg2, double scale) 262 { 263 arc_measure(loc, leg1, leg2, P(0,0), "", none, scale); 264 } 265 axis_break(const P & tail,const P & head,double scale)266 void axis_break(const P& tail, const P& head, double scale) 267 { 268 const P midpt(0.5*(head+tail)); 269 270 P dir((head-tail)%E_3); // project to (x1,x2)-plane 271 272 if (norm(dir) < EPIX_EPSILON) 273 return; 274 275 // else 276 dir *= pt_to_screen(0.25*scale)/norm(dir); // zag is scale pt long 277 278 path bd; 279 bd.pt(tail).pt(midpt-2*dir).pt(midpt-dir+1.5*J(dir)) 280 .pt(midpt+dir-1.5*J(dir)).pt(midpt+2*dir).pt(head); 281 282 bd.draw(); 283 } 284 h_error_bar(const P & loc,double err,epix_mark_type mk,double ht)285 void h_error_bar(const P& loc, double err, epix_mark_type mk, double ht) 286 { 287 const P dy(0, pt_to_screen(0.5*ht)); 288 const P bot(loc - P(err,0)); 289 const P top(loc + P(err,0)); 290 291 line(bot, top); 292 line(bot - dy, bot + dy); 293 line(top - dy, top + dy); 294 marker(loc, mk); 295 } 296 v_error_bar(const P & loc,double err,epix_mark_type mk,double wd)297 void v_error_bar(const P& loc, double err, epix_mark_type mk, double wd) 298 { 299 const P dx(pt_to_screen(0.5*wd), 0); 300 const P bot(loc - P(0,err)); 301 const P top(loc + P(0,err)); 302 303 line(bot, top); 304 line(bot - dx, bot + dx); 305 line(top - dx, top + dx); 306 marker(loc, mk); 307 } 308 } // end of namespace 309