// -*- mode:C++ ; compile-command: "g++-3.4 -I.. -g -c tex.cc" -*-
#include "giacPCH.h"

/*
 *  Copyright (C) 2002,2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres
 *  Figure printing adapted from eukleides (c) 2002, Christian Obrecht
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
//#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#ifdef __ANDROID__
using std::vector;
#endif

using namespace std;
#include "gen.h"
#include "gausspol.h"
#include "identificateur.h"
#include "symbolic.h"
#include "poly.h"
#include "usual.h"
#include "tex.h"
#include "prog.h"
#include "rpn.h"
#include "plot.h"
#include "giacintl.h"
#if defined GIAC_HAS_STO_38 || defined NSPIRE || defined NSPIRE_NEWLIB || defined FXCG || defined GIAC_GGB || defined USE_GMP_REPLACEMENTS || defined KHICAS
inline bool is_graphe(const giac::gen &g,std::string &disp_out,const giac::context *){ return false; }
#else
#include "graphtheory.h"
#endif

#if !defined NSPIRE && !defined FXCG && !defined GIAC_HAS_STO_38 && !defined KHICAS && !defined NSPIRE_NEWLIB
#include <fstream>
#endif

#ifndef NO_NAMESPACE_GIAC
namespace giac {
#endif // ndef NO_NAMESPACE_GIAC

  // find if a*x+b*y=c intersects the rectangle xmin..xmax,ymin..ymax
  // if true set x0,y0 and x1,y1 to the intersections
  bool is_clipped(double a,double xmin,double xmax,double b,double ymin,double ymax,double c,double & x0,double &y0,double & x1,double &y1){
    int found=0;
    // find the intersects with x=xmin/x=xmax
    double x,y;
    // test whether a or b is too small
    double theta=std::atan2(b,a);
    if (absdouble(M_PI/2-absdouble(theta))<1e-3){
      // line y=cst
      x0=xmin;
      x1=xmax;
      y0=y1=c/b;
      return y0>=ymin && y0<=ymax;
    }
    if (absdouble(theta)<1e-3 || (M_PI-absdouble(theta))<1e-3){
      // line x=cst
      y0=ymin;
      y1=ymax;
      x0=x1=c/a;
      return x0>=xmin && x0<=xmax;
    }
    y=(c-a*xmin)/b;
    if (y>=ymin && y<=ymax){
      ++found;
      x0=xmin;
      y0=y;
    }
    y=(c-a*xmax)/b;
    if (y>=ymin && y<=ymax){
      if (found){
	x1=xmax;
	y1=y;
	return true;
      }
      ++found;
      x0=xmax;
      y0=y;
    }
    x=(c-b*ymin)/a;
    if (x>=xmin && x<=xmax){
      if (found){
	x1=x;
	y1=ymin;
	return true;
      }
      ++found;
      x0=x;
      y0=ymin;
    }
    x=(c-b*ymax)/a;
    if (x>=xmin && x<=xmax){
      if (found){
	x1=x;
	y1=ymax;
	return true;
      }
      ++found;
      x0=x;
      y0=ymax;
    }
    return false;
  }

  bool in_rectangle(double ax,double ay,double xmin,double ymin,double xmax,double ymax){
    return (ax>=xmin && ax<=xmax && ay>=ymin && ay<=ymax);
  }

  // clip line or segment or halfline, result in xa,ya xb,yb
  // mode can be _LINE__VECT (line), _HALFLINE__VECT (halfline)
  // anything else is considered to be a segment
  // return true if there is something to draw
  bool clip_line(double x1,double y1,double x2,double y2,double xmin,double ymin,double xmax,double ymax,int mode,double & xa,double & ya,double & xb,double & yb){
    bool in1=in_rectangle(x1,y1,xmin,ymin,xmax,ymax);
    bool in2=in_rectangle(x2,y2,xmin,ymin,xmax,ymax);
    if (mode!=_LINE__VECT && mode !=_HALFLINE__VECT && in1 && in2){
      xa=x1; ya=y1; xb=x2; yb=y2;
      return true;
    }
    // Line equation is (y2-y1)*x-(x2-x1)*y=(y2*x1-x2*y1)
    double dy=y2-y1;
    double dx=x2-x1;
    double c=(y2*x1-x2*y1);
    bool a=false,b=false;
    // Find 2 intersections y of x=xmin and x=xmax with line
    // Check if they are inside clip region >=ymin and <=ymax
    if (dx){
      double y=(dy*xmin-c)/dx;
      if (y>=ymin && y<=ymax){
	xa=xmin;
	ya=y;
	a=true;
      }
      y=(dy*xmax-c)/dx;
      if (y>=ymin && y<=ymax){
	if (a){ xb=xmax; yb=y; b=true; } 
	else { xa=xmax; ya=y; a=true; }
      }
    }
    // Find 2 intersections of y=ymin and y=ymax with line
    if (!b && dy){
      double x=(dx*ymin+c)/dy;
      if (x>=xmin && x<=xmax){
	if (a){ xb=x; yb=ymin; b=true; }
	else { xa=x; ya=ymin; a=true;}
      }
      x=(dx*ymax+c)/dy;
      if (x>=xmin && x<=xmax){
	if (a){ xb=x; yb=ymax; b=true; }
	else { xa=x; ya=ymax; a=true;}
      }
    }
    if (a && b){ // if not true there is nothing to draw
      // First case is line, we are done
      if (mode==_LINE__VECT)
	return true;
      if (mode!=_HALFLINE__VECT){ // segment
	// we know that both points are not inside
	if (!in1 && !in2) // both are outside, it's like a line
	  return (xa-xmin)*(xb-xmin)<0;
	if (in1){ // 1 is in, 2 not, find if a is between 1 and 2
	  if ((xa-x1)*(x2-x1)>0 || (ya-y1)*(y2-y1)>0){
	    xb=x1; yb=y1;
	  }
	  else { 
	    xa=x1; ya=y1; 
	  }
	  return true;
	}
	if (in2){ // 2 is in, 1 not, find if a is between 2 and 1
	  if ((xa-x2)*(x1-x2)>0 || (ya-y2)*(y1-y2)>0){
	    xb=x2; yb=y2;
	  }
	  else { 
	    xa=x2; ya=y2; 
	  }
	  return true;
	}
      }
    }
    return false;
  }

  // dimension of the LaTeX output figures default 12 cm x 12 cm
  double horiz_latex=12.;
  double vert_latex=12.;
  const char tex_preamble[]="\\documentclass{article} \n\\usepackage{pst-plot,color} \n\\usepackage{graphicx} \n\\begin{document}\n";
#if defined RTOS_THREADX || defined POCKETCAS
  const char tex_color[]="";
#else
  const char tex_color[]="\\newrgbcolor{fltkcolor0}{0 0 0}\n\\newrgbcolor{fltkcolor1}{0.9961 0 0}\n\\newrgbcolor{fltkcolor2}{0 0.9961 0}\n\\newrgbcolor{fltkcolor3}{0.9961 0.9961 0}\n\\newrgbcolor{fltkcolor4}{0 0 0.9961}\n\\newrgbcolor{fltkcolor5}{0.9961 0 0.9961}\n\\newrgbcolor{fltkcolor6}{0 0.9961 0.9961}\n\\newrgbcolor{fltkcolor7}{0.9961 0.9961 0.9961}\n\\newrgbcolor{fltkcolor8}{0.332 0.332 0.332}\n\\newrgbcolor{fltkcolor9}{0.7734 0.4414 0.4414}\n\\newrgbcolor{fltkcolor10}{0.4414 0.7734 0.4414}\n\\newrgbcolor{fltkcolor11}{0.5547 0.5547 0.2188}\n\\newrgbcolor{fltkcolor12}{0.4414 0.4414 0.7734}\n\\newrgbcolor{fltkcolor13}{0.5547 0.2188 0.5547}\n\\newrgbcolor{fltkcolor14}{0.2188 0.5547 0.5547}\n\\newrgbcolor{fltkcolor15}{0 0 0.5}\n\\newrgbcolor{fltkcolor16}{0.6562 0.6562 0.5938}\n\\newrgbcolor{fltkcolor17}{0.9062 0.9062 0.8438}\n\\newrgbcolor{fltkcolor18}{0.4062 0.4062 0.3438}\n\\newrgbcolor{fltkcolor19}{0.5938 0.6562 0.6562}\n\\newrgbcolor{fltkcolor20}{0.8438 0.9062 0.9062}\n\\newrgbcolor{fltkcolor21}{0.3438 0.4062 0.4062}\n\\newrgbcolor{fltkcolor22}{0.6094 0.6094 0.6562}\n\\newrgbcolor{fltkcolor23}{0.8594 0.8594 0.9062}\n\\newrgbcolor{fltkcolor24}{0.3594 0.3594 0.4062}\n\\newrgbcolor{fltkcolor25}{0.6094 0.6562 0.6094}\n\\newrgbcolor{fltkcolor26}{0.8594 0.9062 0.8594}\n\\newrgbcolor{fltkcolor27}{0.3594 0.4062 0.3594}\n\\newrgbcolor{fltkcolor28}{0.5625 0.5625 0.5625}\n\\newrgbcolor{fltkcolor29}{0.75 0.75 0.75}\n\\newrgbcolor{fltkcolor30}{0.3125 0.3125 0.3125}\n\\newrgbcolor{fltkcolor31}{0.625 0.625 0.625}\n\\newrgbcolor{fltkcolor32}{0 0 0}\n\\newrgbcolor{fltkcolor33}{0.05078 0.05078 0.05078}\n\\newrgbcolor{fltkcolor34}{0.1016 0.1016 0.1016}\n\\newrgbcolor{fltkcolor35}{0.1484 0.1484 0.1484}\n\\newrgbcolor{fltkcolor36}{0.1914 0.1914 0.1914}\n\\newrgbcolor{fltkcolor37}{0.2383 0.2383 0.2383}\n\\newrgbcolor{fltkcolor38}{0.2812 0.2812 0.2812}\n\\newrgbcolor{fltkcolor39}{0.332 0.332 0.332}\n\\newrgbcolor{fltkcolor40}{0.3711 0.3711 0.3711}\n\\newrgbcolor{fltkcolor41}{0.4141 0.4141 0.4141}\n\\newrgbcolor{fltkcolor42}{0.457 0.457 0.457}\n\\newrgbcolor{fltkcolor43}{0.5 0.5 0.5}\n\\newrgbcolor{fltkcolor44}{0.5391 0.5391 0.5391}\n\\newrgbcolor{fltkcolor45}{0.582 0.582 0.582}\n\\newrgbcolor{fltkcolor46}{0.625 0.625 0.625}\n\\newrgbcolor{fltkcolor47}{0.6641 0.6641 0.6641}\n\\newrgbcolor{fltkcolor48}{0.707 0.707 0.707}\n\\newrgbcolor{fltkcolor49}{0.75 0.75 0.75}\n\\newrgbcolor{fltkcolor50}{0.793 0.793 0.793}\n\\newrgbcolor{fltkcolor51}{0.832 0.832 0.832}\n\\newrgbcolor{fltkcolor52}{0.875 0.875 0.875}\n\\newrgbcolor{fltkcolor53}{0.9141 0.9141 0.9141}\n\\newrgbcolor{fltkcolor54}{0.957 0.957 0.957}\n\\newrgbcolor{fltkcolor55}{0.9961 0.9961 0.9961}\n\\newrgbcolor{fltkcolor56}{0 0 0}\n\\newrgbcolor{fltkcolor57}{0 0.1406 0}\n\\newrgbcolor{fltkcolor58}{0 0.2812 0}\n\\newrgbcolor{fltkcolor59}{0 0.4258 0}\n\\newrgbcolor{fltkcolor60}{0 0.5664 0}\n\\newrgbcolor{fltkcolor61}{0 0.7109 0}\n\\newrgbcolor{fltkcolor62}{0 0.8516 0}\n\\newrgbcolor{fltkcolor63}{0 0.9961 0}\n\\newrgbcolor{fltkcolor64}{0.2461 0 0}\n\\newrgbcolor{fltkcolor65}{0.2461 0.1406 0}\n\\newrgbcolor{fltkcolor66}{0.2461 0.2812 0}\n\\newrgbcolor{fltkcolor67}{0.2461 0.4258 0}\n\\newrgbcolor{fltkcolor68}{0.2461 0.5664 0}\n\\newrgbcolor{fltkcolor69}{0.2461 0.7109 0}\n\\newrgbcolor{fltkcolor70}{0.2461 0.8516 0}\n\\newrgbcolor{fltkcolor71}{0.2461 0.9961 0}\n\\newrgbcolor{fltkcolor72}{0.4961 0 0}\n\\newrgbcolor{fltkcolor73}{0.4961 0.1406 0}\n\\newrgbcolor{fltkcolor74}{0.4961 0.2812 0}\n\\newrgbcolor{fltkcolor75}{0.4961 0.4258 0}\n\\newrgbcolor{fltkcolor76}{0.4961 0.5664 0}\n\\newrgbcolor{fltkcolor77}{0.4961 0.7109 0}\n\\newrgbcolor{fltkcolor78}{0.4961 0.8516 0}\n\\newrgbcolor{fltkcolor79}{0.4961 0.9961 0}\n\\newrgbcolor{fltkcolor80}{0.7461 0 0}\n\\newrgbcolor{fltkcolor81}{0.7461 0.1406 0}\n\\newrgbcolor{fltkcolor82}{0.7461 0.2812 0}\n\\newrgbcolor{fltkcolor83}{0.7461 0.4258 0}\n\\newrgbcolor{fltkcolor84}{0.7461 0.5664 0}\n\\newrgbcolor{fltkcolor85}{0.7461 0.7109 0}\n\\newrgbcolor{fltkcolor86}{0.7461 0.8516 0}\n\\newrgbcolor{fltkcolor87}{0.7461 0.9961 0}\n\\newrgbcolor{fltkcolor88}{0.9961 0 0}\n\\newrgbcolor{fltkcolor89}{0.9961 0.1406 0}\n\\newrgbcolor{fltkcolor90}{0.9961 0.2812 0}\n\\newrgbcolor{fltkcolor91}{0.9961 0.4258 0}\n\\newrgbcolor{fltkcolor92}{0.9961 0.5664 0}\n\\newrgbcolor{fltkcolor93}{0.9961 0.7109 0}\n\\newrgbcolor{fltkcolor94}{0.9961 0.8516 0}\n\\newrgbcolor{fltkcolor95}{0.9961 0.9961 0}\n\\newrgbcolor{fltkcolor96}{0 0 0.2461}\n\\newrgbcolor{fltkcolor97}{0 0.1406 0.2461}\n\\newrgbcolor{fltkcolor98}{0 0.2812 0.2461}\n\\newrgbcolor{fltkcolor99}{0 0.4258 0.2461}\n\\newrgbcolor{fltkcolor100}{0 0.5664 0.2461}\n\\newrgbcolor{fltkcolor101}{0 0.7109 0.2461}\n\\newrgbcolor{fltkcolor102}{0 0.8516 0.2461}\n\\newrgbcolor{fltkcolor103}{0 0.9961 0.2461}\n\\newrgbcolor{fltkcolor104}{0.2461 0 0.2461}\n\\newrgbcolor{fltkcolor105}{0.2461 0.1406 0.2461}\n\\newrgbcolor{fltkcolor106}{0.2461 0.2812 0.2461}\n\\newrgbcolor{fltkcolor107}{0.2461 0.4258 0.2461}\n\\newrgbcolor{fltkcolor108}{0.2461 0.5664 0.2461}\n\\newrgbcolor{fltkcolor109}{0.2461 0.7109 0.2461}\n\\newrgbcolor{fltkcolor110}{0.2461 0.8516 0.2461}\n\\newrgbcolor{fltkcolor111}{0.2461 0.9961 0.2461}\n\\newrgbcolor{fltkcolor112}{0.4961 0 0.2461}\n\\newrgbcolor{fltkcolor113}{0.4961 0.1406 0.2461}\n\\newrgbcolor{fltkcolor114}{0.4961 0.2812 0.2461}\n\\newrgbcolor{fltkcolor115}{0.4961 0.4258 0.2461}\n\\newrgbcolor{fltkcolor116}{0.4961 0.5664 0.2461}\n\\newrgbcolor{fltkcolor117}{0.4961 0.7109 0.2461}\n\\newrgbcolor{fltkcolor118}{0.4961 0.8516 0.2461}\n\\newrgbcolor{fltkcolor119}{0.4961 0.9961 0.2461}\n\\newrgbcolor{fltkcolor120}{0.7461 0 0.2461}\n\\newrgbcolor{fltkcolor121}{0.7461 0.1406 0.2461}\n\\newrgbcolor{fltkcolor122}{0.7461 0.2812 0.2461}\n\\newrgbcolor{fltkcolor123}{0.7461 0.4258 0.2461}\n\\newrgbcolor{fltkcolor124}{0.7461 0.5664 0.2461}\n\\newrgbcolor{fltkcolor125}{0.7461 0.7109 0.2461}\n\\newrgbcolor{fltkcolor126}{0.7461 0.8516 0.2461}\n\\newrgbcolor{fltkcolor127}{0.7461 0.9961 0.2461}\n\\newrgbcolor{fltkcolor128}{0.9961 0 0.2461}\n\\newrgbcolor{fltkcolor129}{0.9961 0.1406 0.2461}\n\\newrgbcolor{fltkcolor130}{0.9961 0.2812 0.2461}\n\\newrgbcolor{fltkcolor131}{0.9961 0.4258 0.2461}\n\\newrgbcolor{fltkcolor132}{0.9961 0.5664 0.2461}\n\\newrgbcolor{fltkcolor133}{0.9961 0.7109 0.2461}\n\\newrgbcolor{fltkcolor134}{0.9961 0.8516 0.2461}\n\\newrgbcolor{fltkcolor135}{0.9961 0.9961 0.2461}\n\\newrgbcolor{fltkcolor136}{0 0 0.4961}\n\\newrgbcolor{fltkcolor137}{0 0.1406 0.4961}\n\\newrgbcolor{fltkcolor138}{0 0.2812 0.4961}\n\\newrgbcolor{fltkcolor139}{0 0.4258 0.4961}\n\\newrgbcolor{fltkcolor140}{0 0.5664 0.4961}\n\\newrgbcolor{fltkcolor141}{0 0.7109 0.4961}\n\\newrgbcolor{fltkcolor142}{0 0.8516 0.4961}\n\\newrgbcolor{fltkcolor143}{0 0.9961 0.4961}\n\\newrgbcolor{fltkcolor144}{0.2461 0 0.4961}\n\\newrgbcolor{fltkcolor145}{0.2461 0.1406 0.4961}\n\\newrgbcolor{fltkcolor146}{0.2461 0.2812 0.4961}\n\\newrgbcolor{fltkcolor147}{0.2461 0.4258 0.4961}\n\\newrgbcolor{fltkcolor148}{0.2461 0.5664 0.4961}\n\\newrgbcolor{fltkcolor149}{0.2461 0.7109 0.4961}\n\\newrgbcolor{fltkcolor150}{0.2461 0.8516 0.4961}\n\\newrgbcolor{fltkcolor151}{0.2461 0.9961 0.4961}\n\\newrgbcolor{fltkcolor152}{0.4961 0 0.4961}\n\\newrgbcolor{fltkcolor153}{0.4961 0.1406 0.4961}\n\\newrgbcolor{fltkcolor154}{0.4961 0.2812 0.4961}\n\\newrgbcolor{fltkcolor155}{0.4961 0.4258 0.4961}\n\\newrgbcolor{fltkcolor156}{0.4961 0.5664 0.4961}\n\\newrgbcolor{fltkcolor157}{0.4961 0.7109 0.4961}\n\\newrgbcolor{fltkcolor158}{0.4961 0.8516 0.4961}\n\\newrgbcolor{fltkcolor159}{0.4961 0.9961 0.4961}\n\\newrgbcolor{fltkcolor160}{0.7461 0 0.4961}\n\\newrgbcolor{fltkcolor161}{0.7461 0.1406 0.4961}\n\\newrgbcolor{fltkcolor162}{0.7461 0.2812 0.4961}\n\\newrgbcolor{fltkcolor163}{0.7461 0.4258 0.4961}\n\\newrgbcolor{fltkcolor164}{0.7461 0.5664 0.4961}\n\\newrgbcolor{fltkcolor165}{0.7461 0.7109 0.4961}\n\\newrgbcolor{fltkcolor166}{0.7461 0.8516 0.4961}\n\\newrgbcolor{fltkcolor167}{0.7461 0.9961 0.4961}\n\\newrgbcolor{fltkcolor168}{0.9961 0 0.4961}\n\\newrgbcolor{fltkcolor169}{0.9961 0.1406 0.4961}\n\\newrgbcolor{fltkcolor170}{0.9961 0.2812 0.4961}\n\\newrgbcolor{fltkcolor171}{0.9961 0.4258 0.4961}\n\\newrgbcolor{fltkcolor172}{0.9961 0.5664 0.4961}\n\\newrgbcolor{fltkcolor173}{0.9961 0.7109 0.4961}\n\\newrgbcolor{fltkcolor174}{0.9961 0.8516 0.4961}\n\\newrgbcolor{fltkcolor175}{0.9961 0.9961 0.4961}\n\\newrgbcolor{fltkcolor176}{0 0 0.7461}\n\\newrgbcolor{fltkcolor177}{0 0.1406 0.7461}\n\\newrgbcolor{fltkcolor178}{0 0.2812 0.7461}\n\\newrgbcolor{fltkcolor179}{0 0.4258 0.7461}\n\\newrgbcolor{fltkcolor180}{0 0.5664 0.7461}\n\\newrgbcolor{fltkcolor181}{0 0.7109 0.7461}\n\\newrgbcolor{fltkcolor182}{0 0.8516 0.7461}\n\\newrgbcolor{fltkcolor183}{0 0.9961 0.7461}\n\\newrgbcolor{fltkcolor184}{0.2461 0 0.7461}\n\\newrgbcolor{fltkcolor185}{0.2461 0.1406 0.7461}\n\\newrgbcolor{fltkcolor186}{0.2461 0.2812 0.7461}\n\\newrgbcolor{fltkcolor187}{0.2461 0.4258 0.7461}\n\\newrgbcolor{fltkcolor188}{0.2461 0.5664 0.7461}\n\\newrgbcolor{fltkcolor189}{0.2461 0.7109 0.7461}\n\\newrgbcolor{fltkcolor190}{0.2461 0.8516 0.7461}\n\\newrgbcolor{fltkcolor191}{0.2461 0.9961 0.7461}\n\\newrgbcolor{fltkcolor192}{0.4961 0 0.7461}\n\\newrgbcolor{fltkcolor193}{0.4961 0.1406 0.7461}\n\\newrgbcolor{fltkcolor194}{0.4961 0.2812 0.7461}\n\\newrgbcolor{fltkcolor195}{0.4961 0.4258 0.7461}\n\\newrgbcolor{fltkcolor196}{0.4961 0.5664 0.7461}\n\\newrgbcolor{fltkcolor197}{0.4961 0.7109 0.7461}\n\\newrgbcolor{fltkcolor198}{0.4961 0.8516 0.7461}\n\\newrgbcolor{fltkcolor199}{0.4961 0.9961 0.7461}\n\\newrgbcolor{fltkcolor200}{0.7461 0 0.7461}\n\\newrgbcolor{fltkcolor201}{0.7461 0.1406 0.7461}\n\\newrgbcolor{fltkcolor202}{0.7461 0.2812 0.7461}\n\\newrgbcolor{fltkcolor203}{0.7461 0.4258 0.7461}\n\\newrgbcolor{fltkcolor204}{0.7461 0.5664 0.7461}\n\\newrgbcolor{fltkcolor205}{0.7461 0.7109 0.7461}\n\\newrgbcolor{fltkcolor206}{0.7461 0.8516 0.7461}\n\\newrgbcolor{fltkcolor207}{0.7461 0.9961 0.7461}\n\\newrgbcolor{fltkcolor208}{0.9961 0 0.7461}\n\\newrgbcolor{fltkcolor209}{0.9961 0.1406 0.7461}\n\\newrgbcolor{fltkcolor210}{0.9961 0.2812 0.7461}\n\\newrgbcolor{fltkcolor211}{0.9961 0.4258 0.7461}\n\\newrgbcolor{fltkcolor212}{0.9961 0.5664 0.7461}\n\\newrgbcolor{fltkcolor213}{0.9961 0.7109 0.7461}\n\\newrgbcolor{fltkcolor214}{0.9961 0.8516 0.7461}\n\\newrgbcolor{fltkcolor215}{0.9961 0.9961 0.7461}\n\\newrgbcolor{fltkcolor216}{0 0 0.9961}\n\\newrgbcolor{fltkcolor217}{0 0.1406 0.9961}\n\\newrgbcolor{fltkcolor218}{0 0.2812 0.9961}\n\\newrgbcolor{fltkcolor219}{0 0.4258 0.9961}\n\\newrgbcolor{fltkcolor220}{0 0.5664 0.9961}\n\\newrgbcolor{fltkcolor221}{0 0.7109 0.9961}\n\\newrgbcolor{fltkcolor222}{0 0.8516 0.9961}\n\\newrgbcolor{fltkcolor223}{0 0.9961 0.9961}\n\\newrgbcolor{fltkcolor224}{0.2461 0 0.9961}\n\\newrgbcolor{fltkcolor225}{0.2461 0.1406 0.9961}\n\\newrgbcolor{fltkcolor226}{0.2461 0.2812 0.9961}\n\\newrgbcolor{fltkcolor227}{0.2461 0.4258 0.9961}\n\\newrgbcolor{fltkcolor228}{0.2461 0.5664 0.9961}\n\\newrgbcolor{fltkcolor229}{0.2461 0.7109 0.9961}\n\\newrgbcolor{fltkcolor230}{0.2461 0.8516 0.9961}\n\\newrgbcolor{fltkcolor231}{0.2461 0.9961 0.9961}\n\\newrgbcolor{fltkcolor232}{0.4961 0 0.9961}\n\\newrgbcolor{fltkcolor233}{0.4961 0.1406 0.9961}\n\\newrgbcolor{fltkcolor234}{0.4961 0.2812 0.9961}\n\\newrgbcolor{fltkcolor235}{0.4961 0.4258 0.9961}\n\\newrgbcolor{fltkcolor236}{0.4961 0.5664 0.9961}\n\\newrgbcolor{fltkcolor237}{0.4961 0.7109 0.9961}\n\\newrgbcolor{fltkcolor238}{0.4961 0.8516 0.9961}\n\\newrgbcolor{fltkcolor239}{0.4961 0.9961 0.9961}\n\\newrgbcolor{fltkcolor240}{0.7461 0 0.9961}\n\\newrgbcolor{fltkcolor241}{0.7461 0.1406 0.9961}\n\\newrgbcolor{fltkcolor242}{0.7461 0.2812 0.9961}\n\\newrgbcolor{fltkcolor243}{0.7461 0.4258 0.9961}\n\\newrgbcolor{fltkcolor244}{0.7461 0.5664 0.9961}\n\\newrgbcolor{fltkcolor245}{0.7461 0.7109 0.9961}\n\\newrgbcolor{fltkcolor246}{0.7461 0.8516 0.9961}\n\\newrgbcolor{fltkcolor247}{0.7461 0.9961 0.9961}\n\\newrgbcolor{fltkcolor248}{0.9961 0 0.9961}\n\\newrgbcolor{fltkcolor249}{0.9961 0.1406 0.9961}\n\\newrgbcolor{fltkcolor250}{0.9961 0.2812 0.9961}\n\\newrgbcolor{fltkcolor251}{0.9961 0.4258 0.9961}\n\\newrgbcolor{fltkcolor252}{0.9961 0.5664 0.9961}\n\\newrgbcolor{fltkcolor253}{0.9961 0.7109 0.9961}\n\\newrgbcolor{fltkcolor254}{0.9961 0.8516 0.9961}\n\\newrgbcolor{fltkcolor255}{0.9961 0.9961 0.9961}\n";
#endif
  const char tex_end[]="\n\\end{document}";
  const char mbox_begin[]="\\mathrm{"; // ("\\mbox{");
  const char mbox_end[]="}";

  string spread2tex(const matrice & m,int formule,GIAC_CONTEXT){
    int l=int(m.size());
    if (!l)
      return "\\mbox{empty_spread}";
    int c=int(m.front()._VECTptr->size());
    string s("\\ \\mbox{\\begin{tabular}{|");
    for (int j=0;j<=c;++j)
      s += "r|";
    s += "}\\hline\n & ";
    for (int k=0;;){ // write first line
      string tmp;
      int i=k;
      for(int j=0;;++j){
	tmp=char('A'+i%26-(j!=0))+tmp;
	i=i/26;
	if (!i)
	  break;
      }
      s += tmp;
      ++k;
      if (k==c){
	s += " \\\\\\hline\n";
	break;
      }
      else
	s += " & ";
    }
    for (int i=0;i<l;++i){
      s += print_INT_(i)+" & ";
      for (int j=0;j<c;++j){
	if (formule)
	  s += "$"+gen2tex(m[i][j][formule],contextptr)+"$" ;
	else {
	  int save_r=printcell_current_row(contextptr),save_c=printcell_current_col(contextptr);
	  printcell_current_row(contextptr)=i,printcell_current_col(contextptr)=j;
	  string t(m[i][j][0].print(contextptr)),tt;
	  int ll=int(t.size());
	  for (int l=0;l<ll;++l){
	    if (t[l]!='$')
	      tt += t[l];
	    else
	      tt += "\\$";
	  }
	  s += "{\\tt $"+tt+"$}";
	  printcell_current_row(contextptr)=save_r;printcell_current_col(contextptr)=save_c;
	}
	if (j!=c-1)
	  s += " & ";
      }
      if (i!=l-1){
	if (i%5==4)
	  s += " \\\\\\hline";
	else
	  s += " \\\\";
      }
      else
	s += " \\\\\\hline";
      s+='\n';
    }
    s += "\\end{tabular} } ";
    return s;
  }

  static string matrix2tex(const matrice & m,GIAC_CONTEXT){
    int l=int(m.size());
    if (!l)
      return string("()");
    int c=int(m.front()._VECTptr->size());
    string s("\\left(\\begin{array}{");
    for (int j=0;j<c;++j)
      s += 'c';
    s += "}\n";
    for (int i=0;i<l;++i){
      for (int j=0;j<c;++j){
	  s += gen2tex(m[i][j],contextptr) ;
	  if (j!=c-1)
	    s += " & ";
      }
      if (i!=l-1)
	s += " \\\\";
      s+='\n';
    }
    s += "\\end{array}\\right) ";
    return s;
  }

  static string _VECT2tex(const vecteur & v,int subtype,GIAC_CONTEXT){
    string s(begin_VECT_string(subtype,true,contextptr));
    vecteur::const_iterator it=v.begin(),itend=v.end();
    for (;it!=itend;){
      s += gen2tex(*it,contextptr);
      ++it;
      if (it!=itend)
	s += ',';
    }
    s += end_VECT_string(subtype,true,contextptr);
    return s;
  }

  static string prod_vect2tex(const vecteur & v,GIAC_CONTEXT){
    if (v.empty())
      return "1";
    vecteur::const_iterator it=v.begin(),itend=v.end();
    string s;
    for (;;){
      if ( (it->type==_CPLX && !is_zero(*it->_CPLXptr) && !is_zero(*(it->_CPLXptr+1))) || (it->type==_SYMB && ( it->_SYMBptr->sommet==at_plus || (it->_SYMBptr->sommet==at_neg && need_parenthesis(it->_SYMBptr->feuille)) ) ) )
	s += string("(")+gen2tex(*it,contextptr)+string(")");
      else 
	s += gen2tex(*it,contextptr);
      ++it;
      if (it==itend)
	return s;
      if (it->type<=_IDNT || (it->type==_SYMB && 
			      (it->_SYMBptr->sommet==at_neg || (it->_SYMBptr->sommet.ptr()->printsommet && it->_SYMBptr->feuille.type==_VECT && !it->_SYMBptr->feuille._VECTptr->empty() && it->_SYMBptr->feuille._VECTptr->front().type<=_IDNT))
			      )) // second part of the test added for e.g. latex('2*3*5^2')
	s += "\\cdot ";
      else
	s += " ";
    }
  }

  string translate_underscore(const string & s){
    string res;
    string::const_iterator it=s.begin(),itend=s.end();
    for (;it!=itend;++it){
      switch (*it){
      case '_':
	res += "\\_";
	break;
      case '^':
	res += "{\\tt\\symbol{94}}";
	break;
      case '~':
	res += "{\\tt\\symbol{126}}";
	break;
      case '<':
	res += "{\\tt\\symbol{60}}";
	break;
      case '>':
	res += "{\\tt\\symbol{62}}";
	break;
      case '\n':
	res += "\\\\\n";
	break;
      case '&':
	res += "\\&";
	break;
      case '{':
	res += "\\{";
	break;
      case '}':
	res += "\\}";
	break;
      case '\\':
	res += "$\\backslash $";
	break;
      case '%':
	res += "\\%";
	break;
      case '#':
	res += "\\#";
	break;
      case '$':
	res += "\\$";
	break;
      default:
	res += *it;
      }
    }
    string s0;
    greek2tex(res,s0,false);
    return s0;
  }

  static string fill_flag(bool flag){
    if (flag)
      return "linestyle=none,fillstyle=solid,";
    else
      return "";
  }

  /*
  static string line_flag(int flag){
    switch(flag) {
    case _STYLE_FULL : return "";
    case _STYLE_DOTTED : return "[linestyle=dotted]";
    case _STYLE_DASHED : return "[linestyle=dashed]";
    }
    return "error";
  }
  */

  static string vector_flag(int flag){
    switch(flag) {
    case _VECTOR__VECT : return "{->}";
      // case BACKARROW : return  "{<-}";
      // case DOUBLEARROW : return "{<->}";
    default : return "";
    }
  }

  static string point_flag(int flag){
    switch(flag) {
    case _STYLE_BOX : return "[dotstyle=square*]"; 
    case _STYLE_CROSS : return "[dotstyle=x]"; 
    case _STYLE_PLUS : return "[dotstyle=+]"; 
    default : return "[dotstyle=*]"; 
    }
  }

