Ticket #1217: gdal_svn_trunk_ogr_shape_bug1217.patch

File gdal_svn_trunk_ogr_shape_bug1217.patch, 11.4 kB (added by rouault, 8 months ago)
  • ogr/ogrsf_frmts/shape/makefile.vc

    old new  
    11 
    22OBJ     =       shape2ogr.obj shpopen.obj dbfopen.obj ogrshapedriver.obj \ 
    33                ogrshapedatasource.obj ogrshapelayer.obj shptree.obj 
    4 EXTRAFLAGS =    -I.. -I..\.. /DSHAPELIB_DLLEXPORT -DUSE_CPL 
     4EXTRAFLAGS =    -I.. -I..\.. /DSHAPELIB_DLLEXPORT -DUSE_CPL $(GEOS_CFLAGS) 
    55 
    66GDAL_ROOT       =       ..\..\.. 
    77 
  • ogr/ogrsf_frmts/shape/GNUmakefile

    old new  
    55OBJ     =       shape2ogr.o shpopen.o dbfopen.o shptree.o \ 
    66                ogrshapedriver.o ogrshapedatasource.o ogrshapelayer.o 
    77 
     8ifeq ($(HAVE_GEOS),yes) 
     9CPPFLAGS        :=      -DHAVE_GEOS=1 $(GEOS_CFLAGS) $(CPPFLAGS) 
     10endif 
     11 
    812CPPFLAGS        :=      -DUSE_CPL -I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS) 
    913 
    1014default:        $(O_OBJ) 
  • ogr/ogrsf_frmts/shape/shape2ogr.cpp

    old new  
    306306 
    307307    return ( poRing ); 
    308308} 
    309      
     309 
     310 
    310311/************************************************************************/ 
     312/*                           MakeMultiPolygon()                         */ 
     313/************************************************************************/ 
     314 
     315 
     316enum 
     317{ 
     318    CONTAINS, 
     319    IS_CONTAINED_BY, 
     320    NOT_RELATED 
     321}; 
     322 
     323static 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/************************************************************************/ 
    311550/*                          SHPReadOGRObject()                          */ 
    312551/*                                                                      */ 
    313552/*      Read an item in a shapefile, and translate to OGR geometry      */ 
     
    460699        } 
    461700        else 
    462701        { 
     702#ifdef HAVE_GEOS 
     703            OGRPolygon** tabPolygons = new OGRPolygon*[psShape->nParts]; 
     704            for( iRing = 0; iRing < psShape->nParts; iRing++ ) 
     705            { 
     706                tabPolygons[iRing] = new OGRPolygon(); 
     707                tabPolygons[iRing]->addRingDirectly(CreateLinearRing ( psShape, iRing )); 
     708            } 
     709 
     710            int isValidGeometry; 
     711            poOGR = MakeMultiPolygon (tabPolygons, 
     712                                      psShape->nParts, 
     713                                      &isValidGeometry); 
     714 
     715            if (!isValidGeometry) 
     716            { 
     717                CPLError(CE_Warning, CPLE_AppDefined,  
     718                        "Geometry of polygon of fid %d cannot be translated to Simple Geometry. " 
     719                        "All polygons will be contained in a multipolygon.\n", 
     720                        iShape); 
     721            } 
     722 
     723            for( iRing = 0; iRing < psShape->nParts; iRing++ ) 
     724            { 
     725                delete tabPolygons[iRing]; 
     726            } 
     727            delete[] tabPolygons; 
     728#else 
    463729            /* Multipart polygon. */ 
    464730 
    465731            int nOuter = 0;         /* Number of outer rings */  
     
    637903            CPLFree( direction ); 
    638904            CPLFree( outer ); 
    639905            CPLFree( outside ); 
    640  
     906#endif 
    641907        } /* End of multipart polygon processing. */ 
    642908 
    643909        if( psShape->nSHPType == SHPT_POLYGON )