def create_mesh_from_regions(bounding_polygon,
                             boundary_tags,
                             maximum_triangle_area=None,
                             filename=None,
                             interior_regions=None,
                             interior_holes=None,
                             hole_tags=None,
                             poly_geo_reference=None,
                             mesh_geo_reference=None,
                             minimum_triangle_angle=28.0,
                             fail_if_polygons_outside=True,
                             breaklines=None,
                             use_cache=False,
                             verbose=True,
                             regionPtArea=None):
    """Create mesh from bounding polygons, and resolutions.

    bounding_polygon is a list of points in Eastings and Northings,
    relative to the poly_geo_reference.

    Boundary tags is a dictionary of symbolic tags. For every tag there
    is a list of indices referring to segments associated with that tag.
    If a segment is omitted an Exception will be raised.

    maximum_triangle_area is the maximal area per triangle
    for the bounding polygon, excluding the  interior regions.

    Interior_regions is a list of tuples consisting of (polygon,
    resolution) for each region to be separately refined. Do not have
    polygon lines cross or be on-top of each other.  Also do not have
    polygon close to each other.
    
    NOTE: If a interior_region is outside the bounding_polygon it should 
    throw an error
    
    Interior_holes is a list of polygons for each hole.
    hole_tags is an optional list of boundary tags for the holes, see
                boundary_tags parameter.

    This function does not allow segments to share points - use underlying
    pmesh functionality for that

    poly_geo_reference is the geo_reference of the bounding polygon and
    the interior polygons.
    If none, assume absolute.  Please pass one though, since absolute
    references have a zone.
    
    mesh_geo_reference is the geo_reference of the mesh to be created.
    If none is given one will be automatically generated.  It was use
    the lower left hand corner of  bounding_polygon (absolute)
    as the x and y values for the geo_ref.

    breaklines is a list of polygons. These lines will be preserved by the
               triangulation algorithm - useful for coastlines, walls, etc.
               The polygons are not closed.			   
    
    Returns the mesh instance if no filename is given

    Note, interior regions should be fully nested, as overlaps may cause
    unintended resolutions. 

    fail_if_polygons_outside: If True (the default) Exception in thrown
    where interior polygons fall outside bounding polygon. If False, these
    will be ignored and execution continued.
        
    
    """
    
    
    if verbose: log.resource_usage_timing(log.logging.INFO, "start_")
    if verbose: log.timingInfo("maximum_triangle_area, " + str(maximum_triangle_area))
    if verbose: log.timingInfo("minimum_triangle_angle, " + str(minimum_triangle_angle))
    if verbose: log.timingInfo("startMesh, '%s'" % log.CurrentDateTime())
    
    # Build arguments and keyword arguments for use with caching or apply.
    args = (bounding_polygon,
            boundary_tags)
    
    kwargs = {'maximum_triangle_area': maximum_triangle_area,
              'filename': filename,
              'interior_regions': interior_regions,
              'interior_holes': interior_holes,
              'hole_tags': hole_tags,
              'poly_geo_reference': poly_geo_reference,
              'mesh_geo_reference': mesh_geo_reference,
              'minimum_triangle_angle': minimum_triangle_angle,
              'fail_if_polygons_outside': fail_if_polygons_outside,
              'breaklines': breaklines,
              'verbose': verbose,
              'regionPtArea': regionPtArea}   # FIXME (Ole): Should be bypassed one day. See ticket:14

    # Call underlying engine with or without caching
    if use_cache is True:
        try:
            from anuga.caching import cache
        except:
            msg = 'Caching was requested, but caching module'+\
                  'could not be imported'
            raise Exception(msg)


        m = cache(_create_mesh_from_regions,
                  args, kwargs,
                  verbose=verbose,
                  compression=False)
    else:
        m = apply(_create_mesh_from_regions,
                  args, kwargs)


    
    return m    
