static void visit_coords(map_t *m,int startX, int startY, int x, int y, int dx, int dy, TCOD_list_t active_views, bool light_walls) { // top left int tlx=x, tly=y+STEP_SIZE; // bottom right int brx=x+STEP_SIZE, bry=y; view_t *view=NULL; while (current_view != (view_t **)TCOD_list_end(active_views)) { view=*current_view; if ( ! BELOW_OR_COLINEAR(&view->steep_line,brx,bry) ) { break; } current_view++; } if ( current_view == (view_t **)TCOD_list_end(active_views) || ABOVE_OR_COLINEAR(&view->shallow_line,tlx,tly)) { // no more active view return; } if ( !is_blocked(m,view,startX,startY,x,y,dx,dy,light_walls) ) return; if ( ABOVE(&view->shallow_line,brx,bry) && BELOW(&view->steep_line,tlx,tly)) { // view blocked // slow ! TCOD_list_remove_iterator(active_views,(void **)current_view); } else if ( ABOVE(&view->shallow_line,brx,bry)) { // shallow bump add_shallow_bump(tlx,tly,view); check_view(active_views,current_view); } else if (BELOW(&view->steep_line,tlx,tly)) { // steep bump add_steep_bump(brx,bry,view); check_view(active_views,current_view); } else { // view splitted int offset=startX+x*dx/STEP_SIZE + (startY+y*dy/STEP_SIZE)*m->width; view_t *shallower_view= & views[offset]; int view_index=current_view - (view_t **)TCOD_list_begin(active_views); view_t **shallower_view_it; view_t **steeper_view_it; *shallower_view=**current_view; // slow ! shallower_view_it = (view_t **)TCOD_list_insert_before(active_views,shallower_view,view_index); steeper_view_it=shallower_view_it+1; current_view=shallower_view_it; add_steep_bump(brx,bry,shallower_view); if (!check_view(active_views,shallower_view_it)) steeper_view_it--; add_shallow_bump(tlx,tly,*steeper_view_it); check_view(active_views,steeper_view_it); if ( view_index > TCOD_list_size(active_views)) current_view=(view_t **)TCOD_list_end(active_views); } }
static bool is_blocked(map_t *map, view_t *view, int startX, int startY, int x, int y, int dx, int dy, bool light_walls) { int posx=x*dx/STEP_SIZE+startX; int posy=y*dy/STEP_SIZE+startY; int offset=posx + (posy)*map->width; bool blocked=!map->cells[offset].transparent; int tlx,tly,brx,bry; if ( blocked ) { tlx=x; tly=y+STEP_SIZE; brx=x+STEP_SIZE; bry=y; } else { tlx=x+offset; tly=y+limit; brx=x+limit; bry=y+offset; } if ( light_walls || ( ABOVE(&view->steep_line,brx,bry) && BELOW(&view->shallow_line,tlx,tly) ) // ! blocked ) { map->cells[offset].fov=1; } return blocked; }
static void add_shallow_bump(int x, int y, view_t *view) { viewbump_t *shallow, *curbump; view->shallow_line.xf=x; view->shallow_line.yf=y; shallow= &bumps[bumpidx++]; shallow->x=x; shallow->y=y; shallow->parent=view->shallow_bump; view->shallow_bump=shallow; curbump=view->steep_bump; while ( curbump ) { if ( ABOVE(&view->shallow_line,curbump->x,curbump->y)) { view->shallow_line.xi=curbump->x; view->shallow_line.yi=curbump->y; } curbump=curbump->parent; } }
Datum geography_gist_picksplit(PG_FUNCTION_ARGS) { GistEntryVector *entryvec = (GistEntryVector*) PG_GETARG_POINTER(0); GIST_SPLITVEC *v = (GIST_SPLITVEC*) PG_GETARG_POINTER(1); OffsetNumber i; /* One union box for each half of the space. */ GIDX **box_union; /* One offset number list for each half of the space. */ OffsetNumber **list; /* One position index for each half of the space. */ int *pos; GIDX *box_pageunion; GIDX *box_current; int direction = -1; bool all_entries_equal = true; OffsetNumber max_offset; int nbytes, ndims_pageunion, d; int posmax = -1; POSTGIS_DEBUG(4, "[GIST] 'picksplit' function called"); /* ** First calculate the bounding box and maximum number of dimensions in this page. */ max_offset = entryvec->n - 1; box_current = (GIDX*) DatumGetPointer(entryvec->vector[FirstOffsetNumber].key); box_pageunion = gidx_copy(box_current); /* Calculate the containing box (box_pageunion) for the whole page we are going to split. */ for ( i = OffsetNumberNext(FirstOffsetNumber); i <= max_offset; i = OffsetNumberNext(i) ) { box_current = (GIDX*) DatumGetPointer(entryvec->vector[i].key); if ( all_entries_equal == true && ! gidx_equals (box_pageunion, box_current) ) all_entries_equal = false; gidx_merge( &box_pageunion, box_current ); } POSTGIS_DEBUGF(3, "[GIST] box_pageunion: %s", gidx_to_string(box_pageunion)); /* Every box in the page is the same! So, we split and just put half the boxes in each child. */ if ( all_entries_equal ) { POSTGIS_DEBUG(4, "[GIST] picksplit finds all entries equal!"); geography_gist_picksplit_fallback(entryvec, v); PG_RETURN_POINTER(v); } /* Initialize memory structures. */ nbytes = (max_offset + 2) * sizeof(OffsetNumber); ndims_pageunion = GIDX_NDIMS(box_pageunion); POSTGIS_DEBUGF(4, "[GIST] ndims_pageunion == %d", ndims_pageunion); pos = palloc(2*ndims_pageunion * sizeof(int)); list = palloc(2*ndims_pageunion * sizeof(OffsetNumber*)); box_union = palloc(2*ndims_pageunion * sizeof(GIDX*)); for ( d = 0; d < ndims_pageunion; d++ ) { list[BELOW(d)] = (OffsetNumber*) palloc(nbytes); list[ABOVE(d)] = (OffsetNumber*) palloc(nbytes); box_union[BELOW(d)] = gidx_new(ndims_pageunion); box_union[ABOVE(d)] = gidx_new(ndims_pageunion); pos[BELOW(d)] = 0; pos[ABOVE(d)] = 0; } /* ** Assign each entry in the node to the volume partitions it belongs to, ** such as "above the x/y plane, left of the y/z plane, below the x/z plane". ** Each entry thereby ends up in three of the six partitions. */ POSTGIS_DEBUG(4, "[GIST] 'picksplit' calculating best split axis"); for ( i = FirstOffsetNumber; i <= max_offset; i = OffsetNumberNext(i) ) { box_current = (GIDX*) DatumGetPointer(entryvec->vector[i].key); for ( d = 0; d < ndims_pageunion; d++ ) { if ( GIDX_GET_MIN(box_current,d)-GIDX_GET_MIN(box_pageunion,d) < GIDX_GET_MAX(box_pageunion,d)-GIDX_GET_MAX(box_current,d) ) { geography_gist_picksplit_addlist(list[BELOW(d)], &(box_union[BELOW(d)]), box_current, &(pos[BELOW(d)]), i); } else { geography_gist_picksplit_addlist(list[ABOVE(d)], &(box_union[ABOVE(d)]), box_current, &(pos[ABOVE(d)]), i); } } } /* ** "Bad disposition", too many entries fell into one octant of the space, so no matter which ** plane we choose to split on, we're going to end up with a mostly full node. Where the ** data is pretty homogeneous (lots of duplicates) entries that are equidistant from the ** sides of the page union box can occasionally all end up in one place, leading ** to this condition. */ if ( geography_gist_picksplit_badratios(pos,ndims_pageunion) == TRUE ) { /* ** Instead we split on center points and see if we do better. ** First calculate the average center point for each axis. */ double *avgCenter = palloc(ndims_pageunion * sizeof(double)); for ( d = 0; d < ndims_pageunion; d++ ) { avgCenter[d] = 0.0; } POSTGIS_DEBUG(4, "[GIST] picksplit can't find good split axis, trying center point method"); for ( i = FirstOffsetNumber; i <= max_offset; i = OffsetNumberNext(i) ) { box_current = (GIDX*) DatumGetPointer(entryvec->vector[i].key); for ( d = 0; d < ndims_pageunion; d++ ) { avgCenter[d] += (GIDX_GET_MAX(box_current,d) + GIDX_GET_MIN(box_current,d)) / 2.0; } } for ( d = 0; d < ndims_pageunion; d++ ) { avgCenter[d] /= max_offset; pos[BELOW(d)] = pos[ABOVE(d)] = 0; /* Re-initialize our counters. */ POSTGIS_DEBUGF(4, "[GIST] picksplit average center point[%d] = %.12g", d, avgCenter[d]); } /* For each of our entries... */ for ( i = FirstOffsetNumber; i <= max_offset; i = OffsetNumberNext(i) ) { double center; box_current = (GIDX*) DatumGetPointer(entryvec->vector[i].key); for ( d = 0; d < ndims_pageunion; d++ ) { center = (GIDX_GET_MIN(box_current,d)+GIDX_GET_MAX(box_current,d))/2.0; if ( center < avgCenter[d] ) geography_gist_picksplit_addlist(list[BELOW(d)], &(box_union[BELOW(d)]), box_current, &(pos[BELOW(d)]), i); else if ( FPeq(center, avgCenter[d]) ) if ( pos[BELOW(d)] > pos[ABOVE(d)] ) geography_gist_picksplit_addlist(list[ABOVE(d)], &(box_union[ABOVE(d)]), box_current, &(pos[ABOVE(d)]), i); else geography_gist_picksplit_addlist(list[BELOW(d)], &(box_union[BELOW(d)]), box_current, &(pos[BELOW(d)]), i); else geography_gist_picksplit_addlist(list[ABOVE(d)], &(box_union[ABOVE(d)]), box_current, &(pos[ABOVE(d)]), i); } } /* Do we have a good disposition now? If not, screw it, just cut the node in half. */ if ( geography_gist_picksplit_badratios(pos,ndims_pageunion) == TRUE ) { POSTGIS_DEBUG(4, "[GIST] picksplit still cannot find a good split! just cutting the node in half"); geography_gist_picksplit_fallback(entryvec, v); PG_RETURN_POINTER(v); } } /* ** Now, what splitting plane gives us the most even ratio of ** entries in our child pages? Since each split region has been apportioned entries ** against the same number of total entries, the axis that has the smallest maximum ** number of entries in its regions is the most evenly distributed. ** TODO: what if the distributions are equal in two or more axes? */ for ( d = 0; d < ndims_pageunion; d++ ) { int posd = Max(pos[ABOVE(d)],pos[BELOW(d)]); if ( posd > posmax ) { direction = d; posmax = posd; } } if ( direction == -1 || posmax == -1 ) { /* ERROR OUT HERE */ elog(ERROR, "Error in building split, unable to determine split direction."); } POSTGIS_DEBUGF(3, "[GIST] 'picksplit' splitting on axis %d", direction); geography_gist_picksplit_constructsplit(v, list[BELOW(direction)], pos[BELOW(direction)], &(box_union[BELOW(direction)]), list[ABOVE(direction)], pos[ABOVE(direction)], &(box_union[ABOVE(direction)]) ); POSTGIS_DEBUGF(4, "[GIST] spl_ldatum: %s", gidx_to_string((GIDX*)v->spl_ldatum)); POSTGIS_DEBUGF(4, "[GIST] spl_rdatum: %s", gidx_to_string((GIDX*)v->spl_rdatum)); POSTGIS_DEBUGF(4, "[GIST] axis %d: parent range (%.12g, %.12g) left range (%.12g, %.12g), right range (%.12g, %.12g)", direction, GIDX_GET_MIN(box_pageunion, direction), GIDX_GET_MAX(box_pageunion, direction), GIDX_GET_MIN((GIDX*)v->spl_ldatum, direction), GIDX_GET_MAX((GIDX*)v->spl_ldatum, direction), GIDX_GET_MIN((GIDX*)v->spl_rdatum, direction), GIDX_GET_MAX((GIDX*)v->spl_rdatum, direction) ); PG_RETURN_POINTER(v); }
/* +-----------------------------------------------------------+ * @desc FIXME +-----------------------------------------------------------+ */ static void visit_coords(RLFL_map_t *m,int startX, int startY, int x, int y, int dx, int dy, RLFL_list_t active_views, bool light_walls) { // top left int tlx = x, tly = (y+1); // bottom right int brx = (x+1), bry = y; int realX = (x*dx), realY = (y*dy); int offset; view_t *view = NULL; while (current_view != (view_t **)RLFL_list_end(active_views)) { view = *current_view; if ( !BELOW_OR_COLINEAR(&view->steep_line, brx, bry) ) { break; } current_view++; } if(current_view == (view_t **)RLFL_list_end(active_views) || ABOVE_OR_COLINEAR(&view->shallow_line, tlx, tly)) { return; } offset = (startX + realX + ((startY+realY) * m->width)); if (light_walls || RLFL_has_flag(m->mnum, startX+realX, startY+realY, CELL_OPEN)) { RLFL_set_flag(m->mnum, startX+realX, startY+realY, CELL_FOV); } if (RLFL_has_flag(m->mnum, startX+realX, startY+realY, CELL_OPEN)) return; if ( ABOVE(&view->shallow_line, brx, bry) && BELOW(&view->steep_line, tlx, tly)) { // slow ! RLFL_list_remove_iterator(active_views, (void **)current_view); } else if( ABOVE(&view->shallow_line, brx, bry)) { add_shallow_bump(tlx, tly, view); check_view(active_views, current_view); } else if(BELOW(&view->steep_line, tlx, tly)) { add_steep_bump(brx,bry,view); check_view(active_views,current_view); } else { view_t *shallower_view = &views[offset]; int view_index = (current_view - (view_t **)RLFL_list_begin(active_views)); view_t **shallower_view_it; view_t **steeper_view_it; *shallower_view = **current_view; // slow ! shallower_view_it = (view_t **)RLFL_list_insert(active_views, shallower_view, view_index); steeper_view_it = shallower_view_it+1; current_view = shallower_view_it; add_steep_bump(brx, bry, shallower_view); if (!check_view(active_views,shallower_view_it)) { steeper_view_it--; } add_shallow_bump(tlx, tly, *steeper_view_it); check_view(active_views, steeper_view_it); if ( view_index > RLFL_list_size(active_views)) { current_view = (view_t **)RLFL_list_end(active_views); } } }