def render(self):
        """
        Returns
        -------
        img
        
        Description
        -----------
        This method returns an image of map canvas with car image plotted over it. This image
        can be used to visualize car motion on the map canvas

        """
        
        # Fetch the car image rotated by current car inclination angle
        carImg = self.car.getCarImg()
        # Get image's dimensions
        carHeight,carWidth = carImg.shape[:2]
        
        # get car coordinates in image reference frame
        centerX,centerY = self.getCarCoordinates()
        
        # Estimate location of top left corner of car image in map canvas
        plotX = int(centerX - carWidth/2)
        plotY = int(centerY - carHeight/2)
        #print('plotX',plotX,'plotY',plotY)

        # Make a copy of original map image so that changes arre not permanently 
        # written
        
        mapImg2 = copy.deepcopy(self.mapImg)
        
        # The car could be at the border so we add padding first, plot car and then crop out the border
        
        # max width and height that 10,20 car take is 22,22 so
        # we must have border of 11. but we set border as 15 as safe margin 
        border = 15
        mapImg2 = cv2.copyMakeBorder(mapImg2, border, border, border, border, cv2.BORDER_CONSTANT,value=0 )
        
        # take care of border for car image top left corner
        plotX += border
        plotY += border
        
        # Blend car image with portion of map image at the location calculated above
        # mergeImages combines two images in proportion alpha and beta (output = alpha*img1 + beta*img2)
        blendedPart = mergeImages(carImg,1.0,mapImg2[plotY:plotY+ carHeight,plotX:plotX+carWidth ],0.0)
        
        # paste the blended part onto map image
        mapImg2[plotY:plotY+ carHeight,plotX:plotX+carWidth ]  = blendedPart
        
        # Remove the borders
        mapImg2 = mapImg2[border:border+self.mapHeight,border:border+self.mapWidth]
        
        #plot goal circles
        #Inner solid circle
        mapImg2 = cv2.circle(mapImg2,(self.goalX,self.mapHeight-1-self.goalY),8,(255,0,0),-1)
        # Outer ring representing area of radius 30 around goal
        mapImg2 = cv2.circle(mapImg2,(self.goalX,self.mapHeight-1-self.goalY),30,(0,0,255),2)
        return mapImg2
    def renderV2(self):
        """
        Returns
        -------
        img
        
        Description
        -----------
        This is another version of render() method.
        This method returns an image of map canvas with car image plotted over it. This image
        can be used to visualize car motion on the map canvas. It also plots current state image,
        step reward and next goal location in the bottom right corner of map image

        """
        
        
        # Fetch the car image rotated by current car inclination angle
        carImg = self.car.getCarImg()
        
        # Get image's dimensions
        carHeight,carWidth = carImg.shape[:2]
        
        # get car coordinates in image reference frame
        centerX,centerY = self.getCarCoordinates()
        
        # Estimate location of top left corner of car image in map canvas
        plotX = int(centerX - carWidth/2)
        plotY = int(centerY - carHeight/2)
        
        # Make a copy of original map image so that changes arre not permanently 
        # written
        
        mapImg2 = copy.deepcopy(self.mapImg)
        
        
        
        # The car could be at the border so we add padding first, plot car and then crop out the border
        
        # max width and height that 10,20 car take is 22,22 so
        # we must have border of 11. but we set border as 15 as safe margin 
        border = 15
        mapImg2 = cv2.copyMakeBorder(mapImg2, border, border, border, border, cv2.BORDER_CONSTANT,value=0 )
        
        # take care of border for car image top left corner
        plotX += border
        plotY += border
        
        # Blend car image with portion of map image at the location calculated above
        # mergeImages combines two images in proportion alpha and beta (output = alpha*img1 + beta*img2)
        blendedPart = mergeImages(carImg,1.0,mapImg2[plotY:plotY+ carHeight,plotX:plotX+carWidth ],0.0)
        
        # paste the blended part onto map image
        mapImg2[plotY:plotY+ carHeight,plotX:plotX+carWidth ]  = blendedPart
        
        # Remove the borders
        mapImg2 = mapImg2[border:border+self.mapHeight,border:border+self.mapWidth]
        
        #plot goal circles
        #Inner solid circle
        mapImg2 = cv2.circle(mapImg2,(self.goalX,self.mapHeight-1-self.goalY),8,(255,0,0),-1)
        # Outer ring representing area of radius 30 around goal
        mapImg2 = cv2.circle(mapImg2,(self.goalX,self.mapHeight-1-self.goalY),30,(0,0,255),2)
        
        
        # get Current state image
        state = self.estimateStateV2()
        
        # Make a copy of the state image
        stateImg = copy.deepcopy(state[0].squeeze())    # squeeze out extra dimesion of state image
        stateHeight,stateWidth = stateImg.shape
        
        # State image is in normalized form [0.0,1.0]. So multiply by 255.0 to bring it to [0,255]
        stateImg = np.array(stateImg*255.0,dtype = np.uint8)
        
        # Convert grayscale image to RGB because map image where we want to paste it is RGB
        stateImg = cv2.cvtColor(stateImg,cv2.COLOR_GRAY2RGB)
        
        # Paste state image onto map image
        mapImg2[500:500+stateHeight,1200:1200+stateWidth,:] = stateImg[:,:,:]
        
        # Set text color to be blue
        textColor = (255,0,0)   # in openCV order of color channels is BGR
        # Indicate 'state image'
        cv2.putText(img=mapImg2,text='State Image',org=(1170,480),fontFace=cv2.FONT_HERSHEY_SIMPLEX,\
                    fontScale=0.5,color=textColor,thickness=2)
        
        # Prepare text for showing step reward
        stepRewardMsg = 'Step Reward: %f'%self.reward
        # Write step reward onto map image
        cv2.putText(img=mapImg2,text=stepRewardMsg,org=(1115,570),fontFace=cv2.FONT_HERSHEY_SIMPLEX,\
                    fontScale=0.5,color=textColor,thickness=2)
        
        # Prepare text for showing next goal
        goalMsg = 'Next Goal: (%d,%d)'%(self.goalX,self.goalY)
        # Write next goal location onto map image
        cv2.putText(img=mapImg2,text=goalMsg,org=(1125,600),fontFace=cv2.FONT_HERSHEY_SIMPLEX,\
                    fontScale=0.5,color=textColor,thickness=2)
            
        return mapImg2
    def estimateStateV2(self):
        """
        Returns
        -------
        state : list
        
        Description
        -----------
        Estimate current state of the environment. 
        State consists of 4 elements
        # 0: Crop of mask image centered at car's location rotated by (90 - Car.angle) and
                arrow image pasted on it.
        # 1: Distance to Goal scaled by maxGoalDistance
        # 2: Orientation of Goal wrt car 
        # 3: Negative orientation of Goal wrt car

        """
        
        ################ State Element 0 #################################

        # Fetch the crop of Mask image of size 'crop_size' centered at car's location and rotated
        # by (90 - car.angle). This represents car's front view
        cropWithCar = self.getCurrentMaskCropV2()
        w,h =cropWithCar.shape[:2]
        
        # Rotate the image of an Arrow by 90 because car will always be facing up in
        # its front view
        arrowImgRotated = imgRotate(self.arrowImg,90.0) # arrow always facing up
        
        # Check the size of rotated image
        arrowH,arrowW = arrowImgRotated.shape[:2]
        
        # Calculate where in the cropped image , arrow image's top left corner should be
        plotX = int(w/2 - arrowW/2)
        plotY = int(h/2 - arrowH/2)
        
        
        # Blend Arrow image with portion of cropped image at the location calculated above
        # mergeImages combines two images in proportion alpha and beta (output = alpha*img1 + beta*img2)
        blendedPart = mergeImages(img1=arrowImgRotated,alpha=1.0,img2=cropWithCar[plotY:plotY+ arrowH,plotX:plotX+arrowW ],beta=0.0)
        
        # paste the blended part onto the cropped image at location calculated earlier
        cropWithCar[plotY:plotY+ arrowH,plotX:plotX+arrowW ]  = blendedPart
        
        # Normalize the crop image to [0.0,1.0] pixel values. This image will be used as one of the states
        # to be fed into the CNN. So it is better to provide normalized image rather than [0,255] image
        cropWithCar = (cropWithCar)/(255.0)   
        
        # output dimension should be 1xHxW so expand dimension
        cropWithCar = np.expand_dims(cropWithCar,0)
        
        ####################### State element 1 ###############################
        
        # calculate distance to goal
        goalDistance = np.sqrt((self.car.posX - self.goalX)**2 + (self.car.posY - self.goalY)**2)
       
        # normalize goalDistance by maxGoalDistance to lie between [0.0,1.0]
        goalDistance = (goalDistance)/(self.maxGoalDistance)
        
        ####################### State element 2 and 3 ###############################
        
        # Estimate vector joining car position and goal position
        xx = self.goalX - self.car.posX
        yy = self.goalY - self.car.posY
        angle = math.radians(self.car.angle)
        
        # code taken from kivy vector.rotate (https://github.com/kivy/kivy/blob/420c8e2b8432d5363ed0662be7a649c2a8b86274/kivy/vector.py#L289)

        # Estimate vector representing Car's pointing direction
        carVecX = (self.car.velocityX * math.cos(angle)) - (self.car.velocityY * math.sin(angle))
        carVecY = (self.car.velocityY * math.cos(angle)) + (self.car.velocityX * math.sin(angle))
        
        # code taken from kivy vector.angle (https://github.com/kivy/kivy/blob/420c8e2b8432d5363ed0662be7a649c2a8b86274/kivy/vector.py#L289)
       
        # Estimate angle between vectors calculated above 
        orientation = -(180 / math.pi) * math.atan2(
            carVecX * yy - carVecY * xx,
            carVecX * xx + carVecY * yy)
        
        # normalize orientation to range [-1.0,1.0]
        orientation /= 180
        
        # Assemble the state list
        state = [cropWithCar,goalDistance,-orientation,orientation]
        
        return state