コード例 #1
0
ファイル: merge.c プロジェクト: rashadkm/grass_cmake
static int merge_lines(struct line_pnts *Points1, struct line_cats *Cats1,
		       struct line_pnts *Points2, struct line_cats *Cats2,
		       double thresh, struct line_pnts **Points)
{
    struct line_pnts *ps = *Points;
    struct line_cats *cs = Cats1;

    int i, mindistidx;
    double mindist;

    /* find mininal distance and its index */
    mindist = Vedit_get_min_distance(Points1, Points2, 0,	/* TODO 3D */
				     &mindistidx);

    G_debug(3, "   merge line ? index: %d, mindist: %g, thresh: %g",
	    mindistidx, mindist, thresh);

    if (thresh > 0 && mindist > thresh) {
	return 0;
    }

    /* set index and other things */
    switch (mindistidx) {
	/* for each mindistidx create new line */
    case 0:
	Vect_append_points(ps, Points2, GV_BACKWARD);
	if (ps->n_points == Points2->n_points)
	    Vect_append_points(ps, Points1, GV_FORWARD);
	break;
    case 1:
	Vect_append_points(ps, Points2, GV_FORWARD);
	if (ps->n_points == Points2->n_points)
	    Vect_append_points(ps, Points1, GV_FORWARD);
	break;
    case 2:
	if (ps->n_points == 0)
	    Vect_append_points(ps, Points1, GV_FORWARD);
	Vect_append_points(ps, Points2, GV_FORWARD);
	break;
    case 3:
	if (ps->n_points == 0)
	    Vect_append_points(ps, Points1, GV_FORWARD);
	Vect_append_points(ps, Points2, GV_BACKWARD);
	break;
    default:
	break;
    }

    /* remove duplicate points */
    Vect_line_prune(ps);

    /* copy categories if needed */
    for (i = 0; i < Cats2->n_cats; i++) {
	Vect_cat_set(cs, Cats2->field[i], Cats2->cat[i]);
    }

    return 1;
}
コード例 #2
0
ファイル: area_pg.c プロジェクト: rashadkm/grass_cmake
/*!
  \brief Get area boundary points (PostGIS Topology)
  
  Used by Vect_build_line_area() and Vect_get_area_points().

  \param Map pointer to Map_info struct
  \param lines array of boundary lines
  \param n_lines number of lines in array
  \param[out] APoints pointer to output line_pnts struct

  \return number of points
  \return -1 on error
*/
int Vect__get_area_points_pg(const struct Map_info *Map, const plus_t *lines, int n_lines,
                             struct line_pnts *APoints)
{
    int i, direction;
    
    struct Format_info_pg *pg_info;
    
    PGresult *res;
    
    pg_info = (struct Format_info_pg *)&(Map->fInfo.pg);
   
    Vect_reset_line(APoints);

    res = build_stmt(&(Map->plus), pg_info, lines, n_lines);
    if (!res)
        return -1;
    
    for (i = 0; i < n_lines; i++) {
        Vect__cache_feature_pg(PQgetvalue(res, i, 0), FALSE, FALSE,
                               &(pg_info->cache), NULL); /* do caching in readable way */
	direction = lines[i] > 0 ? GV_FORWARD : GV_BACKWARD;
	Vect_append_points(APoints, pg_info->cache.lines[0], direction);
	APoints->n_points--;	/* skip last point, avoids duplicates */
    }
    APoints->n_points++;	/* close polygon */

    PQclear(res);
    
    return APoints->n_points;
}
コード例 #3
0
ファイル: area.c プロジェクト: caomw/grass
/*!
  \brief Get area boundary points (native format)
  
  Used by Vect_build_line_area() and Vect_get_area_points().
  
  \param Map pointer to Map_info struct
  \param lines array of boundary lines
  \param n_lines number of lines in array
  \param[out] APoints pointer to output line_pnts struct

  \return number of points
  \return -1 on error
*/
int Vect__get_area_points_nat(const struct Map_info *Map, const plus_t *lines, int n_lines,
                              struct line_pnts *BPoints)
{
    int i, line, aline, dir;
    static struct line_pnts *Points;
    
    if (!Points)
        Points = Vect_new_line_struct();
    
    Vect_reset_line(BPoints);
    for (i = 0; i < n_lines; i++) {
        line = lines[i];
        aline = abs(line);
        G_debug(5, "  append line(%d) = %d", i, line);
        
        if (0 > Vect_read_line(Map, Points, NULL, aline))
            return -1;
        
        dir = line > 0 ? GV_FORWARD : GV_BACKWARD;
        Vect_append_points(BPoints, Points, dir);
        BPoints->n_points--;    /* skip last point, avoids duplicates */
    }
    BPoints->n_points++;        /* close polygon */

    return BPoints->n_points;
}
コード例 #4
0
void QgsGrassEditNewLine::mouseMove( QgsPoint & newPoint )
{
  if ( e->mEditPoints->n_points > 0 )
  {
    // Draw the line with new segment
    Vect_reset_line( e->mPoints );
    Vect_append_points( e->mPoints, e->mEditPoints, GV_FORWARD );
    Vect_append_point( e->mPoints, newPoint.x(), newPoint.y(), 0.0 );
    e->displayDynamic( e->mPoints );
  }
}
コード例 #5
0
ファイル: arcs.c プロジェクト: AsherBond/MondocosmOS
/**
 * \brief Create network arcs (edge) based on given point vector map (nodes)
 *
 * \param file input file defining arcs
 * \param Points input vector point map
 * \param Out output vector map
 * \param afield arcs layer 
 * \param nfield nodes layer 
 *
 * \return number of new arcs
 */
int create_arcs(FILE * file, struct Map_info *Pnts,
		struct Map_info *Out, int afield, int nfield)
{
    char buff[1024];
    int lcat, fcat, tcat;
    int node1, node2;
    int narcs;

    struct line_pnts *points, *points2;
    struct line_cats *cats;

    points = Vect_new_line_struct();
    points2 = Vect_new_line_struct();
    points = Vect_new_line_struct();
    cats = Vect_new_cats_struct();

    narcs = 0;

    while (G_getl2(buff, sizeof(buff) - 1, file)) {
	if (sscanf(buff, "%d%d%d", &lcat, &fcat, &tcat) != 3)
	    G_fatal_error(_("Error reading file: '%s'"), buff);

	node1 = find_node(Pnts, afield, fcat);
	node2 = find_node(Pnts, afield, tcat);

	if (node1 < 1 || node2 < 1) {
	    G_warning(_("Skipping arc %d"), lcat);
	    continue;
	}

	/* geometry */
	Vect_read_line(Pnts, points, cats, node1);
	field2n(cats, nfield);
	Vect_write_line(Out, GV_POINT, points, cats);
	Vect_read_line(Pnts, points2, cats, node2);
	field2n(cats, nfield);
	Vect_write_line(Out, GV_POINT, points2, cats);
	Vect_append_points(points, points2, GV_FORWARD);

	/* category */
	Vect_reset_cats(cats);
	Vect_cat_set(cats, afield, lcat);
	Vect_write_line(Out, GV_LINE, points, cats);

	narcs++;
    }

    Vect_destroy_line_struct(points);
    Vect_destroy_cats_struct(cats);

    return narcs;
}
コード例 #6
0
void QgsGrassEditNewLine::deactivate()
{
  // Delete last segment
  if ( e->mEditPoints->n_points > 1 )
  {
    Vect_reset_line( e->mPoints );
    Vect_append_points( e->mPoints, e->mEditPoints, GV_FORWARD );
    e->displayDynamic( e->mPoints );
  }
  e->setCanvasPrompt( tr( "New vertex" ), "", "" );

  QgsGrassEditTool::deactivate(); // call default bahivour
}
コード例 #7
0
ファイル: area.c プロジェクト: AsherBond/MondocosmOS
/*!
   \brief Returns polygon array of points (outer ring) of given area

   \param Map pointer to Map_info structure
   \param area area id
   \param[out] BPoints points array

   \return number of points
   \return -1 on error
 */
int Vect_get_area_points(const struct Map_info *Map,
			 int area, struct line_pnts *BPoints)
{
    int i, line, aline, dir;
    const struct Plus_head *Plus;
    struct P_area *Area;
    static int first_time = 1;
    static struct line_pnts *Points;

    G_debug(3, "Vect_get_area_points(): area = %d", area);
    BPoints->n_points = 0;

    Plus = &(Map->plus);
    Area = Plus->Area[area];

    if (Area == NULL) {		/* dead area */
	G_warning(_("Attempt to read points of nonexistent area"));
	return -1;		/* error , because we should not read dead areas */
    }

    if (first_time == 1) {
	Points = Vect_new_line_struct();
	first_time = 0;
    }

    G_debug(3, "  n_lines = %d", Area->n_lines);
    for (i = 0; i < Area->n_lines; i++) {
	line = Area->lines[i];
	aline = abs(line);
	G_debug(3, "  append line(%d) = %d", i, line);

	if (0 > Vect_read_line(Map, Points, NULL, aline)) {
	    G_fatal_error(_("Unable to read read line %d"), aline);
	}

	G_debug(3, "  line n_points = %d", Points->n_points);

	if (line > 0)
	    dir = GV_FORWARD;
	else
	    dir = GV_BACKWARD;

	Vect_append_points(BPoints, Points, dir);
	if (i != (Area->n_lines - 1))	/* all but not last */
	    BPoints->n_points--;
	G_debug(3, "  area n_points = %d", BPoints->n_points);
    }

    return BPoints->n_points;
}
コード例 #8
0
void QgsGrassEditNewLine::activate()
{
  QgsDebugMsg( "entered." );

  // Display dynamic segment
  if ( e->mEditPoints->n_points > 0 )
  {
    Vect_reset_line( e->mPoints );
    Vect_append_points( e->mPoints, e->mEditPoints, GV_FORWARD );
    QgsPoint point = toMapCoordinates( e->mCanvas->mouseLastXY() );
    Vect_append_point( e->mPoints, point.x(), point.y(), 0.0 );
    e->displayDynamic( e->mPoints );
  }

  QgsGrassEditTool::activate(); // call default bahivour
}
コード例 #9
0
ファイル: area.c プロジェクト: AsherBond/MondocosmOS
/*!
   \brief Returns polygon array of points for given isle

   \param Map vector map
   \param isle island id
   \param[out] BPoints points array

   \return number of points
   \return -1 on error
 */
