level fourth
diff --git a/src/elements/Camera.java b/src/elements/Camera.java
new file mode 100644
index 0000000..bad0290
--- /dev/null
+++ b/src/elements/Camera.java
@@ -0,0 +1,136 @@
+package elements;
+
+import primitives.Point3D;
+import primitives.Ray;
+import primitives.Vector;
+import static primitives.Util.*;
+
+/**
+ * This class represents the elements of the scene
+ *
+ * @author Adiel
+ *
+ */
+public class Camera {
+
+ final Point3D p0;// Location of the camera
+ final Vector vUp;// Vector upward direction
+ final Vector vTo;// Vector forward direction
+ final Vector vRight;// Vector direction to the right
+
+ private double width;//Width of the View Plane
+ private double height;//Height of the View Plane
+ private double distance;//Distance of the View Plane from the Camera
+
+ /**
+ * Getter for p0
+ *
+ * @return the camera position
+ */
+ public Point3D getP0() {
+ return p0;
+ }
+
+ /**
+ * Getter for vector Up
+ *
+ * @return vector Up
+ */
+ public Vector getvUp() {
+ return vUp;
+ }
+
+ /**
+ * Getter for vector Forward
+ *
+ * @return vector To
+ */
+ public Vector getvTo() {
+ return vTo;
+ }
+
+ /**
+ * Getter for vector Right
+ *
+ * @return vector Right
+ */
+ public Vector getvRight() {
+ return vRight;
+ }
+
+ /**
+ * A constructor that initializes the position and direction vectors
+ *
+ * @param p0 for location values
+ * @param vTo for vector forward
+ * @param vUp for vector up
+ */
+ public Camera(Point3D p0, Vector vTo, Vector vUp) {
+ this.p0 = p0;
+
+ if (!isZero(vUp.dotProduct(vTo)))// Check if vUp and vTo vectors are vertical
+ throw new IllegalArgumentException("vUp and vTo are not vertical");
+
+ this.vUp = vUp.normalized();
+ this.vTo = vTo.normalized();
+ this.vRight = this.vTo.crossProduct(this.vUp);
+ }
+
+ /**
+ * Borrowing from Builder pattern
+ *
+ * @param width for the width of the view plane
+ * @param height for the height of the view plane
+ * @return the camera object itself
+ */
+ public Camera setViewPlaneSize(double width, double height) {
+ this.width = width;
+ this.height = height;
+ return this;
+ }
+
+ /**
+ * Update method for the View Plane distance from the camera
+ *
+ * @param distance for the distance
+ * @return the camera object itself
+ */
+ public Camera setVpDistance(double distance) {
+ this.distance = distance;
+ return this;
+ }
+
+ /**
+ * Constructing a ray through a pixel
+ *
+ * @param nX for quantity of columns (row width)
+ * @param nY for quantity of rows (column height)
+ * @param j for a column of pixels
+ * @param i for a line of pixels
+ * @return the position and the direction vector
+ */
+ public Ray constructRayThroughPixel(int nX, int nY, int j, int i) {
+
+ Point3D pC = p0.add(vTo.scale(distance));
+
+ double rY = height / nY;
+ double rX = width / nX;
+
+ double yI = (i - (nY - 1) / 2d) * rY;
+ double xJ = (j - (nX - 1) / 2d) * rX;
+
+ Point3D pIJ = pC;
+
+ if (!isZero(xJ)) {
+ pIJ = pIJ.add(vRight.scale(xJ));
+
+ }
+ if (!isZero(yI)) {
+ pIJ = pIJ.add(vUp.scale(-yI));
+
+ }
+
+ return new Ray(p0, pIJ.subtract(p0));
+ }
+
+}
diff --git a/src/geometries/Sphere.java b/src/geometries/Sphere.java
index a46c901..45bc424 100644
--- a/src/geometries/Sphere.java
+++ b/src/geometries/Sphere.java
@@ -21,10 +21,10 @@
/**
* Sphere constructor receiving 2 values
*
- * @param center of the Sphere
* @param radius of the Sphere
+ * @param center of the Sphere
*/
- public Sphere(Point3D center, double radius) {
+ public Sphere(double radius, Point3D center) {
this.center = center;
this.radius = radius;
}
diff --git a/src/primitives/Ray.java b/src/primitives/Ray.java
index da37cf0..7643377 100644
--- a/src/primitives/Ray.java
+++ b/src/primitives/Ray.java
@@ -44,7 +44,7 @@
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
- if (!(obj instanceof Vector))
+ if (!(obj instanceof Ray))
return false;
Ray other = (Ray)obj;
return p0.equals(other.p0) && dir.equals(other.dir);
diff --git a/src/unittests/CameraTests.java b/src/unittests/CameraTests.java
new file mode 100644
index 0000000..13fb558
--- /dev/null
+++ b/src/unittests/CameraTests.java
@@ -0,0 +1,57 @@
+package unittests;
+
+import static org.junit.Assert.*;
+import org.junit.Test;
+import elements.Camera;
+import primitives.*;
+
+/**
+ * Testing Camera Class
+ *
+ * @author Dan
+ *
+ */
+public class CameraTests{
+
+ /**
+ * Test method for
+ * {@link elements.Camera#constructRayThroughPixel(int, int, int, int)}.
+ */
+ @Test
+ public void testConstructRayThroughPixel(){
+ Camera camera = new Camera(Point3D.ZERO, new Vector(0, 0, 1),
+ new Vector(0, -1, 0)).setVpDistance(10);
+
+ // ============ Equivalence Partitions Tests ==============
+ // TC01: 3X3 Corner (0,0)
+ assertEquals("Bad ray", new Ray(Point3D.ZERO, new Vector(-2, -2, 10)),
+ camera.setViewPlaneSize(6, 6).constructRayThroughPixel(3, 3, 0, 0));
+
+ // TC02: 4X4 Corner (0,0)
+ assertEquals("Bad ray", new Ray(Point3D.ZERO, new Vector(-3, -3, 10)),
+ camera.setViewPlaneSize(8, 8).constructRayThroughPixel(4, 4, 0, 0));
+
+ // TC03: 4X4 Side (0,1)
+ assertEquals("Bad ray", new Ray(Point3D.ZERO, new Vector(-1, -3, 10)),
+ camera.setViewPlaneSize(8, 8).constructRayThroughPixel(4, 4, 1, 0));
+
+ // TC04: 4X4 Inside (1,1)
+ assertEquals("Bad ray", new Ray(Point3D.ZERO, new Vector(-1, -1, 10)),
+ camera.setViewPlaneSize(8, 8).constructRayThroughPixel(4, 4, 1, 1));
+
+ // =============== Boundary Values Tests ==================
+ // TC11: 3X3 Center (1,1)
+ assertEquals("Bad ray", new Ray(Point3D.ZERO, new Vector(0, 0, 10)),
+ camera.setViewPlaneSize(6, 6).constructRayThroughPixel(3, 3, 1, 1));
+
+ // TC12: 3X3 Center of Upper Side (0,1)
+ assertEquals("Bad ray", new Ray(Point3D.ZERO, new Vector(0, -2, 10)),
+ camera.setViewPlaneSize(6, 6).constructRayThroughPixel(3, 3, 1, 0));
+
+ // TC13: 3X3 Center of Left Side (1,0)
+ assertEquals("Bad ray", new Ray(Point3D.ZERO, new Vector(-2, 0, 10)),
+ camera.setViewPlaneSize(6, 6).constructRayThroughPixel(3, 3, 0, 1));
+
+ }
+
+}
diff --git a/src/unittests/GeometriesTests.java b/src/unittests/GeometriesTests.java
index 4d8bcaa..7d81864 100644
--- a/src/unittests/GeometriesTests.java
+++ b/src/unittests/GeometriesTests.java
@@ -29,7 +29,7 @@
new Point3D(0, 1, 0),
new Point3D(0, 0, 1));
- Sphere sphere = new Sphere(new Point3D(0, 6, 0), 2);
+ Sphere sphere = new Sphere(2, new Point3D(0, 6, 0));
Triangle triangle = new Triangle(
new Point3D(1, 0, 0),
new Point3D(3, 2, 0),
@@ -58,7 +58,7 @@
//TC04: All shapes are intersected
- sphere = new Sphere(new Point3D(3, 0, -3), 2);
+ sphere = new Sphere(2, new Point3D(3, 0, -3));
geometries.add(sphere);
intersections = geometries.findIntersections(ray);
assertEquals("Some shapes are intersected",4, intersections.size());
diff --git a/src/unittests/IntegrationTests.java b/src/unittests/IntegrationTests.java
new file mode 100644
index 0000000..e184f25
--- /dev/null
+++ b/src/unittests/IntegrationTests.java
@@ -0,0 +1,123 @@
+package unittests;
+
+import geometries.*;
+import elements.Camera;
+import primitives.*;
+import static org.junit.Assert.*;
+
+import java.util.List;
+
+import org.junit.Test;
+
+
+/**
+ * This class is used for integration tests between the formation of rays from a camera
+ * and the calculation of cuts of a ray with geometric bodies
+ * @author Adiel
+ *
+ */
+public class IntegrationTests {
+
+ /**
+ *
+ * Auxiliary function for cutting a ray with the body and counting the amount of cuts
+ *
+ * @param cam camera for the test
+ * @param geo 3D body to test the integration of the camera with the ray
+ * @param expected amount of intersections
+ */
+ private void assertCountIntersections(Camera cam, Intersectable geo, int expected) {
+ int count = 0;
+ cam.setViewPlaneSize(3, 3).setVpDistance(1);
+
+ //Loop of creating rays and count of cuts
+ for (int i = 0; i < 3; ++i)
+ for (int j = 0; j < 3; ++j) {
+ List<Point3D> intersections = geo.findIntersections(
+ cam.constructRayThroughPixel(3, 3, j, i));
+ if(intersections!=null) {
+ count += intersections.size();
+ }
+
+
+ }
+ //Check that the amount of cuts is correct
+ assertEquals("Wrong amount of intersections", expected, count);
+ }
+
+ /**
+ * Integration tests of Camera Ray construction with Ray-Sphere intersections
+ */
+ @Test
+ public void cameraRaySphereIntegretion() {
+
+ Camera camera1 = new Camera(Point3D.ZERO, new Vector(0, 0, -1),
+ new Vector(0, -1, 0));
+ Camera camera2 = new Camera(new Point3D(0, 0, 0.5), new Vector(0, 0, -1),
+ new Vector(0, -1, 0));
+
+ // TC01: Small Sphere (2 point)
+ assertCountIntersections(camera1, new Sphere(
+ 1, new Point3D(0, 0, -3)), 2);
+
+ // TC02: Big Sphere (18 points)
+ assertCountIntersections(camera2, new Sphere(
+ 2.5, new Point3D(0, 0, -2.5)), 18);
+
+ // TC03: Medium Sphere (10 points)
+ assertCountIntersections(camera2, new Sphere(
+ 2, new Point3D(0, 0, -2)), 10);
+
+ // TC04: Inside Sphere (9 points)
+ assertCountIntersections(camera2, new Sphere(
+ 4, new Point3D(0, 0, -1)), 9);
+
+ // TC05: Beyond Sphere (0 points)
+ assertCountIntersections(camera1, new Sphere(
+ 0.5, new Point3D(0, 0, 1)), 0);
+ }
+
+ /**
+ * Integration tests of Camera Ray construction with Ray-Plane intersections
+ */
+ @Test
+ public void cameraRayPlaneIntegration() {
+ Camera camera = new Camera(Point3D.ZERO, new Vector(0, 0, -1),
+ new Vector(0, -1, 0));
+
+ // TC01: Plane against camera (9 points)
+ assertCountIntersections(camera, new Plane(new Point3D(0, 0, -5),
+ new Vector(0, 0, 1)), 9);
+
+ // TC02: Plane with small angle (9 points)
+ assertCountIntersections(camera, new Plane(new Point3D(0, 0, -5),
+ new Vector(0, 1, 2)), 9);
+
+ // TC03: Plane parallel to lower rays (6 points)
+ assertCountIntersections(camera, new Plane(new Point3D(0, 0, -5),
+ new Vector(0, 1, 1)), 6);
+
+ // TC04: Beyond Plane (0 points)
+ assertCountIntersections(camera, new Plane(new Point3D(0, 0, 1),
+ new Vector(0, 2, 0)), 0);
+ }
+
+ /**
+ * Integration tests of Camera Ray construction with Ray-Triangle intersections
+ */
+ @Test
+ public void cameraRayTriangleIntegration() {
+ Camera camera = new Camera(Point3D.ZERO,
+ new Vector(0, 0, -1), new Vector(0, -1, 0));
+
+ // TC01: Small triangle (1 point)
+ assertCountIntersections(camera, new Triangle(new Point3D(1, -1, -2),
+ new Point3D(-1, -1, -2), new Point3D(0, 1, -2)), 1);
+
+ //TC02: Medium triangle (2 points)
+ assertCountIntersections(camera, new Triangle(new Point3D(1, -1, -2),
+ new Point3D(-1, -1, -2), new Point3D(0, 20, -2)), 2);
+ }
+
+
+}
diff --git a/src/unittests/SphereTests.java b/src/unittests/SphereTests.java
index 277ffcf..4a2535c 100644
--- a/src/unittests/SphereTests.java
+++ b/src/unittests/SphereTests.java
@@ -26,7 +26,7 @@
public void testGetNormal() {
// ============ Equivalence Partitions Tests ==============
- Sphere sp = new Sphere(new Point3D(0, 0, 1), 1d);
+ Sphere sp = new Sphere(1d, new Point3D(0, 0, 1));
double sqrt2 = Math.sqrt(2);
// Standard normal test
assertEquals("Bad normal to sphere", new Vector(1 / sqrt2, 0, -1 / sqrt2),
@@ -39,7 +39,7 @@
*/
@Test
public void testFindIntersections() {
- Sphere sphere = new Sphere(new Point3D(1, 0, 0), 1d);
+ Sphere sphere = new Sphere(1d, new Point3D(1, 0, 0));
// ============ Equivalence Partitions Tests ==============