我应该为它创建一个函数和测试用例,它返回光线和球体的交点。如果有多个交叉点(光线进出球体),那么它应该返回最接近光线起点的点。我必须使用二次方程来做到这一点。这就是我现在所拥有的。
import vector_math
import data
def sphere_intersection_point(ray, sphere):
pnt = data.Point(2*(ray.pt.x - sphere.center.x), 2*(ray.pt.y - sphere.center.y), 2*(ray.pt.z - sphere.center.z))
pnt2 = data.Point(ray.pt.x - sphere.center.x, ray.pt.y - sphere.center.y, ray.pt.z - sphere.center.z)
a = (vector_math.dot_vector(ray.dir, ray.dir))
b = (pnt.x*ray.dir.x) + (pnt.y*ray.dir.y) + (pnt.z*ray.dir.z)
c = (vector_math.dot_vector(pnt2, pnt2)-sphere.radius**2)
discriminant = (b**2 - 4*a*c)
t1 = (-b+discriminant)/(2*a)
t2 = (-b-discriminant)/(2*a)
t = t1 or t2
(a*(t**2)) + (b*t) + c == 0
if t1 > 0 and t2 > 0:
mt = min(t1,t2)
vec = vector_math.scale_vector(ray.dir, mt)
return data.Point(ray.pt.x + vec.x, ray.pt.y + vec.y, ray.pt.z + vec.z)
elif (t1>0 and t2<0) or (t1<0 and t2>0):
maxt = max(t1, t2)
vec2 = vector_math.scale_vector(ray.dir, maxt)
return data.Point(ray.pt.x + vec2.x, ray.pt.y + vec2.y, ray.pt.z + vec2.z)
elif t1<0 and t2<0:
return None
到目前为止,我为此编写了一个测试用例,但它没有返回正确的观点。这是我的测试用例代码。这只是最后一个。
import unittest
import data
import vector_math
import math
import collisions
class TestData(unittest.TestCase):
def test_point_1(self):
self.assertEqual(data.Point(1,2,3).x,1)
self.assertEqual(data.Point(1,2,3).y,2)
self.assertEqual(data.Point(1,2,3).z,3)
def test_point_2(self):
self.assertEqual(data.Point(3,3,4).x,3)
self.assertEqual(data.Point(3,3,4).y,3)
self.assertEqual(data.Point(3,3,4).z,4)
def test_vector_1(self):
self.assertEqual(data.Vector(1,2,3).x,1)
self.assertEqual(data.Vector(1,2,3).y,2)
self.assertEqual(data.Vector(1,2,3).z,3)
def test_vector_2(self):
self.assertEqual(data.Vector(4,5,6).x,4)
self.assertEqual(data.Vector(4,5,6).y,5)
self.assertEqual(data.Vector(4,5,6).z,6)
def test_ray_1(self):
self.assertEqual(data.Ray(data.Point(0,0,0),data.Vector(1,2,3)).pt.x,0)
self.assertEqual(data.Ray(data.Point(0,0,0),data.Vector(1,2,3)).pt.y,0)
self.assertEqual(data.Ray(data.Point(0,0,0),data.Vector(1,2,3)).pt.z,0)
self.assertEqual(data.Ray(data.Point(0,0,0),data.Vector(1,2,3)).dir.x,1)
self.assertEqual(data.Ray(data.Point(0,0,0),data.Vector(1,2,3)).dir.y,2)
self.assertEqual(data.Ray(data.Point(0,0,0),data.Vector(1,2,3)).dir.z,3)
def test_ray_2(self):
self.assertEqual(data.Ray(data.Point(1,2,3),data.Vector(2,2,2)).pt.x,1)
self.assertEqual(data.Ray(data.Point(1,2,3),data.Vector(2,2,2)).pt.y,2)
self.assertEqual(data.Ray(data.Point(1,2,3),data.Vector(2,2,2)).pt.z,3)
self.assertEqual(data.Ray(data.Point(1,2,3),data.Vector(2,2,2)).dir.x,2)
self.assertEqual(data.Ray(data.Point(1,2,3),data.Vector(2,2,2)).dir.y,2)
self.assertEqual(data.Ray(data.Point(1,2,3),data.Vector(2,2,2)).dir.z,2)
def test_sphere_1(self):
self.assertEqual(data.Sphere(data.Point(1,1,1),4.0).center.x,1)
self.assertEqual(data.Sphere(data.Point(1,1,1),4.0).center.y,1)
self.assertEqual(data.Sphere(data.Point(1,1,1),4.0).center.z,1)
self.assertEqual(data.Sphere(data.Point(1,1,1),4.0).radius,4.0)
def test_sphere_2(self):
self.assertEqual(data.Sphere(data.Point(1,1,1),3.0).center.x,1)
self.assertEqual(data.Sphere(data.Point(1,1,1),3.0).center.y,1)
self.assertEqual(data.Sphere(data.Point(1,1,1),3.0).center.z,1)
self.assertEqual(data.Sphere(data.Point(1,1,1),3.0).radius,3.0)
def test_equality(self):
self.assertTrue(data.Point(1,2,3) == data.Point(1,2,3))
self.assertTrue(data.Vector(1,2,3) == data.Vector(1,2,3))
self.assertTrue(data.Ray(data.Point(0,0,0), data.Vector(1,1,1)) == data.Ray(data.Point(0,0,0), data.Vector(1,1,1)))
self.assertTrue(data.Sphere(data.Point(0,0,0),3.0) == data.Sphere(data.Point(0,0,0),3.0))
def test_scale_vector(self):
self.assertEqual(vector_math.scale_vector(data.Vector(1,1,1),3.0), data.Vector(3.0,3.0,3.0))
def test_dot_product(self):
self.assertEqual(vector_math.dot_vector(data.Vector(1,1,1), data.Vector(2,2,2)), 6)
def test_length_vector(self):
self.assertEqual(vector_math.length_vector(data.Vector(1,2,3)), math.sqrt(1**2+2**2+3**2))
def test_normalize_vector(self):
self.assertEqual(vector_math.normalize_vector(data.Vector(2,0,0)), data.Vector(1,0,0))
def test_difference_point(self):
self.assertEqual(vector_math.difference_point(data.Point(2,0,0), data.Point(0,0,0)), data.Vector(2,0,0))
def test_difference_vector(self):
self.assertEqual(vector_math.difference_vector(data.Vector(3,3,3), data.Vector(1,1,1)), data.Vector(2,2,2))
def test_translate_point(self):
self.assertEqual(vector_math.translate_point(data.Point(0,0,0), data.Vector(1,1,1)), data.Point(1,1,1))
def test_vector_from_to(self):
self.assertEqual(vector_math.vector_from_to(data.Point(0,0,0), data.Point(2,2,2)), data.Vector(2,2,2))
def test_sphere_intersection_pt_1(self):
ray1 = data.Ray(data.Point(0,0,0), data.Vector(3,0,0))
sphere1 = data.Sphere(data.Point(5,0,0), 1)
self.assertEqual(collisions.sphere_intersection_point(ray1, sphere1), data.Point(4,0,0))
if __name__ == '__main__':
unittest.main()
我知道有些缩进是关闭的,但它们在我的文本编辑器中是正确的,它只是复制和粘贴很奇怪。这是我得到的错误。
root@THEO_PC:/mnt/c/Users/Theo/Desktop/cpe101/hw3# python tests.py
.............F....
======================================================================
FAIL: test_sphere_intersection_pt_1 (__main__.TestData)
----------------------------------------------------------------------
Traceback (most recent call last):
File "tests.py", line 89, in test_sphere_intersection_pt_1
self.assertEqual(collisions.sphere_intersection_point(ray1, sphere1), data.Point(4,0,0))
AssertionError: <data.Point instance at 0x7f42757cedd0> != <data.Point instance at 0x7f42757ced88>
----------------------------------------------------------------------
Ran 18 tests in 0.003s
FAILED (failures=1)
这里还有我的vector_math文件。
import math
import data
def scale_vector (vector, scalar):
return data.Vector(vector.x*scalar, vector.y*scalar, vector.z*scalar)
def dot_vector (vector1, vector2):
return vector1.x*vector2.x + vector1.y*vector2.y + vector1.z*vector2.z
def length_vector (vector):
return math.sqrt(vector.x**2 + vector.y**2 + vector.z**2)
def normalize_vector (vector):
return data.Vector(vector.x/length_vector(vector), vector.y/length_vector(vector), vector.z/length_vector(vector))
def difference_point (point1, point2):
return data.Vector(point1.x - point2.x, point1.y - point2.y, point1.z - point2.z)
def difference_vector (vector1, vector2):
return data.Vector(vector1.x - vector2.x, vector1.y - vector2.y, vector1.z - vector2.z)
def translate_point (point, vector):
return data.Point(point.x + vector.x, point.y + vector.y, point.z + vector.z)
def vector_from_to (from_point, to_point):
return data.Vector(to_point.x - from_point.x, to_point.y - from_point.y, to_point.z - from_point.z)
这是我的数据文件。
import utility
class Point:
def __init__ (self,x,y,z):
self.x=x
self.y=y
self.z=z
def __eq__ (self, other):
x = utility.epsilon_equal(self.x, other.x)
y = utility.epsilon_equal(self.y, other.y)
z = utility.epsilon_equal(self.z, other.z)
return x and y and z
class Vector:
def __init__ (self,x,y,z):
self.x=x
self.y=y
self.z=z
def __eq__ (self, other):
x = utility.epsilon_equal(self.x, other.x)
y = utility.epsilon_equal(self.y, other.y)
z = utility.epsilon_equal(self.z, other.z)
return x and y and z
class Ray:
def __init__ (self,pt,dir):
self.pt=pt
self.dir=dir
def __eq__ (self, other):
a = utility.epsilon_equal(self.pt.x, other.pt.x)
b = utility.epsilon_equal(self.pt.y, other.pt.y)
c = utility.epsilon_equal(self.pt.z, other.pt.z)
d = utility.epsilon_equal(self.dir.x, other.dir.x)
e = utility.epsilon_equal(self.dir.y, other.dir.y)
f = utility.epsilon_equal(self.dir.z, other.dir.z)
return a and b and c and d and e and f
class Sphere:
def __init__ (self,center,radius):
self.center=center
self.radius=radius
def __eq__ (self, other):
a = utility.epsilon_equal(self.center.x, other.center.x)
b = utility.epsilon_equal(self.center.y, other.center.y)
c = utility.epsilon_equal(self.center.z, other.center.z)
d = utility.epsilon_equal(self.radius, other.radius)
return a and b and c and d
再次对缩进感到抱歉。我知道这些类看起来不对,但它在我的代码中是正确的。此外,任何建议使我的代码更整洁,更简洁的感谢。
assertEqual调用正在比较对象是否相等,而不是对象的内容。根据unittest模块的文档,您必须通过__eq__
在几何类型中注册unittest.addTypeEqualityFunc()函数。