1 /*
  2     Copyright 2009.2010
  3         Matthias Ehmann,
  4         Michael Gerhaeuser,
  5         Carsten Miller,
  6         Bianca Valentin,
  7         Alfred Wassermann,
  8         Peter Wilfahrt
  9 
 10     This file is part of JSXGraph.
 11 
 12     JSXGraph is free software: you can redistribute it and/or modify
 13     it under the terms of the GNU Lesser General Public License as published by
 14     the Free Software Foundation, either version 3 of the License, or
 15     (at your option) any later version.
 16 
 17     JSXGraph is distributed in the hope that it will be useful,
 18     but WITHOUT ANY WARRANTY; without even the implied warranty of
 19     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 20     GNU Lesser General Public License for more details.
 21 
 22     You should have received a copy of the GNU Lesser General Public License
 23     along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
 24 */
 25 
 26 JXG.PsTricks = {
 27 
 28     convert: function (board) {
 29         var topleft = new JXG.Coords(JXG.COORDS_BY_SCREEN, [0, 0], board),
 30             bottomright = new JXG.Coords(JXG.COORDS_BY_SCREEN, [board.canvasWidth, board.canvasHeight], board),
 31             i, el, result = [];
 32 
 33         result.push('\\begin{pspicture*}('+topleft.usrCoords[1]+','+bottomright.usrCoords[2]+')('+bottomright.usrCoords[1]+','+topleft.usrCoords[2]+')\n');
 34 
 35         for(i in board.objects) {
 36             el = board.objects[i];
 37 
 38             if (el.visProp.visible) {
 39                 switch (el.elementClass) {
 40                     case JXG.OBJECT_CLASS_CIRCLE:
 41                         result.push(this.addCircle(el));
 42                         break;
 43                     case JXG.OBJECT_CLASS_LINE:
 44                         result.push(this.addLine(el));
 45                         break;
 46                     case JXG.OBJECT_CLASS_POINT:
 47                         result.push(this.addPoint(el));
 48                         break;
 49                     default:
 50                         switch (el.type) {
 51                             case JXG.OBJECT_TYPE_ARC:
 52                                 result.push(this.addArc(el));
 53                                 break;
 54                             case JXG.OBJECT_TYPE_SECTOR:
 55                                 result.push(this.addArc(el));
 56                                 result.push(this.addSector(el));
 57                                 break;
 58                             case JXG.OBJECT_TYPE_POLYGON:
 59                                 result.push(this.addPolygon(el));
 60                                 break;
 61                             case JXG.OBJECT_TYPE_ANGLE:
 62                                 result.push(this.addAngle(el));
 63                                 break;
 64                         }
 65                         break;
 66                 }
 67             }
 68         }
 69 
 70         result.push('\\end{pspicture*}');
 71 
 72         return result.join('\n');
 73     },
 74 
 75     setArrows: function (el) {
 76         var result = '';
 77 
 78         if(el.visProp.firstarrow && el.visProp.lastarrow) {
 79             result = '{<->}';
 80         } else if (el.visProp.firstarrow) {
 81             result = '{<-}';
 82         } else if (el.visProp.lastarrow) {
 83             result = '{->}';
 84         }
 85 
 86         return result;
 87     },
 88 
 89     /**
 90      * Draws a wedge.
 91      * @param {String} color HTML/CSS color string.
 92      * @param {Number} opacity Numbe between 0 and 1.
 93      * @param {Array} midpoint x and y value of the midpoint.
 94      * @param {Number} radius
 95      * @param {Number} angle1
 96      * @param {Number} angle2
 97      */
 98     drawWedge: function (color, opacity, midpoint, radius, angle1, angle2) {
 99         var result = '';
100 
101         if(color != 'none' && opacity > 0) {
102             result += "\\pswedge[linestyle=none, fillstyle=solid, fillcolor="+this.parseColor(color)+", opacity="+opacity.toFixed(5)+"]";
103             result += "("+midpoint.join(',')+"){"+radius+"}{"+angle1+"}{"+angle2+"}\n";
104         }
105 
106         return result;
107     },
108 
109     addPoint: function (el) {
110         var result = "\\psdot[linecolor=" + this.parseColor(el.visProp.strokecolor) + ",dotstyle=",
111             face = el.normalizeFace(el.visProp.face) || 'o',
112             size = el.visProp.size > 4 ? 4 : el.visProp.size,
113             sizemap = [0, 0, '2pt 2', '5pt 2', '5pt 3'];
114 
115         // TODO: size == 1 and size > 4, faces <>, ^, v, <, and >
116 
117         if(face == 'x') {
118             result += "x, dotsize=" + sizemap[size];
119         } else if(face == 'o') {
120             result += "*, dotsize=";
121             if(size == 1) {
122                 result += "2pt 2";
123             } else if(size == 2) {
124                 result += "4pt 2";
125             } else if(size == 3) {
126                 result += "6pt 2";
127             } else if(size == 4) {
128                 result += "6pt 3";
129             }
130         } else if(face == '[]') {
131             result += "square*, dotsize=" + sizemap[size];
132         } else if(face == '+') {
133             result += "+, dotsize=" + sizemap[size];
134         }
135         result += "]("+el.coords.usrCoords.slice(1).join(',')+")\n";
136         result += "\\rput("+(el.coords.usrCoords[1]+15/ el.board.unitY)+","+(el.coords.usrCoords[2]+15/ el.board.unitY)+"){\\small $"+el.name+"$}\n";
137 
138         return result;
139     },
140 
141     addLine: function (el) {
142         var screenCoords1 = new JXG.Coords(JXG.COORDS_BY_USER, el.point1.coords.usrCoords, el.board),
143             screenCoords2 = new JXG.Coords(JXG.COORDS_BY_USER, el.point2.coords.usrCoords, el.board),
144             result = "\\psline[linecolor=" + this.parseColor(el.visProp.strokecolor) + ", linewidth=" +el.visProp.strokewidth+"px]";
145 
146         if(el.visProp.straightfirst || el.visProp.straightlast) {
147             JXG.Math.Geometry.calcStraight(el, screenCoords1, screenCoords2);
148         }
149 
150         result += this.setArrows(el);
151         result += "("+screenCoords1.usrCoords.slice(1).join(',')+")("+screenCoords2.usrCoords.slice(2).join(',')+")\n";
152 
153         return result;
154     },
155 
156     addCircle: function (el) {
157         var radius = el.Radius(),
158             result = "\\pscircle[linecolor=" + this.parseColor(el.visProp.strokecolor) +", linewidth=" +el.visProp.strokewidth+"px";
159 
160         if(el.visProp.fillcolor != 'none' && el.visProp.fillopacity != 0) {
161             result += ", fillstyle=solid, fillcolor="+this.parseColor(el.visProp.fillcolor)+", opacity="+el.visProp.fillopacity.toFixed(5);
162         }
163         result += "]("+el.center.coords.usrCoords.slice(1).join('1')+"){"+radius+"}\n";
164 
165         return result;
166     },
167 
168     addPolygon: function (el) {
169         var result = "\\pspolygon[linestyle=none, fillstyle=solid, fillcolor="+this.parseColor(el.visProp.fillcolor)+", opacity="+el.visProp.fillopacity.toFixed(5)+"]",
170             i;
171 
172         for(i = 0; i < el.vertices.length; i++) {
173             result += "("+el.vertices[i].coords.usrCoords.slice(1).join(',')+")";
174         }
175         result += "\n";
176 
177         return result;
178     },
179 
180     addArc: function (el) {
181         var radius = el.Radius(),
182             p = {
183                 coords: new JXG.Coords(JXG.COORDS_BY_USER,[el.board.canvasWidth/(el.board.unitY), el.center.coords.usrCoords[2]], el.board)
184             },
185             angle2 = JXG.Math.Geometry.trueAngle(p, el.center, el.point2).toFixed(4),
186             angle1 = JXG.Math.Geometry.trueAngle(p, el.center, el.point3).toFixed(4),
187             result = "\\psarc[linecolor=" + this.parseColor(el.visProp.strokecolor) + ", linewidth=" +el.visProp.strokewidth+"px]";
188 
189         result += this.setArrows(el);
190         result += "("+el.center.coords.usrCoords.slice(1).join(',')+"){"+radius+"}{"+angle2+"}{"+angle1+"}\n";
191 
192         return result;
193     },
194 
195     addSector: function (el) {
196         var radius = el.Radius(),
197             p = {
198                 coords: new JXG.Coords(JXG.COORDS_BY_USER, [el.board.canvasWidth / (el.board.unitY), el.point1.coords.usrCoords[2]], el.board)
199             },
200             angle2 = JXG.Math.Geometry.trueAngle(p, el.point1, el.point2).toFixed(4),
201             angle1 = JXG.Math.Geometry.trueAngle(p, el.point1, el.point3).toFixed(4);
202 
203         return this.drawWedge(el.visProp.fillcolor, el.visProp.fillopacity, el.point1.coords.usrCoords.slice(1), radius, angle2, angle1);
204     },
205 
206     addAngle: function (el) {
207         var radius = el.radius,
208             p = {
209                 coords: new JXG.Coords(JXG.COORDS_BY_USER, [el.board.canvasWidth/(el.board.unitY), el.point2.coords.usrCoords[2]], el.board)
210             },
211             angle2 = JXG.Math.Geometry.trueAngle(p, el.point2, el.point1).toFixed(4),
212             angle1 = JXG.Math.Geometry.trueAngle(p, el.point2, el.point3).toFixed(4),
213             result;
214 
215         result = this.drawWedge(el.visProp.fillcolor, el.visProp.fillopacity, el.point2.coords.usrCoords.slice(1), radius, angle2, angle1);
216 
217         result += "\\psarc[linecolor=" + this.parseColor(el.visProp.strokecolor) + ", linewidth=" +el.visProp.strokewidth+"px]";
218         result += "("+el.point2.coords.usrCoords.slice(1).join(',')+"){"+radius+"}{"+angle2+"}{"+angle1+"}\n";
219 
220         return result;
221     },
222 
223     parseColor: function (color) {
224         var arr = JXG.rgbParser(color);
225         return "{[rgb]{"+arr[0]/255+","+arr[1]/255+","+arr[2]/255+"}}";
226     }
227 };