static int map_id;
-//prototype
+/*prototypes*/
static int
csv_coord_set(void *priv_data, struct coord *c, int count, enum change_mode mode);
static struct item * csv_create_item(struct map_rect_priv *mr, enum item_type it_type);
dbg(0, "Error opening csv file to write new entries");
return;
}
- //query the world
+ /*query the world*/
iter=quadtree_query(m->tree_root, -180, 180, -180, 180, quadtree_item_free, m);
while((qitem = quadtree_item_next(iter))!=NULL) {
GList* attr_list = ((struct quadtree_data*)(qitem->data))->attr_list;
GList* attr_it = attr_list;
struct attr* found_attr = NULL;
- //search attributes
+ /*search attributes*/
while(attr_it) {
if(((struct attr*)(attr_it->data))->type == *at) {
found_attr = attr_it->data;
map_destroy_csv(struct map_priv *m)
{
dbg(1,"map_destroy_csv\n");
- //save if changed
+ /*save if changed */
save_map_csv(m);
- //g_hash_table_destroy(m->item_hash);
g_hash_table_destroy(m->qitem_hash);
quadtree_destroy(m->tree_root);
g_free(m->filename);
static void
csv_attr_rewind(void *priv_data)
{
-// struct map_rect_priv *mr=priv_data;
- //TODO implement if needed
+ /*TODO implement if needed*/
}
static int
attr_list = ((struct quadtree_data*)(mr->qitem->data))->attr_list;
if (attr_type == attr_any) {
- if (mr->at_iter==NULL) { //start iteration
+ if (mr->at_iter==NULL) { /*start iteration*/
mr->at_iter = attr_list;
if (mr->at_iter) {
*attr = *(struct attr*)(mr->at_iter->data);
- //mr->at_iter = g_list_next(mr->at_iter);
return 1;
- } else { //empty attr list
+ } else { /*empty attr list*/
mr->at_iter = NULL;
return 0;
}
- } else { //continue iteration
+ } else { /*continue iteration*/
mr->at_iter = g_list_next(mr->at_iter);
if(mr->at_iter) {
*attr = *(struct attr*)mr->at_iter->data;
return 0;
}
- //if attribute is not supported by this csv map return 0
+ /*if attribute is not supported by this csv map return 0*/
for(i=0;i<m->attr_cnt;++i) {
if(*at==attr->type) {
bFound = 1;
if(new_it) {
qi->longitude = cg.lng;
qi->latitude = cg.lat;
- quadtree_add( m->tree_root, qi);
+ quadtree_add( m->tree_root, qi, mr->qiter);
dbg(1,"Set coordinates %f %f\n", cg.lng, cg.lat);
m->new_items = g_list_remove_link(m->new_items,new_it);
m->dirty=1;
insert_item->data=quadtree_data_dup(query_res->data);
insert_item->longitude = cg.lng;
insert_item->latitude = cg.lat;
- quadtree_add(m->tree_root, query_res);
+ quadtree_add(m->tree_root, query_res, mr->qiter);
mr->qitem->ref_count--;
mr->qitem=insert_item;
g_free(data);
}
+static void map_csv_debug_dump(struct map_priv *map)
+{
+ GList *l=g_hash_table_get_values(map->qitem_hash);
+ GList *ll=l;
+ while(ll) {
+ struct quadtree_item *qi;
+ GList *attrs;
+ qi=ll->data;
+ dbg(0,"%p del=%d ref=%d\n", qi,qi->deleted, qi->ref_count);
+ attrs=((struct quadtree_data *)qi->data)->attr_list;
+ while(attrs) {
+ if(((struct attr*)attrs->data)->type==attr_label)
+ dbg(0,"... %s\n",((struct attr*)attrs->data)->u.str);
+ attrs=g_list_next(attrs);
+ }
+ ll=g_list_next(ll);
+ }
+ g_list_free(l);
+}
static struct map_rect_priv *
map_rect_new_csv(struct map_priv *map, struct map_selection *sel)
struct coord_geo lu;
struct coord_geo rl;
struct quadtree_iter *res = NULL;
-
dbg(1,"map_rect_new_csv\n");
+
+#if 0
+ /* Set above value to 1 to have all map data dumped (including deleted items) to the log at each maprect creation */
+ map_csv_debug_dump(map);
+#endif
+
mr=g_new0(struct map_rect_priv, 1);
mr->m=map;
mr->bStarted = 0;
static struct item *
map_rect_get_item_byid_csv(struct map_rect_priv *mr, int id_hi, int id_lo)
{
- //currently id_hi is ignored
+ /*currently id_hi is ignored*/
struct quadtree_item *qit = g_hash_table_lookup(mr->m->qitem_hash,&id_lo);
}
m->dirty = 1;
- //add item to the map
+ /*add item to the map*/
curr_item = item_new("",zoom_max);
curr_item->type = m->item_type;
curr_item->meth=&methods_csv;
qd->item = curr_item;
qd->attr_list = NULL;
qi->data = qd;
- //we don`t have valid coord yet
+ /*we don`t have valid coord yet*/
qi->longitude = 0;
qi->latitude = 0;
- //add the coord less item to the new list
+ /*add the coord less item to the new list*/
m->new_items = g_list_prepend(m->new_items, qi);
if(mr->qitem)
mr->qitem->ref_count--;
mr->item=*curr_item;
mr->item.priv_data=mr;
mr->qitem->ref_count++;
- //don't add to the quadtree yet, wait until we have a valid coord
+ /*don't add to the quadtree yet, wait until we have a valid coord*/
pID = g_new(int,1);
*pID = m->next_item_idx;
- //g_hash_table_insert(m->item_hash, pID,curr_item);
g_hash_table_insert(m->qitem_hash, pID,qi);
++m->next_item_idx;
return &mr->item;
m->filename=g_strdup(wexp_data[0]);
file_wordexp_destroy(wexp);
- //load csv file into quadtree structure
- //if column number is wrong skip
+ /*load csv file into quadtree structure*/
+ /*if column number is wrong skip*/
if((fp=fopen(m->filename,"rt"))) {
const int max_line_len = 256;
char *line=g_alloca(sizeof(char)*max_line_len);
}
if(col_cnt==attr_cnt) {
- int cnt = 0; //idx of current attr
+ int cnt = 0; /*index of current attr*/
char*tok;
GList* attr_list = NULL;
int bAddSum = 1;
double longitude = 0.0, latitude=0.0;
- struct item *curr_item = item_new("",zoom_max);//does not use parameters
+ struct item *curr_item = item_new("",zoom_max);/*does not use parameters*/
curr_item->type = item_type_attr->u.item_type;
curr_item->id_lo = m->next_item_idx;
if (m->flags & 1)
}
}
else {
- //unknown attribute
+ /*unknown attribute*/
bAddSum = bAdd = 0;
g_free(curr_attr);
}
qi->data = qd;
qi->longitude = longitude;
qi->latitude = latitude;
- quadtree_add(tree_root, qi);
+ quadtree_add(tree_root, qi, NULL);
*pID = m->next_item_idx;
- //g_hash_table_insert(m->item_hash, pID,curr_item);
g_hash_table_insert(m->qitem_hash, pID,qi);
++m->next_item_idx;
dbg(1,"%s\n",line);
/* Check if two given rectanlgles overlap (2-d case) */
#define rects_overlap(x11,y11,x12,y12, x21,y21,x22,y22) (segments_overlap(x11,x12, x21,x22) && segments_overlap(y11,y12, y21,y22))
+/* Structure describing quadtree iterative query */
+struct quadtree_iter {
+ /* List representing stack of quad_tree_iter_nodes referring to higher-level quadtree_nodes */
+ GList *iter_nodes;
+ double xmin,xmax,ymin,ymax;
+ /* Current item pointer */
+ struct quadtree_item *item;
+ void (*item_free)(void *context, struct quadtree_item *qitem);
+ void *item_free_context;
+};
+
+/* Structure describing one level of the quadtree iterative query */
+struct quadtree_iter_node {
+ struct quadtree_node *node;
+ /* Number of subnode being analyzed (for non-leafs) */
+ int subnode;
+ /* Number of item being analyzed (for leafs) */
+ int item;
+ /* Number of subitems in items array (for leafs) */
+ int node_num;
+ /* If the node referenced was a leaf when it was analyzed */
+ int is_leaf;
+ struct quadtree_item *items[QUADTREE_NODE_CAPACITY];
+};
+
+
static double
dist_sq(double x1,double y1,double x2,double y2)
{
struct quadtree_node* nodes[4] = { this_->aa, this_->ab, this_->ba, this_->bb };
if( this_->is_leaf ) {
int i;
- //double distance_sq = current_max;
for(i=0;i<this_->node_num;++i) { //select only items within input rectangle
if(dXMin<=this_->items[i]->longitude && this_->items[i]->longitude<=dXMax &&
dYMin<=this_->items[i]->latitude && this_->items[i]->latitude<=dYMax
}
+
+/**
+ * @brief Free space occupied by deleted unreferenced items.
+ * @param node pointer to the quadtree node
+ * @param iter Quadtree iteration context.
+ * @return nothing
+ */
+void quadtree_node_drop_garbage(struct quadtree_node* node, struct quadtree_iter *iter)
+{
+ int i,j;
+ int node_num=node->node_num;
+ dbg(1,"Processing unreferenced subnode children...\n");
+ for(i=0,j=0;i<node_num;i++) {
+ if(node->items[i]->deleted && !node->items[i]->ref_count) {
+ if(iter->item_free) {
+ (iter->item_free)(iter->item_free_context, node->items[i]);
+ } else {
+ g_free(node->items[i]);
+ }
+ node->node_num--;
+ node->items[i]=NULL;
+ } else {
+ node->items[j++]=node->items[i];
+ }
+ if(i>j)
+ node->items[i]=NULL;
+ }
+}
+
+/**
+ * @brief Add new node to quadtree.
+ * @param this_ pointer to the quadtree (root) node
+ * @param item item to add
+ * @param iter Quadtree iteration context. Can be NULL if no garbage collection is needed.
+ * @return nothing
+ */
void
-quadtree_add(struct quadtree_node* this_, struct quadtree_item* item) {
+quadtree_add(struct quadtree_node* this_, struct quadtree_item* item, struct quadtree_iter *iter) {
if( this_->is_leaf ) {
int bSame = 1;
int i;
- item->deleted=0;
- item->ref_count=0;
+
+ if(iter)
+ quadtree_node_drop_garbage(this_, iter);
+
if(QUADTREE_NODE_CAPACITY-1 == this_->node_num) {
double lon, lat;
//avoid infinite recursion when all elements have the same coordinate
if(!this_->aa) {
this_->aa = quadtree_node_new( this_, this_->xmin, this_->xmin+(this_->xmax-this_->xmin)/2.0 , this_->ymin, this_->ymin+(this_->ymax-this_->ymin)/2.0 );
}
- quadtree_add(this_->aa,item);
+ quadtree_add(this_->aa,item,iter);
}
else if(
this_->xmin+(this_->xmax-this_->xmin)/2.0<=item->longitude && item->longitude<this_->xmax &&
if(!this_->ab) {
this_->ab = quadtree_node_new( this_, this_->xmin+(this_->xmax-this_->xmin)/2.0, this_->xmax , this_->ymin, this_->ymin+(this_->ymax-this_->ymin)/2.0 );
}
- quadtree_add(this_->ab,item);
+ quadtree_add(this_->ab,item,iter);
}
else if(
this_->xmin<=item->longitude && item->longitude<this_->xmin+(this_->xmax-this_->xmin)/2.0 &&
if(!this_->ba) {
this_->ba = quadtree_node_new( this_, this_->xmin, this_->xmin+(this_->xmax-this_->xmin)/2.0 , this_->ymin+(this_->ymax-this_->ymin)/2.0 , this_->ymax);
}
- quadtree_add(this_->ba,item);
+ quadtree_add(this_->ba,item,iter);
}
else if(
this_->xmin+(this_->xmax-this_->xmin)/2.0<=item->longitude && item->longitude<this_->xmax &&
if(!this_->bb) {
this_->bb = quadtree_node_new( this_, this_->xmin+(this_->xmax-this_->xmin)/2.0, this_->xmax , this_->ymin+(this_->ymax-this_->ymin)/2.0 , this_->ymax);
}
- quadtree_add(this_->bb,item);
+ quadtree_add(this_->bb,item,iter);
}
}
}
if(!this_->aa) {
this_->aa = quadtree_node_new( this_, this_->xmin, this_->xmin+(this_->xmax-this_->xmin)/2.0 , this_->ymin, this_->ymin+(this_->ymax-this_->ymin)/2.0 );
}
- quadtree_add(this_->aa,this_->items[i]);
+ quadtree_add(this_->aa,this_->items[i],NULL);
}
else if(
this_->xmin+(this_->xmax-this_->xmin)/2.0<=this_->items[i]->longitude && this_->items[i]->longitude<this_->xmax &&
if(!this_->ab) {
this_->ab = quadtree_node_new( this_, this_->xmin+(this_->xmax-this_->xmin)/2.0, this_->xmax , this_->ymin, this_->ymin+(this_->ymax-this_->ymin)/2.0 );
}
- quadtree_add(this_->ab,this_->items[i]);
+ quadtree_add(this_->ab,this_->items[i],NULL);
}
else if(
this_->xmin<=this_->items[i]->longitude && this_->items[i]->longitude<this_->xmin+(this_->xmax-this_->xmin)/2.0 &&
if(!this_->ba) {
this_->ba = quadtree_node_new( this_, this_->xmin, this_->xmin+(this_->xmax-this_->xmin)/2.0 , this_->ymin+(this_->ymax-this_->ymin)/2.0 , this_->ymax);
}
- quadtree_add(this_->ba,this_->items[i]);
+ quadtree_add(this_->ba,this_->items[i],NULL);
}
else if(
this_->xmin+(this_->xmax-this_->xmin)/2.0<=this_->items[i]->longitude && this_->items[i]->longitude<this_->xmax &&
if(!this_->bb) {
this_->bb = quadtree_node_new( this_, this_->xmin+(this_->xmax-this_->xmin)/2.0, this_->xmax , this_->ymin+(this_->ymax-this_->ymin)/2.0 , this_->ymax);
}
- quadtree_add(this_->bb,this_->items[i]);
+ quadtree_add(this_->bb,this_->items[i],NULL);
}
+ this_->items[i]=NULL;
}
this_->node_num = 0;
}
free(this_);
}
-/* Structure describing one level of the quadtree iteration query */
-struct quadtree_iter_node {
- struct quadtree_node *node;
- /* Number of subnode being analyzed (for non-leafs) */
- int subnode;
- /* Number of item being analyzed (for leafs) */
- int item;
- /* Number of subitems in items array (for leafs) */
- int node_num;
- /* If the node referenced was a leaf when it was analyzed */
- int is_leaf;
- struct quadtree_item *items[QUADTREE_NODE_CAPACITY];
-};
-
-
-/* Structure describing quadtree iteration query */
-struct quadtree_iter {
- /* List representing stack of quad_tree_iter_nodes referring to higher-level quadtree_nodes */
- GList *iter_nodes;
- double xmin,xmax,ymin,ymax;
- /* Current item pointer */
- struct quadtree_item *item;
- void (*item_free)(void *context, struct quadtree_item *qitem);
- void *item_free_context;
-};
/*
* @brief Start iterating over quadtree items not marked for deletion.
while(iter->iter_nodes) {
struct quadtree_node *nodes[4];
iter_node=iter->iter_nodes->data;
- int i,j;
+ int i;
if(iter_node->is_leaf) {
/* Try to find undeleted item in the current node */
if(!subnode->aa && !subnode->ab && !subnode->ba && !subnode->bb)
subnode->is_leaf=1;
- /* 1. free deleted items if this subnode is not referenced from any competing iterator */
- if(!subnode->ref_count) {
- int node_num=subnode->node_num;
- dbg(1,"Processing unreferenced subnode children...\n");
- for(i=0,j=0;i<node_num;i++) {
- if(subnode->items[i]->deleted && !subnode->items[i]->ref_count) {
- if(iter->item_free) {
- (iter->item_free)(iter->item_free_context, subnode->items[i]);
- } else {
- g_free(subnode->items[i]);
- }
- subnode->node_num--;
- subnode->items[i]=NULL;
- } else {
- subnode->items[j++]=subnode->items[i];
- }
- if(i>j)
- subnode->items[i]=NULL;
- }
- }
-
+ /* 1. free deleted unreferenced items */
+ quadtree_node_drop_garbage(subnode, iter);
+
/* 2. remove empty leaf subnode if it's unreferenced */
if(!subnode->ref_count && !subnode->node_num && subnode->is_leaf ) {
iter->item=NULL;
return NULL;
-
}