int
Vect_get_isle_points(const struct Map_info *Map,
		     int isle, struct line_pnts *BPoints)
{
    int i, line, aline, dir;
    const struct Plus_head *Plus;
    struct P_isle *Isle;
    static int first_time = 1;
    static struct line_pnts *Points;

    G_debug(3, "Vect_get_isle_points(): isle = %d", isle);
    BPoints->n_points = 0;

    Plus = &(Map->plus);
    Isle = Plus->Isle[isle];

    if (first_time == 1) {
	Points = Vect_new_line_struct();
	first_time = 0;
    }

    G_debug(3, "  n_lines = %d", Isle->n_lines);
    for (i = 0; i < Isle->n_lines; i++) {
	line = Isle->lines[i];
	aline = abs(line);
	G_debug(3, "  append line(%d) = %d", i, line);

	if (0 > Vect_read_line(Map, Points, NULL, aline)) {
	    G_fatal_error(_("Unable to read line %d"), aline);
	}

	G_debug(3, "  line n_points = %d", Points->n_points);

	if (line > 0)
	    dir = GV_FORWARD;
	else
	    dir = GV_BACKWARD;

	Vect_append_points(BPoints, Points, dir);
	if (i != (Isle->n_lines - 1))	/* all but not last */
	    BPoints->n_points--;
	G_debug(3, "  isle n_points = %d", BPoints->n_points);
    }

    return (BPoints->n_points);
}
コード例 #10
0
void QgsGrassEditMoveLine::mouseMove( QgsPoint & newPoint )
{
  // Move previously selected line
  if ( e->mSelectedLine > 0 )
  {
    // Transform coordinates
    Vect_reset_line( e->mPoints );
    Vect_append_points( e->mPoints, e->mEditPoints, GV_FORWARD );

    for ( int i = 0; i < e->mPoints->n_points; i++ )
    {
      e->mPoints->x[i] += newPoint.x() - e->mLastPoint.x();
      e->mPoints->y[i] += newPoint.y() - e->mLastPoint.y();
    }

    e->displayDynamic( e->mPoints );
  }
}
コード例 #11
0
ファイル: line_area.c プロジェクト: GRASS-GIS/grass-ci
/* merge a given line with all other lines of the same type and 
 * with the same categories */
static int merge_line(struct Map_info *Map, int line,
		      struct line_pnts *MPoints, struct line_cats *MCats)
{
    int nlines, i, first, last, next_line, curr_line;
    int merged = 0, newl = 0;
    int next_node, direction, node_n_lines, type, ltype, lines_type;
    static struct ilist *List = NULL;
    static struct line_pnts *Points = NULL;
    static struct line_cats *Cats = NULL;
    type = GV_LINE;

    nlines = Vect_get_num_lines(Map);

    if (!Points)
	Points = Vect_new_line_struct();
    if (!Cats)
	Cats = Vect_new_cats_struct();
    if (!List)
	List = Vect_new_list();

    Vect_reset_line(Points);
    Vect_reset_cats(Cats);
    Vect_reset_cats(MCats);
    Vect_reset_list(List);

    if (!Vect_line_alive(Map, line))
	return 0;

    ltype = Vect_get_line_type(Map, line);

    if (!(ltype & type))
	return 0;
	
    Vect_read_line(Map, MPoints, MCats, line);

    /* special cases:
     *  - loop back to start boundary via several other boundaries
     *  - one boundary forming closed loop
     *  - node with 3 entries but only 2 boundaries, one of them connecting twice,
     *    the other one must then be topologically incorrect in case of boundary */

    /* go backward as long as there is only one other line/boundary at the current node */
    G_debug(3, "go backward");
    Vect_get_line_nodes(Map, line, &next_node, NULL);

    first = -line;
    while (1) {
	node_n_lines = Vect_get_node_n_lines(Map, next_node);
	/* count lines/boundaries at this node */
	lines_type = 0;
	next_line = first;
	for (i = 0; i < node_n_lines; i++) {
	    curr_line = Vect_get_node_line(Map, next_node, i);
	    if ((Vect_get_line_type(Map, abs(curr_line)) & GV_LINES))
		lines_type++;
	    if ((Vect_get_line_type(Map, abs(curr_line)) == ltype)) {
		if (abs(curr_line) != abs(first)) {
		    Vect_read_line(Map, NULL, Cats, abs(curr_line));
		    
		    /* catgories must be identical */
		    if (compare_cats(MCats, Cats) == 0)
			next_line = curr_line;
		}
	    }
	}
	if (lines_type == 2 && abs(next_line) != abs(first) &&
	    abs(next_line) != line) {
	    first = next_line;

	    if (first < 0) {
		Vect_get_line_nodes(Map, -first, &next_node, NULL);
	    }
	    else {
		Vect_get_line_nodes(Map, first, NULL, &next_node);
	    }
	}
	else
	    break;
    }

    /* go forward as long as there is only one other line/boundary at the current node */
    G_debug(3, "go forward");

    /* reverse direction */
    last = -first;

    if (last < 0) {
	Vect_get_line_nodes(Map, -last, &next_node, NULL);
    }
    else {
	Vect_get_line_nodes(Map, last, NULL, &next_node);
    }

    Vect_reset_list(List);
    while (1) {
	G_ilist_add(List, last);
	node_n_lines = Vect_get_node_n_lines(Map, next_node);
	lines_type = 0;
	next_line = last;
	for (i = 0; i < node_n_lines; i++) {
	    curr_line = Vect_get_node_line(Map, next_node, i);
	    if ((Vect_get_line_type(Map, abs(curr_line)) & GV_LINES))
		lines_type++;
	    if ((Vect_get_line_type(Map, abs(curr_line)) == ltype)) {
		if (abs(curr_line) != abs(last)) {
		    Vect_read_line(Map, NULL, Cats, abs(curr_line));
		    
		    if (compare_cats(MCats, Cats) == 0)
			next_line = curr_line;
		}
	    }
	}

	if (lines_type == 2 && abs(next_line) != abs(last) &&
	    abs(next_line) != abs(first)) {
	    last = next_line;

	    if (last < 0) {
		Vect_get_line_nodes(Map, -last, &next_node, NULL);
	    }
	    else {
		Vect_get_line_nodes(Map, last, NULL, &next_node);
	    }
	}
	else
	    break;
    }

    /* merge lines */
    G_debug(3, "merge %d lines", List->n_values);
    Vect_reset_line(MPoints);

    for (i = 0; i < List->n_values; i++) {
	Vect_reset_line(Points);
	Vect_read_line(Map, Points, Cats, abs(List->value[i]));
	direction = (List->value[i] < 0 ? GV_BACKWARD : GV_FORWARD);
	Vect_append_points(MPoints, Points, direction);
	MPoints->n_points--;
	Vect_delete_line(Map, abs(List->value[i]));
    }
    MPoints->n_points++;
    merged += List->n_values;
    newl++;

    return merged;
}
コード例 #12
0
ファイル: buffer.c プロジェクト: imincik/pkg-grass
/*!
   \brief Create buffer around the line line.

   Buffer is closed counter clockwise polygon.
   Warning: output line may contain loops!

   \param InPoints input line
   \param distance create buffer in distance
   \param tolerance maximum distance between theoretical arc and polygon segments
   \param[out] OutPoints output line
 */
