Source code: jpicedt/format/pstricks/PstricksFormatter.java
1 /* jPicEdt version 1.3.2, a picture editor for LaTeX.
2 Copyright (C) 1999-2002 Sylvain Reynal
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 Sylvain Reynal
19 Département de Physique
20 Ecole Nationale Supérieure de l'Electronique et de ses Applications (ENSEA)
21 6, avenue du Ponceau
22 95014 CERGY CEDEX
23 FRANCE
24
25 Tel : 00 +33 130 736 245
26 Fax : 00 +33 130 736 667
27 e-mail : reynal@ensea.fr
28 jPicEdt web page : http://www.jpicedt.org/
29 */
30
31 package jpicedt.format.pstricks;
32
33 import jpicedt.graphic.io.formatter.*;
34 import jpicedt.graphic.*;
35 import jpicedt.graphic.model.*;
36
37 import java.awt.*;
38 import java.awt.geom.*;
39 import java.util.*;
40
41 /**
42 * FormatterFactory that produces formatters for the Pstricks macro package.
43 * @author $Author: reynal $
44 * @version $Id: PstricksFormatter.java,v 1.2 2002/08/05 16:44:10 reynal Exp $
45 */
46 public class PstricksFormatter implements FormatterFactory, PicObjectConstants, PstricksConstants {
47
48 protected static String fileWrapperProlog = DEFAULT_FILE_WRAPPER_PROLOG;
49 protected static String fileWrapperEpilog = DEFAULT_FILE_WRAPPER_EPILOG;
50
51 /**
52 * @return a Formatter able to format the given Element in the PsTricks format
53 */
54 public Formatter createFormatter(Element e){
55 if (e instanceof PicBezierQuad) return new PicBezierCubicFormatter(new PicBezierCubic((PicBezierQuad)e),this);
56 if (e instanceof PicBezierCubic) return new PicBezierCubicFormatter((PicBezierCubic)e,this);
57 if (e instanceof PicEllipse) return new PicEllipseFormatter((PicEllipse)e,this);
58 if (e instanceof PicPolygon) return new PicPolygonFormatter((PicPolygon)e,this);
59 if (e instanceof PicRectangle) return new PicRectangleFormatter((PicRectangle)e,this);
60 if (e instanceof PicText) return new PicTextFormatter((PicText)e,this);
61 if (e instanceof PicGroup) return new PicGroupFormatter((PicGroup)e,this);
62 return null;
63 }
64
65 /**
66 * Configure static fields using the given Properties object
67 * @param properties used to read shared parameters
68 * If null, default values are used.
69 */
70 public static void configure(Properties preferences){
71 fileWrapperProlog = preferences.getProperty(KEY_FILE_WRAPPER_PROLOG,DEFAULT_FILE_WRAPPER_PROLOG);
72 fileWrapperEpilog = preferences.getProperty(KEY_FILE_WRAPPER_EPILOG,DEFAULT_FILE_WRAPPER_EPILOG);
73 }
74
75 /**
76 * @return a Formatter able to format the given Drawing in the PsTricks format ;
77 * this may reliy on calls to <code>createFormatter(Element e)</code> on the elements
78 * of the drawing, plus creating auxiliary
79 * @param outputConstraint constraint used by the factory to create a specific Formatter on-the-fly
80 */
81 public Formatter createFormatter(Drawing d, Object outputConstraint){
82 return new DrawingFormatter(d,outputConstraint);
83 }
84
85 ////////////////////////////////////////////////////////////////////
86 //// Toolkit
87 ////////////////////////////////////////////////////////////////////
88
89 /**
90 * @return PsTricks's "standard" parameter string for the given Element :
91 * - linewidth=xxx, linecolor=xxxx, doubleline=true/false and rel.
92 * - if dash non-nul : linestyle=dashed, dash=xx yy
93 * - if object if filled : fillstyle=solid, fillcolor=xxxx + possibly shadow and hatch parameter
94 * leading and trailing bracket must be added by the caller ! (this allows the caller to add its own set of parameters
95 * <p>
96 * Not supported yet : "border" and "bordercolor"
97 */
98 public ParameterString createParameterString(Element obj){
99
100 PicAttributeSet attributes = obj.getAttributeSet();
101
102 StringBuffer paramBuf = new StringBuffer(100);
103 StringBuffer userDefinedColorBuffer=null; // no user-defined colour by default
104
105 // linewidth
106 paramBuf.append("linewidth=");
107 paramBuf.append(PEToolKit.doubleToString(StyleConstants.getLineWidth(attributes)));
108
109 // linecolor
110 paramBuf.append(",linecolor=");
111 Color lineColor = StyleConstants.getLineColor(attributes);
112 String lineColorName = PstricksUtilities.getPsTricksColorName(lineColor);
113 if (lineColorName != null)
114 paramBuf.append(lineColorName); // ok, this is a predefined colour
115 else { // define a new colour named "userLineColor" (it doesn't matter if it's not a unique name, provided the caller insert it just BEFORE the command that needs it)
116 float[] colourComponents = lineColor.getRGBColorComponents(null); // creates the array from scratch
117 userDefinedColorBuffer = new StringBuffer(100);
118 userDefinedColorBuffer.append("\\newrgbcolor{userLineColour}{");
119 userDefinedColorBuffer.append(PEToolKit.doubleToString(colourComponents[0]));
120 userDefinedColorBuffer.append(" ");
121 userDefinedColorBuffer.append(PEToolKit.doubleToString(colourComponents[1]));
122 userDefinedColorBuffer.append(" ");
123 userDefinedColorBuffer.append(PEToolKit.doubleToString(colourComponents[2]));
124 userDefinedColorBuffer.append("}");
125 userDefinedColorBuffer.append(CR_LF);
126 paramBuf.append("userLineColour");
127 }
128
129 // linestyle
130 if (StyleConstants.getLineStyle(attributes)==DASHED){
131 paramBuf.append(",linestyle=dashed,dash=");
132 paramBuf.append(PEToolKit.doubleToString(StyleConstants.getDashOpaque(attributes)));
133 paramBuf.append(" ");
134 paramBuf.append(PEToolKit.doubleToString(StyleConstants.getDashTransparent(attributes)));
135 }
136 else if (StyleConstants.getLineStyle(attributes)==DOTTED){
137 paramBuf.append(",linestyle=dotted,dotsep=");
138 paramBuf.append(PEToolKit.doubleToString(StyleConstants.getDotSep(attributes)));
139 }
140 else if (StyleConstants.getLineStyle(attributes)==NONE){
141 paramBuf.append(",linestyle=none");
142 }
143 // else paramBuf.append(",linestyle=solid"); default
144
145 // fill style and fill colour
146 String fillStyle = StyleConstants.getFillStyle(attributes);
147 if (fillStyle==NONE){
148 }
149 else { // solid or hatches -> add fill colour (even if it's redundant for hatches that are not "starred"=
150 paramBuf.append(",fillcolor=");
151 Color fillColor = StyleConstants.getFillColor(attributes);
152 String fillColorName = PstricksUtilities.getPsTricksColorName(fillColor);
153 if (fillColorName != null)
154 paramBuf.append(fillColorName); // ok, this is a predefined colour
155 else { // define a new colour named "userFillColor" (it doesn't matter if it's not a unique name, provided the caller insert it just BEFORE the command that needs it)
156 float[] colourComponents = fillColor.getRGBColorComponents(null); // creates the array from scratch
157 if (userDefinedColorBuffer==null) userDefinedColorBuffer = new StringBuffer(100); // there was no user-defined colour for linecolor
158 userDefinedColorBuffer.append("\\newrgbcolor{userFillColour}{");
159 userDefinedColorBuffer.append(PEToolKit.doubleToString(colourComponents[0]));
160 userDefinedColorBuffer.append(" ");
161 userDefinedColorBuffer.append(PEToolKit.doubleToString(colourComponents[1]));
162 userDefinedColorBuffer.append(" ");
163 userDefinedColorBuffer.append(PEToolKit.doubleToString(colourComponents[2]));
164 userDefinedColorBuffer.append("}");
165 userDefinedColorBuffer.append(CR_LF);
166 paramBuf.append("userFillColour");
167 }
168
169 if (fillStyle==SOLID) paramBuf.append(",fillstyle=solid");
170 else { // hatches
171 if (fillStyle==VLINES) paramBuf.append(",fillstyle=vlines");
172 else if (fillStyle==VLINES_FILLED) paramBuf.append(",fillstyle=vlines*");
173 else if (fillStyle==HLINES) paramBuf.append(",fillstyle=hlines");
174 else if (fillStyle==HLINES_FILLED) paramBuf.append(",fillstyle=vlines*");
175 else if (fillStyle==CROSSHATCH) paramBuf.append(",fillstyle=crosshatch");
176 else if (fillStyle==CROSSHATCH_FILLED) paramBuf.append(",fillstyle=crosshatch*");
177
178 paramBuf.append(",hatchwidth=");
179 paramBuf.append(PEToolKit.doubleToString(StyleConstants.getHatchWidth(attributes)));
180 paramBuf.append(",hatchsep=");
181 paramBuf.append(PEToolKit.doubleToString(StyleConstants.getHatchSep(attributes)));
182 paramBuf.append(",hatchangle=");
183 paramBuf.append(PEToolKit.doubleToString(StyleConstants.getHatchAngle(attributes)));
184 paramBuf.append(",hatchcolor=");
185 Color hatchColor = StyleConstants.getHatchColor(attributes);
186 String hatchColorName = PstricksUtilities.getPsTricksColorName(hatchColor);
187 if (hatchColorName != null)
188 paramBuf.append(hatchColorName); // ok, this is a predefined colour
189 else { // define a new colour named "userHatchColor" (it doesn't matter if it's not a unique name, provided the caller insert it just BEFORE the command that needs it)
190 float[] colourComponents = hatchColor.getRGBColorComponents(null); // creates the array from scratch
191 if (userDefinedColorBuffer==null) userDefinedColorBuffer = new StringBuffer(100); // there was no user-defined colour for linecolor or fillcolor
192 userDefinedColorBuffer.append("\\newrgbcolor{userHatchColour}{");
193 userDefinedColorBuffer.append(PEToolKit.doubleToString(colourComponents[0]));
194 userDefinedColorBuffer.append(" ");
195 userDefinedColorBuffer.append(PEToolKit.doubleToString(colourComponents[1]));
196 userDefinedColorBuffer.append(" ");
197 userDefinedColorBuffer.append(PEToolKit.doubleToString(colourComponents[2]));
198 userDefinedColorBuffer.append("}");
199 userDefinedColorBuffer.append(CR_LF);
200 paramBuf.append("userHatchColour");
201 }
202 }
203 }
204 // shadow
205 if (StyleConstants.isShadow(attributes)){
206 paramBuf.append(",shadow=true");
207 paramBuf.append(",shadowsize=");
208 paramBuf.append(PEToolKit.doubleToString(StyleConstants.getShadowSize(attributes)));
209 paramBuf.append(",shadowangle=");
210 paramBuf.append(PEToolKit.doubleToString(StyleConstants.getShadowAngle(attributes)));
211 paramBuf.append(",shadowcolor=");
212 Color shadowColor = StyleConstants.getShadowColor(attributes);
213 String shadowColorName = PstricksUtilities.getPsTricksColorName(shadowColor);
214 if (shadowColorName != null)
215 paramBuf.append(shadowColorName); // ok, this is a predefined colour
216 else { // define a new colour named "userShadowColor"
217 float[] colourComponents = shadowColor.getRGBColorComponents(null); // creates the array from scratch
218 if (userDefinedColorBuffer==null) userDefinedColorBuffer = new StringBuffer(100); // there was no user-defined colour for linecolor or fillcolor
219 userDefinedColorBuffer.append("\\newrgbcolor{userShadowColour}{");
220 userDefinedColorBuffer.append(PEToolKit.doubleToString(colourComponents[0]));
221 userDefinedColorBuffer.append(" ");
222 userDefinedColorBuffer.append(PEToolKit.doubleToString(colourComponents[1]));
223 userDefinedColorBuffer.append(" ");
224 userDefinedColorBuffer.append(PEToolKit.doubleToString(colourComponents[2]));
225 userDefinedColorBuffer.append("}");
226 userDefinedColorBuffer.append(CR_LF);
227 paramBuf.append("userShadowColour");
228 }
229 }
230
231 // double line
232 if (StyleConstants.isDoubleLine(attributes)) {
233 paramBuf.append(",doubleline=true");
234 paramBuf.append(",doublesep=");
235 paramBuf.append(PEToolKit.doubleToString(StyleConstants.getDoubleLineSep(attributes)));
236 paramBuf.append(",doublecolor=");
237 Color doubleColor = StyleConstants.getDoubleLineColor(attributes);
238 String doubleColorName = PstricksUtilities.getPsTricksColorName(doubleColor);
239 if (doubleColorName != null)
240 paramBuf.append(doubleColorName); // ok, this is a predefined colour
241 else { // define a new colour named "userDoubleColor"
242 float[] colourComponents = doubleColor.getRGBColorComponents(null);
243 if (userDefinedColorBuffer==null) userDefinedColorBuffer = new StringBuffer(100);
244 userDefinedColorBuffer.append("\\newrgbcolor{userDoubleColour}{");
245 userDefinedColorBuffer.append(PEToolKit.doubleToString(colourComponents[0]));
246 userDefinedColorBuffer.append(" ");
247 userDefinedColorBuffer.append(PEToolKit.doubleToString(colourComponents[1]));
248 userDefinedColorBuffer.append(" ");
249 userDefinedColorBuffer.append(PEToolKit.doubleToString(colourComponents[2]));
250 userDefinedColorBuffer.append("}");
251 userDefinedColorBuffer.append(CR_LF);
252 paramBuf.append("userDoubleColour");
253 }
254 }
255
256 // misc params
257 if (StyleConstants.getDimen(attributes)==INNER) paramBuf.append(",dimen=inner");
258 else if (StyleConstants.getDimen(attributes)==MIDDLE) paramBuf.append(",dimen=inner");
259 // else default
260
261 return (new ParameterString(paramBuf, userDefinedColorBuffer));
262 }
263
264 /**
265 * an inner class that represents a PsTricks parameter string (useful especially to handle User Defined Colours)
266 *
267 * the basic problem is that, if a new colour has to be defined, this has to be done through e.g. a \\newrgbcolor command
268 * BEFORE the Element command appears in the file. Hence it's necessary to return an object encapsulating
269 * several strings, not only the parameter string that appears inside the Element formated string.
270 */
271 public class ParameterString {
272
273 /* formated parameter string */
274 StringBuffer paramBuf;
275
276 /* a formated string for user-defined colour commands (aka \\newrgbcolour... each being separated by CR's)
277 * that may be used for "linecolor" or "fillcolor" for instance.
278 * if non-null, there's a user-defined colour (i.e. a colour that doesn't belong to PsTricks default colour dictionary)
279 * if null, there's no user-defined colour
280 * It's the responsability of the caller to insert this string at the appropriate location */
281 StringBuffer userDefinedColourBuf;
282
283 public ParameterString(StringBuffer paramBuf, StringBuffer userDefinedColourBuf){
284
285 this.paramBuf = paramBuf;
286 this.userDefinedColourBuf = userDefinedColourBuf;
287 }
288
289 /**
290 * @return true if there's at least one user-defined colour that need to be defined
291 */
292 public boolean isDefinedColourString(){ return (userDefinedColourBuf != null);}
293
294 /**
295 * @return the formated parameter string (w/o leading and trailing brackets)
296 */
297 public StringBuffer getParameterBuffer(){ return paramBuf;}
298
299 /**
300 * @return a string containing \\newrgbcolor... like commands, separated by CR's,
301 * or an empty stringBuffer if there's no user-defined colours.
302 */
303 public StringBuffer getUserDefinedColourBuffer(){
304 if (isDefinedColourString()) return userDefinedColourBuf;
305 else return new StringBuffer(); // empty !
306 }
307 } // inner class
308
309
310
311
312
313 ////////////////////////////////////////////////////////////////////////////////////
314 //// DRAWING
315 ////////////////////////////////////////////////////////////////////////////////////
316
317 /**
318 * "begin{pspicture}(x0,y0)(x1,y1)" (PsTricks) where
319 * (x0,y0)=lower-left corner and
320 * (x1,y1)=upper-right corner
321 */
322 public class DrawingFormatter implements Formatter {
323
324 /** the Drawing this formatter acts upon */
325 private Drawing drawing;
326 private Object outputConstraint;
327
328 /**
329 * init this formatter for the given drawing
330 * @param outputConstraint if MAKE_STANDALONE_FILE, prepend/append prolog and epilog.
331 */
332 public DrawingFormatter(Drawing drawing,Object outputConstraint){
333 this.drawing = drawing;
334 this.outputConstraint = outputConstraint;
335 }
336
337 /**
338 * @return a String representing this Drawing in the PsTricks format
339 * !!! PsTricks's default unit = 1cm !!!
340 */
341 public String format(){
342
343 StringBuffer buf = new StringBuffer(200);
344 buf.append("%Created by jPicEdt 1.x"+CR_LF+"%PsTricks format (pstricks.sty needed)"+CR_LF+"%");
345 buf.append(new Date());
346 buf.append(CR_LF);
347 if (outputConstraint == FormatterFactory.MAKE_STANDALONE_FILE) buf.append(fileWrapperProlog);
348 buf.append("\\psset{xunit=1mm,yunit=1mm,runit=1mm}"+CR_LF); // make 1mm the default unit
349
350 /* first we compute the coordinates of the "begin{pspicture}(x0,y0)(x1,y1)" command from the drawing's bounding box */
351
352 //
353 // first we compute the location of the upper-right corner of the picture,
354 // then we convert it in LaTeX coordinates
355 Rectangle2D box = drawing.getBoundingBox(); // recursively calls getBounds2D() on each Element [pending] annoying bug with PicText objects !
356 //jpicedt.Log.debug(this,"format","bbox = "+box);
357 buf.append("\\begin{pspicture}(0,0)(");
358 buf.append(PEToolKit.doubleToString(box.getMaxX()));
359 buf.append(",");
360 buf.append(PEToolKit.doubleToString(box.getMaxY()));
361 buf.append(")");
362 buf.append(CR_LF);
363
364 /* then for each Element in the Drawing, we call "toFormatedString" and append the returned String to our buffer */
365 for (Iterator it=drawing.elements(); it.hasNext(); ){
366 Element e = (Element)it.next();
367 buf.append(createFormatter(e).format());
368 }
369 // previously registered not-parsed-commands:
370 String s = drawing.getNotparsedCommands();
371 if (s != null && !s.equals("")){
372 buf.append("%Begin not parsed");
373 buf.append(CR_LF);
374 buf.append(s);
375 buf.append("%End not parsed");
376 buf.append(CR_LF);
377 }
378 //épilogue
379 buf.append("\\end{pspicture}");
380 buf.append(CR_LF);
381 if (outputConstraint == FormatterFactory.MAKE_STANDALONE_FILE) buf.append(fileWrapperEpilog);
382 return buf.toString();
383 }
384 }
385
386 }