Beispiel #1
0
/*!
  \brief Reads next unread line each time called.  Use Vect_rewind to reset.
  
  This function implements sequential access on level 2.

  \param Map vector map layer
  \param[out] line_p container used to store line points within
  \param[out] line_c container used to store line categories within
  
  \return line type ( > 0 )
  \return 0 dead line
  \return -1 out of memory
  \return -2 end of file
*/
int V2_read_next_line_nat(struct Map_info *Map,
			  struct line_pnts *line_p, struct line_cats *line_c)
{
    register int line, ret;
    register struct P_line *Line;
    struct bound_box lbox, mbox;

    G_debug(3, "V2_read_next_line_nat()");

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

    while (1) {
	line = Map->next_line;

	if (line > Map->plus.n_lines)
	    return (-2);

	Line = Map->plus.Line[line];
	if (Line == NULL) {	/* Dead line */
	    Map->next_line++;
	    continue;
	}

	if ((Map->Constraint_type_flag &&
	     !(Line->type & Map->Constraint_type))) {
	    Map->next_line++;
	    continue;
	}

	ret = V2_read_line_nat(Map, line_p, line_c, Map->next_line++);
	if (Map->Constraint_region_flag) {
	    Vect_line_box(line_p, &lbox);
	    if (!Vect_box_overlap(&lbox, &mbox)) {
		continue;
	    }
	}

	return ret;
    }

    /* NOTREACHED */ }
Beispiel #2
0
/*!
  \brief Read next line from coor file.
  
  This function implements sequential access on level 1.
    
  \param Map vector map layer
  \param[out] line_p container used to store line points within
  \param[out] line_c container used to store line categories within
  
  \return line type
  \return 0 dead line
  \return -2 end of table (last row)
  \return -1 out of memory
*/
int V1_read_next_line_nat(struct Map_info *Map,
			  struct line_pnts *line_p, struct line_cats *line_c)
{
    int itype;
    off_t offset;
    struct bound_box lbox, mbox;

    G_debug(3, "V1_read_next_line_nat()");

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

