source: anuga_core/source/anuga/pmesh/mesh_interface.py @ 4649

Last change on this file since 4649 was 4623, checked in by ole, 18 years ago

Allowed create_mesh_from_regions to (optionally) allow interior polygons
to fall outside the bounding polygon. In such cases they can now be ignored
by setting the keyword argument fail_if_polygons_outside to False.

File size: 11.7 KB
Line 
1
2#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
3# Assume that the directory anuga_core/source is included in your pythonpath
4#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
5
6from anuga.coordinate_transforms.geo_reference import Geo_reference,DEFAULT_ZONE
7from anuga.utilities.polygon import  point_in_polygon ,populate_polygon
8from anuga.utilities.numerical_tools import ensure_numeric
9from Numeric import Float
10from anuga.utilities.polygon import inside_polygon
11
12# This is due to pmesh being a package and a module and
13# the current dir being unknown
14try:
15    from anuga.pmesh.mesh import Mesh
16except ImportError: 
17    from mesh import Mesh
18
19import exceptions
20class PolygonError(exceptions.Exception): pass
21
22def create_mesh_from_regions(bounding_polygon,
23                             boundary_tags,
24                             maximum_triangle_area=None,
25                             filename=None,
26                             interior_regions=None,
27                             interior_holes=None,
28                             poly_geo_reference=None,
29                             mesh_geo_reference=None,
30                             minimum_triangle_angle=28.0,
31                             fail_if_polygons_outside=True,
32                             use_cache=False,
33                             verbose=True):
34    """Create mesh from bounding polygons, and resolutions.
35
36    bounding_polygon is a list of points in Eastings and Northings,
37    relative to the poly_geo_reference.
38
39    Boundary tags is a dictionary of symbolic tags. For every tag there
40    is a list of indices referring to segments associated with that tag.
41    If a segment is omitted it will be assigned the default tag ''.
42
43    maximum_triangle_area is the maximal area per triangle
44    for the bounding polygon, excluding the  interior regions.
45
46    Interior_regions is a list of tuples consisting of (polygon, resolution)
47    for each region to be separately refined.
48   
49    NOTE: If a interior_region is outside the bounding_polygon it should
50    throw an error
51   
52    Interior_holes is a list of ploygons for each hole.
53
54    This function does not allow segments to share points - use underlying
55    pmesh functionality for that
56
57    poly_geo_reference is the geo_reference of the bounding polygon and
58    the interior polygons.
59    If none, assume absolute.  Please pass one though, since absolute
60    references have a zone.
61   
62    mesh_geo_reference is the geo_reference of the mesh to be created.
63    If none is given one will be automatically generated.  It was use
64    the lower left hand corner of  bounding_polygon (absolute)
65    as the x and y values for the geo_ref.
66   
67    Returns the mesh instance if no filename is given
68
69    Note, interior regions should be fully nested, as overlaps may cause
70    unintended resolutions.
71
72    fail_if_polygons_outside: If True (the default) Exception in thrown
73    where interior polygons fall outside bounding polygon. If False, these
74    will be ignored and execution continued.
75       
76   
77    """
78   
79    # Build arguments and keyword arguments for use with caching or apply.
80    args = (bounding_polygon,
81            boundary_tags)
82   
83    kwargs = {'maximum_triangle_area': maximum_triangle_area,
84              'filename': filename,
85              'interior_regions': interior_regions,
86              'interior_holes': interior_holes,
87              'poly_geo_reference': poly_geo_reference,
88              'mesh_geo_reference': mesh_geo_reference,
89              'minimum_triangle_angle': minimum_triangle_angle,
90              'fail_if_polygons_outside': fail_if_polygons_outside,
91              'verbose': verbose}   # FIXME (Ole): Should be bypassed one day
92                                    # What should be bypassed? Verbose?
93   
94    #print 'kwargs', kwargs
95
96    # Call underlying engine with or without caching
97    if use_cache is True:
98        try:
99            from anuga.caching import cache
100        except:
101            msg = 'Caching was requested, but caching module'+\
102                  'could not be imported'
103            raise msg
104
105
106        m = cache(_create_mesh_from_regions,
107                  args, kwargs,
108                  verbose=verbose,
109                  compression=False)
110    else:
111        m = apply(_create_mesh_from_regions,
112                  args, kwargs)
113
114    return m   
115       
116
117
118def _create_mesh_from_regions(bounding_polygon,
119                              boundary_tags,
120                              maximum_triangle_area=None,
121                              filename=None,                             
122                              interior_regions=None,
123                              interior_holes=None,
124                              poly_geo_reference=None,
125                              mesh_geo_reference=None,
126                              minimum_triangle_angle=28.0,
127                              fail_if_polygons_outside=True,
128                              verbose=True):
129    """_create_mesh_from_regions - internal function.
130
131    See create_mesh_from_regions for documentation.
132    """
133    #FIXME (OLE-DSG)
134    # check the segment indexes - throw an error if they are out of bounds
135    #(DSG) Yes!
136
137   
138    #In addition I reckon the polygons could be of class Geospatial_data
139    #(DSG) If polygons were classes caching would break in places.
140
141    # First check that interior polygons are fully contained in bounding
142    # polygon
143    #Note, Both poly's have the same geo_ref, therefore don't take into account
144    # geo_ref
145
146    # Simple check
147    bounding_polygon = ensure_numeric(bounding_polygon, Float)
148    msg = 'Bounding polygon must be a list of points or an Nx2 array'
149    assert len(bounding_polygon.shape) == 2, msg
150    assert bounding_polygon.shape[1] == 2, msg   
151
152    #
153    if interior_regions is not None:       
154        # Test that all the interior polygons are inside the bounding_poly
155        # and throw out those that aren't fully included.
156
157        polygons_inside_boundary = []
158        for interior_polygon, res in interior_regions:
159            indices = inside_polygon(interior_polygon, bounding_polygon,
160                                     closed = True, verbose = False)
161   
162            if len(indices) <> len(interior_polygon): 
163                msg = 'Interior polygon %s is not fully inside'\
164                      %(str(interior_polygon))
165                msg += ' bounding polygon: %s.' %(str(bounding_polygon))
166
167                if fail_if_polygons_outside is True:
168                    raise PolygonError, msg                   
169                else:
170                    msg += ' I will ignore it.'
171                    print msg
172
173            else:
174                polygons_inside_boundary.append([interior_polygon, res])
175               
176        # Record only those that were fully contained       
177        interior_regions = polygons_inside_boundary
178
179           
180   
181# the following segment of code could be used to Test that all the
182# interior polygons are inside the bounding_poly... however it might need
183# to be change a bit   
184#
185#count = 0
186#for i in range(len(interior_regions)):
187#    region = interior_regions[i]
188#    interior_polygon = region[0]
189#    if len(inside_polygon(interior_polygon, bounding_polygon,
190#                   closed = True, verbose = False)) <> len(interior_polygon):
191#        print 'WARNING: interior polygon %d is outside bounding polygon' %(i)
192#        count += 1
193
194#if count == 0:
195#    print 'interior regions OK'
196#else:
197#    print 'check out your interior polygons'
198#    print 'check %s in production directory' %figname
199#    import sys; sys.exit()
200   
201
202    if interior_holes is not None:       
203        # Test that all the interior polygons are inside the bounding_poly
204        for interior_polygon in interior_holes:
205            indices = inside_polygon(interior_polygon, bounding_polygon,
206                                     closed = True, verbose = False)
207   
208            if len(indices) <> len(interior_polygon): 
209                msg = 'Interior polygon %s is outside bounding polygon: %s'\
210                      %(str(interior_polygon), str(bounding_polygon))
211                raise PolygonError, msg
212
213    # Resolve geo referencing       
214    if mesh_geo_reference is None:
215        xllcorner = min(bounding_polygon[:,0])
216        yllcorner = min(bounding_polygon[:,1])   
217        #
218        if poly_geo_reference is None:
219            zone = DEFAULT_ZONE
220        else:
221            zone = poly_geo_reference.get_zone()
222            [(xllcorner,yllcorner)] = poly_geo_reference.get_absolute( \
223            [(xllcorner,yllcorner)])
224        # create a geo_ref, based on the llc of the bounding_polygon
225        mesh_geo_reference = Geo_reference(xllcorner = xllcorner,
226                                           yllcorner = yllcorner,
227                                           zone = zone)
228
229    m = Mesh(geo_reference=mesh_geo_reference)
230
231    # Do bounding polygon
232    m.add_region_from_polygon(bounding_polygon,
233                              tags=boundary_tags,
234                              geo_reference=poly_geo_reference)
235
236    # Find one point inside region automatically
237    if interior_regions is not None:
238        excluded_polygons = []       
239        for polygon, res in interior_regions:
240            excluded_polygons.append( polygon )
241    else:
242        excluded_polygons = None
243
244    # Convert bounding poly to absolute values
245    # this sort of thing can be fixed with the geo_points class
246    if poly_geo_reference is not None:
247        bounding_polygon_absolute = \
248            poly_geo_reference.get_absolute(bounding_polygon)
249    else:
250        bounding_polygon_absolute = bounding_polygon
251   
252    inner_point = point_in_polygon(bounding_polygon_absolute)
253    inner = m.add_region(inner_point[0], inner_point[1])
254    inner.setMaxArea(maximum_triangle_area)
255
256    # Do interior regions
257#    if interior_regions is not None:   
258#        for polygon, res in interior_regions:
259#            m.add_region_from_polygon(polygon,
260#                                      geo_reference=poly_geo_reference)
261#            # convert bounding poly to absolute values
262#            if poly_geo_reference is not None:
263#                polygon_absolute = \
264#                    poly_geo_reference.get_absolute(polygon)
265#            else:
266#                polygon_absolute = polygon
267#            inner_point = point_in_polygon(polygon_absolute)
268#            region = m.add_region(inner_point[0], inner_point[1])
269#            region.setMaxArea(res)
270           
271           
272    if interior_regions is not None:   
273        for polygon, res in interior_regions:
274            m.add_region_from_polygon(polygon,
275                                      max_triangle_area=res,
276                                      geo_reference=poly_geo_reference)
277   
278           
279    # Do interior holes
280    if interior_holes is not None:   
281        for polygon in interior_holes:
282            m.add_hole_from_polygon(polygon,
283                                    geo_reference=poly_geo_reference)
284       
285
286
287
288    # NOTE (Ole): This was moved here as it is annoying if mesh is always
289    # stored irrespective of whether the computation
290    # was cached or not. This caused Domain to
291    # recompute as it has meshfile as a dependency
292
293    # Decide whether to store this mesh or return it   
294    if filename is None:
295        return m
296    else:
297        if verbose: print 'Generating mesh to file "%s"' %filename
298        m.generate_mesh(minimum_triangle_angle=minimum_triangle_angle,
299                        verbose=verbose)
300        m.export_mesh_file(filename)
301
302
Note: See TracBrowser for help on using the repository browser.