1 /*
2  * pst.cc -- ePiX's pstricks 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.20
8  * Last Change: September 19, 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 <list>
35 
36 #include <string>
37 #include <sstream>
38 
39 #include <set>
40 
41 #include "constants.h"
42 
43 #include "functions.h"
44 
45 #include "pairs.h"
46 #include "edge_data.h"
47 
48 #include "Color.h"
49 
50 #include "path_style.h"
51 #include "pen_data.h"
52 
53 #include "format.h"
54 #include "pst.h"
55 
56 namespace ePiX {
57 
pst()58   pst::pst()
59     : m_fill(Neutral()), m_line(Black()), m_base(Neutral()),
60       m_lwidth(PLAIN_WIDTH), m_bwidth("0pt") { }
61 
clone() const62   pst* pst::clone() const
63   {
64     return new pst(*this);
65   }
66 
print_fill(const std::list<edge2d> & edges,const pair & offset,const Color & fc,const pen_data & line,const std::string & len) const67   std::string pst::print_fill(const std::list<edge2d>& edges,
68 			      const pair& offset,
69 			      const Color& fc,
70 			      const pen_data& line,
71 			      const std::string& len) const
72   {
73     std::stringstream obuf;
74 
75     // compute attribute string
76     std::string attribs("[fillstyle=");
77 
78     if (fc.is_unset())
79       attribs += "none";
80     else
81       attribs += "solid";
82 
83     attribs += "]";
84 
85     obuf << set_fill_state(fc) << set_pen_state(line); // side effects
86     obuf << print_paths(edges, offset, attribs, len);
87 
88     return obuf.str();
89   }
90 
91 
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) const92   std::string pst::print_line(const std::list<edge2d>& edges,
93 			      const pair& offset,
94 			      const pen_data& line,
95 			      const pen_data& base,
96 			      const path_state& style,
97 			      const std::string& len) const
98   {
99     std::stringstream value, obuf;
100 
101     obuf << set_pen_state(line);
102 
103     // update base
104     m_base = base.color();
105     m_bwidth = base.width();
106 
107     std::string attribs;
108 
109     // Generate string to pass as third argument to print_paths if need border
110     if (m_lwidth < m_bwidth && !m_base.is_unset())
111       {
112 	length tmp_b(m_bwidth), tmp_l(m_lwidth);
113 	tmp_b += (tmp_l *= -1);
114 	tmp_b *= 0.5;
115 
116 	std::stringstream bordbuf;
117 	bordbuf << "[border=" << print(tmp_b)
118 		<< ",bordercolor=" << m_base.name() << "]";
119 
120 	attribs = bordbuf.str();
121       }
122 
123     if (style.is_solid())
124       obuf << print_paths(edges, offset, attribs, len);
125 
126     else // not solid
127       {
128 	// Use base to draw solid underlayer, line to draw top layer.
129 	// Attempt to adjust PST pen alignment; m_bwidth too large.
130 	if (m_lwidth < m_bwidth && !base.color().is_unset())
131 	  obuf << set_pen_state(pen_data(base.color(),
132 					 0.5*(m_bwidth + m_lwidth)))
133 	       << print_paths(edges, offset, attribs, len);
134 
135 	obuf << format::print_line(edges, offset, line, style, "", len);
136       }
137 
138     return obuf.str();
139   }
140 
141 
print_color(const std::string & model,const std::string & name,double d1,double d2,double d3) const142   std::string pst::print_color(const std::string& model,
143 			       const std::string& name,
144 			       double d1, double d2,
145 			       double d3) const
146   {
147     // PSTricks declaration
148     std::stringstream obuf;
149     obuf << "\\new" << model;
150     if (model == "cmy")
151       obuf << "k";
152 
153     obuf << "color{" << name << "}";
154 
155     if (model == "cmy")
156       {
157 	double bk(min(min(d1,d2),d3));
158 
159 	obuf << "{"
160 	     << d1-bk << " " << d2-bk << " " << d3-bk << " " << bk
161 	     << "}%"  << std::endl;
162       }
163 
164     else
165       obuf << "{"
166 	   << d1 << " " << d2 << " " << d3
167 	   << "}%" << std::endl;
168 
169     return obuf.str();
170   }
171 
print_color(const std::string & model,const std::string & name,double d1,double d2,double d3,double d4) const172   std::string pst::print_color(const std::string& model,
173 			       const std::string& name,
174 			       double d1, double d2,
175 			       double d3, double d4) const
176   {
177     // model presumably "cmyk"
178     std::stringstream obuf;
179     obuf << "\\newcmykcolor{" << name << "}{"
180 	 << d1 << " " << d2 << " " << d3 << " " << d4 << "}%"
181 	 << std::endl;
182 
183     return obuf.str();
184   }
185 
186 
print_comment(const std::string & msg) const187   std::string pst::print_comment(const std::string& msg) const
188   {
189     std::stringstream obuf;
190     obuf << "%% " << msg << std::endl;
191 
192     return obuf.str();
193   }
194 
195   // verbatim text, %-protected newline
print_verbatim(const std::string & msg) const196   std::string pst::print_verbatim(const std::string& msg) const
197   {
198     std::stringstream obuf;
199     obuf << msg << "%" << std::endl;
200 
201     return obuf.str();
202   }
203 
reset_state() const204   void pst::reset_state() const
205   {
206     m_fill = Neutral();
207     m_line = Neutral();
208     m_base = Neutral();
209 
210     m_lwidth = length(0);
211     m_bwidth = length(0);
212   }
213 
214 
215   //// private member functions ////
start_picture(const pair & sz,const pair & offset) const216   std::string pst::start_picture(const pair& sz, const pair& offset) const
217   {
218     std::stringstream obuf;
219     obuf << "\\begin{pspicture}"
220 	 << format::print(sz) << format::print(-offset) << "%" << std::endl;
221 
222     return obuf.str();
223   }
224 
end_picture() const225   std::string pst::end_picture() const
226   {
227     std::stringstream obuf;
228     obuf << "\\end{pspicture}%" << std::endl;
229     return obuf.str();
230   }
231 
set_unitlength(const std::string & len) const232   std::string pst::set_unitlength(const std::string& len) const
233   {
234     std::stringstream obuf;
235 
236     obuf << "\\psset{unit=1" << len
237 	 << ",linewidth=" << print(length(PLAIN_WIDTH)) << "}%"
238 	 << std::endl;
239 
240     return obuf.str();
241   }
242 
243 
usepackages() const244   std::string pst::usepackages() const
245   {
246     return "usepackages pstricks";
247   }
248 
start_open_path(const std::string & attribs) const249   std::string pst::start_open_path(const std::string& attribs) const
250   {
251     return "\\psline" + attribs;
252   }
253 
end_open_path(const std::string & attribs) const254   std::string pst::end_open_path(const std::string& attribs) const
255   {
256     std::stringstream obuf;
257     obuf << std::endl;
258     return obuf.str();
259   }
260 
start_closed_path(const std::string & attribs) const261   std::string pst::start_closed_path(const std::string& attribs) const
262   {
263     return "\\pspolygon" + attribs;
264   }
265 
end_closed_path(const std::string & attribs) const266   std::string pst::end_closed_path(const std::string& attribs) const
267   {
268     std::stringstream obuf;
269     obuf << std::endl;
270     return obuf.str();
271   }
272 
set_fill_state(const Color & col) const273   std::string pst::set_fill_state(const Color& col) const
274   {
275     if (m_fill == col)
276       return "";
277 
278     // else
279     m_fill = col;
280 
281     std::stringstream obuf;
282     obuf << "\\psset{";
283 
284     // filled paths set fillstyle
285     if (m_fill.is_unset())
286       obuf << "fillstyle=none";
287 
288     else
289       obuf << "fillcolor=" << m_fill.name();
290 
291     obuf << "}%" << std::endl;
292 
293     return obuf.str();
294   }
295 
set_pen_state(const pen_data & pen) const296   std::string pst::set_pen_state(const pen_data& pen) const
297   {
298     std::stringstream obuf;
299 
300     if (pen.color().is_unset())
301       {
302 	m_lwidth=length(0);
303 	return "\\psset{linewidth=0pt}";
304       }
305 
306     // else
307     bool change_width(m_lwidth != pen.width());
308     bool change_color(m_line != pen.color());
309 
310     if (change_width || change_color)
311       {
312 	obuf << "\\psset{";
313 
314 	if (change_width)
315 	  {
316 	    m_lwidth = pen.width();
317 	    obuf << "linewidth=" << m_lwidth.name();
318 
319 	    if (change_color) // both true, need separator
320 	      obuf << ",";
321 	  }
322 
323 	if (change_color)
324 	  {
325 	    m_line = pen.color();
326 	    obuf << "linecolor=" << m_line.name();
327 	  }
328 
329 	obuf << "}%" << std::endl;
330       }
331 
332     return obuf.str();
333   }
334 
335   // place a LaTeX box of width zero (containing string) at location (pair)
put_box(const pair & loc,const std::string & msg) const336   std::string pst::put_box(const pair& loc, const std::string& msg) const
337   {
338     std::stringstream obuf;
339     obuf << "\\rput" << print(loc) << "{" << msg << "}" << std::endl;
340 
341     return obuf.str();
342   }
343 
print_circle_marker(const pair & here,double diam,bool fill,const Color & color,const std::string & len) const344   std::string pst::print_circle_marker(const pair& here, double diam,
345 				       bool fill, const Color& color,
346 				       const std::string& len) const
347   {
348     std::stringstream obuf;
349     obuf << "\\pscircle";
350 
351     if (fill)
352       obuf << "*";
353 
354     obuf << "[linecolor=" << print(color) << "]" << print(here)
355 	 << "{" << 0.5*diam << "}%" << std::endl;
356 
357     return obuf.str();
358   }
359 } // end of namespace
360