123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474 |
- /* ****************************************************************************
- *
- * MODULE: v.label
- * AUTHOR(S): Philip Verhagen (original s.label), Radim Blazek, Hamish Bowman
- * PURPOSE: Create paint labels
- * COPYRIGHT: (C) 2000 by the GRASS Development Team
- *
- * This program is free software under the GNU General Public
- * License (>=v2). Read the file COPYING that comes with GRASS
- * for details.
- *
- *****************************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
- #include <grass/gis.h>
- #include <grass/display.h>
- #include <grass/raster.h>
- #include <grass/Vect.h>
- #include <grass/dbmi.h>
- #include <grass/glocale.h>
- #define PI M_PI
- struct Option *Xoffset, *Yoffset, *Reference, *Font, *Color, *Size;
- struct Option *Width, *Hcolor, *Hwidth, *Bcolor, *Border, *Opaque;
- int fontsize;
- char ref_pt[24];
- void print_label(FILE *, double, double, double, char *);
- int main(int argc, char **argv)
- {
- int i, cnt, nrows, txtlength, field, more;
- int type, ltype;
- int cat, direction;
- double x, y, linlength, lablength, size, space, ldist;
- double rotate, rot;
- char *mapset;
- char *txt, buf[2000];
- struct line_pnts *Points;
- struct line_cats *Cats;
- FILE *labels;
- struct Map_info Map;
- struct GModule *module;
- struct Option *Vectfile, *Typopt, *Fieldopt, *Colopt, *whereopt;
- struct Option *Labelfile, *Space, *FontSize, *Rotation;
- struct Flag *Along_flag, *Curl_flag;
- struct field_info *fi;
- dbDriver *driver;
- dbString stmt, valstr;
- dbCursor cursor;
- dbTable *table;
- dbColumn *column;
- G_gisinit(argv[0]);
- module = G_define_module();
- module->keywords = _("vector, paint labels");
- module->description =
- _("Creates paint labels for a vector map from attached attributes.");
- Labelfile = G_define_option();
- Labelfile->key = "labels";
- Labelfile->label = _("Name for new paint-label file");
- Labelfile->description =
- _("If not given the name of the input map is used");
- Labelfile->type = TYPE_STRING;
- Labelfile->required = NO;
- Labelfile->key_desc = "name";
- Vectfile = G_define_standard_option(G_OPT_V_MAP);
- Colopt = G_define_standard_option(G_OPT_COLUMN);
- Colopt->required = YES;
- Colopt->description = _("Name of attribute column to be used for labels");
- Typopt = G_define_standard_option(G_OPT_V_TYPE);
- Typopt->options = "point,line,boundary,centroid";
- Typopt->answer = "point,line,boundary,centroid";
- Fieldopt = G_define_standard_option(G_OPT_V_FIELD);
- whereopt = G_define_standard_option(G_OPT_WHERE);
- Along_flag = G_define_flag();
- Along_flag->key = 'a';
- Along_flag->description = _("Rotate labels to align with lines");
- Along_flag->guisection = _("Effects");
- Curl_flag = G_define_flag();
- Curl_flag->key = 'c';
- Curl_flag->description = _("Curl labels along lines");
- Curl_flag->guisection = _("Effects");
- Xoffset = G_define_option();
- Xoffset->key = "xoffset";
- Xoffset->description = _("Offset label in x-direction");
- Xoffset->type = TYPE_DOUBLE;
- Xoffset->answer = "0";
- Xoffset->guisection = _("Placement");
- Yoffset = G_define_option();
- Yoffset->key = "yoffset";
- Yoffset->description = _("Offset label in y-direction");
- Yoffset->type = TYPE_DOUBLE;
- Yoffset->answer = "0";
- Yoffset->guisection = _("Placement");
- Reference = G_define_option();
- Reference->key = "reference";
- Reference->description = _("Reference position");
- Reference->type = TYPE_STRING;
- Reference->multiple = YES;
- Reference->answer = "center";
- Reference->options = "center,left,right,upper,lower";
- Reference->guisection = _("Placement");
- Font = G_define_option();
- Font->key = "font";
- Font->description = _("Font name");
- Font->type = TYPE_STRING;
- Font->answer = "standard";
- Font->guisection = _("Font");
- Size = G_define_option();
- Size->key = "size";
- Size->description = _("Label size (in map-units)");
- Size->type = TYPE_DOUBLE;
- Size->answer = "100";
- Size->guisection = _("Font");
- Space = G_define_option();
- Space->key = "space";
- Space->description =
- _("Space between letters for curled labels (in map-units)");
- Space->type = TYPE_DOUBLE;
- Space->required = NO;
- Space->guisection = _("Font");
- FontSize = G_define_option();
- FontSize->key = "fontsize";
- FontSize->description = _("Label size (in points)");
- FontSize->type = TYPE_INTEGER;
- FontSize->required = NO;
- FontSize->options = "1-1000";
- FontSize->guisection = _("Font");
- Color = G_define_standard_option(G_OPT_C_FG);
- Color->label = _("Text color");
- Color->guisection = _("Colors");
- Rotation = G_define_option();
- Rotation->key = "rotation";
- Rotation->description = _("Rotation angle (degrees counter-clockwise)");
- Rotation->type = TYPE_DOUBLE;
- Rotation->required = NO;
- Rotation->options = "0-360";
- Rotation->answer = "0";
- Rotation->key_desc = "angle";
- Rotation->guisection = _("Placement");
- Width = G_define_option();
- Width->key = "width";
- Width->description = _("Border width");
- Width->type = TYPE_DOUBLE;
- Width->answer = "1";
- Width->options = "0-25";
- Width->guisection = _("Effects");
- Hcolor = G_define_standard_option(G_OPT_C_BG);
- Hcolor->key = "hcolor";
- Hcolor->label = _("Highlight color for text");
- Hcolor->answer = "none";
- Hcolor->guisection = _("Colors");
- Hwidth = G_define_option();
- Hwidth->key = "hwidth";
- Hwidth->description = _("Width of highlight coloring");
- Hwidth->type = TYPE_DOUBLE;
- Hwidth->answer = "0";
- Hwidth->guisection = _("Effects");
- Bcolor = G_define_standard_option(G_OPT_C_BG);
- Bcolor->key = "background";
- Bcolor->label = _("Background color");
- Bcolor->answer = "none";
- Bcolor->guisection = _("Colors");
- Border = G_define_standard_option(G_OPT_C_BG);
- Border->key = "border";
- Border->label = _("Border color");
- Border->answer = "none";
- Border->guisection = _("Colors");
- Opaque = G_define_option();
- Opaque->key = "opaque";
- Opaque->description =
- _("Opaque to vector (only relevant if background color is selected)");
- Opaque->type = TYPE_STRING;
- Opaque->answer = "yes";
- Opaque->options = "yes,no";
- Opaque->key_desc = "yes|no";
- Opaque->guisection = _("Colors");
- if (G_parser(argc, argv))
- exit(EXIT_FAILURE);
- if (Curl_flag->answer)
- Along_flag->answer = 1;
- db_init_string(&stmt);
- db_init_string(&valstr);
- Points = Vect_new_line_struct();
- Cats = Vect_new_cats_struct();
- type = Vect_option_to_types(Typopt);
- size = atof(Size->answer);
- space = size; /* default: set spacing according to letter size (map units) */
- rotate = atof(Rotation->answer);
- if (FontSize->answer) {
- fontsize = atoi(FontSize->answer);
- /* figure out space param dynamically from current dispay */
- /* don't bother if Space was explicitly given (bypasses xmon req) */
- if (Along_flag->answer && !Space->answer) {
- if (R_open_driver() != 0) /* connect to the driver */
- G_fatal_error(_("No graphics device selected"));
- /* Read in the map region associated with graphics window */
- D_setup(0);
- space = fontsize / D_get_u_to_d_xconv(); /* in earth units */
- R_close_driver();
- }
- }
- else
- fontsize = 0;
- /* or if user explicitly gave a number for letter spacing, use that */
- if (Space->answer)
- space = atof(Space->answer);
- if (Along_flag->answer && !fontsize &&
- (size / space >= 2 || size / space <= 0.5))
- G_warning(_("size and space options vary significantly which may lead to crummy output"));
- /* parse reference answers */
- i = 0;
- strcpy(ref_pt, "");
- while (Reference->answers[i]) {
- if (i > 1)
- G_fatal_error(_("Too many parameters for <reference>"));
- if (i > 0)
- strcat(ref_pt, " ");
- strncat(ref_pt, Reference->answers[i], 7);
- i++;
- }
- /* open vector */
- mapset = G_find_vector2(Vectfile->answer, NULL);
- if (mapset == NULL)
- G_fatal_error(_("Vector map <%s> not found"), Vectfile->answer);
- Vect_open_old(&Map, Vectfile->answer, mapset);
- /* open database */
- field = atoi(Fieldopt->answer);
- fi = Vect_get_field(&Map, field);
- if (fi == NULL)
- G_fatal_error(_("Unable to get layer info for vector map"));
- 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);
- /* open labels */
- if (!Labelfile->answer)
- Labelfile->answer = Vectfile->answer;
- labels = G_fopen_new("paint/labels", Labelfile->answer);
- /* write label */
- cnt = 0;
- while (1) {
- ltype = Vect_read_next_line(&Map, Points, Cats);
- if (ltype == -1)
- G_fatal_error(_("Unable to read vector map"));
- if (ltype == -2)
- break; /* EOF */
- if (!(type & ltype))
- continue;
- Vect_cat_get(Cats, field, &cat);
- if (cat < 0)
- continue; /* no cat for this field */
- /* Read label from database */
- if (whereopt->answer) {
- sprintf(buf, "select %s from %s where %s = %d and %s",
- Colopt->answer, fi->table, fi->key, cat,
- whereopt->answer);
- }
- else {
- sprintf(buf, "select %s from %s where %s = %d",
- Colopt->answer, fi->table, fi->key, cat);
- }
- G_debug(3, "SQL: %s", buf);
- db_set_string(&stmt, buf);
- if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) !=
- DB_OK)
- G_fatal_error(_("Unable to select attributes"));
- nrows = db_get_num_rows(&cursor);
- if (nrows < 1) {
- /* not optimal, but the warning isn't /that/ critical. */
- if (!whereopt->answer) {
- G_warning(_("No record for category %d in table <%s>"),
- cat, fi->table);
- }
- continue;
- }
- if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK || !more)
- continue;
- table = db_get_cursor_table(&cursor);
- column = db_get_table_column(table, 0); /* first column */
- db_convert_column_value_to_string(column, &valstr);
- db_close_cursor(&cursor);
- txt = db_get_string(&valstr);
- G_debug(3, "Label: %s", txt);
- txtlength = strlen(txt);
- if (txtlength == 0)
- continue;
- /* Line length */
- linlength = Vect_line_length(Points);
- if (ltype & GV_POINTS) {
- print_label(labels, Points->x[0], Points->y[0], rotate, txt);
- }
- else if (!Along_flag->answer) { /* Line, but not along */
- /* get centre */
- Vect_point_on_line(Points, linlength / 2, &x, &y, NULL, NULL,
- NULL);
- print_label(labels, x, y, rotate, txt);
- }
- else { /* Along line */
- /* find best orientation (most letters by bottom to down side */
- rotate = 0;
- for (i = 0; i < txtlength; i++) {
- /* distance of the letter from the beginning of line */
- lablength = txtlength * space;
- ldist = i * space + (linlength - lablength) / 2;
- if (ldist < 0)
- ldist = 0;
- if (ldist > linlength)
- ldist = linlength;
- Vect_point_on_line(Points, ldist, &x, &y, NULL, &rot, NULL);
- rot = rot * 180 / PI;
- if (rot > 90 || rot < -90)
- rotate += -1;
- else
- rotate += 1;
- }
- if (rotate >= 0) {
- direction = 0;
- }
- else {
- direction = 1;
- }
- if (Curl_flag->answer) {
- for (i = 0; i < txtlength; i++) {
- /* distance of the letter from the beginning of line */
- lablength = txtlength * space;
- ldist = i * space + (linlength - lablength) / 2;
- if (ldist < 0)
- ldist = 0;
- if (ldist > linlength)
- ldist = linlength;
- Vect_point_on_line(Points, ldist, &x, &y, NULL, &rotate,
- NULL);
- rotate = rotate * 180 / PI;
- if (direction == 0) {
- sprintf(buf, "%c", txt[i]);
- }
- else {
- sprintf(buf, "%c", txt[txtlength - i - 1]);
- rotate += 180;
- }
- print_label(labels, x, y, rotate, buf);
- }
- }
- else { /* same as above but take center value for placement & rotation */
- i = (int)(txtlength / 2.0 + 0.5);
- lablength = txtlength * space;
- ldist = i * space + (linlength - lablength) / 2;
- if (ldist < 0)
- ldist = 0;
- if (ldist > linlength)
- ldist = linlength;
- Vect_point_on_line(Points, ldist, &x, &y, NULL, &rotate,
- NULL);
- rotate = rotate * 180 / PI;
- if (direction != 0)
- rotate += 180;
- print_label(labels, x, y, rotate, txt);
- }
- }
- cnt++;
- }
- Vect_destroy_line_struct(Points);
- Vect_close(&Map);
- db_close_database_shutdown_driver(driver);
- fclose(labels);
- G_message(_("Labeled %d lines."), cnt);
- exit(EXIT_SUCCESS);
- }
- void print_label(FILE * labels, double x, double y, double rotate,
- char *label)
- {
- fprintf(labels, "east: %f\n", x);
- fprintf(labels, "north: %f\n", y);
- fprintf(labels, "xoffset: %s\n", Xoffset->answer);
- fprintf(labels, "yoffset: %s\n", Yoffset->answer);
- fprintf(labels, "ref: %s\n", ref_pt);
- fprintf(labels, "font: %s\n", Font->answer);
- fprintf(labels, "color: %s\n", Color->answer);
- if (fontsize)
- fprintf(labels, "fontsize: %d\n", fontsize);
- else
- fprintf(labels, "size: %s\n", Size->answer);
- fprintf(labels, "width: %s\n", Width->answer);
- fprintf(labels, "hcolor: %s\n", Hcolor->answer);
- fprintf(labels, "hwidth: %s\n", Hwidth->answer);
- fprintf(labels, "background: %s\n", Bcolor->answer);
- fprintf(labels, "border: %s\n", Border->answer);
- fprintf(labels, "opaque: %s\n", Opaque->answer);
- if (rotate != 0)
- fprintf(labels, "rotate: %f\n", rotate);
- fprintf(labels, "text: %s\n\n", label);
- }
|