| | 312 | /* MakeMultiPolygon() */ |
|---|
| | 313 | /************************************************************************/ |
|---|
| | 314 | |
|---|
| | 315 | |
|---|
| | 316 | enum |
|---|
| | 317 | { |
|---|
| | 318 | CONTAINS, |
|---|
| | 319 | IS_CONTAINED_BY, |
|---|
| | 320 | NOT_RELATED |
|---|
| | 321 | }; |
|---|
| | 322 | |
|---|
| | 323 | static OGRGeometry* MakeMultiPolygon (OGRPolygon const * const * polygons, |
|---|
| | 324 | int nbPolygons, |
|---|
| | 325 | int* pIsValidGeometry) |
|---|
| | 326 | { |
|---|
| | 327 | int i, j; |
|---|
| | 328 | |
|---|
| | 329 | if (nbPolygons == 1) |
|---|
| | 330 | { |
|---|
| | 331 | return polygons[0]->clone(); |
|---|
| | 332 | } |
|---|
| | 333 | else |
|---|
| | 334 | { |
|---|
| | 335 | #ifndef HAVE_GEOS |
|---|
| | 336 | static int firstTime = 1; |
|---|
| | 337 | if (firstTime) |
|---|
| | 338 | { |
|---|
| | 339 | CPLError(CE_Warning, CPLE_AppDefined, |
|---|
| | 340 | "GDAL should be built with GEOS support enabled in order the " |
|---|
| | 341 | "SHAPE driver to provide reliable results on complex polygons."); |
|---|
| | 342 | firstTime = 0; |
|---|
| | 343 | } |
|---|
| | 344 | #endif |
|---|
| | 345 | |
|---|
| | 346 | OGREnvelope* envelopes = new OGREnvelope[nbPolygons]; |
|---|
| | 347 | int** relations = new int*[nbPolygons]; |
|---|
| | 348 | double* areas = new double[nbPolygons]; |
|---|
| | 349 | int go_on = 1; |
|---|
| | 350 | for(i=0;i<nbPolygons;i++) |
|---|
| | 351 | { |
|---|
| | 352 | relations[i] = new int[nbPolygons]; |
|---|
| | 353 | polygons[i]->getEnvelope(&envelopes[i]); |
|---|
| | 354 | areas[i] = polygons[i]->get_Area(); |
|---|
| | 355 | } |
|---|
| | 356 | |
|---|
| | 357 | /* This a several step algorithm : |
|---|
| | 358 | 1) Compute in a matrix how polygons relate to each other |
|---|
| | 359 | (this is the moment for detecting pathological intersections and exiting) |
|---|
| | 360 | 2) For each polygon, find the smallest enclosing polygon |
|---|
| | 361 | 3) For each polygon, compute its inclusion depth (0 means toplevel) |
|---|
| | 362 | 4) For each polygon of odd depth (= inner ring), add it to its outer ring |
|---|
| | 363 | |
|---|
| | 364 | Complexity : O(nbPolygons^2) |
|---|
| | 365 | */ |
|---|
| | 366 | |
|---|
| | 367 | /* Compute how each polygon relate to the other ones |
|---|
| | 368 | To save a bit of computation we always begin the computation by a test on the |
|---|
| | 369 | enveloppe. We also take into account the areas to avoid some useless tests. |
|---|
| | 370 | (A contains B implies envelop(A) contains envelop(B) and area(A) > area(B)) |
|---|
| | 371 | In practise, we can hope that few full geometry intersection of inclusion test is done: |
|---|
| | 372 | * if the polygons are well separated geographically |
|---|
| | 373 | (a set of islands for example), no full geometry intersection or inclusion |
|---|
| | 374 | test is done. (the envelopes don't intersect each other) |
|---|
| | 375 | * if the polygons are 'lake inside an island inside a lake inside an area' and |
|---|
| | 376 | that each polygon is much smaller than its enclosing one, their bounding boxes |
|---|
| | 377 | are stricly contained into each oter, and thus, no full geometry intersection or inclusion |
|---|
| | 378 | test is done |
|---|
| | 379 | */ |
|---|
| | 380 | for(i=0;go_on && i<nbPolygons;i++) |
|---|
| | 381 | { |
|---|
| | 382 | for(j=i+1;go_on && j<nbPolygons;j++) |
|---|
| | 383 | { |
|---|
| | 384 | if (areas[i] > areas[j] |
|---|
| | 385 | && envelopes[i].Contains(envelopes[j]) |
|---|
| | 386 | #ifdef HAVE_GEOS |
|---|
| | 387 | && polygons[i]->Contains(polygons[j]) |
|---|
| | 388 | #endif |
|---|
| | 389 | ) |
|---|
| | 390 | { |
|---|
| | 391 | relations[i][j] = CONTAINS; |
|---|
| | 392 | relations[j][i] = IS_CONTAINED_BY; |
|---|
| | 393 | } |
|---|
| | 394 | else if (areas[j] > areas[i] |
|---|
| | 395 | && envelopes[j].Contains(envelopes[i]) |
|---|
| | 396 | #ifdef HAVE_GEOS |
|---|
| | 397 | && polygons[j]->Contains(polygons[i]) |
|---|
| | 398 | #endif |
|---|
| | 399 | ) |
|---|
| | 400 | { |
|---|
| | 401 | relations[j][i] = CONTAINS; |
|---|
| | 402 | relations[i][j] = IS_CONTAINED_BY; |
|---|
| | 403 | } |
|---|
| | 404 | else if (envelopes[i].Intersects(envelopes[j]) == FALSE |
|---|
| | 405 | #ifdef HAVE_GEOS |
|---|
| | 406 | /* We use Overlaps instead of Intersects to be more tolerant about touching polygons */ |
|---|
| | 407 | || polygons[i]->Overlaps(polygons[j]) == FALSE |
|---|
| | 408 | #endif |
|---|
| | 409 | ) |
|---|
| | 410 | { |
|---|
| | 411 | relations[i][j] = NOT_RELATED; |
|---|
| | 412 | relations[j][i] = NOT_RELATED; |
|---|
| | 413 | } |
|---|
| | 414 | else |
|---|
| | 415 | { |
|---|
| | 416 | /* Bad... The polygons are intersecting but no one is |
|---|
| | 417 | contained inside the other one. This is a really broken |
|---|
| | 418 | case. We just make a multipolygon with the whole set of |
|---|
| | 419 | polygons */ |
|---|
| | 420 | go_on = 0; |
|---|
| | 421 | #if 0 |
|---|
| | 422 | fprintf(stderr, "bad intersection for polygons %d and %d\n", i, j); |
|---|
| | 423 | char* wkt1; |
|---|
| | 424 | char* wkt2; |
|---|
| | 425 | polygons[i]->exportToWkt(&wkt1); |
|---|
| | 426 | polygons[j]->exportToWkt(&wkt2); |
|---|
| | 427 | fprintf(stderr, "geom %d : %s\n", i, wkt1); |
|---|
| | 428 | fprintf(stderr, "geom %d : %s\n", j, wkt2); |
|---|
| | 429 | CPLFree(wkt1); |
|---|
| | 430 | CPLFree(wkt2); |
|---|
| | 431 | #endif |
|---|
| | 432 | } |
|---|
| | 433 | } |
|---|
| | 434 | } |
|---|
| | 435 | |
|---|
| | 436 | if (pIsValidGeometry) |
|---|
| | 437 | *pIsValidGeometry = go_on; |
|---|
| | 438 | |
|---|
| | 439 | OGRGeometry* geom = NULL; |
|---|
| | 440 | |
|---|
| | 441 | if (go_on == 0) |
|---|
| | 442 | { |
|---|
| | 443 | geom = new OGRMultiPolygon(); |
|---|
| | 444 | for(i=0;i<nbPolygons;i++) |
|---|
| | 445 | { |
|---|
| | 446 | ((OGRMultiPolygon*)geom)->addGeometry(polygons[i]); |
|---|
| | 447 | } |
|---|
| | 448 | } |
|---|
| | 449 | else |
|---|
| | 450 | { |
|---|
| | 451 | int* directContainerIndex = new int[nbPolygons]; |
|---|
| | 452 | |
|---|
| | 453 | /* Find the smallest enclosing polygon of each polygon */ |
|---|
| | 454 | for(i=0;i<nbPolygons;i++) |
|---|
| | 455 | { |
|---|
| | 456 | int jSmallestContainer = -1; |
|---|
| | 457 | double areaSmallestContainer = 0; |
|---|
| | 458 | for(j=0;j<nbPolygons;j++) |
|---|
| | 459 | { |
|---|
| | 460 | if (i != j) |
|---|
| | 461 | { |
|---|
| | 462 | if (relations[i][j] == IS_CONTAINED_BY) |
|---|
| | 463 | { |
|---|
| | 464 | if (jSmallestContainer < 0 || areas[j] < areaSmallestContainer) |
|---|
| | 465 | { |
|---|
| | 466 | jSmallestContainer = j; |
|---|
| | 467 | areaSmallestContainer = areas[j]; |
|---|
| | 468 | } |
|---|
| | 469 | } |
|---|
| | 470 | } |
|---|
| | 471 | } |
|---|
| | 472 | directContainerIndex[i] = jSmallestContainer; |
|---|
| | 473 | } |
|---|
| | 474 | |
|---|
| | 475 | /* Compute the inclusion depth of each polygon */ |
|---|
| | 476 | int* containedDepth = new int [nbPolygons]; |
|---|
| | 477 | for(i=0;i<nbPolygons;i++) |
|---|
| | 478 | { |
|---|
| | 479 | int depth = 0; |
|---|
| | 480 | int j = directContainerIndex[i]; |
|---|
| | 481 | while (j >= 0) |
|---|
| | 482 | { |
|---|
| | 483 | j = directContainerIndex[j]; |
|---|
| | 484 | depth++; |
|---|
| | 485 | } |
|---|
| | 486 | containedDepth[i] = depth; |
|---|
| | 487 | // fprintf(stderr, "%d is of depth %d\n", i, depth); |
|---|
| | 488 | } |
|---|
| | 489 | |
|---|
| | 490 | int nbTopLevelPolygons = 0; |
|---|
| | 491 | OGRPolygon** tempPolygons = new OGRPolygon*[nbPolygons]; |
|---|
| | 492 | |
|---|
| | 493 | /* Create a copy of toplevel polygons */ |
|---|
| | 494 | for(i=0;i<nbPolygons;i++) |
|---|
| | 495 | { |
|---|
| | 496 | if ((containedDepth[i] % 2) == 0) |
|---|
| | 497 | { |
|---|
| | 498 | nbTopLevelPolygons ++; |
|---|
| | 499 | tempPolygons[i] = (OGRPolygon*)polygons[i]->clone(); |
|---|
| | 500 | if (nbTopLevelPolygons == 1) |
|---|
| | 501 | geom = tempPolygons[i]; |
|---|
| | 502 | } |
|---|
| | 503 | } |
|---|
| | 504 | |
|---|
| | 505 | /* Add interior rings to toplevel polygons */ |
|---|
| | 506 | for(i=0;i<nbPolygons;i++) |
|---|
| | 507 | { |
|---|
| | 508 | if ((containedDepth[i] % 2) == 1) |
|---|
| | 509 | { |
|---|
| | 510 | tempPolygons[directContainerIndex[i]]->addRing((OGRLinearRing*)polygons[i]->getExteriorRing()); |
|---|
| | 511 | } |
|---|
| | 512 | } |
|---|
| | 513 | |
|---|
| | 514 | if (nbTopLevelPolygons > 1) |
|---|
| | 515 | { |
|---|
| | 516 | geom = new OGRMultiPolygon(); |
|---|
| | 517 | |
|---|
| | 518 | /* Add toplevel polygons to the multipolygon */ |
|---|
| | 519 | for(i=0;i<nbPolygons;i++) |
|---|
| | 520 | { |
|---|
| | 521 | if ((containedDepth[i] % 2) == 0) |
|---|
| | 522 | { |
|---|
| | 523 | ((OGRMultiPolygon*)geom)->addGeometryDirectly(tempPolygons[i]); |
|---|
| | 524 | } |
|---|
| | 525 | } |
|---|
| | 526 | } |
|---|
| | 527 | |
|---|
| | 528 | delete[] tempPolygons; |
|---|
| | 529 | delete[] directContainerIndex; |
|---|
| | 530 | delete[] containedDepth; |
|---|
| | 531 | } |
|---|
| | 532 | |
|---|
| | 533 | for(i=0;i<nbPolygons;i++) |
|---|
| | 534 | { |
|---|
| | 535 | delete[] relations[i]; |
|---|
| | 536 | } |
|---|
| | 537 | delete[] relations; |
|---|
| | 538 | delete[] areas; |
|---|
| | 539 | delete[] envelopes; |
|---|
| | 540 | |
|---|
| | 541 | return geom; |
|---|
| | 542 | } |
|---|
| | 543 | } |
|---|
| | 544 | |
|---|
| | 545 | |
|---|
| | 546 | |
|---|
| | 547 | |
|---|
| | 548 | |
|---|
| | 549 | /************************************************************************/ |
|---|