// Critical definitions for transform3 needed by projection and picture.
pair viewportmargin=settings.viewportmargin;
using transform3=real[][];
restricted transform3 identity4=identity(4);
// A uniform 3D scaling.
transform3 scale3(real s)
{
transform3 t=identity(4);
t[0][0]=t[1][1]=t[2][2]=s;
return t;
}
// Simultaneous 3D scalings in the x, y, and z directions.
transform3 scale(real x, real y, real z)
{
transform3 t=identity(4);
t[0][0]=x;
t[1][1]=y;
t[2][2]=z;
return t;
}
struct projection {
transform3 t; // projection*modelview (cached)
bool infinity;
bool absolute=false;
triple camera; // Position of camera.
triple up; // A vector that should be projected to direction (0,1).
triple target; // Point where camera is looking at.
triple normal; // Normal vector from target to projection plane.
pair viewportshift; // Fractional viewport shift.
real zoom=1; // Zoom factor.
real angle; // Lens angle (for perspective projection).
bool showtarget=true; // Expand bounding volume to include target?
using projector=transformation(triple camera, triple up, triple target);
projector projector;
bool autoadjust=true; // Adjust camera to lie outside bounding volume?
bool center=false; // Center target within bounding volume?
int ninterpolate; // Used for projecting nurbs to 2D Bezier curves.
bool bboxonly=true; // Typeset label bounding box only.
// Return the maximum distance of box(m,M) from target.
real distance(triple m, triple M) {
triple[] c={m,(m.x,m.y,M.z),(m.x,M.y,m.z),(m.x,M.y,M.z),
(M.x,m.y,m.z),(M.x,m.y,M.z),(M.x,M.y,m.z),M};
return max(abs(c-target));
}
// This is redefined here to make projection as self-contained as possible.
static private real sqrtEpsilon=sqrt(realEpsilon);
// Move the camera so that the box(m,M) rotated about target will always
// lie in front of the far clipping plane.
bool adjust(triple m, triple M) {
triple v=camera-target;
real d=distance(m,M);
static real lambda=camerafactor*(1-sqrtEpsilon);
if(lambda*d >= abs(v)) {
camera=target+camerafactor*d*unit(v);
calculate();
return true;
}
return false;
}
}
projection currentprojection;
struct light {
real[][] diffuse;
real[][] specular;
pen background=nullpen; // Background color of the 3D canvas.
real specularfactor;
triple[] position; // Only directional lights are currently implemented.
transform3 T=identity(4); // Transform to apply to normal vectors.
bool on() {return position.length > 0;}
void operator init(pen[] diffuse,
pen[] specular=diffuse, pen background=nullpen,
real specularfactor=1,
triple[] position) {
int n=diffuse.length;
assert(specular.length == n && position.length == n);
void operator init(pen diffuse=white, pen specular=diffuse,
pen background=nullpen, real specularfactor=1 ...triple[] position) {
int n=position.length;
operator init(array(n,diffuse),array(n,specular),
background,specularfactor,position);
}
void operator init(pen diffuse=white, pen specular=diffuse,
pen background=nullpen, real x, real y, real z) {
operator init(diffuse,specular,background,(x,y,z));
}