def find_ppp(opsys, opaxis): """Function to find the primary principal plane location of a lens or an optical component Arguments: opsys Optical system or optical component whose principal planes are to be found opaxis Ray defining the optical axis of the system For this function to operate, the system should have a rotational symetry around the optical axis. Note: This function is returns the intersection point of the optical axis and the principal plane. """ # Create a system with the component if isinstance(opsys, (Component)): c = opsys opsys = System(complist=[(c, (0, 0, 0), (0, 0, 0))], n=1) # To create a ray parallel to the optical axis, find a displacement vector # perpendicular to the optical axis, and to the XYZ axes d = opaxis.dir pv1 = cross(d, (0, 0, 1)) pv2 = cross(d, (0, 1, 0)) pv3 = cross(d, (1, 0, 0)) pv = [pv1, pv2, pv3] # Search for the longest pv pvn = array((dot(pv1, pv1), dot(pv2, pv2), dot(pv3, pv3))) pvm = pv[pvn.argmax()] # Create parallel ray par_ray = opaxis.copy() par_ray.pos = par_ray.pos + pvm * 0.0001 opsys.clear_ray_list() opsys.ray_add([opaxis, par_ray]) opsys.propagate() par_ray_end = par_ray.get_final_rays(inc_zeros=False) if len(par_ray_end) != 1: raise Exception, "The paraxial ray has more than one final ray" pppl = intersection(par_ray, par_ray_end[0]) # Move the intersection point toward the optical axis ppp = pppl[0] - pvm * 0.0001 return ppp # , pppl[1])
def intersection(r1, r2): ''' Return the point of intersection between the rays r1 and r2. **Arguments:** == =================================== r1 First Ray to test for intersection r2 Second Ray to test for intersection == =================================== **Return Value:** Tuple (ip,rv) where: == ============================================================ ip Intersection point coordinates. If the rays do not intersect ip=(nan,nan,nan) rv Boolean that indicates if the intersection point represent a real image (rv=true) , or a virtual image (rv=false). == ============================================================ ''' d1 = r1.dir d2 = r2.dir p1 = r1.pos p2 = r2.pos d1xd2 = cross(d1, d2) # check if the rays are parallel #log.info("Vector cross product:"+str(d1xd2)) if dot(d1xd2, d1xd2) == 0.: return array((nan, nan, nan)), False p2p1xv2 = cross(p2 - p1, d2) p2p1xv1 = cross(p2 - p1, d1) a = p2p1xv2 / d1xd2 b = p2p1xv1 / d1xd2 # Remove the nan from the list keep = ~isnan(a) an = a[keep] keep = ~isnan(b) bn = b[keep] ip = array((nan, nan, nan)) rv = False #print an,bn if len(an) > 0: if alltrue(an == an[0]): ip = p1 + an[0] * d1 # check if all the solutions are equal if alltrue(an >= 0) and alltrue(bn >= 0): rv = True #log.info("Intersection point found at:"+str(ip)+" "+str(rv)) return ip, rv
def intersection(r1,r2): ''' Return the point of intersection between the rays r1 and r2. **Arguments:** == =================================== r1 First Ray to test for intersection r2 Second Ray to test for intersection == =================================== **Return Value:** Tuple (ip,rv) where: == ============================================================ ip Intersection point coordinates. If the rays do not intersect ip=(nan,nan,nan) rv Boolean that indicates if the intersection point represent a real image (rv=true) , or a virtual image (rv=false). == ============================================================ ''' d1=r1.dir d2=r2.dir p1=r1.pos p2=r2.pos d1xd2=cross(d1,d2) # check if the rays are parallel #log.info("Vector cross product:"+str(d1xd2)) if dot(d1xd2,d1xd2)==0. : return array((nan,nan,nan)),False p2p1xv2=cross(p2-p1,d2) p2p1xv1=cross(p2-p1,d1) a=p2p1xv2/d1xd2 b=p2p1xv1/d1xd2 # Remove the nan from the list keep=~isnan(a) an=a[keep] keep=~isnan(b) bn=b[keep] ip=array((nan,nan,nan)) rv=False #print an,bn if len(an)>0: if alltrue(an==an[0]) : ip=p1+an[0]*d1 # check if all the solutions are equal if alltrue(an>=0) and alltrue(bn>=0): rv=True #log.info("Intersection point found at:"+str(ip)+" "+str(rv)) return ip,rv
def intersection(r1, r2): ''' Return the point of intersection between the rays r1 and r2. Parameters ---------- r1,r2 : :class:`~pyoptools.raytrace.ray.Ray` Rays to test for intersection. Returns ------- ip : tuple(float, float, float) Intersection point coordinates. If the rays do not intersect ip=(nan,nan,nan) rv : bool Indicates if the intersection point represent a real image (rv=true), or a virtual image (rv=false). In this case virtual has the same meaning as in virtual image i.e. intersection point is not in the actual path, or is behind the ray's origin. ''' d1 = r1.dir d2 = r2.dir p1 = r1.pos p2 = r2.pos d1xd2 = cross(d1, d2) # check if the rays are parallel #log.info("Vector cross product:"+str(d1xd2)) if dot(d1xd2, d1xd2) == 0.: return array((nan, nan, nan)), False p2p1xv2 = cross(p2 - p1, d2) p2p1xv1 = cross(p2 - p1, d1) a = p2p1xv2 / d1xd2 b = p2p1xv1 / d1xd2 # Remove the nan from the list keep = ~isnan(a) an = a[keep] keep = ~isnan(b) bn = b[keep] ip = array((nan, nan, nan)) rv = False #print an,bn if len(an) > 0: if alltrue(an == an[0]): ip = p1 + an[0] * d1 # check if all the solutions are equal if alltrue(an >= 0) and alltrue(bn >= 0): rv = True #log.info("Intersection point found at:"+str(ip)+" "+str(rv)) return ip, rv
def draw_surf(surf, P, D): if isinstance(surf, Surface): #points, polylist =surf.shape.polylist(surf.topo) points, polylist = surf.polylist() glPushMatrix() glTranslatef(P[0], P[1], P[2]) glRotatef(180 * D[2] / pi, 0.0, 0.0, 1.0) glRotatef(180 * D[1] / pi, 0.0, 1.0, 0.0) glRotatef(180 * D[0] / pi, 1.0, 0.0, 0.0) glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, [1., 1., 0, 0.7]) #glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, [1.,1.,0.,1.]) #glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, [1.,0.,0.,1.]) for p in polylist: if len(p) == 3: p0 = points[p[0]] p1 = points[p[1]] p2 = points[p[2]] v0 = array(p1) - array(p0) v1 = array(p2) - array(p0) v3 = cross(v0, v1) v3 = v3 / sqrt(v3[0]**2 + v3[1]**2 + v3[2]**2) #if v3[2]<0: print "**" glBegin(GL_TRIANGLES) #Drawing Using Triangles #glColor4f(1,0,0, 1.) glNormal3f(v3[0], v3[1], v3[2]) glVertex3f(p0[0], p0[1], p0[2]) #glNormal3f(v3[0],v3[1],v3[2]) glVertex3f(p1[0], p1[1], p1[2]) #glNormal3f(v3[0],v3[1],v3[2]) glVertex3f(p2[0], p2[1], p2[2]) glEnd() elif len(p) == 4: p0 = points[p[0]] p1 = points[p[1]] p2 = points[p[2]] p3 = points[p[3]] v0 = array(p1) - array(p0) v1 = array(p2) - array(p0) v3 = cross(v0, v1) v3 = v3 / sqrt(v3[0]**2 + v3[1]**2 + v3[2]**2) #print p0,p1,p2,p3 glBegin(GL_QUADS) # Start Drawing The Cube #glColor4f(1,0,0, 1.) glNormal3f(v3[0], v3[1], v3[2]) glVertex3f(p0[0], p0[1], p0[2]) #glNormal3f(v3[0],v3[1],v3[2]) glVertex3f(p1[0], p1[1], p1[2]) #glNormal3f(v3[0],v3[1],v3[2]) glVertex3f(p2[0], p2[1], p2[2]) #glNormal3f(v3[0],v3[1],v3[2]) glVertex3f(p3[0], p3[1], p3[2]) glEnd() glPopMatrix()
def draw_surf(surf, P, D): if isinstance(surf, Surface): #points, polylist =surf.shape.polylist(surf.topo) points, polylist =surf.polylist() glPushMatrix() glTranslatef(P[0],P[1],P[2]) glRotatef(180*D[2]/pi,0.0,0.0,1.0) glRotatef(180*D[1]/pi,0.0,1.0,0.0) glRotatef(180*D[0]/pi,1.0,0.0,0.0) glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, [1.,1.,0,0.7]) #glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, [1.,1.,0.,1.]) #glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, [1.,0.,0.,1.]) for p in polylist: if len(p)==3: p0=points[p[0]] p1=points[p[1]] p2=points[p[2]] v0=array(p1)-array(p0) v1=array(p2)-array(p0) v3=cross(v0,v1) v3=v3/sqrt(v3[0]**2+v3[1]**2+v3[2]**2) #if v3[2]<0: print "**" glBegin(GL_TRIANGLES) #Drawing Using Triangles #glColor4f(1,0,0, 1.) glNormal3f(v3[0],v3[1],v3[2]) glVertex3f( p0[0], p0[1], p0[2]) #glNormal3f(v3[0],v3[1],v3[2]) glVertex3f( p1[0], p1[1], p1[2]) #glNormal3f(v3[0],v3[1],v3[2]) glVertex3f( p2[0], p2[1], p2[2]) glEnd() elif len(p)==4: p0=points[p[0]] p1=points[p[1]] p2=points[p[2]] p3=points[p[3]] v0=array(p1)-array(p0) v1=array(p2)-array(p0) v3=cross(v0,v1) v3=v3/sqrt(v3[0]**2+v3[1]**2+v3[2]**2) #print p0,p1,p2,p3 glBegin(GL_QUADS) # Start Drawing The Cube #glColor4f(1,0,0, 1.) glNormal3f(v3[0],v3[1],v3[2]) glVertex3f( p0[0], p0[1], p0[2]) #glNormal3f(v3[0],v3[1],v3[2]) glVertex3f( p1[0], p1[1], p1[2]) #glNormal3f(v3[0],v3[1],v3[2]) glVertex3f( p2[0], p2[1], p2[2]) #glNormal3f(v3[0],v3[1],v3[2]) glVertex3f( p3[0], p3[1], p3[2]) glEnd() glPopMatrix()
def find_ppp(opsys, opaxis): """Function to find the primary principal plane location of a lens or an optical component Arguments: opsys Optical system or optical component whose principal planes are to be found opaxis Ray defining the optical axis of the system For this function to operate, the system should have a rotational symmetry around the optical axis. Note: This function is returns the intersection point of the optical axis and the principal plane. """ # Create a system with the component if isinstance(opsys, (Component)): c = opsys opsys = System(complist=[ (c, (0, 0, 0), (0, 0, 0)), ], n=1) # To create a ray parallel to the optical axis, find a displacement vector # perpendicular to the optical axis, and to the XYZ axes d = opaxis.dir pv1 = cross(d, (0, 0, 1)) pv2 = cross(d, (0, 1, 0)) pv3 = cross(d, (1, 0, 0)) pv = [pv1, pv2, pv3] # Search for the longest pv pvn = array((dot(pv1, pv1), dot(pv2, pv2), dot(pv3, pv3))) pvm = pv[pvn.argmax()] # Create parallel ray par_ray = opaxis.copy() par_ray.pos = par_ray.pos + pvm * .0001 opsys.clear_ray_list() opsys.ray_add([opaxis, par_ray]) opsys.propagate() par_ray_end = par_ray.get_final_rays(inc_zeros=False) if len(par_ray_end) != 1: raise Exception("The paraxial ray has more than one final ray") pppl = intersection(par_ray, par_ray_end[0]) #Move the intersection point toward the optical axis ppp = pppl[0] - pvm * .0001 return ppp #, pppl[1])
def paraxial_location(opsys, opaxis): """Function to find the paraxial image location This function finds the paraxial image location of a point located in the optical axis, and a boolean indicating if the image is real or virtual (image_location, real_virtual). The origin of the opaxis location is taken as the object location **ARGUMENTS** ====== =================================== opsys Optical system to use. opaxis Ray representating the optical axis ====== =================================== **RETURN VALUE:** Tuple (image_location, real) where: ============== ================================================== image_location Image location coordinates real Boolean that indicates if the intersection point represent a real image (real=True) , or a virtual image (real=False). ============== ================================================== For this function to operate, the system should have a rotational symmetry around the optical axis. """ #log.info("Propagate Optical axis ray") opsys.clear_ray_list() opsys.reset() #opsys.ray_add(cray) opsys.ray_add(opaxis) opsys.propagate() # Calculate vectors perpendicular to the optical axis and to the XYZ axes d = opaxis.dir pv1 = cross(d, (0, 0, 1)) pv2 = cross(d, (0, 1, 0)) pv3 = cross(d, (1, 0, 0)) pv = [pv1, pv2, pv3] # Search for the longest pv pvn = array((dot(pv1, pv1), dot(pv2, pv2), dot(pv3, pv3))) pvm = pv[pvn.argmax()] #log.info("Displacement vector found: "+str(pvm)) # Create paraxial ray par_ray = opaxis.copy() par_ray.dir = par_ray.dir + pvm * .001 opsys.clear_ray_list() opsys.reset() opsys.ray_add(par_ray) opsys.propagate() par = par_ray.get_final_rays(inc_zeros=False) oax = opaxis.get_final_rays(inc_zeros=False) #log.info("par="+str(par)) #log.info("oax="+str(oax)) if len(par) != 1 or len(oax) != 1: raise Exception("The paraxial ray or the optical axis ray have more" " than one final ray") #log.info("Calculating object location") expl = intersection(oax[0], par[0]) return expl
def pupil_location(opsys, ccds, opaxis): ''' Function to find the optical system pupils position .. note: For this function to operate, the system should have a rotational symmetry around the optical axis. **Parameters:** opsys Optical system to use. opaxis Ray representing the optical axis ccds Surface that represents a detector in the aperture plane **Return Value** (enpl,expl) enpl tuple (xen,yen,zen) containing the entrance pupil coordinates expl tuple (xex,yex,zex) containing the exit pupil coordinates ''' #log.info("Propagate Optical axis ray") opsys.clear_ray_list() opsys.reset() #opsys.ray_add(cray) opsys.ray_add(opaxis) opsys.propagate() if (len(ccds.hit_list) == 0): raise Exception("The optical axis did not intersect the aperture") if (len(ccds.hit_list) > 1): raise Exception( "The optical axis intersected the aperture more than once") aip = ccds.hit_list[0][0] air = ccds.hit_list[0][1] #log.info("Optical Axis Intersection point= "+str(aip)) #log.info("Intersection Ray= "+str(air)) #Getting Intersection point in global coordinates if (len(air.childs) != 1): raise Exception("The intersected ray can only have one child") ip = air.childs[0].pos d = air.childs[0].dir #log.info("Intersection point in world coordinates= "+str(ip)) #log.info("Direction of the optical axis at the intersection point"+str(d)) #Todo: Check if the optical axis and the aperture are perpendicular # Calculate vectors perpendicular to the optical axis and to the XYZ axes pv1 = cross(d, (0, 0, 1)) pv2 = cross(d, (0, 1, 0)) pv3 = cross(d, (1, 0, 0)) pv = [pv1, pv2, pv3] # Search for the longest pv pvn = array((dot(pv1, pv1), dot(pv2, pv2), dot(pv3, pv3))) pvm = pv[pvn.argmax()] #log.info("Displacement vector found: "+str(pvm)) # Create ray to calculate the exit pupil expuray = air.childs[0].copy() expuray.dir = expuray.dir + pvm * .0001 # Create the ray to calculate the entrance pupil enpuray = expuray.reverse() opsys.clear_ray_list() opsys.reset() opsys.ray_add(enpuray) opsys.ray_add(expuray) opsys.propagate() enp = enpuray.get_final_rays(inc_zeros=False) exp = expuray.get_final_rays(inc_zeros=False) oax = opaxis.get_final_rays(inc_zeros=False) #log.info("enp="+str(enp)) #log.info("exp="+str(exp)) #log.info("oax="+str(oax)) if len(enp) != 1 or len(exp) != 1 or len(oax) != 1: raise Exception("The principal ray or the optical axis ray have more" " than one final ray") #log.info("Calculating entrance pupil location") # Find the nearest points between the rays. # Some times because of numerical errors, or some aberrations in the optical # system, the rays do not trully intersect. # Use instead the nearest points and issue a warning when the rays do not trully # intersect. enpl = intersection(opaxis, enp[0])[0] if (isnan(enpl)).all(): p1, p2, d, rv = nearest_points(opaxis, enp[0]) print( "Warning: The optical axis does not intersect the principal ray at the entrance" ) print("pupil. The minimum distance is:", d) enpl = (p1 + p2) / 2 #log.info("Calculating exit pupil location") expl = intersection(oax[0], exp[0])[0] if (isnan(expl)).all(): p1, p2, d, rv = nearest_points(oax[0], exp[0]) print( "Warning: The optical axis does not intersect the principal ray at the exit" ) print("pupil. The minimum distance is:", d) expl = (p1 + p2) / 2 return enpl, expl
def surf2mesh(S, P=(0, 0, 0), D=(0, 0, 0), wire=False): color = "#ffff00" points, polylist = S.polylist() #Conversion para quethreejs la entienda polylist = list(polylist) lpoly = [] lpoints = [] for l in points: lpoints.append(list(l)) for l in polylist: lpoly.append(list(map(int, l))) vertices = lpoints faces = lpoly # Map the vertex colors into the 'color' slot of the faces # Map the normals nfaces = [] for f in faces: p0 = points[f[0]] p1 = points[f[1]] p2 = points[f[2]] v0 = array(p1) - array(p0) v1 = array(p2) - array(p0) v3 = cross(v0, v1) v3 = tuple(v3 / sqrt(v3[0]**2 + v3[1]**2 + v3[2]**2)) nfaces.append(f + [v3, color, None]) # Create the geometry: surfaceGeometry = py3js.Geometry( vertices=vertices, faces=nfaces, #colors=vertexcolors ) #surfaceGeometry = py3js.SphereGeometry(radius=300, widthSegments=32, heightSegments=24) if wire: surfaceGeometry = py3js.WireframeGeometry(surfaceGeometry) # Calculate normals per face, for nice crisp edges: surfaceGeometry.exec_three_obj_method('computeFaceNormals') surfaceMaterial = py3js.MeshPhongMaterial(color=color, ambient="#050505", specular="#ffffff", shininess=15, emissive="#000000", side='DoubleSide', transparent=True, opacity=.8) #surfaceMaterial = py3js.MeshLambertMaterial(color='red',side='DoubleSide') # Create a mesh. Note that the material need to be told to use the vertex colors. surfaceMesh = py3js.Mesh( geometry=surfaceGeometry, material=surfaceMaterial, ) surfaceMesh.rotation = *D, "ZYX" surfaceMesh.position = tuple(P) return surfaceMesh
def paraxial_location(opsys, opaxis): """Function to find the paraxial image location This function finds the paraxial image location of a point located in the optical axis, and a boolean indicating if the image is real or virtual (image_location, real_virtual). The origin of the opaxis location is taken as the object location Parameters: *opsys* Optical system to use. *opaxis* Ray representating the optical axis For this function to operate, the system should have a rotational symmetry around the optical axis. """ #log.info("Propagate Optical axis ray") opsys.clear_ray_list() opsys.reset() #opsys.ray_add(cray) opsys.ray_add(opaxis) opsys.propagate() # Calculate vectors perpendicular to the optical axis and to the XYZ axes d=opaxis.dir pv1= cross(d,(0,0,1)) pv2= cross(d,(0,1,0)) pv3= cross(d,(1,0,0)) pv=[pv1,pv2,pv3] # Search for the longest pv pvn=array((dot(pv1,pv1),dot(pv2,pv2),dot(pv3,pv3))) pvm=pv[pvn.argmax()] #log.info("Displacement vector found: "+str(pvm)) # Create paraxial ray par_ray=opaxis.copy() par_ray.dir=par_ray.dir+pvm*.001 opsys.clear_ray_list() opsys.reset() opsys.ray_add(par_ray) opsys.propagate() par=par_ray.get_final_rays(inc_zeros = False) oax=opaxis.get_final_rays(inc_zeros = False) #log.info("par="+str(par)) #log.info("oax="+str(oax)) if len(par)!=1 or len(oax)!=1: raise Exception("The paraxial ray or the optical axis ray have more" " than one final ray") #log.info("Calculating object location") expl=intersection(oax[0],par[0]) return expl
def pupil_location(opsys,ccds,opaxis): ''' Function to find the optical system pupils position .. note: For this function to operate, the system should have a rotational symmetry around the optical axis. **Parameters:** opsys Optical system to use. opaxis Ray representing the optical axis ccds Surface that represents a detector in the aperture plane **Return Value** (enpl,expl) enpl tuple (xen,yen,zen) containing the entrance pupil coordinates expl tuple (xex,yex,zex) containing the exit pupil coordinates ''' #log.info("Propagate Optical axis ray") opsys.clear_ray_list() opsys.reset() #opsys.ray_add(cray) opsys.ray_add(opaxis) opsys.propagate() if (len(ccds.hit_list)==0): raise Exception("The optical axis did not intersect the aperture") if(len(ccds.hit_list)>1): raise Exception("The optical axis intersected the aperture more than once") aip=ccds.hit_list[0][0] air=ccds.hit_list[0][1] #log.info("Optical Axis Intersection point= "+str(aip)) #log.info("Intersection Ray= "+str(air)) #Getting Intersection point in global coordinates if(len(air.childs)!=1): raise Exception("The intersected ray can only have one child") ip=air.childs[0].pos d=air.childs[0].dir #log.info("Intersection point in world coordinates= "+str(ip)) #log.info("Direction of the optical axis at the intersection point"+str(d)) #Todo: Check if the optical axis and the aperture are perpendicular # Calculate vectors perpendicular to the optical axis and to the XYZ axes pv1= cross(d,(0,0,1)) pv2= cross(d,(0,1,0)) pv3= cross(d,(1,0,0)) pv=[pv1,pv2,pv3] # Search for the longest pv pvn=array((dot(pv1,pv1),dot(pv2,pv2),dot(pv3,pv3))) pvm=pv[pvn.argmax()] #log.info("Displacement vector found: "+str(pvm)) # Create ray to calculate the exit pupil expuray=air.childs[0].copy() expuray.dir=expuray.dir+pvm*.0001 # Create the ray to calculate the entrance pupil enpuray=expuray.reverse() opsys.clear_ray_list() opsys.reset() opsys.ray_add(enpuray) opsys.ray_add(expuray) opsys.propagate() enp=enpuray.get_final_rays(inc_zeros = False) exp=expuray.get_final_rays(inc_zeros = False) oax=opaxis.get_final_rays(inc_zeros = False) #log.info("enp="+str(enp)) #log.info("exp="+str(exp)) #log.info("oax="+str(oax)) if len(enp)!=1 or len(exp)!=1 or len(oax)!=1: raise Exception("The principal ray or the optical axis ray have more" " than one final ray") #log.info("Calculating entrance pupil location") # Find the nearest points between the rays. # Some times because of numerical errors, or some aberrations in the optical # system, the rays do not trully intersect. # Use instead the nearest points and issue a warning when the rays do not trully # intersect. enpl=intersection(opaxis,enp[0])[0] if (isnan(enpl)).all(): p1, p2, d, rv =nearest_points(opaxis,enp[0]) print("Warning: The optical axis does not intersect the principal ray at the entrance") print("pupil. The minimum distance is:", d) enpl=(p1+p2)/2 #log.info("Calculating exit pupil location") expl=intersection(oax[0],exp[0])[0] if (isnan(expl)).all(): p1, p2, d, rv =nearest_points(oax[0],exp[0]) print("Warning: The optical axis does not intersect the principal ray at the exit") print("pupil. The minimum distance is:", d) expl=(p1+p2)/2 return enpl,expl