def surface_normal(self, ray, acute=True):
        """
        Returns surface normal in point where ray hits CSGint surface
        """

        """
        Ensure surface_point on CSGint surface
        """

        invtransform = tf.inverse_matrix(self.transform)
        localray = Ray()
        localray.position = transform_point(ray.position, invtransform)
        localray.direction = transform_direction(ray.direction, invtransform)
        
        bool1 = self.INTone.on_surface(localray.position)
        bool2 = self.INTtwo.on_surface(localray.position)
        
        assertbool = False
        if bool1 == True and self.INTtwo.contains(localray.position) == True:
            assertbool = True
        if bool2 == True and self.INTone.contains(localray.position) == True:
            assertbool = True
        if bool1 == bool2 == True:
            assertbool = True
        assert assertbool == True
                     
        if bool1 == True:
            return self.INTone.surface_normal(ray, acute)
        else:
            return self.INTtwo.surface_normal(ray, acute)
    def surface_normal(self, ray, acute=True):
        """
        Return the surface normal for a ray arriving on the CSGsub surface.
        """

        invtransform = tf.inverse_matrix(self.transform)
        localray = Ray()
        localray.position = transform_point(ray.position, invtransform)
        localray.direction = transform_direction(ray.direction, invtransform)
        
        bool1 = self.SUBplus.on_surface(localray.position)
        bool2 = self.SUBminus.on_surface(localray.position)

        assertbool = False
        if bool1 == True and self.SUBminus.contains(localray.position) == False:
            assertbool = True
        if bool2 == True and self.SUBplus.contains(localray.position) == True:
            assertbool = True
        assert assertbool == True

        if bool1 == True and self.SUBminus.contains(localray.position) == False:            
            return self.SUBplus.surface_normal(ray, acute)            

        if bool2 == True and self.SUBplus.contains(localray.position) == True:
            if acute:            
                return self.SUBminus.surface_normal(ray,acute)
            else:
                normal = -1 * self.SUBminus.surface_normal(ray, acute=True)
                # Remove signed zeros
                for i in range(0,3):
                    if normal[i] == 0.0:
                        normal[i] = 0.0
                return normal
    def intersection(self, ray):
        """
        Returns the intersection points of ray with CSGadd in global frame
        """

        # We will need the invtransform later when we return the results..."
        invtransform = tf.inverse_matrix(self.transform)

        localray = Ray()

        localray.position = transform_point(ray.position, invtransform)
        localray.direction = transform_direction(ray.direction, invtransform)

        ADDone__intersections = self.ADDone.intersection(localray)
        ADDtwo__intersections = self.ADDtwo.intersection(localray)

        """
        Cover the simpler cases
        """
        if ADDone__intersections == None and ADDtwo__intersections == None:
            return None  

        """
        Change ..._intersections into tuples
        """
        if ADDone__intersections != None:
            for i in range(0,len(ADDone__intersections)):
                point = ADDone__intersections[i]
                new_point = (point[0], point[1], point[2])
                ADDone__intersections[i] = new_point
                
        if ADDtwo__intersections != None:
            for i in range(0,len(ADDtwo__intersections)):
                point = ADDtwo__intersections[i]
                new_point = (point[0],point[1],point[2])
                ADDtwo__intersections[i] = new_point

        """
        Only intersection points NOT containted in resp. other structure relevant
        """
        ADDone_intersections = []
        ADDtwo_intersections = []

        if ADDone__intersections != None:
            for i in range(0,len(ADDone__intersections)):
                if self.ADDtwo.contains(ADDone__intersections[i]) == False:
                    ADDone_intersections.append(ADDone__intersections[i])

        if ADDtwo__intersections != None:
            for j in range(0,len(ADDtwo__intersections)):
                if self.ADDone.contains(ADDtwo__intersections[j]) == False:
                    ADDtwo_intersections.append(ADDtwo__intersections[j])

        """
        => Convert to list
        """
        ADDone_set = set(ADDone_intersections[:])
        ADDtwo_set = set(ADDtwo_intersections[:])
        combined_set = ADDone_set | ADDtwo_set
        combined_intersections = list(combined_set)

        """
        Just in case...
        """
        if len(combined_intersections) == 0:
            return None

        """
        Sort by separation from ray origin
        """
        intersection_separations = []
        for point in combined_intersections:
            intersection_separations.append(separation(ray.position, point))

        """
        Convert into Numpy arrays in order to sort
        """
                                            
        intersection_separations = np.array(intersection_separations)
        sorted_indices = intersection_separations.argsort()
        sorted_combined_intersections = []
        for index in sorted_indices:
            sorted_combined_intersections.append(np.array(combined_intersections[index]))

        global_frame_intersections = []
        for point in sorted_combined_intersections:
            global_frame_intersections.append(transform_point(point, self.transform))

        global_frame_intersections_cleared = []
        for point in global_frame_intersections:
            if self.on_surface(point) == True:
                """
                This is only necessary if the two objects have an entire surface region in common,
                for example consider two boxes joined at one face.
                """
                global_frame_intersections_cleared.append(point)

        if len(global_frame_intersections_cleared) == 0:
            return None
                
        return global_frame_intersections_cleared
    def intersection(self, ray):
        """
        Returns the intersection points of ray with CSGint in global frame
        """

        # We will need the invtransform later when we return the results..."
        invtransform = tf.inverse_matrix(self.transform)

        localray = Ray()

        localray.position = transform_point(ray.position, invtransform)
        localray.direction = transform_direction(ray.direction, invtransform)

        INTone__intersections = self.INTone.intersection(localray)
        INTtwo__intersections = self.INTtwo.intersection(localray)

        """
        Cover the simpler cases
        """
        if INTone__intersections == None and INTtwo__intersections == None:
            return None  
                                    
        """
        Change ..._intersections into tuples
        """
        if INTone__intersections != None:
            for i in range(0,len(INTone__intersections)):
                point = INTone__intersections[i]
                new_point = (point[0], point[1], point[2])
                INTone__intersections[i] = new_point

        if INTtwo__intersections != None:
            for i in range(0,len(INTtwo__intersections)):
                point = INTtwo__intersections[i]
                new_point = (point[0], point[1], point[2])
                INTtwo__intersections[i] = new_point

        """
        Only intersection points contained in resp. other structure relevant
        """
        INTone_intersections = []
        INTtwo_intersections = []

        if INTone__intersections != None:
            for i in range(0,len(INTone__intersections)):
                if self.INTtwo.contains(INTone__intersections[i]) == True:
                    INTone_intersections.append(INTone__intersections[i])

        if INTtwo__intersections != None:       
            for j in range(0,len(INTtwo__intersections)):
                if self.INTone.contains(INTtwo__intersections[j]) == True:
                    INTtwo_intersections.append(INTtwo__intersections[j])

        """
        => Convert to list
        """
        INTone_set = set(INTone_intersections[:])
        INTtwo_set = set(INTtwo_intersections[:])
        combined_set = INTone_set | INTtwo_set
        combined_intersections = list(combined_set)

        """
        Just in case...
        """
        if len(combined_intersections) == 0:
            return None

        """
        Sort by separation from ray origin
        """
        intersection_separations = []
        for point in combined_intersections:
            intersection_separations.append(separation(ray.position, point))

        """
        Convert into Numpy arrays in order to sort
        """
        intersection_separations = np.array(intersection_separations)
        sorted_indices = intersection_separations.argsort()
        sorted_combined_intersections = []
        for index in sorted_indices:
            sorted_combined_intersections.append(np.array(combined_intersections[index]))
            

        global_frame_intersections = []
        for point in sorted_combined_intersections:
            global_frame_intersections.append(transform_point(point, self.transform))

        return global_frame_intersections
    def intersection(self, ray):
        """
        Returns the intersection points of ray with CSGsub in global frame
        """

        # We will need the invtransform later when we return the results..."
        invtransform = tf.inverse_matrix(self.transform)

        localray = Ray()

        localray.position = transform_point(ray.position, invtransform)
        localray.direction = transform_direction(ray.direction, invtransform)
        
        SUBplus__intersections = self.SUBplus.intersection(localray)
        SUBminus__intersections = self.SUBminus.intersection(localray)
                  
        """
        Cover the simpler cases
        """
        if SUBplus__intersections == None and SUBminus__intersections == None:
            return None  
         
        """
        Change ..._intersections into tuples
        """
        if SUBplus__intersections != None:
            for i in range(0,len(SUBplus__intersections)):
                point = SUBplus__intersections[i]
                new_point = (point[0], point[1], point[2])
                SUBplus__intersections[i] = new_point

        if SUBminus__intersections != None:
            for i in range(0,len(SUBminus__intersections)):
                point = SUBminus__intersections[i]
                new_point = (point[0], point[1], point[2])
                SUBminus__intersections[i] = new_point
        
        """
        Valid intersection points:
        SUBplus intersections must lie outside SUBminus
        SUBminus intersections must lie inside SUBplus
        """
        
        SUBplus_intersections = []
        SUBminus_intersections = []

        if SUBplus__intersections != None:
            for intersection in SUBplus__intersections:
                if not self.SUBminus.contains(intersection):
                    SUBplus_intersections.append(intersection)

        if SUBminus__intersections != None:
            for intersection in SUBminus__intersections:
                if self.SUBplus.contains(intersection):
                    SUBminus_intersections.append(intersection)
            
        # SUBplus_set = set(SUBplus_intersections[:])
        # SUBminus_set = set(SUBminus_intersections[:])
        # combined_set = SUBplus_set ^ SUBminus_set
        # combined_intersections = list(combined_set)
        
        combined_intersections = np.array(list(set(SUBplus_intersections+SUBminus_intersections)))
        
        # intersection_separations = combined_intersections[0]**2+combined_intersections[1]**2+combined_intersections[2]**2
        """
        Just in case...
        """
        if len(combined_intersections) == 0:
            return None
        
        transposed_intersections = combined_intersections.transpose()
        
        
        intersection_vectors = transposed_intersections[0]-ray.position[0], transposed_intersections[1]-ray.position[1], transposed_intersections[2]-ray.position[2]
        
        # intersection_separations= []
        # print combined_intersections, point, intersection_vectors
              
        intersection_separations = intersection_vectors[0]**2+intersection_vectors[1]**2+intersection_vectors[2]**2
        
        # for point in combined_intersections:
        #     intersection_separations.append(separation(ray.position, point))

        # for i in range(len(intersection_separations)):
        #     print intersection_separations[i], intersection_separations2[i]

        """
        Sort by distance from ray origin => Use Numpy arrays
        """
        # intersection_separations = np.array(intersection_separations)
        sorted_combined_intersections = combined_intersections[intersection_separations.argsort()]
        # sorted_combined_intersections = []
        #         for index in sorted_indices:
        #             sorted_combined_intersections.append(np.array(combined_intersections[index]))
        
        
        # global_frame_intersections = []
        # for point in sorted_combined_intersections:
        #     global_frame_intersections.append(transform_point(point, self.transform))

        global_frame_intersections = [transform_point(point, self.transform) for point in sorted_combined_intersections]
        
        return global_frame_intersections