Ticket #754: area_relation.diff

File area_relation.diff, 17.1 KB (added by tegzed, 10 years ago)

added support for disjunct outer polygons

  • osm.c

     
    710710        "w      waterway=canal          water_canal\n"
    711711        "w      waterway=drain          water_drain\n"
    712712        "w      waterway=river          water_river\n"
     713        "w      water=river             water_river\n"
    713714        "w      waterway=riverbank      poly_water\n"
    714715        "w      waterway=stream         water_stream\n"
    715716        "w      barrier=ditch   ditch\n"
     
    943944        char buffer[BUFFER_SIZE*2+2];
    944945        if (in_relation) {
    945946                relation_add_tag(k,v);
     947
     948                //for relation areas we don't set flags
     949                strcpy(buffer,"*=*");
     950                if ((idx=(int)(long)g_hash_table_lookup(attr_hash, buffer)))
     951                        attr_present[idx]=1;
     952
     953                sprintf(buffer,"%s=*", k);
     954                if ((idx=(int)(long)g_hash_table_lookup(attr_hash, buffer)))
     955                        attr_present[idx]=2;
     956
     957                sprintf(buffer,"*=%s", v);
     958                if ((idx=(int)(long)g_hash_table_lookup(attr_hash, buffer)))
     959                        attr_present[idx]=2;
     960
     961                sprintf(buffer,"%s=%s", k, v);
     962                if ((idx=(int)(long)g_hash_table_lookup(attr_hash, buffer)))
     963                        attr_present[idx]=4;
     964
    946965                return;
    947966        }
    948967        if (! strcmp(k,"ele"))
     
    14831502}
    14841503
    14851504
     1505static int
     1506attr_longest_match(struct attr_mapping **mapping, int mapping_count, enum item_type *types, int types_count)
     1507{
     1508        int i,j,longest=0,ret=0,sum,val;
     1509        struct attr_mapping *curr;
     1510        for (i = 0 ; i < mapping_count ; i++) {
     1511                sum=0;
     1512                curr=mapping[i];
     1513                for (j = 0 ; j < curr->attr_present_idx_count ; j++) {
     1514                        val=attr_present[curr->attr_present_idx[j]];
     1515                        if (val)
     1516                                sum+=val;
     1517                        else {
     1518                                sum=-1;
     1519                                break;
     1520                        }
     1521                }
     1522                if (sum > longest) {
     1523                        longest=sum;
     1524                        ret=0;
     1525                }
     1526                if (sum > 0 && sum == longest && ret < types_count)
     1527                        types[ret++]=curr->type;
     1528        }
     1529        return ret;
     1530}
     1531
     1532static void
     1533attr_longest_match_clear(void)
     1534{
     1535        memset(attr_present, 0, sizeof(*attr_present)*attr_present_count);
     1536}
     1537
    14861538void
    14871539osm_end_relation(struct maptool_osm *osm)
    14881540{
     1541        int count,itcount=0;
     1542        enum item_type types[10];
     1543        types[0] = type_none;
     1544
     1545        count=attr_longest_match(attr_mapping_way, attr_mapping_way_count, types, sizeof(types)/sizeof(enum item_type));
     1546        if(count>0) {
     1547                int ii;
     1548
     1549                struct attr attr;
     1550                attr.type = attr_item_types;
     1551                attr.u.item_types = NULL;
     1552
     1553                for(ii=0;ii<count;ii++) {
     1554                        if(item_type_is_area(types[ii])) {
     1555                                boundary = 1;
     1556                                attr.u.item_types = g_realloc(attr.u.item_types, (itcount+2)*sizeof(enum item_type));
     1557                                attr.u.item_types[itcount] = types[ii];
     1558                                attr.u.item_types[itcount+1] = type_none;
     1559                                ++itcount;
     1560                        }
     1561                }
     1562                if(itcount>0) {
     1563                        item_bin_add_attr(item_bin, &attr);
     1564                }
     1565        }
     1566        attr_longest_match_clear();
     1567
    14891568        in_relation=0;
    14901569        if ((!strcmp(relation_type, "multipolygon") || !strcmp(relation_type, "boundary")) && boundary) {
    14911570#if 0
     
    15541633        }
    15551634}
    15561635
    1557 
    1558 static int
    1559 attr_longest_match(struct attr_mapping **mapping, int mapping_count, enum item_type *types, int types_count)
    1560 {
    1561         int i,j,longest=0,ret=0,sum,val;
    1562         struct attr_mapping *curr;
    1563         for (i = 0 ; i < mapping_count ; i++) {
    1564                 sum=0;
    1565                 curr=mapping[i];
    1566                 for (j = 0 ; j < curr->attr_present_idx_count ; j++) {
    1567                         val=attr_present[curr->attr_present_idx[j]];
    1568                         if (val)
    1569                                 sum+=val;
    1570                         else {
    1571                                 sum=-1;
    1572                                 break;
    1573                         }
    1574                 }
    1575                 if (sum > longest) {
    1576                         longest=sum;
    1577                         ret=0;
    1578                 }
    1579                 if (sum > 0 && sum == longest && ret < types_count)
    1580                         types[ret++]=curr->type;
    1581         }
    1582         return ret;
    1583 }
    1584 
    1585 static void
    1586 attr_longest_match_clear(void)
    1587 {
    1588         memset(attr_present, 0, sizeof(*attr_present)*attr_present_count);
    1589 }
    1590 
    15911636void
    15921637osm_end_way(struct maptool_osm *osm)
    15931638{
     
    25632608        processed_nodes=processed_nodes_out=processed_ways=processed_relations=processed_tiles=0;
    25642609        sig_alrm(0);
    25652610        while ((ib=read_item(in))) {
     2611                int self_intersect;
    25662612#if 0
    25672613                fprintf(stderr,"type 0x%x len %d clen %d\n", ib->type, ib->len, ib->clen);
    25682614#endif
     
    25782624                                if (ni) {
    25792625                                        c[i]=ni->c;
    25802626                                        if (ni->ref_way > 1 && i != 0 && i != ccount-1 && i != last && item_get_default_flags(ib->type)) {
    2581                                                 write_item_part(out, out_index, out_graph, ib, last, i, &last_id);
     2627                                                if(!(0 != self_intersect_test(ib) && item_type_is_area(ib->type)))
     2628                                                        write_item_part(out, out_index, out_graph, ib, last, i, &last_id);
    25822629                                                last=i;
    25832630                                        }
    25842631                                } else if (final) {
     
    25932640                                }
    25942641                        }
    25952642                }
     2643                self_intersect = self_intersect_test(ib);
     2644                if(self_intersect!=0 && (ib->type == type_water_line || item_type_is_area(ib->type)) ) {
     2645                        osm_warning("way", item_bin_get_wayid(ib), 0, "Self intersecting area\n");
     2646                }
    25962647                if (ccount) {
    2597                         write_item_part(out, out_index, out_graph, ib, last, ccount-1, &last_id);
     2648                        if(!(0 != self_intersect && item_type_is_area(ib->type)))
     2649                                write_item_part(out, out_index, out_graph, ib, last, ccount-1, &last_id);
    25982650                        if (final && ib->type == type_water_line && out_coastline) {
    2599                                 write_item_part(out_coastline, NULL, NULL, ib, last, ccount-1, NULL);
     2651                                if(0 == self_intersect)
     2652                                        write_item_part(out_coastline, NULL, NULL, ib, last, ccount-1, NULL);
    26002653                        }
    26012654                }
    26022655        }
  • itembin_buffer.c

     
    2222#include "debug.h"
    2323
    2424
    25 static char buffer[800000];
     25static char buffer[8000000];
    2626struct item_bin *item_bin=(struct item_bin *)(void *)buffer;
     27static char buffer_relation_area[8000000];
     28struct item_bin *item_bin_relation_area=(struct item_bin *)(void *)buffer_relation_area;
    2729static struct node_item *node_item=(struct node_item *)(void *)buffer;
    2830
    2931struct node_item *
  • maptool.h

     
    121121struct boundary {
    122122        struct item_bin *ib;
    123123        struct country_table *country;
     124        enum item_type* area_item_types;
    124125        char *iso2;
    125126        GList *segments,*sorted_segments;
    126127        GList *children;
     
    187188GList *geom_poly_segments_sort(GList *in, enum geom_poly_segment_type type);
    188189struct geom_poly_segment *item_bin_to_poly_segment(struct item_bin *ib, int type);
    189190int geom_poly_segments_point_inside(GList *in, struct coord *c);
     191GList* geom_poly_segments_group(GList *in, GList *out);
    190192void clip_line(struct item_bin *ib, struct rect *r, struct tile_parameter *param, struct item_bin_sink *out);
    191193void clip_polygon(struct item_bin *ib, struct rect *r, struct tile_parameter *param, struct item_bin_sink *out);
     194int self_intersect_test(struct item_bin*ib);
    192195
    193196/* itembin.c */
    194197
     
    240243extern struct buffer node_buffer;
    241244extern int processed_nodes, processed_nodes_out, processed_ways, processed_relations, processed_tiles;
    242245extern struct item_bin *item_bin;
     246extern struct item_bin *item_bin_relation_area;
    243247extern int bytes_read;
    244248extern int overlap;
    245249extern int unknown_country;
  • geom.c

     
    357357        return ret;
    358358}
    359359
     360/*
     361 * create groups of segments by merging segments with common endpoint
     362 */
     363GList* geom_poly_segments_group(GList *in, GList *out)
     364{
     365        out = g_list_copy(in);
     366        //TODO check that there is no memleak
     367
     368        int changed;
     369        do {
     370                changed = 0;
     371                GList*l1 = out;
     372                while(l1) {
     373                        struct geom_poly_segment *l1_ = l1->data;
     374                        if(l1_->type!=geom_poly_segment_type_way_outer) {
     375                                GList*l1_d = l1;
     376                                l1 = g_list_next(l1);
     377                                if(!l1) {
     378                                        break;
     379                                }
     380                                l1_ = l1->data;
     381                                out = g_list_remove(out, l1_d);
     382                                continue;
     383                        }
     384                        GList*l2 = l1;
     385                        while(l2) {
     386                                struct geom_poly_segment *l2_ = l2->data;
     387                                if(l2_->type!=geom_poly_segment_type_way_outer) {
     388                                        GList*l2_d = l2;
     389                                        l2 = g_list_next(l2);
     390                                        if(!l2) {
     391                                                break;
     392                                        }
     393                                        l2_ = l2->data;
     394                                        out = g_list_remove(out, l2_d);
     395                                        continue;
     396                                }
     397                                if( l1!=l2 && l1_ && l2_ && l1_->first && l2_->last &&
     398                                        (coord_equal(l1_->first, l2_->first) || /* have_common_endpoints(l1,l2)*/
     399                                                coord_equal(l1_->first, l2_->last) ||
     400                                                coord_equal(l1_->last, l2_->first) ||
     401                                                coord_equal(l1_->last, l2_->last))              &&
     402                                        !coord_equal(l1_->first,l1_->last) && !coord_equal(l2_->first,l2_->last) /*do not group closed polys*/ ) {
     403                                        int reverse_1 = 0;
     404                                        int reverse_2 = 0;
     405                                        int order_12 = 1;
     406                                        //merge coords of (l1,l2) (append coords to the front or rear, perhaps reversed)
     407                                                //l1.front==l2.front
     408                                                        //l2 reversed ... l1 inorder
     409                                                if (coord_equal(l1_->first,l2_->first)) {
     410                                                        reverse_1 = 0;
     411                                                        reverse_2 = 1;
     412                                                        order_12  = 0;
     413                                                }
     414                                                //l1.rear==l2.front
     415                                                        //l1 inorder ... l2 inorder
     416                                                else if (coord_equal(l1_->last,l2_->first)) {
     417                                                        reverse_1 = 0;
     418                                                        reverse_2 = 0;
     419                                                        order_12  = 1;
     420                                                }
     421                                                //l1.front==l2.rear
     422                                                        //l2 inorder ... l1 inorder
     423                                                else if (coord_equal(l1_->first,l2_->last)) {
     424                                                        reverse_1 = 0;
     425                                                        reverse_2 = 0;
     426                                                        order_12  = 0;
     427                                                }
     428                                                                //l1.rear==l2.rear
     429                                                        //l1 inorder ... l2 reversed
     430                                                else if (coord_equal(l1_->last,l2_->last)) {
     431                                                        reverse_1 = 0;
     432                                                        reverse_2 = 1;
     433                                                        order_12  = 1;
     434                                                }
     435                                        //reverse l1 or l2 if necessary
     436                                        int size_1 = (l1_->last-l1_->first)+1;
     437                                        int size_2 = (l2_->last-l2_->first)+1;
     438                                        if (reverse_1) {
     439                                                int ii;
     440                                                for (ii=0;ii<size_1/2;++ii) {
     441                                                        struct coord tmp = l1_->first[ii];
     442                                                        l1_->first[ii] = l1_->first[size_1-ii-1];
     443                                                        l1_->first[size_1-ii-1] = tmp;
     444                                                }
     445                                        }
     446                                        if (reverse_2) {
     447                                                int ii;
     448                                                for (ii=0;ii<size_2/2;++ii) {
     449                                                        struct coord tmp = l2_->first[ii];
     450                                                        l2_->first[ii] = l2_->first[size_2-ii-1];
     451                                                        l2_->first[size_2-ii-1] = tmp;
     452                                                }
     453                                        }
     454                                        //append l1 to l2 or l2 to l1 appropriately (with the common point added only once)
     455                                        if(order_12 && size_2>1) {
     456                                                l1_->first = g_realloc(l1_->first,sizeof(struct coord)*(size_1+size_2)-1);
     457                                                memcpy(l1_->first+size_1,l2_->first,(size_2-1)*sizeof(struct coord));
     458                                                l1_->last += size_2-1;
     459                                        } else if( !order_12 && size_1>1) {
     460                                                l2_->first = g_realloc(l2_->first,sizeof(struct coord)*(size_1+size_2-1));
     461                                                memcpy(l2_->first+size_2,l1_->first,(size_1-1)*sizeof(struct coord));
     462                                                l2_->last = size_1-1;
     463                                        }
     464                                        //remove l1 or l2 appropriately
     465                                        if (order_12) {
     466                                                out = g_list_remove(out, l2);
     467                                        } else {
     468                                                out = g_list_remove(out, l1);
     469                                        }
     470                                        changed=1;
     471                                }
     472                                l2 = g_list_next(l2);
     473                        }
     474                        l1 = g_list_next(l1);
     475                }
     476        } while(changed);
     477return out;
     478}
     479
     480
    360481int
    361482geom_poly_segments_point_inside(GList *in, struct coord *c)
    362483{
     
    620741                item_bin_write_clipped(ib_in, param, out);
    621742        }
    622743}
     744
     745
     746
     747
     748static int coord_dot_prod (struct coord* c1, struct coord* c2)
     749{
     750        return c1->x*c2->x + c1->y*c2->y;
     751}
     752
     753
     754static void coord_sub (struct coord* c1, struct coord* c2, struct coord* cout)
     755{
     756        cout->x = c1->x - c2->x;
     757        cout->y = c1->y - c2->y;
     758}
     759
     760int self_intersect_test(struct item_bin*ib)
     761{
     762        int vertices_count = ib->clen/2;
     763        if(vertices_count<4) {
     764                return 0;
     765        }
     766        struct coord*vertices = (struct coord*)(ib+1);
     767        int i;
     768        for (i = 0; i < vertices_count; ++i) {
     769                if (i < vertices_count - 1) {
     770                    int h;
     771                    for (h = i + 1; h < vertices_count; ++h)
     772                    {
     773                        // Do two vertices lie on top of one another?
     774                        if ( i!=0 && h-i!=1 && h-i!=-1 && vertices[i].x == vertices[h].x && vertices[i].y == vertices[h].y ) {
     775                            return 1;
     776                        }
     777                    }
     778                }
     779
     780                int j = (i + 1) % vertices_count;
     781                struct coord iToj;
     782                coord_sub(&vertices[j], &vertices[i], &iToj);
     783                struct coord iTojNormal;
     784                iTojNormal.x =  iToj.y;
     785                iTojNormal.y = -iToj.x;
     786                // i is the first vertex and j is the second
     787                int startK = (j + 1) % vertices_count;
     788                int endK = (i - 1 + vertices_count) % vertices_count;
     789                endK += startK < endK ? 0 : startK + 1;
     790                int k = startK;
     791                struct coord iTok;
     792                coord_sub(&vertices[k], &vertices[i], &iTok);
     793                int onLeftSide = coord_dot_prod(&iTok, &iTojNormal) >= 0;
     794                struct coord prevK = vertices[k];
     795                ++k;
     796                for (; k <= endK; ++k)
     797                {
     798                    int modK = k % vertices_count;
     799                    coord_sub(&vertices[modK], &vertices[i], &iTok);
     800                    if (onLeftSide != coord_dot_prod(&iTok, &iTojNormal) >= 0)
     801                    {
     802                        struct coord prevKtoK, idiff, jdiff;
     803                        coord_sub(&vertices[modK], &prevK, &prevKtoK);
     804                        struct coord prevKtoKNormal;
     805                        prevKtoKNormal.x = prevKtoK.y;
     806                        prevKtoKNormal.y = -prevKtoK.x;
     807                        coord_sub(&vertices[i],&prevK,&idiff);
     808                        coord_sub(&vertices[j],&prevK,&jdiff);
     809                        if ((coord_dot_prod(&idiff, &prevKtoKNormal) >= 0) != (coord_dot_prod(&jdiff, &prevKtoKNormal) >= 0))
     810                        {
     811                            if(i!=j-1 && i!=j+1) {
     812                               return 1;
     813                            }
     814                        }
     815                    }
     816                    onLeftSide = coord_dot_prod(&iTok, &iTojNormal) > 0;
     817                    prevK = vertices[modK];
     818                }
     819            }
     820            return 0;
     821}
     822
     823
  • boundaries.c

     
    7070        while ((ib=read_item(boundaries))) {
    7171                char *member=NULL;
    7272                struct boundary *boundary=g_new0(struct boundary, 1);
     73                boundary->area_item_types = NULL;
     74                enum item_type* p_item_type;
     75                if(p_item_type = item_bin_get_attr(ib,attr_item_types,NULL)) {
     76                        int i=0;
     77                        do {
     78                                boundary->area_item_types = g_realloc(boundary->area_item_types, (i+1)*sizeof(enum item_type));
     79                                boundary->area_item_types[i] = *p_item_type;
     80                                i++;
     81                        } while(*p_item_type++!=type_none);
     82                }
    7383                char *admin_level=osm_tag_value(ib, "admin_level");
    7484                char *iso=osm_tag_value(ib, "ISO3166-1");
    7585                /* disable spain for now since it creates a too large index */
     
    202212        while (l) {
    203213                struct boundary *boundary=l->data;
    204214                int first=1;
    205                 FILE *f=NULL,*fu=NULL;
     215                FILE *f=NULL,*fu=NULL,*ways_split=NULL;
    206216                if (boundary->country) {
    207217                        char *name=g_strdup_printf("country_%s_poly",boundary->iso2);
    208218                        f=tempfile("",name,1);
    209219                        g_free(name);
    210220                }
     221                int to_write = 0;
     222                if (boundary->area_item_types) {
     223                        ways_split=tempfile("","ways_split",2);
     224                        struct item_bin *ib=item_bin_relation_area;
     225                        item_bin_init(ib, boundary->area_item_types[0]);
     226                }
    211227                boundary->sorted_segments=geom_poly_segments_sort(boundary->segments, geom_poly_segment_type_way_right_side);
    212228                sl=boundary->sorted_segments;
    213229                while (sl) {
     
    228244                                item_bin_add_coord(ib, gs->first, gs->last-gs->first+1);
    229245                                item_bin_write(ib, f);
    230246                        }
     247                        if (ways_split && gs->type==geom_poly_segment_type_way_outer) {
     248                                struct item_bin *ib=item_bin_relation_area;
     249                                item_bin_add_coord(ib, gs->first, gs->last-gs->first+1);
     250                                to_write = 1;
     251                        }
    231252                        if (boundary->country) {
    232253                                if (!coord_is_equal(*gs->first,*gs->last)) {
    233254                                        if (!fu) {
     
    246267                        }
    247268                        sl=g_list_next(sl);
    248269                }       
     270
     271
     272                if (ways_split && to_write ) {
     273                        struct item_bin *ib=item_bin_relation_area;
     274                        if(0 == self_intersect_test(ib)) {
     275                                int i=0;
     276                                do {
     277                                        ib->type= boundary->area_item_types[i++];
     278                                        item_bin_write(ib, ways_split);
     279                                } while(boundary->area_item_types[i]!=type_none);
     280                        } else {
     281                                //TODO is segments are disjunct polygons, group outer segments and write items for them
     282                                GList*grouped_segments =
     283                                        geom_poly_segments_group(boundary->sorted_segments, grouped_segments);
     284                                GList *l = grouped_segments;
     285                                int self_intersected_grouped = 0;
     286                                while (l) {
     287                                        struct geom_poly_segment *gs=l->data;
     288                                        //create item_bin-s for the current segment
     289                                        int i=0;
     290                                        struct item_bin *ib=item_bin_relation_area;
     291                                        //TODO if segment type is outer
     292                                        item_bin_init(ib,boundary->area_item_types[0]);
     293                                        item_bin_add_coord(ib, gs->first, gs->last-gs->first+1);
     294                                        if( 0!=self_intersect_test(ib)) {
     295                                                self_intersected_grouped = 1;
     296                                        } else {
     297                                                do {
     298                                                        ib->type= boundary->area_item_types[i++];
     299                                                        item_bin_write(ib, ways_split);
     300                                                } while(boundary->area_item_types[i]!=type_none);
     301                                        }
     302                                        l=g_list_next(l);
     303                                }
     304
     305                                //TODO if there is also self intersecting poly in the disjuct set
     306                                if(self_intersected_grouped) {
     307                                        osm_warning("relation",item_bin_get_relationid(boundary->ib),0,"Self intersecting relation area\n");
     308                                }
     309#if 0
     310                                struct coord*crd = (struct coord*)(ib+1);
     311                                int ii;
     312                                for(ii=0;ii<ib->clen/2;++ii) {
     313                                        printf("CRD:%d %d\n",crd->x,crd->y);
     314                                        crd++;
     315                                }
     316#endif
     317                        }
     318                        item_bin_init(ib, type_poly_water);
     319#if 0
     320                        printf("CRD:\n");
     321#endif
     322                }
     323
    249324                ret=process_boundaries_insert(ret, boundary);
    250325                l=g_list_next(l);
    251326                if (f)
    252327                        fclose(f);
     328                if (ways_split)
     329                        fclose(ways_split);
    253330                if (fu) {
    254331                        if (boundary->country)
    255332                                osm_warning("relation",item_bin_get_relationid(boundary->ib),0,"Broken country polygon '%s'\n",boundary->iso2);
    256333                        fclose(fu);
    257334                }
    258                
     335        g_free(boundary->area_item_types);
    259336        }
    260337#if 0
    261338        printf("hierarchy\n");