package math3D;
import generalMathClasses.Window2D;
import java.awt.Point;
import java.awt.geom.Point2D;
import primitives3D.Vector3D;
/**
* Translates 3D coordinates from values to pixels and handles rotation
* calculations.
*
* @author Curran Kelleher
*
*/
public class Window3D extends Window2D {
/**
* The distance of the viewer from the origin.
*/
private double viewerZdist = 50;
/**
* The zoom factor.
*/
private double zoom = 30;
/**
* When true, 3D perspective is implemented. When false, this window behaves
* like a 2D window.
*/
public boolean drawFor3D = true;
/**
* Vectors used in rotation calculation.
*/
private Vector3D rotatedXAxis = new Vector3D(1, 0, 0),
rotatedYAxis = new Vector3D(0, 1, 0), rotatedZAxis = new Vector3D(
0, 0, 1);
/**
* Temporary variable used by getPixelFromRotatedVector3D()
*/
double denom = 0;
/**
* Temporary variable used by getPixelFromVector3D()
*/
Vector3D tempPoint = new Vector3D(0, 0, 0);
/**
* Construct a Window3D with the specified dimensions (in pixels) of the
* viewing space. The range is set to -10, 10, -10, 10.
*
* @param w
* the width (in pixels) of the drawing space.
* @param h
* the height (in pixels) of the drawing space.
*/
public Window3D(int w, int h) {
super(w, h);
}
public void setRotation(double xrot, double yrot, double zrot) {
// reset the axes for fresh rotation
rotatedXAxis.x = 1;
rotatedXAxis.y = 0;
rotatedXAxis.z = 0;
rotatedYAxis.x = 0;
rotatedYAxis.y = 1;
rotatedYAxis.z = 0;
rotatedZAxis.x = 0;
rotatedZAxis.y = 0;
rotatedZAxis.z = 1;
// perform the rotation
rotatedXAxis.rotateVectorAboutZAxis(zrot, rotatedXAxis);
rotatedYAxis.rotateVectorAboutZAxis(zrot, rotatedYAxis);
rotatedZAxis.rotateVectorAboutZAxis(zrot, rotatedZAxis);
rotatedXAxis.rotateVectorAboutXAxis(xrot, rotatedXAxis);
rotatedYAxis.rotateVectorAboutXAxis(xrot, rotatedYAxis);
rotatedZAxis.rotateVectorAboutXAxis(xrot, rotatedZAxis);
rotatedXAxis.rotateVectorAboutYAxis(yrot, rotatedXAxis);
rotatedYAxis.rotateVectorAboutYAxis(yrot, rotatedYAxis);
rotatedZAxis.rotateVectorAboutYAxis(yrot, rotatedZAxis);
}
/**
* Rotates the specified point according to the rotation parameters which
* were set by calling setRotation().
*
* @param pointToRotate
* the template point to rotate (this point is not changed, the
* coordinates of the rotated point are put into
* pointToPutResultIn.)
* @param pointToPutResultIn
* the point which will get set to the coordinates of
* pointToRotate after the rotation has been calculated.
*/
public void getRotatedVector3D(Vector3D pointToRotate,
Vector3D pointToPutResultIn) {
if (drawFor3D)
rotatePoint(pointToRotate, rotatedXAxis, rotatedYAxis,
rotatedZAxis, pointToPutResultIn);
else
pointToPutResultIn.set(pointToRotate);
}
/**
* Rotates the specified point given the rotated X,Y,and Z axes.
*
* @param pointToRotate
* @param rotatedXAxis
* @param rotatedYAxis
* @param rotatedZAxis
* @param pointToPutResultIn
*/
private void rotatePoint(Vector3D pointToRotate, Vector3D rotatedXAxis,
Vector3D rotatedYAxis, Vector3D rotatedZAxis,
Vector3D pointToPutResultIn) {
pointToPutResultIn.x = pointToRotate.x * rotatedXAxis.x
+ pointToRotate.y * rotatedYAxis.x + pointToRotate.z
* rotatedZAxis.x;
pointToPutResultIn.y = pointToRotate.x * rotatedXAxis.y
+ pointToRotate.y * rotatedYAxis.y + pointToRotate.z
* rotatedZAxis.y;
pointToPutResultIn.z = pointToRotate.x * rotatedXAxis.z
+ pointToRotate.y * rotatedYAxis.z + pointToRotate.z
* rotatedZAxis.z;
}
/**
* Maps a Vector3D to a pixel, applying the window's transformation
* (rotation and and scale).
*
* Puts the result directly into the x and y coordinates of the given
* <code>Point</code> (pointToPutResultIn) This is done to optimize memory
* usage and enhance performance.
*
* If the specified <code>Vector3D</code> is not drawable on the screen,
* the x coordinate of pointToPutResultIn gets set to
* <code>Integer.MIN_VALUE</code>
*
*/
public void getPixelFromVector3D(Vector3D p, Point pointToPutResultIn) {
if (drawFor3D)
getRotatedVector3D(p, tempPoint);
getPixelFromRotatedPoint3D(tempPoint, pointToPutResultIn);
}
/**
* Maps a Vector3D to a pixel, applying the window's transformation
* (rotation and and scale).
*
* Puts the result directly into the x and y coordinates of the given
* <code>Point</code> (pointToPutResultIn) This is done to optimize memory
* usage and enhance performance.
*
* If the specified <code>Vector3D</code> is not drawable on the screen,
* the x coordinate of pointToPutResultIn gets set to
* <code>Integer.MIN_VALUE</code>
*
*/
public void getPixelFromVector3D(Vector3D p, Point2D.Float pointToPutResultIn) {
getRotatedVector3D(p, tempPoint);
getPixelFromRotatedPoint3D(tempPoint, pointToPutResultIn);
}
/**
* Maps a Vector3D to a pixel, but without applying the window's rotation.
*
* Puts the result directly into the x and y coordinates of the given
* <code>Point</code> (pointToPutResultIn) This is done to optimize memory
* usage and enhance performance.
*
* If the specified <code>Vector3D</code> is not drawable on the screen,
* the x coordinate of pointToPutResultIn gets set to
* <code>Integer.MIN_VALUE</code>
*/
public void getPixelFromRotatedPoint3D(Vector3D p, Point pointToPutResultIn) {
if (drawFor3D) {
denom = p.z - viewerZdist;
if (denom > 0 || p.z == Double.NaN || p.x == Double.NaN
|| p.y == Double.NaN || Double.isInfinite(p.z)
|| Double.isInfinite(p.x) || Double.isInfinite(p.y)) {
pointToPutResultIn.x = Integer.MIN_VALUE;
} else {
pointToPutResultIn.x = getXpixel(zoom * p.x / denom);
pointToPutResultIn.y = getYpixel(zoom * p.y / denom);
}
} else {
pointToPutResultIn.x = getXpixel(p.x);
pointToPutResultIn.y = getYpixel(p.y);
}
}
/**
* Maps a Vector3D to a pixel, but without applying the window's rotation.
*
* Puts the result directly into the x and y coordinates of the given
* <code>Point</code> (pointToPutResultIn) This is done to optimize memory
* usage and enhance performance.
*
* If the specified <code>Vector3D</code> is not drawable on the screen,
* the x coordinate of pointToPutResultIn gets set to
* <code>Integer.MIN_VALUE</code>
*/
public void getPixelFromRotatedPoint3D(Vector3D p, Point2D.Float pointToPutResultIn) {
if (drawFor3D) {
denom = p.z - viewerZdist;
if (denom > 0 || p.z == Double.NaN || p.x == Double.NaN
|| p.y == Double.NaN || Double.isInfinite(p.z)
|| Double.isInfinite(p.x) || Double.isInfinite(p.y)) {
pointToPutResultIn.x = Integer.MIN_VALUE;
} else {
pointToPutResultIn.x = (float)getXpixelAsDouble(zoom * p.x / denom);
pointToPutResultIn.y = (float)getYpixelAsDouble(zoom * p.y / denom);
}
} else {
pointToPutResultIn.x = (float)getXpixelAsDouble(p.x);
pointToPutResultIn.y = (float)getYpixelAsDouble(p.y);
}
}
}