[GRASS-SVN] r55582 - grass/trunk/lib/vector/Vlib
svn_grass at osgeo.org
svn_grass at osgeo.org
Mon Apr 1 08:15:14 PDT 2013
Author: martinl
Date: 2013-04-01 08:15:14 -0700 (Mon, 01 Apr 2013)
New Revision: 55582
Modified:
grass/trunk/lib/vector/Vlib/bridges.c
grass/trunk/lib/vector/Vlib/local_proto.h
grass/trunk/lib/vector/Vlib/open.c
grass/trunk/lib/vector/Vlib/read.c
grass/trunk/lib/vector/Vlib/read_nat.c
grass/trunk/lib/vector/Vlib/read_sfa.c
grass/trunk/lib/vector/Vlib/write.c
grass/trunk/lib/vector/Vlib/write_nat.c
grass/trunk/lib/vector/Vlib/write_sfa.c
Log:
vlib: add V2__delete_line_topo_nat()
update V2__add_line_topo_nat()
add extra checks (invalid line id) + update doxygen (note required build level)
various minor issue
Modified: grass/trunk/lib/vector/Vlib/bridges.c
===================================================================
--- grass/trunk/lib/vector/Vlib/bridges.c 2013-04-01 14:13:18 UTC (rev 55581)
+++ grass/trunk/lib/vector/Vlib/bridges.c 2013-04-01 15:15:14 UTC (rev 55582)
@@ -28,9 +28,8 @@
return (*ai < *bi ? -1 : (*ai > *bi));
}
-static void
-remove_bridges(struct Map_info *Map, int chtype, struct Map_info *Err,
- int *lrm, int *brm);
+static void remove_bridges(struct Map_info *Map, int chtype, struct Map_info *Err,
+ int *lrm, int *brm);
/*!
\brief Remove bridges from vector map.
@@ -45,12 +44,9 @@
\param Err vector map where deleted bridges are written or NULL
\param lines_removed number of lines removed
\param bridges_removed Err number of bridges removed
-
- \return
- */
-void
-Vect_remove_bridges(struct Map_info *Map, struct Map_info *Err,
- int *lines_removed, int *bridges_removed)
+*/
+void Vect_remove_bridges(struct Map_info *Map, struct Map_info *Err,
+ int *lines_removed, int *bridges_removed)
{
remove_bridges(Map, 0, Err, lines_removed, bridges_removed);
}
@@ -69,12 +65,8 @@
\param Err vector map where changed bridges are written or NULL
\param lines_changed number of lines changed
\param bridges_changed Err number of bridges changed
-
- \return
- */
-
-void
-Vect_chtype_bridges(struct Map_info *Map, struct Map_info *Err,
+*/
+void Vect_chtype_bridges(struct Map_info *Map, struct Map_info *Err,
int *lines_changed, int *bridges_changed)
{
remove_bridges(Map, 1, Err, lines_changed, bridges_changed);
@@ -93,11 +85,10 @@
List of all lines in chain is created during the cycle.
*/
-void
-remove_bridges(struct Map_info *Map, int chtype, struct Map_info *Err,
- int *lrm, int *brm)
+void remove_bridges(struct Map_info *Map, int chtype, struct Map_info *Err,
+ int *lrm, int *brm)
{
- int i, type, nlines, line, *bline;
+ int type, nlines, line, *bline;
int left, right, node1, node2, current_line, next_line, abs_line;
int bridges_removed = 0; /* number of removed bridges */
int lines_removed = 0; /* number of lines removed */
@@ -219,6 +210,6 @@
if (brm)
*brm = bridges_removed;
- G_verbose_message("Removed lines: %d", lines_removed);
- G_verbose_message("Removed bridges: %d", bridges_removed);
+ G_verbose_message(_("Removed lines: %d"), lines_removed);
+ G_verbose_message(_("Removed bridges: %d"), bridges_removed);
}
Modified: grass/trunk/lib/vector/Vlib/local_proto.h
===================================================================
--- grass/trunk/lib/vector/Vlib/local_proto.h 2013-04-01 14:13:18 UTC (rev 55581)
+++ grass/trunk/lib/vector/Vlib/local_proto.h 2013-04-01 15:15:14 UTC (rev 55582)
@@ -3,9 +3,8 @@
#include <grass/vector.h>
-void V2__add_line_to_topo_nat(struct Map_info *, int ,
- const struct line_pnts *, const struct line_cats *,
- int (*external_routine) (const struct Map_info *, int));
+/* Internal vector library subroutines which are not part of public
+ API*/
/* map.c */
int Vect__delete(const char *, int);
@@ -16,4 +15,11 @@
char *Vect__get_path(const struct Map_info *);
char *Vect__get_element_path(const struct Map_info *, const char *);
+/* write_nat.c */
+int V2__add_line_to_topo_nat(struct Map_info *, off_t, int,
+ const struct line_pnts *, const struct line_cats *, int,
+ int (*external_routine) (const struct Map_info *, int));
+int V2__delete_line_from_topo_nat(struct Map_info *, int, int,
+ const struct line_pnts *, const struct line_cats *);
+
#endif /* PG_LOCAL_PROTO_H__ */
Modified: grass/trunk/lib/vector/Vlib/open.c
===================================================================
--- grass/trunk/lib/vector/Vlib/open.c 2013-04-01 14:13:18 UTC (rev 55581)
+++ grass/trunk/lib/vector/Vlib/open.c 2013-04-01 15:15:14 UTC (rev 55582)
@@ -782,6 +782,8 @@
/* set 2D/3D */
Map->plus.spidx_with_z = Map->plus.with_z = Map->head.with_z = (with_z != 0);
+ Map->level = LEVEL_1;
+
if ((*Open_new_array[Map->format][1]) (Map, name, with_z) < 0) {
if (getenv("GRASS_VECTOR_PGFILE") == NULL) /* GRASS_VECTOR_PGFILE defined by v.out.postgis */
Vect_delete(name); /* clean up */
@@ -798,7 +800,6 @@
Vect_open_sidx(Map, 2);
Map->open = VECT_OPEN_CODE;
- Map->level = 1;
Map->head_only = FALSE;
Map->support_updated = FALSE;
Map->plus.built = GV_BUILD_NONE;
Modified: grass/trunk/lib/vector/Vlib/read.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read.c 2013-04-01 14:13:18 UTC (rev 55581)
+++ grass/trunk/lib/vector/Vlib/read.c 2013-04-01 15:15:14 UTC (rev 55582)
@@ -5,7 +5,7 @@
Higher level functions for reading/writing/manipulating vectors.
- (C) 2001-2009, 2011 by the GRASS Development Team
+ (C) 2001-2009, 2011-2013 by the GRASS Development Team
This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.
@@ -83,13 +83,16 @@
\param Map pointer to Map_info struct
\return feature id
+ \return -1 on error
*/
int Vect_get_next_line_id(const struct Map_info *Map)
{
G_debug(3, "Vect_get_next_line()");
- if (!VECT_OPEN(Map))
- G_fatal_error(_("Vector map is not open for reading"));
+ if (!VECT_OPEN(Map)) {
+ G_warning(_("Vector map is not open for reading"));
+ return -1;
+ }
return Map->next_line - 1;
}
@@ -99,17 +102,17 @@
This function implements sequential access, constraints are
reflected, see Vect_set_constraint_region(),
- Vect_set_constraint_type(), or Vect_set_constraint_field().
+ Vect_set_constraint_type(), or Vect_set_constraint_field() for
+ details.
- Use Vect_rewind() to reset reading.
+ Use Vect_rewind() to reset reading. Topological level is not
+ required.
- G_fatal_error() is called on failure.
+ A warning is printed on failure.
\param Map pointer Map_info struct
- \param[out] line_p feature geometry
- (pointer to line_pnts struct)
- \param[out] line_c feature categories
- (pointer to line_cats struct)
+ \param[out] line_p feature geometry (pointer to line_pnts struct)
+ \param[out] line_c feature categories (pointer to line_cats struct)
\return feature type (GV_POINT, GV_LINE, ...)
\return -1 on error
@@ -122,32 +125,32 @@
G_debug(3, "Vect_read_next_line(): next_line = %d", Map->next_line);
- if (!VECT_OPEN(Map))
- G_fatal_error(_("Vector map is not open for reading"));
+ if (!VECT_OPEN(Map)) {
+ G_warning(_("Vector map is not open for reading"));
+ return -1;
+ }
ret = (*Read_next_line_array[Map->format][Map->level]) (Map, line_p,
line_c);
- /*
if (ret == -1)
- G_fatal_error(_("Unable to read feature %d vector map <%s>"),
- Map->next_line, Vect_get_full_name(Map));
- */
+ G_warning(_("Unable to read feature %d from vector map <%s>"),
+ Map->next_line, Vect_get_full_name(Map));
+
return ret;
}
/*!
- \brief Read vector feature
+ \brief Read vector feature (topological level required)
- This function implements random access. Note that constraits are
- ignored!
+ This function implements random access. Constraits are ignored.
- G_fatal_error() is called on failure.
+ Note: Topology must be built at level >= GV_BUILD_BASE
+
+ A warning is printed on failure.
\param Map pointer to vector map
- \param[out] line_p feature geometry
- (pointer to line_pnts struct)
- \param[out] line_c feature categories
- (pointer to line_cats struct)
+ \param[out] line_p feature geometry (pointer to line_pnts struct)
+ \param[out] line_c feature categories (pointer to line_cats struct)
\param line feature id (starts at 1)
\return feature type
@@ -161,35 +164,43 @@
G_debug(3, "Vect_read_line(): line = %d", line);
- if (!VECT_OPEN(Map))
- G_fatal_error(_("Vector map is not open for reading"));
-
- if (line < 1 || line > Map->plus.n_lines)
- G_fatal_error(_("Requested feature id %d is not reasonable"
- "(max features in vector map <%s>: %d)"),
- line, Vect_get_full_name(Map), Map->plus.n_lines);
-
+ if (!VECT_OPEN(Map)) {
+ G_warning(_("Vector map is not open for reading"));
+ return -1;
+ }
+
+ if (line < 1 || line > Map->plus.n_lines) {
+ G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+ return -1;
+ }
+
ret = (*Read_line_array[Map->format]) (Map, line_p, line_c, line);
- /*
if (ret == -1)
- G_fatal_error(_("Unable to read feature %d from vector map <%s>"),
- line, Vect_get_full_name(Map));
- */
+ G_warning(_("Unable to read feature %d from vector map <%s>"),
+ line, Vect_get_full_name(Map));
+
return ret;
}
/*!
- \brief Check if feature is alive or dead (level 2 required)
+ \brief Check if feature is alive or dead (topological level required)
+ Note: Topology must be built at level >= GV_BUILD_BASE
+
\param Map pointer to Map_info structure
\param line feature id
\return 1 feature alive
\return 0 feature is dead
+ \return -1 on error
*/
int Vect_line_alive(const struct Map_info *Map, int line)
{
+ if (line < 1 || line > Map->plus.n_lines) {
+ return -1;
+ }
+
if (Map->plus.Line[line] != NULL)
return 1;
@@ -197,8 +208,10 @@
}
/*!
- \brief Check if node is alive or dead (level 2 required)
+ \brief Check if node is alive or dead (topological level required)
+ Note: Topology must be built at level >= GV_BUILD_BASE
+
\param Map pointer to Map_info structure
\param node node id
@@ -207,6 +220,10 @@
*/
int Vect_node_alive(const struct Map_info *Map, int node)
{
+ if (node < 1 || node > Map->plus.n_nodes) {
+ return -1;
+ }
+
if (Map->plus.Node[node] != NULL)
return 1;
@@ -214,16 +231,22 @@
}
/*!
- \brief Check if area is alive or dead (level 2 required)
+ \brief Check if area is alive or dead (topological level required)
+ Note: Topology must be built at level >= GV_BUILD_AREAS
+
\param Map pointer to Map_info structure
\param area area id
\return 1 area alive
\return 0 area is dead
+ \return -1 on error
*/
int Vect_area_alive(const struct Map_info *Map, int area)
{
+ if (area < 1 || area > Map->plus.n_areas)
+ return -1;
+
if (Map->plus.Area[area] != NULL)
return 1;
@@ -231,8 +254,10 @@
}
/*!
- \brief Check if isle is alive or dead (level 2 required)
+ \brief Check if isle is alive or dead (topological level required)
+ Note: Topology must be built at level >= GV_BUILD_AREAS
+
\param Map pointer to Map_info structure
\param isle isle id
@@ -241,6 +266,9 @@
*/
int Vect_isle_alive(const struct Map_info *Map, int isle)
{
+ if (isle < 1 || isle > Map->plus.n_isles)
+ return -1;
+
if (Map->plus.Isle[isle] != NULL)
return 1;
@@ -248,8 +276,10 @@
}
/*!
- \brief Get feature offset
+ \brief Get feature offset (topological level required)
+ Note: Topology must be built at level >= GV_BUILD_BASE
+
Used for Vect_restore_line().
\param Map pointer to Map_info structure
@@ -260,8 +290,9 @@
*/
off_t Vect_get_line_offset(const struct Map_info *Map, int line)
{
- if (line < 1 || line > Map->plus.n_lines)
+ if (line < 1 || line > Map->plus.n_lines) {
return -1;
+ }
if (Map->plus.Line[line] != NULL) {
return Map->plus.Line[line]->offset;
Modified: grass/trunk/lib/vector/Vlib/read_nat.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read_nat.c 2013-04-01 14:13:18 UTC (rev 55581)
+++ grass/trunk/lib/vector/Vlib/read_nat.c 2013-04-01 15:15:14 UTC (rev 55582)
@@ -122,11 +122,11 @@
This function implements random access for native format,
constraints are ignored!
+ Note: Topology must be built at level >= GV_BUILD_BASE
+
\param Map pointer to Map_info struct
- \param[out] Points container used to store line points within
- (pointer to line_pnts struct)
- \param[out] Cats container used to store line categories within
- (pointer to line_cats struct)
+ \param[out] Points container used to store line points within (pointer to line_pnts struct)
+ \param[out] Cats container used to store line categories within (pointer to line_cats struct)
\param line feature id to read (starts at 1)
\return feature type (GV_POINT, GV_LINE, ...)
@@ -140,10 +140,14 @@
G_debug(3, "V2_read_line_nat(): line = %d", line);
+ if (line < 1 || line > Map->plus.n_lines) {
+ G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+ return -1;
+ }
+
Line = Map->plus.Line[line];
-
if (Line == NULL) {
- G_warning(_("Attempt to read dead feature %d"), line);
+ G_warning(_("Attempt to access dead feature %d"), line);
return -1;
}
Modified: grass/trunk/lib/vector/Vlib/read_sfa.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read_sfa.c 2013-04-01 14:13:18 UTC (rev 55581)
+++ grass/trunk/lib/vector/Vlib/read_sfa.c 2013-04-01 15:15:14 UTC (rev 55582)
@@ -24,6 +24,8 @@
This function implements random access on level 2.
+ Note: Topology must be built at level >= GV_BUILD_BASE
+
\param Map pointer to Map_info structure
\param[out] line_p container used to store line points within
(pointer to line_pnts struct)
@@ -44,9 +46,14 @@
G_debug(4, "V2_read_line_sfa() line = %d", line);
+ if (line < 1 || line > Map->plus.n_lines) {
+ G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+ return -1;
+ }
+
Line = Map->plus.Line[line];
if (Line == NULL) {
- G_warning(_("Attempt to read dead feature %d"), line);
+ G_warning(_("Attempt to access dead feature %d"), line);
return -1;
}
@@ -106,9 +113,11 @@
else
type = V1_read_line_ogr(Map, line_p, line_c, Line->offset);
- if (type != Line->type)
- G_fatal_error(_("Unexpected feature type (%d) - should be (%d)"),
- type, Line->type);
+ if (type != Line->type) {
+ G_warning(_("Unexpected feature type (%d) - should be (%d)"),
+ type, Line->type);
+ return -1;
+ }
return type;
#else
Modified: grass/trunk/lib/vector/Vlib/write.c
===================================================================
--- grass/trunk/lib/vector/Vlib/write.c 2013-04-01 14:13:18 UTC (rev 55581)
+++ grass/trunk/lib/vector/Vlib/write.c 2013-04-01 15:15:14 UTC (rev 55582)
@@ -5,20 +5,19 @@
Higher level functions for reading/writing/manipulating vectors.
- Operations:
- - Write new feature
- - Rewrite feature
- - Delete feature
+ Supported operations:
+ - Write a new feature
+ - Rewrite existing feature
+ - Delete existing feature
- Restore deleted feature
- (C) 2001-2010, 2012 by the GRASS Development Team
+ (C) 2001-2010, 2012-2013 by the GRASS Development Team
This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.
\author Radim Blazek
- \author Updated by Martin Landa <landa.martin gmail.com>
- (restore lines, OGR & PostGIS support)
+ \author Updated by Martin Landa <landa.martin gmail.com> (restore lines, OGR & PostGIS support)
*/
#include <sys/types.h>
@@ -104,7 +103,7 @@
#endif
#ifdef HAVE_POSTGRES
, {
- rewrite_dummy, V1_rewrite_line_pg, V2_rewrite_line_sfa}
+ rewrite_dummy, V1_rewrite_line_pg, V2_rewrite_line_pg}
#else
, {
rewrite_dummy, format_l, format_l}
@@ -127,7 +126,7 @@
#endif
#ifdef HAVE_POSTGRES
, {
- delete_dummy, V1_delete_line_pg, V2_delete_line_sfa}
+ delete_dummy, V1_delete_line_pg, V2_delete_line_pg}
#else
, {
delete_dummy, format, format}
@@ -157,20 +156,22 @@
#endif
};
+static int check_map(const struct Map_info *);
+
/*!
- \brief Writes new feature
+ \brief Writes a new feature
New feature is written to the end of file (in the case of native
- format). Vector map topology is not required.
+ format). Topological level is not required.
- Calls G_fatal_error() when vector map is not opened.
+ A warning is printed on error.
\param Map pointer to Map_info structure
\param type feature type (see dig_defines.h for supported types)
- \param points ointer to line_pnts structure (feature geometry)
+ \param points pointer to line_pnts structure (feature geometry)
\param cats pointer to line_cats structure (feature categories)
- \return new feature id (on level 2)
+ \return new feature id (on level 2) (or 0 when build level < GV_BUILD_BASE)
\return offset into file where the feature starts (on level 1)
\return -1 on error
*/
@@ -182,44 +183,42 @@
G_debug(3, "Vect_write_line(): name = %s, format = %d, level = %d",
Map->name, Map->format, Map->level);
- if (!VECT_OPEN(Map))
- G_fatal_error(_("Unable to write feature, vector map is not opened"));
-
+ if (!VECT_OPEN(Map)) {
+ G_warning(_("Vector map <%s> is not opened"), Vect_get_name(Map));
+ return -1;
+ }
+
if (!(Map->plus.update_cidx)) {
- Map->plus.cidx_up_to_date = FALSE;
+ Map->plus.cidx_up_to_date = FALSE; /* category index will be outdated */
}
offset =
(*Vect_write_line_array[Map->format][Map->level]) (Map, type, points,
cats);
- /*
- if (offset == -1)
- G_fatal_error(_("Unable to write feature (negative offset)"));
- */
+ if (offset < 0)
+ G_warning(_("Unable to write feature in vector map <%s>"), Vect_get_name(Map));
- /* note: returns new feature id on level 2 and file offset on
- level 1 */
return offset;
}
/*!
- \brief Rewrites feature info at the given offset.
+ \brief Rewrites existing feature (topological level required)
- Vector map must be opened with full topology (level 2).
+ Note: Topology must be built at level >= GV_BUILD_BASE
+
+ A warning is printed on error.
The number of points or cats or type may change. If necessary, the
old feature is deleted and new is written.
- This function calls G_fatal_error() on error.
-
\param Map pointer to Map_info structure
\param line feature id
\param type feature type (GV_POINT, GV_LINE, ...)
\param points feature geometry
\param cats feature categories
- \return feature offset
+ \return new feature offset
\return -1 on error
*/
off_t Vect_rewrite_line(struct Map_info *Map, int line, int type,
@@ -227,33 +226,39 @@
{
off_t ret, offset;
- if (!VECT_OPEN(Map))
- G_fatal_error(_("Unable to rewrite feature, vector map is not opened"));
+ if (!check_map(Map))
+ return -1;
+ if (line < 1 || line > Map->plus.n_lines) {
+ G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+ return -1;
+ }
+
if (!(Map->plus.update_cidx)) {
- Map->plus.cidx_up_to_date = FALSE;
+ Map->plus.cidx_up_to_date = FALSE; /* category index will be outdated */
}
offset = Map->plus.Line[line]->offset;
- G_debug(3, "Vect_rewrite_line(): name = %s, line = %d offset = %lu",
+
+ G_debug(3, "Vect_rewrite_line(): name = %s, line = %d, offset = %lu",
Map->name, line, offset);
+
ret = (*Vect_rewrite_line_array[Map->format][Map->level]) (Map, line, type,
offset,
points, cats);
- /*
if (ret == -1)
- G_fatal_error(_("Unable to rewrite feature %d"), line);
- */
+ G_warning(_("Unable to rewrite feature %d in vector map <%s>"), line, Vect_get_name(Map));
+
return ret;
}
/*!
- \brief Delete feature
+ \brief Delete existing feature (topological level required)
- Vector map must be opened with full topology (level 2).
+ Note: Topology must be built at level >= GV_BUILD_BASE
+
+ A warning is printed on error.
- This function calls G_fatal_error() on error.
-
\param Map pointer to Map_info structure
\param line feature id
@@ -266,41 +271,37 @@
G_debug(3, "Vect_delete_line(): name = %s, line = %d", Map->name, line);
- if (Map->level < 2) {
- G_fatal_error(_("Unable to delete feature %d, "
- "vector map <%s> is not opened on topology level"),
- line, Map->name);
+ if (!check_map(Map))
+ return -1;
+
+ if (line < 1 || line > Map->plus.n_lines) {
+ G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+ return -1;
}
- if (Map->mode != GV_MODE_RW && Map->mode != GV_MODE_WRITE) {
- G_fatal_error(_("Unable to delete feature %d, "
- "vector map <%s> is not opened in 'write' mode"),
- line, Map->name);
- }
-
if (!(Map->plus.update_cidx)) {
- Map->plus.cidx_up_to_date = FALSE;
+ Map->plus.cidx_up_to_date = FALSE; /* category index will be outdated */
}
ret = (*Vect_delete_line_array[Map->format][Map->level]) (Map, line);
- /*
if (ret == -1)
- G_fatal_error(_("Unable to delete feature id %d from vector map <%s>"),
- line, Vect_get_full_name(Map));
- */
+ G_warning(_("Unable to delete feature %d from vector map <%s>"),
+ line, Vect_get_name(Map));
+
return ret;
}
/*!
- \brief Restore previously deleted feature
+ \brief Restore previously deleted feature (topological level required)
- Vector map must be opened with full topology (level 2).
+ Note: Topology must be built at level >= GV_BUILD_BASE
+
+ A warning is printed on error.
- This function calls G_fatal_error() on error.
-
\param Map pointer to Map_info structure
\param line feature id to be restored
+ \param offset feature offset
\return 0 on success
\return -1 on error
@@ -311,16 +312,12 @@
G_debug(3, "Vect_restore_line(): name = %s, line = %d", Map->name, line);
- if (Map->level < 2) {
- G_fatal_error(_("Unable to restore feature %d, "
- "vector map <%s> is not opened on topology level"),
- line, Map->name);
- }
+ if (!check_map(Map))
+ return -1;
- if (Map->mode != GV_MODE_RW && Map->mode != GV_MODE_WRITE) {
- G_fatal_error(_("Unable to restore feature %d, "
- "vector map <%s> is not opened in 'write' mode"),
- line, Map->name);
+ if (line < 1 || line > Map->plus.n_lines) {
+ G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+ return -1;
}
if (!(Map->plus.update_cidx)) {
@@ -329,10 +326,31 @@
ret = (*Vect_restore_line_array[Map->format][Map->level]) (Map, line, offset);
- /*
if (ret == -1)
- G_fatal_error(_("Unable to restore feature %d from vector map <%s>"),
- line, Map->name);
- */
+ G_warning(_("Unable to restore feature %d in vector map <%s>"),
+ line, Vect_get_name(Map));
+
return ret;
}
+
+int check_map(const struct Map_info *Map)
+{
+ if (!VECT_OPEN(Map)) {
+ G_warning(_("Vector map <%s> is not opened"), Vect_get_name(Map));
+ return 0;
+ }
+
+ if (Map->level < 2) {
+ G_warning(_("Vector map <%s> is not opened on topology level"),
+ Vect_get_name(Map));
+ return 0;
+ }
+
+ if (Map->mode != GV_MODE_RW && Map->mode != GV_MODE_WRITE) {
+ G_warning(_("Vector map <%s> is not opened in write mode"),
+ Vect_get_name(Map));
+ return 0;
+ }
+
+ return 1;
+}
Modified: grass/trunk/lib/vector/Vlib/write_nat.c
===================================================================
--- grass/trunk/lib/vector/Vlib/write_nat.c 2013-04-01 14:13:18 UTC (rev 55581)
+++ grass/trunk/lib/vector/Vlib/write_nat.c 2013-04-01 15:15:14 UTC (rev 55582)
@@ -1,11 +1,11 @@
/*!
\file lib/vector/Vlib/write_nat.c
- \brief Vector library - write/modify vector feature (native format)
+ \brief Vector library - write/modify/delete vector feature (native format)
Higher level functions for reading/writing/manipulating vectors.
- (C) 2001-2012 by the GRASS Development Team
+ (C) 2001-2013 by the GRASS Development Team
This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.
@@ -24,298 +24,16 @@
#include "local_proto.h"
+static struct line_cats *Cats;
+static struct line_pnts *Points;
+
static off_t V1__rewrite_line_nat(struct Map_info *, off_t, int,
const struct line_pnts *, const struct line_cats *);
+static void V2__delete_area_cats_from_cidx_nat(struct Map_info *, int);
+static void V2__add_area_cats_to_cidx_nat(struct Map_info *, int);
-/*!
- \brief Deletes area (i.e. centroid) categories from category
- index (internal use only)
-
- Call G_fatal_error() when area do not exits.
-
- \param Map pointer to Map_info structure
- \param area area id
-*/
-static void V2__delete_area_cats_from_cidx_nat(struct Map_info *Map, int area)
-{
- int i;
- struct P_area *Area;
- static struct line_cats *Cats = NULL;
-
- G_debug(3, "V2__delete_area_cats_from_cidx_nat(), area = %d", area);
-
- Area = Map->plus.Area[area];
- if (!Area)
- G_fatal_error(_("%s: Area %d does not exist"),
- "delete_area_cats_from_cidx()", area);
-
- if (Area->centroid == 0) /* no centroid found */
- return;
-
- if (!Cats)
- Cats = Vect_new_cats_struct();
-
- V2_read_line_nat(Map, NULL, Cats, Area->centroid);
-
- for (i = 0; i < Cats->n_cats; i++) {
- dig_cidx_del_cat(&(Map->plus), Cats->field[i], Cats->cat[i], area,
- GV_AREA);
- }
-}
-
-/*!
- \brief Adds area (i.e. centroid) categories from category index
- (internal use only)
-
- Call G_fatal_error() when area do not exits.
-
- \param Map pointer to Map_info structure
- \param area area id
-*/
-static void V2__add_area_cats_to_cidx_nat(struct Map_info *Map, int area)
-{
- int i;
- struct P_area *Area;
- static struct line_cats *Cats = NULL;
-
- G_debug(3, "V2__add_area_cats_to_cidx_nat(), area = %d", area);
-
- Area = Map->plus.Area[area];
- if (!Area)
- G_fatal_error(_("%s: Area %d does not exist"),
- "add_area_cats_to_cidx():", area);
-
- if (Area->centroid == 0) /* no centroid found */
- return;
-
- if (!Cats)
- Cats = Vect_new_cats_struct();
-
- V2_read_line_nat(Map, NULL, Cats, Area->centroid);
-
- for (i = 0; i < Cats->n_cats; i++) {
- dig_cidx_add_cat_sorted(&(Map->plus), Cats->field[i], Cats->cat[i],
- area, GV_AREA);
- }
-}
-
/*!
- \brief Add feature (line) to topo file (internal use only)
-
- Update areas. Areas are modified if:
-
- 1) first or/and last point are existing nodes ->
- - drop areas/islands whose boundaries are neighbour to this boundary at these nodes
- - try build areas and islands for this boundary and neighbour boundaries going through these nodes
-
- Question: may be by adding line created new area/isle which doesn't go through nodes of this line
-
- <pre>
- old new line
- +----+----+ +----+----+ +----+----+
- | A1 | A2 | + / -> | A1 | /| or + \ -> | A1 | A2 | \
- | | | | | | | | |
- +----+----+ +----+----+ +----+----+
- I1 I1 I1 I1
- </pre>
-
- - re-attach all centroids/isles inside new area(s)
- - attach new isle to area outside
-
- 2) line is closed ring (node at the end is new, so it is not case above)
- - build new area/isle
- - check if it is island or contains island(s)
- - re-attach all centroids/isles inside new area(s)
- - attach new isle to area outside
-
- Note that 1) and 2) is done by the same code.
-
- \param Map pointer to Map_info structure
- \param line feature id
- \param points pointer to line_pnts structure (feature's geometry)
- \param cats pointer to line_cats structure (feature's categories)
-*/
-void V2__add_line_to_topo_nat(struct Map_info *Map, int line,
- const struct line_pnts *points, const struct line_cats *cats,
- int (*external_routine) (const struct Map_info *, int))
-{
- int first, s, n, i;
- int type, node, next_line, area, side, sel_area, new_area[2];
-
- struct Plus_head *plus;
- struct P_line *Line, *NLine;
- struct P_node *Node;
- struct P_area *Area;
-
- struct bound_box box, abox;
-
- G_debug(3, "V2__add_line_to_topo_nat(), line = %d", line);
-
- plus = &(Map->plus);
- Line = plus->Line[line];
- type = Line->type;
-
- if (plus->built >= GV_BUILD_AREAS &&
- type == GV_BOUNDARY) {
- struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
-
- /* Delete neighbour areas/isles */
- first = TRUE;
- for (s = 0; s < 2; s++) { /* for each node */
- node = (s == 0 ? topo->N1 : topo->N2);
- G_debug(3,
- " delete neighbour areas/isles: %s node = %d",
- (s == 0 ? "first" : "second"), node);
- Node = plus->Node[node];
- n = 0;
- for (i = 0; i < Node->n_lines; i++) {
- NLine = plus->Line[abs(Node->lines[i])];
- if (NLine->type == GV_BOUNDARY)
- n++;
- }
-
- G_debug(3, " number of boundaries at node = %d", n);
- if (n > 2) {
- /* more than 2 boundaries at node ( >= 2 old + 1 new ) */
- /* Line above (to the right), it is enough to check to
- the right, because if area/isle exists it is the
- same to the left */
- if (!s)
- next_line =
- dig_angle_next_line(plus, line, GV_RIGHT,
- GV_BOUNDARY, NULL);
- else
- next_line =
- dig_angle_next_line(plus, -line, GV_RIGHT,
- GV_BOUNDARY, NULL);
-
- if (next_line != 0) { /* there is a boundary to the right */
- NLine = plus->Line[abs(next_line)];
- topo = (struct P_topo_b *)NLine->topo;
- if (next_line > 0) /* the boundary is connected by 1. node */
- /* we are interested just in this side (close to our line) */
- area = topo->right;
- else if (next_line < 0) /* the boundary is connected by 2. node */
- area = topo->left;
-
- G_debug(3, " next_line = %d area = %d", next_line,
- area);
- if (area > 0) { /* is area */
- Vect_get_area_box(Map, area, &box);
- if (first) {
- Vect_box_copy(&abox, &box);
- first = FALSE;
- }
- else
- Vect_box_extend(&abox, &box);
-
- if (plus->update_cidx) {
- V2__delete_area_cats_from_cidx_nat(Map, area);
- }
- dig_del_area(plus, area);
- if (external_routine) /* call external subroutine if defined */
- external_routine(Map, area);
- }
- else if (area < 0) { /* is isle */
- dig_del_isle(plus, -area);
- if (external_routine) /* call external subroutine if defined */
- external_routine(Map, area);
- }
- }
- }
- }
- /* Build new areas/isles.
- * It's true that we deleted also adjacent areas/isles, but
- * if they form new one our boundary must participate, so
- * we need to build areas/isles just for our boundary */
- for (s = 0; s < 2; s++) {
- side = (s == 0 ? GV_LEFT : GV_RIGHT);
- area = Vect_build_line_area(Map, line, side);
-
- if (area > 0) { /* area */
- Vect_get_area_box(Map, area, &box);
- if (first) {
- Vect_box_copy(&abox, &box);
- first = FALSE;
- }
- else
- Vect_box_extend(&abox, &box);
- }
- else if (area < 0) {
- /* isle -> must be attached -> add to abox */
- Vect_get_isle_box(Map, -area, &box);
- if (first) {
- Vect_box_copy(&abox, &box);
- first = FALSE;
- }
- else
- Vect_box_extend(&abox, &box);
- }
- new_area[s] = area;
- }
- /* Reattach all centroids/isles in deleted areas + new area.
- * Because isles are selected by box it covers also possible
- * new isle created above */
- if (!first) { /* i.e. old area/isle was deleted or new one created */
- /* Reattach isles */
- if (plus->built >= GV_BUILD_ATTACH_ISLES)
- Vect_attach_isles(Map, &abox);
-
- /* Reattach centroids */
- if (plus->built >= GV_BUILD_CENTROIDS)
- Vect_attach_centroids(Map, &abox);
- }
- /* Add to category index */
- if (plus->update_cidx) {
- for (s = 0; s < 2; s++) {
- if (new_area[s] > 0) {
- V2__add_area_cats_to_cidx_nat(Map, new_area[s]);
- }
- }
- }
- }
-
- /* Attach centroid */
- if (plus->built >= GV_BUILD_CENTROIDS) {
- struct P_topo_c *topo;
-
- if (type == GV_CENTROID) {
- sel_area = Vect_find_area(Map, points->x[0], points->y[0]);
- G_debug(3, " new centroid %d is in area %d", line, sel_area);
- if (sel_area > 0) {
- Area = plus->Area[sel_area];
- Line = plus->Line[line];
- topo = (struct P_topo_c *)Line->topo;
- if (Area->centroid == 0) { /* first centroid */
- G_debug(3, " first centroid -> attach to area");
- Area->centroid = line;
- topo->area = sel_area;
- if (plus->update_cidx) {
- V2__add_area_cats_to_cidx_nat(Map, sel_area);
- }
- }
- else { /* duplicate centroid */
- G_debug(3,
- " duplicate centroid -> do not attach to area");
- topo->area = -sel_area;
- }
- }
- }
- }
-
- /* Add category index */
- if (cats) {
- for (i = 0; i < cats->n_cats; i++) {
- dig_cidx_add_cat_sorted(plus, cats->field[i], cats->cat[i], line,
- type);
- }
- }
-
- return;
-}
-
-/*!
- \brief Writes feature to 'coor' file (level 1)
+ \brief Writes feature to 'coor' file at level 1 (internal use only)
\param Map pointer to Map_info structure
\param type feature type (GV_POINT, GV_LINE, ...)
@@ -325,8 +43,8 @@
\return feature offset into file
\return -1 on error
*/
-off_t V1_write_line_nat(struct Map_info *Map,
- int type, const struct line_pnts *points, const struct line_cats *cats)
+off_t V1_write_line_nat(struct Map_info *Map, int type,
+ const struct line_pnts *points, const struct line_cats *cats)
{
off_t offset;
@@ -334,6 +52,7 @@
return -1;
offset = dig_ftell(&(Map->dig_fp));
+ G_debug(3, "V1_write_line_nat(): offset = %lu", offset);
if (offset == -1)
return -1;
@@ -342,65 +61,46 @@
/*!
\brief Writes feature to 'coor' file at topological level (internal use only)
+
+ Note: Function returns feature id, but is defined as off_t for
+ compatibility with level 1 functions.
\param Map pointer to Map_info structure
\param type feature type (GV_POINT, GV_LINE, ...)
\param points feature geometry
\param cats feature categories
- \return new feature id
+ \return new feature id
+ \return 0 topology is not requested to be built (build level < GV_BUILD_BASE)
\return -1 on error
*/
off_t V2_write_line_nat(struct Map_info *Map, int type,
const struct line_pnts *points, const struct line_cats *cats)
{
- int line;
off_t offset;
- struct Plus_head *plus;
- struct bound_box box;
- line = 0;
+ G_debug(3, "V2_write_line_nat(): type=%d", type);
- G_debug(3, "V2_write_line_nat()");
+ /* write feature to 'coor' file */
offset = V1_write_line_nat(Map, type, points, cats);
if (offset < 0)
return -1;
- /* Update topology */
- plus = &(Map->plus);
- /* Add line */
- if (plus->built >= GV_BUILD_BASE) {
- dig_line_box(points, &box);
- line = dig_add_line(plus, type, points, &box, offset);
- G_debug(3, " line added to topo with id = %d", line);
- if (line == 1)
- Vect_box_copy(&(plus->box), &box);
- else
- Vect_box_extend(&(plus->box), &box);
- }
-
- V2__add_line_to_topo_nat(Map, line, points, cats, NULL);
-
- G_debug(3, "updated lines : %d , updated nodes : %d", plus->uplist.n_uplines,
- plus->uplist.n_upnodes);
-
- /* returns int line, but is defined as off_t for compatibility with
- * Vect_write_line_array in write.c */
-
- return line;
+ /* update topology (build level >= GV_BUILD_BASE) */
+ return V2__add_line_to_topo_nat(Map, offset, type, points, cats, -1, NULL);
}
/*!
- \brief Rewrites feature at the given offset (level 1)
+ \brief Rewrites feature to 'coor' file at level 1 (internal use only)
- If the number of points or cats differs from the original one or
- the type is changed: GV_POINTS -> GV_LINES or GV_LINES ->
- GV_POINTS, the old one is deleted and the new is appended to the
- end of the file.
+ If the number of points or cats differs from the original one or the
+ type is changed: GV_POINTS -> GV_LINES or GV_LINES -> GV_POINTS, the
+ old one is deleted and the new is appended to the end of the file.
- Old feature is deleted (marked as dead), new feature written.
+ Old feature is deleted (marked as dead), and a new feature written.
\param Map pointer to Map_info structure
+ \param line feature id to be rewritten
\param offset feature offset
\param type feature type (GV_POINT, GV_LINE, ...)
\param points feature geometry
@@ -458,14 +158,20 @@
/*!
\brief Rewrites feature to 'coor' file at topological level (internal use only)
+
+ Note: Topology must be built at level >= GV_BUILD_BASE
+ Note: Function returns feature id, but is defined as off_t for
+ compatibility with level 1 functions.
+
\param Map pointer to Map_info structure
- \param type feature type (GV_POINT, GV_LINE, ...)
- \param line feature id
+ \param type feature type (GV_POINT, GV_LINE, ...)
+ \param line feature id to be rewritten
+ \param old_offset feature offset
\param points feature geometry
\param cats feature categories
- \return offset where line was rewritten
+ \return new feature id
\return -1 on error
*/
off_t V2_rewrite_line_nat(struct Map_info *Map, int line, int type, off_t old_offset,
@@ -478,45 +184,216 @@
* angles not changed etc.) */
off_t offset;
- struct Plus_head *plus;
- struct bound_box box;
- V2_delete_line_nat(Map, line);
+ if (0 != V2_delete_line_nat(Map, line))
+ return -1;
G_debug(3, "V2_write_line_nat(), line = %d", line);
+
+ /* rewrite feature in 'coor' file */
offset = V1_rewrite_line_nat(Map, line, type, old_offset, points, cats);
if (offset < 0)
return -1;
- /* Update topology */
+ /* update topology */
+ return V2__add_line_to_topo_nat(Map, offset, type, points, cats, -1, NULL);
+}
+
+/*!
+ \brief Deletes feature at level 1 (internal use only)
+
+ \param Map pointer Map_info structure
+ \param offset feature offset
+
+ \return 0 on success
+ \return -1 on error
+*/
+int V1_delete_line_nat(struct Map_info *Map, off_t offset)
+{
+ char rhead;
+ struct gvfile *dig_fp;
+
+ G_debug(3, "V1_delete_line_nat(): offset = %lu", (unsigned long) offset);
+
+ dig_set_cur_port(&(Map->head.port));
+ dig_fp = &(Map->dig_fp);
+
+ if (dig_fseek(dig_fp, offset, 0) == -1)
+ return -1;
+
+ /* read old */
+ if (0 >= dig__fread_port_C(&rhead, 1, dig_fp))
+ return -1;
+
+ rhead &= 0xFE;
+
+ if (dig_fseek(dig_fp, offset, 0) == -1)
+ return -1;
+
+ if (0 >= dig__fwrite_port_C(&rhead, 1, dig_fp))
+ return -1;
+
+ if (0 != dig_fflush(dig_fp))
+ return -1;
+
+ return 0;
+}
+
+/*!
+ \brief Deletes feature at topological level (internal use only)
+
+ Note: Topology must be built at level >= GV_BUILD_BASE
+
+ \param pointer to Map_info structure
+ \param line feature id
+
+ \return 0 on success
+ \return -1 on error
+*/
+int V2_delete_line_nat(struct Map_info *Map, int line)
+{
+ int type;
+ struct P_line *Line;
+ struct Plus_head *plus;
+
+ G_debug(3, "V2_delete_line_nat(): line = %d", line);
+
+ Line = NULL;
plus = &(Map->plus);
- /* Add line */
- if (plus->built >= GV_BUILD_BASE) {
- dig_line_box(points, &box);
- line = dig_add_line(plus, type, points, &box, offset);
- G_debug(3, " line added to topo with id = %d", line);
- if (line == 1)
- Vect_box_copy(&(plus->box), &box);
- else
- Vect_box_extend(&(plus->box), &box);
+
+ if (line < 1 || line > plus->n_lines) {
+ G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+ return -1;
}
+
+ Line = Map->plus.Line[line];
+ if (Line == NULL) {
+ G_warning(_("Attempt to access dead feature %d"), line);
+ return -1;
+ }
- V2__add_line_to_topo_nat(Map, line, points, cats, NULL);
+ /* read the line */
+ if (!Points) {
+ Points = Vect_new_line_struct();
+ }
+ if (!Cats) {
+ Cats = Vect_new_cats_struct();
+ }
+ type = V2_read_line_nat(Map, Points, Cats, line);
+ if (type < 0)
+ return -1;
- G_debug(3, "updated lines : %d , updated nodes : %d", plus->uplist.n_uplines,
- plus->uplist.n_upnodes);
+ /* delete feature from coor file */
+ if (0 != V1_delete_line_nat(Map, Line->offset))
+ return -1;
- /* returns int line, but is defined as off_t for compatibility with
- * Vect_rewrite_line_array in write.c */
+ /* delete feature from topology */
+ if (0 != V2__delete_line_from_topo_nat(Map, line, type, Points, Cats))
+ return -1;
- return line;
+ return 0;
}
/*!
- \brief Rewrites feature at the given offset.
+ \brief Restores feature at level 1 (internal use only)
\param Map pointer to Map_info structure
\param offset feature offset
+
+ \return 0 on success
+ \return -1 on error
+*/
+int V1_restore_line_nat(struct Map_info *Map, off_t offset)
+{
+ char rhead;
+ struct gvfile *dig_fp;
+
+ G_debug(3, "V1_restore_line_nat(), offset = %lu", (unsigned long) offset);
+
+ dig_set_cur_port(&(Map->head.port));
+ dig_fp = &(Map->dig_fp);
+
+ if (dig_fseek(dig_fp, offset, 0) == -1)
+ return -1;
+
+ /* read old */
+ if (0 >= dig__fread_port_C(&rhead, 1, dig_fp))
+ return -1;
+
+ /* mark as alive */
+ rhead |= 1;
+
+ /* write new */
+ if (dig_fseek(dig_fp, offset, 0) == -1)
+ return -1;
+
+ if (0 >= dig__fwrite_port_C(&rhead, 1, dig_fp))
+ return -1;
+
+ if (0 != dig_fflush(dig_fp))
+ return -1;
+
+ return 0;
+}
+
+/*!
+ \brief Restores feature at topological level (internal use only)
+
+ Note: This function requires build level >= GV_BUILD_BASE.
+
+ \param Map pointer to Map_info structure
+ \param line feature id
+ \param offset feature offset
+
+ \return 0 on success
+ \return -1 on error
+*/
+int V2_restore_line_nat(struct Map_info *Map, int line, off_t offset)
+{
+ int type;
+ struct Plus_head *plus;
+ struct P_line *Line;
+
+ plus = &(Map->plus);
+
+ G_debug(3, "V2_restore_line_nat(), line = %d", line);
+
+ if (line < 1 || line > plus->n_lines) {
+ G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+ return -1;
+ }
+
+ Line = Map->plus.Line[line];
+ if (Line != NULL) {
+ G_warning(_("Attempt to access alive feature %d"), line);
+ return -1;
+ }
+
+ /* restore feature in 'coor' file */
+ if (0 != V1_restore_line_nat(Map, offset))
+ return -1;
+
+
+ /* read feature geometry */
+ if (!Points)
+ Points = Vect_new_line_struct();
+ if (!Cats)
+ Cats = Vect_new_cats_struct();
+ type = V1_read_line_nat(Map, Points, Cats, offset);
+ if (type < 0)
+ return -1;
+
+ /* update topology */
+ return V2__add_line_to_topo_nat(Map, offset, type, Points, Cats, line, NULL) > 0 ? 0 : -1;
+}
+
+/*** static or internal subroutines bellow ****/
+
+/*!
+ \brief Rewrites feature at the given offset
+
+ \param Map pointer to Map_info structure
+ \param offset feature offset
\param type feature type (GV_POINT, GV_LINE, ...)
\param points feature geometry
\param cats feature categories
@@ -611,109 +488,135 @@
return offset;
}
-/*!
- \brief Deletes feature at the given offset (level 1)
+/*!
+ \brief Deletes area (i.e. centroid) categories from category
+ index (internal use only)
+
+ Call G_fatal_error() when area do not exits.
- \param Map pointer Map_info structure
- \param offset feature offset
-
- \return 0 on success
- \return -1 on error
+ \param Map pointer to Map_info structure
+ \param area area id
*/
-int V1_delete_line_nat(struct Map_info *Map, off_t offset)
+void V2__delete_area_cats_from_cidx_nat(struct Map_info *Map, int area)
{
- char rhead;
- struct gvfile *dig_fp;
+ int i;
+ struct P_area *Area;
+ static struct line_cats *Cats = NULL;
- G_debug(3, "V1_delete_line_nat(), offset = %lu", (unsigned long) offset);
+ G_debug(3, "V2__delete_area_cats_from_cidx_nat(), area = %d", area);
- dig_set_cur_port(&(Map->head.port));
- dig_fp = &(Map->dig_fp);
+ Area = Map->plus.Area[area];
+ if (!Area)
+ G_fatal_error(_("%s: Area %d does not exist"),
+ "delete_area_cats_from_cidx()", area);
+
+ if (Area->centroid == 0) /* no centroid found */
+ return;
- if (dig_fseek(dig_fp, offset, 0) == -1)
- return -1;
+ if (!Cats)
+ Cats = Vect_new_cats_struct();
- /* read old */
- if (0 >= dig__fread_port_C(&rhead, 1, dig_fp))
- return (-1);
+ V2_read_line_nat(Map, NULL, Cats, Area->centroid);
- rhead &= 0xFE;
+ for (i = 0; i < Cats->n_cats; i++) {
+ dig_cidx_del_cat(&(Map->plus), Cats->field[i], Cats->cat[i], area,
+ GV_AREA);
+ }
+}
- if (dig_fseek(dig_fp, offset, 0) == -1)
- return -1;
+/*!
+ \brief Adds area (i.e. centroid) categories from category index
+ (internal use only)
- if (0 >= dig__fwrite_port_C(&rhead, 1, dig_fp))
- return -1;
-
- if (0 != dig_fflush(dig_fp))
- return -1;
-
- return 0;
-}
-
-/*!
- \brief Deletes feature at topological level (internal use only)
+ Call G_fatal_error() when area do not exits.
- \param pointer to Map_info structure
- \param line feature id
-
- \return 0 on success
- \return -1 on error
+ \param Map pointer to Map_info structure
+ \param area area id
*/
-int V2_delete_line_nat(struct Map_info *Map, int line)
+void V2__add_area_cats_to_cidx_nat(struct Map_info *Map, int area)
{
- int ret, i, side, type, first, next_line, area;
- struct P_line *Line;
+ int i;
struct P_area *Area;
- struct Plus_head *plus;
- struct bound_box box, abox;
- int adjacent[4], n_adjacent;
static struct line_cats *Cats = NULL;
- static struct line_pnts *Points = NULL;
- G_debug(3, "V2_delete_line_nat(), line = %d", line);
+ G_debug(3, "V2__add_area_cats_to_cidx_nat(), area = %d", area);
- type = first = n_adjacent = 0;
- Line = NULL;
- plus = &(Map->plus);
+ Area = Map->plus.Area[area];
+ if (!Area)
+ G_fatal_error(_("%s: Area %d does not exist"),
+ "add_area_cats_to_cidx():", area);
- if (plus->built >= GV_BUILD_BASE) {
- Line = Map->plus.Line[line];
+ if (Area->centroid == 0) /* no centroid found */
+ return;
- if (Line == NULL)
- G_fatal_error(_("Attempt to delete dead feature"));
- type = Line->type;
- }
-
- if (!Cats) {
+ if (!Cats)
Cats = Vect_new_cats_struct();
- }
- if (!Points) {
- Points = Vect_new_line_struct();
- }
- type = V2_read_line_nat(Map, Points, Cats, line);
+ V2_read_line_nat(Map, NULL, Cats, Area->centroid);
- /* Update category index */
- if (plus->update_cidx) {
- for (i = 0; i < Cats->n_cats; i++) {
- dig_cidx_del_cat(plus, Cats->field[i], Cats->cat[i], line, type);
- }
+ for (i = 0; i < Cats->n_cats; i++) {
+ dig_cidx_add_cat_sorted(&(Map->plus), Cats->field[i], Cats->cat[i],
+ area, GV_AREA);
}
+}
- /* delete the line from coor */
- ret = V1_delete_line_nat(Map, Line->offset);
+/*!
+ \brief Delete feature from topology (internal use only)
- if (ret == -1) {
- return ret;
+ Note: This function requires build level >= GV_BUILD_BASE.
+
+ Also updates category index if requested.
+
+ Calls G_warning() on error.
+
+ \param Map pointer to Map_info struct
+ \param line feature id to be removed
+ \param Points feature geometry (pointer to line_pnts struct)
+ \param external_routine external subroutine to execute (used by PostGIS Topology)
+
+ \return 0 on success
+ \return -1 on failure
+ */
+int V2__delete_line_from_topo_nat(struct Map_info *Map, int line, int type,
+ const struct line_pnts *points, const struct line_cats *cats)
+{
+ int i, first;
+ int adjacent[4], n_adjacent;
+
+ struct bound_box box, abox;
+ struct Plus_head *plus;
+ struct P_line *Line;
+
+ n_adjacent = 0;
+
+ plus = &(Map->plus);
+
+ if (line < 1 || line > plus->n_lines) {
+ G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+ return -1;
}
+
+ Line = Map->plus.Line[line];
+ if (!Line) {
+ G_warning(_("Attempt to access dead feature %d"), line);
+ return -1;
+ }
- /* Update topology */
- if (plus->built >= GV_BUILD_AREAS && type == GV_BOUNDARY) {
- struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
+ /* delete feature from category index */
+ if (plus->update_cidx && cats) {
+ for (i = 0; i < cats->n_cats; i++) {
+ dig_cidx_del_cat(plus, cats->field[i], cats->cat[i], line, type);
+ }
+ }
+
+ /* update areas when deleting boundary from topology */
+ if (plus->built >= GV_BUILD_AREAS && Line->type == GV_BOUNDARY) {
+ int next_line;
+
+ struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
- /* Store adjacent boundaries at nodes (will be used to rebuild area/isle) */
- /* Adjacent are stored: > 0 - we want right side; < 0 - we want left side */
+ /* store adjacent boundaries at nodes (will be used to rebuild area/isle) */
+ /* adjacent are stored: > 0 - we want right side; < 0 - we want left side */
n_adjacent = 0;
next_line = dig_angle_next_line(plus, line, GV_RIGHT, GV_BOUNDARY, NULL);
@@ -741,7 +644,7 @@
n_adjacent++;
}
- /* Delete area(s) and islands this line forms */
+ /* delete area(s) and islands this line forms */
first = 1;
if (topo->left > 0) { /* delete area */
Vect_get_area_box(Map, topo->left, &box);
@@ -779,8 +682,10 @@
}
}
- /* Delete reference from area */
- if (plus->built >= GV_BUILD_CENTROIDS && type == GV_CENTROID) {
+ /* delete reference from area */
+ if (plus->built >= GV_BUILD_CENTROIDS && Line->type == GV_CENTROID) {
+ struct P_area *Area;
+
struct P_topo_c *topo = (struct P_topo_c *)Line->topo;
if (topo->area > 0) {
@@ -792,15 +697,17 @@
if (Area)
Area->centroid = 0;
else
- G_warning(_("Attempt to access dead area (%d)"), topo->area);
+ G_warning(_("Attempt to access dead area %d"), topo->area);
}
}
/* delete the line from topo */
- dig_del_line(plus, line, Points->x[0], Points->y[0], Points->z[0]);
-
- /* Rebuild areas/isles and attach centroids and isles */
+ if (0 != dig_del_line(plus, line, points->x[0], points->y[0], points->z[0]))
+ return -1;
+
+ /* rebuild areas/isles and attach centroids and isles */
if (plus->built >= GV_BUILD_AREAS && type == GV_BOUNDARY) {
+ int i, side, area;
int new_areas[4], nnew_areas = 0;
/* Rebuild areas/isles */
@@ -834,14 +741,14 @@
Vect_box_extend(&abox, &box);
}
}
- /* Reattach all centroids/isles in deleted areas + new area.
- * Because isles are selected by box it covers also possible new isle created above */
+ /* reattach all centroids/isles in deleted areas + new area.
+ * because isles are selected by box it covers also possible new isle created above */
if (!first) { /* i.e. old area/isle was deleted or new one created */
- /* Reattach isles */
+ /* reattach isles */
if (plus->built >= GV_BUILD_ATTACH_ISLES)
Vect_attach_isles(Map, &abox);
- /* Reattach centroids */
+ /* reattach centroids */
if (plus->built >= GV_BUILD_CENTROIDS)
Vect_attach_centroids(Map, &abox);
}
@@ -853,128 +760,257 @@
}
}
- G_debug(3, "updated lines : %d , updated nodes : %d", plus->uplist.n_uplines,
- plus->uplist.n_upnodes);
-
- return ret;
+ if (plus->uplist.do_uplist) {
+ G_debug(3, "updated lines : %d , updated nodes : %d", plus->uplist.n_uplines,
+ plus->uplist.n_upnodes);
+ }
+
+ return 0;
}
/*!
- \brief Restores feature at the given offset.
-
- \param Map pointer to Map_info structure
- \param offset feature offset
-
- \return 0 on success
- \return -1 on error
-*/
-int V1_restore_line_nat(struct Map_info *Map, off_t offset)
-{
- char rhead;
- struct gvfile *dig_fp;
-
- G_debug(3, "V1_restore_line_nat(), offset = %lu", (unsigned long) offset);
-
- dig_set_cur_port(&(Map->head.port));
- dig_fp = &(Map->dig_fp);
-
- if (dig_fseek(dig_fp, offset, 0) == -1)
- return -1;
-
- /* read old */
- if (0 >= dig__fread_port_C(&rhead, 1, dig_fp))
- return (-1);
+ \brief Add feature (line) to topology (internal use only)
- /* mark as alive */
- rhead |= 1;
-
- /* write new */
- if (dig_fseek(dig_fp, offset, 0) == -1)
- return -1;
+ Also updates category index if requested.
- if (0 >= dig__fwrite_port_C(&rhead, 1, dig_fp))
- return -1;
+ Update areas. Areas are modified if:
+
+ 1) first or/and last point are existing nodes ->
+ - drop areas/islands whose boundaries are neighbour to this boundary at these nodes
+ - try build areas and islands for this boundary and neighbour boundaries going through these nodes
+
+ Question: may be by adding line created new area/isle which doesn't go through nodes of this line
+
+ <pre>
+ old new line
+ +----+----+ +----+----+ +----+----+
+ | A1 | A2 | + / -> | A1 | /| or + \ -> | A1 | A2 | \
+ | | | | | | | | |
+ +----+----+ +----+----+ +----+----+
+ I1 I1 I1 I1
+ </pre>
+
+ - re-attach all centroids/isles inside new area(s)
+ - attach new isle to area outside
+
+ 2) line is closed ring (node at the end is new, so it is not case above)
+ - build new area/isle
+ - check if it is island or contains island(s)
+ - re-attach all centroids/isles inside new area(s)
+ - attach new isle to area outside
- if (0 != dig_fflush(dig_fp))
- return -1;
-
- return 0;
-}
+ Note that 1) and 2) is done by the same code.
-/*!
- \brief Restores feature at topological level (internal use only)
-
- \param Map pointer to Map_info structure
- \param line feature id
- \param offset feature offset
-
- \return 0 on success
- \return -1 on error
+ \param Map pointer to Map_info structure
+ \param line feature id to be added
+ \param points pointer to line_pnts structure (feature's geometry)
+ \param cats pointer to line_cats structure (feature's categories)
+ \param external_routine pointer to external routine (used by PostGIS Topology)
+
+ \return feature id to be added
+ \return 0 nothing to do (build level must be >= GV_BUILD_BASE)
+ \return -1 on error
*/
-int V2_restore_line_nat(struct Map_info *Map, int line, off_t offset)
+int V2__add_line_to_topo_nat(struct Map_info *Map, off_t offset, int type,
+ const struct line_pnts *points, const struct line_cats *cats,
+ int restore_line,
+ int (*external_routine) (const struct Map_info *, int))
{
- int i, ret, type;
- struct P_line *Line;
+ int first, s, n, i, line;
+ int node, next_line, area, side, sel_area, new_area[2];
+
struct Plus_head *plus;
- struct bound_box box;
+ struct P_line *Line, *NLine;
+ struct P_node *Node;
+ struct P_area *Area;
- static struct line_pnts *points = NULL;
- static struct line_cats *cats = NULL;
-
- Line = NULL;
- type = 0;
-
- G_debug(3, "V2_restore_line_nat(), line = %d", line);
+ struct bound_box box, abox;
plus = &(Map->plus);
+
+ G_debug(3, "V2__add_line_to_topo_nat(): offset = %ld (build level = %d)", offset, plus->built);
- if (plus->built >= GV_BUILD_BASE) {
- Line = Map->plus.Line[line];
+ if (plus->built < GV_BUILD_BASE) /* nothing to build */
+ return 0;
+
+ /* add line to topology */
+ dig_line_box(points, &box);
+ if (restore_line > 0)
+ line = dig_restore_line(plus, restore_line, type, points, &box, offset);
+ else
+ line = dig_add_line(plus, type, points, &box, offset);
+ G_debug(3, " line added to topo with id = %d", line);
+
+ Line = plus->Line[line];
+
+ /* extend map bounding box */
+ if (line == 1)
+ Vect_box_copy(&(plus->box), &box);
+ else
+ Vect_box_extend(&(plus->box), &box);
- if (Line != NULL)
- G_fatal_error(_("Attempt to restore alive feature"));
+ /* build areas on left/right side */
+ if (plus->built >= GV_BUILD_AREAS &&
+ type == GV_BOUNDARY) {
+ struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
+
+ /* delete neighbour areas/isles */
+ first = TRUE;
+ for (s = 0; s < 2; s++) { /* for each node */
+ node = (s == 0 ? topo->N1 : topo->N2);
+ G_debug(3,
+ " delete neighbour areas/isles: %s node = %d",
+ (s == 0 ? "first" : "second"), node);
+ Node = plus->Node[node];
+ n = 0;
+ for (i = 0; i < Node->n_lines; i++) {
+ NLine = plus->Line[abs(Node->lines[i])];
+ if (NLine->type == GV_BOUNDARY)
+ n++;
+ }
+
+ G_debug(3, " number of boundaries at node = %d", n);
+ if (n > 2) {
+ /* more than 2 boundaries at node ( >= 2 old + 1 new ) */
+ /* Line above (to the right), it is enough to check to
+ the right, because if area/isle exists it is the
+ same to the left */
+ if (!s)
+ next_line =
+ dig_angle_next_line(plus, line, GV_RIGHT,
+ GV_BOUNDARY, NULL);
+ else
+ next_line =
+ dig_angle_next_line(plus, -line, GV_RIGHT,
+ GV_BOUNDARY, NULL);
+
+ if (next_line != 0) { /* there is a boundary to the right */
+ NLine = plus->Line[abs(next_line)];
+ topo = (struct P_topo_b *)NLine->topo;
+ if (next_line > 0) /* the boundary is connected by 1. node */
+ /* we are interested just in this side (close to our line) */
+ area = topo->right;
+ else if (next_line < 0) /* the boundary is connected by 2. node */
+ area = topo->left;
+
+ G_debug(3, " next_line = %d area = %d", next_line,
+ area);
+ if (area > 0) { /* is area */
+ Vect_get_area_box(Map, area, &box);
+ if (first) {
+ Vect_box_copy(&abox, &box);
+ first = FALSE;
+ }
+ else
+ Vect_box_extend(&abox, &box);
+
+ if (plus->update_cidx) {
+ V2__delete_area_cats_from_cidx_nat(Map, area);
+ }
+ dig_del_area(plus, area);
+ if (external_routine) /* call external subroutine if defined */
+ external_routine(Map, area);
+ }
+ else if (area < 0) { /* is isle */
+ dig_del_isle(plus, -area);
+ if (external_routine) /* call external subroutine if defined */
+ external_routine(Map, area);
+ }
+ }
+ }
+ }
+
+ /* Build new areas/isles.
+ * It's true that we deleted also adjacent areas/isles, but
+ * if they form new one our boundary must participate, so
+ * we need to build areas/isles just for our boundary */
+ for (s = 0; s < 2; s++) {
+ side = (s == 0 ? GV_LEFT : GV_RIGHT);
+ area = Vect_build_line_area(Map, line, side);
+
+ if (area > 0) { /* area */
+ Vect_get_area_box(Map, area, &box);
+ if (first) {
+ Vect_box_copy(&abox, &box);
+ first = FALSE;
+ }
+ else
+ Vect_box_extend(&abox, &box);
+ }
+ else if (area < 0) {
+ /* isle -> must be attached -> add to abox */
+ Vect_get_isle_box(Map, -area, &box);
+ if (first) {
+ Vect_box_copy(&abox, &box);
+ first = FALSE;
+ }
+ else
+ Vect_box_extend(&abox, &box);
+ }
+ new_area[s] = area;
+ }
+ /* Reattach all centroids/isles in deleted areas + new area.
+ * Because isles are selected by box it covers also possible
+ * new isle created above */
+ if (!first) { /* i.e. old area/isle was deleted or new one created */
+ /* Reattach isles */
+ if (plus->built >= GV_BUILD_ATTACH_ISLES)
+ Vect_attach_isles(Map, &abox);
+
+ /* Reattach centroids */
+ if (plus->built >= GV_BUILD_CENTROIDS)
+ Vect_attach_centroids(Map, &abox);
+ }
+ /* Add to category index */
+ if (plus->update_cidx) {
+ for (s = 0; s < 2; s++) {
+ if (new_area[s] > 0) {
+ V2__add_area_cats_to_cidx_nat(Map, new_area[s]);
+ }
+ }
+ }
}
+
+ /* attach centroid */
+ if (plus->built >= GV_BUILD_CENTROIDS) {
+ struct P_topo_c *topo;
- if (!points) {
- points = Vect_new_line_struct();
+ if (type == GV_CENTROID) {
+ sel_area = Vect_find_area(Map, points->x[0], points->y[0]);
+ G_debug(3, " new centroid %d is in area %d", line, sel_area);
+ if (sel_area > 0) {
+ Area = plus->Area[sel_area];
+ Line = plus->Line[line];
+ topo = (struct P_topo_c *)Line->topo;
+ if (Area->centroid == 0) { /* first centroid */
+ G_debug(3, " first centroid -> attach to area");
+ Area->centroid = line;
+ topo->area = sel_area;
+ if (plus->update_cidx) {
+ V2__add_area_cats_to_cidx_nat(Map, sel_area);
+ }
+ }
+ else { /* duplicate centroid */
+ G_debug(3,
+ " duplicate centroid -> do not attach to area");
+ topo->area = -sel_area;
+ }
+ }
+ }
}
- if (!cats) {
- cats = Vect_new_cats_struct();
+ /* add category index */
+ if (plus->update_cidx && cats) {
+ for (i = 0; i < cats->n_cats; i++) {
+ dig_cidx_add_cat_sorted(plus, cats->field[i], cats->cat[i], line,
+ type);
+ }
}
- /* restore the line in coor */
- ret = V1_restore_line_nat(Map, offset);
-
- if (ret == -1) {
- return ret;
+ if (plus->uplist.do_uplist) {
+ G_debug(3, "updated lines : %d , updated nodes : %d", plus->uplist.n_uplines,
+ plus->uplist.n_upnodes);
}
- /* read feature geometry */
- type = V1_read_line_nat(Map, points, cats, offset);
- if (type < 0) {
- return -1;
- }
-
- /* update category index */
- if (plus->update_cidx) {
- for (i = 0; i < cats->n_cats; i++) {
- dig_cidx_add_cat(plus, cats->field[i], cats->cat[i], line, type);
- }
- }
-
- /* restore the line from topo */
- if (plus->built >= GV_BUILD_BASE) {
- dig_line_box(points, &box);
- dig_restore_line(plus, line, type, points, &box, offset);
- G_debug(3, " line restored in topo with id = %d", line);
- Vect_box_extend(&(plus->box), &box);
- }
-
- V2__add_line_to_topo_nat(Map, line, points, cats, NULL);
-
- G_debug(3, "updated lines : %d , updated nodes : %d", plus->uplist.n_uplines,
- plus->uplist.n_upnodes);
-
- return ret;
+ return line;
}
Modified: grass/trunk/lib/vector/Vlib/write_sfa.c
===================================================================
--- grass/trunk/lib/vector/Vlib/write_sfa.c 2013-04-01 14:13:18 UTC (rev 55581)
+++ grass/trunk/lib/vector/Vlib/write_sfa.c 2013-04-01 15:15:14 UTC (rev 55582)
@@ -126,7 +126,9 @@
/*!
\brief Rewrites feature at the given offset on level 2 (OGR/PostGIS
interface, pseudo-topological level)
-
+
+ Note: Topology must be built at level >= GV_BUILD_BASE
+
\param Map pointer to Map_info structure
\param line feature id to be rewritten
\param type feature type (see V1_write_line_ogr() for supported types)
@@ -143,13 +145,19 @@
G_debug(3, "V2_rewrite_line_sfa(): line=%d type=%d offset=%lu",
line, type, offset);
+ if (line < 1 || line > Map->plus.n_lines) {
+ G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+ return -1;
+ }
+
#if defined HAVE_OGR || defined HAVE_POSTGRES
if (type != V2_read_line_sfa(Map, NULL, NULL, line)) {
G_warning(_("Unable to rewrite feature (incompatible feature types)"));
return -1;
}
- V2_delete_line_sfa(Map, line);
+ if (V2_delete_line_sfa(Map, line) != 0)
+ return -1;
return V2_write_line_sfa(Map, type, points, cats);
#else
@@ -160,6 +168,8 @@
/*!
\brief Deletes feature on level 2 (OGR/PostGIS interface)
+
+ Note: Topology must be built at level >= GV_BUILD_BASE
\todo Update fidx
@@ -178,12 +188,17 @@
static struct line_cats *Cats = NULL;
static struct line_pnts *Points = NULL;
- G_debug(3, "V2_delete_line_sfa(), line = %d", line);
+ G_debug(3, "V2_delete_line_sfa(): line = %d", line);
type = first = 0;
Line = NULL;
plus = &(Map->plus);
+ if (line < 1 || line > Map->plus.n_lines) {
+ G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+ return -1;
+ }
+
if (plus->built >= GV_BUILD_BASE) {
Line = Map->plus.Line[line];
@@ -200,7 +215,9 @@
}
type = V2_read_line_sfa(Map, Points, Cats, line);
-
+ if (type < 0)
+ return -1;
+
/* Update category index */
if (plus->update_cidx) {
for (i = 0; i < Cats->n_cats; i++) {
More information about the grass-commit
mailing list