#ifdef GIAC_HAS_STO_38
  static string flcolor2pstrickscolor(int color){
    switch(color) {
    case FL_BLACK: return "black";
    case FL_WHITE: return "white";
    case FL_DARK1: return "darkgray"; 
    case FL_GRAY: return "gray"; 
    }
    return "unknown";
  }
#else

  static string flcolor2pstrickscolor(int color){
    switch(color) {
    case FL_BLACK: return "black";
    case FL_DARK1: return "darkgray"; 
    case FL_GRAY: return "gray"; 
    case FL_LIGHT1  : return "lightgray"; 
#ifdef HAVE_LIBFLTK
    case _WHITE: return "white"; 
#endif
    case FL_WHITE : return "white"; 
#ifdef HAVE_LIBFLTK
    case _RED: return "red"; 
#endif
    case FL_RED	: return "red"; 
#ifdef HAVE_LIBFLTK
    case _GREEN: return "green"; 
#endif
    case FL_GREEN : return "green"; 
#ifdef HAVE_LIBFLTK
    case _BLUE: return "blue"; 
#endif
    case FL_BLUE : return "blue"; 
#ifdef HAVE_LIBFLTK
    case _CYAN: return "cyan"; 
#endif
    case FL_CYAN : return "cyan"; 
#ifdef HAVE_LIBFLTK
    case _MAGENTA: return "magenta"; 
#endif
    case FL_MAGENTA : return "magenta"; 
#ifdef HAVE_LIBFLTK
    case _YELLOW: return "yellow"; 
#endif
    case FL_YELLOW : return "yellow"; 
    default: return "black";
    } 
    return "fltkcolor"+print_INT_(color); 
  }
