// -*- mode:C++ ; compile-command: "g++-3.4 -I. -I.. -I../include -I../../giac/include -g -c Graph3d.cc -DIN_GIAC -DHAVE_CONFIG_H" -*-
#include "Graph3d.h"
/*
* Copyright (C) 2006,2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#define __CARBONSOUND__
#ifdef HAVE_LIBFLTK_GL
#include
#include
#include
#include
#include
#include
#include
#include
#include "vector.h"
#include
#include
#include
#include // for nanosleep
#include
#include
#include // auto-recovery function
#include "path.h"
#ifndef IN_GIAC
#include
#else
#include "misc.h"
#endif
#include "Equation.h"
#include "Editeur.h"
#include "Xcas1.h"
#include "Print.h"
#include "gl2ps.h"
#ifdef __APPLE__
#include
#include
#include
#define __APPLE_QUARTZ__ 1
#include "Fl_Gl_Choice.H"
extern Fl_Gl_Choice * gl_choice;
// be sure to remove static declaration in gl_start.cxx in fltk src directory
#endif
#ifndef HAVE_PNG_H
#undef HAVE_LIBPNG
#endif
#ifdef HAVE_LIBPNG
#include
#endif
using namespace std;
using namespace giac;
#ifndef NO_NAMESPACE_XCAS
namespace xcas {
#endif // ndef NO_NAMESPACE_XCAS
std::map texture_cache;
int Graph3d::opengl2png(const std::string & filename){
#ifdef HAVE_LIBPNG
if (!screenbuf)
return -1;
int i;
// unsigned rowbytes = w()*4;
unsigned char *rows[h()];
for (i = 0; i < h(); i++) {
rows[i] = &screenbuf[(h() - i - 1)*4*w()];
}
int res= write_png(filename.c_str(), rows, w(), h(), PNG_COLOR_TYPE_RGBA, 8);
if (res!=-1){
string command="pngtopnm "+filename+" | pnmtops > "+remove_extension(filename)+".ps &";
cerr << command << endl;
system_no_deprecation(command.c_str());
command="pngtopnm "+filename+" | pnmtojpeg > "+remove_extension(filename)+".jpg &";
cerr << command << endl;
system_no_deprecation(command.c_str());
}
#endif
return -1;
}
double giac_max(double i,double j){
return i>j?i:j;
}
quaternion_double rotation_2_quaternion_double(double x, double y, double z,double theta){
double t=theta*M_PI/180;
double qx,qy,qz,qw,s=std::sin(t/2),c=std::cos(t/2);
qx=x*s;
qy=y*s;
qz=z*s;
qw=c;
double n=std::sqrt(qx*qx+qy*qy+qz*qz+qw*qw);
return quaternion_double(qw/n,qx/n,qy/n,qz/n);
}
void Graph3d::resize(int X,int Y,int W,int H){
int oldh=h(),oldw=w();
Graph2d3d::resize(X,Y,W,H);
if (screenbuf){
if (oldh==H && oldw==W)
return;
delete screenbuf;
}
screenbuf = new unsigned char[H*W*4];
}
Graph3d::Graph3d(int x,int y,int width, int height,const char* title,History_Pack * hp_):
Graph2d3d(x,y,width, height, title,hp_),
theta_z(-110),theta_x(-13),theta_y(-95),
delta_theta(5),draw_mode(GL_QUADS),printing(0),glcontext(0),dragi(0),dragj(0),push_in_area(false),depth(0),below_depth_hidden(false),screenbuf(0) {
// end();
// mode=0;
display_mode |= 0x80;
display_mode |= 0x200;
box(FL_FLAT_BOX);
couleur=_POINT_WIDTH_5;
q=euler_deg_to_quaternion_double(theta_z,theta_x,theta_y);
legende_size=max(min(legende_size,width/4),width/6);
resize(x,y,width-legende_size,height);
add_mouse_param_group(x,y,width,height);
// 8 light initialization
for (int i=0;i<8;++i)
reset_light(i);
}
// t angle in radians -> r,g,b
void arc_en_ciel2(double t,int & r,int & g,int &b){
int k=int(t/2/M_PI*126);
arc_en_ciel(k,r,g,b);
}
bool get_glvertex(const vecteur & v,double & d1,double & d2,double & d3,double realiscmplx,double zmin,GIAC_CONTEXT){
if (v.size()==3){
gen tmp;
tmp=evalf_double(v[0],2,contextptr);
if (tmp.type!=_DOUBLE_) return false;
d1=tmp._DOUBLE_val;
tmp=evalf_double(v[1],2,contextptr);
if (tmp.type!=_DOUBLE_) return false;
d2=tmp._DOUBLE_val;
tmp=evalf_double(v[2],2,contextptr);
if (realiscmplx){
double arg=0;
if (realiscmplx<0){
d3=evalf_double(im(tmp,contextptr),2,contextptr)._DOUBLE_val-zmin;
arg=-d3*realiscmplx;
}
else {
if (tmp.type==_DOUBLE_){
d3=tmp._DOUBLE_val;
if (d3<0){
arg=M_PI;
d3=-d3;
}
}
else {
if (tmp.type==_CPLX && tmp._CPLXptr->type==_DOUBLE_ && (tmp._CPLXptr+1)->type==_DOUBLE_){
double r=tmp._CPLXptr->_DOUBLE_val;
double i=(tmp._CPLXptr+1)->_DOUBLE_val;
arg=std::atan2(i,r);
d3=std::sqrt(r*r+i*i);
}
else
return false;
}
} // end realiscmplx>0
// set color corresponding to argument
int r,g,b;
arc_en_ciel2(arg,r,g,b);
glColor3f(r/255.,g/255.,b/255.);
// glColor4i(r,g,b,int(std::log(d3+1)));
} // end if (realiscmplx)
else {
if (tmp.type!=_DOUBLE_) return false;
d3=tmp._DOUBLE_val;
}
return true;
}
return false;
}
bool get_glvertex(const gen & g,double & d1,double & d2,double & d3,double realiscmplx,double zmin,GIAC_CONTEXT){
if (g.type!=_VECT)
return false;
return get_glvertex(*g._VECTptr,d1,d2,d3,realiscmplx,zmin,contextptr);
}
bool glvertex(const vecteur & v,double realiscmplx,double zmin,GIAC_CONTEXT){
double d1,d2,d3;
if (get_glvertex(v,d1,d2,d3,realiscmplx,zmin,contextptr)){
glVertex3d(d1,d2,d3);
return true;
}
return false;
}
void glraster(const vecteur & v){
if (v.size()==3){
double d1=evalf_double(v[0],2,context0)._DOUBLE_val;
double d2=evalf_double(v[1],2,context0)._DOUBLE_val;
double d3=evalf_double(v[2],2,context0)._DOUBLE_val;
glRasterPos3d(d1,d2,d3);
}
}
void glraster(const gen & g){
if (g.type==_VECT)
glraster(*g._VECTptr);
}
// draw s at g with mode= 0 (upper right), 1, 2 or 3
void Graph3d::legende_draw(const gen & g,const string & s,int mode){
context * contextptr=hp?hp->contextptr:get_context(this);
gen gf=evalf_double(g,1,contextptr);
if (gf.type==_VECT && gf._VECTptr->size()==3){
double Ax=gf[0]._DOUBLE_val;
double Ay=gf[1]._DOUBLE_val;
double Az=gf[2]._DOUBLE_val;
double Ai,Aj,Ad;
find_ij(Ax,Ay,Az,Ai,Aj,Ad);
int di=3,dj=1;
find_dxdy(s,mode,labelsize(),di,dj);
find_xyz(Ai+di,Aj+dj,Ad,Ax,Ay,Az);
glRasterPos3d(Ax,Ay,Az);
// string s1(s);
// cst_greek_translate(s1);
// draw_string(s1);
draw_string(s);
}
}
void glnormal(const vecteur & v){
if (v.size()==3){
double d1=evalf_double(v[0],2,context0)._DOUBLE_val;
double d2=evalf_double(v[1],2,context0)._DOUBLE_val;
double d3=evalf_double(v[2],2,context0)._DOUBLE_val;
glNormal3d(d1,d2,d3);
}
}
void glnormal(double d1,double d2,double d3,double e1,double e2,double e3,double f1,double f2,double f3){
double de1(e1-d1),de2(e2-d2),de3(e3-d3),df1(f1-d1),df2(f2-d2),df3(f3-d3);
glNormal3d(de2*df3-de3*df2,de3*df1-de1*df3,de1*df2-de2*df1);
}
void gltranslate(const vecteur & v){
if (v.size()==3){
double d1=evalf_double(v[0],2,context0)._DOUBLE_val;
double d2=evalf_double(v[1],2,context0)._DOUBLE_val;
double d3=evalf_double(v[2],2,context0)._DOUBLE_val;
glTranslated(d1,d2,d3);
}
}
void iso3d(const double &i1,const double &i2,const double &i3,const double &j1,const double &j2,const double &j3,const double &k1,const double &k2,const double &k3,double & x,double & y,double & z){
double X=x,Y=y,Z=z;
x=i1*X+j1*Y+k1*Z;
y=i2*X+j2*Y+k2*Z;
z=i3*X+j3*Y+k3*Z;
}
#define LI 64
#define LH 64
GLubyte image[LI][LH][3];
void makeImage(void) {
int i,j,c;
for( i = 0 ; i < LI ; i++ ) {
for( j = 0 ; j < LH ; j++ ) {
c = (((i&0x8)==0)^
((j&0x8)==0))*255;
image[i][j][0] =(GLubyte) c;
image[i][j][1] =(GLubyte) c;
image[i][j][2] =(GLubyte) c; } }
}
bool test_enable_texture(Fl_Image * texture){
if (!texture)
return false;
int depth=-1;
if (texture->count()==1)
depth=texture->d();
if (depth==3 || depth==4){
// define texture
// makeImage();
char * ptr=(char *)texture->data()[0];
/*
int W=texture->w(),H=texture->h();
for (int y=0;yw() and texture->h() must be a power of 2!!
glTexImage2D(GL_TEXTURE_2D,0,depth,
// LI,LH,
texture->w(),texture->h(),
0,
// GL_RGB,
(depth==3?GL_RGB:GL_RGBA),
GL_UNSIGNED_BYTE,
// &image[0][0][0]);
ptr);
// not periodically
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
// adjust to nearest
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,
// GL_NEAREST);
GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,
// GL_NEAREST);
GL_LINEAR);
//
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,
GL_MODULATE);
//GL_REPLACE);
glEnable(GL_TEXTURE_2D);
return true;
}
return false;
}
// Sphere centered at center, radius radius, i,j,k orthonormal, ntheta/nphi
// number of subdivisions
// mode=GL_QUADS for example
void glsphere(const vecteur & center,const gen & radius,const vecteur & i0,const vecteur & j0,const vecteur & k0,int ntheta,int nphi,int mode,Fl_Image * texture,GIAC_CONTEXT){
test_enable_texture(texture);
double c1=evalf_double(center[0],1,contextptr)._DOUBLE_val; // center
double c2=evalf_double(center[1],1,contextptr)._DOUBLE_val;
double c3=evalf_double(center[2],1,contextptr)._DOUBLE_val;
double r=evalf_double(radius,1,contextptr)._DOUBLE_val;
double i1=evalf_double(i0[0],1,contextptr)._DOUBLE_val;
double i2=evalf_double(i0[1],1,contextptr)._DOUBLE_val;
double i3=evalf_double(i0[2],1,contextptr)._DOUBLE_val;
double j1=evalf_double(j0[0],1,contextptr)._DOUBLE_val;
double j2=evalf_double(j0[1],1,contextptr)._DOUBLE_val;
double j3=evalf_double(j0[2],1,contextptr)._DOUBLE_val;
double k1=evalf_double(k0[0],1,contextptr)._DOUBLE_val;
double k2=evalf_double(k0[1],1,contextptr)._DOUBLE_val;
double k3=evalf_double(k0[2],1,contextptr)._DOUBLE_val;
double dtheta=2*M_PI/ntheta; // longitude
double dphi=M_PI/nphi; // latitude
double jsurtheta=0,isurphi=0,djsurtheta=1.0/ntheta,disurphi=1.0/nphi;
double parallele1[ntheta+1],parallele2[ntheta+1],parallele3[ntheta+1];
double x,y,z,oldx,oldy,oldz,X,Z;
// Set initial parallel to the North pole
for (int j=0;j<=ntheta;++j){
parallele1[j]=k1; parallele2[j]=k2; parallele3[j]=k3;
}
// parallele1/2/3 contains the coordinate of the previous parallel
for (int i=1;i<=nphi;i++,isurphi+=disurphi){
// longitude theta=0, latitude phi=i*dphi
X=std::sin(i*dphi); Z=std::cos(i*dphi);
oldx=X; oldy=0; oldz=Z;
iso3d(i1,i2,i3,j1,j2,j3,k1,k2,k3,oldx,oldy,oldz);
double * par1j=parallele1,* par2j=parallele2,*par3j=parallele3;
jsurtheta=0;
if (mode==GL_QUADS){
glBegin(GL_QUAD_STRIP);
for (int j=0;j<=ntheta;++par1j,++par2j,++par3j,jsurtheta+=djsurtheta){
glNormal3d(*par1j,*par2j,*par3j);
if (texture)
glTexCoord2f(jsurtheta,isurphi);
glVertex3d(c1+r*(*par1j),c2+r*(*par2j),c3+r*(*par3j));
if (texture)
glTexCoord2f(jsurtheta,isurphi+disurphi);
glVertex3d(c1+r*oldx,c2+r*oldy,c3+r*oldz);
*par1j=oldx; *par2j=oldy; *par3j=oldz;
// theta=j*dtheta, phi=i*dphi
++j;
x=X*std::cos(j*dtheta); y=X*std::sin(j*dtheta); z=Z;
iso3d(i1,i2,i3,j1,j2,j3,k1,k2,k3,x,y,z);
oldx=x; oldy=y; oldz=z;
}
glEnd();
}
else
{
for (int j=0;jsize()==3){
if (!is_zero(re(surface._VECTptr->back(),context0)))
return false;
gen s3=evalf_double(surface._VECTptr->back()/cst_i,2,context0);
if (s3.type==_DOUBLE_){
double s3d = s3._DOUBLE_val;
if (s3dzmax) zmax=s3d;
}
return true;
}
const_iterateur it=surface._VECTptr->begin(),itend=surface._VECTptr->end();
for (;it!=itend;++it){
if (!find_zscale(*it,zmin,zmax))
return false;
}
return true;
}
void glsurface(const gen & surfaceg,int draw_mode,Fl_Image * texture,GIAC_CONTEXT){
if (!ckmatrix(surfaceg,true))
return;
test_enable_texture(texture);
double realiscmplx=has_i(surfaceg),zmin=1e300,zmax=-1e300;
matrice & surface = *surfaceg._VECTptr;
if (realiscmplx && !texture){
if (find_zscale(surface,zmin,zmax))
realiscmplx=2*M_PI/(zmin-zmax);
}
int n=surface.size();
if (surfaceg.subtype==_POLYEDRE__VECT){
// implicit surface drawing with the given triangulation
if (draw_mode==GL_QUADS || draw_mode==GL_TRIANGLES){
glBegin(GL_TRIANGLES);
for (int i=0;isize()<2){
if (texture)
glDisable(GL_TEXTURE_2D);
return;
}
gen a,b,c,d;
double xt=0,yt,dxt=double(1)/n,dyt;
for (int i=1;isize()==3){
closed=true;
double dPx=evalf_double(dP[0],2,context0)._DOUBLE_val;
if (fabs(dPx)>(window_xmax-window_xmin)*1e-6)
closed=false;
double dPy=evalf_double(dP[1],2,context0)._DOUBLE_val;
if (fabs(dPy)>(window_ymax-window_ymin)*1e-6)
closed=false;
double dPz=evalf_double(dP[2],2,context0)._DOUBLE_val;
if (fabs(dPz)>(window_zmax-window_zmin)*1e-6)
closed=false;
}
return closed;
}
// translate giac GL constant to open GL constant
unsigned gl_translate(unsigned i){
switch (i){
case _GL_LIGHT0:
return GL_LIGHT0;
case _GL_LIGHT1:
return GL_LIGHT1;
case _GL_LIGHT2:
return GL_LIGHT2;
case _GL_LIGHT3:
return GL_LIGHT3;
case _GL_LIGHT4:
return GL_LIGHT4;
case _GL_LIGHT5:
return GL_LIGHT5;
case _GL_AMBIENT:
return GL_AMBIENT;
case _GL_SPECULAR:
return GL_SPECULAR;
case _GL_DIFFUSE:
return GL_DIFFUSE;
case _GL_POSITION:
return GL_POSITION;
case _GL_SPOT_DIRECTION:
return GL_SPOT_DIRECTION;
case _GL_SPOT_EXPONENT:
return GL_SPOT_EXPONENT;
case _GL_SPOT_CUTOFF:
return GL_SPOT_CUTOFF;
case _GL_CONSTANT_ATTENUATION:
return GL_CONSTANT_ATTENUATION;
case _GL_LINEAR_ATTENUATION:
return GL_LINEAR_ATTENUATION;
case _GL_QUADRATIC_ATTENUATION:
return GL_QUADRATIC_ATTENUATION;
case _GL_LIGHT_MODEL_AMBIENT:
return GL_LIGHT_MODEL_AMBIENT;
case _GL_LIGHT_MODEL_LOCAL_VIEWER:
return GL_LIGHT_MODEL_LOCAL_VIEWER;
case _GL_LIGHT_MODEL_TWO_SIDE:
return GL_LIGHT_MODEL_TWO_SIDE;
#ifndef WIN32
case _GL_LIGHT_MODEL_COLOR_CONTROL:
return GL_LIGHT_MODEL_COLOR_CONTROL;
#endif
case _GL_SMOOTH:
return GL_SMOOTH;
case _GL_FLAT:
return GL_FLAT;
case _GL_SHININESS:
return GL_SHININESS;
case _GL_FRONT:
return GL_FRONT;
case _GL_BACK:
return GL_BACK;
case _GL_FRONT_AND_BACK:
return GL_FRONT_AND_BACK;
case _GL_AMBIENT_AND_DIFFUSE:
return GL_AMBIENT_AND_DIFFUSE;
case _GL_EMISSION:
return GL_EMISSION;
#ifndef WIN32
case _GL_SEPARATE_SPECULAR_COLOR:
return GL_SEPARATE_SPECULAR_COLOR;
case _GL_SINGLE_COLOR:
return GL_SINGLE_COLOR;
#endif
case _GL_BLEND:
return GL_BLEND;
case _GL_SRC_ALPHA:
return GL_SRC_ALPHA;
case _GL_ONE_MINUS_SRC_ALPHA:
return GL_ONE_MINUS_SRC_ALPHA;
case _GL_COLOR_INDEXES:
return GL_COLOR_INDEXES;
}
cerr << "No GL equivalent for " << i << endl;
return i;
}
void tran4(double * colmat){
giac::swapdouble(colmat[1],colmat[4]);
giac::swapdouble(colmat[2],colmat[8]);
giac::swapdouble(colmat[3],colmat[12]);
giac::swapdouble(colmat[6],colmat[9]);
giac::swapdouble(colmat[7],colmat[13]);
giac::swapdouble(colmat[11],colmat[14]);
}
void get_texture(const gen & attrv1,Fl_Image * & texture){
// set texture
if (attrv1.type==_STRNG){
std::map::const_iterator it,itend=texture_cache.end();
it=texture_cache.find(*attrv1._STRNGptr);
if (it!=itend){
texture=it->second;
// texture->uncache();
}
else {
texture=Fl_Shared_Image::get(attrv1._STRNGptr->c_str());
if (texture){
int W=texture->w(),H=texture->h();
// take a power of 2 near w/h
W=1 << min(int(std::log(double(W))/std::log(2.)+.5),8);
H=1 << min(int(std::log(double(H))/std::log(2.)+.5),8);
texture=texture->copy(W,H);
texture_cache[*attrv1._STRNGptr]=texture;
}
}
}
}
int gen2int(const gen & g){
if (g.type==_INT_)
return g.val;
if (g.type==_DOUBLE_)
return int(g._DOUBLE_val);
setsizeerr(gettext("Unable to convert to int")+g.print());
return -1;
}
void Graph3d::indraw(const giac::gen & g){
context * contextptr=hp?hp->contextptr:get_context(this);
if (g.type==_VECT)
indraw(*g._VECTptr);
if (g.is_symb_of_sommet(at_animation)){
indraw(get_animation_pnt(g,animation_instructions_pos));
return;
}
if (!g.is_symb_of_sommet(at_pnt)){
update_infos(g,contextptr);
return;
}
gen & f=g._SYMBptr->feuille;
if (f.type!=_VECT)
return;
vecteur & v = *f._VECTptr;
gen v0=v[0];
bool est_hyperplan=v0.is_symb_of_sommet(at_hyperplan);
string legende;
vecteur style(get_style(v,legende));
int styles=style.size();
// color
bool hidden_name = false;
int ensemble_attributs=style.front().val;
if (style.front().type==_ZINT){
ensemble_attributs = mpz_get_si(*style.front()._ZINTptr);
hidden_name=true;
}
else
hidden_name=ensemble_attributs<0;
int couleur=ensemble_attributs & 0x0000ff;
int width =(ensemble_attributs & 0x00070000) >> 16; // 3 bits
int epaisseur_point =((ensemble_attributs & 0x00380000) >> 19)+1; // 3 bits
int type_line =(ensemble_attributs & 0x01c00000) >> 22; // 3 bits
int type_point =(ensemble_attributs & 0x0e000000) >> 25; // 3 bits
int labelpos =(ensemble_attributs & 0x30000000) >> 28; // 2 bits
bool fill_polygon =(ensemble_attributs & 0x40000000) >> 30;
hidden_name = hidden_name || legende.empty();
Fl_Image * texture=0;
glLineWidth(width+1);
gl2psLineWidth(width);
// FIXME line_stipple disabled because of printing
if (!printing)
glLineStipple(1,line_stipple(type_line));
else
glLineStipple(1,0xffff);
glPointSize(epaisseur_point);
gl2psPointSize(epaisseur_point);
if (styles<=2){
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);
}
else
glDisable(GL_COLOR_MATERIAL);
GLfloat tab[4]={0,0,0,1};
glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,tab);
glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,50);
glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,tab);
GLfloat tab1[4]={0.2,0.2,0.2,1};
glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,tab1);
GLfloat tab2[4]={0.8,0.8,0.8,1};
glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,tab2);
if (est_hyperplan){
glPolygonMode(GL_FRONT_AND_BACK,fill_polygon?GL_FILL:GL_LINE);
}
else {
glPolygonMode(GL_FRONT_AND_BACK,fill_polygon?GL_FILL:GL_LINE);
// glPolygonMode(GL_BACK,GL_POINT);
// glMaterialfv(GL_BACK,GL_EMISSION,tab);
// glMaterialfv(GL_BACK,GL_SPECULAR,tab);
// glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,tab);
}
// glGetFloatv(GL_CURRENT_COLOR,tab);
// set other style attributs :
/* material = [gl_front|gl_back|gl_front_and_back,gl_shininess,valeur] or
material = [gl_front|gl_back|gl_front_and_back, GL_AMBIENT| GL_DIFFUSE |
GL_SPECULAR | GL_EMISSION | GL_AMBIENT_AND_DIFFUSE | GL_COLOR_INDEXES,
[r,g,b,a] ]
last arg is [ambient,diffuse,specular] for GL_COLOR_INDEXES
or
material=[gl_texture,"image_filename",...]
*/
for (int i=2;i=2 && attrv.front().type==_INT_ && attrv.front().val==_GL_TEXTURE){
get_texture(attrv[1],texture);
continue;
}
if (attrv.size()==2 && attrv.front().type==_INT_ && attrv.front().val==_GL_MATERIAL){
gen attrm =evalf_double(attrv.back(),1,contextptr);
if (debug_infolevel)
cerr << "Setting material " << attrm << endl;
if (attrm.type==_VECT && attrm._VECTptr->size()<=3 ){
gen attrv0=attrv.back()._VECTptr->front();
if (attrv0.type==_INT_ && attrv0.val==_GL_TEXTURE){
gen attrv1=(*attrv.back()._VECTptr)[1];
get_texture(attrv1,texture);
continue;
}
vecteur & attrmv = *attrm._VECTptr;
if (attrmv.back().type==_VECT && attrmv.back()._VECTptr->size()==4){
vecteur & w=*attrmv.back()._VECTptr;
GLfloat tab[4]={w[0]._DOUBLE_val,w[1]._DOUBLE_val,w[2]._DOUBLE_val,w[3]._DOUBLE_val};
glMaterialfv(gl_translate(gen2int(attrmv[0])),gl_translate(gen2int(attrmv[1])),tab);
continue;
}
if (attrmv.back().type==_VECT && attrmv.back()._VECTptr->size()==3){
vecteur & w=*attrmv.back()._VECTptr;
GLfloat tab[3]={w[0]._DOUBLE_val,w[1]._DOUBLE_val,w[2]._DOUBLE_val};
glMaterialfv(gl_translate(gen2int(attrmv[0])),GL_COLOR_INDEXES,tab);
continue;
}
if (attrmv.back().type==_DOUBLE_ && attrmv[1]._DOUBLE_val==_GL_SHININESS){
// glMaterialf(gl_translate(gen2int(attrmv[0])),GL_SHININESS,float(attrmv[2]._DOUBLE_val));
glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,float(attrmv[2]._DOUBLE_val));
continue;
}
}
}
}
}
if (texture){
fill_polygon=true;
couleur=FL_WHITE;
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
}
bool hidden_line = fill_polygon && (width==7 || (display_mode & 0x8) || texture );
xcas_color(couleur,true);
if (debug_infolevel){
cerr << "opengl displaying " << g << endl;
GLint b;
GLfloat posf[4],direcf[4],ambient[4],diffuse[4],specular[4],emission[4],shini[1];
GLfloat expo,cutoff;
double pos[4],direc[4];
glGetIntegerv(GL_BLEND,&b);
cerr << "blend " << b << endl;
for (int i=0;i<8;++i){
glGetIntegerv(GL_LIGHT0+i,&b);
if (b){
glGetLightfv(GL_LIGHT0+i,GL_SPOT_EXPONENT,&expo);
glGetLightfv(GL_LIGHT0+i,GL_SPOT_CUTOFF,&cutoff);
glGetLightfv(GL_LIGHT0+i,GL_POSITION,posf);
glGetLightfv(GL_LIGHT0+i,GL_SPOT_DIRECTION,direcf);
direcf[3]=0; // 4 was out of bound
mult4(model_inv,posf,pos);
tran4(model);
mult4(model,direcf,direc);
tran4(model);
glGetLightfv(GL_LIGHT0+i,GL_AMBIENT,ambient);
glGetLightfv(GL_LIGHT0+i,GL_DIFFUSE,diffuse);
glGetLightfv(GL_LIGHT0+i,GL_SPECULAR,specular);
cerr << "light " << i << ": " <<
" pos " << pos[0] << "," << pos[1] << "," << pos[2] << "," << pos[3] <<
" dir " << direc[0] << "," << direc[1] << "," << direc[2] << "," << direc[3] <<
" ambient " << ambient[0] << "," << ambient[1] << "," << ambient[2] << "," << ambient[3] <<
" diffuse " << diffuse[0] << "," << diffuse[1] << "," << diffuse[2] << "," << diffuse[3] <<
" specular " << specular[0] << "," << specular[1] << "," << specular[2] << "," << specular[3] <<
" exponent " << expo << " cutoff " << cutoff << endl;
}
}
// material colors
glGetMaterialfv(GL_FRONT,GL_AMBIENT,ambient);
glGetMaterialfv(GL_FRONT,GL_DIFFUSE,diffuse);
glGetMaterialfv(GL_FRONT,GL_SPECULAR,specular);
glGetMaterialfv(GL_FRONT,GL_EMISSION,emission);
glGetMaterialfv(GL_FRONT,GL_SHININESS,shini);
cerr << "front " << ": " <<
" ambient " << ambient[0] << "," << ambient[1] << "," << ambient[2] << "," << ambient[3] <<
" diffuse " << diffuse[0] << "," << diffuse[1] << "," << diffuse[2] << "," << diffuse[3] <<
" specular " << specular[0] << "," << specular[1] << "," << specular[2] << "," << specular[3] <<
" emission " << emission[0] << "," << emission[1] << "," << emission[2] << "," << emission[3] <<
" shininess " << shini[0] << endl;
glGetMaterialfv(GL_BACK,GL_AMBIENT,ambient);
glGetMaterialfv(GL_BACK,GL_DIFFUSE,diffuse);
glGetMaterialfv(GL_BACK,GL_SPECULAR,specular);
glGetMaterialfv(GL_BACK,GL_EMISSION,emission);
glGetMaterialfv(GL_BACK,GL_SHININESS,shini);
cerr << "back " << ": " <<
" ambient " << ambient[0] << "," << ambient[1] << "," << ambient[2] << "," << ambient[3] <<
" diffuse " << diffuse[0] << "," << diffuse[1] << "," << diffuse[2] << "," << diffuse[3] <<
" specular " << specular[0] << "," << specular[1] << "," << specular[2] << "," << specular[3] <<
" emission " << emission[0] << "," << emission[1] << "," << emission[2] << "," << emission[3] <<
" shininess " << shini[0] << endl;
}
if (est_hyperplan){
vecteur P,n;
if (!hyperplan_normal_point(v0,n,P))
return;
P=*evalf_double(P,1,contextptr)._VECTptr;
vecteur Porig(P);
double n1=evalf_double(n[0],1,contextptr)._DOUBLE_val;
double n2=evalf_double(n[1],1,contextptr)._DOUBLE_val;
double n3=evalf_double(n[2],1,contextptr)._DOUBLE_val;
if (fill_polygon){
vecteur v1,v2;
if (!normal3d(n,v1,v2))
return;
double v11=evalf_double(v1[0],1,contextptr)._DOUBLE_val;
double v12=evalf_double(v1[1],1,contextptr)._DOUBLE_val;
double v13=evalf_double(v1[2],1,contextptr)._DOUBLE_val;
double v21=evalf_double(v2[0],1,contextptr)._DOUBLE_val;
double v22=evalf_double(v2[1],1,contextptr)._DOUBLE_val;
double v23=evalf_double(v2[2],1,contextptr)._DOUBLE_val;
// moves P along v1 so that one coordinate is in clip
if (std::abs(v11)>=std::abs(v12) && std::abs(v11)>=std::abs(v13)){
P=addvecteur(P,multvecteur((window_xmin-P[0])/v11,v1));
}
if (std::abs(v12)>std::abs(v11) && std::abs(v12)>=std::abs(v13)){
P=addvecteur(P,multvecteur((window_ymin-P[1])/v12,v1));
}
if (std::abs(v13)>std::abs(v11) && std::abs(v13)>std::abs(v12)){
P=addvecteur(P,multvecteur((window_zmin-P[2])/v13,v1));
}
// find a large constant so that the points are outside clipping
double v31=v11+v21,v32=v12+v22,v33=v13+v23,v41=v11-v21,v42=v12-v22,v43=v13-v23;
double nv3=std::sqrt(v31*v31+v32*v32+v33*v33);
double nv4=std::sqrt(v41*v41+v42*v42+v43*v43);
double lambda=1;
if (std::abs(v31)>0.1*nv3)
lambda=giac_max(lambda,(window_xmax-window_xmin)/std::abs(v31));
if (std::abs(v32)>0.1*nv3)
lambda=giac_max(lambda,(window_ymax-window_ymin)/std::abs(v32));
if (std::abs(v33)>0.1*nv3)
lambda=giac_max(lambda,(window_zmax-window_zmin)/std::abs(v33));
if (std::abs(v41)>0.1*nv4)
lambda=giac_max(lambda,(window_xmax-window_xmin)/std::abs(v41));
if (std::abs(v42)>0.1*nv4)
lambda=giac_max(lambda,(window_ymax-window_ymin)/std::abs(v42));
if (std::abs(v43)>0.1*nv4)
lambda=giac_max(lambda,(window_zmax-window_zmin)/std::abs(v43));
lambda *= 2;
if (display_mode & 0x8){
// if lighting enabled, we must draw small quads otherwise
// light will be incorrectly rendered (vertices too far)
// divide v1 and v2 by 10 (100 quads)
P=subvecteur(P,multvecteur(lambda,addvecteur(v1,v2))); // base point
unsigned hyperplan_light_rep=10;
v1=multvecteur(2*double(lambda)/hyperplan_light_rep,v1);
v2=multvecteur(2*double(lambda)/hyperplan_light_rep,v2);
for (unsigned j=1;j=std::abs(n2) && std::abs(n1)>=std::abs(n3)){
// x=a*y+b*z+c
double a=-n2/n1, b=-n3/n1;
double c=evalf_double(P[0]-a*P[1]-b*P[2],1,contextptr)._DOUBLE_val;
double dy=(window_ymax-window_ymin)/10;
for (int j=0;j<=10;++j){
double y=window_ymin+j*dy;
glBegin(GL_LINES);
glVertex3d(a*y+b*window_zmin+c,y,window_zmin);
glVertex3d(a*y+b*window_zmax+c,y,window_zmax);
glEnd();
}
double dz=(window_zmax-window_zmin)/10;
for (int j=0;j<=10;++j){
double z=window_zmin+j*dz;
glBegin(GL_LINES);
glVertex3d(a*window_ymin+b*z+c,window_ymin,z);
glVertex3d(a*window_ymax+b*z+c,window_ymax,z);
glEnd();
}
}
if (std::abs(n2)>std::abs(n1) && std::abs(n2)>=std::abs(n3)){
// y=a*x+b*z+c
double a=-n1/n2, b=-n3/n2;
double c=evalf_double(P[1]-a*P[0]-b*P[2],1,contextptr)._DOUBLE_val;
double dx=(window_xmax-window_xmin)/10;
for (int j=0;j<=10;++j){
double x=window_xmin+j*dx;
glBegin(GL_LINES);
glVertex3d(x,a*x+b*window_zmin+c,window_zmin);
glVertex3d(x,a*x+b*window_zmax+c,window_zmax);
glEnd();
}
double dz=(window_zmax-window_zmin)/10;
for (int j=0;j<=10;++j){
double z=window_zmin+j*dz;
glBegin(GL_LINES);
glVertex3d(window_xmin,a*window_xmin+b*z+c,z);
glVertex3d(window_xmax,a*window_xmax+b*z+c,z);
glEnd();
}
}
if (std::abs(n3)>std::abs(n1) && std::abs(n3)>std::abs(n2)){
// z=a*x+b*y+c
double a=-n1/n3, b=-n2/n3;
double c=evalf_double(P[2]-a*P[0]-b*P[1],1,contextptr)._DOUBLE_val;
double dx=(window_xmax-window_xmin)/10;
for (int j=0;j<=10;++j){
double x=window_xmin+j*dx;
glBegin(GL_LINES);
glVertex3d(x,window_ymin,a*x+b*window_ymin+c);
glVertex3d(x,window_ymax,a*x+b*window_ymax+c);
glEnd();
}
double dy=(window_ymax-window_ymin)/10;
for (int j=0;j<=10;++j){
double y=window_ymin+j*dy;
glBegin(GL_LINES);
glVertex3d(window_xmin,y,a*window_xmin+b*y+c);
glVertex3d(window_xmax,y,a*window_xmax+b*y+c);
glEnd();
}
}
}
if (!hidden_name && show_names)
legende_draw(Porig,legende,labelpos);
return;
}
if (v0.is_symb_of_sommet(at_hypersphere)){
gen & f=v0._SYMBptr->feuille;
if (f.type==_VECT && f._VECTptr->size()>=2){
vecteur & v=*f._VECTptr;
// Check that center is a 3-d point
if (v.front().type==_VECT && v.front()._VECTptr->size()==3){
// Radius
gen r=v[1];
if (r.type==_VECT && r._VECTptr->size()==3)
r=l2norm(*r._VECTptr,contextptr);
// Direction of axis, parallels and meridiens
vecteur dir1(makevecteur(1,0,0)),dir2(makevecteur(0,1,0)),dir3(makevecteur(0,0,1));
if (v.size()>=3 && v[2].type==_VECT && v[2]._VECTptr->size()==3){
dir3=*v[2]._VECTptr;
dir3=divvecteur(dir3,sqrt(dotvecteur(dir3,dir3),contextptr));
if (v.size()>=4 && v[3].type==_VECT && v[3]._VECTptr->size()==3){
dir1=*v[3]._VECTptr;
dir1=divvecteur(dir1,sqrt(dotvecteur(dir1,dir1),contextptr));
}
else {
if (!is_zero(dir3[0]) || !is_zero(dir3[1]) ){
dir1=makevecteur(-dir3[1],dir3[0],0);
dir1=divvecteur(dir1,sqrt(dotvecteur(dir1,dir1),contextptr));
}
}
dir2=cross(dir3,dir1,contextptr);
}
// optional discretisation info for drawing
if (v.size()>=5 && v[4].type==_INT_){
nphi=max(absint(v[4].val),3);
ntheta=ntheta;
}
if (v.size()>=6 && v[5].type==_INT_){
ntheta=max(absint(v[5].val),3);
}
// Now make the sphere
if (fill_polygon){
glsphere(*v.front()._VECTptr,r,dir1,dir2,dir3,ntheta,nphi,GL_QUADS,texture,contextptr);
}
if (!hidden_line){
if (fill_polygon)
glColor3d(0,0,0);
glsphere(*v.front()._VECTptr,r,dir1,dir2,dir3,min(ntheta,36),min(nphi,36),GL_LINE_LOOP,texture,contextptr);
xcas_color(couleur,true);
}
if (!hidden_name && show_names) legende_draw(v.front(),legende,labelpos);
}
}
return;
}
if (v0.is_symb_of_sommet(at_curve) && v0._SYMBptr->feuille.type==_VECT && !v0._SYMBptr->feuille._VECTptr->empty()){
gen & f = v0._SYMBptr->feuille._VECTptr->front();
// f = vect[ pnt,var,xmin,xmax ]
if (f.type==_VECT && f._VECTptr->size()>=4){
vecteur & vf = *f._VECTptr;
if (vf.size()>4){
gen poly=vf[4];
if (ckmatrix(poly)){
const_iterateur it=poly._VECTptr->begin(),itend=poly._VECTptr->end();
bool closed=fill_polygon && !(display_mode & 0x8); // ?is_approx_zero(poly._VECTptr->back()-poly._VECTptr->front(),window_xmin,window_xmax,window_ymin,window_ymax,window_zmin,window_zmax):false;
if (it->_VECTptr->size()==3){
glBegin(closed?GL_POLYGON:GL_LINE_STRIP);
// if (closed) ++it;
for (;it!=itend;++it){
if (!glvertex(*it->_VECTptr,0,0,contextptr)){
glEnd();
glBegin(closed?GL_POLYGON:GL_LINE_STRIP);
}
}
glEnd();
if (!hidden_name && show_names && !poly._VECTptr->empty()) legende_draw(poly._VECTptr->front(),legende,labelpos);
return ;
}
}
}
gen point=vf[0];
gen var=vf[1];
gen mini=vf[2];
gen maxi=vf[3];
bool closed=false;
if (fill_polygon && !(display_mode & 0x8) )
closed=is_approx_zero(subst(point,var,mini,false,contextptr)-subst(point,var,maxi,false,contextptr),window_xmin,window_xmax,window_ymin,window_ymax,window_zmin,window_zmax);
int n=nphi*10;
gen delta=(maxi-mini)/n;
glBegin(closed?GL_POLYGON:GL_LINE_STRIP);
for (int i=closed?1:0;i<=n;++i){
if (!glvertex(*subst(point,var,mini,false,contextptr)._VECTptr,0,0,contextptr)){
glEnd();
glBegin(closed?GL_POLYGON:GL_LINE_STRIP);
}
mini = mini + delta;
}
glEnd();
if (!hidden_name && show_names) legende_draw(mini,legende,labelpos);
}
return;
}
if (v0.is_symb_of_sommet(at_hypersurface)){
gen & f = v0._SYMBptr->feuille;
if (f.type!=_VECT || f._VECTptr->size()<3)
return;
gen & tmp = f._VECTptr->front();
if (tmp.type!=_VECT || tmp._VECTptr->size()<4)
return;
if (tmp._VECTptr->size()>4){
if (!fill_polygon)
glsurface((*tmp._VECTptr)[4],GL_LINE_LOOP,texture,contextptr);
else {
glsurface((*tmp._VECTptr)[4],GL_QUADS,texture,contextptr);
// glLineWidth(width+2);
if (!hidden_line){
glColor3d(0,0,0);
glsurface((*tmp._VECTptr)[4],GL_LINE_LOOP,texture,contextptr);
xcas_color(couleur,true);
}
}
// if (!hidden_name && show_names) legende_draw(legende.c_str());
return;
}
gen point = tmp._VECTptr->front(); // [x(u,v),y(u,v),z(u,v)]
gen vars = (*tmp._VECTptr)[1]; // [u,v]
gen mini = (*tmp._VECTptr)[2]; // [umin,vmin]
gen maxi = (*tmp._VECTptr)[3]; // [umax,vmax]
if (!check3dpoint(point) ||
vars.type!=_VECT || vars._VECTptr->size()!=2
|| mini.type!=_VECT || mini._VECTptr->size()!=2
|| maxi.type!=_VECT || maxi._VECTptr->size()!=2 )
return;
double umin=evalf_double(mini._VECTptr->front(),1,contextptr)._DOUBLE_val;
double vmin=evalf_double(mini._VECTptr->back(),1,contextptr)._DOUBLE_val;
double umax=evalf_double(maxi._VECTptr->front(),1,contextptr)._DOUBLE_val;
double vmax=evalf_double(maxi._VECTptr->back(),1,contextptr)._DOUBLE_val;
if (fill_polygon){
glsurface(*point._VECTptr,vars,umin,umax,vmin,vmax,ntheta,nphi,GL_QUADS,contextptr);
if (!hidden_line){
glColor3d(0,0,0);
glsurface(*point._VECTptr,vars,umin,umax,vmin,vmax,ntheta,nphi,GL_LINE_LOOP,contextptr);
xcas_color(couleur,true);
}
}
else
glsurface(*point._VECTptr,vars,umin,umax,vmin,vmax,ntheta,nphi,GL_LINE_LOOP,contextptr);
// if (!hidden_name && show_names) legende_draw(?,legende,labelpos);
return;
}
if (v0.type==_VECT && v0.subtype==_POINT__VECT && v0._VECTptr->size()==3 ){
gen A(evalf_double(v0,1,contextptr));
if (A.type==_VECT && A._VECTptr->size()==3 && type_point!=4){
double xA=A._VECTptr->front()._DOUBLE_val;
double yA=(*A._VECTptr)[1]._DOUBLE_val;
double zA=A._VECTptr->back()._DOUBLE_val;
double iA,jA,depthA;
find_ij(xA,yA,zA,iA,jA,depthA);
glLineWidth(1+epaisseur_point/2);
switch(type_point){
case 0:
glBegin(GL_LINES);
find_xyz(iA-epaisseur_point,jA-epaisseur_point,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
find_xyz(iA+epaisseur_point,jA+epaisseur_point,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
find_xyz(iA-epaisseur_point,jA+epaisseur_point,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
find_xyz(iA+epaisseur_point,jA-epaisseur_point,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
glEnd();
break;
case 1:
// 1 losange,
glBegin(GL_LINE_LOOP);
find_xyz(iA-epaisseur_point,jA,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
find_xyz(iA,jA+epaisseur_point,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
find_xyz(iA+epaisseur_point,jA,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
find_xyz(iA,jA-epaisseur_point,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
glEnd();
break;
case 2: // 2 croix verticale,
glBegin(GL_LINES);
find_xyz(iA,jA-epaisseur_point,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
find_xyz(iA,jA+epaisseur_point,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
find_xyz(iA-epaisseur_point,jA,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
find_xyz(iA+epaisseur_point,jA,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
glEnd();
break;
case 3: // 3 carre.
glBegin(GL_LINE_LOOP);
find_xyz(iA-epaisseur_point,jA-epaisseur_point,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
find_xyz(iA+epaisseur_point,jA-epaisseur_point,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
find_xyz(iA+epaisseur_point,jA+epaisseur_point,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
find_xyz(iA-epaisseur_point,jA+epaisseur_point,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
glEnd();
break;
case 5: // 5 triangle,
glBegin(GL_LINE_LOOP);
find_xyz(iA+epaisseur_point,jA-epaisseur_point,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
find_xyz(iA+epaisseur_point,jA+epaisseur_point,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
find_xyz(iA-epaisseur_point,jA,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
glEnd();
break;
case 6: // 6 etoile,
glBegin(GL_LINES);
find_xyz(iA,jA-epaisseur_point,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
find_xyz(iA,jA+epaisseur_point,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
find_xyz(iA-epaisseur_point/2,jA+epaisseur_point,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
find_xyz(iA+epaisseur_point/2,jA-epaisseur_point,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
find_xyz(iA-epaisseur_point/2,jA-epaisseur_point,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
find_xyz(iA+epaisseur_point/2,jA+epaisseur_point,depthA,xA,yA,zA);
glVertex3d(xA,yA,zA);
glEnd();
break;
default: // 7 point
glBegin(GL_POINTS);
glvertex(*v0._VECTptr,0,0,contextptr);
glEnd();
}
glLineWidth(width+1);
}
if (!hidden_name && show_names)
legende_draw(v0,legende,labelpos);
return;
}
if (v0.type==_VECT && v0.subtype!=_POINT__VECT){
vecteur & vv0=*v0._VECTptr;
vecteur w,lastpnt;
if (v0.subtype==_POLYEDRE__VECT){
// each element of v is a face
const_iterateur it=vv0.begin(),itend=vv0.end();
for (;it!=itend;++it){
if (it->type==_VECT){
w = *evalf_double(*it,1,contextptr)._VECTptr;
int s=w.size();
if (s<3)
continue;
double d1,d2,d3,e1,e2,e3,f1,f2,f3;
if (get_glvertex(w[0],d1,d2,d3,0,0,contextptr) &&
get_glvertex(w[1],e1,e2,e3,0,0,contextptr) &&
get_glvertex(w[2],f1,f2,f3,0,0,contextptr) ){
glnormal(d1,d2,d3,e1,e2,e3,f1,f2,f3);
if (fill_polygon){
glBegin(GL_POLYGON);
glVertex3d(d1,d2,d3);
glVertex3d(e1,e2,e3);
glVertex3d(f1,f2,f3);
for (int j=3;jsize()!=3)
glvertex(vecteur(3,0),0,0,contextptr);
else
glvertex( lastpnt=*w[j]._VECTptr,0,0,contextptr );
}
glEnd();
xcas_color(couleur,true);
// FIXME?? back face
/*
glnormal(f1,f2,f3,e1,e2,e3,d1,d2,d3);
glBegin(GL_POLYGON);
for (int j=s-1;j>=3;--j){
if (w[j].type!=_VECT || w[j]._VECTptr->size()!=3)
glvertex(vecteur(3,0),0,0,contextptr);
else
glvertex( *w[j]._VECTptr ,0,0,contextptr);
}
glVertex3d(f1,f2,f3);
glVertex3d(e1,e2,e3);
glVertex3d(d1,d2,d3);
glEnd();
*/
}
}
}
}
for (it=vv0.begin();it!=itend;++it){
if (it->type==_VECT){
w = *evalf_double(*it,1,contextptr)._VECTptr;
int s=w.size();
if (s<3)
continue;
double d1,d2,d3,e1,e2,e3,f1,f2,f3;
if (get_glvertex(w[0],d1,d2,d3,0,0,contextptr) &&
get_glvertex(w[1],e1,e2,e3,0,0,contextptr) &&
get_glvertex(w[2],f1,f2,f3,0,0,contextptr) ){
glnormal(d1,d2,d3,e1,e2,e3,f1,f2,f3);
if (!hidden_line){
glColor3d(0,0,0);
glBegin(GL_LINE_LOOP);
glVertex3d(d1,d2,d3);
glVertex3d(e1,e2,e3);
glVertex3d(f1,f2,f3);
for (int j=3;jsize()!=3)
glvertex(vecteur(3,0),0,0,contextptr);
else
glvertex( lastpnt=*w[j]._VECTptr,0,0,contextptr );
}
glEnd();
xcas_color(couleur,true);
}
}
} // end it->type==_VECT
} // end for (;it!=itend;)
if (!hidden_name && show_names) legende_draw(lastpnt,legende,labelpos);
return;
} // end polyedre
int s=vv0.size();
if (s==2 && check3dpoint(vv0.front()) && check3dpoint(vv0.back()) ){
// segment, half-line, vector or line
vecteur A(*evalf_double(vv0.front(),1,contextptr)._VECTptr),B(*evalf_double(vv0.back(),1,contextptr)._VECTptr);
vecteur dir(subvecteur(B,A));
double lambda=1,nu;
double d1=evalf_double(dir[0],1,contextptr)._DOUBLE_val;
double d2=evalf_double(dir[1],1,contextptr)._DOUBLE_val;
double d3=evalf_double(dir[2],1,contextptr)._DOUBLE_val;
double nd=std::sqrt(d1*d1+d2*d2+d3*d3);
if (std::abs(d1)>=std::abs(d2) && std::abs(d1)>=std::abs(d3)){
nu=(window_xmin-evalf_double(A[0],1,contextptr)._DOUBLE_val)/d1;
}
if (std::abs(d2)>std::abs(d1) && std::abs(d2)>=std::abs(d3)){
nu=(window_ymin-evalf_double(A[1],1,contextptr)._DOUBLE_val)/d2;
}
if (std::abs(d3)>std::abs(d1) && std::abs(d3)>std::abs(d2)){
nu=(window_zmin-evalf_double(A[2],1,contextptr)._DOUBLE_val)/d3;
}
if (std::abs(d1)>=0.1*nd)
lambda=giac_max(lambda,(window_xmax-window_xmin)/std::abs(d1));
if (std::abs(d2)>=0.1*nd)
lambda=giac_max(lambda,(window_ymax-window_ymin)/std::abs(d2));
if (std::abs(d3)>=0.1*nd)
lambda=giac_max(lambda,(window_ymax-window_ymin)/std::abs(d3));
lambda *= 2;
glBegin(GL_LINE_STRIP);
if (v0.subtype==_LINE__VECT){
// move A in clip
A=addvecteur(A,multvecteur(nu,dir));
B=subvecteur(B,multvecteur(nu,dir));
glvertex(subvecteur(A,multvecteur(lambda,dir)),0,0,contextptr);
glvertex(addvecteur(A,multvecteur(lambda,dir)),0,0,contextptr);
}
else {
glvertex(A,0,0,contextptr);
if (v0.subtype==_HALFLINE__VECT)
glvertex(addvecteur(A,multvecteur(lambda,dir)),0,0,contextptr);
else
glvertex(B,0,0,contextptr);
}
glEnd();
if (v0.subtype==_VECTOR__VECT){
double xB=evalf_double(B[0],1,contextptr)._DOUBLE_val;
double yB=evalf_double(B[1],1,contextptr)._DOUBLE_val;
double zB=evalf_double(B[2],1,contextptr)._DOUBLE_val;
double xA=evalf_double(A[0],1,contextptr)._DOUBLE_val;
double yA=evalf_double(A[1],1,contextptr)._DOUBLE_val;
double zA=evalf_double(A[2],1,contextptr)._DOUBLE_val;
/* 2-d code */
double iA,jA,depthA,iB,jB,depthB,di,dj,dij;
find_ij(xB,yB,zB,iB,jB,depthB);
find_ij(xA,yA,zA,iA,jA,depthA);
di=iA-iB; dj=jA-jB;
dij=std::sqrt(di*di+dj*dj);
if (dij){
dij /= min(5,int(dij/10))+width;
di/=dij;
dj/=dij;
double dip=-dj,djp=di;
di*=std::sqrt(3.0);
dj*=std::sqrt(3.0);
double iC=iB+di+dip,jC=jB+dj+djp;
double iD=iB+di-dip,jD=jB+dj-djp;
double xC,yC,zC,xD,yD,zD;
find_xyz(iC,jC,depthB,xC,yC,zC);
find_xyz(iD,jD,depthB,xD,yD,zD);
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
glBegin(GL_POLYGON);
glVertex3d(xB,yB,zB);
glVertex3d(xC,yC,zC);
glVertex3d(xD,yD,zD);
glEnd();
}
}
if (!hidden_name && show_names && v0.subtype!=_GROUP__VECT)
legende_draw(multvecteur(0.5,addvecteur(A,B)),legende,labelpos);
return;
}
if (s>2){ // polygon
bool closed=vv0.front()==vv0.back();
double d1,d2,d3,e1,e2,e3,f1,f2,f3;
if (get_glvertex(vv0[0],d1,d2,d3,0,0,contextptr) &&
get_glvertex(vv0[1],e1,e2,e3,0,0,contextptr) &&
get_glvertex(vv0[2],f1,f2,f3,0,0,contextptr) ){
if (test_enable_texture(texture) && s<=5 && closed){
glBegin(GL_QUADS);
glnormal(d1,d2,d3,e1,e2,e3,f1,f2,f3);
glTexCoord2f(0,0);
glVertex3d(d1,d2,d3);
glTexCoord2f(0,1);
glVertex3d(e1,e2,e3);
glTexCoord2f(1,1);
glVertex3d(f1,f2,f3);
if (s==5){
glTexCoord2f(1,0);
glvertex(*vv0[3]._VECTptr,0,0,contextptr);
}
else
glVertex3d(d1,d2,d3);
glEnd();
glDisable(GL_TEXTURE_2D);
}
else {
glBegin(closed?GL_POLYGON:GL_LINE_STRIP);
glnormal(d1,d2,d3,e1,e2,e3,f1,f2,f3);
const_iterateur it=vv0.begin(),itend=vv0.end();
if (closed)
++it;
for (;it!=itend;++it){
if (check3dpoint(*it))
glvertex(*it->_VECTptr,0,0,contextptr);
}
glEnd();
}
if (!hidden_name && show_names && !vv0.empty())
legende_draw(vv0.front(),legende,labelpos);
}
return;
}
}
}
void Graph3d::indraw(const vecteur & v){
const_iterateur it=v.begin(),itend=v.end();
for (;it!=itend;++it)
indraw(*it);
}
void mult4(double * colmat,double * vect,double * res){
res[0]=colmat[0]*vect[0]+colmat[4]*vect[1]+colmat[8]*vect[2]+colmat[12]*vect[3];
res[1]=colmat[1]*vect[0]+colmat[5]*vect[1]+colmat[9]*vect[2]+colmat[13]*vect[3];
res[2]=colmat[2]*vect[0]+colmat[6]*vect[1]+colmat[10]*vect[2]+colmat[14]*vect[3];
res[3]=colmat[3]*vect[0]+colmat[7]*vect[1]+colmat[11]*vect[2]+colmat[15]*vect[3];
}
void mult4(double * colmat,float * vect,double * res){
res[0]=colmat[0]*vect[0]+colmat[4]*vect[1]+colmat[8]*vect[2]+colmat[12]*vect[3];
res[1]=colmat[1]*vect[0]+colmat[5]*vect[1]+colmat[9]*vect[2]+colmat[13]*vect[3];
res[2]=colmat[2]*vect[0]+colmat[6]*vect[1]+colmat[10]*vect[2]+colmat[14]*vect[3];
res[3]=colmat[3]*vect[0]+colmat[7]*vect[1]+colmat[11]*vect[2]+colmat[15]*vect[3];
}
void mult4(double * c,double k,double * res){
for (int i=0;i<16;i++)
res[i]=k*c[i];
}
double det4(double * c){
return c[0]*c[5]*c[10]*c[15]-c[0]*c[5]*c[14]*c[11]-c[0]*c[9]*c[6]*c[15]+c[0]*c[9]*c[14]*c[7]+c[0]*c[13]*c[6]*c[11]-c[0]*c[13]*c[10]*c[7]-c[4]*c[1]*c[10]*c[15]+c[4]*c[1]*c[14]*c[11]+c[4]*c[9]*c[2]*c[15]-c[4]*c[9]*c[14]*c[3]-c[4]*c[13]*c[2]*c[11]+c[4]*c[13]*c[10]*c[3]+c[8]*c[1]*c[6]*c[15]-c[8]*c[1]*c[14]*c[7]-c[8]*c[5]*c[2]*c[15]+c[8]*c[5]*c[14]*c[3]+c[8]*c[13]*c[2]*c[7]-c[8]*c[13]*c[6]*c[3]-c[12]*c[1]*c[6]*c[11]+c[12]*c[1]*c[10]*c[7]+c[12]*c[5]*c[2]*c[11]-c[12]*c[5]*c[10]*c[3]-c[12]*c[9]*c[2]*c[7]+c[12]*c[9]*c[6]*c[3];
}
void inv4(double * c,double * res){
res[0]=c[5]*c[10]*c[15]-c[5]*c[14]*c[11]-c[10]*c[7]*c[13]-c[15]*c[9]*c[6]+c[14]*c[9]*c[7]+c[11]*c[6]*c[13];
res[1]=-c[1]*c[10]*c[15]+c[1]*c[14]*c[11]+c[10]*c[3]*c[13]+c[15]*c[9]*c[2]-c[14]*c[9]*c[3]-c[11]*c[2]*c[13];
res[2]=c[1]*c[6]*c[15]-c[1]*c[14]*c[7]-c[6]*c[3]*c[13]-c[15]*c[5]*c[2]+c[14]*c[5]*c[3]+c[7]*c[2]*c[13];
res[3]=-c[1]*c[6]*c[11]+c[1]*c[10]*c[7]+c[6]*c[3]*c[9]+c[11]*c[5]*c[2]-c[10]*c[5]*c[3]-c[7]*c[2]*c[9];
res[4]=-c[4]*c[10]*c[15]+c[4]*c[14]*c[11]+c[10]*c[7]*c[12]+c[15]*c[8]*c[6]-c[14]*c[8]*c[7]-c[11]*c[6]*c[12];
res[5]=c[0]*c[10]*c[15]-c[0]*c[14]*c[11]-c[10]*c[3]*c[12]-c[15]*c[8]*c[2]+c[14]*c[8]*c[3]+c[11]*c[2]*c[12];
res[6]=-c[0]*c[6]*c[15]+c[0]*c[14]*c[7]+c[6]*c[3]*c[12]+c[15]*c[4]*c[2]-c[14]*c[4]*c[3]-c[7]*c[2]*c[12];
res[7]=c[0]*c[6]*c[11]-c[0]*c[10]*c[7]-c[6]*c[3]*c[8]-c[11]*c[4]*c[2]+c[10]*c[4]*c[3]+c[7]*c[2]*c[8];
res[8]=c[4]*c[9]*c[15]-c[4]*c[13]*c[11]-c[9]*c[7]*c[12]-c[15]*c[8]*c[5]+c[13]*c[8]*c[7]+c[11]*c[5]*c[12];
res[9]=-c[0]*c[9]*c[15]+c[0]*c[13]*c[11]+c[9]*c[3]*c[12]+c[15]*c[8]*c[1]-c[13]*c[8]*c[3]-c[11]*c[1]*c[12];
res[10]=c[0]*c[5]*c[15]-c[0]*c[13]*c[7]-c[5]*c[3]*c[12]-c[15]*c[4]*c[1]+c[13]*c[4]*c[3]+c[7]*c[1]*c[12];
res[11]=-c[0]*c[5]*c[11]+c[0]*c[9]*c[7]+c[5]*c[3]*c[8]+c[11]*c[4]*c[1]-c[9]*c[4]*c[3]-c[7]*c[1]*c[8];
res[12]=-c[4]*c[9]*c[14]+c[4]*c[13]*c[10]+c[9]*c[6]*c[12]+c[14]*c[8]*c[5]-c[13]*c[8]*c[6]-c[10]*c[5]*c[12];
res[13]=c[0]*c[9]*c[14]-c[0]*c[13]*c[10]-c[9]*c[2]*c[12]-c[14]*c[8]*c[1]+c[13]*c[8]*c[2]+c[10]*c[1]*c[12];
res[14]=-c[0]*c[5]*c[14]+c[0]*c[13]*c[6]+c[5]*c[2]*c[12]+c[14]*c[4]*c[1]-c[13]*c[4]*c[2]-c[6]*c[1]*c[12];
res[15]=c[0]*c[5]*c[10]-c[0]*c[9]*c[6]-c[5]*c[2]*c[8]-c[10]*c[4]*c[1]+c[9]*c[4]*c[2]+c[6]*c[1]*c[8];
double det=det4(c);
mult4(res,1/det,res);
}
void dim32dim2(double * view,double * proj,double * model,double x0,double y0,double z0,double & i,double & j,double & dept){
double vect[4]={x0,y0,z0,1},res1[4],res2[4];
mult4(model,vect,res1);
mult4(proj,res1,res2);
i=res2[0]/res2[3]; // x and y are in [-1..1]
j=res2[1]/res2[3];
dept=res2[2]/res2[3];
i=view[0]+(i+1)*view[2]/2;
j=view[1]+(j+1)*view[3]/2;
// x and y are the distance to the BOTTOM LEFT of the window
}
void dim22dim3(double * view,double * proj_inv,double * model_inv,double i,double j,double depth_,double & x,double & y,double & z){
i=(i-view[0])*2/view[2]-1;
j=(j-view[1])*2/view[3]-1;
double res2[4]={i,j,depth_,1},res1[4],vect[4];
mult4(proj_inv,res2,res1);
mult4(model_inv,res1,vect);
x=vect[0]/vect[3];
y=vect[1]/vect[3];
z=vect[2]/vect[3];
}
void Graph3d::find_ij(double x,double y,double z,double & i,double & j,double & depth_) {
dim32dim2(view,proj,model,x,y,z,i,j,depth_);
#ifdef __APPLE__
j=this->y()+h()-j;
i=i+this->x();
#else
j=window()->h()-j;
#endif
// cout << i << " " << j << endl;
}
void Graph3d::find_xyz(double i,double j,double depth_,double & x,double & y,double & z) {
#ifdef __APPLE__
j=this->y()+h()-j;
i=i-this->x();
#else
j=window()->h()-j;
#endif
dim22dim3(view,proj_inv,model_inv,i,j,depth_,x,y,z);
}
double sqrt3over2=std::sqrt(double(3.0))/2;
bool find_xmin_dx(double x0,double x1,double & xmin,double & dx){
if (x0>=x1)
return false;
double x0x1=x1-x0;
dx=std::pow(10,std::floor(std::log10(x0x1)));
if (x0x1/dx>6)
dx *= 2;
if (x0x1/dx<1.3)
dx /= 5;
if (x0x1/dx<3)
dx /=2;
if (!dx)
return false;
xmin=std::ceil(x0/dx)*dx;
return true;
}
void Graph3d::draw_string(const string & s){
if (printing){
gl2psText(s.c_str(),"Helvetica",labelsize());
}
else {
#if !defined(__APPLE__) || !defined(INT128) // (does not work with textures on mac 64 bits)
gl_font(FL_HELVETICA,labelsize());
gl_draw(s.c_str());
#endif
}
}
void normalize(double & a,double &b,double &c){
double n=std::sqrt(a*a+b*b+c*c);
a /= n;
b /= n;
c /= n;
}
void Graph3d::normal2plan(double & a,double &b,double &c){
context * contextptr=hp?hp->contextptr:get_context(this);
a /= std::pow(window_xmax-window_xmin,2);
b /= std::pow(window_ymax-window_ymin,2);
c /= std::pow(window_zmax-window_zmin,2);
normalize(a,b,c);
if (std::abs(a)<=1e-3){
a=0;
if (std::abs(b)<=1e-3){
b=0;
c=1;
}
else {
gen gcb(float2rational(c/b,1e-3,contextptr));
gen cbn,cbd;
fxnd(gcb,cbn,cbd);
if (cbn.type==_INT_ && cbd.type==_INT_ && std::abs(double(cbn.val)/cbd.val-c/a)<1e-2){
b=cbn.val;
c=cbd.val;
}
}
}
else {
gen gba(float2rational(b/a,1e-3,contextptr));
gen ban,bad,can,cad;
fxnd(gba,ban,bad);
if (ban.type==_INT_ && bad.type==_INT_ && std::abs(double(ban.val)/bad.val-b/a)<1e-2){
gen gca(float2rational(c/a,1e-3,contextptr));
fxnd(gca,can,cad);
if (can.type==_INT_ && cad.type==_INT_ && std::abs(double(can.val)/cad.val-c/a)<1e-2){
int g=gcd(cad.val,bad.val);
// b/a=ban/bad=ban*(cad/g)/ppcm
int ai,bi,ci;
ai=(cad.val*bad.val/g);
bi=(ban.val*cad.val/g);
ci=(can.val*bad.val/g);
if (std::abs(ai)<=13 && std::abs(bi)<=13 && std::abs(ci)<13){
a=ai; b=bi; c=ci;
}
}
}
}
}
void Graph3d::current_normal(double & a,double & b,double & c) {
double res1[4]={0,0,1,1},vect[4];
mult4(model_inv,res1,vect);
a=vect[0]/vect[3]-(window_xmax+window_xmin)/2;
b=vect[1]/vect[3]-(window_ymax+window_ymin)/2;
c=vect[2]/vect[3]-(window_zmax+window_zmin)/2;
if (std::abs(a)<1e-3*(window_xmax-window_xmin))
a=0;
if (std::abs(b)<1e-3*(window_ymax-window_ymin))
b=0;
if (std::abs(c)<1e-3*(window_zmax-window_zmin))
c=0;
}
void round0(double & x,double xmin,double xmax){
if (std::abs(x)<1e-3*(xmax-xmin))
x=0;
}
void Graph3d::display(){
glEnable(GL_NORMALIZE);
glEnable(GL_LINE_STIPPLE);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.0,1.0);
glEnable(GL_CLIP_PLANE0);
glEnable(GL_CLIP_PLANE1);
glEnable(GL_CLIP_PLANE2);
glEnable(GL_CLIP_PLANE3);
glEnable(GL_CLIP_PLANE4);
glEnable(GL_CLIP_PLANE5);
// cout << glIsEnabled(GL_CLIP_PLANE0) << endl;
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
glShadeModel((display_mode & 0x10)?GL_FLAT:GL_SMOOTH);
bool lighting=display_mode & 0x8;
if (lighting)
glClearColor(0, 0, 0, 0);
else
glClearColor(1, 1, 1, 1);
// clear the color and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// view transformations
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
bool notperspective=display_mode & 0x4;
if (notperspective)
// glFrustum(-sqrt3over2,sqrt3over2,-sqrt3over2,sqrt3over2,sqrt3over2,3*sqrt3over2);
glOrtho(-sqrt3over2,sqrt3over2,-sqrt3over2,sqrt3over2,-sqrt3over2,sqrt3over2);
else
glFrustum(-0.5,0.5,-0.5,0.5,sqrt3over2,3*sqrt3over2);
// put the visualisation cube inside above visualisation
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
double dx=(window_xmax-window_xmin),dy=(window_ymax-window_ymin),dz=(window_zmax-window_zmin);
if (dx==0) { dx=1; ++window_xmax; }
if (dy==0) { dy=1; ++window_ymax; }
if (dz==0) { dz=1; ++window_zmax; }
double x,y,z,theta;
get_axis_angle_deg( (dragi || dragj)?(quaternion_double(dragi*180/h(),0,0)*rotation_2_quaternion_double(1,0,0,dragj*180/w())*q):q,x,y,z,theta);
// cerr << theta << " " << x << "," << y << "," << z << endl;
if (!notperspective)
glTranslated(0,0,-2*sqrt3over2);
glRotated(theta,x,y,z);
glScaled(1/dx,1/dy,1/dz);
glTranslated(-(window_xmin+window_xmax)/2,-(window_ymin+window_ymax)/2,-(window_zmin+window_zmax)/2);
// glRotated(theta_y,0,0,1);
double plan0[]={1,0,0,0.5};
double plan1[]={-1,0,0,0.5};
double plan2[]={0,1,0,0.5};
double plan3[]={0,-1,0,0.5};
double plan4[]={0,0,1,0.5};
double plan5[]={0,0,-1,0.5};
plan0[3]=-window_xmin+dx/256;
plan1[3]=window_xmax+dx/256;
plan2[3]=-window_ymin+dy/256;
plan3[3]=window_ymax+dy/256;
plan4[3]=-window_zmin+dz/256;
plan5[3]=window_zmax+dz/256;
glGetDoublev(GL_PROJECTION_MATRIX,proj); // projection matrix in columns
/*
for (int i=0;i<15;++i)
proj[i]=0;
proj[0]=1/sqrt3over2;
proj[5]=proj[0];
proj[10]=-proj[0];
proj[15]=1;
*/
inv4(proj,proj_inv);
glGetDoublev(GL_MODELVIEW_MATRIX,model); // modelview matrix in columns
inv4(model,model_inv);
glGetDoublev(GL_VIEWPORT,view);
if (debug_infolevel>=2){
double check[16];
mult4(model,&model_inv[0],&check[0]);
mult4(model,&model_inv[4],&check[4]);
mult4(model,&model_inv[8],&check[8]);
mult4(model,&model_inv[12],&check[12]);
for (int i=0;i<16;++i){
cout << model[i] << ",";
if (i%4==3) cout << endl;
}
cout << endl;
for (int i=0;i<16;++i){
cout << model_inv[i] << ",";
if (i%4==3) cout << endl;
}
cout << endl;
for (int i=0;i<16;++i){
cout << check[i] << ",";
if (i%4==3) cout << endl;
}
cout << endl;
}
// drax
bool fbox=(display_mode & 0x100);
bool triedre=(display_mode & 0x200);
glLineStipple(1,0xffff);
glLineWidth(1);
gl2psLineWidth(1);
gl_color(FL_RED);
// glColor3f(1,0,0);
if (show_axes || triedre){
glLineWidth(3);
gl2psLineWidth(3);
glBegin(GL_LINES);
glVertex3d(0,0,0);
glVertex3d(1,0,0);
glEnd();
}
if (show_axes){
glLineWidth(1);
gl2psLineWidth(1);
glBegin(GL_LINES);
glVertex3d(0,0,0);
glVertex3d(window_xmax,0,0);
glEnd();
}
if (show_axes && !printing){
glBegin(GL_LINES);
glVertex3d(window_xmin,window_ymin,window_zmin);
glVertex3d(window_xmax,window_ymin,window_zmin);
glVertex3d(window_xmin,window_ymax,window_zmin);
glVertex3d(window_xmax,window_ymax,window_zmin);
glVertex3d(window_xmin,window_ymin,window_zmax);
glVertex3d(window_xmax,window_ymin,window_zmax);
glVertex3d(window_xmin,window_ymax,window_zmax);
glVertex3d(window_xmax,window_ymax,window_zmax);
glEnd();
}
gl_color(FL_GREEN);
// glColor3f(0,1,0);
if (show_axes || triedre){
glLineWidth(3);
gl2psLineWidth(3);
glBegin(GL_LINES);
glVertex3d(0,0,0);
glVertex3d(0,1,0);
glEnd();
}
if (show_axes){
glLineWidth(1);
gl2psLineWidth(1);
glBegin(GL_LINES);
glVertex3d(0,0,0);
glVertex3d(0,window_ymax,0);
glEnd();
}
if (show_axes && !printing){
glBegin(GL_LINES);
glVertex3d(window_xmin,window_ymin,window_zmin);
glVertex3d(window_xmin,window_ymax,window_zmin);
glVertex3d(window_xmax,window_ymin,window_zmin);
glVertex3d(window_xmax,window_ymax,window_zmin);
glVertex3d(window_xmin,window_ymin,window_zmax);
glVertex3d(window_xmin,window_ymax,window_zmax);
glVertex3d(window_xmax,window_ymin,window_zmax);
glVertex3d(window_xmax,window_ymax,window_zmax);
glEnd();
}
gl_color(FL_BLUE);
// glColor3f(0,0,1);
if (show_axes || triedre){
glLineWidth(3);
gl2psLineWidth(3);
glBegin(GL_LINES);
glVertex3d(0,0,0);
glVertex3d(0,0,1);
glEnd();
}
if (show_axes){
glLineWidth(1);
gl2psLineWidth(1);
glBegin(GL_LINES);
glVertex3d(0,0,0);
glVertex3d(0,0,window_zmax);
glEnd();
}
if (show_axes && !printing){
glBegin(GL_LINES);
glVertex3d(window_xmin,window_ymin,window_zmin);
glVertex3d(window_xmin,window_ymin,window_zmax);
glVertex3d(window_xmax,window_ymax,window_zmin);
glVertex3d(window_xmax,window_ymax,window_zmax);
glVertex3d(window_xmin,window_ymax,window_zmin);
glVertex3d(window_xmin,window_ymax,window_zmax);
glVertex3d(window_xmax,window_ymin,window_zmin);
glVertex3d(window_xmax,window_ymin,window_zmax);
glEnd();
}
if(show_axes){ // maillage
glColor3f(1,0,0);
glRasterPos3d(1,0,0);
draw_string(x_axis_name.empty()?"x":x_axis_name);
glColor3f(0,1,0);
glRasterPos3d(0,1,0);
draw_string(y_axis_name.empty()?"y":y_axis_name);
glColor3f(0,0,1);
glRasterPos3d(0,0,1);
draw_string(z_axis_name.empty()?"z":z_axis_name);
if (fbox){
double xmin,dx,x,ymin,dy,y,zmin,dz,z;
find_xmin_dx(window_xmin,window_xmax,xmin,dx);
find_xmin_dx(window_ymin,window_ymax,ymin,dy);
find_xmin_dx(window_zmin,window_zmax,zmin,dz);
glLineStipple(1,0x3333);
glBegin(GL_LINES);
gl_color(FL_CYAN);
for (z=zmin;z<=window_zmax;z+=2*dz){
for (y=ymin;y<=window_ymax;y+=2*dy){
glVertex3d(window_xmin,y,z);
glVertex3d(window_xmax,y,z);
}
}
for (z=zmin;z<=window_zmax;z+=2*dz){
for (x=xmin;x<=window_xmax;x+=2*dx){
glVertex3d(x,window_ymin,z);
glVertex3d(x,window_ymax,z);
}
}
for (x=xmin;x<=window_xmax;x+=2*dx){
for (y=ymin;y<=window_ymax;y+=2*dy){
glVertex3d(x,y,window_zmin);
glVertex3d(x,y,window_zmax);
}
}
glEnd();
gl_color((display_mode & 0x8)?FL_WHITE:FL_BLACK);
glPointSize(3);
for (x=xmin;x<=window_xmax;x+=dx){
round0(x,window_xmin,window_xmax);
glBegin(GL_POINTS);
glVertex3d(x,window_ymin,window_zmin);
glEnd();
glRasterPos3d(x,window_ymin,window_zmin);
string tmps=giac::print_DOUBLE_(x,2)+x_axis_unit;
draw_string(tmps);
}
for (y=ymin;y<=window_ymax;y+=dy){
round0(y,window_ymin,window_ymax);
glBegin(GL_POINTS);
glVertex3d(window_xmin,y,window_zmin);
glEnd();
glRasterPos3d(window_xmin,y,window_zmin);
string tmps=giac::print_DOUBLE_(y,2)+y_axis_unit;
draw_string(tmps);
}
for (z=zmin;z<=window_zmax;z+=dz){
round0(z,window_zmin,window_zmax);
glBegin(GL_POINTS);
glVertex3d(window_xmin,window_ymin,z);
glEnd();
glRasterPos3d(window_xmin,window_ymin,z);
string tmps=giac::print_DOUBLE_(z,2)+z_axis_unit;
draw_string(tmps);
}
}
}
glClipPlane(GL_CLIP_PLANE0,plan0);
glClipPlane(GL_CLIP_PLANE1,plan1);
glClipPlane(GL_CLIP_PLANE2,plan2);
glClipPlane(GL_CLIP_PLANE3,plan3);
glClipPlane(GL_CLIP_PLANE4,plan4);
glClipPlane(GL_CLIP_PLANE5,plan5);
// mouse plan
double normal_a,normal_b,normal_c;
current_normal(normal_a,normal_b,normal_c);
normal2plan(normal_a,normal_b,normal_c);
double plan_x0,plan_y0,plan_z0,plan_t0;
find_xyz(0,0,depth,plan_x0,plan_y0,plan_z0);
plan_t0=normal_a*plan_x0+normal_b*plan_y0+normal_c*plan_z0;
if (std::abs(plan_t0)(parent())){
gl_color((display_mode & 0x8)?FL_WHITE:FL_BLACK);
glLineWidth(2);
gl2psLineWidth(2);
double xa,ya,za,xb,yb,zb;
// show mouse plan intersections with the faces of the clip planes
// example with the face z=Z:
// a*x+b*y=plan_t0-normal_c*Z
// get the 4 intersections, keep only the valid ones
glLineStipple(1,0x3333);
if (is_clipped(normal_a,window_xmin,window_xmax,normal_b,window_ymin,window_ymax,plan_t0-normal_c*window_zmin,xa,ya,xb,yb)){
glBegin(GL_LINE_STRIP);
glVertex3d(xa,ya,window_zmin+dz/256);
glVertex3d(xb,yb,window_zmin+dz/256);
glEnd();
}
if (is_clipped(normal_a,window_xmin,window_xmax,normal_b,window_ymin,window_ymax,plan_t0-normal_c*window_zmax,xa,ya,xb,yb)){
glBegin(GL_LINE_STRIP);
glVertex3d(xa,ya,window_zmax-dz/256);
glVertex3d(xb,yb,window_zmax-dz/256);
glEnd();
}
if (is_clipped(normal_a,window_xmin,window_xmax,normal_c,window_zmin,window_zmax,plan_t0-normal_b*window_ymin,xa,za,xb,zb)){
glBegin(GL_LINE_STRIP);
glVertex3d(xa,window_ymin+dy/256,za);
glVertex3d(xb,window_ymin+dy/256,zb);
glEnd();
}
if (is_clipped(normal_a,window_xmin,window_xmax,normal_c,window_zmin,window_zmax,plan_t0-normal_b*window_ymax,xa,za,xb,zb)){
glBegin(GL_LINE_STRIP);
glVertex3d(xa,window_ymax-dy/256,za);
glVertex3d(xb,window_ymax-dy/256,zb);
glEnd();
}
if (is_clipped(normal_b,window_ymin,window_ymax,normal_c,window_zmin,window_zmax,plan_t0-normal_a*window_xmin,ya,za,yb,zb)){
glBegin(GL_LINE_STRIP);
glVertex3d(window_xmin+dx/256,ya,za);
glVertex3d(window_xmin+dx/256,yb,zb);
glEnd();
}
if (is_clipped(normal_b,window_ymin,window_ymax,normal_c,window_zmin,window_zmax,plan_t0-normal_a*window_xmax,ya,za,yb,zb)){
glBegin(GL_LINE_STRIP);
glVertex3d(window_xmax-dx/256,ya,za);
glVertex3d(window_xmax-dx/256,yb,zb);
glEnd();
}
// same for window_zmax, etc.
glLineWidth(1);
gl2psLineWidth(1);
glLineStipple(1,0xffff);
}
if (lighting){
/*
GLfloat mat_specular[] = { 1.0,1.0,1.0,1.0 };
GLfloat mat_shininess[] = { 50.0 };
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess);
*/
glEnable(GL_LIGHTING);
glEnable(GL_CULL_FACE);
glEnable(GL_COLOR_MATERIAL);
static GLfloat l_pos[8][4],l_dir[8][3],ambient[8][4],diffuse[8][4],specular[8][4];
for (int i=0;i<8;++i){
if (!light_on[i]){
glDisable(GL_LIGHT0+i);
continue;
}
glEnable(GL_LIGHT0+i);
l_pos[i][0]=light_x[i];
l_pos[i][1]=light_y[i];
l_pos[i][2]=light_z[i];
l_pos[i][3]=light_w[i];
glLightfv(GL_LIGHT0+i,GL_POSITION,l_pos[i]);
l_dir[i][0]=light_spot_x[i];
l_dir[i][1]=light_spot_y[i];
l_dir[i][2]=light_spot_z[i];
glLightfv(GL_LIGHT0+i,GL_SPOT_DIRECTION,l_dir[i]);
glLightf(GL_LIGHT0+i,GL_SPOT_EXPONENT,light_spot_exponent[i]);
glLightf(GL_LIGHT0+i,GL_SPOT_CUTOFF,light_spot_cutoff[i]);
glLightf(GL_LIGHT0+i,GL_CONSTANT_ATTENUATION,light_0[i]);
glLightf(GL_LIGHT0+i,GL_LINEAR_ATTENUATION,light_1[i]);
glLightf(GL_LIGHT0+i,GL_QUADRATIC_ATTENUATION,light_2[i]);
ambient[i][0]=light_ambient_r[i];
ambient[i][1]=light_ambient_g[i];
ambient[i][2]=light_ambient_b[i];
ambient[i][3]=light_ambient_a[i];
glLightfv(GL_LIGHT0+i,GL_AMBIENT,ambient[i]);
diffuse[i][0]=light_diffuse_r[i];
diffuse[i][1]=light_diffuse_g[i];
diffuse[i][2]=light_diffuse_b[i];
diffuse[i][3]=light_diffuse_a[i];
glLightfv(GL_LIGHT0+i,GL_DIFFUSE,diffuse[i]);
specular[i][0]=light_specular_r[i];
specular[i][1]=light_specular_g[i];
specular[i][2]=light_specular_b[i];
specular[i][3]=light_specular_a[i];
glLightfv(GL_LIGHT0+i,GL_SPECULAR,specular[i]);
if (debug_infolevel>=2){
GLfloat posf[4],direcf[4],ambient[4],diffuse[4],specular[4];
GLfloat expo,cutoff;
double pos[4],direc[4];
glGetLightfv(GL_LIGHT0+i,GL_SPOT_EXPONENT,&expo);
glGetLightfv(GL_LIGHT0+i,GL_SPOT_CUTOFF,&cutoff);
glGetLightfv(GL_LIGHT0+i,GL_POSITION,posf);
glGetLightfv(GL_LIGHT0+i,GL_SPOT_DIRECTION,direcf);
direcf[3]=0; // 4 was out of bound
mult4(model_inv,posf,pos);
tran4(model);
mult4(model,direcf,direc);
tran4(model);
glGetLightfv(GL_LIGHT0+i,GL_AMBIENT,ambient);
glGetLightfv(GL_LIGHT0+i,GL_DIFFUSE,diffuse);
glGetLightfv(GL_LIGHT0+i,GL_SPECULAR,specular);
cerr << "light " << i << ": " <<
" pos " << pos[0] << "," << pos[1] << "," << pos[2] << "," << pos[3] <<
" dir " << direc[0] << "," << direc[1] << "," << direc[2] << "," << direc[3] <<
" ambient " << ambient[0] << "," << ambient[1] << "," << ambient[2] << "," << ambient[3] <<
" diffuse " << diffuse[0] << "," << diffuse[1] << "," << diffuse[2] << "," << diffuse[3] <<
" specular " << specular[0] << "," << specular[1] << "," << specular[2] << "," << specular[3] <<
" exponent " << expo << " cutoff " << cutoff << endl;
}
}
}
if (display_mode & 0x20){
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
}
// now draw each object
if ( (display_mode & 2) && !animation_instructions.empty())
indraw(animation_instructions[animation_instructions_pos % animation_instructions.size()]);
if ( display_mode & 0x40 )
indraw(trace_instructions);
if (display_mode & 1)
indraw(plot_instructions);
if (display_mode & 0x8){
glDisable(GL_LIGHTING);
for (int i=0;i<8;++i)
glDisable(GL_LIGHT0+i);
}
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
gen plot_tmp,title_tmp;
History_Pack * hp =get_history_pack(this);
context * contextptr=hp?hp->contextptr:get_context(this);
find_title_plot(title_tmp,plot_tmp,contextptr);
indraw(plot_tmp);
if (mode==1 && pushed && push_in_area && in_area){
// draw segment between push and current
gl_color(FL_RED);
double x,y,z;
glBegin(GL_LINES);
find_xyz(push_i,push_j,push_depth,x,y,z);
glVertex3d(x,y,z);
find_xyz(current_i,current_j,current_depth,x,y,z);
glVertex3d(x,y,z);
glEnd();
}
glDisable(GL_CLIP_PLANE0);
glDisable(GL_CLIP_PLANE1);
glDisable(GL_CLIP_PLANE2);
glDisable(GL_CLIP_PLANE3);
glDisable(GL_CLIP_PLANE4);
glDisable(GL_CLIP_PLANE5);
/*
if( show_axes){
gl_color((display_mode & 0x8)?FL_WHITE:FL_BLACK);
glRasterPos3d(window_xmin,window_ymin,window_zmin);
string tmps=giac::print_DOUBLE_(window_xmin,2)+","+giac::print_DOUBLE_(window_ymin,2)+","+giac::print_DOUBLE_(window_zmin,2);
draw_string(tmps);
glRasterPos3d(window_xmax,window_ymax,window_zmax);
tmps=giac::print_DOUBLE_(window_xmax,2)+","+giac::print_DOUBLE_(window_ymax,2)+","+giac::print_DOUBLE_(window_zmax,2);
draw_string(tmps);
}
*/
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gl_color((display_mode & 0x8)?FL_WHITE:FL_BLACK);
double td=fl_width(title.c_str());
glRasterPos3d(-0.4*td/w(),-1,depth-0.001);
string mytitle(title);
if (!is_zero(title_tmp) && function_final.type==_FUNC)
mytitle=gen(symbolic(*function_final._FUNCptr,title_tmp)).print(contextptr);
if (!mytitle.empty())
draw_string(mytitle);
glRasterPos3d(-1,-1,depth-0.001);
if (!args_help.empty() && args_tmp.size()<= args_help.size()){
draw_string(gettext("Click ")+args_help[giacmax(1,args_tmp.size())-1]);
}
glRasterPos3d(-0.98,0.87,depth-0.001);
if (show_axes && !printing){
string tmps=gettext("mouse plan ")+giac::print_DOUBLE_(normal_a,3)+"x+"+giac::print_DOUBLE_(normal_b,3)+"y+"+giac::print_DOUBLE_(normal_c,3)+"z="+ giac::print_DOUBLE_(plan_t0,3);
// cerr << tmps << endl;
draw_string(tmps); // +" Z="+giac::print_DOUBLE_(-depth,3));
}
if (below_depth_hidden){
/* current mouse position
double i=Fl::event_x();
double j=Fl::event_y();
j=window()->h()-j;
i=(i-view[0])*2/view[2]-1;
j=(j-view[1])*2/view[3]-1;
*/
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
xcas_color((display_mode & 0x8)?FL_WHITE:FL_BLACK,true);
glBegin(GL_POLYGON);
glVertex3d(-1,-1,depth);
glVertex3d(-1,1,depth);
glVertex3d(1,1,depth);
glVertex3d(1,-1,depth);
glEnd();
}
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glFlush();
glFinish();
if (screenbuf && !printing){
glReadBuffer(GL_FRONT);
glReadPixels(this->x(), window()->h()-this->y()-this->h(), w(), h(), GL_RGBA, GL_UNSIGNED_BYTE, screenbuf);
}
}
void Graph3d::print(){
if (!printing)
return;
// EPS output
glViewport(0,0, w(), h()); // lower left
int buf=1024*1024;
for (;;buf+=1024*1024){
gl2psBeginPage(label(),"xcasnew",0,GL2PS_EPS,GL2PS_BSP_SORT,GL2PS_SIMPLE_LINE_OFFSET | GL2PS_DRAW_BACKGROUND | GL2PS_USE_CURRENT_VIEWPORT,GL_RGBA,0,0,0,0,0,buf,printing,"output");
gl2psEnable(GL2PS_LINE_STIPPLE);
display();
if (gl2psEndPage()!=GL2PS_OVERFLOW){
break;
}
}
}
bool find_clip_box(Fl_Widget * wid,int & x,int & y,int & w,int & h){
if (!wid || !wid->window())
return false;
fl_push_no_clip();
vector p;
for (;wid;wid=wid->parent())
p.push_back(wid);
for (int i=p.size()-2;i>=0;--i){
fl_clip_box(p[i]->x(),p[i]->y(),p[i]->w(),p[i]->h(),x,y,w,h);
fl_push_clip(x,y,w,h);
}
for (int i=p.size()-1;i>=0;--i)
fl_pop_clip();
return true;
}
// if printing is true, we call gl2ps to make an eps file
void Graph3d::draw(){
// cerr << "graph3d" << endl;
int clip_x,clip_y,clip_w,clip_h;
#ifdef __APPLE__
if (!find_clip_box(this,clip_x,clip_y,clip_w,clip_h))
#endif
fl_clip_box(x(),y(),w(),h(),clip_x,clip_y,clip_w,clip_h);
// cerr << clip_x << " " << clip_y<< " " << clip_w<< " " << clip_h << endl;
if (printing){
fprintf(printing,"%s","\nGS\n\nCR\nCS\n% avant eps -> BeginDocument\n/b4_Inc_state save def\n%save state for cleanup\n/dict_count countdictstack def\n/op_count count 1 sub def\n%count objects on op stack\nuserdict begin\n%make userdict current dict\n/showpage { } def\n%redefine showpage to be null\n0 setgray 0 setlinecap\n1 setlinewidth 0 setlinejoin\n10 setmiterlimit [] 0 setdash newpath\n/languagelevel where\n%if not equal to 1 then\n{pop languagelevel %set strokeadjust and\n1 ne\n%overprint to their defaults\n{false setstrokeadjust false setoverprint\n} if\n} if\n");
// Translate by previous widget h()
fprintf(printing,"[1 0 0 -1 0 0] concat\n%d %d translate\n",x(),-h()-y());
fprintf(printing,"%s","\n%%BeginDocument: out.eps\n");
print();
fprintf(printing,"%s","\n%%EndDocument\ncount op_count sub {pop} repeat\ncountdictstack dict_count sub {end} repeat %clean up dict stack\nb4_Inc_state restore\n% apres eps\n\nGR\n");
return;
}
Fl_Window * win = window();
if (!win)
return;
if (!hp)
hp=geo_find_history_pack(this);
context * contextptr = hp?hp->contextptr:0;
int locked=0;
#ifdef HAVE_LIBPTHREAD
locked=pthread_mutex_trylock(&interactive_mutex);
#endif
bool b,block;
if (!locked){
b=io_graph(contextptr);
io_graph(contextptr)=false;
block=block_signal;
block_signal=true;
}
#if defined __APPLE__ && !defined GRAPH_WINDOW
GLContext context;
if (!glcontext){ // create context
GLContext shared_ctx = 0;
context = aglCreateContext( gl_choice->pixelformat, shared_ctx);
if (!context){
if (!locked){
block_signal=block;
io_graph(contextptr)=b;
#ifdef HAVE_LIBPTHREAD
pthread_mutex_unlock(&interactive_mutex);
#endif
}
return ;
}
glcontext = (void *) context;
}
else
context = (GLContext) glcontext;
aglSetCurrentContext(context);
GLint rect[] = { clip_x, win->h()-clip_y-clip_h, clip_w, clip_h};
aglSetInteger( (GLContext)context, AGL_BUFFER_RECT, rect );
aglEnable( (GLContext)context, AGL_BUFFER_RECT );
OpaqueWindowPtr * winid=(OpaqueWindowPtr*) win->window_ref();
aglSetWindowRef( context, winid );
glEnable(GL_DEPTH_TEST);
// glLoadIdentity();
// glEnable(GL_SCISSOR_TEST);
// glScissor(clip_x, win->h()-clip_y-clip_h, clip_w, clip_h); // lower left
// glViewport(clip_x, win->h()-clip_y-clip_h, clip_w, clip_h); // lower left
glViewport(0,0,w(),h());
// glDrawBuffer(GL_FRONT);
gl_font(FL_HELVETICA,labelsize());
// GLint viewport[4];
// glGetIntergerv(GL_VIEWPORT,viewport);
//fl_push_clip(clip_x,clip_y,clip_w,clip_h);
display();
#else
gl_start();
glEnable(GL_SCISSOR_TEST);
// glViewport(clip_x, win->h()-clip_y-clip_h, clip_w, clip_h); // lower left
#ifdef GRAPH_WINDOW
glViewport(0,0, w(), h()); // lower left
#else
glScissor(clip_x, win->h()-clip_y-clip_h, clip_w, clip_h); // lower left
glViewport(x(),win->h()-y()-h(), w(), h()); // lower left
#endif
gl_font(FL_HELVETICA,labelsize());
// GLint viewport[4];
// glGetIntergerv(GL_VIEWPORT,viewport);
//fl_push_clip(clip_x,clip_y,clip_w,clip_h);
display();
gl_finish();
#endif
struct timezone tz;
gettimeofday(&animation_last,&tz);
if (!paused)
++animation_instructions_pos;
//fl_pop_clip();
if (!locked){
block_signal=block;
io_graph(contextptr)=b;
#ifdef HAVE_LIBPTHREAD
pthread_mutex_unlock(&interactive_mutex);
#endif
}
}
const char * Graph3d::latex(const char * filename_){
const char * filename=0;
if ( (filename=Graph2d3d::latex(filename_)) ){
ofstream of(filename);
if (of){
string epsfile(remove_extension(filename)+".eps");
FILE * f=fopen(epsfile.c_str(),"w");
if (f){
of << "% Generated by xcas\n" << endl;
of << giac::tex_preamble << endl;
of << "\\includegraphics[bb=0 0 400 "<< h() <<"]{" << remove_path(epsfile) << "}" << endl << endl ;
of << giac::tex_end << endl;
of.close();
int gw=w();
resize(x(),y(),400,h());
printing=f;
print();
printing=0;
resize(x(),y(),gw,h());
fclose(f);
}
}
/*
FILE * f=fopen(filename,"w");
if (f){
int gw=w();
resize(x(),y(),400,h());
fprintf(f,"%s","% Generated by xcas\n");
fprintf(f,"%s",giac::tex_preamble.c_str()) ;
fprintf(f,"\n\n{\n\\setlength{\\unitlength}{1pt}\n\\begin{picture}(%d,%d)(%d,%d)\n{\\special{\"\n",w(),h(),0,0);
printing=f;
print();
printing=0;
resize(x(),y(),gw,h());
fprintf(f,"%s","}\n}\\end{picture}\n}\n\n");
fprintf(f,"%s",giac::tex_end.c_str());
fclose(f);
}
*/
}
return filename;
}
Graph3d::~Graph3d(){
#if defined __APPLE__ && !defined GRAPH_WINDOW
if (glcontext){
aglSetCurrentContext( NULL );
aglSetWindowRef((GLContext) glcontext, NULL );
aglDestroyContext((GLContext)glcontext);
}
#endif
}
int Graph3d::in_handle(int event){
int res=Graph2d3d::in_handle(event);
if (event==FL_FOCUS){
if (!paused)
--animation_instructions_pos;
redraw();
}
if (event==FL_FOCUS || event==FL_UNFOCUS)
return 1;
if (event==FL_KEYBOARD){
theta_z -= int(theta_z/360)*360;
theta_x -= int(theta_x/360)*360;
theta_y -= int(theta_y/360)*360;
switch (Fl::event_text()?Fl::event_text()[0]:0){
case 'y':
theta_z += delta_theta;
q=q*euler_deg_to_quaternion_double(delta_theta,0,0);
redraw();
return 1;
case 'z':
theta_x += delta_theta;
q=q*euler_deg_to_quaternion_double(0,delta_theta,0);
redraw();
return 1;
case 'x':
theta_y += delta_theta;
q=q*euler_deg_to_quaternion_double(0,0,delta_theta);
redraw();
return 1;
case 'Y':
theta_z -= delta_theta;
q=q*euler_deg_to_quaternion_double(-delta_theta,0,0);
redraw();
return 1;
case 'Z':
theta_x -= delta_theta;
q=q*euler_deg_to_quaternion_double(0,-delta_theta,0);
redraw();
return 1;
case 'X':
theta_y -= delta_theta;
q=q*euler_deg_to_quaternion_double(0,0,-delta_theta);
redraw();
return 1;
case 'u': case 'f':
depth += 0.01;
mouse_position->redraw();
redraw();
return 1;
case 'd': case 'n':
depth -= 0.01;
mouse_position->redraw();
redraw();
return 1;
case 'h': case 'H': // hide below depth
below_depth_hidden=true;
redraw();
return 1;
case 's': case 'S': // show below depth
below_depth_hidden=false;
redraw();
return 1;
}
}
current_i=Fl::event_x();
current_j=Fl::event_y();
current_depth=depth;
double x,y,z;
find_xyz(current_i,current_j,current_depth,x,y,z);
in_area=(x>=window_xmin) && (x<=window_xmax) &&
(y>=window_ymin) && (y<=window_ymax) &&
(z>=window_zmin) && (z<=window_zmax);
if (event==FL_MOUSEWHEEL){
if (!Fl::event_inside(this))
return 0;
if (show_axes){ // checking in_area seems to difficult, especially if mouse plan is not viewed
depth = int(1000*(depth-Fl::e_dy *0.01)+.5)/1000.0;
mouse_position->redraw();
redraw();
return 1;
}
else {
if (Fl::e_dy<0)
zoom(0.8);
else
zoom(1.25);
return 1;
}
}
if ( (event==FL_PUSH || push_in_area))
;
else
in_area=false;
if (event==FL_PUSH){
if (this!=Fl::focus()){
Fl::focus(this);
handle(FL_FOCUS);
}
push_i=current_i;
push_j=current_j;
push_depth=current_depth;
push_in_area = in_area;
pushed = true;
return 1;
}
if (!(display_mode & 0x80) && push_in_area && (event==FL_DRAG || event==FL_RELEASE)){
double x1,y1,z1,x2,y2,z2;
find_xyz(current_i,current_j,current_depth,x1,y1,z1);
find_xyz(push_i,push_j,push_depth,x2,y2,z2);
double newx=x1-x2, newy=y1-y2, newz=z1-z2;
round3(newx,window_xmin,window_xmax);
round3(newy,window_ymin,window_ymax);
round3(newz,window_zmin,window_zmax);
window_xmin -= newx;
window_xmax -= newx;
window_ymin -= newy;
window_ymax -= newy;
window_zmin -= newz;
window_zmax -= newz;
push_i = current_i;
push_j = current_j;
redraw();
if (event==FL_RELEASE)
pushed=false;
return 1;
}
if (event==FL_DRAG){
if (push_in_area)
return 0;
dragi=current_i-push_i;
dragj=current_j-push_j;
redraw();
return 1;
}
if (event==FL_RELEASE){
pushed = false;
if (push_in_area)
return 0;
dragi=current_i-push_i;
dragj=current_j-push_j;
if (paused && absint(dragi)<4 && absint(dragj)<4)
++animation_instructions_pos;
else
q=quaternion_double(dragi*180/h(),0,0)*rotation_2_quaternion_double(1,0,0,dragj*180/w())*q;
dragi=dragj=0;
redraw();
return 1;
}
return res;
}
Geo3d::Geo3d(int x,int y,int width, int height, History_Pack * _hp): Graph3d(x,y,width,height,0,_hp) {
hp=_hp?_hp:geo_find_history_pack(this);
if (hp){
hp->eval_below=true;
hp->eval_below_once=false;
show_mouse_on_object=true;
}
}
int Geo3d::in_handle(int event){
if (!event)
return 1;
if (!hp)
hp=geo_find_history_pack(this);
// cerr << event << " " << mode << endl;
int res=Graph3d::in_handle(event);
if (event==FL_UNFOCUS){
return 1;
}
if (event==FL_FOCUS){
return 1;
}
if (int gres=geo_handle(event))
return gres;
// event not handeld by geometry
return res;
}
void Geo3d::draw(){
Graph3d::draw();
}
// set evryone to x
void Graph3d::orthonormalize(){
window_ymax=window_xmax;
window_ymin=window_xmin;
window_zmax=window_xmax;
window_zmin=window_xmin;
redraw();
}
void Graph3d::geometry_round(double x,double y,double z,double eps,gen & tmp,GIAC_CONTEXT) {
tmp= geometry_round_numeric(x,y,z,eps,approx);
if (tmp.type==_VECT)
tmp.subtype = _POINT__VECT;
selected=nearest_point(plot_instructions,tmp,eps,contextptr);
// if there is a point inside selected, stop there,
// otherwise find a point that is near the line
int pos=findfirstpoint(selection2vecteur(selected));
if (pos<0){
// line passing through tmp
double a,b,c;
double i,j,k;
find_ij(x,y,z,i,j,k);
k--;
find_xyz(i,j,k,a,b,c);
gen line(makevecteur(tmp,makevecteur(a,b,c)),_LINE__VECT);
/*
current_normal(a,b,c);
vecteur v(makevecteur(a,b,c));
gen line(makevecteur(tmp,tmp+v),_LINE__VECT);
*/
vector sel2=nearest_point(plot_instructions,line,eps,contextptr);
pos=findfirstpoint(selection2vecteur(sel2));
if (pos>=0){
selected.insert(selected.begin(),sel2[pos]);
}
else {
vector::const_iterator it=sel2.begin(),itend=sel2.end();
for (;it!=itend;++it)
selected.push_back(*it);
}
if (selected.empty()){
// add hyperplans
const_iterateur it=plot_instructions.begin(),itend=plot_instructions.end();
for (int pos=0;it!=itend;++it,++pos){
gen tmp=remove_at_pnt(*it);
if (tmp.is_symb_of_sommet(at_hyperplan)){
vecteur v=interdroitehyperplan(line,tmp,contextptr);
if (!v.empty() && !is_undef(v.front())){
gen inters=evalf_double(remove_at_pnt(v.front()),1,contextptr);
if (inters.type==_VECT && inters._VECTptr->size()==3){
vecteur & xyz=*inters._VECTptr;
if (xyz[0].type==_DOUBLE_ && xyz[1].type==_DOUBLE_ && xyz[2].type==_DOUBLE_){
double x=xyz[0]._DOUBLE_val;
double y=xyz[1]._DOUBLE_val;
double z=xyz[2]._DOUBLE_val;
if (x>=window_xmin && x<=window_xmax &&
y>=window_ymin && y<=window_ymax &&
z>=window_zmin && z<=window_zmax)
selected.push_back(pos);
}
}
}
}
}
}
}
}
#ifndef NO_NAMESPACE_XCAS
} // namespace giac
#endif // ndef NO_NAMESPACE_XCAS
#endif // HAVE_LIBFLTK_GL