仍未解决-问题在于paralaxtrace2方法,即更新通过两个透镜传播的光线对象
我尝试用Python构建一个光线跟踪器,使用两个不同的类:sphericalrefraction(包含平面、凸面和凹面透镜)和outputplane(仅包含一个无限大的平面),继承自一个类Optical。在这些类中的每一个类中,都有方法intercept(用于计算具有给定方向和点的光线与镜头相交的位置)和refract(使用光线的最新方向向量计算光线的新方向向量)。它们在每个光学元件中都有传播光线的方法,将最新点附加到光线上作为intercept()点,将最新方向附加到refract()中方向。那个光线只有一维的x,y,z元素阵列,一个用于点,一个用于方向
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())
当我将两条光线穿过一个球体折射和一个输出平面时,我使用以下方法:
def paralaxtrace(自身、光线、球体折射、输出平面): SphericalRefraction.propagate_光线(自我) SphericalRefraction.propagate_光线(雷) OutputPlane.propagate_-ray(自我) OutputPlane.propagate_-ray(雷) 自我绘图(雷)
我得到了一个如下所示的图表,例如:
我实现了这个方法,让它通过两个sphericalrefraction对象和一个输出平面,并且由于某些原因它在sphericalrefraction元素之间没有更新?在
^{pr2}$如您所见,intercept/refract方法总是使用ray.p()来获得最新的点,但由于某些原因,它实际上没有在与第二个球形元素相交和折射时附加新的点/方向?这张图看起来和上面的一模一样。在
我传错东西了吗?还有别的问题吗?如果您需要更多我的代码,请让我知道,因为我已经尽了最低限度的理解这个问题。在
编辑:
在控制台中:
^{3}$为此,我得到了上面的图表。它应该做的是,由于第二个凸透镜在60度,它应该使光线更加会聚。相反,看起来什么也没发生。在
编辑2:
这个问题似乎不是ray中可变的默认参数;我仍然得到相同的错误。出于某种原因,它更多的是要在函数中添加另一个镜头作为参数。在每个镜头的传播之间,它不会更新坐标。这和lens类中可变的默认参数错误有关吗?在
为了演示可变默认参数问题,请参见以下示例:
输出:
^{pr2}$(为什么两个字符串似乎都附加到两个列表中?)在
这种令人惊讶的行为是否与你所看到的行为相符?如果是这样,mutable default arguments实际上是问题的根源。在
简短说明: 赋值
p = [0.0, 0.0, 0.0]
不会在对象构造时(当调用__init__
时)计算,而是在声明时计算一次。因此,p
对该类的所有实例引用同一个列表(最初是[0.0, 0.0, 0.0]
),如果更改其中一个,则所有其他实例也将更改。在避免这种情况的方法是使用
None
(或另一个不可变的标记值)作为默认参数,并在__init__
中设置实际的默认值:相关问题 更多 >
编程相关推荐