1 /* -*- mode:C++ ; compile-command: "g++ -I. -I.. -I../include -g -c plot.cc -Wall -DIN_GIAC -DHAVE_CONFIG_H -DGIAC_GENERIC_CONSTANTS " -*- */
2 // NB: Using gnuplot optimally requires patching and recompiling gnuplot
3 // If you use the -DGNUPLOT_IO compile flag, you
4 // MUST compile gnuplot with interactive mode enabled, file src/plot.c
5 // line 448
6 /*
7   diff plot.c plot.c~
8   448c448
9   <     interactive = TRUE; // isatty(fileno(stdin));
10   ---
11   >     interactive = isatty(fileno(stdin));
12 */
13 
14 /*
15  *  Copyright (C) 2000/14 B. Parisse, Institut Fourier, 38402 St Martin d'Heres
16  *  implicitplot3d code adapted from
17  *  http://astronomy.swin.edu.au/~pbourke/modelling/polygonise
18  *  by Paul Bourke and  Cory Gene Bloyd
19  *
20  *  This program is free software; you can redistribute it and/or modify
21  *  it under the terms of the GNU General Public License as published by
22  *  the Free Software Foundation; either version 3 of the License, or
23  *  (at your option) any later version.
24  *
25  *  This program is distributed in the hope that it will be useful,
26  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
27  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28  *  GNU General Public License for more details.
29  *
30  *  You should have received a copy of the GNU General Public License
31  *  along with this program. If not, see <http://www.gnu.org/licenses/>.
32  */
33 
34 #include "giacPCH.h"
35 
36 using namespace std;
37 #if !defined NSPIRE && !defined FXCG && !defined KHICAS
38 #ifdef VISUALC13
39 #undef clock
40 #undef clock_t
41 #endif
42 #include <iomanip>
43 #endif
44 #if !defined GIAC_HAS_STO_38 && !defined NSPIRE && !defined FXCG && !defined POCKETCAS
45 #include <fstream>
46 #endif
47 #include "vector.h"
48 #include <algorithm>
49 #include <cmath>
50 
51 #if 0
52 #include<ext/stdio_filebuf.h>
53 
54 typedef std::basic_ofstream<char>::__filebuf_type buffer_t;
55 typedef __gnu_cxx::stdio_filebuf<char>            io_buffer_t;
cfile_impl(buffer_t * const fb)56 FILE* cfile_impl(buffer_t* const fb){
57     return (static_cast<io_buffer_t* const>(fb))->file(); //type std::__c_file
58 }
59 
cfile(std::ofstream const & ofs)60 FILE* cfile(std::ofstream const& ofs){return cfile_impl(ofs.rdbuf());}
cfile(std::ifstream const & ifs)61 FILE* cfile(std::ifstream const& ifs){return cfile_impl(ifs.rdbuf());}
62 #endif
63 
64 // C headers
65 #include <stdio.h>
66 #ifndef __VISUALC__
67 #if !defined RTOS_THREADX && !defined BESTA_OS && !defined FREERTOS && !defined FXCG
68 #include <fcntl.h>
69 #endif
70 #endif // __VISUALC__
71 #ifdef FXCG
72 extern "C" {
73 #include <keyboard.h>
74 }
75 #endif
76 
77 // Giac headers
78 #include "gen.h"
79 #include "usual.h"
80 #include "prog.h"
81 #include "rpn.h"
82 #include "identificateur.h"
83 #include "subst.h"
84 #include "symbolic.h"
85 #include "derive.h"
86 #include "solve.h"
87 #include "intg.h"
88 #include "path.h"
89 #include "sym2poly.h"
90 #include "input_parser.h"
91 #include "input_lexer.h"
92 #include "ti89.h"
93 #include "isom.h"
94 #include "unary.h"
95 #include "plot.h"
96 #include "plot3d.h"
97 #include "ifactor.h"
98 #include "gauss.h"
99 #include "misc.h"
100 #include "lin.h"
101 #include "quater.h"
102 #include "giacintl.h"
103 #ifdef USE_GMP_REPLACEMENTS
104 #undef HAVE_GMPXX_H
105 #undef HAVE_LIBMPFR
106 #endif
107 
108 #ifdef HAVE_UNISTD_H
109 #include <unistd.h>
110 #endif
111 #ifdef HAVE_SYS_TYPES_H
112 #include <sys/types.h>
113 #endif
114 #ifdef HAVE_SYS_TIME_H
115 #include <sys/time.h>
116 #else
117 #ifndef BESTA_OS
118 #define clock_t int
119 //#define CLOCK() 0
120 #endif
121 #endif
122 #ifndef HAVE_NO_SYS_RESOURCE_WAIT_H
123 #include <sys/resource.h>
124 #include <sys/wait.h>
125 #endif
126 
127 #if defined GIAC_HAS_STO_38 || defined NSPIRE || defined NSPIRE_NEWLIB || defined FXCG || defined GIAC_GGB || defined USE_GMP_REPLACEMENTS || defined KHICAS
is_graphe(const giac::gen & g,std::string & disp_out,const giac::context *)128 inline bool is_graphe(const giac::gen &g,std::string &disp_out,const giac::context *){ return false; }
_graph_vertices(const giac::gen & g,const giac::context *)129 inline giac::gen _graph_vertices(const giac::gen &g,const giac::context *){ return g;}
_is_planar(const giac::gen & g,const giac::context *)130 inline giac::gen _is_planar(const giac::gen &g,const giac::context *){ return g;}
131 #else
132 #include "graphtheory.h"
133 #endif
134 
135 extern const int BUFFER_SIZE;
136 
137 #ifndef NO_NAMESPACE_GIAC
138 namespace giac {
139 #endif // ndef NO_NAMESPACE_GIAC
140 
141 #ifdef IPAQ
142   int LEGENDE_SIZE=40;
143   int COORD_SIZE=26;
144   int PARAM_STEP=18;
145 #else // IPAQ
146   int LEGENDE_SIZE=100;
147   int COORD_SIZE=30;
148   int PARAM_STEP=20;
149 #endif // IPAQ
150 
151 #ifdef GNUWINCE
152   ofstream * outptr=0;
153 #endif
154   // int plot_instructionsh=300,plot_instructionsw=300;
155 
156 
157   const int _GROUP__VECT_subtype[]={_GROUP__VECT,_LINE__VECT,_HALFLINE__VECT,_VECTOR__VECT,_POLYEDRE__VECT,_POINT__VECT,0};
158 #ifdef IPAQ
159   double gnuplot_xmin=-4,gnuplot_xmax=4,gnuplot_ymin=-4,gnuplot_ymax=4,gnuplot_zmin=-5,gnuplot_zmax=5,gnuplot_tmin=-6,gnuplot_tmax=6,gnuplot_tstep=0.3;
160 #else
161   double gnuplot_xmin=-5,gnuplot_xmax=5,gnuplot_ymin=-5,gnuplot_ymax=5,gnuplot_zmin=-5,gnuplot_zmax=5,gnuplot_tmin=-6,gnuplot_tmax=6,gnuplot_tstep=0.1;
162 #endif
163   double global_window_xmin(gnuplot_xmin),global_window_xmax(gnuplot_xmax),global_window_ymin(gnuplot_ymin),global_window_ymax(gnuplot_ymax);
164   double x_tick(1.0),y_tick(1.0);
165   double class_minimum(0.0),class_size(1.0);
166 #if defined RTOS_THREADX || defined EMCC || defined KHICAS
167   int gnuplot_pixels_per_eval=128;
168 #else
169   int gnuplot_pixels_per_eval=401;
170 #endif
171   bool autoscale=true;
172 
173   bool has_gnuplot=true;
174 
175   bool fastcurveprint=false;
176 
rand_complex()177   static gen rand_complex(){
178     int i=std_rand(),j=std_rand();
179     i=i/(RAND_MAX/10)-5;
180     j=j/(RAND_MAX/10)-5;
181     return i+j*cst_i;
182   }
183 
abs_norm(const gen & g,GIAC_CONTEXT)184   gen abs_norm(const gen & g,GIAC_CONTEXT){
185     if (g.type==_VECT)
186       return sqrt(dotvecteur(*g._VECTptr,*g._VECTptr),contextptr);
187     else
188       return abs(g,contextptr);
189   }
190 
abs_norm(const gen & a,const gen & b,GIAC_CONTEXT)191   gen abs_norm(const gen & a,const gen & b,GIAC_CONTEXT){
192     if (a.type==_VECT)
193       return abs_norm(b-a,contextptr);
194     gen ax,ay,bx,by;
195     reim(a,ax,ay,contextptr);
196     reim(b,bx,by,contextptr);
197     bx -= ax;
198     by -= ay;
199     return sqrt(bx*bx+by*by,contextptr);
200   }
201 
abs_norm2(const gen & g,GIAC_CONTEXT)202   gen abs_norm2(const gen & g,GIAC_CONTEXT){
203     if (g.type==_VECT)
204       return dotvecteur(*g._VECTptr,*g._VECTptr);
205     else
206       return ratnormal(_lin(g*conj(g,contextptr),contextptr),contextptr);
207   }
208 
dotvecteur(const gen & a,const gen & b,GIAC_CONTEXT)209   gen dotvecteur(const gen & a,const gen & b,GIAC_CONTEXT){
210     return scalar_product(a,b,contextptr);
211     /*
212       if (a.type==_VECT)
213       return dotvecteur(*a._VECTptr,*b._VECTptr);
214       else
215       return -im(a*conj(cst_i*b,contextptr),contextptr);
216     */
217   }
218 
set3derr(GIAC_CONTEXT)219   static gen set3derr(GIAC_CONTEXT){
220     return gensizeerr(contextptr); // 2-d instruction
221   }
222 
in_autoname_plus_plus(string & autoname)223   static void in_autoname_plus_plus(string & autoname){
224     int labs=int(autoname.size());
225     if (!labs){
226       autoname="A";
227       labs=1;
228     }
229 #ifdef GIAC_HAS_STO_38
230     int labsmin=1;
231 #else
232     int labsmin=0;
233 #endif
234     for (;labs>labsmin;--labs){
235       char c=autoname[labs-1];
236       if (c!='Z' && c!='z'){
237 	autoname[labs-1]=char(c+1);
238 	return;
239       }
240       autoname[labs-1]='A';
241     }
242     if (labs==labsmin)
243       autoname += 'A';
244   }
245 
autoname_plus_plus(string & autoname)246   void autoname_plus_plus(string & autoname){
247 #ifdef GIAC_HAS_STO_38
248     if (autoname.size()==2 && autoname[0]=='G' && autoname[1]<'Z'){
249       if (autoname[1]=='E')
250 	autoname[1]='G';
251       else {
252 	if (autoname[1]=='Z')
253 	  autoname[1]='a';
254 	else
255 	  ++autoname[1];
256       }
257       return;
258     }
259 #endif
260     for (;;){
261       in_autoname_plus_plus(autoname);
262       if (gen(autoname,context0).type==_IDNT) // FIXME GIAC_CONTEXT
263 	break;
264     }
265   }
266 
267 #ifdef WITH_GNUPLOT
268   string PICTautoname("A");
269 
PICTautoname_plus_plus()270   void PICTautoname_plus_plus(){
271     autoname_plus_plus(PICTautoname);
272   }
273 #endif
274 
275   // find last at_erase in history, return next position (or 0 if not found)
erase_pos(GIAC_CONTEXT)276   int erase_pos(GIAC_CONTEXT){
277     int s=int(history_out(contextptr).size());
278     if (!s)
279       return s;
280     gen e;
281     for (int i=s-1;i>=0;--i){
282       e=history_out(contextptr)[i];
283       if ( (e.type==_SYMB && (e._SYMBptr->sommet==at_erase
284 			      // || equalposcomp(implicittex_plot_sommets,e._SYMBptr->sommet)
285 			      )) ||
286 	   (e.type==_FUNC && (*e._FUNCptr==at_erase
287 			      // || equalposcomp(implicittex_plot_sommets,e._SYMBptr->sommet)
288 			      ) ) )
289 	return i+1;
290     }
291     return 0;
292     // int i=history_out(contextptr).find_last_of(at_erase);
293   }
294 
erase_pos(int current,GIAC_CONTEXT)295   int erase_pos(int current,GIAC_CONTEXT){
296     int s=int(history_out(contextptr).size());
297     if (current>=s)
298       current=s-1;
299     if (!s)
300       return s;
301     gen e;
302     for (int i=current;i>=0;--i){
303       e=history_out(contextptr)[i];
304       if ( (e.type==_SYMB && (e._SYMBptr->sommet==at_erase
305 			      // || equalposcomp(implicittex_plot_sommets,e._SYMBptr->sommet)
306 			      )) ||
307 	   (e.type==_FUNC && (*e._FUNCptr==at_erase
308 			      // || equalposcomp(implicittex_plot_sommets,e._SYMBptr->sommet)
309 			      ) ) )
310 	return i+1;
311     }
312     return 0;
313     // int i=history_out(contextptr).find_last_of(at_erase);
314   }
315 
316 
remove_at_pnt(const gen & e)317   gen remove_at_pnt(const gen & e){
318     int t=e.type;
319     if (t==_VECT && e.subtype==_GGB__VECT){
320       if (e._VECTptr->size()==2)
321 	return e._VECTptr->front()+cst_i*e._VECTptr->back();
322       if (e._VECTptr->size()==3)
323 	return change_subtype(e,_POINT__VECT);
324     }
325     if (t==_SYMB && e._SYMBptr->sommet==at_pnt){
326       const gen & f = e._SYMBptr->feuille;
327 #if 1
328       if (f.type==_VECT){
329 	const vecteur & v = *f._VECTptr;
330 	if (!v.empty())
331 	  return v.front();
332       }
333 #else
334       if (f.type==_VECT){
335 	vecteur & v = *f._VECTptr;
336 	/*
337 	int s=int(v.size());
338 	if (s){
339 	    if (s>1 && v[1].type==_VECT){
340 	    gen & v1=v[1];
341 	    if (v1.type==_VECT && v1._VECTptr->size()>1){
342 	    gen v12=(*v1._VECTptr)[1];
343 	    if (v12.type<=_CPLX)
344 	    return v12;
345 	    if (v12.type==_STRNG){
346 	    string s=*v12._STRNGptr;
347 	    if (!s.empty() && s[s.size()-1]==' '){
348 	    gen g(s,context0);
349 	    if (g.is_symb_of_sommet(at_equal))
350 	    return g._SYMBptr->feuille._VECTptr->back();
351 	    }
352 	    }
353 	    }
354 	    }
355 	  */
356 	  return v.front();
357 	}
358       }
359 #endif
360       return gensizeerr("Bad pnt argument");
361     }
362     return e;
363   }
364 
365   /*
366     static gen unsubtype(const gen & g){
367     return (g.type==_VECT)?gen(*g._VECTptr):g;
368     }
369   */
370 
remove_sto(const gen & e)371   gen remove_sto(const gen & e){
372     if ( (e.type==_SYMB) && (e._SYMBptr->sommet==at_sto))
373       return e._SYMBptr->feuille._VECTptr->back();
374     else
375       return e;
376   }
377 
selection2vecteur(const vector<int> & selected,GIAC_CONTEXT)378   vecteur selection2vecteur(const vector<int> & selected,GIAC_CONTEXT){
379     int i=erase_pos(contextptr);
380     vecteur res;
381     vector<int>::const_iterator it=selected.begin(),itend=selected.end();
382     for (;it!=itend;++it){
383       gen e=history_in(contextptr)[i+*it];
384       if ( (e.type==_SYMB) && (e._SYMBptr->sommet==at_sto))
385 	res.push_back(e._SYMBptr->feuille._VECTptr->back());
386       else
387 	res.push_back(e);
388     }
389     return res;
390   }
391 
selection2vecteureval(const vector<int> & selected,GIAC_CONTEXT)392   vecteur selection2vecteureval(const vector<int> & selected,GIAC_CONTEXT){
393     int i=erase_pos(contextptr);
394     vecteur res;
395     vector<int>::const_iterator it=selected.begin(),itend=selected.end();
396     for (;it!=itend;++it){
397       gen e=history_out(contextptr)[i+*it];
398       res.push_back(e);
399     }
400     return res;
401   }
402 
is_segment(const gen & e)403   bool is_segment(const gen & e){
404     gen f=remove_at_pnt(e);
405     if ( (f.type!=_VECT) || (f._VECTptr->size()!=2))
406       return false;
407     return true;
408   }
409 
findfirstpoint(const vecteur & v)410   int findfirstpoint(const vecteur & v){
411     const_iterateur it=v.begin(),itend=v.end();
412     gen p;
413     for (;it!=itend;++it){
414       p=*it;
415       if ( (p.type==_SYMB) && (p._SYMBptr->sommet==at_pnt)){
416 	p=p._SYMBptr->feuille._VECTptr->front();
417 	if ( (p.type!=_VECT || p.subtype==_POINT__VECT) && ( (p.type!=_SYMB) || (!equalposcomp(not_point_sommets,p._SYMBptr->sommet))) )
418 	  return int(it-v.begin());
419       }
420     }
421     return -1;
422   }
423 
findfirstcercle(const vecteur & v)424   int findfirstcercle(const vecteur & v){
425     const_iterateur it=v.begin(),itend=v.end();
426     gen p;
427     for (;it!=itend;++it){
428       p=*it;
429       if ( (p.type==_SYMB) && (p._SYMBptr->sommet==at_pnt)){
430 	p=p._SYMBptr->feuille._VECTptr->front();
431 	if ( (p.type==_SYMB) && (p._SYMBptr->sommet==at_cercle) )
432 	  return int(it-v.begin());
433       }
434     }
435     return -1;
436   }
437 
symb_curve(const gen & source,const gen & plot)438   symbolic symb_curve(const gen & source,const gen & plot){
439     return symbolic(at_curve,gen(makevecteur(source,plot),_GROUP__VECT));
440   }
symb_perpendiculaire(const gen & aa)441   static symbolic symb_perpendiculaire(const gen & aa){
442     gen a(aa);
443     if (a.type==_VECT) a.subtype=_SEQ__VECT;
444     return symbolic(at_perpendiculaire,a);
445   }
symb_milieu(const gen & aa)446   static symbolic symb_milieu(const gen & aa){
447     gen a(aa);
448     if (a.type==_VECT) a.subtype=_SEQ__VECT;
449     return symbolic(at_milieu,a);
450   }
symb_plotfunc(const gen & a,const gen & b)451   static symbolic symb_plotfunc(const gen & a,const gen & b){
452     return symbolic(at_plotfunc,makesequence(a,b));
453   }
setplotfuncerr()454   static gen setplotfuncerr(){
455     return gensizeerr(gettext("Plotfunc: bad variable name"));
456   }
457 
458   // find best int in selected (and modify selected)
459   // p is the pointed mouse point, eps the precision
460   // try_perp=-1 if no try of perp line, =an history_position otherwise
find_best(vector<int> & selected,const gen & p,double eps,int try_perp_history_pos,int & pnt_pos,int & history_position,gen & res,GIAC_CONTEXT)461   bool find_best(vector<int> & selected,const gen & p,double eps,int try_perp_history_pos,int & pnt_pos,int & history_position,gen & res,GIAC_CONTEXT){
462     vecteur v=selection2vecteur(selected,contextptr),w=selection2vecteureval(selected,contextptr);
463     pnt_pos=findfirstpoint(w);
464     if (pnt_pos<0){ // no point nearby, try to make one
465       // try intersection or midpoint
466       int nsegments=0,n1=-1,n2=-1;
467       const_iterateur it=w.begin(),itend=w.end();
468       for (;it!=itend;++it){
469 	if (is_segment(*it)){
470 	  ++nsegments;
471 	  n2=int(it-w.begin());
472 	  if (n1<0)
473 	    n1=n2;
474 	}
475       }
476       if (nsegments>=2){
477 	history_position=erase_pos(contextptr)+selected[n1];
478 	gen l1=remove_sto(history_in(contextptr)[history_position]);
479 	history_position=erase_pos(contextptr)+selected[n2];
480 	gen l2=remove_sto(history_in(contextptr)[history_position]);
481 	res = symbolic(at_head,symbolic(at_inter,makesequence(l1,l2)));
482 	selected=vector<int>(2);
483 	selected[0]=n1;
484 	selected[1]=n2;
485 	return true;
486       }
487       if (nsegments){ // near middle point?
488 	gen m=remove_at_pnt(_milieu(w[n1],0));
489 	if (!is_undef(m) && is_greater(eps,abs(p-m,contextptr),contextptr)){
490 	  history_position=erase_pos(contextptr)+selected[n1];
491 	  gen l1=remove_sto(history_in(contextptr)[history_position]);
492 	  res=symb_milieu(l1);
493 	  selected=vector<int>(1,n1);
494 	  return true;
495 	}
496 	// near perp?
497 	if (try_perp_history_pos>=0){
498 	  m=remove_at_pnt(history_out(contextptr)[try_perp_history_pos]);
499 	  gen pm=p-m;
500 	  gen wv=remove_at_pnt(w[n1]);
501 	  wv=wv._VECTptr->front()-wv._VECTptr->back();
502 	  if (is_greater(eps*abs(pm,contextptr)*abs(wv,contextptr),scalar_product(pm,wv,contextptr),contextptr)){
503 	    history_position=erase_pos(contextptr)+selected[n1];
504 	    gen l1=remove_sto(history_in(contextptr)[history_position]);
505 	    res=symb_perpendiculaire(makevecteur(remove_sto(history_in(contextptr)[try_perp_history_pos]),l1));
506 	    res=symbolic(at_head,symbolic(at_inter,makesequence(l1,res)));
507 	    selected=vector<int>(1,n1);
508 	    return true;
509 	  }
510 	}
511       }
512       // try a cercle
513       pnt_pos=findfirstcercle(w);
514       if (pnt_pos<0)
515 	return false;
516       history_position=erase_pos(contextptr)+selected[pnt_pos];
517       res=remove_sto(history_in(contextptr)[history_position]);
518       return true;
519     }
520     else {
521       history_position=erase_pos(contextptr)+selected[pnt_pos];
522       res=remove_sto(history_in(contextptr)[history_position]);
523       return true;
524     }
525   }
526 
streamcopy(FILE * source,FILE * target)527   void streamcopy(FILE * source,FILE * target){
528     char c;
529     for (;!feof(source);){
530       c=fgetc(source);
531       if (!feof(source))
532 	fputc(c,target);
533     }
534     fclose(source);
535   }
536 
537 #if !defined VISUALC && ! defined __MINGW_H && !defined BESTA_OS && !defined FXCG
set_nonblock_flag(int desc,int value)538   int set_nonblock_flag (int desc, int value){
539     int oldflags = fcntl (desc, F_GETFL, 0);
540     /* If reading the flags failed, return error indication now. */
541     if (oldflags == -1)
542       return -1;
543     /* Set just the flag we want to set. */
544     if (value != 0)
545       oldflags |= O_NONBLOCK;
546     else
547       oldflags &= ~O_NONBLOCK;
548     /* Store modified flag word in the descriptor. */
549     return fcntl (desc, F_SETFL, oldflags);
550   }
551 
set_cloexec_flag(int desc,int value)552   int set_cloexec_flag (int desc, int value){
553     int oldflags = fcntl (desc, F_GETFD, 0);
554     /* If reading the flags failed, return error indication now.
555        if (oldflags < 0)
556        return oldflags;
557        // Set just the flag we want to set. */
558     if (value != 0)
559       oldflags |= FD_CLOEXEC;
560     else
561       oldflags &= ~FD_CLOEXEC;
562     /* Store modified flag word in the descriptor. */
563     return fcntl (desc, F_SETFD, oldflags);
564   }
565 #endif
566 
567 #ifdef WITH_GNUPLOT
568   vecteur plot_instructions;
569 
570 #ifdef WIN32
571   static bool win9x=true; // For win95/98/Me we can not pipe to gnuplot
572 #else
573   static bool win9x=false;
574 #endif
575   static pid_t gnuplot_pid=0;
576   string gnuplot_name(giac_gnuplot_location);
577   int gnuplot_fileno=0;
578   bool gnuplot_do_splot=true;
579   int gnuplot_in_pipe[2]={-1,-1},gnuplot_out_pipe[2]={-1,-1};
580   FILE * gnuplot_out_readstream=0;
581 
582 #ifdef IPAQ
583   bool gnuplot_hidden3d=false;
584 #else
585   bool gnuplot_hidden3d=true;
586 #endif
587   bool gnuplot_pm3d=false;
588   static int gnuplot_wait_times=5;
589   string gnuplot_filename("session3d");
590 
ck_gnuplot(string & s)591   bool ck_gnuplot(string & s){
592     if (!access(s.c_str(),R_OK))
593       return true;
594     if (!access("/usr/local/bin/gnuplot",R_OK)){
595       s="/usr/local/bin/gnuplot";
596       return true;
597     }
598     if (!access("/usr/bin/gnuplot",R_OK)){
599       s="/usr/bin/gnuplot";
600       return true;
601     }
602     if (!access((xcasroot()+"gnuplot").c_str(),R_OK)){
603       s=xcasroot()+"gnuplot";
604       return true;
605     }
606     return false;
607   }
608 
run_gnuplot(int & r)609   int run_gnuplot(int & r){
610 #ifdef WIN32
611     has_gnuplot=false;
612     return -1;
613 #ifdef GNUWINCE
614 #endif
615     gnuplot_name=xcasroot()+"pgnuplot.exe";
616 #endif //WIN32
617     if (!gnuplot_pid){ // start a gnuplot process
618       if (!ck_gnuplot(gnuplot_name))
619 	{
620 	  has_gnuplot=false;
621 	  return -1;
622 	}
623       if (pipe(gnuplot_in_pipe) || pipe(gnuplot_out_pipe))
624 	throw(std::runtime_error("Plot error: Unable to create pipe"));
625       gnuplot_pid=fork();
626       if (gnuplot_pid<(pid_t) 0)
627 	throw(std::runtime_error("Plot error: Unable to fork"));
628       if (!gnuplot_pid){ // child process, redirect input/output
629 #ifndef GNUPLOT_IO
630 	int gnuplot_out=open("gnuplot.out",O_WRONLY | O_CREAT);
631 	dup2(gnuplot_out,STDERR_FILENO);
632 	close(gnuplot_out);
633 #else
634 	dup2(gnuplot_out_pipe[1],STDERR_FILENO);
635 	close(gnuplot_out_pipe[1]);
636 	set_cloexec_flag(STDERR_FILENO,0);
637 #endif
638 	dup2(gnuplot_in_pipe[0],STDIN_FILENO);
639 	close(gnuplot_in_pipe[0]);
640 	// cout << errno << '\n';
641 #ifdef IPAQ
642 	execlp("gnuplot","gnuplot -geometry 235x300 -noraise",0);
643 #else
644 	execlp("gnuplot","gnuplot -geometry 500x700 -noraise",0); // start gnuplot
645 #endif
646 	return -1; // in case gnuplot is not found
647       }
648       else {
649 	usleep(10000);
650 	bool clrplot=false;
651 	FILE * stream = open_gnuplot(clrplot,gnuplot_out_readstream,r);
652 	gnuplot_out_readstream=fdopen(r,"r");
653 	gnuplot_wait(r,gnuplot_out_readstream,3);
654 	// close(gnuplot_out_pipe[1]);
655 	// close(gnuplot_in_pipe[0]);
656       }
657     }
658     r=gnuplot_out_pipe[0];
659     return gnuplot_in_pipe[1];
660     return 0;
661   }
662 
open_gnuplot(bool & clrplot,FILE * & gnuplot_out_r,int & r)663   FILE * open_gnuplot(bool & clrplot,FILE * & gnuplot_out_r,int & r){
664     if (win9x){
665       r=-1;
666 #ifdef WIN32
667       gnuplot_name="'"+xcasroot()+"wgnuplot.exe'"; // was xcasroot()+"wgnuplot.exe",
668 #ifdef GNUWINCE
669       gnuplot_name="/gnuplot.exe";
670 #endif
671 #endif
672       FILE * stream= fopen("gnuplot.txt","a");
673       if (!stream)
674 	stream=fopen("gnuplot.txt","w");
675       if (!stream)
676 	setsizeerr(gettext("Gnuplot write error"));
677       return stream;
678     }
679     FILE * res=fdopen(run_gnuplot(r),"w");
680     if (!res)
681       setsizeerr(gettext("Gnuplot write error"));
682 #ifdef __APPLE__
683     if (debug_infolevel)
684       printf("set terminal aqua\n");
685     fprintf(res,"set terminal aqua\n");
686 #endif
687     // CERR << errno << '\n';
688     gnuplot_out_r = gnuplot_out_readstream;
689     // CERR << r << " " << errno << '\n';
690     return res;
691   }
692 
terminal_stream_replot(const char * terminal,FILE * stream,const char * filename)693   void terminal_stream_replot(const char * terminal,FILE * stream,const char * filename){
694 #ifdef IPAQ
695     if (string(terminal)=="png")
696       return;
697 #endif
698 #ifdef __APPLE__
699     if (string(terminal)=="png")
700       return;
701 #endif
702     fprintf(stream,"set terminal %s\nset output \"%s\"\nreplot\nset output\n",terminal,filename);
703     if (debug_infolevel)
704       printf("set terminal %s\nset output \"%s\"\nreplot\nset output\n",terminal,filename);
705 #ifdef WIN32
706     if (debug_infolevel)
707       printf("set terminal windows\n");
708     fprintf(stream,"set terminal windows\n");
709 #else
710 #ifdef __APPLE__
711     if (debug_infolevel)
712       printf("set terminal aqua\n");
713     fprintf(stream,"set terminal aqua\n");
714 #else
715     if (debug_infolevel)
716       printf("set terminal x11\n");
717     fprintf(stream,"set terminal x11\n");
718 #endif
719 #endif
720     fflush(stream);
721   }
722 
terminal_stream_replot(const char * terminal,FILE * stream,int i,const char * file_extension)723   void terminal_stream_replot(const char * terminal,FILE * stream,int i,const char * file_extension){
724     terminal_stream_replot(terminal,stream,(gnuplot_filename+print_INT_(i)+"."+string(file_extension)).c_str());
725   }
726 
gnuplot_wait(int handle,FILE * gnuplot_out_readstream,int ngwait)727   void gnuplot_wait(int handle,FILE * gnuplot_out_readstream,int ngwait){
728 #ifndef GNUPLOT_IO
729     usleep(200000);
730     return;
731 #endif
732     // CERR << "gnuplot_wait " << handle << " " << gnuplot_out_readstream << " " << ngwait << '\n';
733     // wait for gnuplot to be quiet
734     if (handle>0 && gnuplot_out_readstream){
735       int i,ntry=500;
736       for (;ntry;){
737 	usleep(10000);
738 	set_nonblock_flag(handle,1);
739 	i=fgetc(gnuplot_out_readstream);
740 	// CERR << char(i) ;
741 	if (char(i)=='>')
742 	  --ngwait;
743 	set_nonblock_flag(handle,0);
744 	if (i==EOF){
745 	  if (ngwait<=0)
746 	    break;
747 	  usleep(10000);
748 	  --ntry;
749 	}
750 	set_nonblock_flag(handle,1);
751 	while (i!=EOF){
752 	  i=fgetc(gnuplot_out_readstream);
753 	  // CERR << char(i);
754 	  if (char(i)=='>')
755 	    --ngwait;
756 	}
757 	set_nonblock_flag(handle,0);
758       }
759       // fclose(gnuplot_out_readstream);
760       usleep(10000);
761       // CERR << "gnuplot_wait end " << getpid() << " " <<CLOCK() << '\n';
762     }
763     else
764       ;// CERR << "gnuplot wait no input" << '\n';
765   }
766 
terminal_replot(const char * terminal,int i,const char * file_extension)767   bool terminal_replot(const char * terminal,int i,const char * file_extension){
768     if (!has_gnuplot)
769       return 0;
770     if (win9x){
771       FILE * stream2 =fopen("gnuplot.gp","w");
772       FILE * stream =fopen("gnuplot.txt","r");
773       streamcopy(stream,stream2);
774       terminal_stream_replot(terminal,stream2,i,file_extension);
775       system_no_deprecation((gnuplot_name+" gnuplot.gp").c_str());
776     }
777     else {
778       bool clrplot;
779       int r;
780       FILE * gnuplot_out_readstream,* stream = open_gnuplot(clrplot,gnuplot_out_readstream,r);
781       terminal_stream_replot(terminal,stream,i,file_extension);
782       gnuplot_wait(r,gnuplot_out_readstream,gnuplot_wait_times);
783     }
784     return true;
785   }
786 
terminal_replot(const char * terminal,const string & s)787   bool terminal_replot(const char * terminal,const string & s){
788     if (!has_gnuplot)
789       return 0;
790 #ifdef IPAQ
791     if (string(terminal)=="png")
792       return 0;
793 #endif
794 #ifdef __APPLE__
795     if (string(terminal)=="png")
796       return 0;
797 #endif
798     if (win9x){
799       FILE * stream = fopen("gnuplot.txt","r");
800       FILE * stream2 =fopen("gnuplot.gp","w");
801       streamcopy(stream,stream2);
802       terminal_stream_replot(terminal,stream2,s.c_str());
803       system_no_deprecation((gnuplot_name+" gnuplot.gp").c_str());
804     }
805     else {
806       bool clrplot;
807       int r;
808       FILE * gnuplot_out_readstream,* stream = open_gnuplot(clrplot,gnuplot_out_readstream,r);
809       terminal_stream_replot(terminal,stream,s.c_str());
810       gnuplot_wait(r,gnuplot_out_readstream,gnuplot_wait_times);
811     }
812     return true;
813   }
814 
win9x_gnuplot(FILE * stream)815   void win9x_gnuplot(FILE * stream){
816     if (!win9x){
817 #ifndef IPAQ
818 #ifndef __APPLE__
819       latex_replot(stream,(gnuplot_filename+print_INT_(gnuplot_fileno)+".tex").c_str());
820       terminal_stream_replot("png",stream,gnuplot_fileno,"png");
821 #endif
822 #endif
823       fflush(stream);
824       return;
825     }
826     fflush(stream);
827     fclose(stream);
828 #ifdef GNUWINCE
829     (*outptr) << "// <plot> </plot>" << '\n';
830     return ;
831 #endif
832     // Copy to a temporary gnuplot
833     unlink("gnuplot.gp");
834     FILE * stream2 = fopen("gnuplot.gp","w");
835     stream = fopen("gnuplot.txt","r");
836     streamcopy(stream,stream2);
837     fprintf(stream2,"pause -1 \"Press RETURN when OK\"\n");
838     latex_replot(stream2,(gnuplot_filename+print_INT_(gnuplot_fileno)+".tex").c_str());
839     terminal_stream_replot("png",stream2,gnuplot_fileno,"png");
840     fflush(stream2);
841     fclose(stream2);
842     system_no_deprecation((gnuplot_name+" gnuplot.gp").c_str());
843   }
844 
kill_gnuplot()845   void kill_gnuplot(){
846     if (gnuplot_pid){
847       FILE *stream;
848       stream = fdopen (gnuplot_in_pipe[1], "w");
849       fprintf(stream,"\n\nq\n");
850       if (fclose(stream))
851 	CERR << "Error closing gnuplot" << '\n';
852     }
853   }
854 
png_replot(int i)855   bool png_replot(int i){
856     return terminal_replot("png",i,"png");
857   }
858 
png_replot(const string & s)859   bool png_replot(const string & s){
860     return terminal_replot("png",s);
861   }
862 
gnuplot_traduit(const gen & g)863   string gnuplot_traduit(const gen & g){
864     string s(evalf(g,1,0).print());
865     string f_s(s),ff_s;
866     string::iterator it=f_s.begin(),itend=f_s.end();
867     for (;it!=itend;++it){
868       if (*it=='^')
869 	ff_s += "**";
870       else
871 	ff_s += *it;
872     }
873     return  ff_s;
874   }
875 
876 #endif // WITH_GNUPLOT
877 
plotpreprocess(gen & g,vecteur & quoted,GIAC_CONTEXT)878   static void plotpreprocess(gen & g,vecteur & quoted,GIAC_CONTEXT){
879     gen tmp=eval(g,contextptr);
880     if (tmp.type==_IDNT){
881       g=tmp;
882       quoted=vecteur(1,tmp);
883       return;
884     }
885     if (tmp.type==_VECT){
886       bool done=true;
887       const_iterateur it=tmp._VECTptr->begin(),itend=tmp._VECTptr->end();
888       if (it!=itend){
889 	for (;it!=itend;++it){
890 	  if (it->type!=_IDNT && !it->is_symb_of_sommet(at_at))
891 	    break;
892 	}
893 	if (it==itend){
894 	  g=tmp;
895 	  quoted=*tmp._VECTptr;
896 	}
897         else
898 	  done=false;
899       }
900       else
901 	done=false;
902       if (!done){
903 	if (g.type==_VECT)
904 	  quoted=*g._VECTptr;
905 	else
906 	  quoted=vecteur(1,g);
907       }
908     }
909     else {
910       quoted=vecteur(1,g);
911     }
912   }
913 
quote_eval(const vecteur & v,const vecteur & quoted,GIAC_CONTEXT)914   vecteur quote_eval(const vecteur & v,const vecteur & quoted,GIAC_CONTEXT){
915     /*
916       vecteur l(quoted);
917       lidnt(v,l);
918       int qs=quoted.size();
919       l=vecteur(l.begin()+qs,l.end());
920       vecteur lnew=*eval(l,1,contextptr)._VECTptr;
921       vecteur w=subst(v,l,lnew,true,contextptr);
922       return w;
923     */
924     const_iterateur it=quoted.begin(),itend=quoted.end();
925     vector<int> save;
926     for (;it!=itend;++it){
927       gen tmp=*it;
928       if (is_equal(tmp))
929 	tmp=tmp._SYMBptr->feuille._VECTptr->front();
930       if (tmp.type!=_IDNT)
931 	save.push_back(-1);
932       else {
933 	if (contextptr && contextptr->quoted_global_vars){
934 	  contextptr->quoted_global_vars->push_back(tmp);
935 	  save.push_back(0);
936 	}
937 	else {
938 	  if (tmp._IDNTptr->quoted){
939 	    save.push_back(*tmp._IDNTptr->quoted);
940 	    *tmp._IDNTptr->quoted=1;
941 	  }
942 	  else
943 	    save.push_back(0);
944 	}
945       }
946     }
947     vecteur res(v);
948     int s=int(v.size());
949     for (int i=0;i<s;++i){
950 #ifndef NO_STDEXCEPT
951       try {
952 #endif
953 	bool done=false;
954 	if (v[i].is_symb_of_sommet(at_prod) && v[i]._SYMBptr->feuille.type==_VECT){ // hack for polarplot using re(rho)
955 	  vecteur vi = *v[i]._SYMBptr->feuille._VECTptr;
956 	  if (!vi.empty() && vi.front().is_symb_of_sommet(at_re)){
957 	    vi.front()=vi.front()._SYMBptr->feuille;
958 	    gen tmp=eval(vi,contextptr);
959 	    if (tmp.type==_VECT){
960 	      vi=*tmp._VECTptr;
961 	      vi.front()=symbolic(at_re,vi.front());
962 	      res[i]=_prod(vi,contextptr);
963 	      done=true;
964 	    }
965 	  }
966 	}
967 	if (!done){
968 #if 0
969 	  vecteur lv=lidnt(v[i]);
970 	  vecteur lw(lv);
971 	  for (int j=0;j<int(lw.size());++j){
972 	    gen g=eval(lv[j],1,contextptr);
973 	    g=ifte2when(g,contextptr);
974 	    lw[j]=g;
975 	  }
976 	  res[i]=quotesubst(v[i],lv,lw,contextptr); // otherwise plots with if else fails (error not catched with emscripten)
977 #endif
978 	  res[i]=eval(v[i],contextptr);
979 	}
980 #ifndef NO_STDEXCEPT
981       } catch (std::runtime_error & ){
982 	last_evaled_argptr(contextptr)=NULL;
983 	//    *logptr(contextptr) << e.what() << '\n';
984       }
985 #endif
986     }
987     it=quoted.begin();
988     for (int i=0;it!=itend;++it,++i){
989       if (save[i]>=0){
990 	if (contextptr && contextptr->quoted_global_vars)
991 	  contextptr->quoted_global_vars->pop_back();
992 	else {
993 	  gen tmp=*it;
994 	  if (is_equal(tmp))
995 	    tmp=tmp._SYMBptr->feuille._VECTptr->front();
996 	  if (tmp.type==_IDNT && tmp._IDNTptr->quoted)
997 	    *tmp._IDNTptr->quoted=save[i]>0?save[i]:0;
998 	}
999       }
1000     }
1001     return res;
1002   }
1003 
1004   // args -> vector
1005   // add vx_var if args is not a seq
1006   // evaluate v[1], if it's not an idnt or a vector of idnt keep v[1]
1007   // evaluate v with v[1] quoted
plotpreprocess(const gen & args,GIAC_CONTEXT)1008   vecteur plotpreprocess(const gen & args,GIAC_CONTEXT){
1009     vecteur v;
1010     if (args.type==_FUNC)
1011       return makevecteur(args(vx_var,contextptr),vx_var);
1012     gen var,res;
1013     if (args.type!=_VECT && is_algebraic_program(args,var,res))
1014       return makevecteur(args,symb_interval(gnuplot_xmin,gnuplot_xmax));
1015     int nd;
1016     if ( (nd=is_distribution(args)) ){
1017       gen a,b;
1018       if (distrib_support(nd,a,b,true))
1019 	return makevecteur(args,symb_interval(a,b));
1020     }
1021     if ((args.type!=_VECT) || (args.subtype!=_SEQ__VECT) )
1022       v=makevecteur(args,vx_var);
1023     else {
1024       v=*args._VECTptr;
1025       if (v.empty())
1026 	return vecteur(1,gensizeerr(contextptr));
1027       if (v.size()==1)
1028 	v.push_back(vx_var);
1029     }
1030     // find quoted variables from v[1]
1031     vecteur quoted;
1032     if ( v[1].type==_SYMB && (v[1]._SYMBptr->sommet==at_equal || v[1]._SYMBptr->sommet==at_equal2 ||v[1]._SYMBptr->sommet==at_same ))
1033       plotpreprocess(v[1]._SYMBptr->feuille._VECTptr->front(),quoted,contextptr);
1034     else
1035       plotpreprocess(v[1],quoted,contextptr);
1036     return quote_eval(v,quoted,contextptr);
1037   }
1038 
pnt_attrib(const gen & point,const vecteur & attributs,GIAC_CONTEXT)1039   gen pnt_attrib(const gen & point,const vecteur & attributs,GIAC_CONTEXT){
1040     if (is_undef(point))
1041       return point;
1042     if (attributs.empty())
1043       return symb_pnt(point,default_color(contextptr),contextptr);
1044     int s=int(attributs.size());
1045     if (s==1)
1046       return symb_pnt(point,attributs[0],contextptr);
1047     if (s>=3)
1048       return symb_pnt_name(point,symbolic(at_couleur,attributs),attributs[1],contextptr);
1049     return symb_pnt_name(point,attributs[0],attributs[1],contextptr);
1050   }
1051 
print_DOUBLE_(double d,unsigned ndigits)1052   string print_DOUBLE_(double d,unsigned ndigits){
1053     char s[256];
1054 #ifdef KHICAS
1055     sprint_double(s,d);
1056 #else
1057     ndigits=ndigits<2?2:ndigits;
1058     ndigits=ndigits>15?15:ndigits;
1059     sprintfdouble(s,("%."+print_INT_(ndigits)+"g").c_str(),d);
1060 #endif
1061     return s;
1062   }
1063 
1064 #ifdef KHICAS
arc_en_ciel(int k,int & r,int & g,int & b)1065   void arc_en_ciel(int k,int & r,int & g,int & b){
1066     k += 21;
1067     k %= 126;
1068     if (k<0)
1069       k += 126;
1070     if (k<21){
1071       r=251; g=0; b=12*k;
1072     }
1073     if (k>=21 && k<42){
1074       r=251-(12*(k-21)); g=0; b=251;
1075     }
1076     if (k>=42 && k<63){
1077       r=0; g=(k-42)*12; b=251;
1078     }
1079     if (k>=63 && k<84){
1080       r=0; g=251; b=251-(k-63)*12;
1081     }
1082     if (k>=84 && k<105){
1083       r=(k-84)*12; g=251; b=0;
1084     }
1085     if (k>=105 && k<126){
1086       r=251; g=251-(k-105)*12; b=0;
1087     }
1088   }
1089 
rgb888to565(int c)1090   int rgb888to565(int c){
1091     int r=(c>>16)&0xff,g=(c>>8)&0xff,b=c&0xff;
1092     return (((r*32)/256)<<11) | (((g*64)/256)<<5) | (b*32/256);
1093   }
1094 
1095   static const int arc_en_ciel_colors=15;
density(double z,double fmin,double fmax)1096   int density(double z,double fmin,double fmax){
1097     // z -> 256+arc_en_ciel_colors*(z-fmin)/(fmax-fmin)
1098     if (z<fmin)
1099       return 0;
1100     if (z>fmax)
1101       return 0;
1102     double d=(z-fmin)/(fmax-fmin);
1103     int r,g,b;
1104     arc_en_ciel(126.0/d,r,g,b);
1105     return (((r*32)/256)<<11) | (((g*64)/256)<<5) | (b*32/256);
1106   }
1107 
1108 #else
1109   static const int arc_en_ciel_colors=105;
density(double z,double fmin,double fmax)1110   inline int density(double z,double fmin,double fmax){
1111     // z -> 256+arc_en_ciel_colors*(z-fmin)/(fmax-fmin)
1112     if (z<fmin)
1113       return 256;
1114     if (z>fmax)
1115       return 256+arc_en_ciel_colors;
1116     return 256+int(arc_en_ciel_colors*(z-fmin)/(fmax-fmin));
1117   }
1118 
1119 #endif
1120 
1121   // horizontal scale for colors
densityscale(double xmin,double xmax,double ymin,double ymax,double fmin,double fmax,int n,GIAC_CONTEXT)1122   static vecteur densityscale(double xmin,double xmax,double ymin,double ymax,double fmin, double fmax,int n,GIAC_CONTEXT){
1123     vecteur res;
1124     if (n<10)
1125       n=10;
1126     if (n>100)
1127       n=100;
1128     double dx=(xmax-xmin)/n;
1129     double x=xmin;
1130     for (int i=0;i<n;i++){
1131       gen A(x,ymin);
1132       gen B(x,ymax);
1133       x+=dx;
1134       gen C(x,ymax);
1135       gen D(x,ymin);
1136       int rgb;
1137 #ifdef KHICAS
1138       int r,g,b;
1139       arc_en_ciel(i*double(126.0)/n,r,g,b);
1140       rgb=(((r*32)/256)<<11) | (((g*64)/256)<<5) | (b*32/256);
1141       vecteur attrib(1,rgb+_FILL_POLYGON+(i?_QUADRANT4:_QUADRANT3));
1142 #else
1143       rgb=256+int(i*double(arc_en_ciel_colors)/n);
1144       vecteur attrib(1,rgb+_FILL_POLYGON+(i?_QUADRANT4:_QUADRANT2));
1145 #endif
1146 #ifdef KHICAS
1147       if (!i)
1148 	attrib.push_back(string2gen(print_DOUBLE_(fmin,contextptr),false));
1149       if (i==n-1)
1150 	attrib.push_back(string2gen(print_DOUBLE_(fmax,contextptr),false));
1151 #else
1152       if (!i)
1153 	attrib.push_back(string2gen(print_DOUBLE_(fmin,4),false));
1154       if (i==n-1)
1155 	attrib.push_back(string2gen(print_DOUBLE_(fmax,4),false));
1156 #endif
1157       res.push_back(pnt_attrib(gen((i?makevecteur(D,A,B,C,D):makevecteur(B,C,D,A,B)),_GROUP__VECT),attrib,contextptr));
1158     }
1159     return res;
1160   }
1161 
1162   // return a vector of values with simple decimal representation
1163   // between xmin/xmax or including xmin/xmax (if bounds is true)
ticks(double xmin,double xmax,bool bounds)1164   vecteur ticks(double xmin,double xmax,bool bounds){
1165     if (xmax<xmin)
1166       swapdouble(xmin,xmax);
1167     double dx=xmax-xmin;
1168     vecteur res;
1169     if (dx==0)
1170       return res;
1171     double d=std::pow(10.0,std::floor(std::log10(dx)));
1172     if (dx<2*d)
1173       d=d/5;
1174     else {
1175       if (dx<5*d)
1176 	d=d/2;
1177     }
1178     double x1=std::floor(xmin/d)*d;
1179     double x2=(bounds?std::ceil(xmax/d):std::floor(xmax/d))*d;
1180     for (double x=x1+(bounds?0:d);x<=x2;x+=d){
1181       if ( absdouble(x-int(x+.5))<1e-6*d)
1182 	res.push_back(int(x+.5));
1183       else
1184 	res.push_back(x);
1185     }
1186     return res;
1187   }
1188 
1189   // return a sequence of filled polygons with a color mapped from fmin..fmax
1190   // to 256..256+125 from a matrix of points
1191   // if regular is true, m is assumed to be equidistributed in x and y
density(const matrice & m,double fmin,double fmax,bool regular,GIAC_CONTEXT)1192   static vecteur density(const matrice & m,double fmin,double fmax,bool regular,GIAC_CONTEXT){
1193 #ifdef RTOS_THREADX
1194     return vecteur(1,undef);
1195 #else
1196     if (!ckmatrix(m,true))
1197       return vecteur(1,undef);
1198     int r=int(m.size()); // imax
1199     int c=int(m.front()._VECTptr->size()); // jmax
1200     if (regular){
1201       vector< vector< double > > fij;
1202       double Fmax=-1e307,Fmin=1e307;
1203       fij.reserve(r);
1204       double nan=0.0;
1205       nan=nan/nan;
1206       for (int i=0;i<r;++i){
1207 	vector<double> tmp;
1208 	tmp.reserve(c);
1209 	for (int j=0;j<c;++j){
1210 	  gen val=m[i][j];
1211 	  if (val.type==_VECT)
1212 	    val=val[2];
1213 	  val=evalf_double(val,eval_level(contextptr),contextptr);
1214 	  if (val.type!=_DOUBLE_)
1215 	    tmp.push_back(nan);
1216 	  else {
1217 	    double vald=val._DOUBLE_val;
1218 	    tmp.push_back(vald);
1219 	    if (vald>Fmax)
1220 	      Fmax=vald;
1221 	    if (vald<Fmin)
1222 	      Fmin=vald;
1223 	  }
1224 	}
1225 	fij.push_back(tmp);
1226       }
1227       if (fmax<=fmin){
1228 	fmax=Fmax;
1229 	fmin=Fmin;
1230       }
1231       double xmin,xmax,dx,ymin,ymax,dy;
1232       gen xymin=m[0][0];
1233       if (xymin.type==_VECT && xymin._VECTptr->size()>=2){
1234 	xmin=xymin[0]._DOUBLE_val;
1235 	ymin=xymin[1]._DOUBLE_val;
1236       }
1237       else {
1238 	xmin=0;
1239 	ymin=-c;
1240       }
1241       gen xymax=m[r-1][c-1];
1242       if (xymax.type==_VECT && xymax._VECTptr->size()>=2){
1243 	xmax=xymax[0]._DOUBLE_val;
1244 	ymax=xymax[1]._DOUBLE_val;
1245       }
1246       else {
1247 	xmax=r;
1248 	ymax=0;
1249       }
1250       dx=(xmax-xmin)/(r-1);
1251       dy=(ymax-ymin)/(c-1);
1252       vecteur lz;
1253       lz.resize(arc_en_ciel_colors);
1254       double df=(fmax-fmin)/arc_en_ciel_colors;
1255       for (int i=0;i<arc_en_ciel_colors;++i)
1256 	lz[i]=fmin+i*df;
1257       vecteur attr(arc_en_ciel_colors);
1258       for (int i=0;i<arc_en_ciel_colors;++i){
1259 #ifdef KHICAS
1260 	int r,g,b;
1261 	arc_en_ciel(126.0/(arc_en_ciel_colors-1)*i,r,g,b);
1262 	attr[i]=_FILL_POLYGON + (((r*32)/256)<<11) | (((g*64)/256)<<5) | (b*32/256);
1263 #else
1264 	attr[i]=_FILL_POLYGON+257+i;
1265 #endif
1266       }
1267       gen rect=pnt_attrib(gen(makevecteur(gen(xmin,ymin),gen(xmax,ymin),gen(xmax,ymax),gen(xmin,ymax),gen(xmin,ymin)),_GROUP__VECT),vecteur(1,_FILL_POLYGON+256),contextptr);
1268       vecteur niveaux=ticks(fmin,fmax,false);
1269       lz=mergevecteur(lz,niveaux);
1270       attr=mergevecteur(attr,vecteur(niveaux.size(),default_color(contextptr)));
1271       vecteur legendes=mergevecteur(vecteur(arc_en_ciel_colors,string2gen("",false)),niveaux);
1272       gen res=plot_array(fij,r,c,xmin,xmax,dx,ymin,ymax,dy,lz,makevecteur(attr,legendes),true,contextptr);
1273       if (res.type==_VECT){
1274 	vecteur v = *res._VECTptr;
1275 	v.insert(v.begin(),rect);
1276 	return v;
1277       }
1278       return makevecteur(rect,res);
1279     }
1280     else {
1281       vecteur res;
1282       for (int i=1;i<r-1;++i){
1283 	vecteur & prec = *m[i-1]._VECTptr;
1284 	vecteur & cur = *m[i]._VECTptr;
1285 	vecteur & next = *m[i+1]._VECTptr;
1286 	for (int j=1;j<c-1;++j){
1287 	  vecteur &m=*cur[j]._VECTptr;
1288 	  gen M=m[0]+cst_i*m[1];
1289 	  if (m[2].type==_DOUBLE_){
1290 	    vecteur &c=*cur[j-1]._VECTptr;
1291 	    vecteur &d=*cur[j+1]._VECTptr;
1292 	    vecteur &a=*prec[j]._VECTptr;
1293 	    vecteur &b=*next[j]._VECTptr;
1294 	    gen x1=(a[0]+m[0])/2;
1295 	    gen x2=(b[0]+m[0])/2;
1296 	    gen y1=(d[1]+m[1])/2;
1297 	    gen y2=(c[1]+m[1])/2;
1298 	    gen A=x1+cst_i*y1;
1299 	    gen B=x1+cst_i*y2;
1300 	    gen C=x2+cst_i*y2;
1301 	    gen D=x2+cst_i*y1;
1302 	    int e=density(m[2]._DOUBLE_val,fmin,fmax);
1303 	    res.push_back(pnt_attrib(gen(makevecteur(A,B,C,D,A),_GROUP__VECT),vecteur(1,e+_FILL_POLYGON),contextptr));
1304 	  }
1305 	}
1306       }
1307       return res;
1308     } // end not regular
1309 #endif
1310   }
1311 
local_sto_double(double value,const identificateur & i,GIAC_CONTEXT)1312   void local_sto_double(double value,const identificateur & i,GIAC_CONTEXT){
1313     control_c();
1314     if (contextptr)
1315       (*contextptr->tabptr)[i.id_name]=value;
1316     else
1317       i.localvalue->back()=value;
1318   }
1319 
local_sto_double_increment(double value,const identificateur & i,GIAC_CONTEXT)1320   void local_sto_double_increment(double value,const identificateur & i,GIAC_CONTEXT){
1321     control_c();
1322     if (contextptr)
1323       (*contextptr->tabptr)[i.id_name] += value;
1324     else
1325       i.localvalue->back() += value;
1326   }
1327 
1328   double max_nstep=2e4;
1329 
plotfunc(const gen & f_,const gen & vars,const vecteur & attributs,bool densityplot,double function_xmin,double function_xmax,double function_ymin,double function_ymax,double function_zmin,double function_zmax,int nstep,int jstep,bool showeq,const context * contextptr)1330   gen plotfunc(const gen & f_,const gen & vars,const vecteur & attributs,bool densityplot,double function_xmin,double function_xmax,double function_ymin,double function_ymax,double function_zmin, double function_zmax,int nstep,int jstep,bool showeq,const context * contextptr){
1331     if (f_.is_symb_of_sommet(at_equal) || is_inequation(f_)){
1332       return string2gen("Try plot(["+f_._SYMBptr->feuille.print(contextptr)+"],"+vars.print(contextptr)+"). (In)equations can not be plotted.",false);
1333     }
1334     gen f=when2piecewise(f_,contextptr);
1335     f=Heavisidetopiecewise(f,contextptr);
1336     double step=(function_xmax-function_xmin)/nstep;
1337     if (debug_infolevel)
1338       CERR << "plot " << f << " x=" << function_xmin << ".." << function_xmax << " " << step << '\n';
1339     if (step<=0 || (function_xmax-function_xmin)/step>max_nstep)
1340       return gensizeerr(gettext("Plotfunc: unable to discretize: xmin, xmax, step=")+print_DOUBLE_(function_xmin,12)+","+print_DOUBLE_(function_xmax,12)+","+print_DOUBLE_(step,12)+gettext("\nTry a larger value for xstep"));
1341     vecteur res;
1342     int color=default_color(contextptr);
1343     gen attribut=attributs.empty()?color:attributs[0];
1344     if (attribut.type==_INT_)
1345       color=attribut.val;
1346     if (f.type==_VECT){ // multi-plot
1347       vecteur & vf=*f._VECTptr;
1348       unsigned s=unsigned(vf.size());
1349       vecteur vattribut;
1350       if (attribut.type==_VECT)
1351 	vattribut=gen2vecteur(attribut);
1352       for (unsigned j=0;j<s;++color,++j)
1353 	vattribut.push_back(color);
1354       vecteur res;
1355       for (unsigned i=0;i<s;++i){
1356 	vecteur cur_attributs(1,vattribut[i]);
1357 	if (attributs.size()>1 && attributs[1].type==_VECT && attributs[1]._VECTptr->size()>i)
1358 	  cur_attributs.push_back((*attributs[1]._VECTptr)[i]);
1359 	gen tmp=plotfunc(vf[i],vars,cur_attributs,false,function_xmin,function_xmax,function_ymin,function_ymax,function_zmin,function_zmax,nstep,jstep,showeq,contextptr);
1360 	if (tmp.type==_VECT)
1361 	  res=mergevecteur(res,*tmp._VECTptr);
1362 	else
1363 	  res.push_back(tmp);
1364       }
1365       return res; // gen(res,_SEQ__VECT);
1366     }
1367 #ifndef GNUWINCE
1368     if (vars.type==_IDNT){ // function plot
1369       gen a,b;
1370       if (taille(f,100)<=100 && is_linear_wrt(f,vars,a,b,contextptr))
1371 	return put_attributs(_segment(makesequence(function_xmin+cst_i*(a*gen(function_xmin)+b),function_xmax+cst_i*(a*gen(function_xmax)+b)),contextptr),attributs,contextptr); // replace segment by droite so that legend=... works?
1372       vecteur lpiece(lop(f,at_piecewise));
1373       if (!lpiece.empty()) lpiece=lvarx(lpiece,vars);
1374       if (!lpiece.empty()){
1375 	gen piece=lpiece.front();
1376 	gen & piecef=piece._SYMBptr->feuille;
1377 	if (piecef.type==_VECT){
1378 	  vecteur piecev=*piecef._VECTptr,res;
1379 	  // check conditions: they must be linear wrt x
1380 	  double function_xmin_save=function_xmin,function_xmax_save=function_xmax;
1381 	  int vs=int(piecev.size()),i;
1382 	  for (i=0;i<vs/2;++i){
1383 	    gen cond=piecev[2*i];
1384 	    if (is_equal(cond) || cond.is_symb_of_sommet(at_same)){
1385 	      *logptr(contextptr) << gettext("Assuming false condition ") << cond << '\n';
1386 	      continue;
1387 	    }
1388 	    if (cond.is_symb_of_sommet(at_different)){
1389 	      *logptr(contextptr) << gettext("Assuming true condition ") << cond << '\n';
1390 	      f=quotesubst(f,piece,piecev[2*i+1],contextptr);
1391 	      return plotfunc(f,vars,attributs,densityplot,function_xmin,function_xmax,function_ymin,function_ymax,function_zmin,function_zmax,nstep,jstep,showeq,contextptr);
1392 	    }
1393 	    bool unable=true;
1394 	    if (cond.is_symb_of_sommet(at_superieur_strict) || cond.is_symb_of_sommet(at_superieur_egal)){
1395 	      cond=cond._SYMBptr->feuille[0]-cond._SYMBptr->feuille[1];
1396 	      unable=false;
1397 	    }
1398 	    if (cond.is_symb_of_sommet(at_inferieur_strict) || cond.is_symb_of_sommet(at_inferieur_egal)){
1399 	      cond=cond._SYMBptr->feuille[1]-cond._SYMBptr->feuille[0];
1400 	      unable=false;
1401 	    }
1402 	    gen a,b,l;
1403 	    if (unable || !is_linear_wrt(cond,vars,a,b,contextptr))
1404 	      break;
1405 	    // check if a*x+b>0 on [borne_inf,borne_sup]
1406 	    l=-b/a;
1407 	    l=evalf_double(l,1,contextptr);
1408 	    if (l.type!=_DOUBLE_)
1409 	      break;
1410 	    bool positif=ck_is_greater(a,0,contextptr);
1411 	    gen tmp=quotesubst(f,piece,piecev[2*i+1],contextptr);
1412 	    if (ck_is_greater(l,function_xmax,contextptr)){
1413 	      // borne_inf < borne_sup <= l
1414 	      if (positif) // test is false, continue
1415 		continue;
1416 	      // test is true make the plot
1417 	      gen curres=plotfunc(tmp,vars,attributs,densityplot,function_xmin,function_xmax,function_ymin,function_ymax,function_zmin,function_zmax,nstep,jstep,showeq,contextptr);
1418 	      if (curres.type==_VECT)
1419 		res = mergevecteur(res,*curres._VECTptr);
1420 	      else
1421 		res.push_back(curres);
1422 	      return res;
1423 	    }
1424 	    if (ck_is_greater(function_xmin,l,contextptr)){
1425 	      // l <= borne_inf < borne_sup
1426 	      if (!positif) // test is false, continue
1427 		continue;
1428 	      // test is true we can compute the integral
1429 	      gen curres=plotfunc(tmp,vars,attributs,densityplot,function_xmin,function_xmax,function_ymin,function_ymax,function_zmin,function_zmax,nstep,jstep,showeq,contextptr);
1430 	      if (curres.type==_VECT)
1431 		res = mergevecteur(res,*curres._VECTptr);
1432 	      else
1433 		res.push_back(curres);
1434 	      return res;
1435 	    }
1436 	    // borne_inf<l<borne_sup
1437 	    if (positif){
1438 	      // make plot between l and borne_sup
1439 	      gen curres = plotfunc(tmp,vars,attributs,densityplot,l._DOUBLE_val,function_xmax,function_ymin,function_ymax,function_zmin,function_zmax,nstep,jstep,showeq,contextptr);
1440 	      if (curres.type==_VECT)
1441 		res = mergevecteur(res,*curres._VECTptr);
1442 	      else
1443 		res.push_back(curres);
1444 	      function_xmax=l._DOUBLE_val; // continue with plot from borne_inf to l
1445 	      continue;
1446 	    }
1447 	    // make plot between borne_inf and l
1448 	    gen curres=plotfunc(tmp,vars,attributs,densityplot,function_xmin,l._DOUBLE_val,function_ymin,function_ymax,function_zmin,function_zmax,nstep,jstep,showeq,contextptr);
1449 	    if (curres.type==_VECT)
1450 	      res = mergevecteur(res,*curres._VECTptr);
1451 	    else
1452 	      res.push_back(curres);
1453 	    function_xmin=l._DOUBLE_val; // continue with plot from l to borne_sup
1454 	  } // end loop on i
1455 	  if (i==vs/2){
1456 	    if (vs%2){
1457 	      f=quotesubst(f,piece,piecev[vs-1],contextptr);
1458 	      gen curres = plotfunc(f,vars,attributs,densityplot,function_xmin,function_xmax,function_ymin,function_ymax,function_zmin,function_zmax,nstep,jstep,showeq,contextptr);
1459 	      if (curres.type==_VECT)
1460 		res = mergevecteur(res,*curres._VECTptr);
1461 	      else
1462 		res.push_back(curres);
1463 	    }
1464 	    return res;
1465 	  } // end i==vs/2
1466 	  // restore xmin/xmax
1467 	  function_xmin=function_xmin_save;
1468 	  function_xmax=function_xmax_save;
1469 	} // end piecef.type==_VECT
1470       } // end piecewise
1471       gen locvar(vars);
1472       locvar.subtype=0;
1473       gen y=quotesubst(f,vars,locvar,contextptr),yy;
1474       // gen y=f.evalf2double(),yy;
1475       double j,entrej,oldj=0,xmin=function_xmin,xmax=function_xmax+step/2;
1476       bool joindre;
1477       vecteur localvar(1,vars);
1478       context * newcontextptr= (context *) contextptr;
1479       int protect=giac_bind(vecteur(1,xmin),localvar,newcontextptr);
1480       vecteur chemin;
1481       double i=xmin;
1482       for (;!ctrl_c && !interrupted && i<xmax;i+= step){
1483 	// yy=evalf_double(subst(f,vars,i,false,contextptr),1,contextptr);
1484 	local_sto_double(i,*vars._IDNTptr,newcontextptr);
1485 	// vars._IDNTptr->localvalue->back()._DOUBLE_val =i;
1486 	yy=y.evalf2double(eval_level(contextptr),newcontextptr);
1487 #ifdef EMCC
1488 	if (yy.is_symb_of_sommet(at_neg))
1489 	  yy=-yy._SYMBptr->feuille.evalf2double(eval_level(contextptr),newcontextptr);
1490 #endif
1491 	if (yy.type!=_DOUBLE_){
1492 	  if (debug_infolevel)
1493 	    CERR << y << " not real at " << i << " value " << yy << " type " << int(yy.type) << '\n';
1494 	  if (!chemin.empty())
1495 	    res.push_back(pnt_attrib(symb_curve(gen(makevecteur(vars+cst_i*f,vars,xmin,i,showeq),_PNT__VECT),gen(chemin,_GROUP__VECT)),attributs.empty()?color:attributs,contextptr));
1496 	  xmin=i;
1497 	  chemin.clear();
1498 	  continue;
1499 	}
1500 	j=yy._DOUBLE_val;
1501 	if (j>function_ymax)
1502 	  function_ymax=j;
1503 	if (j<function_ymin)
1504 	  function_ymin=j;
1505 	if (i!=xmin){
1506 	  if (fabs(oldj-j)>(function_ymax-function_ymin)/5){ // try middle-pnt
1507 	    if (debug_infolevel)
1508 	      CERR << y << " checking step at " << i << " " << yy << '\n';
1509 	    local_sto_double_increment(-step/2,*vars._IDNTptr,newcontextptr);
1510 	    // vars._IDNTptr->localvalue->back()._DOUBLE_val -= step/2;
1511 	    yy=y.evalf2double(eval_level(contextptr),newcontextptr);
1512 	    if (yy.type!=_DOUBLE_)
1513 	      joindre=false;
1514 	    else {
1515 	      entrej=yy._DOUBLE_val;
1516 	      if (j>oldj)
1517 		joindre=(j>=entrej) && (entrej>=oldj);
1518 	      else
1519 		joindre=(j<=entrej) && (entrej<=oldj);
1520 	    }
1521 	    local_sto_double_increment(step/2,*vars._IDNTptr,newcontextptr);
1522 	    // vars._IDNTptr->localvalue->back()._DOUBLE_val += step/2;
1523 	  }
1524 	  else
1525 	    joindre=true;
1526 	}
1527 	else
1528 	  joindre=false;
1529 	if (joindre)
1530 	  chemin.push_back(gen(i,j));
1531 	else {
1532 	  if (!chemin.empty()){
1533 	    if (debug_infolevel){
1534 	      CERR << y << " step at " << i << " " << yy << '\n';
1535 	      CERR << "curve " << chemin.size() << " " << chemin.front() << " .. " << chemin.back() << '\n';
1536 	    }
1537 	    res.push_back(pnt_attrib(symb_curve(gen(makevecteur(vars+cst_i*f,vars,xmin,i,showeq),_PNT__VECT),gen(chemin,_GROUP__VECT)),attributs.empty()?color:attributs,contextptr));
1538 	  }
1539 	  xmin=i;
1540 	  chemin=vecteur(1,gen(i,j));
1541 	}
1542 	oldj=j;
1543       }
1544       if (!chemin.empty()){
1545 	if (debug_infolevel)
1546 	  CERR << "curve " << chemin.size() << " " << chemin.front() << " .. " << chemin.back() << '\n';
1547 	res.push_back(pnt_attrib(symb_curve(gen(makevecteur(vars+cst_i*f,vars,xmin,i-step,showeq),_PNT__VECT),gen(chemin,_GROUP__VECT)),attributs.empty()?color:attributs,contextptr));
1548       }
1549       leave(protect,localvar,newcontextptr);
1550 #ifndef WIN32
1551       //      if (child_id)
1552       //	plot_instructions.push_back(res);
1553 #endif // WIN32
1554       if (res.size()==1)
1555 	return res.front();
1556       // gen e(res,_SEQ__VECT);
1557       return res; // e;
1558     } // end 1-var function plot
1559 #endif
1560     ck_parameter_x(contextptr);
1561     ck_parameter_y(contextptr);
1562     int s=0;
1563     gen var1,var2;
1564     if (vars.type==_VECT){
1565       s=int(vars._VECTptr->size());
1566       if (s>2)
1567 	s=0;
1568       if (s)
1569 	var1=vars._VECTptr->front();
1570       if (s==2)
1571 	var2=vars._VECTptr->back();
1572       if ((var1.type!=_IDNT) || (var2.type!=_IDNT))
1573 	s=0;
1574     }
1575     if (vars.type==_IDNT){
1576       s=1;
1577       var1=vars;
1578     }
1579     if (!s)
1580       return gentypeerr(gettext("Plotfunc 2nd arg must be var or [var1,var2]"));
1581     gen ff=f; // f.evalf(eval_level(contextptr),contextptr);
1582     if (s==1)
1583       ff=makevecteur(t__IDNT_e,subst(ff,*var1._IDNTptr,t__IDNT_e,false,contextptr));
1584     if (s==2){
1585       ff=subst(ff,*var1._IDNTptr,u__IDNT_e,false,contextptr);
1586       ff=subst(ff,*var2._IDNTptr,v__IDNT_e,false,contextptr);
1587       ff=makevecteur(u__IDNT_e,v__IDNT_e,ff);
1588     }
1589     gen r=symb_plotfunc(f,vars);
1590     if (s==2){
1591       gen vars(makevecteur(var1,var2));
1592       vecteur vals(2);
1593       double x=function_xmin,y=function_ymin;
1594       int nu,nv;
1595       if (jstep){
1596 	nu=nstep;
1597 	nv=jstep;
1598       }
1599       else {
1600 	nu=int(std::sqrt(double(nstep)));
1601 	nv=int(std::sqrt(double(nstep)));
1602       }
1603 #ifdef KHICAS
1604       if (nu*nv>25){
1605 	nu=nv=5;
1606       }
1607 #endif
1608       double dx=(function_xmax-function_xmin)/nu;
1609       double dy=(function_ymax-function_ymin)/nv;
1610       double fmin=1e300,fmax=-fmin;
1611       // Compute a grid of values
1612       vecteur values;
1613       for (int i=0;i<=nu;++i,x+=dx){
1614 	y=function_ymin;
1615 	vals[0]=x;
1616 	vecteur tmp;
1617 	for (int j=0;j<=nv;++j,y+=dy){
1618 	  vals[1]=y;
1619 	  gen fval=evalf_double(evalf(subst(f,vars,vals,false,contextptr),eval_level(contextptr),contextptr),1,contextptr);
1620 	  if (fval.type==_DOUBLE_){
1621 	    if (fval._DOUBLE_val<fmin)
1622 	      fmin=fval._DOUBLE_val;
1623 	    if (fval._DOUBLE_val>fmax)
1624 	      fmax=fval._DOUBLE_val;
1625 	  }
1626 	  tmp.push_back(gen(makevecteur(x,y,fval),_POINT__VECT));
1627 	}
1628 	values.push_back(gen(tmp,_GROUP__VECT));
1629       }
1630       if (densityplot){
1631 	if (function_zmin==function_zmax){
1632 	  function_zmin=fmin;
1633 	  function_zmax=fmax;
1634 	}
1635 	dy=(function_ymax-function_ymin)/10;
1636 	dx=(function_xmax-function_xmin)/10;
1637 	r=mergevecteur(density(values,function_zmin,function_zmax,true,contextptr),densityscale(function_xmin+dx,function_xmax-dx,function_ymin-dy,function_ymin-2*dy,function_zmin,function_zmax,20,contextptr));
1638       }
1639       else
1640 	r=pnt_attrib(hypersurface(gen(makevecteur(makevecteur(var1,var2,f),makevecteur(var1,var2),makevecteur(function_xmin,function_ymin),makevecteur(function_xmax,function_ymax),gen(values,_GROUP__VECT)),_PNT__VECT),z__IDNT_e-f,makevecteur(var1,var2,z__IDNT_e)),attributs.empty()?color:attributs,contextptr);
1641     }
1642     if (!has_gnuplot)
1643       return r;
1644 #ifdef WITH_GNUPLOT
1645     int out_handle;
1646     bool clrplot=false;
1647     FILE * gnuplot_out_readstream,* stream = open_gnuplot(clrplot,gnuplot_out_readstream,out_handle);
1648     int ng=0;
1649 #ifdef IPAQ
1650     fprintf(stream,"set samples 10\n");
1651     ++ng;
1652     //    fprintf(stream,"show samples\n");
1653 #endif
1654     r.subtype=gnuplot_fileno;
1655     reset_gnuplot_hidden3d(stream);
1656     ++ng;
1657     if (debug_infolevel)
1658       printf("set xrange [%g:%g]\n",function_xmin,function_xmax);
1659     fprintf(stream,"set xrange [%g:%g]\n",function_xmin,function_xmax);
1660     ++ng;
1661     if (s==2){
1662       if (debug_infolevel)
1663 	printf("set urange [%g:%g]\n",function_xmin,function_xmax);
1664       fprintf(stream,"set urange [%g:%g]\n",function_xmin,function_xmax);
1665       ++ng;
1666       if (debug_infolevel)
1667 	printf("set yrange [%g:%g]\n",function_ymin,function_ymax);
1668       fprintf(stream,"set yrange [%g:%g]\n",function_ymin,function_ymax);
1669       ++ng;
1670     }
1671     if ((s==2) || (!autoscale)){
1672       if (debug_infolevel)
1673 	printf("set vrange [%g:%g]\n",function_ymin,function_ymax);
1674       fprintf(stream,"set vrange [%g:%g]\n",function_ymin,function_ymax);
1675       ++ng;
1676     }
1677     if (autoscale){
1678       if (debug_infolevel)
1679 	printf("%s","set autoscale\n");
1680       fprintf(stream,"%s","set autoscale\n");
1681       ++ng;
1682     }
1683     if (clrplot || gnuplot_do_splot){
1684       gnuplot_do_splot=false;
1685       if (s==1){
1686 	if (debug_infolevel)
1687 	  printf("%s","plot ");
1688 	fprintf(stream,"%s","plot ");
1689       }
1690       else {
1691 	if (!autoscale){
1692 	  if (debug_infolevel)
1693 	    printf("set zrange [%g:%g]\n",function_zmin,function_zmax);
1694 	  fprintf(stream,"set zrange [%g:%g]\n",function_zmin,function_zmax);
1695 	  ++ng;
1696 	}
1697 	if (debug_infolevel)
1698 	  printf("%s","set view\n");
1699 	fprintf(stream,"%s","set view\n");
1700 	++ng;
1701 	if (debug_infolevel)
1702 	  printf("%s","splot ");
1703 	fprintf(stream,"%s","splot ");
1704       }
1705     }
1706     else {
1707       if (debug_infolevel)
1708 	printf("%s","replot ");
1709       fprintf(stream,"%s","replot ");
1710     }
1711     if (ff.type!=_VECT){
1712       if (debug_infolevel)
1713 	printf("%s\n",gnuplot_traduit(ff).c_str());
1714       fprintf(stream,"%s\n",gnuplot_traduit(ff).c_str());
1715       ++ng;
1716     }
1717     else {
1718       string tmp(gnuplot_traduit(ff));
1719       // cout << tmp.substr(1,tmp.size()-2) << '\n';
1720       if (debug_infolevel)
1721 	printf("%s\n",tmp.substr(1,tmp.size()-2).c_str());
1722       fprintf(stream,"%s\n",tmp.substr(1,tmp.size()-2).c_str());
1723       ++ng;
1724     }
1725     win9x_gnuplot(stream);
1726     gnuplot_wait(out_handle,gnuplot_out_readstream,ng+gnuplot_wait_times);
1727     // usleep(50000);
1728     r.subtype=gnuplot_fileno,
1729       ++gnuplot_fileno;
1730     return r;
1731     //return gnuplot_fileno-1;
1732 #endif
1733     return r;
1734   }
1735 
1736   // Note gnuplot 3.7.2 seems to have a bug
1737   // The unit is set to 0.1bp at the beginning and scale to 0.05
1738   // gnuplot 3.7.1 seems to work correctly
latex_replot(FILE * stream,const string & s)1739   bool latex_replot(FILE * stream,const string & s){
1740     if (!has_gnuplot)
1741       return 0;
1742 #ifdef WITH_GNUPLOT
1743     // printf("%s\n%s\"%s\"\n%s\n%s\n","set terminal pslatex","set output ",s.c_str(),"replot","set output");
1744     if (debug_infolevel){
1745       printf("%s\n","set terminal pslatex");
1746       printf("%s","set output ");
1747       printf("\"%s",s.c_str());
1748       printf("\"\n%s\n%s\n","replot","set output");
1749     }
1750     fprintf(stream,"%s\n","set terminal pslatex");
1751     fprintf(stream,"%s","set output ");
1752     fprintf(stream,"\"%s",s.c_str());
1753     fprintf(stream,"\"\n%s\n%s\n","replot","set output");
1754 #ifdef WIN32
1755     if (debug_infolevel)
1756       printf("%s\n","set terminal windows");
1757     fprintf(stream,"%s\n","set terminal windows");
1758 #else
1759 #ifdef __APPLE__
1760     if (debug_infolevel)
1761       printf("set terminal aqua\n");
1762     fprintf(stream,"set terminal aqua\n");
1763 #else
1764     if (debug_infolevel)
1765       printf("%s\n","set terminal x11");
1766     fprintf(stream,"%s\n","set terminal x11");
1767 #endif
1768 #endif
1769     fflush(stream);
1770 #endif
1771     return true;
1772   }
1773 
bit_and(const gen & a,unsigned mask)1774   static gen bit_and(const gen & a,unsigned mask){
1775     if (a.type==_INT_)
1776       return int(unsigned(a.val) & mask);
1777     if (a.type==_VECT){
1778       vecteur res;
1779       const_iterateur it=a._VECTptr->begin(),itend=a._VECTptr->end();
1780       for (;it!=itend;++it)
1781 	res.push_back(bit_and(*it,mask));
1782       return res;
1783     }
1784     return a;
1785   }
1786 
bit_ori(const gen & a,unsigned mask)1787   static gen bit_ori(const gen & a,unsigned mask){
1788     if (a.type==_INT_)
1789       return int(unsigned(a.val) | mask);
1790     if (a.type==_VECT){
1791       vecteur res;
1792       const_iterateur it=a._VECTptr->begin(),itend=a._VECTptr->end();
1793       for (;it!=itend;++it)
1794 	res.push_back(bit_ori(*it,mask));
1795       return res;
1796     }
1797     return a;
1798   }
1799 
bit_orv(const gen & a,const vecteur & v)1800   static gen bit_orv(const gen & a,const vecteur & v){
1801     if (a.type==_INT_)
1802       return bit_ori(v,a.val);
1803     if (a.type==_VECT){
1804       vecteur res;
1805       const_iterateur it=a._VECTptr->begin(),itend=a._VECTptr->end(),jt=v.begin(),jtend=v.end();
1806       for (;it!=itend && jt!=jtend;++it,++jt){
1807 	if (jt->type==_INT_)
1808 	  res.push_back(bit_ori(*it,jt->val));
1809 	else
1810 	  res.push_back(*it);
1811       }
1812       for (;it!=itend;++it){
1813 	res.push_back(*it);
1814       }
1815       return res;
1816     }
1817     return a;
1818   }
1819 
get_style(const vecteur & v,string & legende)1820   vecteur get_style(const vecteur & v,string & legende){
1821     int s=int(v.size());
1822     vecteur style(1,int(FL_BLACK));
1823     if (s>=3)
1824       legende=gen2string(v[2]);
1825     if (s>1){
1826       gen f1(v[1]);
1827       if ( f1.type==_VECT && !f1._VECTptr->empty() )
1828 	f1=f1._VECTptr->front();
1829       int typ=f1.type;
1830       if (typ==_INT_ || typ==_ZINT)
1831 	style.front()=f1;
1832       if ( typ==_SYMB ){
1833 	gen & f2 =f1._SYMBptr->feuille;
1834 	if (f2.type==_VECT)
1835 	  style=*f2._VECTptr;
1836 	else
1837 	  style.front()=f2;
1838       }
1839     }
1840     return style;
1841   }
1842 
1843   // read color like attributs and returns the first attribut index
read_attributs(const vecteur & v,vecteur & attributs,GIAC_CONTEXT)1844   int read_attributs(const vecteur & v,vecteur & attributs,GIAC_CONTEXT){
1845     if (attributs.empty())
1846       attributs.push_back(default_color(contextptr));
1847     const_iterateur it=v.begin(),itend=v.end();
1848     int s=int(itend-it),smax(s);
1849     for (;it!=itend;++it){
1850       if (*it==at_normalize){
1851 	s=int(it-v.begin());
1852 	attributs.push_back(*it);
1853 	continue;
1854       }
1855       if (it->type==_VECT){
1856 	if (read_attributs(*it->_VECTptr,attributs,contextptr)!=int(it->_VECTptr->size()))
1857 	  s=int(it-v.begin());
1858 	continue;
1859       }
1860       gen opt;
1861       if (it->is_symb_of_sommet(at_label)){
1862 	opt=it->_SYMBptr->feuille;
1863 	if (opt.is_symb_of_sommet(at_nop))
1864 	  opt=makevecteur(at_legende,opt._SYMBptr->feuille);
1865       }
1866       else {
1867 	if (!is_equal(*it))
1868 	  continue;
1869 	opt=it->_SYMBptr->feuille;
1870       }
1871       opt=eval(opt,1,contextptr);
1872       if (opt.type!=_VECT || opt._VECTptr->size()!=2)
1873 	continue;
1874       gen opt1=opt._VECTptr->front(),opt2=opt._VECTptr->back().eval(1,0);
1875       unsigned colormask=0xffff0000;
1876       if (opt1.type==_IDNT){
1877 	const char * s1 =opt1._IDNTptr->id_name;
1878 	if (strlen(s1)==1){
1879 	  if (s1[0]=='c')
1880 	    opt1=at_couleur;
1881 	  if (s1[0]=='s')
1882 	    opt1=at_size;
1883 	}
1884 	if (strcmp(s1,"marker")==0){
1885 	  if (opt2.type==_STRNG){
1886 	    const string s2 =*opt2._STRNGptr;
1887 	    opt2=0;
1888 	    opt1=_STYLE; opt1.subtype=_INT_COLOR;
1889 	    if (s2.size()==1){
1890 	      switch (s2[0]){
1891 	      case 's': case 'o':
1892 		opt2=_POINT_CARRE;
1893 		break;
1894 	      case 'x':
1895 		opt2=0;
1896 		break;
1897 	      case '*':
1898 		opt2=_POINT_ETOILE;
1899 		break;
1900 	      case '+':
1901 		opt2=_POINT_PLUS;
1902 		break;
1903 	      case 'D':
1904 		opt2=_POINT_LOSANGE;
1905 		break;
1906 	      case 'v': case '^':
1907 		opt2=_POINT_TRIANGLE;
1908 		break;
1909 	      case '.':
1910 		opt2=_POINT_POINT;
1911 		break;
1912 	      }
1913 	    }
1914 	  }
1915 	}
1916 	if (strcmp(s1,"linewidth")==0){
1917 	  opt2=_round(opt2,contextptr);
1918 	  if (opt2.type==_INT_ && opt2.val>0 && opt2.val<8){
1919 	    opt1=_THICKNESS;
1920 	    opt1.subtype=_INT_COLOR;
1921 	  }
1922 	}
1923       }
1924       if (opt2.type==_STRNG && opt2._STRNGptr->size()>1){
1925 	const string & s=*opt2._STRNGptr;
1926 	if (s.size()==2){
1927 	  if (s=="--")
1928 	    opt2=_DASHDOT_LINE;
1929 	  if (s=="-.")
1930 	    opt2=_DASHDOTDOT_LINE;
1931 	}
1932 	else {
1933 	  if (opt1!=at_label && opt1!=at_legende && opt1!=_GL_TEXTURE)
1934 	    opt2=gen(s,contextptr);
1935 	}
1936       }
1937       if (opt1==at_size && opt2.type==_INT_){
1938 	int s=opt2.val;
1939 	if (s<4)
1940 	  opt2=_POINT_WIDTH_1;
1941 	if (s>=4 && s<9)
1942 	  opt2=_POINT_WIDTH_2;
1943 	if (s>=9 && s<16)
1944 	  opt2=_POINT_WIDTH_3;
1945 	if (s>=16 && s<25)
1946 	  opt2=_POINT_WIDTH_4;
1947 	if (s>=25 && s<36)
1948 	  opt2=_POINT_WIDTH_5;
1949 	if (s>=36 && s<49)
1950 	  opt2=_POINT_WIDTH_6;
1951 	if (s>=49 && s<64)
1952 	  opt2=_POINT_WIDTH_7;
1953 	if (s>=64)
1954 	  opt2=_POINT_WIDTH_8;
1955 	opt1=_STYLE; opt1.subtype=_INT_COLOR;
1956 	colormask=0xffffffff;
1957       }
1958       if (opt1==at_couleur || opt1==at_display){
1959 	if (opt2.type==_STRNG && opt2._STRNGptr->size()==1){
1960 	  switch ((*opt2._STRNGptr)[0]){
1961 	  case 'r':
1962 	    opt2=_RED;
1963 	    break;
1964 	  case 'b':
1965 	    opt2=_BLUE;
1966 	    break;
1967 	  case 'g':
1968 	    opt2=_GREEN;
1969 	    break;
1970 	  case 'c':
1971 	    opt2=_CYAN;
1972 	    break;
1973 	  case 'm':
1974 	    opt2=_MAGENTA;
1975 	    break;
1976 	  case 'y':
1977 	    opt2=_YELLOW;
1978 	    break;
1979 	  case 'k':
1980 	    opt2=_BLACK;
1981 	    break;
1982 	  case 'w':
1983 	    opt2=_WHITE;
1984 	    break;
1985 	  }
1986 	}
1987 	opt1=_COLOR; opt1.subtype=_INT_COLOR;
1988       }
1989       if (opt1==at_legende){
1990 	opt1=_LEGEND;
1991 	opt1.subtype=_INT_COLOR;
1992       }
1993       if (opt1.type==_DOUBLE_)
1994 	opt1=gen(int(opt1._DOUBLE_val));
1995       if (opt2.type==_DOUBLE_ && opt1.val!=_LEGEND)
1996 	opt2=gen(int(opt2._DOUBLE_val));
1997       if ( opt1.type!=_INT_ || opt1.subtype==0
1998 	   // || (opt1.subtype==_INT_PLOT && opt1.val>=_GL_X && opt1.val<=_GL_Z)
1999 	   )
2000 	continue;
2001       if (s==smax)
2002 	s=int(it-v.begin());
2003       switch (opt1.val){
2004       case _COLOR:
2005 	if (opt2.type==_INT_)
2006 	  attributs[0]=bit_ori(bit_and(attributs[0],0xcfff0000),opt2.val);
2007 	if (opt2.type==_VECT)
2008 	  attributs[0]=bit_orv(bit_and(attributs[0],0xcfff0000),*opt2._VECTptr);
2009 	break;
2010       case _STYLE:
2011 	if (opt2.type==_INT_)
2012 	  attributs[0]=bit_ori(attributs[0],opt2.val);
2013 	break;
2014       case _LINESTYLE:
2015 	if (opt2==at_point)
2016 	  opt2=_DOT_LINE;
2017 	if (opt2==at_neg)
2018 	  opt2=0;
2019 	if (opt2.type==_INT_)
2020 	  attributs[0]=bit_ori(bit_and(attributs[0],0xfe3fffff),opt2.val);
2021 	break;
2022       case _THICKNESS:
2023 	attributs[0]=bit_and(attributs[0], 0xfff8ffff);
2024 	attributs[0]=bit_ori(attributs[0],_LINE_WIDTH_2*(bit_and(opt2,0x7).val-1));
2025 	break;
2026       case _LEGEND:
2027 	if (attributs.size()>1)
2028 	  attributs[1]=opt2;
2029 	else
2030 	  attributs.push_back(opt2);
2031 	break;
2032       case _GL_OPTION:
2033 	if (attributs.size()==1)
2034 	  attributs.push_back(string2gen("",false));
2035 	attributs.push_back(opt2);
2036 	break;
2037       case _GL_MATERIAL: case _GL_TEXTURE:
2038 	if (attributs.size()==1)
2039 	  attributs.push_back(string2gen("",false));
2040 	attributs.push_back(makevecteur(opt1,opt2));
2041       }
2042     }
2043     return s;
2044   }
2045 
2046 
read_option(const vecteur & v,double xmin,double xmax,double ymin,double ymax,double zmin,double zmax,vecteur & attributs,int & nstep,int & jstep,int & kstep,bool unfactored,GIAC_CONTEXT)2047   static void read_option(const vecteur & v,double xmin,double xmax,double ymin,double ymax,double zmin,double zmax,vecteur & attributs, int & nstep,int & jstep,int & kstep,bool unfactored,GIAC_CONTEXT){
2048     read_attributs(v,attributs,contextptr);
2049     const_iterateur it=v.begin(),itend=v.end();
2050     for (;it!=itend;++it){
2051       if (it->type==_VECT){
2052 	read_option(*it->_VECTptr,xmin,xmax,ymin,ymax,zmin,zmax,attributs,nstep,jstep,kstep,contextptr);
2053 	continue;
2054       }
2055       if (it->subtype==_INT_SOLVER && *it==_UNFACTORED)
2056 	unfactored=true;
2057       if (!is_equal(*it))
2058 	continue;
2059       gen & opt=it->_SYMBptr->feuille;
2060       if (opt.type!=_VECT || opt._VECTptr->size()!=2)
2061 	continue;
2062       gen opt1=opt._VECTptr->front(),opt2=opt._VECTptr->back();
2063       if ( opt1.type!=_INT_)
2064 	continue;
2065       switch (opt1.val){
2066       case _NSTEP:
2067 	if (opt2.type==_INT_)
2068 	  nstep=abs(opt2,context0).val; // ok
2069 	break;
2070       case _XSTEP:
2071 	opt2=evalf_double(abs(opt2,context0),2,context0); // ok
2072 	if (opt2.type==_DOUBLE_){
2073 	  nstep=int((xmax-xmin)/opt2._DOUBLE_val+.5);
2074 	  if (!jstep)
2075 	    jstep=nstep;
2076 	}
2077 	break;
2078       case _YSTEP:
2079 	opt2=evalf_double(abs(opt2,context0),2,context0); // ok
2080 	if (opt2.type==_DOUBLE_)
2081 	  jstep=int((ymax-ymin)/opt2._DOUBLE_val+.5);
2082 	break;
2083       case _ZSTEP:
2084 	opt2=evalf_double(abs(opt2,context0),2,context0); // ok
2085 	if (opt2.type==_DOUBLE_)
2086 	  kstep=int((zmax-zmin)/opt2._DOUBLE_val+.5);
2087 	break;
2088       }
2089     }
2090   }
2091 
read_option(const vecteur & v,double xmin,double xmax,double ymin,double ymax,double zmin,double zmax,vecteur & attributs,int & nstep,int & jstep,int & kstep,GIAC_CONTEXT)2092   void read_option(const vecteur & v,double xmin,double xmax,double ymin,double ymax,double zmin,double zmax,vecteur & attributs, int & nstep,int & jstep,int & kstep,GIAC_CONTEXT){
2093     bool unfactored=false;
2094     read_option(v,xmin,xmax,ymin,ymax,zmin,zmax,attributs,nstep,jstep,kstep,unfactored,contextptr);
2095   }
2096 
read_option(const vecteur & v,double xmin,double xmax,double ymin,double ymax,vecteur & attributs,int & nstep,int & jstep,GIAC_CONTEXT)2097   static void read_option(const vecteur & v,double xmin,double xmax,double ymin,double ymax,vecteur & attributs, int & nstep,int & jstep,GIAC_CONTEXT){
2098     double zmin=gnuplot_zmin,zmax=gnuplot_zmax; int kstep=0;
2099     bool unfactored=false;
2100     read_option(v,xmin,xmax,ymin,ymax,zmin,zmax,attributs,nstep,jstep,kstep,unfactored,contextptr);
2101   }
2102 
funcplotfunc(const gen & args,bool densityplot,const context * contextptr)2103   gen funcplotfunc(const gen & args,bool densityplot,const context * contextptr){
2104     double xmin=gnuplot_xmin,xmax=gnuplot_xmax,ymin=gnuplot_ymin,ymax=gnuplot_ymax,zmin=gnuplot_zmin,zmax=gnuplot_zmax;
2105     bool showeq=false;
2106     if (densityplot)
2107       zmin=zmax; // if z-range is not given, then fmin/fmax will be used
2108     int nstep=gnuplot_pixels_per_eval,jstep=0;
2109     gen attribut=default_color(contextptr);
2110     vecteur vargs(plotpreprocess(args,contextptr));
2111     if (is_undef(vargs))
2112       return vargs;
2113     int s=int(vargs.size());
2114     if (ckmatrix(vargs[0])){
2115       matrice m=*vargs[0]._VECTptr;
2116       reverse(m.begin(),m.end());
2117       return density(mtran(m),0,0,true,contextptr);
2118     }
2119     for (int i=0;i<s;++i){
2120       if (vargs[i]==at_equation){
2121 	showeq=true;
2122 	vargs.erase(vargs.begin()+i);
2123 	--s;
2124 	break;
2125       }
2126     }
2127     if (s<1)
2128       return gensizeerr(contextptr);
2129     gen e1=vargs[1];
2130 #if 0 // ?#ifdef EMCC
2131     if (!densityplot && e1.type==_IDNT){
2132       gen m=minus_inf,M=plus_inf;
2133       vecteur poi,tvi;
2134       if (step_func(vargs[0],e1,m,M,poi,tvi,true,false,contextptr)){
2135 	gen scale=(gnuplot_xmax-gnuplot_xmin)/5.0;
2136 	if (is_inf(m))
2137 	  m=gnuplot_xmin;
2138 	if (is_inf(M))
2139 	  M=gnuplot_xmax;
2140 	if (m!=M)
2141 	  scale=(M-m)/3.0;
2142 	m=m-0.973456*scale; M=M+1.018546*scale;
2143 	vargs[1]=symb_equal(vargs[1],symb_interval(m,M));
2144 	gen p=funcplotfunc(gen(vargs,_SEQ__VECT),false,contextptr);
2145 	poi=mergevecteur(poi,gen2vecteur(p));
2146 	//poi=mergevecteur(gen2vecteur(p),poi);
2147 	return gen(poi,_SEQ__VECT);
2148       }
2149     }
2150 #endif
2151     bool newsyntax;
2152     if (e1.type!=_VECT){
2153       newsyntax=readrange(e1,gnuplot_xmin,gnuplot_xmax,e1,xmin,xmax,contextptr) && (is_equal(vargs[1]) || s<4);
2154     }
2155     else {
2156       if (e1._VECTptr->size()!=2)
2157 	return setplotfuncerr();
2158       vecteur v(*e1._VECTptr);
2159       newsyntax=readrange(v[0],gnuplot_xmin,gnuplot_xmax,v[0],xmin,xmax,contextptr) && readrange(v[1],gnuplot_ymin,gnuplot_ymax,v[1],ymin,ymax,contextptr);
2160       if (newsyntax)
2161 	e1=v;
2162     }
2163     if (!newsyntax){ // plotfunc(fonction,var,min,max[,zminmax,attribut])
2164       if (s<=3)
2165 	return setplotfuncerr();
2166       gen e2=vargs[2];
2167       gen e3=vargs[3];
2168       if (e1.type==_VECT){
2169 	if ((e2.type!=_VECT) || (e3.type!=_VECT) || (e2._VECTptr->size()!=2) || (e3._VECTptr->size()!=2))
2170 	  return gentypeerr(gettext("Plotfunc: Range must be [xmin,ymin] or [xmax,ymax]"));
2171 	gen e21=evalf_double(e2._VECTptr->front(),eval_level(contextptr),contextptr);
2172 	gen e22=evalf_double(e2._VECTptr->back(),eval_level(contextptr),contextptr);
2173 	gen e31=evalf_double(e3._VECTptr->front(),eval_level(contextptr),contextptr);
2174 	gen e32=evalf_double(e3._VECTptr->back(),eval_level(contextptr),contextptr);
2175 	if ((e21.type!=_DOUBLE_) || (e22.type!=_DOUBLE_) || (e31.type!=_DOUBLE_) || (e32.type!=_DOUBLE_))
2176 	  return gentypeerr(gettext("Plotfunc: bad range value!"));
2177 	xmin=e21._DOUBLE_val;
2178 	ymin=e22._DOUBLE_val;
2179 	xmax=e31._DOUBLE_val;
2180 	ymax=e32._DOUBLE_val;
2181 	if (s>4){
2182 	  gen e4=vargs[4];
2183 	  if (e4.type==_VECT && e4._VECTptr->size()==2){
2184 	    gen e41=evalf_double(e4._VECTptr->front(),eval_level(contextptr),contextptr);
2185 	    gen e42=evalf_double(e4._VECTptr->back(),eval_level(contextptr),contextptr);
2186 	    if (e41.type!=_DOUBLE_ || e42.type!=_DOUBLE_)
2187 	      return gentypeerr(gettext("Plotfunc: bad range value!"));
2188 	    zmin=e41._DOUBLE_val;
2189 	    zmax=e42._DOUBLE_val;
2190 	  }
2191 	  if (s>5)
2192 	    attribut=vargs[5];
2193 	  if (s>6 && vargs[6].type==_INT_)
2194 	    nstep=vargs[6].val;
2195 	  if (s>7 && vargs[7].type==_INT_)
2196 	    jstep=vargs[7].val;
2197 	}
2198       }
2199       else {
2200 	e2=e2.evalf_double(eval_level(contextptr),contextptr);
2201 	e3=e3.evalf_double(eval_level(contextptr),contextptr);
2202 	if ((e2.type!=_DOUBLE_) || (e3.type!=_DOUBLE_))
2203 	  return gentypeerr(gettext("Plotfunc: bad range value!"));
2204 	xmin=e2._DOUBLE_val;
2205 	xmax=e3._DOUBLE_val;
2206 	if (s>4)
2207 	  attribut=vargs[4];
2208 	if (s>5 && vargs[5].type==_INT_)
2209 	  nstep=vargs[5].val;
2210 	if (s>6 && vargs[6].type==_INT_)
2211 	  jstep=vargs[6].val;
2212       }
2213       return plotfunc(vargs.front(),e1,vecteur(1,attribut),densityplot,xmin,xmax,ymin,ymax,zmin,zmax,nstep,jstep,showeq,contextptr);
2214     }
2215     // plotfunc(func,x=xmin..xmax[,zminmax,attribut])
2216     if (e1.type==_VECT && s>2){
2217       double z1,z2;
2218       if (readrange(vargs[2],gnuplot_zmin,gnuplot_zmax,vargs[2],z1,z2,contextptr)){
2219 	zmin=z1; zmax=z2;
2220       }
2221     }
2222     vecteur attributs(1,attribut);
2223     read_option(vargs,xmin,xmax,ymin,ymax,attributs,nstep,jstep,contextptr);
2224     return plotfunc(vargs[0],e1,attributs,densityplot,xmin,xmax,ymin,ymax,zmin,zmax,nstep,jstep,showeq,contextptr);
2225   }
_plotfunc(const gen & args,const context * contextptr)2226   gen _plotfunc(const gen & args,const context * contextptr){
2227     if ( args.type==_STRNG && args.subtype==-1) return  args;
2228     int nd;
2229     if ( (nd=is_distribution(args)) || (args.type==_VECT && !args._VECTptr->empty() && (nd=is_distribution(args._VECTptr->front())) ) ){
2230       if (is_discrete_distribution(nd))
2231 	*logptr(contextptr) << "Correct commandname is histogram" << '\n';
2232       return _plot(args,contextptr);
2233     }
2234     return funcplotfunc(args,false,contextptr);
2235   }
2236   static const char _plotfunc_s []="plotfunc";
2237   static define_unary_function_eval_quoted (__plotfunc,&_plotfunc,_plotfunc_s);
2238   define_unary_function_ptr5( at_plotfunc ,alias_at_plotfunc,&__plotfunc,_QUOTE_ARGUMENTS,true);
2239 
_funcplot(const gen & args,const context * contextptr)2240   gen _funcplot(const gen & args,const context * contextptr){
2241     if ( args.type==_STRNG && args.subtype==-1) return  args;
2242     return funcplotfunc(args,false,contextptr);
2243   }
2244   static const char _funcplot_s []="funcplot"; // Same as plotfunc but with tex print
2245   static define_unary_function_eval_quoted (__funcplot,&_funcplot,_funcplot_s);
2246   define_unary_function_ptr5( at_funcplot ,alias_at_funcplot,&__funcplot,_QUOTE_ARGUMENTS,true);
2247 
_plotdensity(const gen & args,const context * contextptr)2248   gen _plotdensity(const gen & args,const context * contextptr){
2249     if ( args.type==_STRNG && args.subtype==-1) return  args;
2250     return funcplotfunc(args,true,contextptr);
2251   }
2252   static const char _plotdensity_s []="plotdensity";
2253   static define_unary_function_eval_quoted (__plotdensity,&_plotdensity,_plotdensity_s);
2254   define_unary_function_ptr5( at_plotdensity ,alias_at_plotdensity,&__plotdensity,_QUOTE_ARGUMENTS,true);
2255 
_plotmatrix(const gen & args,const context * contextptr)2256   gen _plotmatrix(const gen & args,const context * contextptr){
2257     if ( args.type==_STRNG && args.subtype==-1) return  args;
2258     return funcplotfunc(args,true,contextptr);
2259   }
2260   static const char _plotmatrix_s []="plotmatrix";
2261   static define_unary_function_eval_quoted (__plotmatrix,&_plotmatrix,_plotmatrix_s);
2262   define_unary_function_ptr5( at_plotmatrix ,alias_at_plotmatrix,&__plotmatrix,_QUOTE_ARGUMENTS,true);
2263 
2264   static const char _densityplot_s []="densityplot";
2265   static define_unary_function_eval_quoted (__densityplot,&_plotdensity,_densityplot_s);
2266   define_unary_function_ptr5( at_densityplot ,alias_at_densityplot,&__densityplot,_QUOTE_ARGUMENTS,true);
2267 
chk_double_interval(const gen & g,double & inf,double & sup,GIAC_CONTEXT)2268   bool chk_double_interval(const gen & g,double & inf,double & sup,GIAC_CONTEXT){
2269     gen h(g);
2270     if (!h.is_symb_of_sommet(at_interval))
2271       return false;
2272     h=h._SYMBptr->feuille;
2273     if (h.type!=_VECT || h._VECTptr->size()!=2)
2274       return false;
2275     gen h1=evalf_double(h._VECTptr->front(),1,contextptr);
2276     gen h2=evalf_double(h._VECTptr->back(),1,contextptr);
2277     if (h1.type!=_DOUBLE_  || h2.type!=_DOUBLE_ )
2278       return false;
2279     inf=h1._DOUBLE_val;
2280     sup=h2._DOUBLE_val;
2281     return true;
2282   }
2283 
readvar(const gen & g)2284   gen readvar(const gen & g){
2285     if (g.type==_IDNT)
2286       return g;
2287     if (!is_equal(g))
2288       return undef;
2289     gen & f=g._SYMBptr->feuille;
2290     if (f.type!=_VECT || f._VECTptr->size()!=2)
2291       return undef;
2292     return f._VECTptr->front();
2293   }
2294 
readrange(const gen & g,double defaultxmin,double defaultxmax,gen & x,double & xmin,double & xmax,GIAC_CONTEXT)2295   bool readrange(const gen & g,double defaultxmin,double defaultxmax,gen & x, double & xmin, double & xmax,GIAC_CONTEXT){
2296     xmin=defaultxmin;
2297     xmax=defaultxmax;
2298     if (g.type==_IDNT){
2299       x=g;
2300       return true;
2301     }
2302     if (is_equal(g)){
2303       gen & f=g._SYMBptr->feuille;
2304       if (f.type!=_VECT)
2305 	return false;
2306       vecteur & v=*f._VECTptr;
2307       if (v.size()!=2 || v[0].type!=_IDNT)
2308 	return false;
2309       bool res= chk_double_interval(v[1],xmin,xmax,contextptr);
2310       x=v[0];
2311       return res;
2312     }
2313     return false;
2314   }
symb_erase(const gen & aa)2315   static symbolic symb_erase(const gen & aa){
2316     gen a(aa);
2317     if (a.type==_VECT) a.subtype=_SEQ__VECT;
2318     return symbolic(at_erase,a);
2319   }
_erase(const gen & args,GIAC_CONTEXT)2320   gen _erase(const gen & args,GIAC_CONTEXT){
2321     if ( args.type==_STRNG && args.subtype==-1) return  args;
2322 #ifdef WITH_GNUPLOT
2323     plot_instructions.clear();
2324 #endif
2325     history_plot(contextptr).clear();
2326     __interactive.op(symbolic(at_erase,0),contextptr);
2327     return symb_erase(args);
2328   }
2329   static const char _erase_s []="erase";
2330   static define_unary_function_eval2 (__erase,&_erase,_erase_s,&printasconstant);
2331   define_unary_function_ptr( at_erase ,alias_at_erase ,&__erase);
2332 
erase3d()2333   int erase3d(){
2334 #ifdef WITH_GNUPLOT
2335     if (gnuplot_do_splot)
2336       return gnuplot_fileno-1;
2337     int out_handle;
2338     bool clrplot;
2339     if (win9x){
2340       FILE * stream = fopen("gnuplot.txt","w");
2341       fputc(' ',stream);
2342       fflush(stream);
2343       fclose(stream);
2344     }
2345     else {
2346       FILE * gnuplot_out_readstream,* stream = open_gnuplot(clrplot,gnuplot_out_readstream,out_handle);
2347       if (show_axes(0))
2348 	fprintf(stream,"unset arrow 1\nunset arrow 2\nunset arrow 3\n");
2349       fprintf(stream,"\nclear\n");
2350       fflush(stream);
2351       gnuplot_wait(out_handle,gnuplot_out_readstream);
2352       // WARNING never close the pipe! fclose(stream);
2353     }
2354     ++gnuplot_fileno;
2355     gnuplot_do_splot=true;
2356     return gnuplot_fileno-1;
2357 #else
2358     return -1;
2359 #endif
2360   }
2361 
_erase3d(const gen & args,GIAC_CONTEXT)2362   gen _erase3d(const gen & args,GIAC_CONTEXT){
2363     if ( args.type==_STRNG && args.subtype==-1) return  args;
2364     return erase3d();
2365   }
2366   static const char _erase3d_s []="erase3d";
2367   static define_unary_function_eval (__erase3d,&_erase3d,_erase3d_s);
2368   define_unary_function_ptr5( at_erase3d ,alias_at_erase3d,&__erase3d,0,true);
2369 
2370   // arg=real/complex or (real/complex,label) or same+color
pointonoff(const gen & args,const vecteur & attributs,GIAC_CONTEXT)2371   static gen pointonoff(const gen & args,const vecteur & attributs,GIAC_CONTEXT){
2372     gen e,a(args.evalf(eval_level(contextptr),contextptr));
2373     if ( (a.is_real(contextptr)) || (a.type==_CPLX) ){
2374       if (attributs.size()<=1)
2375 	e=symb_pnt(args.eval(eval_level(contextptr),contextptr),attributs,contextptr);
2376       else
2377 	e=symb_pnt_name(args.eval(eval_level(contextptr),contextptr),attributs[0],attributs[1],contextptr);
2378     }
2379     else {
2380       if (args.type!=_VECT)
2381 	return symb_pnt(args,attributs,contextptr);
2382       int s=int(args._VECTptr->size());
2383       if ( (s!=2) && (s!=3) )
2384 	return gensizeerr(gettext("pointon"));
2385       gen x=args._VECTptr->front(),y=(*args._VECTptr)[1],c;
2386       if ( (s==3) || (y.type==_STRNG))
2387 	e=symbolic(at_pnt,args);
2388       else
2389 	e=symb_pnt_name(x,attributs[0].val,y,contextptr);
2390     }
2391 #if !defined(WIN32) && defined(WITH_GNUPLOT)
2392     if (child_id) plot_instructions.push_back(e);
2393 #endif // WIN32
2394     return e;
2395   }
2396 
merge_pixon(const vecteur & v,vecteur & w)2397   void merge_pixon(const vecteur & v,vecteur & w){
2398     const_iterateur it=v.begin(),itend=v.end();
2399     w.reserve(itend-it);
2400     int lastxmin=-1,lastxmax=-1,lastymin=-1,lastymax=-1,lastcolor=-1;
2401     for (;it!=itend;++it){
2402       if (!is_pnt_or_pixon(*it)){
2403 	if (it->type==_VECT){
2404 	  merge_pixon(*it->_VECTptr,w);
2405 	  continue;
2406 	}
2407 	w.push_back(*it);
2408 	continue;
2409       }
2410       gen tmp=remove_at_pnt(*it);
2411       if (!tmp.is_symb_of_sommet(at_pixon) || tmp._SYMBptr->feuille.type!=_VECT){
2412 	w.push_back(*it);
2413 	continue;
2414       }
2415       vecteur & f=*tmp._SYMBptr->feuille._VECTptr;
2416       if (f.size()<2 || f.size()>=4){
2417 	w.push_back(*it);
2418 	continue;
2419       }
2420       gen x=f[0],y=f[1],c=0;
2421       if (f.size()>2)
2422 	c=f[2];
2423       if (!is_integral(x) || !is_integral(y) || !is_integral(c)){
2424 	w.push_back(*it);
2425 	continue;
2426       }
2427       if (lastcolor==c.val && lastxmax==lastxmin && lastxmax==x.val && lastymax+1==y.val){
2428 	++lastymax;
2429 	continue;
2430       }
2431       if (lastcolor==c.val && lastymax==lastymin && lastymax==y.val && lastxmax+1==x.val){
2432 	++lastxmax;
2433 	continue;
2434       }
2435 #ifdef EMCC
2436       if (lastcolor!=-1){
2437 	if (lastxmax==lastxmin){
2438 	  if (lastymax==lastymin)
2439 	    w.push_back(symbolic(at_pixon,makesequence(lastxmin,lastymin,lastcolor)));
2440 	  else
2441 	    w.push_back(symbolic(at_pixon,makesequence(lastxmin,lastymin,lastcolor,lastymax+1-lastymin)));
2442 	}
2443 	else {
2444 	  if (lastymax==lastymin)
2445 	    w.push_back(symbolic(at_pixon,makesequence(lastxmin,lastymin,lastcolor,lastxmin-lastxmax-1)));
2446 	}
2447       }
2448 #else
2449       if (lastcolor!=-1){
2450 	if (lastxmax==lastxmin){
2451 	  if (lastymax==lastymin)
2452 	    w.push_back(symbolic(at_pnt,makesequence(symbolic(at_pixon,makesequence(lastxmin,lastymin,lastcolor)),0)));
2453 	  else
2454 	    w.push_back(symbolic(at_pnt,makesequence(symbolic(at_pixon,makesequence(lastxmin,lastymin,lastcolor,lastymax+1-lastymin)),0)));
2455 	}
2456 	else {
2457 	  if (lastymax==lastymin)
2458 	    w.push_back(symbolic(at_pnt,makesequence(symbolic(at_pixon,makesequence(lastxmin,lastymin,lastcolor,lastxmin-lastxmax-1)),0)));
2459 	}
2460       }
2461 #endif
2462       lastxmax=lastxmin=x.val;
2463       lastymax=lastymin=y.val;
2464       lastcolor=c.val;
2465     }
2466     if (lastcolor!=-1){
2467       if (lastxmax==lastxmin){
2468 	if (lastymax==lastymin)
2469 	  w.push_back(symbolic(at_pnt,makesequence(symbolic(at_pixon,makesequence(lastxmin,lastymin,lastcolor)),0)));
2470 	else
2471 	  w.push_back(symbolic(at_pnt,makesequence(symbolic(at_pixon,makesequence(lastxmin,lastymin,lastcolor,lastymax+1-lastymin)),0)));
2472       }
2473       else {
2474 	if (lastymax==lastymin)
2475 	  w.push_back(symbolic(at_pnt,makesequence(symbolic(at_pixon,makesequence(lastxmin,lastymin,lastcolor,lastxmin-lastxmax-1)),0)));
2476       }
2477     }
2478   }
2479 
merge_pixon(const vecteur & v)2480   vecteur merge_pixon(const vecteur & v){
2481     vecteur w;
2482     merge_pixon(v,w);
2483     return w;
2484   }
2485 
pixon_print(const gen & g,std::string & S,GIAC_CONTEXT)2486   void pixon_print(const gen &g,std::string & S,GIAC_CONTEXT){
2487     if (g.type==_VECT){
2488       vecteur v;
2489       merge_pixon(*g._VECTptr,v);
2490       const_iterateur it=v.begin(),itend=v.end();
2491       if (it==itend) return;
2492       S+='[';
2493       S+=print_INT_(pixon_size);
2494       S+=",";
2495       for (;it!=itend;++it){
2496 	if (it->type!=_SYMB)
2497 	  continue;
2498 	const gen * f;
2499 	if (it->_SYMBptr->sommet==at_pnt){
2500 	  const gen & g=it->_SYMBptr->feuille;
2501 	  if (g.type!=_VECT)
2502 	    continue;
2503 	  const vecteur & w= *g._VECTptr;
2504 	  if (w.empty() || w.front().type!=_SYMB || w.front()._SYMBptr->sommet!=at_pixon)
2505 	    continue;
2506 	  f=&w.front()._SYMBptr->feuille;
2507 	}
2508 	else {
2509 	  if (it->_SYMBptr->sommet!=at_pixon)
2510 	    continue;
2511 	  f=&it->_SYMBptr->feuille;
2512 	}
2513 	if (f->type!=_VECT){
2514 	  S+=f->print(contextptr);
2515 	  continue;
2516 	}
2517 	S+='[';
2518 	const_iterateur jt=f->_VECTptr->begin(),jtend=f->_VECTptr->end();
2519 	for (;;){
2520 	  if (jt->type==_INT_)
2521 	    add_print_INT_(S,jt->val);
2522 	  else
2523 	    S+=jt->print(contextptr);
2524 	  ++jt;
2525 	  if (jt==jtend) break;
2526 	  S+=',';
2527 	}
2528 	S+=']';
2529 	if (it+1==itend) break;
2530 	S+=',';
2531       }
2532       S+=']';
2533     }
2534     if (g.type!=_SYMB)
2535       return;
2536     if (g._SYMBptr->sommet==at_pnt && g._SYMBptr->feuille.type==_VECT){
2537       pixon_print(g._SYMBptr->feuille._VECTptr->front(),S,contextptr);
2538       return;
2539     }
2540     if (g._SYMBptr->sommet!=at_pixon)
2541       return;
2542     const gen & f=g._SYMBptr->feuille;
2543     if (f.type!=_VECT){
2544       S+=f.print(contextptr);
2545       return;
2546     }
2547     S+='[';
2548     const_iterateur it=f._VECTptr->begin(),itend=f._VECTptr->end();
2549     for (;;){
2550       S+=it->print(contextptr);
2551       ++it;
2552       if (it==itend) break;
2553       S+=',';
2554     }
2555     S+=']';
2556   }
2557 
2558   int pixon_size=1; // global size, used in all sessions
2559   // pixel (i,j,[color])
_pixon(const gen & a,GIAC_CONTEXT)2560   gen _pixon(const gen & a,GIAC_CONTEXT){
2561     gen args(a);
2562     if ( args.type==_STRNG && args.subtype==-1) return  args;
2563     int s=1;
2564     if (is_integral(args)){
2565       s=args.val;
2566       if (s<=0 || s>=10)
2567 	return gendimerr(contextptr);
2568       int n=pixon_size;
2569       pixon_size=s;
2570       return n;
2571     }
2572     if (args.type!=_VECT || (s=int(args._VECTptr->size()))<2){
2573       if (s==0) return pixon_size;
2574       return gensizeerr(contextptr);
2575     }
2576     if (s>=3){
2577 #ifdef EMCC
2578       return symbolic(at_pixon,a);
2579 #else
2580       return symb_pnt(symbolic(at_pixon,a),0,contextptr);
2581 #endif
2582     }
2583     vecteur v(*args._VECTptr);
2584     v.push_back(default_color(contextptr));
2585     return symb_pnt(symbolic(at_pixon,gen(v,_SEQ__VECT)),0,contextptr);
2586   }
2587   static const char _pixon_s []="pixon";
2588   static define_unary_function_eval (__pixon,&_pixon,_pixon_s);
2589   define_unary_function_ptr5( at_pixon ,alias_at_pixon,&__pixon,0,true);
2590 
_pixoff(const gen & args,GIAC_CONTEXT)2591   gen _pixoff(const gen & args,GIAC_CONTEXT){
2592     if ( args.type==_STRNG && args.subtype==-1) return  args;
2593     if (args.type!=_VECT || args._VECTptr->size()!=2)
2594       return gensizeerr(contextptr);
2595     vecteur v(*args._VECTptr);
2596     v.push_back(int(FL_WHITE));
2597     return _pixon(gen(v,_SEQ__VECT),contextptr);
2598   }
2599   static const char _pixoff_s []="pixoff";
2600   static define_unary_function_eval (__pixoff,&_pixoff,_pixoff_s);
2601   define_unary_function_ptr5( at_pixoff ,alias_at_pixoff,&__pixoff,0,true);
2602 
_droite_segment(const gen & args,int subtype,const vecteur & attributs,GIAC_CONTEXT)2603   static gen _droite_segment(const gen & args,int subtype,const vecteur & attributs,GIAC_CONTEXT){
2604     if ( args.type==_STRNG && args.subtype==-1) return  args;
2605     gen e;
2606     vecteur res(*args._VECTptr);
2607     iterateur it=res.begin(),itend=res.end();
2608     for (;it!=itend;++it){
2609       if (it->is_symb_of_sommet(at_equal))
2610 	*it=_droite(*it,contextptr);
2611       bool ispnt=it->is_symb_of_sommet(at_pnt);
2612       *it=remove_at_pnt(*it);
2613       if ( (it->type==_SYMB) && (it->_SYMBptr->sommet==at_cercle)){
2614 	gen centre,rayon;
2615 	if (!centre_rayon(*it,centre,rayon,false,contextptr))
2616 	  return gensizeerr(contextptr);// we don't care about rayon
2617 	*it=centre;
2618       }
2619       if (it->type==_VECT){
2620 	if (it->_VECTptr->size()==2){
2621 	  if (ispnt){
2622 	    if (it->subtype==_LINE__VECT || it->subtype==_HALFLINE__VECT || it->subtype==_VECTOR__VECT)
2623 	      *it=res[0]+it->_VECTptr->back()-it->_VECTptr->front();
2624 	    else
2625 	      *it=(it->_VECTptr->front()+it->_VECTptr->back())/2;
2626 	  }
2627 	  else {
2628 	    *it=it->_VECTptr->front()+cst_i*it->_VECTptr->back();
2629 	    if (it!=res.begin())
2630 	      *it=*it+res[0];
2631 	  }
2632 	}
2633 	else {
2634 	  if (!ispnt && it!=res.begin() && it->subtype!=_POINT__VECT)
2635 	    *it=*it+res[0];
2636 	  it->subtype=_POINT__VECT;
2637 	}
2638       }
2639     }
2640     if (res.size()==2 && is_zero(res.front()-res.back(),contextptr) && subtype!=_GROUP__VECT && subtype!=_VECTOR__VECT)
2641       return undef;
2642     e=pnt_attrib(gen(res,subtype),attributs,contextptr);
2643     // ofstream pict("PICT",ios::app);
2644     // pict << " ," << '\n' << e ;
2645     // pict.close();
2646 #if !defined(WIN32) && defined(WITH_GNUPLOT)
2647     if (child_id) plot_instructions.push_back(e);
2648 #endif // WIN32
2649     return e;
2650   }
2651 
droite_by_equation(const vecteur & v,bool est_plan,GIAC_CONTEXT)2652   gen droite_by_equation(const vecteur & v,bool est_plan,GIAC_CONTEXT){
2653     vecteur attributs(1,default_color(contextptr));
2654     int s=read_attributs(v,attributs,contextptr);
2655     if (!s)
2656       return gendimerr(contextptr);
2657     gen eq(remove_equal(v[0])),x(x__IDNT_e),y(y__IDNT_e),z;
2658     if (s>=2 && is_equal(v[1])){
2659       if (est_plan) // Only 1 cartesian eq for a 3-d plan
2660 	return gensizeerr(contextptr);
2661       if (s<3) ck_parameter_x(contextptr); else x=v[2];
2662       if (s<4) ck_parameter_y(contextptr); else y=v[3];
2663       if (s<5){
2664 	z=z__IDNT_e;
2665 	ck_parameter_z(contextptr);
2666       }
2667       else
2668 	z=v[4];
2669       if (x.type!=_IDNT || y.type!=_IDNT || z.type!=_IDNT)
2670 	return gensizeerr(contextptr);
2671       vecteur vxyz(makevecteur(x,y,z));
2672       gen eq1(v[1]._SYMBptr->feuille._VECTptr->front()-v[1]._SYMBptr->feuille._VECTptr->back());
2673       gen v0(derive(eq,vxyz,contextptr)),v1(derive(eq1,vxyz,contextptr));
2674       if (is_undef(v0) || is_undef(v1))
2675 	return v0+v1;
2676       gen A;
2677       if (!is_zero(derive(v0,vxyz,contextptr),contextptr) || !is_zero(derive(v1,vxyz,contextptr),contextptr) )
2678 	return gensizeerr(gettext("Non linear equations"));
2679       vecteur directeur(*normal(cross(*v0._VECTptr,*v1._VECTptr,contextptr),contextptr)._VECTptr);
2680       if (is_zero(directeur,contextptr))
2681 	return gensizeerr(gettext("Parallel plans"));
2682       if (is_zero(directeur[2],contextptr)){ // z is constant on the line
2683 	if (is_zero(directeur[1],contextptr)){ // fix x=0 and solve for y and z
2684 	  gen sol=solve(makevecteur(subst(eq,x,0,false,contextptr),subst(eq1,x,0,false,contextptr)),makevecteur(y,z),0,contextptr);
2685 	  if (is_undef(sol) || sol.type!=_VECT || sol._VECTptr->size()!=1)
2686 	    return gensizeerr(contextptr);
2687 	  sol=sol._VECTptr->front();
2688 	  A=gen(makevecteur(0,sol._VECTptr->front(),sol._VECTptr->back()),_POINT__VECT);
2689 	}
2690 	else {
2691 	  // fix y=0 for A, solve
2692 	  gen sol=solve(makevecteur(subst(eq,y,0,false,contextptr),subst(eq1,y,0,false,contextptr)),makevecteur(x,z),0,contextptr);
2693 	  if (is_undef(sol) || sol.type!=_VECT || sol._VECTptr->size()!=1)
2694 	    return gensizeerr(contextptr);
2695 	  sol=sol._VECTptr->front();
2696 	  A=gen(makevecteur(sol._VECTptr->front(),0,sol._VECTptr->back()),_POINT__VECT);
2697 	}
2698       }
2699       else { // Fix z=0
2700 	gen sol=solve(makevecteur(subst(eq,z,0,false,contextptr),subst(eq1,z,0,false,contextptr)),makevecteur(x,y),0,contextptr);
2701 	if (is_undef(sol) || sol.type!=_VECT || sol._VECTptr->size()!=1)
2702 	  return gensizeerr(contextptr);
2703 	sol=sol._VECTptr->front();
2704 	A=gen(makevecteur(sol._VECTptr->front(),sol._VECTptr->back(),0),_POINT__VECT);
2705       }
2706       gen B(A+directeur);
2707       return pnt_attrib(gen(makevecteur(A,B),_LINE__VECT),attributs,contextptr);
2708     }
2709     if (s<2) ck_parameter_x(contextptr); else x=v[1];
2710     if (s<3) ck_parameter_y(contextptr); else y=v[2];
2711     if (est_plan){
2712       if (s<4){
2713 	z=z__IDNT_e;
2714 	ck_parameter_z(contextptr);
2715       }
2716       else
2717 	z=v[3];
2718     }
2719     if ( x.type!=_IDNT || y.type!=_IDNT || (est_plan && z.type!=_IDNT) )
2720       return gensizeerr(contextptr);
2721     gen eqx=normal(derive(eq,*x._IDNTptr,contextptr),contextptr);
2722     gen eqy=normal(derive(eq,*y._IDNTptr,contextptr),contextptr);
2723     gen eqz;
2724     if (est_plan)
2725       eqz=normal(derive(eq,*z._IDNTptr,contextptr),contextptr);
2726     if (is_undef(eqx)||is_undef(eqy)||is_undef(eqz))
2727       return eqx+eqy+eqz;
2728     vecteur eqxyz=makevecteur(eqx,eqy,eqz);
2729     // FIXME The test should be done with all derivatives
2730     if (!lvarx(eqxyz,x).empty() || !lvarx(eqxyz,y).empty() || (est_plan && !lvarx(eqxyz,z).empty()) )
2731       return gensizeerr(contextptr);
2732     if (is_zero(eqx,contextptr) && is_zero(eqy,contextptr) && is_zero(eqz,contextptr) )
2733       return gensizeerr(contextptr);
2734     // equation: eqx*x+eqy*y+eqz*z+cte=0
2735     gen cte,A,B;
2736     if (est_plan)
2737       cte=subst(eq,makevecteur(x,y,z),vecteur(3,zero),false,contextptr);
2738     else
2739       cte=subst(eq,makevecteur(x,y),vecteur(2,zero),false,contextptr);
2740     if (est_plan){
2741       B=makevecteur(eqx,eqy,eqz);
2742       if (is_zero(eqz,contextptr)){
2743 	if (is_zero(eqy,contextptr))
2744 	  A=gen(makevecteur(-cte/eqx,0,0),_POINT__VECT);
2745 	else
2746 	  A=gen(makevecteur(0,-cte/eqy,0),_POINT__VECT);
2747       }
2748       else
2749 	A=gen(makevecteur(0,0,-cte/eqz),_POINT__VECT);
2750       A=ratnormal(A,contextptr);
2751       return pnt_attrib(symbolic(at_hyperplan,gen(makevecteur(B,A),_SEQ__VECT)),attributs,contextptr);
2752     }
2753     // 2-d line
2754     if (is_zero(eqy,contextptr)){
2755       eqx=-eqx;
2756       A=rdiv(cte,eqx,contextptr);
2757     }
2758     else
2759       A=cst_i*rdiv(-cte,eqy,contextptr);
2760     A=ratnormal(A,contextptr);
2761     B=A + eqy - eqx*cst_i;
2762     B=ratnormal(B,contextptr);
2763     gen e=pnt_attrib(gen(makevecteur(A,B),_LINE__VECT),attributs,contextptr);
2764     return e;
2765   }
2766 
mkrand2d3d(int dim,int nargs,gen (* f)(const gen &,const context *),GIAC_CONTEXT)2767   gen mkrand2d3d(int dim,int nargs,gen (* f)(const gen &,const context *),GIAC_CONTEXT){
2768     vecteur v;
2769     switch (dim){
2770     case 2:
2771       for (int i=0;i<nargs;++i)
2772 	v.push_back(rand_complex());
2773       break;
2774     case 3:
2775       for (int i=0;i<nargs;++i)
2776 	v.push_back(rand_3d());
2777       break;
2778     default:
2779       return gendimerr(contextptr);
2780     }
2781     return f(gen(v,_SEQ__VECT),contextptr);
2782   }
2783 
2784   // v[0] should be a vect
droite_parametric(const vecteur & v,const vecteur & attributs,GIAC_CONTEXT)2785   static gen droite_parametric(const vecteur & v,const vecteur & attributs,GIAC_CONTEXT){
2786     if (v.size()<2 || v.front().type!=_VECT)
2787       return gensizeerr(contextptr);
2788     vecteur & v0=*v[0]._VECTptr;
2789     int s=int(v0.size());
2790     const gen & t=v[1];
2791     gen diffv0=derive(v0,t,contextptr);
2792     if (is_undef(diffv0) || diffv0.type!=_VECT)
2793       return diffv0;
2794     vecteur directeur(*diffv0._VECTptr);
2795     if (!is_zero(derive(directeur,t,contextptr),contextptr))
2796       return gensizeerr(gettext("Not a line!"));
2797     gen A(subst(v0,t,0,false,contextptr)),d(directeur);
2798     if (s==2){
2799       A=A[0]+cst_i*A[1];
2800       d=d[0]+cst_i*d[1];
2801     }
2802     else
2803       return _droite_segment(makevecteur(A,d),_LINE__VECT,attributs,contextptr);
2804     return _droite_segment(makevecteur(A,A+d),_LINE__VECT,attributs,contextptr);
2805   }
2806 
_slope(const gen & args,GIAC_CONTEXT)2807   gen _slope(const gen & args,GIAC_CONTEXT){
2808     if ( args.type==_STRNG && args.subtype==-1) return  args;
2809     gen g=remove_at_pnt(args);
2810     if (g.type!=_VECT || g._VECTptr->size()!=2)
2811       return gensizeerr(contextptr);
2812     g=g._VECTptr->front()-g._VECTptr->back();
2813     if (g.type==_VECT)
2814       return gentypeerr(gettext("2-d instruction"));
2815     return normal(im(g,contextptr)/re(g,contextptr),contextptr);
2816   }
2817   static const char _slope_s []="slope";
2818   static define_unary_function_eval (__slope,&_slope,_slope_s);
2819   define_unary_function_ptr5( at_slope ,alias_at_slope,&__slope,0,true);
2820 
eval_with_xy_quoted(const gen & args0,GIAC_CONTEXT)2821   vecteur eval_with_xy_quoted(const gen & args0,GIAC_CONTEXT){
2822     vecteur v(lidnt(args0));
2823     int xy=0, XY=0;
2824     for (unsigned i=0;i<v.size();++i){
2825       gen & g=v[i];
2826       if (g.type!=_IDNT || strlen(g._IDNTptr->id_name)!=1)
2827 	continue;
2828       char ch=g._IDNTptr->id_name[0];
2829       if (ch=='x' || ch=='y')
2830 	++xy;
2831       if (ch=='X' || ch=='Y')
2832 	++XY;
2833     }
2834     if (xy || !XY){ // priority to x/y
2835       gen idx(identificateur("x")),idy(identificateur("y"));
2836       vecteur v(makevecteur(idx,idy));
2837       vecteur argv(makevecteur(args0,idx,idy));
2838       argv=quote_eval(argv,v,contextptr);
2839       return argv;
2840     }
2841     if (XY){
2842       gen idx(identificateur("X")),idy(identificateur("Y"));
2843       vecteur v(makevecteur(idx,idy));
2844       vecteur argv(makevecteur(args0,idx,idy));
2845       argv=quote_eval(argv,v,contextptr);
2846       return argv;
2847     }
2848     return vecteur(1,eval(args0,eval_level(contextptr),contextptr));
2849   }
2850 
_droite(const gen & args0,GIAC_CONTEXT)2851   gen _droite(const gen & args0,GIAC_CONTEXT){
2852     if (is_undef(args0)) return args0;
2853     if (args0.type==_SYMB || args0.type==_IDNT){
2854       // eval args with x/y or X/Y quoted
2855       vecteur argv=eval_with_xy_quoted(args0,contextptr);
2856       return droite_by_equation(argv,false,contextptr);
2857     }
2858     gen args=eval(args0,eval_level(contextptr),contextptr);
2859     if (args.type==_INT_)
2860       return mkrand2d3d(args.val,2,_droite,contextptr);
2861     if (args.type!=_VECT)
2862       return gentypeerr(contextptr);
2863     vecteur attributs(1,default_color(contextptr));
2864     int s=read_attributs(*args._VECTptr,attributs,contextptr);
2865     if (s<1)
2866       return gendimerr(contextptr);
2867     gen & v0=args._VECTptr->front();
2868     if ( v0.type==_IDNT || is_equal(v0))
2869       return droite_by_equation(*args._VECTptr,false,contextptr);
2870     if (s<2)
2871       return gendimerr(contextptr);
2872     gen v1=(*args._VECTptr)[1];
2873     if (is_equal(v1) && v1._SYMBptr->feuille.type==_VECT){
2874       vecteur & v1v=*v1._SYMBptr->feuille._VECTptr;
2875       if (v1v.size()==2 && v1v[0]==at_slope){
2876 	v0=_affixe(v0,contextptr);
2877 	v1=v0+(1+cst_i*v1v[1]);
2878       }
2879     }
2880     if ( v0.type==_VECT && v1.type!=_VECT && !v1.is_symb_of_sommet(at_pnt))
2881       return droite_parametric(*args._VECTptr,attributs,contextptr);
2882     if (v1.type==_VECT && v0.is_symb_of_sommet(at_pnt))
2883       return _parallele(args,contextptr);
2884     return _droite_segment(gen(makevecteur(v0,v1),_SEQ__VECT),_LINE__VECT,attributs,contextptr);
2885   }
2886   static const char _droite_s []="line";
2887   static define_unary_function_eval_quoted (__droite,&_droite,_droite_s);
2888   define_unary_function_ptr5( at_droite ,alias_at_droite,&__droite,_QUOTE_ARGUMENTS,true);
2889 
_demi_droite(const gen & args,GIAC_CONTEXT)2890   gen _demi_droite(const gen & args,GIAC_CONTEXT){
2891     if ( args.type==_STRNG && args.subtype==-1) return  args;
2892     if (args.type==_INT_)
2893       return mkrand2d3d(args.val,2,_demi_droite,contextptr);
2894     if (args.type!=_VECT)
2895       return gentypeerr(contextptr);
2896     vecteur attributs(1,default_color(contextptr));
2897     int s=read_attributs(*args._VECTptr,attributs,contextptr);
2898     if (s<2)
2899       return gendimerr(contextptr);
2900     vecteur v = *args._VECTptr;
2901     gen seg=gen(makevecteur(v[0],v[1]),_SEQ__VECT);
2902     if (s==3){
2903       v[0]=remove_at_pnt(v[0]);
2904       // v[1]=remove_at_pnt(v[1]);
2905       vecteur w;
2906       w.push_back(eval(symb_sto(_point(v[0],contextptr),v[2]),contextptr));
2907       w.push_back(_droite_segment(seg,_HALFLINE__VECT,attributs,contextptr));
2908       return gen(w,_GROUP__VECT);
2909     }
2910     return _droite_segment(seg,_HALFLINE__VECT,attributs,contextptr);
2911   }
2912   static const char _demi_droite_s []="half_line";
2913   static define_unary_function_eval (__demi_droite,&_demi_droite,_demi_droite_s);
2914   define_unary_function_ptr5( at_demi_droite ,alias_at_demi_droite,&__demi_droite,0,true);
2915 
_vector(const gen & args,GIAC_CONTEXT)2916   gen _vector(const gen & args,GIAC_CONTEXT){
2917     if ( is_undef(args)) return args;
2918     if (args.type!=_VECT || args.subtype!=_SEQ__VECT)
2919       return _vector(gen(vecteur(1,args),_SEQ__VECT),contextptr);
2920     vecteur attributs(1,default_color(contextptr));
2921     int s=read_attributs(*args._VECTptr,attributs,contextptr);
2922     vecteur v = *args._VECTptr;
2923     if (!s)
2924       return gendimerr(contextptr);
2925     if (s==1){
2926       v=makevecteur(0*v[0],v[0]);
2927       ++s;
2928     }
2929     if (s==4){
2930       v[0]=makevecteur(v[0],v[1]);
2931       v[1]=makevecteur(v[2],v[3]);
2932       s=2;
2933     }
2934     if (s>=2 && s<=3 && v[0].type!=_VECT && v[1].type!=_VECT && !v[0].is_symb_of_sommet(at_pnt) && !v[1].is_symb_of_sommet(at_pnt) && is_zero(im(v[0],contextptr),contextptr) && is_zero(im(v[1],contextptr),contextptr)){
2935       if (s==2){
2936 	v[1]=v[0]+cst_i*v[1];
2937 	v[0]=0;
2938       }
2939       else {
2940 	if (v[2].type!=_VECT && !v[2].is_symb_of_sommet(at_pnt) && is_zero(im(v[2],contextptr),contextptr)){
2941 	  v[1]=v;
2942 	  v[0]=makevecteur(0,0,0);
2943 	  v.pop_back();
2944 	}
2945       }
2946     }
2947     v[0]=remove_at_pnt(v[0]);
2948     if (v[1].type!=_VECT) {
2949       v[1]=remove_at_pnt(v[1]);
2950       if (v[0].type==_VECT && v[0]._VECTptr->size()==2)
2951 	v[0]=v[0]._VECTptr->front()+cst_i*v[0]._VECTptr->back();
2952       if (v[1].type==_VECT && v[1].subtype==_VECTOR__VECT && v[1]._VECTptr->size()==2){
2953 	vecteur & w=*v[1]._VECTptr;
2954 	v[1]=v[0]+w[1]-w[0];
2955       }
2956       if (v[1].type==_VECT && v[1]._VECTptr->size()==2)
2957 	v[1]=v[1]._VECTptr->front()+cst_i*v[1]._VECTptr->back();
2958     }
2959     gen seg=gen(makevecteur(v[0],v[1]),_SEQ__VECT);
2960     return _droite_segment(seg,_VECTOR__VECT,attributs,contextptr);
2961   }
2962   static const char _vector_s []="vector";
2963   static define_unary_function_eval (_pb_vector,(const gen_op_context &)&_vector,_vector_s);
2964   define_unary_function_ptr5( at_vector ,alias_at_vector,&_pb_vector,0,true);
2965 
_segment(const gen & args,GIAC_CONTEXT)2966   gen _segment(const gen & args,GIAC_CONTEXT){
2967     if ( args.type==_STRNG && args.subtype==-1) return  args;
2968     if (args.type==_INT_)
2969       return mkrand2d3d(args.val,2,_segment,contextptr);
2970     if (args.type!=_VECT)
2971       return gensizeerr(contextptr);
2972     vecteur attributs(1,default_color(contextptr));
2973     int s=read_attributs(*args._VECTptr,attributs,contextptr);
2974     if (s<2)
2975       return gendimerr(contextptr);
2976     vecteur v = *args._VECTptr;
2977     gen seg=gen(makevecteur(v[0],v[1]),_SEQ__VECT);
2978     if (s==4){
2979       v[0]=remove_at_pnt(v[0]);
2980       v[1]=remove_at_pnt(v[1]);
2981       gen name;
2982 #ifndef NO_STDEXCEPT
2983       try {
2984 #endif
2985 	name=gen(v[2].print(contextptr)+v[3].print(contextptr),contextptr);
2986 #ifndef NO_STDEXCEPT
2987       }
2988       catch (std::runtime_error & ){
2989 	last_evaled_argptr(contextptr)=NULL;
2990 	name=undef;
2991       }
2992 #endif
2993       vecteur w;
2994       if (v[2].type>=_IDNT)
2995 	w.push_back(eval(symb_sto(_point(v[0],contextptr),v[2]),contextptr));
2996       if (v[3].type>=_IDNT)
2997 	w.push_back(eval(symb_sto(_point(v[1],contextptr),v[3]),contextptr));
2998       if (name.type!=_IDNT)
2999 	w.push_back(_droite_segment(seg,_GROUP__VECT,attributs,contextptr));
3000       else
3001 	w.push_back(eval(symb_sto(_droite_segment(seg,_GROUP__VECT,attributs,contextptr),name),contextptr));
3002       return gen(w,_GROUP__VECT);
3003       // return _droite_segment(gen(makevecteur(v[0]+cst_i*v[1],v[2]+cst_i*v[3]),_SEQ__VECT),_GROUP__VECT);
3004     }
3005     return _droite_segment(seg,_GROUP__VECT,attributs,contextptr);
3006   }
3007   static const char _segment_s []="segment";
3008   static define_unary_function_eval_index (28,__segment,&_segment,_segment_s);
3009   define_unary_function_ptr5( at_segment ,alias_at_segment,&__segment,0,true);
3010 
3011 #ifdef WITH_GNUPLOT
gnuplot_set_hidden3d(bool hidden)3012   void gnuplot_set_hidden3d(bool hidden){
3013     gnuplot_hidden3d=hidden;
3014   }
3015 
gnuplot_set_pm3d(bool b)3016   void gnuplot_set_pm3d(bool b){
3017     gnuplot_pm3d=b;
3018   }
3019 
show_3d_axes(FILE * stream)3020   void show_3d_axes(FILE * stream){
3021     if (!show_axes(0))
3022       return;
3023     if (debug_infolevel)
3024       printf("set arrow 1 to %g,0,0 lt 1\nset arrow 2 to 0,%g,0 lt 2\nset arrow 3 to 0,0,%g lt 3\n",gnuplot_xmax,gnuplot_ymax,gnuplot_zmax);
3025     fprintf(stream,"set arrow 1 to %g,0,0 lt 1\nset arrow 2 to 0,%g,0 lt 2\nset arrow 3 to 0,0,%g lt 3\n",gnuplot_xmax,gnuplot_ymax,gnuplot_zmax);
3026   }
3027 
reset_gnuplot_hidden3d(FILE * stream)3028   void reset_gnuplot_hidden3d(FILE * stream){
3029 #ifndef GNUWICE
3030     if (gnuplot_hidden3d){
3031       if (debug_infolevel)
3032 	printf("\nset hidden3d nooffset\nset isosamples 16\n");
3033       fprintf(stream,"\nset hidden3d nooffset\nset isosamples 16\n");
3034     }
3035     else {
3036       if (debug_infolevel)
3037 	printf("\nunset hidden3d nooffset\nset isosamples 10\n");
3038       fprintf(stream,"\nunset hidden3d nooffset\nset isosamples 10\n");
3039     }
3040 #endif
3041     if (debug_infolevel)
3042       printf("set parametric\n");
3043     fprintf(stream,"set parametric\n");
3044     // Problems with history inclusion, see if it's a FLTK problem
3045 #ifndef GNUWINCE // GNUWINCE gnuplot is 3.7, no pm3d
3046     if (gnuplot_pm3d){
3047       if (debug_infolevel)
3048 	printf("set pm3d\n");
3049       fprintf(stream,"set pm3d\n");
3050     }
3051     else {
3052       if (debug_infolevel)
3053 	printf("unset pm3d\n");
3054       fprintf(stream,"unset pm3d\n");
3055     }
3056 #endif // GNUWINCE
3057   }
3058 
3059 #endif
3060 
gnuplot_show_pnt(const symbolic & e,GIAC_CONTEXT)3061   int gnuplot_show_pnt(const symbolic & e,GIAC_CONTEXT){
3062 #ifdef WITH_GNUPLOT
3063     if (!show_point(contextptr))
3064       return -1;
3065     gen f=e.feuille;
3066     vecteur fv(lidnt(f));
3067     vecteur fvs(*evalf(fv)._VECTptr);
3068     if (!lidnt(fvs).empty())
3069       return -1;
3070     f = subst(f,fv,fvs,false,contextptr);
3071     if (f.type==_VECT && !f._VECTptr->empty()){
3072       string legende;
3073       if (f._VECTptr->size()>=3){
3074 	gen & g=(*f._VECTptr)[2];
3075 	if (g.type==_STRNG)
3076 	  legende=g.print(contextptr);
3077 	else
3078 	  legende='"'+g.print(contextptr)+'"';
3079 	legende=" title "+legende;
3080       }
3081       // Plottable: 3-d points vector of length 3 with real coord. [,,]
3082       // 3-d poly-line vector of arbitrary length with 3-d point or 2-d points
3083       // 3-d hyperplan (symb of sommet at_hyperplan, feuille=3-d pt + normal )
3084       // 3-d sphere (symb of sommet at_cercle and diameter = 3-d points)
3085       double les3=gnuplot_xmax-gnuplot_xmin+gnuplot_ymax-gnuplot_ymin+gnuplot_zmax-gnuplot_zmin,deltat=gnuplot_tmax-gnuplot_tmin,milieut=(gnuplot_tmax+gnuplot_tmin)/2;
3086       const gen & p=e.feuille._VECTptr->front();
3087       string tmpfilename("#xcas"+print_INT_(gnuplot_fileno)+".gnu");
3088       bool doplot=false,clrplot=false;
3089       int with_point;
3090       string splot;
3091       // splot if gnuplot_do_splot && !clrplot, replot otherwise
3092       identificateur _u("u"),_v("v");
3093       if (p.type==_VECT && p.subtype==_POINT__VECT && p._VECTptr->size()==3){
3094 	vecteur & v=*p._VECTptr;
3095 	splot=evalf(gen(v,_SEQ__VECT),1,contextptr).print(contextptr) +" with point";
3096 	with_point=2;
3097 	doplot=true;
3098       }
3099       if (p.type==_VECT && p.subtype!=_POINT__VECT){
3100 	vecteur & v=*p._VECTptr;
3101 	if (p.subtype==_POLYEDRE__VECT){
3102 	  // each element of v is a face with 3 or 4 vertices
3103 	  ofstream tmpfile(tmpfilename.c_str());
3104 	  const_iterateur it=v.begin(),itend=v.end();
3105 	  for (;it!=itend;++it){
3106 	    if (it->type==_VECT){
3107 	      vecteur w = * it->_VECTptr;
3108 	      int s=w.size();
3109 	      if (s%2){
3110 		w.insert(w.begin()+s/2,w[s/2]);
3111 		++s;
3112 	      }
3113 	      if (s>=4){
3114 		for (int j=0;j<s/2;++j){
3115 		  if (w[j].type!=_VECT || w[j]._VECTptr->size()!=3)
3116 		    tmpfile << "0 0 0" <<'\n';
3117 		  else {
3118 		    const vecteur & ww=*w[j]._VECTptr;
3119 		    tmpfile << evalf(ww[0],1,contextptr) << " " << evalf(ww[1],1,contextptr) << " " << evalf(ww[2],1,contextptr) << '\n';
3120 		  }
3121 		}
3122 		tmpfile << '\n';
3123 		for (int j=s-1;j>=s/2;--j){
3124 		  if (w[j].type!=_VECT || w[j]._VECTptr->size()!=3)
3125 		    tmpfile << "0 0 0" <<'\n';
3126 		  else {
3127 		    const vecteur & ww=*w[j]._VECTptr;
3128 		    tmpfile << evalf(ww[0],1,contextptr) << " " << evalf(ww[1],1,contextptr) << " " << evalf(ww[2],1,contextptr) << '\n';
3129 		  }
3130 		}
3131 		doplot=true;
3132 	      }
3133 	    }
3134 	    tmpfile << '\n' << '\n'; // next face
3135 	  } // end for
3136 	  with_point=0;
3137 	  tmpfile.close();
3138 	}
3139 	else {
3140 	  if (v.size()==2){
3141 	    // Using arrow
3142 	    // parametric plot of the line
3143 	    gen coeff=evalf(v.back()-v.front(),1,contextptr);
3144 	    if (coeff.type!=_VECT)
3145 	      return -1;
3146 	    gen d;
3147 	    if (p.subtype==_GROUP__VECT || p.subtype==_VECTOR__VECT)
3148 	      d=1.0;
3149 	    else
3150 	      d=2*les3/abs_norm(coeff,0);
3151 	    coeff=(d/deltat)*coeff;
3152 	    gen tmp_eq;
3153 	    if (p.subtype==_GROUP__VECT || p.subtype==_VECTOR__VECT)
3154 	      tmp_eq=v.front()+coeff*(_u-gnuplot_tmin);
3155 	    else
3156 	      tmp_eq=v.front()+coeff*(_u-milieut);
3157 	    // add an epsilon to see lines on plans
3158 	    tmp_eq=tmp_eq+1e-3*makevecteur(gnuplot_xmax-gnuplot_xmin,gnuplot_ymax-gnuplot_ymin,gnuplot_zmax-gnuplot_zmin);
3159 	    if (tmp_eq.type==_VECT){
3160 	      tmp_eq.subtype=_SEQ__VECT;
3161 	      splot=evalf(tmp_eq,1,contextptr).print(contextptr);
3162 	      doplot=true;
3163 	      with_point=2;
3164 	    }
3165 	  }
3166 	  else {
3167 	    ofstream tmpfile(tmpfilename.c_str());
3168 	    const_iterateur it=v.begin(),itend=v.end();
3169 	    for (;it!=itend;++it){
3170 	      if (it->type==_VECT && it->_VECTptr->size()==3){
3171 		const vecteur & w = * it->_VECTptr;
3172 		tmpfile << evalf(w[0],1,contextptr) << " " << evalf(w[1],1,contextptr) << " " << evalf(w[2],1,contextptr) << '\n';
3173 		doplot=true;
3174 	      }
3175 	    }
3176 	    with_point=0;
3177 	    tmpfile.close();
3178 	  }
3179 	} // end else polyedre
3180       } // end if (p.type==_VECT)
3181       if (p.is_symb_of_sommet(at_hyperplan)){
3182 	vecteur P,n;
3183 	if (!hyperplan_normal_point(p,n,P))
3184 	  return false;
3185 	with_point=2;
3186 	vecteur v1,v2;
3187 	if (!normal3d(n,v1,v2))
3188 	  return false;
3189 	gen v1c=evalf(v1,1,contextptr);
3190 	v1c=(les3/2/deltat)*v1c/abs_norm(v1c,0);
3191 	gen v2c=evalf(v2,1,contextptr);
3192 	v2c=(les3/2/deltat)*v2c/abs_norm(v2c,0);
3193 	gen par_eq=P+(_u-milieut)*v1c+(_v-milieut)*v2c;
3194 	par_eq.subtype=_SEQ__VECT;
3195 	splot=evalf(par_eq,1,contextptr).print(contextptr);
3196 	doplot=true;
3197       }
3198       if (p.is_symb_of_sommet(at_hypersphere)){
3199 	// The optional 3rd argument of hypersphere is used for a "directional"
3200 	// plot. A fourth arg might be used later for half-sphere...
3201 	gen & f=p._SYMBptr->feuille;
3202 	if (f.type==_VECT && f._VECTptr->size()>=2){
3203 	  vecteur & v=*f._VECTptr;
3204 	  if (v.front().type==_VECT && v.front()._VECTptr->size()==3){
3205 	    with_point=2;
3206 	    gen r=v[1];
3207 	    if (r.type==_VECT && r._VECTptr->size()==3)
3208 	      r=l2norm(*r._VECTptr,contextptr);
3209 	    gen uu=2*M_PI/deltat*_u;
3210 	    gen vv=2*M_PI/deltat*_v;
3211 	    vecteur dir1(makevecteur(1,0,0)),dir2(makevecteur(0,1,0)),dir3(makevecteur(0,0,1));
3212 	    if (v.size()>=3 && v[2].type==_VECT && v[2]._VECTptr->size()==3){
3213 	      dir3=*v[2]._VECTptr;
3214 	      dir3=divvecteur(dir3,sqrt(dotvecteur(dir3,dir3),contextptr));
3215 	      if (!is_zero(dir3[0],contextptr) || !is_zero(dir3[1],contextptr) ){
3216 		dir1=makevecteur(-dir3[1],dir3[0],0);
3217 		dir1=divvecteur(dir1,sqrt(dotvecteur(dir1,dir1),contextptr));
3218 		dir2=cross(dir3,dir1,contextptr);
3219 	      }
3220 	    }
3221 	    gen par_eq=v.front()+r*(cos(uu,contextptr)*(cos(vv,contextptr)*dir1+sin(vv,contextptr)*dir2)+sin(uu,contextptr)*dir3);
3222 	    par_eq.subtype=_SEQ__VECT;
3223 	    splot=evalf(par_eq,1,contextptr).print(contextptr)+" notitle";
3224 	    doplot=true;
3225 	  }
3226 	}
3227       }
3228       if (doplot){
3229 	int out_handle;
3230 	FILE * gnuplot_out_readstream,* stream = open_gnuplot(clrplot,gnuplot_out_readstream,out_handle);
3231 	reset_gnuplot_hidden3d(stream);
3232 	if (debug_infolevel)
3233 	  printf("set xrange [%g:%g]\n",gnuplot_xmin,gnuplot_xmax);
3234 	fprintf(stream,"set xrange [%g:%g]\n",gnuplot_xmin,gnuplot_xmax);
3235 	if (debug_infolevel)
3236 	  printf("set yrange [%g:%g]\n",gnuplot_ymin,gnuplot_ymax);
3237 	fprintf(stream,"set yrange [%g:%g]\n",gnuplot_ymin,gnuplot_ymax);
3238 	if (debug_infolevel)
3239 	  printf("set zrange [%g:%g]\n",gnuplot_zmin,gnuplot_zmax);
3240 	fprintf(stream,"set zrange [%g:%g]\n",gnuplot_zmin,gnuplot_zmax);
3241 	if (debug_infolevel)
3242 	  printf("set urange [%g:%g]\n",gnuplot_tmin,gnuplot_tmax);
3243 	fprintf(stream,"set urange [%g:%g]\n",gnuplot_tmin,gnuplot_tmax);
3244 	if (debug_infolevel)
3245 	  printf("set vrange [%g:%g]\n",gnuplot_tmin,gnuplot_tmax);
3246 	fprintf(stream,"set vrange [%g:%g]\n",gnuplot_tmin,gnuplot_tmax);
3247 	gnuplot_wait(out_handle,gnuplot_out_readstream);
3248 	gnuplot_set_hidden3d(gnuplot_hidden3d);
3249 	if (clrplot || gnuplot_do_splot){
3250 	  show_3d_axes(stream);
3251 	  if (show_axes(contextptr))
3252 	    gnuplot_wait(out_handle,gnuplot_out_readstream);
3253 	}
3254 	if (clrplot || gnuplot_do_splot){
3255 	  if (debug_infolevel)
3256 	    printf("splot");
3257 	  fprintf(stream,"splot");
3258 	}
3259 	else {
3260 	  if (debug_infolevel)
3261 	    printf("replot");
3262 	  fprintf(stream,"replot");
3263 	}
3264 	if (with_point ==2 ){
3265 	  if (debug_infolevel)
3266 	    printf((" "+splot+legende +'\n').c_str());
3267 	  fprintf(stream,(" "+splot+legende +'\n').c_str());
3268 	}
3269 	else {
3270 	  if (debug_infolevel)
3271 	    printf(" \"%s\" with ",tmpfilename.c_str());
3272 	  fprintf(stream," \"%s\" with ",tmpfilename.c_str());
3273 	  if (with_point){
3274 	    if (debug_infolevel)
3275 	      printf("point\n");
3276 	    fprintf(stream,"point\n");
3277 	  }
3278 	  else {
3279 	    if (debug_infolevel)
3280 	      printf("line\n");
3281 	    fprintf(stream,"line\n");
3282 	  }
3283 	}
3284 	gnuplot_wait(out_handle,gnuplot_out_readstream);
3285 	gnuplot_do_splot=false;
3286 	win9x_gnuplot(stream);
3287 	gnuplot_wait(out_handle,gnuplot_out_readstream,gnuplot_wait_times);
3288 	++gnuplot_fileno;
3289 	return gnuplot_fileno-1;
3290       }
3291     }
3292 #endif
3293     return -1;
3294   }
symb_pnt_name(const gen & x,const gen & c,const gen & nom,GIAC_CONTEXT)3295   gen symb_pnt_name(const gen & x,const gen & c,const gen & nom,GIAC_CONTEXT){
3296     symbolic e=symbolic(at_pnt,gen(makevecteur(x,c,nom),_PNT__VECT));
3297     gen ee(e);
3298     ee.subtype=gnuplot_show_pnt(e,contextptr);
3299     history_plot(contextptr).push_back(ee);
3300 #ifndef KHICAS
3301     if (io_graph(contextptr))
3302       __interactive.op(ee,contextptr);
3303 #endif
3304     return ee;
3305   }
symb_segment(const gen & x,const gen & y,const vecteur & c,int type,GIAC_CONTEXT)3306   gen symb_segment(const gen & x,const gen & y,const vecteur & c,int type,GIAC_CONTEXT){
3307     gen e;
3308     if (c.empty())
3309       e=symbolic(at_pnt,gen(makevecteur(gen(makevecteur(x,y),type),default_color(contextptr)),_PNT__VECT));
3310     if (c.size()==1 || is_zero(c[1],contextptr))
3311       e=symbolic(at_pnt,gen(makevecteur(gen(makevecteur(x,y),type),c[0]),_PNT__VECT));
3312     else
3313       e=symbolic(at_pnt,gen(makevecteur(gen(makevecteur(x,y),type),c[0],c[1]),_PNT__VECT));
3314     gen ee(e);
3315     ee.subtype=gnuplot_show_pnt(*e._SYMBptr,contextptr);
3316     history_plot(contextptr).push_back(ee);
3317 #ifndef KHICAS
3318     if (io_graph(contextptr))
3319       __interactive.op(ee,contextptr);
3320 #endif
3321     return ee;
3322   }
symb_pnt(const gen & x,const gen & c,GIAC_CONTEXT)3323   gen symb_pnt(const gen & x,const gen & c,GIAC_CONTEXT){
3324     if (is_undef(x)) return x;
3325     gen ee = new_ref_symbolic(symbolic(at_pnt,gen(makenewvecteur(x,c),_PNT__VECT)));
3326 #ifdef WITH_GNUPLOT
3327     ee.subtype=gnuplot_show_pnt(*ee._SYMBptr,contextptr);
3328 #else
3329     ee.subtype=-1;
3330 #endif
3331     history_plot(contextptr).push_back(ee);
3332 #ifndef KHICAS
3333     if (io_graph(contextptr))
3334       __interactive.op(ee,contextptr);
3335 #endif
3336     return ee;
3337   }
symb_pnt(const gen & x,GIAC_CONTEXT)3338   gen symb_pnt(const gen & x,GIAC_CONTEXT){
3339     return symb_pnt(x,gen(0),contextptr); // 0 instead of FL_BLACK
3340   }
printaspnt(const gen & feuille,const char * sommetstr,GIAC_CONTEXT)3341   static string printaspnt(const gen & feuille,const char * sommetstr,GIAC_CONTEXT){
3342     if ( calc_mode(contextptr)==1 && feuille.type==_VECT && !feuille._VECTptr->empty()){
3343       gen f0=feuille._VECTptr->front();
3344       /*
3345 	if (f0.type==_VECT && f0.subtype==_VECTOR__VECT){
3346 	f0.subtype=_SEQ__VECT;
3347 	return "vector("+f0.print(contextptr)+")";
3348 	}
3349       */
3350       if (f0.type==_VECT && f0.subtype==_POINT__VECT){
3351 	f0.subtype=_SEQ__VECT;
3352 	return '('+f0.print(contextptr)+')';
3353       }
3354       if (f0.type!=_VECT){
3355 	if (f0.type==_SYMB && (f0._SYMBptr->sommet==at_hyperplan || f0._SYMBptr->sommet==at_hypersphere)){
3356 	  return f0.print(contextptr);
3357 	}
3358 	if (f0.type!=_SYMB || !equalposcomp(plot_sommets,f0._SYMBptr->sommet)){
3359 	  gen r,i;
3360 	  reim(f0,r,i,contextptr);
3361 	  r=ratnormal(r,contextptr); // _evalfa(recursive_normal(r,contextptr),contextptr);
3362 	  i=ratnormal(i,contextptr); // _evalfa(recursive_normal(i,contextptr),contextptr);
3363 	  return '('+r.print(contextptr)+','+i.print(contextptr)+')';
3364 	}
3365       }
3366     }
3367     return string(sommetstr)+('('+feuille.print(contextptr)+')');
3368   }
_pnt(const gen & args,GIAC_CONTEXT)3369   gen _pnt(const gen & args,GIAC_CONTEXT){
3370     if ( args.type==_STRNG && args.subtype==-1) return  args;
3371     if ((args.type==_SYMB) && (args._SYMBptr->sommet==at_pnt))
3372       return args;
3373     if ( (args.type==_VECT) && (args._VECTptr->size()) ){
3374       vecteur v(*args._VECTptr);
3375       gen e=v.front();
3376       if ( (e.type==_SYMB) && (e._SYMBptr->sommet==at_pnt))
3377 	return e;
3378       if (v.size()==3)
3379 	v.pop_back();
3380       return symbolic(at_pnt,gen(v,_PNT__VECT));
3381     }
3382     return symbolic(at_pnt,args);
3383   }
3384   static const char _pnt_s []="pnt";
3385   static define_unary_function_eval2_index (24,__pnt,&_pnt,_pnt_s,&printaspnt);
3386   define_unary_function_ptr5( at_pnt ,alias_at_pnt,&__pnt,0,true);
3387 
centre_rayon(const gen & cercle,gen & centre,gen & rayon,bool absrayon,GIAC_CONTEXT)3388   bool centre_rayon(const gen & cercle,gen & centre,gen & rayon,bool absrayon,GIAC_CONTEXT){
3389     gen c=remove_at_pnt(cercle);
3390     if (c.is_symb_of_sommet(at_hypersphere)){
3391       gen & f=c._SYMBptr->feuille;
3392       if (f.type!=_VECT || f._VECTptr->size()!=2)
3393 	return false; // setsizeerr(contextptr);
3394       centre=f._VECTptr->front();
3395       rayon=f._VECTptr->back();
3396       return true;
3397     }
3398     if ( (c.type!=_SYMB) || (c._SYMBptr->sommet!=at_cercle))
3399       return false;
3400     gen diam=remove_at_pnt(c._SYMBptr->feuille._VECTptr->front());
3401     if (diam.type!=_VECT)
3402       return false;
3403     gen a=remove_at_pnt(diam._VECTptr->front());
3404     gen b=remove_at_pnt(diam._VECTptr->back());
3405     centre=recursive_normal(ratnormal(rdiv(a+b,plus_two,contextptr),contextptr),contextptr);
3406     rayon=rdiv(b-a,plus_two,contextptr);
3407     if (absrayon)
3408       rayon=abs(recursive_normal(ratnormal(rayon,contextptr),contextptr),contextptr);
3409     return true;
3410   }
3411 
3412   // for a point nothing, segment/line/vect->1st point
3413   // circle/sphere->diam
get_point(const gen & g,int n,GIAC_CONTEXT)3414   gen get_point(const gen & g,int n,GIAC_CONTEXT){
3415     gen tmp=remove_at_pnt(g);
3416     bool sphere=tmp.is_symb_of_sommet(at_hypersphere);
3417     if (tmp.is_symb_of_sommet(at_cercle) || sphere){
3418       gen c=remove_at_pnt(tmp);
3419       gen f=c._SYMBptr->feuille;
3420       if (f.type==_VECT && f._VECTptr->size()>=3)
3421 	f=f._VECTptr->front();
3422       if (f.type!=_VECT || f._VECTptr->size()!=2)
3423 	return undef;
3424       gen c1=f._VECTptr->front(),c2=f._VECTptr->back();
3425       if (n==0 && !sphere)
3426 	return (c1+c2)/2;
3427       return c1;
3428     }
3429     if (tmp.is_symb_of_sommet(at_curve))
3430       return gensizeerr(contextptr);
3431     if (tmp.is_symb_of_sommet(at_hyperplan)){
3432       vecteur n,P;
3433       if (!hyperplan_normal_point(tmp,n,P))
3434 	return gensizeerr(contextptr);
3435       return gen(P,_POINT__VECT);
3436     }
3437     if (tmp.type!=_VECT)
3438       return tmp;
3439     vecteur & v =*tmp._VECTptr;
3440     int s=int(v.size());
3441     if (tmp.subtype==_POINT__VECT || (tmp.subtype==0 && (s==2 || s==3)) ){
3442       if (s==2)
3443 	return v[0]+cst_i*v[1];
3444       return tmp;
3445     }
3446     if (n>=s)
3447       n=s-1;
3448     if (!s)
3449       return undef;
3450     return v[n];
3451   }
3452 
_point(const gen & args,GIAC_CONTEXT)3453   gen _point(const gen & args,GIAC_CONTEXT){
3454     if ( args.type==_STRNG && args.subtype==-1) return  args;
3455     if ( (args.type==_SYMB) && (args._SYMBptr->sommet==at_pnt))
3456       return args;
3457     vecteur attributs(1,default_color(contextptr) | _QUADRANT3);
3458     if (args.type==_VECT) {
3459       int s=read_attributs(*args._VECTptr,attributs,contextptr);
3460       vecteur v(args._VECTptr->begin(),args._VECTptr->begin()+s);
3461       if (s<1)
3462 	return gendimerr(contextptr);
3463       bool ismat=ckmatrix(v);
3464       if (has_i(v) || ismat){
3465 	if ( (v.size()==2 || v.size()==3) && ismat && v.front()._VECTptr->size()>3){
3466 	  v=mtran(v);
3467 	  for (int i=0;i<int(v.size());++i)
3468 	    v[i]=put_attributs(_point(v[i],contextptr),attributs,contextptr);
3469 	  return gen(v,_SEQ__VECT);
3470 	}
3471 	for (int i=0;i<s;++i){
3472 	  if (v[i].type==_VECT)
3473 	    v[i]=put_attributs(_point(v[i],contextptr),attributs,contextptr);
3474 	  else
3475 	    v[i]=pnt_attrib(v[i],attributs,contextptr);
3476 	}
3477 	if (s==1)
3478 	  return v[0];
3479 	return gen(v,_SEQ__VECT);
3480       }
3481       if (s==1){
3482 	gen arg1=args._VECTptr->front();
3483 	if (arg1.type==_VECT){
3484 	  if (arg1._VECTptr->size()==2)
3485 	    arg1=arg1._VECTptr->front()+cst_i*arg1._VECTptr->back();
3486 	  else {
3487 	    arg1=gen(*arg1._VECTptr,_POINT__VECT);
3488 	  }
3489 	}
3490 	return pnt_attrib(arg1,attributs,contextptr);
3491       }
3492       if (s==2){
3493 	if (args._VECTptr->front().type==_VECT || args._VECTptr->back().type==_VECT)
3494 	  return gensizeerr(contextptr);
3495 	return pointonoff(args._VECTptr->front()+cst_i*(*args._VECTptr)[1],attributs,contextptr);
3496       }
3497       return pnt_attrib(gen(v,_POINT__VECT),attributs,contextptr);
3498     }
3499     return pnt_attrib(args,attributs,contextptr);
3500   }
3501   static const char _point_s []="point";
3502   static define_unary_function_eval_index (26,__point,&_point,_point_s);
3503   define_unary_function_ptr5( at_point ,alias_at_point,&__point,0,true);
3504 
rand_2d3d(bool espace)3505   static gen rand_2d3d(bool espace){
3506     if (espace)
3507       return do_point3d(rand_3d());
3508     else
3509       return rand_complex();
3510   }
point2d3d(bool espace,const vecteur & attributs,GIAC_CONTEXT)3511   static gen point2d3d(bool espace,const vecteur & attributs,GIAC_CONTEXT){
3512     return pnt_attrib(rand_2d3d(espace),attributs,contextptr);
3513   }
point2d3d(const gen & args,bool espace,GIAC_CONTEXT)3514   static gen point2d3d(const gen & args,bool espace,GIAC_CONTEXT){
3515     vecteur v(gen2vecteur(args));
3516     vecteur attributs(1,default_color(contextptr));
3517     int s=read_attributs(v,attributs,contextptr);
3518     v=vecteur(v.begin(),v.begin()+s);
3519     if (v.empty())
3520       return point2d3d(espace,attributs,contextptr);
3521     vecteur w;
3522     const_iterateur it=v.begin(),itend=v.end();
3523     for (;it!=itend;++it){
3524       w.push_back(symbolic(at_sto,makesequence(symbolic(at_pnt,gen(makevecteur(rand_2d3d(espace),attributs[0]),_PNT__VECT)),*it)));
3525     }
3526     return eval(w,contextptr);
3527   }
_point3d(const gen & args,GIAC_CONTEXT)3528   gen _point3d(const gen & args,GIAC_CONTEXT){
3529     if ( args.type==_STRNG && args.subtype==-1) return  args;
3530     return point2d3d(args,true,contextptr);
3531   }
3532   static const char _point3d_s []="point3d";
3533   static define_unary_function_eval_quoted (__point3d,&_point3d,_point3d_s);
3534   define_unary_function_ptr5( at_point3d ,alias_at_point3d,&__point3d,_QUOTE_ARGUMENTS,true);
3535 
_point2d(const gen & args,GIAC_CONTEXT)3536   gen _point2d(const gen & args,GIAC_CONTEXT){
3537     if ( args.type==_STRNG && args.subtype==-1) return  args;
3538     return point2d3d(args,false,contextptr);
3539   }
3540   static const char _point2d_s []="point2d";
3541   static define_unary_function_eval_quoted (__point2d,&_point2d,_point2d_s);
3542   define_unary_function_ptr5( at_point2d ,alias_at_point2d,&__point2d,_QUOTE_ARGUMENTS,true);
3543 
_affixe(const gen & args,GIAC_CONTEXT)3544   gen _affixe(const gen & args,GIAC_CONTEXT){
3545     if ( args.type==_STRNG && args.subtype==-1) return  args;
3546     if (args.type==_VECT && args._VECTptr->size()==2 && !args._VECTptr->front().is_symb_of_sommet(at_pnt))
3547       return args._VECTptr->front()+cst_i*args._VECTptr->back();
3548     if (args.type==_VECT)
3549       return apply(args,_affixe,contextptr);
3550     gen g=remove_at_pnt(args);
3551     if (g.type==_VECT && g.subtype==_VECTOR__VECT && g._VECTptr->size()==2)
3552       return g._VECTptr->back()-g._VECTptr->front();
3553     return g;
3554   }
3555   static const char _affixe_s []="affix";
3556   static define_unary_function_eval (__affixe,&_affixe,_affixe_s);
3557   define_unary_function_ptr5( at_affixe ,alias_at_affixe,&__affixe,0,true);
3558 
_abscisse(const gen & args,GIAC_CONTEXT)3559   gen _abscisse(const gen & args,GIAC_CONTEXT){
3560     if ( args.type==_STRNG && args.subtype==-1) return  args;
3561     if (args.type==_VECT && args._VECTptr->size()==2 && !args._VECTptr->front().is_symb_of_sommet(at_pnt))
3562       return args._VECTptr->front();
3563     if (args.type==_VECT&& args.subtype!=_POINT__VECT)
3564       return apply(args,contextptr,_abscisse);
3565     if (args.type==_IDNT)
3566       return symbolic(at_abscisse,args);
3567     if (is_equal(args)){
3568       gen tmp=equal2diff(args),a,b;
3569       if (is_linear_wrt(tmp,x__IDNT_e,a,b,contextptr) && a!=0)
3570 	return -b/a;
3571       return gensizeerr(contextptr);
3572     }
3573     gen g=remove_at_pnt(args);
3574     if (g.type==_VECT && g._VECTptr->size()>=2){
3575       if (g.subtype==_VECTOR__VECT)
3576 	return _abscisse(g._VECTptr->back()-g._VECTptr->front(),contextptr);
3577       return (*g._VECTptr)[0];
3578     }
3579     return re(g,contextptr);
3580   }
3581   static const char _abscisse_s []="abscissa";
3582   static define_unary_function_eval (__abscisse,&_abscisse,_abscisse_s);
3583   define_unary_function_ptr5( at_abscisse ,alias_at_abscisse,&__abscisse,0,true);
3584 
_ordonnee(const gen & args,GIAC_CONTEXT)3585   gen _ordonnee(const gen & args,GIAC_CONTEXT){
3586     if ( args.type==_STRNG && args.subtype==-1) return  args;
3587     if (args.type==_VECT && args._VECTptr->size()==2 && !args._VECTptr->front().is_symb_of_sommet(at_pnt))
3588       return args._VECTptr->back();
3589     if (args.type==_VECT && args.subtype!=_POINT__VECT)
3590       return apply(args,contextptr,_ordonnee);
3591     if (args.type==_IDNT)
3592       return symbolic(at_ordonnee,args);
3593     if (is_equal(args)){
3594       gen tmp=equal2diff(args),a,b;
3595       if (is_linear_wrt(tmp,y__IDNT_e,a,b,contextptr) && a!=0)
3596 	return -b/a;
3597       return gensizeerr(contextptr);
3598     }
3599     gen g=remove_at_pnt(args);
3600     if (g.type==_VECT && g._VECTptr->size()>=2){
3601       if (g.subtype==_VECTOR__VECT)
3602 	return _ordonnee(g._VECTptr->back()-g._VECTptr->front(),contextptr);
3603       return (*g._VECTptr)[1];
3604     }
3605     return im(g,contextptr);
3606   }
3607   static const char _ordonnee_s []="ordinate";
3608   static define_unary_function_eval (__ordonnee,&_ordonnee,_ordonnee_s);
3609   define_unary_function_ptr5( at_ordonnee ,alias_at_ordonnee,&__ordonnee,0,true);
3610 
_cote(const gen & args,GIAC_CONTEXT)3611   gen _cote(const gen & args,GIAC_CONTEXT){
3612     if ( args.type==_STRNG && args.subtype==-1) return  args;
3613     if (args.type==_VECT && args.subtype!=_POINT__VECT)
3614       return apply(args,contextptr,_cote);
3615     if (args.type==_IDNT)
3616       return symbolic(at_cote,args);
3617     if (is_equal(args)){
3618       gen tmp=equal2diff(args),a,b;
3619       if (is_linear_wrt(tmp,z__IDNT_e,a,b,contextptr) && a!=0)
3620 	return -b/a;
3621       return gensizeerr(contextptr);
3622     }
3623     gen g=remove_at_pnt(args);
3624     if (g.type==_VECT && g._VECTptr->size()>=3)
3625       return (*g._VECTptr)[2];
3626     return gensizeerr(gettext("3-d instruction"));
3627   }
3628   static const char _cote_s []="cote";
3629   static define_unary_function_eval (__cote,&_cote,_cote_s);
3630   define_unary_function_ptr5( at_cote ,alias_at_cote,&__cote,0,true);
3631 
coordonnees(const gen & args,bool in,GIAC_CONTEXT)3632   gen coordonnees(const gen & args,bool in,GIAC_CONTEXT){
3633     if ( args.type==_STRNG && args.subtype==-1) return  args;
3634     if (args.type==_VECT){
3635       if (args._VECTptr->empty())
3636 	return args;
3637       if (args.subtype==_POINT__VECT){
3638 	gen g=args;
3639 	g.subtype=calc_mode(contextptr)==1?_GGB__VECT:0;
3640 	return g;
3641       }
3642       if (is_equal(args._VECTptr->front())){
3643 	vecteur v=*args._VECTptr,res;
3644 	vecteur last(2);
3645 	bool lastx=false;
3646 	for (unsigned i=0;i<v.size();++i){
3647 	  string args0s="x";
3648 	  if (i<v.size() && v[i].is_symb_of_sommet(at_equal)){
3649 	    args0s=v[i]._SYMBptr->feuille[0].print(contextptr);
3650 	    v[i]=v[i]._SYMBptr->feuille[1];
3651 	  }
3652 	  if (args0s[args0s.size()-1]=='x'){
3653 	    if (lastx)
3654 	      res.push_back(gen(last,_GGB__VECT));
3655 	    last[0]=v[i];
3656 	    last[1]=0;
3657 	    lastx=true;
3658 	  }
3659 	  if (args0s[args0s.size()-1]=='y'){
3660 	    last[1]=v[i];
3661 	    res.push_back(gen(last,_GGB__VECT));
3662 	    lastx=false;
3663 	  }
3664 	}
3665 	if (lastx)
3666 	  res.push_back(gen(last,_GGB__VECT));
3667 	return res;
3668       }
3669       if (args._VECTptr->size()==2 && args.subtype==_VECTOR__VECT){
3670 	gen a = args._VECTptr->front();
3671 	gen b = args._VECTptr->back();
3672 	// if (!a.is_symb_of_sommet(at_pnt) && !b.is_symb_of_sommet(at_pnt))
3673 	//  return makevecteur(a,b);
3674 	a = remove_at_pnt(a);
3675 	b = remove_at_pnt(b);
3676 	if ( (a.type==_VECT && b.type!=_VECT) &&
3677 	     (b.type==_VECT && a.type!=_VECT) )
3678 	  return gentypeerr(contextptr);
3679 	gen c=b-a;
3680 	if (c.type==_VECT)
3681 	  return c;
3682 	return gen(makevecteur(re(c,contextptr),im(c,contextptr)),calc_mode(contextptr)==1?_GGB__VECT:0);
3683       }
3684       if (calc_mode(contextptr)==1 && args.subtype!=_GGB__VECT){
3685 	vecteur res;
3686 	iterateur it=args._VECTptr->begin(),itend=args._VECTptr->end();
3687 	if (in && itend-it==2 && it->type!=_VECT)
3688 	  return change_subtype(args,_GGB__VECT);
3689 	for (;it!=itend;++it){
3690 	  res.push_back(coordonnees(*it,true,contextptr));
3691 	}
3692 	return res; // normal list here
3693       }
3694       return apply(args,contextptr,_coordonnees);
3695     }
3696     gen P=remove_at_pnt(args);
3697     if (P.type==_VECT){
3698       if (P.subtype==_VECTOR__VECT && P._VECTptr->size()==2){
3699 	P=P._VECTptr->back()-P._VECTptr->front();
3700 	if (P.type==_VECT)
3701 	  P.subtype=_POINT__VECT;
3702 	return coordonnees(P,true,contextptr);
3703       }
3704       if (P.subtype==_POINT__VECT)
3705 	P.subtype=calc_mode(contextptr)==1?_GGB__VECT:0;
3706       return P;
3707     }
3708     return gen(makevecteur(re(P,contextptr),im(P,contextptr)),calc_mode(contextptr)==1?_GGB__VECT:0);
3709   }
_coordonnees(const gen & args,GIAC_CONTEXT)3710   gen _coordonnees(const gen & args,GIAC_CONTEXT){
3711     return coordonnees(args,false,contextptr);
3712   }
3713   static const char _coordonnees_s []="coordinates";
3714   static define_unary_function_eval (__coordonnees,&_coordonnees,_coordonnees_s);
3715   define_unary_function_ptr5( at_coordonnees ,alias_at_coordonnees,&__coordonnees,0,true);
3716 
_coordonnees_polaires(const gen & args,GIAC_CONTEXT)3717   gen _coordonnees_polaires(const gen & args,GIAC_CONTEXT){
3718     if ( args.type==_STRNG && args.subtype==-1) return  args;
3719     gen c=args.is_symb_of_sommet(at_pnt)?_coordonnees(args,contextptr):args;
3720     if (c.type==_VECT && c._VECTptr->size()==2){
3721       gen a=c._VECTptr->front();
3722       gen b=c._VECTptr->back();
3723       if (a.type==_VECT && b.type==_VECT){
3724 	gen tmp=a-b;
3725 	if (tmp.type==_VECT && tmp._VECTptr->size()==2){
3726 	  a=tmp._VECTptr->front();
3727 	  b=tmp._VECTptr->back();
3728 	  c=a+cst_i*b;
3729 	}
3730       }
3731       else {
3732 	if (!has_i(a) && !has_i(b))
3733 	  c=a+cst_i*b;
3734       }
3735     }
3736     if (c.type==_VECT)
3737       return apply(c,_coordonnees_polaires,contextptr);
3738     gen a=abs(c,contextptr);
3739     gen b=arg(c,contextptr);
3740     return makevecteur(a,b);
3741   }
3742   static const char _coordonnees_polaires_s []="polar_coordinates";
3743   static define_unary_function_eval (__coordonnees_polaires,&_coordonnees_polaires,_coordonnees_polaires_s);
3744   define_unary_function_ptr5( at_coordonnees_polaires ,alias_at_coordonnees_polaires,&__coordonnees_polaires,0,true);
3745 
_coordonnees_rectangulaires(const gen & args,GIAC_CONTEXT)3746   gen _coordonnees_rectangulaires(const gen & args,GIAC_CONTEXT){
3747     if ( args.type==_STRNG && args.subtype==-1) return  args;
3748     if (args.is_symb_of_sommet(at_pnt))
3749       return _coordonnees(args,contextptr);
3750     if (args.type!=_VECT)
3751       return makevecteur(re(args,contextptr),im(args,contextptr));
3752     if (args._VECTptr->size()!=2)
3753       return apply(args,_coordonnees_rectangulaires,contextptr);
3754     gen a=args._VECTptr->front();
3755     gen b=args._VECTptr->back();
3756     if (a.type!=_VECT && b.type!=_VECT)
3757       return makevecteur(a*cos(b,contextptr),a*sin(b,contextptr));
3758     return apply(args,_coordonnees_rectangulaires,contextptr);
3759   }
3760   static const char _coordonnees_rectangulaires_s []="rectangular_coordinates";
3761   static define_unary_function_eval (__coordonnees_rectangulaires,&_coordonnees_rectangulaires,_coordonnees_rectangulaires_s);
3762   define_unary_function_ptr5( at_coordonnees_rectangulaires ,alias_at_coordonnees_rectangulaires,&__coordonnees_rectangulaires,0,true);
3763 
_point_polaire(const gen & args,GIAC_CONTEXT)3764   gen _point_polaire(const gen & args,GIAC_CONTEXT){
3765     if ( args.type==_STRNG && args.subtype==-1) return  args;
3766     if (args.type!=_VECT || args._VECTptr->size()!=2)
3767       return gensizeerr(contextptr);
3768     gen a=args._VECTptr->front();
3769     gen b=args._VECTptr->back();
3770     return _point(a*exp(cst_i*b,contextptr),contextptr);
3771   }
3772   static const char _point_polaire_s []="polar_point";
3773   static define_unary_function_eval (__point_polaire,&_point_polaire,_point_polaire_s);
3774   define_unary_function_ptr5( at_point_polaire ,alias_at_point_polaire,&__point_polaire,0,true);
3775 
divide_by_2(const gen & ra,GIAC_CONTEXT)3776   static inline gen divide_by_2(const gen & ra,GIAC_CONTEXT){
3777     if (ra.type==_DOUBLE_ || (ra.type==_CPLX && (ra._CPLXptr->type==_DOUBLE_ || (ra._CPLXptr+1)->type==_DOUBLE_)) )
3778       return ra/gen(2.0);
3779     else
3780       return normal(rdiv(ra,plus_two,contextptr),contextptr);
3781   }
3782 
3783   // point + rayon or line
_cercle(const gen & args,GIAC_CONTEXT)3784   gen _cercle(const gen & args,GIAC_CONTEXT){
3785     if (is_undef(args)) return args;
3786     // inert form (since cercle return itself with a pnt__vect arg)
3787     if (args.type==_VECT && args.subtype==_PNT__VECT) return symbolic(at_cercle,args);
3788     if (args.type==_INT_)
3789       return _rond(args,contextptr);
3790     vecteur v(gen2vecteur(args));
3791     if (v.empty())
3792       return gensizeerr(gettext("circle"));
3793     vecteur attributs(1,default_color(contextptr));
3794     int s=read_attributs(v,attributs,contextptr);
3795     // find diametre
3796     if (s==1){
3797       vecteur w=eval_with_xy_quoted(v.front(),contextptr);
3798       for (unsigned i=1;i<v.size();++i)
3799 	w.push_back(v[i]);
3800       gen tmp=_plotimplicit(gen(w,_SEQ__VECT),contextptr);
3801       if (tmp.type==_VECT && tmp._VECTptr->size()==1)
3802 	return tmp._VECTptr->front();
3803       else
3804 	return tmp;
3805     }
3806     gen e=eval(v.front(),contextptr),diametre;
3807     bool diam=true;
3808     if (e.is_symb_of_sommet(at_equal) && e._SYMBptr->feuille.type==_VECT && e._SYMBptr->feuille._VECTptr->size()==2){
3809       if (e._SYMBptr->feuille._VECTptr->front()==at_centre){
3810 	diam=false;
3811 	e=e._SYMBptr->feuille._VECTptr->back();
3812       }
3813     }
3814     int narg=0;
3815     if ( (e.type==_SYMB) && (e._SYMBptr->sommet==at_pnt)){
3816       gen f=e._SYMBptr->feuille._VECTptr->front();
3817       if (f.type==_VECT && f._VECTptr->size()==2){
3818 	diametre=f;
3819 	narg=1;
3820       }
3821       else e=remove_at_pnt(e);
3822     }
3823     else {
3824       if ((e.type==_VECT) && (e._VECTptr->size()==2)){
3825 	diametre=e;
3826 	narg=1;
3827       }
3828     }
3829     if (!narg){
3830       if (s<2)
3831 	return gensizeerr(gettext("circle"));
3832       gen f=eval(v[1],contextptr);
3833       if ((f.type==_SYMB) && (f._SYMBptr->sommet==at_pnt)){
3834 	gen g=remove_at_pnt(f);
3835 	if (g.type==_VECT && g._VECTptr->size()==2){
3836 	  // e=center, g=line, project e on g
3837 	  gen g1=g._VECTptr->front();
3838 	  gen g2=g._VECTptr->back();
3839 	  gen t=projection(g1,g2,e,contextptr);
3840 	  if (is_undef(t)) return t;
3841 	  g=g1+t*(g2-g1); // this is the projection
3842 	  diametre=gen(makevecteur(e+(e-g),g),_GROUP__VECT);
3843 	}
3844 	else {
3845 	  g=get_point(g,0,contextptr);
3846 	  if (is_undef(g)) return g;
3847 	  if (diam)
3848 	    diametre=gen(makevecteur(e,g),_GROUP__VECT);
3849 	  else
3850 	    diametre=gen(makevecteur(e+(e-g),g),_GROUP__VECT);
3851 	}
3852       }
3853       else {
3854 	while (f.type==_VECT){
3855 	  if (f._VECTptr->empty())
3856 	    return gensizeerr(contextptr);
3857 	  f=f._VECTptr->front();
3858 	}
3859 	if (e.type==_VECT)
3860 	  return gensizeerr(contextptr);
3861 	gen ee=e-f;
3862 	gen ff=e+f;
3863 	diametre=gen(makevecteur(ee,ff),_GROUP__VECT);
3864       }
3865       narg=2;
3866     }
3867     if (diametre.type!=_VECT || diametre._VECTptr->size()!=2 )
3868       return gensizeerr(contextptr);
3869     gen d0=get_point(diametre._VECTptr->front(),0,contextptr);
3870     gen d1=get_point((*diametre._VECTptr)[1],1,contextptr);
3871     if (is_undef(d0)) return d0;
3872     if (is_undef(d1)) return d1;
3873     gen ce,ra;
3874     if (d0.type==_VECT){
3875       // 3-d circle, angles not allowed yet
3876       if (s!=1+narg)
3877 	return set3derr(contextptr);
3878       // 3rd point defines the plan
3879       gen d2=get_point(remove_at_pnt(eval(v[narg],contextptr)),2,contextptr);
3880       if (is_undef(d2)) return d2;
3881       gen d02=d2-d0;
3882       ra=divide_by_2(d1-d0,contextptr);
3883       d02=cross(cross(ra,d02,contextptr),ra,contextptr); // normal in the same plan
3884       d02=sqrt(dotvecteur(ra,ra)/dotvecteur(d02,d02),contextptr)*d02; // normalized
3885       // Make a parametric plot
3886       identificateur t(" t"),u(" u");
3887       ce=divide_by_2(d0+d1,contextptr);
3888       return plotparam3d(ce+cos(t,contextptr)*ra+sin(t,contextptr)*d02,makevecteur(t,u),gnuplot_xmin,gnuplot_xmax,gnuplot_ymin,gnuplot_ymax,gnuplot_zmin,gnuplot_zmax,0,2*M_PI,0,0,false,false,attributs,M_PI/30,0,undef,makevecteur(t,u),contextptr);
3889       // gen theta=(2*M_PI/(gnuplot_tmax-gnuplot_tmin))*t;
3890       // return paramplotparam(gen(makevecteur(ce+cos(theta,contextptr)*ra+sin(theta,contextptr)*d02,t),_SEQ__VECT),false,contextptr);
3891     }
3892     // find angles
3893     gen a1(zero),a2(cst_two_pi);
3894     if (s==1+narg){
3895       *logptr(contextptr) << "Assuming circumcircle call" << '\n';
3896       return _circonscrit(args,contextptr);
3897     }
3898     if (s>1+narg){
3899       a1=eval(v[narg],contextptr);
3900       a2=eval(v[narg+1],contextptr);
3901     }
3902     gen res=pnt_attrib(new_ref_symbolic(symbolic(at_cercle,gen(makenewvecteur(diametre,a1,a2),_PNT__VECT))),attributs,contextptr);
3903     if (s<3+narg)
3904       return res;
3905     vecteur w(1,res);
3906     ce=divide_by_2(d0+d1,contextptr);
3907     ra=divide_by_2(d1-d0,contextptr);
3908     gen ga1=ce+ra*exp(cst_i*a1,contextptr);
3909     gen ga2=ce+ra*exp(cst_i*a2,contextptr);
3910     if (v[narg+2].type==_IDNT)
3911       w.push_back(eval(symb_sto(_point(ga1,contextptr),v[narg+2]),contextptr));
3912     if (s>3+narg)
3913       w.push_back(eval(symb_sto(_point(ga2,contextptr),v[narg+3]),contextptr));
3914     return  gen(w,_GROUP__VECT);
3915   }
3916   static const char _cercle_s []="circle";
3917   static define_unary_function_eval_quoted (__cercle,&_cercle,_cercle_s);
3918   define_unary_function_ptr5( at_cercle ,alias_at_cercle,&__cercle,_QUOTE_ARGUMENTS,true);
3919 
_centre(const gen & args,GIAC_CONTEXT)3920   gen _centre(const gen & args,GIAC_CONTEXT){
3921     if ( args.type==_STRNG && args.subtype==-1) return  args;
3922     gen a=args;
3923     if (a.is_symb_of_sommet(at_equal)){
3924       a=_cercle(a,contextptr);
3925       if (a.type==_VECT && !a._VECTptr->empty())
3926 	a=a._VECTptr->front();
3927     }
3928     if (a.type==_VECT && a.subtype==_SEQ__VECT && a._VECTptr->size()==1)
3929       a=a._VECTptr->front();
3930     a=remove_at_pnt(a);
3931     gen centre,rayon;
3932     if (!centre_rayon(a,centre,rayon,false,contextptr))
3933       return gensizeerr(contextptr);
3934     vecteur attributs(1,default_color(contextptr));
3935     read_attributs(gen2vecteur(args),attributs,contextptr);
3936     return pnt_attrib(centre,attributs,contextptr);
3937   }
3938   static const char _centre_s []="center";
3939   static define_unary_function_eval (__centre,&_centre,_centre_s);
3940   define_unary_function_ptr5( at_centre ,alias_at_centre,&__centre,0,true);
3941 
_rayon(const gen & args,GIAC_CONTEXT)3942   gen _rayon(const gen & args,GIAC_CONTEXT){
3943     if ( args.type==_STRNG && args.subtype==-1) return  args;
3944     gen a(args);
3945     if (a.is_symb_of_sommet(at_equal)){
3946       a=_cercle(a,contextptr);
3947       if (a.type==_VECT && !a._VECTptr->empty())
3948 	a=a._VECTptr->front();
3949     }
3950     a=remove_at_pnt(a);
3951     gen centre,rayon;
3952     if (!centre_rayon(a,centre,rayon,true,contextptr))
3953       return false;
3954     return rayon;
3955   }
3956   static const char _rayon_s []="radius";
3957   static define_unary_function_eval (__rayon,&_rayon,_rayon_s);
3958   define_unary_function_ptr5( at_rayon ,alias_at_rayon,&__rayon,0,true);
3959 
_milieu(const gen & args,GIAC_CONTEXT)3960   gen _milieu(const gen & args,GIAC_CONTEXT){
3961     if ( args.type==_STRNG && args.subtype==-1) return  args;
3962 #if defined HAVE_LIBMPFI && !defined NO_RTTI
3963     if (args.type==_REAL){
3964       if (real_interval * ptr=dynamic_cast<real_interval *>(args._REALptr)){
3965 	mpfr_t tmp;
3966 	mpfr_init2(tmp,mpfi_get_prec(ptr->infsup));
3967 	mpfi_get_fr(tmp,ptr->infsup);
3968 	gen res=real_object(tmp);
3969 	mpfr_clear(tmp);
3970 	return res;
3971       }
3972       return real_object(args._REALptr->inf);
3973     }
3974 #endif
3975     if (args.type==_FRAC || args.type<=_POLY)
3976       return args;
3977     vecteur attributs(1,default_color(contextptr));
3978     read_attributs(gen2vecteur(args),attributs,contextptr);
3979     gen e,f;
3980     if ( (args.type==_SYMB) && (args._SYMBptr->sommet==at_pnt)){
3981       e=remove_at_pnt(args);
3982       if ((e.type!=_VECT) || (e._VECTptr->size()!=2))
3983 	return gensizeerr(gettext("milieu"));
3984       f=e._VECTptr->back();
3985       e=e._VECTptr->front();
3986     }
3987     else {
3988       if (args.type!=_VECT || args._VECTptr->empty())
3989 	return symbolic(at_milieu,args);
3990       e=remove_at_pnt(args._VECTptr->front());
3991       if (args._VECTptr->size()==1)
3992 	return pnt_attrib(e,attributs,contextptr);
3993       f=remove_at_pnt((*args._VECTptr)[1]);
3994     }
3995     e=get_point(e,0,contextptr);
3996     f=get_point(f,1,contextptr);
3997     return pnt_attrib(e+(f-e)/2,attributs,contextptr);
3998   }
3999   static const char _milieu_s []="midpoint";
4000   static define_unary_function_eval (__milieu,&_milieu,_milieu_s);
4001   define_unary_function_ptr5( at_milieu ,alias_at_milieu,&__milieu,0,true);
4002 
4003   // if suppl is true return in 3-d an object of dim'=3-dim, else dim'=dim
perpendiculaire(const gen & args,bool suppl,GIAC_CONTEXT)4004   gen perpendiculaire(const gen & args,bool suppl,GIAC_CONTEXT){
4005     if ( (args.type!=_VECT) || (args._VECTptr->size()<2))
4006       return gensizeerr(contextptr);
4007     vecteur attributs(1,default_color(contextptr));
4008     vecteur v(*args._VECTptr);
4009     int s=read_attributs(v,attributs,contextptr);
4010     if (s<2)
4011       return gendimerr(contextptr);
4012     gen e=v.front(),f=v[1],M;
4013     e=remove_at_pnt(e);
4014     f=remove_at_pnt(f);
4015     if (f.type==_VECT && f.subtype==_VECTOR__VECT && f._VECTptr->size()==2){
4016       v.push_back(f._VECTptr->back());
4017       ++s;
4018       f=f._VECTptr->front();
4019     }
4020     if (e.is_symb_of_sommet(at_hyperplan))
4021       swapgen(e,f);
4022     if (!f.is_symb_of_sommet(at_hyperplan))
4023       e=get_point(e,0,contextptr);
4024     if (is_undef(e)) return e;
4025     if (f.is_symb_of_sommet(at_hyperplan)){
4026       // args=point/line, hyperplan
4027       vecteur n,P;
4028       if (!hyperplan_normal_point(f,n,P))
4029 	return gensizeerr(contextptr);
4030       if (e.type==_VECT &&e._VECTptr->size()==2){
4031 	// line/plan -> line or plan
4032 	M=e._VECTptr->front();
4033 	e=e._VECTptr->back()-e._VECTptr->front();
4034 	if (suppl){ // -> plan defined by line and n
4035 	  return pnt_attrib(symbolic(at_hyperplan,makesequence(cross(e,n,contextptr),M)),attributs,contextptr); // _plan(makevecteur(cross(e,n,contextptr),M),contextptr);
4036 	}
4037 	// line in plan orthogonal to e
4038 	gen directeur(cross(e,n,contextptr));
4039 	// base point M+ke s.t. (M-P+ke).n=0 -> k=(P-M).n/e.n
4040 	gen k(dotvecteur(P-M,n)/dotvecteur(e,n));
4041 	gen base=M+k*e;
4042 	return symb_segment(base,base+directeur,attributs,_LINE__VECT,contextptr);
4043       }
4044       // point/plan -> line
4045       return pnt_attrib(gen(makevecteur(e,e+n),_LINE__VECT),attributs,contextptr);
4046     } // end f hyperplan
4047     if (f.type==_VECT && f._VECTptr->size()==2){ // args=point,line
4048       if (f.subtype==_GGBVECT){
4049 	f=-f[1]+cst_i*f[0];
4050 	return _droite(makesequence(e,e+f),contextptr);
4051       }
4052       M=f._VECTptr->front();
4053       f=f._VECTptr->back()-M;
4054     }
4055     else {
4056       if (f.type==_VECT && f._VECTptr->size()==3){
4057 	M=e;
4058       }
4059       else {
4060 	// args=point,point,point
4061 	if (s!=3)
4062 	  return gensizeerr(gettext("3 points expected"));
4063 	M=f;
4064 	f=remove_at_pnt(v[2])-f;
4065       }
4066     }
4067     // f is a complex or a vector normal to the perpendicular
4068     if (f.type==_VECT) {
4069       // 3-d point/line ->line or plan
4070       if (suppl)
4071 	return pnt_attrib(symbolic(at_hyperplan,makesequence(f,e)),attributs,contextptr); // _plan(makevecteur(f,e),contextptr);
4072       // -> line, e in line, second point is M+kf s.t. (M-e+kf).f=0
4073       gen k=dotvecteur(e-M,f)/dotvecteur(f,f);
4074       return symb_segment(e,M+k*f,attributs,_LINE__VECT,contextptr);
4075     }
4076     f=cst_i*f; // 2-d point/line
4077     return symb_segment(e,e+f,attributs,_LINE__VECT,contextptr);
4078   }
4079 
makecomplex(const gen & a,const gen & b)4080   gen makecomplex(const gen & a,const gen &b){
4081     if ( (a.type>=_CPLX && a.type!=_FLOAT_) || (b.type>=_CPLX && b.type!=_FLOAT_) )
4082       return a+cst_i*b;
4083     else
4084       return gen(a,b);
4085   }
_mediatrice(const gen & args,GIAC_CONTEXT)4086   gen _mediatrice(const gen & args,GIAC_CONTEXT){
4087     if ( args.type==_STRNG && args.subtype==-1) return  args;
4088     vecteur attributs(1,default_color(contextptr));
4089     read_attributs(gen2vecteur(args),attributs,contextptr);
4090     gen e,f;
4091     if ( (args.type==_SYMB) && (args._SYMBptr->sommet==at_pnt)){
4092       e=remove_at_pnt(args);
4093       if ((e.type!=_VECT) || (e._VECTptr->size()!=2))
4094 	return gensizeerr(gettext("midpoint"));
4095       f=e._VECTptr->back();
4096       e=e._VECTptr->front();
4097     }
4098     else {
4099       if ( (args.type!=_VECT) || (args._VECTptr->size()<2))
4100 	return symbolic(at_mediatrice,args);
4101       e=remove_at_pnt(args._VECTptr->front());
4102       f=remove_at_pnt((*args._VECTptr)[1]);
4103     }
4104     e=get_point(e,0,contextptr);
4105     f=get_point(f,1,contextptr);
4106     if (is_undef(e)) return e;
4107     if (is_undef(f)) return f;
4108     if (e.type==_VECT && f.type==_VECT)
4109       return perpendiculaire(makevecteur((e+f)/2,f-e),true,contextptr);
4110     gen ex,ey,fx,fy,efx,efy,mx,my,ax,ay,bx,by;
4111     reim(e,ex,ey,contextptr); reim(f,fx,fy,contextptr);
4112     mx=(ex+fx)/2; my=(ey+fy)/2;
4113     efy=ex-fx; efx=fy-ey; // perpendicular to ef
4114     ax=mx-efx; ay=my-efy;
4115     bx=mx+efx; by=my+efy;
4116     return symb_segment(makecomplex(ax,ay),makecomplex(bx,by),attributs,_LINE__VECT,contextptr);
4117     /*
4118       gen direction=im(f-e,contextptr)-cst_i*re(f-e,contextptr);
4119       gen m=rdiv(e+f,plus_two);
4120       return symb_segment(m-direction,m+direction,attributs,_LINE__VECT,contextptr);
4121     */
4122   }
4123   static const char _mediatrice_s []="perpen_bisector";
4124   static define_unary_function_eval (__mediatrice,&_mediatrice,_mediatrice_s);
4125   define_unary_function_ptr5( at_mediatrice ,alias_at_mediatrice,&__mediatrice,0,true);
4126 
_perpendiculaire(const gen & args,GIAC_CONTEXT)4127   gen _perpendiculaire(const gen & args,GIAC_CONTEXT){
4128     if ( args.type==_STRNG && args.subtype==-1) return  args;
4129     return perpendiculaire(args,false,contextptr);
4130   }
4131   static const char _perpendiculaire_s []="perpendicular";
4132   static define_unary_function_eval (__perpendiculaire,&_perpendiculaire,_perpendiculaire_s);
4133   define_unary_function_ptr5( at_perpendiculaire ,alias_at_perpendiculaire,&__perpendiculaire,0,true);
4134 
_orthogonal(const gen & args,GIAC_CONTEXT)4135   gen _orthogonal(const gen & args,GIAC_CONTEXT){
4136     if ( args.type==_STRNG && args.subtype==-1) return  args;
4137     return perpendiculaire(args,true,contextptr);
4138   }
4139   static const char _orthogonal_s []="orthogonal";
4140   static define_unary_function_eval (__orthogonal,&_orthogonal,_orthogonal_s);
4141   define_unary_function_ptr5( at_orthogonal ,alias_at_orthogonal,&__orthogonal,0,true);
4142 
check3dpoint(const gen & g)4143   bool check3dpoint(const gen & g){
4144     return g.type==_VECT && g._VECTptr->size()==3;
4145   }
4146 
_parallele(const gen & args,GIAC_CONTEXT)4147   gen _parallele(const gen & args,GIAC_CONTEXT){
4148     if ( is_undef(args)) return args;
4149     vecteur attributs(1,default_color(contextptr));
4150     if ( args.type!=_VECT )
4151       return symbolic(at_parallele,args);
4152     int s=read_attributs(*args._VECTptr,attributs,contextptr);
4153     if (s<2)
4154       return gentypeerr(contextptr);
4155     gen a=remove_at_pnt(args._VECTptr->front()),b((*args._VECTptr)[1]),d;
4156     a=get_point(a,0,contextptr);
4157     if (is_undef(a)) return a;
4158     if (!b.is_symb_of_sommet(at_pnt)){
4159       // b=vector or complex -> make a line
4160       if (b.type==_VECT && b.subtype==_VECTOR__VECT)
4161 	b=vector2vecteur(*b._VECTptr);
4162       if (b.type==_VECT && b._VECTptr->size()==2)
4163 	b=b._VECTptr->front()+cst_i*b._VECTptr->back();
4164       if (b.type!=_VECT)
4165 	b=symbolic(at_pnt,gen(makevecteur(gen(makevecteur(0,b),_LINE__VECT),attributs[0]),_PNT__VECT));
4166     }
4167     if (s>2){
4168       b=remove_at_pnt(b);
4169       d=remove_at_pnt(args._VECTptr->back());
4170       if (a.type==_VECT && a._VECTptr->size()==3 && b.type==_VECT && b._VECTptr->size()==2 && d.type==_VECT && d._VECTptr->size()==2){
4171 	gen n=cross(b._VECTptr->front()-b._VECTptr->back(),d._VECTptr->front()-d._VECTptr->back(),contextptr);
4172 	return pnt_attrib(symbolic(at_hyperplan,makesequence(n,a)),attributs,contextptr); // _plan(makevecteur(n,a),contextptr);
4173       }
4174     }
4175     bool ahyper=a.is_symb_of_sommet(at_hyperplan);
4176     if (!ahyper && b.type==_VECT){
4177       if (b._VECTptr->size()==2)
4178 	b=b._VECTptr->front()+cst_i*b._VECTptr->back();
4179       else
4180 	if (a.type==_VECT)
4181 	  a.subtype=_POINT__VECT;
4182       d=gen(makevecteur(zero*b,b),_LINE__VECT);
4183       b=a;
4184     }
4185     else {
4186       b=remove_at_pnt(b);
4187       if (ahyper)
4188 	swapgen(a,b);
4189       if (b.is_symb_of_sommet(at_hyperplan)){ // hyperplan, point
4190 	return pnt_attrib(symbolic(at_hyperplan,makesequence(hyperplan_normal(b),a)),attributs,contextptr); // _plan(makevecteur(hyperplan_normal(b),a),contextptr);
4191       }
4192       if (b.type==_VECT && b._VECTptr->size()==2 && b.subtype!=_POINT__VECT){ // b is a line
4193 	if (a.type==_VECT && a._VECTptr->size()==2 && a.subtype!=_POINT__VECT){ // a is a line -> d
4194 	  gen M=a._VECTptr->front();
4195 	  gen n=cross(M-a._VECTptr->back(),b._VECTptr->front()-b._VECTptr->back(),contextptr);
4196 	  return pnt_attrib(symbolic(at_hyperplan,makesequence(n,M)),attributs,contextptr); // _plan(makevecteur(n,M),contextptr);
4197 	}
4198 	// b is a line, a is not a line
4199 	d=b;
4200 	b=a;
4201       }
4202       else // a is the line ->d , b the point
4203 	d=a;
4204     }
4205     if ( d.type!=_VECT || d._VECTptr->size()!=2 || (b.type==_VECT && b.subtype!=_POINT__VECT && b._VECTptr->size()!=3) )
4206       return gensizeerr(contextptr);
4207     // parallel to d through b
4208     if (d.type==_VECT)
4209       d.subtype=_LINE__VECT;
4210     return pnt_attrib(d+(b-d._VECTptr->front()),attributs,contextptr);
4211   }
4212   static const char _parallele_s []="parallel";
4213   static define_unary_function_eval (__parallele,&_parallele,_parallele_s);
4214   define_unary_function_ptr5( at_parallele ,alias_at_parallele,&__parallele,0,true);
4215 
_triangle(const gen & args,GIAC_CONTEXT)4216   gen _triangle(const gen & args,GIAC_CONTEXT){
4217     if ( args.type==_STRNG && args.subtype==-1) return  args;
4218     if (args.type!=_VECT)
4219       return symbolic(at_triangle,args);
4220     vecteur attributs(1,default_color(contextptr));
4221     vecteur v(*args._VECTptr);
4222     int s=read_attributs(v,attributs,contextptr);
4223     if (s<3)
4224       return gendimerr(contextptr);
4225     gen a=remove_at_pnt(v.front()),b=remove_at_pnt(v[1]),c=remove_at_pnt(v[2]);
4226     a=get_point(a,0,contextptr);
4227     b=get_point(b,0,contextptr);
4228     c=get_point(c,0,contextptr);
4229     v=makevecteur(a,b,c,a);
4230     return pnt_attrib(gen(v,_GROUP__VECT),attributs,contextptr);
4231   }
4232   static const char _triangle_s []="triangle";
4233   static define_unary_function_eval (__triangle,&_triangle,_triangle_s);
4234   define_unary_function_ptr5( at_triangle ,alias_at_triangle,&__triangle,0,true);
4235 
_quadrilatere(const gen & args,GIAC_CONTEXT)4236   gen _quadrilatere(const gen & args,GIAC_CONTEXT){
4237     if ( args.type==_STRNG && args.subtype==-1) return  args;
4238     if (args.type!=_VECT)
4239       return symbolic(at_quadrilatere,args);
4240     vecteur v(*args._VECTptr);
4241     vecteur attributs(1,default_color(contextptr));
4242     int s=read_attributs(v,attributs,contextptr);
4243     if (s<4)
4244       return gendimerr(contextptr);
4245     gen a=remove_at_pnt(v.front()),b=remove_at_pnt(v[1]),c=remove_at_pnt(v[2]),d=remove_at_pnt(v[3]);
4246     a=get_point(a,0,contextptr);
4247     b=get_point(b,0,contextptr);
4248     c=get_point(c,0,contextptr);
4249     d=get_point(d,0,contextptr);
4250     return pnt_attrib(gen(makevecteur(a,b,c,d,a),_GROUP__VECT),attributs,contextptr);
4251   }
4252   static const char _quadrilatere_s []="quadrilateral";
4253   static define_unary_function_eval (__quadrilatere,&_quadrilatere,_quadrilatere_s);
4254   define_unary_function_ptr5( at_quadrilatere ,alias_at_quadrilatere,&__quadrilatere,0,true);
4255 
get_rectangle_args(const vecteur & v,gen & e,gen & f,gen & g,gen & tmp,GIAC_CONTEXT)4256   static void get_rectangle_args(const vecteur & v,gen & e,gen & f,gen & g,gen & tmp,GIAC_CONTEXT){
4257     e=remove_at_pnt(eval(v[0],contextptr));
4258     f=remove_at_pnt(eval(v[1],contextptr));
4259     e=remove_at_pnt(get_point(e,0,contextptr));
4260     f=remove_at_pnt(get_point(f,1,contextptr));
4261     gen v2=eval(v[2],contextptr);
4262     gen d=remove_at_pnt(v2);
4263     if (d.type==_VECT){
4264       gen eg,ef=f-e;
4265       if (d._VECTptr->size()==2){
4266 	eg=remove_at_pnt(d._VECTptr->front())-e;
4267 	tmp=d._VECTptr->back()*sqrt(dotvecteur(ef,ef),contextptr);
4268       }
4269       else {
4270 	eg=d-e;
4271 	tmp=sqrt(dotvecteur(eg,eg),contextptr);
4272       }
4273       eg=cross(cross(ef,eg,contextptr),ef,contextptr);
4274       tmp=tmp/sqrt(dotvecteur(eg,eg),contextptr)*eg;
4275     }
4276     else {
4277       gen ef=f-e;
4278       if (v2.is_symb_of_sommet(at_pnt)){
4279 	tmp=projection(e,f,d,contextptr);
4280 	tmp=d-tmp*ef-e;
4281       }
4282       else
4283 	tmp=ef*d*cst_i;
4284     }
4285     g=e+tmp;
4286   }
4287 
_triangle_rectangle(const gen & args,GIAC_CONTEXT)4288   gen _triangle_rectangle(const gen & args,GIAC_CONTEXT){
4289     if ( args.type==_STRNG && args.subtype==-1) return  args;
4290     if (args.type!=_VECT)
4291       return symbolic(at_triangle_rectangle,args);
4292     vecteur v(*args._VECTptr);
4293     vecteur attributs(1,default_color(contextptr));
4294     int s=read_attributs(v,attributs,contextptr);
4295     if (s<3)
4296       return gendimerr(contextptr);
4297     gen e,f,g,tmp;
4298     get_rectangle_args(v,e,f,g,tmp,contextptr);
4299     if (is_undef(e) || is_undef(f) || is_undef(g))
4300       return e+f+g;
4301     gen res=pnt_attrib(gen(makevecteur(e,f,g,e),_GROUP__VECT),attributs,contextptr);
4302     if (s==3)
4303       return res;
4304     vecteur w(1,res);
4305     w.push_back(eval(symb_sto(_point(g,contextptr),v[3]),contextptr));
4306     return gen(w,_GROUP__VECT);
4307   }
4308   static const char _triangle_rectangle_s []="right_triangle";
4309   static define_unary_function_eval_quoted (__triangle_rectangle,&_triangle_rectangle,_triangle_rectangle_s);
4310   define_unary_function_ptr5( at_triangle_rectangle ,alias_at_triangle_rectangle,&__triangle_rectangle,_QUOTE_ARGUMENTS,true);
4311 
_rectangle(const gen & args,GIAC_CONTEXT)4312   gen _rectangle(const gen & args, GIAC_CONTEXT){
4313     if ( args.type==_STRNG && args.subtype==-1) return  args;
4314     if (args.type!=_VECT)
4315       return symbolic(at_rectangle,args);
4316     vecteur v(*args._VECTptr);
4317     vecteur attributs(1,default_color(contextptr));
4318     int s=read_attributs(v,attributs,contextptr);
4319     if (s<3)
4320       return gendimerr(contextptr);
4321     gen e,f,g,tmp;
4322     get_rectangle_args(v,e,f,g,tmp,contextptr);
4323     if (is_undef(e) || is_undef(f) || is_undef(g))
4324       return e+f+g;
4325     gen h=f+tmp;
4326     gen res=pnt_attrib(gen(makevecteur(e,f,h,g,e),_GROUP__VECT),attributs,contextptr);
4327     if (s==3)
4328       return res;
4329     vecteur w(1,res);
4330     w.push_back(eval(symb_sto(_point(g,contextptr),v[3]),contextptr));
4331     if (s>4)
4332       w.push_back(eval(symb_sto(_point(h,contextptr),v[4]),contextptr));
4333     return gen(w,_GROUP__VECT);
4334   }
4335   static const char _rectangle_s []="rectangle";
4336   static define_unary_function_eval_quoted (__rectangle,&_rectangle,_rectangle_s);
4337   define_unary_function_ptr5( at_rectangle ,alias_at_rectangle,&__rectangle,_QUOTE_ARGUMENTS,true);
4338 
_parallelogramme(const gen & args0,GIAC_CONTEXT)4339   gen _parallelogramme(const gen & args0,GIAC_CONTEXT){
4340     if ( args0.type==_STRNG && args0.subtype==-1) return  args0;
4341     gen args(args0);
4342     if (args.type!=_VECT)
4343       args=eval(args,1,contextptr);
4344     if (args.type!=_VECT)
4345       return symbolic(at_parallelogramme,args);
4346     vecteur v(*args._VECTptr);
4347     vecteur attributs(1,default_color(contextptr));
4348     int s=read_attributs(v,attributs,contextptr);
4349     if (s==2){
4350       gen e=remove_at_pnt(eval(v[0],contextptr)),f=remove_at_pnt(eval(v[1],contextptr));
4351       v.clear();
4352       if (e.type==_VECT && e.subtype==_VECTOR__VECT && e._VECTptr->size()==2){
4353 	v.push_back(e._VECTptr->front());
4354 	v.push_back(e._VECTptr->back());
4355       }
4356       else
4357 	v.push_back(e);
4358       if (f.type==_VECT && f.subtype==_VECTOR__VECT && f._VECTptr->size()==2){
4359 	if (v.size()==1){
4360 	  v.insert(v.begin(),f._VECTptr->front());
4361 	  v.push_back(f._VECTptr->back());
4362 	}
4363 	else
4364 	  v.push_back(v.back()+f._VECTptr->back()-f._VECTptr->front());
4365       }
4366       else
4367 	v.push_back(f);
4368       s=int(v.size());
4369     }
4370     if (s<3)
4371       return gendimerr(contextptr);
4372     gen e=remove_at_pnt(eval(v[0],contextptr)),f=remove_at_pnt(eval(v[1],contextptr)),d=remove_at_pnt(eval(v[2],contextptr));
4373     e=remove_at_pnt(get_point(e,0,contextptr));
4374     if (f.type==_VECT && f.subtype==_VECTOR__VECT && f._VECTptr->size()==2)
4375       f=e+f._VECTptr->back()-f._VECTptr->front();
4376     else
4377       f=remove_at_pnt(get_point(f,0,contextptr));
4378     if (d.type==_VECT && d.subtype==_VECTOR__VECT && d._VECTptr->size()==2)
4379       d=e+d._VECTptr->back()-d._VECTptr->front();
4380     else
4381       d=remove_at_pnt(get_point(d,0,contextptr));
4382     gen g=(e-f)+d;
4383     if (is_undef(g)) return g;
4384     gen res=pnt_attrib(gen(makevecteur(e,f,d,g,e),_GROUP__VECT),attributs,contextptr);
4385     if (s==3)
4386       return res;
4387     vecteur w(1,res);
4388     w.push_back(eval(symb_sto(_point(g,contextptr),v[3]),contextptr));
4389     return gen(w,_GROUP__VECT);
4390   }
4391   static const char _parallelogramme_s []="parallelogram";
4392   static define_unary_function_eval_quoted (__parallelogramme,&_parallelogramme,_parallelogramme_s);
4393   define_unary_function_ptr5( at_parallelogramme ,alias_at_parallelogramme,&__parallelogramme,_QUOTE_ARGUMENTS,true);
4394 
get_losange_args(const vecteur & v,gen & e,gen & f,gen & g,GIAC_CONTEXT)4395   static void get_losange_args(const vecteur &v,gen &e,gen &f,gen & g,GIAC_CONTEXT){
4396     e=remove_at_pnt(eval(v[0],contextptr));
4397     f=remove_at_pnt(eval(v[1],contextptr));
4398     e=remove_at_pnt(get_point(e,0,contextptr));
4399     f=remove_at_pnt(get_point(f,1,contextptr));
4400     gen angle=remove_at_pnt(eval(v[2],contextptr));
4401     if (angle.type==_VECT){ // In 3-d angle is not the angle!
4402       gen ef=f-e;
4403       if (angle._VECTptr->size()==2){
4404 	gen eg=remove_at_pnt(angle._VECTptr->front())-e;
4405 	angle=angle._VECTptr->back();
4406 	eg=cross(cross(ef,eg,contextptr),ef,contextptr);
4407 	eg=sqrt(dotvecteur(ef,ef)/dotvecteur(eg,eg),contextptr)*eg;
4408 	g=e+ef*cos(angle,contextptr)+eg*sin(angle,contextptr);
4409       }
4410       else {
4411 	gen eg=angle-e;
4412 	g=e+sqrt(dotvecteur(ef,ef)/dotvecteur(eg,eg),contextptr)*eg;
4413       }
4414     }
4415     else
4416       g=e+(f-e)*(cos(angle,contextptr)+cst_i*sin(angle,contextptr));
4417   }
4418 
_triangle_isocele(const gen & args,GIAC_CONTEXT)4419   gen _triangle_isocele(const gen & args,GIAC_CONTEXT){
4420     if ( args.type==_STRNG && args.subtype==-1) return  args;
4421     if ( (args.type!=_VECT) || (args._VECTptr->size()<3))
4422       return symbolic(at_triangle_isocele,args);
4423     vecteur v(*args._VECTptr);
4424     vecteur attributs(1,default_color(contextptr));
4425     int s=read_attributs(v,attributs,contextptr);
4426     if (s<3)
4427       return gendimerr(contextptr);
4428     gen e,f,g;
4429     get_losange_args(v,e,f,g,contextptr);
4430     if (is_undef(e) || is_undef(f) || is_undef(g))
4431       return e+f+g;
4432     gen res=pnt_attrib(gen(makevecteur(e,f,g,e),_GROUP__VECT),attributs,contextptr);
4433     if (s==3)
4434       return res;
4435     vecteur w(1,res);
4436     w.push_back(eval(symb_sto(_point(g,contextptr),v[3]),contextptr));
4437     return gen(w,_GROUP__VECT);
4438   }
4439   static const char _triangle_isocele_s []="isosceles_triangle";
4440   static define_unary_function_eval_quoted (__triangle_isocele,&_triangle_isocele,_triangle_isocele_s);
4441   define_unary_function_ptr5( at_triangle_isocele ,alias_at_triangle_isocele,&__triangle_isocele,_QUOTE_ARGUMENTS,true);
4442 
_losange(const gen & args,GIAC_CONTEXT)4443   gen _losange(const gen & args,GIAC_CONTEXT){
4444     if ( args.type==_STRNG && args.subtype==-1) return  args;
4445     if ( (args.type!=_VECT) || (args._VECTptr->size()<3))
4446       return symbolic(at_losange,args);
4447     vecteur v(*args._VECTptr);
4448     vecteur attributs(1,default_color(contextptr));
4449     int s=read_attributs(v,attributs,contextptr);
4450     if (s<3)
4451       return gendimerr(contextptr);
4452     gen e,f,g;
4453     get_losange_args(v,e,f,g,contextptr);
4454     if (is_undef(e) || is_undef(f) || is_undef(g))
4455       return e+f+g;
4456     gen h=g;
4457     g=h-e+f;
4458     gen res=pnt_attrib(gen(makevecteur(e,f,g,h,e),_GROUP__VECT),attributs,contextptr);
4459     if (s==3)
4460       return res;
4461     vecteur w(1,res);
4462     w.push_back(eval(symb_sto(_point(g,contextptr),v[3]),contextptr));
4463     if (s>4)
4464       w.push_back(eval(symb_sto(_point(h,contextptr),v[4]),contextptr));
4465     return gen(w,_GROUP__VECT);
4466   }
4467   static const char _losange_s []="rhombus";
4468   static define_unary_function_eval_quoted (__losange,&_losange,_losange_s);
4469   define_unary_function_ptr5( at_losange ,alias_at_losange,&__losange,_QUOTE_ARGUMENTS,true);
4470 
_triangle_equilateral(const gen & args,GIAC_CONTEXT)4471   gen _triangle_equilateral(const gen & args,GIAC_CONTEXT){
4472     if ( args.type==_STRNG && args.subtype==-1) return  args;
4473     if ( (args.type!=_VECT) || (args._VECTptr->size()<2))
4474       return symbolic(at_triangle_equilateral,args);
4475     vecteur & v=*args._VECTptr;
4476     vecteur attributs(1,default_color(contextptr));
4477     int s=read_attributs(v,attributs,contextptr);
4478     if (s<2)
4479       return gendimerr(contextptr);
4480     int dim=2;
4481     gen e=remove_at_pnt(eval(v[0],contextptr)),f=remove_at_pnt(eval(v[1],contextptr)),g;
4482     e=remove_at_pnt(get_point(e,0,contextptr));
4483     f=remove_at_pnt(get_point(f,1,contextptr));
4484     if (e.type==_VECT){
4485       dim=3;
4486       if (s==2)
4487 	return set3derr(contextptr);
4488       g=remove_at_pnt(eval(v[2],contextptr));
4489       gen ef=f-e,eg=g-e;
4490       eg=cross(cross(ef,eg,contextptr),ef,contextptr);
4491       g=e+(ef+sqrt(3*dotvecteur(ef,ef)/dotvecteur(eg,eg),contextptr)*eg)/2;
4492     }
4493     else
4494       g=e+(f-e)*rdiv((plus_sqrt3*cst_i+plus_one),plus_two,contextptr);
4495     if (is_undef(g)) return g;
4496     gen res=pnt_attrib(gen(makevecteur(e,f,g,e),_GROUP__VECT),attributs,contextptr);
4497     if (s==dim)
4498       return res;
4499     vecteur w(1,res);
4500     w.push_back(eval(symb_sto(_point(g,contextptr),v[dim]),contextptr));
4501     return gen(w,_GROUP__VECT);
4502   }
4503   static const char _triangle_equilateral_s []="equilateral_triangle";
4504   static define_unary_function_eval_quoted (__triangle_equilateral,&_triangle_equilateral,_triangle_equilateral_s);
4505   define_unary_function_ptr5( at_triangle_equilateral ,alias_at_triangle_equilateral,&__triangle_equilateral,_QUOTE_ARGUMENTS,true);
4506 
4507   // Args= Center A, point B, number of vertices
_isopolygone(const gen & args,GIAC_CONTEXT)4508   gen _isopolygone(const gen & args,GIAC_CONTEXT){
4509     if ( args.type==_STRNG && args.subtype==-1) return  args;
4510     if ( (args.type!=_VECT) || (args._VECTptr->size()<3))
4511       return symbolic(at_isopolygone,args);
4512     vecteur & v=*args._VECTptr;
4513     vecteur attributs(1,default_color(contextptr));
4514     int s=read_attributs(v,attributs,contextptr);
4515     if (s<2)
4516       return gendimerr(contextptr);
4517     gen e=remove_at_pnt(v[0]);
4518     gen f=remove_at_pnt(v[1]),g;
4519     e=remove_at_pnt(get_point(e,0,contextptr));
4520     f=remove_at_pnt(get_point(f,1,contextptr));
4521     gen ef=f-e,nd;
4522     if (is_undef(ef)) return ef;
4523     if (s>3){
4524       g=remove_at_pnt(v[2]);
4525       gen eg=g-e;
4526       nd=cross(cross(ef,eg,contextptr),ef,contextptr);
4527       nd=sqrt(ratnormal(dotvecteur(ef,ef)/dotvecteur(nd,nd),contextptr),contextptr)*nd;
4528     }
4529     else
4530       nd=cst_i*ef;
4531     gen gn=v[s-1];
4532     if (!is_integral(gn))
4533       return gensizeerr(contextptr);
4534     int n=gn.val;
4535     if (gn.type!=_INT_ || absint(n)<2)
4536       return gensizeerr(contextptr);
4537     //grad
4538     int mode=get_mode_set_radian(contextptr);
4539     if (n>0){
4540       context tmp;
4541       gen c;
4542       c=(e+f)/2+nd/(2*tan(cst_pi/n,&tmp));
4543       f=e;
4544       e=c;
4545       ef=f-e;
4546       if (s>3){
4547 	gen eg=g-e;
4548 	nd=cross(cross(ef,eg,contextptr),ef,contextptr);
4549 	nd=sqrt(ratnormal(dotvecteur(ef,ef)/dotvecteur(nd,nd),contextptr),contextptr)*nd;
4550       }
4551       else
4552 	nd=cst_i*ef;
4553     }
4554     else
4555       n=-n;
4556     vecteur w;
4557     w.push_back(f);
4558     for (int i=1;i<n;++i){
4559       w.push_back(e+ef*cos(2*i*cst_pi/n,contextptr)+nd*sin(2*i*cst_pi/n,contextptr));
4560     }
4561     w.push_back(f);
4562     //grad
4563     angle_mode(mode,contextptr);
4564     gen res=pnt_attrib(gen(w,_GROUP__VECT),attributs,contextptr);
4565     return res;
4566   }
4567   static const char _isopolygone_s []="isopolygon";
4568   static define_unary_function_eval (__isopolygone,&_isopolygone,_isopolygone_s);
4569   define_unary_function_ptr5( at_isopolygone ,alias_at_isopolygone,&__isopolygone,0,true);
4570 
_carre(const gen & args,GIAC_CONTEXT)4571   gen _carre(const gen & args,GIAC_CONTEXT){
4572     if ( args.type==_STRNG && args.subtype==-1) return  args;
4573     if ( (args.type!=_VECT) || (args._VECTptr->size()<2))
4574       return symbolic(at_carre,args);
4575     vecteur & v=*args._VECTptr;
4576     vecteur attributs(1,default_color(contextptr));
4577     int s=read_attributs(v,attributs,contextptr);
4578     if (s<2)
4579       return gendimerr(contextptr);
4580     gen e=remove_at_pnt(eval(v[0],contextptr));
4581     gen f=remove_at_pnt(eval(v[1],contextptr));
4582     e=remove_at_pnt(get_point(e,0,contextptr));
4583     f=remove_at_pnt(get_point(f,1,contextptr));
4584     gen ef=f-e,g;
4585     if (is_undef(ef)) return ef;
4586     int dim=2;
4587     if (ef.type==_VECT){
4588       dim=3;
4589       if (s==2)
4590 	return set3derr(contextptr);
4591       g=remove_at_pnt(eval(v[2],contextptr));
4592       gen eg=g-e;
4593       eg=cross(cross(ef,eg,contextptr),ef,contextptr);
4594       g=f+sqrt(dotvecteur(ef,ef)/dotvecteur(eg,eg),contextptr)*eg;
4595     }
4596     else
4597       g=f+ef*cst_i;
4598     gen h=g-ef;
4599     gen res=pnt_attrib(gen(makevecteur(e,f,g,h,e),_GROUP__VECT),attributs,contextptr);
4600     if (s==dim)
4601       return res;
4602     vecteur w(1,res);
4603     w.push_back(eval(symb_sto(_point(g,contextptr),v[dim]),contextptr));
4604     if (s>dim+1)
4605       w.push_back(eval(symb_sto(_point(h,contextptr),v[dim+1]),contextptr));
4606     return gen(w,_GROUP__VECT);
4607   }
4608   static const char _carre_s []="square";
4609   static define_unary_function_eval_quoted (__carre,&_carre,_carre_s);
4610   define_unary_function_ptr5( at_carre ,alias_at_carre,&__carre,_QUOTE_ARGUMENTS,true);
4611 
_hexagone(const gen & args,GIAC_CONTEXT)4612   gen _hexagone(const gen & args,GIAC_CONTEXT){
4613     if ( args.type==_STRNG && args.subtype==-1) return  args;
4614     if (args.type!=_VECT)
4615       return gensizeerr(contextptr);
4616     vecteur & v=*args._VECTptr;
4617     vecteur attributs(1,default_color(contextptr));
4618     int s=read_attributs(v,attributs,contextptr);
4619     if (s<2)
4620       return gendimerr(contextptr);
4621     gen e=remove_at_pnt(eval(v[0],contextptr));
4622     gen f=remove_at_pnt(eval(v[1],contextptr));
4623     e=remove_at_pnt(get_point(e,0,contextptr));
4624     f=remove_at_pnt(get_point(f,1,contextptr));
4625     gen ef=f-e,ecenter,g,h,i,j;
4626     if (is_undef(ef)) return ef;
4627     int dim=2;
4628     if (ef.type==_VECT){
4629       dim=3;
4630       if (s==2)
4631 	return set3derr(contextptr);
4632       ecenter=remove_at_pnt(eval(v[2],contextptr));
4633       gen eg=ecenter-e;
4634       eg=cross(cross(ef,eg,contextptr),ef,contextptr);
4635       ecenter=(ef+sqrt(3*dotvecteur(ef,ef)/dotvecteur(eg,eg),contextptr)*eg)/2;
4636     }
4637     else
4638       ecenter=ef*rdiv((plus_sqrt3*cst_i+plus_one),plus_two,contextptr);
4639     g=e+ecenter+ef;
4640     h=e+2*ecenter;
4641     i=h-ef;
4642     j=e+ecenter-ef;
4643     gen res=pnt_attrib(gen(makevecteur(e,f,g,h,i,j,e),_GROUP__VECT),attributs,contextptr);
4644     if (s==dim)
4645       return res;
4646     vecteur w(1,res);
4647     w.push_back(eval(symb_sto(_point(g,contextptr),v[dim]),contextptr));
4648     if (s>dim+1)
4649       w.push_back(eval(symb_sto(_point(h,contextptr),v[dim+1]),contextptr));
4650     if (s>dim+2)
4651       w.push_back(eval(symb_sto(_point(i,contextptr),v[dim+2]),contextptr));
4652     if (s>dim+3)
4653       w.push_back(eval(symb_sto(_point(j,contextptr),v[dim+3]),contextptr));
4654     return gen(w,_GROUP__VECT);
4655   }
4656   static const char _hexagone_s []="hexagon";
4657   static define_unary_function_eval_quoted (__hexagone,&_hexagone,_hexagone_s);
4658   define_unary_function_ptr5( at_hexagone ,alias_at_hexagone,&__hexagone,_QUOTE_ARGUMENTS,true);
4659 
polygonify(vecteur & v,GIAC_CONTEXT)4660   static void polygonify(vecteur & v,GIAC_CONTEXT){
4661     int vs=int(v.size());
4662     for (int i=0;i<vs;++i){
4663       v[i]=get_point(v[i],0,contextptr);
4664       if (v[i].type==_VECT && v[i]._VECTptr->size()==2)
4665 	v[i]=v[i]._VECTptr->front()+cst_i*v[i]._VECTptr->back();
4666     }
4667   }
4668 
_polygone(const gen & args,GIAC_CONTEXT)4669   gen _polygone(const gen & args,GIAC_CONTEXT){
4670     if ( args.type==_STRNG && args.subtype==-1) return  args;
4671     if (args.type!=_VECT)
4672       return symbolic(at_polygone,args);
4673     vecteur v(*apply(args,remove_at_pnt)._VECTptr);
4674     vecteur attributs(1,default_color(contextptr));
4675     int s=read_attributs(v,attributs,contextptr);
4676     if (s<2)
4677       return gendimerr(contextptr);
4678     v=vecteur(v.begin(),v.begin()+s);
4679     v.push_back(v.front());
4680     polygonify(v,contextptr);
4681     return pnt_attrib(gen(v,_GROUP__VECT),attributs,contextptr);
4682   }
4683   static const char _polygone_s []="polygon";
4684   static define_unary_function_eval (__polygone,&_polygone,_polygone_s);
4685   define_unary_function_ptr5( at_polygone ,alias_at_polygone,&__polygone,0,true);
4686 
_polygone_ouvert(const gen & args,GIAC_CONTEXT)4687   gen _polygone_ouvert(const gen & args,GIAC_CONTEXT){
4688     if ( args.type==_STRNG && args.subtype==-1) return  args;
4689     if (args.type!=_VECT)
4690       return symbolic(at_polygone,args);
4691     vecteur v(*apply(args,remove_at_pnt)._VECTptr);
4692     vecteur attributs(1,default_color(contextptr));
4693     int s=read_attributs(v,attributs,contextptr);
4694     if (s<2)
4695       return gendimerr(contextptr);
4696     v=vecteur(v.begin(),v.begin()+s);
4697     polygonify(v,contextptr);
4698     return pnt_attrib(gen(v,_GROUP__VECT),attributs,contextptr);
4699   }
4700   static const char _polygone_ouvert_s []="open_polygon";
4701   static define_unary_function_eval (__polygone_ouvert,&_polygone_ouvert,_polygone_ouvert_s);
4702   define_unary_function_ptr5( at_polygone_ouvert ,alias_at_polygone_ouvert,&__polygone_ouvert,0,true);
4703 
gen23points(const gen & args,gen & e,gen & f,gen & g,vecteur & attributs,GIAC_CONTEXT)4704   static bool gen23points(const gen & args,gen &e,gen &f,gen &g,vecteur & attributs,GIAC_CONTEXT){
4705     if (args.type!=_VECT) return false; // setsizeerr(gettext("plot.cc/gen23points"));
4706     vecteur v(*args._VECTptr);
4707     int s=read_attributs(v,attributs,contextptr);
4708     if (s<2)
4709       return false; // setdimerr(contextptr);
4710     e=v.front();f=v[1];
4711     e=remove_at_pnt(e);
4712     f=remove_at_pnt(f);
4713     e=remove_at_pnt(get_point(e,0,contextptr));
4714     if (f.type==_VECT && f.subtype!=_POINT__VECT){
4715       if (f._VECTptr->size()!=2)
4716 	return false; // setsizeerr(gettext("gen23points"));
4717       g=f._VECTptr->back();
4718       f=f._VECTptr->front();
4719     }
4720     else {
4721       if (s!=3)
4722 	return false; // setsizeerr(gettext("gen23points"));
4723       g=remove_at_pnt(v[2]);
4724     }
4725     f=remove_at_pnt(get_point(f,0,contextptr));
4726     g=remove_at_pnt(get_point(g,0,contextptr));
4727     return true;
4728   }
4729 
_hauteur(const gen & args,GIAC_CONTEXT)4730   gen _hauteur(const gen & args,GIAC_CONTEXT){
4731     if ( args.type==_STRNG && args.subtype==-1) return  args;
4732     if (args.type!=_VECT)
4733       return symbolic(at_hauteur,args);
4734     gen e,f,g;
4735     vecteur attributs(1,default_color(contextptr));
4736     if (!gen23points(args,e,f,g,attributs,contextptr))
4737       return gensizeerr(contextptr);
4738     if (f.type==_VECT && f._VECTptr->size()==3){
4739       // projection of e on f,g
4740       gen h=_projection(gen(makevecteur(_droite(gen(makevecteur(f,g),_SEQ__VECT),contextptr),e),_SEQ__VECT),contextptr);
4741       return symb_segment(e,h,attributs,_LINE__VECT,contextptr);
4742     }
4743     f=f-g;
4744     f=im(f,contextptr)-cst_i*re(f,contextptr);
4745     return symb_segment(e,e+f,attributs,_LINE__VECT,contextptr);
4746   }
4747   static const char _hauteur_s []="altitude";
4748   static define_unary_function_eval (__hauteur,&_hauteur,_hauteur_s);
4749   define_unary_function_ptr5( at_hauteur ,alias_at_hauteur,&__hauteur,0,true);
4750 
bissectrice(const gen & args,bool interieur,GIAC_CONTEXT)4751   gen bissectrice(const gen & args,bool interieur,GIAC_CONTEXT){
4752     gen E,e,f,g;
4753     vecteur attributs(1,default_color(contextptr));
4754     if (!gen23points(args,e,f,g,attributs,contextptr))
4755       return gensizeerr(contextptr);
4756     if (e==f || e==g)
4757       return gensizeerr(contextptr);
4758     // direction (f-e)+(g-e)*||f-e||/||g-e||
4759     E=f+(g-e)*rdiv(abs_norm(f,e,contextptr),abs_norm(g,e,contextptr),contextptr);
4760     if (E==e){
4761       if (interieur)
4762 	E=e+cst_i*(f-e);
4763       else
4764 	E=f;
4765     }
4766     else {
4767       if (!interieur)
4768 	E=e+cst_i*(E-e);
4769     }
4770     return symb_segment(e,E,attributs,_LINE__VECT,contextptr);
4771   }
4772 
_bissectrice(const gen & args,GIAC_CONTEXT)4773   gen _bissectrice(const gen & args,GIAC_CONTEXT){
4774     if ( args.type==_STRNG && args.subtype==-1) return  args;
4775     if ( (args.type!=_VECT) || (args._VECTptr->size()<2))
4776       return symbolic(at_bissectrice,args);
4777     return bissectrice(args,true,contextptr);
4778   }
4779   static const char _bissectrice_s []="bisector";
4780   static define_unary_function_eval (__bissectrice,&_bissectrice,_bissectrice_s);
4781   define_unary_function_ptr5( at_bissectrice ,alias_at_bissectrice,&__bissectrice,0,true);
4782 
_exbissectrice(const gen & args,GIAC_CONTEXT)4783   gen _exbissectrice(const gen & args,GIAC_CONTEXT){
4784     if ( args.type==_STRNG && args.subtype==-1) return  args;
4785     if ( (args.type!=_VECT) || (args._VECTptr->size()<2))
4786       return symbolic(at_exbissectrice,args);
4787     return bissectrice(args,false,contextptr);
4788   }
4789   static const char _exbissectrice_s []="exbisector";
4790   static define_unary_function_eval (__exbissectrice,&_exbissectrice,_exbissectrice_s);
4791   define_unary_function_ptr5( at_exbissectrice ,alias_at_exbissectrice,&__exbissectrice,0,true);
4792 
_mediane(const gen & args,GIAC_CONTEXT)4793   gen _mediane(const gen & args,GIAC_CONTEXT){
4794     if ( args.type==_STRNG && args.subtype==-1) return  args;
4795     if (args.type==_VECT && args.subtype!=_SEQ__VECT) return _median(args,contextptr);
4796     unsigned s=0;
4797     if ( (args.type!=_VECT) || ((s=unsigned(args._VECTptr->size()))<2))
4798       return gensizeerr(contextptr);
4799     if (s==2 && args._VECTptr->front().type==_VECT && args._VECTptr->front()._VECTptr->size()>3) return _median(args,contextptr);
4800     gen e,f,g;
4801     vecteur attributs(1,default_color(contextptr));
4802     if (!gen23points(args,e,f,g,attributs,contextptr))
4803       return gensizeerr(contextptr);
4804     // direction (f-e)+(g-e)*||f-e||/||g-e||
4805     return symb_segment(e,rdiv(f+g,plus_two,contextptr),attributs,_LINE__VECT,contextptr);
4806   }
4807   static const char _mediane_s []="median_line";
4808   static define_unary_function_eval (__mediane,&_mediane,_mediane_s);
4809   define_unary_function_ptr5( at_mediane ,alias_at_mediane,&__mediane,0,true);
4810 
4811   // chk if g is a pnt with 3 pnts as first argument
chk_3pnt(const gen & g)4812   static gen chk_3pnt(const gen & g){
4813     if (!g.is_symb_of_sommet(at_pnt))
4814       return zero;
4815     gen & f=g._SYMBptr->feuille;
4816     if (f.type!=_VECT || f._VECTptr->empty())
4817       return zero;
4818     gen & g0=f._VECTptr->front();
4819     if (g0.type==_VECT && g0._VECTptr->size()>2)
4820       return vecteur(g0._VECTptr->begin(),g0._VECTptr->begin()+3);
4821     else
4822       return zero;
4823   }
4824 
4825   // True if a=coeff*b
est_parallele_vecteur(const vecteur & a,const vecteur & b,gen & coeff,GIAC_CONTEXT)4826   bool est_parallele_vecteur(const vecteur & a,const vecteur &b,gen & coeff,GIAC_CONTEXT){
4827     unsigned int s=unsigned(a.size()),i,j;
4828     if (s!=b.size())
4829       return false; // setsizeerr(contextptr);
4830     for (i=0;i<s;++i){
4831       if (!is_zero(b[i],contextptr))
4832 	break;
4833     }
4834     if (i==s){ // b==0
4835       coeff=unsigned_inf;
4836       return true;
4837     }
4838     coeff=a[i]/b[i];
4839     j=i;
4840     for (i=0;i<s;++i){
4841       if (i==j)
4842 	continue;
4843       if (!is_zero(simplify(a[i]*b[j]-a[j]*b[i],contextptr),contextptr))
4844 	return false;
4845     }
4846     return true;
4847   }
est_parallele_vecteur(const vecteur & a,const vecteur & b,GIAC_CONTEXT)4848   bool est_parallele_vecteur(const vecteur & a,const vecteur &b,GIAC_CONTEXT){
4849     gen coeff;
4850     return est_parallele_vecteur(a,b,coeff,contextptr);
4851   }
est_parallele(const gen & a,const gen & b,GIAC_CONTEXT)4852   bool est_parallele(const gen & a,const gen & b,GIAC_CONTEXT){
4853     if (a.type==_VECT && b.type==_VECT){
4854       gen coeff;
4855       return est_parallele_vecteur(*a._VECTptr,*b._VECTptr,coeff,contextptr);
4856     }
4857     gen d(im(a*conj(b,contextptr),contextptr));
4858     return is_zero(simplify(d,contextptr),contextptr);
4859   }
est_aligne(const gen & a,const gen & b,const gen & c,GIAC_CONTEXT)4860   int est_aligne(const gen & a,const gen & b,const gen & c,GIAC_CONTEXT){
4861     return est_parallele(b-a,c-a,contextptr);
4862     // gen d(im((b-a)*conj(c-a,contextptr),contextptr));
4863     // return is_zero(d,contextptr);
4864   }
4865 
inter2droites2(const gen & a1,const gen & a2,const gen & b1,const gen & b2,int asub,int bsub,GIAC_CONTEXT)4866   static vecteur inter2droites2(const gen & a1,const gen & a2,const gen & b1,const gen & b2,int asub,int bsub,GIAC_CONTEXT){
4867     // 2-d line intersection
4868     gen v(a2-a1),w(b2-b1);
4869     gen x=(b1-a1).re(contextptr),y=(b1-a1).im(contextptr),vx=v.re(contextptr),vy=v.im(contextptr);
4870     gen wx=w.re(contextptr),wy=w.im(contextptr);
4871     gen alpha=rdiv(wy*x-wx*y,wy*vx-wx*vy,contextptr);
4872     return remove_not_in_segment(b1,b2,bsub,remove_not_in_segment(a1,a2,asub,makevecteur(symb_pnt(normal(a1+alpha*v,contextptr),default_color(contextptr),contextptr)),contextptr),contextptr);
4873   }
4874 
inter2droites3(const gen & a1,const gen & a2,const gen & b1,const gen & b2,int asub,int bsub,GIAC_CONTEXT)4875   static vecteur inter2droites3(const gen & a1,const gen & a2,const gen & b1,const gen & b2,int asub,int bsub,GIAC_CONTEXT){
4876     // 3-d line intersection
4877     gen M,N;
4878     vecteur n;
4879     if (perpendiculaire_commune(makevecteur(a1,a2),makevecteur(b1,b2),M,N,n,contextptr)){
4880       if (is_zero(ratnormal(M-N,contextptr),contextptr))
4881 	return remove_not_in_segment(b1,b2,bsub,remove_not_in_segment(a1,a2,asub,makevecteur(symb_pnt(M,default_color(contextptr),contextptr)),contextptr),contextptr);
4882     }
4883     return vecteur(0);
4884   }
4885 
inscrit_circonscrit(const gen & arg_orig,vecteur & attributs,GIAC_CONTEXT)4886   static gen inscrit_circonscrit(const gen & arg_orig,vecteur & attributs,GIAC_CONTEXT){
4887     gen args(arg_orig);
4888     if (args.type==_VECT){
4889       int s=read_attributs(*args._VECTptr,attributs,contextptr);
4890       if (s==1)
4891 	args=args._VECTptr->front();
4892       else
4893 	args=vecteur(args._VECTptr->begin(),args._VECTptr->begin()+s);
4894     }
4895     if ( (args.type!=_VECT) || (args._VECTptr->size()!=3)){
4896       gen tmp=chk_3pnt(args);
4897       if (is_zero(tmp,contextptr))
4898 	return gensizeerr(contextptr);
4899       else
4900 	return tmp;
4901     }
4902     return args;
4903   }
4904 
_circonscrit(const gen & arg_orig,GIAC_CONTEXT)4905   gen _circonscrit(const gen & arg_orig,GIAC_CONTEXT){
4906     if ( arg_orig.type==_STRNG && arg_orig.subtype==-1) return  arg_orig;
4907     vecteur attributs(1,default_color(contextptr));
4908     gen args(inscrit_circonscrit(arg_orig,attributs,contextptr));
4909     if (is_undef(args) || args.type!=_VECT || args._VECTptr->size()<3)
4910       return args;
4911     vecteur v(*args._VECTptr);
4912     gen e,f,g,h;
4913     e=remove_at_pnt(v[0]);
4914     f=remove_at_pnt(v[1]);
4915     g=remove_at_pnt(v[2]);
4916     e=remove_at_pnt(get_point(e,0,contextptr));
4917     f=remove_at_pnt(get_point(f,0,contextptr));
4918     g=remove_at_pnt(get_point(g,0,contextptr));
4919     if (est_aligne(e,f,g,contextptr) || is_undef(e) || is_undef(f) || is_undef(g))
4920       return undef;
4921     if (e.type==_VECT || f.type==_VECT || g.type==_VECT)
4922       return set3derr(contextptr);
4923     gen ef=(e+f)/2; gen fg=(f+g)/2;
4924     vecteur w(inter2droites2(ef,ef+cst_i*(f-e),fg,fg+cst_i*(g-f),_LINE__VECT,_LINE__VECT,contextptr));
4925     if (w.empty())
4926       return gensizeerr(contextptr);
4927     h=remove_at_pnt(w.front());
4928     return pnt_attrib(symbolic(at_cercle,gen(makevecteur(makevecteur(e,2*h-e),0,2*cst_pi),_PNT__VECT)),attributs,contextptr);
4929     // was return _cercle(makevecteur(h,e-remove_at_pnt(h)),contextptr);
4930   }
4931   static const char _circonscrit_s []="circumcircle";
4932   static define_unary_function_eval (__circonscrit,&_circonscrit,_circonscrit_s);
4933   define_unary_function_ptr5( at_circonscrit ,alias_at_circonscrit,&__circonscrit,0,true);
4934 
_orthocentre(const gen & arg_orig,GIAC_CONTEXT)4935   gen _orthocentre(const gen & arg_orig,GIAC_CONTEXT){
4936     if ( arg_orig.type==_STRNG && arg_orig.subtype==-1) return  arg_orig;
4937     vecteur attributs(1,default_color(contextptr));
4938     gen args(inscrit_circonscrit(arg_orig,attributs,contextptr));
4939     if (is_undef(args) || args.type!=_VECT || args._VECTptr->size()<3)
4940       return args;
4941     vecteur v(*args._VECTptr);
4942     gen e,f,g,h;
4943     e=remove_at_pnt(v[0]);
4944     f=remove_at_pnt(v[1]);
4945     g=remove_at_pnt(v[2]);
4946     e=remove_at_pnt(get_point(e,0,contextptr));
4947     f=remove_at_pnt(get_point(f,0,contextptr));
4948     g=remove_at_pnt(get_point(g,0,contextptr));
4949     if (est_aligne(e,f,g,contextptr) || is_undef(e) || is_undef(f) || is_undef(g))
4950       return undef;
4951     if (e.type==_VECT || f.type==_VECT || g.type==_VECT)
4952       return set3derr(contextptr);
4953     gen e1=e+cst_i*(g-f);
4954     gen f1=f+cst_i*(e-g);
4955     vecteur w(inter2droites2(e,e1,f,f1,_LINE__VECT,_LINE__VECT,contextptr));
4956     if (w.empty())
4957       return gensizeerr(contextptr);
4958     h=remove_at_pnt(w.front());
4959     return pnt_attrib(h,attributs,contextptr);
4960     // was return _cercle(makevecteur(h,e-remove_at_pnt(h)),contextptr);
4961   }
4962   static const char _orthocentre_s []="orthocenter";
4963   static define_unary_function_eval (__orthocentre,&_orthocentre,_orthocentre_s);
4964   define_unary_function_ptr5( at_orthocentre ,alias_at_orthocentre,&__orthocentre,0,true);
4965 
4966   // given 2 points e and f return equation of line e,f as coeffs a,b,c
point2abc(const gen & e,const gen & f,gen & a,gen & b,gen & c,GIAC_CONTEXT)4967   bool point2abc(const gen & e,const gen & f,gen & a,gen & b,gen & c,GIAC_CONTEXT){
4968     gen tmp=f-e;
4969     if (tmp.type==_VECT)
4970       return false;
4971     a=im(tmp,contextptr);
4972     b=-re(tmp,contextptr);
4973     c=-a*re(e,contextptr)-b*im(e,contextptr);
4974     vecteur v(makevecteur(a,b,c));
4975     lcmdeno(v,c,contextptr);
4976     a=v[0];
4977     b=v[1];
4978     c=v[2];
4979     return true;
4980   }
4981 
inscrit(const gen & args,const vecteur & attributs,bool exinscrit,GIAC_CONTEXT)4982   static gen inscrit(const gen & args,const vecteur & attributs,bool exinscrit,GIAC_CONTEXT){
4983     vecteur v(*args._VECTptr),w;
4984     // /* new code using barycentre A,a B,c C,c
4985     gen A,B,C;
4986     A=remove_at_pnt(v[0]);
4987     B=remove_at_pnt(v[1]);
4988     C=remove_at_pnt(v[2]);
4989     A=remove_at_pnt(get_point(A,0,contextptr));
4990     B=remove_at_pnt(get_point(B,0,contextptr));
4991     C=remove_at_pnt(get_point(C,0,contextptr));
4992     if (est_aligne(A,B,C,contextptr) || is_undef(A) || is_undef(B) || is_undef(B))
4993       return undef;
4994     gen a2=distance2pp(B,C,contextptr),b2=distance2pp(C,A,contextptr),c2=distance2pp(A,B,contextptr);
4995     gen a=exinscrit?-sqrt(a2,contextptr):sqrt(a2,contextptr);
4996     gen b=sqrt(b2,contextptr);
4997     gen c=sqrt(c2,contextptr);
4998     gen I=(a*A+b*B+c*C)/(a+b+c);
4999     I=normal(I,contextptr);
5000     gen AB(B-A), AC(C-A);
5001     gen surface=re(AB,contextptr)*im(AC,contextptr)-im(AB,contextptr)*re(AC,contextptr);
5002     gen r=normal(surface/(a+b+c),contextptr);
5003     return pnt_attrib(symbolic(at_cercle,gen(makevecteur(makevecteur(I-r,I+r),0,2*cst_pi),_PNT__VECT)),attributs,contextptr);
5004     // was return _cercle(makevecteur(I,r),contextptr);
5005     // end new code */
5006     // old code
5007     /*
5008       gen e,f,g;
5009       e=remove_at_pnt(v[0]);
5010       f=remove_at_pnt(v[1]);
5011       g=remove_at_pnt(v[2]);
5012       // find equations of droite(e,f) droite(e,g) droite(f,g)
5013       gen a_ef,b_ef,c_ef,a_fg,b_fg,c_fg,a_ge,b_ge,c_ge;
5014       point2abc(e,f,a_ef,b_ef,c_ef,contextptr);
5015       point2abc(f,g,a_fg,b_fg,c_fg,contextptr);
5016       point2abc(e,g,a_ge,b_ge,c_ge,contextptr);
5017       // value of equations droite(e,f) at g, etc.
5018       gen efg,fge,gef;
5019       efg=a_ef*re(g,contextptr)+b_ef*im(g,contextptr)+c_ef;
5020       fge=a_fg*re(e,contextptr)+b_fg*im(e,contextptr)+c_fg;
5021       gef=a_ge*re(f,contextptr)+b_ge*im(f,contextptr)+c_ge;
5022       gen eq_ef,eq_fg,eq_ge;
5023       gen sqrtg(sign(efg,contextptr)*sqrt(a_ef*a_ef+b_ef*b_ef)),sqrte(sign(fge,contextptr)*sqrt(a_fg*a_fg+b_fg*b_fg)),sqrtf(sign(gef,contextptr)*sqrt(a_ge*a_ge+b_ge*b_ge));
5024       vecteur coeff_eq_ef(makevecteur(a_ef/sqrtg,b_ef/sqrtg,c_ef/sqrtg));
5025       vecteur coeff_eq_fg(makevecteur(a_fg/sqrte,b_fg/sqrte,c_fg/sqrte));
5026       vecteur coeff_eq_ge(makevecteur(a_ge/sqrtf,b_ge/sqrtf,c_ge/sqrtf));
5027       matrice m(makevecteur(coeff_eq_fg,coeff_eq_ge,coeff_eq_ef));
5028       vecteur lv(alg_lvar(m));
5029       m=*e2r(m,lv)._VECTptr;
5030       // system to solve is A*x+B*y+C=0 D*x+E*y+F=0
5031       gen A,B,C,D,E,F;
5032       if (exinscrit){
5033       A=m[0][0]+m[1][0];
5034       B=m[0][1]+m[1][1];
5035       C=m[0][2]+m[1][2];
5036       }
5037       else {
5038       A=m[0][0]-m[1][0];
5039       B=m[0][1]-m[1][1];
5040       C=m[0][2]-m[1][2];
5041       }
5042       D=m[1][0]-m[2][0];
5043       E=m[1][1]-m[2][1];
5044       F=m[1][2]-m[2][2];
5045       // Solution is :
5046       gen x=(B*F-E*C)/(-D*B+A*E),y=(A*F-D*C)/(-A*E+B*D);
5047       // Compute r
5048       gen r=r2sym(dotvecteur(*m[0]._VECTptr,makevecteur(x,y,1)),lv);
5049       gen xy=r2sym(x+cst_i*y,lv);
5050       return _cercle(makevecteur(xy,r),contextptr);
5051       // end old code     */
5052     /*
5053       if (exinscrit)
5054       w=inter(bissectrice(makevecteur(e,f,g),false),bissectrice(makevecteur(f,g,e)));
5055       else
5056       w=inter(bissectrice(makevecteur(e,f,g)),bissectrice(makevecteur(f,g,e)));
5057       if (w.empty())
5058       return gensizeerr(contextptr);
5059       h=w.front();
5060       ef=_droite(makevecteur(e,f));
5061       w= inter(ef,_perpendiculaire(makevecteur(h,ef))); // point on circle
5062       if (w.empty())
5063       return gensizeerr(contextptr);
5064       d=w.front();
5065       return _cercle(makevecteur(h,d-h));
5066     */
5067   }
5068 
_inscrit(const gen & arg_orig,GIAC_CONTEXT)5069   gen _inscrit(const gen & arg_orig,GIAC_CONTEXT){
5070     if ( arg_orig.type==_STRNG && arg_orig.subtype==-1) return  arg_orig;
5071     vecteur attributs(1,default_color(contextptr));
5072     gen args=inscrit_circonscrit(arg_orig,attributs,contextptr);
5073     if (is_undef(args) || args.type!=_VECT || args._VECTptr->size()<3)
5074       return args;
5075     return inscrit(args,attributs,false,contextptr);
5076   }
5077   static const char _inscrit_s []="incircle";
5078   static define_unary_function_eval (__inscrit,&_inscrit,_inscrit_s);
5079   define_unary_function_ptr5( at_inscrit ,alias_at_inscrit,&__inscrit,0,true);
5080 
_exinscrit(const gen & arg_orig,GIAC_CONTEXT)5081   gen _exinscrit(const gen & arg_orig,GIAC_CONTEXT){
5082     if ( arg_orig.type==_STRNG && arg_orig.subtype==-1) return  arg_orig;
5083     vecteur attributs(1,default_color(contextptr));
5084     gen args=inscrit_circonscrit(arg_orig,attributs,contextptr);
5085     if (is_undef(args) || args.type!=_VECT || args._VECTptr->size()<3)
5086       return args;
5087     return inscrit(args,attributs,true,contextptr);
5088   }
5089   static const char _exinscrit_s []="excircle";
5090   static define_unary_function_eval (__exinscrit,&_exinscrit,_exinscrit_s);
5091   define_unary_function_ptr5( at_exinscrit ,alias_at_exinscrit,&__exinscrit,0,true);
5092 
_isobarycentre(const gen & args,GIAC_CONTEXT)5093   gen _isobarycentre(const gen & args,GIAC_CONTEXT){
5094     if ( args.type==_STRNG && args.subtype==-1) return  args;
5095     if (args.type!=_VECT){
5096       if (args.is_symb_of_sommet(at_pnt)){
5097 	gen & f=args._SYMBptr->feuille;
5098 	if (f.type!=_VECT)
5099 	  return args;
5100 	vecteur & v=*f._VECTptr;
5101 	int s=int(v.size());
5102 	if (!s)
5103 	  return args;
5104 	gen &g=v[0];
5105 	if (g.type!=_VECT || (s=int(g._VECTptr->size()))<2)
5106 	  return args;
5107 	gen sum;
5108 	const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end();
5109 	--itend;
5110 	--s;
5111 	for (;it!=itend;++it)
5112 	  sum=sum+*it;
5113 	return _point(sum/s,contextptr);
5114       }
5115       return _point(args,contextptr);
5116     }
5117     vecteur attributs(1,default_color(contextptr));
5118     const_iterateur it=args._VECTptr->begin(); // ,itend=args._VECTptr->end();
5119     int i=0;
5120     int s=read_attributs(*args._VECTptr,attributs,contextptr);
5121     gen sum;
5122     for (;i<s;++it,++i){
5123       sum = sum+remove_at_pnt(*it);
5124     }
5125     if (sum.type==_VECT)
5126       sum.subtype=_POINT__VECT;
5127     return pnt_attrib(rdiv(sum,i,contextptr),attributs,contextptr);
5128   }
5129   static const char _isobarycentre_s []="isobarycenter";
5130   static define_unary_function_eval (__isobarycentre,&_isobarycentre,_isobarycentre_s);
5131   define_unary_function_ptr5( at_isobarycentre ,alias_at_isobarycentre,&__isobarycentre,0,true);
5132 
inbarycentre(const gen & args,GIAC_CONTEXT)5133   static gen inbarycentre(const gen & args,GIAC_CONTEXT){
5134     if (args.type!=_VECT) return gensizeerr(contextptr);
5135     const_iterateur it=args._VECTptr->begin(); // ,itend=args._VECTptr->end();
5136     int i=0;
5137     vecteur attributs(1,default_color(contextptr));
5138     int s=read_attributs(*args._VECTptr,attributs,contextptr);
5139     gen sum,n;
5140     for (;i<s;++it,++i){
5141       if (it->type!=_VECT){
5142 	sum = sum+remove_at_pnt(*it);
5143 	n = n + 1;
5144       }
5145       else {
5146 	vecteur & v = *it->_VECTptr;
5147 	if (v.size()!=2)
5148 	  return gensizeerr(contextptr);
5149 	sum = sum + v.back()*remove_at_pnt(v.front());
5150 	n = n + v.back();
5151       }
5152     }
5153     if (is_zero(n,contextptr))
5154       return gensizeerr(gettext("Sum of coeff is 0"));
5155     if (sum.type==_VECT)
5156       sum=inv(n,contextptr)*sum;
5157     else
5158       sum=rdiv(sum,n,contextptr);
5159     if (sum.type==_VECT)
5160       sum.subtype=_POINT__VECT;
5161     return pnt_attrib(sum,attributs,contextptr);
5162   }
_barycentre(const gen & args,GIAC_CONTEXT)5163   gen _barycentre(const gen & args,GIAC_CONTEXT){
5164     if ( args.type==_STRNG && args.subtype==-1) return  args;
5165     if (args.type!=_VECT || args._VECTptr->empty())
5166       return gensizeerr(contextptr);
5167     const_iterateur it=args._VECTptr->begin(),itend=args._VECTptr->end();
5168     if (itend-it==2 && args.subtype!=_SEQ__VECT && ckmatrix(args)){
5169       vecteur & v=*(it+1)->_VECTptr;
5170       if (!v.front().is_symb_of_sommet(at_pnt) && is_zero(im(v.front(),contextptr),contextptr))
5171 	return inbarycentre(_tran(args,contextptr),contextptr);
5172     }
5173     return inbarycentre(args,contextptr);
5174   }
5175 
5176   static const char _barycentre_s []="barycenter";
5177   static define_unary_function_eval (__barycentre,&_barycentre,_barycentre_s);
5178   define_unary_function_ptr5( at_barycentre ,alias_at_barycentre,&__barycentre,0,true);
5179 
scalar_product(const gen & a0,const gen & b0,GIAC_CONTEXT)5180   gen scalar_product(const gen & a0,const gen & b0,GIAC_CONTEXT){
5181     gen a=remove_at_pnt(a0);
5182     gen b=remove_at_pnt(b0);
5183     if (a.type==_VECT && b.type==_VECT)
5184       return scalarproduct(*a._VECTptr,*b._VECTptr,contextptr);
5185     gen ax,ay; reim(a,ax,ay,contextptr);
5186     gen bx,by; reim(b,bx,by,contextptr);
5187     return ax*bx+ay*by;
5188     // gen res=re(a,contextptr)*re(b,contextptr)+im(a,contextptr)*im(b,contextptr);
5189     // return res;
5190   }
5191 #if 0
normalized_scalar_product(const gen & a,const gen & b,GIAC_CONTEXT)5192   static gen normalized_scalar_product(const gen & a,const gen & b,GIAC_CONTEXT){
5193     if (a.type==_VECT && b.type==_VECT)
5194       return dotvecteur(*a._VECTptr,*b._VECTptr)/sqrt(dotvecteur(*a._VECTptr,*a._VECTptr)*dotvecteur(*b._VECTptr,*b._VECTptr),contextptr);
5195     gen res1=re(a,contextptr)*re(b,contextptr)+im(a,contextptr)*im(b,contextptr);
5196     gen res2=sqrt(a.squarenorm(contextptr)*b.squarenorm(contextptr),contextptr);
5197     return rdiv(res1,res2,contextptr);
5198   }
5199 #endif
5200   // return t such that tb+(1-t)a is the projection of c on [a,b]
projection(const gen & a,const gen & b,const gen & c,GIAC_CONTEXT)5201   gen projection(const gen & a,const gen & b,const gen & c,GIAC_CONTEXT){
5202     gen ax,ay,bx,by,cx,cy,abx,aby;
5203     reim(a,ax,ay,contextptr);
5204     reim(b,bx,by,contextptr);
5205     reim(c,cx,cy,contextptr);
5206     abx=ax-bx;aby=ay-by;
5207     gen num=(ax-cx)*abx+(ay-cy)*aby;
5208     gen den=abx*abx+aby*aby;
5209     // gen num=scalar_product(a-c,a-b,contextptr),den=scalar_product(b-a,b-a,contextptr);
5210     return rdiv(num,den,contextptr);
5211   }
5212 
rewrite_with_t_real(gen & eq,const gen & t,GIAC_CONTEXT)5213   void rewrite_with_t_real(gen & eq,const gen & t,GIAC_CONTEXT){
5214     gen tx,ty; reim(t,tx,ty,contextptr);
5215     if (!is_zero(ty,contextptr)){
5216       eq=subst(eq,ty,zero,false,contextptr);
5217       eq=subst(eq,tx,t,false,contextptr);
5218     }
5219   }
5220 
5221   // test if a point f is on a parametric curve e
5222   // compute t if true
on(const gen & e_orig,const gen & f,gen & t,GIAC_CONTEXT)5223   bool on(const gen & e_orig,const gen & f,gen & t,GIAC_CONTEXT){
5224     gen e;
5225     if ( (e_orig.type==_SYMB) && (e_orig._SYMBptr->sommet==at_curve))
5226       e=e_orig._SYMBptr->feuille._VECTptr->front();
5227     else
5228       e=e_orig;
5229     if ((e.type!=_VECT) || (e._VECTptr->size()<4) )
5230       return false; // settypeerr(gettext("on"));
5231     vecteur ee(*e._VECTptr);
5232     gen tt=ee[1];
5233     gen tmin=ee[2],tmax=ee[3];
5234     gen eq=re(ee[0],contextptr)-re(f,contextptr);
5235     rewrite_with_t_real(eq,tt,contextptr);
5236     vecteur v(solve(eq,tt,0,contextptr));
5237     const_iterateur it=v.begin(),itend=v.end();
5238     for (;it!=itend;++it){
5239       if ( is_zero(normal(subst(im(ee[0],contextptr),tt,*it,false,contextptr)-im(f,contextptr),contextptr),contextptr) &&
5240 	   ck_is_greater(*it,tmin,contextptr) && ck_is_greater(tmax,*it,contextptr) ){
5241 	t=*it;
5242 	return true;
5243       }
5244     }
5245     return false;
5246   }
5247   // projection of a (true) point pp on a parametric curve
5248   // e=symb_cercle or line, returns t
projection(const gen & e,const gen & pp,GIAC_CONTEXT)5249   gen projection(const gen & e,const gen & pp,GIAC_CONTEXT){
5250     gen p=remove_at_pnt(pp);
5251     if (p.type==_SYMB){
5252       if ( (p._SYMBptr->sommet==at_cercle) || (p._SYMBptr->sommet==at_curve))
5253 	return gensizeerr(contextptr);
5254     }
5255     if (p.type==_VECT)
5256       return gensizeerr(contextptr);
5257     gen sur=remove_at_pnt(e);
5258     if (e.type==_VECT && !e._VECTptr->empty())
5259       sur=remove_at_pnt(e._VECTptr->front());
5260     if ( (sur.type==_VECT) && (sur._VECTptr->size()>=2)){
5261       int s=int(sur._VECTptr->size());
5262       gen res,proj,dist;
5263       for (int i=0;i<s-1;++i){
5264 	gen a=(*sur._VECTptr)[i];
5265 	gen b=(*sur._VECTptr)[i+1];
5266 	gen c=projection(a,b,p,contextptr);
5267 	if (s>2){
5268 	  if (is_positive(-c,contextptr))
5269 	    c=0;
5270 	  if (is_positive(c-1,contextptr))
5271 	    c=1;
5272 	}
5273 	gen cur_proj=a+c*(b-a),cur_dist;
5274 	if (!is_undef(c) && (i==0 || is_strictly_greater(dist,(cur_dist=distance2pp(p,cur_proj,contextptr)),contextptr))){
5275 	  res=i?makevecteur(i,c):c;
5276 	  proj=cur_proj;
5277 	  dist=i?cur_dist:distance2pp(p,cur_proj,contextptr);
5278 	}
5279       }
5280       return res;
5281     }
5282     if ( (sur.type==_SYMB) && (sur._SYMBptr->sommet==at_cercle) ){
5283       gen centre,rayon;
5284       if (!centre_rayon(sur,centre,rayon,false,contextptr))
5285 	return gensizeerr(contextptr); // don't care about radius
5286       //grad
5287       int mode=get_mode_set_radian(contextptr);
5288       gen res=arg(p-centre,contextptr);
5289       angle_mode(mode,contextptr);
5290 
5291       return res;
5292     }
5293     // if p is on e return 0
5294     if ( (sur.type==_SYMB) && (sur._SYMBptr->sommet==at_curve) ){
5295       sur = sur._SYMBptr->feuille._VECTptr->front();
5296       gen t;
5297       // if (on(sur,p,t))
5298       // return zero;
5299       // find all orthogonalities tangeant/rayon
5300       vecteur v(*sur._VECTptr);
5301       identificateur tt=*v[1]._IDNTptr;
5302       gen vparameq(v[0]);
5303 #if 1
5304       bool numereq=false,approxafter=false,conique=false;
5305       if (v.size()>6 && !is_undef(v[6])){
5306 	if (is_constant_wrt(vparameq,v[1],contextptr))
5307 	  v[1]=t__IDNT_e;
5308 	v[2]=minus_inf;
5309 	v[3]=plus_inf;
5310 	if (has_num_coeff(v[6]))
5311 	  approxafter=true;
5312 	if (v.size()>7 && v[7].type==_VECT && !v[7]._VECTptr->empty())
5313 	  conique=v[7]._VECTptr->front()==at_ellipse;
5314 	v[0]=vparameq=conique?v[6]:exact(v[6],contextptr);
5315 	tt=*v[1]._IDNTptr;
5316 	numereq=true;
5317 	if (has_num_coeff(p))
5318 	  approxafter=true;
5319       }
5320 #endif
5321       gen t_found=v[2];
5322 #ifndef NO_STDEXCEPT
5323       try {
5324 #endif
5325 	gen eq;
5326 	if (numereq){
5327 	  gen xy,d,x,y,mx,my,d1,x1,y1;
5328 	  gen tmp=_fxnd(vparameq,contextptr);
5329 	  if (tmp.type!=_VECT)
5330 	    numereq=false;
5331 	  else {
5332 	    xy=tmp._VECTptr->front(); d=tmp._VECTptr->back();
5333 	    d1=derive(d,tt,contextptr);
5334 	    if (is_zero(im(d1,contextptr))){
5335 	      reim(xy,x,y,contextptr);
5336 	      reim(exact(p,contextptr),mx,my,contextptr);
5337 	      x1=derive(x,tt,contextptr);
5338 	      y1=derive(y,tt,contextptr);
5339 	      eq=d*((x1*d-d1*x)*mx+(y1*d-d1*y)*my)+(x*x+y*y)*d1-d*(x1*x+y1*y);
5340 	      if (!conique)
5341 		eq=_numer(eq,contextptr);
5342 	    }
5343 	    else numereq=false;
5344 	  }
5345 	}
5346 	if (!numereq){
5347 	  gen tangeant(derive(vparameq,tt,contextptr));
5348 	  if (is_undef(tangeant))
5349 	    return tangeant;
5350 	  eq=scalar_product(tangeant,p-v[0],contextptr);
5351 	  if (is_undef(eq)) return eq;
5352 	  if (is_inf(v[2]) || is_inf(v[3]))
5353 	    eq=exact(eq,contextptr);
5354 	  // should expand and assume that tt is real
5355 	  rewrite_with_t_real(eq,v[1],contextptr);
5356 	}
5357 	vecteur sol;
5358 	if (has_num_coeff(eq) && !conique){
5359 	  gen rep=re(p,contextptr);
5360 	  // first try bisection near re(p) if re(v[0])==v[1]
5361 	  if (re(v[0],contextptr)==v[1]){
5362 	    gen dx=(gnuplot_xmax-gnuplot_xmin)/2; // or maybe v[3]-v[2]?
5363 	    int iszero=-1;
5364 	    vecteur sol1=bisection_solver(eq,v[1],rep-dx,rep+dx,iszero,contextptr);
5365 	    // keep only solutions, no sign reversal
5366 	    for (unsigned i=0;i<sol1.size();++i){
5367 	      if (is_greater(1e-4,subst(eq,v[1],sol1[i],false,contextptr),contextptr))
5368 		sol.push_back(sol1[i]);
5369 	    }
5370 	  }
5371 	  if (sol.empty()){
5372 	    vecteur eqv(makevecteur(eq,symb_equal(v[1],symb_interval(v[2],v[3])),symb_equal(change_subtype(_NSTEP,_INT_PLOT),30),1e-4));
5373 	    sol=gen2vecteur(in_fsolve(eqv,contextptr));
5374 	  }
5375 	}
5376 	else {
5377 	  if (approxafter && lvarxwithinv(eq,tt,contextptr).size()<2) {
5378 	    sol=gen2vecteur(_proot(makesequence(evalf(eq,1,contextptr),tt),contextptr));//eq=evalf(eq,1,contextptr);
5379 	  }
5380 	  else
5381 	    sol=solve(eq,v[1],0,contextptr);
5382 	}
5383 	if (calc_mode(contextptr)==1 && sol.empty())
5384 	  return undef;
5385 	sol.push_back(v[3]);
5386 	// find smallest
5387 	const_iterateur it=sol.begin(),itend=sol.end();
5388 	gen distance2_found=undef,cur_distance2;
5389 #ifdef NO_STDEXCEPT
5390 	distance2_found=distance2pp(limit(v[0],*v[1]._IDNTptr,v[2],0,contextptr),p,contextptr);
5391 #else
5392 	try {
5393 	  if (conique)
5394 	    distance2_found=distance2pp(subst(v[0],*v[1]._IDNTptr,v[2],false,contextptr),p,contextptr);
5395 	  else
5396 	    distance2_found=distance2pp(limit(v[0],*v[1]._IDNTptr,v[2],0,contextptr),p,contextptr);
5397 	} catch (std::runtime_error) {
5398 	  last_evaled_argptr(contextptr)=NULL;
5399 	}
5400 #endif
5401 	if (is_undef(distance2_found))
5402 	  distance2_found=plus_inf;
5403 	for (;it!=itend;++it){
5404 	  if (!is_zero(it->im(contextptr),contextptr))
5405 	    continue;
5406 	  if (conique)
5407 	    cur_distance2=distance2pp(subst(v[0],*v[1]._IDNTptr,*it,false,contextptr),p,contextptr);
5408 	  else
5409 	    cur_distance2=distance2pp(limit(v[0],*v[1]._IDNTptr,*it,0,contextptr),p,contextptr);
5410 	  if (is_undef(cur_distance2)) continue;
5411 	  if (ck_is_greater(distance2_found,cur_distance2,contextptr)){
5412 	    t_found=*it;
5413 	    distance2_found=cur_distance2;
5414 	  }
5415 	} // end for
5416 #ifndef NO_STDEXCEPT
5417       } // end try
5418       catch(std::runtime_error & ){ // could not solve
5419 	last_evaled_argptr(contextptr)=NULL;
5420 	// if curve is a function (plotfunc) return re(p)
5421 	gen eq=re(v[0],contextptr);
5422 	rewrite_with_t_real(eq,v[1],contextptr);
5423 	vecteur sol(solve(eq-re(p,contextptr),v[1],0,contextptr));
5424 	if (sol.empty())
5425 	  return gensizeerr(contextptr);
5426 	t_found=sol.front();
5427       }
5428 #endif
5429       return t_found;
5430     }
5431     // unknown
5432     return undef;
5433   }
5434 
5435   // cercle to parametric curve
cercle2curve(const gen & f,GIAC_CONTEXT)5436   gen cercle2curve(const gen & f,GIAC_CONTEXT){
5437     // ck_parameter_t();
5438     gen centre,rayon;
5439     if (!centre_rayon(f,centre,rayon,false,contextptr))
5440       return gensizeerr(contextptr); // don't care about radius sign
5441     return symb_curve(gen(makevecteur(centre+normal(rayon,contextptr)*symb_exp(cst_i*t__IDNT_e),t__IDNT_e,zero,cst_two_pi),_PNT__VECT),f);
5442   }
5443 
5444   // line to parametric curve
line2curve(const gen & f)5445   gen line2curve(const gen & f){
5446     if ( (f.type!=_VECT) || (f._VECTptr->size()!=2))
5447       return gensizeerr(gettext("line2curve"));
5448     identificateur idt(" t");
5449     gen t(idt);
5450     gen A(f._VECTptr->front());
5451     gen B(f._VECTptr->back());
5452     gen tmin,tmax;
5453     if (f.subtype==_LINE__VECT){
5454       tmin=minus_inf;
5455       tmax=plus_inf;
5456     }
5457     else {
5458       tmin=zero;
5459       tmax=plus_one;
5460     }
5461     return symb_curve(gen(makevecteur(ratnormal(t*B+(1-t)*A,context0),t,tmin,tmax),_PNT__VECT),f);
5462   }
5463 
5464   // square distance curve/curve
distance2cc(const gen & e,const gen & f,GIAC_CONTEXT)5465   static gen distance2cc(const gen & e,const gen & f,GIAC_CONTEXT){
5466     return gensizeerr(gettext("Distance curve/curve not implemented"));
5467   }
complex_abs3(const gen & f,GIAC_CONTEXT)5468   static gen complex_abs3(const gen & f,GIAC_CONTEXT){
5469     if (f.type==_VECT && f.subtype==_POINT__VECT && f._VECTptr->size()==3){
5470       if (f._VECTptr->back().type==_CPLX){
5471 	vecteur f1(*f._VECTptr);
5472 	f1[2]=abs(f1[2],contextptr);
5473 	return gen(f1,_POINT__VECT);
5474       }
5475     }
5476     return f;
5477   }
5478 
5479   // square distance curve/point or curve/curve
5480   // ee is a curve
distance2cp(const gen & ee,const gen & f0,GIAC_CONTEXT)5481   static gen distance2cp(const gen & ee,const gen & f0,GIAC_CONTEXT){
5482     gen f=complex_abs3(f0,contextptr);
5483     gen e=ee._SYMBptr->feuille;
5484     if (e.type==_VECT && !e._VECTptr->empty())
5485       e=e._VECTptr->front();
5486     if ((f.type==_SYMB) && (f._SYMBptr->sommet==at_curve))
5487       return distance2cc(e,f._SYMBptr->feuille._VECTptr->front(),contextptr);
5488     if ((f.type==_SYMB) && (f._SYMBptr->sommet==at_cercle))
5489       return distance2cp(ee,cercle2curve(f,contextptr),contextptr);
5490     if (e.type!=_VECT || e._VECTptr->size()<2)
5491       return undef;
5492     vecteur v(*e._VECTptr);
5493     gen p=projection(ee,f,contextptr);
5494     gen projete=subst(v[0],v[1],p,false,contextptr);
5495     return distance2pp(projete,f,contextptr);
5496   }
5497 
5498   // square distance line/point
distance2sp(const_iterateur it,const const_iterateur itend,const gen & p0,int subtype,GIAC_CONTEXT)5499   static gen distance2sp(const_iterateur it,const const_iterateur itend,const gen & p0,int subtype,GIAC_CONTEXT){
5500     gen res,newres,a,b,t,c,r,p=complex_abs3(p0,contextptr);
5501     bool is_cercle=centre_rayon(p,c,r,false,contextptr);
5502     a=*it;
5503     if (is_cercle && it+2==itend && subtype==_LINE__VECT){
5504       ++it;
5505       b=*it;
5506       t=projection(a,b,c,contextptr);
5507       if (is_undef(t)) return undef;
5508       gen pr=t*b+(1-t)*a; // projection of the center c
5509       gen d2=abs_norm2(pr-c,contextptr);
5510       gen r2=r*conj(r,contextptr);
5511       if (is_strictly_greater(d2,r2,contextptr))
5512 	return pow(sqrt(d2,contextptr)-sqrt(r2,contextptr),2);
5513       return 0;
5514     }
5515     res=distance2pp(a,p,contextptr);
5516     ++it;
5517     for (;;){
5518       b=*it;
5519       if (is_cercle) // FIXME this is incorrect, see above for line__vect
5520 	t=projection(a,b,c,contextptr);
5521       else
5522 	t=projection(a,b,p,contextptr);
5523       if (is_undef(t)) return t;
5524       if (subtype==_LINE__VECT || (ck_is_positive(t,contextptr) && (subtype==_HALFLINE__VECT || ck_is_greater(1,t,contextptr))))
5525 	newres=distance2pp(t*b+(1-t)*a,p,contextptr);
5526       else
5527 	newres=distance2pp(b,p,contextptr);
5528       if (subtype==_LINE__VECT || ck_is_greater(res,newres,contextptr))
5529 	res=newres;
5530       ++it;
5531       if (it==itend)
5532 	break;
5533       a=b;
5534     }
5535     return res;
5536   }
5537 
5538   // square distance point/point
distance2pp(const gen & ee,const gen & ff,GIAC_CONTEXT)5539   gen distance2pp(const gen & ee,const gen & ff,GIAC_CONTEXT){
5540     if (is_undef(ee) || is_undef(ff))
5541       return ee+ff;
5542     gen e(remove_at_pnt(ee));
5543     gen f(remove_at_pnt(ff));
5544     f=complex_abs3(f,contextptr);
5545     if (e.is_symb_of_sommet(at_hyperplan)){
5546       if (!f.is_symb_of_sommet(at_hyperplan))
5547 	return distance2pp(f,e,contextptr);
5548       vecteur n1,P1,n2,P2;
5549       hyperplan_normal_point(e,n1,P1);
5550       hyperplan_normal_point(f,n2,P2);
5551       if (!est_parallele_vecteur(n1,n2,contextptr))
5552 	return 0;
5553       return pow(dotvecteur(n1,subvecteur(P2,P1)),2,contextptr)/dotvecteur(n1,n1);
5554     }
5555     if (e.type==_VECT){
5556       if (e.subtype==_POINT__VECT || (f.type==_VECT && f.subtype==_POINT__VECT && e.subtype!=_LINE__VECT)){ // n-d point
5557 	vecteur & ev = *e._VECTptr;
5558 	if (f.type==_VECT && f.subtype==_POINT__VECT){ // square distance between 2 n-d points
5559 	  vecteur ef(subvecteur(*f._VECTptr,ev));
5560 	  return dotvecteur(ef,ef);
5561 	}
5562 	if (f.is_symb_of_sommet(at_hyperplan)){ // point to hyperplan
5563 	  // get normal vector n and base point P of hyperplan
5564 	  gen & ff=f._SYMBptr->feuille;
5565 	  if (ff.type==_VECT && ff._VECTptr->size()==2){
5566 	    gen & n = ff._VECTptr->front();
5567 	    gen & P = ff._VECTptr->back();
5568 	    // -> ((P-e).n)^2/n.n
5569 	    if (P.type==_VECT && n.type==_VECT){
5570 	      vecteur & nv = *n._VECTptr;
5571 	      vecteur & Pv = *P._VECTptr;
5572 	      return pow(dotvecteur(subvecteur(Pv,ev),nv),2,contextptr)/dotvecteur(nv,nv);
5573 	    }
5574 	  }
5575 	}
5576 	if (f.is_symb_of_sommet(at_hypersphere)){
5577 	  // point to hypersphere: (abs_norm(point-center)-radius)^2
5578 	  gen centre,rayon;
5579 	  if (!centre_rayon(f,centre,rayon,true,contextptr))
5580 	    return gensizeerr(contextptr);
5581 	  gen delta=abs_norm(e-centre,contextptr)-rayon;
5582 	  return delta*delta;
5583 	}
5584 	if (f.type==_VECT && f._VECTptr->size()==2){ // point to line
5585 	  gen & A=f._VECTptr->front();
5586 	  gen & B=f._VECTptr->back();
5587 	  if (A.type==_VECT && B.type==_VECT){
5588 	    // M=A+t(B-A), find t s.t. B-A is orthogonal to e-M
5589 	    // (B-A).e=(B-A).M=(B-A).A+t(B-A).(B-A)
5590 	    // t=(B-A).(e-A)/(B-A).(B-A)
5591 	    vecteur & vA=*A._VECTptr;
5592 	    vecteur & vB=*B._VECTptr;
5593 	    vecteur vAB(subvecteur(vB,vA));
5594 	    vecteur veA(subvecteur(vA,ev));
5595 	    gen t=-dotvecteur(veA,vAB)/dotvecteur(vAB,vAB);
5596 	    // distance2 = (M-e).(M-e), M-e=A-e+t*(B-A)
5597 	    vecteur veM(addvecteur(veA,multvecteur(t,vAB)));
5598 	    t=dotvecteur(veM,veM);
5599 	    // cerr << dotvecteur(veM,vAB)  << '\n';
5600 	    return  t;
5601 	  }
5602 	}
5603       } // end e of type n-d point
5604       if (e._VECTptr->size()==2){ // e of type line
5605 	if (f.type!=_VECT){ // 2-d line/point
5606 	  return distance2sp(e._VECTptr->begin(),e._VECTptr->end(),f,e.subtype,contextptr);
5607 	}
5608 	if (f.type==_VECT && f.subtype==_POINT__VECT)
5609 	  return distance2pp(f,e,contextptr);
5610 	if (f.type==_VECT && f._VECTptr->size()==2){ // line to line
5611 	  gen M,N;
5612 	  vecteur n;
5613 	  if (e._VECTptr->front().type!=_VECT){ // 2-d
5614 	    gen & A =e._VECTptr->front();
5615 	    gen & B =e._VECTptr->back();
5616 	    gen & C =f._VECTptr->front();
5617 	    gen & D =f._VECTptr->back();
5618 	    gen AB=B-A;
5619 	    if (!est_parallele(AB,D-C,contextptr))
5620 	      return 0;
5621 	    n=makevecteur(im(AB,contextptr),re(AB,contextptr));
5622 	    return pow(dotvecteur(n,makevecteur(re(C-A,contextptr),im(C-A,contextptr))),2,contextptr)/dotvecteur(n,n);
5623 	  }
5624 	  else { // 3-d
5625 	    if (perpendiculaire_commune(e,f,M,N,n,contextptr)){
5626 	      gen MN(M-N);
5627 	      if (MN.type==_VECT){
5628 		vecteur & vMN=*MN._VECTptr;
5629 		return dotvecteur(vMN,vMN);
5630 	      }
5631 	    }
5632 	  } // end 3-d
5633 	} // end f.type==_VECT && f._VECTptr->size()==2
5634       } // end e._VECTptr->size()==2
5635       return gensizeerr(contextptr); // undef; // setsizeerr(contextptr);
5636       // commented setsizeerr otherwise lots of bad arg when loading a Figure
5637     } // end e.type==_VECT
5638     if (f.type==_VECT) // f is a line or a point
5639       return distance2pp(f,e,contextptr);
5640     if ((e.type==_SYMB) && (e._SYMBptr->sommet==at_curve))
5641       return distance2cp(e,f,contextptr);
5642     if ((f.type==_SYMB) && (f._SYMBptr->sommet==at_curve))
5643       return distance2cp(f,e,contextptr);
5644     if ( (e.type==_SYMB) && (e._SYMBptr->sommet==at_cercle)){
5645       if ( (f.type==_SYMB) && (f._SYMBptr->sommet==at_cercle)){
5646 	gen centre1,rayon1,centre2,rayon2;
5647 	if (!centre_rayon(e,centre1,rayon1,true,contextptr) || !centre_rayon(f,centre2,rayon2,true,contextptr))
5648 	  return gensizeerr(contextptr);
5649 	gen r=abs_norm(centre2-centre1,contextptr)-rayon1-rayon2;
5650 	if (ck_is_positive(r,contextptr))
5651 	  return r*r;
5652 	else
5653 	  return zero;
5654       }
5655       // cercle <-> point: (abs_norm(point-center)-radius)^2
5656       gen centre,rayon;
5657       if (!centre_rayon(e,centre,rayon,true,contextptr))
5658 	return gensizeerr(contextptr);
5659       gen delta=abs_norm(f-centre,contextptr)-rayon;
5660       return delta*delta;
5661     }
5662     if ( (f.type==_SYMB) && (f._SYMBptr->sommet==at_cercle))
5663       return distance2pp(f,e,contextptr);
5664 #ifdef IPAQ
5665     gen r(re(e-f,contextptr)),i(im(e-f,contextptr));
5666     return r*r+i*i;
5667 #else
5668     if (e.type==_CPLX && f.type==_CPLX){
5669       gen ref=*e._CPLXptr-*f._CPLXptr;
5670       gen ief=*(e._CPLXptr+1)-*(f._CPLXptr+1);
5671       return ref*ref+ief*ief;
5672     }
5673     gen ef=e-f;
5674     return pow(re(ef,contextptr),2)+pow(im(ef,contextptr),2);
5675 #endif
5676   }
5677 
distance2(const gen & f1,const gen & f2,GIAC_CONTEXT)5678   gen distance2(const gen & f1,const gen & f2,GIAC_CONTEXT){
5679     gen e1(remove_at_pnt(f1)),e2(f2);
5680     if (e2.is_symb_of_sommet(at_equal)){
5681       e2=_plotimplicit(e2,contextptr);
5682       if (e2.type==_VECT && !e2._VECTptr->empty())
5683 	e2=e2._VECTptr->front();
5684     }
5685     e2=remove_at_pnt(e2);
5686     if (e1.type==_VECT && e1.subtype==_VECTOR__VECT)
5687       e1=vector2vecteur(*e1._VECTptr);
5688     if (e2.type==_VECT && e2.subtype==_VECTOR__VECT)
5689       e2=vector2vecteur(*e2._VECTptr);
5690     vecteur v1,v2;
5691     if (e1.type!=_VECT || e1.subtype==_POINT__VECT || e1.subtype==_LINE__VECT )
5692       v1=makevecteur(e1);
5693     else
5694       v1=*e1._VECTptr;
5695     if (e2.type!=_VECT || e2.subtype==_POINT__VECT || e2.subtype==_LINE__VECT)
5696       v2=makevecteur(e2);
5697     else
5698       v2=*e2._VECTptr;
5699     const_iterateur it=v1.begin(),itend=v1.end(),jt=v2.begin(),jtend=v2.end();
5700     if ( (itend==it+1) && (jtend==jt+1) )
5701       return distance2pp(*it,*jt,contextptr);
5702     if (itend==it+1)
5703       return distance2sp(jt,jtend,*it,e2.subtype,contextptr);
5704     if (jtend==jt+1)
5705       return distance2sp(it,itend,*jt,e1.subtype,contextptr);
5706     gen res=plus_inf,newres;
5707     for (;it!=itend;++it){
5708       for (jt=v2.begin();jt!=jtend;++jt){
5709 	newres=distance2pp(*it,*jt,contextptr);
5710 	if (ck_is_strictly_greater(res,newres,contextptr))
5711 	  res=newres;
5712       }
5713     }
5714     return res;
5715   }
_longueur2(const gen & args,GIAC_CONTEXT)5716   gen _longueur2(const gen & args,GIAC_CONTEXT){
5717     if ( args.type==_STRNG && args.subtype==-1) return  args;
5718     if (args.type==_INT_){int d=args.val; return d*d;}
5719     if (args.type==_DOUBLE_){double d=args._DOUBLE_val; return d*d;}
5720     if (args.type==_CPLX && args.subtype==3){
5721       double r=args._CPLXptr->_DOUBLE_val,i=(args._CPLXptr+1)->_DOUBLE_val;
5722       return r*r+i*i;
5723     }
5724     if ( args.type!=_VECT || args.subtype!=_SEQ__VECT || args._VECTptr->size()!=2){
5725       if (args.type!=_VECT) return args*args;
5726       return gensizeerr(contextptr);
5727     }
5728     gen e1=args._VECTptr->front(),e2=args._VECTptr->back();
5729     if (e1.type==_VECT && e2.type==_VECT){
5730       vecteur e12=subvecteur(*e1._VECTptr,*e2._VECTptr);
5731       return dotvecteur(e12,e12);
5732     }
5733     return distance2(e1,e2,contextptr);
5734   }
5735   static const char _longueur2_s []="distance2";
5736   static define_unary_function_eval (__longueur2,&_longueur2,_longueur2_s);
5737   define_unary_function_ptr5( at_longueur2 ,alias_at_longueur2,&__longueur2,0,true);
5738 
_longueur(const gen & args,GIAC_CONTEXT)5739   gen _longueur(const gen & args,GIAC_CONTEXT){
5740     if ( args.type==_STRNG && args.subtype==-1) return  args;
5741     vecteur * argptr;
5742     if ( args.type!=_VECT || args.subtype!=_SEQ__VECT || (argptr=args._VECTptr)->size()!=2)
5743       return gensizeerr(contextptr);
5744     const gen & e1=argptr->front();
5745     const gen & e2=argptr->back();
5746     if (e1.type==_CPLX && e1.subtype==3 && e2.type==_CPLX && e2.subtype==3){
5747       double x=e1._CPLXptr->_DOUBLE_val-e2._CPLXptr->_DOUBLE_val,y=(e1._CPLXptr+1)->_DOUBLE_val-(e2._CPLXptr+1)->_DOUBLE_val;
5748       return std::sqrt(x*x+y*y);
5749     }
5750     return sqrt(_longueur2(args,contextptr),contextptr);
5751   }
5752   static const char _longueur_s []="distance";
5753   static define_unary_function_eval (__longueur,&_longueur,_longueur_s);
5754   define_unary_function_ptr5( at_longueur ,alias_at_longueur,&__longueur,0,true);
5755 
approx_area(const gen & f,const gen & x,const gen & a_,const gen & b_,int n,int method,GIAC_CONTEXT)5756   gen approx_area(const gen & f,const gen & x,const gen & a_,const gen &b_,int n,int method,GIAC_CONTEXT){
5757     gen a(a_),b(b_);
5758     if (a.is_symb_of_sommet(at_pnt))
5759       a=_abscisse(a,contextptr);
5760     if (b.is_symb_of_sommet(at_pnt))
5761       b=_abscisse(b,contextptr);
5762     gen dx=(b-a)/n,x0=a,xf=x0,fxf,A;
5763     if (method==_RECTANGLE_DROIT || method==_RECTANGLE_GAUCHE || method==_POINT_MILIEU){
5764       if (method==_RECTANGLE_DROIT)
5765 	xf=a+dx;
5766       if (method==_POINT_MILIEU)
5767 	xf=a+dx/2;
5768       for (int i=0;i<n;++i){
5769 	fxf=evalf(quotesubst(f,x,xf,contextptr),1,contextptr);
5770 	A=A+dx*fxf;
5771 	xf=xf+dx;
5772       }
5773       return A;
5774     }
5775     if (method==_TRAPEZE){
5776       fxf=evalf(quotesubst(f,x,a,contextptr),1,contextptr);
5777       A=dx*fxf/2;
5778       xf=a+dx;
5779       for (int i=0;i<n-1;++i){
5780 	fxf=evalf(quotesubst(f,x,xf,contextptr),1,contextptr);
5781 	A=A+dx*fxf;
5782 	xf=xf+dx;
5783       }
5784       fxf=evalf(quotesubst(f,x,b,contextptr),1,contextptr);
5785       A=A+dx*fxf/2;
5786       return A;
5787     }
5788     if (method==_SIMPSON){
5789       fxf=evalf(quotesubst(f,x,a,contextptr),1,contextptr);
5790       A = dx*fxf/6;
5791       xf = a+dx;
5792       x0 = a+dx/2;
5793       for (int i=0;i<n-1;++i){
5794 	fxf=evalf(quotesubst(f,x,x0,contextptr),1,contextptr);
5795 	A += 2*dx*fxf/3;
5796 	fxf=evalf(quotesubst(f,x,xf,contextptr),1,contextptr);
5797 	A += dx*fxf/3;
5798 	x0 += dx;
5799 	xf += dx;
5800       }
5801       fxf=evalf(quotesubst(f,x,x0,contextptr),1,contextptr);
5802       A += 2*dx*fxf/3;
5803       fxf=evalf(quotesubst(f,x,b,contextptr),1,contextptr);
5804       A += dx*fxf/6;
5805       return A;
5806     }
5807     if (method==_ROMBERGM)
5808       return rombergo(f,x,a,b,n,contextptr);
5809     if (method==_ROMBERGT)
5810       return rombergt(f,x,a,b,n,contextptr);
5811     return evalf_int(f,x,a,b,epsilon(contextptr),n,false,contextptr);
5812   }
5813 
_aire(const gen & args,GIAC_CONTEXT)5814   gen _aire(const gen & args,GIAC_CONTEXT){
5815     if ( args.type==_STRNG && args.subtype==-1) return  args;
5816     if (args.type==_VECT && !args._VECTptr->empty() && args._VECTptr->front().is_symb_of_sommet(at_pnt) && args._VECTptr->back().is_symb_of_sommet(at_pnt)){
5817       gen res=0;
5818       for (unsigned i=0;i<args._VECTptr->size();++i)
5819 	res += _aire((*args._VECTptr)[i],contextptr);
5820       return res;
5821     }
5822     gen g=args;
5823     if (g.is_symb_of_sommet(at_equal)){
5824       g=_cercle(g,contextptr);
5825       if (g.type==_VECT && !g._VECTptr->empty())
5826 	g=g._VECTptr->front();
5827     }
5828     g=remove_at_pnt(g);
5829     if (g.is_symb_of_sommet(at_cercle)){
5830       gen centre,rayon;
5831       if (!centre_rayon(g,centre,rayon,false,contextptr))
5832 	return gensizeerr(contextptr);
5833       if (g._SYMBptr->feuille.type==_VECT && g._SYMBptr->feuille._VECTptr->size()>=3)
5834 	return normal(((*g._SYMBptr->feuille._VECTptr)[2]-(*g._SYMBptr->feuille._VECTptr)[1])*(rayon*conj(rayon,contextptr))/2,contextptr);
5835       return cst_pi*normal(rayon*conj(rayon,contextptr),contextptr);
5836     }
5837     if (g.is_symb_of_sommet(at_curve)){
5838       gen f=g._SYMBptr->feuille;
5839       if (f.type==_VECT && !f._VECTptr->empty())
5840 	f=f._VECTptr->front();
5841       if (f.type==_VECT && f._VECTptr->size()>=4){
5842 	vecteur v=*f._VECTptr;
5843 #if 0
5844 	// workaround for ellipse because plotparam does evalf on range
5845 	if (is_zero(v[2]))
5846 	  v[2]=zero;
5847 	if (v[3].type==_DOUBLE_ && v[3]==2*M_PI)
5848 	  v[3]=cst_two_pi;
5849 #endif
5850 	gen x,y;
5851 	reim(v[0],x,y,contextptr);
5852 	y=-y*derive(x,v[1],contextptr);
5853 	return _integrate(makesequence(y,v[1],v[2],v[3]),contextptr);
5854       }
5855     }
5856     if (g.type!=_VECT || g.subtype==_POINT__VECT || g._VECTptr->empty())
5857       return 0; // so that a single point has area 0
5858     vecteur v=*g._VECTptr;
5859     int s=int(v.size());
5860     v[0]=remove_at_pnt(v[0]);
5861     if (s==3 && v[0].is_symb_of_sommet(at_curve)){
5862       v[1]=symb_interval(v[1],v[2]);
5863       v.pop_back();
5864       --s;
5865     }
5866     // search for a numeric integration method
5867     if (s==2 && (v[1].is_symb_of_sommet(at_equal) || v[1].is_symb_of_sommet(at_interval)) ){
5868       gen f(v[0]),x(vx_var),tmp(v[1]),a,b;
5869       if (tmp.is_symb_of_sommet(at_equal) && tmp._SYMBptr->feuille.type==_VECT && tmp._SYMBptr->feuille._VECTptr->size()==2){
5870 	x=tmp._SYMBptr->feuille[0];
5871 	tmp=tmp._SYMBptr->feuille[1];
5872       }
5873       if (tmp.is_symb_of_sommet(at_interval) && tmp._SYMBptr->feuille.type==_VECT && tmp._SYMBptr->feuille._VECTptr->size()==2){
5874 	a=tmp._SYMBptr->feuille[0];
5875 	b=tmp._SYMBptr->feuille[1];
5876 	if (f.is_symb_of_sommet(at_curve)){
5877 	  f=f._SYMBptr->feuille;
5878 	  if (f.type!=_VECT || f._VECTptr->empty())
5879 	    return gensizeerr();
5880 	  f=f._VECTptr->front();
5881 	  if (f.type==_VECT && f._VECTptr->size()>1){
5882 	    gen r,i;
5883 	    reim(f._VECTptr->front(),r,i,contextptr);
5884 	    x=(*f._VECTptr)[1];
5885 	    f=i*derive(r,x,contextptr);
5886 	    return _integrate(gen(makevecteur(f,x,a,b),_SEQ__VECT),contextptr);
5887 	  }
5888 	}
5889 	return _integrate(gen(makevecteur(f,x,a,b),_SEQ__VECT),contextptr);
5890       }
5891     }
5892     if (v[0].is_symb_of_sommet(at_curve))
5893       return gensizeerr(contextptr);
5894     if (s>3){
5895       for (int i=0;i<s;++i){
5896 	if (v[i].type==_INT_ && v[i].subtype==_INT_SOLVER){
5897 	  int method=v[i].val,n;
5898 	  v.erase(v.begin()+i);
5899 	  v[2]=_floor(v[2],contextptr);
5900 	  if (v[2].type!=_INT_)
5901 	    return gensizeerr(gettext("area(f(x),x=a..b,n,method])"));
5902 	  n=v[2].val;
5903 	  gen f(v[0]),x(vx_var),tmp(v[1]),a,b;
5904 	  if (tmp.is_symb_of_sommet(at_equal) && tmp._SYMBptr->feuille.type==_VECT && tmp._SYMBptr->feuille._VECTptr->size()==2){
5905 	    x=tmp._SYMBptr->feuille[0];
5906 	    tmp=tmp._SYMBptr->feuille[1];
5907 	  }
5908 	  if (tmp.is_symb_of_sommet(at_interval) && tmp._SYMBptr->feuille.type==_VECT && tmp._SYMBptr->feuille._VECTptr->size()==2){
5909 	    a=tmp._SYMBptr->feuille[0];
5910 	    b=tmp._SYMBptr->feuille[1];
5911 	  }
5912 	  else
5913 	    return gensizeerr(gettext("area(f(x),x=a..b,n,method])"));
5914 	  return approx_area(f,x,a,b,n,method,contextptr);
5915 	}
5916       }
5917     }
5918     if (s<3)
5919       return undef;
5920     if (v.front()!=v.back()){
5921       ++s;
5922       v.push_back(v.front());
5923     }
5924     gen res;
5925     for (int i=3;i<s;++i){
5926       gen cote1(v[i-2]-v[0]),cote2(v[i-1]-v[0]);
5927       if (cote1.type==_VECT && cote2.type==_VECT)
5928 	res += l2norm(cross(*cote1._VECTptr,*cote2._VECTptr,contextptr),contextptr);
5929       else
5930 	res += im(cote2,contextptr)*re(cote1,contextptr)-re(cote2,contextptr)*im(cote1,contextptr);
5931     }
5932     return recursive_normal(res/2,contextptr);
5933   }
5934   static const char _aire_s []="area";
5935   static define_unary_function_eval (__aire,&_aire,_aire_s);
5936   define_unary_function_ptr5( at_aire ,alias_at_aire,&__aire,0,true);
5937 
_perimetre(const gen & args,GIAC_CONTEXT)5938   gen _perimetre(const gen & args,GIAC_CONTEXT){
5939     if ( args.type==_STRNG && args.subtype==-1) return  args;
5940     gen g=args;
5941     if (g.is_symb_of_sommet(at_equal)){
5942       g=_cercle(g,contextptr);
5943       if (g.type==_VECT && !g._VECTptr->empty())
5944 	g=g._VECTptr->front();
5945     }
5946     g=remove_at_pnt(g);
5947     if (g.is_symb_of_sommet(at_cercle)){
5948       gen centre,rayon;
5949       if (!centre_rayon(g,centre,rayon,true,contextptr))
5950 	return gensizeerr(contextptr);
5951       if (g._SYMBptr->feuille.type==_VECT && g._SYMBptr->feuille._VECTptr->size()>=3)
5952 	return recursive_normal(((*g._SYMBptr->feuille._VECTptr)[2]-(*g._SYMBptr->feuille._VECTptr)[1])*rayon,contextptr);
5953       return recursive_normal(cst_two_pi*rayon,contextptr);
5954     }
5955     if (g.is_symb_of_sommet(at_curve)){ // -> arclen
5956       gen f=g._SYMBptr->feuille;
5957       if (f.type==_VECT && !f._VECTptr->empty())
5958 	f=f._VECTptr->front();
5959       if (f.type==_VECT && f._VECTptr->size()>=4){
5960 	vecteur v=*f._VECTptr;
5961 	gen x,y;
5962 	reim(v[0],x,y,contextptr);
5963 	y=derive(y,v[1],contextptr);
5964 	x=derive(x,v[1],contextptr);
5965 	return _integrate(makesequence(symbolic(at_sqrt,x*x+y*y),v[1],v[2],v[3]),contextptr);
5966       }
5967     }
5968     if (g.type!=_VECT)
5969       return undef;
5970     vecteur v=*g._VECTptr;
5971     int s=int(v.size());
5972     if (s<3)
5973       return undef;
5974     if (v.front()!=v.back()){
5975       ++s;
5976       v.push_back(v.front());
5977     }
5978     gen res;
5979     for (int i=0;i<s-1;++i){
5980       res = res + sqrt(distance2pp(v[i],v[i+1],contextptr),contextptr);
5981     }
5982     return recursive_normal(res,contextptr);
5983   }
5984   static const char _perimetre_s []="perimeter";
5985   static define_unary_function_eval (__perimetre,&_perimetre,_perimetre_s);
5986   define_unary_function_ptr5( at_perimetre ,alias_at_perimetre,&__perimetre,0,true);
5987 
5988   // angle accepts an optionnal last argument as a string
5989   // for legends, if the string has a terminal =, the value of
5990   // the angle is added to the legend
angle(const vecteur & v1,const vecteur & v2,GIAC_CONTEXT)5991   gen angle(const vecteur & v1,const vecteur & v2,GIAC_CONTEXT){
5992     return acos(simplify(dotvecteur(v1,v2)/sqrt(dotvecteur(v1,v1)*dotvecteur(v2,v2),contextptr),contextptr),contextptr);
5993   }
5994 
_angle(const gen & args,GIAC_CONTEXT)5995   gen _angle(const gen & args,GIAC_CONTEXT){
5996     if ( args.type==_STRNG && args.subtype==-1) return  args;
5997     if ( (args.type!=_VECT) || args.subtype!=_SEQ__VECT || (args._VECTptr->size()<2))
5998       return arg(simplify(remove_at_pnt(args),contextptr),contextptr);
5999     vecteur v(*args._VECTptr);
6000     vecteur attributs(1,default_color(contextptr));
6001     int s=read_attributs(v,attributs,contextptr);
6002     v=vecteur(v.begin(),v.begin()+s);
6003     bool montrer=attributs.size()>1;
6004     string legende;
6005     if (montrer)
6006       legende=gen2string(attributs[1]);
6007     if (v.back().type==_STRNG){
6008       legende=*v.back()._STRNGptr;
6009       v.pop_back();
6010       montrer=true;
6011     }
6012     if (v.size()<2)
6013       return gensizeerr(contextptr);
6014     gen e=v.front(),f=v[1],g;
6015     e=remove_at_pnt(e);
6016     f=remove_at_pnt(f);
6017     if (e.type==_VECT && e.subtype==_GGBVECT && f.type==_VECT && f.subtype==_GGBVECT){
6018       if (e._VECTptr->size()==2 && f._VECTptr->size()==2)
6019 	return arg((f._VECTptr->front()+cst_i*f._VECTptr->back())/
6020 		   (e._VECTptr->front()+cst_i*e._VECTptr->back()),contextptr);
6021       return angle(*e._VECTptr,*f._VECTptr,contextptr);
6022     }
6023     if (f.type==_VECT && f.subtype==_VECTOR__VECT && f._VECTptr->size()==2){
6024       g=f._VECTptr->back();
6025       f=f._VECTptr->front();
6026       if (e.type==_VECT && e.subtype==_VECTOR__VECT && e._VECTptr->size()==2){
6027 	g=g-f;
6028 	f=e._VECTptr->back()-e._VECTptr->front();
6029 	e=0;
6030       }
6031       v=makevecteur(e,f,g);
6032     }
6033     if (e.type==_VECT && e.subtype==_VECTOR__VECT && e._VECTptr->size()==2){
6034       g=f;
6035       f=e._VECTptr->back();
6036       e=e._VECTptr->front();
6037       v=makevecteur(e,f,g);
6038     }
6039     //grad
6040     int mode=get_mode_set_radian(contextptr);
6041     gen res;
6042     if (e.is_symb_of_sommet(at_hyperplan)){
6043       swapgen(e,f);
6044     }
6045     if (f.is_symb_of_sommet(at_hyperplan)){
6046       vecteur nf=hyperplan_normal(f);
6047       if (e.is_symb_of_sommet(at_hyperplan)){
6048 	vecteur ne=hyperplan_normal(e);
6049 	res=angle(nf,ne,contextptr);
6050       }
6051       else {
6052 	if (e.type!=_VECT || e._VECTptr->size()!=2)
6053 	  return gensizeerr(gettext("angle plan with unknown"));
6054 	gen de=e._VECTptr->back()-e._VECTptr->front();
6055 	if (de.type!=_VECT)
6056 	  return gensizeerr(contextptr);
6057 	res=angle(nf,*de._VECTptr,contextptr);
6058       }
6059     }
6060     else {
6061       if (e.type==_VECT && e._VECTptr->size()!=3){
6062 	if ((e._VECTptr->size()!=2) || (f._VECTptr->size()!=2))
6063 	  return gensizeerr(gettext("angle"));
6064 	if (e._VECTptr->front().type==_VECT
6065 	    // check added 12/8/2014 for angle(droite(y=x),droite(y=1-x),"")
6066 	    || (e.subtype==_LINE__VECT || e.subtype==_HALFLINE__VECT)
6067 	    ){
6068 	  vecteur w=inter(v.front(),v[1],0); // context does not apply for lines
6069 	  if (w.empty())
6070 	    return gensizeerr(gettext("Lines must intersect"));
6071 	  gen w0=remove_at_pnt(w.front());
6072 	  g=f._VECTptr->back();
6073 	  if (g==w0)
6074 	    g=f._VECTptr->front();
6075 	  f=e._VECTptr->back();
6076 	  if (f==w0)
6077 	    f=e._VECTptr->front();
6078 	  e=w0;
6079 	}
6080 	else {
6081 	  g=f._VECTptr->back()-f._VECTptr->front();
6082 	  f=e._VECTptr->back()-e._VECTptr->front();
6083 	  e=0;
6084 	}
6085       }
6086       else {
6087 	if (f.type==_VECT && f._VECTptr->size()!=3){
6088 	  if (f._VECTptr->size()!=2)
6089 	    return gensizeerr(gettext("angle"));
6090 	  if (v.size()==3){
6091 	    f=e+f._VECTptr->back()-f._VECTptr->front();
6092 	    g=remove_at_pnt(v[2]);
6093 	    if (g.type==_VECT && g._VECTptr->size()==2)
6094 	      g=e+g._VECTptr->back()-g._VECTptr->front();
6095 	  }
6096 	  else {
6097 	    g=f._VECTptr->back();
6098 	    f=f._VECTptr->front();
6099 	  }
6100 	}
6101 	else {
6102 	  if (v.size()!=3)
6103 	    return gensizeerr(gettext("angle"));
6104 	  g=remove_at_pnt(v[2]);
6105 	  if (g.type==_VECT && g._VECTptr->size()==2)
6106 	    g=e+g._VECTptr->back()-g._VECTptr->front();
6107 	}
6108       }
6109       if (e.type==_VECT && e._VECTptr->size()==3 && f.type==_VECT && f._VECTptr->size()==3 && g.type==_VECT && g._VECTptr->size()==3){
6110 	vecteur v1(*(f-e)._VECTptr),v2(*(g-e)._VECTptr);
6111 	res=angle(v1,v2,contextptr);
6112       }
6113       else
6114 	res=recursive_normal(arg(simplify(conj(f-e,contextptr)*(g-e),contextptr),contextptr),contextptr);
6115     }
6116     gen c,c2;
6117     montrer = montrer && f.type!=_VECT;
6118     if (montrer){
6119       gen ef=(f-e)/5,eg=(g-e)/5;
6120       // Show the angle on the figure, using an arc of circle
6121       if (is_zero(evalf(abs(res,contextptr)-cst_pi_over_2,1,contextptr),contextptr)){
6122 	gen ef_eg=abs(evalf(ef,1,contextptr)/evalf(eg,1,contextptr),contextptr);
6123 	if (is_greater(ef_eg,0.2,contextptr) && is_greater(5.0,ef_eg,contextptr)){
6124 	  ef_eg=sqrt(ef_eg,contextptr);
6125 	  ef=ef/ef_eg;
6126 	  eg=eg*ef_eg;
6127 	}
6128 	c=gen(makevecteur(e+ef,e+ef+eg,e+eg),_LINE__VECT);
6129       }
6130       else
6131 	c=symbolic(at_cercle,gen(makevecteur(makevecteur(e-ef,e+ef),0,res,1),_PNT__VECT));
6132       c=symb_pnt(c,attributs[0],contextptr);
6133       c2=gen(makevecteur(f,e,g),_LINE__VECT);
6134       c2=symb_pnt(c2,attributs[0],contextptr);
6135     }
6136     //grad
6137     if (mode){ //not radians
6138       gen resd;
6139       if (has_evalf(res,resd,1,contextptr)){
6140 	if(mode==1) //are we in degrees
6141 	  res= rad2deg_d*resd;
6142 	else
6143 	  res= rad2grad_d*resd;
6144       }
6145       angle_mode(mode,contextptr);
6146     }
6147     if (montrer && c.is_symb_of_sommet(at_pnt) && c._SYMBptr->feuille.type==_VECT && c._SYMBptr->feuille._VECTptr->size()==2){
6148       vecteur v=*c._SYMBptr->feuille._VECTptr;
6149       if (!legende.empty() && legende[legende.size()-1]=='=')
6150 	v.push_back(string2gen(legende+res.print(contextptr),false));
6151       else
6152 	v.push_back(string2gen(legende,false));
6153       c=symbolic(at_pnt,gen(v,_PNT__VECT));
6154       return gen(makevecteur(res,c,c2),_SEQ__VECT);
6155     }
6156     return res;
6157   }
6158   static const char _angle_s []="angle";
6159   static define_unary_function_eval (__angle,&_angle,_angle_s);
6160   define_unary_function_ptr5( at_angle ,alias_at_angle,&__angle,0,true);
6161 
is_near(const gen & a,const gen & b0,double eps,GIAC_CONTEXT)6162   static bool is_near(const gen & a,const gen & b0,double eps,GIAC_CONTEXT){
6163     gen b=b0;
6164     if (b.is_symb_of_sommet(at_hyperplan) || b.is_symb_of_sommet(at_animation))
6165       return false;
6166     if (b.type==_VECT){
6167       if (b.subtype==_VECTOR__VECT)
6168 	b.subtype=0;
6169       if (b.subtype==_POLYEDRE__VECT){
6170 	const_iterateur it=b._VECTptr->begin(),itend=b._VECTptr->end();
6171 	for (;it!=itend;++it){
6172 	  if (it->type==_VECT){ // *it is a face
6173 	    const_iterateur jt=it->_VECTptr->begin(),jtend=it->_VECTptr->end();
6174 	    // *jt is a polygone
6175 	    for (;jt!=jtend;++jt){
6176 	      if (is_near(a,*jt,eps,contextptr))
6177 		return true;
6178 	    }
6179 	  }
6180 	}
6181 	return false;
6182       }
6183       if (b.subtype!=_POINT__VECT && b._VECTptr->size()>6 ){
6184 	const_iterateur it=b._VECTptr->begin(),itend=b._VECTptr->end();
6185 	for (;it!=itend;++it){
6186 	  if (is_near(a,*it,eps,contextptr))
6187 	    return true;
6188 	}
6189 	return false;
6190       }
6191     }
6192     if (b.is_symb_of_sommet(at_curve) && b._SYMBptr->feuille.type==_VECT && b._SYMBptr->feuille._VECTptr->size()>1){
6193       gen tmp=(*b._SYMBptr->feuille._VECTptr)[1];
6194       return is_near(a,tmp,eps,contextptr);
6195     }
6196     if (b.is_symb_of_sommet(at_hypersurface) && b._SYMBptr->feuille.type==_VECT && b._SYMBptr->feuille._VECTptr->size()>=2){
6197       gen & b0=(*b._SYMBptr->feuille._VECTptr)[0];
6198       if (b0.type==_VECT && b0._VECTptr->size()>=5){
6199 	gen & b04=(*b0._VECTptr)[4];
6200 	if (b04.type==_VECT)
6201 	  return is_near(a,b04,eps,contextptr);
6202       }
6203       return false;
6204     }
6205     gen d;
6206 #ifndef NO_STDEXCEPT
6207     try {
6208 #endif
6209       d=distance2(a,b,contextptr).evalf_double(eval_level(contextptr),contextptr);
6210 #ifndef NO_STDEXCEPT
6211     }
6212     catch (std::runtime_error & ){
6213       last_evaled_argptr(contextptr)=NULL;
6214       // CERR  << error.what() << '\n';
6215       // *logptr(contextptr) << error.what() << '\n';
6216       return false;
6217     }
6218 #endif
6219     return d.type==_DOUBLE_ && d._DOUBLE_val<eps*eps;
6220   }
6221 
6222   // added protection
6223   // find neighboor points of p in a history vector v (distance < eps)
nearest_point(const vecteur & v,const gen & p,double eps,GIAC_CONTEXT)6224   vector<int> nearest_point(const vecteur & v,const gen & p,double eps,GIAC_CONTEXT){
6225     vector<int> res;
6226     gen pf=evalf(p,1,contextptr),qf;
6227     if (!lidnt(pf).empty())
6228       return res;
6229     const_iterateur it=v.begin(),itend=v.end();
6230 #ifndef NO_STDEXCEPT
6231     try {
6232 #endif
6233       for (int i=0;it!=itend;++it,++i){
6234 	vecteur w=gen2vecteur(*it);
6235 	const_iterateur jt=w.begin(),jtend=w.end();
6236 	for (;jt!=jtend;++jt){
6237 	  gen g=*jt;
6238 	  if ( (g.type==_SYMB) && equalposcomp(plot_sommets,g._SYMBptr->sommet) && !g.is_symb_of_sommet(at_parameter)){
6239 	    qf=remove_at_pnt(evalf(g,1,contextptr));
6240 	    if ( (qf.is_symb_of_sommet(at_curve) || qf.is_symb_of_sommet(at_hypersurface) || lidnt(qf).empty()) && is_near(pf,qf,eps,contextptr)){
6241 	      if (is_segment(qf))
6242 		res.insert(res.begin(),i);
6243               else
6244 		res.push_back(i);
6245 	      break;
6246 	    }
6247 	  }
6248 	}
6249       }
6250 #ifndef NO_STDEXCEPT
6251     } catch (std::runtime_error & e){
6252       last_evaled_argptr(contextptr)=NULL;
6253       *logptr(contextptr) << e.what() << '\n';
6254     }
6255 #endif
6256     return res;
6257   }
6258 
6259 #ifdef HAVE_SIGNAL_H_OLD
6260   extern bool signal_store; // if false then child sto is not signal to parent
6261 
6262   // used to signal an intermediate answer to the parent process
_signal(const gen & args,GIAC_CONTEXT)6263   gen _signal(const gen & args,GIAC_CONTEXT){
6264     if ( args.type==_STRNG && args.subtype==-1) return  args;
6265 #ifndef WIN32
6266     if (child_id) // must be a child process!
6267       return symbolic(at_signal,args);
6268 #endif
6269     gen args_evaled;
6270     try {
6271       args_evaled=args.eval(1,contextptr);
6272     }
6273     catch (std::runtime_error & error ){
6274       last_evaled_argptr(contextptr)=NULL;
6275       args_evaled = string2gen('"'+string(error.what())+'"');
6276     }
6277 #ifdef WIN32
6278     history_in(contextptr).push_back(symbolic(at_signal,args));
6279     history_out(contextptr).push_back(args_evaled);
6280 #ifdef WITH_GNUPLOT
6281     plot_instructions.push_back(args_evaled);
6282 #endif
6283     return args_evaled;
6284 #else // WIN32
6285     ofstream child_out(cas_sortie_name().c_str());
6286     archive(child_out,symbolic(at_signal,args),contextptr);
6287     archive(child_out,args_evaled,contextptr);
6288     child_out << messages_to_print << "ÿ" ;
6289     child_out.close();
6290     // CERR << "Signal reads " << res << '\n';
6291     return wait_parent();
6292 #endif // WIN32
6293   }
6294   static const char _signal_s []="signal";
6295   static define_unary_function_eval_quoted (__signal,&_signal,_signal_s);
6296   define_unary_function_ptr5( at_signal ,alias_at_signal,&__signal,_QUOTE_ARGUMENTS,true);
6297 #endif // HAVE_SIGNAL_H_OLD
6298 
gen2vecteur(const gen & args)6299   vecteur gen2vecteur(const gen & args){
6300     if (args.type==_VECT)
6301       return *args._VECTptr;
6302     else
6303       return vecteur(1,args);
6304   }
6305 #ifdef EMCC
6306 #include <emscripten.h>
6307 #endif
6308   // user input sent back to the parent process
6309   // Use a vector of format [message,default_value,variable,convert_to_string]
_click(const gen & args,GIAC_CONTEXT)6310   gen _click(const gen & args,GIAC_CONTEXT){
6311     if (interactive_op_tab && interactive_op_tab[3])
6312       return interactive_op_tab[3](args,contextptr);
6313     if ( args.type==_STRNG && args.subtype==-1) return  args;
6314     vecteur v(gen2vecteur(args));
6315     int vs=int(v.size());
6316     if (vs==1 && args.type==_STRNG){
6317       v.push_back(0);
6318       v.push_back(identificateur("_input_"));
6319       v.push_back(0);
6320       ++vs;
6321     }
6322     if (vs>1)
6323       v[1]=eval(v[1],contextptr);
6324     gen res;
6325 #if defined EMCC && !defined GIAC_GGB
6326     string mesg="Input\n";
6327     mesg += v[0].type==_STRNG?*v[0]._STRNGptr:v[0].print(contextptr);
6328     int i=EM_ASM_INT({
6329 	var msg = Pointer_stringify($0); // Convert message to JS string
6330 	var tst=prompt(msg,' ');
6331 	if (tst==null) return 0;
6332 	return allocate(intArrayFromString(tst), 'i8', ALLOC_NORMAL);
6333       }, mesg.c_str());
6334     if (i==0){ ctrl_c=interrupted=true; return undef; }
6335     char *ptr=(char *)i;
6336     string s(ptr);
6337     free(ptr);
6338     if (vs==4)
6339       res=string2gen(s,false);
6340     else
6341       res=gen(s,contextptr);
6342 #else
6343 #if 1 // def WIN32
6344 #ifdef FXCG // FIXME!
6345     res=PRGM_GetKey();
6346 #else
6347     COUT << "// " << args ;
6348     string s;
6349     CIN >> s;
6350     if (vs==4)
6351       res=string2gen(s,false);
6352     else
6353       res=gen(s,contextptr);
6354 #endif // FXCG
6355 #else
6356 #ifdef HAVE_SIGNAL_H_OLD
6357     if (child_id){
6358       COUT << "// " << args;
6359       string s;
6360       cin >> s;
6361       if (vs==4)
6362 	res=string2gen(s,false);
6363       else
6364 	res=gen(s,contextptr);
6365     }
6366     else {
6367       ofstream child_out(cas_sortie_name().c_str());
6368       gen e(symbolic(at_click,args));
6369       // CERR << "Archiving " << e << '\n';
6370       archive(child_out,e,contextptr);
6371       archive(child_out,e,contextptr);
6372       if ( (args.type==_VECT) && (args._VECTptr->empty()) )
6373 	child_out << "User input requested\n" << "ÿ" ;
6374       else
6375 	child_out << args << "ÿ" ;
6376       child_out.close();
6377       kill_and_wait_sigusr2();
6378       ifstream child_in(cas_entree_name().c_str());
6379       res= unarchive(child_in,contextptr);
6380       child_in.close();
6381       // CERR << "Click reads " << res << '\n';
6382     }
6383 #else // HAVE_SIGNAL_H_OLD
6384     return undef;
6385 #endif // HAVE_SIGNAL_H_OLD
6386 #endif //WIN32
6387 #endif // EMCC
6388     if (vs>2 && !is_zero(v[2],contextptr)){
6389       if (res.type==_VECT){
6390 	if (vs==4 && res._VECTptr->size()==2){
6391 	  vecteur tmp=*res._VECTptr;
6392 	  if (tmp[1].is_symb_of_sommet(at_sto)){
6393 	    gen f=tmp[1]._SYMBptr->feuille;
6394 	    if (f.type==_VECT && f._VECTptr->size()==2){
6395 	      tmp[1]=symb_sto(string2gen(f._VECTptr->front().print(contextptr),false),f._VECTptr->back());
6396 	      *logptr(contextptr) << tmp[1] << '\n';
6397 	      res=tmp;
6398 	    }
6399 	  }
6400 	}
6401 	return eval(res,contextptr);
6402       }
6403       else
6404 	return sto(res,v[2],contextptr);
6405     }
6406     else
6407       return res;
6408   }
6409   static const char _click_s []="click";
6410 #ifdef RTOS_THREADX
6411   define_unary_function_eval_index(1,__click,&_click,_click_s);
6412   // const unary_function_eval __click(1,&_click,_click_s);
6413 #else
6414   unary_function_eval __click(1,&_click,_click_s);
6415 #endif
6416   define_unary_function_ptr5( at_click ,alias_at_click,&__click,_QUOTE_ARGUMENTS,true);
6417 
make_VECTifnot_VECT(const gen & e)6418   static vecteur make_VECTifnot_VECT(const gen & e){
6419     if ((e.type==_VECT) && !e._VECTptr->empty())
6420       return *e._VECTptr;
6421     return makevecteur(e);
6422   }
6423 
in_parameter2point(const vecteur & v,GIAC_CONTEXT)6424   static gen in_parameter2point(const vecteur & v,GIAC_CONTEXT){
6425     // convert geometric object, parameter value to
6426     // a point on the geometric object
6427     gen res;
6428     if (v.size()<2) return gensizeerr(gettext("plot.cc/parameter2point"));
6429     gen t=v.back(); // was v[1], fixed for G:=plotfunc(1/t,t);element(G,t)
6430     gen v0=v[0];
6431     if (v0.type==_VECT && !v0._VECTptr->empty())
6432       v0=v0._VECTptr->front();
6433     gen geo_obj=remove_at_pnt(v0);
6434     gen attribut=default_color(contextptr);
6435     if (v0.is_symb_of_sommet(at_pnt) && v0._SYMBptr->feuille.type==_VECT && v0._SYMBptr->feuille._VECTptr->size()>1)
6436       attribut=(*v0._SYMBptr->feuille._VECTptr)[1];
6437     // geo_obj.type = _VECT (ligne brisee), _SYMB (at_cercle), symb_curve
6438     if (geo_obj.type==_VECT){
6439       vecteur ligne=*geo_obj._VECTptr;
6440       if (ligne.size()<2) return gensizeerr(gettext("plot.cc/parameter2point"));
6441       if (t.type!=_VECT && ligne.size()==2){
6442 	if ( (geo_obj.subtype==_GROUP__VECT || geo_obj.subtype==_HALFLINE__VECT) && is_positive(-t,contextptr))
6443 	  t=0;
6444 	if (geo_obj.subtype==_GROUP__VECT && is_greater(t,1,contextptr))
6445 	  t=1;
6446 	return symb_pnt(ligne[0]+t*(ligne[1]-ligne[0]),attribut,contextptr);
6447       }
6448       int n;
6449       if (t.type==_VECT)
6450 	{
6451 	  vecteur param=*t._VECTptr;
6452 	  if (param.size()<2) return gensizeerr(gettext("plot.cc/parameter2point"));
6453 	  if (param[0].type!=_INT_)
6454 	    {
6455 	      if (param[0].type!=_DOUBLE_) return gensizeerr(gettext("plot.cc/parameter2point"));
6456 	      n= (int)param[0].DOUBLE_val();
6457 	    } else n=param[0].val;
6458 	  t= param[1];
6459 	} else {
6460         t= t.evalf2double(1, contextptr);
6461         if (t.type!=_DOUBLE_) return gensizeerr(gettext("plot.cc/parameter2point"));
6462         n= (int)(t.DOUBLE_val());
6463         t= t-n;
6464       }
6465       if (n<0) return symb_pnt(ligne.front(),attribut,contextptr);
6466       if (n>=signed(ligne.size())-1) return symb_pnt(ligne.back(),attribut,contextptr);
6467       return symb_pnt(ligne[n]+t*(ligne[n+1]-ligne[n]),attribut,contextptr);
6468     }
6469     if ( (geo_obj.type==_SYMB) && (geo_obj._SYMBptr->sommet==at_cercle)){
6470       gen centre,rayon;
6471       if (!centre_rayon(geo_obj,centre,rayon,true,contextptr))
6472 	return gensizeerr(contextptr);
6473       return symb_pnt(centre+normal(rayon,contextptr)*exp(cst_i*t,contextptr),attribut,contextptr);
6474     }
6475     if ( (geo_obj.type==_SYMB) && (geo_obj._SYMBptr->sommet==at_curve)){
6476       vecteur w(*geo_obj._SYMBptr->feuille._VECTptr->front()._VECTptr);
6477       gen w06=w[0];
6478       if (w.size()>6 && !is_undef(w[6]))
6479 	w06=w[6];
6480       gen res=_limit(makesequence(w06,w[1],t),contextptr);
6481       if (has_num_coeff(t))
6482 	res=evalf(res,1,contextptr);
6483       if (res.type==_VECT && res._VECTptr->size()==2)
6484 	res=res._VECTptr->front()+cst_i*res._VECTptr->back();
6485       return res;
6486     }
6487     return res;
6488   }
6489 
parameter2point(const vecteur & v,GIAC_CONTEXT)6490   gen parameter2point(const vecteur & v,GIAC_CONTEXT){
6491     gen res=in_parameter2point(v,contextptr);
6492     if (res.type==_VECT && res._VECTptr->size()==3)
6493       res.subtype=_POINT__VECT;
6494     return res;
6495   }
element(const gen & args,vecteur & attributs,GIAC_CONTEXT)6496   static gen element(const gen & args,vecteur & attributs,GIAC_CONTEXT){
6497     if ( args.type==_SYMB && args._SYMBptr->sommet==at_interval )
6498       return symbolic(at_parameter,args);
6499     if ( args.type==_VECT && args._VECTptr->size()>=2 ){
6500       vecteur & v=*args._VECTptr;
6501       if (v.front().type==_SYMB && v.front()._SYMBptr->sommet==at_interval){
6502 	vecteur w=gen2vecteur(v.front()._SYMBptr->feuille);
6503 	w=mergevecteur(w,vecteur(v.begin()+1,v.end()));
6504 	return symbolic(at_parameter,gen(w,_SEQ__VECT));
6505       }
6506     }
6507     gen a(args);
6508     vecteur v(make_VECTifnot_VECT(a));
6509     if (args.type==_VECT){
6510       v=(*a._VECTptr);
6511       if (v.empty())
6512 	return gensizeerr(contextptr);
6513       if ( (v.front().type==_VECT) && (v.front()._VECTptr->size()) )
6514 	v.front()=v.front()._VECTptr->front();
6515       if ( (v.front().type!=_SYMB) || (v.front()._SYMBptr->sommet!=at_pnt))
6516 	v=make_VECTifnot_VECT(v.front());
6517     }
6518     if (v.size()==1)
6519       v.push_back(plus_one_half);
6520     if (v[1].is_symb_of_sommet(at_pnt))
6521       v[1]=plus_one_half;
6522     gen s=remove_at_pnt(parameter2point(v,contextptr));
6523     if (is_undef(s))
6524       return s;
6525     gen color=default_color(contextptr);
6526     if (!attributs.empty())
6527       color=attributs[0];
6528     vecteur tmp=makevecteur(s,makevecteur(color,v));
6529     if (attributs.size()>1)
6530       tmp.push_back(attributs[1]);
6531     return symbolic(at_pnt,gen(tmp,_PNT__VECT)); // 0 instead of FL_BLACK
6532   }
_element(const gen & args,GIAC_CONTEXT)6533   gen _element(const gen & args,GIAC_CONTEXT){
6534     if ( args.type==_STRNG && args.subtype==-1) return  args;
6535     vecteur attributs(1,default_color(contextptr));
6536     vecteur v(seq2vecteur(args));
6537     gen g;
6538     int s=read_attributs(v,attributs,contextptr);
6539     if (!s)
6540       return gendimerr(contextptr);
6541     if (s==1 && (args.type!=_VECT || args.subtype==_SEQ__VECT))
6542       g=v.front();
6543     else
6544       g=gen(vecteur(v.begin(),v.begin()+s),_SEQ__VECT);
6545     return element(g,attributs,contextptr);
6546   }
6547   static const char _element_s []="element";
6548   static define_unary_function_eval (__element,&_element,_element_s);
6549   define_unary_function_ptr5( at_element ,alias_at_element,&__element,0,true);
6550 
6551   // returns res as a local bloc
6552   // def_x is the definition of x as read from history
reeval_with_1arg_quoted(const gen & x,gen & res,gen & def_x,GIAC_CONTEXT)6553   static bool reeval_with_1arg_quoted(const gen & x,gen & res,gen & def_x,GIAC_CONTEXT){
6554     // CERR << x << " " << res << " " << history_in(contextptr) << '\n';
6555     // find first occurence of storing something in x in the history
6556     def_x=undef;
6557     const_iterateur it0=history_in(contextptr).begin()-1,itend=history_in(contextptr).end(),itpos,it;
6558     it=itend-1;
6559     vecteur localvars;
6560     for (;;--it){
6561       if (it==it0)
6562 	return false; // setsizeerr();
6563       // CERR << *it << " " << x << '\n';
6564       if ( (it->type==_SYMB) && (it->_SYMBptr->sommet==at_sto) ){
6565 	if (it->_SYMBptr->feuille._VECTptr->back()==x){
6566 	  def_x=it->_SYMBptr->feuille._VECTptr->front();
6567 	  break;
6568 	}
6569       }
6570     }
6571     ++it;
6572     itpos=it;
6573     // CERR << "Position " << itpos-history_in(contextptr).begin() << '\n';
6574     for (;it!=itend;++it){
6575       // CERR << *it << " " << x << '\n';
6576       if ( (it->type==_SYMB) && (it->_SYMBptr->sommet==at_sto) ){
6577 	if (it->_SYMBptr->feuille._VECTptr->back()==res)
6578 	  break;
6579 	if (it->_SYMBptr->feuille._VECTptr->back().type==_IDNT)
6580 	  localvars.push_back(it->_SYMBptr->feuille._VECTptr->back());
6581       }
6582     }
6583     if (it==itend)
6584       return false; // setsizeerr();
6585     ++it;
6586     vecteur prog(itpos,it);
6587     prog.back()=symbolic(at_return,(it-1)->_SYMBptr->feuille._VECTptr->front());
6588     res=symb_local(gen(localvars,_SEQ__VECT),prog,contextptr);
6589     return true;
6590   }
6591 
_as_function_of(const gen & args,GIAC_CONTEXT)6592   gen _as_function_of(const gen & args,GIAC_CONTEXT){
6593     if ( args.type==_STRNG && args.subtype==-1) return  args;
6594     if ( rpn_mode(contextptr) || (args.type!=_VECT) || (args._VECTptr->size()!=2) || (args._VECTptr->back().type!=_IDNT) )
6595       return symbolic(at_as_function_of,args);
6596     gen res=args._VECTptr->front();
6597     gen x=args._VECTptr->back(),def_x;
6598     if (!reeval_with_1arg_quoted(x,res,def_x,contextptr))
6599       return gensizeerr(contextptr);
6600     return symb_program(x,zero,res,contextptr);
6601   }
6602   static const char _as_function_of_s []="as_function_of";
6603   static define_unary_function_eval_quoted (__as_function_of,&_as_function_of,_as_function_of_s);
6604   define_unary_function_ptr5( at_as_function_of ,alias_at_as_function_of,&__as_function_of,_QUOTE_ARGUMENTS,true);
6605 
6606   // equation f -> geometric object g
6607   // allowed 1 lines
6608   // 2 lines and circles
6609   // >2 all conics
equation2geo2d(const gen & f0,const gen & x,const gen & y,gen & g,double tmin,double tmax,double tstep,const gen & pointon,int allowed,const context * contextptr)6610   static bool equation2geo2d(const gen & f0,const gen & x,const gen & y,gen & g,double tmin,double tmax,double tstep,const gen & pointon,int allowed,const context * contextptr){
6611     gen f=_fxnd(remove_equal(f0),contextptr)._VECTptr->front();
6612     gen eq=subst(f,makevecteur(x,y),makevecteur(x__IDNT_e,y__IDNT_e),false,contextptr);
6613     if (!lop(f,at_abs).empty() || !lop(f,at_sign).empty())
6614       return false;
6615     gen fx(derive(f,x,contextptr)),fy(derive(f,y,contextptr));
6616     bool fx0=is_zero(fx,contextptr),fy0=is_zero(fy,contextptr);
6617     if (fx0 && fy0)
6618       return false;
6619     gen fxx(derive(fx,x,contextptr)),fxy(derive(fx,y,contextptr)),fyy(derive(fy,y,contextptr));
6620     if (is_undef(fx)||is_undef(fy) || is_undef(fxx) || is_undef(fxy) || is_undef(fyy))
6621       return false;
6622     if (is_zero(derive(fxx,x,contextptr),contextptr) && is_zero(derive(fxy,x,contextptr),contextptr) && is_zero(derive(fyy,x,contextptr),contextptr) && is_zero(derive(fxx,y,contextptr),contextptr) && is_zero(derive(fxy,y,contextptr),contextptr) && is_zero(derive(fyy,y,contextptr),contextptr) ){
6623       vecteur vxy(makevecteur(x,y)),v0(2,0);
6624       gen c=ratnormal(subst(f,vxy,v0,false,contextptr),contextptr);
6625       fxx=ratnormal(fxx,contextptr); fyy=ratnormal(fyy,contextptr);
6626       fxy=ratnormal(fxy,contextptr);
6627       if (is_zero(fxy,contextptr)){
6628 	if (is_zero(fxx,contextptr) && is_zero(fyy,contextptr)){
6629 	  gen d=gcd(fx,fy);
6630 	  fx=normal(fx/d,contextptr); fy=normal(fy/d,contextptr); c=normal(c/d,contextptr);
6631 #ifndef GIAC_HAS_STO_38
6632 	  *logptr(contextptr) << gettext("Line ") << fx*x+fy*y+c<< "=0" << '\n';
6633 #endif
6634 	  // line
6635 	  if (fy0){
6636 	    gen tmp=ratnormal(-c/fx,contextptr);
6637 	    g=gen(makevecteur(tmp,tmp+cst_i),_LINE__VECT);
6638 	  }
6639 	  else {
6640 	    gen tmp=ratnormal(-c/fy,contextptr);
6641 	    g=gen(makevecteur(tmp*cst_i,tmp*cst_i+fy-fx*cst_i),_LINE__VECT);
6642 	  }
6643 	  return true;
6644 	} // fxx==0 && fyy==0
6645 	if (allowed<=1) return false;
6646 	if (is_zero(fxx-fyy,contextptr)){
6647 	  fx=ratnormal(subst(fx,vxy,v0,false,contextptr),contextptr);
6648 	  fy=ratnormal(subst(fy,vxy,v0,false,contextptr),contextptr);
6649 	  if (is_positive(-fxx,contextptr)){
6650 	    fxx=-fxx; fx=-fx; fy=-fy; c=-c;
6651 	  }
6652 	  // f=fxx/2 (x^2 + y^2) + fx*x + fy*y + c=0
6653 	  // x^2 + y^2 + 2fx/fxx*x + 2fy/fxx*y + 2c/fxx
6654 	  // (x+fx/fxx)^2 + (y+fy/fxx)^2 = (fx^2+fy^2- 2c fxx)/fxx^2
6655 	  gen centre=ratnormal(-(fx+cst_i*fy)/fxx,contextptr);
6656 	  gen rayon2( ratnormal((fx*fx+fy*fy-2*c*fxx)/(fxx*fxx),contextptr) );
6657 	  if (is_strictly_positive(-rayon2,contextptr)){
6658 	    g=vecteur(0);
6659 	    return true;
6660 	  }
6661 	  gen rayon(recursive_normal(sqrt(rayon2,contextptr),contextptr));
6662 	  g=symbolic(at_cercle,gen(makevecteur(gen(makevecteur(centre-rayon,centre+rayon),_GROUP__VECT),0,cst_two_pi),_PNT__VECT));
6663 	  return true;
6664 	}
6665       }
6666       if (allowed<=2) return false;
6667       // conique
6668       gen x0,y0,propre,equation_reduite,ratparam;
6669       vecteur V0,V1,param_curves;
6670       if (!conique_reduite(eq,pointon,makevecteur(x__IDNT_e,y__IDNT_e),x0,y0,V0,V1,propre,equation_reduite,param_curves,ratparam,true,contextptr))
6671 	return false;
6672       vecteur res;
6673       int n=int(param_curves.size());
6674       for (int i=0;i<n;++i){
6675 	gen & obj=param_curves[i];
6676 	if (obj.type==_VECT){
6677 	  vecteur & objv=*obj._VECTptr;
6678 	  int s=int(objv.size());
6679 	  if (s==2)
6680 	    res.push_back(obj);
6681 	  if (s>=5){
6682 	    gen tmp=paramplotparam(gen(objv,_SEQ__VECT),false,contextptr);
6683 	    res.push_back(remove_at_pnt(tmp));
6684 	  }
6685 	}
6686 	else
6687 	  res.push_back(obj);
6688       }
6689       g= (res.size()==1)? res.front() : res; // gen(res,_SEQ__VECT);
6690       return true;
6691     }
6692     return false;
6693   }
6694 
find_curve_parametrization(const gen & geo_obj,gen & m,const gen & gen_t,double T,gen & tmin,gen & tmax,bool tminmax_defined,GIAC_CONTEXT)6695   bool find_curve_parametrization(const gen & geo_obj,gen & m,const gen & gen_t,double T,gen & tmin,gen & tmax,bool tminmax_defined,GIAC_CONTEXT){
6696     if (gen_t.type!=_IDNT)
6697       return false;
6698     if (geo_obj.is_symb_of_sommet(at_cercle)){
6699       gen centre,rayon;
6700       if (!centre_rayon(geo_obj,centre,rayon,false,contextptr))
6701 	return false;
6702       m=centre+rayon*(1+cst_i*gen_t)/(1-cst_i*gen_t);
6703       if (!tminmax_defined){
6704 	tmin=-T;
6705 	tmax=T;
6706       }
6707     }
6708     if (geo_obj.is_symb_of_sommet(at_curve)){
6709       gen fg=geo_obj._SYMBptr->feuille;
6710       if (fg.type==_VECT && !fg._VECTptr->empty()){
6711 	fg=fg._VECTptr->front();
6712 	if (fg.type==_VECT && fg._VECTptr->size()>3){
6713 	  vecteur & fgv=*fg._VECTptr;
6714 	  if (!tminmax_defined){
6715 	    tmin=fgv[2]; tmax=fgv[3];
6716 	  }
6717 	  m=fgv[0];
6718 	  if (fgv.size()>6 && !is_undef(fgv[6])){
6719 	    tmin=-1e307;
6720 	    tmax=1e307;
6721 	    m=fgv[6];
6722 	  }
6723 	  m=subst(m,fgv[1],gen_t,false,contextptr);
6724 	  // Check for a conic: parametrization with cos(t)/sin(t) or cosh(t)/sinh(t)
6725 	  vecteur lv;
6726 	  rlvarx(m,gen_t,lv);
6727 	  if (lv.size()==3){
6728 	    lv=makevecteur(lv[0],lv[2]);
6729 	    bool deg=(equalposcomp(lidnt(lv),cst_pi))!=0;
6730 	    gen tg=gen_t;
6731 	    if (deg)
6732 	      tg=gen(180)/cst_pi*gen_t;
6733 	    vecteur sincost(makevecteur(symb_sin(tg),symb_cos(tg)));
6734 	    if (lv[0]==sincost[1])
6735 	      lv=makevecteur(lv[1],lv[0]);
6736 	    if (lv==sincost){
6737 	      gen t2p1=(1+gen_t*gen_t);
6738 	      m=subst(m,sincost,makevecteur(2*gen_t/t2p1,(1-gen_t*gen_t)/t2p1),false,contextptr);
6739 	      if (!tminmax_defined){
6740 		tmin=-T;
6741 		tmax=T;
6742 	      }
6743 	    }
6744 	    else {
6745 	      sincost=makevecteur(symb_sinh(gen_t),symb_cosh(gen_t));
6746 	      if (lv[0]==sincost[1])
6747 		lv=makevecteur(lv[1],lv[0]);
6748 	      if (lv==sincost){
6749 		m=subst(m,sincost,makevecteur((gen_t-inv(gen_t,contextptr))/2,(gen_t+inv(gen_t,contextptr))/2),false,contextptr);
6750 		if (!tminmax_defined){
6751 		  tmin=-T;
6752 		  tmax=T;
6753 		}
6754 	      }
6755 	    }
6756 	  }
6757 	}
6758 	else
6759 	  return false;
6760       }
6761     }
6762     if (geo_obj.type==_VECT && geo_obj._VECTptr->size()>2){
6763       tmin=0;
6764       tmax=int(geo_obj._VECTptr->size()-1);
6765     }
6766     if (geo_obj.type==_VECT && geo_obj._VECTptr->size()==2){
6767       m=geo_obj._VECTptr->front()+gen_t*(geo_obj._VECTptr->back()-geo_obj._VECTptr->front());
6768       if (!tminmax_defined){
6769 	tmin=0;
6770 	tmax=1;
6771 	switch (geo_obj.subtype){
6772 	case _LINE__VECT:
6773 	  tmin=-T;
6774 	case _HALFLINE__VECT:
6775 	  tmax=T;
6776 	  break;
6777 	}
6778       }
6779     }
6780     return true;
6781   }
6782 
doublify(const gen & tmin,const gen & tmax,double T,double & tmin_d,double & tmax_d,GIAC_CONTEXT)6783   static bool doublify(const gen & tmin,const gen & tmax,double T,double & tmin_d,double & tmax_d,GIAC_CONTEXT){
6784     tmin_d=gnuplot_tmin;
6785     tmax_d=gnuplot_tmax;
6786     gen tmin1=evalf_double(tmin,1,contextptr), tmax1=evalf_double(tmax,1,contextptr);
6787     bool res=true;
6788     if (tmin1.type==_DOUBLE_)
6789       tmin_d=tmin1._DOUBLE_val;
6790     else
6791       res=false;
6792     if (tmax1.type==_DOUBLE_)
6793       tmax_d=tmax1._DOUBLE_val;
6794     else
6795       res=false;
6796     return res;
6797   }
6798 
read_tmintmaxtstep(vecteur & vargs,gen & t,int vstart,double & tmin,double & tmax,double & tstep,bool & tminmax_defined,bool & tstep_defined,GIAC_CONTEXT)6799   void read_tmintmaxtstep(vecteur & vargs,gen & t,int vstart,double &tmin,double & tmax,double &tstep,bool & tminmax_defined,bool & tstep_defined,GIAC_CONTEXT){
6800     tstep=gnuplot_tstep;
6801     tminmax_defined=false;
6802     tstep_defined=false;
6803     gen tmp;
6804     if (t.is_symb_of_sommet(at_equal)){
6805       readrange(t,gnuplot_tmin,gnuplot_tmax,tmp,tmin,tmax,contextptr);
6806       tminmax_defined=true;
6807       t=t._SYMBptr->feuille._VECTptr->front();
6808     }
6809     int vs=int(vargs.size());
6810     for (int i=vstart;i<vs;++i){
6811       if (readvar(vargs[i])==t){
6812 	readrange(vargs[i],gnuplot_tmin,gnuplot_tmax,tmp,tmin,tmax,contextptr);
6813 	tminmax_defined=true;
6814 	vargs.erase(vargs.begin()+i);
6815 	--vs;
6816 	--i;
6817       }
6818       if (vargs[i].is_symb_of_sommet(at_equal) && vargs[i]._SYMBptr->feuille.type==_VECT && vargs[i]._SYMBptr->feuille._VECTptr->front().type==_INT_){
6819 	gen n=vargs[i]._SYMBptr->feuille._VECTptr->back();
6820 	if (vargs[i]._SYMBptr->feuille._VECTptr->front().val==_TSTEP){
6821 	  n=evalf_double(n,1,contextptr);
6822 	  tstep=absdouble(n._DOUBLE_val);
6823 	  tstep_defined=true;
6824 	  vargs.erase(vargs.begin()+i);
6825 	  --vs;
6826 	  --i;
6827 	}
6828       }
6829     }
6830   }
6831 
_lieu(const gen & args,GIAC_CONTEXT)6832   gen _lieu(const gen & args,GIAC_CONTEXT){
6833     if ( args.type==_STRNG && args.subtype==-1) return  args;
6834     if ( rpn_mode(contextptr) || args.type!=_VECT  )
6835       return symbolic(at_lieu,args);
6836     vecteur attributs(1,default_color(contextptr));
6837     vecteur vargs=*args._VECTptr;
6838     int vs=read_attributs(vargs,attributs,contextptr);
6839     if (vs<2)
6840       return gendimerr(contextptr);
6841     vs=int(vargs.size());
6842     identificateur id_t("t_lieu");
6843     gen gen_t(id_t),m,tmin,tmax,tmp,prog;
6844     double T=1e300;
6845     double tstep;
6846     bool tminmax_defined,tstep_defined;
6847     double Tmin,Tmax;
6848     gen tcopy(t__IDNT_e);
6849     read_tmintmaxtstep(vargs,tcopy,2,Tmin,Tmax,tstep,tminmax_defined,tstep_defined,contextptr);
6850     if (tminmax_defined){
6851       tmin=Tmin; tmax=Tmax;
6852     }
6853 #ifdef HAVE_SIGNAL_H_OLD
6854     bool old_signal_store=signal_store;
6855     signal_store=false;
6856 #endif
6857     bool old_io_graph=io_graph(contextptr);
6858     io_graph(false,contextptr);
6859 #ifndef NO_STDEXCEPT
6860     try {
6861 #endif
6862       gen res=vargs[0];
6863       gen x=vargs[1],def_x;
6864       vecteur w;
6865       // x must eval to a parametric element of an object
6866       gen tt=x.eval(1,contextptr),N;
6867       // COUT << history_in(contextptr) << '\n' << history_out(contextptr) << '\n';
6868       if (tt.type==_IDNT){
6869 	// search back in history if tt is a parameter
6870 	const_iterateur it0=history_out(contextptr).begin()-1,itend=history_out(contextptr).end(),it;
6871 	it=itend-1;
6872 	for (;;--it){
6873 	  if (it==it0){ // no assume/element found for tt
6874 	    N=res.eval(1,contextptr);
6875 	    N=quotesubst(N,tt,gen_t,contextptr);
6876 	    tmin=gnuplot_tmin;
6877 	    tmax=gnuplot_tmax;
6878 	    tstep=gnuplot_tstep;
6879 	    break;
6880 	  }
6881 	  if (it->is_symb_of_sommet(at_parameter)){
6882 	    vecteur v=*it->_SYMBptr->feuille._VECTptr;
6883 	    if (v.size()>=4 && v[0]==tt){
6884 	      tmin=v[1];
6885 	      tmax=v[2];
6886 	      if (!tstep_defined && v.size()>=5){
6887 		tstep_defined=true;
6888 		tstep=evalf_double(v[4],1,contextptr)._DOUBLE_val;
6889 	      }
6890 	      tminmax_defined=true;
6891 	      N=res.eval(1,contextptr);
6892 	      N=quotesubst(N,tt,gen_t,contextptr);
6893 	      break;
6894 	    }
6895 	  }
6896 	} // end for
6897       }
6898       else {
6899 	if (!reeval_with_1arg_quoted(x,res,def_x,contextptr))
6900 	  return gensizeerr(contextptr);
6901 	prog=symb_program(x,zero,res,contextptr);
6902 	if ( (def_x.type==_SYMB) && (def_x._SYMBptr->sommet==at_element) ){
6903 	  gen e;
6904 	  if (def_x._SYMBptr->feuille.type==_VECT) {
6905 	    vecteur & v=*def_x._SYMBptr->feuille._VECTptr;
6906 	    if ( !v.empty() )
6907 	      e=v.front();
6908 	  }
6909 	  else
6910 	    e=def_x._SYMBptr->feuille;
6911 	  if ( (e.type==_SYMB) && (e._SYMBptr->sommet==at_interval)){
6912 	    gen tmin=e._SYMBptr->feuille._VECTptr->front().evalf_double(1,contextptr);
6913 	    gen tmax=e._SYMBptr->feuille._VECTptr->back().evalf_double(1,contextptr);
6914 	    if ( (tmin.type==_DOUBLE_) && (tmax.type==_DOUBLE_) ){
6915 	      // adjust tstep
6916 #ifdef RTOS_THREADX
6917 	      if (!tstep_defined)
6918 		tstep=(tmax._DOUBLE_val-tmin._DOUBLE_val)/10;
6919 #else
6920 	      if (!tstep_defined)
6921 		tstep=(tmax._DOUBLE_val-tmin._DOUBLE_val)/10;
6922 #endif
6923 	      vecteur p;
6924 	      double tmin_d=tmin._DOUBLE_val,tmax_d=tmax._DOUBLE_val;
6925 	      for (double t=tmin_d;t<tmax_d;t+=tstep){
6926 		p.push_back(remove_at_pnt(prog(t,contextptr)));
6927 	      }
6928 #ifdef HAVE_SIGNAL_H_OLD
6929 	      signal_store=old_signal_store;
6930 #endif
6931 	      io_graph(old_io_graph,contextptr);
6932 	      return pnt_attrib(gen(p,_GROUP__VECT),attributs,contextptr);
6933 	    }
6934 	  }
6935 	}
6936 	// type checking
6937 	if ( (tt.type!=_SYMB) || (tt._SYMBptr->sommet!=at_pnt) || (tt._SYMBptr->feuille.type!=_VECT) )
6938 	  return gensizeerr(contextptr);
6939 	vecteur v=*tt._SYMBptr->feuille._VECTptr;
6940 	gen t0=v[1];
6941 	if (t0.type!=_VECT)
6942 	  return gensizeerr(contextptr);
6943 	w=*t0._VECTptr;
6944 	t0=w[1];
6945 	if (t0.type!=_VECT)
6946 	  return gensizeerr(contextptr);
6947 	w=*t0._VECTptr; // w[0] is the parametric object=pnt( pnt[object,.] )
6948 	gen geo_obj=remove_at_pnt(w[0]);
6949 	// geo_obj.type = _VECT (ligne brisee), _SYMB (at_cercle), symb_curve
6950 	// for lines, circles or rational curves try to find exact object eq
6951 	// circle rational parametrization by center+radius*(1+it)/(1-it)
6952 	if (!find_curve_parametrization(geo_obj,m,gen_t,T,tmin,tmax,tminmax_defined,contextptr))
6953 	  return gensizeerr(gettext("Locus on an unknown parametric curve type"));
6954 	if (!is_zero(m,contextptr)){
6955 	  gen tmpg=giac_assume(makevecteur(gen_t,at_real),contextptr);
6956 	  if (is_undef(tmpg)) return tmpg;
6957 	  gen M=symbolic(at_pnt,gen(makevecteur(m,0),_PNT__VECT));
6958 	  if (tmin!=-T){
6959 	    if (tmax!=T)
6960 	      tmpg=giac_assume(symbolic(at_and,makevecteur(symb_superieur_egal(gen_t,tmin),
6961 							   symb_inferieur_egal(gen_t,tmax)))
6962 			       ,contextptr);
6963 	    else
6964 	      tmpg=giac_assume(symb_superieur_egal(gen_t,tmin),contextptr);
6965 	  }
6966 	  else {
6967 	    if (tmax!=T)
6968 	      tmpg=giac_assume(symb_inferieur_egal(gen_t,tmax),contextptr);
6969 	  }
6970 	  if (is_undef(tmpg)) return tmpg;
6971 	  N=prog(M,contextptr);
6972 	}
6973       }
6974       if (!is_zero(N,contextptr)){
6975 	N=ratnormal(exact(remove_at_pnt(N),contextptr),contextptr);
6976 	gen Nx,Ny,Nz;
6977 	if (N.type==_VECT && N._VECTptr->size()==2){
6978 	  // enveloppe, find equation of N as
6979 	  // a(t)*x + b(t)*y + c(t) = 0
6980 	  // M(t) = (x(t),y(t)) \in N + tangent at M(t) // N hence
6981 	  // a(t)*x + b(t)*y + c(t) = 0
6982 	  // a(t)*x'+ b(t)*y'=0
6983 	  // derive first equation: a'(t)*x+b'(t)*y+c'(t)=0
6984 	  // d=(a*b'-a'*b)
6985 	  // x=(b*c'-b'*c)/d, y=(a'*c-a*c')/d
6986 	  Nx=N._VECTptr->front();
6987 	  if (Nx.type==_VECT)
6988 	    return gensizeerr(gettext("3-d enveloppe not implemented"));
6989 	  gen ab(N._VECTptr->back()-Nx);
6990 	  gen a=im(ab,contextptr);
6991 	  // rewrite_with_t_real(a,gen_t,contextptr);
6992 	  gen b=-re(ab,contextptr);
6993 	  // rewrite_with_t_real(b,gen_t,contextptr);
6994 	  gen c=-(a*re(Nx,contextptr)+b*im(Nx,contextptr));
6995 	  // rewrite_with_t_real(c,gen_t,contextptr);
6996 	  gen ap(derive(a,gen_t,contextptr)),bp(derive(b,gen_t,contextptr)),cp(derive(c,gen_t,contextptr));
6997 	  if (is_undef(ap) || is_undef(bp) || is_undef(cp))
6998 	    return ap+bp+cp;
6999 	  gen d=a*bp-ap*b;
7000 	  Nx=ratnormal((b*cp-bp*c)/d,contextptr);
7001 	  Ny=ratnormal((ap*c-a*cp)/d,contextptr);
7002 	  N=Nx+cst_i*Ny;
7003 	}
7004 	else {
7005 	  if (N.type==_VECT && N._VECTptr->size()==3){
7006 	    Nx=N._VECTptr->front();
7007 	    Ny=(*N._VECTptr)[1];
7008 	    Nz=N._VECTptr->back();
7009 	  }
7010 	  else {
7011 	    Nx=re(N,contextptr);
7012 	    // rewrite_with_t_real(Nx,gen_t,contextptr);
7013 	    Ny=im(N,contextptr);
7014 	    // rewrite_with_t_real(Ny,gen_t,contextptr);
7015 	  }
7016 	}
7017 	purgenoassume(gen_t,contextptr);
7018 	if (lvarxpow(N,gen_t).size()==1){
7019 	  // print resultant
7020 	  gen x(identificateur("x")),y(identificateur("y")),z(identificateur("z"));
7021 	  gen lieu_eq(undef),geoobj,lieu_geo;
7022 	  if (is_zero(Nz,contextptr)){
7023 #if 1
7024 	    lieu_eq=_resultant(makevecteur(x-Nx,y-Ny,gen_t),contextptr);
7025 	    lieu_eq=_factor(lieu_eq,contextptr);
7026 #else
7027 	    gen tmp,numx,denx,numy,deny;
7028 	    tmp=_fxnd(Nx,contextptr);
7029 	    numx=tmp[0]; denx=tmp[1];
7030 	    tmp=_fxnd(Ny,contextptr);
7031 	    numy=tmp[0]; deny=tmp[1];
7032 	    lieu_eq=_resultant(makevecteur(x*denx-numx,y*deny-numy,gen_t),contextptr);
7033 	    lieu_eq=_factor(lieu_eq,contextptr);
7034 #endif
7035 #ifndef GIAC_HAS_STO_38
7036 	    *logptr(contextptr) << gettext("Equation 0 = ") << lieu_eq << '\n';
7037 #endif
7038 	  }
7039 	  // FIXME: recognize 3-d locus
7040 	  double tmin_d,tmax_d;
7041 	  if (!doublify(tmin,tmax,T,tmin_d,tmax_d,contextptr))
7042 	    return gensizeerr(contextptr);
7043 	  double tstep_d=tstep_defined?tstep:(tmax_d-tmin_d)/80;
7044 	  if (equation2geo2d(lieu_eq,x,y,geoobj,tmin_d,tmax_d,tstep_d,undef,3,contextptr)){
7045 	    vecteur lieu_vect;
7046 	    if (geoobj.type==_VECT && geoobj.subtype==_SEQ__VECT)
7047 	      lieu_vect=*geoobj._VECTptr;
7048 	    else
7049 	      lieu_vect=vecteur(1,geoobj);
7050 	    const_iterateur it=lieu_vect.begin(),itend=lieu_vect.end();
7051 	    vecteur resv;
7052 	    for (;it!=itend;++it){
7053 	      lieu_geo=*it;
7054 	      // Nx,Ny is on lieu_geo
7055 	      if (lieu_geo.type==_VECT && lieu_geo._VECTptr->size()==2){
7056 		gen N1(lieu_geo._VECTptr->front()),N2(lieu_geo._VECTptr->back());
7057 		int subt=_LINE__VECT;
7058 		if (tmin!=-T){
7059 		  N1=subst(Nx,gen_t,tmin,false,contextptr)+cst_i*subst(Ny,gen_t,tmin,false,contextptr);
7060 		  subt=_HALFLINE__VECT;
7061 		  if (tmax==T)
7062 		    N2=subst(Nx,gen_t,tmin+1,false,contextptr)+cst_i*subst(Ny,gen_t,tmin+1,false,contextptr);
7063 		}
7064 		if (tmax!=T){
7065 		  N2=subst(Nx,gen_t,tmax,false,contextptr)+cst_i*subst(Ny,gen_t,tmax,false,contextptr);
7066 		  subt=(subt==_HALFLINE__VECT)?_GROUP__VECT:_HALFLINE__VECT;
7067 		  if (tmax==-T)
7068 		    N1=subst(Nx,gen_t,tmax-1,false,contextptr)+cst_i*subst(Ny,gen_t,tmax-1,false,contextptr);
7069 		}
7070 		resv.push_back(pnt_attrib(gen(makevecteur(N1,N2),subt),attributs,contextptr));
7071 		continue;
7072 	      }
7073 	      if (lieu_geo.is_symb_of_sommet(at_cercle)){
7074 		// FIXME: find arc of circle if tmin/tmax = +/-T
7075 		resv.push_back(pnt_attrib(lieu_geo,attributs,contextptr));
7076 		continue;
7077 	      }
7078 	      resv.push_back(pnt_attrib(lieu_geo,attributs,contextptr));
7079 	    } // end for
7080 	    if (resv.size()==1)
7081 	      return resv.front();
7082 	    return resv; // gen(resv,_SEQ__VECT);
7083 	  } // end if equation2geo2d ...
7084 	}
7085 	if (tmax==T)
7086 	  tmax=gnuplot_tmax;
7087 	if (tmin==-T)
7088 	  tmin=gnuplot_tmin;
7089 	gen gtstep=tstep_defined?tstep:(tmax-tmin)/80;
7090 	gen ntstep(_TSTEP);
7091 	ntstep.subtype=_INT_PLOT;
7092 	return _plotparam(gen(makevecteur(N,symb_equal(gen_t,symb_interval(tmin,tmax)),symb_equal(ntstep,gtstep)),_SEQ__VECT),contextptr);
7093       }
7094       if (w.size()<2)
7095 	return gendimerr(contextptr);
7096       bool is_ligne_brisee=(w[1].type==_VECT);
7097       w[0]=w[0].evalf(1,contextptr);
7098       vecteur p;
7099       if (tmax==T)
7100 	tmax=10;
7101       if (tmax==-T)
7102 	tmin=-10;
7103       double tmin_d,tmax_d;
7104       if (!doublify(tmin,tmax,T,tmin_d,tmax_d,contextptr))
7105 	return gensizeerr(contextptr);
7106       double tstep_d=tstep_defined?tstep:(tmax_d-tmin_d)/80;
7107       for (double t=tmin_d;t<=tmax_d;t+=tstep_d){
7108 	if (is_ligne_brisee)
7109 	  w[1]._VECTptr->back()=t;
7110 	else
7111 	  w[1]=t;
7112 	gen tmp=prog(parameter2point(w,contextptr),contextptr);
7113 	if (is_undef(tmp))
7114 	  continue;
7115 	// makes lieu easier if the image is a line intersection
7116 	if (tmp.type==_VECT && tmp._VECTptr->size()==1)
7117 	  tmp=tmp._VECTptr->front();
7118 	p.push_back(remove_at_pnt(tmp));
7119       }
7120 #ifdef HAVE_SIGNAL_H_OLD
7121       signal_store=old_signal_store;
7122 #endif
7123       io_graph(old_io_graph,contextptr);
7124       return pnt_attrib(gen(p,_GROUP__VECT),attributs,contextptr);
7125 #ifndef NO_STDEXCEPT
7126     }
7127     catch (std::runtime_error & e){
7128       last_evaled_argptr(contextptr)=NULL;
7129 #ifdef HAVE_SIGNAL_H_OLD
7130       signal_store=old_signal_store;
7131 #endif
7132       io_graph(old_io_graph,contextptr);
7133       throw(std::runtime_error(e.what()));
7134     }
7135 #endif
7136   }
7137   static const char _lieu_s []="locus";
7138   static define_unary_function_eval_quoted (__lieu,&_lieu,_lieu_s);
7139   define_unary_function_ptr5( at_lieu ,alias_at_lieu,&__lieu,_QUOTE_ARGUMENTS,true);
7140 
_head(const gen & args,GIAC_CONTEXT)7141   gen _head(const gen & args,GIAC_CONTEXT){
7142     if ( args.type==_STRNG && args.subtype==-1) return  args;
7143     if (args.type==_STRNG){
7144       string & s =*args._STRNGptr;
7145       int l=int(s.size());
7146       if (!l)
7147 	return args;
7148       return string2gen(s.substr(0,1),false);
7149     }
7150     if (args.type!=_VECT)
7151       return args;
7152     if (args._VECTptr->size())
7153       return args._VECTptr->front();
7154     else
7155       return args;
7156   }
7157   static const char _head_s []="head";
7158   static define_unary_function_eval (__head,&_head,_head_s);
7159   define_unary_function_ptr5( at_head ,alias_at_head,&__head,0,true);
7160 
_tail(const gen & args,GIAC_CONTEXT)7161   gen _tail(const gen & args,GIAC_CONTEXT){
7162     if ( args.type==_STRNG && args.subtype==-1) return  args;
7163     if (args.type==_STRNG){
7164       string & s =*args._STRNGptr;
7165       int l=int(s.size());
7166       if (!l)
7167 	return args;
7168       return string2gen(s.substr(1,l-1),false);
7169     }
7170     if (args.type!=_VECT)
7171       return vecteur(0);
7172     if (args._VECTptr->size()){
7173       const_iterateur it=args._VECTptr->begin(),itend=args._VECTptr->end();
7174       return gen(vecteur(it+1,itend),args.subtype);
7175     }
7176     else
7177       return args;
7178   }
7179   static const char _tail_s []="tail";
7180   static define_unary_function_eval (__tail,&_tail,_tail_s);
7181   define_unary_function_ptr5( at_tail ,alias_at_tail,&__tail,0,true);
7182 
_back(const gen & args,GIAC_CONTEXT)7183   gen _back(const gen & args,GIAC_CONTEXT){
7184     if ( args.type==_STRNG && args.subtype==-1) return  args;
7185     if (args.type==_STRNG){
7186       string & s =*args._STRNGptr;
7187       int l=int(s.size());
7188       if (!l)
7189 	return args;
7190       return string2gen(s.substr(l-1,1),false);
7191     }
7192     if (args.type!=_VECT)
7193       return args;
7194     if (args._VECTptr->size())
7195       return args._VECTptr->back();
7196     else
7197       return args;
7198   }
7199   static const char _back_s []="back";
7200   static define_unary_function_eval (__back,&_back,_back_s);
7201   define_unary_function_ptr5( at_back ,alias_at_back,&__back,0,true);
7202 
7203 
7204   // return the vector of affixes of vertices of a polygonal line
7205   // If popback is true and the polygonal line is closed
7206   // the last vertex is removed from the returned vector
sommet(const gen & args,bool popback=true)7207   static vecteur sommet(const gen & args,bool popback=true){
7208     if (args.type==_VECT){
7209       if (args.subtype==_POINT__VECT)
7210 	return vecteur(1,args);
7211       if (!args._VECTptr->empty() && args.subtype==0){
7212 	vecteur v(*args._VECTptr);
7213 	gen v0=remove_at_pnt(v[0]);
7214 	if (v0.type==_VECT && v0.subtype!=_POINT__VECT)
7215 	  return sommet(v0,popback);
7216       }
7217     }
7218     gen g=remove_at_pnt(args);
7219     if (g.is_symb_of_sommet(at_cercle)){
7220       gen & feuille=g._SYMBptr->feuille;
7221       if (feuille.type==_VECT && !feuille._VECTptr->empty()){
7222 	g=feuille._VECTptr->front();
7223 	return sommet(g,false);
7224       }
7225     }
7226     if (g.is_symb_of_sommet(at_hyperplan)){
7227       vecteur P,n;
7228       if (!hyperplan_normal_point(g,n,P))
7229 	return vecteur(3,gensizeerr(gettext("sommet")));
7230       vecteur v1,v2;
7231       if (!normal3d(n,v1,v2))
7232 	return vecteur(3,gensizeerr(gettext("sommet")));
7233       return makevecteur(P,v1,v2);
7234     }
7235     if (g.is_symb_of_sommet(at_hypersphere)){
7236       gen & feuille=g._SYMBptr->feuille;
7237       if (feuille.type==_VECT && !feuille._VECTptr->empty())
7238 	return sommet(feuille._VECTptr->front(),false);
7239     }
7240     vecteur v(gen2vecteur(g));
7241     if (ckmatrix(v.front())){ // polyedre
7242       vecteur res;
7243       const_iterateur it=v.begin(),itend=v.end();
7244       for (;it!=itend;++it){
7245 	if (!ckmatrix(*it))
7246 	  return vecteur(1,gensizeerr(gettext("sommet")));
7247 	const_iterateur jt=it->_VECTptr->begin(),jtend=it->_VECTptr->end();
7248 	for (;jt!=jtend;++jt){
7249 	  if (!equalposcomp(res,*jt))
7250 	    res.push_back(*jt);
7251 	}
7252       }
7253       return res;
7254     }
7255     if (popback && v.size()>1 && v.back()==v.front())
7256       v.pop_back();
7257     return v;
7258   }
7259 
_sommets(const gen & args,GIAC_CONTEXT)7260   gen _sommets(const gen & args,GIAC_CONTEXT){
7261     if ( args.type==_STRNG && args.subtype==-1) return  args;
7262     string s;
7263     if (is_graphe(args,s,contextptr))
7264       return _graph_vertices(args,contextptr);
7265     if (args.type==_VECT && args.subtype==_SEQ__VECT && args._VECTptr->size()==2){
7266       gen g=_sommets(args._VECTptr->front(),contextptr);
7267       return g[args._VECTptr->back()];//+array_start(contextptr)];
7268     }
7269     gen g=sommet(args,true);
7270     if (is_undef(g))
7271       return g;
7272     bool tmp=show_point(contextptr);
7273     show_point(false,contextptr);
7274     g=apply(g,_point,contextptr);
7275     show_point(tmp,contextptr);
7276     return g;
7277   }
7278   static const char _sommets_s []="vertices";
7279   static define_unary_function_eval (__sommets,&_sommets,_sommets_s);
7280   define_unary_function_ptr5( at_sommets ,alias_at_sommets,&__sommets,0,true);
7281 
_faces(const gen & args,GIAC_CONTEXT)7282   gen _faces(const gen & args,GIAC_CONTEXT){
7283     if ( args.type==_STRNG && args.subtype==-1) return  args;
7284     string s;
7285     if (is_graphe(args,s,contextptr)){
7286       identificateur faces;
7287       gen ret=_is_planar(makesequence(args,faces),contextptr);
7288       gen retval=is_one(ret)?_eval(faces,contextptr):ret;
7289       _purge(faces,contextptr);
7290       return retval;
7291     }
7292     return remove_at_pnt(args);
7293   }
7294   static const char _faces_s []="faces";
7295   static define_unary_function_eval (__faces,&_faces,_faces_s);
7296   define_unary_function_ptr5( at_faces ,alias_at_faces,&__faces,0,true);
7297 
_sommets_abca(const gen & args,GIAC_CONTEXT)7298   gen _sommets_abca(const gen & args,GIAC_CONTEXT){
7299     if ( args.type==_STRNG && args.subtype==-1) return  args;
7300     gen g=sommet(args,false);
7301     if (is_undef(g))
7302       return g;
7303     bool tmp=show_point(contextptr);
7304     show_point(false,contextptr);
7305     g=apply(g,_point,contextptr);
7306     show_point(tmp,contextptr);
7307     return g;
7308   }
7309   static const char _sommets_abca_s []="vertices_abca";
7310   static define_unary_function_eval (__sommets_abca,&_sommets_abca,_sommets_abca_s);
7311   define_unary_function_ptr5( at_sommets_abca ,alias_at_sommets_abca,&__sommets_abca,0,true);
7312 
7313   static const char _sommets_abc_s []="vertices_abc";
7314   static define_unary_function_eval (__sommets_abc,&_sommets,_sommets_abc_s);
7315   define_unary_function_ptr5( at_sommets_abc ,alias_at_sommets_abc,&__sommets_abc,0,true);
7316 
symetriepoint(const gen & a,const gen & b,GIAC_CONTEXT)7317   static gen symetriepoint(const gen & a,const gen & b,GIAC_CONTEXT){
7318     gen res= 2*a-b;
7319     res.subtype=_POINT__VECT;
7320     return res;
7321   }
7322 
symetrieplan(const gen & a,const gen & b,GIAC_CONTEXT)7323   static gen symetrieplan(const gen & a,const gen & b,GIAC_CONTEXT){
7324     if (a.type==_VECT && a._VECTptr->size()==3){
7325       vecteur & w(*a._VECTptr);
7326       vecteur n(*w[0]._VECTptr),P(*w[1]._VECTptr);
7327       gen n2(w[2]);
7328       gen res= b-2*scalar_product(n,b-P,contextptr)/n2*n;
7329       if (is_undef(res)) return res;
7330       res.subtype=_POINT__VECT;
7331       return res;
7332     }
7333     return gensizeerr(contextptr);
7334   }
7335 
apply3d(const gen & e1,const gen & e2,const context * contextptr,gen (* f)(const gen &,const gen &,const context *))7336   gen apply3d(const gen & e1, const gen & e2,const context * contextptr, gen (* f) (const gen &, const gen &,const context *) ){
7337     if (is_undef(e2))
7338       return e2;
7339     if (e2.type!=_VECT || e2.subtype==_POINT__VECT)
7340       return f(e1,e2,contextptr);
7341     const_iterateur it=e2._VECTptr->begin(),itend=e2._VECTptr->end();
7342     vecteur v;
7343     v.reserve(itend-it);
7344     for (;it!=itend;++it){
7345       gen tmp=apply3d(e1,*it,contextptr,f);
7346       if (is_undef(tmp))
7347 	return gen2vecteur(tmp);
7348       v.push_back(tmp);
7349     }
7350     return gen(v,e2.subtype);
7351   }
7352 
curve_surface_apply(const gen & elem,const gen & b,gen (* func)(const gen &,const gen &,const context *),GIAC_CONTEXT)7353   gen curve_surface_apply(const gen & elem,const gen & b,gen (* func) (const gen &, const gen &,const context *),GIAC_CONTEXT){
7354     if (func &&
7355 	(b.is_symb_of_sommet(at_curve) || b.is_symb_of_sommet(at_hypersurface))
7356 	&& b._SYMBptr->feuille.type==_VECT && b._SYMBptr->feuille._VECTptr->size()>=2){
7357       // f = vect[ pnt,var,xmin,xmax ]
7358       gen f= b._SYMBptr->feuille._VECTptr->front();
7359       gen g=(*b._SYMBptr->feuille._VECTptr)[1];
7360       if (f.type==_VECT && !f._VECTptr->empty()){
7361 	vecteur fv=*f._VECTptr;
7362 	if (fv.size()==7){
7363 	  fv[6]=func(elem,fv[6],contextptr);
7364 	  fv[5]=rationalparam2equation(fv[6],t__IDNT_e,x__IDNT_e,y__IDNT_e,contextptr);
7365 	}
7366 	if (fv.size()==6)
7367 	  fv.pop_back();
7368 	fv[0]=func(elem,fv[0],contextptr);
7369 	if (fv.size()>4)
7370 	  fv[4]=apply3d(elem,fv[4],contextptr,func);
7371 	f=gen(fv,f.subtype);
7372       }
7373       if (b.is_symb_of_sommet(at_curve)){
7374 	g= apply3d(elem,g,contextptr,func);
7375 	g=symb_curve(f,g);
7376       }
7377       else {
7378 	if (b._SYMBptr->feuille._VECTptr->size()>=3){
7379 	  gen vars=(*b._SYMBptr->feuille._VECTptr)[2];
7380 	  gen fvars=func(elem,vars,contextptr);
7381 	  // subst(g,fvars,vars); invert affine function
7382 	  if (vars.type==_VECT){
7383 	    gen difffvars=derive(fvars,*vars._VECTptr,contextptr);
7384 	    if (is_undef(difffvars) || difffvars.type!=_VECT)
7385 	      return difffvars;
7386 	    vecteur dfunc=*difffvars._VECTptr;
7387 	    if (is_zero(derive(dfunc,vars,contextptr),contextptr)){
7388 	      matrice m(minv(dfunc,contextptr));
7389 	      if (is_undef(m)) return m;
7390 	      gen y_minus_b=vars-func(elem,vecteur(vars._VECTptr->size()),contextptr);
7391 	      fvars=m*y_minus_b;
7392 	      g=subst(g,vars,fvars,false,contextptr);
7393 	      g=hypersurface(f,g,vars);
7394 	    }
7395 	    else
7396 	      g=hypersurface(f,undef,vars);
7397 	  }
7398 	  else
7399 	    g=hypersurface(f,undef,vars);
7400 	}
7401 	else
7402 	  g=hypersurface(f,undef,undef);
7403       }
7404       return symb_pnt(g,default_color(contextptr),contextptr);
7405     }
7406     return gensizeerr(contextptr);
7407   }
7408 
7409   // image of b wrt to the line defined by vector of affixe w and point w0
symetrie_droite(const gen & w,const gen & w0,const gen & b,GIAC_CONTEXT)7410   static gen symetrie_droite(const gen & w,const gen & w0,const gen & b,GIAC_CONTEXT){
7411     if (b.type==_VECT){
7412       const_iterateur it=b._VECTptr->begin(),itend=b._VECTptr->end();
7413       vecteur res;
7414       res.reserve(itend-it);
7415       for (;it!=itend;++it)
7416 	res.push_back(symetrie_droite(w,w0,*it,contextptr));
7417       gen b1=gen(res,b.subtype);
7418       return b1;
7419     }
7420     return b-plus_two*w*rdiv(scalar_product(b-w0,w,contextptr),w.squarenorm(contextptr),contextptr);
7421   }
7422 
rotation(const gen & centre,const gen & angle,const gen & M,GIAC_CONTEXT)7423   static gen rotation(const gen & centre,const gen & angle,const gen & M,GIAC_CONTEXT){
7424     if (M.type==_CPLX && centre.type==_CPLX){
7425       gen Mx,My; reim(M,Mx,My,contextptr);
7426       gen Cx,Cy; reim(centre,Cx,Cy,contextptr);
7427       gen ca=cos(angle,contextptr);
7428       gen sa=sin(angle,contextptr);
7429       Mx -= Cx; My -= Cy;
7430       // (ca+i*sa)*(Mx+i*My)=ca*Mx-sa*My+i*(sa*Mx+ca*My)
7431       gen x=ca*Mx-sa*My,y=sa*Mx+ca*My;
7432       x += Cx;
7433       y += Cy;
7434       return makecomplex(x,y);
7435     }
7436     return centre+exp(cst_i*angletorad(angle,contextptr),contextptr)*(M-centre);
7437   }
7438 
7439   // 2-d r(centre,angle,M) or 3-d r(line,angle,M)
rotation(const vecteur & v,int s,GIAC_CONTEXT)7440   static gen rotation(const vecteur & v,int s,GIAC_CONTEXT){
7441     if (s==3){
7442       gen centre=remove_at_pnt(v[0]);
7443       gen angle=v[1];
7444       gen b=v[2];
7445       if (b.type==_VECT){
7446 	const_iterateur it=b._VECTptr->begin(),itend=b._VECTptr->end();
7447 	vecteur res;
7448 	res.reserve(itend-it);
7449 	for (;it!=itend;++it){
7450 	  res.push_back(rotation(makevecteur(centre,angle,*it),s,contextptr));
7451 	}
7452 	return gen(res,b.subtype);
7453       }
7454       b=remove_at_pnt(b);
7455       if (b.type==_VECT && b.subtype==_VECTOR__VECT && b._VECTptr->size()==2)
7456 	return _vector(gen(makevecteur(rotation(makevecteur(centre,angle,b._VECTptr->front()),s,contextptr),rotation(makevecteur(centre,angle,b._VECTptr->back()),s,contextptr)),_SEQ__VECT),contextptr);
7457       if ( centre.type==_SYMB && (centre._SYMBptr->sommet==at_cercle) )
7458 	return gensizeerr(contextptr);
7459       if (centre.is_symb_of_sommet(at_hyperplan)){
7460 	vecteur n,P;
7461 	if (!hyperplan_normal_point(centre,n,P))
7462 	  return gensizeerr(contextptr);
7463 	return similitude3d(makevecteur(P,P+n),angle,1,b,-1,contextptr);
7464       }
7465       if (centre.type!=_VECT) // 2-d rotation
7466 	return symb_pnt(rotation(centre,angle,b,contextptr),default_color(contextptr),contextptr);
7467       return similitude3d(*centre._VECTptr,angle,1,b,1,contextptr);
7468     }
7469     if (s==2){
7470       vecteur w(v.begin(),v.begin()+s);
7471       w.push_back(x__IDNT_e);
7472       return symb_program(x__IDNT_e,zero,symbolic(at_rotation,gen(w,_SEQ__VECT)),contextptr);
7473     }
7474     return gendimerr(contextptr);
7475   }
symetrie(const gen & aa,const gen & bb,GIAC_CONTEXT)7476   static gen symetrie(const gen & aa,const gen & bb,GIAC_CONTEXT){
7477     if (bb.type==_VECT)
7478       return apply2nd(aa,bb,contextptr,symetrie);
7479     gen a=remove_at_pnt(aa);
7480     if ( (a.type==_SYMB) && (a._SYMBptr->sommet==at_cercle) )
7481       return gensizeerr(contextptr);
7482     gen b=remove_at_pnt(bb);
7483     if (b.type==_VECT && b.subtype==_VECTOR__VECT && b._VECTptr->size()==2)
7484       return _vector(gen(makevecteur(symetrie(aa,b._VECTptr->front(),contextptr),symetrie(aa,b._VECTptr->back(),contextptr)),_SEQ__VECT),contextptr);
7485     if (a.is_symb_of_sommet(at_hyperplan)){ // symmetry of b wrt plan
7486       vecteur n,P;
7487       if (!hyperplan_normal_point(a,n,P))
7488 	return gensizeerr(contextptr);
7489       gen n2(dotvecteur(n,n));
7490       gen elem=makevecteur(n,P,n2);
7491       if (b.type==_VECT)
7492 	return symb_pnt(apply3d(elem,b,contextptr,symetrieplan),default_color(contextptr),contextptr);
7493       if (b.is_symb_of_sommet(at_hyperplan)){ // hyperplan wrt plan
7494 	vecteur nb,Pb;
7495 	if (!hyperplan_normal_point(b,nb,Pb))
7496 	  return gensizeerr(contextptr);
7497 	gen nbi=nb-dotvecteur(nb,n)/n2*n;
7498 	gen Pbi=Pb-scalar_product(n,Pb-P,contextptr)/n2*n;
7499 	if (is_undef(Pbi)) return Pbi;
7500 	return _plan(makevecteur(nbi,Pbi),contextptr);
7501       }
7502       if (b.is_symb_of_sommet(at_hypersphere)){ // hypersphere wrt plan
7503 	gen c,r;
7504 	if (!centre_rayon(b,c,r,false,contextptr))
7505 	  return gensizeerr(contextptr);
7506 	return _sphere(makevecteur(c-scalar_product(n,c-P,contextptr)/n2*n,r),contextptr);
7507       }
7508       return curve_surface_apply(elem,b,symetrieplan,contextptr);
7509     }
7510     vecteur v;
7511     if (a.type!=_VECT) // 2-d point symmetry
7512       return symb_pnt(plus_two*a-b,default_color(contextptr),contextptr);
7513     v=*a._VECTptr;
7514     if (a.subtype==_POINT__VECT || v.size()==3){ // 3-d point symmetry
7515       if (b.type==_VECT){ // point3d, line, polygon or polyedre
7516 	gen res=apply3d(a,b,contextptr,symetriepoint);
7517 	return symb_pnt(res,default_color(contextptr),contextptr);
7518       }
7519       if (b.is_symb_of_sommet(at_hyperplan)){ // plan wrt point
7520 	vecteur n,P;
7521 	if (!hyperplan_normal_point(b,n,P))
7522 	  return gensizeerr(contextptr);
7523 	return _plan(makevecteur(n,2*a-P),contextptr);
7524       }
7525       if (b.is_symb_of_sommet(at_hypersphere)){ // sphere wrt point
7526 	gen centre,rayon;
7527 	if (!centre_rayon(b,centre,rayon,false,contextptr))
7528 	  return gensizeerr(contextptr);
7529 	return _sphere(makevecteur(2*a-centre,rayon),contextptr);
7530       }
7531       return curve_surface_apply(a,b,symetriepoint,contextptr);
7532     } // end 3-d point symmetry
7533     if (v.size()!=2)
7534       return gensizeerr(contextptr);
7535     // line symmetry
7536     if (v[0].type==_VECT){ // 3-d line symmetry -> rotation of angle pi
7537       return rotation(makevecteur(aa,cst_pi,bb),3,contextptr);
7538     }
7539     // 2-d line symmetry
7540     gen w=cst_i*(v[1]-v[0]);
7541     if (b.is_symb_of_sommet(at_cercle)){
7542       gen bf=b._SYMBptr->feuille;
7543       if (bf.type!=_VECT || bf._VECTptr->size()<2)
7544 	return gensizeerr(contextptr);
7545       vecteur vb=*bf._VECTptr;
7546       vb[0]=symetrie_droite(w,v[0],vb[0],contextptr);
7547       if (vb.size()==3 && vb[2]-vb[1]!=cst_two_pi){
7548 	vb[1] = -vb[1];
7549 	vb[2] = -vb[2];
7550       }
7551       bf=gen(vb,bf.subtype);
7552       b=symbolic(at_cercle,bf);
7553       return symb_pnt(b,default_color(contextptr),contextptr);
7554     }
7555     if (b.is_symb_of_sommet(at_curve)){
7556       gen bf=b._SYMBptr->feuille;
7557       if (bf.type!=_VECT || bf._VECTptr->size()<2)
7558 	return gensizeerr(contextptr);
7559       gen bf1=bf._VECTptr->front(),bf2=(*bf._VECTptr)[1];
7560       if (bf1.type==_VECT && !bf1._VECTptr->empty()){
7561 	vecteur bf1v=*bf1._VECTptr;
7562 	if (bf1v.size()==7) {
7563 	  bf1v[6]=symetrie_droite(w,v[0],bf1v[6],contextptr);
7564 	  // recompute cartesian equation
7565 	  bf1v[5]=rationalparam2equation(bf1v[6],t__IDNT_e,x__IDNT_e,y__IDNT_e,contextptr);
7566 	}
7567 	if (bf1v.size()==6)
7568 	  bf1v.pop_back();
7569 	bf1v[0]=symetrie_droite(w,v[0],bf1v[0],contextptr);
7570 	bf1=gen(bf1v,bf1.subtype);
7571       }
7572       if (bf2.type==_VECT){
7573 	const_iterateur it=bf2._VECTptr->begin(),itend=bf2._VECTptr->end();
7574 	vecteur res;
7575 	res.reserve(itend-it);
7576 	for (;it!=itend;++it){
7577 	  res.push_back(symetrie_droite(w,v[0],*it,contextptr));
7578 	}
7579 	bf2=gen(res,bf2.subtype);
7580 	bf=gen(makevecteur(bf1,bf2),bf.subtype);
7581 	return symb_pnt(symbolic(at_curve,bf),default_color(contextptr),contextptr);
7582       }
7583     }
7584     return symb_pnt(symetrie_droite(w,v[0],b,contextptr),default_color(contextptr),contextptr);
7585   }
7586 
seq2vecteur(const gen & g)7587   vecteur seq2vecteur(const gen & g){
7588     if (g.type==_VECT && g.subtype==_SEQ__VECT)
7589       return *g._VECTptr;
7590     else
7591       return vecteur(1,g);
7592   }
symetrie(const vecteur & v,int s,GIAC_CONTEXT)7593   static gen symetrie(const vecteur & v,int s,GIAC_CONTEXT){
7594     if (s==2)
7595       return symetrie(v[0],v[1],contextptr);
7596     if (s==1){
7597       return symb_program(x__IDNT_e,zero,symbolic(at_symetrie,gen(makevecteur(v[0],x__IDNT_e),_SEQ__VECT)),contextptr);
7598     }
7599     return gentypeerr(contextptr);
7600   }
_symetrie(const gen & args,GIAC_CONTEXT)7601   gen _symetrie(const gen & args,GIAC_CONTEXT){
7602     if ( args.type==_STRNG && args.subtype==-1) return  args;
7603     vecteur attributs(1,default_color(contextptr));
7604     vecteur v(seq2vecteur(args));
7605     int s=read_attributs(v,attributs,contextptr);
7606     if (!s)
7607       return gendimerr(contextptr);
7608     return put_attributs(symetrie(v,s,contextptr),attributs,contextptr);
7609   }
7610   static const char _symetrie_s []="reflection";
7611   static define_unary_function_eval (__symetrie,&_symetrie,_symetrie_s);
7612   define_unary_function_ptr5( at_symetrie ,alias_at_symetrie,&__symetrie,0,true);
7613 
_rotation(const gen & args,GIAC_CONTEXT)7614   gen _rotation(const gen & args,GIAC_CONTEXT){
7615     if ( args.type==_STRNG && args.subtype==-1) return  args;
7616     vecteur attributs(1,default_color(contextptr));
7617     vecteur v(seq2vecteur(args));
7618     int s=read_attributs(v,attributs,contextptr);
7619     if (!s)
7620       return gendimerr(contextptr);
7621     return put_attributs(rotation(v,s,contextptr),attributs,contextptr);
7622   }
7623   static const char _rotation_s []="rotation";
7624   static define_unary_function_eval (__rotation,&_rotation,_rotation_s);
7625   define_unary_function_ptr5( at_rotation ,alias_at_rotation,&__rotation,0,true);
7626 
projectionpoint(const gen & aa,const gen & bb,GIAC_CONTEXT)7627   static gen projectionpoint(const gen & aa,const gen & bb,GIAC_CONTEXT){
7628     gen b=remove_at_pnt(bb);
7629     if (b.type==_VECT && b.subtype==_VECTOR__VECT && b._VECTptr->size()==2)
7630       return _vector(gen(makevecteur(projectionpoint(aa,b._VECTptr->front(),contextptr),projectionpoint(aa,b._VECTptr->back(),contextptr)),_SEQ__VECT),contextptr);
7631     if (aa.is_symb_of_sommet(at_hypersphere)){
7632       const gen & f=aa._SYMBptr->feuille;
7633       if (f.type==_VECT && f._VECTptr->size()>=2){
7634 	const vecteur & v=*f._VECTptr;
7635 	gen c=v.front();
7636 	if (c.type==_VECT && c._VECTptr->size()==3 && b.type==_VECT && b._VECTptr->size()==3){
7637 	  vecteur cb=subvecteur(*b._VECTptr,*c._VECTptr);
7638 	  c=c+v[1]/l2norm(cb,contextptr)*cb;
7639 	  c.subtype=_POINT__VECT;
7640 	  return symb_pnt(c,contextptr);
7641 	}
7642       }
7643     }
7644     if (aa.is_symb_of_sommet(at_hyperplan)){
7645       vecteur n,P;
7646       if (!hyperplan_normal_point(aa,n,P))
7647 	return gensizeerr(contextptr);
7648       gen n2(dotvecteur(n,n));
7649       // projection of point and line on hyperplan
7650       if (b.type==_VECT && b._VECTptr->size()==2){ // line
7651 	// project both points and return the line
7652 	gen & A=b._VECTptr->front();
7653 	gen & B=b._VECTptr->back();
7654 	gen AP=A+scalar_product(P-A,n,contextptr)/n2*n;
7655 	gen BP=B+scalar_product(P-B,n,contextptr)/n2*n;
7656 	if (is_undef(AP)) return AP;
7657 	if (is_undef(BP)) return BP;
7658 	return symb_pnt(gen(makevecteur(AP,BP),b.subtype),contextptr);
7659       }
7660       // point: b -> M=b+tn such that MP is orthogonal to n
7661       // hence (b-P+tn).n=0 -> t=(P-b).n/n.n
7662       if (b.type!=_VECT)
7663 	return gensizeerr(contextptr);
7664       gen tmp=b+scalar_product(P-b,n,contextptr)/n2*n;
7665       if (is_undef(tmp)) return tmp;
7666       return symb_pnt(do_point3d(tmp),contextptr);
7667     }
7668     if (aa.type==_VECT && aa._VECTptr->size()==2){
7669       // FIXME: for circle!
7670       // projection of a point b over a line AB
7671       gen & A=aa._VECTptr->front();
7672       gen & B=aa._VECTptr->back();
7673       gen v(B-A);
7674       // Find M such that M=A+t*(B-A) and (M-b).(B-A)=0
7675       // Hence (A-b).(B-A)+t(B-A)^2=0 -> t=(b-A).(B-A)/(B-A)^2
7676       gen t=scalar_product(b-A,v,contextptr)/scalar_product(v,v,contextptr);
7677       if (is_undef(t)) return t;
7678       return symb_pnt(A+t*v,default_color(contextptr),contextptr);
7679     }
7680     vecteur v;
7681     v.push_back(aa);
7682     gen tmpaa=projection(aa,b,contextptr);
7683     if (is_undef(tmpaa)) return tmpaa;
7684     v.push_back(tmpaa);
7685     return parameter2point(v,contextptr);
7686   }
7687 
projection(const vecteur & v,int s,GIAC_CONTEXT)7688   static gen projection(const vecteur & v,int s,GIAC_CONTEXT){
7689     if (s==2){
7690       gen a=remove_at_pnt(v[0]);
7691       gen af=evalf_double(a,1,contextptr);
7692       if (af.type<=_REAL)
7693 	return gensizeerr("projection first argument must be a line/curve");
7694       gen b=v[1];
7695       if (b.type==_VECT)
7696 	return apply2nd(a,b,contextptr,projectionpoint);
7697       else
7698 	return projectionpoint(a,b,contextptr);
7699     }
7700     if (s==1)
7701       return symb_program(x__IDNT_e,zero,symbolic(at_projection,gen(makevecteur(v[0],x__IDNT_e),_SEQ__VECT)),contextptr);
7702     return gentypeerr(contextptr);
7703   }
_projection(const gen & args,GIAC_CONTEXT)7704   gen _projection(const gen & args,GIAC_CONTEXT){
7705     if ( args.type==_STRNG && args.subtype==-1) return  args;
7706     vecteur attributs(1,default_color(contextptr));
7707     vecteur v(seq2vecteur(args));
7708     int s=read_attributs(v,attributs,contextptr);
7709     if (!s)
7710       return gendimerr(contextptr);
7711     return put_attributs(projection(v,s,contextptr),attributs,contextptr);
7712   }
7713   static const char _projection_s []="projection";
7714   static define_unary_function_eval (__projection,&_projection,_projection_s);
7715   define_unary_function_ptr5( at_projection ,alias_at_projection,&__projection,0,true);
7716 
7717   // h(centre,rapport,M)
homothetie(const vecteur & v,int s,GIAC_CONTEXT)7718   static gen homothetie(const vecteur & v,int s,GIAC_CONTEXT){
7719     if (s==3){
7720       gen centre=remove_at_pnt(v[0]);
7721       if ( centre.type==_SYMB && centre._SYMBptr->sommet==at_cercle )
7722 	return gensizeerr(contextptr);
7723       gen rapport=v[1];
7724       gen b=v[2];
7725       if (b.type==_VECT){
7726 	const_iterateur it=b._VECTptr->begin(),itend=b._VECTptr->end();
7727 	vecteur res;
7728 	res.reserve(itend-it);
7729 	for (;it!=itend;++it)
7730 	  res.push_back(homothetie(makevecteur(centre,rapport,*it),s,contextptr));
7731 	return gen(res,_GROUP__VECT);
7732       }
7733       b=remove_at_pnt(b);
7734       if (b.type==_VECT && b.subtype==_VECTOR__VECT && b._VECTptr->size()==2)
7735 	return _vector(gen(makevecteur(homothetie(makevecteur(centre,rapport,b._VECTptr->front()),s,contextptr),homothetie(makevecteur(centre,rapport,b._VECTptr->back()),s,contextptr)),_SEQ__VECT),contextptr);
7736       if (b.is_symb_of_sommet(at_hyperplan)){
7737 	vecteur n,P;
7738 	if (!hyperplan_normal_point(b,n,P))
7739 	  return gensizeerr(contextptr);
7740 	return _plan(makevecteur(n,centre+rapport*(P-centre)),contextptr);
7741       }
7742       if (b.is_symb_of_sommet(at_hypersphere)){
7743 	gen c,r;
7744 	if (!centre_rayon(b,c,r,false,contextptr))
7745 	  return gensizeerr(contextptr);
7746 	return _sphere(makevecteur(centre+rapport*(c-centre),rapport*r),contextptr);
7747       }
7748       return symb_pnt(centre+rapport*(b-centre),default_color(contextptr),contextptr);
7749     }
7750     if (s==2){
7751       vecteur w=makevecteur(v[0],v[1],x__IDNT_e);
7752       return symb_program(x__IDNT_e,zero,symbolic(at_homothetie,gen(w,_SEQ__VECT)),contextptr);
7753     }
7754     return gentypeerr(contextptr);
7755   }
_homothetie(const gen & args,GIAC_CONTEXT)7756   gen _homothetie(const gen & args,GIAC_CONTEXT){
7757     if ( args.type==_STRNG && args.subtype==-1) return  args;
7758     vecteur attributs(1,default_color(contextptr));
7759     vecteur v(seq2vecteur(args));
7760     int s=read_attributs(v,attributs,contextptr);
7761     if (!s)
7762       return gendimerr(contextptr);
7763     return put_attributs(homothetie(v,s,contextptr),attributs,contextptr);
7764   }
7765   static const char _homothetie_s []="homothety";
7766   static define_unary_function_eval (__homothetie,&_homothetie,_homothetie_s);
7767   define_unary_function_ptr5( at_homothetie ,alias_at_homothetie,&__homothetie,0,true);
7768 
7769   // renvoie 2 si tous les points sont confondus
7770   // renvoie 1 si tous les points sont alignes et 0 sinon
_est_aligne(const gen & args,GIAC_CONTEXT)7771   gen _est_aligne(const gen & args,GIAC_CONTEXT){
7772     if ( args.type==_STRNG && args.subtype==-1) return  args;
7773     gen a;
7774     if (args.type!=_VECT) {
7775       a=remove_at_pnt(args);
7776       if (a.type==_VECT) return gensizeerr(contextptr);
7777       return 2;
7778     }
7779     int s=int(args._VECTptr->size());
7780     vecteur v(*args._VECTptr);
7781     if (s==1) {
7782       a=remove_at_pnt(v[0]);
7783       if (a.type==_VECT)
7784 	return gensizeerr(contextptr);
7785       return 2;
7786     }
7787     if (s>=2){
7788       a=remove_at_pnt(v[0]);
7789       gen b=remove_at_pnt(v[1]);
7790       bool res=false;
7791       int i=2;
7792       while (a==b && i<s){
7793 	b=remove_at_pnt(v[i]);
7794 	i++;
7795       }
7796       //a==b tous les points sonts confondus sinon on a a!=b
7797       if (i==s){
7798 	if (a==b) return(2);
7799 	return(1);
7800       }
7801       //a!=b
7802       for (int j=i;j<s;j++){
7803 	gen c=remove_at_pnt(v[j]);
7804 	res=(est_aligne(a,b,c,contextptr))!=0;
7805 	if (res==0) return 0;
7806       }
7807       return res;
7808     }
7809     return symbolic(at_est_aligne,args);
7810   }
7811   static const char _est_aligne_s []="is_collinear";
7812   static define_unary_function_eval (__est_aligne,&_est_aligne,_est_aligne_s);
7813   define_unary_function_ptr5( at_est_aligne ,alias_at_est_aligne,&__est_aligne,0,true);
7814 
est_coplanaire(const gen & a,const gen & b,const gen & c,const gen & d,GIAC_CONTEXT)7815   bool est_coplanaire(const gen & a,const gen & b,const gen & c,const gen & d,GIAC_CONTEXT){
7816     if (a.type!=_VECT)
7817       return false; // setsizeerr(gettext("3-d instruction"));
7818     gen n1(b-a),n2(c-a),n3(d-a);
7819     return is_zero(mdet(makevecteur(n1,n2,n3),contextptr),contextptr);
7820   }
7821 
add_if_not_colinear(vecteur & v,const gen & p,GIAC_CONTEXT)7822   static void add_if_not_colinear(vecteur & v,const gen & p,GIAC_CONTEXT){
7823     int s=int(v.size());
7824     bool add=true;
7825     if (s==1)
7826       add=!is_zero(v.front()-p,contextptr);
7827     else {
7828       if (s==2)
7829 	add=!est_aligne(v[0],v[1],p,contextptr);
7830     }
7831     if (add)
7832       v.push_back(p);
7833   }
_est_coplanaire(const gen & args,GIAC_CONTEXT)7834   gen _est_coplanaire(const gen & args,GIAC_CONTEXT){
7835     if ( args.type==_STRNG && args.subtype==-1) return  args;
7836     if (args.type!=_VECT)
7837       return gensizeerr(contextptr);
7838     vecteur & w=*args._VECTptr,v;
7839     int s=int(w.size());
7840     for (int j=0;j<s;++j){
7841       gen tmp=remove_at_pnt(w[j]);
7842       if (tmp.type==_VECT && tmp._VECTptr->size()==2){
7843 	add_if_not_colinear(v,tmp._VECTptr->front(),contextptr);
7844 	add_if_not_colinear(v,tmp._VECTptr->back(),contextptr);
7845       }
7846       else {
7847 	add_if_not_colinear(v,tmp,contextptr);
7848       }
7849     }
7850     int vs=int(v.size());
7851     for(int i=3;i<vs;++i){
7852       if (!est_coplanaire(v[0],v[1],v[2],v[i],contextptr))
7853 	return false;
7854     }
7855     return true;
7856   }
7857   static const char _est_coplanaire_s []="is_coplanar";
7858   static define_unary_function_eval (__est_coplanaire,&_est_coplanaire,_est_coplanaire_s);
7859   define_unary_function_ptr5( at_est_coplanaire ,alias_at_est_coplanaire,&__est_coplanaire,0,true);
7860 
gen2complex(const gen & a)7861   static gen gen2complex(const gen & a){
7862     if (a.type!=_VECT)
7863       return a;
7864     if (a._VECTptr->size()!=2)
7865       return gensizeerr(gettext("gen2complex"));
7866     return a._VECTptr->front()+cst_i*a._VECTptr->back();
7867   }
7868 
est_cocyclique(const gen & a,const gen & b,const gen & c,const gen & d,GIAC_CONTEXT)7869   bool est_cocyclique(const gen & a,const gen & b,const gen & c,const gen & d,GIAC_CONTEXT){
7870     gen ab=b-a,ac=c-a,ad=d-a;
7871     if (is_zero(ab,contextptr) || is_zero(ac,contextptr) || is_zero(ad,contextptr) )
7872       return true;
7873     if (a.type==_VECT && a._VECTptr->size()==3){
7874       if (!est_coplanaire(a,b,c,d,contextptr))
7875 	return false;
7876       return (est_aligne(a+ab/abs_norm2(ab,contextptr),a+ac/abs_norm2(ac,contextptr),a+ad/abs_norm2(ad,contextptr),contextptr))!=0;
7877     }
7878     gen A(gen2complex(a)),B(gen2complex(b)),C(gen2complex(c)),D(gen2complex(d));
7879     gen e(im((B-A)*(C-D)*conj(C-A,contextptr)*conj(B-D,contextptr),contextptr));
7880     return is_zero(simplify(e,contextptr),contextptr);
7881   }
7882   // renvoie 1 si tous les points sont cocycliques et 0 sinon
_est_cocyclique(const gen & args,GIAC_CONTEXT)7883   gen _est_cocyclique(const gen & args,GIAC_CONTEXT){
7884     if ( args.type==_STRNG && args.subtype==-1) return  args;
7885     if (args.type!=_VECT)
7886       return 3;
7887     int s=int(args._VECTptr->size());
7888     vecteur & v=*args._VECTptr ;
7889     gen a(v[0]),b(undef),c(undef);
7890     for (int i=1;i<s;++i){
7891       if (is_undef(b)){
7892 	if (!is_zero(v[0]-v[i],contextptr))
7893 	  b=v[i];
7894       }
7895       else {
7896 	if (is_zero(v[i]-b,contextptr) || is_zero(v[i]-a,contextptr))
7897 	  continue;
7898 	if (est_aligne(a,b,v[i],contextptr))
7899 	  return 0;
7900 	if (is_undef(c))
7901 	  c=v[i];
7902 	else {
7903 	  if (!est_cocyclique(a,b,c,v[i],contextptr))
7904 	    return 0;
7905 	}
7906       }
7907     }
7908     return 1;
7909   }
7910   static const char _est_cocyclique_s []="is_concyclic";
7911   static define_unary_function_eval (__est_cocyclique,&_est_cocyclique,_est_cocyclique_s);
7912   define_unary_function_ptr5( at_est_cocyclique ,alias_at_est_cocyclique,&__est_cocyclique,0,true);
7913 
_est_parallele(const gen & args,GIAC_CONTEXT)7914   gen _est_parallele(const gen & args,GIAC_CONTEXT){
7915     if ( args.type==_STRNG && args.subtype==-1) return  args;
7916     if ((args.type==_VECT) && (args._VECTptr->size()==2)){
7917       vecteur v(*args._VECTptr);
7918       gen a=remove_at_pnt(v[0]),b=remove_at_pnt(v[1]);
7919       bool av=a.type==_VECT && a._VECTptr->size()==2;
7920       bool bv=b.type==_VECT && b._VECTptr->size()==2;
7921       if (a.is_symb_of_sommet(at_hyperplan)){
7922 	vecteur n(hyperplan_normal(a));
7923 	if (b.is_symb_of_sommet(at_hyperplan))
7924 	  return est_parallele_vecteur(n,hyperplan_normal(b),contextptr);
7925 	if (bv)
7926 	  return is_zero(simplify(scalar_product(n,b[0]-b[1],contextptr),contextptr),contextptr);
7927       }
7928       if (b.is_symb_of_sommet(at_hyperplan) && av)
7929 	return is_zero(simplify(scalar_product(hyperplan_normal(b),a[0]-a[1],contextptr),contextptr),contextptr);
7930       if ( !av || !bv)
7931 	return gensizeerr(contextptr);
7932       return est_parallele(a[0]-a[1],b[0]-b[1],contextptr);
7933     }
7934     return symbolic(at_est_parallele,args);
7935   }
7936   static const char _est_parallele_s []="is_parallel";
7937   static define_unary_function_eval (__est_parallele,&_est_parallele,_est_parallele_s);
7938   define_unary_function_ptr5( at_est_parallele ,alias_at_est_parallele,&__est_parallele,0,true);
7939 
est_perpendiculaire(const gen & a,const gen & b,GIAC_CONTEXT)7940   bool est_perpendiculaire(const gen & a,const gen & b,GIAC_CONTEXT){
7941     gen d;
7942     if (a.type==_VECT && b.type==_VECT)
7943       d=dotvecteur(*a._VECTptr,*b._VECTptr);
7944     else
7945       d=re(a*conj(b,contextptr),contextptr);
7946     return is_zero(simplify(d,contextptr),contextptr);
7947   }
7948 
7949   // check if a belongs to b, a must be a complex, b a line or circle or curve
est_element(const gen & a_orig,const gen & b_orig,GIAC_CONTEXT)7950   int est_element(const gen & a_orig,const gen & b_orig,GIAC_CONTEXT){
7951     gen a=remove_at_pnt(a_orig),b=remove_at_pnt(b_orig);
7952     if (b.type==_REAL)
7953       return contains(b,a)?1:0;
7954     if (b.type==_VECT && b.subtype<=_SET__VECT){
7955       int p=equalposcomp(*b._VECTptr,a);
7956       if (p) return p;
7957       const_iterateur it=b._VECTptr->begin(),itend=b._VECTptr->end();
7958       for (;it!=itend;++it){
7959 	if (it->is_symb_of_sommet(at_pnt))
7960 	  p=est_element(a,*it,contextptr);
7961 	if (p)
7962 	  return int(1+it-b._VECTptr->begin());
7963       }
7964       return 0;
7965     }
7966     if (b.is_symb_of_sommet(at_cercle)){
7967       // check orthogonality with diameter
7968       gen diam=remove_at_pnt(b._SYMBptr->feuille._VECTptr->front());
7969       if (diam.type!=_VECT)
7970 	return 0;
7971       gen c1=remove_at_pnt(diam._VECTptr->front());
7972       gen c2=remove_at_pnt(diam._VECTptr->back());
7973       return est_perpendiculaire(a-c1,a-c2,contextptr);
7974     }
7975     if (b.is_symb_of_sommet(at_hypersphere)){
7976       gen c,r;
7977       if (!centre_rayon(b,c,r,false,contextptr))
7978 	return 0;
7979       return is_zero(simplify(pow(a-c,2)-pow(r,2),contextptr),contextptr);
7980     }
7981     if (b.is_symb_of_sommet(at_hyperplan)){
7982       vecteur n,P;
7983       if (!hyperplan_normal_point(b,n,P))
7984 	return 0;// gensizeerr(contextptr);
7985       return is_zero(simplify(scalar_product(a-P,n,contextptr),contextptr),contextptr);
7986     }
7987     if (b.is_symb_of_sommet(at_curve)){
7988       gen t;
7989       return on(b,a,t,contextptr);
7990     }
7991     if (b.type==_VECT && b._VECTptr->size()==2){
7992       gen c1=remove_at_pnt(b._VECTptr->front());
7993       gen c2=remove_at_pnt(b._VECTptr->back());
7994       return est_aligne(c1,c2,a,contextptr);
7995     }
7996     if (b.type==_VECT && b.subtype==_GROUP__VECT && b._VECTptr->size()>2){
7997       vecteur v=*b._VECTptr;
7998       int s=int(v.size());
7999       for (int i=1;i<s;++i){
8000 	gen c1=remove_at_pnt(v[i-1]);
8001 	gen c2=remove_at_pnt(v[i]);
8002 	if (est_aligne(c1,c2,a,contextptr)){
8003 	  gen m=re((a-c1)/(c2-c1),contextptr);
8004 	  if (is_greater(m,0,contextptr) && is_greater(1,m,contextptr))
8005 	    return i;
8006 	}
8007       }
8008     }
8009     return 0; // FIXME implement est_element of a polygon
8010   }
_est_element(const gen & args,GIAC_CONTEXT)8011   gen _est_element(const gen & args,GIAC_CONTEXT){
8012     if ( args.type==_STRNG && args.subtype==-1) return  args;
8013     if ((args.type==_VECT) && (args._VECTptr->size()==2)){
8014       vecteur v(*args._VECTptr);
8015       gen a=v[0],b=v[1];
8016       return est_element(a,b,contextptr);
8017     }
8018     return symbolic(at_est_element,args);
8019   }
8020   static const char _est_element_s []="is_element";
8021   static define_unary_function_eval (__est_element,&_est_element,_est_element_s);
8022   define_unary_function_ptr5( at_est_element ,alias_at_est_element,&__est_element,0,true);
8023 
est_dans(const gen & a_,const gen & b_,GIAC_CONTEXT)8024   gen est_dans(const gen & a_,const gen &b_,GIAC_CONTEXT){
8025     gen b=remove_at_pnt(b_);
8026     gen M=remove_at_pnt(a_);
8027     if (M.type<=_CPLX || M.type==_SYMB || M.type==_IDNT || M.type==_FLOAT_ || M.type==_FRAC){
8028       if (b.is_symb_of_sommet(at_cercle)){
8029 	gen c,r;
8030 	centre_rayon(b,c,r,false,contextptr);
8031 	gen Mc=(c-M).squarenorm(contextptr),r2=r.squarenorm(contextptr);
8032 	return ck_is_greater(r2,Mc,contextptr);
8033       }
8034       if (b.type==_VECT && b._VECTptr->size()>=3 && is_zero(b._VECTptr->front()-b._VECTptr->back(),contextptr)){
8035 	// point in a polygon?
8036 	int n=0; // n is the number of intersections of halfline M direction 1 with polygon
8037 	for (unsigned j=1;j<b._VECTptr->size();++j){
8038 	  gen A=(*b._VECTptr)[j-1];
8039 	  gen B=(*b._VECTptr)[j];
8040 	  gen Ax,Ay,Bx,By,Mx,My;
8041 	  reim(A,Ax,Ay,contextptr);
8042 	  reim(B,Bx,By,contextptr);
8043 	  reim(M,Mx,My,contextptr);
8044 	  if (is_zero(recursive_normal(Ay-By,contextptr),contextptr))
8045 	    continue;
8046 	  if (ck_is_greater(Ay,By,contextptr)){
8047 	    swapgen(Ax,Bx);
8048 	    swapgen(Ay,By);
8049 	  }
8050 	  if (ck_is_greater(By,My,contextptr) && ck_is_strictly_greater(My,Ay,contextptr)){
8051 	    gen t=(My-Ay)/(By-Ay);
8052 	    gen alpha=recursive_normal((Ax-Mx)+t*(Bx-Ax),contextptr);
8053 	    if (ck_is_greater(alpha,0,contextptr))
8054 	      ++n;
8055 	  }
8056 	}
8057 	return n%2;
8058       }
8059     }
8060     return gensizeerr(gettext("Not implemented or bad argument type/value"));
8061   }
_est_dans(const gen & args,GIAC_CONTEXT)8062   gen _est_dans(const gen & args,GIAC_CONTEXT){
8063     if ( args.type==_STRNG && args.subtype==-1) return  args;
8064     if ((args.type==_VECT) && (args._VECTptr->size()==2)){
8065       vecteur v(*args._VECTptr);
8066       gen a=v[0],b=v[1];
8067       return est_dans(a,b,contextptr);
8068     }
8069     return gensizeerr(contextptr);
8070   }
8071   static const char _est_dans_s []="is_inside";
8072   static define_unary_function_eval (__est_dans,&_est_dans,_est_dans_s);
8073   define_unary_function_ptr5( at_est_dans ,alias_at_est_dans,&__est_dans,0,true);
8074 
8075   // adjust arguments and return true if b is an angle between a and c
arg_between(const gen & a,const gen & b,const gen & c,GIAC_CONTEXT)8076   static bool arg_between(const gen & a,const gen &b,const gen & c,GIAC_CONTEXT){
8077     gen C=c;
8078     if (is_greater(a,c,contextptr))
8079       C=c+cst_two_pi;
8080     gen B=b;
8081     if (is_greater(a,b,contextptr))
8082       B=b+cst_two_pi;
8083     return is_greater(C,B,contextptr);
8084   }
8085 
inversion(const gen & centre,const gen & rapport,const gen & argument,GIAC_CONTEXT)8086   static gen inversion(const gen & centre,const gen & rapport,const gen & argument,GIAC_CONTEXT){
8087     gen b=remove_at_pnt(argument);
8088     // special care must be taken for circles and segments
8089     if (b.type==_VECT && b.subtype!=_POINT__VECT){
8090       if (b._VECTptr->size()!=2)
8091 	return gensizeerr(gettext("not implemented"));
8092       // inversion of a line
8093       gen c=b._VECTptr->front(),d=b._VECTptr->back();
8094       if (est_aligne(centre,c,d,contextptr)){
8095 	if (b.subtype==_LINE__VECT)
8096 	  return b;
8097 	return gen(makevecteur(inversion(centre,rapport,c,contextptr),inversion(centre,rapport,d,contextptr)),b.subtype);
8098       }
8099       // find the image of the projection of the center of inversion
8100       // the image of the line is the circle of diameter centre,image
8101       gen t=projection(c,d,centre,contextptr);
8102       if (is_undef(t)) return t;
8103       gen p=c+t*(d-c);
8104       gen image=inversion(centre,rapport,p,contextptr);
8105       if (is_undef(image)) return image;
8106       if (b.subtype==_LINE__VECT)
8107 	return remove_at_pnt(_cercle(gen(makevecteur((centre+image)/2,(image-centre)/2),_SEQ__VECT),contextptr));
8108       p=(centre+image)/2; // center of circle
8109       c=inversion(centre,rapport,c,contextptr);
8110       c=arg(c-p,contextptr);
8111       d=inversion(centre,rapport,d,contextptr);
8112       d=arg(d-p,contextptr);
8113       if (is_greater(c,d,contextptr))
8114 	swapgen(c,d);
8115       gen e=arg(centre-p,contextptr),a1,a2;
8116       // Segment: choose c,d or d,c (never contains e), halfline: choose c,e or e,c (should contain d)
8117       if (b.subtype==_HALFLINE__VECT){
8118 	if (arg_between(c,d,e,contextptr)){
8119 	  a1=c; a2=e;
8120 	}
8121 	else {
8122 	  a1=e; a2=c+cst_two_pi;
8123 	}
8124       }
8125       else {
8126 	if (arg_between(c,e,d,contextptr)){
8127 	  a1=d; a2=c+cst_two_pi;
8128 	}
8129 	else {
8130 	  a1=c; a2=d;
8131 	}
8132       }
8133       return remove_at_pnt(_cercle(gen(makevecteur(p,abs(image-centre,contextptr)/2,a1,a2),_SEQ__VECT),contextptr));
8134     }
8135     if ( (b.type!=_SYMB) || (!equalposcomp(plot_sommets,b._SYMBptr->sommet)) ){
8136       gen centre_b=b-centre;
8137       return centre+rapport/abs_norm2(centre_b,contextptr)*centre_b;
8138       // return centre+rapport*inv(conj(b-centre,contextptr));
8139     }
8140     if (b._SYMBptr->sommet!=at_cercle)
8141       return gensizeerr(gettext("not implemented"));
8142     // inversion of a circle
8143     // if it contains the center of inversion it's a line, otherw. a circle
8144     gen c,r;
8145     if (!centre_rayon(b,c,r,true,contextptr))
8146       return gensizeerr(contextptr);
8147     if (is_zero(evalf_double(distance2pp(c,centre,contextptr)-r*r,1,contextptr),contextptr)){
8148       // c-centre is the normal direction
8149       gen n(c-centre);
8150       n=im(n,contextptr)-cst_i*re(n,contextptr);
8151       // the line passes at the image of 2*centre-c
8152       gen pied(inversion(centre,rapport,plus_two*c-centre,contextptr));
8153       return remove_at_pnt(_droite(makevecteur(pied,pied+n),contextptr));
8154     }
8155     else {
8156       gen d(c-centre);
8157       if (is_zero(d,contextptr)){
8158 	return _cercle(makesequence(centre,rapport/r),contextptr);
8159       }
8160       else {
8161 	r=rdiv(r,abs_norm(d,contextptr),contextptr)*d;
8162 	gen d1(inversion(centre,rapport,c+r,contextptr));
8163 	gen d2(inversion(centre,rapport,c-r,contextptr));
8164 	if (is_undef(d2)) return d2;
8165 	gen d3(inversion(centre,rapport,c+r*cst_i,contextptr));
8166 	return remove_at_pnt(_circonscrit(makesequence(d1,d2,d3),contextptr));
8167       }
8168     }
8169   }
8170 
inversion(const vecteur & v,int s,GIAC_CONTEXT)8171   gen inversion(const vecteur & v,int s,GIAC_CONTEXT){
8172     if (s==3){
8173       gen centre=remove_at_pnt(v[0]);
8174       gen rapport=v[1];
8175       gen b=v[2];
8176       if ( (centre.type==_VECT && centre.subtype!=_POINT__VECT) || (centre.type==_SYMB && centre._SYMBptr->sommet==at_cercle) )
8177 	return gensizeerr(contextptr);
8178       if (b.type==_VECT){
8179 	const_iterateur it=b._VECTptr->begin(),itend=b._VECTptr->end();
8180 	vecteur res;
8181 	res.reserve(itend-it);
8182 	for (;it!=itend;++it){
8183 	  res.push_back(inversion(centre,rapport,*it,contextptr));
8184 	}
8185 	return gen(res,_GROUP__VECT);
8186       }
8187       return symb_pnt(inversion(centre,rapport,b,contextptr),default_color(contextptr),contextptr);
8188     }
8189     if (s==2){
8190       return symb_program(x__IDNT_e,zero,symbolic(at_inversion,gen(makevecteur(v[0],v[1],x__IDNT_e),_SEQ__VECT)),contextptr);
8191     }
8192     return gentypeerr(contextptr);
8193   }
_inversion(const gen & args,GIAC_CONTEXT)8194   gen _inversion(const gen & args,GIAC_CONTEXT){
8195     if ( args.type==_STRNG && args.subtype==-1) return  args;
8196     vecteur attributs(1,default_color(contextptr));
8197     vecteur v(seq2vecteur(args));
8198     int s=read_attributs(v,attributs,contextptr);
8199     if (!s)
8200       return gendimerr(contextptr);
8201     return put_attributs(inversion(v,s,contextptr),attributs,contextptr);
8202   }
8203   static const char _inversion_s []="inversion";
8204   static define_unary_function_eval (__inversion,&_inversion,_inversion_s);
8205   define_unary_function_ptr5( at_inversion ,alias_at_inversion,&__inversion,0,true);
8206 
8207   // s(centre,rapport,angle,M)
similitude(const vecteur & v,int s,GIAC_CONTEXT)8208   static gen similitude(const vecteur & v,int s,GIAC_CONTEXT){
8209     if (s==4){
8210       gen centre=remove_at_pnt(v[0]);
8211       if ( centre.type==_SYMB && centre._SYMBptr->sommet==at_cercle )
8212 	return gensizeerr(contextptr);
8213       gen rapport=v[1];
8214       gen angle=v[2];
8215       gen b=v[3];
8216       if (b.type==_VECT){
8217 	const_iterateur it=b._VECTptr->begin(),itend=b._VECTptr->end();
8218 	vecteur res;
8219 	res.reserve(itend-it);
8220 	for (;it!=itend;++it){
8221 	  res.push_back(similitude(makevecteur(centre,rapport,angle,*it),s,contextptr));
8222 	}
8223 	return gen(res,_GROUP__VECT);
8224       }
8225       if (centre.is_symb_of_sommet(at_hyperplan)){
8226 	vecteur n,P;
8227 	if (!hyperplan_normal_point(centre,n,P))
8228 	  return gensizeerr(contextptr);
8229 	return similitude3d(makevecteur(P,P+n),angle,rapport,b,-1,contextptr);
8230       }
8231       b=remove_at_pnt(b);
8232       if (b.type==_VECT && b.subtype==_VECTOR__VECT && b._VECTptr->size()==2)
8233 	return _vector(gen(makevecteur(similitude(makevecteur(centre,rapport,angle,b._VECTptr->front()),s,contextptr),similitude(makevecteur(centre,rapport,angle,b._VECTptr->back()),s,contextptr)),_SEQ__VECT),contextptr);
8234       if (centre.type!=_VECT)
8235 	return symb_pnt(centre+rapport*exp(cst_i*angletorad(angle,contextptr),contextptr)*(b-centre),default_color(contextptr),contextptr);
8236       return similitude3d(*centre._VECTptr,angle,rapport,b,1,contextptr);
8237     }
8238     if (s==3){
8239       vecteur w=makevecteur(v[0],v[1],v[2],x__IDNT_e);
8240       return symb_program(x__IDNT_e,zero,symbolic(at_similitude,gen(w,_SEQ__VECT)),contextptr);
8241     }
8242     return gentypeerr(contextptr);
8243   }
_similitude(const gen & args,GIAC_CONTEXT)8244   gen _similitude(const gen & args,GIAC_CONTEXT){
8245     if ( args.type==_STRNG && args.subtype==-1) return  args;
8246     vecteur attributs(1,default_color(contextptr));
8247     vecteur v(seq2vecteur(args));
8248     int s=read_attributs(v,attributs,contextptr);
8249     if (!s)
8250       return gendimerr(contextptr);
8251     return put_attributs(similitude(v,s,contextptr),attributs,contextptr);
8252   }
8253   static const char _similitude_s []="similarity";
8254   static define_unary_function_eval (__similitude,&_similitude,_similitude_s);
8255   define_unary_function_ptr5( at_similitude ,alias_at_similitude,&__similitude,0,true);
8256 
translationpoint(const gen & a,const gen & b,GIAC_CONTEXT)8257   static gen translationpoint(const gen & a,const gen & b,GIAC_CONTEXT){
8258     if (has_i(a) || (a.type==_VECT && a._VECTptr->size()>3)){
8259       // change made 19 mai 2015 for e.g. translation(1+i,circle(0,1))
8260       if (!is_analytic(b) && !b.is_symb_of_sommet(at_cercle) && evalf(b,1,contextptr).type==_SYMB)
8261 	return gensizeerr(contextptr);
8262     }
8263     return a+b;
8264   }
8265 
translation(const gen & a,const gen & bb,GIAC_CONTEXT)8266   gen translation(const gen & a,const gen & bb,GIAC_CONTEXT){
8267     gen elem(a);
8268     if (a.type==_VECT && a._VECTptr->size()==2){
8269       if (a.subtype==_LINE__VECT)
8270 	elem=a._VECTptr->back()-a._VECTptr->front();
8271       else
8272 	elem=a._VECTptr->front()+cst_i*a._VECTptr->back();
8273     }
8274     gen b=remove_at_pnt(bb);
8275     if (b.is_symb_of_sommet(at_hyperplan)){
8276       vecteur n,P;
8277       if (!hyperplan_normal_point(b,n,P))
8278 	return gensizeerr(contextptr);
8279       return _plan(makevecteur(n,elem+P),contextptr);
8280     }
8281     if (b.is_symb_of_sommet(at_hypersphere)){
8282       gen c,r;
8283       if (!centre_rayon(b,c,r,false,contextptr))
8284 	return gensizeerr(contextptr);
8285       return _sphere(makevecteur(elem+c,r),contextptr);
8286     }
8287     if (b.is_symb_of_sommet(at_parameter))
8288       return b;
8289     gen res;
8290     if (b.is_symb_of_sommet(at_hypersurface) || b.is_symb_of_sommet(at_curve))
8291       res=remove_at_pnt(curve_surface_apply(elem,b,translationpoint,contextptr));
8292     else
8293       res=apply3d(elem,b,contextptr,translationpoint);
8294     return symb_pnt(res,default_color(contextptr),contextptr);
8295   }
8296 
translation(const vecteur & v,int s,GIAC_CONTEXT)8297   static gen translation(const vecteur & v,int s,GIAC_CONTEXT){
8298     if (s==2){
8299       gen a=v[0];
8300       if (a.is_symb_of_sommet(at_pnt)){
8301 	a=remove_at_pnt(a);
8302 	if (a.type==_VECT && (a.subtype==_VECTOR__VECT || a.subtype==_GROUP__VECT) && a._VECTptr->size()==2){
8303 	  return translation(makevecteur(a._VECTptr->back()-a._VECTptr->front(),v[1]),s,contextptr);
8304 	}
8305 	if (a.type!=_VECT || a.subtype!=_LINE__VECT)
8306 	  return gensizeerr(gettext("First arg of translation should not be a point"));
8307       }
8308       if ( (a.type==_SYMB) && (a._SYMBptr->sommet==at_cercle) )
8309 	return gensizeerr(contextptr);
8310       gen b=v[1];
8311       return apply2nd(a,b,contextptr,translation);
8312     }
8313     if (s==1){
8314       return symb_program(x__IDNT_e,zero,symbolic(at_translation,gen(makevecteur(v[0],x__IDNT_e),_SEQ__VECT)),contextptr);
8315     }
8316     return gentypeerr(contextptr);
8317   }
_translation(const gen & args,GIAC_CONTEXT)8318   gen _translation(const gen & args,GIAC_CONTEXT){
8319     if ( args.type==_STRNG && args.subtype==-1) return  args;
8320     vecteur attributs(1,default_color(contextptr));
8321     vecteur v(seq2vecteur(args));
8322     int s=read_attributs(v,attributs,contextptr);
8323     if (!s)
8324       return gendimerr(contextptr);
8325     return put_attributs(translation(v,s,contextptr),attributs,contextptr);
8326   }
8327   static const char _translation_s []="translation";
8328   static define_unary_function_eval (__translation,&_translation,_translation_s);
8329   define_unary_function_ptr5( at_translation ,alias_at_translation,&__translation,0,true);
8330 
8331   // curve is the innert form of a parametric curve
8332   // source=[pnt,var], plot=ligne brisee
printascurve(const gen & feuille,const char * sommetstr,GIAC_CONTEXT)8333   static string printascurve(const gen & feuille,const char * sommetstr,GIAC_CONTEXT){
8334     if ( !fastcurveprint || (feuille.type!=_VECT) || (feuille._VECTptr->size()!=2) )
8335       return string(sommetstr)+('('+feuille.print(contextptr)+')');
8336     return string(sommetstr)+('('+feuille._VECTptr->front().print(contextptr)+string(",undef)"));
8337   }
8338   /*
8339     static int sprintascurve(const gen & feuille,const char * sommetstr,string * sptr,GIAC_CONTEXT){
8340     int res=1+strlen(sommetstr);
8341     if (sptr)
8342     *sptr += '(';
8343     if ( !fastcurveprint || (feuille.type!=_VECT) || (feuille._VECTptr->size()!=2) ){
8344     res += feuille.sprint(sptr,contextptr);
8345     if (sptr)
8346     *sptr += ')';
8347     return res+1;
8348     }
8349     res += feuille._VECTptr->front().sprint(sptr,contextptr);
8350     if (sptr)
8351     *sptr += ",undef)";
8352     return res+7;
8353     }
8354   */
_curve(const gen & args,GIAC_CONTEXT)8355   gen _curve(const gen & args,GIAC_CONTEXT){
8356     if ( args.type==_STRNG && args.subtype==-1) return  args;
8357     return symbolic(at_curve,args);
8358   }
8359   static const char _curve_s []="curve";
8360   static define_unary_function_eval2 (__curve,&_curve,_curve_s,&printascurve);
8361   define_unary_function_ptr5( at_curve ,alias_at_curve,&__curve,0,true);
8362 
plotparam(const gen & f,const gen & vars,const vecteur & attributs,bool densityplot,double function_xmin,double function_xmax,double function_ymin,double function_ymax,double function_tmin,double function_tmax,double function_tstep,const gen & equation,const gen & parameq,const gen & vparam,const context * contextptr)8363   gen plotparam(const gen & f,const gen & vars,const vecteur & attributs,bool densityplot,double function_xmin,double function_xmax,double function_ymin,double function_ymax,double function_tmin, double function_tmax,double function_tstep,const gen & equation,const gen & parameq,const gen & vparam,const context * contextptr){
8364     if (function_tstep<=0 || (function_tmax-function_tmin)/function_tstep>max_nstep || function_tmax==function_tmin)
8365       return gensizeerr(gettext("Plotparam: unable to discretize: tmin, tmax, tstep=")+print_DOUBLE_(function_tmin,12)+","+print_DOUBLE_(function_tmax,12)+","+print_DOUBLE_(function_tstep,12)+gettext("\nTry a larger value for tstep"));
8366     gen fC(f);
8367     if (f.type==_VECT && f._VECTptr->size()==2)
8368       fC=f._VECTptr->front()+cst_i*f._VECTptr->back();
8369     gen attribut=attributs.empty()?default_color(contextptr):attributs[0];
8370     // bool save_approx_mode=approx_mode(contextptr);
8371     // approx_mode(true,contextptr);
8372     gen locvar(vars);
8373     locvar.subtype=0;
8374     gen xy=quotesubst(f,vars,locvar,contextptr),xy_,x_,y_;
8375     bool joindre;
8376     vecteur localvar(1,vars),res;
8377     context * newcontextptr=(context *) contextptr;
8378     int protect=giac_bind(vecteur(1,function_tmin),localvar,newcontextptr);
8379     vecteur chemin;
8380     double i,j,oldi=0,oldj=0,entrei,entrej;
8381     double t=function_tmin;
8382     int nstep=int((function_tmax-function_tmin)/function_tstep+.5);
8383     // bool old_io_graph=io_graph(contextptr);
8384     // io_graph(false,contextptr);
8385     for (int count=0;!ctrl_c && !interrupted && count<=nstep;++count,t+= function_tstep){
8386       local_sto_double(t,*vars._IDNTptr,newcontextptr);
8387       // vars._IDNTptr->localvalue->back()._DOUBLE_val =t;
8388       if (xy.type==_VECT && xy._VECTptr->size()==2){
8389 	x_=xy._VECTptr->front().evalf2double(eval_level(contextptr),newcontextptr);
8390 	y_=xy._VECTptr->back().evalf2double(eval_level(contextptr),newcontextptr);
8391       }
8392       else {
8393 	xy_=xy.evalf2double(eval_level(contextptr),newcontextptr);
8394 	if (xy_.type==_VECT && xy_._VECTptr->size()==2){
8395 	  x_=xy_._VECTptr->front();
8396 	  y_=xy_._VECTptr->back();
8397 	}
8398 	else {
8399 	  x_=re(xy_,newcontextptr);
8400 	  y_=im(xy_,newcontextptr).evalf_double(eval_level(contextptr),newcontextptr);
8401 	}
8402       }
8403       if ( (x_.type!=_DOUBLE_) || (y_.type!=_DOUBLE_) )
8404 	continue;
8405       i=x_._DOUBLE_val;
8406       j=y_._DOUBLE_val;
8407       if (t!=function_tmin){
8408 	if ( (fabs(oldj-j)>(function_ymax-function_ymin)/5) ||
8409 	     (fabs(oldi-i)>(function_xmax-function_xmin)/5) ){
8410 	  local_sto_double_increment(-function_tstep/2,*vars._IDNTptr,newcontextptr);
8411 	  // vars._IDNTptr->localvalue->back()._DOUBLE_val -= function_tstep/2;
8412 	  xy_=xy.evalf2double(eval_level(contextptr),newcontextptr);
8413 	  if (xy_.type==_VECT && xy_._VECTptr->size()==2){
8414 	    x_=xy_._VECTptr->front();
8415 	    y_=xy_._VECTptr->back();
8416 	  }
8417 	  else {
8418 	    x_=re(xy_,newcontextptr);
8419 	    y_=im(xy_,newcontextptr);
8420 	  }
8421 	  if ( (x_.type!=_DOUBLE_) || (y_.type!=_DOUBLE_) )
8422 	    joindre=false;
8423 	  else {
8424 	    entrei=x_._DOUBLE_val;
8425 	    entrej=y_._DOUBLE_val;
8426 	    if (j>oldj)
8427 	      joindre=(j>=entrej) && (entrej>=oldj);
8428 	    else
8429 	      joindre=(j<=entrej) && (entrej<=oldj);
8430 	    if (i>oldi)
8431 	      joindre=joindre && (i>=entrei) && (entrei>=oldi);
8432 	    else
8433 	      joindre=joindre && (i<=entrei) && (entrei<=oldi);
8434 	  }
8435 	  local_sto_double_increment(-function_tstep/2,*vars._IDNTptr,newcontextptr);
8436 	  // vars._IDNTptr->localvalue->back()._DOUBLE_val -= function_tstep/2;
8437 	}
8438 	else
8439 	  joindre=true;
8440       } // if t!=function_tmin
8441       else
8442 	joindre=true;
8443       if (joindre)
8444 	chemin.push_back(gen(i,j));
8445       else {
8446 	if (!chemin.empty())
8447 	  res.push_back(symb_pnt(symb_curve(gen(makevecteur(fC,vars,function_tmin,t,0,equation,parameq,vparam),_PNT__VECT),gen(chemin,_GROUP__VECT)),attribut,contextptr));
8448 	function_tmin=t;
8449 	chemin=vecteur(1,gen(i,j));
8450       }
8451       oldi=i;
8452       oldj=j;
8453     }
8454     if (!chemin.empty())
8455       res.push_back(symb_pnt(symb_curve(gen(makevecteur(fC,vars,function_tmin,function_tmax,0,equation,parameq,vparam),_PNT__VECT),gen(chemin,_GROUP__VECT)),attribut,contextptr));
8456     leave(protect,localvar,newcontextptr);
8457     // io_graph(old_io_graph,contextptr);
8458 #if !defined(WIN32) && defined(WITH_GNUPLOT)
8459     if (child_id) plot_instructions.push_back(res);
8460 #endif // WIN32
8461     // approx_mode(save_approx_mode,contextptr);
8462     if (res.size()==1)
8463       return res.front();
8464     // gen e(res,_SEQ__VECT);
8465     return res; // e;
8466   }
8467 
plotparam(const gen & f,const gen & vars,const vecteur & attributs,bool densityplot,double function_xmin,double function_xmax,double function_ymin,double function_ymax,double function_tmin,double function_tmax,double function_tstep,const gen & equation,const gen & parameq,const context * contextptr)8468   gen plotparam(const gen & f,const gen & vars,const vecteur & attributs,bool densityplot,double function_xmin,double function_xmax,double function_ymin,double function_ymax,double function_tmin, double function_tmax,double function_tstep,const gen & equation,const gen & parameq,const context * contextptr){
8469     return plotparam(f,vars,attributs,densityplot,function_xmin,function_xmax,function_ymin,function_ymax,function_tmin,function_tmax,function_tstep,equation,parameq,undef,contextptr);
8470   }
8471 
paramplotparam(const gen & args,bool densityplot,const context * contextptr)8472   gen paramplotparam(const gen & args,bool densityplot,const context * contextptr){
8473     // args= [x(t)+i*y(t),t] should add a t interval
8474     bool f_autoscale=autoscale;
8475     if (args.type!=_VECT || args.subtype!=_SEQ__VECT){
8476       gen m=minus_inf,M=plus_inf;
8477       vecteur poi,tvi;
8478       gen t=ggb_var(args);
8479       gen fg=eval(args,1,contextptr),r,i;
8480       if (fg.type==_VECT && fg._VECTptr->size()!=2)
8481 	return paramplotparam(makesequence(args,t),false,contextptr);
8482       if (fg.type==_VECT && fg._VECTptr->size()==2){
8483 	r=fg._VECTptr->front();
8484 	i=fg._VECTptr->back();
8485 	fg=r+cst_i*i;
8486       }
8487       else
8488 	reim(fg,r,i,contextptr);
8489 #if 0 // ? #ifdef EMCC
8490       if (step_param(r,i,t,m,M,poi,tvi,true,false,contextptr)){
8491 	gen scale=(gnuplot_tmax-gnuplot_tmin)/5.0;
8492 	if (is_inf(m))
8493 	  m=gnuplot_tmin;
8494 	if (is_inf(M))
8495 	  M=gnuplot_tmax;
8496 	if (m!=M)
8497 	  scale=(M-m)/3.0;
8498 	m=m-0.973456*scale; M=M+1.018546*scale;
8499 	gen p=paramplotparam(makesequence(fg,symb_equal(t,symb_interval(m,M))),false,contextptr);
8500 	poi=mergevecteur(poi,gen2vecteur(p));
8501 	return gen(poi,_SEQ__VECT);
8502       }
8503       else
8504 #endif
8505 	return paramplotparam(makesequence(args,t),false,contextptr);
8506     }
8507     vecteur vargs(plotpreprocess(args,contextptr));
8508     if (is_undef(vargs))
8509       return vargs;
8510     if (vargs.size()<2)
8511       return symbolic(at_plotparam,args);
8512     gen f=vargs.front();
8513     gen vars=vargs[1];
8514     /*
8515       if (f.type==_VECT && f._VECTptr->size()==2)
8516       f=f._VECTptr->front()+cst_i*f._VECTptr->back();
8517     */
8518     bool param2d=f.type!=_VECT || f._VECTptr->size()==2;
8519     if (param2d){
8520       if (vars.type==_VECT){
8521 	if (vars._VECTptr->size()!=1)
8522 	  return gensizeerr(contextptr);
8523 	vars=vars._VECTptr->front();
8524       }
8525     }
8526     int s=int(vargs.size());
8527     gen eq=undef,parameq=undef,vparam=undef;
8528     if (s>5)
8529       eq=vargs[5];
8530     if (s>6)
8531       parameq=vargs[6];
8532     if (s>7)
8533       vparam=vargs[7];
8534     double umin=gnuplot_tmin,vmin=gnuplot_tmin,umax=gnuplot_tmax,vmax=gnuplot_tmax,tmin=gnuplot_tmin,tmax=gnuplot_tmax,xmin=gnuplot_xmin,xmax=gnuplot_xmax,ymin=gnuplot_ymin,ymax=gnuplot_ymax,zmin=gnuplot_zmin,zmax=gnuplot_zmax,tstep=-1,ustep=-1,vstep=-1;
8535     if (param2d && s>=3){
8536       gen trange=vargs[2].evalf_double(eval_level(contextptr),contextptr);
8537       if ( (trange.type==_SYMB) && (trange._SYMBptr->sommet==at_interval)){
8538 	tmin=evalf_double(trange._SYMBptr->feuille._VECTptr->front(),eval_level(contextptr),contextptr)._DOUBLE_val;
8539 	tmax=evalf_double(trange._SYMBptr->feuille._VECTptr->back(),eval_level(contextptr),contextptr)._DOUBLE_val;
8540 	if (s>3)
8541 	  tstep=vargs[3].evalf_double(eval_level(contextptr),contextptr)._DOUBLE_val;
8542       }
8543       else {
8544 	if (s>=4){
8545 	  tmin=vargs[2].evalf_double(eval_level(contextptr),contextptr)._DOUBLE_val;
8546 	  tmax=vargs[3].evalf_double(eval_level(contextptr),contextptr)._DOUBLE_val;
8547 	  if (s>4 && !vargs[4].is_symb_of_sommet(at_equal))
8548 	    tstep=vargs[4].evalf_double(eval_level(contextptr),contextptr)._DOUBLE_val;
8549 	}
8550       }
8551       if (tmin>tmax )
8552 	swapdouble(tmin,tmax);
8553     }
8554     gen attribut=default_color(contextptr);
8555     for (int i=1;i<s;++i){
8556 #if 0 // def GIAC_HAS_STO_38
8557       if (readvar(vargs[i])==vx_var){
8558 	f_autoscale=false;
8559 	readrange(vargs[i],tmin,tmax,vargs[i],tmin,tmax,contextptr);
8560 	umin=tmin; umax=tmax;
8561       }
8562 #endif
8563       if (readvar(vargs[i])==x__IDNT_e){
8564 	f_autoscale=false;
8565 	readrange(vargs[i],gnuplot_xmin,gnuplot_xmax,vargs[i],xmin,xmax,contextptr);
8566       }
8567       if (readvar(vargs[i])==y__IDNT_e){
8568 	f_autoscale=false;
8569 	readrange(vargs[i],gnuplot_ymin,gnuplot_ymax,vargs[i],ymin,ymax,contextptr);
8570       }
8571       if (readvar(vargs[i])==z__IDNT_e){
8572 	f_autoscale=false;
8573 	readrange(vargs[i],gnuplot_zmin,gnuplot_zmax,vargs[i],zmin,zmax,contextptr);
8574       }
8575       if (readvar(vargs[i])==u__IDNT_e){
8576 	f_autoscale=false;
8577 	readrange(vargs[i],tmin,tmax,vargs[i],umin,umax,contextptr);
8578       }
8579       if (readvar(vargs[i])==v__IDNT_e){
8580 	f_autoscale=false;
8581 	readrange(vargs[i],tmin,tmax,vargs[i],vmin,vmax,contextptr);
8582       }
8583       if (readvar(vargs[i])==t__IDNT_e){
8584 	f_autoscale=false;
8585 	readrange(vargs[i],tmin,tmax,vargs[i],tmin,tmax,contextptr);
8586 	umin=tmin; umax=tmax;
8587       }
8588       if (vargs[i].is_symb_of_sommet(at_equal) && vargs[i]._SYMBptr->feuille.type==_VECT && vargs[i]._SYMBptr->feuille._VECTptr->front().type==_INT_){
8589 	gen n=vargs[i]._SYMBptr->feuille._VECTptr->back();
8590 	switch (vargs[i]._SYMBptr->feuille._VECTptr->front().val){
8591 	case _NSTEP:
8592 	  if (n.type!=_INT_) return gensizeerr(contextptr);
8593 	  tstep=absdouble((tmax-tmin)/n.val);
8594 	  ustep=(umax-umin)/int(std::sqrt(double(n.val)));
8595 	  vstep=(vmax-vmin)/int(std::sqrt(double(n.val)));
8596 	  break;
8597 	case _TSTEP:
8598 	  n=evalf_double(n,1,contextptr);
8599 	  tstep=absdouble(n._DOUBLE_val);
8600 	  ustep=absdouble(n._DOUBLE_val);
8601 	  vstep=absdouble(n._DOUBLE_val);
8602 	  break;
8603 	case _USTEP:
8604 	  n=evalf_double(n,1,contextptr);
8605 	  ustep=absdouble(n._DOUBLE_val);
8606 	  break;
8607 	case _VSTEP:
8608 	  n=evalf_double(n,1,contextptr);
8609 	  vstep=absdouble(n._DOUBLE_val);
8610 	  break;
8611 	}
8612       }
8613     }
8614     vecteur attributs(1,attribut);
8615     s=read_attributs(vargs,attributs,contextptr);
8616     bool curve3d=false;
8617     if (f.type==_VECT && f._VECTptr->size()==3 && vars.type!=_VECT){ // 3-d curve
8618       if (s==4){
8619 	if (vargs[2].is_symb_of_sommet(at_interval)){
8620 	  vars=symbolic(at_equal,makesequence(vars,vargs[2]));
8621 	  tstep=absdouble(evalf_double(vargs[3],1,contextptr)._DOUBLE_val);
8622 	}
8623 	else
8624 	  vars=symbolic(at_equal,makesequence(vars,symbolic(at_interval,makesequence(vargs[2],vargs[3]))));
8625       }
8626       vars=makevecteur(vars,symbolic(at_equal,makesequence(v__IDNT_e,symbolic(at_interval,makesequence(vmin,vmax)))));
8627       curve3d=true;
8628     }
8629     if (tstep<0)
8630       tstep=(tmax-tmin)/gnuplot_pixels_per_eval;
8631     if (vars.type==_VECT && vars._VECTptr->size()>=2){
8632       vecteur v=*vars._VECTptr;
8633       if (v.size()!=2)
8634 	return gensizeerr(contextptr);
8635       if (readrange(v[0],tmin,tmax,v[0],umin,umax,contextptr) && readrange(v[1],tmin,tmax,v[1],vmin,vmax,contextptr)){
8636 	if (ustep<0)
8637 	  ustep=(umax-umin)/(curve3d?gnuplot_pixels_per_eval:std::sqrt(double(gnuplot_pixels_per_eval)));
8638 	if (vstep<0)
8639 	  vstep=(vmax-vmin)/std::sqrt(double(gnuplot_pixels_per_eval));
8640 	return plotparam3d(f,makevecteur(v[0],v[1]),xmin,xmax,ymin,ymax,zmin,zmax,umin,umax,vmin,vmax,densityplot,f_autoscale,attributs,ustep,vstep,undef,vecteur(0),contextptr);
8641       }
8642       return gensizeerr(contextptr);
8643     }
8644     if (!readrange(vars,tmin,tmax,vars,tmin,tmax,contextptr))
8645       return gensizeerr(gettext("2nd arg must be a free variable"));
8646     return plotparam(f,vars,attributs,densityplot,xmin,xmax,ymin,ymax,tmin,tmax,tstep,eq,parameq,vparam,contextptr);
8647   }
_plotparam(const gen & args,const context * contextptr)8648   gen _plotparam(const gen & args,const context * contextptr){
8649     if ( args.type==_STRNG && args.subtype==-1) return  args;
8650     return paramplotparam(args,true,contextptr);
8651   }
8652   static const char _plotparam_s []="plotparam";
8653   static define_unary_function_eval_quoted (__plotparam,&_plotparam,_plotparam_s);
8654   define_unary_function_ptr5( at_plotparam ,alias_at_plotparam,&__plotparam,_QUOTE_ARGUMENTS,true);
8655 
8656   static const char _courbe_parametrique_s []="courbe_parametrique";
8657   static define_unary_function_eval_quoted (__courbe_parametrique,&_plotparam,_courbe_parametrique_s);
8658   define_unary_function_ptr5( at_courbe_parametrique ,alias_at_courbe_parametrique,&__courbe_parametrique,_QUOTE_ARGUMENTS,true);
8659 
_paramplot(const gen & args,const context * contextptr)8660   gen _paramplot(const gen & args,const context * contextptr){
8661     if ( args.type==_STRNG && args.subtype==-1) return  args;
8662     return paramplotparam(args,false,contextptr);
8663   }
8664   static const char _paramplot_s []="paramplot";
8665   static define_unary_function_eval_quoted (__paramplot,&_paramplot,_paramplot_s);
8666   define_unary_function_ptr5( at_paramplot ,alias_at_paramplot,&__paramplot,_QUOTE_ARGUMENTS,true);
8667 
plotpoints(const vecteur & v,const vecteur & attributs,GIAC_CONTEXT)8668   static gen plotpoints(const vecteur & v,const vecteur & attributs,GIAC_CONTEXT){
8669     gen attribut=attributs.empty()?default_color(contextptr):attributs[0];
8670     vecteur w(v);
8671     iterateur it=w.begin(),itend=w.end();
8672     for (;it!=itend;++it){
8673       if (it->type!=_VECT || it->_VECTptr->size()!=2)
8674 	return gensizeerr(contextptr);
8675       *it=it->_VECTptr->front()+cst_i*it->_VECTptr->back();
8676     }
8677     return symb_pnt(gen(w,_GROUP__VECT),attribut.val,contextptr);
8678     // should change symb_pnt so that attribut is more generic than color
8679   }
_plot(const gen & g,const context * contextptr)8680   gen _plot(const gen & g,const context * contextptr){
8681     if ( g.type==_STRNG && g.subtype==-1) return  g;
8682     gen var,res;
8683     if (g.type!=_VECT && !is_distribution(g) && !is_algebraic_program(g,var,res) )
8684       return _plotfunc(g,contextptr);
8685     vecteur v;
8686     gen g_(g);
8687     if (g.type==_VECT){
8688       v=*g._VECTptr;
8689       int s=int(v.size()),nd=0,nargs=0;
8690       if (s && v[0].type==_FUNC && (nd=is_distribution(v[0])) && 1+(nargs=distrib_nargs(nd))<=s){
8691 	if (is_discrete_distribution(nd))
8692 	  return _histogram(g,contextptr);
8693 	gen d=distribution(nd);
8694 	if (d.type==_FUNC){
8695 	  if (nargs==1)
8696 	    v[0]=symbolic(*d._FUNCptr,v[1]);
8697 	  else
8698 	    v[0]=symbolic(*d._FUNCptr,gen(vecteur(v.begin()+1,v.begin()+1+nargs),_SEQ__VECT));
8699 	  s -= nargs;
8700 	  v.erase(v.begin()+1,v.begin()+1+nargs);
8701 	  if (s==1)
8702 	    g_=v.front();
8703 	  else
8704 	    g_=gen(vecteur(v.begin(),v.end()),_SEQ__VECT);
8705 	}
8706       }
8707     }
8708     else {
8709       int nd;
8710       if ((nd=is_distribution(g))){
8711 	if (is_discrete_distribution(nd))
8712 	  return _histogram(g,contextptr);
8713       }
8714     }
8715     v=plotpreprocess(g_,contextptr);
8716     if (is_undef(v))
8717       return v;
8718     int s=int(v.size());
8719     gen attribut=default_color(contextptr);
8720     vecteur attributs(1,attribut);
8721     gen v0=eval(v[0],1,contextptr);
8722     gen v1=eval(v[1],1,contextptr);
8723     if (s>1 && v0.type<=_REAL && v1.type<=_REAL){
8724       *logptr(contextptr) << gettext("To get a point, run point(")<<v0<<","<<v1<<")" << '\n';
8725       // gen pos=v[0]+cst_i*v1; s=read_attributs(v,attributs,contextptr); return put_attributs(_point(pos,contextptr),attributs,contextptr);
8726     }
8727     if (s>1 && v0.type==_VECT && v1.type==_VECT && v0._VECTptr->size()==v1._VECTptr->size()){
8728       *logptr(contextptr) << gettext("Assuming you want to run polygonplot") << '\n';
8729       vecteur w0=*v0._VECTptr,w1=*v1._VECTptr;
8730       int ss=w0.size(),i;
8731       for (i=0;i<ss;++i){
8732 	if ( (w0[i].type>_REAL && w0[i].type!=_FRAC) || (w1[i].type>_REAL && w1[i].type!=_FRAC))
8733 	  break;
8734       }
8735       if (i==ss){
8736 	// polygonplot
8737 	s=read_attributs(v,attributs,contextptr);
8738 	return put_attributs(_polygonplot(makesequence(v0,v1),contextptr),attributs,contextptr);
8739       }
8740     }
8741     if (g.subtype!=_SEQ__VECT && s==3 ){
8742       if (v[2].type==_IDNT)
8743 	return plotparam(v[0]+cst_i*v[1],v[2],attributs,true,gnuplot_xmin,gnuplot_xmax,gnuplot_ymin,gnuplot_ymax,gnuplot_tmin,gnuplot_tmax,gnuplot_tstep,undef,undef,contextptr); // FIX equation?
8744       if (v[2].is_symb_of_sommet(at_equal)){ // parametric plot
8745 	gen & gw=v[2]._SYMBptr->feuille;
8746 	if (gw.type==_VECT && gw._VECTptr->size()==2){
8747 	  gen gx=gw._VECTptr->front();
8748 	  double inf,sup;
8749 	  if (gx.type==_IDNT && chk_double_interval(gw._VECTptr->back(),inf,sup,contextptr))
8750 	    return plotparam(v[0]+cst_i*v[1],gx,attributs,true,gnuplot_xmin,gnuplot_xmax,gnuplot_ymin,gnuplot_ymax,inf,sup,gnuplot_tstep,undef,undef,contextptr); // FIX EQUATION?
8751 	}
8752       }
8753     }
8754     if (s<1)
8755       return _plotfunc(g,contextptr);
8756     if (g.type==_VECT && g.subtype!=_SEQ__VECT)
8757       return plotpoints(v,attributs,contextptr);
8758     double xmin=gnuplot_xmin,xmax=gnuplot_xmax,ymin=gnuplot_ymin,ymax=gnuplot_ymax,zmin=gnuplot_zmin,zmax=gnuplot_zmax;
8759     gen xvar=vx_var,yvar=y__IDNT_e;
8760     int nstep=gnuplot_pixels_per_eval;
8761     bool showeq=false;
8762     // bool clrplot=true;
8763     // parse options
8764     for (int i=1;i<s;++i){
8765       if (v[i]==at_equation){
8766 	showeq=true;
8767 	continue;
8768       }
8769       if (v[i].type==_IDNT){
8770 	if (i==1)
8771 	  xvar=v[1];
8772 	if (i==2)
8773 	  yvar=v[2];
8774       }
8775       if (i==1 && v[i].is_symb_of_sommet(at_interval)){
8776 	identificateur tmp(" x");
8777 	vecteur w(v);
8778 	w[0]=v[0](tmp,contextptr);
8779 	w[1]=symbolic(at_equal,makesequence(tmp,v[1]));
8780 	return _plot(gen(w,_SEQ__VECT),contextptr);
8781       }
8782       if (i==2 && (v[i].type<_CPLX || v[i].type==_FLOAT_))
8783 	xmin=evalf_double(v[i],1,contextptr)._DOUBLE_val;
8784       if (i==3 && (v[i].type<_CPLX || v[i].type==_FLOAT_))
8785 	xmax=evalf_double(v[i],1,contextptr)._DOUBLE_val;
8786       if (!v[i].is_symb_of_sommet(at_equal))
8787 	continue;
8788       gen & opt=v[i]._SYMBptr->feuille;
8789       if (opt.type!=_VECT || opt._VECTptr->size()!=2)
8790 	continue;
8791       gen opt1=opt._VECTptr->front(),opt2=opt._VECTptr->back();
8792       double inf,sup;
8793       if ( opt1.type==_IDNT &&chk_double_interval(opt2,inf,sup,contextptr)){
8794 	if (i==1){
8795 	  xvar=opt1;
8796 	  xmin=inf;
8797 	  xmax=sup;
8798 	}
8799 	if (i==2){
8800 	  yvar=opt1;
8801 	  ymin=inf;
8802 	  ymax=sup;
8803 	}
8804       }
8805     }
8806     int jstep,kstep;
8807     read_option(v,xmin,xmax,ymin,ymax,zmin,zmax,attributs,nstep,jstep,kstep,contextptr);
8808     bool v0cst=false,v1cst=false;
8809 #ifndef NO_STDEXCEPT
8810     try {
8811       v0cst=lidnt(evalf(v0,1,contextptr)).empty();
8812       v1cst=lidnt(evalf(v1,1,contextptr)).empty();
8813     } catch(std::exception & e) {
8814     }
8815 #endif
8816     if (v0cst && v1cst){
8817       if (s==2 || v[2].is_symb_of_sommet(at_equal))
8818 	return _point(eval(g,1,contextptr),contextptr);
8819       gen v2=eval(v[2],1,contextptr);
8820       if (lidnt(evalf(v2,1,contextptr)).empty())
8821 	return _point(eval(g,1,contextptr),contextptr);
8822     }
8823     if (v0cst && v0.type==_VECT && !v0._VECTptr->empty() && v0._VECTptr->front().type==_VECT)
8824       return plotpoints(*v0._VECTptr,attributs,contextptr);
8825     return plotfunc(v[0],xvar,attributs,false,xmin,xmax,ymin,ymax,zmin,zmax,nstep,0,showeq,contextptr);
8826   }
8827   static const char _plot_s []="plot"; // FIXME use maple arguments
8828   static define_unary_function_eval_quoted (__plot,&_plot,_plot_s);
8829   define_unary_function_ptr5( at_plot ,alias_at_plot,&__plot,_QUOTE_ARGUMENTS,true);
8830 
8831   static const char _graphe_s []="graphe";
8832   static define_unary_function_eval_quoted (__graphe,&_plot,_graphe_s);
8833   define_unary_function_ptr5( at_graphe ,alias_at_graphe,&__graphe,_QUOTE_ARGUMENTS,true);
8834 
_plotpolar(const gen & args,const context * contextptr)8835   gen _plotpolar(const gen & args,const context * contextptr){
8836     if ( args.type==_STRNG && args.subtype==-1) return  args;
8837     // args= [rho(theta),theta] should add a theta interval
8838     vecteur vargs(plotpreprocess(args,contextptr));
8839     if (is_undef(vargs))
8840       return vargs;
8841     gen rho=vargs.front();
8842     gen theta=vargs[1];
8843     if (theta.is_symb_of_sommet(at_equal))
8844       theta=theta._SYMBptr->feuille._VECTptr->front();
8845     if (theta.type!=_IDNT)
8846       return gensizeerr(gettext("2nd arg must be a free variable"));
8847     // vargs.front()=symbolic(at_re,rho)*exp(cst_i*degtorad(theta,contextptr),contextptr);
8848     vargs.front()=makevecteur(rho*cos(angletorad(theta,contextptr),contextptr),rho*sin(angletorad(theta,contextptr),contextptr));
8849     return _plotparam(gen(vargs,_SEQ__VECT),contextptr);
8850   }
8851   static const char _plotpolar_s []="plotpolar";
8852   static define_unary_function_eval_quoted (__plotpolar,&_plotpolar,_plotpolar_s);
8853   define_unary_function_ptr5( at_plotpolar ,alias_at_plotpolar,&__plotpolar,_QUOTE_ARGUMENTS,true);
8854 
8855   static const char _polarplot_s []="polarplot";
8856   static define_unary_function_eval_quoted (__polarplot,&_plotpolar,_polarplot_s);
8857   define_unary_function_ptr5( at_polarplot ,alias_at_polarplot,&__polarplot,_QUOTE_ARGUMENTS,true);
8858 
8859   static const char _courbe_polaire_s []="courbe_polaire";
8860   static define_unary_function_eval_quoted (__courbe_polaire,&_plotpolar,_courbe_polaire_s);
8861   define_unary_function_ptr5( at_courbe_polaire ,alias_at_courbe_polaire,&__courbe_polaire,_QUOTE_ARGUMENTS,true);
8862 
ck_parameter_x(GIAC_CONTEXT)8863   void ck_parameter_x(GIAC_CONTEXT){
8864 #if 1 // ndef GIAC_HAS_STO_38
8865     if (x__IDNT_e.evalf(1,contextptr)!=x__IDNT_e)
8866       *logptr(contextptr) << gettext("Variable x should be purged") << '\n';
8867 #endif
8868   }
8869 
ck_parameter_y(GIAC_CONTEXT)8870   void ck_parameter_y(GIAC_CONTEXT){
8871 #if 1 // ndef GIAC_HAS_STO_38
8872     if (y__IDNT_e.evalf(1,contextptr)!=y__IDNT_e)
8873       *logptr(contextptr) << gettext("Variable y should be purged") << '\n';
8874 #endif
8875   }
8876 
ck_parameter_z(GIAC_CONTEXT)8877   void ck_parameter_z(GIAC_CONTEXT){
8878 #if 1 // ndef GIAC_HAS_STO_38
8879     if (z__IDNT_e.evalf(1,contextptr)!=z__IDNT_e)
8880       *logptr(contextptr) << gettext("Variable z should be purged") << '\n';
8881 #endif
8882   }
8883 
ck_parameter(const gen & g,GIAC_CONTEXT)8884   void ck_parameter(const gen & g,GIAC_CONTEXT){
8885 #if 1 // ndef GIAC_HAS_STO_38
8886     if ( (g.type==_IDNT) && (g.evalf(1,contextptr)!=g) )
8887       *logptr(contextptr) << gettext("Variable ")+g.print(contextptr)+gettext(" should be purged") << '\n';
8888 #endif
8889   }
8890 
ck_parameter_t(GIAC_CONTEXT)8891   void ck_parameter_t(GIAC_CONTEXT){
8892 #if 1 // ndef GIAC_HAS_STO_38
8893     if (t__IDNT_e.evalf(1,contextptr)!=t__IDNT_e)
8894       *logptr(contextptr) << gettext("Variable t should be purged") << '\n';
8895 #endif
8896   }
8897 
ck_parameter_u(GIAC_CONTEXT)8898   void ck_parameter_u(GIAC_CONTEXT){
8899 #if 1 // ndef GIAC_HAS_STO_38
8900     if (u__IDNT_e.evalf(1,contextptr)!=u__IDNT_e)
8901       *logptr(contextptr) << gettext("Variable u should be purged") << '\n';
8902 #endif
8903   }
8904 
ck_parameter_v(GIAC_CONTEXT)8905   void ck_parameter_v(GIAC_CONTEXT){
8906 #if 1 // ndef GIAC_HAS_STO_38
8907     if (v__IDNT_e.evalf(1,contextptr)!=v__IDNT_e)
8908       *logptr(contextptr) << gettext("Variable v should be purged") << '\n';
8909 #endif
8910   }
8911 
8912   // Parametric equation
_parameq(const gen & args,GIAC_CONTEXT)8913   gen _parameq(const gen & args,GIAC_CONTEXT){
8914     if ( args.type==_STRNG && args.subtype==-1) return  args;
8915     if (args.is_symb_of_sommet(at_equal)){
8916       // supposed to be a cartesian equation in x/y
8917       gen x0,y0,propre,equation_reduite,ratparam;
8918       vecteur V0,V1,param_curves;
8919       if (conique_reduite(args,undef,makevecteur(vx_var,y__IDNT_e),x0,y0,V0,V1,propre,equation_reduite,param_curves,ratparam,false,contextptr))
8920 	return ratparam;
8921       return gensizeerr(contextptr);
8922     }
8923     vecteur v;
8924     int s=1;
8925     if (args.type!=_VECT){
8926       v=vecteur(1,args);
8927       v.push_back(t__IDNT_e);
8928     }
8929     else {
8930       s=int(args._VECTptr->size());
8931       if (s==1)
8932 	return _parameq(args._VECTptr->front(),contextptr);
8933       if (s>=2 && (*args._VECTptr)[1].is_symb_of_sommet(at_pnt))
8934 	return _parameq(args._VECTptr->front(),contextptr);
8935       if (s<2)
8936 	return gensizeerr(contextptr);
8937       v=*args._VECTptr;
8938     }
8939     // e= symb_curve or line or cercle
8940     gen e=remove_at_pnt(v.front());
8941     if (e.is_symb_of_sommet(at_Bezier)){
8942       gen f=e._SYMBptr->feuille;
8943       if (f.type!=_VECT || f._VECTptr->size()<2)
8944 	return gensizeerr(contextptr);
8945       gen t=v[1];
8946       vecteur & w=*f._VECTptr;
8947       int s=int(w.size())-1;
8948       vecteur coeff=pascal_nth_line(s);
8949       gen res=0;
8950       for (int i=0;i<=s;++i){
8951 	res += coeff[i]*pow(t,i,contextptr)*pow(1-t,s-i,contextptr)*w[i];
8952       }
8953       return res;
8954     }
8955     if (e.is_symb_of_sommet(at_hypersurface)){
8956       gen & f = e._SYMBptr->feuille;
8957       if (f.type==_VECT && f._VECTptr->size()==3){
8958 	gen & p=f._VECTptr->front();
8959 	if (p.type==_VECT && !p._VECTptr->empty())
8960 	  return p._VECTptr->front();
8961       }
8962       return undef;
8963     }
8964     gen t=v[1],u,par_eq;
8965     if (e.type==_SYMB && (e._SYMBptr->sommet==at_hyperplan || e._SYMBptr->sommet==at_hypersphere) ){
8966       if (s<2){
8967 	ck_parameter_u(contextptr);
8968 	t=u__IDNT_e;
8969       }
8970       if (s<3){
8971 	ck_parameter_v(contextptr);
8972 	u=v__IDNT_e;
8973       }
8974       else
8975 	u=v[2];
8976       if (e._SYMBptr->sommet==at_hypersphere){
8977 	gen centre,rayon;
8978 	if (!centre_rayon(e,centre,rayon,false,contextptr) ||centre.type!=_VECT)
8979 	  return gensizeerr(contextptr);
8980 	vecteur & v=*centre._VECTptr;
8981 	if (v.size()!=3)
8982 	  return gendimerr(contextptr);
8983 	par_eq=centre+makevecteur(rayon*cos(t,contextptr)*cos(u,contextptr),rayon*cos(t,contextptr)*sin(u,contextptr),rayon*sin(t,contextptr));
8984       }
8985       else {
8986 	vecteur P,n;
8987 	if (!hyperplan_normal_point(e,n,P))
8988 	  return gensizeerr(contextptr);
8989 	vecteur v1,v2;
8990 	if (!normal3d(n,v1,v2))
8991 	  return gensizeerr(contextptr);
8992 	par_eq=t*v1+u*v2+P;
8993       }
8994       return par_eq;
8995     }
8996     if (s==1)
8997       ck_parameter_t(contextptr);
8998     if ((e.type==_SYMB) && (e._SYMBptr->sommet==at_cercle))
8999       e=cercle2curve(e,contextptr);
9000     if (e.type==_VECT)
9001       e=line2curve(e);
9002     if (is_undef(e))
9003       return e;
9004     if ( (e.type==_SYMB) && (e._SYMBptr->sommet==at_curve)){
9005       vecteur v=*e._SYMBptr->feuille._VECTptr->front()._VECTptr;
9006       gen pareq=v[0];
9007       if (v.size()>6 && !is_undef(v[6]))
9008 	pareq=v[6];
9009       gen tmp= subst(pareq,v[1],t,false,contextptr);
9010       if (tmp.type==_VECT)
9011 	tmp.subtype=0;
9012       return tmp;
9013     }
9014     else
9015       return e;
9016   }
9017   static const char _parameq_s []="parameq";
9018   static define_unary_function_eval (__parameq,&_parameq,_parameq_s);
9019   define_unary_function_ptr5( at_parameq ,alias_at_parameq,&__parameq,0,true);
9020 
rationalparam2equation(const gen & at_orig,const gen & t_orig,const gen & x,const gen & y,GIAC_CONTEXT)9021   gen rationalparam2equation(const gen & at_orig,const gen & t_orig,const gen &x,const gen & y,GIAC_CONTEXT){
9022     if (t_orig==x || t_orig==y){
9023       gen t(identificateur(t_orig.print(contextptr)+"_"));
9024       return rationalparam2equation(subst(at_orig,t_orig,t,false,contextptr),t,x,y,contextptr);
9025     }
9026     // detect function plots
9027     if (at_orig.is_symb_of_sommet(at_plus) && at_orig._SYMBptr->feuille.type==_VECT){
9028       vecteur & v=*at_orig._SYMBptr->feuille._VECTptr;
9029       if (v.size()==2 && v[0]==t_orig && v[1].is_symb_of_sommet(at_prod) && v[1]._SYMBptr->feuille.type==_VECT){
9030 	vecteur & w=*v[1]._SYMBptr->feuille._VECTptr;
9031 	if (w.size()==2 && w[0]==cst_i)
9032 	  return y-subst(w[1],t_orig,x,false,contextptr);
9033       }
9034     }
9035     gen anum,aden,ax,ay;
9036     gen at=at_orig;
9037     gen t=t_orig;
9038     bool approx=has_num_coeff(at);
9039     if (approx)
9040       at=exact(at,contextptr);
9041     ax=re(at,contextptr);
9042     ay=im(at,contextptr);
9043     if (ax==t)
9044       return y-subst(ay,t,x,false,contextptr);
9045     if (t==x){
9046       t=identificateur(" t");
9047       at=subst(at,x,t,true,contextptr);
9048     }
9049     if (t==y){
9050       t=identificateur(" t");
9051       at=subst(at,y,t,true,contextptr);
9052     }
9053     vecteur v=lvar(ax);
9054     fraction f=e2r(ax,v,contextptr);
9055     fxnd(f,anum,aden);
9056     anum=r2e(anum,v,contextptr);
9057     aden=r2e(aden,v,contextptr);
9058     gen eq1=anum-x*aden;
9059     v=lvar(ay);
9060     f=e2r(ay,v,contextptr);
9061     fxnd(f,anum,aden);
9062     anum=r2e(anum,v,contextptr);
9063     aden=r2e(aden,v,contextptr);
9064     gen eq2=anum-y*aden;
9065     gen res=_resultant(makevecteur(eq1,eq2,t),contextptr);
9066     vecteur resl=alg_lvar(res);
9067     res=e2r(res,resl,contextptr);
9068     if (res.type==_FRAC)
9069       res=res._FRACptr->num;
9070     if (res.type==_POLY){
9071       gen c=Tcontent(*res._POLYptr);
9072       if (is_positive(-res._POLYptr->coord.front()))
9073 	c=-c;
9074       res=*res._POLYptr/c;
9075     }
9076     res=r2e(res,resl,contextptr);
9077     if (is_undef(res)) return res;
9078     if (approx)
9079       res=evalf(res,1,contextptr);
9080     v=lvar(res);
9081     f=e2r(res,v,contextptr);
9082     fxnd(f,anum,aden);
9083     if (anum.type!=_POLY)
9084       return res;
9085     if (approx)
9086       anum=anum/anum._POLYptr->coord.front().value;
9087     else
9088       ppz(*anum._POLYptr);
9089     res=r2e(anum,v,contextptr);
9090     return res;
9091   }
9092 
equation(const gen & arg,const gen & x,const gen & y,const gen & z,GIAC_CONTEXT)9093   static gen equation(const gen & arg,const gen & x,const gen & y, const gen & z,GIAC_CONTEXT){
9094     if (arg.type==_VECT){
9095       vecteur res;
9096       const_iterateur it=arg._VECTptr->begin(),itend=arg._VECTptr->end();
9097       gen prev;
9098       for (;it!=itend;++it){
9099 	gen tmp=equation(*it,x,y,z,contextptr);
9100 	if (tmp==prev)
9101 	  continue;
9102 	prev=tmp;
9103 	//if (calc_mode(contextptr)==1) tmp=remove_equal(tmp);
9104 	res.push_back(tmp);
9105       }
9106       // if (calc_mode(contextptr)==1) return symbolic(at_equal,makesequence(_prod(res,contextptr),0));
9107       if (res.size()==1)
9108 	return res.front();
9109       return res;
9110     }
9111     gen e=remove_at_pnt(arg);
9112     vecteur vxyz(makevecteur(x,y,z));
9113     if (e.is_symb_of_sommet(at_hyperplan)){
9114       gen & f=e._SYMBptr->feuille;
9115       if (ckmatrix(f) && f._VECTptr->size()==2){
9116 	return symbolic(at_equal,makesequence(normal(dotvecteur(*f._VECTptr->front()._VECTptr,subvecteur(vxyz,*f._VECTptr->back()._VECTptr)),contextptr),zero));
9117       }
9118     }
9119     if (e.is_symb_of_sommet(at_hypersphere)){
9120       gen f=hypersphere_equation(e,vxyz);
9121       return symbolic(at_equal,makesequence(f,zero));
9122     }
9123     if (e.is_symb_of_sommet(at_hypersurface)){
9124       gen f=hypersurface_equation(e,vxyz,contextptr);
9125       return symbolic(at_equal,makesequence(f,zero));
9126     }
9127     if ((e.type==_SYMB) && (e._SYMBptr->sommet==at_cercle)){
9128       gen centre,rayon,r,i;
9129       if (!centre_rayon(e,centre,rayon,false,contextptr))
9130 	return gensizeerr(contextptr);
9131       rayon=recursive_normal(rayon,contextptr);
9132       reim(rayon,r,i,contextptr);
9133       r=recursive_normal(r*r+i*i,contextptr);
9134       return symbolic(at_equal,makesequence(pow(x-re(centre,contextptr),2)+pow(y-im(centre,contextptr),2),r));
9135     }
9136     if ( (e.type==_VECT) && (e._VECTptr->size()==2) ){
9137       gen A=e._VECTptr->front();
9138       gen B=e._VECTptr->back();
9139       gen v=B-A;
9140       if (v.type==_VECT){ // 3-d line?
9141 	vecteur & vv=*v._VECTptr;
9142 	if (vv.size()!=3 || A.type!=_VECT || A._VECTptr->size()!=3)
9143 	  return gensizeerr(contextptr);
9144 	vecteur & vA=*A._VECTptr;
9145 	if (is_zero(vv[0],contextptr)&&is_zero(vv[1],contextptr))
9146 	  return gen(makevecteur(symbolic(at_equal,makesequence(x,vA[0])),symbolic(at_equal,makesequence(y,vA[1]))),_SEQ__VECT);
9147 	vecteur v1(makevecteur(vv[1],-vv[0],0));
9148 	vecteur v2(cross(vv,v1,contextptr));
9149 	vecteur xyz(subvecteur(vxyz,vA));
9150 	return gen(makevecteur(symbolic(at_equal,makesequence(normal(dotvecteur(v1,xyz),contextptr),zero)),symbolic(at_equal,makesequence(normal(dotvecteur(v2,xyz),contextptr),zero))),_SEQ__VECT);
9151       }
9152       gen a=im(v,contextptr);
9153       gen b=-re(v,contextptr),d;
9154 #ifdef NO_STDEXCEPT
9155       d=gcd(a,b);
9156 #else
9157       try {
9158 	d=gcd(a,b);
9159       } catch (std::runtime_error & err){
9160 	d=1;
9161       }
9162 #endif
9163       a=normal(a/d,contextptr);
9164       b=normal(b/d,contextptr);
9165       gen Ar,Ai;
9166       reim(A,Ar,Ai,contextptr);
9167       gen c=a*Ar+b*Ai;
9168       if (!is_zero(b,contextptr))
9169 	return symbolic(at_equal,makesequence(y,normal(-a/b,contextptr)*x+normal(c/b,contextptr)));
9170       return symbolic(at_equal,makesequence(x,normal(c/a,contextptr)));//symbolic(at_equal,makesequence(a*x+b*y,c));
9171     }
9172     if ( (e.type==_SYMB) && (e._SYMBptr->sommet==at_curve)){
9173       vecteur v=*e._SYMBptr->feuille._VECTptr->front()._VECTptr;
9174       if (v.size()>=6 && !is_undef(v[5]))
9175 	return symbolic(at_equal,makesequence(subst(v[5],makevecteur(x__IDNT_e,y__IDNT_e,z__IDNT_e),makevecteur(x,y,z),false,contextptr),0));
9176       if (v[1].type!=_IDNT)
9177 	return gensizeerr(gettext("Wrong parameter type ")+v[1].print(contextptr));
9178       identificateur & id=*v[1]._IDNTptr;
9179       if (v[0].type!=_VECT){
9180 	gen m,tmin,tmax;
9181 	double T=1;
9182 	if (find_curve_parametrization(e,m,v[1],T,tmin,tmax,false,contextptr))
9183 	  v[0]=m;
9184 	gen xt=re(v[0],contextptr);
9185 	rewrite_with_t_real(xt,v[1],contextptr);
9186 	gen yt=im(v[0],contextptr);
9187 	rewrite_with_t_real(yt,v[1],contextptr);
9188 	// if xt and yt are rational fractions of v[1], use the resultant
9189 	if (lvarxpow(makevecteur(xt,yt),v[1]).size()<=1){
9190 	  // return _resultant(makevecteur(xt-x,yt-y,v[1]),contextptr);
9191 	  return symbolic(at_equal,makesequence(rationalparam2equation(v[0],v[1],x,y,contextptr),0));
9192 	}
9193 	vecteur w(solve(xt-x,v[1],0,contextptr));
9194 	if (w.empty())
9195 	  return gensizeerr(gettext("Can't isolate"));
9196 	yt=subst(yt,v[1],w.front(),false,contextptr);
9197 	return symbolic(at_equal,makesequence(y,yt));
9198       }
9199       if (v[0].type==_VECT && v[0]._VECTptr->size()==3){
9200 	// 3-d curve -> 2 equations
9201 	vecteur & vv=*v[0]._VECTptr;
9202 	gen xt=vv[0],yt=vv[1],zt=vv[2];
9203 	if (lvarxpow(makevecteur(xt,yt,zt),v[1]).size()<=1){
9204 	  return makevecteur(_resultant(makesequence(xt-x,zt-z,id),contextptr),_resultant(makesequence(yt-y,zt-z,id),contextptr));
9205 	}
9206       }
9207       return gensizeerr(contextptr);
9208     }
9209     return e;
9210   }
9211 
_equation(const gen & args,GIAC_CONTEXT)9212   gen _equation(const gen & args,GIAC_CONTEXT){
9213     if ( args.type==_STRNG && args.subtype==-1) return  args;
9214     if (args.type!=_VECT || args._VECTptr->size()!=2 || (*args._VECTptr)[1].type!=_IDNT){
9215       ck_parameter_x(contextptr);
9216       ck_parameter_y(contextptr);
9217       ck_parameter_z(contextptr);
9218       return equation(args,x__IDNT_e,y__IDNT_e,z__IDNT_e,contextptr);
9219     }
9220     vecteur v(*args._VECTptr);
9221     // e= symb_curve or line or cercle
9222     gen xy=v.back();
9223     if ( (xy.type!=_VECT) || (xy._VECTptr->size()<2))
9224       return gensizeerr(contextptr);
9225     vecteur & vxyz=*xy._VECTptr;
9226     gen x(vxyz[0]),y(vxyz[1]),z;
9227     if (vxyz.size()==3)
9228       z=vxyz[2];
9229     return equation(v.front(),x,y,z,contextptr);
9230   }
9231   static const char _equation_s []="equation";
9232   static define_unary_function_eval (__equation,&_equation,_equation_s);
9233   define_unary_function_ptr5( at_equation ,alias_at_equation,&__equation,0,true);
9234 
9235   // If subtype is segment/vector or halfline remove
9236   // the element of v that are not in the segment/halfline/... ab
remove_not_in_segment(const gen & a,const gen & b,int subtype,const vecteur & v,GIAC_CONTEXT)9237   vecteur remove_not_in_segment(const gen & a,const gen & b,int subtype,const vecteur & v,GIAC_CONTEXT){
9238     if (subtype==_LINE__VECT || is_undef(v))
9239       return v;
9240     gen ab(b-a);
9241     const_iterateur it=v.begin(),itend=v.end();
9242     vecteur res;
9243     for (;it!=itend;++it){
9244       if (is_undef(*it))
9245 	continue;
9246       gen t=scalar_product(remove_at_pnt(*it)-a,ab,contextptr)/scalar_product(ab,ab,contextptr);
9247       if (is_undef(t)) continue;
9248       if (subtype==_HALFLINE__VECT){
9249 	if (!is_strictly_positive(-t,contextptr))
9250 	  res.push_back(*it);
9251       }
9252       else {
9253 	if (!is_strictly_positive(-t,contextptr) && !is_strictly_positive(t-1,contextptr))
9254 	  res.push_back(*it);
9255       }
9256     }
9257     return res;
9258   }
9259 
remove_not_in_arc(const vecteur & v_,const gen & g,GIAC_CONTEXT)9260   vecteur remove_not_in_arc(const vecteur & v_,const gen & g,GIAC_CONTEXT){
9261     vecteur v;
9262     for (unsigned i=0;i<v_.size();++i){
9263       if (!is_undef(v_[i]))
9264 	v.push_back(v_[i]);
9265     }
9266     if (g.type==_VECT && g._VECTptr->size()==2)
9267       return remove_not_in_segment(g._VECTptr->front(),g._VECTptr->back(),g.subtype,v,contextptr);
9268     if (!g.is_symb_of_sommet(at_cercle))
9269       return v;
9270     gen &f=g._SYMBptr->feuille;
9271     if (f.type!=_VECT || f._VECTptr->size()!=3)
9272       return v;
9273     vecteur & fv=*f._VECTptr;
9274     if (fv.front().type!=_VECT || fv.front()._VECTptr->size()!=2)
9275       return v;
9276     gen a=fv.front()._VECTptr->front(),b=fv.front()._VECTptr->back(),alpha=fv[1],beta=fv[2];
9277     if (is_greater(beta-alpha,cst_two_pi,contextptr))
9278       return v;
9279     alpha=alpha-_floor(alpha/cst_two_pi,contextptr)*cst_two_pi;
9280     beta=beta-_floor(beta/cst_two_pi,contextptr)*cst_two_pi;
9281     if (is_greater(alpha,beta,contextptr))
9282       beta+=cst_two_pi;
9283     gen centre=(b+a)/2,rayon=(b-a)/2;
9284     const_iterateur it=v.begin(),itend=v.end();
9285     vecteur res;
9286     for (;it!=itend;++it){
9287       gen gamma=arg((remove_at_pnt(*it)-centre)/rayon,contextptr);
9288       if (is_strictly_positive(-gamma,contextptr))
9289 	gamma+=cst_two_pi;
9290       if (is_greater(gamma,alpha,contextptr) && is_greater(beta,gamma,contextptr))
9291 	res.push_back(*it);
9292     }
9293     return res;
9294   }
9295 
interdroitecercle(const gen & a,const gen & b,GIAC_CONTEXT)9296   vecteur interdroitecercle(const gen & a,const gen &b,GIAC_CONTEXT){
9297     // D inter C
9298     gen centre,rayon;
9299     if (!centre_rayon(b,centre,rayon,true,contextptr))
9300       return vecteur(1,gensizeerr(contextptr));
9301     // projection of the center of C over D
9302     gen a1(a._VECTptr->front()),a2(a._VECTptr->back()); // D=(a1a2)
9303     if (a1.type==_VECT && b.is_symb_of_sommet(at_cercle))
9304       return vecteur(1,gensizeerr(gettext("3-d line/2-d circle")));
9305     if (a1.type!=_VECT && b.is_symb_of_sommet(at_hypersphere))
9306       return vecteur(1,gensizeerr(gettext("2-d line/sphere")));
9307     gen t(projection(a1,a2,centre,contextptr));
9308     if (is_undef(t))
9309       return vecteur(1,t);
9310     gen pr(t*a2+(1-t)*a1);
9311     gen a_pr(recursive_normal(pr-centre,contextptr));
9312     gen delta(abs_norm(a_pr,contextptr));
9313     if (ck_is_strictly_positive(recursive_normal(delta-rayon,contextptr),contextptr))
9314       return vecteur(0);
9315     gen a_pr_perp=a2-a1;
9316     a_pr_perp=rdiv(a_pr_perp,abs_norm(a_pr_perp,contextptr),contextptr);
9317     gen d_a(sqrt(pow(rayon,plus_two,contextptr)-pow(delta,plus_two,contextptr),contextptr));
9318     gen I1(recursive_normal(pr+d_a*a_pr_perp,contextptr)),I2(recursive_normal(pr-d_a*a_pr_perp,contextptr));
9319     if (I1.type==_VECT)
9320       I1.subtype=_POINT__VECT;
9321     if (I2.type==_VECT)
9322       I2.subtype=_POINT__VECT;
9323     return remove_not_in_arc(remove_not_in_segment(a1,a2,a.subtype,makevecteur(symb_pnt(I1,default_color(contextptr),contextptr),symb_pnt(I2,default_color(contextptr),contextptr)),contextptr),b,contextptr);
9324   }
9325 
9326 
interpolygone(const vecteur & p,const gen & bb,GIAC_CONTEXT)9327   vecteur interpolygone(const vecteur & p,const gen & bb,GIAC_CONTEXT){
9328     vecteur res;
9329     const_iterateur it=p.begin(),itend=p.end();
9330     if (itend-it<2)
9331       return res;
9332     for (++it;it!=itend;++it){
9333       gen tmp=symbolic(at_pnt,gen(makevecteur(gen(makevecteur(*(it-1),*it),_GROUP__VECT),0),_PNT__VECT));
9334       vecteur add(inter(tmp,bb,contextptr));
9335       const_iterateur jt=add.begin(),jtend=add.end();
9336       for (;jt!=jtend;++jt){
9337 	if (!equalposcomp(res,*jt))
9338 	  res.push_back(*jt);
9339       }
9340     }
9341     return res;
9342   }
9343 
inter2cercles_or_spheres(const gen & centre_a,const gen & rayon_a2,const gen & centre_b,const gen & rayon_b2,bool a2d,GIAC_CONTEXT)9344   vecteur inter2cercles_or_spheres(const gen & centre_a,const gen & rayon_a2,const gen & centre_b,const gen & rayon_b2,bool a2d,GIAC_CONTEXT){
9345     gen ab(centre_b-centre_a);
9346     gen ab2(abs_norm2(ab,contextptr));
9347     gen ab2minusr2=ab2-rayon_a2-rayon_b2;
9348     if (is_strictly_greater(ab2minusr2,0,contextptr) && is_strictly_greater(pow(ab2minusr2,2)-4*rayon_a2*rayon_b2,0,contextptr) )
9349       return vecteur(0); // empty
9350     gen ababs(sqrt(ab2,contextptr));
9351     if (!a2d && (centre_a.type!=_VECT || centre_a._VECTptr->size()!=3 || centre_b.type!=_VECT || centre_b._VECTptr->size()!=3 ))
9352       return vecteur(1,gensizeerr(contextptr));
9353     // delta=ra^2-rb^2+AB^2
9354     gen delta=rayon_a2-rayon_b2+ab2;
9355     gen ab4=centre_a+delta/2/ab2*ab;
9356     gen d_perp(sqrt(4*ab2*rayon_a2-pow(delta,2),contextptr)/2/ab2);
9357     if (a2d){ // circle inter circle = 2 points (or 1)
9358       gen ab_perp(im(ab,contextptr)-cst_i*re(ab,contextptr));
9359       return makevecteur(symb_pnt(ratnormal(ab4+d_perp*ab_perp,contextptr),default_color(contextptr),contextptr),symb_pnt(ratnormal(ab4-d_perp*ab_perp,contextptr),default_color(contextptr),contextptr));
9360     }
9361     else { // 3-d sphere inter sphere = 2-d circle
9362       // we will draw a parametric curve in the plan perpendicular to ab
9363       // at ab4, with radius d_perp
9364       // Find 2 vectors normal to ab
9365       vecteur v1,v2;
9366       if (!normal3d(ab,v1,v2))
9367 	return vecteur(1,gensizeerr(contextptr));
9368       d_perp=sqrt(rayon_a2-pow(delta,2)/4/ab2,contextptr);
9369       gen eq=ab4+d_perp/abs_norm(v1,contextptr)*symb_cos(vx_var)*v1+d_perp/abs_norm(v2,contextptr)*symb_sin(vx_var)*v2;
9370       return makevecteur(_plotparam(eq,contextptr));
9371     }
9372   }
9373 
curveintercircle(const gen & curve,const gen & circle,bool iscircle,GIAC_CONTEXT)9374   vecteur curveintercircle(const gen & curve,const gen &circle,bool iscircle,GIAC_CONTEXT){
9375     gen f=curve._SYMBptr->feuille;
9376     if (f.type!=_VECT || f._VECTptr->empty() || f._VECTptr->front().type!=_VECT)
9377       return vecteur(1,gensizeerr(contextptr));
9378     vecteur vf=*f._VECTptr->front()._VECTptr;
9379     gen m,tmin,tmax;
9380     double T=1e300;
9381     if (vf.size()>5 && !is_undef(vf[5])){
9382       // use parametric equation for circle or line
9383       gen carteq=vf[5];
9384       gen intervart("intervart",contextptr);
9385       if (find_curve_parametrization(circle,m,intervart,T,tmin,tmax,false,contextptr)){
9386 	gen circlex,circley;
9387 	reim(m,circlex,circley,contextptr);
9388 	carteq=subst(carteq,makevecteur(x__IDNT_e,y__IDNT_e),makevecteur(circlex,circley),false,contextptr);
9389 	gen s=solve(carteq,intervart,0,contextptr);
9390 	if (s.type==_VECT){
9391 	  vecteur res;
9392 	  for (int i=0;i<int(s._VECTptr->size());++i)
9393 	    res.push_back(subst(m,intervart,s[i],false,contextptr));
9394 	  return remove_not_in_arc(res,circle,contextptr);
9395 	}
9396       }
9397     }
9398     if (vf.size()<2 || vf[1].type!=_IDNT)
9399       return vecteur(1,gensizeerr(contextptr));
9400     if (find_curve_parametrization(curve,m,vf[1],T,tmin,tmax,false,contextptr)){
9401       vf[0]=m;
9402     }
9403     gen eq;
9404 #ifndef NO_STDEXCEPT
9405     try {
9406 #endif
9407       if (iscircle){
9408 	gen centre,rayon;
9409 	if (!centre_rayon(circle,centre,rayon,false,contextptr))
9410 	  return vecteur(1,gensizeerr(contextptr)); // don't care about radius sign
9411 	gen rec,imc,rer,imr,ref,imf;
9412 	rec=re(centre,contextptr);
9413 	imc=im(centre,contextptr);
9414 	rer=re(rayon,contextptr);
9415 	imr=im(rayon,contextptr);
9416 	bool b=do_lnabs(contextptr);
9417 	do_lnabs(false,contextptr);
9418 	ref=re(vf[0],contextptr);
9419 	imf=im(vf[0],contextptr);
9420 	do_lnabs(b,contextptr);
9421 	eq=pow(ref-rec,2,contextptr)+pow(imf-imc,2,contextptr)-rer*rer-imr*imr;
9422       }
9423       else { // line
9424 	gen A(circle._VECTptr->front()),B(circle._VECTptr->back());
9425 	gen reA,imA,reB,imB,ref,imf;
9426 	reA=re(A,contextptr);
9427 	imA=im(A,contextptr);
9428 	reB=re(B,contextptr);
9429 	imB=im(B,contextptr);
9430 	bool b=do_lnabs(contextptr);
9431 	do_lnabs(false,contextptr);
9432 	ref=re(vf[0],contextptr);
9433 	imf=im(vf[0],contextptr);
9434 	do_lnabs(b,contextptr);
9435 	eq=(reA-ref)*(imA-imB)-(imA-imf)*(reA-reB);
9436       }
9437       eq=ratnormal(eq,contextptr);
9438       vecteur num,den;
9439       prod2frac(eq,num,den);
9440       eq=vecteur2prod(num);
9441       eq=normal(eq,contextptr);
9442       vecteur res=solve(eq,*vf[1]._IDNTptr,0,contextptr);
9443       int s=int(res.size());
9444       for (int i=0;i<s;++i){
9445 	res[i]=symb_pnt(subst(vf[0],vf[1],res[i],false,contextptr),contextptr);
9446       }
9447       return remove_not_in_arc(res,circle,contextptr);
9448 #ifndef NO_STDEXCEPT
9449     } catch (std::runtime_error & ){
9450       last_evaled_argptr(contextptr)=NULL;
9451       *logptr(contextptr) << gettext("Unable to solve intersection equation ") << eq << '\n';
9452       return makevecteur(symbolic(at_inter,makesequence(curve,circle)));
9453     }
9454 #endif
9455   }
9456 
_innertln(const gen & g0,GIAC_CONTEXT)9457   gen _innertln(const gen & g0,GIAC_CONTEXT){
9458     return symbolic(at_innertln,g0);
9459   }
9460   static const char _innertln_s[]="innertln";
9461   static define_unary_function_eval(__innertln,&_innertln,_innertln_s);
9462   define_unary_function_ptr5( at_innertln ,alias_at_innertln,&__innertln,0,true);
equationintercurve(const gen & at_orig,const gen & t,const gen & b,const gen & bu_orig,const gen & u,GIAC_CONTEXT)9463   static vecteur equationintercurve(const gen & at_orig,const gen & t,const gen & b,const gen & bu_orig,const gen & u,GIAC_CONTEXT){
9464     gen bu=bu_orig,at=at_orig;
9465     gen m,tmin,tmax; double T=1e300;
9466     if (find_curve_parametrization(b,m,u,T,tmin,tmax,false,contextptr)){
9467       bu=m;
9468     }
9469     bool approx=has_num_coeff(bu) || has_num_coeff(at);
9470     if (approx){
9471       bu=exact(bu,contextptr);
9472       at=exact(at,contextptr);
9473     }
9474     // at has a rational parametrization, find cartesian equation
9475     if (u.type!=_IDNT)
9476       return vecteur(1,gensizeerr(contextptr));
9477     gen x("x__"+print_INT_(std_rand()),contextptr),y("y__"+print_INT_(std_rand()),contextptr);
9478     gen eq=rationalparam2equation(at,t,x,y,contextptr),tmp;
9479     if (is_undef(eq))
9480       return vecteur(1,eq);
9481     // replace bu inside and solve for u
9482     // insure ln are considered as reals
9483     vecteur vln=lop(bu,at_ln),wln(vln);
9484     for (int i=0;i<int(vln.size());++i){
9485       if (vln[i].type==_SYMB)
9486 	wln[i]=symbolic(at_innertln,vln[i]._SYMBptr->feuille);
9487     }
9488     gen bu1=subst(bu,vln,wln,false,contextptr);
9489     eq=subst(eq,makevecteur(x,y),makevecteur(re(bu1,contextptr),im(bu1,contextptr)),false,contextptr);
9490     vln=lop(eq,at_innertln);wln=vln;
9491     for (int i=0;i<int(vln.size());++i){
9492       if (vln[i].type==_SYMB)
9493 	wln[i]=symbolic(at_ln,vln[i]._SYMBptr->feuille);
9494     }
9495     eq=subst(eq,vln,wln,false,contextptr);
9496     gen eqx=evalf(eq,1,contextptr);
9497     vecteur v=lvar(eqx);
9498     if (v.size()>1)
9499       eq=eqx;
9500     else {
9501       v=lvar(eq);
9502       fraction f=e2r(eq,v,contextptr);
9503       fxnd(f,eq,tmp);
9504       if (approx)
9505 	eq=evalf(eq,1,contextptr);
9506       eq=r2e(eq,v,contextptr);
9507     }
9508     vecteur res;
9509 #ifndef NO_STDEXCEPT
9510     try {
9511 #endif
9512       res=solve(eq,*u._IDNTptr,0,contextptr);
9513       iterateur it=res.begin(),itend=res.end();
9514       for (;it!=itend;++it){
9515 	*it=subst(bu,u,*it,false,contextptr);
9516       }
9517 #ifndef NO_STDEXCEPT
9518     }
9519     catch (std::runtime_error & ) {
9520       last_evaled_argptr(contextptr)=NULL;
9521     }
9522 #endif
9523     return res;
9524   }
9525 
intercartesianparametric(const gen & a0,const gen & b0,vecteur & res,GIAC_CONTEXT)9526   bool intercartesianparametric(const gen & a0,const gen & b0,vecteur & res,GIAC_CONTEXT){
9527     // intersection a0 cartesian equation, b0 parametric curve
9528     gen a=remove_equal(a0);
9529     if (is_undef(a))
9530       return false;
9531     gen m,mx,my,t(t__IDNT_e),tmin,tmax; double T=-1e300; bool tminmax=false; vecteur v;
9532     if (!find_curve_parametrization(b0,m,t,T,tmin,tmax,tminmax,contextptr))
9533       return false;
9534     reim(m,mx,my,contextptr);
9535     gen eq=subst(a,makevecteur(x__IDNT_e,y__IDNT_e),makevecteur(mx,my),false,contextptr);
9536 #ifndef NO_STDEXCEPT
9537     try {
9538 #endif
9539       v=solve(eq,t,0,contextptr);
9540 #ifndef NO_STDEXCEPT
9541     } catch(std::runtime_error) {
9542       last_evaled_argptr(contextptr)=NULL;
9543       return false;
9544     }
9545 #endif
9546     for (unsigned i=0;i<v.size();++i){
9547       if (is_greater(v[i],tmin,contextptr) && is_greater(tmax,v[i],contextptr))
9548 	res.push_back(v[i]);
9549     }
9550     for (unsigned i=0;i<res.size();++i){
9551       res[i]=subst(m,t,res[i],false,contextptr);
9552     }
9553     return true;
9554   }
9555 
inter(const gen & aa,const gen & bb,GIAC_CONTEXT)9556   vecteur inter(const gen & aa,const gen & bb,GIAC_CONTEXT){
9557     if (aa.type==_VECT){
9558       if (bb.type==_VECT){
9559 	vecteur res;
9560 	const_iterateur it=aa._VECTptr->begin(),itend=aa._VECTptr->end();
9561 	for (;it!=itend;++it){
9562 	  res=mergevecteur(res,inter(*it,bb,contextptr));
9563 	}
9564 	return res;
9565       }
9566       return inter(bb,aa,contextptr);
9567     }
9568     if (bb.type==_VECT){
9569       vecteur res;
9570       const_iterateur it=bb._VECTptr->begin(),itend=bb._VECTptr->end();
9571       for (;it!=itend;++it){
9572 	res=mergevecteur(res,inter(aa,*it,contextptr));
9573       }
9574       return res;
9575     }
9576     gen a=remove_at_pnt(aa);
9577     gen b=remove_at_pnt(bb);
9578     bool asp=a.is_symb_of_sommet(at_hypersphere),bsp=b.is_symb_of_sommet(at_hypersphere);
9579     bool ac=a.is_symb_of_sommet(at_cercle),bc=b.is_symb_of_sommet(at_cercle);
9580     if (a.type==_VECT){
9581       if (a.subtype==_POLYEDRE__VECT)
9582 	return interpolyedre(*a._VECTptr,bb,contextptr);
9583       int as=int(a._VECTptr->size());
9584       if (as>2)
9585 	return interpolygone(*a._VECTptr,bb,contextptr);
9586       if (as==2){
9587 	if (b.type==_VECT){
9588 	  int bs=int(b._VECTptr->size());
9589 	  if (bs>2)
9590 	    return interpolygone(*b._VECTptr,aa,contextptr);
9591 	  if (bs==2){ // D inter D'
9592 	    gen a1=a._VECTptr->front(),a2=a._VECTptr->back(),b1=b._VECTptr->front(),b2=b._VECTptr->back();
9593 	    gen v(a2-a1),w(b2-b1);
9594 	    if (v.type==_VECT){
9595 	      if (w.type!=_VECT || v._VECTptr->size()!=3 || w._VECTptr->size()!=3)
9596 		return vecteur(1,gensizeerr(contextptr));
9597 	      return inter2droites3(a1,a2,b1,b2,a.subtype,b.subtype,contextptr);
9598 	    }
9599 	    return inter2droites2(a1,a2,b1,b2,a.subtype,b.subtype,contextptr);
9600 	  } // end bs==2
9601 	} // end b.type==_VECT
9602 	if (bc || bsp)
9603 	  return interdroitecercle(a,b,contextptr);
9604 	if (b.is_symb_of_sommet(at_hyperplan)) // n-d line inter hyperplan
9605 	  return interdroitehyperplan(a,b,contextptr);
9606       } // end droite inter something (as==2)
9607     }
9608     if (b.type==_VECT) {
9609       if (b.subtype==_POLYEDRE__VECT)
9610 	return interpolyedre(*b._VECTptr,aa,contextptr);
9611       int bs=int(b._VECTptr->size());
9612       if (bs>2)
9613 	return interpolygone(*b._VECTptr,aa,contextptr);
9614       if (bs==2){
9615 	if (a.is_symb_of_sommet(at_hyperplan))
9616 	  return interdroitehyperplan(b,a,contextptr);
9617 	if (ac || asp)
9618 	  return interdroitecercle(b,a,contextptr);
9619       }
9620     }
9621     if ( (ac && bc) || (asp && bsp) ){
9622       gen centre_a,rayon_a,centre_b,rayon_b;
9623       if (!centre_rayon(a,centre_a,rayon_a,false,contextptr) || !centre_rayon(b,centre_b,rayon_b,false,contextptr))
9624 	return vecteur(1,gensizeerr(contextptr));
9625       vecteur res=inter2cercles_or_spheres(centre_a,abs_norm2(rayon_a,contextptr),centre_b,abs_norm2(rayon_b,contextptr),ac,contextptr);
9626       return (ac && bc)?remove_not_in_arc(remove_not_in_arc(res,a,contextptr),b,contextptr):res;
9627     }
9628     if (a.is_symb_of_sommet(at_curve) && bc)
9629       return curveintercircle(a,b,true,contextptr);
9630     if (b.is_symb_of_sommet(at_curve) && ac)
9631       return curveintercircle(b,a,true,contextptr);
9632     // Now replace line and circles by curve
9633     if ((a.type==_VECT) && (a._VECTptr->size()==2)){
9634       if (b.is_symb_of_sommet(at_curve))
9635 	return curveintercircle(b,a,false,contextptr);
9636       a=line2curve(a);
9637     }
9638     if ((b.type==_VECT) && (b._VECTptr->size()==2)){
9639       if (a.is_symb_of_sommet(at_curve))
9640 	return curveintercircle(a,b,false,contextptr);
9641       b=line2curve(b);
9642     }
9643     if (ac)
9644       a=cercle2curve(a,contextptr);
9645     if (bc)
9646       b=cercle2curve(b,contextptr);
9647     if (is_undef(a)||is_undef(b))
9648       return vecteur(1,a+b);
9649     if (a.is_symb_of_sommet(at_hyperplan)){
9650       if (b.is_symb_of_sommet(at_hyperplan))
9651 	return interhyperplan(a,b,contextptr);
9652       if (b.is_symb_of_sommet(at_hypersphere))
9653 	return interplansphere(a,b,contextptr);
9654       return inter(bb,aa,contextptr);
9655     }
9656     if (b.is_symb_of_sommet(at_hyperplan)){
9657       if (a.is_symb_of_sommet(at_hypersphere))
9658 	return interplansphere(b,a,contextptr);
9659       b=hyperplan2hypersurface(b);
9660       if (is_undef(b))
9661 	return vecteur(1,b);
9662     }
9663     if (asp)
9664       a=hypersphere2hypersurface(a);
9665     if (is_undef(a))
9666       return vecteur(1,a);
9667     if (bsp)
9668       b=hypersphere2hypersurface(b);
9669     if (is_undef(b))
9670       return vecteur(1,b);
9671     if (a.is_symb_of_sommet(at_hypersurface) && b.is_symb_of_sommet(at_curve))
9672       return interhypersurfacecurve(a,b,contextptr);
9673     if (b.is_symb_of_sommet(at_hypersurface) && a.is_symb_of_sommet(at_curve))
9674       return interhypersurfacecurve(b,a,contextptr);
9675     if (a.is_symb_of_sommet(at_hypersurface) && b.is_symb_of_sommet(at_hypersurface))
9676       return inter2hypersurface(a,b,contextptr);
9677     vecteur res;
9678     if (a.is_symb_of_sommet(at_equal) && b.is_symb_of_sommet(at_curve) && intercartesianparametric(a,b,res,contextptr))
9679       return res;
9680     if (b.is_symb_of_sommet(at_equal) && a.is_symb_of_sommet(at_curve) && intercartesianparametric(b,a,res,contextptr))
9681       return res;
9682     if ( (a.type==_SYMB) && (a._SYMBptr->sommet==at_curve) && (b.type==_SYMB) && (b._SYMBptr->sommet==at_curve) ){ // curve inter curve
9683       gen fa,fb;
9684       if ((fa=a._SYMBptr->feuille).type!=_VECT || (fb=b._SYMBptr->feuille).type!=_VECT || fa._VECTptr->empty() || fb._VECTptr->empty() || fa._VECTptr->front().type!=_VECT || fb._VECTptr->front().type!=_VECT)
9685 	return vecteur(1,gensizeerr(contextptr));
9686       vecteur va=*fa._VECTptr->front()._VECTptr;
9687       if (va.size()>=6 && intercartesianparametric(va[5],b,res,contextptr))
9688 	return res;
9689       vecteur vb=*fb._VECTptr->front()._VECTptr;
9690       if (vb.size()>=6 && intercartesianparametric(vb[5],a,res,contextptr))
9691 	return res;
9692       if (va.size()<2 || vb.size()<2 || va[1].type!=_IDNT || vb[1].type!=_IDNT)
9693 	return vecteur(1,gensizeerr(contextptr));
9694       gen m,tmin,tmax; double T=1e300;
9695       if (find_curve_parametrization(ac?remove_at_pnt(aa):a,m,va[1],T,tmin,tmax,false,contextptr)){
9696 	return equationintercurve(m,va[1],b,vb[0],vb[1],contextptr);
9697 	// va[0]=m;
9698       }
9699       if (find_curve_parametrization(bc?remove_at_pnt(bb):b,m,vb[1],T,tmin,tmax,false,contextptr)){
9700 	return equationintercurve(m,vb[1],a,va[0],va[1],contextptr);
9701 	// vb[0]=m;
9702       }
9703       if (va[1]==vb[1]){
9704 	gen newvb(va[1].print(contextptr)+print_INT_(std_rand()),contextptr);
9705 	vb[0]=subst(vb[0],vb[1],newvb,true,contextptr);
9706 	vb[1]=newvb;
9707       }
9708       gen xa=re(va[0],contextptr),ya=im(va[0],contextptr);
9709       rewrite_with_t_real(xa,va[1],contextptr);
9710       rewrite_with_t_real(ya,va[1],contextptr);
9711       gen xb=re(vb[0],contextptr),yb=im(vb[0],contextptr);
9712       rewrite_with_t_real(xb,vb[1],contextptr);
9713       rewrite_with_t_real(yb,vb[1],contextptr);
9714       gen eq=xa-xb;
9715       vecteur sol,res;
9716 #ifndef NO_STDEXCEPT
9717       try {
9718 #endif
9719 	sol=solve(eq,*va[1]._IDNTptr,0,contextptr);
9720 	bool exchanged=sol.empty();
9721 	if (exchanged)
9722 	  sol=solve(eq,*vb[1]._IDNTptr,0,contextptr);
9723 	const_iterateur it=sol.begin(),itend=sol.end();
9724 	for (;it!=itend;++it){
9725 	  eq=subst(yb-ya,(exchanged?vb:va)[1],*it,false,contextptr);
9726 	  res=mergevecteur(res,solve(eq,*(exchanged?va:vb)[1]._IDNTptr,0,contextptr));
9727 	}
9728 	sol.clear();
9729 	it=res.begin(); itend=res.end();
9730 	for (;it!=itend;++it){
9731 	  sol.push_back(symb_pnt(subst((exchanged?va:vb)[0],(exchanged?va:vb)[1],*it,false,contextptr),default_color(contextptr),contextptr));
9732 	}
9733 	return sol;
9734 #ifndef NO_STDEXCEPT
9735       }
9736       catch (std::runtime_error &){
9737 	last_evaled_argptr(contextptr)=NULL;
9738 	return makevecteur(symbolic(at_inter,makesequence(a,b)));
9739       }
9740 #endif
9741     }
9742     return makevecteur(symbolic(at_inter,makesequence(a,b)));
9743   }
9744 
9745   // args=[curve, parameter] or element(curve)
tangent(const gen & args,GIAC_CONTEXT)9746   static gen tangent(const gen & args,GIAC_CONTEXT){
9747     gen arg=args;
9748     if (arg.type!=_VECT){
9749       // check if arg is an element of a curve
9750       if ( (arg.type==_SYMB) && (arg._SYMBptr->sommet==at_pnt)){
9751 	arg=(*arg._SYMBptr->feuille._VECTptr)[1];
9752 	if (arg.type==_VECT)
9753 	  arg=(*arg._VECTptr)[1];
9754       }
9755     }
9756     if (arg.type!=_VECT || arg._VECTptr->empty())
9757       return gensizeerr(contextptr);
9758     vecteur & argv=*arg._VECTptr;
9759     int s=int(argv.size())-1;
9760     vecteur result,parameqs;
9761     gen t=argv.back();
9762     if (has_op(t,*at_curve)){
9763       if (s==1 && est_element(t,argv.front(),contextptr))
9764 	return tangent(t,contextptr);
9765       return gensizeerr(contextptr);
9766     }
9767     if (s==1 && argv[0].type==_SYMB && !argv[0].is_symb_of_sommet(at_pnt)){
9768       vecteur s1,s2;
9769       t=remove_at_pnt(t);
9770       surd2pow(t,s1,s2,contextptr);
9771       t=subst(t,s1,s2,false,contextptr);
9772       gen argv0=remove_equal(argv[0]);
9773       if (t.type!=_VECT){
9774 	// tangent to a 2-d curve given by an equation
9775 	gen xy(makevecteur(x__IDNT_e,y__IDNT_e));
9776 	gen der(derive(argv0,xy,contextptr));
9777 	gen tr,ti;
9778 	reim(t,tr,ti,contextptr);
9779 	gen tri(makevecteur(tr,ti));
9780 	if (is_zero(simplify(subst(argv0,xy,tri,false,contextptr),contextptr),contextptr)){
9781 	  der=subst(der,xy,tri,false,contextptr);
9782 	  if (der.type==_VECT && der._VECTptr->size()==2){
9783 	    if (is_zero(der,contextptr))
9784 	      return gensizeerr("Tangent at a singular point");
9785 	    return _droite((xy[0]-tri[0])*der[0]+(xy[1]-tri[1])*der[1],contextptr);
9786 	  }
9787 	}
9788 	if (der.type==_VECT && der._VECTptr->size()==2){
9789 	  gen droite=der._VECTptr->front()*(xy[0]-tr)+der._VECTptr->back()*(xy[1]-ti);
9790 	  vecteur sol=gsolve(makevecteur(droite,argv0),*xy._VECTptr,false,(approx_mode(contextptr)?1:0),contextptr);
9791 	  if (!is_undef(sol)){
9792 	    vecteur res;
9793 	    for (unsigned i=0;i<sol.size();++i){
9794 	      gen soli=normal(sol[i],contextptr);
9795 	      gen derp=subst(makevecteur(-der._VECTptr->back(),der._VECTptr->front()),xy,soli,false,contextptr);
9796 	      if (!is_zero(derp,contextptr))
9797 		res.push_back(_droite(makesequence(soli,derp),contextptr));
9798 	    }
9799 	    if (res.size()==1)
9800 	      return res.front();
9801 	    else
9802 	      return gen(res,_SEQ__VECT);
9803 	  }
9804 	}
9805 	return gensizeerr(gettext("Point is not on curve"));
9806       }
9807       return gensizeerr(gettext("2-d point expected"));
9808     }
9809     for (int i=0;i<s;++i){
9810       gen curve=remove_at_pnt(argv[i]);
9811       if (curve.type==_VECT && !curve._VECTptr->empty() && curve._VECTptr->back().is_symb_of_sommet(at_pnt))
9812 	curve=remove_at_pnt(curve._VECTptr->front());
9813       gen p=_parameq(curve,contextptr);
9814       if (equalposcomp(parameqs,p))
9815 	continue;
9816       if (curve.type==_VECT){
9817 	result.push_back(symb_pnt(curve,contextptr));
9818 	continue;
9819       }
9820       if ( (curve.type==_SYMB) && (curve._SYMBptr->sommet==at_cercle || curve._SYMBptr->sommet==at_hypersphere)){
9821 	gen centre,rayon;
9822 	if (!centre_rayon(curve,centre,rayon,false,contextptr))
9823 	  continue;
9824 	rayon=ratnormal(rayon,contextptr);
9825 	if ( t.type==_VECT || t.is_symb_of_sommet(at_pnt) || !is_zero(im(t,contextptr),contextptr) ){
9826 	  // tangent to cercle via point
9827 	  t=remove_at_pnt(t);
9828 	  if (t.type==_SYMB && equalposcomp(plot_sommets,t._SYMBptr->sommet))
9829 	    return gensizeerr(contextptr);
9830 	  gen OA=t-centre;
9831 	  gen rayon2=rayon*conj(rayon,contextptr);
9832 	  gen rayonb2(normal(abs_norm2(OA,contextptr)-rayon2,contextptr));
9833 	  if (is_zero(rayonb2/rayon2,contextptr)){
9834 	    if (OA.type==_VECT)
9835 	      result.push_back(_plan(makesequence(OA,t),contextptr));
9836 	    else
9837 	      result.push_back(_droite(makesequence(t,t+im(OA,contextptr)-cst_i*re(OA,contextptr)),contextptr));
9838 	    continue;
9839 	  }
9840 	  if (is_positive(-rayonb2,contextptr))
9841 	    continue;
9842 	  if (OA.type==_VECT)
9843 	    return gensizeerr(contextptr);
9844 	  vecteur v=inter2cercles_or_spheres(centre,rayon2,t,rayonb2,true,contextptr); // inter(_cercle(makevecteur(symb_pnt(t,contextptr),sqrt(rayonb2)),contextptr),curve,contextptr);
9845 	  if (!v.empty()){
9846 	    if (is_undef(v.front()))
9847 	      return v.front();
9848 	    result.push_back(_droite(makesequence(t,v.front()),contextptr));
9849 	    result.push_back(_droite(makesequence(t,v.back()),contextptr));
9850 	  }
9851 	}
9852 	else {
9853 	  t=centre+abs(rayon,contextptr)*exp(cst_i*t,contextptr);
9854 	  result.push_back(_perpendiculaire(makesequence(t,t,centre),contextptr));
9855 	}
9856 	continue;
9857       }
9858       if (curve.is_symb_of_sommet(at_hyperplan)){
9859 	result.push_back(curve);
9860 	continue;
9861       }
9862       if (curve.is_symb_of_sommet(at_hypersurface)){
9863 	gen & curvef=curve._SYMBptr->feuille;
9864 	if (curvef.type!=_VECT || curvef._VECTptr->size()<3)
9865 	  return gensizeerr(contextptr);
9866 	vecteur curvev=*curvef._VECTptr;
9867 	gen eq(undef),vars;
9868 	if (curvev[1].type!=_VECT){
9869 	  eq=curvev[1];
9870 	  vars=curvev[2];
9871 	  curvev=*curvev[0]._VECTptr;
9872 	}
9873 	if (t.type==_VECT){ // parameters values
9874 	  gen f=curvev[0];
9875 	  vars=curvev[1];
9876 	  gen fprime=derive(f,vars,contextptr);
9877 	  if (is_undef(fprime))
9878 	    return fprime;
9879 	  fprime=ratnormal(subst(fprime,vars,t,false,contextptr),contextptr);
9880 	  t=ratnormal(subst(f,vars,t,false,contextptr),contextptr);
9881 	  // make hyperplan by t with normal orthogonal to fprime
9882 	  if (!ckmatrix(fprime) || fprime._VECTptr->size()!=2)
9883 	    return gensizeerr(contextptr);
9884 	  vecteur n(cross(*fprime._VECTptr->front()._VECTptr,*fprime._VECTptr->back()._VECTptr,contextptr));
9885 	  result.push_back(symbolic(at_hyperplan,makesequence(n,t)));
9886 	  continue;
9887 	}
9888 	if (is_undef(eq))
9889 	  return gensizeerr(gettext("Hypersurface w/o equation not implemented"));
9890 	t=remove_at_pnt(t);
9891 	// Check that the point is on the hypersurface (with the equation)
9892 	gen res=simplify(subst(eq,vars,t,false,contextptr),contextptr);
9893 	if (!is_zero(res,contextptr))
9894 	  return gensizeerr(gettext("f(t)!=0:")+res.print(contextptr));
9895 	gen fprime(derive(eq,vars,contextptr));
9896 	if (is_undef(fprime))
9897 	  return fprime;
9898 	fprime=ratnormal(subst(fprime,vars,t,false,contextptr),contextptr);
9899 	fprime=fprime/abs_norm(fprime,contextptr);
9900 	result.push_back(symbolic(at_hyperplan,makesequence(fprime,t)));
9901 	continue;
9902       }
9903       if ( (curve.type!=_SYMB) || (curve._SYMBptr->sommet!=at_curve))
9904 	return gensizeerr(contextptr);
9905       vecteur v=*curve._SYMBptr->feuille._VECTptr->front()._VECTptr;
9906       gen v06=v[0];
9907       if (v.size()>6 && !is_undef(v[6]))
9908 	v06=v[6];
9909       gen direction;
9910       direction=derive(v06,*v[1]._IDNTptr,contextptr);
9911       if (is_undef(direction))
9912 	return direction;
9913       if ( (t.type==_SYMB) && (t._SYMBptr->sommet==at_pnt)){
9914 	if (t._SYMBptr->feuille[1].type==_VECT){
9915 	  vecteur tv=*t._SYMBptr->feuille[1]._VECTptr;
9916 	  if (tv.size()>=2){
9917 	    gen M=tv[1];
9918 	    if (M.type==_VECT && M._VECTptr->size()==2){
9919 	      gen Mon=M._VECTptr->front();
9920 	      gen Mt=M._VECTptr->back();
9921 	      if (remove_at_pnt(Mon)==curve){
9922 		direction=subst(direction,v[1],Mt,false,contextptr);
9923 		M=t._SYMBptr->feuille[0]; // remove_at_pnt(t);
9924 		return _droite_segment(gen(makevecteur(M,M+direction),_SEQ__VECT),_LINE__VECT,vecteur(1,default_color(contextptr)),contextptr);
9925 	      }
9926 	    }
9927 	  }
9928 	}
9929 	gen M=remove_at_pnt(t);
9930 	if (M.is_symb_of_sommet(at_curve)) return gensizeerr(contextptr);
9931 	if (v.size()>7 && v[7].type==_VECT){
9932 	  vecteur v7=*v[7]._VECTptr;
9933 	  if (v7.size()==7 && v7.front()==at_ellipse){
9934 	    // geometric construction
9935 	    // tanellipse(P,F1,F2,a):={
9936 	    // local c1,c2,M1,M2,l1,l2;
9937 	    // l1:=longueur(P,F1);
9938 	    // l2:=longueur(P,F2);
9939 	    // si l1+l2<2a alors retourne [] fsi;
9940 	    // c1:=cercle(F1,2a);
9941 	    // c2:=cercle(P,l2);
9942 	    // [M1,M2]:=inter(c1,c2);
9943 	    // d1:=mediatrice(F2,M1);
9944 	    // d2:=mediatrice(F2,M2);
9945 	    // T1:=inter_unique(droite(F1,M1),d1);
9946 	    // T2:=inter_unique(droite(F1,M2),d2);
9947 	    // retourne d1,d2,T1,T2;
9948 	    // }:;
9949 	    // rational parametrization analytic construction
9950 	    // conic O+(1+i*t)*(d*t+e)/(a*t^2+b*t+c)
9951 	    gen O=v7[1],a=v7[2],b=v7[3],c=v7[4],d=v7[5],f=v7[6],xM,yM;
9952 	    // t must satisfy a 2nd order equation of coeffs
9953 	    // poly1[a*d*yM-a*f*xM+b*d*xM-d^2,2*a*f*yM+2*c*d*xM-2*d*f,b*f*yM-c*d*yM+c*f*xM-f^2]
9954 	    reim(M-O,xM,yM,contextptr);
9955 	    gen A=a*d*yM-a*f*xM+b*d*xM-d*d,B=2*a*f*yM+2*c*d*xM-2*d*f,C=b*f*yM-c*d*yM+c*f*xM-f*f;
9956 	    gen D=B*B-4*A*C;
9957 	    if (is_positive(D,contextptr)){
9958 	      D=sqrt(D,contextptr);
9959 	      gen t1=(-B-D)/(2*A),t2=(-B+D)/(2*A);
9960 	      t1=O+(1+cst_i*t1)*(d*t1+f)/(a*t1*t1+b*t1+c);
9961 	      t2=O+(1+cst_i*t2)*(d*t2+f)/(a*t2*t2+b*t2+c);
9962 	      return makevecteur(_droite(makesequence(M,t1),contextptr),_droite(makesequence(M,t2),contextptr));
9963 	    }
9964 	    return vecteur(0);
9965 	  }
9966 	}
9967 	gen m,tmin,tmax;
9968 	double T=1;
9969 	if (v[1].type==_IDNT && find_curve_parametrization(curve,m,v[1],T,tmin,tmax,false,contextptr)){
9970 	  gen rem;
9971 	  if (m.is_symb_of_sommet(at_plus) && m._SYMBptr->feuille.type==_VECT && m._SYMBptr->feuille._VECTptr->size()==2 && m._SYMBptr->feuille._VECTptr->front()==v[1] && !has_i(rem=_simplifier(-cst_i*m._SYMBptr->feuille._VECTptr->back(),contextptr)))
9972 	    rem=v[1];
9973 	  else
9974 	    rem=re(m,contextptr);
9975 	  if (rem==v[1]){
9976 	    gen r;
9977 	    if (M.is_symb_of_sommet(at_plus) && M._SYMBptr->feuille.type==_VECT && M._SYMBptr->feuille._VECTptr->size()==2 && !has_i(r=_simplifier(-cst_i*M._SYMBptr->feuille._VECTptr->back(),contextptr)))
9978 	      r=M._SYMBptr->feuille._VECTptr->front();
9979 	    else
9980 	      r=re(M,contextptr);
9981 	    // check that M is on the curve? was disabled, re-enabled, if not don't draw anything
9982 	    if (
9983 		// true || is_zero(normal(M-subst(m,v[1],r,false,contextptr),contextptr))
9984 		is_zero(evalf(M-subst(m,v[1],r,false,contextptr),1,contextptr),contextptr)
9985 		){
9986 	      direction=subst(direction,v[1],r,false,contextptr);
9987 	      result.push_back(_droite(makevecteur(M,M+direction),contextptr));
9988 	      return result;
9989 	    }
9990 	    // not on the curve, if not polynomial return undef
9991 	    if (lvarx(m,v[1]).size()>=2){
9992 	      *logptr(contextptr) << "Point is not on curve" << '\n';
9993 	      return undef;
9994 	    }
9995 	  }
9996 	  vecteur mv=rlvarx(m,v[1]);
9997 	  if (mv.empty() || (mv.size()==1 && mv.front()==v[1])){
9998 	    gen x(" x",contextptr),y(" y",contextptr);
9999 	    gen eq=rationalparam2equation(m,v[1],x,y,contextptr);
10000 	    if (is_undef(eq))
10001 	      return eq;
10002 	    // contact point N(x,y) must verify eq and M-N normal to diff(eq,x),diff(eq,y)
10003 	    gen Mx=re(M,contextptr),My=im(M,contextptr);
10004 	    gen eqx=derive(eq,x,contextptr),eqy=derive(eq,y,contextptr);
10005 	    if (is_undef(eqx) || is_undef(eqy))
10006 	      return eqx+eqy;
10007 	    gen eq2=(Mx-x)*eqx+(My-y)*eqy;
10008 	    vecteur sols=gsolve(makevecteur(eq,eq2),makevecteur(x,y),false,(approx_mode(contextptr)?1:0),contextptr);
10009 	    if (is_undef(sols))
10010 	      return sols;
10011 	    // build tangents
10012 	    vecteur res;
10013 	    const_iterateur it=sols.begin(),itend=sols.end();
10014 	    for (;it!=itend;++it){
10015 	      gen N=it->_VECTptr->front()+cst_i*it->_VECTptr->back();
10016 	      if (!is_zero(recursive_normal(M-N,contextptr),contextptr))
10017 		res.push_back(_droite(gen(makevecteur(M,N),_SEQ__VECT),contextptr));
10018 	      else {
10019 		gen dir=subst(eqy-cst_i*eqx,makevecteur(x,y),*it,false,contextptr);
10020 		res.push_back(_droite(gen(makevecteur(N,N+dir),_SEQ__VECT),contextptr));
10021 	      }
10022 	    }
10023 	    if (res.size()==1)
10024 	      return res.front();
10025 	    return res;
10026 	  }
10027 	} // end if (v[1].type==_IDNT ...)
10028 	gen xt(re(v06,contextptr)),yt(im(v06,contextptr)),xp(re(direction,contextptr)),yp(im(direction,contextptr));
10029 	gen var=v[1];
10030 	rewrite_with_t_real(xt,var,contextptr);
10031 	rewrite_with_t_real(yt,var,contextptr);
10032 	rewrite_with_t_real(xp,var,contextptr);
10033 	rewrite_with_t_real(yp,var,contextptr);
10034 	// for plotfunc, check if var=re(M)
10035 	gen test1=recursive_normal(subst(yt,var,re(M,contextptr),false,contextptr)-im(M,contextptr),contextptr),test2=recursive_normal(subst(xt,var,re(M,contextptr),false,contextptr)-re(M,contextptr),contextptr);
10036 	if (is_zero(test1,contextptr) && is_zero(test2,contextptr)){
10037 	  direction=subst(direction,var,re(M,contextptr),false,contextptr);
10038 	  result.push_back(_droite(makevecteur(M,M+direction),contextptr));
10039 	  continue;
10040 	}
10041 	vecteur sol;
10042 	gen lambda=xp*(yt-im(M,contextptr))-yp*(xt-re(M,contextptr));
10043 #ifndef NO_STDEXCEPT
10044 	try {
10045 #endif
10046 	  // find t such that x'(t)*(M_y-y(t)) = y'(t)*(M_x-x(t))
10047 	  sol=solve( lambda,*var._IDNTptr,0,contextptr);
10048 #ifndef NO_STDEXCEPT
10049 	}
10050 	catch (std::runtime_error & error ){
10051 	  last_evaled_argptr(contextptr)=NULL;
10052 	  *logptr(contextptr) << error.what() << '\n';
10053 	  sol.clear();
10054 	}
10055 #endif
10056 	iterateur it=sol.begin(),itend=sol.end();
10057 	for (;it!=itend;++it){
10058 	  if (is_undef(*it))
10059 	    return gensizeerr(gettext("Unable to solve"));
10060 	  gen Mt=subst(v06,var,*it,false,contextptr); // point on the curve
10061 	  if (is_zero(normal(M-Mt,contextptr),contextptr)){
10062 	    direction=subst(direction,var,*it,false,contextptr);
10063 	    result.push_back(_droite(makesequence(M,M+direction),contextptr));
10064 	    continue;
10065 	  }
10066 	  result.push_back(_droite(makesequence(M,Mt),contextptr));
10067 	}
10068 	continue;
10069       }
10070       else {
10071 	direction=subst(direction,v[1],t,false,contextptr);
10072 	gen point(subst(v06,v[1],t,false,contextptr));
10073 	result.push_back(_droite(makesequence(point,point+direction),contextptr));
10074 	continue;
10075       }
10076     }
10077     if (result.size()==1)
10078       return result.front();
10079     return gen(result,_GROUP__VECT);
10080   }
_tangent(const gen & args,GIAC_CONTEXT)10081   gen _tangent(const gen & args,GIAC_CONTEXT){
10082     if ( args.type==_STRNG && args.subtype==-1) return  args;
10083     vecteur attributs(1,default_color(contextptr));
10084     vecteur v(seq2vecteur(args));
10085     int s=read_attributs(v,attributs,contextptr);
10086     if (!s)
10087       return gendimerr(contextptr);
10088     if (s==1)
10089       return put_attributs(tangent(v.front(),contextptr),attributs,contextptr);
10090     gen res=tangent(gen(vecteur(v.begin(),v.begin()+s),args.subtype),contextptr);
10091     if (res.type==_VECT && res._VECTptr->size()==1)
10092       res=res._VECTptr->front();
10093     return put_attributs(res,attributs,contextptr);
10094   }
10095   static const char _tangent_s []="tangent";
10096   static define_unary_function_eval (__tangent,&_tangent,_tangent_s);
10097   define_unary_function_ptr5( at_tangent ,alias_at_tangent,&__tangent,0,true);
10098 
is_valid_point(const gen & g)10099   static bool is_valid_point(const gen & g){
10100     if (is_undef(g))
10101       return false;
10102     if (g.type==_VECT){
10103       vecteur & v = *g._VECTptr;
10104       int s=int(v.size());
10105       if (s!=3)
10106 	return false;
10107       if (v.front().type==_VECT)
10108 	return false;
10109     }
10110     return true;
10111   }
foyers_a(const gen & args,gen & F1,gen & F2,gen & a,GIAC_CONTEXT)10112   static bool foyers_a(const gen & args,gen & F1,gen & F2, gen & a,GIAC_CONTEXT){
10113     gen FF=remove_at_pnt(args._VECTptr->front());
10114     if (FF.type==_VECT && FF._VECTptr->size()!=3){
10115       if (FF._VECTptr->size()!=2)
10116 	return false; // setsizeerr(contextptr);
10117       F1=FF._VECTptr->front();
10118       F2=FF._VECTptr->back();
10119     }
10120     else {
10121       if (args._VECTptr->size()!=3)
10122 	return false; // setsizeerr(contextptr);
10123       F1=FF;
10124       F2=remove_at_pnt((*args._VECTptr)[1]);
10125     }
10126     a=args._VECTptr->back();
10127     a=remove_at_pnt(get_point(a,0,contextptr));
10128     F1=remove_at_pnt(get_point(F1,0,contextptr));
10129     F2=remove_at_pnt(get_point(F2,0,contextptr));
10130     if (!is_valid_point(a) || !is_valid_point(F1) || !is_valid_point(F2))
10131       return false;
10132     return true;
10133   }
10134 
xy2eitheta(const gen & x,const gen & y,GIAC_CONTEXT)10135   static gen xy2eitheta(const gen & x,const gen & y,GIAC_CONTEXT){
10136     if (is_zero(x,contextptr))
10137       return cst_i;
10138     gen t=rdiv(y,x,contextptr);
10139     t=rdiv(plus_one+cst_i*t,sqrt(plus_one+t*t,contextptr),contextptr);
10140     if (!is_positive(x,contextptr))
10141       return -t;
10142     else
10143       return t;
10144   }
10145 
10146   // cartesian ellipse or hyperbola equation from focus F1/F2 and square of a
ellipse_hyperbole_equation(const gen & F1,const gen & F2,const gen & a2,GIAC_CONTEXT)10147   gen ellipse_hyperbole_equation(const gen & F1,const gen & F2,const gen & a2,GIAC_CONTEXT){
10148     gen x1,x2,y1,y2,x(x__IDNT_e),y(y__IDNT_e);
10149     if (F1.type==_VECT)
10150       return undef;
10151     reim(F1,x1,y1,contextptr);
10152     reim(F2,x2,y2,contextptr);
10153     gen diffMF2=(x2-x1)*(2*x-(x1+x2))+(y2-y1)*(2*y-(y1+y2));
10154     gen MF2=pow(x-x1,2,contextptr)+pow(y-y1,2,contextptr);
10155     gen eq=16*a2*a2+8*a2*diffMF2+pow(diffMF2,2)-16*a2*MF2;
10156     return eq;
10157   }
10158 
_ellipse(const gen & args,GIAC_CONTEXT)10159   gen _ellipse(const gen & args,GIAC_CONTEXT){
10160     if ( args.type==_STRNG && args.subtype==-1) return  args;
10161     ck_parameter_t(contextptr);
10162     if (args.type!=_VECT)
10163       return _plotimplicit(args,contextptr);
10164     vecteur attributs(1,default_color(contextptr));
10165     int s=read_attributs(*args._VECTptr,attributs,contextptr);
10166     if (!s)
10167       return gendimerr(contextptr);
10168     if (s==1)
10169       return _plotimplicit(args,contextptr);
10170     // args=[F,F',M] or [F,F',a] / FM+F'M=2*a
10171     gen F1,F2,M,a,a2,n;
10172     gen aorig=*(args._VECTptr->begin()+s-1);
10173     if (!foyers_a(vecteur(args._VECTptr->begin(),args._VECTptr->begin()+s),F1,F2,a,contextptr))
10174       return gensizeerr(contextptr);
10175     if ( aorig.is_symb_of_sommet(at_pnt) || a.type==_VECT || !is_zero(im(a,contextptr),contextptr) ){
10176       M=a=remove_at_pnt(get_point(remove_at_pnt(a),0,contextptr));
10177       if (is_undef(a)) return a;
10178       if (a.type==_VECT)
10179 	n=a;
10180       a=rdiv(abs_norm(a-F1,contextptr)+abs_norm(a-F2,contextptr),plus_two,contextptr);
10181       gen MF1=distance2(M,F1,contextptr),MF2=distance2(M,F2,contextptr);
10182       a2=(MF1+MF2)/4+sqrt(MF1*MF2,contextptr)/2;
10183     }
10184     else {
10185       gen F1F2=F2-F1;
10186       gen c=abs_norm(F1F2,contextptr)/2;
10187       M=F1+(a/c+1)/2*F1F2;
10188       a2=recursive_normal(a*a,contextptr);
10189     }
10190     gen eq=ellipse_hyperbole_equation(F1,F2,a2,contextptr);
10191     vecteur vparam=conique_ratparams(eq,M,contextptr);
10192     gen parameq=conique_ratparam(eq,M,contextptr);
10193     gen F1F2=F2-F1;
10194     gen O=rdiv(F1+F2,plus_two,contextptr);
10195     gen c2=rdiv(F1F2.squarenorm(contextptr),gen(4),contextptr);
10196     gen b=sqrt(a2-c2,contextptr),res;
10197 #if 0 // def GIAC_HAS_STO_38
10198     gen theta=vx_var;
10199 #else
10200     gen theta=identificateur("t"); // t__IDNT_e;
10201 #endif
10202     gen theta_orig=theta;
10203     if(!angle_radian(contextptr))
10204       {
10205 	//grad
10206 	if(angle_degree(contextptr))
10207 	  theta=gen(180)/cst_pi*theta;
10208 	else
10209 	  theta = gen(200) / cst_pi*theta;
10210       }
10211     if (n.type==_VECT){ // 3-d
10212       n=n-O;
10213       n=cross(cross(F1F2,n,contextptr),F1F2,contextptr);
10214       res=O+a*symb_cos(theta)*F1F2/abs_norm(F1F2,contextptr)+b*symb_sin(theta)*n/abs_norm(n,contextptr);
10215     }
10216     else { // 2-d
10217       gen xF1F2=re(F1F2,contextptr),yF1F2=im(F1F2,contextptr);
10218       gen eitheta(xy2eitheta(xF1F2,yF1F2,contextptr));
10219       res=eitheta*(a*symb_cos(theta)+b*cst_i*symb_sin(theta))+O;
10220       gen r,i;
10221       reim(res,r,i,contextptr);
10222       res=makevecteur(r,i);
10223     }
10224     gen ustep=_USTEP;
10225     ustep.subtype=_INT_PLOT;
10226     gen nstep=_NSTEP;
10227     nstep.subtype=_INT_PLOT;
10228 #if 0 // def GIAC_HAS_STO_38
10229     return _paramplot(gen(makevecteur(res,symb_equal(vx_var,symb_interval(0,2*cst_pi)),symb_equal(nstep,60),symb_equal(ustep,M_PI/30),symbolic(at_equal,makesequence(at_display,attributs[0])),eq,parameq,vparam),_SEQ__VECT),contextptr);
10230 #else
10231     return _paramplot(gen(makevecteur(res,symb_equal(theta_orig,symb_interval(0,2*cst_pi)),symb_equal(nstep,120),symb_equal(ustep,M_PI/60),symbolic(at_equal,makesequence(at_display,attributs[0])),eq,parameq,vparam),_SEQ__VECT),contextptr);
10232 #endif
10233   }
10234   static const char _ellipse_s []="ellipse";
10235   static define_unary_function_eval (__ellipse,&_ellipse,_ellipse_s);
10236   define_unary_function_ptr5( at_ellipse ,alias_at_ellipse,&__ellipse,0,true);
10237 
_hyperbole(const gen & args,GIAC_CONTEXT)10238   gen _hyperbole(const gen & args,GIAC_CONTEXT){
10239     if ( args.type==_STRNG && args.subtype==-1) return  args;
10240     ck_parameter_t(contextptr);
10241     if (args.type!=_VECT)
10242       return _plotimplicit(args,contextptr);
10243     // args=[F,F',M] or [F,F',a] / FM+F'M=2*a
10244     vecteur attributs(1,default_color(contextptr));
10245     int s=read_attributs(*args._VECTptr,attributs,contextptr);
10246     if (!s)
10247       return gendimerr(contextptr);
10248     if (s==1)
10249       return _plotimplicit(args,contextptr);
10250     gen F1,F2,a,a2,n;
10251     gen aorig=*(args._VECTptr->begin()+s-1);
10252     gen M;
10253     if (!foyers_a(vecteur(args._VECTptr->begin(),args._VECTptr->begin()+s),F1,F2,a,contextptr))
10254       return gensizeerr(contextptr);
10255     if ( aorig.is_symb_of_sommet(at_pnt) || a.type==_VECT || !is_zero(im(a,contextptr),contextptr) ){
10256       M=a=remove_at_pnt(get_point(remove_at_pnt(a),0,contextptr));
10257       if (is_undef(a)) return a;
10258       if (a.type==_VECT)
10259 	n=a;
10260       a=rdiv(abs_norm(a-F1,contextptr)-abs_norm(a-F2,contextptr),plus_two,contextptr);
10261       gen MF1=distance2(M,F1,contextptr),MF2=distance2(M,F2,contextptr);
10262       a2=(MF1+MF2)/4-sqrt(MF1*MF2,contextptr)/2;
10263     }
10264     else {
10265       gen F1F2=F2-F1;
10266       gen c=abs_norm(F1F2,contextptr)/2;
10267       M=F1+(a/c+1)/2*F1F2;
10268       a2=recursive_normal(a*a,contextptr);
10269     }
10270     gen eq=ellipse_hyperbole_equation(F1,F2,a2,contextptr);
10271     gen parameq=conique_ratparam(eq,M,contextptr);
10272     vecteur vparam=conique_ratparams(eq,M,contextptr);
10273     gen F1F2=F2-F1;
10274     gen O=rdiv(F1+F2,plus_two,contextptr);
10275     gen c2=rdiv(F1F2.squarenorm(contextptr),gen(4),contextptr);
10276     gen b=sqrt(c2-a2,contextptr),res,res1,res2;
10277 #if 0 // def GIAC_HAS_STO_38
10278     gen theta=vx_var;
10279 #else
10280     gen theta=identificateur("t"); // t__IDNT_e;
10281 #endif
10282     if (n.type==_VECT){
10283       n=n-O;
10284       n=cross(cross(F1F2,n,contextptr),F1F2,contextptr);
10285       res1=a*cosh(theta,contextptr)*F1F2/abs_norm(F1F2,contextptr)+b*sinh(theta,contextptr)*n/abs_norm(n,contextptr);
10286       res2=-a*cosh(theta,contextptr)*F1F2/abs_norm(F1F2,contextptr)+b*sinh(theta,contextptr)*n/abs_norm(n,contextptr);
10287     }
10288     else {
10289       gen xF1F2=re(F1F2,contextptr),yF1F2=im(F1F2,contextptr);
10290       gen eitheta(xy2eitheta(xF1F2,yF1F2,contextptr));
10291       res=eitheta*(a*cosh(theta,contextptr)+b*cst_i*sinh(theta,contextptr));
10292       gen r,i;
10293       reim(res+O,r,i,contextptr);
10294       res1=makevecteur(r,i);
10295       reim(-res+O,r,i,contextptr);
10296       res2=makevecteur(r,i);
10297     }
10298     gen ustep=_USTEP;
10299     ustep.subtype=_INT_PLOT;
10300     gen nstep=_NSTEP;
10301     nstep.subtype=_INT_PLOT;
10302 #if 0 // def GIAC_HAS_STO_38
10303     return makevecteur(_paramplot(gen(makevecteur(res1,symb_equal(vx_var,symb_interval(-3,3)),symb_equal(nstep,60),symb_equal(ustep,0.1),symbolic(at_equal,makesequence(at_display,attributs[0])),eq),_SEQ__VECT),contextptr),_paramplot(gen(makevecteur(res2,symb_equal(vx_var,symb_interval(-3,3)),symb_equal(nstep,60),symb_equal(ustep,0.1),symbolic(at_equal,makesequence(at_display,attributs[0])),eq,parameq),_SEQ__VECT),contextptr)); // should be -inf..inf
10304 #else
10305     return makevecteur(_paramplot(gen(makevecteur(res1,symb_equal(theta,symb_interval(-3,3)),symb_equal(nstep,60),symb_equal(ustep,0.1),symbolic(at_equal,makesequence(at_display,attributs[0])),eq,parameq,vparam),_SEQ__VECT),contextptr),_paramplot(gen(makevecteur(res2,symb_equal(theta,symb_interval(-3,3)),symb_equal(nstep,60),symb_equal(ustep,0.1),symbolic(at_equal,makesequence(at_display,attributs[0])),eq,parameq,vparam),_SEQ__VECT),contextptr)); // should be -inf..inf
10306 #endif
10307   }
10308   static const char _hyperbole_s []="hyperbola";
10309   static define_unary_function_eval (__hyperbole,&_hyperbole,_hyperbole_s);
10310   define_unary_function_ptr5( at_hyperbole ,alias_at_hyperbole,&__hyperbole,0,true);
10311 
_parabole(const gen & args,GIAC_CONTEXT)10312   gen _parabole(const gen & args,GIAC_CONTEXT){
10313     if ( args.type==_STRNG && args.subtype==-1) return  args;
10314     ck_parameter_t(contextptr);
10315     vecteur attributs(1,default_color(contextptr));
10316     // args=[F,O] symmetry axe=OF (t+i*t^2)/OF
10317     // or args=[0,c] symmetry axe=Oy y=c*x^2 (t+i*t^2)/c or args=c
10318     gen O,F,c,eitheta=plus_one;
10319     vecteur v=gen2vecteur(args);
10320     int s=read_attributs(v,attributs,contextptr);
10321     v=vecteur(v.begin(),v.begin()+s);
10322     if (!s)
10323       return gendimerr(contextptr);
10324     if (s==1)
10325       return _plotimplicit(args,contextptr);
10326     F=remove_at_pnt(v.front());
10327     O=v[1];
10328     if ( O.is_symb_of_sommet(at_pnt) || !is_zero(im(O,contextptr),contextptr) ){
10329       gen OF=remove_at_pnt(O);
10330       if (OF.type==_VECT && OF._VECTptr->size()==2){
10331 	// find the projection of F over O
10332 	OF=projectionpoint(O,F,contextptr);
10333 	OF=(remove_at_pnt(OF)+F)/2;
10334       }
10335       O=OF;
10336       OF=F-OF;
10337       c=abs_norm(OF,contextptr);
10338       if (OF.type!=_VECT){
10339 	eitheta=(im(OF,contextptr)-cst_i*re(OF,contextptr))/c;
10340       }
10341       else {
10342 	eitheta=remove_at_pnt(v[2])-O;
10343 	eitheta=cross(cross(OF,eitheta,contextptr),OF,contextptr);
10344 	eitheta=eitheta/abs_norm(eitheta,contextptr);
10345       }
10346     }
10347     else {
10348       c=O;
10349       O=F;
10350     }
10351     gen res;
10352 #if 0 // def GIAC_HAS_STO_38
10353     gen theta=vx_var;
10354 #else
10355     gen theta=identificateur("t"); // t__IDNT_e;
10356 #endif
10357     if (eitheta.type==_VECT){
10358       res=O+(F-O)/(4*c*abs_norm(F-O,contextptr))*pow(theta,2)+eitheta*theta;
10359     }
10360     else {
10361       res=O+eitheta*theta*(1+cst_i*theta/4/c);
10362       gen r,i;
10363       reim(res,r,i,contextptr);
10364       res=makevecteur(r,i);
10365     }
10366     gen ustep=_USTEP;
10367     ustep.subtype=_INT_PLOT;
10368     gen nstep=_NSTEP;
10369     nstep.subtype=_INT_PLOT;
10370 #if 0 // def GIAC_HAS_STO_38
10371     res= _paramplot(gen(makevecteur(res,symb_equal(vx_var,symb_interval(-12,12)),symb_equal(nstep,60),symb_equal(ustep,0.15),symbolic(at_equal,makesequence(at_display,attributs[0]))),_SEQ__VECT),contextptr);
10372 #else
10373     res= _paramplot(gen(makevecteur(res,symb_equal(theta,symb_interval(-12,12)),symb_equal(nstep,60),symb_equal(ustep,0.15),symbolic(at_equal,makesequence(at_display,attributs[0]))),_SEQ__VECT),contextptr);
10374 #endif
10375     return res;
10376   }
10377   static const char _parabole_s []="parabola";
10378   static define_unary_function_eval (__parabole,&_parabole,_parabole_s);
10379   define_unary_function_ptr5( at_parabole ,alias_at_parabole,&__parabole,0,true);
10380 
put_attributs(const gen & lieu_g,const vecteur & attributs,GIAC_CONTEXT)10381   gen put_attributs(const gen & lieu_g,const vecteur & attributs,GIAC_CONTEXT){
10382     if (is_undef(lieu_g))
10383       return lieu_g;
10384     if (lieu_g.is_symb_of_sommet(at_program))
10385       return lieu_g;
10386     gen lieu_geo=remove_at_pnt(lieu_g);
10387     if (!lieu_g.is_symb_of_sommet(at_pnt) && lieu_geo.type==_VECT && (lieu_geo.subtype<_LINE__VECT || lieu_geo.subtype>_HALFLINE__VECT) ){
10388       const_iterateur it=lieu_geo._VECTptr->begin(),itend=lieu_geo._VECTptr->end();
10389       vecteur res;
10390       res.reserve(itend-it);
10391       for (;it!=itend;++it){
10392 	res.push_back(put_attributs(*it,attributs,contextptr));
10393       }
10394       return gen(res,lieu_geo.subtype);
10395     }
10396     return pnt_attrib(lieu_geo,attributs,contextptr);
10397   }
10398 
_conique(const gen & args,GIAC_CONTEXT)10399   gen _conique(const gen & args,GIAC_CONTEXT){
10400     if ( args.type==_STRNG && args.subtype==-1) return  args;
10401     if (args.type!=_VECT)
10402       return _plotimplicit(args,contextptr);
10403     vecteur attributs(1,default_color(contextptr));
10404     vecteur & v =*args._VECTptr;
10405     int s=read_attributs(v,attributs,contextptr);
10406     if (!s)
10407       return gendimerr(contextptr);
10408     if (s<=3)
10409       return _plotimplicit(args,contextptr);
10410     if (s==5){
10411       vecteur w(5),m(5),ligne(6);
10412       gen wx,wy;
10413       // find m such that m*[a,b,c,d,e,f]=0 where a*x^2+b*x*y+c*y^2+d*x+e*y+f=0
10414       for (int i=0;i<5;++i){
10415 	w[i]=remove_at_pnt(v[i]);
10416 	wx=re(w[i],contextptr);
10417 	wy=im(w[i],contextptr);
10418 	ligne[0]=wx*wx;
10419 	ligne[1]=wx*wy;
10420 	ligne[2]=wy*wy;
10421 	ligne[3]=wx;
10422 	ligne[4]=wy;
10423 	ligne[5]=1;
10424 	m[i]=ligne;
10425       }
10426       // find ker(m)
10427       gen me=m; // exact(m,contextptr);
10428       vecteur base;
10429       if (me.type==_VECT)
10430 	base=mker(*me._VECTptr,contextptr);
10431       if (is_undef(base) || base.empty() || base.front().type!=_VECT || base.front()._VECTptr->size()!=6)
10432 	return gensizeerr(gettext("Bug in conique reducing ")+gen(m).print(contextptr));
10433       vecteur & res = *base.front()._VECTptr;
10434       identificateur x(" x"),y(" y");
10435       gen eq=res[0]*x*x+res[1]*x*y+res[2]*y*y+res[3]*x+res[4]*y+res[5];
10436       gen g;
10437       if (equation2geo2d(eq,x,y,g,gnuplot_tmin,gnuplot_tmax,gnuplot_tstep,w[0],3,contextptr))
10438 	return put_attributs(g,attributs,contextptr);
10439       else
10440 	return gensizeerr(gettext("Bug in conique, equation ")+eq.print(contextptr));
10441     }
10442     return gendimerr(contextptr);
10443   }
10444   static const char _conique_s []="conic";
10445   static define_unary_function_eval (__conique,&_conique,_conique_s);
10446   define_unary_function_ptr5( at_conique ,alias_at_conique,&__conique,0,true);
10447 
_legende(const gen & a,GIAC_CONTEXT)10448   gen _legende(const gen & a,GIAC_CONTEXT){
10449     if ( a.type==_STRNG && a.subtype==-1) return  a;
10450     gen args=a.eval(1,contextptr);
10451     if ( (a.type==_SYMB) && (args.type!=_VECT)){
10452       vecteur v;
10453       gen e(a._SYMBptr->feuille);
10454       if ( (e.type==_VECT) && (!e._VECTptr->empty()) )
10455 	e=e._VECTptr->front();
10456       v.push_back(e.eval(1,contextptr));
10457       v.push_back(args);
10458       args=v;
10459     }
10460     else {
10461       if ((args.type!=_VECT) || (args._VECTptr->size()<2))
10462 	return symbolic(at_legende,args);
10463     }
10464     // gen decal=gen(5*(gnuplot_xmax-gnuplot_xmin)/plot_instructionsh+5*(gnuplot_ymax-gnuplot_ymin)/(plot_instructionsw-LEGENDE_SIZE))*cst_i;
10465     gen decal=0;
10466     int save_digits=decimal_digits(contextptr);
10467     int couleur=0;
10468     decimal_digits(contextptr)=3;
10469     string s;
10470     vecteur v(*args._VECTptr);
10471     if (v.size()==3 && v[2].type==_STRNG){
10472       gen a=evalf_double(v[0],1,contextptr);
10473       gen b=evalf_double(v[1],1,contextptr);
10474       if (a.type==_DOUBLE_ && b.type==_DOUBLE_)
10475 	v=makevecteur(gen(a,b),v[2]);
10476     }
10477     for (unsigned int i=1;i<v.size();++i){
10478       if (v[i].type==_STRNG)
10479 	s += *v[i]._STRNGptr;
10480       else {
10481 	if (v[i].type==_INT_ && v[i].subtype==_INT_COLOR){
10482 	  couleur |= v[i].val;
10483 	  continue;
10484 	}
10485 	if (v[i].is_symb_of_sommet(at_equal)){
10486 	  gen & f = v[i]._SYMBptr->feuille;
10487 	  if (f.type==_VECT && f._VECTptr->size()==2){
10488 	    gen f2=evalf_double(f._VECTptr->back(),1,contextptr);
10489 	    if (f._VECTptr->front()==at_couleur || f._VECTptr->front()==at_display){
10490 	      if (f2.type==_DOUBLE_)
10491 		couleur |= int(f2._DOUBLE_val);
10492 	      if (f2.type==_INT_)
10493 		couleur |= f2.val;
10494 	      if (f2.type==_FLOAT_)
10495 		couleur |= get_int(f2._FLOAT_val);
10496 	      continue;
10497 	    }
10498 	  }
10499 	}
10500 	s += v[i].print(contextptr);
10501       }
10502     }
10503     decimal_digits(contextptr)=save_digits;
10504     gen position=v[0];
10505     if (position.type==_VECT && position._VECTptr->size()==2)
10506       return symb_pnt(symbolic(at_legende,makesequence(position,string2gen(s,false),couleur)),couleur,contextptr);
10507     position=remove_at_pnt(v[0]);
10508     if (position.type==_SYMB) {
10509       if (position._SYMBptr->sommet==at_cercle)
10510 	position=position._SYMBptr->feuille;
10511       else
10512 	if (position._SYMBptr->sommet==at_curve){
10513 	  vecteur v(*position._SYMBptr->feuille._VECTptr->front()._VECTptr);
10514 	  position=subst(v[0],v[1],rdiv(v[2]+v[3],plus_two,contextptr),false,contextptr);
10515 	}
10516     }
10517     if ( (position.type==_VECT) && (position._VECTptr->size()==2) ){
10518       position=rdiv(position._VECTptr->front()+position._VECTptr->back(),plus_two,contextptr);
10519     }
10520     gen sg=string2gen(s,false);
10521     if (v.size()<2)
10522       return symb_pnt_name(position+decal,couleur+_POINT_POINT,sg,contextptr);
10523     else
10524       return symb_pnt_name(position+decal,makevecteur(couleur+_POINT_POINT,v[1],sg),sg,contextptr);
10525   }
10526   static const char _legende_s []="legend";
10527   static define_unary_function_eval_quoted (__legende,&_legende,_legende_s);
10528   define_unary_function_ptr5( at_legende ,alias_at_legende,&__legende,_QUOTE_ARGUMENTS,true);
10529 
add_names(std::string & ss,const gen & v0,const gen & v1,GIAC_CONTEXT)10530   static void add_names(std::string & ss,const gen & v0,const gen & v1,GIAC_CONTEXT){
10531 #ifdef GIAC_HAS_STO_38
10532     if (v0.type==_IDNT && v1.type==_IDNT){
10533       ss += v0._IDNTptr->id_name;
10534       if (strlen(v1._IDNTptr->id_name)==2 && v1._IDNTptr->id_name[0]=='G')
10535 	ss += v1._IDNTptr->id_name[1];
10536       else
10537 	ss += v1._IDNTptr->id_name;
10538     }
10539     else
10540       ss += v0.print(contextptr)+v1.print(contextptr);
10541 #else
10542     ss += v0.print(contextptr)+v1.print(contextptr);
10543 #endif
10544   }
10545 
add_name(string & ss,const gen & v0,GIAC_CONTEXT)10546   static void add_name(string & ss,const gen & v0,GIAC_CONTEXT){
10547 #ifdef GIAC_HAS_STO_38
10548     if (v0.type==_IDNT && strlen(v0._IDNTptr->id_name)==2 && v0._IDNTptr->id_name[0]=='G')
10549       ss += v0._IDNTptr->id_name[1];
10550     else
10551       ss += v0.print(contextptr);
10552 #else
10553     ss += v0.print(contextptr);
10554 #endif
10555   }
10556 
_distanceat(const gen & args,GIAC_CONTEXT)10557   gen _distanceat(const gen & args,GIAC_CONTEXT){
10558     if ( args.type==_STRNG && args.subtype==-1) return  args;
10559     if ( args.type!=_VECT )
10560       return gentypeerr(contextptr);
10561     vecteur v = *args._VECTptr;
10562     int s=int(v.size());
10563     if (s<3)
10564       return gentypeerr(contextptr);
10565     gen l=sqrt(_longueur2(gen(makevecteur(eval(v[0],eval_level(contextptr),contextptr),eval(v[1],eval_level(contextptr),contextptr)),_SEQ__VECT),contextptr),contextptr);
10566     int save_digits=decimal_digits(contextptr);
10567     decimal_digits(contextptr)=3;
10568     string ss(1,'"');
10569     add_names(ss,v[0],v[1],contextptr);
10570     ss +='=';
10571     ss += l.print(contextptr);
10572     ss +=' ';
10573     ss +='"';
10574     decimal_digits(contextptr)=save_digits;
10575     l=string2gen(ss,false);
10576     vecteur w=makevecteur(v[2],l);
10577     for (int i=3; i<s;++i)
10578       w.push_back(v[i]);
10579     return _legende(gen(w,_SEQ__VECT),contextptr);
10580   }
10581   static const char _distanceat_s []="distanceat";
10582   static define_unary_function_eval_quoted (__distanceat,&_distanceat,_distanceat_s);
10583   define_unary_function_ptr5( at_distanceat ,alias_at_distanceat,&__distanceat,_QUOTE_ARGUMENTS,true);
10584 
_distanceatraw(const gen & args,GIAC_CONTEXT)10585   gen _distanceatraw(const gen & args,GIAC_CONTEXT){
10586     if ( args.type==_STRNG && args.subtype==-1) return  args;
10587     if ( args.type!=_VECT )
10588       return gentypeerr(contextptr);
10589     vecteur v = *args._VECTptr;
10590     int s=int(v.size());
10591     if (s<3)
10592       return gentypeerr(contextptr);
10593     gen l=sqrt(_longueur2(gen(makevecteur(v[0],v[1]),_SEQ__VECT),contextptr),contextptr);
10594     vecteur w=makevecteur(v[2],l);
10595     for (int i=3; i<s;++i)
10596       w.push_back(v[i]);
10597     return _legende(gen(w,_SEQ__VECT),contextptr);
10598   }
10599   static const char _distanceatraw_s []="distanceatraw";
10600   static define_unary_function_eval (__distanceatraw,&_distanceatraw,_distanceatraw_s);
10601   define_unary_function_ptr5( at_distanceatraw ,alias_at_distanceatraw,&__distanceatraw,0,true);
10602 
_areaatraw(const gen & args,GIAC_CONTEXT)10603   gen _areaatraw(const gen & args,GIAC_CONTEXT){
10604     if ( args.type==_STRNG && args.subtype==-1) return  args;
10605     if ( args.type!=_VECT )
10606       return gentypeerr(contextptr);
10607     vecteur v = *args._VECTptr;
10608     int s=int(v.size());
10609     if (s<2)
10610       return gentypeerr(contextptr);
10611     gen l=_aire(v[0],contextptr);
10612     vecteur w=makevecteur(v[1],l);
10613     for (int i=2; i<s;++i)
10614       w.push_back(v[i]);
10615     return _legende(gen(w,_SEQ__VECT),contextptr);
10616   }
10617   static const char _areaatraw_s []="areaatraw";
10618   static define_unary_function_eval (__areaatraw,&_areaatraw,_areaatraw_s);
10619   define_unary_function_ptr5( at_areaatraw ,alias_at_areaatraw,&__areaatraw,0,true);
10620 
_areaat(const gen & args,GIAC_CONTEXT)10621   gen _areaat(const gen & args,GIAC_CONTEXT){
10622     if ( args.type==_STRNG && args.subtype==-1) return  args;
10623     if ( args.type!=_VECT )
10624       return gentypeerr(contextptr);
10625     vecteur v = *args._VECTptr;
10626     int s=int(v.size());
10627     if (s<2)
10628       return gentypeerr(contextptr);
10629     gen l=_aire(eval(v[0],eval_level(contextptr),contextptr),contextptr);
10630     int save_digits=decimal_digits(contextptr);
10631     decimal_digits(contextptr)=3;
10632     string ss="\"a";
10633     add_name(ss,v[0],contextptr);
10634     ss +="="+l.print(contextptr)+" \"";
10635     // string ss="◼"+v[0].print(contextptr)+"="+l.print(contextptr)+" ";
10636     decimal_digits(contextptr)=save_digits;
10637     l=string2gen(ss,false);
10638     vecteur w=makevecteur(v[1],l);
10639     for (int i=2; i<s;++i)
10640       w.push_back(v[i]);
10641     return _legende(gen(w,_SEQ__VECT),contextptr);
10642   }
10643   static const char _areaat_s []="areaat";
10644   static define_unary_function_eval_quoted (__areaat,&_areaat,_areaat_s);
10645   define_unary_function_ptr5( at_areaat ,alias_at_areaat,&__areaat,_QUOTE_ARGUMENTS,true);
10646 
_slopeatraw(const gen & args,GIAC_CONTEXT)10647   gen _slopeatraw(const gen & args,GIAC_CONTEXT){
10648     if ( args.type==_STRNG && args.subtype==-1) return  args;
10649     if ( args.type!=_VECT )
10650       return gentypeerr(contextptr);
10651     vecteur v = *args._VECTptr;
10652     int s=int(v.size());
10653     if (s<2)
10654       return gentypeerr(contextptr);
10655     gen l=_slope(v[0],contextptr);
10656     vecteur w=makevecteur(v[1],l);
10657     for (int i=2; i<s;++i)
10658       w.push_back(v[i]);
10659     return _legende(gen(w,_SEQ__VECT),contextptr);
10660   }
10661   static const char _slopeatraw_s []="slopeatraw";
10662   static define_unary_function_eval (__slopeatraw,&_slopeatraw,_slopeatraw_s);
10663   define_unary_function_ptr5( at_slopeatraw ,alias_at_slopeatraw,&__slopeatraw,0,true);
10664 
_slopeat(const gen & args,GIAC_CONTEXT)10665   gen _slopeat(const gen & args,GIAC_CONTEXT){
10666     if ( args.type==_STRNG && args.subtype==-1) return  args;
10667     if ( args.type!=_VECT )
10668       return gentypeerr(contextptr);
10669     vecteur v = *args._VECTptr;
10670     int s=int(v.size());
10671     if (s<2)
10672       return gentypeerr(contextptr);
10673     gen l=_slope(eval(v[0],eval_level(contextptr),contextptr),contextptr);
10674     int save_digits=decimal_digits(contextptr);
10675     decimal_digits(contextptr)=3;
10676     // string ss="∡"+v[0].print(contextptr)+"="+l.print(contextptr)+" ";
10677     string ss="\"s";
10678     add_name(ss,v[0],contextptr);
10679     ss += "="+l.print(contextptr)+" \"";
10680     decimal_digits(contextptr)=save_digits;
10681     l=string2gen(ss,false);
10682     vecteur w=makevecteur(v[1],l);
10683     for (int i=2; i<s;++i)
10684       w.push_back(v[i]);
10685     return _legende(gen(w,_SEQ__VECT),contextptr);
10686   }
10687   static const char _slopeat_s []="slopeat";
10688   static define_unary_function_eval_quoted (__slopeat,&_slopeat,_slopeat_s);
10689   define_unary_function_ptr5( at_slopeat ,alias_at_slopeat,&__slopeat,_QUOTE_ARGUMENTS,true);
10690 
_perimeterat(const gen & args,GIAC_CONTEXT)10691   gen _perimeterat(const gen & args,GIAC_CONTEXT){
10692     if ( args.type==_STRNG && args.subtype==-1) return  args;
10693     if ( args.type!=_VECT )
10694       return gentypeerr(contextptr);
10695     vecteur v = *args._VECTptr;
10696     int s=int(v.size());
10697     if (s<2)
10698       return gentypeerr(contextptr);
10699     gen l=_perimetre(eval(v[0],eval_level(contextptr),contextptr),contextptr);
10700     int save_digits=decimal_digits(contextptr);
10701     decimal_digits(contextptr)=3;
10702     string ss="\"p";
10703     add_name(ss,v[0],contextptr);
10704     ss += "="+l.print(contextptr)+" \"";
10705     // string ss="◻"+v[0].print(contextptr)+"="+l.print(contextptr)+" ";
10706     decimal_digits(contextptr)=save_digits;
10707     l=string2gen(ss,false);
10708     vecteur w=makevecteur(v[1],l);
10709     for (int i=2; i<s;++i)
10710       w.push_back(v[i]);
10711     return _legende(gen(w,_SEQ__VECT),contextptr);
10712   }
10713   static const char _perimeterat_s []="perimeterat";
10714   static define_unary_function_eval_quoted (__perimeterat,&_perimeterat,_perimeterat_s);
10715   define_unary_function_ptr5( at_perimeterat ,alias_at_perimeterat,&__perimeterat,_QUOTE_ARGUMENTS,true);
10716 
_perimeteratraw(const gen & args,GIAC_CONTEXT)10717   gen _perimeteratraw(const gen & args,GIAC_CONTEXT){
10718     if ( args.type==_STRNG && args.subtype==-1) return  args;
10719     if ( args.type!=_VECT )
10720       return gentypeerr(contextptr);
10721     vecteur v = *args._VECTptr;
10722     int s = int(v.size());
10723     if (s<2)
10724       return gentypeerr(contextptr);
10725     gen l=_perimetre(v[0],contextptr);
10726     vecteur w=makevecteur(v[1],l);
10727     for (int i=2; i<s;++i)
10728       w.push_back(v[i]);
10729     return _legende(gen(w,_SEQ__VECT),contextptr);
10730   }
10731   static const char _perimeteratraw_s []="perimeteratraw";
10732   static define_unary_function_eval (__perimeteratraw,&_perimeteratraw,_perimeteratraw_s);
10733   define_unary_function_ptr5( at_perimeteratraw ,alias_at_perimeteratraw,&__perimeteratraw,0,true);
10734 
_extract_measure(const gen & valeur,GIAC_CONTEXT)10735   gen _extract_measure(const gen & valeur,GIAC_CONTEXT){
10736     if ( valeur.type==_STRNG && valeur.subtype==-1) return  valeur;
10737     gen tmp=valeur;
10738     if (valeur.is_symb_of_sommet(at_pnt)){
10739       gen & valf = valeur._SYMBptr->feuille;
10740       if (valf.type==_VECT){
10741 	vecteur & valv = *valf._VECTptr;
10742 	int s = int(valv.size());
10743 	if (s>1){
10744 	  gen valv1=valv[1];
10745 	  if (valv1.type==_VECT && valv1._VECTptr->size()>2){
10746 	    tmp=(*valv1._VECTptr)[1];
10747 	    while (tmp.type==_STRNG)
10748 	      tmp=gen(*tmp._STRNGptr,contextptr);
10749 	    if (tmp.is_symb_of_sommet(at_equal))
10750 	      tmp=tmp._SYMBptr->feuille._VECTptr->back();
10751 	  }
10752 	}
10753       }
10754     }
10755     return tmp;
10756   }
10757   static const char _extract_measure_s []="extract_measure";
10758   static define_unary_function_eval (__extract_measure,&_extract_measure,_extract_measure_s);
10759   define_unary_function_ptr5( at_extract_measure ,alias_at_extract_measure,&__extract_measure,0,true);
10760 
_angleat(const gen & args,GIAC_CONTEXT)10761   gen _angleat(const gen & args,GIAC_CONTEXT){
10762     if ( args.type==_STRNG && args.subtype==-1) return  args;
10763     if ( args.type!=_VECT )
10764       return gentypeerr(contextptr);
10765     vecteur v = *args._VECTptr;
10766     int s = int(v.size());
10767     if (s<4)
10768       return gentypeerr(contextptr);
10769     gen l=_angle(gen(makevecteur(eval(v[0],eval_level(contextptr),contextptr),eval(v[1],eval_level(contextptr),contextptr),eval(v[2],eval_level(contextptr),contextptr)),_SEQ__VECT),contextptr);
10770     int save_digits=decimal_digits(contextptr);
10771     decimal_digits(contextptr)=3;
10772     string ss="\"α";
10773     add_name(ss,v[0],contextptr);
10774     ss += "="+l.print(contextptr)+" \"";
10775     // string ss="∡"+v[0].print(contextptr)+"="+l.print(contextptr)+" ";
10776     decimal_digits(contextptr)=save_digits;
10777     l=string2gen(ss,false);
10778     vecteur w=makevecteur(v[3],l);
10779     for (int i=4; i<s;++i)
10780       w.push_back(v[i]);
10781     return _legende(gen(w,_SEQ__VECT),contextptr);
10782   }
10783   static const char _angleat_s []="angleat";
10784   static define_unary_function_eval_quoted (__angleat,&_angleat,_angleat_s);
10785   define_unary_function_ptr5( at_angleat ,alias_at_angleat,&__angleat,_QUOTE_ARGUMENTS,true);
10786 
_angleatraw(const gen & args,GIAC_CONTEXT)10787   gen _angleatraw(const gen & args,GIAC_CONTEXT){
10788     if ( args.type==_STRNG && args.subtype==-1) return  args;
10789     if ( args.type!=_VECT )
10790       return gentypeerr(contextptr);
10791     vecteur v = *args._VECTptr;
10792     int s = int(v.size());
10793     if (s<4)
10794       return gentypeerr(contextptr);
10795     gen l=_angle(gen(makevecteur(v[0],v[1],v[2]),_SEQ__VECT),contextptr);
10796     l=recursive_normal(l,contextptr);
10797     vecteur w=makevecteur(v[3],l);
10798     for (int i=4; i<s;++i)
10799       w.push_back(v[i]);
10800     return _legende(gen(w,_SEQ__VECT),contextptr);
10801   }
10802   static const char _angleatraw_s []="angleatraw";
10803   static define_unary_function_eval (__angleatraw,&_angleatraw,_angleatraw_s);
10804   define_unary_function_ptr5( at_angleatraw ,alias_at_angleatraw,&__angleatraw,0,true);
10805 
_couleur(const gen & a,GIAC_CONTEXT)10806   gen _couleur(const gen & a,GIAC_CONTEXT){
10807     if (is_undef(a)) return a;
10808     if (a.type==_STRNG){
10809       *logptr(contextptr) << gettext("Use pencolor for the turtle") << '\n';
10810       return _couleur(gen(*a._STRNGptr,contextptr),contextptr);
10811     }
10812     if (a.type==_INT_){
10813       int i=default_color(contextptr);
10814       default_color(a.val,contextptr);
10815       return i;
10816     }
10817     if ( (a.type!=_VECT) || (a._VECTptr->size()<2))
10818       return default_color(contextptr);
10819     gen c=a._VECTptr->back(),b;
10820     if (a._VECTptr->size()==3 && c.type==_INT_ && (b=a._VECTptr->front()).type==_INT_ && (*a._VECTptr)[1].type==_INT_){
10821       // 565 color
10822       int d=(((b.val*32)/256)<<11) | ((((*a._VECTptr)[1].val*64)/256)<<5) | ((c.val*32)/256);
10823       if (d>0 && d<512){
10824 	d += (1<<11);
10825       }
10826       return d;
10827     }
10828     if (a._VECTptr->size()>2)
10829       b=vecteur(a._VECTptr->begin(),a._VECTptr->end()-1);
10830     else
10831       b=a._VECTptr->front();
10832     if (b.type==_VECT){
10833       const_iterateur it=b._VECTptr->begin(),itend=b._VECTptr->end();
10834       vecteur res;
10835       res.reserve(itend-it);
10836       for (;it!=itend;++it)
10837 	res.push_back(_couleur(makevecteur(*it,c),contextptr));
10838       return gen(res,b.subtype);
10839     }
10840     if ( (b.type!=_SYMB) || (b._SYMBptr->sommet!=at_pnt))
10841       return symbolic(at_couleur,a);
10842     vecteur v(*b._SYMBptr->feuille._VECTptr);
10843     v[1]=c;
10844     gen e=symbolic(at_pnt,gen(v,_PNT__VECT));
10845     history_plot(contextptr).push_back(e);
10846 #ifndef KHICAS
10847     if (io_graph(contextptr))
10848       __interactive.op(e,contextptr);
10849 #endif
10850     return e;
10851   }
10852   static const char _display_s []="display";
10853   static define_unary_function_eval_index (160,__display,&_couleur,_display_s);
10854   define_unary_function_ptr5( at_display ,alias_at_display,&__display,0,true);
10855 
10856   static const char _couleur_s []="color";
10857   static define_unary_function_eval (__couleur,&_couleur,_couleur_s);
10858   define_unary_function_ptr5( at_couleur ,alias_at_couleur,&__couleur,0,true);
10859 
10860   // innert instruction, used e.g. for a:=element(3..5)
10861   // returns parameter(a,3..5,4) and stores 4 in a
_parameter(const gen & args,GIAC_CONTEXT)10862   gen _parameter(const gen & args,GIAC_CONTEXT){
10863     if ( args.type==_STRNG && args.subtype==-1) return  args;
10864     if ( (args.type!=_VECT) || (args._VECTptr->size()<4))
10865       return gensizeerr(contextptr);
10866     return symbolic(at_parameter,args);
10867   }
10868   static const char _parameter_s []="parameter";
10869   static define_unary_function_eval (__parameter,&_parameter,_parameter_s);
10870   define_unary_function_ptr5( at_parameter ,alias_at_parameter,&__parameter,0,true);
10871 
10872   // plot solution of y'=f(x,y) [x0,y0] in current plot range
10873   // OR [x,y]'=f(t,x,y) t0 x0 y0 in current plot range
10874   // args = dy/dx, [x, y], [x0, y0]
10875   // OR [dx/dt, dy/dt], [t, x, y], [t0, x0, y0]
plotode(const vecteur & w,GIAC_CONTEXT)10876   static gen plotode(const vecteur & w,GIAC_CONTEXT){
10877     vecteur v(w);
10878     bool curve=true;
10879     gen fp=v[0];
10880     if (fp.is_symb_of_sommet(at_equal) && fp._SYMBptr->feuille[0].type==_INT_){
10881       fp=fp._SYMBptr->feuille[1];
10882       *logptr(contextptr) << "Warning, replacing plotode(" << v[0] << " by plotode(" << fp << '\n';
10883     }
10884     if (fp.type!=_VECT) // y'=f(x,y)
10885       fp=makevecteur(plus_one,fp);
10886     gen vars=v[1];
10887     bool dim3=vars.type==_VECT && vars._VECTptr->size()==3;
10888     if (abs_calc_mode(contextptr)==38)
10889       dim3=false; // no 3-d rendering :-(
10890     gen init=remove_at_pnt(v[2]);
10891     if (init.type!=_VECT)
10892       init=makevecteur(re(init,contextptr),im(init,contextptr));
10893     gen t;
10894     int s;
10895     if (vars.type != _VECT || (s = int(vars._VECTptr->size()))<2)
10896       return gensizeerr(contextptr);
10897     if (s==3){
10898       t=vars._VECTptr->front();
10899       vars=makevecteur(vars[1],vars[2]);
10900     }
10901     else {
10902       identificateur tt(" t");
10903       t=tt;
10904       if (s==2 && vars[0].is_symb_of_sommet(at_equal)){
10905 	v.push_back(vars[0]);
10906 	t=vars[0]._SYMBptr->feuille[0];
10907 	vars=makevecteur(t,vars[1]);
10908       }
10909     }
10910     if (vars.type==_VECT && vars._VECTptr->size()==2 && vars._VECTptr->back().is_symb_of_sommet(at_equal))
10911       vars=makevecteur(vars._VECTptr->front(),vars._VECTptr->back()._SYMBptr->feuille[0]);
10912     v[1]=vars;
10913     vecteur f=makevecteur(fp,(t.is_symb_of_sommet(at_equal)?t._SYMBptr->feuille._VECTptr->front():t),vars);
10914     if (init.type != _VECT || (s = int(init._VECTptr->size()))<2)
10915       return gensizeerr(contextptr);
10916     vecteur & initv=*init._VECTptr;
10917     gen t0=initv.front();
10918     gen x0=t0;
10919     if (s==3)
10920       x0=initv[1];
10921     gen y0=makevecteur(x0,initv.back());
10922     double ym[2]={gnuplot_xmin,gnuplot_ymin},yM[2]={gnuplot_xmin,gnuplot_ymin};
10923     double * ymin = 0;
10924     double * ymax = 0;
10925     double tstep=0,tmin=-1e300,tmax=1e300;
10926     bool tminmax_defined,tstep_defined;
10927     read_tmintmaxtstep(v,t,3,tmin,tmax,tstep,tminmax_defined,tstep_defined,contextptr);
10928     if (tmin>tmax || tstep<=0)
10929       return gensizeerr(gettext("Time"));
10930 #ifdef KHICAS
10931     int maxstep=80;
10932 #else
10933     int maxstep=500;
10934 #endif
10935     if (tminmax_defined && tstep_defined)
10936       maxstep=giacmax(maxstep,2*int((tmax-tmin)/tstep));
10937     int vs=int(v.size());
10938     for (int i=3;i<vs;++i){
10939       if (readvar(v[i])==vars[0]){
10940 	if (readrange(v[i],gnuplot_xmin,gnuplot_xmax,v[i],ym[0],yM[0],contextptr)){
10941 	  ymin=ym;
10942 	  ymax=yM;
10943 	  v.erase(v.begin()+i);
10944 	  --vs;
10945 	}
10946       }
10947       if (readvar(v[i])==vars[1]){
10948 	if (readrange(v[i],gnuplot_xmin,gnuplot_xmax,v[i],ym[1],yM[1],contextptr)){
10949 	  ymin=ym;
10950 	  ymax=yM;
10951 	  v.erase(v.begin()+i);
10952 	  --vs;
10953 	}
10954       }
10955     }
10956     if (dim3 && vs>3)
10957       dim3=(v[3]!=at_plan);
10958     vecteur res1v,resv;
10959     if (tmin<0){
10960       gen res1=odesolve(t0,tmin,f,y0,tstep,curve,ymin,ymax,maxstep,contextptr);
10961       if (is_undef(res1)) return res1;
10962       res1v=*res1._VECTptr;
10963       std::reverse(res1v.begin(),res1v.end());
10964     }
10965     res1v.push_back(makevecteur(t0,y0));
10966     if (tmax>0){
10967       gen res2=odesolve(t0,tmax,f,y0,tstep,curve,ymin,ymax,maxstep,contextptr);
10968       if (is_undef(res2)) return res2;
10969       resv=mergevecteur(res1v,*res2._VECTptr);
10970     }
10971     else
10972       resv=res1v;
10973     // make the curve
10974     const_iterateur it=resv.begin(),itend=resv.end();
10975     vecteur res;
10976     res.reserve(itend-it);
10977     for (;it!=itend;++it){
10978       if (it->type!=_VECT || it->_VECTptr->empty() || it->_VECTptr->back().type!=_VECT)
10979 	continue;
10980       vecteur tmp=*it->_VECTptr->back()._VECTptr;
10981       if (tmp.size()!=2 || is_undef(tmp.front()) || is_undef(tmp.back()))
10982 	continue;
10983       if (dim3)
10984 	res.push_back(gen(makevecteur(it->_VECTptr->front(),tmp.front(),tmp.back()),_POINT__VECT));
10985       else
10986 	res.push_back(tmp.front()+cst_i*tmp.back());
10987     }
10988     return symb_pnt(gen(res,_GROUP__VECT),contextptr);
10989   }
_plotode(const gen & args,GIAC_CONTEXT)10990   gen _plotode(const gen & args,GIAC_CONTEXT){
10991     if ( args.type==_STRNG && args.subtype==-1) return  args;
10992     vecteur attributs(1,default_color(contextptr));
10993     vecteur v(seq2vecteur(args));
10994     int s=read_attributs(v,attributs,contextptr);
10995     if (s<3)
10996       return gendimerr(contextptr);
10997     // v.erase(v.begin()+s,v.end());
10998     return put_attributs(plotode(v,contextptr),attributs,contextptr);
10999   }
11000   static const char _plotode_s []="plotode";
11001   static define_unary_function_eval (__plotode,&_plotode,_plotode_s);
11002   define_unary_function_ptr5( at_plotode ,alias_at_plotode,&__plotode,0,true);
11003 
11004   static const char _odeplot_s []="odeplot";
11005   static define_unary_function_eval (__odeplot,&_plotode,_odeplot_s);
11006   define_unary_function_ptr5( at_odeplot ,alias_at_odeplot,&__odeplot,0,true);
11007 
plotfield(const gen & xp,const gen & yp,const gen & x,const gen & y,double xmin,double xmax,double xstep,double ymin,double ymax,double ystep,double scaling,vecteur & attributs,bool normalize,const context * contextptr)11008   gen plotfield(const gen & xp,const gen & yp,const gen & x,const gen & y,double xmin,double xmax,double xstep,double ymin,double ymax,double ystep,double scaling,vecteur & attributs,bool normalize,const context * contextptr){
11009     if (xstep<=0 || ystep<=0)
11010       return gensizeerr("Invalid xstep or ystep");
11011     bool old_iograph=io_graph(contextptr);
11012     if (old_iograph){
11013 #ifdef HAVE_LIBPTHREAD
11014       pthread_mutex_lock(&interactive_mutex);
11015 #endif
11016       io_graph(false,contextptr);
11017 #ifdef HAVE_LIBPTHREAD
11018       pthread_mutex_unlock(&interactive_mutex);
11019 #endif
11020     }
11021     vecteur xy_v;
11022     xy_v.push_back(x);
11023     xy_v.push_back(y);
11024     gen xp_eval,yp_eval,xy(xy_v),origine;
11025     vecteur curxcury(2);
11026     vecteur res;
11027     double echelle,minxstepystep;
11028     if (xstep<ystep) minxstepystep=xstep; else minxstepystep=ystep;
11029     echelle=minxstepystep;
11030     for (double curx=xmin;curx<=xmax;curx+=scaling*xstep){
11031       if (ctrl_c || interrupted) break;
11032       curxcury[0]=curx;
11033       for (double cury=ymin;cury<=ymax;cury+=scaling*ystep){
11034 	if (ctrl_c || interrupted) break;
11035 	curxcury[1]=cury;
11036 	xp_eval=subst(xp,xy,curxcury,false,contextptr).evalf2double(eval_level(contextptr),contextptr);
11037 	yp_eval=subst(yp,xy,curxcury,false,contextptr).evalf2double(eval_level(contextptr),contextptr);
11038 	if ((xp_eval.type==_DOUBLE_) && (yp_eval.type==_DOUBLE_)){
11039 	  double xpd=xp_eval._DOUBLE_val,ypd=yp_eval._DOUBLE_val;
11040 	  if (normalize){
11041 	    echelle=minxstepystep/std::sqrt(xpd*xpd+ypd*ypd);
11042 	    origine=gen(curx-xpd/2*echelle)+cst_i*gen(cury-ypd/2*echelle);
11043 	  }
11044 	  else {
11045 	    origine=gen(curx)+cst_i*gen(cury);
11046 	  }
11047 	  // always return vectors now, before it was != in dimension 1
11048 	  res.push_back(pnt_attrib(gen(makevecteur(origine,origine+echelle*xp_eval+echelle*cst_i*yp_eval),
11049 				       //is_one(xp)?_GROUP__VECT:_VECTOR__VECT
11050 				       _VECTOR__VECT
11051 				       ),attributs,contextptr));
11052 	}
11053       }
11054     }
11055     if (old_iograph){
11056 #ifdef HAVE_LIBPTHREAD
11057       pthread_mutex_lock(&interactive_mutex);
11058 #endif
11059       io_graph(true,contextptr);
11060 #ifdef HAVE_LIBPTHREAD
11061       pthread_mutex_unlock(&interactive_mutex);
11062 #endif
11063       iterateur it=res.begin(),itend=res.end();
11064       for (;it!=itend;++it)
11065 	__interactive.op(*it,contextptr);
11066     }
11067     return gen(res,_GROUP__VECT);
11068   }
11069 
read_plotfield_args(const gen & args,gen & xp,gen & yp,gen & x,gen & y,double & xmin,double & xmax,double & xstep,double & ymin,double & ymax,double & ystep,vecteur & attributs,bool & normalize,vecteur & initcondv,GIAC_CONTEXT)11070   static bool read_plotfield_args(const gen & args,gen & xp,gen & yp,gen & x,gen & y,double & xmin,double & xmax,double & xstep,double & ymin,double & ymax,double & ystep,vecteur & attributs,bool & normalize,vecteur & initcondv,GIAC_CONTEXT){
11071     if (args.type!=_VECT || args._VECTptr->size()<2)
11072       return false; // setsizeerr(contextptr);
11073     normalize=false;
11074     vecteur v(*args._VECTptr);
11075     int s = int(v.size());
11076     if (s && v[0].is_symb_of_sommet(at_equal)){
11077       // accept plotfield(y'=f(t,y),...) instead of plotfield(f(t,y),...)
11078       gen f=v[0]._SYMBptr->feuille;
11079       if (f.type==_VECT && f._VECTptr->size()==2 && f._VECTptr->front().type==_INT_){
11080 	*logptr(contextptr) << "Warning, replacing plotfield of " << v[0] << " by " << f._VECTptr->back() << '\n';
11081 	v[0]=f._VECTptr->back();
11082       }
11083     }
11084     for (int i=0;i<s;++i){
11085       if (v[i]==at_normalize){
11086 	normalize=true;
11087 	v.erase(v.begin()+i);
11088 	--s;
11089       }
11090       if (v[i].type==_VECT && v[i]._VECTptr->size()==1 && v[i]._VECTptr->front().type==_VECT){
11091 	initcondv.push_back(v[i]._VECTptr->front());
11092 	v.erase(v.begin()+i);
11093 	--s;
11094       }
11095       if (v[i].is_symb_of_sommet(at_equal) && v[i]._SYMBptr->feuille.type==_VECT && v[i]._SYMBptr->feuille._VECTptr->size()==2 && v[i]._SYMBptr->feuille._VECTptr->front()==at_plotode){
11096 	gen add=v[i]._SYMBptr->feuille._VECTptr->back();
11097 	if (add.type==_VECT && !add._VECTptr->empty()){
11098 	  if (add._VECTptr->front().type==_VECT){
11099 	    const_iterateur it=add._VECTptr->begin(),itend=add._VECTptr->end();
11100 	    for (;it!=itend;++it)
11101 	      initcondv.push_back(*it);
11102 	  }
11103 	  else
11104 	    initcondv.push_back(add);
11105 	  v.erase(v.begin()+i);
11106 	}
11107 	--s;
11108       }
11109     }
11110     s=read_attributs(v,attributs,contextptr);
11111     v=vecteur(args._VECTptr->begin(),args._VECTptr->begin()+s);
11112     if (s>=2){
11113       initcondv.insert(initcondv.begin(),v[0]);
11114       if (v[1].type==_VECT || s==2)
11115 	initcondv.insert(initcondv.begin()+1,v[1]);
11116       else
11117 	initcondv.insert(initcondv.begin()+1,makevecteur(v[1],v[2]));
11118     }
11119     switch (s){
11120     case 0: case 1:
11121       return false; // setsizeerr(contextptr);
11122     case 2:
11123       if ( (v.back().type!=_VECT) || (v.back()._VECTptr->size()!=2) )
11124 	return false; // setsizeerr(contextptr);
11125       x=v.back()._VECTptr->front();
11126       y=v.back()._VECTptr->back();
11127       yp=equal2diff(v.front());
11128       if (yp.type==_VECT){
11129 	xp=yp._VECTptr->front();
11130 	yp=yp._VECTptr->back();
11131       }
11132       else
11133 	xp=plus_one;
11134       break;
11135     case 3:
11136       if (v[0].type!=_VECT){
11137 	xp=plus_one;
11138 	yp=equal2diff(v[0]);
11139       }
11140       else {
11141 	if (v[0]._VECTptr->size()!=2)
11142 	  return false; // setsizeerr(contextptr);
11143 	xp=v[0]._VECTptr->front();
11144 	yp=v[0]._VECTptr->back();
11145       }
11146       x=v[1];
11147       y=v[2];
11148       break;
11149     default:
11150       xp=v[0];
11151       yp=v[1];
11152       x=v[2];
11153       y=v[3];
11154     }
11155     int nstep=int(std::sqrt(double(gnuplot_pixels_per_eval)/2)),jstep=0,kstep=0;
11156     readrange(x,gnuplot_xmin,gnuplot_xmax,x,xmin,xmax,contextptr);
11157     readrange(y,gnuplot_xmin,gnuplot_xmax,y,ymin,ymax,contextptr);
11158     vecteur tmp;
11159     read_option(*args._VECTptr,xmin,xmax,ymin,ymax,gnuplot_zmin,gnuplot_zmax,tmp,nstep,jstep,kstep,contextptr);
11160     xstep=(xmax-xmin)/nstep;
11161     ystep=(ymax-ymin)/(jstep?jstep:nstep);
11162     return true;
11163   }
11164   // args=[dx/dt,dy/dt,x,y] or [dy/dx,x,y]
11165   // or [ [dx/dt,dy/dt], [x,y] ] or [ dy/dx, [x,y]]
_plotfield(const gen & args,const context * contextptr)11166   gen _plotfield(const gen & args,const context * contextptr){
11167     if ( args.type==_STRNG && args.subtype==-1) return  args;
11168     vecteur attributs;
11169     gen xp,yp,x,y;
11170     double xmin,xmax,ymin,ymax,xstep,ystep;
11171     bool normalize;
11172     vecteur initcondv;
11173     if (!read_plotfield_args(args,xp,yp,x,y,xmin,xmax,xstep,ymin,ymax,ystep,attributs,normalize,initcondv,contextptr))
11174       return gensizeerr(contextptr);
11175     int s=initcondv.size();
11176     double scaling=2;
11177     if (s>2){
11178       vecteur res;
11179       res.push_back(plotfield(xp,yp,x,y,xmin,xmax,xstep/scaling,ymin,ymax,ystep/scaling,scaling,attributs,normalize,contextptr));
11180       vecteur argu(3);
11181       argu[0]=initcondv[0]; argu[1]=initcondv[1];
11182       for (int i=2;i<s;++i){
11183 	argu[2]=initcondv[i];
11184 	res.push_back(plotode(argu,contextptr));
11185       }
11186       return res;
11187     }
11188     return plotfield(xp,yp,x,y,xmin,xmax,xstep/scaling,ymin,ymax,ystep/scaling,scaling,attributs,normalize,contextptr);
11189   }
11190   static const char _plotfield_s []="plotfield";
11191   static define_unary_function_eval (__plotfield,&_plotfield,_plotfield_s);
11192   define_unary_function_ptr5( at_plotfield ,alias_at_plotfield,&__plotfield,0,true);
11193 
11194   static const char _fieldplot_s []="fieldplot";
11195   static define_unary_function_eval (__fieldplot,&_plotfield,_fieldplot_s);
11196   define_unary_function_ptr5( at_fieldplot ,alias_at_fieldplot,&__fieldplot,0,true);
11197 
11198 
11199   // like plotode but the initial(s) condition(s) will be specified
11200   // by the user
_interactive_plotode(const gen & args,GIAC_CONTEXT)11201   gen _interactive_plotode(const gen & args,GIAC_CONTEXT){
11202     if ( args.type==_STRNG && args.subtype==-1) return  args;
11203     vecteur attributs;
11204     gen xp,yp,x,y;
11205     double xmin,xmax,ymin,ymax,xstep,ystep;
11206     bool normalize;
11207     vecteur initcondv;
11208     if (!read_plotfield_args(args,xp,yp,x,y,xmin,xmax,xstep,ymin,ymax,ystep,attributs,normalize,initcondv,contextptr))
11209       return gensizeerr(contextptr);
11210     // double scaling=3;
11211     vecteur res;
11212 #if defined(WIN32) || !defined(HAVE_SIGNAL_H_OLD)
11213     res.push_back(_plotfield(args,contextptr));
11214 #else
11215     if (thread_eval_status(contextptr)==1){
11216       res.push_back(_plotfield(args,contextptr));
11217       _DispG(0,contextptr);
11218     }
11219     else
11220       res.push_back(_signal(_plotfield(args,contextptr),contextptr));
11221 #endif
11222     identificateur tt(" t");
11223     gen t(tt);
11224     vecteur vars=makevecteur(t,x,y);
11225     // if (is_one(xp)) vars[0]=symb_equal(t,symb_interval(xmin,xmax));
11226     vecteur f(makevecteur(xp,yp));
11227     gen xminmax=symb_equal(x,symb_interval(xmin,xmax));
11228     gen yminmax=symb_equal(y,symb_interval(ymin,ymax));
11229     for (;;){
11230       gen localisation=__click.op(vecteur(0),contextptr).evalf_double(1,contextptr);
11231       double x0,y0;
11232       if (localisation.type==_DOUBLE_){
11233 	x0=localisation._DOUBLE_val;
11234 	y0=0;
11235       }
11236       else {
11237 	if ((localisation.type==_CPLX) && (localisation.subtype==3) ) {
11238 	  x0=localisation._CPLXptr->_DOUBLE_val;
11239 	  y0=(localisation._CPLXptr+1)->_DOUBLE_val;
11240 	}
11241 	else {
11242 	  *logptr(contextptr) << gettext("End interactive_plotode") << '\n';
11243 	  break;
11244 	}
11245       }
11246 #if defined(WIN32) || !defined(HAVE_SIGNAL_H_OLD)
11247       res.push_back(_plotode(gen(makevecteur(f,vars,makevecteur(0,x0,y0),xminmax,yminmax,at_plan),_SEQ__VECT),contextptr));
11248 #else
11249       if (thread_eval_status(contextptr)==1)
11250 	res.push_back(_plotode(gen(makevecteur(f,vars,makevecteur(0,x0,y0),xminmax,yminmax,at_plan),_SEQ__VECT),contextptr));
11251       else
11252 	res.push_back(_signal(_plotode(gen(makevecteur(f,vars,makevecteur(0,x0,y0),xminmax,yminmax,at_plan),_SEQ__VECT),contextptr),contextptr));
11253 #endif
11254     }
11255     return res;
11256   }
11257   static const char _interactive_plotode_s []="interactive_plotode";
11258   static define_unary_function_eval (__interactive_plotode,&_interactive_plotode,_interactive_plotode_s);
11259   define_unary_function_ptr5( at_interactive_plotode ,alias_at_interactive_plotode,&__interactive_plotode,0,true);
11260 
11261   static const char _interactive_odeplot_s []="interactive_odeplot";
11262   static define_unary_function_eval (__interactive_odeplot,&_interactive_plotode,_interactive_odeplot_s);
11263   define_unary_function_ptr5( at_interactive_odeplot ,alias_at_interactive_odeplot,&__interactive_odeplot,0,true);
11264 
11265 #if !defined NSPIRE && !defined FXCG //&& !defined EMCC
unarchive_VECT(istream & is,GIAC_CONTEXT)11266   static vecteur unarchive_VECT(istream & is,GIAC_CONTEXT){
11267     vecteur v;
11268     int taille;
11269     is >> taille;
11270     v.reserve(taille);
11271     for (int i=0;i<taille;++i)
11272       v.push_back(unarchive(is,contextptr));
11273     return v;
11274   }
11275 
unarchive_MAP(istream & is,GIAC_CONTEXT)11276   static gen unarchive_MAP(istream & is,GIAC_CONTEXT){
11277 #if 1 // def NSPIRE
11278     gen_map m;
11279 #else
11280     gen_map m(ptr_fun(islesscomplexthanf));
11281 #endif
11282     int taille;
11283     is >> taille;
11284     for (int i=0;i<taille;++i){
11285       gen f=unarchive(is,contextptr);
11286       gen s=unarchive(is,contextptr);
11287       m[f]=s;
11288     }
11289     return m;
11290   }
11291 
unarchive_FUNC(istream & is,GIAC_CONTEXT)11292   static gen unarchive_FUNC(istream & is,GIAC_CONTEXT){
11293     int op;
11294     is >> op;
11295     unary_function_ptr u(*at_plus);
11296     if (op){
11297       if (op<0){
11298 	string s;
11299 	is >> s;
11300 	if (debug_infolevel>20)
11301 	  *logptr(contextptr) << s << '\n';
11302 	// read function from lexer_functions
11303 	std::pair<charptr_gen *,charptr_gen *> p= equal_range(builtin_lexer_functions_begin(),builtin_lexer_functions_end(),std::pair<const char *,gen>(s.c_str(),0),tri);
11304 	if (p.first!=p.second && p.first!=builtin_lexer_functions_end())
11305 	  return p.first->second;
11306 	map_charptr_gen::const_iterator i = lexer_functions().find(s.c_str());
11307 	if (i==lexer_functions().end()) // should be error
11308 	  return undef;
11309 	return i->second;
11310       }
11311       u=archive_function_tab()[op-1];
11312     }
11313     else {
11314       // read using the parser
11315       string s;
11316       is >> s;
11317       gen e;
11318 #ifndef NO_STDEXCEPT
11319       try {
11320 #endif
11321 	e=gen(s,contextptr);
11322 	if (is_undef(e))
11323 	  e=string2gen(s,false);
11324 #ifndef NO_STDEXCEPT
11325       }
11326       catch (std::runtime_error & ){
11327 	last_evaled_argptr(contextptr)=NULL;
11328 	e=string2gen(s,false);
11329       }
11330 #endif
11331       //CERR << s << " " <<e.type << '\n';
11332       if (e.type!=_FUNC){
11333 	if ( (e.type!=_SYMB) ){
11334 	  CERR << "Unarchive error: "+e.print(contextptr) << '\n';
11335 	  return e;
11336 	}
11337 	if (e._SYMBptr->sommet.ptr()->printsommet==printastifunction)
11338 	  return e._SYMBptr->sommet;
11339 	return e._SYMBptr->feuille;
11340       }
11341       u=*e._FUNCptr;
11342     }
11343     return u;
11344   }
11345 
unarchive_SYMB(istream & is,GIAC_CONTEXT)11346   static symbolic unarchive_SYMB(istream & is,GIAC_CONTEXT){
11347     gen e=unarchive_FUNC(is,contextptr);
11348     gen f=unarchive(is,contextptr);
11349     if (e.type==_FUNC){
11350       if (e==at_neg && f.is_symb_of_sommet(at_prod) && f._SYMBptr->feuille.type==_VECT && !f._SYMBptr->feuille._VECTptr->empty() && f._SYMBptr->feuille._VECTptr->front().type==_ZINT){
11351 	mpz_neg(*f._SYMBptr->feuille._VECTptr->front()._ZINTptr,*f._SYMBptr->feuille._VECTptr->front()._ZINTptr);
11352 	return *f._SYMBptr;
11353       }
11354       return symbolic(*e._FUNCptr,f);
11355     }
11356     return symb_of(e,f);
11357   }
11358 
unarchivedefault(istream & is,GIAC_CONTEXT)11359   static gen unarchivedefault(istream & is,GIAC_CONTEXT){
11360     string s;
11361     is >> s;
11362     return gen(s,contextptr);
11363   }
11364 
unarchivestring(istream & is,GIAC_CONTEXT)11365   static gen unarchivestring(istream & is,GIAC_CONTEXT){
11366     int l;
11367     is >> l;
11368     string s;
11369     char c;
11370     for (;;){
11371       is.get(c);
11372       if (c=='|')
11373 	break;
11374     }
11375     for (int i=0;i<l;++i){
11376       is.get(c);
11377       s +=c;
11378     }
11379     return string2gen(s,false);
11380   }
11381 
11382   /* old code: too slow for unarchive
11383      gen unarchiveidnt(istream & is,const vecteur & l,int t,GIAC_CONTEXT){
11384      char c;
11385      is >> c;
11386      string s;
11387      s +=c;
11388      for (int i=1;i<t;++i){
11389      is.get(c);
11390      s +=c;
11391      }
11392      gen res=gen(s,l,contextptr);
11393      if (res.type!=_IDNT && s[0]=='_')
11394      res=find_or_make_symbol(s,false,contextptr);
11395      if (res.type!=_IDNT){
11396      string s1 ="~"+s;
11397      res=gen(s1,l,contextptr);
11398      if (res.type!=_IDNT)
11399      res=find_or_make_symbol(s,false,contextptr);
11400      }
11401      return res;
11402      }
11403   */
11404 
unarchiveidnt(istream & is,int t,GIAC_CONTEXT)11405   static gen unarchiveidnt(istream & is,int t,GIAC_CONTEXT){
11406     char c;
11407     is >> c;
11408     string s;
11409     s +=c;
11410     for (int i=1;i<t;++i){
11411       is.get(c);
11412       s +=c;
11413     }
11414     gen res=find_or_make_symbol(s,false,contextptr); // gen(s,l,contextptr);
11415     if (res.type!=_IDNT){
11416       string s1 ="~"+s;
11417       res=find_or_make_symbol(s1,false,contextptr);
11418     }
11419     return res;
11420   }
11421 
unarchivereal(istream & is,GIAC_CONTEXT)11422   static gen unarchivereal(istream & is,GIAC_CONTEXT){
11423     unsigned int prec;
11424     is >> prec;
11425     string s;
11426     is >> s;
11427     if (!prec)
11428       return gen(s,contextptr);
11429     return read_binary(s,prec);
11430   }
11431 
unarchivezint(istream & is,GIAC_CONTEXT)11432   gen unarchivezint(istream & is,GIAC_CONTEXT){
11433     string s;
11434     is >> s;
11435     if (s.size()>2 && s[0]=='0' && s[1]=='x'){
11436       ref_mpz_t * ptr= new ref_mpz_t(s.size()*4);
11437       mpz_set_str(ptr->z,s.c_str()+2,16);
11438       gen res(ptr);
11439       return res;
11440     }
11441     return gen(s,contextptr);
11442   }
11443 
unarchive(istream & is,GIAC_CONTEXT)11444   gen unarchive(istream & is,GIAC_CONTEXT){
11445     if (is.eof())
11446       return gentypeerr(gettext("End of stream"));
11447     int type,val;
11448     double d;
11449     char ch;
11450     gen a,b;
11451     is >> type;
11452     if (is.eof())
11453       return undef;
11454     switch (type){
11455     case _INT_:
11456       is >> val >> type;
11457       a=val;
11458       a.subtype=type;
11459       return a;
11460     case _DOUBLE_:
11461       is.get(ch);
11462 #ifdef NSPIRE
11463       is.get((char *)&d,sizeof(double));
11464 #else
11465       is.read((char *)&d,sizeof(double));
11466 #endif
11467       return d;
11468     case _CPLX:
11469       a=unarchive(is,contextptr);
11470       b=unarchive(is,contextptr);
11471       return a+cst_i*b;
11472     case _REAL:
11473       a=unarchivereal(is,contextptr);
11474       return a;
11475     case _FRAC:
11476       a=unarchive(is,contextptr);
11477       b=unarchive(is,contextptr);
11478       if (is_undef(a) || is_undef(b))
11479 	return a+b;
11480       return fraction(a,b);
11481     case _VECT:
11482       is >> type;
11483       return gen(unarchive_VECT(is,contextptr),type);
11484     case _SYMB:
11485       is >> type;
11486       a=unarchive_SYMB(is,contextptr);
11487       if (!is_undef(a))
11488 	a.subtype=type;
11489       return a;
11490     case _IDNT:
11491       is >> type;
11492       return unarchiveidnt(is,type,contextptr);
11493     case _FUNC:
11494       is >> type;
11495       a=unarchive_FUNC(is,contextptr);
11496       if (a.type==_FUNC)
11497 	return gen(*a._FUNCptr,type);
11498       return a;
11499     case _STRNG:
11500       return unarchivestring(is,contextptr);
11501     case _MOD:
11502       a=unarchive(is,contextptr);
11503       b=unarchive(is,contextptr);
11504       if (is_undef(a) || is_undef(b))
11505 	return a+b;
11506       return makemodquoted(a,b);
11507     case _MAP:
11508       return unarchive_MAP(is,contextptr);
11509     case _POINTER_:
11510       is >> type;
11511       if (type==_FL_WIDGET_POINTER && fl_widget_unarchive_function)
11512 	return fl_widget_unarchive_function(is);
11513     case _ZINT:
11514       return unarchivezint(is,contextptr);
11515 #if 0 // ndef USE_GMP_REPLACEMENTS
11516     case -_ZINT:{
11517       if (ifstream * f=dynamic_cast<ifstream *>(&is)){
11518 	FILE * F=cfile(*f); // does not work
11519 	ref_mpz_t * ptr= new ref_mpz_t;
11520 	// char ch=fgetc(F);
11521 	int i=mpz_inp_raw(ptr->z,F);
11522 	gen res(ptr);
11523 	return res;
11524       }
11525     }
11526 #endif
11527     default:
11528       return unarchivedefault(is,contextptr);
11529     }
11530   }
11531 
archive_FUNC(ostream & os,const unary_function_ptr & u,GIAC_CONTEXT)11532   static ostream & archive_FUNC(ostream & os,const unary_function_ptr & u,GIAC_CONTEXT){
11533     int i=archive_function_index(u); // equalposcomp(archive_function_tab,u);
11534     if (!i && has_special_syntax(u.ptr()->s)){
11535       os << "-1 " << u.ptr()->s << " ";
11536       return os;
11537     }
11538     os << i << " ";
11539     if (!i){
11540       string s;
11541 #ifndef NO_STDEXCEPT
11542       try {
11543 #endif
11544 	if (u.ptr()->printsommet)
11545 	  s=(u.ptr()->printsommet(zero,u.ptr()->s,0));
11546 #ifndef NO_STDEXCEPT
11547       }
11548       catch (std::runtime_error & ){
11549 	last_evaled_argptr(contextptr)=NULL;
11550 	s=u.ptr()->s;
11551       }
11552 #endif
11553       int l = int(s.size());
11554       if ( (l>4) && (s.substr(l-3,3)=="(0)") )
11555 	os << s.substr(0,l-3) << " ";
11556       else
11557 	os << gen(u) << " ";
11558     }
11559     return os;
11560   }
11561 
archive_SYMB(ostream & os,const symbolic & s,GIAC_CONTEXT)11562   static ostream & archive_SYMB(ostream & os,const symbolic & s,GIAC_CONTEXT){
11563     unary_function_ptr u=s.sommet;
11564     gen f=s.feuille;
11565     archive_FUNC(os,u,contextptr);
11566     archive(os,f,contextptr);
11567     return os;
11568   }
11569 
archive_VECT(ostream & os,const vecteur & v,GIAC_CONTEXT)11570   static ostream & archive_VECT(ostream & os,const vecteur & v,GIAC_CONTEXT){
11571     const_iterateur it=v.begin(),itend=v.end();
11572     os << itend-it << " ";
11573     for (;it!=itend;++it)
11574       archive(os,*it,contextptr);
11575     return os;
11576   }
11577 
archive_MAP(ostream & os,const gen_map & v,GIAC_CONTEXT)11578   static ostream & archive_MAP(ostream & os,const gen_map & v,GIAC_CONTEXT){
11579     gen_map::const_iterator it=v.begin(),itend=v.end();
11580     int i=0;
11581     for (;it!=itend;++it)
11582       ++i;
11583     os << i << " ";
11584     for (it=v.begin();it!=itend;++it){
11585       archive(os,it->first,contextptr);
11586       os << " ";
11587       archive(os,it->second,contextptr);
11588     }
11589     return os;
11590   }
11591 
archive_IDNT(ostream & os,const identificateur & i,GIAC_CONTEXT)11592   static ostream & archive_IDNT(ostream & os,const identificateur & i,GIAC_CONTEXT){
11593     string s=i.print(contextptr);
11594     return os << s.size() << " " << s << " ";
11595   }
11596 
archive(ostream & os,const gen & e,GIAC_CONTEXT)11597   ostream & archive(ostream & os,const gen & e,GIAC_CONTEXT){
11598     unsigned et=e.type;
11599     signed es=e.subtype;
11600     switch (et){
11601     case _INT_:
11602       return os << et << " " << e.val << " " << es << '\n';
11603     case _ZINT: {
11604 #if 0 // ndef USE_GMP_REPLACEMENTS
11605       if (ofstream * f=dynamic_cast<ofstream *>(&os)){
11606 	os << -_ZINT << " ";
11607 	os.flush();
11608 	FILE * F=cfile(*f);
11609 	int i=mpz_out_raw(F,*e._ZINTptr);
11610 	fflush(F);
11611 	return os;
11612       }
11613 #endif
11614       return os << et << " " << hexa_print_ZINT(*e._ZINTptr) << '\n';
11615     }
11616     case _DOUBLE_:
11617       if (my_isinf(e._DOUBLE_val) || my_isnan(e._DOUBLE_val) )
11618 	return archive(os,gen(e.print(contextptr),contextptr),contextptr);
11619       os << et << " ";
11620 #ifdef DOUBLEVAL
11621       os.write((char *)&(e._DOUBLE_val),sizeof(double));
11622 #else
11623       os.write((char *)&e,sizeof(double));
11624 #endif
11625       return os << '\n';
11626     case _CPLX:
11627       os << et << " ";
11628       archive(os,*e._CPLXptr,contextptr);
11629       return archive(os,*(e._CPLXptr+1),contextptr);
11630     case _REAL:
11631       os << et << " ";
11632 #ifdef HAVE_LIBMPFR
11633       os << mpfr_get_prec(e._REALptr->inf) << " ";
11634       return os << print_binary(*e._REALptr) << '\n';
11635 #else
11636       os << 0 << " ";
11637       return os << e.print(contextptr) << '\n' ;
11638 #endif
11639     case _VECT:
11640       os << et << " " << es << " " ;
11641       return archive_VECT(os,*e._VECTptr,contextptr);
11642     case _SYMB:
11643       if (es==-1)
11644 	os << et << " -1 ";
11645       else
11646 	os << et << " "<< es << " ";
11647       return archive_SYMB(os,*e._SYMBptr,contextptr);
11648     case _IDNT:
11649       os << et << " ";
11650       return archive_IDNT(os,*e._IDNTptr,contextptr);
11651     case _FUNC:
11652       os << et << " " << es << " ";
11653       return archive_FUNC(os,*e._FUNCptr,contextptr);
11654     case _FRAC:
11655       os << et << " ";
11656       archive(os,e._FRACptr->num,contextptr);
11657       return archive(os,e._FRACptr->den,contextptr);
11658     case _STRNG:
11659       return os << et << " " << e._STRNGptr->size() << " |" << *e._STRNGptr << " ";
11660     case _MOD:
11661       os << et << " ";
11662       archive(os,*e._MODptr,contextptr);
11663       os << " ";
11664       archive(os,*(e._MODptr+1),contextptr);
11665       return os << " ";
11666     case _MAP:
11667       os << et << " ";
11668       archive_MAP(os,*e._MAPptr,contextptr);
11669       return os << " ";
11670     case _POINTER_:
11671       if (es==_FL_WIDGET_POINTER && fl_widget_archive_function)
11672 	return fl_widget_archive_function(os,e._POINTER_val);
11673       else
11674 	return archive(os,string2gen("Done",false),contextptr);
11675 #ifndef NO_RTTI
11676     case _USER:
11677       {
11678 	if (galois_field * gf=dynamic_cast<galois_field *>(e._USERptr)){
11679 	  return os << et << "GF(" << gf->p << "," << gf->P << "," << gf->x << "," << gf->a << ")" << '\n';
11680 	}
11681       }
11682 #endif
11683     default:
11684       return os << et << " " << e.print(contextptr) << '\n';
11685     }
11686   }
11687 
archive_session(bool save_history,ostream & os,GIAC_CONTEXT)11688   gen archive_session(bool save_history,ostream & os,GIAC_CONTEXT){
11689     os << "giac archive"<< '\n';
11690     gen g(giac_current_status(save_history,contextptr));
11691     archive(os,g,contextptr);
11692     return g;
11693   }
11694 
11695   // Archive cas, geo setup, history_in(contextptr), history_out(contextptr), all variable values
archive_session(bool save_history,const string & s,GIAC_CONTEXT)11696   gen archive_session(bool save_history,const string & s,GIAC_CONTEXT){
11697 #if defined GIAC_BINARY_ARCHIVE || defined GIAC_HAS_STO_38
11698     FILE * f =fopen(s.c_str(),"w");
11699     fprintf(f,"%s","giac binarch\n");
11700     gen g(giac_current_status(save_history,contextptr));
11701     return archive_save(f,g,contextptr)?1:0;
11702 #else
11703     ofstream os(s.c_str());
11704     return archive_session(save_history,os,contextptr);
11705 #endif
11706   }
11707 
archive_session(bool save_history,GIAC_CONTEXT)11708   std::string archive_session(bool save_history,GIAC_CONTEXT){
11709 #ifdef HAVE_SSTREAM
11710     ostringstream os;
11711     archive_session(save_history,os,contextptr);
11712     return os.str();
11713 #else
11714     return "Stringstream not available";
11715 #endif
11716   }
11717 
11718   // Unarchive a session from archive named s
11719   // Replace one level of history by replace
11720   // Return 0 if not successful, or a vector of remaining gen in the archive
unarchive_session(istream & is,int level,const gen & replace,GIAC_CONTEXT)11721   gen unarchive_session(istream & is,int level, const gen & replace,GIAC_CONTEXT){
11722 #if defined BESTA_OS || defined VISUALC
11723     ALLOCA(char, buf, BUFFER_SIZE ); //char * buf = ( char * )alloca( BUFFER_SIZE );
11724 #else
11725     char buf[BUFFER_SIZE];
11726 #endif
11727     is.getline(buf,BUFFER_SIZE,'\n');
11728     string bufs(buf);
11729     if (bufs!="giac archive")
11730       return 0;
11731     gen g=unarchive(is,contextptr);
11732     if (!is)
11733       return 0;
11734     if (!unarchive_session(g,level,replace,contextptr))
11735       return 0;
11736     vecteur res;
11737     while (!is.eof()){
11738       res.push_back(unarchive(is,contextptr));
11739     }
11740     return res;
11741   }
11742 
unarchive_session(const string & s,int level,const gen & replace,GIAC_CONTEXT)11743   gen unarchive_session(const string & s,int level, const gen & replace,GIAC_CONTEXT){
11744     ::FILE * f = fopen(s.c_str(),"r");
11745     char * buf = new char[101];
11746     fread(buf,sizeof(char),12,f);
11747     buf[12]=0;
11748     if (!strcmp(buf,"giac binarch")){
11749       fread(buf,sizeof(char),1,f); // FIXME 2 for windows?
11750       delete [] buf;
11751       gen g=archive_restore(f,contextptr);
11752       if (!unarchive_session(g,level,replace,contextptr))
11753 	return 0;
11754       vecteur res;
11755       while (!feof(f)){
11756 	res.push_back(archive_restore(f,contextptr));
11757       }
11758       return res;
11759     }
11760     fclose(f);
11761     delete [] buf;
11762 #if defined GIAC_HAS_STO_38
11763     return false;
11764 #else
11765 #if defined NSPIRE
11766     file is(s.c_str(),"r");
11767     if (!is)
11768       return false;
11769 #else
11770     ifstream is(s.c_str());
11771     if (!is)
11772       return false;
11773     return unarchive_session(is,level,replace,contextptr);
11774 #endif
11775 #endif
11776   }
11777 
unarchive_session_string(const std::string & s,int level,const gen & replace,GIAC_CONTEXT)11778   gen unarchive_session_string(const std::string & s,int level, const gen & replace,GIAC_CONTEXT){
11779 #ifdef HAVE_SSTREAM
11780     istringstream is(s);
11781     if (!is)
11782       return false;
11783     return unarchive_session(is,level,replace,contextptr);
11784 #else
11785     return gensizeerr("Stringstreams not available");
11786 #endif
11787   }
11788 
_archive(const gen & args,GIAC_CONTEXT)11789   gen _archive(const gen & args,GIAC_CONTEXT){
11790     if ( args.type==_STRNG && args.subtype==-1) return  args;
11791     gen tmp=check_secure();
11792     if (is_undef(tmp)) return tmp;
11793     if (args.type==_STRNG){ // archive session state
11794       return archive_session(true,*args._STRNGptr,contextptr);
11795     }
11796     int s;
11797     if (args.type != _VECT || (s = int(args._VECTptr->size()))<2)
11798       return gensizeerr(contextptr);
11799     gen a=args._VECTptr->front();
11800     gen b=(*args._VECTptr)[1];
11801     if (a.type!=_STRNG)
11802       return gensizeerr(contextptr);
11803     if (s==3){ // new binary archive format
11804       ::FILE * f=fopen(a._STRNGptr->c_str(),"w");
11805       if (!f)
11806 	return gensizeerr(gettext("Unable to open file ")+a.print(contextptr));
11807       fprintf(f,"%s","-1  "); // header: type would be -1
11808       if (!archive_save(f,b,contextptr))
11809 	return gensizeerr(gettext("Error writing ")+b.print(contextptr)+" in file "+a.print(contextptr));
11810       fclose(f);
11811       return b;
11812     }
11813 #if defined NSPIRE || defined GIAC_HAS_STO_38
11814     return 0;
11815 #else
11816     ofstream os(a._STRNGptr->c_str());
11817     archive(os,b,contextptr);
11818     return b;
11819 #endif
11820   }
11821   static const char _archive_s []="archive";
11822   static define_unary_function_eval (__archive,(const gen_op_context)_archive,_archive_s);
11823   define_unary_function_ptr5( at_archive ,alias_at_archive,&__archive,0,true);
11824 
_unarchive(const gen & args,GIAC_CONTEXT)11825   gen _unarchive(const gen & args,GIAC_CONTEXT){
11826     if ( args.type==_STRNG && args.subtype==-1) return  args;
11827     if (args.type!=_STRNG)
11828       return gensizeerr(contextptr);
11829     ::FILE * f = fopen(args._STRNGptr->c_str(),"r");
11830     if (!f)
11831       return gensizeerr(gettext("Unable to read file"));
11832     char * buf = new char[101];
11833     fread(buf,sizeof(char),4,f);
11834     if (buf[0]=='-' && buf[1]=='1' && buf[2]==' '){
11835       delete [] buf;
11836       gen res=archive_restore(f,contextptr);
11837       return res;
11838     }
11839     fclose(f);
11840 #if defined NSPIRE || defined GIAC_HAS_STO_38
11841     return 0;
11842 #else
11843     ifstream is(args._STRNGptr->c_str());
11844     is.getline(buf,100,'\n');
11845     bool ar = (buf==string("giac archive") || buf==string("giac binarch"));
11846     delete [] buf;
11847     is.close();
11848     if (ar)
11849       return unarchive_session(*args._STRNGptr,-1,0,contextptr);
11850     ifstream is0(args._STRNGptr->c_str());
11851     return unarchive(is0,contextptr);
11852 #endif
11853   }
11854   static const char _unarchive_s []="unarchive";
11855   static define_unary_function_eval (__unarchive,&_unarchive,_unarchive_s);
11856   define_unary_function_ptr5( at_unarchive ,alias_at_unarchive,&__unarchive,0,true);
11857 #endif // NSPIRE
11858 
geo_setup(const vecteur & w_,GIAC_CONTEXT)11859   bool geo_setup(const vecteur & w_,GIAC_CONTEXT){
11860     vecteur w(w_);
11861     for (size_t i=0;i<w.size();++i){
11862       if (w[i].type==_VECT && w[i]._VECTptr->size()==2)
11863 	w[i]=w[i]._VECTptr->back();
11864     }
11865     if (w.size()<12)
11866       return false; // setsizeerr(contextptr);
11867     if (w.size()>12) {
11868       gen g=w[12];
11869       g=_floor(g,0);
11870       if (g.type!=_INT_)
11871 	return false; // setsizeerr(contextptr);
11872       show_axes(g.val,contextptr);
11873     }
11874     if (w.size()>15) {
11875       gen g=w[15];
11876       g=_floor(g,0);
11877       if (g.type!=_INT_)
11878 	return false; // setsizeerr(contextptr);
11879 #ifdef WITH_GNUPLOT
11880       int i=g.val;
11881       gnuplot_hidden3d=(i %2)!=0;
11882       i =i/2;
11883       gnuplot_pm3d=(i%2)!=0;
11884 #endif
11885     }
11886     gen tmpw=evalf_double(w,1,contextptr);
11887     if (tmpw.type!=_VECT)
11888       return false;
11889     vecteur v=*tmpw._VECTptr;
11890     if (v.size()>14) {
11891       if (v[13].type!=_DOUBLE_ || v[14].type!=_DOUBLE_)
11892 	return false; // setsizeerr(contextptr);
11893       class_minimum=v[13]._DOUBLE_val;
11894       class_size=v[14]._DOUBLE_val;
11895     }
11896     for (int i=0;i<12;++i){
11897       if (v[i].type!=_DOUBLE_)
11898 	return false; // setsizeerr(contextptr);
11899     }
11900     gnuplot_xmin=v[0]._DOUBLE_val;
11901     gnuplot_xmax=v[1]._DOUBLE_val;
11902     gnuplot_ymin=v[2]._DOUBLE_val;
11903     gnuplot_ymax=v[3]._DOUBLE_val;
11904     gnuplot_zmin=v[4]._DOUBLE_val;
11905     gnuplot_zmax=v[5]._DOUBLE_val;
11906     gnuplot_tmin=v[6]._DOUBLE_val;
11907     gnuplot_tmax=v[7]._DOUBLE_val;
11908     global_window_xmin=v[8]._DOUBLE_val;
11909     global_window_xmax=v[9]._DOUBLE_val;
11910     global_window_ymin=v[10]._DOUBLE_val;
11911     global_window_ymax=v[11]._DOUBLE_val;
11912     return true;
11913   }
11914 
xyztrange(double xmin,double xmax,double ymin,double ymax,double zmin,double zmax,double tmin,double tmax,double wxmin,double wxmax,double wymin,double wymax,int axes,double class_min,double class_size,bool gnuplot_hidden3d,bool gnuplot_pm3d)11915   gen xyztrange(double xmin,double xmax,double ymin,double ymax,double zmin,double zmax,double tmin,double tmax,double wxmin,double wxmax,double wymin, double wymax, int axes,double class_min,double class_size,bool gnuplot_hidden3d,bool gnuplot_pm3d){
11916     vecteur v;
11917     v.push_back(xmin);
11918     v.push_back(xmax);
11919     v.push_back(ymin);
11920     v.push_back(ymax);
11921     v.push_back(zmin);
11922     v.push_back(zmax);
11923     v.push_back(tmin);
11924     v.push_back(tmax);
11925     v.push_back(wxmin);
11926     v.push_back(wxmax);
11927     v.push_back(wymin);
11928     v.push_back(wymax);
11929     v.push_back(axes);
11930     v.push_back(class_min);
11931     v.push_back(class_size);
11932     v.push_back(int(gnuplot_hidden3d+2*gnuplot_pm3d));
11933     return symbolic(at_xyztrange,v);
11934   }
_xyztrange(const gen & args,GIAC_CONTEXT)11935   gen _xyztrange(const gen & args,GIAC_CONTEXT){
11936     if (interactive_op_tab && interactive_op_tab[8])
11937       return interactive_op_tab[8](args,contextptr);
11938     if ( args.type==_STRNG && args.subtype==-1) return  args;
11939     if (args.type!=_VECT || args._VECTptr->size()<4)
11940       return makevecteur(
11941 			 makevecteur(string2gen("x-",false),gnuplot_xmin),
11942 			 makevecteur(string2gen("x+",false),gnuplot_xmax),
11943 			 makevecteur(string2gen("y-",false),gnuplot_ymin),
11944 			 makevecteur(string2gen("y+",false),gnuplot_ymax),
11945 			 makevecteur(string2gen("z-",false),gnuplot_zmin),
11946 			 makevecteur(string2gen("z+",false),gnuplot_zmax),
11947 			 makevecteur(string2gen("t-",false),gnuplot_tmin),
11948 			 makevecteur(string2gen("t+",false),gnuplot_tmax),
11949 			 makevecteur(string2gen("wx-",false),global_window_xmin),
11950 			 makevecteur(string2gen("wx+",false),global_window_xmax),
11951 			 makevecteur(string2gen("wy-",false),global_window_ymin),
11952 			 makevecteur(string2gen("wy+",false),global_window_ymax)
11953 			 ); //gensizeerr(contextptr);
11954     vecteur w=*args._VECTptr;
11955     int s = int(w.size());
11956     if (s<12){
11957       if (s<5) w.push_back(gnuplot_zmin);
11958       if (s<6) w.push_back(gnuplot_zmax);
11959       if (s<7) w.push_back(gnuplot_tmin);
11960       if (s<8) w.push_back(gnuplot_zmin);
11961       if (s<9) w.push_back(w[0]);
11962       if (s<10) w.push_back(w[1]);
11963       if (s<11) w.push_back(w[2]);
11964       if (s<12) w.push_back(w[3]);
11965     }
11966     if (!geo_setup(w,contextptr))
11967       return gensizeerr(contextptr);
11968 #ifdef HAVE_SIGNAL_H_OLD
11969     if (!child_id){
11970       _signal(symbolic(at_quote,symbolic(at_xyztrange,w)),contextptr);
11971     }
11972 #endif
11973     return args;
11974   }
11975   static const char _xyztrange_s []="xyztrange";
11976 #ifdef RTOS_THREADX
11977   static define_unary_function_eval(__xyztrange,&_xyztrange,_xyztrange_s);
11978 #else
11979   unary_function_eval __xyztrange(0,&_xyztrange,_xyztrange_s);
11980 #endif
11981   //unary_function_ptr at_xyztrange_ (&__xyztrange,0,true);
11982   //const unary_function_ptr * at_xyztrange=&at_xyztrange_;
11983   define_unary_function_ptr5( at_xyztrange ,alias_at_xyztrange,&__xyztrange,0,true);
11984 
_switch_axes(const gen & args,GIAC_CONTEXT)11985   gen _switch_axes(const gen & args,GIAC_CONTEXT){
11986     if ( args.type==_STRNG && args.subtype==-1) return  args;
11987     if (args.type==_INT_)
11988       show_axes(args.val,contextptr);
11989     else {
11990       if (show_axes(contextptr))
11991 	show_axes(0,contextptr);
11992       else
11993 	show_axes(1,contextptr);
11994     }
11995     return eval(xyztrange(gnuplot_xmin,gnuplot_xmax,gnuplot_ymin,gnuplot_ymax,gnuplot_zmin,gnuplot_zmax,gnuplot_tmin,gnuplot_tmax,global_window_xmin,global_window_xmax,global_window_ymin,global_window_ymax,show_axes(contextptr),class_minimum,class_size,
11996 #ifdef WITH_GNUPLOT
11997 			  gnuplot_hidden3d,gnuplot_pm3d
11998 #else
11999 			  1,1
12000 #endif
12001 			  ),contextptr);
12002   }
12003   static const char _switch_axes_s []="switch_axes";
12004   static define_unary_function_eval (__switch_axes,&_switch_axes,_switch_axes_s);
12005   define_unary_function_ptr5( at_switch_axes ,alias_at_switch_axes,&__switch_axes,0,true);
12006 
plotseq(const gen & f,const gen & x,double x0,double xmin,double xmax,int niter,const vecteur & attributs,const context * contextptr,bool print)12007 gen plotseq(const gen& f,const gen&x,double x0,double xmin,double xmax,int niter,const vecteur & attributs,const context * contextptr,bool print){
12008     if (xmin>xmax)
12009       swapdouble(xmin,xmax);
12010     vecteur res(2*niter+1);
12011     res[0]=gen(x0,xmin);
12012     int j=1;
12013     gen newx0;
12014     double x1;
12015     //gprintf("======== u_(n+1)=(%gen->%gen)(u_n), u0=%gen",makevecteur(x,f,x0),1,contextptr);
12016     if (print)
12017       gprintf("======== %gen=%gen), %gen=%gen",makevecteur(symb_at(u__IDNT_e,n__IDNT_e+1,contextptr),subst(f,x,symb_at(u__IDNT_e,n__IDNT_e,contextptr),false,contextptr),symb_at(u__IDNT_e,0,contextptr),x0),1,contextptr);
12018     for (int i=0;i<niter;++i){
12019       newx0=subst(f,x,x0,false,contextptr).evalf2double(eval_level(contextptr),contextptr);
12020       if (print)
12021 	gprintf("n=%gen u_n=%gen",makevecteur(i+1,newx0),1,contextptr);
12022       if (newx0.type!=_DOUBLE_)
12023 	return gensizeerr(gettext("Bad iteration"));
12024       x1=newx0._DOUBLE_val;
12025       res[j]=gen(x0,x1);
12026       ++j;
12027       x0=x1;
12028       res[j]=gen(x0,x0);
12029       ++j;
12030     }
12031     vecteur g(gen2vecteur(_plotfunc(gen(makevecteur(f,symb_equal(x,symb_interval(xmin,xmax))),_SEQ__VECT),contextptr)));
12032     g.push_back(pnt_attrib(gen(makevecteur(gen(xmin,xmin),gen(xmax,xmax)),_LINE__VECT),attributs,contextptr));
12033 #ifdef GIAC_HAS_STO_38
12034     int color=FL_BLACK;
12035 #else
12036     int color=FL_MAGENTA;
12037 #endif
12038     if (!attributs.empty())
12039       color = color | (attributs[0].val & 0xffff0000);
12040     g.push_back(symb_pnt(gen(res,_LINE__VECT),color,contextptr));
12041     g.push_back(symb_pnt(gen(makevecteur(gen(x0,x0),gen(x0,xmin)),_VECTOR__VECT), color | _DASH_LINE,contextptr));
12042     return g; // gen(g,_SEQ__VECT);
12043   }
find_plotseq_args(const gen & args,gen & expr,gen & x,double & x0d,double & xmin,double & xmax,int & niter,vecteur & attributs,GIAC_CONTEXT,bool & print)12044 int find_plotseq_args(const gen & args,gen & expr,gen & x,double & x0d,double & xmin,double & xmax,int & niter,vecteur & attributs,GIAC_CONTEXT,bool & print){
12045     vecteur v=gen2vecteur(args);
12046     print=true;
12047     if (v.back()==at_tableseq){
12048       print=false;
12049       v.pop_back();
12050     }
12051     attributs=vecteur(1,default_color(contextptr));
12052     int l=read_attributs(v,attributs,contextptr);
12053     if (l<2)
12054       v.push_back(0);
12055     expr=v[0];
12056     niter=30;
12057     gen x0;
12058     if (l>3){ // expr,var,x0,niter
12059       x=v[1];
12060       x0=v[2];
12061       if (v[3].type==_INT_)
12062 	niter=absint(v[3].val);
12063       else
12064 	return -2; // bad iteration
12065     }
12066     else {
12067       if (l>2){
12068 	if (v[2].type==_INT_)
12069 	  niter=absint(v[2].val);
12070 	else
12071 	  return -2;
12072       }
12073       if ( (v[1].type==_SYMB) && (v[1]._SYMBptr->sommet==at_equal) ){
12074 	vecteur & w=*v[1]._SYMBptr->feuille._VECTptr;
12075 	x=w[0];
12076 	x0=w[1];
12077       }
12078       else {
12079 	x=vx_var;
12080 	x0=v[1];
12081       }
12082     }
12083     x0=evalf_double(x0,eval_level(contextptr),contextptr);
12084     xmin=gnuplot_xmin;xmax=gnuplot_xmax;
12085     if (x0.type==_VECT && x0._VECTptr->size()==3){
12086       vecteur & x0v=*x0._VECTptr;
12087       if (x0v[1].type!=_DOUBLE_ || x0v[2].type!=_DOUBLE_)
12088 	return -3; // gensizeerr(gettext("Non numeric range value"));
12089       xmin=x0v[1]._DOUBLE_val;
12090       xmax=x0v[2]._DOUBLE_val;
12091       x0=remove_at_pnt(x0v[0]);
12092       x0=re(x0,contextptr);
12093     }
12094     if (x0.type!=_DOUBLE_)
12095       return -4; //
12096     x0d=x0._DOUBLE_val;
12097     return 0;
12098   }
12099 
12100   // args=[expr,[var=]x0|[x0,xmin,xmax][,niter]]
_plotseq(const gen & args,const context * contextptr)12101   gen _plotseq(const gen & args,const context * contextptr){
12102     if ( args.type==_STRNG && args.subtype==-1) return  args;
12103     gen expr,var;
12104     double x0d,xmin,xmax;
12105     int niter;
12106     vecteur attributs;
12107     bool print;
12108     if (find_plotseq_args(args,expr,var,x0d,xmin,xmax,niter,attributs,contextptr,print)<0)
12109       return gentypeerr(contextptr);
12110     return plotseq(expr,var,x0d,xmin,xmax,niter,attributs,contextptr,print);
12111   }
12112   static const char _plotseq_s []="plotseq";
12113   static define_unary_function_eval (__plotseq,&_plotseq,_plotseq_s);
12114   define_unary_function_ptr5( at_plotseq ,alias_at_plotseq,&__plotseq,0,true);
12115 
12116   static const char _graphe_suite_s []="graphe_suite";
12117   static define_unary_function_eval (__graphe_suite,&_plotseq,_graphe_suite_s);
12118   define_unary_function_ptr5( at_graphe_suite ,alias_at_graphe_suite,&__graphe_suite,0,true);
12119 
12120   static const char _seqplot_s []="seqplot";
12121   static define_unary_function_eval (__seqplot,&_plotseq,_seqplot_s);
12122   define_unary_function_ptr5( at_seqplot ,alias_at_seqplot,&__seqplot,0,true);
12123 
l2norm(double x,double y)12124   static double l2norm(double x,double y){
12125     return std::sqrt(x*x+y*y);
12126   }
12127 
get_sol(gen & sol,GIAC_CONTEXT)12128   static bool get_sol(gen & sol,GIAC_CONTEXT){
12129     if (is_undef(sol))
12130       return false;
12131     if (sol.type==_VECT && sol._VECTptr->size()==2)
12132       sol=(sol[0]+sol[1])/2;
12133     if (sol.type==_VECT && sol._VECTptr->size()==1)
12134       sol=sol[0];
12135     sol=evalf_double(sol,1,contextptr);
12136     return sol.type==_DOUBLE_;
12137   }
12138 
12139   // FIXME: this function is using absolute constants 0.1 and 0.2 for checking singular points, they should use better estimates depending on f_orig (search for dfxyabs2)
in_plotimplicit(const gen & f_orig,const gen & x,const gen & y,double xmin,double xmax,double ymin,double ymax,int nxstep,int nystep,double eps,const vecteur & attributs,int ckgeo2d,const context * contextptr)12140   static gen in_plotimplicit(const gen& f_orig,const gen&x,const gen & y,double xmin,double xmax,double ymin,double ymax,int nxstep,int nystep,double eps,const vecteur & attributs,int ckgeo2d,const context * contextptr){
12141 #ifdef RTOS_THREADX
12142     return undef;
12143 #else
12144     if (f_orig.type==_VECT){
12145       vecteur & v = *f_orig._VECTptr,w;
12146       int vs = int(v.size());
12147       for (int i=0;i<vs;++i){
12148 	w.push_back(in_plotimplicit(v[i],x,y,xmin,xmax,ymin,ymax,nxstep,nystep,eps,attributs,ckgeo2d,contextptr));
12149       }
12150       return gen(w,_SEQ__VECT);
12151     }
12152     if (f_orig.is_symb_of_sommet(at_inv) || (is_zero(derive(f_orig,x,contextptr),contextptr) && is_zero(derive(f_orig,y,contextptr),contextptr)) )
12153       return vecteur(0); // gen(vecteur(0),_SEQ__VECT);
12154     if (f_orig.is_symb_of_sommet(at_prod) && f_orig._SYMBptr->feuille.type==_VECT){
12155       vecteur res;
12156       vecteur & fv = *f_orig._SYMBptr->feuille._VECTptr;
12157       int s = int(fv.size());
12158       for (int i=0;i<s;++i){
12159 	gen tmp=in_plotimplicit(fv[i],x,y,xmin,xmax,ymin,ymax,nxstep,nystep,eps,attributs,ckgeo2d,contextptr);
12160 	if (!is_undef(tmp))
12161 	  res=mergevecteur(res,gen2vecteur(tmp));
12162 	else
12163 	  *logptr(contextptr) << tmp << '\n';
12164       }
12165       return res; // gen(res,_SEQ__VECT);
12166     }
12167     if (f_orig.is_symb_of_sommet(at_pow)){
12168       gen farg=f_orig._SYMBptr->feuille;
12169       if (farg.type==_VECT && farg._VECTptr->size()==2){
12170 	gen arg=farg._VECTptr->front();
12171 	gen expo=farg._VECTptr->back();
12172 	if (ck_is_positive(expo,contextptr))
12173 	  return in_plotimplicit(arg,x,y,xmin,xmax,ymin,ymax,nxstep,nystep,eps,attributs,ckgeo2d,contextptr);
12174 	else
12175 	  return vecteur(0); // gen(vecteur(0),_SEQ__VECT);
12176       }
12177     }
12178     gen attribut=attributs.empty()?default_color(contextptr):attributs[0];
12179     gen lieu_geo;
12180     if (ckgeo2d && equation2geo2d(f_orig,x,y,lieu_geo,gnuplot_tmin,gnuplot_tmax,gnuplot_tstep,undef,ckgeo2d,contextptr)){
12181       if (lieu_geo.type==_VECT && lieu_geo._VECTptr->empty())
12182 	return gensizeerr("Unable to parametrize geometric object, perhaps depending on a parameter");
12183       return put_attributs(lieu_geo,attributs,contextptr);
12184     }
12185     // make a lattice between gnuplot_xmin/gnuplot_xmax and ymin/ymax
12186     // find zeros of f inside each square and follow the branches
12187     //bool is_regular=lop(f_orig,at_abs).empty() && lop(f_orig,at_sign).empty();
12188 #ifndef WIN32
12189     bool old_iograph=io_graph(contextptr);
12190     if (thread_eval_status(contextptr)!=1)
12191       io_graph(false,contextptr);
12192 #endif
12193 #ifdef HAVE_LIBGSL //
12194     gsl_set_error_handler_off();
12195 #endif //
12196     if (!nystep){
12197       nxstep=int(std::sqrt(double(absdouble(nxstep))));
12198       nystep=nxstep;
12199     }
12200     if (ulonglong(nxstep)*nystep>100*100){
12201       nxstep=100;
12202       nystep=100;
12203     }
12204     double xstep=(xmax-xmin)/nxstep;
12205     double ystep=(ymax-ymin)/nystep;
12206     identificateur xloc(" xloc"),yloc(" yloc");
12207     vecteur xy(makevecteur(x,y)),locvar(makevecteur(xloc,yloc));
12208     gen f=quotesubst(f_orig,xy,locvar,contextptr).evalf(1,contextptr);
12209     gen dfx=derive(f_orig,x,contextptr),dfy=derive(f_orig,y,contextptr);
12210     if (is_undef(dfx) || is_undef(dfy))
12211       return dfx+dfy;
12212     vecteur localvar(makevecteur(xloc,yloc));
12213     context * newcontextptr=(context *) contextptr;
12214     int protect=giac_bind(makevecteur(xmin,ymin),localvar,newcontextptr);
12215     vector< vector<bool> > visited(nxstep+2,vector<bool>(nystep+2));
12216     // vector< vector<bool> > visited(nxstep+2,vector<bool>(nystep+2) );
12217     vector< vector<double> >
12218       fxy(nxstep+1,vector<double>(nystep+1)),
12219       dfxorig(nxstep+1,vector<double>(nystep+1)),
12220       dfyorig(nxstep+1,vector<double>(nystep+1)),
12221       dfxyorig_abs(nxstep+1,vector<double>(nystep+1));
12222     vector< vector<double> > xorig(nxstep+1,vector<double>(nystep+1)),yorig(nxstep+1,vector<double>(nystep+1));
12223     gen gtmp;
12224     // initialize each cell to non visited
12225     local_sto_double(ymin,yloc,newcontextptr);
12226     // yloc.localvalue->back()._DOUBLE_val = ymin ;
12227     for (int i=0;i<=nxstep+1;++i){
12228       for (int j=0;j<=nystep+1;++j)
12229 	visited[i][j]=false;
12230     }
12231     vecteur singular_points,singular_points_tangents,singular_points_directions;
12232     for (int i=0;i<=nxstep;++i){
12233       local_sto_double(ymin,yloc,newcontextptr);
12234       // yloc.localvalue->back()._DOUBLE_val = ymin;
12235       for (int j=0;j<=nystep;++j){
12236 	gtmp=f.evalf2double(eval_level(contextptr),newcontextptr);
12237 	if (gtmp.type==_DOUBLE_)
12238 	  fxy[i][j]=gtmp._DOUBLE_val==0?1e-200:gtmp._DOUBLE_val;
12239 	else
12240 	  fxy[i][j]=0;
12241 	local_sto_double_increment(ystep,yloc,newcontextptr);
12242 	// yloc.localvalue->back()._DOUBLE_val += ystep;
12243       }
12244       local_sto_double_increment(xstep,xloc,newcontextptr);
12245       // xloc.localvalue->back()._DOUBLE_val += xstep;
12246     }
12247     leave(protect,localvar,newcontextptr);
12248     double xx=xmin,yy=ymin,tmp,xcurrent,ycurrent;
12249     vecteur xy1(xy);
12250     lvar(f_orig,xy1); // check for an algebraic curve
12251     if (xy1==xy){
12252       // Polynomial singular points: solve([f_orig,dfx,dfy],xy)
12253       singular_points=gsolve(*exact(makevecteur(f_orig,dfx,dfy),contextptr)._VECTptr,xy,false,(approx_mode(contextptr)?1:0),contextptr);
12254       for (int k=0;k<int(singular_points.size());k++){
12255 	gen sp=singular_points[k];
12256 	gen spd=evalf_double(sp,1,contextptr);
12257 	if (sp.type!=_VECT || sp._VECTptr->size()!=2 || spd[0].type!=_DOUBLE_ || spd[1].type!=_DOUBLE_ )
12258 	  continue;
12259 	int i=int((spd[0]._DOUBLE_val-xmin)/xstep);
12260 	int j=int((spd[1]._DOUBLE_val-xmin)/xstep);
12261 	if (i>=nxstep || j>=nystep)
12262 	  continue;
12263 	for (int ii=i-1;ii<i+1;++ii){
12264 	  for (int jj=j-1;jj<j+1;++jj){
12265 	    if ( ii>=0 && ii<nxstep && jj>=0 && jj<nystep )
12266 	      visited[ii][jj]=true;
12267 	  }
12268 	}
12269 	// FIXME series does not work correctly
12270 	// example eq:=25*x^6*y^2-80*x^6*y+64*x^6-10*x^5*y^2+136*x^5*y-192*x^5+59*x^4*y^2+56*x^4*y+192*x^4-20*x^3*y^2-240*x^3*y-64*x^3+43*x^2*y^2+104*x^2*y-10*x*y^2+9*y^2; implicitplot(eq,x=0..2,y=-1..1,ystep=0.01);
12271 	if (has_op(sp,*at_rootof)) sp=spd;
12272 	// find all tangents starting from sp
12273 	for (int order=2;order<10;++order){
12274 	  gen tays=series(subst(f_orig,xy,xy+sp,false,contextptr),xy,makevecteur(0,0),order,0,contextptr);
12275 	  if (!is_zero(tays,contextptr)){
12276 	    singular_points_tangents.clear();
12277 	    // non-zero homogeneous expansion
12278 	    // find roots of taylor expansion
12279 	    gen t(identificateur(" implicitplot"));
12280 	    tays=subst(tays,xy,makevecteur(1,t),false,contextptr);
12281 	    // search for a multiple root, if last_direction is near a multiple root
12282 	    // of even multiplicity change last_direction sign
12283 	    gen sqfftays=_quo(gen(makevecteur(tays,_gcd(gen(makevecteur(tays,derive(tays,t,contextptr)),_SEQ__VECT),contextptr),t),_SEQ__VECT),contextptr);
12284 	    gen r=_proot(gen(makevecteur(sqfftays,t),_SEQ__VECT),contextptr);
12285 #ifndef GIAC_HAS_STO_38
12286 	    *logptr(contextptr) << gettext("Near ") << sp << ", 1/epsilon^2*f(" << sp<< "+epsilon*[1,t])=" << subst(tays,t,t__IDNT_e,false,contextptr) << " roots " << r << '\n';
12287 #endif
12288 	    if (r.type==_VECT){
12289 	      int total=0;
12290 	      for (unsigned kr=0;kr<r._VECTptr->size();++kr){
12291 		// find multiplicity
12292 		int mult=0;
12293 		gen quo,tmp=tays;
12294 		for (++total;;++mult,++total){
12295 		  quo=_quorem(gen(makevecteur(tmp,t-r[kr],t),_SEQ__VECT),contextptr);
12296 		  if (quo.type!=_VECT || quo._VECTptr->size()!=2 || !is_zero(quo._VECTptr->back(),contextptr))
12297 		    break;
12298 		  tmp=quo._VECTptr->front();
12299 		}
12300 		if (!is_zero(im(r[kr],contextptr),contextptr))
12301 		  continue;
12302 		// add 2 half-tangents with slope r[kr]
12303 		singular_points_tangents.push_back(makevecteur(i,j,spd,1,r[kr],mult));
12304 		singular_points_tangents.push_back(makevecteur(i,j,spd,-1,-r[kr],mult));
12305 	      } // end for kr
12306 	      // add vertical half-tangents if any
12307 	      if (total<order){
12308 		singular_points_tangents.push_back(makevecteur(i,j,spd,0,1,order-total));
12309 		singular_points_tangents.push_back(makevecteur(i,j,spd,0,-1,order-total));
12310 	      }
12311 	    } // end if (r.type==_VECT)
12312 	    // dirc contains affixes of directions
12313 	    vecteur dirc;
12314 	    for (unsigned k=0;k<singular_points_tangents.size();++k){
12315 	      gen tmp=singular_points_tangents[k];
12316 	      if (tmp.type==_VECT && tmp._VECTptr->size()>=6){
12317 		tmp=tmp[3]+cst_i*tmp[4];
12318 		dirc.push_back(tmp);
12319 	      }
12320 	    }
12321 	    for (int sing=0;sing<int(singular_points_tangents.size());++sing){
12322 	      // replace tangents by directions
12323 	      gen tmp=singular_points_tangents[sing];
12324 	      if (tmp.type==_VECT && tmp._VECTptr->size()>=6){
12325 		gen sp=(*tmp._VECTptr)[2];
12326 		gen lastsing=gen(sp[0],sp[1]);
12327 		double xcurrent=evalf_double(sp[0]+xstep/3*(*tmp._VECTptr)[3],1,contextptr)._DOUBLE_val;
12328 		double ycurrent=evalf_double(sp[1]+xstep/3*(*tmp._VECTptr)[4],1,contextptr)._DOUBLE_val;
12329 		// find solutions near half tangent (no more than mult)
12330 		if (is_greater(abs(tmp[4],contextptr),abs(tmp[3],contextptr),contextptr)){
12331 		  // search x
12332 		  gen fx=subst(f_orig,y,ycurrent,false,contextptr);
12333 		  int iszero=-1;
12334 		  vecteur v=bisection_solver(fx,x,xcurrent-xstep,xcurrent+xstep,iszero,contextptr);
12335 		  for (unsigned vi=0;vi<v.size();++vi){
12336 		    gen sol=v[vi];
12337 		    if (sol.type!=_DOUBLE_)
12338 		      continue;
12339 		    xcurrent=sol._DOUBLE_val;
12340 		    sol=gen(xcurrent,ycurrent);
12341 		    // check that sol-lastsing is in the same direction as tmp[3],tmp[4]
12342 		    gen curdir=(sol-lastsing),tmpdir=tmp[3]+cst_i*tmp[4];
12343 		    gen tst=abs(arg(curdir/tmpdir,contextptr),contextptr);
12344 		    unsigned dir_i=0;
12345 		    for (;dir_i<dirc.size();++dir_i){
12346 		      // if (diri==sing) continue;
12347 		      // if arg of quotient is larger in abs value than a quotient
12348 		      // with another direction, then this direction is invalid
12349 		      gen tst_i=abs(arg(curdir/dirc[dir_i],contextptr),contextptr);
12350 		      if (is_strictly_greater(tst,tst_i,contextptr))
12351 			break;
12352 		    }
12353 		    if (dir_i==dirc.size()){
12354 		      singular_points_directions.push_back(makevecteur(i,j,lastsing,sol));
12355 		    }
12356 		  }
12357 		}
12358 		else { // search y
12359 		  gen fy=subst(f_orig,x,xcurrent,false,contextptr);
12360 		  int iszero=-1;
12361 		  vecteur v=bisection_solver(fy,y,ycurrent-ystep,ycurrent+ystep,iszero,contextptr);
12362 		  for (unsigned vi=0;vi<v.size();++vi){
12363 		    gen sol=v[vi];
12364 		    if (sol.type!=_DOUBLE_)
12365 		      continue;
12366 		    ycurrent=sol._DOUBLE_val;
12367 		    sol=gen(xcurrent,ycurrent);
12368 		    // check that sol-lastsing is in the same direction as tmp[3],tmp[4]
12369 		    gen curdir=(sol-lastsing),tmpdir=tmp[3]+cst_i*tmp[4];
12370 		    gen tst=abs(arg(curdir/tmpdir,contextptr),contextptr);
12371 		    unsigned dir_i=0;
12372 		    for (;dir_i<dirc.size();++dir_i){
12373 		      // if (diri==sing) continue;
12374 		      // if arg of quotient is larger in abs value than a quotient
12375 		      // with another direction, then this direction is invalid
12376 		      gen tst_i=abs(arg(curdir/dirc[dir_i],contextptr),contextptr);
12377 		      if (is_strictly_greater(tst,tst_i,contextptr))
12378 			break;
12379 		    }
12380 		    if (dir_i==dirc.size()){
12381 		      singular_points_directions.push_back(makevecteur(i,j,lastsing,sol));
12382 		    }
12383 		  }
12384 		}
12385 	      }
12386 	    }
12387 	    break; // end the for loop on order
12388 	  } // end if !is_zero(tays,contextptr)
12389 	} // end loop on order
12390       } // end if k<singular_points.size()
12391 #ifndef GIAC_HAS_STO_38
12392       if (!singular_points.empty())
12393 	*logptr(contextptr) << gettext("Singular points directions: [cell_i, cell_j, singularity, next solution] ") << singular_points_directions << '\n';
12394 #endif
12395     }
12396     bool pathfound;
12397     vecteur res;
12398     int i=-1,j=nystep,sing=0;
12399     gen lastsing;
12400     bool was_not_singular;
12401     for (;;){
12402       pathfound=false;
12403       vecteur chemin;
12404       int iorig,jorig;
12405       bool chemin_ok=true;
12406       bool orig_sing=sing<int(singular_points_directions.size());
12407       gen lastsingdir;
12408       // First paths from singular points
12409       if (orig_sing){
12410 	was_not_singular=false;
12411 	gen tmp=singular_points_directions[sing];
12412 	++sing;
12413 	lastsing=tmp[2];
12414 	chemin.push_back(lastsing);
12415 	xcurrent=evalf_double(re(tmp[3],contextptr),1,contextptr)._DOUBLE_val;
12416 	ycurrent=evalf_double(im(tmp[3],contextptr),1,contextptr)._DOUBLE_val;
12417 	lastsingdir=xcurrent+cst_i*gen(ycurrent);
12418 	// set iorig,jorig
12419 	iorig=int((xcurrent-xmin)/xstep); // FIXME? +.5
12420 	jorig=int((ycurrent-ymin)/ystep); //
12421 	if (xcurrent>=xmin && ycurrent>=ymin && xcurrent<=xmax && ycurrent<=ymax)
12422 	  pathfound=true;
12423       }
12424       else {
12425 	was_not_singular=true;
12426 	lastsingdir=undef;
12427       }
12428       if (!pathfound){
12429 	++j;
12430 	if (j>nystep){
12431 	  j=0;
12432 	  ++i;
12433 	  if (i>nxstep)
12434 	    break;
12435 	  if (debug_infolevel)
12436 	    COUT << "// Implicitplot row " << i << '\n';
12437 	}
12438 	xx=xmin+i*xstep;
12439 	yy=ymin+j*ystep;
12440 	// If cell has been visited -> done
12441 	if ( visited[i][j] || (
12442 			       ( (j && visited[i][j-1]) || visited[i][j+1]) &&
12443 			       ( visited[i+1][j] || (i && visited[i-1][j]))
12444 				) )
12445 	  continue;
12446 	// now look for annulation from below or left
12447 	tmp=j?fxy[i][j-1]*fxy[i][j]:1;
12448 	if (tmp<0) {
12449 	  pathfound=true;
12450 	  // find an horizontal solution
12451 	  xcurrent=xx;
12452 	  ycurrent=yy;
12453 	  gen fy=subst(f_orig,x,xcurrent,false,contextptr);
12454 	  gen sol=_fsolve(gen(makevecteur(fy,y,makevecteur(ycurrent-ystep,ycurrent),_BISECTION_SOLVER,100*eps),_SEQ__VECT),contextptr);
12455 	  if (!get_sol(sol,contextptr))
12456 	    pathfound=false;
12457 	  else
12458 	    ycurrent=sol._DOUBLE_val;
12459 	}
12460 	else {
12461 	  tmp=i?fxy[i-1][j]*fxy[i][j]:1;
12462 	  if (tmp<0) {
12463 	    pathfound=true;
12464 	    // find a vertical solution
12465 	    xcurrent=xx;
12466 	    ycurrent=yy;
12467 	    gen fx=subst(f_orig,y,ycurrent,false,contextptr);
12468 	    gen sol=_fsolve(gen(makevecteur(fx,x,makevecteur(xcurrent-xstep,xcurrent),_BISECTION_SOLVER,100*eps),_SEQ__VECT),contextptr);
12469 	    if (!get_sol(sol,contextptr))
12470 	      pathfound=false;
12471 	    else
12472 	      xcurrent=sol._DOUBLE_val;
12473 	  }
12474 	}
12475 	if (!pathfound)
12476 	  continue;
12477 	// Annulation found, let's add a path
12478 	jorig=int((ycurrent-ymin)/ystep);
12479 	iorig=int((xcurrent-xmin)/xstep);
12480 	if (xcurrent<xmin || ycurrent<ymin || xcurrent>xmax || ycurrent>ymax)
12481 	  continue;
12482 	if (visited[iorig][jorig] || (
12483 				      ( (jorig?visited[iorig][jorig-1]:false) || visited[iorig][jorig+1])  &&
12484 				      ( (iorig?visited[iorig-1][jorig]:false) ||visited[iorig+1][jorig] )
12485 				      )
12486 	    )
12487 	  continue;
12488       } // end if (!pathfound)
12489       chemin.push_back(gen(xcurrent,ycurrent));
12490       visited[iorig][jorig]=true;
12491       int icur,jcur,oldi=iorig,oldj=jorig;
12492       xorig[iorig][jorig]=xcurrent;
12493       yorig[iorig][jorig]=ycurrent;
12494       gtmp=subst(dfx,xy,makevecteur(xcurrent,ycurrent),false,contextptr).evalf2double(eval_level(contextptr),contextptr);
12495       if (gtmp.type==_DOUBLE_)
12496 	dfxorig[iorig][jorig]=gtmp._DOUBLE_val;
12497       else
12498 	dfxorig[iorig][jorig]=oldi?(fxy[oldi][oldj]-fxy[oldi-1][oldj])/xstep:(fxy[oldi+1][oldj]-fxy[oldi][oldj])/xstep;
12499       gtmp=subst(dfy,xy,makevecteur(xcurrent,ycurrent),false,contextptr).evalf2double(eval_level(contextptr),contextptr);
12500       if (gtmp.type==_DOUBLE_)
12501 	dfyorig[iorig][jorig]=gtmp._DOUBLE_val;
12502       else
12503 	dfyorig[iorig][jorig]=oldj?(fxy[oldi][oldj]-fxy[oldi][oldj-1])/ystep:(fxy[oldi][oldj+1]-fxy[oldi][oldj])/ystep;
12504       dfxyorig_abs[iorig][jorig]=l2norm(dfxorig[iorig][jorig],dfyorig[iorig][jorig]);
12505       int sign=1; // + for increasing y, - for decreasing y
12506       if (chemin.size()==2){
12507 	gen tmp=chemin[1]-chemin[0],direction(dfyorig[iorig][jorig],-dfxorig[iorig][jorig]);
12508 	if (is_greater(abs(arg(tmp/direction,contextptr),contextptr),cst_pi_over_2,contextptr))
12509 	  sign=-1;
12510       }
12511       else {
12512 	if ( (dfyorig[iorig][jorig]<-100*eps*dfxyorig_abs[iorig][jorig]) ||
12513 	     ((dfyorig[iorig][jorig]<100*eps*dfxyorig_abs[iorig][jorig])&&
12514 	      (dfxorig[iorig][jorig]>0)) )
12515 	  sign=-1;
12516       }
12517       gen last_direction=0;
12518       bool change_sign=false;
12519       for (int count=0;count<nxstep*nystep;){
12520 	vecteur xycurrent(makevecteur(xcurrent,ycurrent));
12521 	double dfxcurrent,dfycurrent;
12522 	gtmp=subst(dfx,xy,xycurrent,false,contextptr).evalf2double(eval_level(contextptr),contextptr);
12523 	//bool use_newton=is_regular;
12524 	bool use_newton=false; // FIXME?? Newton does not seem to work
12525 	if (gtmp.type==_DOUBLE_)
12526 	  dfxcurrent=gtmp._DOUBLE_val;
12527 	else {
12528 	  use_newton=false;
12529 	  dfxcurrent=oldi?(fxy[oldi][oldj]-fxy[oldi-1][oldj])/xstep:(fxy[oldi+1][oldj]-fxy[oldi][oldj])/xstep;
12530 	}
12531 	gtmp=subst(dfy,xy,xycurrent,false,contextptr).evalf2double(eval_level(contextptr),contextptr);
12532 	if (gtmp.type==_DOUBLE_)
12533 	  dfycurrent=gtmp._DOUBLE_val;
12534 	else {
12535 	  dfycurrent=oldj?(fxy[oldi][oldj]-fxy[oldi][oldj-1])/ystep:(fxy[oldi][oldj+1]-fxy[oldi][oldj])/ystep;
12536 	  use_newton=false;
12537 	}
12538 	if (sign==-1){
12539 	  dfxcurrent=-dfxcurrent;
12540 	  dfycurrent=-dfycurrent;
12541 	}
12542 	// (dfxcurrent,dfycurrent) is normal to the path
12543 	// If it's near 0 we are near a singular point,
12544 	// that we try to cross by using the same direction
12545 	// Otherwise go to the next cell, and end if at original i,j
12546 	// or at the border
12547 	gen direction(dfycurrent,-dfxcurrent);
12548 	double dfxycurrent_abs=l2norm(dfxcurrent,dfycurrent);
12549 	// Improve eval of derivative at target point
12550 	double dfxyabs2=dfxycurrent_abs;
12551 	gen newxy=undef;
12552 	if (was_not_singular){
12553 	  double pascoeff=std::min(xstep,ystep)/std::sqrt(dfycurrent*dfycurrent+dfxcurrent*dfxcurrent);
12554 	  gen pas=gen(pascoeff)*makevecteur(dfycurrent,-dfxcurrent);
12555 	  newxy=xycurrent+pas;
12556 	  gtmp=subst(dfx,xy,newxy,false,contextptr).evalf2double(eval_level(contextptr),contextptr);
12557 	  if (gtmp.type==_DOUBLE_){
12558 	    double d1=gtmp._DOUBLE_val;
12559 	    gtmp=subst(dfy,xy,newxy,false,contextptr).evalf2double(eval_level(contextptr),contextptr);
12560 	    if (gtmp.type==_DOUBLE_){
12561 	      dfxyabs2=std::sqrt(gtmp._DOUBLE_val*gtmp._DOUBLE_val+d1*d1);
12562 	    }
12563 	  }
12564 	}
12565 	if (was_not_singular && dfxyabs2<0.1 && !is_zero(last_direction,contextptr)){
12566 	  // perhaps near a singular point
12567 	  // compare precedent direction with singular_points_directions
12568 	  gen sp=undef;
12569 	  int k=0;
12570 	  for (;k<int(singular_points.size());k++){
12571 	    sp=singular_points[k];
12572 	    if (sp.type==_VECT && sp._VECTptr->size()==2 && is_greater(2*xstep,abs(sp[0]-newxy[0],contextptr),contextptr) && is_greater(2*ystep,abs(sp[1]-newxy[1],contextptr),contextptr))
12573 	      break;
12574 	  }
12575 	  if (k<int(singular_points.size())){
12576 	    chemin.push_back(evalf_double(sp[0]+cst_i*sp[1],1,contextptr));
12577 	    int pos=-1;
12578 	    gen theta=7;
12579 	    // remove incoming direction from singular_points_direction
12580 	    for (k=0;k<int(singular_points_directions.size());++k){
12581 	      gen tmp=singular_points_directions[k];
12582 	      if (chemin.back()-tmp[2]!=0)
12583 		continue;
12584 	      // compare directions
12585 	      gen cur=abs(arg((tmp[2]-tmp[3])/last_direction,contextptr),contextptr);
12586 	      if (is_greater(theta,cur,contextptr)){
12587 		pos=k;
12588 		theta=cur;
12589 	      }
12590 	    }
12591 	    if (pos>=sing)
12592 	      singular_points_directions.erase(singular_points_directions.begin()+pos);
12593 	    else {
12594 #ifndef GIAC_HAS_STO_38
12595 	      *logptr(contextptr) << gettext("Bad branch, questionnable accuracy") << '\n';
12596 #endif
12597 	    }
12598 	    break; // singular points were already done
12599 	  }
12600 	  else {
12601 	    // FIXME: find a numerical singular point near this point
12602 	    // Find all branches by solving the equation on a circle of small radius
12603 	    // centerd at the numerical singular point
12604 	    // Add them to singular_points_directions
12605 	  }
12606 	  // otherwise continue in the same direction
12607 	  direction=last_direction;
12608 	  change_sign=true;
12609 	}
12610 	else {
12611 	  if (dfxyabs2>=0.2)
12612 	    was_not_singular=true;
12613 	  if (change_sign){
12614 	    sign=-sign;
12615 	    direction=-direction;
12616 	    change_sign=false;
12617 	  }
12618 	  direction=direction/dfxycurrent_abs;
12619 	  last_direction=direction;
12620 	}
12621 	double deltax=evalf_double(re(direction,contextptr),eval_level(contextptr),contextptr)._DOUBLE_val,deltay=evalf_double(im(direction,contextptr),eval_level(contextptr),contextptr)._DOUBLE_val;
12622 	double thestep=ystep/2;
12623 	if (xstep<ystep)
12624 	  thestep=xstep/2;
12625 	xcurrent += thestep*deltax;
12626 	ycurrent += thestep*deltay;
12627 	gen sol,fy,fx;
12628 	// Test for mostly horizontal tangeant
12629 	if (fabs(deltay)<fabs(deltax)) {
12630 	  fy=subst(f_orig,x,xcurrent,false,contextptr);
12631 #if 0
12632 	  int iszero=-1;
12633 	  vecteur sol1=bisection_solver(fy,y,ycurrent-ystep,ycurrent+ystep,iszero,contextptr);
12634 	  if (!sol1.empty()){
12635 	    if (deltay<0){ // reorder sol1 if we have more than 1 sol (almost horizontal)
12636 	      reverse(sol1.begin(),sol1.end());
12637 	      for (unsigned k=0;k<sol1.size();--k){
12638 		if (sol1[k].type==_DOUBLE_)
12639 		  chemin.push_back(xcurrent+cst_i*sol1[k]);
12640 	      }
12641 	    }
12642 	    sol=sol1.back();
12643 	  }
12644 	  else
12645 	    sol=undef;
12646 #else
12647 	  if (is_positive(subst(fy,y,ycurrent-ystep,false,contextptr)*subst(fy,y,ycurrent+ystep,false,contextptr),contextptr) || use_newton){
12648 	    sol=_fsolve(gen(makevecteur(fy,y,ycurrent,_NEWTON_SOLVER),_SEQ__VECT),contextptr);
12649 	  }
12650 	  else {
12651 	    sol=_fsolve(gen(makevecteur(fy,y,makevecteur(ycurrent-ystep,ycurrent+ystep),_BISECTION_SOLVER,100*eps),_SEQ__VECT),contextptr);
12652 	    get_sol(sol,contextptr);
12653 	  }
12654 #endif
12655 	  if (sol.type==_DOUBLE_){
12656 	    if (fabs(ycurrent-sol._DOUBLE_val)>2*ystep){
12657 	      chemin_ok=false;
12658 	      break;
12659 	    }
12660 	    else
12661 	      ycurrent=sol._DOUBLE_val;
12662 	  }
12663 	  else {
12664 #ifndef GIAC_HAS_STO_38
12665 	    *logptr(contextptr) << gettext("Warning! Could not loop or reach boundaries ") << fy << '\n';
12666 #endif
12667 	    break;
12668 	  }
12669 	}
12670 	else {
12671 	  // recompute solution
12672 	  fx=subst(f_orig,y,ycurrent,false,contextptr);
12673 #if 0
12674 	  int iszero=-1;
12675 	  vecteur sol1=bisection_solver(fx,x,xcurrent-xstep,xcurrent+xstep,iszero,contextptr);
12676 	  if (!sol1.empty()){
12677 	    if (deltax<0){ // reorder sol1 if we have more than 1 sol (almost horizontal)
12678 	      reverse(sol1.begin(),sol1.end());
12679 	      for (unsigned k=0;k<sol1.size();--k){
12680 		if (sol1[k].type==_DOUBLE_)
12681 		  chemin.push_back(sol1[k]+cst_i*ycurrent);
12682 	      }
12683 	    }
12684 	    sol=sol1.back();
12685 	  }
12686 	  else
12687 	    sol=undef;
12688 #else
12689 	  if (is_positive(subst(fx,x,xcurrent-xstep,false,contextptr)*subst(fx,x,xcurrent+xstep,false,contextptr),contextptr) || use_newton){
12690 	    sol=_fsolve(gen(makevecteur(fx,x,xcurrent,_NEWTON_SOLVER),_SEQ__VECT),contextptr);
12691 	  }
12692 	  else {
12693 	    sol=_fsolve(gen(makevecteur(fx,x,makevecteur(xcurrent-xstep,xcurrent+xstep),_BISECTION_SOLVER,100*eps),_SEQ__VECT),contextptr);
12694 	    get_sol(sol,contextptr);
12695 	  }
12696 #endif
12697 	  if (sol.type==_DOUBLE_){
12698 	    if (fabs(xcurrent-sol._DOUBLE_val)>2*xstep){
12699 	      chemin_ok=false;
12700 	      break;
12701 	    }
12702 	    else
12703 	      xcurrent=sol._DOUBLE_val;
12704 	  }
12705 	  else {
12706 #ifndef GIAC_HAS_STO_38
12707 	    *logptr(contextptr) << gettext("Warning! Could not loop or reach boundaries ") << fx << '\n';
12708 #endif
12709 	    break;
12710 	  }
12711 	}
12712 	chemin.push_back(gen(xcurrent,ycurrent));
12713 	// check cell
12714 	icur=int((xcurrent-xmin)/xstep);
12715 	jcur=int((ycurrent-ymin)/ystep);
12716 	if (icur<0 || icur>nxstep || jcur<0 || jcur>nystep ){
12717 	  // try to reverse chemin
12718 	  if (chemin.empty() || orig_sing)
12719 	    break;
12720 	  gen orig=chemin.front();
12721 	  double x_orig=evalf_double(re(orig,contextptr),1,contextptr)._DOUBLE_val;
12722 	  double y_orig=evalf_double(im(orig,contextptr),1,contextptr)._DOUBLE_val;
12723 	  int i_orig=int((x_orig-xmin)/xstep);
12724 	  int j_orig=int((y_orig-ymin)/ystep);
12725 	  if (i_orig<0 || i_orig>nxstep || j_orig<0 || j_orig>nystep)
12726 	    break;
12727 	  // revert chemin and restart in reverse direction
12728 	  reverse(chemin.begin(),chemin.end());
12729 	  xcurrent=x_orig;
12730 	  ycurrent=y_orig;
12731 	  sign=-sign;
12732 	  continue;
12733 	}
12734 	if ( (icur==oldi) && (jcur==oldj) ){
12735 	  ++count;
12736 	  continue;
12737 	}
12738 	if (visited[icur][jcur]){
12739 	  if (0.1*dfxyorig_abs[icur][jcur]*dfxycurrent_abs>fabs(dfxcurrent*dfyorig[icur][jcur]-dfycurrent*dfxorig[icur][jcur])){
12740 	    if (count<2)
12741 	      chemin_ok=false;
12742 	    else {
12743 	      // join to this point
12744 	      if (is_greater(xstep,abs(re(chemin.front()-xycurrent,contextptr),contextptr),contextptr) && is_greater(ystep,abs(im(chemin.front()-xycurrent,contextptr),contextptr),contextptr) )
12745 		chemin.push_back(chemin.front());
12746 	      else
12747 		chemin.push_back(gen(xorig[icur][jcur],yorig[icur][jcur]));
12748 	    }
12749 	    break;
12750 	  }
12751 	}
12752 	else {
12753 	  visited[icur][jcur]=true;
12754 	  dfxorig[icur][jcur]=dfxcurrent;
12755 	  dfyorig[icur][jcur]=dfycurrent;
12756 	  xorig[icur][jcur]=xcurrent;
12757 	  yorig[icur][jcur]=ycurrent;
12758 	  if (debug_infolevel)
12759 	    *logptr(contextptr)	<< icur << " " << jcur << " " << xcurrent << " " << ycurrent <<'\n';
12760 	  dfxyorig_abs[icur][jcur]=dfxycurrent_abs;
12761 	}
12762 	if (debug_infolevel)
12763 	  *logptr(contextptr) << gettext("Implicitplot ") << icur << " " << jcur << '\n';
12764 	oldi=icur;
12765 	oldj=jcur;
12766       }
12767       if (!chemin_ok){
12768 #ifndef GIAC_HAS_STO_38
12769 	*logptr(contextptr) << gettext("Warning! Could not loop or reach boundaries ") << '\n';
12770 #endif
12771       }
12772       res.push_back(symb_pnt(gen(chemin,_GROUP__VECT),attribut,contextptr));
12773     } // end for(;;)
12774 #ifndef WIN32
12775 #ifdef WITH_GNUPLOT
12776     if (child_id) plot_instructions.push_back(res);
12777 #endif
12778     io_graph(old_iograph,contextptr);
12779 #endif // WIN32
12780     return res; // gen(res,_SEQ__VECT);
12781     // return zero;
12782 #endif // RTOS_THREADX
12783   }
12784 
plotimplicit(const gen & f_orig,const gen & x,const gen & y,double xmin,double xmax,double ymin,double ymax,int nxstep,int nystep,double eps,const vecteur & attributs,bool unfactored,const context * contextptr,int ckgeo2d)12785   gen plotimplicit(const gen& f_orig,const gen&x,const gen & y,double xmin,double xmax,double ymin,double ymax,int nxstep,int nystep,double eps,const vecteur & attributs,bool unfactored,const context * contextptr,int ckgeo2d){
12786     if ( (x.type!=_IDNT) || (y.type!=_IDNT) )
12787       return gensizeerr(gettext("Variables must be free"));
12788     bool cplx=complex_mode(contextptr);
12789     if (cplx){
12790       complex_mode(false,contextptr);
12791       *logptr(contextptr) << gettext("Impliciplot: temporarily swtiching to real mode") << '\n';
12792     }
12793     // factorization without sqrt
12794     if (!unfactored && has_num_coeff(f_orig))
12795       unfactored=true;
12796     gen ff(unfactored?f_orig:factor(f_orig,false,contextptr));
12797     gen res=in_plotimplicit(ff,x,y,xmin,xmax,ymin,ymax,nxstep,nystep,eps,attributs,ckgeo2d,contextptr);
12798     if (cplx)
12799       complex_mode(true,contextptr);
12800     return res;
12801   }
12802 
_plotimplicit(const gen & args,const context * contextptr)12803   gen _plotimplicit(const gen & args,const context * contextptr){
12804     if ( args.type==_STRNG && args.subtype==-1) return  args;
12805     if (args.type!=_VECT)
12806       return plotimplicit(remove_equal(args),vx_var,y__IDNT_e,gnuplot_xmin,gnuplot_xmax,gnuplot_ymin,gnuplot_ymax,20*gnuplot_pixels_per_eval,0,epsilon(contextptr),vecteur(1,default_color(contextptr)),false,contextptr,3);
12807     // vecteur v(plotpreprocess(args));
12808     vecteur v(*args._VECTptr);
12809     if (v.size()<2)
12810       return gensizeerr(contextptr);
12811     if (v[1].is_symb_of_sommet(at_equal) && v[1]._SYMBptr->feuille._VECTptr->front()==at_display)
12812       v.insert(v.begin()+1,makevecteur(x__IDNT_e,y__IDNT_e));
12813     if ( v[1].type==_VECT) {
12814       if (v[1]._VECTptr->size()==2 ){
12815 	v.insert(v.begin()+2,v[1]._VECTptr->back());
12816 	v[1]=v[1]._VECTptr->front();
12817 	return _plotimplicit(v,contextptr);
12818       }
12819       if (v[1]._VECTptr->size()==3 ){
12820 	v.insert(v.begin()+2,(*v[1]._VECTptr)[2]);
12821 	v.insert(v.begin()+2,(*v[1]._VECTptr)[1]);
12822 	v[1]=v[1]._VECTptr->front();
12823 	return _plotimplicit(v,contextptr);
12824       }
12825     }
12826     int nstep=20*gnuplot_pixels_per_eval,jstep=0,kstep=0;
12827     double xmin,xmax,ymin,ymax,zmin,zmax;
12828     vecteur attributs(1,default_color(contextptr));
12829     gen x,y,z;
12830     readrange(v[1],gnuplot_xmin,gnuplot_xmax,x,xmin,xmax,contextptr);
12831     readrange(v[2],gnuplot_ymin,gnuplot_ymax,y,ymin,ymax,contextptr);
12832     bool dim3=v.size()>3;
12833     if (dim3)
12834       dim3=readrange(v[3],gnuplot_zmin,gnuplot_zmax,z,zmin,zmax,contextptr);
12835     else
12836       zmin=zmax=0.0;
12837     bool unfactored=false;
12838     read_option(v,xmin,xmax,ymin,ymax,zmin,zmax,attributs,nstep,jstep,kstep,unfactored,contextptr);
12839     if (dim3)
12840       return plotimplicit(remove_equal(v[0]),x,y,z,xmin,xmax,ymin,ymax,zmin,zmax,nstep,jstep,kstep,epsilon(contextptr),attributs,unfactored,contextptr);
12841     else
12842       return plotimplicit(remove_equal(v[0]),x,y,xmin,xmax,ymin,ymax,nstep,jstep,epsilon(contextptr),attributs,unfactored,contextptr,3);
12843   }
12844   static const char _plotimplicit_s []="plotimplicit";
12845   static define_unary_function_eval (__plotimplicit,&_plotimplicit,_plotimplicit_s);
12846   define_unary_function_ptr5( at_plotimplicit ,alias_at_plotimplicit,&__plotimplicit,0,true);
12847 
12848   static const char _implicitplot_s []="implicitplot";
12849   static define_unary_function_eval (__implicitplot,&_plotimplicit,_implicitplot_s);
12850   define_unary_function_ptr5( at_implicitplot ,alias_at_implicitplot,&__implicitplot,0,true);
12851 
is_approx0(const gen & a,double dx,double dy)12852   static bool is_approx0(const gen & a,double dx,double dy){
12853     if (a.type==_CPLX)
12854       return (fabs(a._CPLXptr->_DOUBLE_val) < 1e-6*dx) && (fabs((a._CPLXptr+1)->_DOUBLE_val) < 1e-6*dy);
12855     if (a.type==_REAL)
12856       return (fabs(a._CPLXptr->_DOUBLE_val) < 1e-6*dx);
12857     return is_zero(a);
12858   }
12859 
12860 #ifdef RTOS_THREADX
plotcontour(const gen & f0,bool contour,GIAC_CONTEXT)12861   gen plotcontour(const gen & f0,bool contour,GIAC_CONTEXT){
12862     return undef;
12863   }
12864 #else
12865   // v is a list of polygon vertices, add [A,B] to it
add_segment(vecteur & v,const gen & A,const gen & B,double dx,double dy)12866   static void add_segment(vecteur & v,const gen & A,const gen & B,double dx,double dy){
12867     if (is_approx0(A-B,dx,dy))
12868       return;
12869     iterateur it=v.begin(),itend=v.end();
12870     for (;it!=itend;++it){
12871       gen & tmp = *it;
12872       if (tmp.type==_VECT && !tmp._VECTptr->empty()){
12873 	gen & b =tmp._VECTptr->back();
12874 	if (is_approx0(b-A,dx,dy)){
12875 	  tmp._VECTptr->push_back(B);
12876 	  break;
12877 	}
12878 	if (is_approx0(b-B,dx,dy)){
12879 	  tmp._VECTptr->push_back(A);
12880 	  break;
12881 	}
12882 	gen & a=tmp._VECTptr->front();
12883 	if (is_approx0(a-A,dx,dy)){
12884 	  tmp._VECTptr->insert(tmp._VECTptr->begin(),B);
12885 	  break;
12886 	}
12887 	if (is_approx0(a-B,dx,dy)){
12888 	  tmp._VECTptr->insert(tmp._VECTptr->begin(),A);
12889 	  break;
12890 	}
12891       }
12892     }
12893     if (it==itend)
12894       v.push_back(makevecteur(A,B));
12895   }
12896 
glue_components(vecteur & v,double dx,double dy)12897   static void glue_components(vecteur & v,double dx,double dy){
12898     int s = int(v.size());
12899     for (int i=0;i<s-1;++i){
12900       gen & cur = v[i];
12901       for (int j=i+1;j<s;++j){
12902 	gen & next=v[j];
12903 	if (cur.type==_VECT && next.type==_VECT && !cur._VECTptr->empty() && !next._VECTptr->empty()){
12904 	  if (is_approx0(cur._VECTptr->front()-next._VECTptr->back(),dx,dy) || is_approx0(cur._VECTptr->front()-next._VECTptr->front(),dx,dy))
12905 	    reverse(cur._VECTptr->begin(),cur._VECTptr->end());
12906 	  if (is_approx0(cur._VECTptr->back()-next._VECTptr->back(),dx,dy))
12907 	    reverse(next._VECTptr->begin(),next._VECTptr->end());
12908 	  if (is_approx0(cur._VECTptr->back()-next._VECTptr->front(),dx,dy)){
12909 	    // FIXME mergevecteur will repeat cur.back and next.front
12910 	    v[i]=mergevecteur(*cur._VECTptr,*next._VECTptr);
12911 	    v.erase(v.begin()+j);
12912 	    j=i; // restart j loop
12913 	    --s;
12914 	  }
12915 	} // endif
12916       } // end for j
12917     } // end for i
12918   }
12919 
polygonify(vecteur & v,const vecteur & attributs,GIAC_CONTEXT)12920   static void polygonify(vecteur & v,const vecteur & attributs,GIAC_CONTEXT){
12921     iterateur it=v.begin(),itend=v.end();
12922     for (;it!=itend;++it){
12923       gen & tmp=*it;
12924       if (tmp.type==_VECT && tmp._VECTptr->size()>1){
12925 	tmp.subtype=_GROUP__VECT;
12926 	*it=pnt_attrib(tmp,attributs,contextptr);
12927       }
12928     }
12929   }
12930 
plot_array(const vector<vector<double>> & fij,int imax,int jmax,double xmin,double xmax,double dx,double ymin,double ymax,double dy,const vecteur & lz,const vecteur & attributs,bool contour,GIAC_CONTEXT)12931   gen plot_array(const vector< vector< double> > & fij,int imax,int jmax,double xmin,double xmax,double dx,double ymin,double ymax,double dy,const vecteur & lz,const vecteur & attributs,bool contour,GIAC_CONTEXT){
12932     // do linear interpolation between points for levels
12933     // with a marching rectangle
12934     // if all 4 vertices values are > or < nothing added
12935     // else 3/1 -> one segment between 2 interpolated zeros
12936     // 2/2
12937     // ++ __   +- + or \\   +- |
12938     // --      -+           +- |
12939     int nz=int(lz.size());
12940     vector<double> Z;
12941     for (int k=0;k<nz;k++){
12942       gen zg=evalf_double(lz[k],eval_level(contextptr),contextptr);
12943       if (zg.type==_DOUBLE_)
12944 	Z.push_back(zg._DOUBLE_val);
12945     }
12946     nz=int(Z.size());
12947     vector<vecteur> res(nz);
12948     for (int i=0;i<imax-1;++i){
12949       double x=xmin+i*dx;
12950       for (int j=0;j<jmax-1;++j){
12951 	double y=ymin+j*dy;
12952 	double a=fij[i][j+1];
12953 	double b=fij[i+1][j+1];
12954 	double c=fij[i][j];
12955 	double d=fij[i+1][j];
12956 	double eps=1e-12;
12957 	// a b (y+dy)
12958 	// c d (y)
12959 	for (int k=0;k<nz;k++){
12960 	  double z=Z[k];
12961 	  if (a==z)
12962 	    a += z?z*eps:eps;
12963 	  if (b==z)
12964 	    b += z?z*eps:eps;
12965 	  if (c==z)
12966 	    c += z?z*eps:eps;
12967 	  if (d==z)
12968 	    d += z?z*eps:eps;
12969 	  bool ab=(a-z)*(b-z)<=0,ca=(a-z)*(c-z)<=0,db=(d-z)*(b-z)<=0,cd=(d-z)*(c-z)<=0;
12970 	  gen AB,CA,DB,CD;
12971 	  // intercepts
12972 	  if (ab)
12973 	    AB=gen(x+(a-z)/(a-b)*dx,y+dy);
12974 	  if (cd)
12975 	    CD=gen(x+(c-z)/(c-d)*dx,y);
12976 	  if (ca)
12977 	    CA=gen(x,y+(c-z)/(c-a)*dy);
12978 	  if (db)
12979 	    DB=gen(x+dx,y+(d-z)/(d-b)*dy);
12980 	  // diagonal
12981 	  if (ab && ca){
12982 	    add_segment(res[k],AB,CA,dx,dy);
12983 	    ab=false;
12984 	    ca=false;
12985 	  }
12986 	  if (ab && db){
12987 	    add_segment(res[k],AB,DB,dx,dy);
12988 	    ab=false;
12989 	    db=false;
12990 	  }
12991 	  if (db && cd){
12992 	    add_segment(res[k],DB,CD,dx,dy);
12993 	    db=false;
12994 	    cd=false;
12995 	  }
12996 	  if (ca && cd){
12997 	    add_segment(res[k],CA,CD,dx,dy);
12998 	    ca=false;
12999 	    cd=false;
13000 	  }
13001 	  // horizontal
13002 	  if (ab && cd)
13003 	    add_segment(res[k],AB,CD,dx,dy);
13004 	  // vertical
13005 	  if (ca && db)
13006 	    add_segment(res[k],CA,DB,dx,dy);
13007 	}
13008       }
13009     }
13010     vecteur res0,attr(attributs);
13011     vecteur legendes,colors;
13012     if (attr.empty())
13013       attr.push_back(0);
13014     if (attributs.size()<2){
13015       attr.push_back(contour?lz:0);
13016     }
13017     if (attr[0].type==_VECT)
13018       colors=*attr[0]._VECTptr;
13019     else
13020       colors=vecteur(1,attr[0]);
13021     if (attr[1].type==_VECT)
13022       legendes=*attr[1]._VECTptr;
13023     int legs=int(legendes.size());
13024     int cols=int(colors.size());
13025     for (int k=0;k<nz;++k){
13026       attr[0]=colors[k<cols?k:0];
13027       if (!contour && attr[0].type==_INT_)
13028 	attr[0].val=attr[0].val | _FILL_POLYGON;
13029       attr[1]=k<legs?legendes[k]:string2gen("",false);
13030       glue_components(res[k],dx,dy);
13031       if (attr[0].type==_INT_ && (attr[0].val & _FILL_POLYGON)){
13032 	// now finsih gluing with the xmin/xmax/ymin/ymax border
13033 	int ncomp=int(res[k].size());
13034 	for (int n=0;n<ncomp;n++){
13035 	  gen composante=res[k][n];
13036 	  // look if begin and end of composante is at border
13037 	  if (composante.type!=_VECT || composante._VECTptr->size()<2)
13038 	    continue;
13039 	  gen begin=composante._VECTptr->front(),end=composante._VECTptr->back();
13040 	  if (is_approx0(begin-end,dx,dy)){
13041 	    // look if + inside ok else we must break the composante
13042 	    // to display outside instead of inside
13043 	    // find the nearest point to xmin,ymin
13044 	    vecteur cv=*composante._VECTptr;
13045 	    gen xymin(xmin,ymin);
13046 	    int cs=int(cv.size()),pos=0;
13047 	    gen dmin=abs(begin-xymin,contextptr);
13048 	    for (int i=1;i<cs;++i){
13049 	      gen dcur=abs(cv[i]-xymin,contextptr);
13050 	      if (is_strictly_positive(dmin-dcur,contextptr)){
13051 		pos=i;
13052 		dmin=dcur;
13053 	      }
13054 	    }
13055 	    // make a little step from cv[pos] in direction of xymin
13056 	    // and check sign of f
13057 	    int itmp=int((re(cv[pos],contextptr)._DOUBLE_val-xmin)/dx-0.5);
13058 	    int jtmp=int((im(cv[pos],contextptr)._DOUBLE_val-ymin)/dy-0.5);
13059 	    if (fij[itmp][jtmp]>Z[k]){
13060 	      // no luck, build the exterior
13061 	      res[k][n]=mergevecteur(mergevecteur(vecteur(cv.begin(),cv.begin()+pos+1),makevecteur(xymin,gen(xmax,ymin),gen(xmax,ymax),gen(xmin,ymax),xymin)),vecteur(cv.begin()+pos,cv.end()));
13062 	    }
13063 	    continue;
13064 	  }
13065 	  double bx,by=0,ex,ey=0;
13066 	  if (begin.type==_CPLX){
13067 	    bx=begin._CPLXptr->_DOUBLE_val;
13068 	    by=(begin._CPLXptr+1)->_DOUBLE_val;
13069 	  } else {
13070 	    if (begin.type==_DOUBLE_)
13071 	      bx=begin._DOUBLE_val;
13072 	    else
13073 	      continue;
13074 	  }
13075 	  if (end.type==_CPLX){
13076 	    ex=end._CPLXptr->_DOUBLE_val;
13077 	    ey=(end._CPLXptr+1)->_DOUBLE_val;
13078 	  } else {
13079 	    if (end.type==_DOUBLE_)
13080 	      ex=end._DOUBLE_val;
13081 	    else
13082 	      continue;
13083 	  }
13084 	  bool bxmin=fabs(bx-xmin)<1e-6*dx;
13085 	  bool bxmax=fabs(bx-xmax)<1e-6*dx;
13086 	  bool bymin=fabs(by-ymin)<1e-6*dy;
13087 	  bool bymax=fabs(by-ymax)<1e-6*dy;
13088 	  bool exmin=fabs(ex-xmin)<1e-6*dx;
13089 	  bool exmax=fabs(ex-xmax)<1e-6*dx;
13090 	  bool eymin=fabs(ey-ymin)<1e-6*dy;
13091 	  bool eymax=fabs(ey-ymax)<1e-6*dy;
13092 	  if ( (bxmin || bxmax || bymin || bymax) &&
13093 	       (exmin || exmax || eymin || eymax) ){
13094 	    bxmin=fabs(bx-xmin)<1.1*dx;
13095 	    bxmax=fabs(bx-xmax)<1.1*dx;
13096 	    bymin=fabs(by-ymin)<1.1*dy;
13097 	    bymax=fabs(by-ymax)<1.1*dy;
13098 	    exmin=fabs(ex-xmin)<1.1*dx;
13099 	    exmax=fabs(ex-xmax)<1.1*dx;
13100 	    eymin=fabs(ey-ymin)<1.1*dy;
13101 	    eymax=fabs(ey-ymax)<1.1*dy;
13102 	    int i,j,di,dj,ij,ijmax=2*(imax+jmax); // perimeter
13103 	    vecteur coins;
13104 	    // begin and end are on border, try to connect end
13105 	    if (exmin || exmax){
13106 	      // move y to the right, is it + ?
13107 	      i=exmin?0:imax-1;
13108 	      if (eymax){ // coin
13109 		j=jmax-2;
13110 		if (fij[i][j]>Z[k]){
13111 		  dj=-1;
13112 		  di=0;
13113 		}
13114 		else {
13115 		  j=jmax-1;
13116 		  i=exmin?1:imax-2;
13117 		  di=exmin?1:-1;
13118 		  dj=0;
13119 		}
13120 	      }
13121 	      else {
13122 		if (eymin){
13123 		  j=1;
13124 		  if (fij[i][j]>Z[k]){
13125 		    dj=1;
13126 		    di=0;
13127 		  }
13128 		  else {
13129 		    j=0;
13130 		    i=exmin?1:imax-2;
13131 		    di=exmin?1:-1;
13132 		    dj=0;
13133 		  }
13134 		}
13135 		else { // not a coin
13136 		  j=int((ey-ymin)/dy+.5);
13137 		  // yes, increase j, no decrease j
13138 		  dj=(fij[i][j+1]>Z[k])?1:-1;
13139 		  j+=dj;
13140 		  di=0;
13141 		}
13142 	      }
13143 	    }
13144 	    else {
13145 	      i=int((ex-xmin)/dx+.5);
13146 	      j=(eymin)?0:jmax-1;
13147 	      di=(fij[i+1][j]>Z[k])?1:-1;
13148 	      i+=di;
13149 	      dj=0;
13150 	    } // end if bx==xmin or bx==xmax
13151 	    for (ij=0; ij<ijmax;j+=dj,i+=di,++ij){
13152 	      if (fij[i][j]<Z[k]){
13153 		break;
13154 	      }
13155 	      if (di){
13156 		if (i==0 || i==imax-1){
13157 		  coins.push_back(gen(xmin+i*dx,ymin+j*dy));
13158 		  dj=j?-1:1;
13159 		  di=0;
13160 		}
13161 	      }
13162 	      else {
13163 		if (j==0 || j==jmax-1){
13164 		  coins.push_back(gen(xmin+i*dx,ymin+j*dy));
13165 		  di=i?-1:1;
13166 		  dj=0;
13167 		}
13168 	      }
13169 	    } // end for
13170 	    if (ij==ijmax)
13171 	      continue; // everywhere > 0
13172 	    // find component with begin or end near i,j
13173 	    double e1x=xmin+i*dx,e1y=ymin+j*dy;
13174 	    int m=n;
13175 	    for (;m<ncomp;m++){
13176 	      gen composante2=res[k][m];
13177 	      // look if begin and end of composante are on border
13178 	      if (composante2.type!=_VECT || composante2._VECTptr->size()<2)
13179 		continue;
13180 	      gen begin2=composante2._VECTptr->front(),end2=composante2._VECTptr->back();
13181 	      double b2x,b2y,e2x,e2y;
13182 	      if (begin2.type==_DOUBLE_){
13183 		b2x=begin2._DOUBLE_val; b2y=0;
13184 	      }
13185 	      else {
13186 		if (begin2.type!=_CPLX)
13187 		  continue;
13188 		b2x=begin2._CPLXptr->_DOUBLE_val;b2y=(begin2._CPLXptr+1)->_DOUBLE_val;
13189 	      }
13190 	      if (end2.type==_DOUBLE_){
13191 		e2x=end2._DOUBLE_val; e2y=0;
13192 	      }
13193 	      else {
13194 		if (end2.type!=_CPLX)
13195 		  continue;
13196 		e2x=end2._CPLXptr->_DOUBLE_val;
13197 		e2y=(end2._CPLXptr+1)->_DOUBLE_val;
13198 	      }
13199 	      if (fabs(e1x-e2x)<=1.1*dx && fabs(e1y-e2y)<=1.1*dy){
13200 		reverse(composante2._VECTptr->begin(),composante2._VECTptr->end());
13201 		swapdouble(b2x,e2x);
13202 		swapdouble(b2y,e2y);
13203 	      }
13204 	      if (fabs(e1x-b2x)<=1.1*dx && fabs(e1y-b2y)<=1.1*dy){
13205 		// found! glue res[k][n] with coins and res[k][m]
13206 		vecteur tmp=mergevecteur(*composante._VECTptr,coins);
13207 		if (n==m){
13208 		  tmp.push_back(begin2);
13209 		  res[k][n]=tmp;
13210 		}
13211 		else {
13212 		  res[k][n]=mergevecteur(tmp,*composante2._VECTptr);
13213 		  res[k].erase(res[k].begin()+m);
13214 		  --ncomp;
13215 		  --n;
13216 		}
13217 		break;
13218 	      }
13219 	    }
13220 	  }
13221 	} // end for n<=ncomp
13222       } // end if (contour || )
13223       polygonify(res[k],attr,contextptr);
13224       res0=mergevecteur(res0,res[k]);
13225     }
13226     return res0; // gen(res0,_SEQ__VECT);
13227   }
plotcontour(const gen & f0,bool contour,GIAC_CONTEXT)13228   gen plotcontour(const gen & f0,bool contour,GIAC_CONTEXT){
13229     vecteur v(gen2vecteur(f0));
13230     gen xvar=vx_var,yvar=y__IDNT_e;
13231     v=quote_eval(v,makevecteur(xvar,yvar),contextptr);
13232     gen attribut=default_color(contextptr);
13233     vecteur attributs(1,attribut);
13234     int s=read_attributs(v,attributs,contextptr);
13235     if (!s)
13236       return gensizeerr(contextptr);
13237     gen f=v[0];
13238     double xmin=gnuplot_xmin,xmax=gnuplot_xmax*(1+1e-6); // small shift 1e-6 for plotinequation(x^2+y^2<=4)
13239     double ymin=gnuplot_ymin,ymax=gnuplot_ymax*(1+1e-6);
13240     double zmin=gnuplot_zmin,zmax=gnuplot_zmax;
13241     if (s>1){
13242       gen tmp(v[1]);
13243       if (tmp.type==_VECT && tmp._VECTptr->size()==2){
13244 	readrange(tmp._VECTptr->front(),xmin,xmax,xvar,xmin,xmax,contextptr);
13245 	readrange(tmp._VECTptr->back(),ymin,ymax,yvar,ymin,ymax,contextptr);
13246       }
13247     }
13248     vecteur lz;
13249     if (s>2){
13250       gen tmp(v[2]);
13251       if (tmp.type==_VECT && !tmp._VECTptr->empty())
13252 	lz=*tmp._VECTptr;
13253     }
13254     else {
13255       if (contour){
13256 	lz=vecteur(11);
13257 	for (int i=0;i<11;++i)
13258 	  lz[i]=i;
13259       }
13260       else
13261 	lz=vecteur(1);
13262     }
13263     int imax=int(std::sqrt(double(gnuplot_pixels_per_eval)));
13264     int jmax=imax,kmax=0;
13265     vecteur vtmp;
13266     read_option(v,xmin,xmax,ymin,ymax,zmin,zmax,vtmp,imax,jmax,kmax,contextptr);
13267     double dx=(xmax-xmin)/imax,dy=(ymax-ymin)/jmax;
13268     ++imax; ++jmax;
13269     vector< vector<double> > fij;
13270     vecteur xy(makevecteur(xvar,yvar)),xyval(xy);
13271     // eval f from xmin to xmax, in jstep and ymin to ymax in kstep
13272     for (int i=0; i<imax;++i){
13273       vector<double> fi;
13274       xyval[0]=xmin+i*dx;
13275       for (int j=0;!ctrl_c && !interrupted &&j<jmax;++j){
13276 	xyval[1]=ymin+j*dy;
13277 	gen f1=evalf_double(evalf(quotesubst(f,xy,xyval,contextptr),eval_level(contextptr),contextptr),eval_level(contextptr),contextptr);
13278 	double zero=0.0;
13279 	fi.push_back(f1.type==_DOUBLE_?f1._DOUBLE_val:0.0/zero);
13280       }
13281       fij.push_back(fi);
13282     }
13283     return plot_array(fij,imax,jmax,xmin,xmax,dx,ymin,ymax,dy,lz,attributs,contour,contextptr);
13284   }
13285 #endif
_plotcontour(const gen & f0,GIAC_CONTEXT)13286   gen _plotcontour(const gen & f0,GIAC_CONTEXT){
13287     if ( f0.type==_STRNG && f0.subtype==-1) return  f0;
13288     return plotcontour(f0,true,contextptr);
13289   }
13290   static const char _plotcontour_s []="plotcontour";
13291   static define_unary_function_eval_quoted (__plotcontour,&_plotcontour,_plotcontour_s);
13292   define_unary_function_ptr5( at_plotcontour ,alias_at_plotcontour,&__plotcontour,_QUOTE_ARGUMENTS,true);
13293 
13294   static const char _contourplot_s []="contourplot";
13295   static define_unary_function_eval_quoted (__contourplot,&_plotcontour,_contourplot_s);
13296   define_unary_function_ptr5( at_contourplot ,alias_at_contourplot,&__contourplot,_QUOTE_ARGUMENTS,true);
13297 
inequation2equation(const gen & g)13298   static gen inequation2equation(const gen & g){
13299     if (g.type==_VECT){
13300       vecteur res;
13301       const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end();
13302       for (;it!=itend;++it)
13303 	res.push_back(inequation2equation(*it));
13304       return gen(res,g.subtype);
13305     }
13306     if (g.type==_SYMB && g._SYMBptr->feuille.type==_VECT && g._SYMBptr->feuille._VECTptr->size()==2){
13307       if (g._SYMBptr->sommet==at_inferieur_strict || g._SYMBptr->sommet==at_inferieur_egal)
13308 	return g._SYMBptr->feuille._VECTptr->back()-g._SYMBptr->feuille._VECTptr->front();
13309       if (g._SYMBptr->sommet==at_superieur_strict || g._SYMBptr->sommet==at_superieur_egal || g._SYMBptr->sommet==at_equal )
13310 	return g._SYMBptr->feuille._VECTptr->front()-g._SYMBptr->feuille._VECTptr->back();
13311     }
13312     return g;
13313   }
13314 
13315   // f0[0] is either a symbolic (draws f0[0]>=0) or a list (and)
13316   // if you want to draw or inequations, distribute and wrt to or
13317   // and make several plotinequation
_plotinequation(const gen & f0,GIAC_CONTEXT)13318   gen _plotinequation(const gen & f0,GIAC_CONTEXT){
13319     if ( f0.type==_STRNG && f0.subtype==-1) return  f0;
13320     vecteur v(gen2vecteur(f0));
13321     if (v.empty())
13322       return gensizeerr(contextptr);
13323     gen f=inequation2equation(v[0]);
13324     if (f.type==_VECT){
13325       f.subtype=_SEQ__VECT;
13326       f=symbolic(at_min,f);
13327     }
13328     v[0]=f;
13329     return plotcontour(v,false,contextptr);
13330   }
13331   static const char _plotinequation_s []="plotinequation";
13332   static define_unary_function_eval_quoted (__plotinequation,&_plotinequation,_plotinequation_s);
13333   define_unary_function_ptr5( at_plotinequation ,alias_at_plotinequation,&__plotinequation,_QUOTE_ARGUMENTS,true);
13334 
13335   static const char _inequationplot_s []="inequationplot";
13336   static define_unary_function_eval_quoted (__inequationplot,&_plotinequation,_inequationplot_s);
13337   define_unary_function_ptr5( at_inequationplot ,alias_at_inequationplot,&__inequationplot,_QUOTE_ARGUMENTS,true);
13338 
_inter_droite(const gen & args,GIAC_CONTEXT)13339   gen _inter_droite(const gen & args,GIAC_CONTEXT){
13340     if ( args.type==_STRNG && args.subtype==-1) return  args;
13341     if (args.type!=_VECT)
13342       return gentypeerr(contextptr);
13343     vecteur attributs(1,default_color(contextptr));
13344     int s=read_attributs(*args._VECTptr,attributs,contextptr);
13345     if (s<2 || s>3)
13346       return gendimerr(contextptr);
13347     gen res=_inter(gen(makevecteur(args._VECTptr->front(),(*args._VECTptr)[1]),_SEQ__VECT),contextptr);
13348     if (res.type==_VECT && !res._VECTptr->empty()){
13349       if (s==3){ // either a point (find nearest point in res) or a list (find 1st point not in list
13350 	vecteur v = *res._VECTptr;
13351 	gen other=(*args._VECTptr)[2];
13352 	if (other.type==_VECT){
13353 	  vecteur & w = *other._VECTptr;
13354 	  unsigned i,j,vs=unsigned(v.size()),ws=unsigned(w.size());
13355 	  for (i=0;i<vs;++i){
13356 	    for (j=0;j<ws;++j){
13357 	      if (is_zero(evalf(recursive_normal(distance2(other[j],v[i],contextptr),contextptr),1,contextptr),contextptr))
13358 		break;
13359 	    }
13360 	    if (j==ws){
13361 	      res=v[i];
13362 	      break;
13363 	    }
13364 	  }
13365 	}
13366 	else {
13367 	  unsigned i,vs=unsigned(v.size()); res=v[0];
13368 	  gen mind=distance2(other,res,contextptr),curd;
13369 	  for (i=1;i<vs;++i){
13370 	    curd=distance2(other,v[i],contextptr);
13371 	    if (is_strictly_greater(mind,curd,contextptr)){
13372 	      res=v[i];
13373 	      mind=curd;
13374 	    }
13375 	  }
13376 	}
13377       }
13378       else
13379 	res=res._VECTptr->front();
13380       if (res.is_symb_of_sommet(at_pnt) && res._SYMBptr->feuille.type==_VECT){
13381 	vecteur v = *res._SYMBptr->feuille._VECTptr;
13382 	if (v.size()>=2)
13383 	  v[1]=attributs[0];
13384 	if (v.size()>=3 && attributs.size()>=2)
13385 	  v[2]=attributs[1];
13386 	res=symbolic(at_pnt,gen(v,res._SYMBptr->feuille.subtype));
13387       }
13388       return res;
13389     }
13390     return undef;
13391   }
13392   static const char _inter_droite_s []="line_inter";
13393   static define_unary_function_eval (__inter_droite,&_inter_droite,_inter_droite_s);
13394   define_unary_function_ptr5( at_inter_droite ,alias_at_inter_droite,&__inter_droite,0,true);
13395 
13396   static const char _inter_unique_s []="single_inter";
13397   static define_unary_function_eval (__inter_unique,&_inter_droite,_inter_unique_s);
13398   define_unary_function_ptr5( at_inter_unique ,alias_at_inter_unique,&__inter_unique,0,true);
13399 
_bitmap(const gen & args,GIAC_CONTEXT)13400   gen _bitmap(const gen & args,GIAC_CONTEXT){
13401     if ( args.type==_STRNG && args.subtype==-1) return  args;
13402     return symb_pnt(symbolic(at_bitmap,args),0,contextptr);
13403   }
13404   static const char _bitmap_s []="bitmap";
13405   static define_unary_function_eval (__bitmap,&_bitmap,_bitmap_s);
13406   define_unary_function_ptr5( at_bitmap ,alias_at_bitmap,&__bitmap,0,true);
13407 
13408   /*
13409     gen papier_pointe_quadrillage(const gen & args,bool quadrillage,GIAC_CONTEXT){
13410     double xmin=gnuplot_xmin,xmax=gnuplot_xmax,ymin=gnuplot_ymin,ymax=gnuplot_ymax;
13411     double deltax=(xmax-xmin)/20,deltay=(ymax-ymin)/20,angle=evalf_double(cst_pi/2,1,contextptr)._DOUBLE_val;
13412     vecteur attributs(1,default_color(contextptr));
13413     if (args.type==_VECT){
13414     vecteur & w=*args._VECTptr;
13415     int s=w.size();
13416     if (s>0){
13417     gen tmp=evalf_double(w[0],1,contextptr);
13418     if (tmp.type==_DOUBLE_)
13419     deltax=fabs(tmp._DOUBLE_val);
13420     }
13421     if (s>1){
13422     gen tmp=evalf_double(w[1],1,contextptr);
13423     if (tmp.type==_DOUBLE_)
13424     deltay=fabs(tmp._DOUBLE_val);
13425     }
13426     if (s>2){
13427     gen tmp=evalf_double(w[2],1,contextptr);
13428     if (tmp.type==_DOUBLE_){
13429     angle=tmp._DOUBLE_val;
13430     if (fabs(angle)<epsilon(contextptr))
13431     return gensizeerr(contextptr);
13432     }
13433     }
13434     int nstep=int((xmax-xmin)/deltax),kstep=int((ymax-ymin)/deltay);
13435     gen x,y;
13436     for (int i=0;i<s;++i){
13437     if (w[i].is_symb_of_sommet(at_equal)){
13438     if (w[i][1]==x__IDNT_e)
13439     readrange(w[i],gnuplot_xmin,gnuplot_xmax,x,xmin,xmax,contextptr);
13440     if (w[i][1]==y__IDNT_e)
13441     readrange(w[i],gnuplot_xmin,gnuplot_xmax,y,ymin,ymax,contextptr);
13442     }
13443     }
13444     read_option(w,xmin,xmax,ymin,ymax,attributs,nstep,kstep,contextptr);
13445     if (!nstep)
13446     nstep=20;
13447     deltax=(xmax-xmin)/nstep;
13448     if (!kstep)
13449     kstep=20;
13450     deltay=(ymax-ymin)/kstep;
13451     }
13452     deltax=(xmax-xmin)/std::floor(fabs((xmax-xmin)/deltax));
13453     deltay=(ymax-ymin)/std::floor(fabs((ymax-ymin)/deltay));
13454     if (!quadrillage){
13455     int color=attributs[0].val;
13456     color = (color & 0xffff )| (7<<25) | (1 << 19);
13457     attributs[0]=color;
13458     }
13459     vecteur res;
13460     double pente=std::max(fabs(std::tan(angle)),0.05);
13461     if (quadrillage){
13462     res.push_back(pnt_attrib(gen(makevecteur(xmin+cst_i*ymin,xmin+cst_i*ymax),_GROUP__VECT),attributs,contextptr));
13463     res.push_back(pnt_attrib(gen(makevecteur(xmax+cst_i*ymin,xmax+cst_i*ymax),_GROUP__VECT),attributs,contextptr));
13464     for (double y=ymin;y<=ymax+1e-12;y+=deltay){
13465     res.push_back(pnt_attrib(gen(makevecteur(xmin+cst_i*y,xmax+cst_i*y),_GROUP__VECT),attributs,contextptr));
13466     }
13467     for (double x=xmin;x<=xmax+1e-12;x+=deltax){
13468     // line (x,ymax) -> (xmin,y)
13469     double y=ymax+pente*(xmin-x);
13470     if (y>=ymin-1e-12)
13471     res.push_back(pnt_attrib(gen(makevecteur(xmin+cst_i*y,x+cst_i*ymax),_GROUP__VECT),attributs,contextptr));
13472     else
13473     res.push_back(pnt_attrib(gen(makevecteur(x-(ymax-ymin)/pente+cst_i*ymin,x+cst_i*ymax),_GROUP__VECT),attributs,contextptr));
13474     }
13475     for (double y=ymax;y>ymin;y-=pente*deltax){
13476     double x=xmax+(ymin-y)/pente;
13477     if (x>=xmin)
13478     res.push_back(pnt_attrib(gen(makevecteur(x+cst_i*ymin,xmax+cst_i*y),_GROUP__VECT),attributs,contextptr));
13479     else { // xmin,y1 -> xmax,y
13480     double y1=y+(xmin-xmax)*pente;
13481     res.push_back(pnt_attrib(gen(makevecteur(xmin+cst_i*y1,xmax+cst_i*y),_GROUP__VECT),attributs,contextptr));
13482     }
13483     }
13484     }
13485     else {
13486     for (double x=xmin;;x+=deltax){
13487     double X=x;
13488     double y=ymax;
13489     if (X>=xmax+1e-12){
13490     // find y for xmax
13491     y=ymax-(X-xmax)*pente;
13492     if (y<ymin-1e-12)
13493     break;
13494     int ny=int(std::ceil((ymax-y)/deltay));
13495     y=ymax-ny*deltay;
13496     X=x-ny*deltay/pente;
13497     }
13498     // points of line (x,ymax) -> (xmin,y) or (x',ymin) with deltay
13499     for (;y>=ymin-1e-12 && X>=xmin-1e-12;y-=deltay,X-=deltay/pente){
13500     res.push_back(pnt_attrib(X+cst_i*y,attributs,contextptr));
13501     }
13502     }
13503     }
13504     return res; // gen(res,_SEQ__VECT);
13505     }
13506     gen _papier_pointe(const gen & args,GIAC_CONTEXT){
13507     if ( args.type==_STRNG && args.subtype==-1) return  args;
13508     return papier_pointe_quadrillage(args,false,contextptr);
13509     }
13510     static const char _papier_pointe_s []="dot_paper";
13511     static define_unary_function_eval (__papier_pointe,&_papier_pointe,_papier_pointe_s);
13512     define_unary_function_ptr5( at_papier_pointe ,alias_at_papier_pointe,&__papier_pointe,0,true);
13513 
13514     gen _papier_quadrille(const gen & args,GIAC_CONTEXT){
13515     if ( args.type==_STRNG && args.subtype==-1) return  args;
13516     return papier_pointe_quadrillage(args,true,contextptr);
13517     }
13518     static const char _papier_quadrille_s []="grid_paper";
13519     static define_unary_function_eval (__papier_quadrille,&_papier_quadrille,_papier_quadrille_s);
13520     define_unary_function_ptr5( at_papier_quadrille ,alias_at_papier_quadrille,&__papier_quadrille,0,true);
13521   */
13522   // code slice written by R. De Graeve (2010)
papier_lignes(vecteur & res,double xmin,double xmax,double ymin,double ymax,double angle,double deltax,double deltay,double pente,const vecteur & attributs,GIAC_CONTEXT)13523   void papier_lignes(vecteur & res,double xmin,double xmax,double ymin,double ymax,double angle,double deltax,double deltay,double pente,const vecteur & attributs,GIAC_CONTEXT){
13524     res.push_back(pnt_attrib(gen(makevecteur(xmin+ymin*cst_i,xmin+ymax*cst_i),_GROUP__VECT),attributs,contextptr));
13525     res.push_back(pnt_attrib(gen(makevecteur(xmax+ymax*cst_i,xmin+ymax*cst_i),_GROUP__VECT),attributs,contextptr));
13526     res.push_back(pnt_attrib(gen(makevecteur(xmax+ymin*cst_i,xmax+ymax*cst_i),_GROUP__VECT),attributs,contextptr));
13527     res.push_back(pnt_attrib(gen(makevecteur(xmax+ymin*cst_i,xmin+ymin*cst_i),_GROUP__VECT),attributs,contextptr));
13528     //const double cst_pi;
13529     double pi=evalf_double(cst_pi,1,contextptr)._DOUBLE_val;
13530     if (angle==pi/2){
13531       for (double x=xmin;x<=xmax;x+=deltax){
13532 	res.push_back(pnt_attrib(gen(makevecteur(x+ymin*cst_i,x+ymax*cst_i),_GROUP__VECT),attributs,contextptr));
13533       }
13534       //return res;
13535     }
13536     double Y=(ymax-ymin)/pente;
13537     if (angle<pi/2){
13538       double q=std::floor(Y/deltax+1e-12);
13539       for (double x=xmin-q*deltax;x<=xmin;x+=deltax){
13540 	double Y1=pente*(xmax-x)+ymin;
13541 	double Y2=pente*(xmin-x)+ymin;
13542 	double X1=(ymax-ymin)/pente+x;
13543 	if (Y1<ymax){
13544 	  res.push_back(pnt_attrib(gen(makevecteur(xmin+Y2*cst_i,xmax+Y1*cst_i),_GROUP__VECT),attributs,contextptr));
13545 	}
13546 	if (X1<xmax){
13547 	  res.push_back(pnt_attrib(gen(makevecteur(xmin+Y2*cst_i,X1+ymax*cst_i),_GROUP__VECT),attributs,contextptr));
13548 	}
13549       }
13550       for (double x=xmin;x<=xmax;x+=deltax){
13551 	double Y1=pente*(xmax-x)+ymin;
13552 	// double Y2=pente*(xmin-x)+ymin;
13553 	double X1=(ymax-ymin)/pente+x;
13554 	if (Y1<ymax){
13555 	  res.push_back(pnt_attrib(gen(makevecteur(x+ymin*cst_i,xmax+Y1*cst_i),_GROUP__VECT),attributs,contextptr));
13556 	}
13557 	if (X1<xmax){
13558 	  res.push_back(pnt_attrib(gen(makevecteur(x+ymin*cst_i,X1+ymax*cst_i),_GROUP__VECT),attributs,contextptr));
13559 	}
13560       }
13561       //return res;
13562     }
13563     if (angle>pi/2){
13564       double x=xmin;
13565       while (x<=xmax){
13566 	double Y1=pente*(xmin-x)+ymin;
13567 	double X1=(ymax-ymin)/pente+x;
13568 	if (Y1<ymax){
13569 	  res.push_back(pnt_attrib(gen(makevecteur(x+ymin*cst_i,xmin+Y1*cst_i),_GROUP__VECT),attributs,contextptr));
13570 	}
13571 	if (X1>xmin){
13572 	  res.push_back(pnt_attrib(gen(makevecteur(x+ymin*cst_i,X1+ymax*cst_i),_GROUP__VECT),attributs,contextptr));
13573 	}
13574 	x=x+deltax;
13575       }
13576       double q=std::ceil(Y/deltax-1e-12);
13577       while (x<=xmax-q*deltax){
13578 	double Y1=pente*(xmin-x)+ymin;
13579 	double Y2=pente*(xmax-x)+ymin;
13580 	double X1=(ymax-ymin)/pente+x;
13581 	if (Y1<ymax){
13582 	  res.push_back(pnt_attrib(gen(makevecteur(xmax+Y2*cst_i,xmin+Y1*cst_i),_GROUP__VECT),attributs,contextptr));
13583 	}
13584 	if (X1>xmin){
13585 	  res.push_back(pnt_attrib(gen(makevecteur(xmax+Y2*cst_i,X1+ymax*cst_i),_GROUP__VECT),attributs,contextptr));
13586 	}
13587 	x=x+deltax;
13588       }
13589       //return res;
13590     }
13591   }
13592 
Papier_pointe_quadrillage(const gen & args,int quadrillage,GIAC_CONTEXT)13593   static gen Papier_pointe_quadrillage(const gen & args,int quadrillage,GIAC_CONTEXT){
13594     double xmin=gnuplot_xmin,xmax=gnuplot_xmax,ymin=gnuplot_ymin,ymax=gnuplot_ymax;
13595     double deltax=(xmax-xmin)/20,deltay=(ymax-ymin)/20,angle=evalf_double(cst_pi/2,1,contextptr)._DOUBLE_val;
13596     vecteur attributs(1,default_color(contextptr));
13597     if (args.type==_VECT){
13598       vecteur & w=*args._VECTptr;
13599       int s=int(w.size());
13600       if (s>0){
13601 	gen tmp=evalf_double(w[0],1,contextptr);
13602 	if (tmp.type==_DOUBLE_)
13603 	  deltax=fabs(tmp._DOUBLE_val);
13604       }
13605       if (s>1){
13606 	gen tmp=evalf_double(w[1],1,contextptr);
13607 	if (tmp.type==_DOUBLE_){
13608 	  angle=tmp._DOUBLE_val;
13609 	  double pi=M_PI;
13610 	  angle=angle-std::floor(angle/pi)*pi;
13611 	  if (fabs(angle)<epsilon(contextptr) || fabs(pi-angle)<epsilon(contextptr))
13612 	    return gensizeerr(contextptr);
13613 	}
13614       }
13615       if (s>2){
13616 	gen tmp=evalf_double(w[2],1,contextptr);
13617 	if (tmp.type==_DOUBLE_)
13618 	  deltay=fabs(tmp._DOUBLE_val);
13619       }
13620       //int nstep=int((xmax-xmin)/deltax),kstep=int((ymax-ymin)/deltay);
13621       gen x,y;
13622       for (int i=0;i<s;++i){
13623 	if (w[i].is_symb_of_sommet(at_equal)){
13624 	  if (w[i][1]==x__IDNT_e)
13625 	    readrange(w[i],gnuplot_xmin,gnuplot_xmax,x,xmin,xmax,contextptr);
13626 	  if (w[i][1]==y__IDNT_e)
13627 	    readrange(w[i],gnuplot_xmin,gnuplot_xmax,y,ymin,ymax,contextptr);
13628 	}
13629       }
13630       int n1,n2;
13631       read_option(w,xmin,xmax,ymin,ymax,attributs,n1,n2,contextptr);
13632       // if (!nstep)nstep=20;deltax=(xmax-xmin)/nstep;
13633       //if (!kstep) kstep=20;deltay=(ymax-ymin)/kstep;
13634     }
13635 
13636     // deltax=(xmax-xmin)/std::floor(fabs((xmax-xmin)/deltax));
13637     // deltay=(ymax-ymin)/std::floor(fabs((ymax-ymin)/deltay));
13638     if (quadrillage==2){
13639       int color=attributs[0].val;
13640       color = (color & 0xffff )| (7<<25) | (1 << 19);
13641       attributs[0]=color;
13642     }
13643 
13644     vecteur res;
13645 
13646     double pente=std::tan(angle);
13647 
13648     if (quadrillage==0 || quadrillage==1){
13649       for (double y=ymin;y<=ymax;y+=deltay){
13650 	res.push_back(pnt_attrib(gen(makevecteur(xmin+y*cst_i,xmax+y*cst_i),_GROUP__VECT),attributs,contextptr));
13651       }
13652       //papier_lignes(res,xmin,xmax,ymin,ymax,0,deltax,deltay,pente,attributs,contextptr);
13653       papier_lignes(res,xmin,xmax,ymin,ymax,angle,deltax,deltay,pente,attributs,contextptr);
13654     }
13655     if (quadrillage==1){
13656       double u1=deltay/pente;
13657       if (u1-deltax==0) {angle=M_PI/2;}
13658       if (u1-deltax>0) {angle=std::atan(deltay/(u1-deltax)); }
13659       if (u1-deltax<0) {angle=std::atan(deltay/(u1-deltax))+M_PI;}
13660       papier_lignes(res,xmin,xmax,ymin,ymax,angle,deltax,deltay,std::tan(angle),attributs,contextptr);
13661 
13662     } // end if quadrillage== 1
13663     if (quadrillage==2) {
13664       res.push_back(pnt_attrib(gen(makevecteur(xmin+ymin*cst_i,xmin+ymax*cst_i),_GROUP__VECT),attributs,contextptr));
13665       res.push_back(pnt_attrib(gen(makevecteur(xmax+ymax*cst_i,xmin+ymax*cst_i),_GROUP__VECT),attributs,contextptr));
13666       res.push_back(pnt_attrib(gen(makevecteur(xmax+ymin*cst_i,xmax+ymax*cst_i),_GROUP__VECT),attributs,contextptr));
13667       res.push_back(pnt_attrib(gen(makevecteur(xmax+ymin*cst_i,xmin+ymin*cst_i),_GROUP__VECT),attributs,contextptr));
13668       for (double y=ymin;y<=ymax;y+=deltay){
13669 	double X=(y-ymin)/pente;
13670 	int q=int(std::floor(X/deltax+1e-12));
13671 	for (double x=xmin-q*deltax+X;x<xmax;x+=deltax){
13672 	  res.push_back(pnt_attrib(x+y*cst_i,attributs,contextptr));
13673 	}
13674       }
13675     }
13676     if (quadrillage==3) {
13677       papier_lignes(res,xmin,xmax,ymin,ymax,angle,deltax,deltay,pente,attributs,contextptr);
13678     }
13679     return res; // gen(res,_SEQ__VECT);
13680   }
_dot_paper(const gen & args,GIAC_CONTEXT)13681   gen _dot_paper(const gen & args,GIAC_CONTEXT){
13682     if ( args.type==_STRNG && args.subtype==-1) return  args;
13683     return Papier_pointe_quadrillage(args,2,contextptr);
13684   }
13685   //static const char _dot_paper_s []="papierp";
13686   static const char _dot_paper_s[]="dot_paper";
13687   static define_unary_function_eval (__dot_paper,&_dot_paper,_dot_paper_s);
13688   define_unary_function_ptr5( at_dot_paper ,alias_at_dot_paper,&__dot_paper,0,true);
13689 
_grid_paper(const gen & args,GIAC_CONTEXT)13690   gen _grid_paper(const gen & args,GIAC_CONTEXT){
13691     if ( args.type==_STRNG && args.subtype==-1) return  args;
13692     return Papier_pointe_quadrillage(args,0,contextptr);
13693   }
13694   // static const char _grid_paper_s []="papierq";
13695   static const char _grid_paper_s[]= "grid_paper";
13696   static define_unary_function_eval (__grid_paper,&_grid_paper,_grid_paper_s);
13697   define_unary_function_ptr5( at_grid_paper ,alias_at_grid_paper,&__grid_paper,0,true);
13698 
_triangle_paper(const gen & args,GIAC_CONTEXT)13699   gen _triangle_paper(const gen & args,GIAC_CONTEXT){
13700     if ( args.type==_STRNG && args.subtype==-1) return  args;
13701     return Papier_pointe_quadrillage(args,1,contextptr);
13702   }
13703   // static const char _triangle_paper_s []="papiert";
13704   const char _triangle_paper_s[] ="triangle_paper";
13705   static define_unary_function_eval (__triangle_paper,&_triangle_paper,_triangle_paper_s);
13706   define_unary_function_ptr5( at_triangle_paper ,alias_at_triangle_paper,&__triangle_paper,0,true);
13707 
_line_paper(const gen & args,GIAC_CONTEXT)13708   gen _line_paper(const gen & args,GIAC_CONTEXT){
13709     if ( args.type==_STRNG && args.subtype==-1) return  args;
13710     return Papier_pointe_quadrillage(args,3,contextptr);
13711   }
13712   // static const char _line_paper_s []="papierl";
13713   static const char _line_paper_s[]="line_paper";
13714   static define_unary_function_eval (__line_paper,&_line_paper,_line_paper_s);
13715   define_unary_function_ptr5( at_line_paper ,alias_at_line_paper,&__line_paper,0,true);
13716   // end of code slice written by R. De Graeve
13717 
13718   // inert function used to keep the attribute of a graphical object
_plot_style(const gen & args,GIAC_CONTEXT)13719   gen _plot_style(const gen & args,GIAC_CONTEXT){
13720     if ( args.type==_STRNG && args.subtype==-1) return  args;
13721     return symbolic(at_plot_style,args);
13722   }
13723   static const char _plot_style_s []="plot_style";
13724   static define_unary_function_eval_index (114,__plot_style,&_plot_style,_plot_style_s);
13725   define_unary_function_ptr5( at_plot_style ,alias_at_plot_style,&__plot_style,0,true);
13726 
13727   // Returns the current dimensions of the picture
13728   // and adjust plot_instructionsw/h
_Pictsize(const gen & args,GIAC_CONTEXT)13729   gen _Pictsize(const gen & args,GIAC_CONTEXT){
13730     if ( args.type==_STRNG && args.subtype==-1) return  args;
13731     gen res=__interactive.op(symbolic(at_Pictsize,args),contextptr);
13732     /*
13733       if (res.type==_VECT && res._VECTptr->size()==2){
13734       plot_instructionsw=res._VECTptr->front().val;
13735       plot_instructionsh=res._VECTptr->back().val;
13736       }
13737     */
13738     return res;
13739   }
13740   static const char _Pictsize_s []="Pictsize";
13741   static define_unary_function_eval (__Pictsize,&_Pictsize,_Pictsize_s);
13742   define_unary_function_ptr5( at_Pictsize ,alias_at_Pictsize,&__Pictsize,0,true);
13743 
13744 
13745   // FIXME 394 should be T_LOGO, 340 T_RETURN
13746   //#define T_LOGO 394
13747   //#define T_RETURN 340
_DrawInv(const gen & g,const context * contextptr)13748   gen _DrawInv(const gen & g,const context * contextptr){
13749     if ( g.type==_STRNG && g.subtype==-1) return  g;
13750     // return _symetrie(makevecteur(_droite(makevecteur(0,1+cst_i)),_plotfunc(g)));
13751     gen y(g),x(vx_var);
13752     if (g.type==_VECT && g.subtype==_SEQ__VECT && g._VECTptr->size()==2 ){
13753       vecteur & v=*g._VECTptr;
13754       y=v[0];
13755       x=v[1];
13756     }
13757     return _plotparam(gen(makevecteur(y+cst_i*x,x,gnuplot_xmin,gnuplot_xmax),_SEQ__VECT),contextptr);
13758   }
13759   static const char _DrawInv_s []="DrawInv";
13760   static define_unary_function_eval2 (__DrawInv,&_DrawInv,_DrawInv_s,&printastifunction);
13761   define_unary_function_ptr5( at_DrawInv ,alias_at_DrawInv,&__DrawInv,0,T_RETURN);
13762 
_Graph(const gen & g,GIAC_CONTEXT)13763   gen _Graph(const gen & g,GIAC_CONTEXT){
13764     if ( g.type==_STRNG && g.subtype==-1) return  g;
13765     return _plotfunc(g,contextptr);
13766     // FIXME: add a mode
13767     // vecteur v(gen2vecteur(g));
13768 
13769   }
13770   static const char _Graph_s []="Graph";
13771   static define_unary_function_eval2 (__Graph,&_Graph,_Graph_s,&printastifunction);
13772   define_unary_function_ptr5( at_Graph ,alias_at_Graph,&__Graph,0,T_RETURN);
13773 
13774   static const char _DrawFunc_s []="DrawFunc";
13775   static define_unary_function_eval2 (__DrawFunc,&_plotfunc,_DrawFunc_s,&printastifunction);
13776   define_unary_function_ptr5( at_DrawFunc ,alias_at_DrawFunc,&__DrawFunc,0,T_RETURN);
13777 
13778   static const char _DrawPol_s []="DrawPol";
13779   static define_unary_function_eval2 (__DrawPol,&_plotpolar,_DrawPol_s,&printastifunction);
13780   define_unary_function_ptr5( at_DrawPol ,alias_at_DrawPol,&__DrawPol,0,T_RETURN);
13781 
13782   static const char _DrawParm_s []="DrawParm";
13783   static define_unary_function_eval2 (__DrawParm,&_plotparam,_DrawParm_s,&printastifunction);
13784   define_unary_function_ptr5( at_DrawParm ,alias_at_DrawParm,&__DrawParm,0,T_RETURN);
13785 
_DrwCtour(const gen & g,GIAC_CONTEXT)13786   gen _DrwCtour(const gen & g,GIAC_CONTEXT){
13787     if ( g.type==_STRNG && g.subtype==-1) return  g;
13788     // FIXME
13789     return undef;
13790   }
13791   static const char _DrwCtour_s []="DrwCtour";
13792   static define_unary_function_eval2 (__DrwCtour,&_plotcontour,_DrwCtour_s,&printastifunction);
13793   define_unary_function_ptr5( at_DrwCtour ,alias_at_DrwCtour,&__DrwCtour,0,T_RETURN);
13794 
13795   // should be print_string?
gen2string(const gen & g)13796   std::string gen2string(const gen & g){
13797     if (g.type==_STRNG)
13798       return *g._STRNGptr;
13799     else
13800       return g.print(context0);
13801   }
13802 
13803 #ifndef KHICAS // in kdisplay.cc
13804 #if defined RTOS_THREADX || defined NSPIRE || defined FXCG
vecteur2turtle(const vecteur & v)13805   logo_turtle vecteur2turtle(const vecteur & v){
13806     return logo_turtle();
13807   }
13808 
turtle_status(const logo_turtle & turtle)13809   static int turtle_status(const logo_turtle & turtle){
13810     return 0;
13811   }
13812 
set_turtle_state(const vecteur & v,GIAC_CONTEXT)13813   bool set_turtle_state(const vecteur & v,GIAC_CONTEXT){
13814     return false;
13815   }
13816 
turtle2gen(const logo_turtle & turtle)13817   gen turtle2gen(const logo_turtle & turtle){
13818     return undef;
13819   }
13820 
turtlevect2vecteur(const std::vector<logo_turtle> & v)13821   vecteur turtlevect2vecteur(const std::vector<logo_turtle> & v){
13822     return 0;
13823   }
13824 
vecteur2turtlevect(const vecteur & v)13825   std::vector<logo_turtle> vecteur2turtlevect(const vecteur & v){
13826     return std::vector<logo_turtle>(0);
13827   }
13828 
turtle_state(GIAC_CONTEXT)13829   gen turtle_state(GIAC_CONTEXT){
13830     return undef;
13831   }
13832 
update_turtle_state(bool clrstring,GIAC_CONTEXT)13833   static gen update_turtle_state(bool clrstring,GIAC_CONTEXT){
13834     return undef;
13835   }
13836 
_avance(const gen & g,GIAC_CONTEXT)13837   gen _avance(const gen & g,GIAC_CONTEXT){
13838     return undef;
13839   }
13840   static const char _avance_s []="avance";
13841   static define_unary_function_eval2 (__avance,&_avance,_avance_s,&printastifunction);
13842   define_unary_function_ptr5( at_avance ,alias_at_avance,&__avance,0,T_LOGO);
13843 
_recule(const gen & g,GIAC_CONTEXT)13844   gen _recule(const gen & g,GIAC_CONTEXT){
13845     return undef;
13846   }
13847   static const char _recule_s []="recule";
13848   static define_unary_function_eval2 (__recule,&_recule,_recule_s,&printastifunction);
13849   define_unary_function_ptr5( at_recule ,alias_at_recule,&__recule,0,T_LOGO);
13850 
_position(const gen & g,GIAC_CONTEXT)13851   gen _position(const gen & g,GIAC_CONTEXT){
13852     return undef;
13853   }
13854   static const char _position_s []="position";
13855   static define_unary_function_eval2 (__position,&_position,_position_s,&printastifunction);
13856   define_unary_function_ptr5( at_position ,alias_at_position,&__position,0,T_LOGO);
13857 
_cap(const gen & g,GIAC_CONTEXT)13858   gen _cap(const gen & g,GIAC_CONTEXT){
13859     return undef;
13860   }
13861   static const char _cap_s []="cap";
13862   static define_unary_function_eval2 (__cap,&_cap,_cap_s,&printastifunction);
13863   define_unary_function_ptr5( at_cap ,alias_at_cap,&__cap,0,T_LOGO);
13864 
_tourne_droite(const gen & g,GIAC_CONTEXT)13865   gen _tourne_droite(const gen & g,GIAC_CONTEXT){
13866     return undef;
13867   }
13868   static const char _tourne_droite_s []="tourne_droite";
13869   static define_unary_function_eval2 (__tourne_droite,&_tourne_droite,_tourne_droite_s,&printastifunction);
13870   define_unary_function_ptr5( at_tourne_droite ,alias_at_tourne_droite,&__tourne_droite,0,T_LOGO);
13871 
_tourne_gauche(const gen & g,GIAC_CONTEXT)13872   gen _tourne_gauche(const gen & g,GIAC_CONTEXT){
13873     return undef;
13874   }
13875   static const char _tourne_gauche_s []="tourne_gauche";
13876   static define_unary_function_eval2 (__tourne_gauche,&_tourne_gauche,_tourne_gauche_s,&printastifunction);
13877   define_unary_function_ptr5( at_tourne_gauche ,alias_at_tourne_gauche,&__tourne_gauche,0,T_LOGO);
13878 
_leve_crayon(const gen & g,GIAC_CONTEXT)13879   gen _leve_crayon(const gen & g,GIAC_CONTEXT){
13880     return undef;
13881   }
13882   static const char _leve_crayon_s []="leve_crayon";
13883   static define_unary_function_eval2 (__leve_crayon,&_leve_crayon,_leve_crayon_s,&printastifunction);
13884   define_unary_function_ptr5( at_leve_crayon ,alias_at_leve_crayon,&__leve_crayon,0,T_LOGO);
13885 
_baisse_crayon(const gen & g,GIAC_CONTEXT)13886   gen _baisse_crayon(const gen & g,GIAC_CONTEXT){
13887     return undef;
13888   }
13889   static const char _baisse_crayon_s []="baisse_crayon";
13890   static define_unary_function_eval2 (__baisse_crayon,&_baisse_crayon,_baisse_crayon_s,&printastifunction);
13891   define_unary_function_ptr5( at_baisse_crayon ,alias_at_baisse_crayon,&__baisse_crayon,0,T_LOGO);
13892 
_ecris(const gen & g,GIAC_CONTEXT)13893   gen _ecris(const gen & g,GIAC_CONTEXT){
13894     return undef;
13895   }
13896   static const char _ecris_s []="ecris";
13897   static define_unary_function_eval2 (__ecris,&_ecris,_ecris_s,&printastifunction);
13898   define_unary_function_ptr5( at_ecris ,alias_at_ecris,&__ecris,0,T_LOGO);
_signe(const gen & g,GIAC_CONTEXT)13899   gen _signe(const gen & g,GIAC_CONTEXT){
13900     return undef;
13901   }
13902   static const char _signe_s []="signe";
13903   static define_unary_function_eval2 (__signe,&_signe,_signe_s,&printastifunction);
13904   define_unary_function_ptr5( at_signe ,alias_at_signe,&__signe,0,T_LOGO);
13905 
_saute(const gen & g,GIAC_CONTEXT)13906   gen _saute(const gen & g,GIAC_CONTEXT){
13907     return undef;
13908   }
13909   static const char _saute_s []="saute";
13910   static define_unary_function_eval2 (__saute,&_saute,_saute_s,&printastifunction);
13911   define_unary_function_ptr5( at_saute ,alias_at_saute,&__saute,0,T_LOGO);
13912 
13913   static const char _jump_s []="jump";
13914   static define_unary_function_eval2 (__jump,&_saute,_jump_s,&printastifunction);
13915   define_unary_function_ptr5( at_jump ,alias_at_jump,&__jump,0,T_LOGO);
13916 
13917   static const char _hideturtle_s []="hideturtle";
13918   static define_unary_function_eval (__hideturtle,&_cache_tortue,_hideturtle_s);
13919   define_unary_function_ptr5( at_hideturtle ,alias_at_hideturtle,&__hideturtle,0,true);
13920 
13921   static const char _forward_s []="forward";
13922   static define_unary_function_eval (__forward,&_avance,_forward_s);
13923   define_unary_function_ptr5( at_forward ,alias_at_forward,&__forward,0,true);
13924 
13925   static const char _heading_s []="heading";
13926   static define_unary_function_eval (__heading,&_cap,_heading_s);
13927   define_unary_function_ptr5( at_heading ,alias_at_heading,&__heading,0,true);
13928 
13929   static const char _pencolor_s []="pencolor";
13930   static define_unary_function_eval (__pencolor,&_crayon,_pencolor_s);
13931   define_unary_function_ptr5( at_pencolor ,alias_at_pencolor,&__pencolor,0,T_LOGO);
13932 
13933   static const char _showturtle_s []="showturtle";
13934   static define_unary_function_eval (__showturtle,&_montre_tortue,_showturtle_s);
13935   define_unary_function_ptr5( at_showturtle ,alias_at_showturtle,&__showturtle,0,true);
13936 
13937   static const char _turtle_stack_s []="turtle_stack";
13938   static define_unary_function_eval2 (__turtle_stack,&_cap,_turtle_stack_s,&printastifunction);
13939   define_unary_function_ptr5( at_turtle_stack ,alias_at_turtle_stack,&__turtle_stack,0,T_LOGO);
13940 
13941 static const char _pendown_s []="pendown";
13942   static define_unary_function_eval (__pendown,&_baisse_crayon,_pendown_s);
13943   define_unary_function_ptr5( at_pendown ,alias_at_pendown,&__pendown,0,T_LOGO);
13944 
13945   static const char _penup_s []="penup";
13946   static define_unary_function_eval (__penup,&_leve_crayon,_penup_s);
13947   define_unary_function_ptr5( at_penup ,alias_at_penup,&__penup,0,T_LOGO);
13948 
_pas_de_cote(const gen & g,GIAC_CONTEXT)13949   gen _pas_de_cote(const gen & g,GIAC_CONTEXT){
13950     return undef;
13951   }
13952   static const char _pas_de_cote_s []="pas_de_cote";
13953   static define_unary_function_eval2 (__pas_de_cote,&_pas_de_cote,_pas_de_cote_s,&printastifunction);
13954   define_unary_function_ptr5( at_pas_de_cote ,alias_at_pas_de_cote,&__pas_de_cote,0,T_LOGO);
13955   static const char _skip_s []="skip";
13956   static define_unary_function_eval2 (__skip,&_pas_de_cote,_skip_s,&printastifunction);
13957   define_unary_function_ptr5( at_skip ,alias_at_skip,&__skip,0,T_LOGO);
13958 
13959   static const char _backward_s []="backward";
13960   static define_unary_function_eval2 (__backward,&_pas_de_cote,_backward_s,&printastifunction);
13961   define_unary_function_ptr5( at_backward ,alias_at_backward,&__backward,0,T_LOGO);
13962 
_cache_tortue(const gen & g,GIAC_CONTEXT)13963   gen _cache_tortue(const gen & g,GIAC_CONTEXT){
13964     return undef;
13965   }
13966   static const char _cache_tortue_s []="cache_tortue";
13967   static define_unary_function_eval2 (__cache_tortue,&_cache_tortue,_cache_tortue_s,&printastifunction);
13968   define_unary_function_ptr5( at_cache_tortue ,alias_at_cache_tortue,&__cache_tortue,0,T_LOGO);
13969 
_montre_tortue(const gen & g,GIAC_CONTEXT)13970   gen _montre_tortue(const gen & g,GIAC_CONTEXT){
13971     return undef;
13972   }
13973   static const char _montre_tortue_s []="montre_tortue";
13974   static define_unary_function_eval2 (__montre_tortue,&_montre_tortue,_montre_tortue_s,&printastifunction);
13975   define_unary_function_ptr5( at_montre_tortue ,alias_at_montre_tortue,&__montre_tortue,0,T_LOGO);
13976 
_debut_enregistrement(const gen & g,GIAC_CONTEXT)13977   gen _debut_enregistrement(const gen & g,GIAC_CONTEXT){
13978     return undef;
13979   }
13980   static const char _debut_enregistrement_s []="debut_enregistrement";
13981   static define_unary_function_eval2 (__debut_enregistrement,&_debut_enregistrement,_debut_enregistrement_s,&printastifunction);
13982   define_unary_function_ptr5( at_debut_enregistrement ,alias_at_debut_enregistrement,&__debut_enregistrement,0,T_LOGO);
13983 
_fin_enregistrement(const gen & g,GIAC_CONTEXT)13984   gen _fin_enregistrement(const gen & g,GIAC_CONTEXT){
13985     return undef;
13986   }
13987   static const char _fin_enregistrement_s []="fin_enregistrement";
13988   static define_unary_function_eval2 (__fin_enregistrement,&_fin_enregistrement,_fin_enregistrement_s,&printastifunction);
13989   define_unary_function_ptr5( at_fin_enregistrement ,alias_at_fin_enregistrement,&__fin_enregistrement,0,T_LOGO);
13990 
_repete(const gen & g,GIAC_CONTEXT)13991   gen _repete(const gen & g,GIAC_CONTEXT){
13992     return undef;
13993   }
13994   static const char _repete_s []="repete";
13995   static define_unary_function_eval2 (__repete,&_repete,_repete_s,&printastifunction);
13996   define_unary_function_ptr5( at_repete ,alias_at_repete,&__repete,0,T_LOGO);
13997 
_crayon(const gen & g,GIAC_CONTEXT)13998   gen _crayon(const gen & g,GIAC_CONTEXT){
13999     return undef;
14000   }
14001   static const char _crayon_s []="crayon";
14002   static define_unary_function_eval2 (__crayon,&_crayon,_crayon_s,&printastifunction);
14003   define_unary_function_ptr5( at_crayon ,alias_at_crayon,&__crayon,0,T_LOGO);
14004 
_efface(const gen & g,GIAC_CONTEXT)14005   gen _efface(const gen & g,GIAC_CONTEXT){
14006     return undef;
14007   }
14008   static const char _efface_s []="efface";
14009   static define_unary_function_eval2 (__efface,&_efface,_efface_s,&printastifunction);
14010   define_unary_function_ptr5( at_efface ,alias_at_efface,&__efface,0,T_LOGO);
14011 
14012   static const char _clearscreen_s []="clearscreen";
14013   static define_unary_function_eval2 (__clearscreen,&_efface,_clearscreen_s,&printastifunction);
14014   define_unary_function_ptr5( at_clearscreen ,alias_at_clearscreen,&__clearscreen,0,T_LOGO);
14015 
_vers(const gen & g,GIAC_CONTEXT)14016 gen _vers(const gen & g,GIAC_CONTEXT){
14017     return undef;
14018   }
14019   static const char _vers_s []="vers";
14020   static define_unary_function_eval2 (__vers,&_vers,_vers_s,&printastifunction);
14021   define_unary_function_ptr5( at_vers ,alias_at_vers,&__vers,0,T_LOGO);
14022 
find_radius(const gen & g,int & r,int & theta2,bool & direct)14023   static int find_radius(const gen & g,int & r,int & theta2,bool & direct){
14024     return 0;
14025   }
14026 
turtle_move(int r,int theta2,GIAC_CONTEXT)14027   static void turtle_move(int r,int theta2,GIAC_CONTEXT){
14028   }
14029 
_disque(const gen & g,GIAC_CONTEXT)14030   gen _disque(const gen & g,GIAC_CONTEXT){
14031     return undef;
14032   }
14033   static const char _disque_s []="disque";
14034   static define_unary_function_eval2 (__disque,&_disque,_disque_s,&printastifunction);
14035   define_unary_function_ptr5( at_disque ,alias_at_disque,&__disque,0,T_LOGO);
14036 
_disque_centre(const gen & g,GIAC_CONTEXT)14037   gen _disque_centre(const gen & g,GIAC_CONTEXT){
14038     return undef;
14039   }
14040   static const char _disque_centre_s []="disque_centre";
14041   static define_unary_function_eval2 (__disque_centre,&_disque_centre,_disque_centre_s,&printastifunction);
14042   define_unary_function_ptr5( at_disque_centre ,alias_at_disque_centre,&__disque_centre,0,T_LOGO);
14043 
_rond(const gen & g,GIAC_CONTEXT)14044   gen _rond(const gen & g,GIAC_CONTEXT){
14045     return undef;
14046   }
14047   static const char _rond_s []="rond";
14048   static define_unary_function_eval2 (__rond,&_rond,_rond_s,&printastifunction);
14049   define_unary_function_ptr5( at_rond ,alias_at_rond,&__rond,0,T_LOGO);
14050 
_polygone_rempli(const gen & g,GIAC_CONTEXT)14051   gen _polygone_rempli(const gen & g,GIAC_CONTEXT){
14052     return undef;
14053   }
14054   static const char _polygone_rempli_s []="polygone_rempli";
14055   static define_unary_function_eval2 (__polygone_rempli,&_polygone_rempli,_polygone_rempli_s,&printastifunction);
14056   define_unary_function_ptr5( at_polygone_rempli ,alias_at_polygone_rempli,&__polygone_rempli,0,T_LOGO);
14057 
_rectangle_plein(const gen & g,GIAC_CONTEXT)14058   gen _rectangle_plein(const gen & g,GIAC_CONTEXT){
14059     return undef;
14060   }
14061   static const char _rectangle_plein_s []="rectangle_plein";
14062   static define_unary_function_eval2 (__rectangle_plein,&_rectangle_plein,_rectangle_plein_s,&printastifunction);
14063   define_unary_function_ptr5( at_rectangle_plein ,alias_at_rectangle_plein,&__rectangle_plein,0,T_LOGO);
14064 
_triangle_plein(const gen & g,GIAC_CONTEXT)14065   gen _triangle_plein(const gen & g,GIAC_CONTEXT){
14066     return undef;
14067   }
14068   static const char _triangle_plein_s []="triangle_plein";
14069   static define_unary_function_eval2 (__triangle_plein,&_triangle_plein,_triangle_plein_s,&printastifunction);
14070   define_unary_function_ptr5( at_triangle_plein ,alias_at_triangle_plein,&__triangle_plein,0,T_LOGO);
14071 
_dessine_tortue(const gen & g,GIAC_CONTEXT)14072   gen _dessine_tortue(const gen & g,GIAC_CONTEXT){
14073     return undef;
14074   }
14075   static const char _dessine_tortue_s []="dessine_tortue";
14076   static define_unary_function_eval2 (__dessine_tortue,&_dessine_tortue,_dessine_tortue_s,&printastifunction);
14077   define_unary_function_ptr5( at_dessine_tortue ,alias_at_dessine_tortue,&__dessine_tortue,0,T_LOGO);
14078 
14079 #else
vecteur2turtle(const vecteur & v)14080   logo_turtle vecteur2turtle(const vecteur & v){
14081     int s=int(v.size());
14082     if (s>=5 && v[0].type==_DOUBLE_ && v[1].type==_DOUBLE_ && v[2].type==_DOUBLE_ && v[3].type==_INT_ && v[4].type==_INT_ ){
14083       logo_turtle t;
14084       t.x=v[0]._DOUBLE_val;
14085       t.y=v[1]._DOUBLE_val;
14086       t.theta=v[2]._DOUBLE_val;
14087       int i=v[3].val;
14088       t.mark=(i%2)!=0;
14089       i=i >> 1;
14090       t.visible=(i%2)!=0;
14091       i=i >> 1;
14092       t.direct = (i%2)!=0;
14093       i=i >> 1;
14094       t.turtle_length = i & 0xff;
14095       i=i >> 8;
14096       t.color = i;
14097       t.radius = v[4].val;
14098       if (s>5 && v[5].type==_STRNG)
14099 	t.s=*v[5]._STRNGptr;
14100       else
14101 	t.s="";
14102       return t;
14103     }
14104 #ifndef NO_STDEXCEPT
14105     setsizeerr(gettext("vecteur2turtle")); // FIXME
14106 #endif
14107     return logo_turtle();
14108   }
14109 
turtle_status(const logo_turtle & turtle)14110   static int turtle_status(const logo_turtle & turtle){
14111     int status= (turtle.color << 11) | ( (turtle.turtle_length & 0xff) << 3) ;
14112     if (turtle.direct)
14113       status += 4;
14114     if (turtle.visible)
14115       status += 2;
14116     if (turtle.mark)
14117       status += 1;
14118     return status;
14119   }
14120 
set_turtle_state(const vecteur & v,GIAC_CONTEXT)14121   bool set_turtle_state(const vecteur & v,GIAC_CONTEXT){
14122     if (v.size()>=2 && v[0].type==_DOUBLE_ && v[1].type==_DOUBLE_){
14123       vecteur w(v);
14124       int s=int(w.size());
14125       if (s==2)
14126 	w.push_back(turtle(contextptr).theta);
14127       if (s<4)
14128 	w.push_back(turtle_status(turtle(contextptr)));
14129       if (s<5)
14130 	w.push_back(0);
14131       if (w[2].type==_DOUBLE_ && w[3].type==_INT_ && w[4].type==_INT_){
14132 	turtle(contextptr)=vecteur2turtle(w);
14133 	turtle_stack(contextptr).push_back(turtle(contextptr));
14134 	return true;
14135       }
14136     }
14137     return false;
14138   }
14139 
turtle2gen(const logo_turtle & turtle)14140   gen turtle2gen(const logo_turtle & turtle){
14141     return gen(makevecteur(turtle.x,turtle.y,turtle.theta,turtle_status(turtle),turtle.radius,string2gen(turtle.s,false)),_LOGO__VECT);
14142   }
14143 
turtlevect2vecteur(const std::vector<logo_turtle> & v)14144   vecteur turtlevect2vecteur(const std::vector<logo_turtle> & v){
14145     vecteur res;
14146     vector<logo_turtle>::const_iterator it=v.begin(),itend=v.end();
14147     res.reserve(itend-it);
14148     for (;it!=itend;++it)
14149       res.push_back(turtle2gen(*it));
14150     return res;
14151   }
14152 
vecteur2turtlevect(const vecteur & v)14153   std::vector<logo_turtle> vecteur2turtlevect(const vecteur & v){
14154     std::vector<logo_turtle> res;
14155     const_iterateur it=v.begin(),itend=v.end();
14156     for (;it!=itend;++it){
14157       if (it->type==_VECT)
14158 	res.push_back(vecteur2turtle(*it->_VECTptr));
14159     }
14160     return res;
14161   }
14162 
turtle_state(GIAC_CONTEXT)14163   gen turtle_state(GIAC_CONTEXT){
14164     return turtle2gen(turtle(contextptr));
14165   }
14166 
update_turtle_state(bool clrstring,GIAC_CONTEXT)14167   static gen update_turtle_state(bool clrstring,GIAC_CONTEXT){
14168     if (clrstring)
14169       turtle(contextptr).s="";
14170     turtle(contextptr).theta = turtle(contextptr).theta - floor(turtle(contextptr).theta/360)*360;
14171     turtle_stack(contextptr).push_back(turtle(contextptr));
14172     gen res=turtle_state(contextptr);
14173 #ifdef EMCC // should directly interact with canvas
14174     return gen(turtlevect2vecteur(turtle_stack(contextptr)),_LOGO__VECT);
14175 #endif
14176     // update parent turtle state
14177     if (turtle_stack(contextptr).size()==1)
14178       __interactive.op(symbolic(at_pnt,-1),contextptr); // clear parent stack
14179     else { // code turtle
14180       __interactive.op(symbolic(at_pnt,res),contextptr);
14181     }
14182     return res;
14183   }
14184 
_avance(const gen & g,GIAC_CONTEXT)14185   gen _avance(const gen & g,GIAC_CONTEXT){
14186     if ( g.type==_STRNG && g.subtype==-1) return  g;
14187     // logo instruction
14188     double i;
14189     if (g.type!=_INT_){
14190       if (g.type==_VECT)
14191 	i=turtle(contextptr).turtle_length;
14192       else {
14193 	gen g1=evalf_double(g,1,contextptr);
14194 	if (g1.type==_DOUBLE_)
14195 	  i=g1._DOUBLE_val;
14196 	else
14197 	  return gensizeerr(contextptr);
14198       }
14199     }
14200     else
14201       i=g.val;
14202     turtle(contextptr).x += i * std::cos(turtle(contextptr).theta*deg2rad_d);
14203     turtle(contextptr).y += i * std::sin(turtle(contextptr).theta*deg2rad_d) ;
14204     turtle(contextptr).radius = 0;
14205     return update_turtle_state(true,contextptr);
14206   }
14207   static const char _avance_s []="avance";
14208   static define_unary_function_eval2 (__avance,&_avance,_avance_s,&printastifunction);
14209   define_unary_function_ptr5( at_avance ,alias_at_avance,&__avance,0,T_LOGO);
14210 
14211   static const char _forward_s []="forward";
14212   static define_unary_function_eval (__forward,&_avance,_forward_s);
14213   define_unary_function_ptr5( at_forward ,alias_at_forward,&__forward,0,true);
14214 
_recule(const gen & g,GIAC_CONTEXT)14215   gen _recule(const gen & g,GIAC_CONTEXT){
14216     if ( g.type==_STRNG && g.subtype==-1) return  g;
14217     // logo instruction
14218     if (g.type==_VECT)
14219       return _avance(-turtle(contextptr).turtle_length,contextptr);
14220     return _avance(-g,contextptr);
14221   }
14222   static const char _recule_s []="recule";
14223   static define_unary_function_eval2 (__recule,&_recule,_recule_s,&printastifunction);
14224   define_unary_function_ptr5( at_recule ,alias_at_recule,&__recule,0,T_LOGO);
14225 
14226   static const char _backward_s []="backward";
14227   static define_unary_function_eval (__backward,&_recule,_backward_s);
14228   define_unary_function_ptr5( at_backward ,alias_at_backward,&__backward,0,true);
14229 
_position(const gen & g,GIAC_CONTEXT)14230   gen _position(const gen & g,GIAC_CONTEXT){
14231     if ( g.type==_STRNG && g.subtype==-1) return  g;
14232     // logo instruction
14233     if (g.type!=_VECT)
14234       return makevecteur(turtle(contextptr).x,turtle(contextptr).y);
14235     // return turtle_state();
14236     vecteur v = *g._VECTptr;
14237     int s=int(v.size());
14238     if (!s)
14239       return makevecteur(turtle(contextptr).x,turtle(contextptr).y);
14240     v[0]=evalf_double(v[0],1,contextptr);
14241     if (s>1)
14242       v[1]=evalf_double(v[1],1,contextptr);
14243     if (s>2)
14244       v[2]=evalf_double(v[2],1,contextptr);
14245     if (set_turtle_state(v,contextptr))
14246       return update_turtle_state(true,contextptr);
14247     return zero;
14248   }
14249   static const char _position_s []="position";
14250   static define_unary_function_eval2 (__position,&_position,_position_s,&printastifunction);
14251   define_unary_function_ptr5( at_position ,alias_at_position,&__position,0,T_LOGO);
14252 
_cap(const gen & g,GIAC_CONTEXT)14253   gen _cap(const gen & g,GIAC_CONTEXT){
14254     if ( g.type==_STRNG && g.subtype==-1) return  g;
14255     // logo instruction
14256     gen gg=evalf_double(g,1,contextptr);
14257     if (gg.type!=_DOUBLE_)
14258       return turtle(contextptr).theta;
14259     turtle(contextptr).theta=gg._DOUBLE_val;
14260     turtle(contextptr).radius = 0;
14261     return update_turtle_state(true,contextptr);
14262   }
14263   static const char _cap_s []="cap";
14264   static define_unary_function_eval2 (__cap,&_cap,_cap_s,&printastifunction);
14265   define_unary_function_ptr5( at_cap ,alias_at_cap,&__cap,0,T_LOGO);
14266 
14267   static const char _heading_s []="heading";
14268   static define_unary_function_eval (__heading,&_cap,_heading_s);
14269   define_unary_function_ptr5( at_heading ,alias_at_heading,&__heading,0,true);
14270 
14271 
_tourne_droite(const gen & g,GIAC_CONTEXT)14272   gen _tourne_droite(const gen & g,GIAC_CONTEXT){
14273     if ( g.type==_STRNG && g.subtype==-1) return  g;
14274     // logo instruction
14275     if (g.type!=_INT_){
14276       if (g.type==_VECT)
14277 	turtle(contextptr).theta -= 90;
14278       else {
14279 	gen g1=evalf_double(g,1,contextptr);
14280 	if (g1.type==_DOUBLE_)
14281 	  turtle(contextptr).theta -= g1._DOUBLE_val;
14282 	else
14283 	  return gensizeerr(contextptr);
14284       }
14285     }
14286     else
14287       turtle(contextptr).theta -= g.val;
14288     turtle(contextptr).radius = 0;
14289     return update_turtle_state(true,contextptr);
14290   }
14291   static const char _tourne_droite_s []="tourne_droite";
14292   static define_unary_function_eval2 (__tourne_droite,&_tourne_droite,_tourne_droite_s,&printastifunction);
14293   define_unary_function_ptr5( at_tourne_droite ,alias_at_tourne_droite,&__tourne_droite,0,T_LOGO);
14294 
_tourne_gauche(const gen & g,GIAC_CONTEXT)14295   gen _tourne_gauche(const gen & g,GIAC_CONTEXT){
14296     if ( g.type==_STRNG && g.subtype==-1) return  g;
14297     // logo instruction
14298     if (g.type==_VECT){
14299       turtle(contextptr).theta += 90;
14300       turtle(contextptr).radius = 0;
14301       return update_turtle_state(true,contextptr);
14302     }
14303     return _tourne_droite(-g,contextptr);
14304   }
14305   static const char _tourne_gauche_s []="tourne_gauche";
14306   static define_unary_function_eval2 (__tourne_gauche,&_tourne_gauche,_tourne_gauche_s,&printastifunction);
14307   define_unary_function_ptr5( at_tourne_gauche ,alias_at_tourne_gauche,&__tourne_gauche,0,T_LOGO);
14308 
_leve_crayon(const gen & g,GIAC_CONTEXT)14309   gen _leve_crayon(const gen & g,GIAC_CONTEXT){
14310     if ( g.type==_STRNG && g.subtype==-1) return  g;
14311     // logo instruction
14312     turtle(contextptr).mark = false;
14313     turtle(contextptr).radius = 0;
14314     return update_turtle_state(true,contextptr);
14315   }
14316   static const char _leve_crayon_s []="leve_crayon";
14317   static define_unary_function_eval2 (__leve_crayon,&_leve_crayon,_leve_crayon_s,&printastifunction);
14318   define_unary_function_ptr5( at_leve_crayon ,alias_at_leve_crayon,&__leve_crayon,0,T_LOGO);
14319 
14320   static const char _penup_s []="penup";
14321   static define_unary_function_eval (__penup,&_leve_crayon,_penup_s);
14322   define_unary_function_ptr5( at_penup ,alias_at_penup,&__penup,0,T_LOGO);
14323 
_baisse_crayon(const gen & g,GIAC_CONTEXT)14324   gen _baisse_crayon(const gen & g,GIAC_CONTEXT){
14325     if ( g.type==_STRNG && g.subtype==-1) return  g;
14326     // logo instruction
14327     turtle(contextptr).mark = true;
14328     turtle(contextptr).radius = 0;
14329     return update_turtle_state(true,contextptr);
14330   }
14331   static const char _baisse_crayon_s []="baisse_crayon";
14332   static define_unary_function_eval2 (__baisse_crayon,&_baisse_crayon,_baisse_crayon_s,&printastifunction);
14333   define_unary_function_ptr5( at_baisse_crayon ,alias_at_baisse_crayon,&__baisse_crayon,0,T_LOGO);
14334 
14335   static const char _pendown_s []="pendown";
14336   static define_unary_function_eval (__pendown,&_baisse_crayon,_pendown_s);
14337   define_unary_function_ptr5( at_pendown ,alias_at_pendown,&__pendown,0,T_LOGO);
14338 
_ecris(const gen & g,GIAC_CONTEXT)14339   gen _ecris(const gen & g,GIAC_CONTEXT){
14340     if ( g.type==_STRNG && g.subtype==-1) return  g;
14341     // logo instruction
14342     turtle(contextptr).radius=14;
14343     if (g.type==_VECT){
14344       vecteur & v =*g._VECTptr;
14345       int s=int(v.size());
14346       if (s==2 && v[1].type==_INT_){
14347 	turtle(contextptr).radius=absint(v[1].val);
14348 	turtle(contextptr).s=gen2string(v.front());
14349 	return update_turtle_state(false,contextptr);
14350       }
14351       if (s==4 && v[1].type==_INT_ && v[2].type==_INT_ && v[3].type==_INT_){
14352 	logo_turtle t=turtle(contextptr);
14353 	_leve_crayon(0,contextptr);
14354 	_position(makevecteur(v[2],v[3]),contextptr);
14355 	turtle(contextptr).radius=absint(v[1].val);
14356 	turtle(contextptr).s=gen2string(v.front());
14357 	update_turtle_state(false,contextptr);
14358 	turtle(contextptr)=t;
14359 	return update_turtle_state(true,contextptr);
14360       }
14361     }
14362     turtle(contextptr).s=gen2string(g);
14363     return update_turtle_state(false,contextptr);
14364   }
14365   static const char _ecris_s []="ecris";
14366   static define_unary_function_eval2 (__ecris,&_ecris,_ecris_s,&printastifunction);
14367   define_unary_function_ptr5( at_ecris ,alias_at_ecris,&__ecris,0,T_LOGO);
14368 
_signe(const gen & g,GIAC_CONTEXT)14369   gen _signe(const gen & g,GIAC_CONTEXT){
14370     if ( g.type==_STRNG && g.subtype==-1) return  g;
14371     // logo instruction
14372     return _ecris(makevecteur(g,20,10,10),contextptr);
14373   }
14374   static const char _signe_s []="signe";
14375   static define_unary_function_eval2 (__signe,&_signe,_signe_s,&printastifunction);
14376   define_unary_function_ptr5( at_signe ,alias_at_signe,&__signe,0,T_LOGO);
14377 
_saute(const gen & g,GIAC_CONTEXT)14378   gen _saute(const gen & g,GIAC_CONTEXT){
14379     if ( g.type==_STRNG && g.subtype==-1) return  g;
14380     _leve_crayon(0,contextptr);
14381     _avance(g,contextptr);
14382     return _baisse_crayon(0,contextptr);
14383   }
14384   static const char _saute_s []="saute";
14385   static define_unary_function_eval2 (__saute,&_saute,_saute_s,&printastifunction);
14386   define_unary_function_ptr5( at_saute ,alias_at_saute,&__saute,0,T_LOGO);
14387 
14388   static const char _jump_s []="jump";
14389   static define_unary_function_eval2 (__jump,&_saute,_jump_s,&printastifunction);
14390   define_unary_function_ptr5( at_jump ,alias_at_jump,&__jump,0,T_LOGO);
14391 
_pas_de_cote(const gen & g,GIAC_CONTEXT)14392   gen _pas_de_cote(const gen & g,GIAC_CONTEXT){
14393     if ( g.type==_STRNG && g.subtype==-1) return  g;
14394     _leve_crayon(0,contextptr);
14395     _tourne_droite(-90,contextptr);
14396     _avance(g,contextptr);
14397     _tourne_droite(90,contextptr);
14398     return _baisse_crayon(0,contextptr);
14399   }
14400   static const char _pas_de_cote_s []="pas_de_cote";
14401   static define_unary_function_eval2 (__pas_de_cote,&_pas_de_cote,_pas_de_cote_s,&printastifunction);
14402   define_unary_function_ptr5( at_pas_de_cote ,alias_at_pas_de_cote,&__pas_de_cote,0,T_LOGO);
14403 
14404   static const char _skip_s []="skip";
14405   static define_unary_function_eval2 (__skip,&_pas_de_cote,_skip_s,&printastifunction);
14406   define_unary_function_ptr5( at_skip ,alias_at_skip,&__skip,0,T_LOGO);
14407 
_cache_tortue(const gen & g,GIAC_CONTEXT)14408   gen _cache_tortue(const gen & g,GIAC_CONTEXT){
14409     if ( g.type==_STRNG && g.subtype==-1) return  g;
14410     // logo instruction
14411     turtle(contextptr).visible=false;
14412     turtle(contextptr).radius = 0;
14413     return update_turtle_state(true,contextptr);
14414   }
14415   static const char _cache_tortue_s []="cache_tortue";
14416   static define_unary_function_eval2 (__cache_tortue,&_cache_tortue,_cache_tortue_s,&printastifunction);
14417   define_unary_function_ptr5( at_cache_tortue ,alias_at_cache_tortue,&__cache_tortue,0,T_LOGO);
14418 
14419   static const char _hideturtle_s []="hideturtle";
14420   static define_unary_function_eval (__hideturtle,&_cache_tortue,_hideturtle_s);
14421   define_unary_function_ptr5( at_hideturtle ,alias_at_hideturtle,&__hideturtle,0,true);
14422 
_montre_tortue(const gen & g,GIAC_CONTEXT)14423   gen _montre_tortue(const gen & g,GIAC_CONTEXT){
14424     if ( g.type==_STRNG && g.subtype==-1) return  g;
14425     // logo instruction
14426     turtle(contextptr).visible=true;
14427     turtle(contextptr).radius = 0;
14428     return update_turtle_state(true,contextptr);
14429   }
14430   static const char _montre_tortue_s []="montre_tortue";
14431   static define_unary_function_eval2 (__montre_tortue,&_montre_tortue,_montre_tortue_s,&printastifunction);
14432   define_unary_function_ptr5( at_montre_tortue ,alias_at_montre_tortue,&__montre_tortue,0,T_LOGO);
14433 
14434   static const char _showturtle_s []="showturtle";
14435   static define_unary_function_eval (__showturtle,&_montre_tortue,_showturtle_s);
14436   define_unary_function_ptr5( at_showturtle ,alias_at_showturtle,&__showturtle,0,true);
14437 
_debut_enregistrement(const gen & g0,GIAC_CONTEXT)14438   gen _debut_enregistrement(const gen & g0,GIAC_CONTEXT){
14439     if ( g0.type==_STRNG && g0.subtype==-1) return  g0;
14440     gen g(g0);
14441     // logo instruction
14442     int nmax=10,n=0;
14443     for (;n<nmax && g.type!=_SYMB && g.type!=_IDNT;n++){
14444       g=__input.op(gen(makevecteur(string2gen(gettext("Give a name to the procedure, e.g. test"),false),identificateur(" logo_record_name")),_SEQ__VECT),contextptr);
14445       if (g.type==_VECT && g._VECTptr->size()==2)
14446 	g=g._VECTptr->back();
14447     }
14448     if (g.type!=_SYMB && g.type!=_IDNT)
14449       return gensizeerr(gettext("Give a name to thr procedure, e.g. \"test\""));
14450     return g;
14451   }
14452   static const char _debut_enregistrement_s []="debut_enregistrement";
14453   static define_unary_function_eval2 (__debut_enregistrement,&_debut_enregistrement,_debut_enregistrement_s,&printastifunction);
14454   define_unary_function_ptr5( at_debut_enregistrement ,alias_at_debut_enregistrement,&__debut_enregistrement,0,T_LOGO);
14455 
14456 #if !defined GIAC_HAS_STO_38 && !defined NSPIRE && !defined FXCG && !defined POCKETCAS
_fin_enregistrement(const gen & g0,GIAC_CONTEXT)14457   gen _fin_enregistrement(const gen & g0,GIAC_CONTEXT){
14458     if ( g0.type==_STRNG && g0.subtype==-1) return  g0;
14459     gen g(g0);
14460     // logo instruction
14461     int nmax=10,n=0;
14462     for (;n<nmax && g.type!=_STRNG;n++){
14463       g=__input.op(gen(makevecteur(string2gen("Give a filename, e.g. \"test\"",false),identificateur(" logo_file_name")),_SEQ__VECT),contextptr);
14464       if (g.type==_VECT && g._VECTptr->size()==2)
14465 	g=g._VECTptr->back();
14466     }
14467     if (g.type!=_STRNG)
14468       return gensizeerr(gettext("Give a filename, e.g. \"test\""));
14469     // Search for debut_enregistrement in history_out(contextptr)
14470     int s=int(history_in(contextptr).size()),i;
14471     for (i=s-1;i>=0;--i){
14472       if (history_in(contextptr)[i].is_symb_of_sommet(at_debut_enregistrement))
14473 	break;
14474     }
14475     if (i<0)
14476       return gensizeerr(gettext("Instruction debut_enregistrement not found"));
14477     ofstream of(g._STRNGptr->c_str());
14478     if (i<int(history_out(contextptr).size()))
14479       of << history_out(contextptr)[i] << "():={" << '\n';
14480     else
14481       of << history_in(contextptr)[i]._SYMBptr->feuille << "():={" << '\n';
14482     for (++i;i<s-1;++i)
14483       of << " " << history_in(contextptr)[i] << ";" << '\n';
14484     of << "}" << '\n';
14485     return _read(g,contextptr);
14486   }
14487   static const char _fin_enregistrement_s []="fin_enregistrement";
14488   static define_unary_function_eval2 (__fin_enregistrement,&_fin_enregistrement,_fin_enregistrement_s,&printastifunction);
14489   define_unary_function_ptr5( at_fin_enregistrement ,alias_at_fin_enregistrement,&__fin_enregistrement,0,T_LOGO);
14490 #endif
14491 
_repete(const gen & g,GIAC_CONTEXT)14492   gen _repete(const gen & g,GIAC_CONTEXT){
14493     if ( g.type==_STRNG && g.subtype==-1) return  g;
14494     if (g.type!=_VECT || g._VECTptr->size()<2)
14495       return gensizeerr(contextptr);
14496     // logo instruction
14497     vecteur v = *g._VECTptr;
14498     v[0]=eval(v[0],contextptr);
14499     if (v.front().type!=_INT_)
14500       return gentypeerr(contextptr);
14501     gen prog=vecteur(v.begin()+1,v.end());
14502     int i=absint(v.front().val);
14503     gen res;
14504     for (int j=0;j<i;++j){
14505       res=eval(prog,contextptr);
14506     }
14507     return res;
14508   }
14509   static const char _repete_s []="repete";
14510   static define_unary_function_eval2_quoted (__repete,&_repete,_repete_s,&printastifunction);
14511   define_unary_function_ptr5( at_repete ,alias_at_repete,&__repete,_QUOTE_ARGUMENTS,T_RETURN);
14512 
_crayon(const gen & g,GIAC_CONTEXT)14513   gen _crayon(const gen & g,GIAC_CONTEXT){
14514     if ( g.type==_STRNG && g.subtype==-1) return  g;
14515     if (g.type==_STRNG) return _crayon(gen(*g._STRNGptr,contextptr),contextptr);
14516     if (g.type==_VECT && g._VECTptr->size()==3)
14517       return _crayon(_rgb(g,contextptr),contextptr);
14518     // logo instruction
14519     if (g.type!=_INT_){
14520       gen res=turtle(contextptr).color;
14521       res.subtype=_INT_COLOR;
14522       return res;
14523     }
14524     turtle(contextptr).color=g.val;
14525     turtle(contextptr).radius = 0;
14526     return update_turtle_state(true,contextptr);
14527   }
14528   static const char _crayon_s []="crayon";
14529   static define_unary_function_eval2 (__crayon,&_crayon,_crayon_s,&printastifunction);
14530   define_unary_function_ptr5( at_crayon ,alias_at_crayon,&__crayon,0,T_LOGO);
14531 
14532   static const char _pencolor_s []="pencolor";
14533   static define_unary_function_eval (__pencolor,&_crayon,_pencolor_s);
14534   define_unary_function_ptr5( at_pencolor ,alias_at_pencolor,&__pencolor,0,T_LOGO);
14535 
14536 
_efface(const gen & g,GIAC_CONTEXT)14537   gen _efface(const gen & g,GIAC_CONTEXT){
14538     if ( g.type==_STRNG && g.subtype==-1) return  g;
14539     if (g.type==_INT_){
14540       _crayon(int(FL_WHITE),contextptr);
14541       _recule(g,contextptr);
14542       return _crayon(0,contextptr);
14543     }
14544     // logo instruction
14545     turtle(contextptr) = logo_turtle();
14546     turtle_stack(contextptr).clear();
14547     if (g.type==_VECT && g._VECTptr->size()==2){
14548       vecteur v = *g._VECTptr;
14549       int s=int(v.size());
14550       v[0]=evalf_double(v[0],1,contextptr);
14551       if (s>1)
14552 	v[1]=evalf_double(v[1],1,contextptr);
14553       turtle(contextptr).mark = false;
14554       turtle(contextptr).radius = 0;
14555       update_turtle_state(true,contextptr);
14556       set_turtle_state(v,contextptr); // baisse_crayon
14557       update_turtle_state(true,contextptr);
14558       turtle(contextptr).mark = true;
14559       turtle(contextptr).radius = 0;
14560     }
14561     return update_turtle_state(true,contextptr);
14562   }
14563   static const char _efface_s []="efface";
14564   static define_unary_function_eval2 (__efface,&_efface,_efface_s,&printastifunction);
14565   define_unary_function_ptr5( at_efface ,alias_at_efface,&__efface,0,T_LOGO);
14566 
14567   static const char _clearscreen_s []="clearscreen";
14568   static define_unary_function_eval2 (__clearscreen,&_efface,_clearscreen_s,&printastifunction);
14569   define_unary_function_ptr5( at_clearscreen ,alias_at_clearscreen,&__clearscreen,0,T_LOGO);
14570 
_vers(const gen & g,GIAC_CONTEXT)14571   gen _vers(const gen & g,GIAC_CONTEXT){
14572     if ( g.type==_STRNG && g.subtype==-1) return  g;
14573     // logo instruction
14574     if (g.type!=_VECT || g._VECTptr->size()!=2)
14575       return gensizeerr(contextptr);
14576     gen x=evalf_double(g._VECTptr->front(),1,contextptr),
14577       y=evalf_double(g._VECTptr->back(),1,contextptr);
14578     if (x.type!=_DOUBLE_ || y.type!=_DOUBLE_)
14579       return gensizeerr(contextptr);
14580     double xv=x._DOUBLE_val,yv=y._DOUBLE_val,xt=turtle(contextptr).x,yt=turtle(contextptr).y;
14581     double theta=atan2(yv-yt,xv-xt);
14582     return _cap(theta*180/M_PI,contextptr);
14583   }
14584   static const char _vers_s []="vers";
14585   static define_unary_function_eval2 (__vers,&_vers,_vers_s,&printastifunction);
14586   define_unary_function_ptr5( at_vers ,alias_at_vers,&__vers,0,T_LOGO);
14587 
find_radius(const gen & g,int & r,int & theta2,bool & direct)14588   static int find_radius(const gen & g,int & r,int & theta2,bool & direct){
14589     int radius;
14590     direct=true;
14591     theta2 = 360 ;
14592     // logo instruction
14593     if (g.type==_VECT && !g._VECTptr->empty()){
14594       vecteur v = *g._VECTptr;
14595       bool seg=false;
14596       if (v.back()==at_segment){
14597 	v.pop_back();
14598 	seg=true;
14599       }
14600       if (v.size()<2)
14601 	return RAND_MAX; // setdimerr(contextptr);
14602       if (v[0].type==_INT_)
14603 	r=v[0].val;
14604       else {
14605 	gen v0=evalf_double(v[0],1,context0);
14606 	if (v0.type==_DOUBLE_)
14607 	  r=int(v0._DOUBLE_val+0.5);
14608 	else
14609 	  return RAND_MAX; // setsizeerr(contextptr);
14610       }
14611       if (r<0){
14612 	r=-r;
14613 	direct=false;
14614       }
14615       int theta1;
14616       if (v[1].type==_DOUBLE_)
14617 	theta1=int(v[1]._DOUBLE_val+0.5);
14618       else {
14619 	if (v[1].type==_INT_)
14620 	  theta1=v[1].val;
14621 	else return RAND_MAX; // setsizeerr(contextptr);
14622       }
14623       while (theta1<0)
14624 	theta1 += 360;
14625       if (v.size()>=3){
14626 	if (v[2].type==_DOUBLE_)
14627 	  theta2 = int(v[2]._DOUBLE_val+0.5);
14628 	else {
14629 	  if (v[2].type==_INT_)
14630 	    theta2 = v[2].val;
14631 	  else return RAND_MAX; // setsizeerr(contextptr);
14632 	}
14633 	while (theta2<0)
14634 	  theta2 += 360;
14635 	radius = giacmin(r,512) | (giacmin(theta1,360) << 9) | (giacmin(theta2,360) << 18 ) | (seg?(1<<28):0);
14636       }
14637       else {// angle 1=0
14638 	theta2 = theta1;
14639 	if (theta2<0)
14640 	  theta2 += 360;
14641 	radius = giacmin(r,512) | (giacmin(theta2,360) << 18 ) | (seg?(1<<28):0);
14642       }
14643       return radius;
14644     }
14645     radius = 10;
14646     if (g.type==_INT_)
14647       radius= (r=g.val);
14648     if (g.type==_DOUBLE_)
14649       radius= (r=int(g._DOUBLE_val));
14650     if (radius<=0){
14651       radius = -radius;
14652       direct=false;
14653     }
14654     radius = giacmin(radius,512 )+(360 << 18) ; // 2nd angle = 360 degrees
14655     return radius;
14656   }
14657 
turtle_move(int r,int theta2,GIAC_CONTEXT)14658   static void turtle_move(int r,int theta2,GIAC_CONTEXT){
14659     double theta0;
14660     if (turtle(contextptr).direct)
14661       theta0=turtle(contextptr).theta-90;
14662     else {
14663       theta0=turtle(contextptr).theta+90;
14664       theta2=-theta2;
14665     }
14666     turtle(contextptr).x += r*(std::cos(M_PI/180*(theta2+theta0))-std::cos(M_PI/180*theta0));
14667     turtle(contextptr).y += r*(std::sin(M_PI/180*(theta2+theta0))-std::sin(M_PI/180*theta0));
14668     turtle(contextptr).theta = turtle(contextptr).theta+theta2 ;
14669     if (turtle(contextptr).theta<0)
14670       turtle(contextptr).theta += 360;
14671     if (turtle(contextptr).theta>360)
14672       turtle(contextptr).theta -= 360;
14673   }
14674 
_rond(const gen & g,GIAC_CONTEXT)14675   gen _rond(const gen & g,GIAC_CONTEXT){
14676     if ( g.type==_STRNG && g.subtype==-1) return  g;
14677     int r,theta2,tmpr;
14678     tmpr=find_radius(g,r,theta2,turtle(contextptr).direct);
14679     if (tmpr==RAND_MAX)
14680       return gensizeerr(contextptr);
14681     turtle(contextptr).radius=tmpr;
14682     turtle_move(r,theta2,contextptr);
14683     return update_turtle_state(true,contextptr);
14684   }
14685   static const char _rond_s []="rond";
14686   static define_unary_function_eval2 (__rond,&_rond,_rond_s,&printastifunction);
14687   define_unary_function_ptr5( at_rond ,alias_at_rond,&__rond,0,T_LOGO);
14688 
_disque(const gen & g,GIAC_CONTEXT)14689   gen _disque(const gen & g,GIAC_CONTEXT){
14690     if ( g.type==_STRNG && g.subtype==-1) return  g;
14691     int r,theta2,tmpr=find_radius(g,r,theta2,turtle(contextptr).direct);
14692     if (tmpr==RAND_MAX)
14693       return gensizeerr(contextptr);
14694     turtle(contextptr).radius=tmpr;
14695     turtle_move(r,theta2,contextptr);
14696     turtle(contextptr).radius += 1 << 27;
14697     return update_turtle_state(true,contextptr);
14698   }
14699   static const char _disque_s []="disque";
14700   static define_unary_function_eval2 (__disque,&_disque,_disque_s,&printastifunction);
14701   define_unary_function_ptr5( at_disque ,alias_at_disque,&__disque,0,T_LOGO);
14702 
_disque_centre(const gen & g,GIAC_CONTEXT)14703   gen _disque_centre(const gen & g,GIAC_CONTEXT){
14704     if ( g.type==_STRNG && g.subtype==-1) return  g;
14705     int r,theta2;
14706     bool direct;
14707     int radius=find_radius(g,r,theta2,direct);
14708     if (radius==RAND_MAX)
14709       return gensizeerr(contextptr);
14710     r=absint(r);
14711     _saute(r,contextptr);
14712     _tourne_gauche(direct?90:-90,contextptr);
14713     turtle(contextptr).radius = radius;
14714     turtle(contextptr).direct=direct;
14715     turtle_move(r,theta2,contextptr);
14716     turtle(contextptr).radius += 1 << 27;
14717     update_turtle_state(true,contextptr);
14718     _tourne_droite(direct?90:-90,contextptr);
14719     return _saute(-r,contextptr);
14720   }
14721   static const char _disque_centre_s []="disque_centre";
14722   static define_unary_function_eval2 (__disque_centre,&_disque_centre,_disque_centre_s,&printastifunction);
14723   define_unary_function_ptr5( at_disque_centre ,alias_at_disque_centre,&__disque_centre,0,T_LOGO);
14724 
_polygone_rempli(const gen & g,GIAC_CONTEXT)14725   gen _polygone_rempli(const gen & g,GIAC_CONTEXT){
14726     if ( g.type==_STRNG && g.subtype==-1) return  g;
14727     if (g.type==_INT_){
14728       turtle(contextptr).radius=-absint(g.val);
14729       if (turtle(contextptr).radius<-1)
14730 	return update_turtle_state(true,contextptr);
14731     }
14732     return gensizeerr(gettext("Integer argument >= 2"));
14733   }
14734   static const char _polygone_rempli_s []="polygone_rempli";
14735   static define_unary_function_eval2 (__polygone_rempli,&_polygone_rempli,_polygone_rempli_s,&printastifunction);
14736   define_unary_function_ptr5( at_polygone_rempli ,alias_at_polygone_rempli,&__polygone_rempli,0,T_LOGO);
14737 
_rectangle_plein(const gen & g,GIAC_CONTEXT)14738   gen _rectangle_plein(const gen & g,GIAC_CONTEXT){
14739     if ( g.type==_STRNG && g.subtype==-1) return  g;
14740     gen gx=g,gy=g;
14741     if (g.type==_VECT && g._VECTptr->size()==2){
14742       gx=g._VECTptr->front();
14743       gy=g._VECTptr->back();
14744     }
14745     for (int i=0;i<2;++i){
14746       _avance(gx,contextptr);
14747       _tourne_droite(-90,contextptr);
14748       _avance(gy,contextptr);
14749       _tourne_droite(-90,contextptr);
14750     }
14751     return _polygone_rempli(-8,contextptr);
14752   }
14753   static const char _rectangle_plein_s []="rectangle_plein";
14754   static define_unary_function_eval2 (__rectangle_plein,&_rectangle_plein,_rectangle_plein_s,&printastifunction);
14755   define_unary_function_ptr5( at_rectangle_plein ,alias_at_rectangle_plein,&__rectangle_plein,0,T_LOGO);
14756 
_triangle_plein(const gen & g,GIAC_CONTEXT)14757   gen _triangle_plein(const gen & g,GIAC_CONTEXT){
14758     if ( g.type==_STRNG && g.subtype==-1) return  g;
14759     gen gx=g,gy=g,gtheta=60;
14760     if (g.type==_VECT && g._VECTptr->size()>=2){
14761       vecteur & v=*g._VECTptr;
14762       gx=v.front();
14763       gy=v[1];
14764       gtheta=90;
14765       if (v.size()>2)
14766 	gtheta=v[2];
14767     }
14768     logo_turtle t=turtle(contextptr);
14769     _avance(gx,contextptr);
14770     double save_x=turtle(contextptr).x,save_y=turtle(contextptr).y;
14771     _recule(gx,contextptr);
14772     _tourne_gauche(gtheta,contextptr);
14773     _avance(gy,contextptr);
14774     turtle(contextptr).x=save_x;
14775     turtle(contextptr).y=save_y;
14776     update_turtle_state(true,contextptr);
14777     turtle(contextptr)=t;
14778     turtle(contextptr).radius=0;
14779     update_turtle_state(true,contextptr);
14780     return _polygone_rempli(-3,contextptr);
14781   }
14782   static const char _triangle_plein_s []="triangle_plein";
14783   static define_unary_function_eval2 (__triangle_plein,&_triangle_plein,_triangle_plein_s,&printastifunction);
14784   define_unary_function_ptr5( at_triangle_plein ,alias_at_triangle_plein,&__triangle_plein,0,T_LOGO);
14785 
_dessine_tortue(const gen & g,GIAC_CONTEXT)14786   gen _dessine_tortue(const gen & g,GIAC_CONTEXT){
14787     if ( g.type==_STRNG && g.subtype==-1) return  g;
14788     // logo instruction
14789     /*
14790       _triangle_plein(makevecteur(17,5));
14791       _tourne_droite(90);
14792       _triangle_plein(makevecteur(5,17));
14793       return _tourne_droite(-90);
14794     */
14795     double save_x=turtle(contextptr).x,save_y=turtle(contextptr).y;
14796     _tourne_droite(90,contextptr);
14797     _avance(5,contextptr);
14798     _tourne_gauche(106,contextptr);
14799     _avance(18,contextptr);
14800     _tourne_gauche(148,contextptr);
14801     _avance(18,contextptr);
14802     _tourne_gauche(106,contextptr);
14803     _avance(5,contextptr);
14804     turtle(contextptr).x=save_x; turtle(contextptr).y=save_y;
14805     gen res=_tourne_gauche(90,contextptr);
14806     if (is_one(g))
14807       return res;
14808     return _polygone_rempli(-9,contextptr);
14809   }
14810   static const char _dessine_tortue_s []="dessine_tortue";
14811   static define_unary_function_eval2 (__dessine_tortue,&_dessine_tortue,_dessine_tortue_s,&printastifunction);
14812   define_unary_function_ptr5( at_dessine_tortue ,alias_at_dessine_tortue,&__dessine_tortue,0,T_LOGO);
14813 
_turtle_stack(const gen & g,GIAC_CONTEXT)14814   gen _turtle_stack(const gen & g,GIAC_CONTEXT){
14815     if ( g.type==_STRNG && g.subtype==-1) return  g;
14816     if (g==at_remove) turtle_stack(contextptr).clear();
14817     std::vector<logo_turtle> v=turtle_stack(contextptr);
14818     vecteur res;
14819     for (int i=0;i<int(v.size());++i){
14820       res.push_back(turtle2gen(v[i]));
14821     }
14822     return res;
14823   }
14824   static const char _turtle_stack_s []="turtle_stack";
14825   static define_unary_function_eval2 (__turtle_stack,&_turtle_stack,_turtle_stack_s,&printastifunction);
14826   define_unary_function_ptr5( at_turtle_stack ,alias_at_turtle_stack,&__turtle_stack,0,T_LOGO);
14827 
14828 #endif
14829 #endif  // KHICAS
14830 
14831   static const char _ramene_s []="ramene";
14832   static define_unary_function_eval2 (__ramene,&_read,_ramene_s,&printastifunction);
14833   define_unary_function_ptr5( at_ramene ,alias_at_ramene,&__ramene,0,T_LOGO);
14834 
14835   static const char _sauve_s []="sauve";
14836   static define_unary_function_eval2_quoted (__sauve,&_write,_sauve_s,&printastifunction);
14837   define_unary_function_ptr5( at_sauve ,alias_at_sauve,&__sauve,_QUOTE_ARGUMENTS,T_LOGO);
14838 
14839 
14840   static const char _hasard_s []="hasard";
14841   static define_unary_function_eval2 (__hasard,&_RANDOM,_hasard_s,&printasRANDOM);
14842   define_unary_function_ptr5( at_hasard ,alias_at_hasard,&__hasard,0,T_RETURN);
14843 
14844   /* A FAIRE:
14845      traduction latex
14846   */
_arc(const gen & args,GIAC_CONTEXT)14847   gen _arc(const gen & args,GIAC_CONTEXT){
14848     if ( args.type==_STRNG && args.subtype==-1) return  args;
14849     if (args.type!=_VECT)
14850       return symbolic(at_arc,args);
14851     vecteur v=*args._VECTptr;
14852     bool segment_cercle=false;
14853     for (int i=0;i<int(v.size());++i){
14854       if (v[i]==at_segment){
14855 	segment_cercle=true;
14856 	v.erase(v.begin()+i);
14857       }
14858     }
14859     vecteur attributs(1,default_color(contextptr));
14860     int s=read_attributs(v,attributs,contextptr);
14861     if (s<3)
14862       return gendimerr(contextptr);
14863     gen e=remove_at_pnt(eval(v[0],contextptr));
14864     gen f=remove_at_pnt(eval(v[1],contextptr));
14865     gen g=eval(v[2],contextptr);
14866     gen c,diametre;
14867     if (g.is_symb_of_sommet(at_pnt)){
14868       g=remove_at_pnt(g);
14869       if (est_aligne(e,f,g,contextptr))
14870 	return gensizeerr(gettext("Collinear points"));
14871       gen tmp=_circonscrit(gen(makevecteur(e,f,g),_SEQ__VECT),contextptr),tmp2,r;
14872       centre_rayon(tmp,c,r,false,contextptr);
14873       tmp=arg((f-c)/(e-c),contextptr);
14874       if (is_positive(tmp,contextptr))
14875 	tmp2=tmp-cst_two_pi;
14876       else
14877 	tmp2=tmp+cst_two_pi;
14878       r=arg((g-c)/(e-c),contextptr);
14879       if (is_positive(tmp*r,contextptr)&& is_greater(tmp/r,1,contextptr))
14880 	g=tmp;
14881       else
14882 	g=tmp2;
14883     }
14884     else {
14885       if (evalf_double(g,eval_level(contextptr),contextptr).type!=_DOUBLE_)
14886 	return gensizeerr(contextptr);
14887       c=normal((e+f)/2+cst_i*(f-e)/(2*tan(g/2,contextptr)),contextptr);
14888     }
14889     gen res;
14890     if (segment_cercle){
14891       //gen t(identificateur("t_arc"));
14892       //res=_plotparam(makesequence(c+(e-c)*exp(cst_i*t,contextptr),t,0,g),contextptr);
14893       vecteur v;
14894       gen ec=e-c;
14895       for (int i=0;i<=50;i++){
14896 	v.push_back(c+ec*exp(cst_i*g*gen(i/50.0),contextptr));
14897       }
14898       v.push_back(v.front());
14899       polygonify(v,contextptr);
14900       res=pnt_attrib(gen(v,_GROUP__VECT),attributs,contextptr);
14901     }
14902     else {
14903       diametre=gen(makevecteur(2*c-e,e),_GROUP__VECT);
14904       res=pnt_attrib(symbolic(at_cercle,gen((s==4 && v[3].type<_IDNT)?makevecteur(diametre,zero,g,v[3]):makevecteur(diametre,zero,g),_PNT__VECT)),attributs,contextptr);
14905     }
14906     gen h=abs_norm(c-e,contextptr);
14907     if (s==3 || v[3].type<_IDNT)
14908       return res;
14909     vecteur w(1,res);
14910     w.push_back(eval(symb_sto(_point(c,contextptr),v[3]),contextptr));
14911     if (s>4)
14912       eval(symb_sto(h,v[4]),contextptr);
14913     return gen(w,_GROUP__VECT);
14914   }
14915   static const char _arc_s []="arc";
14916   static define_unary_function_eval_quoted (__arc,&_arc,_arc_s);
14917   define_unary_function_ptr5( at_arc ,alias_at_arc,&__arc,_QUOTE_ARGUMENTS,true);
14918 
_est(const gen & args,const propriete & f,GIAC_CONTEXT)14919   gen _est(const gen & args,const propriete & f,GIAC_CONTEXT){
14920     if ( args.type==_STRNG && args.subtype==-1) return  args;
14921     if (args.type!=_SYMB)
14922       return zero;
14923     gen g=args._SYMBptr->feuille;
14924     if (g.type==_VECT){
14925       vecteur v=*g._VECTptr;
14926       if (!v.empty()){
14927 	g=v.front();
14928 	if (g.type==_VECT){
14929 	  v=*g._VECTptr;
14930 	  if (!v.empty() && v.front()==v.back()){
14931 	    v.pop_back();
14932 	    return f(gen(v,_SEQ__VECT),contextptr);
14933 	  }
14934 	}
14935       }
14936     }
14937     return zero;
14938   }
14939 
est_rect(const gen & a,const gen & b,const gen & c,const gen & d,GIAC_CONTEXT)14940   int est_rect(const gen & a,const gen & b,const gen & c,const gen & d,GIAC_CONTEXT){
14941     gen e(a-b+c-d);
14942     gen f(dotvecteur(d-a,b-a,contextptr));
14943     if (is_zero(simplify(e,contextptr),contextptr) && is_zero(simplify(f,contextptr),contextptr)) {
14944       gen g(abs_norm2(a-b,contextptr));
14945       gen gg(abs_norm2(a-d,contextptr));
14946       if (is_zero(simplify(g-gg,contextptr),contextptr))
14947 	return 2;
14948       return 1;
14949     }
14950     return 0;
14951   }
14952 
est_losange(const gen & a,const gen & b,const gen & c,const gen & d,GIAC_CONTEXT)14953   int est_losange(const gen & a,const gen & b,const gen & c,const gen & d,GIAC_CONTEXT){
14954     gen e(a-b+c-d);
14955     gen f(dotvecteur(d-b,c-a,contextptr));
14956     if (is_zero(simplify(e,contextptr),contextptr) && is_zero(simplify(f,contextptr),contextptr)) {
14957       if (is_zero(simplify(dotvecteur(d-a,b-a,contextptr),contextptr),contextptr))
14958 	return 2;
14959       return 1;
14960     }
14961     return 0;
14962   }
14963 
est_parallelogramme(const gen & a,const gen & b,const gen & c,const gen & d,GIAC_CONTEXT)14964   int est_parallelogramme(const gen & a,const gen & b,const gen & c,const gen & d,GIAC_CONTEXT){
14965     gen e(a-b+c-d);
14966     if (is_zero(simplify(e,contextptr),contextptr)) {
14967       gen g(dotvecteur(d-b,c-a,contextptr));
14968       gen h(dotvecteur(d-a,b-a,contextptr));
14969       if (is_zero(simplify(g,contextptr),contextptr)){
14970 	if (is_zero(simplify(h,contextptr),contextptr))
14971 	  return 4;
14972 	return 2;
14973       }
14974       if (is_zero(simplify(h,contextptr),contextptr)) return 3;
14975       return 1;
14976     }
14977     return 0;
14978   }
14979 
est_carre(const gen & a,const gen & b,const gen & c,const gen & d,GIAC_CONTEXT)14980   bool est_carre(const gen & a,const gen & b,const gen & c,const gen & d,GIAC_CONTEXT){
14981     gen e(a-b+c-d);
14982     gen g(dotvecteur(d-b,c-a,contextptr));
14983     gen h(dotvecteur(d-a,b-a,contextptr));
14984     return is_zero(simplify(e,contextptr),contextptr) && is_zero(simplify(g,contextptr),contextptr) && is_zero(simplify(h,contextptr),contextptr);
14985   }
14986 
est_isocele(const gen & a,const gen & b,const gen & c,GIAC_CONTEXT)14987   int est_isocele(const gen & a,const gen & b,const gen & c,GIAC_CONTEXT){
14988     gen d(abs_norm2(b-a,contextptr));
14989     gen f(abs_norm2(c-a,contextptr));
14990     gen e(abs_norm2(b-c,contextptr));
14991     bool de=is_zero(simplify(d-e,contextptr),contextptr);
14992     bool ef=is_zero(simplify(f-e,contextptr),contextptr);
14993     bool fd=is_zero(simplify(f-d,contextptr),contextptr);
14994     if (de && ef && fd)
14995       return 4;
14996     if (ef)
14997       return 3;
14998     if (fd)
14999       return 1;
15000     if (de)
15001       return 2;
15002     return 0;
15003   }
15004 
est_equilateral(const gen & a,const gen & b,const gen & c,GIAC_CONTEXT)15005   bool est_equilateral(const gen & a,const gen & b,const gen & c,GIAC_CONTEXT){
15006     gen d(abs_norm2(b-a,contextptr));
15007     gen f(abs_norm2(c-a,contextptr));
15008     gen e(abs_norm2(b-c,contextptr));
15009     return is_zero(simplify(d-f,contextptr),contextptr) && is_zero(simplify(e-f,contextptr),contextptr);
15010   }
15011 
est_trianglerect(const gen & a,const gen & b,const gen & c,GIAC_CONTEXT)15012   int est_trianglerect(const gen & a,const gen & b,const gen & c,GIAC_CONTEXT){
15013     gen d(dotvecteur(c-a,b-a,contextptr));
15014     gen e(dotvecteur(a-c,b-c,contextptr));
15015     gen f(dotvecteur(a-b,c-b,contextptr));
15016     if (is_zero(simplify(d,contextptr),contextptr))
15017       return 1;
15018     if (is_zero(simplify(e,contextptr),contextptr))
15019       return 3;
15020     if (is_zero(simplify(f,contextptr),contextptr))
15021       return 2;
15022     return 0;
15023   }
15024 
_est_isocele(const gen & args,GIAC_CONTEXT)15025   gen _est_isocele(const gen & args,GIAC_CONTEXT){
15026     if ( args.type==_STRNG && args.subtype==-1) return  args;
15027     if (args.is_symb_of_sommet(at_pnt))
15028       return _est(args,_est_isocele,contextptr);
15029     vecteur v=sommet(args);
15030     if (v.size()==3){
15031       return est_isocele(remove_at_pnt(v[0]),remove_at_pnt(v[1]),remove_at_pnt(v[2]),contextptr);
15032     }
15033     return symbolic(at_est_isocele,args);
15034   }
15035   static const char _est_isocele_s []="is_isosceles";
15036   static define_unary_function_eval (__est_isocele,&_est_isocele,_est_isocele_s);
15037   define_unary_function_ptr5( at_est_isocele ,alias_at_est_isocele,&__est_isocele,0,true);
15038 
_est_equilateral(const gen & args,GIAC_CONTEXT)15039   gen _est_equilateral(const gen & args,GIAC_CONTEXT){
15040     if ( args.type==_STRNG && args.subtype==-1) return  args;
15041     if (args.is_symb_of_sommet(at_pnt))
15042       return _est(args,_est_equilateral,contextptr);
15043     vecteur v=sommet(args);
15044     if (v.size()==3){
15045       return est_equilateral(remove_at_pnt(v[0]),remove_at_pnt(v[1]),remove_at_pnt(v[2]),contextptr);
15046     }
15047     return symbolic(at_est_equilateral,args);
15048   }
15049   static const char _est_equilateral_s []="is_equilateral";
15050   static define_unary_function_eval (__est_equilateral,&_est_equilateral,_est_equilateral_s);
15051   define_unary_function_ptr5( at_est_equilateral ,alias_at_est_equilateral,&__est_equilateral,0,true);
15052 
_est_parallelogramme(const gen & args,GIAC_CONTEXT)15053   gen _est_parallelogramme(const gen & args,GIAC_CONTEXT){
15054     if ( args.type==_STRNG && args.subtype==-1) return  args;
15055     if (args.is_symb_of_sommet(at_pnt))
15056       return _est(args,_est_parallelogramme,contextptr);
15057     vecteur v=sommet(args);
15058     if (v.size()==4){
15059       return est_parallelogramme(remove_at_pnt(v[0]),remove_at_pnt(v[1]),remove_at_pnt(v[2]),remove_at_pnt(v[3]),contextptr);
15060     }
15061     return symbolic(at_est_parallelogramme,args);
15062   }
15063   static const char _est_parallelogramme_s []="is_parallelogram";
15064   static define_unary_function_eval (__est_parallelogramme,&_est_parallelogramme,_est_parallelogramme_s);
15065   define_unary_function_ptr5( at_est_parallelogramme ,alias_at_est_parallelogramme,&__est_parallelogramme,0,true);
15066 
_est_carre(const gen & args,GIAC_CONTEXT)15067   gen _est_carre(const gen & args,GIAC_CONTEXT){
15068     if ( args.type==_STRNG && args.subtype==-1) return  args;
15069     if (args.is_symb_of_sommet(at_pnt))
15070       return _est(args,_est_carre,contextptr);
15071     vecteur v=sommet(args);
15072     if (v.size()==4){
15073       return est_carre(remove_at_pnt(v[0]),remove_at_pnt(v[1]),remove_at_pnt(v[2]),remove_at_pnt(v[3]),contextptr);
15074     }
15075     return symbolic(at_est_carre,args);
15076   }
15077   static const char _est_carre_s []="is_square";
15078   static define_unary_function_eval (__est_carre,&_est_carre,_est_carre_s);
15079   define_unary_function_ptr5( at_est_carre ,alias_at_est_carre,&__est_carre,0,true);
15080 
_est_losange(const gen & args,GIAC_CONTEXT)15081   gen _est_losange(const gen & args,GIAC_CONTEXT){
15082     if ( args.type==_STRNG && args.subtype==-1) return  args;
15083     if (args.is_symb_of_sommet(at_pnt))
15084       return _est(args,_est_losange,contextptr);
15085     vecteur v=sommet(args);
15086     if (v.back()==v.front())
15087       v.pop_back();
15088     if (v.size()==4){
15089       return est_losange(remove_at_pnt(v[0]),remove_at_pnt(v[1]),remove_at_pnt(v[2]),remove_at_pnt(v[3]),contextptr);
15090     }
15091     return symbolic(at_est_losange,args);
15092   }
15093   static const char _est_losange_s []="is_rhombus";
15094   static define_unary_function_eval (__est_losange,&_est_losange,_est_losange_s);
15095   define_unary_function_ptr5( at_est_losange ,alias_at_est_losange,&__est_losange,0,true);
15096 
_est_rectangle(const gen & args,GIAC_CONTEXT)15097   gen _est_rectangle(const gen & args,GIAC_CONTEXT){
15098     if ( args.type==_STRNG && args.subtype==-1) return  args;
15099     if (args.is_symb_of_sommet(at_pnt))
15100       return _est(args,_est_rectangle,contextptr);
15101     vecteur v=sommet(args);
15102     if (v.back()==v.front())
15103       v.pop_back();
15104     if (v.size()==3){
15105       return est_trianglerect(remove_at_pnt(v[0]),remove_at_pnt(v[1]),remove_at_pnt(v[2]),contextptr);
15106     }
15107     if (v.size()==4){
15108       return est_rect(remove_at_pnt(v[0]),remove_at_pnt(v[1]),remove_at_pnt(v[2]),remove_at_pnt(v[3]),contextptr);
15109     }
15110     return symbolic(at_est_rectangle,args);
15111   }
15112   static const char _est_rectangle_s []="is_rectangle";
15113   static define_unary_function_eval (__est_rectangle,&_est_rectangle,_est_rectangle_s);
15114   define_unary_function_ptr5( at_est_rectangle ,alias_at_est_rectangle,&__est_rectangle,0,true);
15115 
is_pnt_or_pixon(const gen & g)15116   bool is_pnt_or_pixon(const gen & g){
15117     if (g.type!=_SYMB) return false;
15118     return g._SYMBptr->sommet==at_pnt || g._SYMBptr->sommet==at_pixon;
15119   }
15120 
_is_3dpoint(const gen & args,GIAC_CONTEXT)15121   gen _is_3dpoint(const gen & args,GIAC_CONTEXT){
15122     if ( args.type==_STRNG && args.subtype==-1) return  args;
15123     gen g=remove_at_pnt(args);
15124     g=(g.type==_VECT && g.subtype==_POINT__VECT && g._VECTptr->size()==3)?1:0;
15125     g.subtype=_INT_BOOLEAN;
15126     return g;
15127   }
15128   static const char _is_3dpoint_s []="is_3dpoint";
15129   static define_unary_function_eval (__is_3dpoint,&_is_3dpoint,_is_3dpoint_s);
15130   define_unary_function_ptr5( at_is_3dpoint ,alias_at_is_3dpoint,&__is_3dpoint,0,true);
15131 
15132   //=(c-a)*(d-b)/((c-b)*(d-a))= birapport de 4 complexes ou points a,b,c,d
_birapport(const gen & args,GIAC_CONTEXT)15133   gen _birapport(const gen & args,GIAC_CONTEXT){
15134     if ( args.type==_STRNG && args.subtype==-1) return  args;
15135     if ((args.type==_VECT) && (args._VECTptr->size()==4)){
15136       vecteur v(*args._VECTptr);
15137       gen a(remove_at_pnt(v[0])),b(remove_at_pnt(v[1])),c(remove_at_pnt(v[2])),d(remove_at_pnt(v[3]));
15138       gen res =normal((c-a)*(d-b)/((c-b)*(d-a)),contextptr);
15139       return normal(res,contextptr);
15140     }
15141     return symbolic(at_birapport,args);
15142   }
15143   static const char _birapport_s []="cross_ratio";
15144   static define_unary_function_eval (__birapport,&_birapport,_birapport_s);
15145   define_unary_function_ptr5( at_birapport ,alias_at_birapport,&__birapport,0,true);
15146   //puissance d'1 point A/ cercle C=d2-R2 (d=distance de A au centre(C))
15147   //parametre C,point ou para du cercle et point
_puissance(const gen & args,GIAC_CONTEXT)15148   gen _puissance(const gen & args,GIAC_CONTEXT){
15149     if ( args.type==_STRNG && args.subtype==-1) return  args;
15150     if (args.type==_VECT) {
15151       vecteur v(*args._VECTptr);
15152       gen a,C;
15153       if (args._VECTptr->size()==3){
15154 	C=_cercle(makevecteur(v[0],v[1]),contextptr);
15155 	if (is_undef(C)) return C;
15156 	a=remove_at_pnt(v[2]);
15157       }
15158       else {
15159 	if (args._VECTptr->size()==2){
15160 	  C=v[0];
15161 	  a=remove_at_pnt(v[1]);
15162 	}
15163 	else
15164 	  return gensizeerr(contextptr);
15165       }
15166       gen c,R;
15167       if (!centre_rayon(C,c,R,false,contextptr))
15168 	return gensizeerr(contextptr);
15169       gen res =ratnormal(abs_norm2(c-a,contextptr)-abs_norm2(R,contextptr),contextptr);
15170       return normal(res,contextptr);
15171     }
15172     return symbolic(at_puissance,args);
15173     //return gensizeerr(contextptr);
15174   }
15175   static const char _puissance_s []="powerpc";
15176   static define_unary_function_eval (__puissance,&_puissance,_puissance_s);
15177   define_unary_function_ptr5( at_puissance ,alias_at_puissance,&__puissance,0,true);
15178 
15179   //axe radical de 2 cercles
15180   //parametres 2 cercles ou 4 parametres=param des 2 cercles
_axe_radical(const gen & args,GIAC_CONTEXT)15181   gen _axe_radical(const gen & args,GIAC_CONTEXT){
15182     if ( args.type==_STRNG && args.subtype==-1) return  args;
15183     if (args.type==_VECT) {
15184       vecteur v(*args._VECTptr);
15185       gen C1,C2;
15186       if (args._VECTptr->size()==4){
15187 	C1=_cercle(makesequence(v[0],v[1]),contextptr);
15188 	C2=_cercle(makesequence(v[2],v[3]),contextptr);
15189       }
15190       else {
15191 	if (args._VECTptr->size()==2){
15192 	  C1=v[0];
15193 	  C2=v[1];
15194 	}
15195 	else
15196 	  return gensizeerr(contextptr);
15197       }
15198       if (is_undef(C1)) return C1;
15199       if (is_undef(C2)) return C2;
15200       gen c1,c2,R1,R2;
15201       if (!centre_rayon(C1,c1,R1,false,contextptr) ||
15202 	  !centre_rayon(C2,c2,R2,false,contextptr) )
15203 	return gensizeerr(contextptr);
15204       if (is_zero(c1-c2,contextptr))
15205 	return gensizeerr(gettext("Circle centers are identical"));
15206       gen k =ratnormal((abs_norm2(R1,contextptr)-abs_norm2(R2,contextptr))/abs_norm2(c1-c2,contextptr),contextptr);
15207       gen H=ratnormal((c1+c2+k*(c2-c1))/2,contextptr);
15208       gen K=ratnormal(H+cst_i*(c2-c1),contextptr); // FIXME 3-d
15209       return _droite(makesequence(normal(H,contextptr),normal(K,contextptr)),contextptr);
15210     }
15211     return symbolic(at_axe_radical,args);
15212     //return gensizeerr(contextptr);
15213   }
15214   static const char _axe_radical_s []="radical_axis";
15215   static define_unary_function_eval (__axe_radical,&_axe_radical,_axe_radical_s);
15216   define_unary_function_ptr5( at_axe_radical ,alias_at_axe_radical,&__axe_radical,0,true);
15217 
equation_homogene(const gen & eq,GIAC_CONTEXT)15218   gen equation_homogene(const gen & eq,GIAC_CONTEXT){
15219     vecteur v(1,makevecteur(x__IDNT_e,y__IDNT_e,z__IDNT_e));
15220     alg_lvar(eq,v);
15221     gen v0=v.front();
15222     if (v0.type!=_VECT || v0._VECTptr->size()<3 || v0[0]!=x__IDNT_e || v0[1]!=y__IDNT_e || v0[2]!=z__IDNT_e)
15223       return gensizeerr(contextptr);
15224     // check that nothing else depends on x/y
15225     if (!is_zero(derive(v,x__IDNT_e,2,contextptr),contextptr) ||
15226 	!is_zero(derive(v,y__IDNT_e,2,contextptr),contextptr) )
15227       return gensizeerr(contextptr);
15228     // homogeneize
15229     fraction feq(e2r(eq,v,contextptr));
15230     if (feq.num.type!=_POLY)
15231       return gensizeerr(contextptr);
15232     polynome p=*feq.num._POLYptr;
15233     // find total degree in x and y
15234     vector< monomial<gen> >::iterator it=p.coord.begin(),itend=p.coord.end();
15235     int xydeg=0,tmp;
15236     for (;it!=itend;++it){
15237       tmp=it->index[0]+it->index[1];
15238       if (tmp>xydeg)
15239 	xydeg=tmp;
15240     }
15241     // adjust z degree
15242     for (it=p.coord.begin();it!=itend;++it){
15243       tmp=it->index[0]+it->index[1];
15244       if (tmp<xydeg)
15245 	it->index[2]=xydeg-tmp; // note: in-place modif
15246     }
15247     return r2e(p,v,contextptr);
15248   }
15249 
15250   //renvoie une droite=la polaire d'un point A/ cercle C
15251   //parametres C,A ou param du cercle et A
_polaire(const gen & args,GIAC_CONTEXT)15252   gen _polaire(const gen & args,GIAC_CONTEXT){
15253     if ( args.type==_STRNG && args.subtype==-1) return  args;
15254     if (args.type==_VECT) {
15255       vecteur v(*args._VECTptr);
15256       gen C,a;
15257       if (args._VECTptr->size()==3){
15258 	gen b0=v[0], b1=v[1];
15259 	if  ((b0.type!=_VECT)&& (b1.type!=_VECT)){
15260 	  C=_cercle(makesequence(b0,b1),contextptr);
15261 	  if (is_undef(C)) return C;
15262 	  a=remove_at_pnt(v[2]);
15263 	}
15264 	else
15265 	  return gensizeerr(contextptr);
15266       }
15267       else {
15268 	if (args._VECTptr->size()==2){
15269 	  C=v[0];
15270 	  a=remove_at_pnt(v[1]);
15271 	}
15272 	else
15273 	  return gensizeerr(contextptr);
15274       }
15275       if (a.is_symb_of_sommet(at_cercle) || a.is_symb_of_sommet(at_curve))
15276 	return gensizeerr(contextptr);
15277       gen c,R,a1,a2,p1,p2;
15278       if (!centre_rayon(C,c,R,false,contextptr)){
15279 	gen eq=_equation(C,contextptr);
15280 	if (is_undef(eq)) return eq;
15281 	eq=equation_homogene(eq,contextptr);
15282 	if (is_undef(eq)) return eq;
15283 	gen x0=re(a,contextptr);
15284 	gen y0=im(a,contextptr);
15285 	// result is
15286 	// D:=x0*diff(p(x,y,z),x)+y0*diff(p(x,y,z),y)+1*diff(p(x,y,z),z)
15287 	gen res=x0*derive(eq,x__IDNT_e,contextptr)+y0*derive(eq,y__IDNT_e,contextptr)+derive(eq,z__IDNT_e,contextptr);
15288 	if (is_undef(res))
15289 	  return res;
15290 	return _droite(recursive_normal(subst(res,z__IDNT_e,1,false,contextptr),contextptr),contextptr);
15291       }
15292       a1=re(a-c,contextptr);
15293       a2=im(a-c,contextptr);
15294       if (a1==0 && a2==0) return gensizeerr(contextptr);
15295       if (a1==0){
15296 	p1=c+cst_i*(R*conj(R,contextptr))/a2;
15297 	p2=1+c+cst_i*(R*conj(R,contextptr))/a2;
15298 	return _droite(makesequence(normal(p1,contextptr),normal(p2,contextptr)),contextptr);
15299       }
15300       if (a2==0){
15301 	p1=c+(R*conj(R,contextptr))/a1;
15302 	p2=c+cst_i+(R*conj(R,contextptr))/a1;
15303 	return _droite(makesequence(normal(p1,contextptr),normal(p2,contextptr)),contextptr);
15304       }
15305       p1=c+(R*conj(R,contextptr))/a1;
15306       p2=c+cst_i*(R*conj(R,contextptr))/a2;
15307       return _droite(makesequence(normal(p1,contextptr),normal(p2,contextptr)),contextptr);
15308     }
15309     return change_subtype(_coordonnees_polaires(args,contextptr),_SEQ__VECT);//return symbolic(at_polaire,args);
15310     //return gensizeerr(contextptr);
15311   }
15312 
15313   static const char _polaire_s []="polar";
15314   static define_unary_function_eval (__polaire,&_polaire,_polaire_s);
15315   define_unary_function_ptr5( at_polaire ,alias_at_polaire,&__polaire,0,true);
15316 
15317   //renvoie un point= le pole d'une droite D par rapport a un cercle C
15318   //parametres C,D
_pole(const gen & args,GIAC_CONTEXT)15319   gen _pole(const gen & args,GIAC_CONTEXT){
15320     if ( args.type==_STRNG && args.subtype==-1) return  args;
15321     if (args.type==_VECT) {
15322       vecteur v(*args._VECTptr);
15323       gen D,C;
15324       if (args._VECTptr->size()==3){
15325 	C=_cercle(makesequence(v[0],v[1]),contextptr);
15326 	if (is_undef(C)) return C;
15327 	D=remove_at_pnt(v[2]);
15328       }
15329       else {
15330 	if (args._VECTptr->size()==2){
15331 	  C=v[0];
15332 	  D=remove_at_pnt(v[1]);
15333 	}
15334 	else
15335 	  return gensizeerr(contextptr);
15336       }
15337       gen c,R,A1,A2,a1,a2,k;
15338       if (!centre_rayon(C,c,R,false,contextptr)){
15339 	gen eq=_equation(C,contextptr);
15340 	eq=equation_homogene(eq,contextptr);
15341 	if (is_undef(eq)) return eq;
15342 	gen mat=qxa(eq,makevecteur(x__IDNT_e,y__IDNT_e,z__IDNT_e),contextptr);
15343 	if (!ckmatrix(mat))
15344 	  return gentypeerr(contextptr);
15345 	matrice M=*mat._VECTptr;
15346 	gen Ax=re(D[0],contextptr),Ay=im(D[0],contextptr);
15347 	gen Bx=re(D[1],contextptr),By=im(D[1],contextptr);
15348 	vecteur v=makevecteur(By-Ay,Ax-Bx,Bx*Ay-By*Ax);
15349 	matrice Minv=minv(M,contextptr);
15350 	if (is_undef(Minv)) return Minv;
15351 	vecteur w=multmatvecteur(Minv,v);
15352 	gen res=w[0]/w[2]+cst_i*w[1]/w[2];
15353 	res=recursive_normal(res,contextptr);
15354 	return symb_pnt(res,contextptr);
15355 	//return gensizeerr(contextptr);
15356       }
15357       A1=D[0]-c;
15358       A2=D[1]-c;
15359       a1=im(A1-A2,contextptr);
15360       a2=re(A2-A1,contextptr);
15361       k=im(A1*conj(A2,contextptr),contextptr);
15362       gen res =ratnormal(c+R*conj(R,contextptr)*(a1+cst_i*a2)/k,contextptr);
15363       return symb_pnt(res,contextptr);
15364     }
15365     return  symbolic(at_pole,args);
15366     //return gensizeerr(contextptr);
15367   }
15368   static const char _pole_s []="pole";
15369   static define_unary_function_eval (__pole,&_pole,_pole_s);
15370   define_unary_function_ptr5( at_pole ,alias_at_pole,&__pole,0,true);
15371 
15372   //renvoie un point (resp une droite) pole (resp polaire) de D/ cercle C
15373   //parametre C (ou param du cercle C), droite D (resp point D)
_polaire_reciproque(const gen & args,GIAC_CONTEXT)15374   gen _polaire_reciproque(const gen & args,GIAC_CONTEXT){
15375     if ( args.type==_STRNG && args.subtype==-1) return  args;
15376     vecteur w(gen2vecteur(args));
15377     vecteur attributs(1,default_color(contextptr));
15378     int s=read_attributs(w,attributs,contextptr);
15379     if (w.empty() || s!=2)
15380       return gensizeerr(gettext("reciprocation"));
15381     gen c=w[0],a=w[1];
15382     // if (a==c) return gensizeerr(gettext("reciprocation"));
15383     if (a.type==_VECT){
15384       const vecteur v=*a._VECTptr;
15385       const_iterateur it=v.begin(),itend=v.end();
15386       vecteur res;
15387       for (;it!=itend;++it){
15388 	a=*it;
15389 	a=remove_at_pnt(a);
15390 	if (a.type==_VECT)
15391 	  res.push_back(put_attributs(_pole(gen(makevecteur(c,a),_SEQ__VECT),contextptr),attributs,contextptr));
15392 	else
15393 	  res.push_back(put_attributs(_polaire(gen(makevecteur(c,a),_SEQ__VECT),contextptr),attributs,contextptr));
15394       }
15395       return gen(res,a.subtype);
15396     }
15397     a=remove_at_pnt(a);
15398     if (a.type==_VECT)
15399       return put_attributs(_pole(gen(makevecteur(c,a),_SEQ__VECT),contextptr),attributs,contextptr);
15400     return put_attributs(_polaire(gen(makevecteur(c,a),_SEQ__VECT),contextptr),attributs,contextptr);
15401   }
15402   static const char _polaire_reciproque_s []="reciprocation";
15403   static define_unary_function_eval (__polaire_reciproque,&_polaire_reciproque,_polaire_reciproque_s);
15404   define_unary_function_ptr5( at_polaire_reciproque ,alias_at_polaire_reciproque,&__polaire_reciproque,0,true);
15405 
15406   //teste si deux cercles C1 centre c1 rayon R1 et C2  centre c2 rayon R2
15407   //sont orthogonaux
est_orthogonal(const gen & c1,const gen & R1,const gen & c2,const gen & R2,GIAC_CONTEXT)15408   bool est_orthogonal(const gen & c1,const gen & R1,const gen & c2,const gen & R2,GIAC_CONTEXT){
15409     gen res =simplify(-abs_norm2(R1,contextptr)-abs_norm2(R2,contextptr)+abs_norm2(c1-c2,contextptr),contextptr);
15410     return is_zero(res,contextptr);
15411   }
15412 
15413   //teste si deux cercles C1 et C2 sont orthogonaux ou
15414   //si 2 droites D1,D2 sont perpendiculaires
15415   //parametres C1, C2 (ou D1,D2 ou 2 vecteurs de 2 points),
est_orthogonal(const gen & args,bool perp,GIAC_CONTEXT)15416   static gen est_orthogonal(const gen & args,bool perp,GIAC_CONTEXT){
15417     if ( args.type==_VECT && args._VECTptr->size()==2){
15418       vecteur v(*args._VECTptr);
15419       gen a=remove_at_pnt(v[0]),b=remove_at_pnt(v[1]);
15420       if (a.is_symb_of_sommet(at_hyperplan)){
15421 	if (b.type==_VECT && b._VECTptr->size()==3)
15422 	  return est_parallele_vecteur(hyperplan_normal(a),*b._VECTptr,contextptr);
15423 	if (ckmatrix(b) && b._VECTptr->size()==2)
15424 	  return est_parallele_vecteur(hyperplan_normal(a),*(b._VECTptr->back()-b._VECTptr->front())._VECTptr,contextptr);
15425 	if (b.is_symb_of_sommet(at_hyperplan))
15426 	  return is_zero(simplify(dotvecteur(hyperplan_normal(a),hyperplan_normal(b)),contextptr),contextptr);
15427       }
15428       if (b.is_symb_of_sommet(at_hyperplan) && !a.is_symb_of_sommet(at_hyperplan))
15429 	return _est_orthogonal(makesequence(b,a),contextptr);
15430       if ( a.type!=_VECT && b.type!=_VECT){
15431 	//on a 2 cercles ou 2 spheres a et b
15432 	gen c1,c2,R1,R2;
15433 	if (!centre_rayon(a,c1,R1,false,contextptr) ||
15434 	    !centre_rayon(b,c2,R2,false,contextptr))
15435 	  return gensizeerr(contextptr);
15436 	return est_orthogonal(c1,R1,c2,R2,contextptr);
15437       }
15438       if ( (a.type!=_VECT) || (a._VECTptr->size()!=2) || (b.type!=_VECT) || (b._VECTptr->size()!=2) )
15439 	return gensizeerr(contextptr);
15440       //on a 2 droites
15441       if (perp && a[0].type==_VECT && !est_coplanaire(a[0],a[1],b[0],b[1],contextptr))
15442 	return false;
15443       return est_perpendiculaire(a[0]-a[1],b[0]-b[1],contextptr);
15444     }
15445     return symbolic(at_est_orthogonal,args);
15446   }
15447 
_est_orthogonal(const gen & args,GIAC_CONTEXT)15448   gen _est_orthogonal(const gen & args,GIAC_CONTEXT){
15449     if ( args.type==_STRNG && args.subtype==-1) return  args;
15450     return est_orthogonal(args,false,contextptr);
15451   }
15452 
15453   static const char _est_orthogonal_s []="is_orthogonal";
15454   static define_unary_function_eval (__est_orthogonal,&_est_orthogonal,_est_orthogonal_s);
15455   define_unary_function_ptr5( at_est_orthogonal ,alias_at_est_orthogonal,&__est_orthogonal,0,true);
15456 
_est_perpendiculaire(const gen & args,GIAC_CONTEXT)15457   gen _est_perpendiculaire(const gen & args,GIAC_CONTEXT){
15458     if ( args.type==_STRNG && args.subtype==-1) return  args;
15459     return est_orthogonal(args,true,contextptr);
15460   }
15461   static const char _est_perpendiculaire_s []="is_perpendicular";
15462   static define_unary_function_eval (__est_perpendiculaire,&_est_perpendiculaire,_est_perpendiculaire_s);
15463   define_unary_function_ptr5( at_est_perpendiculaire ,alias_at_est_perpendiculaire,&__est_perpendiculaire,0,true);
15464 
15465 
15466   //teste si 2 points (resp 2 droites) sont conj /cercle C
15467   //teste si 2 points (resp droites) sont conjugues /2 droites D1,D2
15468   //teste si 2 points sont conjugues /2 points
15469   //est_conjugue(C,D,A) ou est_conjugue(C,A,D)(C=cercle,D=droite,A=point)
15470   //est_conjugue(C,B,A) (C=cercle,B,A= 2 points)
15471   //est_conjugue(C,D3,D4) (C=cercle, D3,D4= 2 droites)
15472   //est_conjugue(D1,D2,B,A) (B,A 2 points)
15473   //est_conjugue(D1,D2,D3,A) ou est_conjugue(D1,D2,A,D3)(D3=droite,A= point)
15474   //est_conjugue(D1,D2,D3,D4) (D3,D4= 2 droites)
15475   //est_conjugue(P1,P2,B,A) (P1,P2,B,A= 4 points)
_est_conjugue(const gen & args,GIAC_CONTEXT)15476   gen _est_conjugue(const gen & args,GIAC_CONTEXT){
15477     if ( args.type==_STRNG && args.subtype==-1) return  args;
15478     if ( (args.type!=_VECT) || (args._VECTptr->size()<3))
15479       return symbolic(at_est_conjugue,args);
15480     gen a,b,c,d;
15481     vecteur v(*args._VECTptr);
15482     a=remove_at_pnt(v[0]);
15483     b=remove_at_pnt(v[1]);
15484     int s=int(v.size());
15485     if (s==3) {
15486       c=remove_at_pnt(v[2]);
15487       //par rapport a un cercle
15488       if ((c.type!=_VECT) && (b.type!=_VECT)) // on a 2 points
15489 	return _est_orthogonal(makesequence(v[0],_cercle(makesequence(v[1],v[2]),contextptr)),contextptr);
15490       if (b.type==_VECT){
15491 	gen p=_pole(makesequence(v[0],v[1]),contextptr);
15492 	if (is_undef(p)) return p;
15493 	if (c.type!=_VECT)
15494 	  return is_zero(c-remove_at_pnt(p),contextptr);
15495 	return est_element(remove_at_pnt(p),c,contextptr);
15496       }
15497       if ((c.type==_VECT) && (b.type!=_VECT)){
15498 	gen p=_pole(makesequence(v[0],c),contextptr);
15499 	if (is_undef(p)) return p;
15500 	return is_zero(b-remove_at_pnt(p),contextptr);
15501       }
15502       return gensizeerr(contextptr);
15503     }
15504     if (s==4 && a.type==_VECT && b.type==_VECT ){
15505       gen dd=_conj_harmonique(makesequence(v[0],v[1],v[2]),contextptr);
15506       if (is_undef(dd)) return dd;
15507       d= remove_at_pnt(v[3]);
15508       dd=remove_at_pnt(dd);
15509       if (d.type!=_VECT)
15510 	return est_element(d,dd,contextptr);
15511       return est_element(d[0],dd,contextptr) && est_element(d[1],dd,contextptr);    }
15512     if (s==4 && (b.type!=_VECT) && (a.type!=_VECT)){ // on a /2 points
15513       if ((c.type!=_VECT)&&(d.type!=_VECT))
15514 	return _est_harmonique(args,contextptr);
15515       return gensizeerr(contextptr);
15516     }
15517     return 0;
15518   }
15519 
15520   static const char _est_conjugue_s []="is_conjugate";
15521   static define_unary_function_eval (__est_conjugue,&_est_conjugue,_est_conjugue_s);
15522   define_unary_function_ptr5( at_est_conjugue ,alias_at_est_conjugue,&__est_conjugue,0,true);
15523 
15524   //teste si 4 points forment une division harmonique
est_harmonique(const gen & a,const gen & b,const gen & c,const gen & d,GIAC_CONTEXT)15525   bool est_harmonique(const gen & a,const gen & b,const gen & c,const gen & d,GIAC_CONTEXT){
15526     if (est_aligne(a,b,c,contextptr) && est_aligne(a,b,d,contextptr)){
15527       gen e((c-a)/(c-b)+(d-a)/(d-b));
15528       return is_zero(simplify(e,contextptr),contextptr);
15529     } else return false; // setsizeerr(contextptr);
15530     // return 0;
15531   }
_est_harmonique(const gen & args,GIAC_CONTEXT)15532   gen _est_harmonique(const gen & args,GIAC_CONTEXT){
15533     if ( args.type==_STRNG && args.subtype==-1) return  args;
15534     if ((args.type==_VECT) && (args._VECTptr->size()==4)){
15535       vecteur v(*args._VECTptr);
15536       return est_harmonique(remove_at_pnt(v[0]),remove_at_pnt(v[1]),remove_at_pnt(v[2]),remove_at_pnt(v[3]),contextptr);
15537     }
15538     return symbolic(at_est_harmonique,args);
15539   }
15540   static const char _est_harmonique_s []="is_harmonic";
15541   static define_unary_function_eval (__est_harmonique,&_est_harmonique,_est_harmonique_s);
15542   define_unary_function_ptr5( at_est_harmonique ,alias_at_est_harmonique,&__est_harmonique,0,true);
15543 
15544   //conj_harmonique(D1,D2,A)= la droite des conjugues de A par rapport a D1,D2
15545   //conj_harmonique(D1,D2,D3)=D4 (D1,D2,D3,D4)=-1 (D1,D2,D3 concourantes ou //)
15546   //point D=conj_harmonique(A,B,C) est le point tel que (A,B,C,D)=-1
_conj_harmonique(const gen & args,GIAC_CONTEXT)15547   gen _conj_harmonique(const gen & args,GIAC_CONTEXT){
15548     if ( args.type==_STRNG && args.subtype==-1) return  args;
15549     if (args.type!=_VECT)
15550       return symbolic(at_conj_harmonique,args);
15551     //setsizeerr(contextptr);
15552     vecteur v(*args._VECTptr);
15553     gen d1,d2,a,D3,p1,p2,b;
15554     if (args._VECTptr->size()==3){
15555       bool est_point=false;
15556       d1=remove_at_pnt(v[0]);
15557       if (d1.type==_VECT){
15558 	if (d1._VECTptr->size()!=2)
15559 	  return gensizeerr(contextptr);
15560 	d1=d1._VECTptr->back()-d1._VECTptr->front();
15561       }
15562       else
15563 	est_point=true;
15564       d2=remove_at_pnt(v[1]);
15565       if (d2.type==_VECT){
15566 	if (est_point || d2._VECTptr->size()!=2)
15567 	  return gensizeerr(contextptr);
15568 	d2=d2._VECTptr->front()-d2._VECTptr->back();
15569       }
15570       else {
15571 	if (!est_point)
15572 	  return gensizeerr(contextptr);
15573       }
15574       a=remove_at_pnt(v[2]);
15575       if (est_point){
15576 	if (a.type==_VECT)
15577 	  return gensizeerr(contextptr);
15578 	gen e(im((a-d1)*conj(a-d2,contextptr),contextptr));
15579 	if (! is_zero(simplify(e,contextptr),contextptr))
15580 	  //les points ne sont pas alignes
15581 	  return gensizeerr(contextptr);
15582 	gen d=normal((d1*a+d2*a-2*d1*d2)/(2*a-d2-d1),contextptr);
15583 	return symb_pnt(d,contextptr);
15584       }
15585       if (est_parallele(d1,d2,contextptr)) {
15586 	if (a.type==_VECT){
15587 	  if (a._VECTptr->size()!=2)
15588 	    return gensizeerr(gettext("conj_harmonique"));
15589 	  gen aa=a._VECTptr->front()-a._VECTptr->back();
15590 	  if (est_parallele(d1,aa,contextptr))
15591 	    a=a._VECTptr->front();
15592 	  else return gensizeerr(gettext("conj_harmonique"));
15593 	}
15594 	D3=_perpendiculaire(makesequence(a,v[0]),contextptr);
15595 	vecteur w1(inter(D3,v[0],contextptr));
15596 	p1=remove_at_pnt(w1.front());
15597 	vecteur w2(inter(D3,v[1],contextptr));
15598 	p2=remove_at_pnt(w2.front());
15599 	b=_conj_harmonique(makesequence(p1,p2,a),contextptr);
15600 	return _parallele(makesequence(b,v[0]),contextptr);
15601       }
15602       else  {
15603 	vecteur w1(inter(v[0],v[1],0));
15604 	p1=remove_at_pnt(w1.front());
15605 	if (a.type==_VECT){
15606 	  if (a._VECTptr->size()!=2)
15607 	    return gensizeerr(gettext("conj_harmonique"));
15608 	  a=a._VECTptr->front()-a._VECTptr->back();
15609 	  if (est_element(p1,v[2],contextptr))
15610 	    a=p1+a; else  return gensizeerr(contextptr);
15611 	}
15612 	D3=_parallele(makesequence(a,v[0]),contextptr);
15613 	if (is_undef(D3)) return D3;
15614 	vecteur w2(inter(D3,v[1],0));
15615 	p2=remove_at_pnt(w2.front());
15616 	b=normal(2*p2-a,contextptr);
15617 	gen res=_droite(makesequence(normal(p1,contextptr),b),contextptr);
15618 	return res;
15619       }
15620     }
15621     else return gensizeerr(contextptr);
15622     return 0;
15623   }
15624   static const char _conj_harmonique_s []="harmonic_conjugate";
15625   static define_unary_function_eval (__conj_harmonique,&_conj_harmonique,_conj_harmonique_s);
15626   define_unary_function_ptr5( at_conj_harmonique ,alias_at_conj_harmonique,&__conj_harmonique,0,true);
15627 
15628   //renvoie M point qui divise AB ds un rapport k(reel ou complexe)
15629   //mes alg(MA=k*MB) (z*a=k*(z-b)), parametres: A,B,k
_point_div(const gen & args,GIAC_CONTEXT)15630   gen _point_div(const gen & args,GIAC_CONTEXT){
15631     if ( args.type==_STRNG && args.subtype==-1) return  args;
15632     if ( args.type==_STRNG && args.subtype==-1) return  args;
15633     if ( (args.type!=_VECT) || (args._VECTptr->size()<3))
15634       return symbolic(at_point_div,args);
15635     vecteur v(*args._VECTptr);
15636     gen a=remove_at_pnt(eval(v[0],contextptr)),b=remove_at_pnt(eval(v[1],contextptr)),k=eval(v[2],contextptr);
15637     //if (! is_zero(im(k,contextptr),contextptr)) return gensizeerr(contextptr);
15638     gen c;
15639     k=normal(1-k,contextptr);
15640     if (is_zero(k,contextptr)) return gensizeerr(contextptr);
15641     //{c=unsigned_inf;}
15642     c=normal((a+(k-1)*b)/k,contextptr);
15643     return symb_pnt(c,contextptr);
15644   }
15645   static const char _point_div_s []="division_point";
15646   static define_unary_function_eval (__point_div,&_point_div,_point_div_s);
15647   define_unary_function_ptr5( at_point_div ,alias_at_point_div,&__point_div,0,true);
15648 
15649   //=1 si 3 cercles ont meme axe radical,2 si concentriques et 0 sinon
est_faisceau_cercle(const gen & c1,const gen & R1,const gen & c2,const gen & R2,const gen & c3,const gen & R3,GIAC_CONTEXT)15650   int est_faisceau_cercle(const gen & c1,const gen & R1,const gen & c2,const gen & R2,const gen & c3,const gen & R3,GIAC_CONTEXT){
15651     if (is_equal(makevecteur(c1,c2))){
15652       if (is_equal(makevecteur(c1,c3)))
15653 	return 2;
15654       else
15655 	return 0;
15656     }
15657     if (is_equal(makevecteur(c1,c3)))
15658       return 0;
15659     //les centres sont distincts
15660     if (!est_aligne(c1,c2,c3,contextptr)) return 0;
15661     //les centres sont alignes
15662     gen v=_axe_radical(makesequence(_cercle(makesequence(c1,R1),contextptr),_cercle(makesequence(c2,R2),contextptr)),contextptr);
15663     gen w=_axe_radical(makesequence(_cercle(makesequence(c1,R1),contextptr),_cercle(makesequence(c3,R3),contextptr)),contextptr);
15664     v=remove_at_pnt(v);
15665     return est_element(v[0],w,contextptr) && est_element(v[1],w,contextptr);
15666   }
15667 
15668   //renvoie 3 si tous les cercles sont confondus
15669   //renvoie 2 si concentriques
15670   //renvoie 1 si les cercles ont meme axe radical et 0 sinon
_est_faisceau_cercle(const gen & args,GIAC_CONTEXT)15671   gen _est_faisceau_cercle(const gen & args,GIAC_CONTEXT){
15672     if ( args.type==_STRNG && args.subtype==-1) return  args;
15673     gen c1,R1;
15674     if (args.type!=_VECT){
15675       if (!centre_rayon(args,c1,R1,false,contextptr))
15676 	return gensizeerr(contextptr);
15677       return 3;
15678     }
15679     int s=int(args._VECTptr->size());
15680     vecteur v(*args._VECTptr);
15681     if (s==1) {
15682       if (!centre_rayon(v[0],c1,R1,false,contextptr))
15683 	return gensizeerr(contextptr);
15684       return 3;
15685     }
15686     if (s>=2){
15687       gen c2,c3,R2,R3;
15688       if (!centre_rayon(v[0],c1,R1,false,contextptr) ||
15689 	  !centre_rayon(v[1],c2,R2,false,contextptr))
15690 	return gensizeerr(contextptr);
15691       c1=remove_at_pnt(c1);
15692       c2=remove_at_pnt(c2);
15693       int res=0;
15694       int i=2;
15695       while (c1==c2 && R1==R2 && i<s){
15696 	if (!centre_rayon(v[i],c2,R2,false,contextptr))
15697 	  return gensizeerr(contextptr);
15698 	c2=remove_at_pnt(c2);
15699 	i=i+1;
15700       }
15701       if (i==s){
15702 	if (c1==c2 && R1==R2) return 3;
15703 	if (c1==c2) return 2;
15704 	return 1;
15705       }
15706       for (int j=i;j<s;j++){
15707 	if (!centre_rayon(v[j],c3,R3,false,contextptr))
15708 	  return gensizeerr(contextptr);
15709 	res=est_faisceau_cercle(c1,R1,c2,R2,remove_at_pnt(c3),R3,contextptr);
15710 	if (res==0) return 0;
15711       }
15712       return res;
15713     }
15714     return symbolic(at_est_faisceau_cercle,args);
15715   }
15716   static const char _est_faisceau_cercle_s []="is_harmonic_circle_bundle";
15717   static define_unary_function_eval (__est_faisceau_cercle,&_est_faisceau_cercle,_est_faisceau_cercle_s);
15718   define_unary_function_ptr5( at_est_faisceau_cercle ,alias_at_est_faisceau_cercle,&__est_faisceau_cercle,0,true);
15719 
15720   //renvoie 1 si les 2 droites sont confondues,2 si elles sont//
15721   //et 0 sinon
est_confondu_droite(const gen & a,const gen & b,GIAC_CONTEXT)15722   static int est_confondu_droite(const gen & a,const gen & b,GIAC_CONTEXT){
15723     gen d(im((a[0]-a[1])*conj(b[0]-b[1],contextptr),contextptr));
15724     if (is_zero(simplify(d,contextptr),contextptr)) {
15725       if (est_element(b[0],_droite(a,contextptr),contextptr))
15726 	return 1;
15727       else return 2;
15728     }
15729     return 0;
15730   }
15731   //renvoie 1 si les 3 droites sont concourantes,2 si elles sont//
15732   //et 0 sinon qd a et b sont 2 droites differentes
est_faisceau_droite(const gen & a,const gen & b,const gen & c,GIAC_CONTEXT)15733   int est_faisceau_droite(const gen & a,const gen & b,const gen & c,GIAC_CONTEXT){
15734     gen d(simplify(im((a[0]-a[1])*conj(b[0]-b[1],contextptr),contextptr),contextptr));
15735     gen e(simplify(im((a[0]-a[1])*conj(c[0]-c[1],contextptr),contextptr),contextptr));
15736     if (is_zero(d,contextptr)) {
15737       if (is_zero(e,contextptr))
15738 	return 2;
15739       else return 0;
15740     }
15741     if (is_zero(e,contextptr))
15742       return 0;
15743     //les 3 droites ne sont pas paralleles
15744     gen v=inter(_droite(a,contextptr),_droite(b,contextptr),0);
15745     //gen w =inter(_droite(a,contextptr),_droite(c,contextptr),0);
15746     if (v.type==_VECT && !v._VECTptr->empty() && est_element(v[0],_droite(c,contextptr),contextptr))
15747       return 1;
15748     else return 0;
15749   }
15750 
15751   //args contient au moins 3 droites
15752   //renvoie 3 si toutes les droites sont confondues
15753   //renvoie 2 si les droites sont //
15754   //renvoie 1 si les droites sont concourantes en 1 meme point
15755   //renvoie 0 sinon
_est_faisceau_droite(const gen & args,GIAC_CONTEXT)15756   gen _est_faisceau_droite(const gen & args,GIAC_CONTEXT){
15757     if ( args.type==_STRNG && args.subtype==-1) return  args;
15758     gen a;
15759     if (args.type!=_VECT){
15760       a=remove_at_pnt(args);
15761       if ((a.type!=_VECT) || (a._VECTptr->size()!=2))
15762 	return gensizeerr(contextptr);
15763       return 3;
15764     }
15765     int s=int(args._VECTptr->size());
15766     vecteur v(*args._VECTptr);
15767     if (s==1) {
15768       a=remove_at_pnt(v[0]);
15769       if (a.type==_VECT)
15770 	return gensizeerr(contextptr);
15771       return 3;
15772     }
15773     if (s>=2){
15774       a=remove_at_pnt(v[0]);
15775       gen b=remove_at_pnt(v[1]);
15776       if ((a.type!=_VECT) || (a._VECTptr->size()!=2) || (b.type!=_VECT) || (b._VECTptr->size()!=2))
15777 	return gensizeerr(contextptr);
15778       int i=2;
15779       int res;
15780       while (est_confondu_droite(a,b,contextptr) && i<s){
15781 	b=remove_at_pnt(v[i]);
15782 	if ((b.type!=_VECT) || (b._VECTptr->size()!=2))
15783 	  return gensizeerr(contextptr);
15784 	i=i+1;
15785       }
15786       if (i==s){
15787 	res=est_confondu_droite(a,b,contextptr);
15788 	if (res==1) return 3;
15789 	if (res==0) return 1;
15790 	return 2;
15791       }
15792       for (int j=i;j<s;j++){
15793 	gen c=remove_at_pnt(v[j]);
15794 	if ((c.type!=_VECT) || (c._VECTptr->size()!=2))
15795 	  return gensizeerr(contextptr);
15796 	res=est_faisceau_droite(a,b,c,contextptr);
15797 	if (res==0) return 0;
15798       }
15799       return res;
15800     }
15801     return symbolic(at_est_faisceau_droite,args);
15802   }
15803   static const char _est_faisceau_droite_s []="is_harmonic_line_bundle";
15804   static define_unary_function_eval (__est_faisceau_droite,&_est_faisceau_droite,_est_faisceau_droite_s);
15805   define_unary_function_ptr5( at_est_faisceau_droite ,alias_at_est_faisceau_droite,&__est_faisceau_droite,0,true);
15806 
15807   //div_harmonique(A,B,C,D) remplit D tel que (A,B,C,D)=-1
15808   //div_harmonique(D1,D2,A,D) remplit D tel que (D1,D2,A,D)=-1
15809   //div_harmonique(D1,D2,D3,D) remplit D tel que (D1,D2,D3,D)=-1
15810   //et dessine les 4 points ou les 3 droites + le point ou les 4 droites
_div_harmonique(const gen & args,GIAC_CONTEXT)15811   gen _div_harmonique(const gen & args,GIAC_CONTEXT){
15812     if ( args.type==_STRNG && args.subtype==-1) return  args;
15813     if ( (args.type!=_VECT) || (args._VECTptr->size()<3))
15814       return symbolic(at_div_harmonique,args);
15815     vecteur v(*args._VECTptr);
15816     gen d;
15817     gen v0=eval(v[0],contextptr),v1=eval(v[1],contextptr),v2=eval(v[2],contextptr);
15818     d=_conj_harmonique(makesequence(v0,v1,v2),contextptr);
15819     if (v.size()==3 || is_undef(d))
15820       return d;
15821     if (v0.is_symb_of_sommet(at_pnt))
15822       v0=symb_pnt(v0,default_color(contextptr),contextptr);
15823     if (v1.is_symb_of_sommet(at_pnt))
15824       v1=symb_pnt(v0,default_color(contextptr),contextptr);
15825     if (v2.is_symb_of_sommet(at_pnt))
15826       v2=symb_pnt(v0,default_color(contextptr),contextptr);
15827     vecteur w=makevecteur(v0,v1,v2);
15828     w.push_back(eval(symb_sto(d,v[3]),contextptr));
15829     return gen(w,_GROUP__VECT);
15830     // return gensizeerr(gettext("div_harmonique)"));
15831   }
15832   static const char _div_harmonique_s []="harmonic_division";
15833   static define_unary_function_eval_quoted (__div_harmonique,&_div_harmonique,_div_harmonique_s);
15834   define_unary_function_ptr5( at_div_harmonique ,alias_at_div_harmonique,&__div_harmonique,_QUOTE_ARGUMENTS,true);
15835 
15836   //enveloppe(y+x*tan(t)-2*sin(t),t)
15837   //enveloppe(y+x*tan(t)-2*sin(t),[t])
15838   //enveloppe(y+x*tan(t)-2*sin(t),[x,y,t])
15839 
_enveloppe(const gen & args,GIAC_CONTEXT)15840   gen _enveloppe(const gen & args,GIAC_CONTEXT){
15841     if ( args.type==_STRNG && args.subtype==-1) return  args;
15842     if ( (args.type!=_VECT) || (args._VECTptr->size()<2))
15843       return symbolic(at_enveloppe,args);
15844     vecteur vargs(*args._VECTptr);
15845     if (vargs[0].is_symb_of_sommet(at_pnt))
15846       vargs[0]=_equation(vargs[0],contextptr);
15847     gen equ=equal2diff(vargs[0]),var=vargs[1];
15848     //identificateur gen xvar=vx_var,yvar=y__IDNT_e;
15849     gen tvar,xvar,yvar;
15850     if (var.type!=_VECT){
15851       tvar=var;
15852       xvar=vx_var;
15853       yvar=y__IDNT_e;
15854     } else
15855       if (var._VECTptr->size()==1) {
15856 	tvar=var[0];
15857 	xvar=vx_var;
15858 	yvar=y__IDNT_e;
15859       } else
15860 	if (var._VECTptr->size()==3){
15861 	  xvar=var[0];
15862 	  if (xvar.type!=_IDNT)
15863 	    return gentypeerr(contextptr);
15864 	  yvar=var[1];
15865 	  if (yvar.type!=_IDNT)
15866 	    return gentypeerr(contextptr);
15867 	  tvar=var[2];
15868 	} else {
15869 	  return gensizeerr(gettext("enveloppe"));
15870 	}
15871     gen T;
15872     double tmin,tmax;
15873     readrange(tvar,gnuplot_tmin,gnuplot_tmax,T,tmin,tmax,contextptr);
15874     gen equder=derive(equ,T,contextptr);
15875     if (is_undef(equder))
15876       return equder;
15877     gen sol;
15878     sol=solve(makevecteur(equ,equder),makevecteur(xvar,yvar),0,contextptr);
15879     if (sol.type==_VECT){
15880       vecteur & v = *sol._VECTptr;
15881       vecteur res;
15882       int s=int(v.size());
15883       for (int i=0;i<s;++i){
15884 	gen tmp=v[i];
15885 	if (tmp.type==_VECT && tmp._VECTptr->size()==2){
15886 	  tmp=tmp._VECTptr->front()+cst_i*tmp._VECTptr->back();
15887 	  vargs[0]=tmp;
15888 	  vargs[1]=tvar;
15889 	  tmp=gen(vargs,_SEQ__VECT);
15890 	  tmp=_paramplot(tmp,contextptr);
15891 	  if (tmp.type==_VECT)
15892 	    res=mergevecteur(res,*tmp._VECTptr);
15893 	  else
15894 	    res.push_back(tmp);
15895 	}
15896       }
15897       return res; // gen(res,_SEQ__VECT);
15898     }
15899     return sol;
15900   }
15901 
15902   static const char _enveloppe_s []="envelope";
15903   static define_unary_function_eval (__enveloppe,&_enveloppe,_enveloppe_s);
15904   define_unary_function_ptr5( at_enveloppe ,alias_at_enveloppe,&__enveloppe,0,true);
15905 
15906 #ifdef WITH_GNUPLOT
_gnuplot(const gen & args,GIAC_CONTEXT)15907   gen _gnuplot(const gen & args,GIAC_CONTEXT){
15908     if ( args.type==_STRNG && args.subtype==-1) return  args;
15909     vecteur v(gen2vecteur(args));
15910     int s=v.size();
15911     bool clrplot;
15912     int out_handle;
15913     FILE * gnuplot_out_readstream,* stream = open_gnuplot(clrplot,gnuplot_out_readstream,out_handle);
15914     for (int i=0;i<s;++i){
15915       if (v[i].type==_STRNG)
15916 	fprintf(stream,"%s\n",v[i]._STRNGptr->c_str());
15917     }
15918     win9x_gnuplot(stream);
15919     return 1;
15920   }
15921   static const char _gnuplot_s []="gnuplot";
15922   static define_unary_function_eval (__gnuplot,&_gnuplot,_gnuplot_s);
15923   define_unary_function_ptr5( at_gnuplot ,alias_at_gnuplot,&__gnuplot,0,true);
15924 #endif
15925 
15926   // 3-d functions that must be declared in plot.cc for plot_sommets definition
15927 
15928   // args=normal,point
_hyperplan(const gen & args,GIAC_CONTEXT)15929   gen _hyperplan(const gen & args,GIAC_CONTEXT){
15930     if ( args.type==_STRNG && args.subtype==-1) return  args;
15931     if (args.type!=_VECT || args._VECTptr->size()!=2)
15932       return gensizeerr(contextptr);
15933     return symbolic(at_hyperplan,args);
15934   }
15935   static const char _hyperplan_s []="hyperplan";
15936   static define_unary_function_eval (__hyperplan,&_hyperplan,_hyperplan_s);
15937   define_unary_function_ptr5( at_hyperplan ,alias_at_hyperplan,&__hyperplan,0,true);
15938 
15939   // args=center,radius
_hypersphere(const gen & args,GIAC_CONTEXT)15940   gen _hypersphere(const gen & args,GIAC_CONTEXT){
15941     if ( args.type==_STRNG && args.subtype==-1) return  args;
15942     if (args.type!=_VECT || args._VECTptr->size()<2)
15943       return gensizeerr(contextptr);
15944     return symbolic(at_hypersphere,args);
15945   }
15946   static const char _hypersphere_s []="hypersphere";
15947   static define_unary_function_eval (__hypersphere,&_hypersphere,_hypersphere_s);
15948   define_unary_function_ptr5( at_hypersphere ,alias_at_hypersphere,&__hypersphere,0,true);
15949 
hypersurface(const gen & args,const gen & equation,const gen & vars)15950   gen hypersurface(const gen & args,const gen & equation,const gen & vars){
15951     return _hypersurface(gen(makevecteur(args,equation,vars),_GROUP__VECT),context0);
15952   }
15953   // Format of an hypersurface is
15954   // pnt_vect[ [parametric_point],[var1,var2],[min1,min2],[max1,max2],values ]
15955   // or pnt_vect[ undef,[x,y,z],[xmin,ymin,zmin], [xmax,ymax,zmax], values ]
15956   // cartesian equation
15957   // variables
_hypersurface(const gen & args,GIAC_CONTEXT)15958   gen _hypersurface(const gen & args,GIAC_CONTEXT){
15959     if ( args.type==_STRNG && args.subtype==-1) return  args;
15960     return symbolic(at_hypersurface,args);
15961   }
15962   static const char _hypersurface_s []="hypersurface";
15963   static define_unary_function_eval (__hypersurface,&_hypersurface,_hypersurface_s);
15964   define_unary_function_ptr5( at_hypersurface ,alias_at_hypersurface,&__hypersurface,0,true);
15965 
15966   // 0 text, 2 2d, 3 3d
graph_output_type(const gen & g)15967   int graph_output_type(const gen & g){
15968     // logo check
15969     if (g.type==_VECT && g.subtype==_LOGO__VECT && g._VECTptr->size()==6){
15970       vecteur & v=*g._VECTptr;
15971       if (v[0].type==_DOUBLE_ && v[1].type==_DOUBLE_ && v[2].type==_DOUBLE_ && v[3].type==_INT_ && v[4].type==_INT_ && v[5].type==_STRNG) return 4;
15972     }
15973     if (g.type==_VECT && !g._VECTptr->empty())
15974       return graph_output_type(g._VECTptr->back());
15975     if (g.is_symb_of_sommet(at_animation))
15976       return graph_output_type(g._SYMBptr->feuille);
15977     if (g.is_symb_of_sommet(at_pnt)){
15978       return is3d(g)?3:2;
15979     }
15980     return 0;
15981   }
15982 
_animation(const gen & args,GIAC_CONTEXT)15983   gen _animation(const gen & args,GIAC_CONTEXT){
15984     if ( args.type==_STRNG && args.subtype==-1) return  args;
15985     return symbolic(at_animation,args);
15986   }
15987   static const char _animation_s []="animation";
15988   static define_unary_function_eval (__animation,&_animation,_animation_s);
15989   define_unary_function_ptr5( at_animation ,alias_at_animation,&__animation,0,true);
15990 
get_animation_pnt(const gen & g,int pos)15991   gen get_animation_pnt(const gen & g,int pos){
15992     gen & f =g._SYMBptr->feuille;
15993     gen fi=f;
15994     if (f.type==_VECT){
15995       vecteur v=*f._VECTptr;
15996       int s=int(v.size());
15997       if (s){
15998 	if (v[0].type==_INT_){
15999 	  int n=absint(v[0].val);
16000 	  if (!n)
16001 	    n=1;
16002 	  pos = pos/n;
16003 	  if (s==2){
16004 	    if (v[1].type==_VECT){
16005 	      v=*v[1]._VECTptr;
16006 	      s=int(v.size());
16007 	    }
16008 	  }
16009 	  else {
16010 	    v.erase(v.begin());
16011 	    --s;
16012 	  }
16013 	}
16014 	pos=pos%s;
16015 	if (pos<0)
16016 	  pos+=s;
16017 	fi=v[pos];
16018       }
16019     }
16020     return fi;
16021   }
16022 
animations(const gen & g)16023   int animations(const gen & g){
16024     if (g.is_symb_of_sommet(at_animation)){
16025       gen & f =g._SYMBptr->feuille;
16026       if (f.type!=_VECT)
16027 	return 1;
16028       return int(f._VECTptr->size());
16029     }
16030     if (g.type!=_VECT)
16031       return 0;
16032     int res=0,tmp;
16033     const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end();
16034     for (;it!=itend;++it){
16035       tmp=animations(*it);
16036       if (tmp>res)
16037 	res=tmp;
16038     }
16039     return res;
16040   }
16041 
16042   // 2-d unit_vector
_Ox_2d_unit_vector(const gen & args,GIAC_CONTEXT)16043   gen _Ox_2d_unit_vector(const gen & args,GIAC_CONTEXT){
16044     if ( args.type==_STRNG && args.subtype==-1) return  args;
16045     vecteur v=makevecteur(_point(makevecteur(0,0),contextptr),_point(makevecteur(1,0),contextptr));
16046     if (args.type==_VECT)
16047       v=mergevecteur(v,*args._VECTptr);
16048     else
16049       v.push_back(args);
16050     return _vector(gen(v,_SEQ__VECT),contextptr);
16051   }
16052   static const char _Ox_2d_unit_vector_s []="Ox_2d_unit_vector";
16053   static define_unary_function_eval (__Ox_2d_unit_vector,&_Ox_2d_unit_vector,_Ox_2d_unit_vector_s);
16054   define_unary_function_ptr5( at_Ox_2d_unit_vector ,alias_at_Ox_2d_unit_vector,&__Ox_2d_unit_vector,0,true);
16055 
16056   // 2-d unit_vector
_Oy_2d_unit_vector(const gen & args,GIAC_CONTEXT)16057   gen _Oy_2d_unit_vector(const gen & args,GIAC_CONTEXT){
16058     if ( args.type==_STRNG && args.subtype==-1) return  args;
16059     vecteur v=makevecteur(_point(makevecteur(0,0),contextptr),_point(makevecteur(0,1),contextptr));
16060     if (args.type==_VECT)
16061       v=mergevecteur(v,*args._VECTptr);
16062     else
16063       v.push_back(args);
16064     return _vector(gen(v,_SEQ__VECT),contextptr);
16065   }
16066   static const char _Oy_2d_unit_vector_s []="Oy_2d_unit_vector";
16067   static define_unary_function_eval (__Oy_2d_unit_vector,&_Oy_2d_unit_vector,_Oy_2d_unit_vector_s);
16068   define_unary_function_ptr5( at_Oy_2d_unit_vector ,alias_at_Oy_2d_unit_vector,&__Oy_2d_unit_vector,0,true);
16069 
16070   // 2-d frame
_frame_2d(const gen & args,GIAC_CONTEXT)16071   gen _frame_2d(const gen & args,GIAC_CONTEXT){
16072     if ( args.type==_STRNG && args.subtype==-1) return  args;
16073     if ( args.type==_STRNG && args.subtype==-1) return  args;
16074     vecteur v=makevecteur(_point(makevecteur(0,0),contextptr),_point(makevecteur(1,0),contextptr));
16075     if (args.type==_VECT)
16076       v=mergevecteur(v,*args._VECTptr);
16077     else
16078       v.push_back(args);
16079     vecteur res(1,_vector(gen(v,_SEQ__VECT),contextptr));
16080     v=makevecteur(_point(makevecteur(0,0),contextptr),_point(makevecteur(0,1),contextptr));
16081     if (args.type==_VECT)
16082       v=mergevecteur(v,*args._VECTptr);
16083     else
16084       v.push_back(args);
16085     res.push_back(_vector(gen(v,_SEQ__VECT),contextptr));
16086     return gen(res,_SEQ__VECT);
16087   }
16088   static const char _frame_2d_s []="frame_2d";
16089   static define_unary_function_eval (__frame_2d,&_frame_2d,_frame_2d_s);
16090   define_unary_function_ptr5( at_frame_2d ,alias_at_frame_2d,&__frame_2d,0,true);
16091 
16092   // 3-d unit_vector
_Ox_3d_unit_vector(const gen & args,GIAC_CONTEXT)16093   gen _Ox_3d_unit_vector(const gen & args,GIAC_CONTEXT){
16094     if ( args.type==_STRNG && args.subtype==-1) return  args;
16095     vecteur v=makevecteur(_point(makevecteur(0,0,0),contextptr),_point(makevecteur(1,0,0),contextptr));
16096     if (args.type==_VECT)
16097       v=mergevecteur(v,*args._VECTptr);
16098     else
16099       v.push_back(args);
16100     return _vector(gen(v,_SEQ__VECT),contextptr);
16101   }
16102   static const char _Ox_3d_unit_vector_s []="Ox_3d_unit_vector";
16103   static define_unary_function_eval (__Ox_3d_unit_vector,&_Ox_3d_unit_vector,_Ox_3d_unit_vector_s);
16104   define_unary_function_ptr5( at_Ox_3d_unit_vector ,alias_at_Ox_3d_unit_vector,&__Ox_3d_unit_vector,0,true);
16105 
16106   // 3-d unit_vector
_Oy_3d_unit_vector(const gen & args,GIAC_CONTEXT)16107   gen _Oy_3d_unit_vector(const gen & args,GIAC_CONTEXT){
16108     if ( args.type==_STRNG && args.subtype==-1) return  args;
16109     vecteur v=makevecteur(_point(makevecteur(0,0,0),contextptr),_point(makevecteur(0,1,0),contextptr));
16110     if (args.type==_VECT)
16111       v=mergevecteur(v,*args._VECTptr);
16112     else
16113       v.push_back(args);
16114     return _vector(gen(v,_SEQ__VECT),contextptr);
16115   }
16116   static const char _Oy_3d_unit_vector_s []="Oy_3d_unit_vector";
16117   static define_unary_function_eval (__Oy_3d_unit_vector,&_Oy_3d_unit_vector,_Oy_3d_unit_vector_s);
16118   define_unary_function_ptr5( at_Oy_3d_unit_vector ,alias_at_Oy_3d_unit_vector,&__Oy_3d_unit_vector,0,true);
16119 
16120   // 3-d unit_vector
_Oz_3d_unit_vector(const gen & args,GIAC_CONTEXT)16121   gen _Oz_3d_unit_vector(const gen & args,GIAC_CONTEXT){
16122     if ( args.type==_STRNG && args.subtype==-1) return  args;
16123     vecteur v=makevecteur(_point(makevecteur(0,0,0),contextptr),_point(makevecteur(0,0,1),contextptr));
16124     if (args.type==_VECT)
16125       v=mergevecteur(v,*args._VECTptr);
16126     else
16127       v.push_back(args);
16128     return _vector(gen(v,_SEQ__VECT),contextptr);
16129   }
16130   static const char _Oz_3d_unit_vector_s []="Oz_3d_unit_vector";
16131   static define_unary_function_eval (__Oz_3d_unit_vector,&_Oz_3d_unit_vector,_Oz_3d_unit_vector_s);
16132   define_unary_function_ptr5( at_Oz_3d_unit_vector ,alias_at_Oz_3d_unit_vector,&__Oz_3d_unit_vector,0,true);
16133 
16134   // 3-d frame
_frame_3d(const gen & args,GIAC_CONTEXT)16135   gen _frame_3d(const gen & args,GIAC_CONTEXT){
16136     if ( args.type==_STRNG && args.subtype==-1) return  args;
16137     vecteur v=makevecteur(_point(makevecteur(0,0,0),contextptr),_point(makevecteur(1,0,0),contextptr));
16138     vecteur res(1,_demi_droite(gen(v,_SEQ__VECT),contextptr));
16139     v.push_back(symb_equal(at_display,131073));
16140     v.push_back(symb_equal(at_legende,string2gen("x",false)));
16141     res.push_back(_vector(gen(v,_SEQ__VECT),contextptr));
16142     v=makevecteur(_point(makevecteur(0,0,0),contextptr),_point(makevecteur(0,1,0),contextptr));
16143     res.push_back(_demi_droite(gen(v,_SEQ__VECT),contextptr));
16144     v.push_back(symb_equal(at_display,131074));
16145     v.push_back(symb_equal(at_legende,string2gen("y",false)));
16146     res.push_back(_vector(gen(v,_SEQ__VECT),contextptr));
16147     v=makevecteur(_point(makevecteur(0,0,0),contextptr),_point(makevecteur(0,0,1),contextptr));
16148     res.push_back(_demi_droite(gen(v,_SEQ__VECT),contextptr));
16149     v.push_back(symb_equal(at_display,131076));
16150     v.push_back(symb_equal(at_legende,string2gen("z",false)));
16151     res.push_back(_vector(gen(v,_SEQ__VECT),contextptr));
16152     return gen(res,_SEQ__VECT);
16153   }
16154   static const char _frame_3d_s []="frame_3d";
16155   static define_unary_function_eval (__frame_3d,&_frame_3d,_frame_3d_s);
16156   define_unary_function_ptr5( at_frame_3d ,alias_at_frame_3d,&__frame_3d,0,true);
16157 
16158   // moved from plot3d.cc for implicittex_plot_sommets_alias
_plot3d(const gen & g,const context * contextptr)16159   gen _plot3d(const gen & g,const context * contextptr){
16160     if ( g.type==_STRNG && g.subtype==-1) return  g;
16161     if (g.type!=_VECT || g._VECTptr->size()<2)
16162       return symbolic(at_plot3d,g);
16163     vecteur v=*g._VECTptr;
16164     if (v.size()<3)
16165       v.push_back(v__IDNT_e);
16166     vecteur attributs(1,default_color(contextptr));
16167     int s=read_attributs(v,attributs,contextptr);
16168     if (s<3)
16169       return gendimerr(contextptr);
16170     v=vecteur(v.begin(),v.begin()+s);
16171     if (v[0].type==_VECT){
16172       if (v[0]._VECTptr->size()!=3)
16173 	return gendimerr(contextptr);
16174       double tmin,tmax,smin,smax;
16175       if (v[1].is_symb_of_sommet(at_interval)){
16176 	if (!chk_double_interval(v[1],tmin,tmax,contextptr) || !chk_double_interval(v[2],smin,smax,contextptr))
16177 	  return gensizeerr(contextptr);
16178 	vecteur vars(makevecteur(s__IDNT_e,t__IDNT_e));
16179 	return plotparam3d(v[0](gen(vars,_SEQ__VECT),contextptr),vars,gnuplot_xmin,gnuplot_xmax,gnuplot_ymin,gnuplot_ymax,gnuplot_zmin,gnuplot_xmax,tmin,tmax,smin,smax,true,autoscale,attributs,gnuplot_tstep,gnuplot_tstep,undef,vecteur(0),contextptr);
16180       }
16181       else {
16182 	if (!readrange(v[1],gnuplot_tmin,gnuplot_tmax,v[1],tmin,tmax,contextptr) || !readrange(v[2],gnuplot_tmin,gnuplot_tmax,v[2],smin,smax,contextptr))
16183 	  return gensizeerr(contextptr);
16184 	return plotparam3d(v[0],makevecteur(v[1],v[2]),gnuplot_xmin,gnuplot_xmax,gnuplot_ymin,gnuplot_ymax,gnuplot_zmin,gnuplot_xmax,tmin,tmax,smin,smax,true,autoscale,attributs,gnuplot_tstep,gnuplot_tstep,undef,vecteur(0),contextptr);
16185       }
16186     }
16187     else {
16188       double xmin,xmax,ymin,ymax;
16189       if (v[1].is_symb_of_sommet(at_interval)){
16190 	if (!chk_double_interval(v[1],xmin,xmax,contextptr) || !chk_double_interval(v[2],ymin,ymax,contextptr))
16191 	  return gensizeerr(contextptr);
16192 	gen vars(makevecteur(x__IDNT_e,y__IDNT_e),_SEQ__VECT);
16193 	return plotfunc(v[0](vars,contextptr),vars,attributs,false,xmin,xmax,ymin,ymax,gnuplot_zmin,gnuplot_zmax,gnuplot_pixels_per_eval,0,false,contextptr);
16194       }
16195       else {
16196 	if (!readrange(v[1],gnuplot_xmin,gnuplot_xmax,v[1],xmin,xmax,contextptr) || !readrange(v[2],gnuplot_ymin,gnuplot_ymax,v[2],ymin,ymax,contextptr))
16197 	  return gensizeerr(contextptr);
16198 	return plotfunc(v[0],makevecteur(v[1],v[2]),attributs,false,xmin,xmax,ymin,ymax,gnuplot_zmin,gnuplot_zmax,gnuplot_pixels_per_eval,0,false,contextptr);
16199       }
16200     }
16201   }
16202   static const char _plot3d_s []="plot3d";
16203   static define_unary_function_eval (__plot3d,&_plot3d,_plot3d_s);
16204   define_unary_function_ptr5( at_plot3d ,alias_at_plot3d,&__plot3d,0,true);
16205 
16206   static const char _graphe3d_s []="graphe3d";
16207   static define_unary_function_eval (__graphe3d,&_plot3d,_graphe3d_s);
16208   define_unary_function_ptr5( at_graphe3d ,alias_at_graphe3d,&__graphe3d,0,true);
16209 
16210   // moved from prog.cc, for nosplit_polygon_function_alias
_inter(const gen & args,GIAC_CONTEXT)16211   gen _inter(const gen & args,GIAC_CONTEXT){
16212     if ( args.type==_STRNG && args.subtype==-1) return  args;
16213     vecteur attributs(1,default_color(contextptr));
16214     vecteur v(seq2vecteur(args));
16215     int s=read_attributs(v,attributs,contextptr);
16216     if (s!=2 && s!=3)
16217       return gendimerr(contextptr);
16218     gen a=v[0],b=v[1];
16219     vecteur ww=inter(a,b,contextptr);
16220     if (ww.size()==1 && ww.front().is_symb_of_sommet(at_inter)){
16221       // try equations (for ggb)
16222       if (a.is_symb_of_sommet(at_equal) ||b.is_symb_of_sommet(at_equal) ){
16223 	vecteur syst=makevecteur(remove_equal(a),remove_equal(b));
16224 	vecteur v=makevecteur(x__IDNT_e,y__IDNT_e);
16225 	vecteur sol=solve(syst,v,0,contextptr);
16226 	iterateur it=sol.begin(),itend=sol.end();
16227 	for (;it!=itend;++it){
16228 	  *it=change_subtype(*it,_GGB__VECT);
16229 	}
16230 	return sol;
16231       }
16232       gen eq=a-b;
16233       gen x=ggb_var(eq);
16234       vecteur sol,res;
16235 #ifndef NO_STDEXCEPT
16236       try {
16237 #endif
16238 	sol=solve(eq,*x._IDNTptr,0,contextptr);
16239 	iterateur it=sol.begin(),itend=sol.end();
16240 	for (;it!=itend;++it){
16241 	  *it=gen(makevecteur(*it,normal(subst(a,x,*it,false,contextptr),contextptr)),_GGB__VECT);
16242 	}
16243 	return sol;
16244 #ifndef NO_STDEXCEPT
16245       }
16246       catch (std::runtime_error &){
16247 	last_evaled_argptr(contextptr)=NULL;
16248 	return makevecteur(symbolic(at_inter,makesequence(a,b)));
16249       }
16250 #endif
16251     }
16252     vecteur w=remove_multiples(ww);
16253     if (s==3 && !w.empty()){
16254       int ws=int(w.size());
16255       a=w[0];
16256       gen c=v[2];
16257       gen d=distance2pp(a,c,contextptr);
16258       for (int i=1;i<ws;++i){
16259 	gen dcur=distance2pp(w[i],c,contextptr);
16260 	if (is_strictly_greater(d,dcur,contextptr)){
16261 	  d=dcur;
16262 	  a=w[i];
16263 	}
16264       }
16265     }
16266     else
16267       a=gen(w,_GROUP__VECT);
16268     return put_attributs(a,attributs,contextptr);
16269   }
16270   static const char _inter_s []="inter";
16271   static define_unary_function_eval (__inter,&_inter,_inter_s);
16272   define_unary_function_ptr5( at_inter ,alias_at_inter,&__inter,0,true);
16273 
_Bezier(const gen & args,GIAC_CONTEXT)16274   gen _Bezier(const gen & args,GIAC_CONTEXT){
16275     return symbolic(at_Bezier,args);
16276   }
16277   static const char _Bezier_s []="Bezier";
16278   static define_unary_function_eval (__Bezier,&_Bezier,_Bezier_s);
16279   define_unary_function_ptr5( at_Bezier ,alias_at_Bezier,&__Bezier,0,true);
16280 
_bezier(const gen & args,GIAC_CONTEXT)16281   gen _bezier(const gen & args,GIAC_CONTEXT){
16282     if (is_undef(args)) return args;
16283     vecteur v(gen2vecteur(args));
16284     if (v.empty())
16285       return gensizeerr(contextptr);
16286     vecteur attributs(1,default_color(contextptr));
16287     int s=read_attributs(v,attributs,contextptr);
16288     bool parameq=false;
16289     v=vecteur(v.begin(),v.begin()+s);
16290     if (v.back().type==_FUNC){
16291       parameq=true;
16292       v.pop_back();
16293     }
16294     bool d3=false;
16295     for (int i=0;i<s;++i){
16296       if (!d3) d3=is3d(v[i]);
16297       v[i]=remove_at_pnt(v[i]);
16298     }
16299     if (parameq){
16300       gen peq=_parameq(gen(makevecteur(symbolic(at_Bezier,gen(v,_GROUP__VECT)),t__IDNT_e),_SEQ__VECT),contextptr);
16301       if (d3)
16302 	return plotparam3d(peq,makevecteur(t__IDNT_e,v__IDNT_e),-1e300,1e300,-1e300,1e300,-1e300,1e300,0,1,0,1,false,true,attributs,0.01,0.01,undef,vecteur(0),contextptr);
16303       return plotparam(peq,t__IDNT_e,attributs,false,-1e300,1e300,-1e300,1e300,0,1,0.01,undef,peq,contextptr);
16304     }
16305     return pnt_attrib(symbolic(at_Bezier,gen(v,_GROUP__VECT)),attributs,contextptr);
16306   }
16307   static const char _bezier_s []="bezier";
16308   static define_unary_function_eval (__bezier,&_bezier,_bezier_s);
16309   define_unary_function_ptr5( at_bezier ,alias_at_bezier,&__bezier,0,true);
16310 
16311 #if defined(GIAC_GENERIC_CONSTANTS) || (defined(VISUALC) && !defined(RTOS_THREADX)) || defined(x86_64)
16312   unary_function_ptr plot_sommets[]={*at_pnt,*at_parameter,*at_cercle,*at_curve,*at_animation,0};
16313   unary_function_ptr not_point_sommets[]={*at_cercle,*at_curve,*at_hyperplan,*at_hypersphere,*at_hypersurface,0};
16314   unary_function_ptr notexprint_plot_sommets[]={*at_funcplot,*at_paramplot,*at_polarplot,*at_implicitplot,*at_contourplot,*at_odeplot,*at_interactive_odeplot,*at_fieldplot,*at_seqplot,*at_ellipse,*at_hyperbole,*at_parabole,0};
16315   unary_function_ptr implicittex_plot_sommets[]={*at_plot,*at_plot3d,*at_plotfunc,*at_plotparam,*at_plotpolar,*at_plotimplicit,*at_plotcontour,*at_DrawInv,*at_DrawFunc,*at_DrawParm,*at_DrawPol,*at_DrwCtour,*at_plotode,*at_plotfield,*at_interactive_plotode,*at_plotseq,*at_Graph,0};
16316   unary_function_ptr point_sommet_tab_op[]={*at_point,*at_element,*at_inter_unique,*at_centre,*at_isobarycentre,*at_barycentre,0};
16317   unary_function_ptr nosplit_polygon_function[]={*at_inter_unique,*at_inter,*at_distanceat,*at_distanceatraw,*at_rotation,*at_projection,*at_symetrie,*at_polaire_reciproque,*at_areaat,*at_areaatraw,*at_perimeterat,*at_perimeteratraw,*at_slopeat,*at_slopeatraw,*at_tangent,*at_cercle,0};
16318   unary_function_ptr measure_functions[]={*at_angleat,*at_angleatraw,*at_areaat,*at_areaatraw,*at_perimeterat,*at_perimeteratraw,*at_slopeat,*at_slopeatraw,*at_distanceat,*at_distanceatraw,0};
16319   unary_function_ptr transformation_functions[]={*at_projection,*at_rotation,*at_translation,*at_homothetie,*at_similitude,*at_inversion,*at_symetrie,*at_polaire_reciproque,0};
16320 
16321 #else
16322   const size_t plot_sommets_alias[]={(size_t)&__pnt,(size_t)&__parameter,(size_t)&__cercle,(size_t)&__curve,(size_t)&__animation,0};
16323   const unary_function_ptr * const plot_sommets = (const unary_function_ptr *) plot_sommets_alias;
16324 
16325   const size_t not_point_sommets_alias[]={(size_t)&__cercle,(size_t)&__curve,(size_t)&__hyperplan,(size_t)&__hypersphere,(size_t)&__hypersurface,0};
16326   const unary_function_ptr * const not_point_sommets = (const unary_function_ptr *) plot_sommets_alias;
16327 
16328   const size_t notexprint_plot_sommets_alias[]={(size_t)&__funcplot,(size_t)&__paramplot,(size_t)&__polarplot,(size_t)&__implicitplot,(size_t)&__contourplot,(size_t)&__odeplot,(size_t)&__interactive_odeplot,(size_t)&__fieldplot,(size_t)&__seqplot,(size_t)&__ellipse,(size_t)&__hyperbole,(size_t)&__parabole,0};
16329   const unary_function_ptr * const notexprint_plot_sommets = (const unary_function_ptr *) notexprint_plot_sommets_alias;
16330 
16331   const size_t implicittex_plot_sommets_alias[]={(size_t)&__plot,(size_t)&__plot3d,(size_t)&__plotfunc,(size_t)&__plotparam,(size_t)&__plotpolar,(size_t)&__plotimplicit,(size_t)&__plotcontour,(size_t)&__DrawInv,(size_t)&__DrawFunc,(size_t)&__DrawParm,(size_t)&__DrawPol,(size_t)&__DrwCtour,(size_t)&__plotode,(size_t)&__plotfield,(size_t)&__interactive_plotode,(size_t)&__plotseq,(size_t)&__Graph,0};
16332   const unary_function_ptr * const implicittex_plot_sommets = (const unary_function_ptr *) implicittex_plot_sommets_alias;
16333 
16334   const size_t point_sommet_tab_op_alias[]={(size_t)&__point,(size_t)&__element,(size_t)&__inter_unique,(size_t)&__centre,(size_t)&__isobarycentre,(size_t)&__barycentre,0};
16335   const unary_function_ptr * const point_sommet_tab_op = (const unary_function_ptr *) point_sommet_tab_op_alias;
16336 
16337   const size_t nosplit_polygon_function_alias[]={(size_t)&__inter_unique,(size_t)&__inter,(size_t)&__distanceatraw,(size_t)&__distanceat,(size_t)&__rotation,(size_t)&__projection,(size_t)&__symetrie,(size_t)&__polaire_reciproque,(size_t)&__areaat,(size_t)&__areaatraw,(size_t)&__perimeterat,(size_t)&__perimeteratraw,(size_t)&__slopeat,(size_t)&__slopeatraw,(size_t)&__tangent,(size_t)&__cercle,0};
16338   const unary_function_ptr * const nosplit_polygon_function = (const unary_function_ptr *) nosplit_polygon_function_alias;
16339 
16340   const size_t measure_functions_alias[]={(size_t)&__angleat,(size_t)&__angleatraw,(size_t)&__areaat,(size_t)&__areaatraw,(size_t)&__perimeterat,(size_t)&__perimeteratraw,(size_t)&__slopeat,(size_t)&__slopeatraw,(size_t)&__distanceat,(size_t)&__distanceatraw,0};
16341   const unary_function_ptr * const measure_functions = (const unary_function_ptr *) measure_functions_alias;
16342 
16343   const size_t transformation_functions_alias[]={(size_t)&__projection,(size_t)&__rotation,(size_t)&__translation,(size_t)&__homothetie,(size_t)&__similitude,(size_t)&__inversion,(size_t)&__symetrie,(size_t)&__polaire_reciproque,0};
16344   const unary_function_ptr * const transformation_functions = (const unary_function_ptr *) transformation_functions_alias;
16345 #endif
16346 
16347 #ifndef NO_NAMESPACE_GIAC
16348 } // namespace giac
16349 #endif // ndef NO_NAMESPACE_GIAC
16350