void
Vect_line_buffer(struct line_pnts *InPoints, double distance,
		 double tolerance, struct line_pnts *OutPoints)
{
    double dangle;
    int side, npoints;
    static struct line_pnts *Points = NULL;
    static struct line_pnts *PPoints = NULL;

    distance = fabs(distance);

    dangle = 2 * acos(1 - tolerance / fabs(distance));	/* angle step */

    if (Points == NULL)
	Points = Vect_new_line_struct();

    if (PPoints == NULL)
	PPoints = Vect_new_line_struct();

    /* Copy and prune input */
    Vect_reset_line(Points);
    Vect_append_points(Points, InPoints, GV_FORWARD);
    Vect_line_prune(Points);

    Vect_reset_line(OutPoints);

    npoints = Points->n_points;
    if (npoints <= 0) {
	return;
    }
    else if (npoints == 1) {	/* make a circle */
	double angle, x, y;

	for (angle = 0; angle < 2 * PI; angle += dangle) {
	    x = Points->x[0] + distance * cos(angle);
	    y = Points->y[0] + distance * sin(angle);
	    Vect_append_point(OutPoints, x, y, 0);
	}
	/* Close polygon */
	Vect_append_point(OutPoints, OutPoints->x[0], OutPoints->y[0], 0);
    }
    else {			/* 2 and more points */
	for (side = 0; side < 2; side++) {
	    double angle, sangle;
	    double lx1, ly1, lx2, ly2;
	    double x, y, nx, ny, sx, sy, ex, ey;

	    /* Parallel on one side */
	    if (side == 0) {
		Vect_line_parallel(Points, distance, tolerance, 0, PPoints);
		Vect_append_points(OutPoints, PPoints, GV_FORWARD);
	    }
	    else {
		Vect_line_parallel(Points, -distance, tolerance, 0, PPoints);
		Vect_append_points(OutPoints, PPoints, GV_BACKWARD);
	    }

	    /* Arc at the end */
	    /* 2 points at theend of original line */
	    if (side == 0) {
		lx1 = Points->x[npoints - 2];
		ly1 = Points->y[npoints - 2];
		lx2 = Points->x[npoints - 1];
		ly2 = Points->y[npoints - 1];
	    }
	    else {
		lx1 = Points->x[1];
		ly1 = Points->y[1];
		lx2 = Points->x[0];
		ly2 = Points->y[0];
	    }

	    /* normalized vector */
	    vect(lx1, ly1, lx2, ly2, &nx, &ny);

	    /* starting point */
	    sangle = atan2(-nx, ny);	/* starting angle */
	    sx = lx2 + ny * distance;
	    sy = ly2 - nx * distance;

	    /* end point */
	    ex = lx2 - ny * distance;
	    ey = ly2 + nx * distance;

	    Vect_append_point(OutPoints, sx, sy, 0);

	    /* arc */
	    for (angle = dangle; angle < PI; angle += dangle) {
		x = lx2 + distance * cos(sangle + angle);
		y = ly2 + distance * sin(sangle + angle);
		Vect_append_point(OutPoints, x, y, 0);
	    }

	    Vect_append_point(OutPoints, ex, ey, 0);
	}

	/* Close polygon */
	Vect_append_point(OutPoints, OutPoints->x[0], OutPoints->y[0], 0);
    }
    Vect_line_prune(OutPoints);

    return;
}
コード例 #13
0
ファイル: area.c プロジェクト: caomw/grass
int display_area(struct Map_info *Map, struct cat_list *Clist, const struct Cell_head *window,
		 const struct color_rgb *bcolor, const struct color_rgb *fcolor, int chcat,
		 int id_flag, int cats_color_flag, 
		 int default_width, double width_scale,
		 struct Colors *zcolors,
		 dbCatValArray *cvarr_rgb, struct Colors *colors,
		 dbCatValArray *cvarr_width, int nrec_width)
{
    int num, area, isle, n_isles, n_points;
    double xl, yl;
    struct line_pnts *Points, * APoints, **IPoints;
    struct line_cats *Cats;
    int n_ipoints_alloc;
    int cat, centroid;
    int red, grn, blu;

    int i, custom_rgb, found;
    int width;
    struct bound_box box;
    
    if (Vect_level(Map) < 2) {
	G_warning(_("Unable to display areas, topology not available. "
		    "Please try to rebuild topology using "
		    "v.build or v.build.all."));
	return 1;
    }

    G_debug(1, "display areas:");
    
    centroid = 0;
    Points = Vect_new_line_struct();
    APoints = Vect_new_line_struct();
    n_ipoints_alloc = 10;
    IPoints = (struct line_pnts **)G_malloc(n_ipoints_alloc * sizeof(struct line_pnts *));
    for (i = 0; i < n_ipoints_alloc; i++) {
	IPoints[i] = Vect_new_line_struct();
    }
    Cats = Vect_new_cats_struct();
    
    num = Vect_get_num_areas(Map);
    G_debug(2, "\tn_areas = %d", num);

    for (area = 1; area <= num; area++) {
	G_debug(3, "\tarea = %d", area);

	if (!Vect_area_alive(Map, area))
	    continue;

	centroid = Vect_get_area_centroid(Map, area);
	if (!centroid) {
	    continue;
	}

	/* Check box */
	Vect_get_area_box(Map, area, &box);
	if (box.N < window->south || box.S > window->north ||
	    box.E < window->west || box.W > window->east) {
	    if (window->proj != PROJECTION_LL)
		continue;
	    else { /* out of bounds for -180 to 180, try 0 to 360 as well */
		if (box.N < window->south || box.S > window->north)
		    continue;
		if (box.E + 360 < window->west || box.W + 360 > window->east)
		    continue;
	    }
	}

	custom_rgb = FALSE;
		
	found = FALSE;
	if (chcat) {		
	    if (id_flag) {
		if (!(Vect_cat_in_cat_list(area, Clist)))
		    continue;
	    }
	    else {
		G_debug(3, "centroid = %d", centroid);
		if (centroid < 1)
		    continue;
		Vect_read_line(Map, Points, Cats, centroid);

		for (i = 0; i < Cats->n_cats; i++) {
		    G_debug(3, "  centroid = %d, field = %d, cat = %d",
			    centroid, Cats->field[i], Cats->cat[i]);

		    if (Cats->field[i] == Clist->field &&
			Vect_cat_in_cat_list(Cats->cat[i], Clist)) {
			found = TRUE;
			break;
		    }
		}
		
		if (!found)
		    continue;
	    }
	}
	else if (Clist->field > 0) {
	    found = FALSE;
	    G_debug(3, "\tcentroid = %d", centroid);
	    if (centroid < 1)
		continue;
	    Vect_read_line(Map, NULL, Cats, centroid);

	    for (i = 0; i < Cats->n_cats; i++) {
		G_debug(3, "\tcentroid = %d, field = %d, cat = %d", centroid,
			Cats->field[i], Cats->cat[i]);
		if (Cats->field[i] == Clist->field) {
		    found = TRUE;
		    break;
		}
	    }
	    
	    /* lines with no category will be displayed */
	    if (Cats->n_cats > 0 && !found)
		continue;
	}

	/* fill */
	Vect_get_area_points(Map, area, APoints);
	G_debug(3, "\tn_points = %d", APoints->n_points);
	if (APoints->n_points < 3) {
	    G_warning(_("Invalid area %d skipped (not enough points)"), area);
	    continue;
	}
	Vect_reset_line(Points);
	Vect_append_points(Points, APoints, GV_FORWARD);

	n_points = Points->n_points;
	xl = Points->x[n_points - 1];
	yl = Points->y[n_points - 1];
	n_isles = Vect_get_area_num_isles(Map, area);
	if (n_isles >= n_ipoints_alloc) {
	    IPoints = (struct line_pnts **)G_realloc(IPoints, (n_isles + 10) * sizeof(struct line_pnts *));
	    for (i = n_ipoints_alloc; i < n_isles + 10; i++) {
		IPoints[i] = Vect_new_line_struct();
	    }
	    n_ipoints_alloc = n_isles + 10;
	}
	for (i = 0; i < n_isles; i++) {
	    isle = Vect_get_area_isle(Map, area, i);
	    Vect_get_isle_points(Map, isle, IPoints[i]);
	    Vect_append_points(Points, IPoints[i], GV_FORWARD);
	    Vect_append_point(Points, xl, yl, 0.0);	/* ??? */
	}

	cat = Vect_get_area_cat(Map, area,
				(Clist->field > 0 ? Clist->field :
				 (Cats->n_cats > 0 ? Cats->field[0] : 1)));

	if (!centroid && cat == -1) {
	    continue;
	}

	/* z height colors */
	if (zcolors) {
	    if (Rast_get_d_color(&Points->z[0], &red, &grn, &blu, zcolors) == 1)
		custom_rgb = TRUE;
	    else
		custom_rgb = FALSE;
	}

        /* custom colors */
	if (colors || cvarr_rgb) {
	    custom_rgb = get_table_color(cat, area, colors, cvarr_rgb,
					 &red, &grn, &blu);
	}
	
	/* random colors */
	if (cats_color_flag) {
	    custom_rgb = get_cat_color(area, Cats, Clist,
				       &red, &grn, &blu);
	}
	
	/* line width */
	if (nrec_width) {
	    width = (int) get_property(cat, area, cvarr_width,
				       (double) width_scale,
				       (double) default_width);
	    
	    D_line_width(width);
	}
	
	if (fcolor || zcolors) {
	    if (!cvarr_rgb && !cats_color_flag && !zcolors && !colors) {
		D_RGB_color(fcolor->r, fcolor->g, fcolor->b);
		D_polygon_abs(Points->x, Points->y, Points->n_points);
	    }
	    else {
		if (custom_rgb) {
		    D_RGB_color((unsigned char)red, (unsigned char)grn,
				(unsigned char)blu);
		}
		else {
		    D_RGB_color(fcolor->r, fcolor->g, fcolor->b);
		}
		if (cat >= 0) {
		    D_polygon_abs(Points->x, Points->y, Points->n_points);
		}
	    }
	}

	/* boundary */
	if (bcolor) {
	    if (custom_rgb) {
		D_RGB_color((unsigned char)red, (unsigned char)grn,
			    (unsigned char)blu);
	    }
	    else {
		D_RGB_color(bcolor->r, bcolor->g, bcolor->b);
	    }
	    /* use different user defined render methods */
	    D_polyline_abs(APoints->x, APoints->y, APoints->n_points);
	    for (i = 0; i < n_isles; i++) {
		/* use different user defined render methods */
		D_polyline_abs(IPoints[i]->x, IPoints[i]->y, IPoints[i]->n_points);
	    }
	}
    }

    if ((colors || cvarr_rgb) && get_num_color_rules_skipped() > 0)
        G_warning(_n("%d invalid color rule for areas skipped", 
                "%d invalid color rules for areas skipped", 
                get_num_color_rules_skipped()), 
                get_num_color_rules_skipped());

    Vect_destroy_line_struct(Points);
    Vect_destroy_line_struct(APoints);
    for (i = 0; i < n_ipoints_alloc; i++) {
	Vect_destroy_line_struct(IPoints[i]);
    }
    G_free(IPoints);
    Vect_destroy_cats_struct(Cats);

    return 0;
}
コード例 #14
0
ファイル: main.c プロジェクト: rashadkm/grass_cmake
int main(int argc, char *argv[])
{
    struct Map_info In, Out, Error;
    struct line_pnts *Points;
    struct line_cats *Cats;
    int i, type, iter;
    struct GModule *module;	/* GRASS module for parsing arguments */
    struct Option *map_in, *map_out, *error_out, *thresh_opt, *method_opt,
	*look_ahead_opt;
    struct Option *iterations_opt, *cat_opt, *alpha_opt, *beta_opt, *type_opt;
    struct Option *field_opt, *where_opt, *reduction_opt, *slide_opt;
    struct Option *angle_thresh_opt, *degree_thresh_opt,
	*closeness_thresh_opt;
    struct Option *betweeness_thresh_opt;
    struct Flag *notab_flag, *loop_support_flag;
    int with_z;
    int total_input, total_output;	/* Number of points in the input/output map respectively */
    double thresh, alpha, beta, reduction, slide, angle_thresh;
    double degree_thresh, closeness_thresh, betweeness_thresh;
    int method;
    int look_ahead, iterations;
    int loop_support;
    int layer;
    int n_lines;
    int simplification, mask_type;
    struct cat_list *cat_list = NULL;
    char *s, *descriptions;

    /* initialize GIS environment */
    G_gisinit(argv[0]);		/* reads grass env, stores program name to G_program_name() */

    /* initialize module */
    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("generalization"));
    G_add_keyword(_("simplification"));
    G_add_keyword(_("smoothing"));
    G_add_keyword(_("displacement"));
    G_add_keyword(_("network generalization"));
    module->description = _("Performs vector based generalization.");

    /* Define the different options as defined in gis.h */
    map_in = G_define_standard_option(G_OPT_V_INPUT);

    field_opt = G_define_standard_option(G_OPT_V_FIELD_ALL);

    type_opt = G_define_standard_option(G_OPT_V_TYPE);
    type_opt->options = "line,boundary,area";
    type_opt->answer = "line,boundary,area";
    type_opt->guisection = _("Selection");
    
    map_out = G_define_standard_option(G_OPT_V_OUTPUT);

    error_out = G_define_standard_option(G_OPT_V_OUTPUT);
    error_out->key = "error";
    error_out->required = NO;
    error_out->description =
	_("Error map of all lines and boundaries not being generalized due to topology issues or over-simplification");

    method_opt = G_define_option();
    method_opt->key = "method";
    method_opt->type = TYPE_STRING;
    method_opt->required = YES;
    method_opt->multiple = NO;
    method_opt->options =
	"douglas,douglas_reduction,lang,reduction,reumann,boyle,sliding_averaging,distance_weighting,chaiken,hermite,snakes,network,displacement";
    descriptions = NULL;
    G_asprintf(&descriptions,
               "douglas;%s;"
               "douglas_reduction;%s;"
               "lang;%s;"
               "reduction;%s;"
               "reumann;%s;"
               "boyle;%s;"
               "sliding_averaging;%s;"
               "distance_weighting;%s;"
               "chaiken;%s;"
               "hermite;%s;"
               "snakes;%s;"
               "network;%s;"
               "displacement;%s;",
               _("Douglas-Peucker Algorithm"),
               _("Douglas-Peucker Algorithm with reduction parameter"),
               _("Lang Simplification Algorithm"),
               _("Vertex Reduction Algorithm eliminates points close to each other"),
               _("Reumann-Witkam Algorithm"),
               _("Boyle's Forward-Looking Algorithm"),
               _("McMaster's Sliding Averaging Algorithm"),
               _("McMaster's Distance-Weighting Algorithm"),
               _("Chaiken's Algorithm"),
               _("Interpolation by Cubic Hermite Splines"),
               _("Snakes method for line smoothing"),
               _("Network generalization"),
               _("Displacement of lines close to each other"));
    method_opt->descriptions = G_store(descriptions);
    
    method_opt->description = _("Generalization algorithm");

    thresh_opt = G_define_option();
    thresh_opt->key = "threshold";
    thresh_opt->type = TYPE_DOUBLE;
    thresh_opt->required = YES;
    thresh_opt->options = "0-1000000000";
    thresh_opt->description = _("Maximal tolerance value");

    look_ahead_opt = G_define_option();
    look_ahead_opt->key = "look_ahead";
    look_ahead_opt->type = TYPE_INTEGER;
    look_ahead_opt->required = NO;
    look_ahead_opt->answer = "7";
    look_ahead_opt->description = _("Look-ahead parameter");

    reduction_opt = G_define_option();
    reduction_opt->key = "reduction";
    reduction_opt->type = TYPE_DOUBLE;
    reduction_opt->required = NO;
    reduction_opt->answer = "50";
    reduction_opt->options = "0-100";
    reduction_opt->description =
	_("Percentage of the points in the output of 'douglas_reduction' algorithm");
    
    slide_opt = G_define_option();
    slide_opt->key = "slide";
    slide_opt->type = TYPE_DOUBLE;
    slide_opt->required = NO;
    slide_opt->answer = "0.5";
    slide_opt->options = "0-1";
    slide_opt->description =
	_("Slide of computed point toward the original point");

    angle_thresh_opt = G_define_option();
    angle_thresh_opt->key = "angle_thresh";
    angle_thresh_opt->type = TYPE_DOUBLE;
    angle_thresh_opt->required = NO;
    angle_thresh_opt->answer = "3";
    angle_thresh_opt->options = "0-180";
    angle_thresh_opt->description =
	_("Minimum angle between two consecutive segments in Hermite method");

    degree_thresh_opt = G_define_option();
    degree_thresh_opt->key = "degree_thresh";
    degree_thresh_opt->type = TYPE_INTEGER;
    degree_thresh_opt->required = NO;
    degree_thresh_opt->answer = "0";
    degree_thresh_opt->description =
	_("Degree threshold in network generalization");

    closeness_thresh_opt = G_define_option();
    closeness_thresh_opt->key = "closeness_thresh";
    closeness_thresh_opt->type = TYPE_DOUBLE;
    closeness_thresh_opt->required = NO;
    closeness_thresh_opt->answer = "0";
    closeness_thresh_opt->options = "0-1";
    closeness_thresh_opt->description =
	_("Closeness threshold in network generalization");

    betweeness_thresh_opt = G_define_option();
    betweeness_thresh_opt->key = "betweeness_thresh";
    betweeness_thresh_opt->type = TYPE_DOUBLE;
    betweeness_thresh_opt->required = NO;
    betweeness_thresh_opt->answer = "0";
    betweeness_thresh_opt->description =
	_("Betweeness threshold in network generalization");

    alpha_opt = G_define_option();
    alpha_opt->key = "alpha";
    alpha_opt->type = TYPE_DOUBLE;
    alpha_opt->required = NO;
    alpha_opt->answer = "1.0";
    alpha_opt->description = _("Snakes alpha parameter");

    beta_opt = G_define_option();
    beta_opt->key = "beta";
    beta_opt->type = TYPE_DOUBLE;
    beta_opt->required = NO;
    beta_opt->answer = "1.0";
    beta_opt->description = _("Snakes beta parameter");

    iterations_opt = G_define_option();
    iterations_opt->key = "iterations";
    iterations_opt->type = TYPE_INTEGER;
    iterations_opt->required = NO;
    iterations_opt->answer = "1";
    iterations_opt->description = _("Number of iterations");

    cat_opt = G_define_standard_option(G_OPT_V_CATS);
    cat_opt->guisection = _("Selection");
    
    where_opt = G_define_standard_option(G_OPT_DB_WHERE);
    where_opt->guisection = _("Selection");

    loop_support_flag = G_define_flag();
    loop_support_flag->key = 'l';
    loop_support_flag->label = _("Disable loop support");
    loop_support_flag->description = _("Do not modify end points of lines forming a closed loop");

    notab_flag = G_define_standard_flag(G_FLG_V_TABLE);
    notab_flag->description = _("Do not copy attributes");
    notab_flag->guisection = _("Attributes");
    
    /* options and flags parser */
    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);

    thresh = atof(thresh_opt->answer);
    look_ahead = atoi(look_ahead_opt->answer);
    alpha = atof(alpha_opt->answer);
    beta = atof(beta_opt->answer);
    reduction = atof(reduction_opt->answer);
    iterations = atoi(iterations_opt->answer);
    slide = atof(slide_opt->answer);
    angle_thresh = atof(angle_thresh_opt->answer);
    degree_thresh = atof(degree_thresh_opt->answer);
    closeness_thresh = atof(closeness_thresh_opt->answer);
    betweeness_thresh = atof(betweeness_thresh_opt->answer);

    mask_type = type_mask(type_opt);
    G_debug(3, "Method: %s", method_opt->answer);

    s = method_opt->answer;

    if (strcmp(s, "douglas") == 0)
	method = DOUGLAS;
    else if (strcmp(s, "lang") == 0)
	method = LANG;
    else if (strcmp(s, "reduction") == 0)
	method = VERTEX_REDUCTION;
    else if (strcmp(s, "reumann") == 0)
	method = REUMANN;
    else if (strcmp(s, "boyle") == 0)
	method = BOYLE;
    else if (strcmp(s, "distance_weighting") == 0)
	method = DISTANCE_WEIGHTING;
    else if (strcmp(s, "chaiken") == 0)
	method = CHAIKEN;
    else if (strcmp(s, "hermite") == 0)
	method = HERMITE;
    else if (strcmp(s, "snakes") == 0)
	method = SNAKES;
    else if (strcmp(s, "douglas_reduction") == 0)
	method = DOUGLAS_REDUCTION;
    else if (strcmp(s, "sliding_averaging") == 0)
	method = SLIDING_AVERAGING;
    else if (strcmp(s, "network") == 0)
	method = NETWORK;
    else if (strcmp(s, "displacement") == 0) {
	method = DISPLACEMENT;
	/* we can displace only the lines */
	mask_type = GV_LINE;
    }
    else {
	G_fatal_error(_("Unknown method"));
	exit(EXIT_FAILURE);
    }


    /* simplification or smoothing? */
    switch (method) {
    case DOUGLAS:
    case DOUGLAS_REDUCTION:
    case LANG:
    case VERTEX_REDUCTION:
    case REUMANN:
	simplification = 1;
	break;
    default:
	simplification = 0;
	break;
    }


    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();

    Vect_check_input_output_name(map_in->answer, map_out->answer,
				 G_FATAL_EXIT);

    Vect_set_open_level(2);

    if (Vect_open_old2(&In, map_in->answer, "", field_opt->answer) < 1)
	G_fatal_error(_("Unable to open vector map <%s>"), map_in->answer);

    if (Vect_get_num_primitives(&In, mask_type) == 0) {
	G_warning(_("No lines found in input map <%s>"), map_in->answer);
	Vect_close(&In);
	exit(EXIT_SUCCESS);
    }
    with_z = Vect_is_3d(&In);

    if (0 > Vect_open_new(&Out, map_out->answer, with_z)) {
	Vect_close(&In);
	G_fatal_error(_("Unable to create vector map <%s>"), map_out->answer);
    }

    if (error_out->answer) {
        if (0 > Vect_open_new(&Error, error_out->answer, with_z)) {
	    Vect_close(&In);
	    G_fatal_error(_("Unable to create error vector map <%s>"), error_out->answer);
        }
    }


    Vect_copy_head_data(&In, &Out);
    Vect_hist_copy(&In, &Out);
    Vect_hist_command(&Out);

    total_input = total_output = 0;

    layer = Vect_get_field_number(&In, field_opt->answer);
    /* parse filter options */
    if (layer > 0)
	cat_list = Vect_cats_set_constraint(&In, layer, 
			      where_opt->answer, cat_opt->answer);

    if (method == DISPLACEMENT) {
	/* modifies only lines, all other features including boundaries are preserved */
	/* options where, cats, and layer are respected */
	G_message(_("Displacement..."));
	snakes_displacement(&In, &Out, thresh, alpha, beta, 1.0, 10.0,
			    iterations, cat_list, layer);
    }

    /* TODO: rearrange code below. It's really messy */
    if (method == NETWORK) {
	/* extracts lines of selected type, all other features are discarded */
	/* options where, cats, and layer are ignored */
	G_message(_("Network generalization..."));
	total_output =
	    graph_generalization(&In, &Out, mask_type, degree_thresh, 
	                         closeness_thresh, betweeness_thresh);
    }

    /* copy tables here because method == NETWORK is complete and 
     * tables for Out may be needed for parse_filter_options() below */
    if (!notab_flag->answer) {
	if (method == NETWORK)
	    copy_tables_by_cats(&In, &Out);
	else
	    Vect_copy_tables(&In, &Out, -1);
    }
    else if (where_opt->answer && method < NETWORK) {
	G_warning(_("Attributes are needed for 'where' option, copying table"));
	Vect_copy_tables(&In, &Out, -1);
    }

    /* smoothing/simplification */
    if (method < NETWORK) {
	/* modifies only lines of selected type, all other features are preserved */
	int not_modified_boundaries = 0, n_oversimplified = 0;
	struct line_pnts *APoints;  /* original Points */

	set_topo_debug();

	Vect_copy_map_lines(&In, &Out);
	Vect_build_partial(&Out, GV_BUILD_CENTROIDS);

	G_message("-----------------------------------------------------");
	G_message(_("Generalization (%s)..."), method_opt->answer);
	G_message(_("Using threshold: %g %s"), thresh, G_database_unit_name(1));
	G_percent_reset();

	APoints = Vect_new_line_struct();

	n_lines = Vect_get_num_lines(&Out);
	for (i = 1; i <= n_lines; i++) {
	    int after = 0;

	    G_percent(i, n_lines, 1);

	    type = Vect_read_line(&Out, APoints, Cats, i);

	    if (!(type & GV_LINES) || !(mask_type & type))
		continue;

	    if (layer > 0) {
		if ((type & GV_LINE) &&
		    !Vect_cats_in_constraint(Cats, layer, cat_list))
		    continue;
		else if ((type & GV_BOUNDARY)) {
		    int do_line = 0;
		    int left, right;
		    
		    do_line = Vect_cats_in_constraint(Cats, layer, cat_list);

		    if (!do_line) {
			
			/* check if any of the centroids is selected */
			Vect_get_line_areas(&Out, i, &left, &right);
			if (left < 0)
			    left = Vect_get_isle_area(&Out, abs(left));
			if (right < 0)
			    right = Vect_get_isle_area(&Out, abs(right));

			if (left > 0) {
			    Vect_get_area_cats(&Out, left, Cats);
			    do_line = Vect_cats_in_constraint(Cats, layer, cat_list);
			}
			
			if (!do_line && right > 0) {
			    Vect_get_area_cats(&Out, right, Cats);
			    do_line = Vect_cats_in_constraint(Cats, layer, cat_list);
			}
		    }
		    if (!do_line)
			continue;
		}
	    }

	    Vect_line_prune(APoints);

	    if (APoints->n_points < 2)
		/* Line of length zero, delete if boundary ? */
		continue;

	    total_input += APoints->n_points;

	    /* copy points */
	    Vect_reset_line(Points);
	    Vect_append_points(Points, APoints, GV_FORWARD);
	    
	    loop_support = 0;
	    if (!loop_support_flag->answer) {
		int n1, n2;

		Vect_get_line_nodes(&Out, i, &n1, &n2);
		if (n1 == n2) {
		    if (Vect_get_node_n_lines(&Out, n1) == 2) {
			if (abs(Vect_get_node_line(&Out, n1, 0)) == i &&
			    abs(Vect_get_node_line(&Out, n1, 1)) == i)
			    loop_support = 1;
		    }
		}
	    }
		
	    for (iter = 0; iter < iterations; iter++) {
		switch (method) {
		case DOUGLAS:
		    douglas_peucker(Points, thresh, with_z);
		    break;
		case DOUGLAS_REDUCTION:
		    douglas_peucker_reduction(Points, thresh, reduction,
					      with_z);
		    break;
		case LANG:
		    lang(Points, thresh, look_ahead, with_z);
		    break;
		case VERTEX_REDUCTION:
		    vertex_reduction(Points, thresh, with_z);
		    break;
		case REUMANN:
		    reumann_witkam(Points, thresh, with_z);
		    break;
		case BOYLE:
		    boyle(Points, look_ahead, loop_support, with_z);
		    break;
		case SLIDING_AVERAGING:
		    sliding_averaging(Points, slide, look_ahead, loop_support, with_z);
		    break;
		case DISTANCE_WEIGHTING:
		    distance_weighting(Points, slide, look_ahead, loop_support, with_z);
		    break;
		case CHAIKEN:
		    chaiken(Points, thresh, loop_support, with_z);
		    break;
		case HERMITE:
		    hermite(Points, thresh, angle_thresh, loop_support, with_z);
		    break;
		case SNAKES:
		    snakes(Points, alpha, beta, loop_support, with_z);
		    break;
		}
	    }

	    if (loop_support == 0) { 
		/* safety check, BUG in method if not passed */
		if (APoints->x[0] != Points->x[0] || 
		    APoints->y[0] != Points->y[0] ||
		    APoints->z[0] != Points->z[0])
		    G_fatal_error(_("Method '%s' did not preserve first point"), method_opt->answer);
		    
		if (APoints->x[APoints->n_points - 1] != Points->x[Points->n_points - 1] || 
		    APoints->y[APoints->n_points - 1] != Points->y[Points->n_points - 1] ||
		    APoints->z[APoints->n_points - 1] != Points->z[Points->n_points - 1])
		    G_fatal_error(_("Method '%s' did not preserve last point"), method_opt->answer);
	    }
	    else {
		/* safety check, BUG in method if not passed */
		if (Points->x[0] != Points->x[Points->n_points - 1] || 
		    Points->y[0] != Points->y[Points->n_points - 1] ||
		    Points->z[0] != Points->z[Points->n_points - 1])
		    G_fatal_error(_("Method '%s' did not preserve loop"), method_opt->answer);
	    }

	    Vect_line_prune(Points);

	    /* oversimplified line */
	    if (Points->n_points < 2) {
		after = APoints->n_points;
		n_oversimplified++;
                if (error_out->answer)
		    Vect_write_line(&Error, type, APoints, Cats);
	    }
	    /* check for topology corruption */
	    else if (type == GV_BOUNDARY) {
		if (!check_topo(&Out, i, APoints, Points, Cats)) {
		    after = APoints->n_points;
		    not_modified_boundaries++;
                    if (error_out->answer)
		        Vect_write_line(&Error, type, APoints, Cats);
		}
		else
		    after = Points->n_points;
	    }
	    else {
		/* type == GV_LINE */
		Vect_rewrite_line(&Out, i, type, Points, Cats);
		after = Points->n_points;
	    }

	    total_output += after;
	}
	if (not_modified_boundaries > 0)
	    G_warning(_("%d boundaries were not modified because modification would damage topology"),
		      not_modified_boundaries);
	if (n_oversimplified > 0)
	    G_warning(_("%d lines/boundaries were not modified due to over-simplification"),
		      n_oversimplified);
	G_message("-----------------------------------------------------");

	/* make sure that clean topo is built at the end */
	Vect_build_partial(&Out, GV_BUILD_NONE);
        if (error_out->answer)
	    Vect_build_partial(&Error, GV_BUILD_NONE);
    }

    Vect_build(&Out);
    if (error_out->answer)
        Vect_build(&Error);

    Vect_close(&In);
    Vect_close(&Out);
    if (error_out->answer)
        Vect_close(&Error);

    G_message("-----------------------------------------------------");
    if (total_input != 0 && total_input != total_output)
	G_done_msg(_("Number of vertices for selected features %s from %d to %d (%d%% remaining)"),
                   simplification ? _("reduced") : _("changed"), 
                   total_input, total_output,
                   (total_output * 100) / total_input);
    else
        G_done_msg(" ");

    exit(EXIT_SUCCESS);
}
コード例 #15
0
ファイル: read_ogr.c プロジェクト: AsherBond/MondocosmOS
/*!
  \brief Read next feature from OGR layer. Skip empty features (level 1)
  
  This function implements sequential access.
  
  The action of this routine can be modified by:
   - Vect_read_constraint_region()
   - Vect_read_constraint_type()
   - Vect_remove_constraints()
  
  \param Map pointer to Map_info structure
  \param[out] line_p container used to store line points within
  \param[out] line_c container used to store line categories within
  
  \return feature type
  \return -2 no more features (EOF)
  \return -1 out of memory
*/
int V1_read_next_line_ogr(struct Map_info *Map, struct line_pnts *line_p,
			  struct line_cats *line_c)
{
    int itype;
    struct bound_box lbox, mbox;
    OGRFeatureH hFeature;
    OGRGeometryH hGeom;