Example #2
0
def create_mesh_from_regions(bounding_polygon,
                             boundary_tags,
                             maximum_triangle_area=None,
                             filename=None,
                             interior_regions=None,
                             interior_holes=None,
                             hole_tags=None,
                             poly_geo_reference=None,
                             mesh_geo_reference=None,
                             minimum_triangle_angle=28.0,
                             fail_if_polygons_outside=True,
                             breaklines=None,
                             use_cache=False,
                             verbose=True,
                             regionPtArea=None):
    """Create mesh from bounding polygons, and resolutions.

    bounding_polygon is a list of points in Eastings and Northings,
    relative to the poly_geo_reference.

    Boundary tags is a dictionary of symbolic tags. For every tag there
    is a list of indices referring to segments associated with that tag.
    If a segment is omitted an Exception will be raised.

    maximum_triangle_area is the maximal area per triangle
    for the bounding polygon, excluding the  interior regions.

    Interior_regions is a list of tuples consisting of (polygon,
    resolution) for each region to be separately refined. Do not have
    polygon lines cross or be on-top of each other.  Also do not have
    polygon close to each other.
    
    NOTE: If a interior_region is outside the bounding_polygon it should 
    throw an error
    
    Interior_holes is a list of polygons for each hole.
    hole_tags is an optional list of boundary tags for the holes, see
                boundary_tags parameter.

    This function does not allow segments to share points - use underlying
    pmesh functionality for that

    poly_geo_reference is the geo_reference of the bounding polygon and
    the interior polygons.
    If none, assume absolute.  Please pass one though, since absolute
    references have a zone.
    
    mesh_geo_reference is the geo_reference of the mesh to be created.
    If none is given one will be automatically generated.  It was use
    the lower left hand corner of  bounding_polygon (absolute)
    as the x and y values for the geo_ref.

    breaklines is a list of polygons. These lines will be preserved by the
               triangulation algorithm - useful for coastlines, walls, etc.
               The polygons are not closed.			   
    
    Returns the mesh instance if no filename is given

    Note, interior regions should be fully nested, as overlaps may cause
    unintended resolutions. 

    fail_if_polygons_outside: If True (the default) Exception in thrown
    where interior polygons fall outside bounding polygon. If False, these
    will be ignored and execution continued.
        
    
    """

    if verbose: log.resource_usage_timing(log.logging.INFO, "start_")
    if verbose:
        log.timingInfo("maximum_triangle_area, " + str(maximum_triangle_area))
    if verbose:
        log.timingInfo("minimum_triangle_angle, " +
                       str(minimum_triangle_angle))
    if verbose: log.timingInfo("startMesh, '%s'" % log.CurrentDateTime())

    # Build arguments and keyword arguments for use with caching or apply.
    args = (bounding_polygon, boundary_tags)

    kwargs = {
        'maximum_triangle_area': maximum_triangle_area,
        'filename': filename,
        'interior_regions': interior_regions,
        'interior_holes': interior_holes,
        'hole_tags': hole_tags,
        'poly_geo_reference': poly_geo_reference,
        'mesh_geo_reference': mesh_geo_reference,
        'minimum_triangle_angle': minimum_triangle_angle,
        'fail_if_polygons_outside': fail_if_polygons_outside,
        'breaklines': breaklines,
        'verbose': verbose,
        'regionPtArea': regionPtArea
    }  # FIXME (Ole): Should be bypassed one day. See ticket:14

    # Call underlying engine with or without caching
    if use_cache is True:
        try:
            from anuga.caching import cache
        except:
            msg = 'Caching was requested, but caching module'+\
                  'could not be imported'
            raise Exception(msg)

        m = cache(_create_mesh_from_regions,
                  args,
                  kwargs,
                  verbose=verbose,
                  compression=False)
    else:
        m = apply(_create_mesh_from_regions, args, kwargs)

    return m
    def __init__(self,
                 nodes,
                 triangles,
                 geo_reference=None,
                 use_inscribed_circle=False,
                 verbose=False):
        """Build triangular 2d mesh from nodes and triangle information

        Input:

          nodes: x,y coordinates represented as a sequence of 2-tuples or
                 a Nx2 numeric array of floats.

          triangles: sequence of 3-tuples or Mx3 numeric array of
                     non-negative integers representing indices into
                     the nodes array.

          georeference (optional): If specified coordinates are
          assumed to be relative to this origin.


        """

        if verbose: log.critical('General_mesh: Building basic mesh structure')

        self.use_inscribed_circle = use_inscribed_circle
         
        self.triangles = num.array(triangles, num.int)

        if verbose: 
            log.timingInfo("numTriangles, " + str(self.triangles.shape[0]))
       
        self.nodes = num.array(nodes, num.float)

        # Register number of elements and nodes
        self.number_of_triangles = N = self.triangles.shape[0]
        self.number_of_nodes = self.nodes.shape[0]


        # FIXME: this stores a geo_reference, but when coords are returned
        # This geo_ref is not taken into account!
        if geo_reference is None:
            self.geo_reference = Geo_reference()    # Use defaults
        else:
            self.geo_reference = geo_reference

        # Input checks
        msg = ('Triangles must an Mx3 numeric array or a sequence of 3-tuples. '
               'The supplied array has the shape: %s'
               % str(self.triangles.shape))
        assert len(self.triangles.shape) == 2, msg

        msg = ('Nodes must an Nx2 numeric array or a sequence of 2-tuples'
               'The supplied array has the shape: %s' % str(self.nodes.shape))
        assert len(self.nodes.shape) == 2, msg

        msg = 'Vertex indices reference non-existing coordinate sets'
        assert num.max(self.triangles) < self.nodes.shape[0], msg

        # FIXME: Maybe move to statistics?
        # Or use with get_extent
        xy_extent = [min(self.nodes[:,0]), min(self.nodes[:,1]),
                     max(self.nodes[:,0]), max(self.nodes[:,1])]

        self.xy_extent = num.array(xy_extent, num.float)

        # Allocate space for geometric quantities
        self.normals = num.zeros((N, 6), num.float)
        self.areas = num.zeros(N, num.float)
        self.edgelengths = num.zeros((N, 3), num.float)

        # Get x,y coordinates for all triangle vertices and store
        self.centroid_coordinates = num.zeros((N, 2), num.float)

        #Allocate space for geometric quantities
        self.radii = num.zeros(N, num.float)

        # Get x,y coordinates for all triangle vertices and store
        self.vertex_coordinates = V = self.compute_vertex_coordinates()

        # Get x,y coordinates for all triangle edge midpoints and store
        self.edge_midpoint_coordinates  = self.compute_edge_midpoint_coordinates()

        # Initialise each triangle
        if verbose:
            log.critical('General_mesh: Computing areas, normals, '
                         'edgelengths, centroids and radii')


        # Calculate Areas
        V0 = V[0:3*N:3, :]
        V1 = V[1:3*N:3, :]
        V2 = V[2:3*N:3, :]


        # Area
        x0 = V0[:,0]
        y0 = V0[:,1]
        x1 = V1[:,0]
        y1 = V1[:,1]
        x2 = V2[:,0]
        y2 = V2[:,1]

        self.areas[:] = -((x1*y0-x0*y1) + (x2*y1-x1*y2) + (x0*y2-x2*y0))/2.0
        
        #areas = -((x0-x1)*(y2-y1) - (y0-y1)*(x2-x1))/2.0

        #assert num.allclose(self.areas, areas)
        
        ind = num.where(self.areas <= 0.0)
        msg = 'Degenerate Triangle(s) '+str(ind[0])
        assert num.all(self.areas > 0.0), msg


        #print V.shape, V0.shape, V1.shape, V2.shape

