-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathCylinder.java
105 lines (88 loc) · 3.38 KB
/
Cylinder.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package ray.surface;
import java.util.Arrays;
import ray.IntersectionRecord;
import ray.Ray;
import ray.math.Point3;
import ray.math.Vector3;
public class Cylinder extends Surface {
/** The center of the cylinder. */
protected final Point3 center = new Point3();
public void setCenter(Point3 center) { this.center.set(center); }
/** The radius of the cylinder. */
protected double radius = 1.0;
public void setRadius(double radius) { this.radius = radius; }
/** The height of the cylinder in the z-direction.
* The cylinder's extent in z is center.z +/- height/2 */
protected double height = 1.0;
public void setHeight(double height) { this.height = height; }
public Cylinder() { }
/**
* Tests this surface for intersection with ray. If an intersection is found
* record is filled out with the information about the intersection and the
* method returns true. It returns false otherwise and the information in
* outRecord is not modified.
*
* @param outRecord the output IntersectionRecord
* @param ray the ray to intersect
* @return true if the surface intersects the ray
*/
public boolean intersect(IntersectionRecord outRecord, Ray rayIn) {
Vector3 eminusc = new Vector3();
eminusc.sub(rayIn.origin, center);
double a = Math.pow(rayIn.direction.x, 2) + Math.pow(rayIn.direction.y, 2);
double b = 2 * (rayIn.direction.x * eminusc.x + rayIn.direction.y * eminusc.y);
double c = Math.pow(eminusc.x, 2) + Math.pow(eminusc.y, 2) - Math.pow(radius, 2);
double discriminant = b * b - 4 * a * c;
if (discriminant < 0) {
return false;
}
double t1 = Math.min((-b + Math.sqrt(discriminant)) / (2 * a), (-b - Math.sqrt(discriminant)) / (2 * a));
double t2 = (height / 2.0 - eminusc.z) / rayIn.direction.z;
double t3 = (-height / 2.0 - eminusc.z) / rayIn.direction.z;
// We'll iterate through the values in sorted order so we find closest intersection first
double[] tarr = {t1, t2, t3};
Arrays.sort(tarr);
Double t = null; // The lowest intersection we find
for (double x : tarr) {
IntersectionRecord tmp = new IntersectionRecord();
tmp.location.add(rayIn.origin, Vector3.getScaledVector(rayIn.direction, x));
if (x == t1) {
if (Math.abs(tmp.location.z - center.z) < height / 2.0) {
outRecord.normal.set(
tmp.location.x - center.x,
tmp.location.y - center.y,
0);
outRecord.normal.normalize();
t = x;
break;
}
} else {
if (Math.pow(tmp.location.x - center.x, 2)
+ Math.pow(tmp.location.y - center.y, 2)
- Math.pow(radius, 2) <= 0) {
if (x == t2) {
outRecord.normal.set(0, 0, 1);
} else if (x == t3) {
outRecord.normal.set(0, 0, -1);
}
t = x;
break;
}
}
}
if (t == null || t > rayIn.end || t < rayIn.start) {
return false;
}
rayIn.end = t;
outRecord.surface = this;
outRecord.t = t;
outRecord.location.add(rayIn.origin, Vector3.getScaledVector(rayIn.direction, t));
return true;
}
/**
* @see Object#toString()
*/
public String toString() {
return "Cylinder " + center + " " + radius + " " + height + " "+ shader + " end";
}
}