    G_debug(3, "V1_read_next_line_ogr()");

    if (line_p != NULL)
	Vect_reset_line(line_p);
    if (line_c != NULL)
	Vect_reset_cats(line_c);

    if (Map->Constraint_region_flag)
	Vect_get_constraint_box(Map, &mbox);

    while (TRUE) {
	/* Read feature to cache if necessary */
	while (Map->fInfo.ogr.lines_next == Map->fInfo.ogr.lines_num) {
	    hFeature = OGR_L_GetNextFeature(Map->fInfo.ogr.layer);

	    if (hFeature == NULL) {
		return -2;
	    }			/* no more features */

	    hGeom = OGR_F_GetGeometryRef(hFeature);
	    if (hGeom == NULL) {	/* feature without geometry */
		OGR_F_Destroy(hFeature);
		continue;
	    }

	    Map->fInfo.ogr.feature_cache_id = (int)OGR_F_GetFID(hFeature);
	    if (Map->fInfo.ogr.feature_cache_id == OGRNullFID) {
		G_warning(_("OGR feature without ID"));
	    }

	    /* Cache the feature */
	    Map->fInfo.ogr.lines_num = 0;
	    cache_feature(Map, hGeom, -1);
	    G_debug(4, "%d lines read to cache", Map->fInfo.ogr.lines_num);
	    OGR_F_Destroy(hFeature);

	    Map->fInfo.ogr.lines_next = 0;	/* next to be read from cache */
	}

	/* Read next part of the feature */
	G_debug(4, "read next cached line %d", Map->fInfo.ogr.lines_next);
	itype = Map->fInfo.ogr.lines_types[Map->fInfo.ogr.lines_next];

	/* Constraint on Type of line 
	 * Default is all of  Point, Line, Area and whatever else comes along
	 */
	if (Map->Constraint_type_flag) {
	    if (!(itype & Map->Constraint_type)) {
		Map->fInfo.ogr.lines_next++;
		continue;
	    }
	}

	/* Constraint on specified region */
	if (Map->Constraint_region_flag) {
	    Vect_line_box(Map->fInfo.ogr.lines[Map->fInfo.ogr.lines_next],
			  &lbox);

	    if (!Vect_box_overlap(&lbox, &mbox)) {
		Map->fInfo.ogr.lines_next++;
		continue;
	    }
	}

	if (line_p != NULL)
	    Vect_append_points(line_p,
			       Map->fInfo.ogr.lines[Map->fInfo.ogr.
						    lines_next], GV_FORWARD);

	if (line_c != NULL && Map->fInfo.ogr.feature_cache_id != OGRNullFID)
	    Vect_cat_set(line_c, 1, Map->fInfo.ogr.feature_cache_id);

	Map->fInfo.ogr.lines_next++;
	G_debug(4, "next line read, type = %d", itype);
	
	return itype;
    }
    return -2;			/* not reached */
}
コード例 #16
0
ファイル: main.c プロジェクト: rashadkm/grass_cmake
int main(int argc, char *argv[])
{
    struct GModule *module;
    struct Option *in_opt, *layer_opt, *out_opt, *length_opt,
                  *units_opt, *vertices_opt;
    struct Flag *nosplit_flag, *fixedlength_flag;
    
    struct Map_info In, Out;
    struct line_pnts *Points, *Points2, *Points3;
    struct line_cats *Cats;

    int line, nlines, layer, nosplit, fixedlength;
    double length = -1;
    int vertices = 0;
    double (*line_length) ();
    int geodesic = 0;

    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("geometry"));
    G_add_keyword(_("densification"));
    G_add_keyword(_("node"));
    G_add_keyword(_("segment"));
    G_add_keyword(_("vertex"));
    module->description = _("Splits vector lines to shorter segments.");
    
    in_opt = G_define_standard_option(G_OPT_V_INPUT);

    layer_opt = G_define_standard_option(G_OPT_V_FIELD_ALL);

    out_opt = G_define_standard_option(G_OPT_V_OUTPUT);
    
    length_opt = G_define_option();
    length_opt->key = "length";
    length_opt->type = TYPE_DOUBLE;
    length_opt->required = NO;
    length_opt->multiple = NO;
    length_opt->description = _("Maximum segment length");

    units_opt = G_define_option();
    units_opt->key = "units";
    units_opt->type = TYPE_STRING;
    units_opt->required = NO;
    units_opt->multiple = NO;
    units_opt->options = "map,meters,kilometers,feet,surveyfeet,miles,nautmiles";
    units_opt->answer = "map";
    units_opt->description = _("Length units");
    
    vertices_opt = G_define_option();
    vertices_opt->key = "vertices";
    vertices_opt->type = TYPE_INTEGER;
    vertices_opt->required = NO;
    vertices_opt->multiple = NO;
    vertices_opt->description = _("Maximum number of vertices in segment");

    nosplit_flag = G_define_flag();
    nosplit_flag->key = 'n';
    nosplit_flag->label = _("Add new vertices, but do not split");
    nosplit_flag->description = _("Applies only to 'length' option");

    fixedlength_flag = G_define_flag();
    fixedlength_flag->key = 'f';
    fixedlength_flag->label = _("Force segments to be exactly of given length, except for last one");
    fixedlength_flag->description = _("Applies only to 'length' option");


    
    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);
    
    if ((length_opt->answer && vertices_opt->answer) ||
	!(length_opt->answer || vertices_opt->answer))
	G_fatal_error(_("Use either length or vertices"));

    line_length = NULL;

    if (length_opt->answer) {
	length = atof(length_opt->answer);
	if (length <= 0)
	    G_fatal_error(_("Length must be positive but is %g"), length);

	/* convert length to meters */
	if (strcmp(units_opt->answer, "meters") == 0)
	    /* do nothing */ ;
	else if (strcmp(units_opt->answer, "kilometers") == 0)
	    length *= FROM_KILOMETERS;
	else if (strcmp(units_opt->answer, "feet") == 0)
	    length *= FROM_FEET;
	else if (strcmp(units_opt->answer, "surveyfeet") == 0)
	    length *= FROM_SFEET;
	else if (strcmp(units_opt->answer, "miles") == 0)
	    length *= FROM_MILES;
	else if (strcmp(units_opt->answer, "nautmiles") == 0)
	    length *= FROM_NAUTMILES;
	else if (strcmp(units_opt->answer, "map") != 0)
	    G_fatal_error(_("Unknown unit %s"), units_opt->answer); 

	/* set line length function */
	if (G_projection() == PROJECTION_LL) {
	    if (strcmp(units_opt->answer, "map") == 0)
		line_length = Vect_line_length;
	    else {
		line_length = Vect_line_geodesic_length;
		geodesic = 1;
	    }
	}
	else {
	    double factor;
	    
	    line_length = Vect_line_length;
	    
	    /* convert length to map units */
	    if ((factor = G_database_units_to_meters_factor()) == 0)
		G_fatal_error(_("Can not get projection units"));
	    else if (strcmp(units_opt->answer, "map") != 0) {
		/* meters to units */
		length = length / factor;
	    }
	}
	if (strcmp(units_opt->answer, "map") == 0)
	    G_verbose_message(_("Length in map units: %g"), length);
	else
	    G_verbose_message(_("Length in meters: %g"), length);
    }

    if (vertices_opt->answer) {
	vertices = atoi(vertices_opt->answer);
	if (vertices < 2)
	    G_fatal_error(_("Number of vertices must be at least 2"));
    }
    nosplit = nosplit_flag->answer;
    fixedlength = fixedlength_flag->answer;
    
    Vect_set_open_level(2);

    if (Vect_open_old2(&In, in_opt->answer, "", layer_opt->answer) < 0)
	G_fatal_error(_("Unable to open vector map <%s>"), in_opt->answer);

    layer = Vect_get_field_number(&In, layer_opt->answer);
    
    if (Vect_open_new(&Out, out_opt->answer, Vect_is_3d(&In)) < 0)
	G_fatal_error(_("Unable to create vector map <%s>"), out_opt->answer);
    
    Vect_copy_head_data(&In, &Out);
    Vect_hist_copy(&In, &Out);
    Vect_hist_command(&Out);
    Vect_copy_tables(&In, &Out, layer);
    
    Points = Vect_new_line_struct();
    Points2 = Vect_new_line_struct();
    Points3 = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();

    nlines = Vect_get_num_lines(&In);

    for (line = 1; line <= nlines; line++) {
	int ltype;

	G_percent(line, nlines, 1);

	if (!Vect_line_alive(&In, line))
	    continue;

	ltype = Vect_read_line(&In, Points, Cats, line);

	if (layer != -1 && !Vect_cat_get(Cats, layer, NULL))
	  continue;

	if (ltype & GV_LINES) {
	    if (length > 0) {
		double l, from, to, step;

		l = line_length(Points);

		if (l <= length) {
		    Vect_write_line(&Out, ltype, Points, Cats);
		}
		else {
		    long n, i;

		    G_debug(3, "l: %f, length: %f", l, length);

		    n = ceil(l / length);

		    if (geodesic)
			l = Vect_line_length(Points);

		    if (fixedlength) {
			    step = length;
		    }
		    else {
			    step = l / n;
		    }

		    from = 0.;
		    
		    G_debug(3, "n: %ld, step: %f", n, step);
		    
		    if (nosplit)
			Vect_reset_line(Points3);

		    for (i = 0; i < n; i++) {
			int ret;
			double x, y, z;

			if (i == n - 1) {
			    to = l;	/* to be sure that it goes to end */
			}
			else {
			    to = from + step;
			}

			ret = Vect_line_segment(Points, from, to, Points2);
			if (ret == 0) {
			    G_warning(_("Unable to make line segment: %f - %f (line length = %f)"),
				      from, to, l);
			    continue;
			}

			/* To be sure that the coordinates are identical */
			if (i > 0) {
			    Points2->x[0] = x;
			    Points2->y[0] = y;
			    Points2->z[0] = z;
			}
			if (i == n - 1) {
			    Points2->x[Points2->n_points - 1] =
				Points->x[Points->n_points - 1];
			    Points2->y[Points2->n_points - 1] =
				Points->y[Points->n_points - 1];
			    Points2->z[Points2->n_points - 1] =
				Points->z[Points->n_points - 1];
			}

			if (nosplit) {
			    if (Points3->n_points > 0)
				Points3->n_points--;
			    Vect_append_points(Points3, Points2, GV_FORWARD);
			}
			else
			    Vect_write_line(&Out, ltype, Points2, Cats);

			/* last point */
			x = Points2->x[Points2->n_points - 1];
			y = Points2->y[Points2->n_points - 1];
			z = Points2->z[Points2->n_points - 1];

			from += step;
		    }
		    if (nosplit)
			Vect_write_line(&Out, ltype, Points3, Cats);
		}
	    }
	    else {
		int start = 0;	/* number of coordinates written */

		while (start < Points->n_points - 1) {
		    int i, v = 0;

		    Vect_reset_line(Points2);
		    for (i = 0; i < vertices; i++) {
			v = start + i;
			if (v == Points->n_points)
			    break;

			Vect_append_point(Points2, Points->x[v], Points->y[v],
					  Points->z[v]);
		    }

		    Vect_write_line(&Out, ltype, Points2, Cats);

		    start = v;
		}
	    }
	}
	else {
	    Vect_write_line(&Out, ltype, Points, Cats);
	}
    }

    Vect_close(&In);
    Vect_build(&Out);
    Vect_close(&Out);
    
    exit(EXIT_SUCCESS);
}
コード例 #17
0
ファイル: walk.c プロジェクト: AsherBond/MondocosmOS
/* Start from the first node on a polyline and walk to the other end,
   collecting the coordinates of each node en route.  */