#        #print E.shape, E[0:3*M:3, :].shape, E[1:3*M:3, :].shape, E[2:3*M:3, :].shape
#        E[0:3*M:3, :] = 0.5*(V1+V2)
#        E[1:3*M:3, :] = 0.5*(V2+V0)
#        E[2:3*M:3, :] = 0.5*(V0+V1)

        i0 = self.triangles[:,0]
        i1 = self.triangles[:,1]
        i2 = self.triangles[:,2]

        assert num.allclose( x0, self.nodes[i0,0] )
        assert num.allclose( y0, self.nodes[i0,1] )

        assert num.allclose( x1, self.nodes[i1,0] )
        assert num.allclose( y1, self.nodes[i1,1] )

        assert num.allclose( x2, self.nodes[i2,0] )
        assert num.allclose( y2, self.nodes[i2,1] )


        xn0 = x2-x1
        yn0 = y2-y1
        l0 = num.sqrt(xn0**2 + yn0**2)

        xn0 /= l0
        yn0 /= l0

        xn1 = x0-x2
        yn1 = y0-y2
        l1 = num.sqrt(xn1**2 + yn1**2)

        xn1 /= l1
        yn1 /= l1

        xn2 = x1-x0
        yn2 = y1-y0
        l2 = num.sqrt(xn2**2 + yn2**2)

        xn2 /= l2
        yn2 /= l2

        # Compute and store

        self.normals[:,0] =  yn0
        self.normals[:,1] = -xn0

        self.normals[:,2] =  yn1
        self.normals[:,3] = -xn1

        self.normals[:,4] =  yn2
        self.normals[:,5] = -xn2
        
        self.edgelengths[:,0] = l0
        self.edgelengths[:,1] = l1
        self.edgelengths[:,2] = l2

        self.centroid_coordinates[:,0] = (x0 + x1 + x2)/3
        self.centroid_coordinates[:,1] = (y0 + y1 + y2)/3



        if self.use_inscribed_circle == False:
            #OLD code. Computed radii may exceed that of an
            #inscribed circle

            #Midpoints
            xm0 = (x1 + x2)/2
            ym0 = (y1 + y2)/2

            xm1 = (x2 + x0)/2
            ym1 = (y2 + y0)/2

            xm2 = (x0 + x1)/2
            ym2 = (y0 + y1)/2


            #The radius is the distance from the centroid of
            #a triangle to the midpoint of the side of the triangle
            #closest to the centroid

            d0 = num.sqrt((self.centroid_coordinates[:,0] - xm0)**2 + (self.centroid_coordinates[:,1] - ym0)**2)
            d1 = num.sqrt((self.centroid_coordinates[:,0] - xm1)**2 + (self.centroid_coordinates[:,1] - ym1)**2)
            d2 = num.sqrt((self.centroid_coordinates[:,0] - xm2)**2 + (self.centroid_coordinates[:,1] - ym2)**2)


            self.radii[:] = num.minimum(num.minimum(d0, d1), d2)

        else:
            #NEW code added by Peter Row. True radius
            #of inscribed circle is computed

            a = num.sqrt((x0-x1)**2+(y0-y1)**2)
            b = num.sqrt((x1-x2)**2+(y1-y2)**2)
            c = num.sqrt((x2-x0)**2+(y2-y0)**2)

            self.radii[:]=2.0*self.areas/(a+b+c)



