1 /*
2  * eepic.cc -- ePiX's eepic output format
3  *
4  * This file is part of ePiX, a C++ library for creating high-quality
5  * figures in LaTeX
6  *
7  * Version 1.2.0-2
8  * Last Change: September 26, 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 #include <cmath>
35 #include <list>
36 
37 #include <string>
38 #include <sstream>
39 
40 #include <set> // for palette
41 
42 #include "constants.h"
43 
44 #include "functions.h"
45 
46 #include "pairs.h"
47 #include "edge_data.h"
48 
49 #include "Color.h"
50 
51 #include "path_style.h"
52 #include "pen_data.h"
53 
54 #include "hatching.h"
55 
56 #include "format.h"
57 #include "eepic.h"
58 
59 namespace ePiX {
60 
61   // rotate successive hatches this much to avoid parallelity
62   const double d_hatch_theta(111.24612); // ~90*(sqrt(5)-1)
63 
eepic()64   eepic::eepic()
65     : m_ink(Black()), m_nib(PLAIN_WIDTH), m_hatch(0) { }
66 
clone() const67   eepic* eepic::clone() const
68   {
69     return new eepic(*this);
70   }
71 
72   // Filled region with specified Cartesian edges, offset, and color
print_fill(const std::list<edge2d> & edges,const pair & offset,const Color & fc,const pen_data & line,const std::string & len) const73   std::string eepic::print_fill(const std::list<edge2d>& edges,
74 				const pair& offset,
75 				const Color& fc,
76 				const pen_data& line,
77 				const std::string& len) const
78   {
79     std::stringstream obuf;
80 
81     // set angle
82     const double hatch_angle(m_hatch);
83     m_hatch += d_hatch_theta;
84 
85     // draw hatch lines separated by pen.width(), actual line width
86     // scaled by density
87     double dens(fc.alpha()); // transparency
88     if (dens < EPIX_EPSILON)
89       return "";
90 
91     // else
92     length hatch_width(length(PLAIN_WIDTH).to(len));
93 
94     path_state style; // solid
95 
96     if (EPIX_EPSILON < dens*hatch_width.magnitude())
97       {
98 	// Use fill color, draw thin lines to simulate transparency.
99 	// Area covered by double-hatching is (supposed to be) dens.
100 	pen_data fill_pen(fc, (1-sqrt(1-dens))*hatch_width);
101 
102 	// draw hatch-filled edges
103 	hatch_data bd1(hatch_angle, hatch_width.magnitude(), edges);
104 	for (unsigned int i=0; i < bd1.data().size(); ++i)
105 	  obuf << format::print_line(bd1.data().at(i), offset,
106 				     fill_pen, style, std::string(""), len);
107 
108 	// re-draw hatch lines at right angles...
109 	hatch_data bd2(hatch_angle+90, hatch_width.magnitude(), edges);
110 	for (unsigned int i=0; i < bd2.data().size(); ++i)
111 	  obuf << format::print_line(bd2.data().at(i), offset,
112 				     fill_pen, style, "", len);
113       }
114 
115     obuf << set_pen_state(line);
116     obuf << print_paths(edges, offset, "", len);
117 
118     return obuf.str();
119   } // end of eepic::print_fill()
120 
121 
122   // may assume line is visible
print_line(const std::list<edge2d> & edges,const pair & offset,const pen_data & line,const pen_data & base,const path_state & style,const std::string & len) const123   std::string eepic::print_line(const std::list<edge2d>& edges,
124 				const pair& offset,
125 				const pen_data& line,
126 				const pen_data& base,
127 				const path_state& style,
128 				const std::string& len) const
129   {
130     std::string value;
131 
132     // draw *solid* base first if necessary
133     if (line.width() < base.width() && !base.color().is_unset())
134       value += format::print_line(edges, offset, base, path_state(), "", len);
135 
136     return value += format::print_line(edges, offset, line, style, "", len);
137   }
138 
139 
print_color(const std::string & model,const std::string & name,double d1,double d2,double d3) const140   std::string eepic::print_color(const std::string& model,
141 				 const std::string& name,
142 				 double d1, double d2, double d3) const
143   {
144     return format::xdefinecolor(model, name, d1, d2, d3);
145   }
146 
print_color(const std::string & model,const std::string & name,double d1,double d2,double d3,double d4) const147   std::string eepic::print_color(const std::string& model,
148 				 const std::string& name,
149 				 double d1, double d2,
150 				 double d3, double d4) const
151   {
152     return format::xdefinecolor(model, name, d1, d2, d3, d4);
153   }
154 
155   // one-line comment
print_comment(const std::string & msg) const156   std::string eepic::print_comment(const std::string& msg) const
157   {
158     std::stringstream obuf;
159     obuf << "%% " << msg << std::endl;
160 
161     return obuf.str();
162   }
163 
164   // verbatim string, newline protected
print_verbatim(const std::string & msg) const165   std::string eepic::print_verbatim(const std::string& msg) const
166   {
167     std::stringstream obuf;
168     obuf << msg << "%" << std::endl;
169 
170     return obuf.str();
171   }
172 
reset_state() const173   void eepic::reset_state() const
174   {
175     m_ink = Neutral();
176     m_nib = length(0);
177   }
178 
179 
180   //// private member functions ////
start_picture(const pair & sz,const pair & offset) const181   std::string eepic::start_picture(const pair& sz, const pair& offset) const
182   {
183     std::stringstream obuf;
184     obuf << "\\begin{picture}"
185 	 << format::print(sz) << format::print(-offset) << "%" << std::endl;
186 
187     return obuf.str();
188   }
189 
end_picture() const190   std::string eepic::end_picture() const
191   {
192     std::stringstream obuf;
193     obuf << "\\end{picture}%" << std::endl;
194     return obuf.str();
195   }
196 
set_unitlength(const std::string & len) const197   std::string eepic::set_unitlength(const std::string& len) const
198   {
199     std::stringstream obuf;
200 
201     obuf << "\\setlength{\\unitlength}{1" << len << "}%" << std::endl;
202 
203     return obuf.str();
204   }
205 
206 
usepackages() const207   std::string eepic::usepackages() const
208   {
209     return "usepackages epic,eepic,xcolor";
210   }
211 
212   // string argument for passing attributes local to this path/loop
start_open_path(const std::string & attribs) const213   std::string eepic::start_open_path(const std::string& attribs) const
214   {
215     return "\\path";
216   }
217 
end_open_path(const std::string & attribs) const218   std::string eepic::end_open_path(const std::string& attribs) const
219   {
220     std::stringstream obuf;
221     obuf << std::endl;
222     return obuf.str();
223   }
224 
start_closed_path(const std::string & attribs) const225   std::string eepic::start_closed_path(const std::string& attribs) const
226   {
227     return "\\path";
228   }
229 
end_closed_path(const std::string & attribs) const230   std::string eepic::end_closed_path(const std::string& attribs) const
231   {
232     std::stringstream obuf;
233     obuf << std::endl;
234     return obuf.str();
235   }
236 
set_fill_state(const Color & col) const237   std::string eepic::set_fill_state(const Color& col) const // unused
238   {
239     std::stringstream obuf;
240 
241     if (m_ink != col)
242       {
243 	m_ink = col;
244 	obuf << "\\color{" << m_ink.name() << "}%" << std::endl;
245       }
246 
247     return obuf.str();
248   }
249 
set_pen_state(const pen_data & pen) const250   std::string eepic::set_pen_state(const pen_data& pen) const
251   {
252     std::stringstream obuf;
253 
254     if (m_nib != pen.width())
255       {
256 	m_nib = pen.width();
257 	obuf << "\\allinethickness{" << m_nib.name() << "}%" << std::endl;
258       }
259 
260     if (m_ink != pen.color())
261       {
262 	m_ink = pen.color();
263 	obuf << "\\color{" << m_ink.name() << "}%" << std::endl;
264       }
265 
266     return obuf.str();
267   }
268 
269   // place a LaTeX box of width zero (containing string) at location (pair)
put_box(const pair & loc,const std::string & msg) const270   std::string eepic::put_box(const pair& loc, const std::string& msg) const
271   {
272     std::stringstream obuf;
273     obuf << "\\put" << print(loc) << "{" << msg << "}" << std::endl;
274 
275     return obuf.str();
276   }
277 
print_circle_marker(const pair & here,double diam,bool fill,const Color & color,const std::string & len) const278   std::string eepic::print_circle_marker(const pair& here, double diam,
279 					 bool fill, const Color& color,
280 					 const std::string& len) const
281   {
282     std::stringstream obuf;
283     obuf << "\\put" << print(here)
284 	 << "{\\color{" << print(color) << "}$";
285 
286     if (fill)
287       obuf << "\\allinethickness{" << 0.5*diam << len << "}"
288 	   << "\\circle{" << 0.5*diam << "}";
289 
290     else
291       obuf << "\\circle{" << diam << "}";
292 
293     obuf << "$}%" << std::endl;
294 
295     return obuf.str();
296   }
297 } // end of namespace
298