    while (1) {
	offset = dig_ftell(&(Map->dig_fp));
	itype = read_line_nat(Map, line_p, line_c, offset);
	if (itype < 0)
	    return (itype);

	if (itype == 0)		/* is it DEAD? */
	    continue;

	/* 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))
		continue;
	}

	/* Constraint on specified region */
	if (Map->Constraint_region_flag) {
	    Vect_line_box(line_p, &lbox);

	    if (!Vect_box_overlap(&lbox, &mbox))
		continue;
	}

	return (itype);
    }
    /* NOTREACHED */
}
Beispiel #3
0
/*!
  \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 */
}
Beispiel #4
0
int main(int argc, char *argv[])
{
    char *output, buf[DB_SQL_MAX];
    double (*rng)(void) = G_drand48;
    double zmin, zmax;
    int seed;
    int i, j, k, n, type, usefloat;
    int area, nareas, field;
    struct boxlist *List = NULL;
    BOX_SIZE *size_list = NULL;
    int alloc_size_list = 0;
    struct Map_info In, Out;
    struct line_pnts *Points;
    struct line_cats *Cats;
    struct cat_list *cat_list;
    struct bound_box box;
    struct Cell_head window;
    struct GModule *module;
    struct
    {
	struct Option *input, *field, *cats, *where, *output, *nsites,
		      *zmin, *zmax, *zcol, *ztype, *seed;
    } parm;
    struct
    {
	struct Flag *z, *notopo, *a;
    } flag;
    struct field_info *Fi;
    dbDriver *driver;
    dbTable *table;
    dbString sql;

    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("sampling"));
    G_add_keyword(_("statistics"));
    G_add_keyword(_("random"));
    module->description = _("Generates random 2D/3D vector points.");

    parm.output = G_define_standard_option(G_OPT_V_OUTPUT);

    parm.nsites = G_define_option();
    parm.nsites->key = "n";
    parm.nsites->type = TYPE_INTEGER;
    parm.nsites->required = YES;
    parm.nsites->description = _("Number of points to be created");

    parm.input = G_define_standard_option(G_OPT_V_INPUT);
    parm.input->required = NO;
    parm.input->description = _("Restrict points to areas in input vector");
    parm.input->guisection = _("Selection");

    parm.field = G_define_standard_option(G_OPT_V_FIELD_ALL);
    parm.field->guisection = _("Selection");

    parm.cats = G_define_standard_option(G_OPT_V_CATS);
    parm.cats->guisection = _("Selection");
    
    parm.where = G_define_standard_option(G_OPT_DB_WHERE);
    parm.where->guisection = _("Selection");

    parm.zmin = G_define_option();
    parm.zmin->key = "zmin";
    parm.zmin->type = TYPE_DOUBLE;
    parm.zmin->required = NO;
    parm.zmin->description =
	_("Minimum z height (needs -z flag or column name)");
    parm.zmin->answer = "0.0";
    parm.zmin->guisection = _("3D output");

    parm.zmax = G_define_option();
    parm.zmax->key = "zmax";
    parm.zmax->type = TYPE_DOUBLE;
    parm.zmax->required = NO;
    parm.zmax->description =
	_("Maximum z height (needs -z flag or column name)");
    parm.zmax->answer = "0.0";
    parm.zmax->guisection = _("3D output");

    parm.seed = G_define_option();
    parm.seed->key = "seed";
    parm.seed->type = TYPE_INTEGER;
    parm.seed->required = NO;
    parm.seed->description =
	_("The seed to initialize the random generator. If not set the process ID is used");

    parm.zcol = G_define_standard_option(G_OPT_DB_COLUMN);
    parm.zcol->label = _("Name of column for z values");
    parm.zcol->description =
	_("Writes z values to column");
    parm.zcol->guisection = _("3D output");

    parm.ztype = G_define_option();
    parm.ztype->key = "column_type";
    parm.ztype->type = TYPE_STRING;
    parm.ztype->required = NO;
    parm.ztype->multiple = NO;
    parm.ztype->description = _("Type of column for z values");
    parm.ztype->options = "integer,double precision";
    parm.ztype->answer = "double precision";
    parm.ztype->guisection = _("3D output");

    flag.z = G_define_flag();
    flag.z->key = 'z';
    flag.z->description = _("Create 3D output");
    flag.z->guisection = _("3D output");

    flag.a = G_define_flag();
    flag.a->key = 'a';
    flag.a->description = _("Generate n points for each individual area");

    flag.notopo = G_define_standard_flag(G_FLG_V_TOPO);

    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);

    output = parm.output->answer;
    n = atoi(parm.nsites->answer);
    
    if(parm.seed->answer)
        seed = atoi(parm.seed->answer);

    if (n <= 0) {
	G_fatal_error(_("Number of points must be > 0 (%d given)"), n);
    }

    nareas = 0;
    cat_list = NULL;
    field = -1;
    if (parm.input->answer) {
	Vect_set_open_level(2); /* topology required */
	if (2 > Vect_open_old2(&In, parm.input->answer, "", parm.field->answer))
	    G_fatal_error(_("Unable to open vector map <%s>"),
			  parm.input->answer);

	if (parm.field->answer)
	    field = Vect_get_field_number(&In, parm.field->answer);

	if ((parm.cats->answer || parm.where->answer) && field == -1) {
	    G_warning(_("Invalid layer number (%d). Parameter '%s' or '%s' specified, assuming layer '1'."),
		      field, parm.cats->key, parm.where->key);
	    field = 1;
	}
	if (field > 0)
	    cat_list = Vect_cats_set_constraint(&In, field, parm.where->answer,
						parm.cats->answer);
	nareas = Vect_get_num_areas(&In);
	if (nareas == 0) {
	    Vect_close(&In);
	    G_fatal_error(_("No areas in vector map <%s>"), parm.input->answer);
	}
    }
    else {
	if (flag.a->answer)
	    G_fatal_error(_("The <-%c> flag requires an input vector with areas"),
	                  flag.a->key);
    }

    /* create new vector map */
    if (-1 == Vect_open_new(&Out, output, flag.z->answer ? WITH_Z : WITHOUT_Z))
        G_fatal_error(_("Unable to create vector map <%s>"), output);
    Vect_set_error_handler_io(NULL, &Out);

    /* Do we need to write random values into attribute table? */
    usefloat = -1;
    if (parm.zcol->answer) {
	Fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE);
	driver =
	    db_start_driver_open_database(Fi->driver,
					  Vect_subst_var(Fi->database, &Out));
	if (driver == NULL) {
	    G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
			  Vect_subst_var(Fi->database, &Out), Fi->driver);
	}
        db_set_error_handler_driver(driver);
        
	db_begin_transaction(driver);

	db_init_string(&sql);
	sprintf(buf, "create table %s (%s integer, %s %s)", Fi->table, GV_KEY_COLUMN,
		parm.zcol->answer, parm.ztype->answer);
	db_set_string(&sql, buf);
	Vect_map_add_dblink(&Out, 1, NULL, Fi->table, GV_KEY_COLUMN, Fi->database,
			    Fi->driver);

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

	/* Create index */
	if (db_create_index2(driver, Fi->table, Fi->key) != DB_OK)
	    G_warning(_("Unable to create index"));

	/* Grant */
	if (db_grant_on_table
	    (driver, Fi->table, DB_PRIV_SELECT,
	     DB_GROUP | DB_PUBLIC) != DB_OK) {
	    G_fatal_error(_("Unable to grant privileges on table <%s>"),
			  Fi->table);
	}

	/* OK. Let's check what type of column user has created */
	db_set_string(&sql, Fi->table);
	if (db_describe_table(driver, &sql, &table) != DB_OK) {
	    G_fatal_error(_("Unable to describe table <%s>"), Fi->table);
	}

	if (db_get_table_number_of_columns(table) != 2) {
	    G_fatal_error(_("Table should contain only two columns"));
	}

	type = db_get_column_sqltype(db_get_table_column(table, 1));
	if (type == DB_SQL_TYPE_SMALLINT || type == DB_SQL_TYPE_INTEGER)
	    usefloat = 0;
	if (type == DB_SQL_TYPE_REAL || type == DB_SQL_TYPE_DOUBLE_PRECISION)
	    usefloat = 1;
	if (usefloat < 0) {
	    G_fatal_error(_("You have created unsupported column type. This module supports only INTEGER"
			   " and DOUBLE PRECISION column types."));
	}
    }

    Vect_hist_command(&Out);

    /* Init the random seed */
    if(parm.seed->answer)
	G_srand48(seed);
    else
	G_srand48_auto();

    G_get_window(&window);

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

    if (nareas > 0) {
	int first = 1, count;
	struct bound_box abox, bbox;

	box.W = window.west;
	box.E = window.east;
	box.S = window.south;
	box.N = window.north;
	box.B = -PORT_DOUBLE_MAX;
	box.T = PORT_DOUBLE_MAX;

	count = 0;

	for (i = 1; i <= nareas; i++) {
	    
	    if (!Vect_get_area_centroid(&In, i))
		continue;

	    if (field > 0) {
		if (Vect_get_area_cats(&In, i, Cats))
		    continue;

		if (!Vect_cats_in_constraint(Cats, field, cat_list))
		    continue;
	    }

	    Vect_get_area_box(&In, i, &abox);
	    if (!Vect_box_overlap(&abox, &box))
		continue;

	    if (first) {
		Vect_box_copy(&bbox, &abox);
		first = 0;
	    }
	    else
		Vect_box_extend(&bbox, &abox);
	    count++;
	}
	if (count == 0) {
	    Vect_close(&In);
	    Vect_close(&Out);
	    Vect_delete(output);
	    G_fatal_error(_("Selected areas in input vector <%s> do not overlap with the current region"),
			  parm.input->answer);
	}
	Vect_box_copy(&box, &bbox);

	/* does the vector overlap with the current region ? */
	if (box.W >= window.east || box.E <= window.west ||
	    box.S >= window.north || box.N <= window.south) {

	    Vect_close(&In);
	    Vect_close(&Out);
	    Vect_delete(output);
	    G_fatal_error(_("Input vector <%s> does not overlap with the current region"),
	                  parm.input->answer);
	}

	/* try to reduce the current region */
	if (window.east > box.E)
	    window.east = box.E;
	if (window.west < box.W)
	    window.west = box.W;
	if (window.north > box.N)
	    window.north = box.N;
	if (window.south < box.S)
	    window.south = box.S;

	List = Vect_new_boxlist(1);
	alloc_size_list = 10;
	size_list = G_malloc(alloc_size_list * sizeof(BOX_SIZE));
    }

    zmin = zmax = 0;
    if (flag.z->answer || parm.zcol->answer) {
	zmax = atof(parm.zmax->answer);
	zmin = atof(parm.zmin->answer);
    }

    G_message(_("Generating points..."));
    if (flag.a->answer && nareas > 0) {
	struct bound_box abox, bbox;
	int cat = 1;

	/* n points for each area */
	nareas = Vect_get_num_areas(&In);
	
	G_percent(0, nareas, 1);
	for (area = 1; area <= nareas; area++) {

	    G_percent(area, nareas, 1);

	    if (!Vect_get_area_centroid(&In, area))
		continue;

	    if (field > 0) {
		if (Vect_get_area_cats(&In, area, Cats))
		    continue;

		if (!Vect_cats_in_constraint(Cats, field, cat_list)) {
		    continue;
		}
	    }

	    box.W = window.west;
	    box.E = window.east;
	    box.S = window.south;
	    box.N = window.north;
	    box.B = -PORT_DOUBLE_MAX;
	    box.T = PORT_DOUBLE_MAX;
	    
	    Vect_get_area_box(&In, area, &abox);
	    if (!Vect_box_overlap(&box, &abox))
		continue;
		
	    bbox = abox;
	    if (bbox.W < box.W)
		bbox.W = box.W;
	    if (bbox.E > box.E)
		bbox.E = box.E;
	    if (bbox.S < box.S)
		bbox.S = box.S;
	    if (bbox.N > box.N)
		bbox.N = box.N;

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

		Vect_reset_line(Points);
		Vect_reset_cats(Cats);

		while (outside) {
		    x = rng() * (bbox.W - bbox.E) + bbox.E;
		    y = rng() * (bbox.N - bbox.S) + bbox.S;
		    z = rng() * (zmax - zmin) + zmin;

		    ret = Vect_point_in_area(x, y, &In, area, &abox);

		    G_debug(3, "    area = %d Vect_point_in_area() = %d", area, ret);

		    if (ret >= 1) {
			outside = 0;
		    }
		}

		if (flag.z->answer)
		    Vect_append_point(Points, x, y, z);
		else
		    Vect_append_point(Points, x, y, 0.0);

		if (parm.zcol->answer) {
		    sprintf(buf, "insert into %s values ( %d, ", Fi->table, i + 1);
		    db_set_string(&sql, buf);
		    /* Round random value if column is integer type */
		    if (usefloat)
			sprintf(buf, "%f )", z);
		    else
			sprintf(buf, "%.0f )", z);
		    db_append_string(&sql, buf);

		    G_debug(3, db_get_string(&sql));
		    if (db_execute_immediate(driver, &sql) != DB_OK) {
			G_fatal_error(_("Cannot insert new row: %s"),
				      db_get_string(&sql));
		    }
		}

		Vect_cat_set(Cats, 1, cat++);
		Vect_write_line(&Out, GV_POINT, Points, Cats);
	    }
	}
    }
    else {
	/* n points in total */
	for (i = 0; i < n; ++i) {
	    double x, y, z;

	    G_percent(i, n, 4);

	    Vect_reset_line(Points);
	    Vect_reset_cats(Cats);

	    x = rng() * (window.west - window.east) + window.east;
	    y = rng() * (window.north - window.south) + window.south;
	    z = rng() * (zmax - zmin) + zmin;
	    
	    if (nareas) {
		int outside = 1;

		do {
		    /* select areas by box */
		    box.E = x;
		    box.W = x;
		    box.N = y;
		    box.S = y;
		    box.T = PORT_DOUBLE_MAX;
		    box.B = -PORT_DOUBLE_MAX;
		    Vect_select_areas_by_box(&In, &box, List);
		    G_debug(3, "  %d areas selected by box", List->n_values);

		    /* sort areas by size, the smallest is likely to be the nearest */
		    if (alloc_size_list < List->n_values) {
			alloc_size_list = List->n_values;
			size_list = G_realloc(size_list, alloc_size_list * sizeof(BOX_SIZE));
		    }

		    k = 0;
		    for (j = 0; j < List->n_values; j++) {
			area = List->id[j];

			if (!Vect_get_area_centroid(&In, area))
			    continue;

			if (field > 0) {
			    if (Vect_get_area_cats(&In, area, Cats))
				continue;

			    if (!Vect_cats_in_constraint(Cats, field, cat_list)) {
				continue;
			    }
			}

			List->id[k] = List->id[j];
			List->box[k] = List->box[j];
			size_list[k].i = List->id[k];
			box = List->box[k];
			size_list[k].box = List->box[k];
			size_list[k].size = (box.N - box.S) * (box.E - box.W);
			k++;
		    }
		    List->n_values = k;
		    
		    if (List->n_values == 2) {
			/* simple swap */
			if (size_list[1].size < size_list[0].size) {
			    size_list[0].i = List->id[1];
			    size_list[1].i = List->id[0];
			    size_list[0].box = List->box[1];
			    size_list[1].box = List->box[0];
			}
		    }
		    else if (List->n_values > 2)
			qsort(size_list, List->n_values, sizeof(BOX_SIZE), sort_by_size);

		    for (j = 0; j < List->n_values; j++) {
			int ret;

			area = size_list[j].i;
			ret = Vect_point_in_area(x, y, &In, area, &size_list[j].box);

			G_debug(3, "    area = %d Vect_point_in_area() = %d", area, ret);

			if (ret >= 1) {
			    outside = 0;
			    break;
			}
		    }
		    if (outside) {
			x = rng() * (window.west - window.east) + window.east;
			y = rng() * (window.north - window.south) + window.south;
			z = rng() * (zmax - zmin) + zmin;
		    }
		} while (outside);
	    }

	    if (flag.z->answer)
		Vect_append_point(Points, x, y, z);
	    else
		Vect_append_point(Points, x, y, 0.0);

	    if (parm.zcol->answer) {
		sprintf(buf, "insert into %s values ( %d, ", Fi->table, i + 1);
		db_set_string(&sql, buf);
		/* Round random value if column is integer type */
		if (usefloat)
		    sprintf(buf, "%f )", z);
		else
		    sprintf(buf, "%.0f )", z);
		db_append_string(&sql, buf);

		G_debug(3, db_get_string(&sql));
		if (db_execute_immediate(driver, &sql) != DB_OK) {
		    G_fatal_error(_("Cannot insert new row: %s"),
				  db_get_string(&sql));
		}
	    }

	    Vect_cat_set(Cats, 1, i + 1);
	    Vect_write_line(&Out, GV_POINT, Points, Cats);
	}
	G_percent(1, 1, 1);
    }
    
    if (parm.zcol->answer) {
	db_commit_transaction(driver);
	db_close_database_shutdown_driver(driver);
    }

    if (!flag.notopo->answer) {
	Vect_build(&Out);
    }
    Vect_close(&Out);

    exit(EXIT_SUCCESS);
}
Beispiel #5
0
/* calculate distance parameters between two primitives
 * return 1 point to point
 * return 2 point to line
 * return 1 line to line
 */