#        for i in range(N):
#            if verbose and i % ((N+10)/10) == 0: log.critical('(%d/%d)' % (i, N))
#
#            x0, y0 = V[3*i, :]
#            x1, y1 = V[3*i+1, :]
#            x2, y2 = V[3*i+2, :]
#
#
#            i0 = self.triangles[i][0]
#            i1 = self.triangles[i][1]
#            i2 = self.triangles[i][2]
#
##            assert x0 == self.nodes[i0][0]
##            assert y0 == self.nodes[i0][1]
##
##            assert x1 == self.nodes[i1][0]
##            assert y1 == self.nodes[i1][1]
##
##            assert x2 == self.nodes[i2][0]
##            assert y2 == self.nodes[i2][1]
#
##            # Area
##            self.areas[i] = abs((x1*y0-x0*y1) + (x2*y1-x1*y2) + (x0*y2-x2*y0))/2
##
##            msg = 'Triangle %g (%f,%f), (%f,%f), (%f, %f)' % (i,x0,y0,x1,y1,x2,y2)
##            msg += ' is degenerate:  area == %f' % self.areas[i]
##            assert self.areas[i] > 0.0, msg
#
#            # Normals
#            # The normal vectors
#            #   - point outward from each edge
#            #   - are orthogonal to the edge
#            #   - have unit length
#            #   - Are enumerated according to the opposite corner:
#            #     (First normal is associated with the edge opposite
#            #     the first vertex, etc)
#            #   - Stored as six floats n0x,n0y,n1x,n1y,n2x,n2y per triangle
#            n0 = num.array([x2-x1, y2-y1], num.float)
#            l0 = num.sqrt(num.sum(n0**2))
#
#            n1 = num.array([x0-x2, y0-y2], num.float)
#            l1 = num.sqrt(num.sum(n1**2))
#
#            n2 = num.array([x1-x0, y1-y0], num.float)
#            l2 = num.sqrt(num.sum(n2**2))
#
#            # Normalise
#            n0 /= l0
#            n1 /= l1
#            n2 /= l2
#
##            # Compute and store
##            self.normals[i, :] = [n0[1], -n0[0],
##                                  n1[1], -n1[0],
##                                  n2[1], -n2[0]]
#
#            # Edgelengths
#            #self.edgelengths[i, :] = [l0, l1, l2]
#
#
#
#            #Compute centroid
##            centroid = num.array([(x0 + x1 + x2)/3, (y0 + y1 + y2)/3], num.float)
###            self.centroid_coordinates[i] = centroid
##
##
##            if self.use_inscribed_circle == False:
##                #OLD code. Computed radii may exceed that of an
##                #inscribed circle
##
##                #Midpoints
##                m0 = num.array([(x1 + x2)/2, (y1 + y2)/2], num.float)
##                m1 = num.array([(x0 + x2)/2, (y0 + y2)/2], num.float)
##                m2 = num.array([(x1 + x0)/2, (y1 + y0)/2], num.float)
##
##                #The radius is the distance from the centroid of
##                #a triangle to the midpoint of the side of the triangle
##                #closest to the centroid
##                d0 = num.sqrt(num.sum( (centroid-m0)**2 ))
##                d1 = num.sqrt(num.sum( (centroid-m1)**2 ))
##                d2 = num.sqrt(num.sum( (centroid-m2)**2 ))
##
##                #self.radii[i] = min(d0, d1, d2)
##
##            else:
##                #NEW code added by Peter Row. True radius
##                #of inscribed circle is computed
##
##                a = num.sqrt((x0-x1)**2+(y0-y1)**2)
##                b = num.sqrt((x1-x2)**2+(y1-y2)**2)
##                c = num.sqrt((x2-x0)**2+(y2-y0)**2)
##
##                self.radii[i]=2.0*self.areas[i]/(a+b+c)


        # Build structure listing which triangles belong to which node.
        if verbose: log.critical('General Mesh: Building inverted triangle structure')
        self.build_inverted_triangle_structure()
        
        if verbose: log.timingInfo("aoi, '%s'" % self.get_area())
    def __init__(self,
                 nodes,
                 triangles,
                 geo_reference=None,
                 use_inscribed_circle=False,
                 verbose=False):
        """Build triangular 2d mesh from nodes and triangle information

        Input:

          nodes: x,y coordinates represented as a sequence of 2-tuples or
                 a Nx2 numeric array of floats.

          triangles: sequence of 3-tuples or Mx3 numeric array of
                     non-negative integers representing indices into
                     the nodes array.

          georeference (optional): If specified coordinates are
          assumed to be relative to this origin.


        """

        self.verbose = verbose

        if verbose: log.critical('General_mesh: Building basic mesh structure')

        self.use_inscribed_circle = use_inscribed_circle

        self.triangles = num.array(triangles, num.int)

        if verbose:
            log.timingInfo("numTriangles, " + str(self.triangles.shape[0]))

        self.nodes = num.array(nodes, num.float)

        # Register number of elements and nodes
        self.number_of_triangles = N = int(self.triangles.shape[0])
        self.number_of_nodes = self.nodes.shape[0]

        # FIXME: this stores a geo_reference, but when coords are returned
        # This geo_ref is not taken into account!
        if geo_reference is None:
            self.geo_reference = Geo_reference()  # Use defaults
        else:
            self.geo_reference = geo_reference

        # Input checks
        msg = (
            'Triangles must an Mx3 numeric array or a sequence of 3-tuples. '
            'The supplied array has the shape: %s' % str(self.triangles.shape))
        assert len(self.triangles.shape) == 2, msg

        msg = ('Nodes must an Nx2 numeric array or a sequence of 2-tuples'
               'The supplied array has the shape: %s' % str(self.nodes.shape))
        assert len(self.nodes.shape) == 2, msg

        msg = 'Vertex indices reference non-existing coordinate sets'
        assert num.max(self.triangles) < self.nodes.shape[0], msg

        # FIXME: Maybe move to statistics?
        # Or use with get_extent
        xy_extent = [
            min(self.nodes[:, 0]),
            min(self.nodes[:, 1]),
            max(self.nodes[:, 0]),
            max(self.nodes[:, 1])
        ]

        self.xy_extent = num.array(xy_extent, num.float)

        # Allocate space for geometric quantities
        self.normals = num.zeros((N, 6), num.float)
        self.areas = num.zeros(N, num.float)
        self.edgelengths = num.zeros((N, 3), num.float)

        # Get x,y coordinates for all triangle vertices and store
        self.centroid_coordinates = num.zeros((N, 2), num.float)

        #Allocate space for geometric quantities
        self.radii = num.zeros(N, num.float)

        # Get x,y coordinates for all triangle vertices and store
        self.vertex_coordinates = V = self.compute_vertex_coordinates()

        # Get x,y coordinates for all triangle edge midpoints and store
        self.edge_midpoint_coordinates = self.compute_edge_midpoint_coordinates(
        )

        # Initialise each triangle
        if verbose:
            log.critical('General_mesh: Computing areas, normals, '
                         'edgelengths, centroids and radii')

        # Calculate Areas
        V0 = V[0:3 * N:3, :]
        V1 = V[1:3 * N:3, :]
        V2 = V[2:3 * N:3, :]

        # Area
        x0 = V0[:, 0]
        y0 = V0[:, 1]
        x1 = V1[:, 0]
        y1 = V1[:, 1]
        x2 = V2[:, 0]
        y2 = V2[:, 1]

        self.areas[:] = -((x1 * y0 - x0 * y1) + (x2 * y1 - x1 * y2) +
                          (x0 * y2 - x2 * y0)) / 2.0

        #areas = -((x0-x1)*(y2-y1) - (y0-y1)*(x2-x1))/2.0

        #assert num.allclose(self.areas, areas)

        ind = num.where(self.areas <= 0.0)
        msg = 'Degenerate Triangle(s) ' + str(ind[0])
        assert num.all(self.areas > 0.0), msg

        #print V.shape, V0.shape, V1.shape, V2.shape

        #        #print E.shape, E[0:3*M:3, :].shape, E[1:3*M:3, :].shape, E[2:3*M:3, :].shape
        #        E[0:3*M:3, :] = 0.5*(V1+V2)
        #        E[1:3*M:3, :] = 0.5*(V2+V0)
        #        E[2:3*M:3, :] = 0.5*(V0+V1)

        i0 = self.triangles[:, 0]
        i1 = self.triangles[:, 1]
        i2 = self.triangles[:, 2]

        assert num.allclose(x0, self.nodes[i0, 0])
        assert num.allclose(y0, self.nodes[i0, 1])

        assert num.allclose(x1, self.nodes[i1, 0])
        assert num.allclose(y1, self.nodes[i1, 1])

        assert num.allclose(x2, self.nodes[i2, 0])
        assert num.allclose(y2, self.nodes[i2, 1])

        xn0 = x2 - x1
        yn0 = y2 - y1
        l0 = num.sqrt(xn0**2 + yn0**2)

        xn0 /= l0
        yn0 /= l0

        xn1 = x0 - x2
        yn1 = y0 - y2
        l1 = num.sqrt(xn1**2 + yn1**2)

        xn1 /= l1
        yn1 /= l1

        xn2 = x1 - x0
        yn2 = y1 - y0
        l2 = num.sqrt(xn2**2 + yn2**2)

        xn2 /= l2
        yn2 /= l2

        # Compute and store

        self.normals[:, 0] = yn0
        self.normals[:, 1] = -xn0

        self.normals[:, 2] = yn1
        self.normals[:, 3] = -xn1

        self.normals[:, 4] = yn2
        self.normals[:, 5] = -xn2

        self.edgelengths[:, 0] = l0
        self.edgelengths[:, 1] = l1
        self.edgelengths[:, 2] = l2

        self.centroid_coordinates[:, 0] = old_div((x0 + x1 + x2), 3)
        self.centroid_coordinates[:, 1] = old_div((y0 + y1 + y2), 3)

        if self.use_inscribed_circle == False:
            #OLD code. Computed radii may exceed that of an
            #inscribed circle

            #Midpoints
            xm0 = old_div((x1 + x2), 2)
            ym0 = old_div((y1 + y2), 2)

            xm1 = old_div((x2 + x0), 2)
            ym1 = old_div((y2 + y0), 2)

            xm2 = old_div((x0 + x1), 2)
            ym2 = old_div((y0 + y1), 2)

            #The radius is the distance from the centroid of
            #a triangle to the midpoint of the side of the triangle
            #closest to the centroid

            d0 = num.sqrt((self.centroid_coordinates[:, 0] - xm0)**2 +
                          (self.centroid_coordinates[:, 1] - ym0)**2)
            d1 = num.sqrt((self.centroid_coordinates[:, 0] - xm1)**2 +
                          (self.centroid_coordinates[:, 1] - ym1)**2)
            d2 = num.sqrt((self.centroid_coordinates[:, 0] - xm2)**2 +
                          (self.centroid_coordinates[:, 1] - ym2)**2)

            self.radii[:] = num.minimum(num.minimum(d0, d1), d2)

        else:
            #NEW code added by Peter Row. True radius
            #of inscribed circle is computed

            a = num.sqrt((x0 - x1)**2 + (y0 - y1)**2)
            b = num.sqrt((x1 - x2)**2 + (y1 - y2)**2)
            c = num.sqrt((x2 - x0)**2 + (y2 - y0)**2)

            self.radii[:] = old_div(2.0 * self.areas, (a + b + c))