int walk_forward_and_pick_up_coords(struct Map_info *map,
				    int start_line, int ltype,
				    struct line_pnts *points,
				    int *lines_visited,
				    struct line_cats *Cats, int write_cats)
{
    int cat_idx;
    int line, next_line, n1, n2;
    int type, node, next_node;
    struct line_pnts *pnts;
    struct line_cats *cats_tmp;

    G_debug(2, "  walk_forward() start = %d", start_line);
    line = start_line;
    pnts = Vect_new_line_struct();
    if (write_cats != NO_CATS) {
	cats_tmp = Vect_new_cats_struct();
    }
    else {
	cats_tmp = NULL;
    }

    Vect_reset_line(points);

    /* Pick up first set of coordinates */
    lines_visited[line] = 1;
    if (cats_tmp)
	type = Vect_read_line(map, pnts, Cats, line);
    else
	type = Vect_read_line(map, pnts, NULL, line);

    Vect_get_line_nodes(map, line, &n1, &n2);
    next_line = find_next_line(map, line, n1, ltype);
    if (next_line > 0) {	/* continue at start node */
	Vect_append_points(points, pnts, GV_BACKWARD);
	next_node = n1;
    }
    else {
	Vect_append_points(points, pnts, GV_FORWARD);
	next_line = find_next_line(map, line, n2, ltype);	/* check end node */
	if (next_line > 0) {
	    next_node = n2;	/* continue at end node */
	}
	else {
	    return 1;		/* no other line */
	}
    }

