Changeset 5286


Ignore:
Timestamp:
May 6, 2008, 6:03:26 PM (17 years ago)
Author:
ole
Message:

Work on ticket:175 with special consideration to mesh intersections
Also reinstated disabled Okada test which currently fails but is faster.

Location:
anuga_core/source/anuga
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • anuga_core/source/anuga/abstract_2d_finite_volumes/general_mesh.py

    r5221 r5286  
    210210
    211211       
    212         # Build structure listing which trianglse belong to which nodet.
     212        # Build structure listing which trianglse belong to which node.
    213213        if verbose: print 'Building inverted triangle structure'         
    214214        self.build_inverted_triangle_structure()
  • anuga_core/source/anuga/abstract_2d_finite_volumes/neighbour_mesh.py

    r5276 r5286  
    1010from general_mesh import General_mesh
    1111from math import pi, sqrt
     12from Numeric import array, allclose
    1213       
    1314
     
    230231            if ratio <= min_ratio: min_ratio = ratio
    231232        return max_ratio,min_ratio
     233
     234
    232235
    233236    def build_neighbour_structure(self):
     
    628631
    629632        N = len(self)
    630         #Get x,y coordinates for all vertices for all triangles
     633
     634        # Get x,y coordinates for all vertices for all triangles
    631635        V = self.get_vertex_coordinates()
    632         #Check each triangle
     636
     637        # Check each triangle
    633638        for i in range(N):
    634639
     
    637642            x2, y2 = V[3*i+2, :]
    638643           
    639             #Check that area hasn't been compromised
     644            # Check that area hasn't been compromised
    640645            area = self.areas[i]
    641646            ref = abs((x1*y0-x0*y1)+(x2*y1-x1*y2)+(x0*y2-x2*y0))/2
     
    644649            assert abs((area - ref)/area) < epsilon, msg
    645650
    646             #Check that points are arranged in counter clock-wise order
     651            # Check that points are arranged in counter clock-wise order
    647652            v0 = [x1-x0, y1-y0]
    648653            v1 = [x2-x1, y2-y1]
     
    656661            assert a0 < pi and a1 < pi and a2 < pi, msg
    657662
    658             #Check that normals are orthogonal to edge vectors
    659             #Note that normal[k] lies opposite vertex k
     663            # Check that normals are orthogonal to edge vectors
     664            # Note that normal[k] lies opposite vertex k
    660665
    661666            normal0 = self.normals[i, 0:2]
     
    665670            for u, v in [ (v0, normal2), (v1, normal0), (v2, normal1) ]:
    666671
    667                 #Normalise
     672                # Normalise
    668673                l_u = sqrt(u[0]*u[0] + u[1]*u[1])
    669674                l_v = sqrt(v[0]*v[0] + v[1]*v[1])               
    670675
    671                 x = (u[0]*v[0] + u[1]*v[1])/l_u/l_v #Inner product
     676                x = (u[0]*v[0] + u[1]*v[1])/l_u/l_v # Inner product
    672677               
    673678                msg = 'Normal vector (%f,%f) is not perpendicular to' %tuple(v)
     
    896901
    897902
     903    def _get_intersecting_segments(self, line, triangle_intersections={}):
     904      """Find edges intersected by line
     905
     906      Input:
     907          line - list of two points forming a segmented line
     908          triangle_intersections to be updated
     909      Output:
     910          list of instances of class Triangle_intersection
     911
     912      This method is used by the public method
     913      get_intersecting_segments(self, polyline) which also contains
     914      more documentation.
     915      """
     916
     917      from anuga.utilities.polygon import intersection
     918     
     919      msg = 'Line segment must contain exactly two points'
     920      assert len(line) == 2, msg
     921     
     922     
     923      # Check intersection with edge segments for all triangles
     924      # FIXME (Ole): This should be implemented in C
     925      V = self.get_vertex_coordinates()
     926      N = len(self)
     927
     928      for i in range(N):
     929          # Get nodes and edge segments for each triangle
     930          x0, y0 = V[3*i, :]
     931          x1, y1 = V[3*i+1, :]
     932          x2, y2 = V[3*i+2, :]
     933           
     934
     935          edge_segments = [[[x0,y0], [x1, y1]],
     936                            [[x1,y1], [x2, y2]],
     937                            [[x2,y2], [x0, y0]]]
     938
     939          # Find segments that are intersected by line
     940          intersections = []
     941          for edge in edge_segments:
     942
     943              status, value = intersection(line, edge)
     944              if status == 1:
     945                  # Normal intersection of one edge
     946
     947                  # Exclude singular intersections with vertices
     948                  if not(allclose(value, edge[0]) or\
     949                         allclose(value, edge[1])):
     950                      intersections.append(value)
     951
     952              if status == 2:
     953                  # Edge is sharing a segment with line
     954
     955                  # Add identified line segment
     956                  for j in range(value.shape[0]):
     957                      intersections.append(value[j,:])
     958
     959
     960          msg = 'There can be only two or no intersections'
     961          assert len(intersections) in [0,2], msg
     962
     963
     964          if len(intersections) == 2:
     965
     966              # Calculate attributes for this segment
     967
     968              # Origin of intersecting line to be used for direction
     969              xi0 = line[0][0]
     970              eta0 = line[0][1]
     971
     972              # End points of intersecting segment
     973              x0, y0 = intersections[0]
     974              x1, y1 = intersections[1]
     975
     976
     977              # Determine which end point is closer to the origin of the line
     978              # This is necessary for determining the direction of
     979              # the line and the normals
     980
     981              # Distances from line origin to the two intersections
     982              z0 = array([x0 - xi0, y0 - eta0])
     983              z1 = array([x1 - xi0, y1 - eta0])             
     984              d0 = sqrt(sum(z0**2))
     985              d1 = sqrt(sum(z1**2))
     986                 
     987              if d1 < d0:
     988                  # Swap
     989                  xi, eta = x0, y0
     990                  x0, y0 = x1, y1
     991                  x1, y1 = xi, eta
     992
     993              # (x0,y0) is now the origin of the intersecting segment
     994                 
     995
     996              # Normal direction (right hand side relative to direction of line)
     997              vector = array([x1 - x0, y1 - y0]) # Segment vector
     998              length = sqrt(sum(vector**2))      # Segment length
     999              normal = array([vector[1], -vector[0]])/length
     1000
     1001
     1002              segment = ((x0,y0), (x1, y1))   
     1003              T = Triangle_intersection(segment=segment,
     1004                                        normal=normal,
     1005                                        length=length,
     1006                                        triangle_id=i)
     1007
     1008
     1009              # Add segment unless it was done earlier
     1010              if not triangle_intersections.has_key(segment):   
     1011                  triangle_intersections[segment] = T
     1012
     1013
     1014      #return triangle_intersections
     1015
     1016
     1017
    8981018    def get_intersecting_segments(self, polyline):
    8991019      """Find edges intersected by polyline
     
    9031023
    9041024      Output:
    905           dictionary where
    906               keys are triangle ids for those elements that are intersected
    907               values are a list of segments each represented as a triplet:
    908                   length of the intersecting segment
    909                   right hand normal
    910                   midpoint of intersecting segment
    911 
    912       The polyline may break inside any triangle causing multiple segments per triabgle.
     1025          list of instances of class Triangle_intersection
     1026
     1027      The polyline may break inside any triangle causing multiple
     1028      segments per triangle - consequently the same triangle may
     1029      appear in several entries.
     1030
     1031      If a polyline segment coincides with a triangle edge,
     1032      the the entire shared segment will be used.
     1033
     1034      Onle one of the triangles thus intersected will be used and that
     1035      is the first one encoutered.
     1036
     1037      intersections with single vertices are ignored.
     1038
     1039      Resulting segments are unsorted
    9131040      """
    9141041
    915       pass
     1042      msg = 'Polyline must contain at least two points'
     1043      assert len(polyline) >= 2, msg
     1044
     1045      # For all segments in polyline
     1046      triangle_intersections = {}
     1047      for i, point0 in enumerate(polyline[:-1]):
     1048          point1 = polyline[i+1]
     1049         
     1050          line = [point0, point1]
     1051
     1052          self._get_intersecting_segments(line, triangle_intersections)
     1053
     1054
     1055      return triangle_intersections.values()
     1056 
    9161057
    9171058 
     
    9311072            return []
    9321073       
     1074
     1075
     1076class Triangle_intersection:
     1077    """Store information about line segments intersecting a triangle
     1078   
     1079    Attributes are
     1080
     1081        segment: Line segment intersecting triangle [[x0,y0], [x1, y1]]
     1082        normal: [a,b] right hand normal to segment
     1083        length: Length of intersecting segment
     1084        triangle_id: id (in mesh) of triangle being intersected
     1085
     1086    """
     1087
     1088
     1089    def __init__(self,
     1090                 segment=None,
     1091                 normal=None,
     1092                 length=None,
     1093                 triangle_id=None):
     1094        self.segment = segment             
     1095        self.normal = normal
     1096        self.length = length
     1097        self.triangle_id = triangle_id
     1098       
     1099
     1100    def __repr__(self):
     1101        s = 'Triangle_intersection('
     1102        s += 'segment=%s, normal=%s, length=%s, triangle_id=%s)'\
     1103             %(self.segment,
     1104               self.normal,
     1105               self.length,
     1106               self.triangle_id)
     1107   
     1108        return s
  • anuga_core/source/anuga/abstract_2d_finite_volumes/test_neighbour_mesh.py

    r5276 r5286  
    12481248
    12491249
    1250     def NOtest_get_intersecting_segments(self):
     1250    def test_get_intersecting_segments1(self):
    12511251        """test_get_intersecting_segments(self):
    1252        
     1252
     1253        Very simple test
    12531254        """
    12541255
     1256        # Build test mesh
     1257       
     1258        # Create basic mesh
     1259        # 9 points at (0,0), (0, 1), ..., (2,2)
     1260        # 8 triangles enumerated from left bottom to right top.
     1261        points, vertices, boundary = rectangular(2, 2, 2, 2)
     1262        mesh = Mesh(points, vertices, boundary)
     1263
     1264        # Very simple horizontal line intersecting
     1265        #
     1266
     1267
     1268        for y_line in [0.1, 0.2, 0.314159, 0.41, 0.6, 0.99, 1.01, 1.5, 1.77, 1.9]:
     1269            if y_line < 1:
     1270                ceiling = 1
     1271                floor = 0
     1272                intersected_triangles = [0,1,4,5]
     1273            elif y_line > 1:
     1274                ceiling = 2
     1275                floor = 1
     1276                intersected_triangles = [2,3,6,7]
     1277            else:
     1278                raise Exception, 'this test is not for parallel lines'
     1279
     1280
     1281            line = [[-1,y_line], [3,y_line]]
     1282
     1283            L = mesh.get_intersecting_segments(line)
     1284            assert len(L) == 4
     1285
     1286           
     1287
     1288            # Check all normals point straight down etc
     1289            for x in L:
     1290                if x.triangle_id % 2 == 0:
     1291                    assert allclose(x.length, ceiling-y_line)
     1292                else:
     1293                    assert allclose(x.length, y_line-floor)               
     1294
     1295               
     1296                assert allclose(x.normal, [0,-1])
     1297
     1298                assert allclose(x.segment[1][0], x.segment[0][0] + x.length)
     1299                assert allclose(x.segment[0][1], y_line)
     1300                assert allclose(x.segment[1][1], y_line)               
     1301
     1302                assert x.triangle_id in intersected_triangles
     1303
     1304
     1305    def test_get_intersecting_segments_coinciding(self):
     1306        """test_get_intersecting_segments_coinciding(self):
     1307
     1308        Test that lines coinciding with triangle edges work.
     1309        """
     1310
     1311        # Build test mesh
     1312       
     1313        # Create basic mesh
     1314        # 9 points at (0,0), (0, 1), ..., (2,2)
     1315        # 8 triangles enumerated from left bottom to right top.
     1316        points, vertices, boundary = rectangular(2, 2, 2, 2)
     1317        mesh = Mesh(points, vertices, boundary)
     1318        intersected_triangles = [1,5]
     1319
     1320        # Very simple horizontal line intersecting
     1321        #
     1322
     1323        y_line = 1.0
     1324       
     1325        line = [[-1,y_line], [3,y_line]]
     1326
     1327        L = mesh.get_intersecting_segments(line)
     1328
     1329
     1330        msg = 'Only two triangles should be returned'   
     1331        assert len(L) == 2, msg   
     1332           
     1333
     1334        # Check all normals point straight down
     1335        for i, x in enumerate(L):
     1336            assert allclose(x.length, 1.0)
     1337            assert allclose(x.normal, [0,-1])
     1338
     1339            assert allclose(x.segment[1][0], x.segment[0][0] + x.length)
     1340            assert allclose(x.segment[0][1], y_line)
     1341            assert allclose(x.segment[1][1], y_line)                           
     1342
     1343
     1344
     1345            assert x.triangle_id in intersected_triangles
     1346
     1347           
     1348
     1349    def test_get_intersecting_segments2(self):
     1350        """test_get_intersecting_segments(self):
     1351
     1352        More complex mesh
     1353       
     1354        """
     1355
     1356        # Build test mesh (from bounding polygon tests
     1357       
     1358
     1359       
    12551360        pass
    12561361       
     
    12581363if __name__ == "__main__":
    12591364    #suite = unittest.makeSuite(Test_Mesh,'test_two_triangles')
     1365    #suite = unittest.makeSuite(Test_Mesh,'test_get_intersecting_segments_coinciding')
    12601366    suite = unittest.makeSuite(Test_Mesh,'test')
    12611367    runner = unittest.TextTestRunner()
  • anuga_core/source/anuga/shallow_water/test_tsunami_okada.py

    r5283 r5286  
    1111
    1212
    13     def NOtest_Okada_func(self):
     13    def test_Okada_func(self):
    1414        from os import sep, getenv
    1515        from Numeric import zeros, Float,allclose
  • anuga_core/source/anuga/utilities/polygon.py

    r5284 r5286  
    116116                # Lines are parallel and would coincide if extended, but not as they are.
    117117                return 3, None
     118
    118119
    119120            # One line fully included in the other. Use direction of included line
Note: See TracChangeset for help on using the changeset viewer.