#        for i in range(N):
#            if verbose and i % ((N+10)/10) == 0: log.critical('(%d/%d)' % (i, N))
#
#            x0, y0 = V[3*i, :]
#            x1, y1 = V[3*i+1, :]
#            x2, y2 = V[3*i+2, :]
#
#
#            i0 = self.triangles[i][0]
#            i1 = self.triangles[i][1]
#            i2 = self.triangles[i][2]
#
##            assert x0 == self.nodes[i0][0]
##            assert y0 == self.nodes[i0][1]
##
##            assert x1 == self.nodes[i1][0]
##            assert y1 == self.nodes[i1][1]
##
##            assert x2 == self.nodes[i2][0]
##            assert y2 == self.nodes[i2][1]
#
##            # Area
##            self.areas[i] = abs((x1*y0-x0*y1) + (x2*y1-x1*y2) + (x0*y2-x2*y0))/2
##
##            msg = 'Triangle %g (%f,%f), (%f,%f), (%f, %f)' % (i,x0,y0,x1,y1,x2,y2)
##            msg += ' is degenerate:  area == %f' % self.areas[i]
##            assert self.areas[i] > 0.0, msg
#
#            # Normals
#            # The normal vectors
#            #   - point outward from each edge
#            #   - are orthogonal to the edge
#            #   - have unit length
#            #   - Are enumerated according to the opposite corner:
#            #     (First normal is associated with the edge opposite
#            #     the first vertex, etc)
#            #   - Stored as six floats n0x,n0y,n1x,n1y,n2x,n2y per triangle
#            n0 = num.array([x2-x1, y2-y1], num.float)
#            l0 = num.sqrt(num.sum(n0**2))
#
#            n1 = num.array([x0-x2, y0-y2], num.float)
#            l1 = num.sqrt(num.sum(n1**2))
#
#            n2 = num.array([x1-x0, y1-y0], num.float)
#            l2 = num.sqrt(num.sum(n2**2))
#
#            # Normalise
#            n0 /= l0
#            n1 /= l1
#            n2 /= l2
#
##            # Compute and store
##            self.normals[i, :] = [n0[1], -n0[0],
##                                  n1[1], -n1[0],
##                                  n2[1], -n2[0]]
#
#            # Edgelengths
#            #self.edgelengths[i, :] = [l0, l1, l2]
#
#
#
#            #Compute centroid
##            centroid = num.array([(x0 + x1 + x2)/3, (y0 + y1 + y2)/3], num.float)
###            self.centroid_coordinates[i] = centroid
##
##
##            if self.use_inscribed_circle == False:
##                #OLD code. Computed radii may exceed that of an
##                #inscribed circle
##
##                #Midpoints
##                m0 = num.array([(x1 + x2)/2, (y1 + y2)/2], num.float)
##                m1 = num.array([(x0 + x2)/2, (y0 + y2)/2], num.float)
##                m2 = num.array([(x1 + x0)/2, (y1 + y0)/2], num.float)
##
##                #The radius is the distance from the centroid of
##                #a triangle to the midpoint of the side of the triangle
##                #closest to the centroid
##                d0 = num.sqrt(num.sum( (centroid-m0)**2 ))
##                d1 = num.sqrt(num.sum( (centroid-m1)**2 ))
##                d2 = num.sqrt(num.sum( (centroid-m2)**2 ))
##
##                #self.radii[i] = min(d0, d1, d2)
##
##            else:
##                #NEW code added by Peter Row. True radius
##                #of inscribed circle is computed
##
##                a = num.sqrt((x0-x1)**2+(y0-y1)**2)
##                b = num.sqrt((x1-x2)**2+(y1-y2)**2)
##                c = num.sqrt((x2-x0)**2+(y2-y0)**2)
##
##                self.radii[i]=2.0*self.areas[i]/(a+b+c)