#endif // GIAC_HAS_STO_38

  static string double2tex(double d){
    char s[32];
	
#if 0 // def BESTA_OS
    assert(0);
    // returning an auto-var, when the string is constructed before the copy?
    // not the niceest of things to do....
    // BP: I don't understand where you see a problem, a string is constructed from s
    // then the std::string is returned
#else
    if (d<=-1e30 || d>=1e30)
      sprintfdouble(s,"%13g",d);
    else
      sprintfdouble(s,"%13.6f",d);
#endif
    return s;
  }

  // convert UTF-8 string to wchar_t *, return adjusted length
  // FIXME: use utf82unicode instead?
  static unsigned int utf8(wchar_t * wline,const char * line,unsigned int n){
    unsigned int i=0,j=0,c;
    for (;i<n;i++){
      c=line[i];
      if ( (c & 0xc0) == 0x80)
	continue;
      if (c < 128){
	wline[j]=c;
	j++;
	continue;
      }
      if ( (c & 0xe0) == 0xc0) {
	i++;
	c = (c & 0x1f) << 6 | (line[i] & 0x3f);
	wline[j]=c;
	j++;
	continue;
      } 
      if ( (c & 0xf0) == 0xe0) {
	i++;
	c = (c & 0x0f) << 6 | (line[i] & 0x3f);
	i++;
	c = c << 6 | (line[i] & 0x3f);
	wline[j]=c;
	j++;
	continue;
      } 
      if ( (c & 0xf1) == 0xf0) {
	i++;
	c = (c & 0x0f) << 6 | (line[i] & 0x3f);
	i++;
	c = c << 6 | (line[i] & 0x3f);
	i++;
	c = c << 6 | (line[i] & 0x3f);
      } else 
	c = 0xfffd;
      wline[j]=c;
      j++;
    }
    wline[j]=0;
    return j;
  }


  int greek2tex(const string & s,string & texs,bool mathmode){
    int n=int(s.size()),res=0;
    wchar_t * w = new wchar_t[n+1];
    n=utf8(w,s.c_str(),n);
    for (int j=0;j<n;j++){
      switch(w[j]){
      case 8745: if (!mathmode) texs+="$"; texs+="\\cap"; texs+=mathmode?' ':'$'; res++; break; // '∩'      
      case 8746: if (!mathmode) texs+="$"; texs+="\\cup"; texs+=mathmode?' ':'$'; res++; break; // '∪'      
      case 8599: if (!mathmode) texs+="$"; texs+="\\nearrow"; texs+=mathmode?' ':'$'; res++; break;       
      case 8600: if (!mathmode) texs+="$"; texs+="\\searrow"; texs+=mathmode?' ':'$'; res++; break;
      case 8595: if (!mathmode) texs+="$"; texs+="\\downarrow"; texs+=mathmode?' ':'$'; res++; break;
      case 8593: if (!mathmode) texs+="$"; texs+="\\uparrow"; texs+=mathmode?' ':'$'; res++; break;
      case 0x0386:  texs+="\\'A"; break;
      case 0x0388:  texs+="\\'E"; break;
      case 0x0389:  texs+="\\'H"; break;
      case 0x038A:  texs+="\\'I"; break;
      case 0x038C:  texs+="\\'O"; break;
      case 0x038E:  texs+="\\'Y"; break;
      case 0x038F:  if (!mathmode) texs+="$"; texs+="\\Omega"; texs+=mathmode?' ':'$'; res++; break;
      case 0x0390:  texs+="\'i"; break;
      case 0x0391:  texs+="A"; break;
      case 0x0392:  texs+="B"; break;
      case 0x0393:  if (!mathmode) texs+="$"; texs+="\\Gamma"; texs+=mathmode?' ':'$'; res++; break;
      case 0x0394:  if (!mathmode) texs+="$"; texs+="\\Delta"; texs+=mathmode?' ':'$'; res++; break;
      case 0x0395:  texs+="E"; break;
      case 0x0396:  texs+="Z"; break;
      case 0x0397:  texs+="H"; break;
      case 0x0398:  if (!mathmode) texs+="$"; texs+="\\Eta"; texs+=mathmode?' ':'$'; res++; break;
      case 0x0399:  texs+="I"; break;
      case 0x039A:  texs+="K"; break;
      case 0x039B:  if (!mathmode) texs+="$"; texs+="\\Lambda"; texs+=mathmode?' ':'$'; res++; break;
      case 0x039C:  texs+="M"; break;
      case 0x039D:  texs+="N"; break;
      case 0x039E:  if (!mathmode) texs+="$"; texs+="\\Xi"; texs+=mathmode?' ':'$'; res++; break;
      case 0x039F:  texs+="O"; break;
      case 0x03A0:  if (!mathmode) texs+="$"; texs+="\\Pi"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03A1:  texs+="P"; break;
      case 0x03A3:  if (!mathmode) texs+="$"; texs+="\\Sigma"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03A4:  texs+="T"; break;
      case 0x03A5:  texs+="Y"; break;
      case 0x03A6:  if (!mathmode) texs+="$"; texs+="\\Phi"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03A7:  texs+="X"; break;
      case 0x03A8:  if (!mathmode) texs+="$"; texs+="\\Psi"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03A9:  if (!mathmode) texs+="$"; texs+="\\Omega"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03AA:  texs+="I"; break;
      case 0x03AB:  texs+="Y"; break;
      case 0x03AC:  if (!mathmode) texs+="$"; texs+="\\alpha"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03AD:  if (!mathmode) texs+="$"; texs+="\\epsilon"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03AE:  if (!mathmode) texs+="$"; texs+="\\eta"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03AF:  texs+="i"; res++; break;
      case 0x03B0:  if (!mathmode) texs+="$"; texs+="\\upsilon"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03B1:  if (!mathmode) texs+="$"; texs+="\\alpha"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03B2:  if (!mathmode) texs+="$"; texs+="\\beta"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03B3:  if (!mathmode) texs+="$"; texs+="\\gamma"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03B4:  if (!mathmode) texs+="$"; texs+="\\delta"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03B5:  if (!mathmode) texs+="$"; texs+="\\epsilon"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03B6:  if (!mathmode) texs+="$"; texs+="\\zeta"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03B7:  if (!mathmode) texs+="$"; texs+="\\eta"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03B8:  if (!mathmode) texs+="$"; texs+="\\theta"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03B9:  texs+="i"; res++; break;
      case 0x03BA:  if (!mathmode) texs+="$"; texs+="\\kappa"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03BB:  if (!mathmode) texs+="$"; texs+="\\lambda"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03BC:  if (!mathmode) texs+="$"; texs+="\\mu"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03BD:  if (!mathmode) texs+="$"; texs+="\\nu"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03BE:  if (!mathmode) texs+="$"; texs+="\\xi"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03BF:  if (!mathmode) texs+="$"; texs+="\\omicron"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03C0:  if (!mathmode) texs+="$"; texs+="\\pi"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03C1:  if (!mathmode) texs+="$"; texs+="\\rho"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03C2:  texs+="V"; res++; break;
      case 0x03C3:  if (!mathmode) texs+="$"; texs+="\\sigma"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03C4:  if (!mathmode) texs+="$"; texs+="\\tau"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03C5:  if (!mathmode) texs+="$"; texs+="\\upsilon"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03C6:  if (!mathmode) texs+="$"; texs+="\\varphi"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03C7:  if (!mathmode) texs+="$"; texs+="\\chi"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03C8:  if (!mathmode) texs+="$"; texs+="\\psi"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03C9:  if (!mathmode) texs+="$"; texs+="\\omega"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03CA:  texs+="i"; res++; break;
      case 0x03CB:  if (!mathmode) texs+="$"; texs+="\\upsilon"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03CC:  if (!mathmode) texs+="$"; texs+="\\omicron"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03CD:  if (!mathmode) texs+="$"; texs+="\\upsilon"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03CE:  if (!mathmode) texs+="$"; texs+="\\omega"; texs+=mathmode?' ':'$'; res++; break;
      case 0x03D1:  texs+="J"; res++; break;
      case 0x03D2:  texs+="j"; res++; break;
      case 0x03D6:  texs+="v"; res++; break;
      default: texs+=char(w[j] & 0xff);
      }
    }
    delete [] w;
    return res;
  }


  static string idnt2tex(const string & sorig,bool & mathmode){
    string s0;
    mathmode=greek2tex(sorig,s0,true)!=0;
    if (mathmode)
      return s0;
    mathmode=true;
    int n=int(s0.size()),j;
    for (j=n-1;j>=2;--j){
      if (s0[j]>32 && isalpha(s0[j]))
	break;
    }
    string s=s0.substr(0,j+1),sadd;
    if (j<n-1)
      sadd=s0.substr(j+1,n-1-j);
    switch (s.size()){
    case 2:
      if (s=="mu" || s=="nu" || s=="pi" || s=="xi" || s=="Xi")
	return "\\"+s+sadd;
      if (s=="im")
	return "\\Im"+s+sadd;
      if (s=="re")
	return "\\Re"+sadd;
      break;
    case 3:
      if (s=="chi" || s=="phi" || s=="Phi" || s=="eta" || s=="rho" || s=="tau" || s=="psi" || s=="Psi")
	return "\\"+s+sadd;
      break;
    case 4:
      if (s=="beta" || s=="zeta")
	return "\\"+s+sadd;
      break;
    case 5:
      if (s=="alpha" || s=="delta" || s=="Delta" || s=="gamma" || s=="Gamma" || s=="kappa" || s=="theta" || s=="Theta" || s=="sigma" || s=="Sigma" || s=="Omega" || s=="omega" || s=="aleph")
	return "\\"+s+sadd;      
      break;
    case 6:
      if (s=="lambda" || s=="Lambda" || s=="approx")
	return "\\"+s+sadd;      
      break;
    case 7:
      if (s=="epsilon" || s=="product")
	return "\\"+s+sadd;      
      break;
    }
    mathmode=false;
    return s0;
  }

  static string idnt2tex(const string & e){
    bool mathmode;
    if (e.size()==3 && (e=="sin" || e=="cos" || e=="tan" || e=="exp" || e=="log"))
      return "\\"+e;
    if (e.size()==2 && (e=="ln"))
      return "\\"+e;
    string s=idnt2tex(e,mathmode);
    if (mathmode || s.size()==1)
      return s;
    else
      return mbox_begin+translate_underscore(s)+mbox_end;
  }

  static string idnt2tex(const gen & e,GIAC_CONTEXT){
    if (e==unsigned_inf)
      return "\\infty ";
    if (e==cst_pi)
      return "\\pi ";
    if (e==undef)
      return "\\,"+(mbox_begin+string("undef")+mbox_end)+"\\,";
    return idnt2tex(e.print(contextptr));
  }

  static void pnt2texlegende(FILE * file,const vecteur & arg,double xd,double yd,double xunit,int couleur,int labelpos,string * sres){
    // draw legende at xd,yd + 
    string ss;
    if (arg[2].type==_STRNG)
      ss=*arg[2]._STRNGptr;
    else
      ss=arg[2].print(context0);
    bool mathmode;
    ss=idnt2tex(ss,mathmode);
    if (mathmode)
      ss="$"+ss+"$";
    ss="\\color{"+flcolor2pstrickscolor(couleur) +"} "+ss;
    double labelsep(0.1/xunit),angle(45+labelpos*90);
    if (file)
      fprintf(file,"\\uput{%.4f}[%.4f](%.4f,%.4f){%s}\n",labelsep,angle,xd,yd, ss.c_str());
    if (sres)
      *sres += "\\uput{"+double2tex(labelsep)+"}["+double2tex(angle)+"]("+double2tex(xd)+","+double2tex(yd)+"){"+ss+"}\n";
  }

  // This function is an adaptation of drawing.c from eukleides by C. Obrecht
  // v is the output history
  // output is written to file or to sres if file==NULL
  static bool pnt2tex_(FILE * file,const vecteur & v,double xmin,double ymin,double xmax,double ymax,double & xd,double & yd,bool & drawlegende, int & labelpos,int & couleur,string * sres,GIAC_CONTEXT){
    drawlegende=true;
    int s=int(v.size());
    if (!s)
      return false;
    // set color
    int ensemble_attributs=0;
    if (s>=2){
      if (v[1].type==_INT_) 
	ensemble_attributs=v[1].val;
      if (v[1].type==_VECT){
	vecteur & w=*v[1]._VECTptr;
	if (!w.empty() && (w.front().type==_INT_) )
	  ensemble_attributs=w.front().val;
      }
    }
    int width           =(ensemble_attributs & 0x00070000) >> 16; // 3 bits
    // FIXME should be used!
    // int epaisseur_point =(ensemble_attributs & 0x00380000) >> 19; // 3 bits
    // int type_line       =(ensemble_attributs & 0x01c00000) >> 22; // 3 bits
    int type_point      =(ensemble_attributs & 0x0e000000) >> 25; // 3 bits
    labelpos        =(ensemble_attributs & 0x30000000) >> 28; // 2 bits
    bool fill_polygon   =((ensemble_attributs & 0x40000000) >> 30)!=0;
    couleur         =(ensemble_attributs & 0x0000ffff);
    string col(flcolor2pstrickscolor(couleur));
    ++width;
    if (file)
      fprintf(file,"\\psset{linecolor=%s}\n\\psset{linewidth=%.4fpt}\n", col.c_str(),width*0.5);
    if (sres)
      *sres += "\\psset{linecolor="+col+"}\n\\psset{linewidth="+double2tex(width*0.5)+"pt}\n";
    // draw point/line/parametric
    gen point=v[0],x,y;
    // point is either a symb that evals to a complex or a param curve
    // or a vector of complex points
    // next line should be replaced by postscript (rpn) translation of curve
    // equation if possible
    if ( (point.type==_SYMB) && (point._SYMBptr->sommet==at_curve) && (point._SYMBptr->feuille.type==_VECT) && (point._SYMBptr->feuille._VECTptr->size()) )
      point=point._SYMBptr->feuille._VECTptr->back();
    if ( (point.type==_SYMB) && (point._SYMBptr->sommet==at_cercle)){
      vecteur v=*point._SYMBptr->feuille._VECTptr;
      gen diametre=remove_at_pnt(v[0]);
      gen e1=diametre._VECTptr->front().evalf(1,contextptr),e2=diametre._VECTptr->back().evalf(1,contextptr);
      gen centre=rdiv(e1+e2,gen(2.0),contextptr),rayon=abs(rdiv(e2-e1,gen(2.0),contextptr),contextptr);
      x=evalf_double(re(centre,contextptr),1,contextptr);
      y=evalf_double(im(centre,contextptr),1,contextptr);
      if ( (x.type==_DOUBLE_) && (y.type==_DOUBLE_) && (rayon.type==_DOUBLE_) ){
	xd=x._DOUBLE_val;
	yd=y._DOUBLE_val;
	if (v.size()>2){
	  gen theta1=evalf_double(v[1],1,contextptr),theta2=evalf_double(v[2],1,contextptr);
	  //grad
	  int mode=get_mode_set_radian(contextptr);
	  gen angle=arg(e2-e1,contextptr).evalf_double(1,contextptr);
	  angle_mode(mode, contextptr);
	  
	  if (theta1.type==_DOUBLE_ && theta2.type==_DOUBLE_ && angle.type==_DOUBLE_){
	    double t1=theta1._DOUBLE_val,t2=theta2._DOUBLE_val;
	    if (t1>t2){
	      double tmp=t1;
	      t1=t2;
	      t2=tmp;
	    }
	    t1=(t1+angle._DOUBLE_val)*rad2deg_d;
	    t2=(t2+angle._DOUBLE_val)*rad2deg_d;
	    if (file)
	      fprintf (file,"\\pswedge[%sfillcolor=%s](%.4f,%.4f){%.4f}{%.4f}{%.4f}\n",fill_flag(fill_polygon).c_str(),col.c_str(),xd,yd,rayon._DOUBLE_val,t1,t2); // was psarc
	    if (sres)
	      *sres += "\\pswedge[" + fill_flag(fill_polygon) + 
		"fillcolor=" + col + "](" + 
		double2tex(xd)+","+double2tex(yd)+"){" + 
		double2tex(rayon._DOUBLE_val) + "}{" + 
		double2tex(t1)+ "}{" + double2tex(t2) + "}\n";
	    xd=x._DOUBLE_val+rayon._DOUBLE_val*std::cos(t1);
	    yd=y._DOUBLE_val+rayon._DOUBLE_val*std::sin(t1);
	    return true;
	  }
	}
	if (file)
	  fprintf(file,"\\pscircle[%sfillcolor=%s](%.4f,%.4f){%.4f}\n",fill_flag(fill_polygon).c_str(),col.c_str(),xd,yd,rayon._DOUBLE_val);
	if (sres)
	  *sres += "\\pscircle["+fill_flag(fill_polygon)+"fillcolor="+col+
	    "]("+ double2tex(xd)+","+double2tex(yd)+"){"+
	    double2tex(rayon._DOUBLE_val)+"}\n";
	xd=x._DOUBLE_val+rayon._DOUBLE_val;
	return true;
      }
      return false;
    } // end cercle
    if (point.type!=_VECT){ // single point
      point=evalf_double(point,1,contextptr);
      x=re(point,contextptr);
      y=im(point,contextptr).evalf(1,contextptr);
      if ( (x.type==_DOUBLE_) && (y.type==_DOUBLE_) ){
	xd=x._DOUBLE_val;
	yd=y._DOUBLE_val;
	if (file)
	  fprintf(file,"\\psdots%s(%.4f,%.4f)\n", point_flag(type_point).c_str(), xd, yd);
	if (sres)
	  *sres += "\\psdots"+point_flag(type_point)+"("+double2tex(xd)+","+double2tex(yd)+")\n";
	return true;
      }
      return false;
    }
    vecteur & w=*point._VECTptr;
    int ws=int(w.size());
    if (ws==2){ 
      gen A=w[0].evalf(1,contextptr),B=w[1].evalf(1,contextptr);
      gen Ax=re(A,contextptr),Ay=im(A,contextptr).evalf(1,contextptr),
	Bx=re(B,contextptr),By=im(B,contextptr).evalf(1,contextptr);
      if ( (Ax.type==_DOUBLE_) && (Ay.type==_DOUBLE_) 
	   && (Bx.type==_DOUBLE_) && (By.type==_DOUBLE_) ){
	double ax=Ax._DOUBLE_val,ay=Ay._DOUBLE_val,bx=Bx._DOUBLE_val,by=By._DOUBLE_val;
	xd=(ax+bx)/2.;
	yd=(ay+by)/2.;
 	if (point.subtype==_GROUP__VECT)
	  drawlegende=false;
	double x1,y1,x2,y2;
	if (point.subtype!=_HALFLINE__VECT){
	  clip_line(ax,ay,bx,by,xmin,ymin,xmax,ymax,point.subtype,x1,y1,x2,y2);
	  if (file)
	    fprintf(file,"\\psline%s(%.4f,%.4f)(%.4f,%.4f)\n",vector_flag(point.subtype).c_str(), x1,y1,x2,y2);	
	  if (sres)
	    *sres += "\\psline"+vector_flag(point.subtype)+
	      "("+double2tex(x1)+","+double2tex(y1)+")("+
	      double2tex(x2)+","+double2tex(y2)+")\n";
	  return true;
	}
	double vx=bx-ax,vy=by-ay;
	// check for line/halfline
	bx=bx+5*vx;
	by=by+5*vy;
	// FIXME: improve clipping!! Removed here
	if (file)
	  fprintf(file,"\\psline%s(%.4f,%.4f)(%.4f,%.4f)\n",vector_flag(point.subtype).c_str(),ax,ay,bx,by);	
	if (sres)
	  *sres += "\\psline"+vector_flag(point.subtype)+"("+double2tex(ax)+","+double2tex(ay)+")("+double2tex(bx)+","+double2tex(by)+")\n";
	return true;
      } // end DOUBLE types
      return false;
    } // end w.size()==2
    // multi-line
    string prefixstr,printstring;
    if (fill_polygon)
      printstring="\\pspolygon["+fill_flag(fill_polygon)+"fillcolor="+col+"]";
    else 
      prefixstr = "\\psline[fillcolor="+col+"]";
    double xprec=0,yprec=0,xa,ya,xb,yb;
    for (int i=0;i<ws;++i){
      x=w[i].evalf(1,contextptr);
      y=im(x,contextptr).evalf(1,contextptr);
      x=re(x,contextptr);
      if ( (x.type!=_DOUBLE_) || (y.type!=_DOUBLE_) )
	continue;
      xd=x._DOUBLE_val;
      yd=y._DOUBLE_val;
      if (fill_polygon){
	if (in_rectangle(xd,yd,xmin,ymin,xmax,ymax))
	  printstring += "("+double2tex(xd)+","+double2tex(yd)+")";
	else {
	  if (i && clip_line(xprec,yprec,xd,yd,xmin,ymin,xmax,ymax,0,xa,ya,xb,yb) ){
	    printstring += "("+double2tex(xa)+","+double2tex(ya)+")";
	    printstring += "("+double2tex(xb)+","+double2tex(yb)+")";
	  }
	}
      }
      else {
	if (i && clip_line(xprec,yprec,xd,yd,xmin,ymin,xmax,ymax,0,xa,ya,xb,yb)){
	  printstring += prefixstr+"("+double2tex(xa)+","+double2tex(ya)+")";
	  printstring += "("+double2tex(xb)+","+double2tex(yb)+")\n";
	}
      }
      xprec=xd;
      yprec=yd;
    }
    printstring += '\n';
    if (file)
      fprintf(file,"%s",printstring.c_str());
    if (sres)
      *sres += printstring;
    return true;
  }

  static bool pnt2tex(FILE * file,const vecteur & v,double xmin,double ymin,double xmax,double ymax,double & xd,double & yd,bool & drawlegende, int & labelpos,int & couleur,string * sres,GIAC_CONTEXT){
    specialtexprint_double(true,contextptr);
    bool b=pnt2tex_(file,v,xmin,ymin,xmax,ymax,xd,yd,drawlegende,labelpos,couleur,sres,contextptr);
    specialtexprint_double(false,contextptr);
    return b;
  }

  static void invectpnt2tex(FILE * file,const gen & g,double X1,double X2,double Y1,double Y2,double xunit,double yunit,string * resptr,GIAC_CONTEXT){
    if (g.type==_VECT){
      const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end();
      for (;it!=itend;++it)
	invectpnt2tex(file,*it,X1,X2,Y1,Y2,xunit,yunit,resptr,contextptr);
    }
    else {
      if (g.is_symb_of_sommet(at_pnt) && !is3d(g)){
	gen & feu = g._SYMBptr->feuille;
	if (feu.type==_VECT){
	  vecteur & arg=*feu._VECTptr;
	  double xd,yd;
	  bool drawlegende;
	  int labelpos,couleur;
	  if (pnt2tex(file,arg,X1,Y1,X2,Y2,xd,yd,drawlegende,labelpos,couleur,resptr,contextptr)){
	    if (drawlegende && (arg.size()>2)){
	      xunit=(gnuplot_xmax-gnuplot_xmin);
	      pnt2texlegende(file,arg,xd,yd,xunit,couleur,labelpos,resptr);
	    }
	  }
	}
      }
    }
  }

  // evalf_double of a and splt re/im
  void evalfdouble2reim(const gen & a,gen & e,gen & f0,gen & f1,GIAC_CONTEXT){
    if (a.type==_CPLX){
      f0=a._CPLXptr->evalf2double(1,contextptr);
      f1=(a._CPLXptr+1)->evalf2double(1,contextptr);
      if (a._CPLXptr->type==_DOUBLE_ && (a._CPLXptr+1)->type==_DOUBLE_)
	e=a;
      else
	e=gen(f0._DOUBLE_val,f1._DOUBLE_val);
      return ;
    }
#ifndef NO_STDEXCEPT
    try {
#endif
      e=a.evalf_double(1,contextptr); // FIXME? level 1 does not work for non 0 context
#ifndef NO_STDEXCEPT
    } catch (std::runtime_error & error ){
      last_evaled_argptr(contextptr)=NULL;
      CERR << error.what() << '\n';
    }
#endif
    if (e.type==_CPLX){
      f0=*e._CPLXptr;
      f1=*(e._CPLXptr+1);
    }
    else {
      f0=e;
      f1=0.0;
    }
  }

  static bool in_autoscale(const gen & g,vector<double> & vx,vector<double> & vy,vector<double> & vz,GIAC_CONTEXT){
    if (g.type==_VECT && g.subtype==_POINT__VECT && g._VECTptr->size()==3){
      vecteur v=*evalf_double(g,1,contextptr)._VECTptr;
      if (v[2].type==_CPLX)
	v[2]=abs(v[2],contextptr);
      if (v[0].type==_DOUBLE_ && v[1].type==_DOUBLE_ && v[2].type==_DOUBLE_ ){
	vx.push_back(v[0]._DOUBLE_val);
	vy.push_back(v[1]._DOUBLE_val);
	vz.push_back(v[2]._DOUBLE_val);
	return false;
      }
    }
    if (g.type==_VECT ){
      bool ortho=false;
      const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end();
      for (;it!=itend;++it){
	ortho = ortho | in_autoscale(*it,vx,vy,vz,contextptr);
      }
      return ortho;
    }
    if (g.is_symb_of_sommet(at_curve)){
      gen & gf=g._SYMBptr->feuille;
      if (gf.type==_VECT && gf._VECTptr->size()>1){
	gen tmp=(*gf._VECTptr)[1];
	if (is_undef(tmp)){
	  tmp=(*gf._VECTptr)[0];
	  if (tmp.type==_VECT && tmp._VECTptr->size()>4)
	    tmp=(*tmp._VECTptr)[4];
	}
	in_autoscale(tmp,vx,vy,vz,contextptr);
      }
      return false;
    }
    if (g.is_symb_of_sommet(at_hypersurface)){
      gen & g0=g._SYMBptr->feuille;
      if (g0.type==_VECT && g0._VECTptr->size()>2){
	gen & gf=g0._VECTptr->front();
	if (gf.type==_VECT && gf._VECTptr->size()>4){
	  in_autoscale((*gf._VECTptr)[4],vx,vy,vz,contextptr);
	}
      }	
      return false;
    }
    if (g.is_symb_of_sommet(at_cercle)){
      gen c,r;
      centre_rayon(g,c,r,false,contextptr);
      if (is_zero(r)) r=1;
      vecteur v;
      if (g._SYMBptr->feuille.type==_VECT && g._SYMBptr->feuille._VECTptr->size()>=3){
	v=*g._SYMBptr->feuille._VECTptr;
	gen v2=evalf_double(v[2],1,contextptr);
	gen v1=evalf_double(v[1],1,contextptr);
	gen delta=v2-v1;
	v=makevecteur(c,c+r*exp(cst_i*(v1-0.1*delta),contextptr),
		      c+r*exp(cst_i*v1,contextptr),
		      c+r*exp(cst_i*(3*v1+v2)/gen(4),contextptr),
		      c+r*exp(cst_i*(v1+v2)/gen(2),contextptr),
		      c+r*exp(cst_i*(v1+3*v2)/gen(4),contextptr),
		      c+r*exp(cst_i*v2,contextptr),
		      c+r*exp(cst_i*(v2+0.1*delta),contextptr)); 
      }
      else
	v=makevecteur(c-r,c+r,c-cst_i*r,c+cst_i*r);
      in_autoscale(v,vx,vy,vz,contextptr);
      return true;
    }
    // FIXME sphere etc.
    if (g.type!=_VECT){
      gen e,f0,f1;
      evalfdouble2reim(g,e,f0,f1,contextptr);
      if (f0.type==_DOUBLE_ && f1.type==_DOUBLE_){
	vx.push_back(f0._DOUBLE_val);
	vy.push_back(f1._DOUBLE_val);
      }
    }
    return false;
  }

  bool autoscaleg(const gen & g,vector<double> & vx,vector<double> & vy,vector<double> & vz,GIAC_CONTEXT){
    if (g.type==_VECT){
      bool ortho=false;
      const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end();
      for (;it!=itend;++it)
	ortho = ortho | autoscaleg(*it,vx,vy,vz,contextptr);
      return ortho;
    }
    if (g.is_symb_of_sommet(at_pnt)){
      gen & gf=g._SYMBptr->feuille;
      if (gf.type==_VECT && !gf._VECTptr->empty()){
	gen & f=gf._VECTptr->front();
	return in_autoscale(f,vx,vy,vz,contextptr);
      }
    }
    if (g.is_symb_of_sommet(at_equal) && g._SYMBptr->feuille.type==_VECT && g._SYMBptr->feuille._VECTptr->size()==2 && g._SYMBptr->feuille._VECTptr->front()==_GL_ORTHO && !is_zero(g._SYMBptr->feuille._VECTptr->back()))
      return true;
    return false;
  }

  // returns true if axes are drawn
  bool overwrite_viewbox(const gen & g,double & window_xmin,double & window_xmax,double & window_ymin,double & window_ymax,double &window_zmin,double & window_zmax){
    bool res=true;
    if (g.type==_VECT){
      vecteur v =*g._VECTptr;
      for (int i=0;i<int(v.size());++i){
	if (!overwrite_viewbox(v[i],window_xmin,window_xmax,window_ymin,window_ymax,window_zmin,window_zmax))
	  res=false;
      }
      return res;
    }
    if (g.is_symb_of_sommet(at_equal)){
      gen f=g._SYMBptr->feuille;
      if (f.type==_VECT && f._VECTptr->size()==2){
	gen optname= f._VECTptr->front(),optvalue=f._VECTptr->back();
	if (optname.type==_INT_ && optname.subtype==_INT_PLOT && optname.val==_AXES && optvalue==0)
	  res=false;
	if (optvalue.is_symb_of_sommet(at_interval) && optname.type==_INT_ && optname.subtype==_INT_PLOT && optname.val>=_GL_X && optname.val<=_GL_Z){
	  gen optvf=evalf_double(optvalue._SYMBptr->feuille,1,context0);
	  if (optvf.type==_VECT && optvf._VECTptr->size()==2){
	    gen a=optvf._VECTptr->front();
	    gen b=optvf._VECTptr->back();
	    if (a.type==_DOUBLE_ && b.type==_DOUBLE_){
	      switch (optname.val){
	      case _GL_X:
		window_xmin=a._DOUBLE_val;
		window_xmax=b._DOUBLE_val;
		break;
	      case _GL_Y:
		window_ymin=a._DOUBLE_val;
		window_ymax=b._DOUBLE_val;
		break;
	      case _GL_Z:
		window_zmin=a._DOUBLE_val;
		window_zmax=b._DOUBLE_val;
		break;
	      }
	    } 
	  }
	}
      }
    }
    return res;
  }

  void title_legende(const gen & g,plot_attr & p){
    if (g.type==_VECT){
      vecteur v =*g._VECTptr;
      for (int i=0;i<int(v.size());++i){
	title_legende(v[i],p);
      }
      return;
    }
    if (g.is_symb_of_sommet(at_equal)){
      gen f=g._SYMBptr->feuille;
      if (f.type==_VECT && f._VECTptr->size()==2){
	gen optname= f._VECTptr->front(),optvalue=f._VECTptr->back();
	if (optname.type==_INT_ && optname.subtype==_INT_PLOT){
	  string s=optvalue.type==_STRNG?*optvalue._STRNGptr:optvalue.print(context0);
	  switch (optname.val){
	  case _TITLE:
	    p.title=s;
	    break;
	  case _GL_X_AXIS_NAME:
	    p.xlegende=s;
	    break;
	  case _GL_Y_AXIS_NAME:
	    p.ylegende=s;
	    break;
	  }
	}
      }
    }
  }

  static void zoom(double &m,double & M,double d){
    double x_center=(M+m)/2;
    double dx=(M-m);
    double s=absdouble(m)+absdouble(M);
    if (dx<=1e-5*s){
      dx=s;
      if (dx<=1e-5)
	dx=1;
    }
    dx *= d/2;
    m = x_center - dx;
    M = x_center + dx;
  }

  void autoscaleminmax(vector<double> & v,double & m,double & M,bool fullview){
    int s=int(v.size());
    for (int i=0;i<s;++i){
      if (my_isinf(v[i])){
	v.erase(v.begin()+i);
	--s; --i;
      }
    }
    if (s==0){
      v.push_back(0);
      ++s;
    }
    if (s==1){
      v.push_back(v.front());
      ++s;
    }
    if (s>1){    
      sort(v.begin(),v.end());
      m=v[s/10];
      M=v[9*s/10];
      if (fullview || 2*(M-m)>(v[s-1]-v[0]) || (M-m)<0.01*(v[s-1]-v[0])){
	M=v[s-1];
	m=v[0];
	zoom(m,M,1.1);
      }
      else
	zoom(m,M,1/0.8);
      // include origin if not too far
      if ( (m>-M/10 && m<M/2) || (m<-M/10 && m>M/2) )
	m=-M/10;
    }
  }

  static string vectpnt2tex(const gen & g,GIAC_CONTEXT){
    string res;
    double X1=gnuplot_xmin,X2=gnuplot_xmax,Y1=gnuplot_ymin,Y2=gnuplot_ymax;
    vector<double> vx,vy,vz;
    autoscaleg(g,vx,vy,vz,contextptr);
    autoscaleminmax(vx,X1,X2,false);
    autoscaleminmax(vy,Y1,Y2,false);
    double xunit=horiz_latex/(X2-X1);
    double yunit=(X2-X1)/(Y2-Y1)*xunit;
    res="\\begin{pspicture}("+double2tex(X1*xunit)+","+double2tex(Y1*xunit)+
      ")("+double2tex(X2*xunit)+","+double2tex(Y2*xunit)+
      ")\n\\psset{unit="+double2tex(xunit)+
      "cm}\n\\psset{linewidth=.5pt}\n\\psset{arrowsize=2pt 4}\n";
    res+="\\psset{linecolor=black}\n";
    if (show_axes(contextptr) && (Y2>=0) && (Y1<=0) ) 
      res+="\\psline[linestyle=dashed]{->}("+double2tex(X1)+","+double2tex(0.0)+")("+double2tex(X2)+","+double2tex(0.0)+")\n";
    if (show_axes(contextptr) && (X2>=0) && (X1<=0) ) 
      res+="\\psline[linestyle=dashed]{->}("+double2tex(0.0)+","+double2tex(Y1)+")("+double2tex(0.0)+","+double2tex(Y2)+")\n";
    invectpnt2tex(0,g,X1,X2,Y1,Y2,xunit,yunit,&res,contextptr);
    res += "\\end{pspicture}\n";
    return res;
  }
   
  static string symbolic2tex(const symbolic & mys,GIAC_CONTEXT){
    const gen &feu=mys.feuille;
    if (mys.sommet==at_pnt && feu.type==_VECT && !is3d(mys))
      return vectpnt2tex(mys,contextptr);
    if (mys.sommet==at_program && feu.type==_VECT && feu._VECTptr->size()>=3){
      const vecteur & v=*feu._VECTptr;
      gen f=v[2];
      if (!f.is_symb_of_sommet(at_local)){
	return gen2tex(v[0],contextptr)+" \\rightarrow "+gen2tex(f,contextptr);
      }
    }
    if (mys.sommet.ptr()->texprint)
      return mys.sommet.ptr()->texprint(feu,mys.sommet.ptr()->s,contextptr);
    if (mys.sommet==at_abs)
      return '|'+gen2tex(feu,contextptr)+'|';
    if (mys.sommet==at_unit)
      return texprintsommetasoperator(feu,"\\_",contextptr);
    string opstring=idnt2tex(mys.sommet.ptr()->print(contextptr));
    if ( (feu.type==_VECT) && (feu._VECTptr->empty()) )
      return opstring+string("()");
    if ( (feu.type!=_VECT) || (feu._VECTptr->front().type==_VECT && mys.sommet!=at_pow) ){
      if ((mys.sommet==at_neg) || (mys.sommet==at_plus)){
	if (feu.type!=_SYMB) 
	  return opstring+gen2tex(feu,contextptr) ;
	if (feu._SYMBptr->sommet==at_inv || !need_parenthesis(feu._SYMBptr->feuille))
	  return opstring+gen2tex(feu,contextptr) ;
	return opstring+string("\\left(") + gen2tex(feu,contextptr) +string("\\right)");
      }
      if (mys.sommet==at_inv && (feu.is_symb_of_sommet(at_prod) || feu.is_symb_of_sommet(at_plus) || feu.is_symb_of_sommet(at_pow) || feu.type<=_IDNT) ){
	if (feu.type==_IDNT)
	  return gen2tex(feu,contextptr)+"^{-1}";
	return string("\\frac{1}{") + gen2tex(feu,contextptr) +string("}");
      }
      return opstring + "\\left(" + gen2tex(feu,contextptr) +"\\right)" ;
    }
    string s;
    int l=int(feu._VECTptr->size());
    if ( mys.sommet==at_plus ){
      for (int i=0;i<l;++i){
	gen e((*(feu._VECTptr))[i]);
	if ((e.type==_SYMB) && (e._SYMBptr->sommet==at_neg)){
	  s += "-";
	  if (e._SYMBptr->feuille.type!=_CPLX && (e._SYMBptr->feuille.type!=_SYMB || e._SYMBptr->feuille._SYMBptr->sommet==at_inv ||  e._SYMBptr->feuille._SYMBptr->sommet==at_prod|| !need_parenthesis(e._SYMBptr->feuille)) )
	    s += gen2tex(e._SYMBptr->feuille,contextptr) ;
	  else
	    s += "\\left(" + gen2tex(e._SYMBptr->feuille,contextptr) + "\\right)";
	}
	else {
	  if ( e.type<=_REAL  && !is_positive(e,0) )
	    s += e.print(contextptr);
	  else {
	    string sadd=gen2tex(e,contextptr);
	    if (i){
	      if (opstring=="+" && !sadd.empty() && sadd[0]=='-')
		;
	      else
		s += opstring;
	    }
	    s += sadd;
	  }
	}
      } // end_for
      return s;
    }
    if (mys.sommet==at_prod) {
      vecteur num;
      vecteur den;
      for (int i=0;i<l;++i){
	gen e((*(feu._VECTptr))[i]);
	if ( (e.type==_SYMB) && (e._SYMBptr->sommet==at_inv) )
	  den.push_back(e._SYMBptr->feuille);
	else {
	  if (!den.empty()){
	    s += "\\frac{"+prod_vect2tex(num,contextptr)+"}{"+prod_vect2tex(den,contextptr)+"} \\cdot ";
	    num.clear();
	    den.clear();
	  }
	  num.push_back(e);
	}
      }
      if (den.empty())
	return s+prod_vect2tex(num,contextptr);
      return s+"\\frac{"+prod_vect2tex(num,contextptr)+"}{"+prod_vect2tex(den,contextptr)+'}';
    } // end if sommet_is_prod
    if (mys.sommet==at_pow){
      vecteur & v=*feu._VECTptr;
      if ( (v.back()==plus_one_half)  )
	return "\\sqrt{"+gen2tex(v.front(),contextptr)+"}";
      if ( v.back()==minus_one_half || v.back()==fraction(minus_one,plus_two) )
	return "\\frac{1}{\\sqrt{"+gen2tex(v.front(),contextptr)+"}}";
      string res=gen2tex(v.front(),contextptr);
      bool par = (v.front().type>=_CPLX || is_strictly_positive(-v.front(),contextptr) ) && v.front().type!=_IDNT && !ckmatrix(v.front());
      if (par && !v.front().is_symb_of_sommet(at_plus)){
	int ress=int(res.size()),i;
	for (i=1;i<ress;++i){
	  if (res[i]<=32 || !isalpha(res[i]))
	    break;
	}
	if (i+12<ress && res.substr(i,6)=="\\left(" && res.substr(ress-6,6)=="right)")
	  par=false;
      }
      if (par)
	res ="\\left("+res+"\\right)";
      return res+"^{"+gen2tex(v.back(),contextptr)+'}';
    }
    s = opstring +"\\left(";
    for (int i=0;;++i){
      s += gen2tex((*(feu._VECTptr))[i],contextptr);
      if (i==l-1)
	return s+"\\right)";
      s += ',';
    }
  }

  bool legacy=false;
  // assume math mode enabled
  string gen2tex(const gen & e,GIAC_CONTEXT){
    string s;
#if 1 //ndef S390X
    if (!legacy && has_improved_latex_export(e,s,false,contextptr))
      return s;
#endif
    switch (e.type){
    case _INT_: case _ZINT: case _REAL:
      if (e.subtype==_INT_BOOLEAN)
	return "\\mbox{"+e.print(contextptr)+'}';      
      return e.print(contextptr);
    case _DOUBLE_:
      if (specialtexprint_double(contextptr))
	return double2tex(e._DOUBLE_val);
      else
	return e.print(contextptr);
    case _CPLX:
      return e.print(contextptr);
    case _IDNT:
      return idnt2tex(e,contextptr);
    case _SYMB:
      return symbolic2tex(*e._SYMBptr,contextptr);
    case _VECT:
      if (e.subtype==_SPREAD__VECT)
	return spread2tex(*e._VECTptr,1,contextptr);
      if (e.subtype==_GRAPH__VECT){
	string s;
	if (is_graphe(e,s,contextptr))
	  return "\\mbox{"+s+'}';
      }
      if (!e._VECTptr->empty() && e._VECTptr->back().is_symb_of_sommet(at_pnt) && !is3d(e._VECTptr->back()) )
	return vectpnt2tex(e,contextptr);
      if (ckmatrix(*e._VECTptr))
	return matrix2tex(*e._VECTptr,contextptr);
      else
	return _VECT2tex(*e._VECTptr,e.subtype,contextptr);
    case _POLY:
      return mbox_begin+string("polynome")+mbox_end+" "; 
    case _SPOL1:
      return gen2tex(spol12gen(*e._SPOL1ptr,contextptr),contextptr);
    case _FRAC:
      return string("\\frac{")+gen2tex(e._FRACptr->num,contextptr)+"}{"+gen2tex(e._FRACptr->den,contextptr)+'}';
    case _EXT: 
      return "";
    case _STRNG:
      return idnt2tex(*e._STRNGptr);
    case _FUNC:
      return idnt2tex(e.print(contextptr));
    case _USER:
      return e._USERptr->texprint(contextptr);
    case _MOD:
      return gen2tex(*e._MODptr,contextptr)+"\\%"+gen2tex(*(e._MODptr+1),contextptr);
    case _POINTER_:
      if (e.subtype==_FL_WIDGET_POINTER &&fl_widget_texprint_function )
	return fl_widget_texprint_function(e._POINTER_val);
      return "Done";
    default:
      return "Error in Tex conversion for "+e.print(contextptr);
    }
    return 0;
  }