    /* While next line exist append coordinates */
    line = next_line;
    node = next_node;
    while (line != 0 && line != start_line) {
	G_debug(2, "  line = %d", line);
	type = Vect_read_line(map, pnts, cats_tmp, line);
	if (cats_tmp && write_cats == MULTI_CATS) {
	    for (cat_idx = 0; cat_idx < cats_tmp->n_cats; cat_idx++) {
		Vect_cat_set(Cats, cats_tmp->field[cat_idx],
			     cats_tmp->cat[cat_idx]);
	    }
	}
	Vect_get_line_nodes(map, line, &n1, &n2);

	if (node == n1) {
	    Vect_line_delete_point(pnts, 0);	/* delete duplicate nodes */
	    Vect_append_points(points, pnts, GV_FORWARD);
	    next_node = n2;
	}
	else {
	    Vect_line_delete_point(pnts, pnts->n_points - 1);
	    Vect_append_points(points, pnts, GV_BACKWARD);
	    next_node = n1;
	}

	lines_visited[line] = 1;

	/* Find next one */
	next_line = find_next_line(map, line, next_node, ltype);

	line = next_line;
	node = next_node;
    }

    if (cats_tmp)
	Vect_destroy_cats_struct(cats_tmp);

    return 1;
}
コード例 #18
0
void QgsGrassEditNewLine::mouseClick( QgsPoint & point, Qt::MouseButton button )
{
  switch ( button )
  {
    case Qt::LeftButton:
      if ( e->mEditPoints->n_points > 2 )
      {
        e->snap( point, e->mEditPoints->x[0], e->mEditPoints->y[0] );
      }
      else
      {
        e->snap( point );
      }
      Vect_append_point( e->mEditPoints, point.x(), point.y(), 0.0 );

      // Draw
      Vect_reset_line( e->mPoints );
      Vect_append_points( e->mPoints, e->mEditPoints, GV_FORWARD );
      e->displayDynamic( e->mPoints );
      break;
    case Qt::MidButton:
      if ( e->mEditPoints->n_points > 0 )
      {
        e->mEditPoints->n_points--;
        Vect_reset_line( e->mPoints );
        Vect_append_points( e->mPoints, e->mEditPoints, GV_FORWARD );
        QgsPoint point = toMapCoordinates( e->mCanvas->mouseLastXY() );
        Vect_append_point( e->mPoints, point.x(), point.y(), 0.0 );
        e->displayDynamic( e->mPoints );
      }
      break;
    case Qt::RightButton:
      e->eraseDynamic();
      if ( e->mEditPoints->n_points > 1 )
      {
        int type;

        if ( mNewBoundary ) // boundary or line?
          type = GV_BOUNDARY;
        else
          type = GV_LINE;

        int line;
        line = e->writeLine( type, e->mEditPoints );
        e->updateSymb();
        e->displayUpdated();

        if ( e->mAttributes )
        {
          e->mAttributes->setLine( line );
          e->mAttributes->clear();
        }
        else
        {
          e->mAttributes = new QgsGrassAttributes( e, e->mProvider, line, e->mIface->mainWindow() );
        }
        for ( int i = 0; i < e->mCats->n_cats; i++ )
        {
          e->addAttributes( e->mCats->field[i], e->mCats->cat[i] );
        }
        e->mAttributes->show();
        e->mAttributes->raise();
      }
      Vect_reset_line( e->mEditPoints );
      break;

    default:
      // ignore others
      break;
  }

  if ( e->mEditPoints->n_points == 0 )
  {
    e->setCanvasPrompt( tr( "New vertex" ), "", "" );
  }
  else if ( e->mEditPoints->n_points == 1 )
  {
    e->setCanvasPrompt( tr( "New vertex" ), tr( "Undo last vertex" ), "" );
  }
  else if ( e->mEditPoints->n_points > 1 )
  {
    e->setCanvasPrompt( tr( "New vertex" ), tr( "Undo last vertex" ), tr( "Close line" ) );
  }
}
コード例 #19
0
ファイル: main.c プロジェクト: rkrug/grass-ci
int main(int argc, char *argv[])
{
    struct Map_info In, Out;
    static struct line_pnts *Points, *PPoints;
    struct line_cats *Cats, *TCats;
    struct ilist *slist;
    struct GModule *module;	/* GRASS module for parsing arguments */
    struct Option *map_in, *map_out;
    struct Option *catf_opt, *fieldf_opt, *wheref_opt;
    struct Option *catt_opt, *fieldt_opt, *wheret_opt, *typet_opt;
    struct Option *afield_opt, *nfield_opt, *abcol, *afcol, *ncol, *atype_opt;
    struct Flag *geo_f, *segments_f;
    int with_z, geo, segments;
    int atype, ttype;
    struct varray *varrayf, *varrayt;
    int flayer, tlayer;
    int afield, nfield;
    dglGraph_s *graph;
    struct ilist *nodest;
    int i, j, nnodes, nlines;
    int *dst, *nodes_to_features;
    int from_nr;			/* 'from' features not reachable */
    dglInt32_t **nxt;
    struct line_cats **on_path;
    char *segdir;
    char buf[2000];

    /* Attribute table */
    dbString sql;
    dbDriver *driver;
    struct field_info *Fi;

    /* initialize GIS environment */
    G_gisinit(argv[0]);		/* reads grass env, stores program name to G_program_name() */

    /* initialize module */
    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("network"));
    G_add_keyword(_("shortest path"));
    module->label = _("Computes shortest distance via the network between "
		      "the given sets of features.");
    module->description =
	_("Finds the shortest paths from each 'from' point to the nearest 'to' feature "
	 "and various information about this relation are uploaded to the attribute table.");

    /* Define the different options as defined in gis.h */
    map_in = G_define_standard_option(G_OPT_V_INPUT);
    map_out = G_define_standard_option(G_OPT_V_OUTPUT);

    afield_opt = G_define_standard_option(G_OPT_V_FIELD);
    afield_opt->key = "arc_layer";
    afield_opt->answer = "1";
    afield_opt->label = _("Arc layer");
    afield_opt->guisection = _("Cost");

    atype_opt = G_define_standard_option(G_OPT_V_TYPE);
    atype_opt->key = "arc_type";
    atype_opt->options = "line,boundary";
    atype_opt->answer = "line,boundary";
    atype_opt->label = _("Arc type");
    atype_opt->guisection = _("Cost");

    nfield_opt = G_define_standard_option(G_OPT_V_FIELD);
    nfield_opt->key = "node_layer";
    nfield_opt->answer = "2";
    nfield_opt->label = _("Node layer");
    nfield_opt->guisection = _("Cost");

    fieldf_opt = G_define_standard_option(G_OPT_V_FIELD);
    fieldf_opt->key = "from_layer";
    fieldf_opt->label = _("From layer number or name");
    fieldf_opt->guisection = _("From");

    catf_opt = G_define_standard_option(G_OPT_V_CATS);
    catf_opt->key = "from_cats";
    catf_opt->label = _("From category values");
    catf_opt->guisection = _("From");

    wheref_opt = G_define_standard_option(G_OPT_DB_WHERE);
    wheref_opt->key = "from_where";
    wheref_opt->label =
	_("From WHERE conditions of SQL statement without 'where' keyword");
    wheref_opt->guisection = _("From");

    fieldt_opt = G_define_standard_option(G_OPT_V_FIELD);
    fieldt_opt->key = "to_layer";
    fieldt_opt->description = _("To layer number or name");
    fieldt_opt->guisection = _("To");

    typet_opt = G_define_standard_option(G_OPT_V_TYPE);
    typet_opt->key = "to_type";
    typet_opt->options = "point,line,boundary";
    typet_opt->answer = "point";
    typet_opt->description = _("To feature type");
    typet_opt->guisection = _("To");

    catt_opt = G_define_standard_option(G_OPT_V_CATS);
    catt_opt->key = "to_cats";
    catt_opt->label = _("To category values");
    catt_opt->guisection = _("To");

    wheret_opt = G_define_standard_option(G_OPT_DB_WHERE);
    wheret_opt->key = "to_where";
    wheret_opt->label =
	_("To WHERE conditions of SQL statement without 'where' keyword");
    wheret_opt->guisection = _("To");

    afcol = G_define_standard_option(G_OPT_DB_COLUMN);
    afcol->key = "arc_column";
    afcol->required = NO;
    afcol->description =
	_("Arc forward/both direction(s) cost column (number)");
    afcol->guisection = _("Cost");

    abcol = G_define_standard_option(G_OPT_DB_COLUMN);
    abcol->key = "arc_backward_column";
    abcol->required = NO;
    abcol->description = _("Arc backward direction cost column (number)");
    abcol->guisection = _("Cost");

    ncol = G_define_standard_option(G_OPT_DB_COLUMN);
    ncol->key = "node_column";
    ncol->required = NO;
    ncol->description = _("Node cost column (number)");
    ncol->guisection = _("Cost");

    geo_f = G_define_flag();
    geo_f->key = 'g';
    geo_f->description =
	_("Use geodesic calculation for longitude-latitude locations");

    segments_f = G_define_flag();