# Build structure listing which triangles belong to which node.
        if verbose:
            log.critical('General Mesh: Building inverted triangle structure')
        self.build_inverted_triangle_structure()

        if verbose: log.timingInfo("aoi, '%s'" % self.get_area())
Example #5
0
    def __init__(self, coordinates, triangles,
                 boundary=None,
                 tagged_elements=None,
                 geo_reference=None,
                 use_inscribed_circle=False,
                 verbose=False):
        """
        Build Mesh

            Input x,y coordinates (sequence of 2-tuples or Mx2 numeric array of floats)
            triangles (sequence of 3-tuples or Nx3 numeric array of non-negative integers).
        """




        General_mesh.__init__(self, coordinates, triangles,
                              geo_reference=geo_reference,
                              use_inscribed_circle=use_inscribed_circle,
                              verbose=verbose)

        if verbose: log.critical('Mesh: Initialising')

        N = len(self) #Number_of_triangles

        # Allocate arrays for neighbour data

        self.neighbours = -1*num.ones((N, 3), num.int)
        self.neighbour_edges = -1*num.ones((N, 3), num.int)
        self.number_of_boundaries = num.zeros(N, num.int)
        self.surrogate_neighbours = num.zeros((N, 3), num.int)

        #Get x,y coordinates for all triangles and store
        V = self.vertex_coordinates # Relative coordinates

