# Copyright (C) 2003 by Intevation GmbH
# Authors:
# Bernhard Herzog <bh@intevation.de>
#
# This program is free software under the GPL (>=v2)
# Read the file COPYING coming with the software for details.

"""Test Thuban.UI.hittest"""

__version__ = "$Revision: 1589 $"
# $Source$
# $Id: test_hittest.py 1589 2003-08-15 12:49:08Z bh $

import unittest

import support
support.initthuban()

from Thuban.UI.hittest import line_hit, polygon_hit, arc_hit


class TestLineHit(unittest.TestCase):

    def test_inside(self):
        """Test line_hit with point that would be on the 'inside'

        Inside here means that the point is to the right of the line but
        not so close that the line itself is hit.
        """
        self.assertEquals(line_hit(0, 0, 10, 10, 20, 5), 1)
        self.assertEquals(line_hit(10, 10, 0, 0, 20, 5), 1)
        self.assertEquals(line_hit(10, 10, 0, 0, 8, 5), 1)

    def test_outside(self):
        """Test line_hit with point that would be on the 'outside'

        Inside here means that the point is to the left of the line but
        not so close that the line itself is hit.
        """
        self.assertEquals(line_hit(0, 0, 10, 10, -10, 5), 0)
        self.assertEquals(line_hit(10, 10, 0, 0, -10, 5), 0)
        self.assertEquals(line_hit(10, 10, 0, 0, 2, 5), 0)

    def test_on_line(self):
        """Test line_hit with point that would be on or near the line"""
        self.assertEquals(line_hit(0, 0, 10, -10, 5, -5), -1)
        self.assertEquals(line_hit(0, 0, 10, -10, 10, -10), -1)
        self.assertEquals(line_hit(0, 0, 10, -10, 5, -6), -1)

    def test_horizontal_line(self):
        """Test line_hit with a horizontal line

        For a horizonal line, line_hit will never return 1. It will
        return -1 though for points close to or on the line.
        """
        self.assertEquals(line_hit(10, 10, 10, 10, -10, 10), 0)
        self.assertEquals(line_hit(10, 10, 15, 10, 20, 10), 0)
        self.assertEquals(line_hit(10, 10, 15, 10, 12, 10), -1)

        # Hits near the line will also be counted as line hits.
        self.assertEquals(line_hit(10, 10, 15, 10, 12, 11), -1)
        self.assertEquals(line_hit(10, 10, 15, 10, 12, 9), -1)

    def test_upper_ignored(self):
        """Test line_hit with a point whose ray would hit the upper end point

        The upper end point is not hit to avoid problems with hit
        testing for polygons.
        """
        self.assertEquals(line_hit(-100, 20, 10, -10, 1000, 20), 0)
        self.assertEquals(line_hit(10, -10, -100, 20, 1000, 20), 0)


class TestPolygonHit(unittest.TestCase):

    def test_simple_inside(self):
        """Test polygon_hit with simple polygon and inside point"""
        self.assertEquals(polygon_hit([[(0, 0), (10, 0), (10, 10), (0, 10),
                                        (0, 0)]], 5, 5),
                          1)

    def test_simple_outside(self):
        """Test polygon_hit with simple polygon and outside point"""
        self.assertEquals(polygon_hit([[(0, 0), (10, 0), (10, 10), (0, 10),
                                        (0, 0)]], 20, 5),
                          0)
        self.assertEquals(polygon_hit([[(0, 0), (10, 0), (10, 10), (0, 10),
                                        (0, 0)]], 20, 100),
                          0)

        self.assertEquals(polygon_hit([[(0, 0), (10, 0), (10, 10), (0, 10),
                                        (0, 0)]], 20, -10),
                          0)

    def test_holes_outside(self):
        """Test polygon_hit with polygon with holes and outside point"""
        points = [[(0, 0), (100, 0), (100, 100), (0, 100), (0, 0)],
                  [(20, 20), (80, 20), (80, 80), (20, 80), (20, 20)]]
        self.assertEquals(polygon_hit(points, 50, 50), 0)
        self.assertEquals(polygon_hit(points, 130, 50), 0)

    def test_holes_inside(self):
        """Test polygon_hit with polygon with holes and inside point"""
        points = [[(0, 0), (100, 0), (100, 100), (0, 100), (0, 0)],
                  [(20, 20), (80, 20), (80, 80), (20, 80), (20, 20)]]
        self.assertEquals(polygon_hit(points, 50, 90), 1)
        self.assertEquals(polygon_hit(points, 90, 50), 1)
        self.assertEquals(polygon_hit(points, 10, 50), 1)

    def test_vertex(self):
        """Test polygon_hit with simple polygon and point whose ray hits corner
        """
        points = [[(-10, -5), (-10, 20), (10, 50), (10, 0), (-10, -5)]]
        self.assertEquals(polygon_hit(points, 0, 20), 1)

    def test_border(self):
        """Test polygon_hit with simple polygon and point on/near border"""
        points = [[(-10, -5), (-10, 20), (10, 50), (10, 0), (-10, -5)]]
        self.assertEquals(polygon_hit(points, -9, 20), -1)
        self.assertEquals(polygon_hit(points, 0, -2), -1)
        self.assertEquals(polygon_hit(points, 0, -4), -1)



class TestArcHit(unittest.TestCase):

    def test_simple_hit(self):
        """Test arc_hit with simple arc and point on/near arc"""
        self.assertEquals(arc_hit([[(0, 0), (10, 0), (10, 10), (20, 20)]],
                                  5, 0), 1)
        self.assertEquals(arc_hit([[(0, 0), (10, 0), (10, 10), (20, 20)]],
                                  15, 16), 1)

    def test_simple_not_hit(self):
        """Test arc_hit with simple arc and point not on arc"""
        self.assertEquals(arc_hit([[(0, 0), (10, 0), (10, 10), (20, 20)]],
                                  5, 100), 0)
        self.assertEquals(arc_hit([[(0, 0), (10, 0), (10, 10), (20, 20)]],
                                  13, 7), 0)

    def test_corner(self):
        """Test arc_hit with point on/near arc's corner"""
        self.assertEquals(arc_hit([[(0, 0), (10, 0), (10, 10), (20, 20)]],
                                  11, 10), 1)
        self.assertEquals(arc_hit([[(0, 0), (10, 0), (10, 10), (20, 20)]],
                                  15, 10), 0)

if __name__ == "__main__":
    support.run_tests()
