double get_property(int cat, int line, dbCatValArray *cvarr, double scale, double default_value) { double value; dbCatVal *cv; cv = NULL; if (cat < 0) return default_value; /* Read line width from db for current area # */ if (db_CatValArray_get_value(cvarr, cat, &cv) != DB_OK) { value = default_value; } else { value = scale * (cvarr->ctype == DB_C_TYPE_INT ? (double) cv->val.i : cv->val.d); if (value < 0) { G_important_message(_("Invalid negative value - feature %d with category %d"), line, cat); value = default_value; } } return value; }
int get_table_color(int cat, int line, struct Colors *colors, dbCatValArray *cvarr, int *red, int *grn, int *blu) { int custom_rgb; char colorstring[12]; /* RRR:GGG:BBB */ dbCatVal *cv; custom_rgb = FALSE; cv = NULL; if (cat < 0) return custom_rgb; if (colors) { /* read color table */ if (Rast_get_c_color(&cat, red, grn, blu, colors) == 1) { custom_rgb = TRUE; G_debug(3, "\tb: %d, g: %d, r: %d", *blu, *grn, *red); } } /* read RGB colors from db for current area # */ if (cvarr && db_CatValArray_get_value(cvarr, cat, &cv) == DB_OK) { sprintf(colorstring, "%s", db_get_string(cv->val.s)); if (*colorstring != '\0') { G_debug(3, "element %d: colorstring: %s", line, colorstring); if (G_str_to_color(colorstring, red, grn, blu) == 1) { custom_rgb = TRUE; G_debug(3, "element:%d cat %d r:%d g:%d b:%d", line, cat, *red, *grn, *blu); } else { G_debug(3, "Invalid color definition '%s' ignored", colorstring); ncolor_rules_skipped++; } } else { G_debug(3, "Invalid color definition '%s' ignored", colorstring); ncolor_rules_skipped++; } } return custom_rgb; }
/* sets *color and returns 1 on success, -1 if no color found */ int get_ps_color_rgbcol_varea(struct Map_info *map, int vec, int area, dbCatValArray * cvarr_rgb, PSCOLOR *color) { int cat, ret; dbCatVal *cv_rgb; int red, grn, blu; char *rgbstring = NULL; cat = Vect_get_area_cat(map, area, vector.layer[vec].field); ret = db_CatValArray_get_value(cvarr_rgb, cat, &cv_rgb); if (ret != DB_OK) { G_warning(_("No record for category [%d]"), cat); } else { rgbstring = db_get_string(cv_rgb->val.s); if (rgbstring == NULL || G_str_to_color(rgbstring, &red, &grn, &blu) != 1) { G_warning(_("Invalid RGB color definition in column <%s> for category [%d]"), vector.layer[vec].rgbcol, cat); rgbstring = NULL; } } if (rgbstring) { G_debug(3, " dynamic varea fill rgb color = %s", rgbstring); set_color(color, red, grn, blu); } else { set_color(color, 0, 0, 0); return -1; } return 1; }
int main(int argc, char *argv[]) { struct GModule *module; struct Option *map_opt, *type_opt, *field_opt, *col_opt, *where_opt, *percentile; struct Flag *shell_flag, *extended; struct Map_info Map; struct field_info *Fi; dbDriver *Driver; dbCatValArray Cvarr; struct line_pnts *Points; struct line_cats *Cats; int otype, ofield; int compatible = 1; /* types are compatible: point+centroid or line+boundary or area */ int nrec, ctype, nlines, line, nareas, area; int nmissing = 0; /* number of missing atttributes */ int nnull = 0; /* number of null values */ int first = 1; /* Statistics */ int count = 0; /* number of features with non-null attribute */ double sum = 0.0; double sumsq = 0.0; double sumcb = 0.0; double sumqt = 0.0; double sum_abs = 0.0; double min = 0.0 / 0.0; /* init as nan */ double max = 0.0 / 0.0; double mean, mean_abs, pop_variance, sample_variance, pop_stdev, sample_stdev, pop_coeff_variation, kurtosis, skewness; double total_size = 0.0; /* total size: length/area */ /* Extended statistics */ int perc; module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("statistics")); module->label = _("Calculates univariate statistics for attribute."); module->description = _("Variance and standard " "deviation is calculated only for points if specified."); map_opt = G_define_standard_option(G_OPT_V_MAP); field_opt = G_define_standard_option(G_OPT_V_FIELD); type_opt = G_define_standard_option(G_OPT_V_TYPE); type_opt->options = "point,line,boundary,centroid,area"; col_opt = G_define_standard_option(G_OPT_DB_COLUMN); col_opt->required = YES; where_opt = G_define_standard_option(G_OPT_DB_WHERE); percentile = G_define_option(); percentile->key = "percentile"; percentile->type = TYPE_INTEGER; percentile->required = NO; percentile->options = "0-100"; percentile->answer = "90"; percentile->description = _("Percentile to calculate (requires extended statistics flag)"); shell_flag = G_define_flag(); shell_flag->key = 'g'; shell_flag->description = _("Print the stats in shell script style"); extended = G_define_flag(); extended->key = 'e'; extended->description = _("Calculate extended statistics"); G_gisinit(argv[0]); if (G_parser(argc, argv)) exit(EXIT_FAILURE); otype = Vect_option_to_types(type_opt); perc = atoi(percentile->answer); Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); /* open input vector */ Vect_set_open_level(2); Vect_open_old2(&Map, map_opt->answer, "", field_opt->answer); ofield = Vect_get_field_number(&Map, field_opt->answer); /* Check if types are compatible */ if ((otype & GV_POINTS) && ((otype & GV_LINES) || (otype & GV_AREA))) compatible = 0; if ((otype & GV_LINES) && (otype & GV_AREA)) compatible = 0; if (!compatible) { G_warning(_("Incompatible vector type(s) specified, only number of features, minimum, maximum and range " "can be calculated")); } if (extended->answer && !(otype & GV_POINTS)) { G_warning(_("Extended statistics is currently supported only for points/centroids")); } /* Read attributes */ db_CatValArray_init(&Cvarr); Fi = Vect_get_field(&Map, ofield); if (Fi == NULL) { G_fatal_error(_(" Database connection not defined for layer <%s>"), field_opt->answer); } Driver = db_start_driver_open_database(Fi->driver, Fi->database); if (Driver == NULL) G_fatal_error("Unable to open database <%s> by driver <%s>", Fi->database, Fi->driver); /* Note do not check if the column exists in the table because it may be an expression */ nrec = db_select_CatValArray(Driver, Fi->table, Fi->key, col_opt->answer, where_opt->answer, &Cvarr); G_debug(2, "nrec = %d", nrec); ctype = Cvarr.ctype; if (ctype != DB_C_TYPE_INT && ctype != DB_C_TYPE_DOUBLE) G_fatal_error(_("Column type not supported")); if (nrec < 0) G_fatal_error(_("Unable to select data from table")); db_close_database_shutdown_driver(Driver); /* Lines */ nlines = Vect_get_num_lines(&Map); for (line = 1; line <= nlines; line++) { int i, type; G_debug(3, "line = %d", line); type = Vect_read_line(&Map, Points, Cats, line); if (!(type & otype)) continue; for (i = 0; i < Cats->n_cats; i++) { if (Cats->field[i] == ofield) { double val; dbCatVal *catval; G_debug(3, "cat = %d", Cats->cat[i]); if (db_CatValArray_get_value(&Cvarr, Cats->cat[i], &catval) != DB_OK) { G_debug(3, "No record for cat = %d", Cats->cat[i]); nmissing++; continue; } if (catval->isNull) { G_debug(3, "NULL value for cat = %d", Cats->cat[i]); nnull++; continue; } if (ctype == DB_C_TYPE_INT) { val = catval->val.i; } else if (ctype == DB_C_TYPE_DOUBLE) { val = catval->val.d; } count++; if (first) { max = val; min = val; first = 0; } else { if (val > max) max = val; if (val < min) min = val; } if (compatible) { if (type & GV_POINTS) { sum += val; sumsq += val * val; sumcb += val * val * val; sumqt += val * val * val * val; sum_abs += fabs(val); } else { /* GV_LINES */ double l; l = Vect_line_length(Points); sum += l * val; sumsq += l * val * val; sumcb += l * val * val * val; sumqt += l * val * val * val * val; sum_abs += l * fabs(val); total_size += l; } } G_debug(3, "sum = %f total_size = %f", sum, total_size); } } } if (otype & GV_AREA) { nareas = Vect_get_num_areas(&Map); for (area = 1; area <= nareas; area++) { int i, centr; G_debug(3, "area = %d", area); centr = Vect_get_area_centroid(&Map, area); if (centr < 1) continue; G_debug(3, "centr = %d", centr); Vect_read_line(&Map, NULL, Cats, centr); for (i = 0; i < Cats->n_cats; i++) { if (Cats->field[i] == ofield) { double val; dbCatVal *catval; G_debug(3, "cat = %d", Cats->cat[i]); if (db_CatValArray_get_value (&Cvarr, Cats->cat[i], &catval) != DB_OK) { G_debug(3, "No record for cat = %d", Cats->cat[i]); nmissing++; continue; } if (catval->isNull) { G_debug(3, "NULL value for cat = %d", Cats->cat[i]); nnull++; continue; } if (ctype == DB_C_TYPE_INT) { val = catval->val.i; } else if (ctype == DB_C_TYPE_DOUBLE) { val = catval->val.d; } count++; if (first) { max = val; min = val; first = 0; } else { if (val > max) max = val; if (val < min) min = val; } if (compatible) { double a; a = Vect_get_area_area(&Map, area); sum += a * val; sumsq += a * val * val; sumcb += a * val * val * val; sumqt += a * val * val * val * val; sum_abs += a * fabs(val); total_size += a; } G_debug(4, "sum = %f total_size = %f", sum, total_size); } } } } G_debug(2, "sum = %f total_size = %f", sum, total_size); if (compatible) { if ((otype & GV_LINES) || (otype & GV_AREA)) { mean = sum / total_size; mean_abs = sum_abs / total_size; /* Roger Bivand says it is wrong see GRASS devel list 7/2004 */ /* pop_variance = (sumsq - sum*sum/total_size)/total_size; pop_stdev = sqrt(pop_variance); */ } else { double n = count; mean = sum / count; mean_abs = sum_abs / count; pop_variance = (sumsq - sum * sum / count) / count; pop_stdev = sqrt(pop_variance); pop_coeff_variation = pop_stdev / (sqrt(sum * sum) / count); sample_variance = (sumsq - sum * sum / count) / (count - 1); sample_stdev = sqrt(sample_variance); kurtosis = (sumqt / count - 4 * sum * sumcb / (n * n) + 6 * sum * sum * sumsq / (n * n * n) - 3 * sum * sum * sum * sum / (n * n * n * n)) / (sample_stdev * sample_stdev * sample_stdev * sample_stdev) - 3; skewness = (sumcb / n - 3 * sum * sumsq / (n * n) + 2 * sum * sum * sum / (n * n * n)) / (sample_stdev * sample_stdev * sample_stdev); } } G_debug(3, "otype %d:", otype); if (shell_flag->answer) { fprintf(stdout, "n=%d\n", count); fprintf(stdout, "nmissing=%d\n", nmissing); fprintf(stdout, "nnull=%d\n", nnull); if (count > 0) { fprintf(stdout, "min=%g\n", min); fprintf(stdout, "max=%g\n", max); fprintf(stdout, "range=%g\n", max - min); if (compatible && (otype & GV_POINTS)) { fprintf(stdout, "mean=%g\n", mean); fprintf(stdout, "mean_abs=%g\n", mean_abs); fprintf(stdout, "population_stddev=%g\n", pop_stdev); fprintf(stdout, "population_variance=%g\n", pop_variance); fprintf(stdout, "population_coeff_variation=%g\n", pop_coeff_variation); if (otype & GV_POINTS) { fprintf(stdout, "sample_stddev=%g\n", sample_stdev); fprintf(stdout, "sample_variance=%g\n", sample_variance); fprintf(stdout, "kurtosis=%g\n", kurtosis); fprintf(stdout, "skewness=%g\n", skewness); } } } } else { fprintf(stdout, "number of features with non NULL attribute: %d\n", count); fprintf(stdout, "number of missing attributes: %d\n", nmissing); fprintf(stdout, "number of NULL attributes: %d\n", nnull); if (count > 0) { fprintf(stdout, "minimum: %g\n", min); fprintf(stdout, "maximum: %g\n", max); fprintf(stdout, "range: %g\n", max - min); if (compatible && (otype & GV_POINTS)) { fprintf(stdout, "mean: %g\n", mean); fprintf(stdout, "mean of absolute values: %g\n", mean_abs); fprintf(stdout, "population standard deviation: %g\n", pop_stdev); fprintf(stdout, "population variance: %g\n", pop_variance); fprintf(stdout, "population coefficient of variation: %g\n", pop_coeff_variation); if (otype & GV_POINTS) { fprintf(stdout, "sample standard deviation: %g\n", sample_stdev); fprintf(stdout, "sample variance: %g\n", sample_variance); fprintf(stdout, "kurtosis: %g\n", kurtosis); fprintf(stdout, "skewness: %g\n", skewness); } } } } /* TODO: mode, skewness, kurtosis */ if (extended->answer && compatible && (otype & GV_POINTS) && count > 0) { double quartile_25 = 0.0, quartile_75 = 0.0, quartile_perc = 0.0; double median = 0.0; int qpos_25, qpos_75, qpos_perc; qpos_25 = (int)(count * 0.25 - 0.5); qpos_75 = (int)(count * 0.75 - 0.5); qpos_perc = (int)(count * perc / 100. - 0.5); if (db_CatValArray_sort_by_value(&Cvarr) != DB_OK) G_fatal_error(_("Cannot sort the key/value array")); if (Cvarr.ctype == DB_C_TYPE_INT) { quartile_25 = (Cvarr.value[qpos_25]).val.i; if (count % 2) /* odd */ median = (Cvarr.value[(int)(count / 2)]).val.i; else /* even */ median = ((Cvarr.value[count / 2 - 1]).val.i + (Cvarr.value[count / 2]).val.i) / 2.0; quartile_75 = (Cvarr.value[qpos_75]).val.i; quartile_perc = (Cvarr.value[qpos_perc]).val.i; } else { /* must be DB_C_TYPE_DOUBLE */ quartile_25 = (Cvarr.value[qpos_25]).val.d; if (count % 2) /* odd */ median = (Cvarr.value[(int)(count / 2)]).val.d; else /* even */ median = ((Cvarr.value[count / 2 - 1]).val.d + (Cvarr.value[count / 2]).val.d) / 2.0; quartile_75 = (Cvarr.value[qpos_75]).val.d; quartile_perc = (Cvarr.value[qpos_perc]).val.d; } if (shell_flag->answer) { fprintf(stdout, "first_quartile=%g\n", quartile_25); fprintf(stdout, "median=%g\n", median); fprintf(stdout, "third_quartile=%g\n", quartile_75); fprintf(stdout, "percentile_%d=%g\n", perc, quartile_perc); } else { fprintf(stdout, "1st quartile: %g\n", quartile_25); if (count % 2) fprintf(stdout, "median (odd number of cells): %g\n", median); else fprintf(stdout, "median (even number of cells): %g\n", median); fprintf(stdout, "3rd quartile: %g\n", quartile_75); if (perc % 10 == 1 && perc != 11) fprintf(stdout, "%dst percentile: %g\n", perc, quartile_perc); else if (perc % 10 == 2 && perc != 12) fprintf(stdout, "%dnd percentile: %g\n", perc, quartile_perc); else if (perc % 10 == 3 && perc != 13) fprintf(stdout, "%drd percentile: %g\n", perc, quartile_perc); else fprintf(stdout, "%dth percentile: %g\n", perc, quartile_perc); } } Vect_close(&Map); exit(EXIT_SUCCESS); }
int main(int argc, char *argv[]) { char *p; int i, j, k; int method, half, use_catno; const char *mapset; struct GModule *module; struct Option *point_opt, /* point vector */ *area_opt, /* area vector */ *point_type_opt, /* point type */ *point_field_opt, /* point layer */ *area_field_opt, /* area layer */ *method_opt, /* stats method */ *point_column_opt, /* point column for stats */ *count_column_opt, /* area column for point count */ *stats_column_opt, /* area column for stats result */ *fs_opt; /* field separator for printed output */ struct Flag *print_flag; char *fs; struct Map_info PIn, AIn; int point_type, point_field, area_field; struct line_pnts *Points; struct line_cats *ACats, *PCats; AREA_CAT *Area_cat; int pline, ptype, count; int area, nareas, nacats, nacatsalloc; int ctype, nrec; struct field_info *PFi, *AFi; dbString stmt; dbDriver *Pdriver, *Adriver; char buf[2000]; int update_ok, update_err; struct boxlist *List; struct bound_box box; dbCatValArray cvarr; dbColumn *column; struct pvalcat { double dval; int catno; } *pvalcats; int npvalcats, npvalcatsalloc; stat_func *statsvalue = NULL; double result; column = NULL; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("attribute table")); G_add_keyword(_("database")); G_add_keyword(_("univariate statistics")); G_add_keyword(_("zonal statistics")); module->description = _("Count points in areas, calculate statistics from point attributes."); point_opt = G_define_standard_option(G_OPT_V_INPUT); point_opt->key = "points"; point_opt->description = _("Name of existing vector map with points"); /* point_opt->guisection = _("Required"); */ area_opt = G_define_standard_option(G_OPT_V_INPUT); area_opt->key = "areas"; area_opt->description = _("Name of existing vector map with areas"); /* area_opt->guisection = _("Required"); */ point_type_opt = G_define_standard_option(G_OPT_V_TYPE); point_type_opt->key = "type"; point_type_opt->options = "point,centroid"; point_type_opt->answer = "point"; point_type_opt->label = _("Feature type"); point_type_opt->required = NO; point_field_opt = G_define_standard_option(G_OPT_V_FIELD); point_field_opt->key = "player"; point_field_opt->label = _("Layer number for points map"); area_field_opt = G_define_standard_option(G_OPT_V_FIELD); area_field_opt->key = "alayer"; area_field_opt->label = _("Layer number for area map"); method_opt = G_define_option(); method_opt->key = "method"; method_opt->type = TYPE_STRING; method_opt->required = NO; method_opt->multiple = NO; p = G_malloc(1024); for (i = 0; menu[i].name; i++) { if (i) strcat(p, ","); else *p = 0; strcat(p, menu[i].name); } method_opt->options = p; method_opt->description = _("Method for aggregate statistics"); point_column_opt = G_define_standard_option(G_OPT_DB_COLUMN); point_column_opt->key = "pcolumn"; point_column_opt->required = NO; point_column_opt->multiple = NO; point_column_opt->label = _("Column name of points map to use for statistics"); point_column_opt->description = _("Column of points map must be numeric"); count_column_opt = G_define_option(); count_column_opt->key = "ccolumn"; count_column_opt->type = TYPE_STRING; count_column_opt->required = NO; count_column_opt->multiple = NO; count_column_opt->label = _("Column name to upload points count"); count_column_opt->description = _("Column to hold points count, must be of type integer, will be created if not existing"); stats_column_opt = G_define_option(); stats_column_opt->key = "scolumn"; stats_column_opt->type = TYPE_STRING; stats_column_opt->required = NO; stats_column_opt->multiple = NO; stats_column_opt->label = _("Column name to upload statistics"); stats_column_opt->description = _("Column to hold statistics, must be of type double, will be created if not existing"); fs_opt = G_define_standard_option(G_OPT_F_SEP); print_flag = G_define_flag(); print_flag->key = 'p'; print_flag->label = _("Print output to stdout, do not update attribute table"); print_flag->description = _("First column is always area category"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); point_type = Vect_option_to_types(point_type_opt); point_field = atoi(point_field_opt->answer); area_field = atoi(area_field_opt->answer); if (print_flag->answer) /* get field separator */ fs = G_option_to_separator(fs_opt); else fs = NULL; /* check for stats */ if (method_opt->answer) { if (!point_column_opt->answer) { G_fatal_error("Method but no point column selected"); } if (!print_flag->answer && !stats_column_opt->answer) G_fatal_error("Name for stats column is missing"); } if (point_column_opt->answer) { if (!method_opt->answer) G_fatal_error("No method for statistics selected"); if (!print_flag->answer && !stats_column_opt->answer) G_fatal_error("Name for stats column is missing"); } /* Open points vector */ if ((mapset = G_find_vector2(point_opt->answer, "")) == NULL) G_fatal_error(_("Vector map <%s> not found"), point_opt->answer); Vect_set_open_level(2); if (Vect_open_old(&PIn, point_opt->answer, mapset) < 0) G_fatal_error(_("Unable to open vector map <%s>"), point_opt->answer); /* Open areas vector */ if ((mapset = G_find_vector2(area_opt->answer, "")) == NULL) G_fatal_error(_("Vector map <%s> not found"), area_opt->answer); if (!print_flag->answer && strcmp(mapset, G_mapset()) != 0) G_fatal_error(_("Vector map <%s> is not in user mapset and cannot be updated"), area_opt->answer); Vect_set_open_level(2); if (Vect_open_old(&AIn, area_opt->answer, mapset) < 0) G_fatal_error(_("Unable to open vector map <%s>"), area_opt->answer); method = -1; use_catno = 0; half = 0; if (method_opt->answer) { /* get the method */ for (method = 0; (p = menu[method].name); method++) if ((strcmp(p, method_opt->answer) == 0)) break; if (!p) { G_warning(_("<%s=%s> unknown %s"), method_opt->key, method_opt->answer, method_opt->answer); G_usage(); exit(EXIT_FAILURE); } /* establish the statsvalue routine */ statsvalue = menu[method].method; /* category number of lowest/highest value */ if ((strcmp(menu[method].name, menu[5].name) == 0) || (strcmp(menu[method].name, menu[7].name) == 0)) use_catno = 1; G_debug(1, "method: %s, use cat value: %s", menu[method].name, (use_catno == 1 ? "yes" : "no")); } /* Open database driver */ db_init_string(&stmt); Adriver = NULL; if (!print_flag->answer) { AFi = Vect_get_field(&AIn, area_field); if (AFi == NULL) G_fatal_error(_("Database connection not defined for layer %d"), area_field); Adriver = db_start_driver_open_database(AFi->driver, AFi->database); if (Adriver == NULL) G_fatal_error(_("Unable to open database <%s> with driver <%s>"), AFi->database, AFi->driver); if (!count_column_opt->answer) G_fatal_error(_("ccolumn is required to upload point counts")); /* check if count column exists */ G_debug(1, "check if count column exists"); db_get_column(Adriver, AFi->table, count_column_opt->answer, &column); if (column) { /* check count column type */ if (db_column_Ctype(Adriver, AFi->table, count_column_opt->answer) != DB_C_TYPE_INT) G_fatal_error(_("ccolumn must be of type integer")); db_free_column(column); column = NULL; } else { /* create count column */ /* db_add_column() exists but is not implemented, * see lib/db/stubs/add_col.c */ sprintf(buf, "alter table %s add column %s integer", AFi->table, count_column_opt->answer); db_set_string(&stmt, buf); if (db_execute_immediate(Adriver, &stmt) != DB_OK) G_fatal_error(_("Unable to add column <%s>"), count_column_opt->answer); } if (method_opt->answer) { if (!stats_column_opt->answer) G_fatal_error(_("scolumn is required to upload point stats")); /* check if stats column exists */ G_debug(1, "check if stats column exists"); db_get_column(Adriver, AFi->table, stats_column_opt->answer, &column); if (column) { /* check stats column type */ if (db_column_Ctype (Adriver, AFi->table, stats_column_opt->answer) != DB_C_TYPE_DOUBLE) G_fatal_error(_("scolumn must be of type double")); db_free_column(column); column = NULL; } else { /* create stats column */ /* db_add_column() exists but is not implemented, * see lib/db/stubs/add_col.c */ sprintf(buf, "alter table %s add column %s double", AFi->table, stats_column_opt->answer); db_set_string(&stmt, buf); if (db_execute_immediate(Adriver, &stmt) != DB_OK) G_fatal_error(_("Unable to add column <%s>"), stats_column_opt->answer); } } } else AFi = NULL; Pdriver = NULL; if (method_opt->answer) { G_verbose_message(_("collecting attributes from points vector...")); PFi = Vect_get_field(&PIn, point_field); if (PFi == NULL) G_fatal_error(_("Database connection not defined for layer %d"), point_field); Pdriver = db_start_driver_open_database(PFi->driver, PFi->database); if (Pdriver == NULL) G_fatal_error(_("Unable to open database <%s> with driver <%s>"), PFi->database, PFi->driver); /* check if point column exists */ db_get_column(Pdriver, PFi->table, point_column_opt->answer, &column); if (column) { db_free_column(column); column = NULL; } else { G_fatal_error(_("Column <%s> not found in table <%s>"), point_column_opt->answer, PFi->table); } /* Check column type */ ctype = db_column_Ctype(Pdriver, PFi->table, point_column_opt->answer); if (ctype == DB_C_TYPE_INT) half = menu[method].half; else if (ctype == DB_C_TYPE_DOUBLE) half = 0; else G_fatal_error(_("column for points vector must be numeric")); db_CatValArray_init(&cvarr); nrec = db_select_CatValArray(Pdriver, PFi->table, PFi->key, point_column_opt->answer, NULL, &cvarr); G_debug(1, "selected values = %d", nrec); db_close_database_shutdown_driver(Pdriver); } Points = Vect_new_line_struct(); ACats = Vect_new_cats_struct(); PCats = Vect_new_cats_struct(); List = Vect_new_boxlist(0); /* Allocate space ( may be more than needed (duplicate cats and elements without cats) ) */ if ((nareas = Vect_get_num_areas(&AIn)) <= 0) G_fatal_error("No areas in area input vector"); nacatsalloc = nareas; Area_cat = (AREA_CAT *) G_calloc(nacatsalloc, sizeof(AREA_CAT)); /* Read all cats from 'area' */ nacats = 0; for (area = 1; area <= nareas; area++) { Vect_get_area_cats(&AIn, area, ACats); if (ACats->n_cats <= 0) continue; for (i = 0; i < ACats->n_cats; i++) { if (ACats->field[i] == area_field) { Area_cat[nacats].area_cat = ACats->cat[i]; Area_cat[nacats].count = 0; Area_cat[nacats].nvalues = 0; Area_cat[nacats].nalloc = 0; nacats++; if (nacats >= nacatsalloc) { nacatsalloc += 100; Area_cat = (AREA_CAT *) G_realloc(Area_cat, nacatsalloc * sizeof(AREA_CAT)); } } } } G_debug(1, "%d cats loaded from vector (including duplicates)", nacats); /* Sort by category */ qsort((void *)Area_cat, nacats, sizeof(AREA_CAT), cmp_area); /* remove duplicate categories */ for (i = 1; i < nacats; i++) { if (Area_cat[i].area_cat == Area_cat[i - 1].area_cat) { for (j = i; j < nacats - 1; j++) { Area_cat[j].area_cat = Area_cat[j + 1].area_cat; } nacats--; } } G_debug(1, "%d cats loaded from vector (unique)", nacats); /* Go through all areas in area vector and find points in points vector * falling into the area */ npvalcatsalloc = 10; npvalcats = 0; pvalcats = (struct pvalcat *)G_calloc(npvalcatsalloc, sizeof(struct pvalcat)); G_message(_("Selecting points for each area...")); count = 0; for (area = 1; area <= nareas; area++) { dbCatVal *catval; G_debug(3, "area = %d", area); G_percent(area, nareas, 2); Vect_get_area_cats(&AIn, area, ACats); if (ACats->n_cats <= 0) continue; /* select points by box */ Vect_get_area_box(&AIn, area, &box); box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX; Vect_select_lines_by_box(&PIn, &box, point_type, List); G_debug(4, "%d points selected by box", List->n_values); /* For each point in box check if it is in the area */ for (i = 0; i < List->n_values; i++) { pline = List->id[i]; G_debug(4, "%d: point %d", i, pline); ptype = Vect_read_line(&PIn, Points, PCats, pline); if (!(ptype & point_type)) continue; /* point in area */ if (Vect_point_in_area(Points->x[0], Points->y[0], &AIn, area, &box)) { AREA_CAT *area_info, search_ai; int tmp_cat; /* stats on point column */ if (method_opt->answer) { npvalcats = 0; tmp_cat = -1; for (j = 0; j < PCats->n_cats; j++) { if (PCats->field[j] == point_field) { if (tmp_cat >= 0) G_debug(3, "More cats found in point layer (point=%d)", pline); tmp_cat = PCats->cat[j]; /* find cat in array */ db_CatValArray_get_value(&cvarr, tmp_cat, &catval); if (catval) { pvalcats[npvalcats].catno = tmp_cat; switch (cvarr.ctype) { case DB_C_TYPE_INT: pvalcats[npvalcats].dval = catval->val.i; npvalcats++; break; case DB_C_TYPE_DOUBLE: pvalcats[npvalcats].dval = catval->val.d; npvalcats++; break; } if (npvalcats >= npvalcatsalloc) { npvalcatsalloc += 10; pvalcats = (struct pvalcat *)G_realloc(pvalcats, npvalcatsalloc * sizeof (struct pvalcat)); } } } } } /* update count for all area cats of given field */ search_ai.area_cat = -1; for (j = 0; j < ACats->n_cats; j++) { if (ACats->field[j] == area_field) { if (search_ai.area_cat >= 0) G_debug(3, "More cats found in area layer (area=%d)", area); search_ai.area_cat = ACats->cat[j]; /* find cat in array */ area_info = (AREA_CAT *) bsearch((void *)&search_ai, Area_cat, nacats, sizeof(AREA_CAT), cmp_area); if (area_info->area_cat != search_ai.area_cat) G_fatal_error(_("could not find area category %d"), search_ai.area_cat); /* each point is counted once, also if it has * more than one category or no category * OK? */ area_info->count++; if (method_opt->answer) { /* ensure enough space */ if (area_info->nvalues + npvalcats >= area_info->nalloc) { if (area_info->nalloc == 0) { area_info->nalloc = npvalcats + 10; area_info->values = (double *)G_calloc(area_info->nalloc, sizeof(double)); area_info->cats = (int *)G_calloc(area_info->nalloc, sizeof(int)); } else area_info->nalloc += area_info->nvalues + npvalcats + 10; area_info->values = (double *)G_realloc(area_info->values, area_info->nalloc * sizeof(double)); area_info->cats = (int *)G_realloc(area_info->cats, area_info->nalloc * sizeof(int)); } for (k = 0; k < npvalcats; k++) { area_info->cats[area_info->nvalues] = pvalcats[k].catno; area_info->values[area_info->nvalues] = pvalcats[k].dval; area_info->nvalues++; } } } } count++; } } /* next point in box */ } /* next area */ G_debug(1, "count = %d", count); /* release catval array */ if (method_opt->answer) db_CatValArray_free(&cvarr); Vect_close(&PIn); /* Update table or print to stdout */ if (print_flag->answer) { /* print header */ fprintf(stdout, "area_cat%scount", fs); if (method_opt->answer) fprintf(stdout, "%s%s", fs, menu[method].name); fprintf(stdout, "\n"); } else { G_message("Updating attributes for area vector..."); update_err = update_ok = 0; } if (Adriver) db_begin_transaction(Adriver); for (i = 0; i < nacats; i++) { if (!print_flag->answer) G_percent(i, nacats, 2); result = 0; if (Area_cat[i].count > 0 && method_opt->answer) { /* get stats */ statsvalue(&result, Area_cat[i].values, Area_cat[i].nvalues, NULL); if (half) result += 0.5; else if (use_catno) result = Area_cat[i].cats[(int)result]; } if (print_flag->answer) { fprintf(stdout, "%d%s%d", Area_cat[i].area_cat, fs, Area_cat[i].count); if (method_opt->answer) { if (Area_cat[i].count > 0) fprintf(stdout, "%s%.15g", fs, result); else fprintf(stdout, "%snull", fs); } fprintf(stdout, "\n"); } else { sprintf(buf, "update %s set %s = %d", AFi->table, count_column_opt->answer, Area_cat[i].count); db_set_string(&stmt, buf); if (method_opt->answer) { if (Area_cat[i].count > 0) sprintf(buf, " , %s = %.15g", stats_column_opt->answer, result); else sprintf(buf, " , %s = null", stats_column_opt->answer); db_append_string(&stmt, buf); } sprintf(buf, " where %s = %d", AFi->key, Area_cat[i].area_cat); db_append_string(&stmt, buf); G_debug(2, "SQL: %s", db_get_string(&stmt)); if (db_execute_immediate(Adriver, &stmt) == DB_OK) { update_ok++; } else { update_err++; } } } if (Adriver) db_commit_transaction(Adriver); if (!print_flag->answer) { G_percent(nacats, nacats, 2); db_close_database_shutdown_driver(Adriver); db_free_string(&stmt); G_message(_("%d records updated"), update_ok); if (update_err > 0) G_message(_("%d update errors"), update_err); Vect_set_db_updated(&AIn); } Vect_close(&AIn); G_done_msg(" "); exit(EXIT_SUCCESS); }
/* *************************************************************** */ int plot1(struct Map_info *Map, int type, int area, struct cat_list *Clist, const struct color_rgb *color, const struct color_rgb *fcolor, int chcat, SYMBOL * Symb, int size, int id_flag, int table_colors_flag, int cats_color_flag, char *rgb_column, int default_width, char *width_column, double width_scale) { int i, ltype, nlines = 0, line, cat = -1; double *x, *y; struct line_pnts *Points, *PPoints; struct line_cats *Cats; double msize; int x0, y0; struct field_info *fi = NULL; dbDriver *driver = NULL; dbCatValArray cvarr_rgb, cvarr_width; dbCatVal *cv_rgb = NULL, *cv_width = NULL; int nrec_rgb = 0, nrec_width = 0; int open_db; int custom_rgb = FALSE; char colorstring[12]; /* RRR:GGG:BBB */ int red, grn, blu; RGBA_Color *line_color, *fill_color, *primary_color; unsigned char which; int width; line_color = G_malloc(sizeof(RGBA_Color)); fill_color = G_malloc(sizeof(RGBA_Color)); primary_color = G_malloc(sizeof(RGBA_Color)); primary_color->a = RGBA_COLOR_OPAQUE; /* change function prototype to pass RGBA_Color instead of color_rgb? */ if (color) { line_color->r = color->r; line_color->g = color->g; line_color->b = color->b; line_color->a = RGBA_COLOR_OPAQUE; } else line_color->a = RGBA_COLOR_NONE; if (fcolor) { fill_color->r = fcolor->r; fill_color->g = fcolor->g; fill_color->b = fcolor->b; fill_color->a = RGBA_COLOR_OPAQUE; } else fill_color->a = RGBA_COLOR_NONE; msize = size * (D_d_to_u_col(2.0) - D_d_to_u_col(1.0)); /* do it better */ Points = Vect_new_line_struct(); PPoints = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); open_db = table_colors_flag || width_column; if (open_db) { fi = Vect_get_field(Map, (Clist->field > 0 ? Clist->field : 1)); if (fi == NULL) { G_fatal_error(_("Database connection not defined for layer %d"), (Clist->field > 0 ? Clist->field : 1)); } driver = db_start_driver_open_database(fi->driver, fi->database); if (driver == NULL) G_fatal_error(_("Unable to open database <%s> by driver <%s>"), fi->database, fi->driver); } if (table_colors_flag) { /* for reading RRR:GGG:BBB color strings from table */ if (rgb_column == NULL || *rgb_column == '\0') G_fatal_error(_("Color definition column not specified")); db_CatValArray_init(&cvarr_rgb); nrec_rgb = db_select_CatValArray(driver, fi->table, fi->key, rgb_column, NULL, &cvarr_rgb); G_debug(3, "nrec_rgb (%s) = %d", rgb_column, nrec_rgb); if (cvarr_rgb.ctype != DB_C_TYPE_STRING) G_fatal_error(_("Color definition column (%s) not a string. " "Column must be of form RRR:GGG:BBB where RGB values range 0-255."), rgb_column); if (nrec_rgb < 0) G_fatal_error(_("Cannot select data (%s) from table"), rgb_column); G_debug(2, "\n%d records selected from table", nrec_rgb); for (i = 0; i < cvarr_rgb.n_values; i++) { G_debug(4, "cat = %d %s = %s", cvarr_rgb.value[i].cat, rgb_column, db_get_string(cvarr_rgb.value[i].val.s)); } } if (width_column) { if (*width_column == '\0') G_fatal_error(_("Line width column not specified.")); db_CatValArray_init(&cvarr_width); nrec_width = db_select_CatValArray(driver, fi->table, fi->key, width_column, NULL, &cvarr_width); G_debug(3, "nrec_width (%s) = %d", width_column, nrec_width); if (cvarr_width.ctype != DB_C_TYPE_INT && cvarr_width.ctype != DB_C_TYPE_DOUBLE) G_fatal_error(_("Line width column (%s) not a number."), width_column); if (nrec_width < 0) G_fatal_error(_("Cannot select data (%s) from table"), width_column); G_debug(2, "\n%d records selected from table", nrec_width); for (i = 0; i < cvarr_width.n_values; i++) { G_debug(4, "cat = %d %s = %d", cvarr_width.value[i].cat, width_column, (cvarr_width.ctype == DB_C_TYPE_INT ? cvarr_width.value[i].val. i : (int)cvarr_width.value[i].val.d)); } } if (open_db) db_close_database_shutdown_driver(driver); Vect_rewind(Map); /* Is it necessary to reset line/label color in each loop ? */ if (color && !table_colors_flag && !cats_color_flag) D_RGB_color(color->r, color->g, color->b); if (Vect_level(Map) >= 2) nlines = Vect_get_num_lines(Map); line = 0; while (1) { if (Vect_level(Map) >= 2) { line++; if (line > nlines) return 0; if (!Vect_line_alive(Map, line)) continue; ltype = Vect_read_line(Map, Points, Cats, line); } else { ltype = Vect_read_next_line(Map, Points, Cats); switch (ltype) { case -1: fprintf(stderr, _("\nERROR: vector map - can't read\n")); return -1; case -2: /* EOF */ return 0; } } if (!(type & ltype)) continue; if (chcat) { int found = 0; if (id_flag) { /* use line id */ if (!(Vect_cat_in_cat_list(line, Clist))) continue; } else { for (i = 0; i < Cats->n_cats; i++) { if (Cats->field[i] == Clist->field && Vect_cat_in_cat_list(Cats->cat[i], Clist)) { found = 1; break; } } if (!found) continue; } } else if (Clist->field > 0) { int found = 0; for (i = 0; i < Cats->n_cats; i++) { if (Cats->field[i] == Clist->field) { found = 1; break; } } /* lines with no category will be displayed */ if (Cats->n_cats > 0 && !found) continue; } if (table_colors_flag) { /* only first category */ cat = Vect_get_line_cat(Map, line, (Clist->field > 0 ? Clist->field : (Cats->n_cats > 0 ? Cats->field[0] : 1))); if (cat >= 0) { G_debug(3, "display element %d, cat %d", line, cat); /* Read RGB colors from db for current area # */ if (db_CatValArray_get_value(&cvarr_rgb, cat, &cv_rgb) != DB_OK) { custom_rgb = FALSE; } else { sprintf(colorstring, "%s", db_get_string(cv_rgb->val.s)); if (*colorstring != '\0') { G_debug(3, "element %d: colorstring: %s", line, colorstring); if (G_str_to_color(colorstring, &red, &grn, &blu) == 1) { custom_rgb = TRUE; G_debug(3, "element:%d cat %d r:%d g:%d b:%d", line, cat, red, grn, blu); } else { custom_rgb = FALSE; G_warning(_("Error in color definition column (%s), element %d " "with cat %d: colorstring [%s]"), rgb_column, line, cat, colorstring); } } else { custom_rgb = FALSE; G_warning(_("Error in color definition column (%s), element %d with cat %d"), rgb_column, line, cat); } } } /* end if cat */ else { custom_rgb = FALSE; } } /* end if table_colors_flag */ /* random colors */ if (cats_color_flag) { custom_rgb = FALSE; if (Clist->field > 0) { cat = Vect_get_line_cat(Map, line, Clist->field); if (cat >= 0) { G_debug(3, "display element %d, cat %d", line, cat); /* fetch color number from category */ which = (cat % palette_ncolors); G_debug(3, "cat:%d which color:%d r:%d g:%d b:%d", cat, which, palette[which].R, palette[which].G, palette[which].B); custom_rgb = TRUE; red = palette[which].R; grn = palette[which].G; blu = palette[which].B; } } else if (Cats->n_cats > 0) { /* fetch color number from layer */ which = (Cats->field[0] % palette_ncolors); G_debug(3, "layer:%d which color:%d r:%d g:%d b:%d", Cats->field[0], which, palette[which].R, palette[which].G, palette[which].B); custom_rgb = TRUE; red = palette[which].R; grn = palette[which].G; blu = palette[which].B; } } if (nrec_width) { /* only first category */ cat = Vect_get_line_cat(Map, line, (Clist->field > 0 ? Clist->field : (Cats->n_cats > 0 ? Cats->field[0] : 1))); if (cat >= 0) { G_debug(3, "display element %d, cat %d", line, cat); /* Read line width from db for current area # */ if (db_CatValArray_get_value(&cvarr_width, cat, &cv_width) != DB_OK) { width = default_width; } else { width = width_scale * (cvarr_width.ctype == DB_C_TYPE_INT ? cv_width->val. i : (int)cv_width->val.d); if (width < 0) { G_warning(_("Error in line width column (%s), element %d " "with cat %d: line width [%d]"), width_column, line, cat, width); width = default_width; } } } /* end if cat */ else { width = default_width; } D_line_width(width); } /* end if nrec_width */ /* enough of the prep work, lets start plotting stuff */ x = Points->x; y = Points->y; if ((ltype & GV_POINTS) && Symb != NULL) { if (!(color || fcolor || custom_rgb)) continue; x0 = D_u_to_d_col(x[0]); y0 = D_u_to_d_row(y[0]); /* skip if the point is outside of the display window */ /* xy<0 tests make it go ever-so-slightly faster */ if (x0 < 0 || y0 < 0 || x0 > D_get_d_east() || x0 < D_get_d_west() || y0 > D_get_d_south() || y0 < D_get_d_north()) continue; /* use random or RGB column color if given, otherwise reset */ /* centroids always use default color to stand out from underlying area */ if (custom_rgb && (ltype != GV_CENTROID)) { primary_color->r = (unsigned char)red; primary_color->g = (unsigned char)grn; primary_color->b = (unsigned char)blu; D_symbol2(Symb, x0, y0, primary_color, line_color); } else D_symbol(Symb, x0, y0, line_color, fill_color); } else if (color || custom_rgb) { if (!table_colors_flag && !cats_color_flag) D_RGB_color(color->r, color->g, color->b); else { if (custom_rgb) D_RGB_color((unsigned char)red, (unsigned char)grn, (unsigned char)blu); else D_RGB_color(color->r, color->g, color->b); } /* Plot the lines */ if (Points->n_points == 1) /* line with one coor */ D_polydots_abs(x, y, Points->n_points); else /*use different user defined render methods */ D_polyline_abs(x, y, Points->n_points); } } Vect_destroy_line_struct(Points); Vect_destroy_cats_struct(Cats); return 0; /* not reached */ }
void select_from_database(void) { int nrec, ctype, nlines, line, nareas, area; struct line_pnts *Points; Fi = Vect_get_field(&Map, ofield); if (Fi == NULL) { G_fatal_error(_(" Database connection not defined for layer <%s>"), field_opt->answer); } Driver = db_start_driver_open_database(Fi->driver, Fi->database); if (Driver == NULL) G_fatal_error("Unable to open database <%s> by driver <%s>", Fi->database, Fi->driver); db_set_error_handler_driver(Driver); /* check if column exists */ ctype = db_column_Ctype(Driver, Fi->table, col_opt->answer); if (ctype == -1) G_fatal_error(_("Column <%s> not found in table <%s>"), col_opt->answer, Fi->table); if (ctype != DB_C_TYPE_INT && ctype != DB_C_TYPE_DOUBLE) G_fatal_error(_("Only numeric column type is supported")); /* Note do not check if the column exists in the table because it may be an expression */ db_CatValArray_init(&Cvarr); nrec = db_select_CatValArray(Driver, Fi->table, Fi->key, col_opt->answer, where_opt->answer, &Cvarr); G_debug(2, "db_select_CatValArray() nrec = %d", nrec); if (nrec < 0) G_fatal_error(_("Unable to select data from table")); db_close_database_shutdown_driver(Driver); Points = Vect_new_line_struct(); /* Lines */ nlines = 0; if ((otype & GV_POINTS) || (otype & GV_LINES)) nlines = Vect_get_num_lines(&Map); G_debug(1, "select_from_database: %d points", nlines); for (line = 1; line <= nlines; line++) { int i, type; G_debug(3, "line = %d", line); G_percent(line, nlines, 2); type = Vect_read_line(&Map, Points, Cats, line); if (!(type & otype)) continue; for (i = 0; i < Cats->n_cats; i++) { if (Cats->field[i] == ofield) { double val = 0.0; dbCatVal *catval; G_debug(3, "cat = %d", Cats->cat[i]); if (db_CatValArray_get_value(&Cvarr, Cats->cat[i], &catval) != DB_OK) { G_debug(3, "No record for cat = %d", Cats->cat[i]); nmissing++; continue; } if (catval->isNull) { G_debug(3, "NULL value for cat = %d", Cats->cat[i]); nnull++; continue; } if (ctype == DB_C_TYPE_INT) { val = catval->val.i; } else if (ctype == DB_C_TYPE_DOUBLE) { val = catval->val.d; } count++; if (first) { max = val; min = val; first = 0; } else { if (val > max) max = val; if (val < min) min = val; } if (compatible) { if (type & GV_POINTS) { sum += val; sumsq += val * val; sumcb += val * val * val; sumqt += val * val * val * val; sum_abs += fabs(val); } else if (type & GV_LINES) { /* GV_LINES */ double l = 1.; if (weight_flag->answer) l = Vect_line_length(Points); sum += l * val; sumsq += l * val * val; sumcb += l * val * val * val; sumqt += l * val * val * val * val; sum_abs += l * fabs(val); total_size += l; } } G_debug(3, "sum = %f total_size = %f", sum, total_size); } } } if (otype & GV_AREA) { nareas = Vect_get_num_areas(&Map); for (area = 1; area <= nareas; area++) { int i, centr; G_debug(3, "area = %d", area); centr = Vect_get_area_centroid(&Map, area); if (centr < 1) continue; G_debug(3, "centr = %d", centr); Vect_read_line(&Map, NULL, Cats, centr); for (i = 0; i < Cats->n_cats; i++) { if (Cats->field[i] == ofield) { double val = 0.0; dbCatVal *catval; G_debug(3, "cat = %d", Cats->cat[i]); if (db_CatValArray_get_value (&Cvarr, Cats->cat[i], &catval) != DB_OK) { G_debug(3, "No record for cat = %d", Cats->cat[i]); nmissing++; continue; } if (catval->isNull) { G_debug(3, "NULL value for cat = %d", Cats->cat[i]); nnull++; continue; } if (ctype == DB_C_TYPE_INT) { val = catval->val.i; } else if (ctype == DB_C_TYPE_DOUBLE) { val = catval->val.d; } count++; if (first) { max = val; min = val; first = 0; } else { if (val > max) max = val; if (val < min) min = val; } if (compatible) { double a = 1.; if (weight_flag->answer) a = Vect_get_area_area(&Map, area); sum += a * val; sumsq += a * val * val; sumcb += a * val * val * val; sumqt += a * val * val * val * val; sum_abs += a * fabs(val); total_size += a; } G_debug(4, "sum = %f total_size = %f", sum, total_size); } } } } G_debug(2, "sum = %f total_size = %f", sum, total_size); }
int display_lines(struct Map_info *Map, struct cat_list *Clist, int chcat, const char *symbol_name, double size, int default_width, dbCatValArray * cvarr, double *breaks, int nbreaks, const struct color_rgb *colors, const struct color_rgb *bcolor) { int ltype, line, nlines; struct line_pnts *Points; struct line_cats *Cats; int n_points, n_lines, n_centroids, n_boundaries, n_faces; RGBA_Color *primary_color, *secondary_color; SYMBOL *Symb; Symb = NULL; double breakval = 0.0; int cat; dbCatVal *cv = NULL; int i; primary_color = G_malloc(sizeof(RGBA_Color)); primary_color->a = RGBA_COLOR_OPAQUE; secondary_color = G_malloc(sizeof(RGBA_Color)); secondary_color->a = RGBA_COLOR_OPAQUE; Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); /* dynamic symbols for points */ Symb = S_read(symbol_name); if (!Symb) G_warning(_("Unable to read symbol <%s>, unable to display points"), symbol_name); else S_stroke(Symb, size, 0.0, 0); Vect_rewind(Map); nlines = -1; line = 0; n_points = n_lines = 0; n_centroids = n_boundaries = 0; n_faces = 0; while (TRUE) { line++; if (nlines > -1) { if (line > nlines) break; ltype = Vect_read_line(Map, Points, Cats, line); } else { ltype = Vect_read_next_line(Map, Points, Cats); if (ltype == -1) { G_fatal_error(_("Unable to read vector map")); } else if ((ltype == -2)) { /* EOF */ break; } } cat = *Cats->cat; if (cat >= 0) { G_debug(3, "display line %d, cat %d", line, cat); /* Get value of data for this area */ if (db_CatValArray_get_value(cvarr, cat, &cv) != DB_OK) { G_debug(3, "No value found for cat %i", cat); } else { db_CatValArray_get_value(cvarr, cat, &cv); breakval = (cvarr->ctype == 2 ? cv->val.i : cv->val.d); } } /* find out into which class breakval falls */ i = 0; while (breakval > breaks[i] && i < nbreaks) i++; primary_color->r = colors[i].r; primary_color->g = colors[i].g; primary_color->b = colors[i].b; if (bcolor !=NULL) { secondary_color->r = bcolor->r; secondary_color->g = bcolor->g; secondary_color->b = bcolor->b; } else secondary_color->a = 0; draw_line(ltype, line, Points, Cats, chcat, size, default_width, Clist, Symb, primary_color, &n_points, &n_lines, &n_centroids, &n_boundaries, &n_faces, secondary_color); } if (n_points > 0) G_verbose_message(n_ ("%d point plotted", "%d points plotted", n_points), n_points); if (n_lines > 0) G_verbose_message(n_("%d line plotted", "%d lines plotted", n_lines), n_lines); if (n_centroids > 0) G_verbose_message(n_ ("%d centroid plotted", "%d centroids plotted", n_centroids), n_centroids); if (n_boundaries > 0) G_verbose_message(n_ ("%d boundary plotted", "%d boundaries plotted", n_boundaries), n_boundaries); if (n_faces > 0) G_verbose_message(n_("%d face plotted", "%d faces plotted", n_faces), n_faces); Vect_destroy_line_struct(Points); Vect_destroy_cats_struct(Cats); G_free(primary_color); return 0; }
int main(int argc, char *argv[]) { int i, j, k; int print_as_matrix; /* only for all */ int all; /* calculate from each to each within the threshold */ struct GModule *module; struct Option *from_opt, *to_opt, *from_type_opt, *to_type_opt, *from_field_opt, *to_field_opt; struct Option *out_opt, *max_opt, *min_opt, *table_opt; struct Option *upload_opt, *column_opt, *to_column_opt; struct Flag *print_flag, *all_flag; struct Map_info From, To, Out, *Outp; int from_type, to_type, from_field, to_field; double max, min; double *max_step; int n_max_steps, curr_step; struct line_pnts *FPoints, *TPoints; struct line_cats *FCats, *TCats; NEAR *Near, *near; int anear; /* allocated space, used only for all */ UPLOAD *Upload; /* zero terminated */ int ftype, fcat, tcat, count; int nfrom, nto, nfcats, fline, tline, tseg, tarea, area, isle, nisles; double tx, ty, tz, dist, talong, tmp_tx, tmp_ty, tmp_tz, tmp_dist, tmp_talong; struct field_info *Fi, *toFi; dbString stmt, dbstr; dbDriver *driver, *to_driver; int *catexist, ncatexist, *cex; char buf1[2000], buf2[2000]; int update_ok, update_err, update_exist, update_notexist, update_dupl, update_notfound; struct boxlist *List; struct bound_box box; dbCatValArray cvarr; dbColumn *column; all = 0; print_as_matrix = 0; column = NULL; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("database")); G_add_keyword(_("attribute table")); module->description = _("Finds the nearest element in vector map 'to' for elements in vector map 'from'."); from_opt = G_define_standard_option(G_OPT_V_INPUT); from_opt->key = "from"; from_opt->description = _("Name of existing vector map (from)"); from_opt->guisection = _("From"); from_field_opt = G_define_standard_option(G_OPT_V_FIELD); from_field_opt->key = "from_layer"; from_field_opt->label = _("Layer number or name (from)"); from_field_opt->guisection = _("From"); from_type_opt = G_define_standard_option(G_OPT_V_TYPE); from_type_opt->key = "from_type"; from_type_opt->options = "point,centroid"; from_type_opt->answer = "point"; from_type_opt->label = _("Feature type (from)"); from_type_opt->guisection = _("From"); to_opt = G_define_standard_option(G_OPT_V_INPUT); to_opt->key = "to"; to_opt->description = _("Name of existing vector map (to)"); to_opt->guisection = _("To"); to_field_opt = G_define_standard_option(G_OPT_V_FIELD); to_field_opt->key = "to_layer"; to_field_opt->label = _("Layer number or name (to)"); to_field_opt->guisection = _("To"); to_type_opt = G_define_standard_option(G_OPT_V_TYPE); to_type_opt->key = "to_type"; to_type_opt->options = "point,line,boundary,centroid,area"; to_type_opt->answer = "point,line,area"; to_type_opt->label = _("Feature type (to)"); to_type_opt->guisection = _("To"); out_opt = G_define_standard_option(G_OPT_V_OUTPUT); out_opt->key = "output"; out_opt->required = NO; out_opt->description = _("Name for output vector map containing lines " "connecting nearest elements"); max_opt = G_define_option(); max_opt->key = "dmax"; max_opt->type = TYPE_DOUBLE; max_opt->required = NO; max_opt->answer = "-1"; max_opt->description = _("Maximum distance or -1 for no limit"); min_opt = G_define_option(); min_opt->key = "dmin"; min_opt->type = TYPE_DOUBLE; min_opt->required = NO; min_opt->answer = "-1"; min_opt->description = _("Minimum distance or -1 for no limit"); upload_opt = G_define_option(); upload_opt->key = "upload"; upload_opt->type = TYPE_STRING; upload_opt->required = YES; upload_opt->multiple = YES; upload_opt->options = "cat,dist,to_x,to_y,to_along,to_angle,to_attr"; upload_opt->description = _("Values describing the relation between two nearest features"); upload_opt->descriptions = _("cat;category of the nearest feature;" "dist;minimum distance to nearest feature;" "to_x;x coordinate of the nearest point on 'to' feature;" "to_y;y coordinate of the nearest point on 'to' feature;" "to_along;distance between points/centroids in 'from' map and the linear feature's " "start point in 'to' map, along this linear feature;" "to_angle;angle between the linear feature in 'to' map and the positive x axis, at " "the location of point/centroid in 'from' map, counterclockwise, in radians, which " "is between -PI and PI inclusive;" "to_attr;attribute of nearest feature given by to_column option"); /* "from_x - x coordinate of the nearest point on 'from' feature;" */ /* "from_y - y coordinate of the nearest point on 'from' feature;" */ /* "from_along - distance to the nearest point on 'from' feature along linear feature;" */ column_opt = G_define_standard_option(G_OPT_DB_COLUMN); column_opt->required = YES; column_opt->multiple = YES; column_opt->description = _("Column name(s) where values specified by 'upload' option will be uploaded"); column_opt->guisection = _("From_map"); to_column_opt = G_define_standard_option(G_OPT_DB_COLUMN); to_column_opt->key = "to_column"; to_column_opt->description = _("Column name of nearest feature (used with upload=to_attr)"); to_column_opt->guisection = _("To"); table_opt = G_define_standard_option(G_OPT_DB_TABLE); table_opt->gisprompt = "new_dbtable,dbtable,dbtable"; table_opt->description = _("Name of table created for output when the distance to all flag is used"); print_flag = G_define_flag(); print_flag->key = 'p'; print_flag->label = _("Print output to stdout, don't update attribute table"); print_flag->description = _("First column is always category of 'from' feature called from_cat"); all_flag = G_define_flag(); all_flag->key = 'a'; all_flag->label = _("Calculate distances to all features within the threshold"); all_flag->description = _("The output is written to stdout but may be uploaded " "to a new table created by this module. " "From categories are may be multiple."); /* huh? */ /* GUI dependency */ from_opt->guidependency = G_store(from_field_opt->key); sprintf(buf1, "%s,%s", to_field_opt->key, to_column_opt->key); to_opt->guidependency = G_store(buf1); to_field_opt->guidependency = G_store(to_column_opt->key); if (G_parser(argc, argv)) exit(EXIT_FAILURE); from_type = Vect_option_to_types(from_type_opt); to_type = Vect_option_to_types(to_type_opt); from_field = atoi(from_field_opt->answer); max = atof(max_opt->answer); min = atof(min_opt->answer); if (all_flag->answer) all = 1; /* Read upload and column options */ /* count */ i = 0; while (upload_opt->answers[i]) i++; if (strcmp(from_opt->answer, to_opt->answer) == 0 && all && !table_opt->answer && i == 1) print_as_matrix = 1; /* alloc */ Upload = (UPLOAD *) G_calloc(i + 1, sizeof(UPLOAD)); /* read upload */ i = 0; while (upload_opt->answers[i]) { if (strcmp(upload_opt->answers[i], "cat") == 0) Upload[i].upload = CAT; else if (strcmp(upload_opt->answers[i], "from_x") == 0) Upload[i].upload = FROM_X; else if (strcmp(upload_opt->answers[i], "from_y") == 0) Upload[i].upload = FROM_Y; else if (strcmp(upload_opt->answers[i], "to_x") == 0) Upload[i].upload = TO_X; else if (strcmp(upload_opt->answers[i], "to_y") == 0) Upload[i].upload = TO_Y; else if (strcmp(upload_opt->answers[i], "from_along") == 0) Upload[i].upload = FROM_ALONG; else if (strcmp(upload_opt->answers[i], "to_along") == 0) Upload[i].upload = TO_ALONG; else if (strcmp(upload_opt->answers[i], "dist") == 0) Upload[i].upload = DIST; else if (strcmp(upload_opt->answers[i], "to_angle") == 0) Upload[i].upload = TO_ANGLE; else if (strcmp(upload_opt->answers[i], "to_attr") == 0) { if (!(to_column_opt->answer)) { G_fatal_error(_("to_column option missing")); } Upload[i].upload = TO_ATTR; } i++; } Upload[i].upload = END; /* read columns */ i = 0; while (column_opt->answers[i]) { if (Upload[i].upload == END) { G_warning(_("Too many column names")); break; } Upload[i].column = G_store(column_opt->answers[i]); i++; } if (Upload[i].upload != END) G_fatal_error(_("Not enough column names")); /* Open 'from' vector */ Vect_set_open_level(2); Vect_open_old(&From, from_opt->answer, G_mapset()); /* Open 'to' vector */ Vect_set_open_level(2); Vect_open_old2(&To, to_opt->answer, "", to_field_opt->answer); to_field = Vect_get_field_number(&To, to_field_opt->answer); /* Open output vector */ if (out_opt->answer) { Vect_open_new(&Out, out_opt->answer, WITHOUT_Z); Vect_hist_command(&Out); Outp = &Out; } else { Outp = NULL; } /* TODO: add maxdist = -1 to Vect_select_ !!! */ /* Calc maxdist */ n_max_steps = 1; if (max != 0) { struct bound_box fbox, tbox; double dx, dy, dz, tmp_max; int n_features = 0; Vect_get_map_box(&From, &fbox); Vect_get_map_box(&To, &tbox); Vect_box_extend(&fbox, &tbox); dx = fbox.E - fbox.W; dy = fbox.N - fbox.S; if (Vect_is_3d(&From)) dz = fbox.T - fbox.B; else dz = 0.0; tmp_max = sqrt(dx * dx + dy * dy + dz * dz); if (max < 0) max = tmp_max; /* how to determine a reasonable number of steps to increase the search box? */ /* with max > 0 but max <<< tmp_max, 2 steps are sufficient, first 0 then max * a reasonable number of steps also depends on the number of features in To * e.g. only one area in To, no need to step */ nto = Vect_get_num_lines(&To); for (tline = 1; tline <= nto; tline++) { /* TODO: Vect_get_line_type() */ n_features += ((to_type & To.plus.Line[tline]->type) != 0); } if (to_type & GV_AREA) { if (Vect_get_num_areas(&To) > n_features) n_features = Vect_get_num_areas(&To); } if (n_features == 0) G_fatal_error(_("No features of selected type in To vector <%s>"), to_opt->answer); n_max_steps = sqrt(n_features) * max / tmp_max; /* max 9 steps from testing */ if (n_max_steps > 9) n_max_steps = 9; if (n_max_steps < 2) n_max_steps = 2; if (n_max_steps > n_features) n_max_steps = n_features; G_debug(2, "max = %f", max); G_debug(2, "maximum reasonable search distance = %f", tmp_max); G_debug(2, "n_features = %d", n_features); G_debug(2, "n_max_steps = %d", n_max_steps); } if (min > max) G_fatal_error("dmin can not be larger than dmax"); if (n_max_steps > 1) { /* set up steps to increase search box */ max_step = G_malloc(n_max_steps * sizeof(double)); /* first step always 0 */ max_step[0] = 0; for (curr_step = 1; curr_step < n_max_steps - 1; curr_step++) { /* for 9 steps, this would be max / [128, 64, 32, 16, 8, 4, 2] */ max_step[curr_step] = max / (2 << (n_max_steps - 1 - curr_step)); } /* last step always max */ max_step[n_max_steps - 1] = max; } else { max_step = G_malloc(sizeof(double)); max_step[0] = max; } /* Open database driver */ db_init_string(&stmt); db_init_string(&dbstr); driver = NULL; if (!print_flag->answer) { if (!all) { Fi = Vect_get_field(&From, from_field); if (Fi == NULL) G_fatal_error(_("Database connection not defined for layer %d"), from_field); driver = db_start_driver_open_database(Fi->driver, Fi->database); if (driver == NULL) G_fatal_error(_("Unable to open database <%s> by driver <%s>"), Fi->database, Fi->driver); /* check if column exists */ i = 0; while (column_opt->answers[i]) { db_get_column(driver, Fi->table, column_opt->answers[i], &column); if (column) { db_free_column(column); column = NULL; } else { G_fatal_error(_("Column <%s> not found in table <%s>"), column_opt->answers[i], Fi->table); } i++; } } else { driver = db_start_driver_open_database(NULL, NULL); if (driver == NULL) G_fatal_error(_("Unable to open default database")); } } to_driver = NULL; if (to_column_opt->answer) { toFi = Vect_get_field(&To, to_field); if (toFi == NULL) G_fatal_error(_("Database connection not defined for layer %d"), to_field); to_driver = db_start_driver_open_database(toFi->driver, toFi->database); if (to_driver == NULL) G_fatal_error(_("Unable to open database <%s> by driver <%s>"), toFi->database, toFi->driver); /* check if to_column exists */ db_get_column(to_driver, toFi->table, to_column_opt->answer, &column); if (column) { db_free_column(column); column = NULL; } else { G_fatal_error(_("Column <%s> not found in table <%s>"), to_column_opt->answer, toFi->table); } /* Check column types */ if (!print_flag->answer && !all) { char *fcname = NULL; int fctype, tctype; i = 0; while (column_opt->answers[i]) { if (Upload[i].upload == TO_ATTR) { fcname = column_opt->answers[i]; break; } i++; } if (fcname) { fctype = db_column_Ctype(driver, Fi->table, fcname); tctype = db_column_Ctype(to_driver, toFi->table, to_column_opt->answer); if (((tctype == DB_C_TYPE_STRING || tctype == DB_C_TYPE_DATETIME) && (fctype == DB_C_TYPE_INT || fctype == DB_C_TYPE_DOUBLE)) || ((tctype == DB_C_TYPE_INT || tctype == DB_C_TYPE_DOUBLE) && (fctype == DB_C_TYPE_STRING || fctype == DB_C_TYPE_DATETIME)) ) { G_fatal_error(_("Incompatible column types")); } } } } FPoints = Vect_new_line_struct(); TPoints = Vect_new_line_struct(); FCats = Vect_new_cats_struct(); TCats = Vect_new_cats_struct(); List = Vect_new_boxlist(1); /* Allocate space ( may be more than needed (duplicate cats and elements without cats) ) */ nfrom = Vect_get_num_lines(&From); nto = Vect_get_num_lines(&To); if (all) { /* Attention with space for all, it can easily run out of memory */ anear = 2 * nfrom; Near = (NEAR *) G_calloc(anear, sizeof(NEAR)); } else { Near = (NEAR *) G_calloc(nfrom, sizeof(NEAR)); } /* Read all cats from 'from' */ if (!all) { nfcats = 0; for (i = 1; i <= nfrom; i++) { ftype = Vect_read_line(&From, NULL, FCats, i); /* This keeps also categories of areas for future (if area s in from_type) */ if (!(ftype & from_type) && (ftype != GV_CENTROID || !(from_type & GV_AREA))) continue; Vect_cat_get(FCats, from_field, &fcat); if (fcat < 0) continue; Near[nfcats].from_cat = fcat; nfcats++; } G_debug(1, "%d cats loaded from vector (including duplicates)", nfcats); /* Sort by cats and remove duplicates */ qsort((void *)Near, nfcats, sizeof(NEAR), cmp_near); /* remove duplicates */ for (i = 1; i < nfcats; i++) { if (Near[i].from_cat == Near[i - 1].from_cat) { for (j = i; j < nfcats - 1; j++) { Near[j].from_cat = Near[j + 1].from_cat; } nfcats--; } } G_debug(1, "%d cats loaded from vector (unique)", nfcats); } /* Go through all lines in 'from' and find nearest in 'to' for each */ /* Note: as from_type is restricted to GV_POINTS (for now) everything is simple */ count = 0; /* count of distances in 'all' mode */ /* Find nearest lines */ if (to_type & (GV_POINTS | GV_LINES)) { struct line_pnts *LLPoints; if (G_projection() == PROJECTION_LL) { LLPoints = Vect_new_line_struct(); } else { LLPoints = NULL; } G_message(_("Finding nearest feature...")); for (fline = 1; fline <= nfrom; fline++) { int tmp_tcat; double tmp_tangle, tangle; double tmp_min = (min < 0 ? 0 : min); double box_edge = 0; int done = 0; curr_step = 0; G_debug(3, "fline = %d", fline); G_percent(fline, nfrom, 2); ftype = Vect_read_line(&From, FPoints, FCats, fline); if (!(ftype & from_type)) continue; Vect_cat_get(FCats, from_field, &fcat); if (fcat < 0 && !all) continue; while (!done) { done = 1; if (!all) { /* enlarge search box until we get a hit */ /* the objective is to enlarge the search box * in the first iterations just a little bit * to keep the number of hits low */ Vect_reset_boxlist(List); while (curr_step < n_max_steps) { box_edge = max_step[curr_step]; if (box_edge < tmp_min) continue; box.E = FPoints->x[0] + box_edge; box.W = FPoints->x[0] - box_edge; box.N = FPoints->y[0] + box_edge; box.S = FPoints->y[0] - box_edge; box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX; Vect_select_lines_by_box(&To, &box, to_type, List); curr_step++; if (List->n_values > 0) break; } } else { box.E = FPoints->x[0] + max; box.W = FPoints->x[0] - max; box.N = FPoints->y[0] + max; box.S = FPoints->y[0] - max; box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX; Vect_select_lines_by_box(&To, &box, to_type, List); } G_debug(3, " %d lines in box", List->n_values); tline = 0; dist = PORT_DOUBLE_MAX; for (i = 0; i < List->n_values; i++) { tmp_tcat = -1; Vect_read_line(&To, TPoints, TCats, List->id[i]); tseg = Vect_line_distance(TPoints, FPoints->x[0], FPoints->y[0], FPoints->z[0], (Vect_is_3d(&From) && Vect_is_3d(&To)) ? WITH_Z : WITHOUT_Z, &tmp_tx, &tmp_ty, &tmp_tz, &tmp_dist, NULL, &tmp_talong); Vect_point_on_line(TPoints, tmp_talong, NULL, NULL, NULL, &tmp_tangle, NULL); if (tmp_dist > max || tmp_dist < min) continue; /* not in threshold */ /* TODO: more cats of the same field */ Vect_cat_get(TCats, to_field, &tmp_tcat); if (G_projection() == PROJECTION_LL) { /* calculate distances in meters not degrees (only 2D) */ Vect_reset_line(LLPoints); Vect_append_point(LLPoints, FPoints->x[0], FPoints->y[0], FPoints->z[0]); Vect_append_point(LLPoints, tmp_tx, tmp_ty, tmp_tz); tmp_dist = Vect_line_geodesic_length(LLPoints); Vect_reset_line(LLPoints); for (k = 0; k < tseg; k++) Vect_append_point(LLPoints, TPoints->x[k], TPoints->y[k], TPoints->z[k]); Vect_append_point(LLPoints, tmp_tx, tmp_ty, tmp_tz); tmp_talong = Vect_line_geodesic_length(LLPoints); } G_debug(4, " tmp_dist = %f tmp_tcat = %d", tmp_dist, tmp_tcat); if (all) { if (anear <= count) { anear += 10 + nfrom / 10; Near = (NEAR *) G_realloc(Near, anear * sizeof(NEAR)); } near = &(Near[count]); /* store info about relation */ near->from_cat = fcat; near->to_cat = tmp_tcat; /* -1 is OK */ near->dist = tmp_dist; near->from_x = FPoints->x[0]; near->from_y = FPoints->y[0]; near->from_z = FPoints->z[0]; near->to_x = tmp_tx; near->to_y = tmp_ty; near->to_z = tmp_tz; near->to_along = tmp_talong; /* 0 for points */ near->to_angle = tmp_tangle; near->count++; count++; } else { if (tline == 0 || (tmp_dist < dist)) { tline = List->id[i]; tcat = tmp_tcat; dist = tmp_dist; tx = tmp_tx; ty = tmp_ty; tz = tmp_tz; talong = tmp_talong; tangle = tmp_tangle; } } } G_debug(4, " dist = %f", dist); if (curr_step < n_max_steps) { /* enlarging the search box is possible */ if (tline > 0 && dist > box_edge) { /* line found but distance > search edge: * line bbox overlaps with search box, line itself is outside search box */ done = 0; } else if (tline == 0) { /* no line within max dist, but search box can still be enlarged */ done = 0; } } if (done && !all && tline > 0) { /* find near by cat */ near = (NEAR *) bsearch((void *)&fcat, Near, nfcats, sizeof(NEAR), cmp_near); G_debug(4, " near.from_cat = %d near.count = %d", near->from_cat, near->count); /* store info about relation */ if (near->count == 0 || near->dist > dist) { near->to_cat = tcat; /* -1 is OK */ near->dist = dist; near->from_x = FPoints->x[0]; near->from_y = FPoints->y[0]; near->from_z = FPoints->z[0]; near->to_x = tx; near->to_y = ty; near->to_z = tz; near->to_along = talong; /* 0 for points */ near->to_angle = tangle; } near->count++; } } /* done */ } /* next feature */ if (LLPoints) { Vect_destroy_line_struct(LLPoints); } } /* Find nearest areas */ if (to_type & GV_AREA) { G_message(_("Finding nearest areas...")); for (fline = 1; fline <= nfrom; fline++) { double tmp_min = (min < 0 ? 0 : min); double box_edge = 0; int done = 0; curr_step = 0; G_debug(3, "fline = %d", fline); G_percent(fline, nfrom, 2); ftype = Vect_read_line(&From, FPoints, FCats, fline); if (!(ftype & from_type)) continue; Vect_cat_get(FCats, from_field, &fcat); if (fcat < 0 && !all) continue; while (!done) { done = 1; if (!all) { /* enlarge search box until we get a hit */ /* the objective is to enlarge the search box * in the first iterations just a little bit * to keep the number of hits low */ Vect_reset_boxlist(List); while (curr_step < n_max_steps) { box_edge = max_step[curr_step]; if (box_edge < tmp_min) continue; box.E = FPoints->x[0] + box_edge; box.W = FPoints->x[0] - box_edge; box.N = FPoints->y[0] + box_edge; box.S = FPoints->y[0] - box_edge; box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX; Vect_select_areas_by_box(&To, &box, List); curr_step++; if (List->n_values > 0) break; } } else { box.E = FPoints->x[0] + max; box.W = FPoints->x[0] - max; box.N = FPoints->y[0] + max; box.S = FPoints->y[0] - max; box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX; Vect_select_areas_by_box(&To, &box, List); } G_debug(4, "%d areas selected by box", List->n_values); /* For each area in box check the distance */ tarea = 0; dist = PORT_DOUBLE_MAX; for (i = 0; i < List->n_values; i++) { int tmp_tcat; area = List->id[i]; G_debug(4, "%d: area %d", i, area); Vect_get_area_points(&To, area, TPoints); /* Find the distance to this area */ if (Vect_point_in_area(FPoints->x[0], FPoints->y[0], &To, area, List->box[i])) { /* in area */ tmp_dist = 0; tmp_tx = FPoints->x[0]; tmp_ty = FPoints->y[0]; } else if (Vect_point_in_poly(FPoints->x[0], FPoints->y[0], TPoints) > 0) { /* in isle */ nisles = Vect_get_area_num_isles(&To, area); for (j = 0; j < nisles; j++) { double tmp2_dist, tmp2_tx, tmp2_ty; isle = Vect_get_area_isle(&To, area, j); Vect_get_isle_points(&To, isle, TPoints); Vect_line_distance(TPoints, FPoints->x[0], FPoints->y[0], FPoints->z[0], WITHOUT_Z, &tmp2_tx, &tmp2_ty, NULL, &tmp2_dist, NULL, NULL); if (j == 0 || tmp2_dist < tmp_dist) { tmp_dist = tmp2_dist; tmp_tx = tmp2_tx; tmp_ty = tmp2_ty; } } } else { /* outside area */ Vect_line_distance(TPoints, FPoints->x[0], FPoints->y[0], FPoints->z[0], WITHOUT_Z, &tmp_tx, &tmp_ty, NULL, &tmp_dist, NULL, NULL); } if (tmp_dist > max || tmp_dist < min) continue; /* not in threshold */ Vect_get_area_cats(&To, area, TCats); tmp_tcat = -1; /* TODO: all cats of given field ? */ for (j = 0; j < TCats->n_cats; j++) { if (TCats->field[j] == to_field) { if (tmp_tcat >= 0) G_warning(_("More cats found in to_layer (area=%d)"), area); tmp_tcat = TCats->cat[j]; } } G_debug(4, " tmp_dist = %f tmp_tcat = %d", tmp_dist, tmp_tcat); if (all) { if (anear <= count) { anear += 10 + nfrom / 10; Near = (NEAR *) G_realloc(Near, anear * sizeof(NEAR)); } near = &(Near[count]); /* store info about relation */ near->from_cat = fcat; near->to_cat = tmp_tcat; /* -1 is OK */ near->dist = tmp_dist; near->from_x = FPoints->x[0]; near->from_y = FPoints->y[0]; near->to_x = tmp_tx; near->to_y = tmp_ty; near->to_along = 0; /* nonsense for areas */ near->to_angle = 0; /* not supported for areas */ near->count++; count++; } else if (tarea == 0 || tmp_dist < dist) { tarea = area; tcat = tmp_tcat; dist = tmp_dist; tx = tmp_tx; ty = tmp_ty; } } if (curr_step < n_max_steps) { /* enlarging the search box is possible */ if (tarea > 0 && dist > box_edge) { /* area found but distance > search edge: * area bbox overlaps with search box, area itself is outside search box */ done = 0; } else if (tarea == 0) { /* no area within max dist, but search box can still be enlarged */ done = 0; } } if (done && !all && tarea > 0) { /* find near by cat */ near = (NEAR *) bsearch((void *)&fcat, Near, nfcats, sizeof(NEAR), cmp_near); G_debug(4, "near.from_cat = %d near.count = %d dist = %f", near->from_cat, near->count, near->dist); /* store info about relation */ if (near->count == 0 || near->dist > dist) { near->to_cat = tcat; /* -1 is OK */ near->dist = dist; near->from_x = FPoints->x[0]; near->from_y = FPoints->y[0]; near->to_x = tx; near->to_y = ty; near->to_along = 0; /* nonsense for areas */ near->to_angle = 0; /* not supported for areas */ } near->count++; } } /* done */ } /* next feature */ } G_debug(3, "count = %d", count); /* Update database / print to stdout / create output map */ if (print_flag->answer) { /* print header */ fprintf(stdout, "from_cat"); i = 0; while (Upload[i].upload != END) { fprintf(stdout, "|%s", Upload[i].column); i++; } fprintf(stdout, "\n"); } else if (all && table_opt->answer) { /* create new table */ db_set_string(&stmt, "create table "); db_append_string(&stmt, table_opt->answer); db_append_string(&stmt, " (from_cat integer"); j = 0; while (Upload[j].upload != END) { db_append_string(&stmt, ", "); switch (Upload[j].upload) { case CAT: sprintf(buf2, "%s integer", Upload[j].column); break; case DIST: case FROM_X: case FROM_Y: case TO_X: case TO_Y: case FROM_ALONG: case TO_ALONG: case TO_ANGLE: sprintf(buf2, "%s double precision", Upload[j].column); } db_append_string(&stmt, buf2); j++; } db_append_string(&stmt, " )"); G_debug(3, "SQL: %s", db_get_string(&stmt)); if (db_execute_immediate(driver, &stmt) != DB_OK) G_fatal_error(_("Unable to create table: '%s'"), db_get_string(&stmt)); if (db_grant_on_table(driver, table_opt->answer, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) G_fatal_error(_("Unable to grant privileges on table <%s>"), table_opt->answer); } else if (!all) { /* read existing cats from table */ ncatexist = db_select_int(driver, Fi->table, Fi->key, NULL, &catexist); G_debug(1, "%d cats selected from the table", ncatexist); } update_ok = update_err = update_exist = update_notexist = update_dupl = update_notfound = 0; if (!all) { count = nfcats; } else if (print_as_matrix) { qsort((void *)Near, count, sizeof(NEAR), cmp_near_to); } if (driver) db_begin_transaction(driver); /* select 'to' attributes */ if (to_column_opt->answer) { int nrec; db_CatValArray_init(&cvarr); nrec = db_select_CatValArray(to_driver, toFi->table, toFi->key, to_column_opt->answer, NULL, &cvarr); G_debug(3, "selected values = %d", nrec); if (cvarr.ctype == DB_C_TYPE_DATETIME) { G_warning(_("DATETIME type not yet supported, no attributes will be uploaded")); } db_close_database_shutdown_driver(to_driver); } if (!(print_flag->answer || (all && !table_opt->answer))) /* no printing */ G_message("Update database..."); for (i = 0; i < count; i++) { dbCatVal *catval = 0; if (!(print_flag->answer || (all && !table_opt->answer))) /* no printing */ G_percent(i, count, 1); /* Write line connecting nearest points */ if (Outp != NULL) { Vect_reset_line(FPoints); Vect_reset_cats(FCats); Vect_append_point(FPoints, Near[i].from_x, Near[i].from_y, 0); if (Near[i].dist == 0) { Vect_write_line(Outp, GV_POINT, FPoints, FCats); } else { Vect_append_point(FPoints, Near[i].to_x, Near[i].to_y, 0); Vect_write_line(Outp, GV_LINE, FPoints, FCats); } } if (Near[i].count > 1) update_dupl++; if (Near[i].count == 0) update_notfound++; if (to_column_opt->answer && Near[i].count > 0) { db_CatValArray_get_value(&cvarr, Near[i].to_cat, &catval); } if (print_flag->answer || (all && !table_opt->answer)) { /* print only */ /* input and output is the same && calculate distances && only one upload option given -> print as a matrix */ if (print_as_matrix) { if (i == 0) { for (j = 0; j < nfrom; j++) { if (j == 0) fprintf(stdout, " "); fprintf(stdout, "|%d", Near[j].to_cat); } fprintf(stdout, "\n"); } if (i % nfrom == 0) { fprintf(stdout, "%d", Near[i].from_cat); for (j = 0; j < nfrom; j++) { print_upload(Near, Upload, i + j, &cvarr, catval); } fprintf(stdout, "\n"); } } else { fprintf(stdout, "%d", Near[i].from_cat); print_upload(Near, Upload, i, &cvarr, catval); fprintf(stdout, "\n"); } } else if (all) { /* insert new record */ sprintf(buf1, "insert into %s values ( %d ", table_opt->answer, Near[i].from_cat); db_set_string(&stmt, buf1); j = 0; while (Upload[j].upload != END) { db_append_string(&stmt, ","); switch (Upload[j].upload) { case CAT: sprintf(buf2, " %d", Near[i].to_cat); break; case DIST: sprintf(buf2, " %f", Near[i].dist); break; case FROM_X: sprintf(buf2, " %f", Near[i].from_x); break; case FROM_Y: sprintf(buf2, " %f", Near[i].from_y); break; case TO_X: sprintf(buf2, " %f", Near[i].to_x); break; case TO_Y: sprintf(buf2, " %f", Near[i].to_y); break; case FROM_ALONG: sprintf(buf2, " %f", Near[i].from_along); break; case TO_ALONG: sprintf(buf2, " %f", Near[i].to_along); break; case TO_ANGLE: sprintf(buf2, " %f", Near[i].to_angle); break; case TO_ATTR: if (catval) { switch (cvarr.ctype) { case DB_C_TYPE_INT: sprintf(buf2, " %d", catval->val.i); break; case DB_C_TYPE_DOUBLE: sprintf(buf2, " %.15e", catval->val.d); break; case DB_C_TYPE_STRING: db_set_string(&dbstr, db_get_string(catval->val.s)); db_double_quote_string(&dbstr); sprintf(buf2, " '%s'", db_get_string(&dbstr)); break; case DB_C_TYPE_DATETIME: /* TODO: formating datetime */ sprintf(buf2, " null"); break; } } else { sprintf(buf2, " null"); } break; } db_append_string(&stmt, buf2); j++; } db_append_string(&stmt, " )"); G_debug(3, "SQL: %s", db_get_string(&stmt)); if (db_execute_immediate(driver, &stmt) == DB_OK) { update_ok++; } else { update_err++; } } else { /* update table */ /* check if exists in table */ cex = (int *)bsearch((void *)&(Near[i].from_cat), catexist, ncatexist, sizeof(int), cmp_exist); if (cex == NULL) { /* cat does not exist in DB */ update_notexist++; continue; } update_exist++; sprintf(buf1, "update %s set", Fi->table); db_set_string(&stmt, buf1); j = 0; while (Upload[j].upload != END) { if (j > 0) db_append_string(&stmt, ","); sprintf(buf2, " %s =", Upload[j].column); db_append_string(&stmt, buf2); if (Near[i].count == 0) { /* no nearest found */ db_append_string(&stmt, " null"); } else { switch (Upload[j].upload) { case CAT: if (Near[i].to_cat > 0) sprintf(buf2, " %d", Near[i].to_cat); else sprintf(buf2, " null"); break; case DIST: sprintf(buf2, " %f", Near[i].dist); break; case FROM_X: sprintf(buf2, " %f", Near[i].from_x); break; case FROM_Y: sprintf(buf2, " %f", Near[i].from_y); break; case TO_X: sprintf(buf2, " %f", Near[i].to_x); break; case TO_Y: sprintf(buf2, " %f", Near[i].to_y); break; case FROM_ALONG: sprintf(buf2, " %f", Near[i].from_along); break; case TO_ALONG: sprintf(buf2, " %f", Near[i].to_along); break; case TO_ANGLE: sprintf(buf2, " %f", Near[i].to_angle); break; case TO_ATTR: if (catval) { switch (cvarr.ctype) { case DB_C_TYPE_INT: sprintf(buf2, " %d", catval->val.i); break; case DB_C_TYPE_DOUBLE: sprintf(buf2, " %.15e", catval->val.d); break; case DB_C_TYPE_STRING: db_set_string(&dbstr, db_get_string(catval->val.s)); db_double_quote_string(&dbstr); sprintf(buf2, " '%s'", db_get_string(&dbstr)); break; case DB_C_TYPE_DATETIME: /* TODO: formating datetime */ sprintf(buf2, " null"); break; } } else { sprintf(buf2, " null"); } break; } db_append_string(&stmt, buf2); } j++; } sprintf(buf2, " where %s = %d", Fi->key, Near[i].from_cat); db_append_string(&stmt, buf2); G_debug(2, "SQL: %s", db_get_string(&stmt)); if (db_execute_immediate(driver, &stmt) == DB_OK) { update_ok++; } else { update_err++; } } } G_percent(count, count, 1); if (driver) db_commit_transaction(driver); /* print stats */ if (update_dupl > 0) G_message(_("%d categories with more than 1 feature in vector map <%s>"), update_dupl, from_opt->answer); if (update_notfound > 0) G_message(_("%d categories - no nearest feature found"), update_notfound); if (!print_flag->answer) { db_close_database_shutdown_driver(driver); db_free_string(&stmt); /* print stats */ if (all && table_opt->answer) { G_message(_("%d distances calculated"), count); G_message(_("%d records inserted"), update_ok); if (update_err > 0) G_message(_("%d insert errors"), update_err); } else if (!all) { if (nfcats > 0) G_message(_("%d categories read from the map"), nfcats); if (ncatexist > 0) G_message(_("%d categories exist in the table"), ncatexist); if (update_exist > 0) G_message(_("%d categories read from the map exist in the table"), update_exist); if (update_notexist > 0) G_message(_("%d categories read from the map don't exist in the table"), update_notexist); G_message(_("%d records updated"), update_ok); if (update_err > 0) G_message(_("%d update errors"), update_err); G_free(catexist); } Vect_set_db_updated(&From); } Vect_close(&From); if (Outp != NULL) { Vect_build(Outp); Vect_close(Outp); } G_done_msg(" "); exit(EXIT_SUCCESS); }