#        #Initialise each triangle
#        if verbose: log.critical('Mesh: Computing centroids and radii')
#        for i in range(N):
#            if verbose and i % ((N+10)/10) == 0: log.critical('(%d/%d)' % (i, N))
#
#            x0, y0 = V[3*i, :]
#            x1, y1 = V[3*i+1, :]
#            x2, y2 = V[3*i+2, :]
#
#            #x0 = V[i, 0]; y0 = V[i, 1]
#            #x1 = V[i, 2]; y1 = V[i, 3]
#            #x2 = V[i, 4]; y2 = V[i, 5]
#
#            #Compute centroid
#            centroid = num.array([(x0 + x1 + x2)/3, (y0 + y1 + y2)/3], num.float)
#            self.centroid_coordinates[i] = centroid
#
#
#            if self.use_inscribed_circle == False:
#                #OLD code. Computed radii may exceed that of an
#                #inscribed circle
#
#                #Midpoints
#                m0 = num.array([(x1 + x2)/2, (y1 + y2)/2], num.float)
#                m1 = num.array([(x0 + x2)/2, (y0 + y2)/2], num.float)
#                m2 = num.array([(x1 + x0)/2, (y1 + y0)/2], num.float)
#
#                #The radius is the distance from the centroid of
#                #a triangle to the midpoint of the side of the triangle
#                #closest to the centroid
#                d0 = num.sqrt(num.sum( (centroid-m0)**2 ))
#                d1 = num.sqrt(num.sum( (centroid-m1)**2 ))
#                d2 = num.sqrt(num.sum( (centroid-m2)**2 ))
#
#                self.radii[i] = min(d0, d1, d2)
#
#            else:
#                #NEW code added by Peter Row. True radius
#                #of inscribed circle is computed
#
#                a = num.sqrt((x0-x1)**2+(y0-y1)**2)
#                b = num.sqrt((x1-x2)**2+(y1-y2)**2)
#                c = num.sqrt((x2-x0)**2+(y2-y0)**2)
#
#                self.radii[i]=2.0*self.areas[i]/(a+b+c)
#
#
#            #Initialise Neighbours (-1 means that it is a boundary neighbour)
#            self.neighbours[i, :] = [-1, -1, -1]
#
#            #Initialise edge ids of neighbours
#            #In case of boundaries this slot is not used
#            self.neighbour_edges[i, :] = [-1, -1, -1]


        #Build neighbour structure
        if verbose: log.critical('Mesh: Building neigbour structure')
        self.build_neighbour_structure()

        #Build surrogate neighbour structure
        if verbose: log.critical('Mesh: Building surrogate neigbour structure')
        self.build_surrogate_neighbour_structure()

        #Build boundary dictionary mapping (id, edge) to symbolic tags
        if verbose: log.critical('Mesh: Building boundary dictionary')
        self.build_boundary_dictionary(boundary)

        #Update boundary_enumeration
        self.build_boundary_neighbours()

        #Build tagged element  dictionary mapping (tag) to array of elements
        if verbose: log.critical('Mesh: Building tagged elements dictionary')
        self.build_tagged_elements_dictionary(tagged_elements)

        # Build a list of vertices that are not connected to any triangles
        self.lone_vertices = []
        #Check that all vertices have been registered
        for node, count in enumerate(self.number_of_triangles_per_node):
            #msg = 'Node %d does not belong to an element.' %node
            #assert count > 0, msg
            if count == 0:
                self.lone_vertices.append(node)

        #Update boundary indices FIXME: OBSOLETE
        #self.build_boundary_structure()



        #FIXME check integrity?
        if verbose: log.critical('Mesh: Done')
        if verbose: log.timingInfo("finishMesh, '%s'" % log.CurrentDateTime())
        if verbose: log.resource_usage_timing(log.logging.INFO, "finishMesh_")