1 /*
2  * tikz.cc -- ePiX::tikz 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.1.15
8  * Last Change: September 07, 2007
9  *
10  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
11  * Andrew D. Hwang <rot 13 nujnat at zngupf dot ubylpebff dot rqh>
12  * Department of Mathematics and Computer Science
13  * College of the Holy Cross
14  * Worcester, MA, 01610-2395, USA
15  *
16  *
17  * ePiX is free software; you can redistribute it and/or modify it
18  * under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 2 of the License, or
20  * (at your option) any later version.
21  *
22  * ePiX is distributed in the hope that it will be useful, but WITHOUT
23  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
25  * License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with ePiX; if not, write to the Free Software Foundation, Inc.,
29  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31 
32 #include <list>
33 
34 #include <string>
35 #include <sstream>
36 
37 #include <set>
38 
39 #include "constants.h"
40 
41 #include "utils.h"
42 
43 #include "pairs.h"
44 #include "edge_data.h"
45 
46 #include "Color.h"
47 
48 #include "path_style.h"
49 #include "pen_data.h"
50 
51 // need to get units from the_picture
52 #include "picture_data.h"
53 #include "picture.h"
54 
55 #include "format.h"
56 #include "tikz.h"
57 
58 namespace ePiX {
59 
tikz()60   tikz::tikz()
61     : m_fill(Neutral()), m_stroke(Black()), m_lwidth(PLAIN_WIDTH),
62       m_units(the_picture().the_unitlength.units()) { }
63 
64 
clone() const65   tikz* tikz::clone() const
66   {
67     return new tikz(*this);
68   }
69 
70   // 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) const71   std::string tikz::print_fill(const std::list<edge2d>& edges,
72 			       const pair& offset,
73 			       const Color& fc,
74 			       const pen_data& line,
75 			       const std::string& len) const
76   {
77     std::stringstream obuf;
78     obuf << set_fill_state(fc) << set_pen_state(line);
79 
80     // compute attribute string
81     std::stringstream attribs;
82 
83     if ( !(fc.is_unset()) )
84       {
85 	attribs << "[fill";
86 
87 	if (fc.alpha() < 1)
88 	  attribs << ",opacity=" << fc.alpha();
89 
90 	attribs << "]";
91       }
92 
93     obuf << print_paths(edges, offset, attribs.str(), len);
94 
95     return obuf.str();
96   }
97 
98   // Unfilled region, specified Cartesian edges
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) const99   std::string tikz::print_line(const std::list<edge2d>& edges,
100 			       const pair& offset,
101 			       const pen_data& line,
102 			       const pen_data& base,
103 			       const path_state& style,
104 			       const std::string& len) const
105   {
106     std::string value;
107 
108     // draw *solid* base first
109     if (line.width() < base.width() && !base.color().is_unset())
110       {
111 	std::stringstream battr;
112 	battr << "[color=" << format::print(base.color()) << ","
113 	      << "line width=" << format::print(base.width()) << "]";
114 
115 	value += format::print_line(edges, offset, base, path_state(),
116 				    battr.str(), len);
117       }
118 
119     value += set_pen_state(line);
120 
121     return value += format::print_line(edges, offset, line, style, "", len);
122   }
123 
124   // Print color declaration strings: model, name, densities
print_color(const std::string & model,const std::string & name,double d1,double d2,double d3) const125   std::string tikz::print_color(const std::string& model,
126 				const std::string& name,
127 				double d1, double d2,
128 				double d3) const
129   {
130     return format::xdefinecolor(model, name, d1, d2, d3);
131   }
132 
print_color(const std::string & model,const std::string & name,double d1,double d2,double d3,double d4) const133   std::string tikz::print_color(const std::string& model,
134 				const std::string& name,
135 				double d1, double d2,
136 				double d3, double d4) const
137   {
138     return format::xdefinecolor(model, name, d1, d2, d3, d4);
139   }
140 
141 
142   // One-line comment
print_comment(const std::string & msg) const143   std::string tikz::print_comment(const std::string& msg) const
144   {
145     std::stringstream obuf;
146     obuf << "%% " << msg << std::endl;
147 
148     return obuf.str();
149   }
150 
151   // verbatim string, newline protected
print_verbatim(const std::string & msg) const152   std::string tikz::print_verbatim(const std::string& msg) const
153   {
154     std::stringstream obuf;
155     obuf << msg << "%" << std::endl;
156 
157     return obuf.str();
158   }
159 
160 
161   // start/end a picture-like environment, set unit length
start_picture(const pair & sz,const pair & offset) const162   std::string tikz::start_picture(const pair& sz, const pair& offset) const
163   {
164     std::stringstream obuf;
165     obuf << "\\begin{tikzpicture}" << std::endl
166 	 << "\\pgfsetlinewidth{" << format::print(PLAIN_WIDTH) << "}"
167 	 << std::endl
168 	 << "\\useasboundingbox " << print(offset)
169 	 << " rectangle " << print(sz + offset) << ";"
170 	 << std::endl;
171 
172     return obuf.str();
173   }
174 
end_picture() const175   std::string tikz::end_picture() const
176   {
177     std::stringstream obuf;
178     obuf << "\\end{tikzpicture}" << std::endl;
179 
180     return obuf.str();
181   }
182 
183   // Actual work done in start_picture
set_unitlength(const std::string & len) const184   std::string tikz::set_unitlength(const std::string& len) const
185   {
186     return "";
187     /*
188     std::stringstream obuf;
189 
190     obuf << "\\setlength{\\unitlength}{1" << len << "}%" << std::endl;
191 
192     return obuf.str();
193     */
194   }
195 
196 
reset_state() const197   void tikz::reset_state() const
198   {
199     m_fill = Neutral();
200     m_stroke = Black();
201     m_lwidth = PLAIN_WIDTH;
202   }
203 
204   //// private member functions ////
path_connector() const205   std::string tikz::path_connector() const
206   {
207     return "--";
208   }
209 
210 
usepackages() const211   std::string tikz::usepackages() const
212   {
213     return "usepackages tikz";
214   }
215 
216   // string argument for passing attributes local to this path/loop
start_open_path(const std::string & attribs) const217   std::string tikz::start_open_path(const std::string& attribs) const
218   {
219     return "\\draw " + attribs;
220   }
221 
end_open_path(const std::string &) const222   std::string tikz::end_open_path(const std::string&) const
223   {
224     std::stringstream obuf;
225     obuf << ";" << std::endl;
226 
227     return obuf.str();
228   }
229 
start_closed_path(const std::string & attribs) const230   std::string tikz::start_closed_path(const std::string& attribs) const
231   {
232     return "\\draw " + attribs;
233   }
234 
end_closed_path(const std::string &) const235   std::string tikz::end_closed_path(const std::string&) const
236   {
237     std::stringstream obuf;
238     obuf <<  "--cycle;" << std::endl;
239 
240     return obuf.str();
241   }
242 
243   // print declarations to set state of output format
set_fill_state(const Color & col) const244   std::string tikz::set_fill_state(const Color& col) const
245   {
246     std::stringstream buf;
247     if (col != m_fill && !col.is_unset())
248       buf << "\\pgfsetfillcolor{" << format::print(col) << "}" << std::endl;
249 
250     m_fill = col;
251     return buf.str();
252   }
253 
set_pen_state(const pen_data & pen) const254   std::string tikz::set_pen_state(const pen_data& pen) const
255   {
256     std::stringstream buf;
257     if (pen.color() != m_stroke)
258       {
259 	buf << "\\pgfsetstrokecolor{" << format::print(pen.color()) << "}"
260 	    << std::endl;
261 
262 	m_stroke = pen.color();
263       }
264 
265     if (pen.width() != m_lwidth)
266       {
267 	buf << "\\pgfsetlinewidth{" << format::print(pen.width()) << "}"
268 	    << std::endl;
269 
270 	m_lwidth = pen.width();
271       }
272 
273     return buf.str();
274   }
275 
276   // place a LaTeX box of width zero (containing string) at location (pair)
put_box(const pair & loc,const std::string & msg) const277   std::string tikz::put_box(const pair& loc, const std::string& msg) const
278   {
279     std::stringstream obuf;
280 
281     obuf << "\\pgftext[at={\\pgfpoint{"
282 	 << truncate(loc.x1()) << m_units << "}{"
283 	 << truncate(loc.x2()) << m_units
284 	 << "}}] {" << msg << "}" << std::endl;
285 
286     return obuf.str();
287   }
288 
print_circle_marker(const pair & here,double diam,bool fill,const Color & color,const std::string & len) const289   std::string tikz::print_circle_marker(const pair& here, double diam,
290 					bool fill, const Color& color,
291 					const std::string& len) const
292   {
293     std::stringstream obuf;
294     obuf << "\\";
295 
296     if (fill)
297       obuf << "fill";
298 
299     obuf << "draw[color=" << format::print(color) << "] "
300 	 << print(here) << " circle(" << 0.5*diam << len << ");" << std::endl;
301 
302     return obuf.str();
303   }
304 
print(const pair & arg) const305   std::string tikz::print(const pair& arg) const
306   {
307     std::stringstream o;
308     o << "(" << truncate(arg.x1()) << m_units
309       << "," << truncate(arg.x2()) << m_units << ")";
310     return o.str();
311   }
312 } // end of namespace
313