def __init__(self, jsonData, lightRay):
        """ Creates an instance of scene.

        Attributes:
            jsonData (dict): The json data containing the information of the scene
                             to be instanciated.
            lightRay (Ray, None): The initial light ray, if present in the scene.
        """
        self.width = jsonData.get('width')
        self.height = jsonData.get('height')
        self.center = Point3D(self.width/2, self.height/2, 0)
        self.objects = [ Box(self.center, self.width, self.height) ]
        self.lightRay = lightRay

        for o in jsonData.get('objects'):          
            type = o.get('type')  
            c = o.get('center')
            center = Point3D(c[0], c[1], 0) 

            if type == "circle":
                radius = o.get('radius')
                self.objects.append( Circle(center, radius) )
            elif type == "box":
                width  = o.get('width')
                height = o.get('height')
                self.objects.append( Box(center, width, height) )
    def intersection(self, line):
        """ Returns the intersection between self and another line.
        
        Args:
            line (Line): The line that may intersect with self. 

        Returns:
            Point3D, Line, None: The result of the intersection, which may be empty,
                                 a single point or the entire line. 
        """
        nullVector = Vector3D.zero()

        if(self.direction == nullVector or line.direction == nullVector):
            # No intersection
            return None

        p1 = self.point
        p2 = line.point

        # choosing another point p2 to represent "line" if p1 == p2
        if (p1 == p2):
            p2 = Point3D(p2.x + line.direction.x, p2.y + line.direction.y, p2.z + line.direction.z)

        if (line.contains(p1)):
            if (self.contains(p2)):
                # line and self represent the same line
                return self
            else:
                # Unique point
                return p1
        elif (self.contains(p2)):
            # Unique point
            return p2
        else:
            s = 1
            u = line.point - self.point
            v = line.direction.cross_product(u)
            w = line.direction.cross_product(self.direction)

            # Since we are in 2D, the z component for all point is 0, which means
            # that the result of any cross-product is a vector with both x and y = 0.
            # We only need to verify the z component.
            if (v.z == 0 or w.z == 0):
                # No intersection
                return None

            elif ( (v.z > 0 and w.z < 0) or \
                   (v.z < 0 and w.z > 0) ): 
                s = -s

            d = s * v.norm() / w.norm()

            px = p1.x + d * self.direction.x
            py = p1.y + d * self.direction.y
            pz = p1.z + d * self.direction.z
         
            return Point3D(px, py, pz)  
    def __init__(self, center, width, height):
        """ Creates a box
        """
        self.center = center
        self.width = width
        self.height = height
      
        p1 = Point3D(center.x - width/2, center.y - height/2, 0)
        p2 = Point3D(center.x + width/2, center.y - height/2, 0)
        p3 = Point3D(center.x + width/2, center.y + height/2, 0)
        p4 = Point3D(center.x - width/2, center.y + height/2, 0)

        self.lineSegments = [LineSegment(p1, p2), \
                             LineSegment(p2, p3), \
                             LineSegment(p3, p4), \
                             LineSegment(p4, p1)]
 def __init__(self, radius, nbLon, nbLat):
     """ Creates an instance of Obj.
     """
     self.radius = radius
     self.center = Point3D(0.0, 0.0, 0.0)
     self.nbLon = nbLon
     self.nbLat = nbLat
     self.vertices = []
     self.faces = []
    def getPoint(self, u, v):
        """ Finds a point on self's surface using u, v coordinates.

        Args:
            u (float): The u coordinate, in radians.
            v (float): The v coordinate, in randians.
        """
        return Point3D((self.radius + self.minorRadius*cos(u))*cos(v),\
                       (self.radius + self.minorRadius*cos(u))*sin(v),\
                        self.minorRadius*sin(u))
    def contains(self, point):
        """ Verifies if self contains a given point.

        Args:
            point (Point3D): The point to verify.
    
        Returns:
            bool: True if self contains "point", false otherwise.
        """
        p1 = self.point
        p2 = Point3D(p1.x + self.direction.x, p1.y + self.direction.y, 0)
         
        p1p0 = point - p1
        p1p2 = point - p2

        return (p1p0.cross_product(p1p2) == Vector3D.zero())
    def reflectedRay(self, lightRay):
        """ Returns the light ray reflected on self and originating
        from "lightRay", if exists. 

        Args:
            lightRay (Ray): The originating light ray

        Returns:
            Ray, None: The reflected light ray, if exists. "None" otherwise. 
        """
        distance = lightRay.origin - self.center

        a = lightRay.direction.square_norm()
        b = 2 * lightRay.direction.dot_product(distance)
        c = distance.square_norm() - self.radius ** 2
        d = b**2 - 4*a*c
        s = 1

        # no intersection
        if (d < 0):
            return None
        
        t1 = (-b - sqrt(b**2 - 4*a*c))/(2*a)
        t2 = (-b + sqrt(b**2 - 4*a*c))/(2*a)

        # no intersection
        if (t1 < 0.001 and t2 < 0.001):
            return None
        # two intersection, taking the closest one to lightRay's origin
        elif (t1 > 0.001 and t2 > 0.001):
            t = min([t1, t2])
        # one intersection, the one with a positive t value
        else:
            t = max([t1, t2])

        origin = Point3D(lightRay.origin.x + lightRay.direction.x*t,
                         lightRay.origin.y + lightRay.direction.y*t,
                         lightRay.origin.z + lightRay.direction.z*t)
        normal = origin - self.center
        direction = lightRay.direction.reflect(normal)

        return Ray(origin, direction, lightRay.intensity - 1)
def loadScene():
    """ Returns the scene using data (json file path, light ray parameters) 
    specified in argv.
    
    Returns:
        Scene: The loaded scene. 
    """
    # Opening Json file
    cwd = os.path.dirname(os.path.realpath(__file__))
    sceneFile = cwd + "/" + sys.argv[1]

    try:
        jsonData = json.loads(open(sceneFile).read())
    except:
        print(ERR_INVALID_FILENAME)
        sys.exit(0)
          
    lightRay = None

    # creating Ray object if the parameters were specified
    if (len(sys.argv) > 3):
        params = [float(s) for s in sys.argv[3].split(",")]
        if (len(params) != 5):
            print(ERR_LIGHT_RAY_PARAMS)
            sys.exit(0)

        origin = Point3D(params[0], params[1], 0)
        direction = Vector3D(params[2], params[3], 0)
        intensity = params[4]
        lightRay = Ray(origin, direction, intensity)

    # creating scene object
    try:
       scene = Scene(jsonData, lightRay)
    except: 
        print(ERR_INVALID_JSON)
        sys.exit(0)

    return scene