使用A类的两个对象A1和A2作为B类对象B1的函数参数时出错:B1不更新属性?

2024-10-01 07:47:18 发布

您现在位置:Python中文网/ 问答频道 /正文

仍未解决-问题在于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(雷) 自我绘图(雷)

我得到了一个如下所示的图表,例如: Using Rays with initial points [+/0.1, +/0.2, 0] and direction [0,0,1] and convex surface SphericalRefraction(50, .02, 1, 1.5168, 49.749)

我实现了这个方法,让它通过两个sphericalrefraction对象和一个输出平面,并且由于某些原因它在sphericalrefraction元素之间没有更新?在

^{pr2}$

如您所见,intercept/refract方法总是使用ray.p()来获得最新的点,但由于某些原因,它实际上没有在与第二个球形元素相交和折射时附加新的点/方向?这张图看起来和上面的一模一样。在

我传错东西了吗?还有别的问题吗?如果您需要更多我的代码,请让我知道,因为我已经尽了最低限度的理解这个问题。在

编辑:

在控制台中:

^{3}$

为此,我得到了上面的图表。它应该做的是,由于第二个凸透镜在60度,它应该使光线更加会聚。相反,看起来什么也没发生。在

编辑2:

这个问题似乎不是ray中可变的默认参数;我仍然得到相同的错误。出于某种原因,它更多的是要在函数中添加另一个镜头作为参数。在每个镜头的传播之间,它不会更新坐标。这和lens类中可变的默认参数错误有关吗?在


Tags: 方法selfreturnifdefnpsqrt方向
1条回答
网友
1楼 · 发布于 2024-10-01 07:47:18

为了演示可变默认参数问题,请参见以下示例:

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

输出:

^{pr2}$

(为什么两个字符串似乎都附加到两个列表中?)在

这种令人惊讶的行为是否与你所看到的行为相符?如果是这样,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

相关问题 更多 >