#if defined USE_GMP_REPLACEMENTS || defined GIAC_GGB || defined EMCC || defined EMCC2 || defined KHICAS || defined NSPIRE_NEWLIB
  bool has_improved_latex_export(const gen &g,string &s,bool override_texmacs,GIAC_CONTEXT){
    return false;
  }
  void enable_texmacs_compatible_latex_export(bool yes){
  }
#endif
  gen _latex(const gen & g,GIAC_CONTEXT){
    if ( g.type==_STRNG && g.subtype==-1) return  g;
    if (g.type==_VECT && g._VECTptr->size()==2 && g._VECTptr->front().type==_STRNG && *g._VECTptr->front()._STRNGptr=="legacy"){
      bool b=is_zero(g._VECTptr->back());
      legacy=!b;
      return legacy;
    }
#if !defined NSPIRE && !defined FXCG && !defined GIAC_HAS_STO_38 && !defined KHICAS && !defined NSPIRE_NEWLIB
    if (!secure_run && g.type==_VECT && g.subtype==_SEQ__VECT && g._VECTptr->size()==2 && (*g._VECTptr)[1].type==_STRNG){
      ofstream of((*g._VECTptr)[1]._STRNGptr->c_str());
      of << gen2tex(g._VECTptr->front(),contextptr) << '\n';
      return plus_one;
    }
#endif
    string s;
    if (legacy || !has_improved_latex_export(g,s,true,contextptr))
      s=gen2tex(g,contextptr);
    return string2gen(s,false);
  }
  static const char _latex_s []="latex";
  static define_unary_function_eval (__latex,&_latex,_latex_s);
  define_unary_function_ptr5( at_latex ,alias_at_latex,&__latex,0,true);

  static const char _TeX_s []="TeX";
  static define_unary_function_eval (__TeX,&_latex,_TeX_s);
  define_unary_function_ptr5( at_TeX ,alias_at_TeX,&__TeX,0,true);



  int graph2tex(FILE * file,const vecteur & v,double X1,double X2,double Y1,double Y2,double Unit,const char * filename,bool logo,GIAC_CONTEXT){
    return graph2tex(file,v,X1,X2,Y1,Y2,Unit,Unit,filename,logo,contextptr);
  }

  static int ingraph2tex(FILE * file,const vecteur & v,double xunit,double yunit,double xmin, double ymin,double xmax,double ymax,GIAC_CONTEXT){
    vecteur w;
    const_iterateur it=v.begin(),itend=v.end();
    for (;it!=itend;++it){
      gen sortie=*it;
      // CERR << "graph2tex " << *it << '\n';
      if (sortie.type==_POINTER_ && sortie.subtype==_FL_WIDGET_POINTER && fl_widget_updatepict_function)
	sortie = fl_widget_updatepict_function(sortie);
      if (sortie.type!=_VECT)
	w=vecteur(1,sortie);
      else
	w=*sortie._VECTptr;
      const_iterateur jt=w.begin(),jtend=w.end();
      for (;jt!=jtend;++jt){
	if (jt->type==_VECT)
	  ingraph2tex(file,*jt->_VECTptr,xunit,yunit,xmin,ymin,xmax,ymax,contextptr);
	if ( (jt->type!=_SYMB) || (jt->_SYMBptr->sommet!=at_pnt) )
	  continue;
	gen & g=jt->_SYMBptr->feuille;
	if (g.type!=_VECT)
	  continue;
	vecteur & arg=*g._VECTptr;
	double xd,yd;
	bool drawlegende;
	int labelpos,couleur;
	if (pnt2tex(file,arg,xmin,ymin,xmax,ymax,xd,yd,drawlegende,labelpos,couleur,0,contextptr) && drawlegende && (arg.size()>2))
	  pnt2texlegende(file,arg,xd,yd,xunit,couleur,labelpos,0);
      }
    }
    return 1;
  }

  int graph2tex(FILE * file,const vecteur & v,double X1,double X2,double Y1,double Y2,double xunit,double yunit,const char * filename,bool logo,GIAC_CONTEXT){
    double z(0);
    if (filename)
      fprintf(file,"\n%%file %s",filename);
    fprintf(file,"\n%% Generated by xcas\n\\noindent\n");
    // BUG xunit/yunit do not work for circles, FIXME
    if (xunit!=yunit)
      fprintf(file,"\\begin{pspicture}(%.4f,%.4f)(%.4f,%.4f)\n\\psset{unit=%.4fcm}\n\\psset{xunit=%.4fcm}\n\\psset{yunit=%.4fcm}\n\\psset{linewidth=.5pt}\n\\psset{arrowsize=2pt 4}\n", X1*xunit,Y1*yunit,X2*xunit,Y2*yunit,xunit,xunit,yunit);
    else
      fprintf(file,"\\begin{pspicture}(%.4f,%.4f)(%.4f,%.4f)\n\\psset{unit=%.4fcm}\n\\psset{linewidth=.5pt}\n\\psset{arrowsize=2pt 4}\n", X1*xunit, Y1*xunit, X2*xunit, Y2*xunit,xunit);
    fprintf(file,"\\psset{linecolor=black}\n");
#ifndef KHICAS
    if (logo){
      // fprintf(file,"\\psframe[fillstyle=solid,fillcolor=gray](%.4f,%.4f)(%.4f,%.4f)\n",X1,Y1,X2,Y2);
      vector<logo_turtle> w=vecteur2turtlevect(v);
      vector<logo_turtle> * turtleptr=&w;
      int l=int(turtleptr->size());
      if (l>0){
	double labelsep(0.1/xunit),angle(45);
	fprintf(file,"%s{%.4f}[%.4f](%.4f,%.4f){%s%i}\n","%\\uput",labelsep,angle,X2-100,Y2-25, "x ",int(turtleptr->back().x+.5));
	fprintf(file,"%s{%.4f}[%.4f](%.4f,%.4f){%s%i}\n","%\\uput",labelsep,angle,X2-100,Y2-48, "y ",int(turtleptr->back().y+.5));
	fprintf(file,"%s{%.4f}[%.4f](%.4f,%.4f){%s%i}\n","%\\uput",labelsep,angle,X2-100,Y2-65, "t ",int(turtleptr->back().theta+.5));
	logo_turtle prec =(*turtleptr)[0];
	for (int k=1;k<l;++k){
	  logo_turtle current =(*turtleptr)[k];
	  if (!current.s.empty()){ // Write a string
	    // FIXME fl_font(FL_HELVETICA,current.radius);
	    fprintf(file,"\\uput{%.4f}[%.4f](%.4f,%.4f){%s}\n",labelsep,angle,current.x,current.y, current.s.c_str());
	  }
	  else {
	    if (current.color!=prec.color){
	      string col(flcolor2pstrickscolor(current.color));
	      fprintf(file,"\\psset{linecolor=%s}\n", col.c_str());
	    }
	    if (current.radius>0){
	      int r=current.radius & 0x1ff; // bit 0-8
	      double theta1,theta2;
	      if (current.direct){
		theta1=prec.theta+double((current.radius >> 9) & 0x1ff); // bit 9-17
		theta2=prec.theta+double((current.radius >> 18) & 0x1ff); // bit 18-26
	      }
	      else {
		theta1=prec.theta-double((current.radius >> 9) & 0x1ff); // bit 9-17
		theta2=prec.theta-double((current.radius >> 18) & 0x1ff); // bit 18-26
	      }
	      bool rempli=(current.radius >> 27) & 0x1;
	      double angle;
	      double x,y;
	      angle = M_PI/180*(theta2-90);
	      if (current.direct){
		x=current.x - r*std::cos(angle);
		y=current.y - r*std::sin(angle);
	      }
	      else {
		x=current.x + r*std::cos(angle);
		y=current.y + r*std::sin(angle);
	      }
	      if (current.direct){
		if (rempli){
		  fprintf(file,"\\pswedge*[fillcolor=");
		  fprintf(file,"%s",flcolor2pstrickscolor(prec.color).c_str());
		  fprintf(file,"]");
		}
		else
		  fprintf(file,"\\psarc");
		fprintf(file,"(%.4f,%.4f){%.4f}{%.4f}{%.4f}\n",x,y,double(r),theta1-90,theta2-90);
	      }
	      else {
		if (rempli){
		  fprintf(file,"\\pswedge*[fillcolor=");
		  fprintf(file,"%s",flcolor2pstrickscolor(prec.color).c_str());
		  fprintf(file,"]");
		}
		else
		  fprintf(file,"\\psarc");
		fprintf(file,"(%.4f,%.4f){%.4f}{%.4f}{%.4f}\n",x,y,double(r),theta2+90,theta1+90);
	      }
	    } // end radius>0
	    else {
	      if (prec.mark && (prec.x!=current.x || prec.y!=current.y) ){
		fprintf(file,"\\psline(%.4f,%.4f)(%.4f,%.4f)\n", prec.x,prec.y,current.x,current.y);	
	      }
	    }
	    if (current.radius<-1 && k+current.radius>=0){
	      // poly-line from (*turtleptr)[k+current.radius] to (*turtleptr)[k]
	      string printstring("\\pspolygon[linestyle=none,fillstyle=solid,fillcolor="+flcolor2pstrickscolor(prec.color)+"]");
	      for (int i=0;i>=current.radius;--i){
		logo_turtle & t=(*turtleptr)[k+i];
		printstring += "("+double2tex(t.x)+","+double2tex(t.y)+")";
	      }
	      printstring += "("+double2tex(current.x)+","+double2tex(current.y)+")\n";
	      fprintf(file,"%s",printstring.c_str());
	    }
	  } // end else (non-string turtle record)
	  prec=current;
	} // end for (all turtle records)
	logo_turtle & t = (*turtleptr)[l-1];
	double x=t.x,y=t.y;
	double cost=std::cos(t.theta*deg2rad_d);
	double sint=std::sin(t.theta*deg2rad_d);
	double Dx=turtle_length*cost/2;
	double Dy=turtle_length*sint/2;
	string col(flcolor2pstrickscolor(prec.color));
	fprintf(file,"\\psset{linecolor=%s}\n", col.c_str());
	if (t.visible){
	  fprintf(file,"\\psline(%.4f,%.4f)(%.4f,%.4f)\n", x+Dy, y-Dx, x-Dy, y+Dx);	
	  // fl_line(deltax+x+Dy,deltay+h()-(y-Dx),deltax+x-Dy,deltay+h()-(y+Dx));
	  if (!t.mark){
	    string col(flcolor2pstrickscolor(t.color+1));
	    fprintf(file,"\\psset{linecolor=%s}\n", col.c_str());
	  }
	  fprintf(file,"\\psline(%.4f,%.4f)(%.4f,%.4f)\n", x+Dy, y-Dx, x+3*Dx, y+3*Dy);	
	  fprintf(file,"\\psline(%.4f,%.4f)(%.4f,%.4f)\n", x-Dy, y+Dx, x+3*Dx, y+3*Dy);	
	} // end if t.visible
      } // end if l>0
    } // end if logo
    else 
#endif
      {
      if (show_axes(contextptr) && (Y2>=0) && (Y1<=0) ) 
	fprintf(file,"\\psline[linestyle=dashed]{->}(%.4f,%.4f)(%.4f,%.4f)\n",X1,z,X2,z);
      if (show_axes(contextptr) && (X2>=0) && (X1<=0) ) 
	fprintf(file,"\\psline[linestyle=dashed]{->}(%.4f,%.4f)(%.4f,%.4f)\n",z,Y1,z,Y2);
      ingraph2tex(file,v,xunit,yunit,X1,Y1,X2,Y2,contextptr);
    }
    fprintf(file,"\\end{pspicture} \n\n");
    return 1;
  }

  int graph2tex(const string &s,const vecteur & v,double X1,double X2,double Y1,double Y2,double Unit,bool logo,GIAC_CONTEXT){
    return graph2tex(s,v,X1,X2,Y1,Y2,Unit,Unit,logo,contextptr);
  }

  std::string get_path(const string & st){
    int s=int(st.size()),i;
    for (i=s-1;i>=0;--i){
      if (st[i]=='/')
	break;
    }
    return st.substr(0,i+1);
  }

  std::string remove_path(const std::string & st){
    int s=int(st.size()),i;
    for (i=s-1;i>=0;--i){
      if (st[i]=='/')
	break;
    }
    return st.substr(i+1,s-i-1);
  }


  int graph2tex(const string &s,const vecteur & v,double X1,double X2,double Y1,double Y2,double xunit,double yunit,bool logo,GIAC_CONTEXT){
    if (is_undef(check_secure()))
      return 0;
    // int file;
    // file = open (s.c_str(), O_WRONLY);
    // if (file==-1)
    //  return file;
    // int savestdout;
    // dup2(STDOUT_FILENO,savestdout);
    // dup2(file,STDOUT_FILENO);
    // Begin eukleides code with redirected stdout
    FILE * filecol=fopen((get_path(s)+"fltkcol.tex").c_str(),"w");
    if (!filecol){
      CERR << "Unable to open color file fltkcol.tex" << '\n';
      return 0;
    }
    fprintf(filecol,"%s",tex_color);
    fclose(filecol);
    FILE * file=fopen(s.c_str(), "w");
    if (!file){
      CERR << "Unable to open file "+s << '\n';
      return 0;
    }
    fprintf(file,"%s",tex_preamble);
    fprintf(file,"\\input fltkcol.tex");
    graph2tex(file,v,X1,X2,Y1,Y2,xunit,yunit,s.c_str(),logo,contextptr);
    fprintf(file,"\\end{document}\n");
    fclose(file);
    return 1;
    // End eukleides code, restore stdout
    // dup2(savestdout,STDOUT_FILENO);  
  }

  gen _graph2tex(const gen & args,GIAC_CONTEXT){
    if ( args.type==_STRNG && args.subtype==-1) return  args;
    int i=erase_pos(contextptr);
    vecteur hist(history_out(contextptr).begin()+i,history_out(contextptr).end());
    return graph2tex(args,hist,contextptr);
  }

  gen graph2tex(const gen & args,const vecteur & hist,GIAC_CONTEXT){
    if (args.type==_STRNG){
      double horiz_unit=horiz_latex/(gnuplot_xmax-gnuplot_xmin);
      double vert_unit=vert_latex/(gnuplot_ymax-gnuplot_ymin);
      double unit=horiz_unit;
      if (horiz_unit>vert_unit)
	unit=vert_unit;
      return graph2tex(*args._STRNGptr,hist,gnuplot_xmin,gnuplot_xmax,gnuplot_ymin,gnuplot_ymax,unit,false,contextptr);
    }
    if ( (args.type!=_VECT) || (args._VECTptr->size()<2) )
      return symbolic(at_graph2tex,args);
    vecteur & v=*args._VECTptr;
    int vs=int(v.size());
    if ( (v[0].type!=_STRNG) || (v[1].type!=_DOUBLE_) )
      return gensizeerr();
    if ( (vs>2) && (v[2].type==_DOUBLE_) )
      gnuplot_xmin=v[2]._DOUBLE_val;
    if ( (vs>3) && (v[3].type==_DOUBLE_) )
      gnuplot_xmax=v[3]._DOUBLE_val;
    if ( (vs>4) && (v[4].type==_DOUBLE_) )
      gnuplot_ymin=v[4]._DOUBLE_val;
    if ( (vs>5) && (v[5].type==_DOUBLE_) )
      gnuplot_ymax=v[5]._DOUBLE_val;
    return graph2tex(*v[0]._STRNGptr,hist,gnuplot_xmin,gnuplot_xmax,gnuplot_ymin,gnuplot_ymax,v[1]._DOUBLE_val,false,contextptr);
  }
  static const char _graph2tex_s []="graph2tex";
  static define_unary_function_eval (__graph2tex,&_graph2tex,_graph2tex_s);
  define_unary_function_ptr5( at_graph2tex ,alias_at_graph2tex,&__graph2tex,0,true);

  gen _graph3d2tex(const gen & args,GIAC_CONTEXT){
    if ( args.type==_STRNG && args.subtype==-1) return  args;
    gen tmp=check_secure();
    if (is_undef(tmp)) return tmp;
    if (args.type==_STRNG){
      string & s=*args._STRNGptr;
#ifdef WITH_GNUPLOT
      bool clrplot;
      int out_handle;
      FILE * gnuplot_out_readstream,* stream = open_gnuplot(clrplot,gnuplot_out_readstream,out_handle);
      latex_replot(stream,s);
      gnuplot_wait(out_handle,gnuplot_out_readstream,5);
#endif
      return string2gen(s,false);
    }
    else { // search in history for the last plot command answer == to an int
      int s=giacmin(int(history_out(contextptr).size()),int(history_in(contextptr).size()));
      for (int i=s-1;i>=0;--i){
	if (history_out(contextptr)[i].is_symb_of_sommet(at_pnt) && history_out(contextptr)[i].subtype>=0)
	  return history_out(contextptr)[i].subtype;
	if ( history_out(contextptr)[i].type==_INT_ && history_in(contextptr)[i].type==_SYMB && ( equalposcomp(implicittex_plot_sommets,history_in(contextptr)[i]._SYMBptr->sommet) || equalposcomp(notexprint_plot_sommets,history_in(contextptr)[i]._SYMBptr->sommet) ) )
	  return history_out(contextptr)[i];
      }
      return undef;
    }
  }
  static const char _graph3d2tex_s []="graph3d2tex";
  static define_unary_function_eval (__graph3d2tex,&_graph3d2tex,_graph3d2tex_s);
  define_unary_function_ptr5( at_graph3d2tex ,alias_at_graph3d2tex,&__graph3d2tex,0,true);
#ifndef NO_NAMESPACE_GIAC
} // namespace giac
#endif // ndef NO_NAMESPACE_GIAC