#if 0
    /* use this to sync with v.net.path */
    segments_f->key = 's';
    segments_f->description = _("Write output as original input segments, "
				"not each path as one line.");
#else
    segments_f->key = 'l';
    segments_f->description = _("Write each output path as one line, "
				"not as original input segments.");
#endif

    /* options and flags parser */
    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);

    atype = Vect_option_to_types(atype_opt);
    ttype = Vect_option_to_types(typet_opt);

    Points = Vect_new_line_struct();
    PPoints = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();
    TCats = Vect_new_cats_struct();
    slist = G_new_ilist();

    Vect_check_input_output_name(map_in->answer, map_out->answer,
				 G_FATAL_EXIT);

    Vect_set_open_level(2);

    if (1 > Vect_open_old(&In, map_in->answer, ""))
	G_fatal_error(_("Unable to open vector map <%s>"), map_in->answer);

    with_z = Vect_is_3d(&In);

    if (0 > Vect_open_new(&Out, map_out->answer, with_z)) {
	Vect_close(&In);
	G_fatal_error(_("Unable to create vector map <%s>"), map_out->answer);
    }


    if (geo_f->answer) {
	geo = 1;
	if (G_projection() != PROJECTION_LL)
	    G_warning(_("The current projection is not longitude-latitude"));
    }
    else
	geo = 0;

