Ignore:
Timestamp:
May 7, 2008, 12:30:35 PM (17 years ago)
Author:
ole
Message:

More work on mesh intersections and much more testing - this includesd
pathological cases where lines intersect vertices, edges and where a
polyline breaks inside a triangle.

Location:
anuga_core/source/anuga/abstract_2d_finite_volumes
Files:
2 edited

Legend:

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

    r5286 r5287  
    901901
    902902
    903     def _get_intersecting_segments(self, line, triangle_intersections={}):
     903    def _get_intersecting_segments(self, line):
    904904      """Find edges intersected by line
    905905
    906906      Input:
    907           line - list of two points forming a segmented line
    908           triangle_intersections to be updated
     907          line - list of two points forming a segmented line 
    909908      Output:
    910909          list of instances of class Triangle_intersection
     
    916915
    917916      from anuga.utilities.polygon import intersection
     917      from anuga.utilities.polygon import is_inside_polygon
    918918     
    919919      msg = 'Line segment must contain exactly two points'
    920920      assert len(line) == 2, msg
    921      
     921
     922      # Origin of intersecting line to be used for
     923      # establishing direction
     924      xi0 = line[0][0]
     925      eta0 = line[0][1]
     926
    922927     
    923928      # Check intersection with edge segments for all triangles
     
    925930      V = self.get_vertex_coordinates()
    926931      N = len(self)
    927 
     932      triangle_intersections={} # Keep track of segments already done
    928933      for i in range(N):
    929934          # Get nodes and edge segments for each triangle
     
    938943
    939944          # Find segments that are intersected by line
    940           intersections = []
     945         
     946          intersections = {} # Use dictionary to record points only once
    941947          for edge in edge_segments:
    942948
    943949              status, value = intersection(line, edge)
    944950              if status == 1:
    945                   # Normal intersection of one edge
     951                  # Normal intersection of one edge or vertex
     952                  intersections[tuple(value)] = i                 
    946953
    947954                  # Exclude singular intersections with vertices
    948                   if not(allclose(value, edge[0]) or\
    949                          allclose(value, edge[1])):
    950                       intersections.append(value)
     955                  #if not(allclose(value, edge[0]) or\
     956                  #       allclose(value, edge[1])):
     957                  #    intersections.append(value)
    951958
    952959              if status == 2:
    953960                  # Edge is sharing a segment with line
    954961
    955                   # Add identified line segment
    956                   for j in range(value.shape[0]):
    957                       intersections.append(value[j,:])
     962                  # This is currently covered by the two
     963                  # vertices that would have been picked up
     964                  # under status == 1
     965                  pass
     966                 
     967
     968
     969          if len(intersections) == 1:
     970              # Check if either line end point lies fully within this triangle
     971              # If this is the case accept that as one end of the intersecting
     972              # segment
     973
     974              poly = V[3*i:3*i+3]
     975              if is_inside_polygon(line[1], poly, closed=False):
     976                  intersections[tuple(line[1])] = i
     977              elif is_inside_polygon(line[0], poly, closed=False):
     978                  intersections[tuple(line[0])] = i         
     979              else:
     980                  # Ignore situations where one vertex is touch, for instance                   
     981                  continue
    958982
    959983
     
    966990              # Calculate attributes for this segment
    967991
    968               # Origin of intersecting line to be used for direction
    969               xi0 = line[0][0]
    970               eta0 = line[0][1]
    971992
    972993              # End points of intersecting segment
    973               x0, y0 = intersections[0]
    974               x1, y1 = intersections[1]
     994              points = intersections.keys()
     995              x0, y0 = points[0]
     996              x1, y1 = points[1]
    975997
    976998
     
    9941016                 
    9951017
    996               # Normal direction (right hand side relative to direction of line)
     1018              # Normal direction:
     1019              # Right hand side relative to line direction
    9971020              vector = array([x1 - x0, y1 - y0]) # Segment vector
    9981021              length = sqrt(sum(vector**2))      # Segment length
     
    10121035
    10131036
    1014       #return triangle_intersections
     1037      # Return segments as a list           
     1038      return triangle_intersections.values()
    10151039
    10161040
     
    10311055      If a polyline segment coincides with a triangle edge,
    10321056      the the entire shared segment will be used.
    1033 
    10341057      Onle one of the triangles thus intersected will be used and that
    10351058      is the first one encoutered.
    10361059
    1037       intersections with single vertices are ignored.
     1060      Intersections with single vertices are ignored.
    10381061
    10391062      Resulting segments are unsorted
     
    10441067
    10451068      # For all segments in polyline
    1046       triangle_intersections = {}
     1069      triangle_intersections = []
    10471070      for i, point0 in enumerate(polyline[:-1]):
    10481071          point1 = polyline[i+1]
     
    10501073          line = [point0, point1]
    10511074
    1052           self._get_intersecting_segments(line, triangle_intersections)
    1053 
    1054 
    1055       return triangle_intersections.values()
     1075          triangle_intersections += self._get_intersecting_segments(line)
     1076
     1077
     1078      return triangle_intersections
    10561079 
    10571080
  • anuga_core/source/anuga/abstract_2d_finite_volumes/test_neighbour_mesh.py

    r5286 r5287  
    12511251        """test_get_intersecting_segments(self):
    12521252
    1253         Very simple test
     1253        Very simple test (horizontal lines)
    12541254        """
    12551255
     
    12871287
    12881288            # Check all normals point straight down etc
     1289            total_length = 0
    12891290            for x in L:
    12901291                if x.triangle_id % 2 == 0:
     
    13021303                assert x.triangle_id in intersected_triangles
    13031304
     1305                total_length += x.length
     1306
     1307            msg = 'Segments do not add up'
     1308            assert allclose(total_length, 2), msg
     1309           
    13041310
    13051311    def test_get_intersecting_segments_coinciding(self):
     
    13331339
    13341340        # Check all normals point straight down
     1341        total_length = 0
    13351342        for i, x in enumerate(L):
    13361343            assert allclose(x.length, 1.0)
     
    13451352            assert x.triangle_id in intersected_triangles
    13461353
    1347            
     1354            total_length += x.length
     1355
     1356        msg = 'Segments do not add up'
     1357        assert allclose(total_length, 2), msg           
     1358
     1359
    13481360
    13491361    def test_get_intersecting_segments2(self):
    13501362        """test_get_intersecting_segments(self):
    13511363
    1352         More complex mesh
    1353        
     1364        Lines with a slope
    13541365        """
    13551366
    1356         # Build test mesh (from bounding polygon tests
    1357        
    1358 
    1359        
    1360         pass
     1367        s2 = sqrt(2.0)/2
     1368       
     1369
     1370        # Build test mesh
     1371       
     1372        # Create basic mesh
     1373        # 9 points at (0,0), (0, 1), ..., (2,2)
     1374        # 8 triangles enumerated from left bottom to right top.
     1375        points, vertices, boundary = rectangular(2, 2, 2, 2)
     1376        mesh = Mesh(points, vertices, boundary)
     1377       
     1378
     1379        # Diagonal cutting through a vertex and hypothenuses
     1380        line = [[0, 2], [2, 0]]
     1381        intersected_triangles = [3,2,5,4]               
     1382
     1383        L = mesh.get_intersecting_segments(line)
     1384        assert len(L) == 4
     1385
     1386        #print L
     1387       
     1388        # Check all segments
     1389        total_length = 0
     1390        for i, x in enumerate(L):
     1391            assert allclose(x.length, s2)
     1392            assert allclose(x.normal, [-s2, -s2])
     1393            assert allclose(sum(x.normal**2), 1)
     1394           
     1395            assert x.triangle_id in intersected_triangles
     1396
     1397            total_length += x.length
     1398
     1399        msg = 'Segments do not add up'
     1400        assert allclose(total_length, 4*s2), msg
     1401
     1402
     1403        # Diagonal cutting through a vertex and hypothenuses (reversed)
     1404        line = [[2, 0], [0, 2]]
     1405        intersected_triangles = [3,2,5,4]               
     1406
     1407        L = mesh.get_intersecting_segments(line)
     1408        assert len(L) == 4
     1409
     1410        #print L
     1411       
     1412        # Check all segments
     1413        total_length = 0
     1414        for i, x in enumerate(L):
     1415            assert allclose(x.length, s2)
     1416            assert allclose(x.normal, [s2, s2])
     1417            assert allclose(sum(x.normal**2), 1)
     1418           
     1419            assert x.triangle_id in intersected_triangles
     1420
     1421            total_length += x.length
     1422
     1423        msg = 'Segments do not add up'
     1424        assert allclose(total_length, 4*s2), msg                   
     1425
     1426
     1427
     1428        # Diagonal coinciding with hypothenuses
     1429        line = [[2, 2], [0, 0]]
     1430        intersected_triangles = [6,0]               
     1431
     1432        L = mesh.get_intersecting_segments(line)
     1433        assert len(L) == 2
     1434
     1435        #print L
     1436       
     1437        # Check all segments
     1438        total_length = 0
     1439        for i, x in enumerate(L):
     1440            assert allclose(x.length, 2*s2)
     1441            assert allclose(x.normal, [-s2, s2])
     1442            assert allclose(sum(x.normal**2), 1)
     1443           
     1444            assert x.triangle_id in intersected_triangles
     1445
     1446            total_length += x.length
     1447
     1448        msg = 'Segments do not add up'
     1449        assert allclose(total_length, 4*s2), msg                       
     1450
     1451
     1452        # Diagonal coinciding with hypothenuses (reversed)
     1453        line = [[0, 0], [2, 2]]
     1454        intersected_triangles = [6,0]               
     1455
     1456        L = mesh.get_intersecting_segments(line)
     1457        assert len(L) == 2
     1458
     1459        #print L
     1460       
     1461        # Check all segments
     1462        total_length = 0
     1463        for i, x in enumerate(L):
     1464            assert allclose(x.length, 2*s2)
     1465            assert allclose(x.normal, [s2, -s2])
     1466            assert allclose(sum(x.normal**2), 1)
     1467           
     1468            assert x.triangle_id in intersected_triangles
     1469
     1470            total_length += x.length
     1471
     1472        msg = 'Segments do not add up'
     1473        assert allclose(total_length, 4*s2), msg                       
     1474
     1475
     1476
     1477        # line with slope [1, -1] cutting through vertices of tri 7 and 6
     1478        line = [[1, 2], [2, 1]]
     1479        intersected_triangles = [7,6]               
     1480
     1481        L = mesh.get_intersecting_segments(line)
     1482        assert len(L) == 2
     1483
     1484        #print L
     1485       
     1486        # Check all segments
     1487        total_length = 0
     1488        for i, x in enumerate(L):
     1489            assert allclose(x.length, s2)
     1490            assert allclose(x.normal, [-s2, -s2])
     1491            assert allclose(sum(x.normal**2), 1)
     1492           
     1493            assert x.triangle_id in intersected_triangles
     1494
     1495            total_length += x.length
     1496
     1497        msg = 'Segments do not add up'
     1498        assert allclose(total_length, 2*s2), msg
     1499
     1500
     1501        # Arbitrary line with slope [1, -1] cutting through tri 7 and 6
     1502        line = [[1.1, 2], [2.1, 1]]
     1503        intersected_triangles = [7,6]               
     1504
     1505        L = mesh.get_intersecting_segments(line)
     1506        assert len(L) == 2
     1507       
     1508        # Check all segments
     1509        total_length = 0
     1510        for i, x in enumerate(L):
     1511            assert allclose(x.normal, [-s2, -s2])
     1512            assert allclose(sum(x.normal**2), 1)
     1513
     1514            msg = 'Triangle %d' %x.triangle_id + ' is not in %s' %(intersected_triangles)
     1515            assert x.triangle_id in intersected_triangles, msg
     1516           
     1517
     1518
     1519    def test_get_intersecting_segments3(self):
     1520        """test_get_intersecting_segments(self):
     1521
     1522        Check that line can stop inside a triangle
     1523       
     1524        """
     1525
     1526
     1527
     1528        s2 = sqrt(2.0)/2
     1529       
     1530
     1531        # Build test mesh
     1532       
     1533        # Create basic mesh
     1534        # 9 points at (0,0), (0, 1), ..., (2,2)
     1535        # 8 triangles enumerated from left bottom to right top.
     1536        points, vertices, boundary = rectangular(2, 2, 2, 2)
     1537        mesh = Mesh(points, vertices, boundary)
     1538       
     1539
     1540        # Line cutting through one triangle and ending on its edge
     1541        line = [[0.5, 3], [0.5, 1.5]]
     1542        intersected_triangles = [3]               
     1543
     1544        L = mesh.get_intersecting_segments(line)
     1545        assert len(L) == 1
     1546        assert L[0].triangle_id == 3
     1547        assert allclose(L[0].length, 0.5)       
     1548        assert allclose(L[0].normal, [-1,0])               
     1549
     1550
     1551
     1552        # Now try to shorten it so that its endpoint falls short of the far edge
     1553        line = [[0.5, 3], [0.5, 1.6]]
     1554        intersected_triangles = [3]               
     1555
     1556        L = mesh.get_intersecting_segments(line)
     1557        assert len(L) == 1
     1558        assert L[0].triangle_id == 3
     1559        assert allclose(L[0].length, 0.4)
     1560        assert allclose(L[0].normal, [-1,0])
     1561
     1562        intersected_triangles = [3]
     1563
     1564        # Now the same, but with direction changed
     1565        line = [[0.5, 3], [0.5, 1.6]]
     1566        line = [[0.5, 1.6], [0.5, 3]]       
     1567        intersected_triangles = [3]               
     1568
     1569        L = mesh.get_intersecting_segments(line)
     1570        assert len(L) == 1
     1571        assert L[0].triangle_id == 3
     1572        assert allclose(L[0].length, 0.4)
     1573        assert allclose(L[0].normal, [1,0])               
     1574       
     1575
     1576           
     1577
     1578    def test_get_intersecting_segments4(self):
     1579        """test_get_intersecting_segments(self):
     1580
     1581        Simple poly line
     1582       
     1583        """
     1584
     1585
     1586
     1587        s2 = sqrt(2.0)/2
     1588       
     1589
     1590        # Build test mesh
     1591       
     1592        # Create basic mesh
     1593        # 9 points at (0,0), (0, 1), ..., (2,2)
     1594        # 8 triangles enumerated from left bottom to right top.
     1595        points, vertices, boundary = rectangular(2, 2, 2, 2)
     1596        mesh = Mesh(points, vertices, boundary)
     1597       
     1598
     1599        # Polyline with three segments cutting through mesh
     1600        line = [[0.5, 3], [0.5, 1.5], [1,1]]
     1601
     1602        L = mesh.get_intersecting_segments(line)
     1603        assert len(L) == 2
     1604
     1605        for x in L:
     1606            if x.triangle_id == 3:
     1607                assert allclose(x.length, 0.5)       
     1608                assert allclose(x.normal, [-1,0])
     1609               
     1610            if x.triangle_id == 2:
     1611                assert allclose(x.length, s2)
     1612                assert allclose(x.normal, [-s2,-s2])
     1613
     1614
     1615
     1616    def test_get_intersecting_segments5(self):
     1617        """test_get_intersecting_segments(self):
     1618
     1619        More complex poly line
     1620       
     1621        """
     1622
     1623
     1624
     1625        s2 = sqrt(2.0)/2
     1626       
     1627
     1628        # Build test mesh
     1629       
     1630        # Create basic mesh
     1631        # 9 points at (0,0), (0, 1), ..., (2,2)
     1632        # 8 triangles enumerated from left bottom to right top.
     1633        points, vertices, boundary = rectangular(2, 2, 2, 2)
     1634        mesh = Mesh(points, vertices, boundary)
     1635       
     1636
     1637        # Polyline with three segments cutting through mesh
     1638        line = [[0.5, 3], [0.5, 1.5], [1.25, 0.75]]
     1639
     1640        L = mesh.get_intersecting_segments(line)
     1641        assert len(L) == 3
     1642
     1643        for x in L:
     1644            if x.triangle_id == 3:
     1645                assert allclose(x.length, 0.5)       
     1646                assert allclose(x.normal, [-1,0])
     1647               
     1648            if x.triangle_id == 2:
     1649                msg = str(x.length)
     1650                assert allclose(x.length, s2), msg
     1651                assert allclose(x.normal, [-s2,-s2])
     1652
     1653            if x.triangle_id == 5:
     1654                segvec = array([line[2][0]-1,
     1655                                line[2][1]-1])
     1656                msg = str(x.length)
     1657                assert allclose(x.length, sqrt(sum(segvec**2))), msg
     1658                assert allclose(x.normal, [-s2,-s2])                                               
     1659
     1660
     1661    def test_get_intersecting_segments6(self):
     1662        """test_get_intersecting_segments(self):
     1663
     1664        Even more complex poly line, where line breaks within triangle 5
     1665
     1666        5 segments are returned even though only four triangles [3,2,5,6] are touched.
     1667        Triangle 5 therefor has two segments in it.
     1668       
     1669        """
     1670
     1671
     1672
     1673        s2 = sqrt(2.0)/2
     1674       
     1675
     1676        # Build test mesh
     1677       
     1678        # Create basic mesh
     1679        # 9 points at (0,0), (0, 1), ..., (2,2)
     1680        # 8 triangles enumerated from left bottom to right top.
     1681        points, vertices, boundary = rectangular(2, 2, 2, 2)
     1682        mesh = Mesh(points, vertices, boundary)
     1683       
     1684
     1685        # Polyline with three segments cutting through mesh
     1686        line = [[0.5, 3], [0.5, 1.5], [1.25, 0.75], [2.25, 1.75]]
     1687
     1688        L = mesh.get_intersecting_segments(line)
     1689        #for x in L:
     1690        #    print x
     1691
     1692        assert len(L) == 5
     1693
     1694        for x in L:
     1695            if x.triangle_id == 3:
     1696                assert allclose(x.length, 0.5)       
     1697                assert allclose(x.normal, [-1,0])
     1698               
     1699            if x.triangle_id == 2:
     1700                msg = str(x.length)
     1701                assert allclose(x.length, s2), msg
     1702                assert allclose(x.normal, [-s2,-s2])
     1703
     1704            if x.triangle_id == 5:
     1705                if x.segment == ((1.0, 1.0), (1.25, 0.75)):                   
     1706                    segvec = array([line[2][0]-1,
     1707                                    line[2][1]-1])
     1708                    msg = str(x.length)
     1709                    assert allclose(x.length, sqrt(sum(segvec**2))), msg
     1710                    assert allclose(x.normal, [-s2,-s2])
     1711                elif x.segment == ((1.25, 0.75), (1.5, 1.0)):
     1712                    segvec = array([1.5-line[2][0],
     1713                                    1.0-line[2][1]])
     1714                   
     1715                    assert allclose(x.length, sqrt(sum(segvec**2))), msg
     1716                    assert allclose(x.normal, [s2,-s2])
     1717                else:
     1718                    msg = 'Unknow segment: %s' %x.segment
     1719                    raise Exception, msg
     1720               
     1721
     1722                   
     1723            if x.triangle_id == 6:
     1724                assert allclose(x.normal, [s2,-s2])
     1725                assert allclose(x.segment, ((1.5, 1.0), (2, 1.5)))
     1726
     1727
     1728      # Internal test that sum of line segments add up
     1729      # to length of input line
     1730      #
     1731      # Could be useful perhaps
     1732      #
     1733      #xi1 = line[1][0]
     1734      #eta1 = line[1][1]
     1735      #linevector = array([xi1-xi0, eta1-eta0])
     1736      #linelength = sqrt(sum(linevector**2))
     1737      #
     1738      #segmentlength = 0
     1739      #for segment in triangle_intersections:
     1740      #    vector = array([segment[1][0] - segment[0][0],
     1741      #                    segment[1][1] - segment[0][1]])
     1742      #    length = sqrt(sum(vector**2))     
     1743      #    segmentlength += length
     1744      #
     1745      #msg = 'Sum of intersecting segments do not add up'   
     1746      #assert allclose(segmentlength, linelength), msg   
     1747
     1748
    13611749       
    13621750#-------------------------------------------------------------
     
    13641752    #suite = unittest.makeSuite(Test_Mesh,'test_two_triangles')
    13651753    #suite = unittest.makeSuite(Test_Mesh,'test_get_intersecting_segments_coinciding')
    1366     suite = unittest.makeSuite(Test_Mesh,'test')
     1754    suite = unittest.makeSuite(Test_Mesh,'test') #_get_intersecting_segments6')
    13671755    runner = unittest.TextTestRunner()
    13681756    runner.run(suite)
Note: See TracChangeset for help on using the changeset viewer.