comment
framed views
endcomment

function getframe (x,y,z)
## gets a box around all points in (x,y,z).
	ex=extrema(x); ey=extrema(y); ez=extrema(z);
	return [min(ex[:,1]'),max(ex[:,3]'),
		min(ey[:,1]'),max(ey[:,3]'),min(ez[:,1]'),max(ez[:,3]')]
endfunction

function framez0 (f)
	wire([f[1],f[2],f[2],f[1],f[1]], ..
		[f[3],f[3],f[4],f[4],f[3]],dup(f[5],5)');
..	grid3d(f);
	return 0	
endfunction

function framez1 (f)
	wire([f[1],f[2],f[2],f[1],f[1]], ..
		[f[3],f[3],f[4],f[4],f[3]],dup(f[6],5)');
	return 0
endfunction

function framexpyp (f)
	wire([f[2],f[2]],[f[4],f[4]],[f[5],f[6]]);
	return 0
endfunction

function framexpym (f)
	wire([f[2],f[2]],[f[3],f[3]],[f[5],f[6]]);
	return 0
endfunction

function framexmyp (f)
	wire([f[1],f[1]],[f[4],f[4]],[f[5],f[6]]);
	return 0
endfunction

function framexmym (f)
	wire([f[1],f[1]],[f[3],f[3]],[f[5],f[6]]);
	return 0
endfunction

function xgrid3d(f,tx,xfactor,yz=3,color=3)
## draws a grid for x axis in the plane y or z = f[yz]
	nx=cols(tx);
	ls=linestyle(".");lw=linewidth(1);c=color(color);
	loop 1 to nx;
		if yz==3||yz==4; .. plane y=cst
			wire([tx[#],tx[#]],[f[yz],f[yz]],[f[5],f[6]]);
		else
			wire([tx[#],tx[#]],[f[3],f[4]],[f[yz],f[yz]]);
		endif;
	end;
	color(c);linewidth(lw);linestyle(ls);
	return 0;
endfunction

function ygrid3d(f,ty,yfactor,xz=1,color=3)
## draws a grid for y axis in the plane x or z = f[xz]
	ny=cols(ty);
	ls=linestyle(".");lw=linewidth(1);c=color(color);
	loop 1 to ny;
		if xz==1||xz==2; .. plane x=cst
			wire([f[xz],f[xz]],[ty[#],ty[#]],[f[5],f[6]]);
		else
			wire([f[1],f[2]],[ty[#],ty[#]],[f[xz],f[xz]]);
		endif;
	end;
	color(c);linewidth(lw);linestyle(ls);
	return 0;
endfunction

function zgrid3d(f,tz,zfactor,xy=1,color=3)
## draws a grid for z axis in the plane x or y = f[xy]
	nz=cols(tz);
	ls=linestyle(".");lw=linewidth(1);c=color(color);
	loop 1 to nz;
		if xy==1||xy==2; .. plane x=cst
			wire([f[xy],f[xy]],[f[3],f[4]],[tz[#],tz[#]]);
		else
			wire([f[1],f[2]],[f[xy],f[xy]],[tz[#],tz[#]]);
		endif;
	end;
	color(c);linewidth(lw);linestyle(ls);
	return 0;
endfunction

function xticks3d(f,tx,xfactor,ctr,color=3)
## draws a grid for z axis in the plane x or y = f[xy]
	nx=cols(tx);
	w=window();
	ht=textheight();
	ls=linestyle(".");lw=linewidth(1);c=color(color);
	y=[f[3],f[3],f[4],f[4]];
	z=[f[5],f[6],f[5],f[6]];
	{c,r}=project(dup(f[1],4)',y,z);
	cmax=max(r);
	loop 1 to 4
		if r[#]==cmax;
			if y[#]==f[3];
				{xp,yp}=project(tx,dup(y[#]-(!ctr)*(f[4]-f[3])/20,nx)',dup(z[#]-ctr*(f[6]-f[5])/20,nx)');
			else
				{xp,yp}=project(tx,dup(y[#]+(!ctr)*(f[4]-f[3])/20,nx)',dup(z[#]-ctr*(f[6]-f[5])/20,nx)');
			endif;
			break;
		endif;
	end;
	loop 1 to nx;
		_ctext(niceform(tx[#]/xfactor),[xp[#],yp[#]]);
	end;
..	if ticks && !(f~=1);
..		_ctext("* "|printscale(f),[(w[1]+w[3])/2,w[4]+1.5*ht]);
..	endif;
	color(c);linewidth(lw);linestyle(ls);
	return 0;
endfunction

function yticks3d(f,ty,yfactor,ctr,color=3)
## draws a grid for z axis in the plane x or y = f[xy]
	ny=cols(ty);
	w=window();
	ht=textheight();
	ls=linestyle(".");lw=linewidth(1);c=color(color);
	x=[f[1],f[1],f[2],f[2]];
	z=[f[5],f[6],f[5],f[6]];
	{c,r}=project(x,dup(f[3],4)',z);
	cmax=max(r);
	loop 1 to 4
		if r[#]==cmax;
			if x[#]==f[1];
				{xp,yp}=project(dup(x[#]-(!ctr)*(f[2]-f[1])/20,ny)',ty,dup(z[#]-ctr*(f[6]-f[5])/20,ny)');
			else
				{xp,yp}=project(dup(x[#]+(!ctr)*(f[2]-f[1])/20,ny)',ty,dup(z[#]-ctr*(f[6]-f[5])/20,ny)');
			endif;
			break;
		endif;
	end;
	loop 1 to ny;
		_ctext(niceform(ty[#]/yfactor),[xp[#],yp[#]]);
	end;
..	if ticks && !(f~=1);
..		_ctext("* "|printscale(f),[(w[1]+w[3])/2,w[4]+1.5*ht]);
..	endif;
	color(c);linewidth(lw);linestyle(ls);
	return 0;
endfunction

function zticks3d(f,tz,zfactor,color=3)
## draws a grid for z axis in the plane x or y = f[xy]
	nz=cols(tz);
	w=window();
	ht=textheight();
	ls=linestyle(".");lw=linewidth(1);c=color(color);
	x=[f[1],f[2],f[1],f[2]];
	y=[f[3],f[3],f[4],f[4]];
	{c,r}=project(x,y,dup(f[5],4)');
	cmin=min(c);
	loop 1 to 4
		if c[#]==cmin;
			{xp,yp}=project(dup(x[#],nz+1)',dup(y[#],nz+1)',tz|tz[nz]+(tz[nz]-tz[nz-1]));
			break;
		endif;
	end;
	loop 1 to nz;
		_rtext(niceform(tz[#]/zfactor),[xp[#]-5,yp[#]-ht/2]);
	end;
..	if !(zfactor~=1);
..		_rtext("* "|printscale(zfactor),[xp[nz+1]-5,yp[nz+1]-ht/2]);
..	endif;
	color(c);linewidth(lw);linestyle(ls);
	return 0;
endfunction

function frame1 (f,grid=0,ticks=0,tx=0,ty=0,tz=0,xfactor=1,yfactor=1,zfactor=1)
## draws the back part of the box (considering view)
	v=view();
	x=sin(v[3])*v[1]; y=-cos(v[3])*v[1];
	if x<=f[2];
		framexpyp(f);
		framexpym(f);
		if grid;
			zgrid3d(f,tz,zfactor,2);
			ygrid3d(f,ty,yfactor,2);
		endif;
	endif;
	if x>=f[1];
		framexmyp(f);
		framexmym(f);
		if grid;
			zgrid3d(f,tz,zfactor,1);
			ygrid3d(f,ty,yfactor,1);
		endif;
	endif;
	if y<=f[4];
		framexmyp(f);
		framexpyp(f);
		if grid;
			zgrid3d(f,tz,zfactor,4);
			xgrid3d(f,tx,xfactor,4);
		endif;
	endif;
	if y>=f[3];
		framexmym(f);
		framexpym(f);
		if grid;
			zgrid3d(f,tz,zfactor,3);
			xgrid3d(f,tx,xfactor,3);
		endif;
	endif;
	if ticks;
		zticks3d(f,tz,zfactor);
	endif;
	y=sin(v[4])*v[1];ctr=0;
	if y>f[5];
		framez0(f);
		if grid;
			xgrid3d(f,tx,xfactor,5);
			ygrid3d(f,ty,yfactor,5);
		endif;
	endif;
	if y<f[6];
		ctr=1;
		framez1(f);
		if grid;
			xgrid3d(f,tx,xfactor,6);
			ygrid3d(f,ty,yfactor,6);
		endif;
	endif;
	if ticks;
		xticks3d(f,tx,xfactor,ctr);
		yticks3d(f,ty,yfactor,ctr);
	endif;
	return 0
endfunction

function frame2 (f)
## draws the front part of the box (considering view).
	v=view();
	y=sin(v[4])*v[1];
	if y<=f[5]; framez0(f); endif;
	if y>=f[6]; framez1(f); endif;
	x=sin(v[3])*v[1]; y=-cos(v[3])*v[1];
	if x>=f[2]; framexpyp(f); framexpym(f); endif;
	if x<=f[1]; framexmyp(f); framexmym(f); endif;
	if y>=f[4]; framexmyp(f); framexpyp(f); endif;
	if y<=f[3]; framexmym(f); framexpym(f); endif;
	return 0
endfunction

function scaleframe (x,y,z,f,m)
	s=max([f[2]-f[1],f[4]-f[3],f[6]-f[5]]);
	xm=(f[2]+f[1])/2;
	ym=(f[4]+f[3])/2;
	zm=(f[6]+f[5])/2;
	ff=m/s*2;
	f=[f[1]-xm,f[2]-xm,f[3]-ym,f[4]-ym,f[5]-zm,f[6]-zm]*ff;
	return {(x-xm)*ff,(y-ym)*ff,(z-zm)*ff}
endfunction

function framedsolid (x,y,z,scale=0,grid=1,ticks=1)
## works like solid and draws a frame around the plot
## if scale is specified, then the plot is scaled to fit into a cube of
## side length 2*scale centered at 0
	frame=getframe(x,y,z);
	if !holding(); clg; endif;
	h=holding(1);
	if scale;
		{x1,y1,z1}=scaleframe(x,y,z,frame,scale);
	else;
		{x1,y1,z1}={x,y,z};
	endif;
	if grid || ticks;
		{tx,xfactor}=ticks(frame[1],frame[2]);
		{ty,yfactor}=ticks(frame[3],frame[4]);
		{tz,zfactor}=ticks(frame[5],frame[6]);
		color(2);frame1(frame,grid,ticks,tx,ty,tz,xfactor,yfactor,zfactor);
		color(1); solid(x1,y1,z1);
		color(2); frame2(frame);
		color(1);
	else
		color(2); frame1(frame);
		color(1); solid(x1,y1,z1);
		color(2); frame2(frame);
		color(1);
	endif;
	holding(h);
	return frame
endfunction

function framedsolidhue (x,y,z,hue,scale=0,f=1,grid=1,ticks=1)
## works like solidhue and draws a frame around the plot
## if scale is specified, then the plot is scaled to fit into a cube of
## side length 2*scale centered at 0
	frame=getframe(x,y,z);
	if !holding(); clg; endif;
	h=holding(1);
	if scale; {x1,y1,z1}=scaleframe(x,y,z,frame,scale);
	else; {x1,y1,z1}={x,y,z}; endif;
	if grid || ticks;
		{tx,xfactor}=ticks(frame[1],frame[2]);
		{ty,yfactor}=ticks(frame[3],frame[4]);
		{tz,zfactor}=ticks(frame[5],frame[6]);
		color(2);frame1(frame,grid,ticks,tx,ty,tz,xfactor,yfactor,zfactor);
		color(1);
		if f; solidhue(x1,y1,z1,hue,f);
		else; solidhue(x1,y1,z1,hue);
		endif;
		color(2); frame2(frame);
		color(1);
	else
		color(2); frame1(frame);
		color(1);
		if f; solidhue(x1,y1,z1,hue,f);
		else; solidhue(x1,y1,z1,hue);
		endif;
		color(2); frame2(frame);
		color(1);
	endif;
	holding(h);
	return frame
endfunction

function framedwire (x,y,z,scale=0,grid=0,ticks=1)
## works like framedsolid
	frame=getframe(x,y,z);
	if !holding(); clg; endif;
	h=holding(1);
	if scale; {x1,y1,z1}=scaleframe(x,y,z,frame,scale);
	else; {x1,y1,z1}={x,y,z}; endif;
	if grid || ticks;
		{tx,xfactor}=ticks(frame[1],frame[2]);
		{ty,yfactor}=ticks(frame[3],frame[4]);
		{tz,zfactor}=ticks(frame[5],frame[6]);
		color(2);frame1(frame,grid,ticks,tx,ty,tz,xfactor,yfactor,zfactor);
		color(1); wire(x1,y1,z1);
		color(2); frame2(frame);
		color(1);
	else
		color(2); frame1(frame);
		color(1); wire(x1,y1,z1);
		color(2); frame2(frame);
		color(1);
	endif;
	holding(h);
	return frame
endfunction


function framedmark3 (x,y,z,scale=0,grid=1,ticks=1)
## Plots points in three dimensions with frame. 
## x,y,z must be 1xn vectors.
	frame=getframe(x,y,z);
	if !holding(); clg; endif;
	h=holding(1);
	if scale; {x1,y1,z1}=scaleframe(x,y,z,frame,scale);
	else {x1,y1,z1}={x,y,z}; endif
	if grid || ticks;
		{tx,xfactor}=ticks(frame[1],frame[2]);
		{ty,yfactor}=ticks(frame[3],frame[4]);
		{tz,zfactor}=ticks(frame[5],frame[6]);
		color(2);frame1(frame,grid,ticks,tx,ty,tz,xfactor,yfactor,zfactor);
		color(1);
		{c0,r0}=project(x1,y1,z1);
		{x0,y0}=fromscreen(c0,r0);
		mark(x0,y0);
		color(2); frame2(frame);
		color(1);
	else
		color(2); frame1(frame);
		color(1);
		{c0,r0}=project(x1,y1,z1);
		{x0,y0}=fromscreen(c0,r0);
		mark(x0,y0);
		color(2); frame2(frame);
		color(1);
	endif;
	holding(h);
	return frame;
endfunction

