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