#if 0
    /* use this to sync with v.net.path */
    segments = segments_f->answer;
#else
    segments = !segments_f->answer;
#endif

    nnodes = Vect_get_num_nodes(&In);
    nlines = Vect_get_num_lines(&In);

    dst = (int *)G_calloc(nnodes + 1, sizeof(int));
    nxt = (dglInt32_t **) G_calloc(nnodes + 1, sizeof(dglInt32_t *));
    nodes_to_features = (int *)G_calloc(nnodes + 1, sizeof(int));
    on_path =
	(struct line_cats **)G_calloc(nlines + 1, sizeof(struct line_cats *));
    segdir = (char *)G_calloc(nlines + 1, sizeof(char));

    if (!dst || !nxt || !nodes_to_features || !on_path || !segdir)
	G_fatal_error(_("Out of memory"));

    for (i = 1; i <= nlines; i++) {
	on_path[i] = Vect_new_cats_struct();
	segdir[i] = 0;
    }

    /*initialise varrays and nodes list appropriatelly */
    afield = Vect_get_field_number(&In, afield_opt->answer);
    nfield = Vect_get_field_number(&In, nfield_opt->answer);

    flayer = atoi(fieldf_opt->answer);
    tlayer = atoi(fieldt_opt->answer);

    if (NetA_initialise_varray(&In, flayer, GV_POINT, wheref_opt->answer,
			   catf_opt->answer, &varrayf) <= 0) {
	G_fatal_error(_("No 'from' features selected. "
			"Please check options '%s', '%s', '%s'."),
			fieldf_opt->key, wheref_opt->key, catf_opt->key);
    }

    if (NetA_initialise_varray(&In, tlayer, ttype, wheret_opt->answer,
			   catt_opt->answer, &varrayt) <= 0) {
	G_fatal_error(_("No 'to' features selected. "
			"Please check options '%s', '%s', '%s'."),
			fieldt_opt->key, wheret_opt->key, catt_opt->key);
    }

    nodest = Vect_new_list();
    NetA_varray_to_nodes(&In, varrayt, nodest, nodes_to_features);
    
    if (nodest->n_values == 0)
	G_fatal_error(_("No 'to' features"));
    
    if (0 != Vect_net_build_graph(&In, atype, afield, nfield, afcol->answer, abcol->answer,
                                   ncol->answer, geo, 2))
        G_fatal_error(_("Unable to build graph for vector map <%s>"), Vect_get_full_name(&In));

    graph = Vect_net_get_graph(&In);

    G_message(_("Distances to 'to' features ..."));

    NetA_distance_to_points(graph, nodest, dst, nxt);

    /* Create table */
    Fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE);
    Vect_map_add_dblink(&Out, 1, NULL, Fi->table, GV_KEY_COLUMN, Fi->database,
			Fi->driver);
    db_init_string(&sql);
    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);

    sprintf(buf,
	    "create table %s ( cat integer, tcat integer, dist double precision)",
	    Fi->table);

    db_set_string(&sql, buf);
    G_debug(2, "%s", db_get_string(&sql));

    if (db_execute_immediate(driver, &sql) != DB_OK) {
	G_fatal_error(_("Unable to create table: '%s'"), db_get_string(&sql));
    }

    if (db_create_index2(driver, Fi->table, GV_KEY_COLUMN) != DB_OK)
	G_warning(_("Cannot create index"));

    if (db_grant_on_table
	(driver, Fi->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK)
	G_fatal_error(_("Cannot grant privileges on table <%s>"), Fi->table);

    db_begin_transaction(driver);

    Vect_copy_head_data(&In, &Out);
    Vect_hist_copy(&In, &Out);
    Vect_hist_command(&Out);

    G_message(_("Tracing paths from 'from' features ..."));
    from_nr = 0;
    for (i = 1; i <= nlines; i++) {
	if (varrayf->c[i]) {
	    int type = Vect_read_line(&In, Points, Cats, i);
	    int node, tcat, cat;
	    double cost;
	    dglInt32_t *vertex, vertex_id;

	    if (!Vect_cat_get(Cats, flayer, &cat))
		continue;
		
	    if (type & GV_POINTS) {
		node = Vect_find_node(&In, Points->x[0], Points->y[0], Points->z[0], 0, 0);
	    }
	    else {
		Vect_get_line_nodes(&In, i, &node, NULL);
	    }
	    if (node < 1)
		continue;
	    if (dst[node] < 0) {
		/* unreachable */
		from_nr++;
 		continue;
	    }
	    cost = dst[node] / (double)In.dgraph.cost_multip;
	    vertex = dglGetNode(graph, node);
	    vertex_id = node;
	    slist->n_values = 0;
	    while (nxt[vertex_id] != NULL) {
		int edge_id;

		edge_id = (int) dglEdgeGet_Id(graph, nxt[vertex_id]);
		if (segments) {
		    Vect_cat_set(on_path[abs(edge_id)], 1, cat);
		    if (edge_id < 0) {
			segdir[abs(edge_id)] = 1;
		    }
		}
		else
		    G_ilist_add(slist, edge_id);

		vertex = dglEdgeGet_Tail(graph, nxt[vertex_id]);
		vertex_id = dglNodeGet_Id(graph, vertex);
	    }
	    G_debug(3, "read line %d, vertex id %d", nodes_to_features[vertex_id], (int)vertex_id);
	    Vect_read_line(&In, NULL, TCats, nodes_to_features[vertex_id]);
	    if (!Vect_cat_get(TCats, tlayer, &tcat))
		continue;

	    Vect_write_line(&Out, type, Points, Cats);
	    sprintf(buf, "insert into %s values (%d, %d, %f)", Fi->table, cat,
		    tcat, cost);
	    db_set_string(&sql, buf);
	    G_debug(3, "%s", db_get_string(&sql));
	    if (db_execute_immediate(driver, &sql) != DB_OK) {
		G_fatal_error(_("Cannot insert new record: %s"),
			      db_get_string(&sql));
	    };

	    if (!segments) {
		Vect_reset_line(PPoints);
		for (j = 0; j < slist->n_values; j++) {
		    Vect_read_line(&In, Points, NULL, abs(slist->value[j]));
		    if (slist->value[j] > 0)
			Vect_append_points(PPoints, Points,
					   GV_FORWARD);
		    else
			Vect_append_points(PPoints, Points,
					   GV_BACKWARD);
		    PPoints->n_points--;
		}
		PPoints->n_points++;
		Vect_reset_cats(Cats);
		Vect_cat_set(Cats, 1, cat);
		Vect_write_line(&Out, GV_LINE, PPoints, Cats);
	    }

	}
    }

    if (segments) {
	for (i = 1; i <= nlines; i++) {
	    if (on_path[i]->n_cats > 0) {
		int type; 
		
		if (segdir[i]) {
		    type = Vect_read_line(&In, PPoints, NULL, i);
		    Vect_reset_line(Points);
		    Vect_append_points(Points, PPoints, GV_BACKWARD);
		}
		else
		    type = Vect_read_line(&In, Points, NULL, i);

		Vect_write_line(&Out, type, Points, on_path[i]);
	    }
	}
    }

    db_commit_transaction(driver);
    db_close_database_shutdown_driver(driver);

    Vect_build(&Out);

    Vect_close(&In);
    Vect_close(&Out);

    for (i = 1; i <= nlines; i++)
	Vect_destroy_cats_struct(on_path[i]);
    G_free(on_path);
    G_free(nodes_to_features);
    G_free(dst);
    G_free(nxt);
    G_free(segdir);

    if (from_nr)
	G_warning(n_("%d 'from' feature was not reachable",
                     "%d 'from' features were not reachable",
                     from_nr), from_nr);

    exit(EXIT_SUCCESS);
}