int line2line(struct line_pnts *FPoints, int ftype,
              struct line_pnts *TPoints, int ttype,
	      double *fx, double *fy, double *fz,
	      double *falong, double *fangle,
	      double *tx, double *ty, double *tz,
	      double *talong, double *tangle,
	      double *dist,
	      int with_z)
{
    int i, fseg, tseg, tmp_seg;
    double tmp_dist, tmp_x, tmp_y, tmp_z, tmp_along;
    int ret = 1;
    static struct line_pnts *iPoints = NULL;
    
    if (!iPoints) {
	iPoints = Vect_new_line_struct();
    }

    *dist = PORT_DOUBLE_MAX;

    /* fangle and tangle are angles in radians, counter clockwise from x axis
     * initialize to invalid angle */
    *fangle = *tangle = -9.;
    *falong = *talong = 0.;

    *fx = FPoints->x[0];
    *fy = FPoints->y[0];
    *fz = FPoints->z[0];

    *tx = TPoints->x[0];
    *ty = TPoints->y[0];
    *tz = TPoints->z[0];

    tmp_z = 0;

    /* point -> point */
    if ((ftype & GV_POINTS) && (ttype & GV_POINTS)) {
	line_distance(TPoints, FPoints->x[0], FPoints->y[0],
			   FPoints->z[0], with_z, tx, ty, tz, dist, 
			   NULL, talong);
    }

    /* point -> line and line -> line */
    if ((ttype & GV_LINES)) {

	fseg = tseg = 0;
	/* calculate the min distance between each point in fline with tline */
	for (i = 0; i < FPoints->n_points; i++) {

	    tmp_seg = line_distance(TPoints, FPoints->x[i],
	                                 FPoints->y[i], FPoints->z[i],
					 with_z, &tmp_x, &tmp_y, &tmp_z,
					 &tmp_dist, NULL, &tmp_along);
	    if (*dist > tmp_dist) {
		*dist = tmp_dist;
		*fx = FPoints->x[i];
		*fy = FPoints->y[i];
		*fz = FPoints->z[i];
		*tx = tmp_x;
		*ty = tmp_y;
		*tz = tmp_z;
		*talong = tmp_along;
		tseg = tmp_seg;
		fseg = i + 1;
	    }
	}
	*tangle = sangle(TPoints, tseg);

	if (FPoints->n_points > 1 && fseg > 0) {
	    int np = FPoints->n_points;
	    
	    fseg--;
	    
	    if (fseg > 0) {
		FPoints->n_points = fseg + 1;
		*falong = Vect_line_length(FPoints);
		FPoints->n_points = np;
	    }
	    np = fseg;
	    if (fseg == 0)
		fseg = 1;
	    *fangle = sangle(FPoints, fseg);
	}

	ret++;
    }

    /* line -> point and line -> line */
    if (ftype & GV_LINES) {

	fseg = tseg = 0;

	/* calculate the min distance between each point in tline with fline */
	for (i = 0; i < TPoints->n_points; i++) {

	    tmp_seg = line_distance(FPoints, TPoints->x[i],
			       TPoints->y[i], TPoints->z[i],
			       with_z, &tmp_x, &tmp_y, &tmp_z,
			       &tmp_dist, NULL, &tmp_along);
	    if (*dist > tmp_dist) {
		*dist = tmp_dist;
		*fx = tmp_x;
		*fy = tmp_y;
		*fz = tmp_z;
		*falong = tmp_along;
		*tx = TPoints->x[i];
		*ty = TPoints->y[i];
		*tz = TPoints->z[i];
		fseg = tmp_seg;
		tseg = i + 1;
	    }
	}
	*fangle = sangle(FPoints, fseg);

	if (TPoints->n_points > 1 && tseg > 0) {
	    int np = TPoints->n_points;
	    
	    tseg--;

	    if (tseg > 0) {
		TPoints->n_points = tseg + 1;
		*talong = Vect_line_length(TPoints);
		TPoints->n_points = np;
	    }
	    np = tseg;
	    if (tseg == 0)
		tseg = 1;
	    *tangle = sangle(TPoints, tseg);
	}

	ret++;
	
	if ((ttype & GV_LINES) && *dist > 0) {
	    /* check for line intersection */
	    struct bound_box fbox, tbox;

	    get_line_box(FPoints, &fbox);
	    get_line_box(TPoints, &tbox);

	    if (Vect_box_overlap(&fbox, &tbox)) {
		Vect_reset_line(iPoints);
		Vect_line_get_intersections(FPoints, TPoints, iPoints, with_z);
		if (iPoints->n_points) {
		    *dist = 0;
		    *fx = *tx = iPoints->x[0];
		    *fy = *ty = iPoints->y[0];
		    *fz = *tz = iPoints->z[0];
		    
		    /* falong, talong */
		    fseg = line_distance(FPoints, iPoints->x[0],
				       iPoints->y[0], iPoints->z[0],
				       with_z, NULL, NULL, NULL,
				       NULL, NULL, falong);
		    tseg = line_distance(TPoints, iPoints->x[0],
				       iPoints->y[0], iPoints->z[0],
				       with_z, NULL, NULL, NULL,
				       NULL, NULL, talong);
		    /* fangle, tangle */
		    *fangle = sangle(FPoints, fseg);
		    *tangle = sangle(TPoints, tseg);
		}
	    }
	}
    }

    return ret;
}