2014-02-09 29 views
1

仍未解決 - 問題在於paralaxtrace2方法,在更新通過兩個鏡片錯誤使用類A的兩個對象A1和A2作爲B類的對象B1上的函數的參數:B1不更新屬性?

我試圖建立一個與光線跟蹤使用Python兩種不同類型的傳播之間的射線對象:(含有平面sphericalrefraction,凸和凹透鏡)和輸出平面(僅包含一個無限大平面),從一類光學繼承而來。在這些類的每一個下,有方法截距(計算具有給定方向和點的光線與透鏡相交的位置),並折射(使用光線的最新方向矢量計算光線的新方向矢量)。它們在每個光學元素中都有傳播方法,它們將最新的點作爲截距()點,將最新的方向作爲折射()方向。該射線僅包含具有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個sphericalrefraction和一個輸出平面上的兩個射線,我用這個方法:

DEF paralaxtrace(個體,雷,SphericalRefraction,OutputPlane): SphericalRefraction.propagate_ray(個體) SphericalRefraction .propagate_ray(雷) OutputPlane.propagate_ray(個體經營) OutputPlane.propagate_ray(雷) self.plotparalax(雷)

我得到的是一張看起來像這樣,例如: 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)

我已經實現了這種方法,通過兩個球面反射對象和一個輸出平面,並且由於某種原因,它不會在球面折射元素之間更新?

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

更少的代碼會比越多越好。你可以創建一個玩具示例,只是演示對象/參數/屬性交互,不像你期望的那樣工作嗎? –

+1

我無法真正理解此代碼(例如,我不明白爲什麼要將'Ray'和'OutputPlane'類作爲參數傳遞給'paralaxtrace2'),但在'Ray中使用默認的可變參數。 __init__'總是一個紅旗:請參閱[這個問題](http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument)一個很好的解釋。 –

+0

+1 @ DanielRoseman對可變默認參數的預感是您問題的原因。 –

回答

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'] 

(?爲什麼串看似追加到名單)

這種令人驚訝的行爲是否符合您所看到的行爲G?如果是這樣,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 
+0

我的確如你所說,但同樣的問題依然存在。我不認爲它與原始值有關,因爲問題更多的是在跟蹤函數中有兩個鏡頭對象而不是光線本身...... – Annika

相關問題