Changeset 6534
- Timestamp:
- Mar 17, 2009, 5:44:57 PM (16 years ago)
- Location:
- anuga_core/source/anuga/utilities
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
anuga_core/source/anuga/utilities/numerical_tools.py
r6438 r6534 84 84 p = num.innerproduct(v1, v2) 85 85 c = num.innerproduct(v1, normal_vector(v2)) # Projection onto normal 86 # (negative cross product)86 # (negative cross product) 87 87 88 88 theta = safe_acos(p) -
anuga_core/source/anuga/utilities/polygon.py
r6223 r6534 186 186 return status, value 187 187 188 189 190 188 def is_inside_triangle(point, triangle, 189 closed=True, 190 rtol=1.0e-6, 191 atol=1.0e-8, 192 check_inputs=True, 193 verbose=False): 194 """Determine if one point is inside a triangle 195 196 This uses the barycentric method: 197 198 Triangle is A, B, C 199 Point P can then be written as 200 201 P = A + alpha * (C-A) + beta * (B-A) 202 or if we let 203 v=P-A, v0=C-A, v1=B-A 204 205 v = alpha*v0 + beta*v1 206 207 Dot this equation by v0 and v1 to get two: 208 209 dot(v0, v) = alpha*dot(v0, v0) + beta*dot(v0, v1) 210 dot(v1, v) = alpha*dot(v1, v0) + beta*dot(v1, v1) 211 212 or if a_ij = dot(v_i, v_j) and b_i = dot(v_i, v) 213 the matrix equation: 214 215 a_00 a_01 alpha b_0 216 = 217 a_10 a_11 beta b_1 218 219 Solving for alpha and beta yields: 220 221 alpha = (b_0*a_11 - b_1*a_01)/denom 222 beta = (b_1*a_00 - b_0*a_10)/denom 223 224 with denom = a_11*a_00 - a_10*a_01 225 226 The point is in the triangle whenever 227 alpha and beta and their sums are in the unit interval. 228 229 rtol and atol will determine how close the point has to be to the edge 230 before it is deemed on the edge. 231 232 """ 233 234 if check_inputs is True: 235 triangle = ensure_numeric(triangle) 236 237 point = ensure_numeric(point, num.Float) # Convert point to array of points 238 msg = 'is_inside_triangle must be invoked with one point only' 239 assert num.allclose(point.shape, [2]), msg 240 241 242 # Quickly reject points that are clearly outside 243 if point[0] < min(triangle[:,0]): return False 244 if point[0] > max(triangle[:,0]): return False 245 if point[1] < min(triangle[:,1]): return False 246 if point[1] > max(triangle[:,1]): return False 247 248 249 # Start search 250 A = triangle[0, :] 251 B = triangle[1, :] 252 C = triangle[2, :] 253 254 # Now check if point lies wholly inside triangle 255 v0 = C-A 256 v1 = B-A 257 258 a00 = num.innerproduct(v0, v0) 259 a10 = a01 = num.innerproduct(v0, v1) 260 a11 = num.innerproduct(v1, v1) 261 262 denom = a11*a00 - a01*a10 263 264 if abs(denom) > 0.0: 265 v = point-A 266 b0 = num.innerproduct(v0, v) 267 b1 = num.innerproduct(v1, v) 268 269 alpha = (b0*a11 - b1*a01)/denom 270 beta = (b1*a00 - b0*a10)/denom 271 272 if (alpha > 0.0) and (beta > 0.0) and (alpha+beta < 1.0): 273 return True 274 275 276 if closed is True: 277 # Check if point lies on one of the edges 278 279 for X, Y in [[A,B], [B,C], [C,A]]: 280 res = _point_on_line(point[0], point[1], 281 X[0], X[1], 282 Y[0], Y[1], 283 rtol, atol) 284 if res: 285 return True 286 287 288 289 290 291 292 293 294 295 def is_inside_polygon_quick(point, polygon, closed=True, verbose=False): 296 """Determine if one point is inside a polygon 297 Both point and polygon are assumed to be numeric arrays or lists and 298 no georeferencing etc or other checks will take place. 299 300 As such it is faster than is_inside_polygon 301 """ 302 303 # FIXME(Ole): This function isn't being used 304 polygon = ensure_numeric(polygon, num.Float) 305 points = ensure_numeric(point, num.Float) # Convert point to array of points 306 points = points[num.NewAxis, :] 307 msg = 'is_inside_polygon must be invoked with one point only' 308 msg += '\nI got %s and converted to %s' % (str(point), str(points.shape)) 309 assert points.shape[0] == 1 and points.shape[1] == 2, msg 310 311 312 indices = num.zeros(1, num.Int) 313 314 count = _separate_points_by_polygon(points, polygon, indices, 315 int(closed), int(verbose)) 316 317 318 #indices, count = separate_points_by_polygon(points, polygon, 319 # closed=closed, 320 # input_checks=False, 321 # verbose=verbose) 322 323 if count > 0: 324 return True 325 326 327 328 191 329 def is_inside_polygon(point, polygon, closed=True, verbose=False): 192 330 """Determine if one point is inside a polygon … … 231 369 raise msg 232 370 371 polygon = ensure_absolute(polygon) 233 372 try: 234 373 polygon = ensure_absolute(polygon) … … 317 456 318 457 319 def in_and_outside_polygon(points, polygon, closed = True, verbose =False):458 def in_and_outside_polygon(points, polygon, closed=True, verbose=False): 320 459 """Determine points inside and outside a polygon 321 460 … … 362 501 363 502 def separate_points_by_polygon(points, polygon, 364 closed = True, verbose = False): 503 closed=True, 504 check_input=True, 505 verbose=False): 365 506 """Determine whether points are inside or outside a polygon 366 507 … … 371 512 regarded as belonging to the polygon (closed = True) 372 513 or not (closed = False) 514 check_input: Allows faster execution if set to False 373 515 374 516 Outputs: … … 403 545 """ 404 546 405 406 #if verbose: print 'Checking input to separate_points_by_polygon' 407 408 409 #Input checks 410 411 assert isinstance(closed, bool), 'Keyword argument "closed" must be boolean' 412 assert isinstance(verbose, bool), 'Keyword argument "verbose" must be boolean' 413 414 415 try: 416 points = ensure_numeric(points, num.Float) 417 except NameError, e: 418 raise NameError, e 419 except: 420 msg = 'Points could not be converted to Numeric array' 421 raise msg 422 423 #if verbose: print 'Checking input to separate_points_by_polygon 2' 424 try: 425 polygon = ensure_numeric(polygon, num.Float) 426 except NameError, e: 427 raise NameError, e 428 except: 429 msg = 'Polygon could not be converted to Numeric array' 430 raise msg 431 432 msg = 'Polygon array must be a 2d array of vertices' 433 assert len(polygon.shape) == 2, msg 434 435 msg = 'Polygon array must have two columns' 436 assert polygon.shape[1] == 2, msg 437 438 439 msg = 'Points array must be 1 or 2 dimensional.' 440 msg += ' I got %d dimensions' %len(points.shape) 441 assert 0 < len(points.shape) < 3, msg 442 443 444 if len(points.shape) == 1: 445 # Only one point was passed in. 446 # Convert to array of points 447 points = num.reshape(points, (1,2)) 448 449 450 msg = 'Point array must have two columns (x,y), ' 451 msg += 'I got points.shape[1] == %d' %points.shape[0] 452 assert points.shape[1] == 2, msg 547 if check_input: 548 #Input checks 549 550 assert isinstance(closed, bool), 'Keyword argument "closed" must be boolean' 551 assert isinstance(verbose, bool), 'Keyword argument "verbose" must be boolean' 552 553 554 try: 555 points = ensure_numeric(points, num.Float) 556 except NameError, e: 557 raise NameError, e 558 except: 559 msg = 'Points could not be converted to Numeric array' 560 raise msg 561 562 try: 563 polygon = ensure_numeric(polygon, num.Float) 564 except NameError, e: 565 raise NameError, e 566 except: 567 msg = 'Polygon could not be converted to Numeric array' 568 raise msg 569 570 msg = 'Polygon array must be a 2d array of vertices' 571 assert len(polygon.shape) == 2, msg 572 573 msg = 'Polygon array must have two columns' 574 assert polygon.shape[1] == 2, msg 575 576 577 msg = 'Points array must be 1 or 2 dimensional.' 578 msg += ' I got %d dimensions' %len(points.shape) 579 assert 0 < len(points.shape) < 3, msg 580 581 582 if len(points.shape) == 1: 583 # Only one point was passed in. 584 # Convert to array of points 585 points = num.reshape(points, (1,2)) 586 587 588 msg = 'Point array must have two columns (x,y), ' 589 msg += 'I got points.shape[1] == %d' %points.shape[0] 590 assert points.shape[1] == 2, msg 453 591 454 592 455 msg = 'Points array must be a 2d array. I got %s' %str(points[:30]) 456 assert len(points.shape) == 2, msg 457 458 msg = 'Points array must have two columns' 459 assert points.shape[1] == 2, msg 460 461 462 N = polygon.shape[0] #Number of vertices in polygon 463 M = points.shape[0] #Number of points 464 465 466 indices = num.zeros( M, num.Int ) 593 msg = 'Points array must be a 2d array. I got %s' %str(points[:30]) 594 assert len(points.shape) == 2, msg 595 596 msg = 'Points array must have two columns' 597 assert points.shape[1] == 2, msg 598 599 600 N = polygon.shape[0] # Number of vertices in polygon 601 M = points.shape[0] # Number of points 602 603 indices = num.zeros(M, num.Int) 467 604 468 605 count = _separate_points_by_polygon(points, polygon, indices, … … 860 997 class Found(exceptions.Exception): pass 861 998 999 polygon = ensure_numeric(polygon) 1000 862 1001 point_in = False 863 1002 while not point_in: … … 879 1018 880 1019 point = [x_delta, y_delta] 881 #print "point",point882 1020 if is_inside_polygon(point, polygon, closed=False): 883 1021 raise Found -
anuga_core/source/anuga/utilities/polygon_ext.c
r6189 r6534 245 245 246 246 int __separate_points_by_polygon(int M, // Number of points 247 int N, // Number of polygon vertices248 double* points,249 double* polygon,250 long* indices, // M-Array for storage indices251 int closed,252 int verbose) {247 int N, // Number of polygon vertices 248 double* points, 249 double* polygon, 250 long* indices, // M-Array for storage indices 251 int closed, 252 int verbose) { 253 253 254 254 double minpx, maxpx, minpy, maxpy, x, y, px_i, py_i, px_j, py_j, rtol=0.0, atol=0.0; -
anuga_core/source/anuga/utilities/test_polygon.py
r6215 r6534 195 195 196 196 197 def test_is_inside_polygon_quick(self): 198 """test_is_inside_polygon_quick 199 200 Test fast version of of is_inside_polygon 201 """ 202 203 # Simplest case: Polygon is the unit square 204 polygon = [[0,0], [1,0], [1,1], [0,1]] 205 206 assert is_inside_polygon_quick( (0.5, 0.5), polygon ) 207 assert not is_inside_polygon_quick( (0.5, 1.5), polygon ) 208 assert not is_inside_polygon_quick( (0.5, -0.5), polygon ) 209 assert not is_inside_polygon_quick( (-0.5, 0.5), polygon ) 210 assert not is_inside_polygon_quick( (1.5, 0.5), polygon ) 211 212 # Try point on borders 213 assert is_inside_polygon_quick( (1., 0.5), polygon, closed=True) 214 assert is_inside_polygon_quick( (0.5, 1), polygon, closed=True) 215 assert is_inside_polygon_quick( (0., 0.5), polygon, closed=True) 216 assert is_inside_polygon_quick( (0.5, 0.), polygon, closed=True) 217 218 assert not is_inside_polygon_quick( (0.5, 1), polygon, closed=False) 219 assert not is_inside_polygon_quick( (0., 0.5), polygon, closed=False) 220 assert not is_inside_polygon_quick( (0.5, 0.), polygon, closed=False) 221 assert not is_inside_polygon_quick( (1., 0.5), polygon, closed=False) 222 223 224 225 197 226 def test_inside_polygon_main(self): 198 227 … … 223 252 assert not is_inside_polygon( (0.5, -0.5), polygon ) 224 253 254 255 assert is_inside_polygon_quick( (0.5, 0.5), polygon ) 256 assert is_inside_polygon_quick( (1, -0.5), polygon ) 257 assert is_inside_polygon_quick( (1.5, 0), polygon ) 258 259 assert not is_inside_polygon_quick( (0.5, 1.5), polygon ) 260 assert not is_inside_polygon_quick( (0.5, -0.5), polygon ) 225 261 226 262 # Very convoluted polygon … … 406 442 assert num.allclose( res, [1,2,3,5,4,0] ) 407 443 assert count == 3 408 444 445 446 447 def test_is_inside_triangle(self): 448 449 450 # Simplest case: 451 triangle = [[0, 0], [1, 0], [0.5, 1]] 452 453 assert is_inside_triangle((0.5, 0.5), triangle) 454 assert is_inside_triangle((0.9, 0.1), triangle) 455 assert not is_inside_triangle((0.5, 1.5), triangle) 456 assert not is_inside_triangle((0.5, -0.5), triangle) 457 assert not is_inside_triangle((-0.5, 0.5), triangle) 458 assert not is_inside_triangle((1.5, 0.5), triangle) 459 460 # Try point on borders 461 assert is_inside_triangle((0.5, 0), triangle, closed=True) 462 assert is_inside_triangle((1, 0), triangle, closed=True) 463 464 assert not is_inside_triangle((0.5, 0), triangle, closed=False) 465 assert not is_inside_triangle((1, 0), triangle, closed=False) 466 467 # Try vertices 468 for P in triangle: 469 assert is_inside_triangle(P, triangle, closed=True) 470 assert not is_inside_triangle(P, triangle, closed=False) 471 472 473 # Slightly different 474 triangle = [[0, 0.1], [1, -0.2], [0.5, 1]] 475 assert is_inside_triangle((0.5, 0.5), triangle) 476 assert is_inside_triangle((0.4, 0.1), triangle) 477 assert not is_inside_triangle((1, 1), triangle) 478 479 # Try vertices 480 for P in triangle: 481 assert is_inside_triangle(P, triangle, closed=True) 482 assert not is_inside_triangle(P, triangle, closed=False) 483 484 485 409 486 410 487 def test_populate_polygon(self): … … 416 493 for point in points: 417 494 assert is_inside_polygon(point, polygon) 418 419 420 #Very convoluted polygon 495 assert is_inside_polygon_quick(point, polygon) 496 497 498 # Very convoluted polygon 421 499 polygon = [[0,0], [10,10], [15,5], [20, 10], [25,0], [30,10], [40,-10]] 422 500 … … 426 504 for point in points: 427 505 assert is_inside_polygon(point, polygon) 506 assert is_inside_polygon_quick(point, polygon) 428 507 429 508 … … 1782 1861 #------------------------------------------------------------- 1783 1862 if __name__ == "__main__": 1784 suite = unittest.makeSuite(Test_Polygon, 'test')1863 suite = unittest.makeSuite(Test_Polygon, 'test') 1785 1864 runner = unittest.TextTestRunner() 1786 1865 runner.run(suite)
Note: See TracChangeset
for help on using the changeset viewer.