/** We calculate the effective area for the first time */ void ptarray_calc_areas(EFFECTIVE_AREAS *ea, int avoid_collaps, int set_area, double trshld) { LWDEBUG(2, "Entered ptarray_calc_areas"); int i; int npoints=ea->inpts->npoints; int is3d = FLAGS_GET_Z(ea->inpts->flags); double area; const double *P1; const double *P2; const double *P3; P1 = (double*)getPoint_internal(ea->inpts, 0); P2 = (double*)getPoint_internal(ea->inpts, 1); /*The first and last point shall always have the maximum effective area. We use float max to not make trouble for bbox*/ ea->initial_arealist[0].area=ea->initial_arealist[npoints-1].area=FLT_MAX; ea->res_arealist[0]=ea->res_arealist[npoints-1]=FLT_MAX; ea->initial_arealist[0].next=1; ea->initial_arealist[0].prev=0; for (i=1;i<(npoints)-1;i++) { ea->initial_arealist[i].next=i+1; ea->initial_arealist[i].prev=i-1; P3 = (double*)getPoint_internal(ea->inpts, i+1); if(is3d) area=triarea3d(P1, P2, P3); else area=triarea2d(P1, P2, P3); LWDEBUGF(4,"Write area %lf to point %d on address %p",area,i,&(ea->initial_arealist[i].area)); ea->initial_arealist[i].area=area; P1=P2; P2=P3; } ea->initial_arealist[npoints-1].next=npoints-1; ea->initial_arealist[npoints-1].prev=npoints-2; for (i=1;i<(npoints)-1;i++) { ea->res_arealist[i]=FLT_MAX; } tune_areas(ea,avoid_collaps,set_area, trshld); return ; }
/** * We calculate the effective area for the first time */ void ptarray_calc_areas( EFFECTIVE_AREAS *ea, int avoid_collaps, int set_area, double trshld ) { //LWDEBUG( 2, "Entered ptarray_calc_areas" ); int i; int npoints = ea->inpts.size(); double area; QgsPointV2 P1; QgsPointV2 P2; QgsPointV2 P3; P1 = ea->inpts.at( 0 ); P2 = ea->inpts.at( 1 ); // The first and last point shall always have the maximum effective area. We use float max to not make trouble for bbox ea->initial_arealist[0].area = ea->initial_arealist[npoints - 1].area = FLT_MAX; ea->res_arealist[0] = ea->res_arealist[npoints - 1] = FLT_MAX; ea->initial_arealist[0].next = 1; ea->initial_arealist[0].prev = 0; for ( i = 1; i < ( npoints ) - 1; i++ ) { ea->initial_arealist[i].next = i + 1; ea->initial_arealist[i].prev = i - 1; P3 = ea->inpts.at( i + 1 ); if ( ea->is3d ) area = triarea3d( P1, P2, P3 ); else area = triarea2d( P1, P2, P3 ); //LWDEBUGF( 4, "Write area %lf to point %d on address %p", area, i, &( ea->initial_arealist[i].area ) ); ea->initial_arealist[i].area = area; P1 = P2; P2 = P3; } ea->initial_arealist[npoints - 1].next = npoints - 1; ea->initial_arealist[npoints - 1].prev = npoints - 2; for ( i = 1; i < ( npoints ) - 1; i++ ) { ea->res_arealist[i] = FLT_MAX; } tune_areas( ea, avoid_collaps, set_area, trshld ); }
/** To get the effective area, we have to check what area a point results in when all smaller areas are eliminated */ static void tune_areas(EFFECTIVE_AREAS *ea, int avoid_collaps, int set_area, double trshld) { LWDEBUG(2, "Entered tune_areas"); const double *P1; const double *P2; const double *P3; double area; int go_on=1; double check_order_min_area = 0; int npoints=ea->inpts->npoints; int i; int current, before_current, after_current; MINHEAP tree = initiate_minheap(npoints); int is3d = FLAGS_GET_Z(ea->inpts->flags); /*Add all keys (index in initial_arealist) into minheap array*/ for (i=0;i<npoints;i++) { tree.key_array[i]=ea->initial_arealist+i; LWDEBUGF(2, "add nr %d, with area %lf, and %lf",i,ea->initial_arealist[i].area, tree.key_array[i]->area ); } tree.usedSize=npoints; /*order the keys by area, small to big*/ qsort(tree.key_array, npoints, sizeof(void*), cmpfunc); /*We have to put references to our tree in our point-list*/ for (i=0;i<npoints;i++) { ((areanode*) tree.key_array[i])->treeindex=i; LWDEBUGF(4,"Check ordering qsort gives, area=%lf and belong to point %d",((areanode*) tree.key_array[i])->area, tree.key_array[i]-ea->initial_arealist); } /*Ok, now we have a minHeap, just need to keep it*/ /*for (i=0;i<npoints-1;i++)*/ i=0; while (go_on) { /*Get a reference to the point with the currently smallest effective area*/ current=minheap_pop(&tree, ea->initial_arealist)-ea->initial_arealist; /*We have found the smallest area. That is the resulting effective area for the "current" point*/ if (i<npoints-avoid_collaps) ea->res_arealist[current]=ea->initial_arealist[current].area; else ea->res_arealist[current]=FLT_MAX; if(ea->res_arealist[current]<check_order_min_area) lwerror("Oh no, this is a bug. For some reason the minHeap returned our points in the wrong order. Please file a ticket in PostGIS ticket system, or send a mial at the mailing list.Returned area = %lf, and last area = %lf",ea->res_arealist[current],check_order_min_area); check_order_min_area=ea->res_arealist[current]; /*The found smallest area point is now regarded as elimnated and we have to recalculate the area the adjacent (ignoring earlier elimnated points) points gives*/ /*FInd point before and after*/ before_current=ea->initial_arealist[current].prev; after_current=ea->initial_arealist[current].next; P2= (double*)getPoint_internal(ea->inpts, before_current); P3= (double*)getPoint_internal(ea->inpts, after_current); /*Check if point before current point is the first in the point array. */ if(before_current>0) { P1= (double*)getPoint_internal(ea->inpts, ea->initial_arealist[before_current].prev); if(is3d) area=triarea3d(P1, P2, P3); else area=triarea2d(P1, P2, P3); ea->initial_arealist[before_current].area = FP_MAX(area,ea->res_arealist[current]); minheap_update(&tree, ea->initial_arealist, ea->initial_arealist[before_current].treeindex); } if(after_current<npoints-1)/*Check if point after current point is the last in the point array. */ { P1=P2; P2=P3; P3= (double*)getPoint_internal(ea->inpts, ea->initial_arealist[after_current].next); if(is3d) area=triarea3d(P1, P2, P3); else area=triarea2d(P1, P2, P3); ea->initial_arealist[after_current].area = FP_MAX(area,ea->res_arealist[current]); minheap_update(&tree, ea->initial_arealist, ea->initial_arealist[after_current].treeindex); } /*rearrange the nodes so the eliminated point will be ingored on the next run*/ ea->initial_arealist[before_current].next = ea->initial_arealist[current].next; ea->initial_arealist[after_current].prev = ea->initial_arealist[current].prev; /*Check if we are finnished*/ if((!set_area && ea->res_arealist[current]>trshld) || (ea->initial_arealist[0].next==(npoints-1))) go_on=0; i++; }; destroy_minheap(tree); return; }