Add extra Parallelepiped options

This commit is contained in:
Petar Kapriš 2022-12-20 14:56:10 +01:00 committed by Петар Каприш
parent b3f073e2be
commit edf8d251ed

View file

@ -0,0 +1,129 @@
package xyz.marsavic.gfxlab.graphics3d.solids;
import xyz.marsavic.functions.interfaces.F1;
import xyz.marsavic.geometry.Vector;
import xyz.marsavic.gfxlab.Vec3;
import xyz.marsavic.gfxlab.graphics3d.Hit;
import xyz.marsavic.gfxlab.graphics3d.Material;
import xyz.marsavic.gfxlab.graphics3d.Ray;
import xyz.marsavic.gfxlab.graphics3d.Solid;
public class Parallelepiped implements Solid {
private final Vec3 p; // starting vertex
private final Vec3[][][] vertices;
HalfSpace [] sides;
private final F1<Material, Vector> mapMaterial;
private final Vec3 a, b, c;
private Parallelepiped(Vec3 point, Vec3 aEdge, Vec3 bEdge, Vec3 cEdge, F1<Material, Vector> mapMaterial) {
this.mapMaterial = mapMaterial;
this.p = point;
this.a = aEdge;
this.b = bEdge;
this.c = cEdge;
vertices = new Vec3[][][]
{{{p, p.add(c)}, {p.add(b), p.add(b).add(c)}},
{{p.add(a), p.add(a).add(c)}, {p.add(a).add(b), p.add(a).add(b).add(c)}}};
sides = new HalfSpace[6];
sides[0] = HalfSpace.pef(p, b, a, mapMaterial);
sides[1] = HalfSpace.pef(p.add(c), a, b, mapMaterial);
sides[2] = HalfSpace.pef(p, a, c, mapMaterial);
sides[3] = HalfSpace.pef(p.add(b), c, a, mapMaterial);
sides[4] = HalfSpace.pef(p, c, b, mapMaterial);
sides[5] = HalfSpace.pef(p.add(a), b, c, mapMaterial);
}
public static Parallelepiped pabc(Vec3 p, Vec3 a, Vec3 b, Vec3 c, F1<Material, Vector> mapMaterial) {
return new Parallelepiped(p, a, b, c, mapMaterial);
}
public static Parallelepiped cabc(Vec3 center, Vec3 a, Vec3 b, Vec3 c, F1<Material, Vector> mapMaterial) {
return new Parallelepiped(center.sub(a.div(2)).sub(b.div(2)).sub(c.div(2)),
a, b, c, mapMaterial);
}
public static Parallelepiped pxyz(Vec3 p, double x, double y, double z, F1<Material, Vector> mapMaterial) {
return new Parallelepiped(p,
Vec3.xyz(x, 0, 0), Vec3.xyz(0, y, 0), Vec3.xyz(0, 0, z),
mapMaterial);
}
public static Parallelepiped cxyz(Vec3 center, double x, double y, double z, F1<Material, Vector> mapMaterial) {
return new Parallelepiped(center.sub(Vec3.xyz(x/2, y/2, z/2)),
Vec3.xyz(x, 0, 0), Vec3.xyz(0, y, 0), Vec3.xyz(0, 0, z),
mapMaterial);
}
public Vec3 p() {
return p;
}
public Vec3 center() { return p.add(a.div(2)).add(b.div(2)).add(c.div(2)); }
public Vec3 a() {
return a;
}
public Vec3 b() {
return b;
}
public Vec3 c() {
return c;
}
public Vec3[][][] vertices() {
return vertices.clone();
}
private static boolean pointOnParallelogram(Vec3 p, Vec3 e, Vec3 f) {
// we solve p as a linear combination of a*e+b*f, then check if this combination is in
// 0<=a<=1 and 0<=b<=1
double D = e.lengthSquared() * f.lengthSquared() - e.dot(f)*e.dot(f);
if (D == 0)
return false;
// System determinant
double Da = p.dot(e)*f.lengthSquared() - p.dot(f)*e.dot(f);
// a's determinant
double Db = e.lengthSquared()*p.dot(f) - e.dot(f)*p.dot(e);
double a = Da/D;
// a's determinant
double b = Db/D;
// b's determinant
return a >= 0 && a <= 1 && b >= 0 && b <= 1;
}
@Override
public Hit firstHit(Ray ray, double afterTime) {
Hit[] planeHits = new Hit[6];
for (int i = 0; i < 6; i++) {
planeHits[i] = sides[i].firstHit(ray, afterTime);
if (planeHits[i] == null) {
continue;
}
Vec3 rayPlaneIntersect = ray.at(planeHits[i].t());
if (!pointOnParallelogram(rayPlaneIntersect.sub(sides[i].p()), sides[i].e(), sides[i].f())) {
planeHits[i] = null;
}
}
double minT = Hit.t(null); // Positive infinity
int minI = 0;
for (int i = 0; i < 6; i++) {
if (Hit.t(planeHits[i]) < minT) {
minT = Hit.t(planeHits[i]);
minI = i;
}
}
return planeHits[minI];
}
}