尚未解决 - 问题在于paralaxtrace2方法,在通过两个镜头传播之间更新Ray对象
我正在尝试使用Python使用两个不同的类构建一个Raytracer:sphericalrefraction(包含平面,凸透镜和凹透镜)和outputplane(仅包含一个无限大的平面),继承自一个类Optical。在这些类中的每一个下,都有方法截距(计算具有给定方向和点的光线与镜头相交的位置),并折射(使用最近的光线方向矢量计算光线的新方向矢量)。它们还在每个光学元素中都有propagate_ray方法,这些方法将最新点作为intercept()点附加到光线上,最新的方向作为refract()方向。光线仅具有带x,y,z元素的1d数组,一个用于点,一个用于方向,例如
class Ray:
def __init__(self, p = [0.0, 0.0, 0.0], k = [0.0, 0.0, 0.0]):
self._points = [np.array(p)]
self._directions = [np.array(k)/np.sqrt(sum(n**2 for n in k))]
self.checklength()
def p(self):
return self._points[len(self._points)-1]
def k(self):
return self._directions[len(self._directions)-1]
class SphericalRefraction(OpticalElement):
def __init__(self, z0 = 0.0, c = 0.0, n1 = 1.0, n2 = 1.0, ar = 0.0):
self.z0 = z0
self.c = c
self.n1 = n1
self.n2 = n2
self.ar = ar
self.R = self.radius()
self.s = self.surface()
self.centre = self.centre()
def intercept(self, ray):
ar_z = np.sqrt(self.R**2 - self.ar**2)
#ar_z = distance from aperture radius z intercept to centre of sphere
r = ray.p() - self.centre
r_mag = np.sqrt(sum(n**2 for n in r))
rdotk = np.dot(r, ray.k())
if (rdotk**2 - r_mag**2 + self.R**2) < 0:
return None
else:
l1 = -rdotk + np.sqrt(rdotk**2 - r_mag**2 + self.R**2)
l2 = -rdotk - np.sqrt(rdotk**2 - r_mag**2 + self.R**2)
lplane = (self.z0 - ray.p()[2]) / ray.k()[2]
if self.s == "convex":
if (rdotk**2 - r_mag**2 + self.R**2) == 0:
if self.centre[2] - ar_z >= (ray.p() + -rdotk*ray.k())[2]:
return ray.p() + -rdotk*ray.k()
def refract(self, ray):
n_unit = self.unitsurfacenormal(ray)
k1 = ray.k()
ref = self.n1/self.n2
ndotk1 = np.dot(n_unit, k1)
if np.sin(np.arccos(ndotk1)) > (1/ref):
return None
else:
return ref*k1 - (ref*ndotk1 - np.sqrt(1- (ref**2)*(1-ndotk1**2)))*n_unit
def propagate_ray(self, ray):
if self.intercept(ray) is None or self.refract(ray) is None:
return "Terminated"
else:
p = self.intercept(ray)
k2 = self.refract(ray)
ray.append(p, k2)
return "Final Point: %s" %(ray.p()) + " and Final Direction: %s" %(ray.k())
当我通过1个球面反射和一个输出平面传递两条光线时,我使用这种方法:
def paralaxtrace(self,Ray,SphericalRefraction,OutputPlane): SphericalRefraction.propagate_ray(个体经营) SphericalRefraction.propagate_ray(雷) OutputPlane.propagate_ray(个体经营) OutputPlane.propagate_ray(雷) self.plotparalax(雷)
我得到的图表看起来像这样,例如:
我已经实现了这个方法来通过两个ballrefraction对象和一个输出平面,并且由于某种原因它不会在sphericalrefraction元素之间更新?
def paralaxtrace2(self, Ray, sr1, sr2, OutputPlane):
sr1.propagate_ray(self)
sr1.propagate_ray(Ray)
sr2.propagate_ray(self)
sr2.propagate_ray(Ray)
OutputPlane.propagate_ray(self)
OutputPlane.propagate_ray(Ray)
self.plotparalax(Ray)
正如你所看到的,截距/折射方法总是使用ray.p()所以最新的点,但由于某种原因,它实际上并没有在交叉和第二个球形元素折射时附加新的点/方向?该图看起来与上面的图完全相同。
我错误地传递了物体吗?还有其他问题吗?如果您需要更多我的代码,请告诉我,因为我已经尽力了解这个问题。
修改
在控制台中:
>> import raytracer as rt
>> lense1 = rt.SphericalRefraction(50, .02, 1, 1.5168, 49.749)
>> lense2 = rt.SphericalRefraction(60, .02, 1, 1.5168, 49.749)
>> ray = rt.Ray([.1,.2,0],[0,0,1])
>> ray.paralaxtrace2(rt.Ray([-0.1, -0.2, 0],[0,0,1]), lense1, lense2, rt.OutputPlane(100))
x, y of 'ray' = [0.0, 50.000500002500019, 100.0] [0.20000000000000001, 0.20000000000000001, -0.13186017048586818]
x, y of passed ray: [0.0, 50.000500002500019, 100.0] [-0.20000000000000001, -0.20000000000000001, 0.13186017048586818]
为此,我得到上面的图表。它应该做的是,因为第二个凸透镜是60,它应该更多地会聚光线。相反,看起来没有任何反应。
编辑2:
这个问题似乎不是光线中可变的默认参数;我仍然得到同样的错误。出于某种原因,它更多地与将另一个镜头添加到函数中作为参数。在每个镜头的传播之间,它不会更新坐标。这是否与镜头类中的可变默认参数错误有关?
答案 0 :(得分:0)
为了演示可变的默认参数问题,请参阅以下示例:
class Ray(object):
def __init__(self, p = [0.0, 0.0, 0.0]):
self.p = p
ray1 = Ray()
ray2 = Ray()
ray1.p.append('appended to ray1.p')
ray2.p.append('appended to ray2.p')
print ray1.p
print ray2.p
输出:
[0.0, 0.0, 0.0, 'appended to ray1.p', 'appended to ray2.p']
[0.0, 0.0, 0.0, 'appended to ray1.p', 'appended to ray2.p']
(为什么两个字符串似乎都附加到两个列表?)
这种令人惊讶的行为是否符合您所看到的行为?如果是这样,mutable default arguments实际上就是问题的根源。
简短说明:
赋值p = [0.0, 0.0, 0.0]
不会在对象构造时(在调用__init__
时)进行评估,而是在声明时进行一次评估。因此p
引用该类的所有实例的相同列表(最初为[0.0, 0.0, 0.0]
),如果您更改了一个,则所有其他实例也将更改。
避免这种情况的方法是使用None
(或不同的,不可变的标记值)作为默认参数,并在__init__
中设置实际默认值:
class Ray(object):
def __init__(self, p=None):
if p is None:
p = [0.0, 0.0, 0.0]
self.p = p