source: trunk/anuga_core/source/anuga/pmesh/mesh_quadtree.py @ 7810

Last change on this file since 7810 was 7810, checked in by hudson, 14 years ago

Added aggressive psyco optimisation, fixed benchmark app to work with new API.

File size: 6.1 KB
Line 
1"""
2General functions used in fit and interpolate.
3
4   Ole Nielsen, Stephen Roberts, Duncan Gray
5   Geoscience Australia, 2006.
6
7"""
8
9from anuga.utilities.numerical_tools import ensure_numeric
10from anuga.config import max_float
11
12from anuga.geometry.quad import Cell
13from anuga.geometry.aabb import AABB
14
15from anuga.utilities import compile as compile_c
16if compile_c.can_use_C_extension('polygon_ext.c'):
17    # Underlying C implementations can be accessed
18    from polygon_ext import _is_inside_triangle       
19else:
20    msg = 'C implementations could not be accessed by %s.\n ' % __file__
21    msg += 'Make sure compile_all.py has been run as described in '
22    msg += 'the ANUGA installation guide.'
23    raise Exception, msg
24
25import numpy as num
26 
27
28LAST_TRIANGLE = [[[-1, num.array([[max_float, max_float],
29                               [max_float, max_float],
30                               [max_float, max_float]]),
31                      num.array([[max_float, max_float],
32                               [max_float, max_float],
33                               [max_float, max_float]])], -10]]
34
35
36
37class MeshQuadtree(Cell):
38    """ A quadtree constructed from the given mesh.
39        This class is the root node of a quadtree,
40        and derives from a Cell.
41        It contains optimisations and search patterns specific to meshes.
42    """
43    def __init__(self, mesh):
44        """Build quad tree for mesh.
45
46        All vertex indices in the mesh are stored in a quadtree.
47        """
48       
49        extents = AABB(*mesh.get_extent(absolute=True))   
50        extents.grow(1.001) # To avoid round off error
51        Cell.__init__(self, extents, None)  # root has no parent
52       
53        N = len(mesh)
54        self.mesh = mesh
55        self.set_last_triangle() 
56
57        # Get x,y coordinates for all vertices for all triangles
58        V = mesh.get_vertex_coordinates(absolute=True)
59       
60        normals = mesh.get_normals()
61       
62        # Check each triangle
63        for i in range(N):
64            i3 = 3*i
65            x0, y0 = V[i3, :]
66            x1, y1 = V[i3+1, :]
67            x2, y2 = V[i3+2, :]
68
69            node_data = [i, V[i3:i3+3, :], normals[i, :]]
70
71            # insert a tuple with an AABB, and the triangle index as data
72            self.insert_item((AABB(min([x0, x1, x2]), max([x0, x1, x2]), \
73                             min([y0, y1, y2]), max([y0, y1, y2])), \
74                             node_data))
75
76    def search_fast(self, point):
77        """
78        Find the triangle (element) that the point x is in.
79
80        Inputs:
81            point:    The point to test
82       
83        Return:
84            element_found, sigma0, sigma1, sigma2, k
85
86            where
87            element_found: True if a triangle containing x was found
88            sigma0, sigma1, sigma2: The interpolated values
89            k: Index of triangle (if found)
90
91        """
92       
93        point = ensure_numeric(point, num.float)
94                 
95        # check the last triangle found first
96        element_found, sigma0, sigma1, sigma2, k = \
97                   self._search_triangles_of_vertices(self.last_triangle, point)
98        if element_found:
99            return True, sigma0, sigma1, sigma2, k
100
101        branch = self.last_triangle[0][1]
102
103        # test neighbouring tris
104        tri_data = branch.test_leaves(point)         
105        element_found, sigma0, sigma1, sigma2, k = \
106                    self._search_triangles_of_vertices(tri_data, point)
107        if element_found:
108            return True, sigma0, sigma1, sigma2, k       
109
110        # search rest of tree
111        element_found = False
112        next_search = [branch]
113        while branch:               
114            for sibling in next_search:
115                tri_data = sibling.search(point)         
116                element_found, sigma0, sigma1, sigma2, k = \
117                            self._search_triangles_of_vertices(tri_data, point)
118                if element_found:
119                    return True, sigma0, sigma1, sigma2, k
120           
121            next_search = branch.get_siblings()                           
122            branch = branch.parent
123            if branch:
124                tri_data = branch.test_leaves(point)     
125                element_found, sigma0, sigma1, sigma2, k = \
126                            self._search_triangles_of_vertices(tri_data, point)
127                if element_found:
128                    return True, sigma0, sigma1, sigma2, k     
129
130        return element_found, sigma0, sigma1, sigma2, k
131
132
133    def _search_triangles_of_vertices(self, triangles, point):
134        """Search for triangle containing x among triangle list
135
136        This is called by search_tree_of_vertices once the appropriate node
137        has been found from the quad tree.
138       
139        Input check disabled to speed things up.
140       
141        point is the point to test
142        triangles is the triangle list
143        return the found triangle and its interpolation sigma.
144        """ 
145
146        for node_data in triangles:             
147            if bool(_is_inside_triangle(point, node_data[0][1], \
148                        int(True), 1.0e-12, 1.0e-12)):
149                normals = node_data[0][2]     
150                n0 = normals[0:2]
151                n1 = normals[2:4]
152                n2 = normals[4:6]         
153                xi0, xi1, xi2 = node_data[0][1]
154
155                sigma0 = num.dot((point-xi1), n0)/num.dot((xi0-xi1), n0)
156                sigma1 = num.dot((point-xi2), n1)/num.dot((xi1-xi2), n1)
157                sigma2 = num.dot((point-xi0), n2)/num.dot((xi2-xi0), n2)
158
159                # Don't look for any other triangles in the triangle list
160                self.last_triangle = [node_data]
161                return True, sigma0, sigma1, sigma2, node_data[0][0] # tri index
162        return False, -1, -1, -1, -10
163
164       
165       
166    def set_last_triangle(self):
167        """ Reset last triangle.
168            The algorithm is optimised to find nearby triangles to the
169            previously found one. This is called to reset the search to
170            the root of the tree.
171        """
172        self.last_triangle = LAST_TRIANGLE
173        self.last_triangle[0][1] = self # point at root by default         
174
175   
176
177               
Note: See TracBrowser for help on using the repository browser.