/*! \file lib/vector/Vlib/write_sfa.c \brief Vector library - write vector feature - simple feature access (level 2) Higher level functions for reading/writing/manipulating vectors. See write_ogr.c (OGR interface) and write_pg.c (PostGIS interface) for imlementation issues. \todo SFA version of V2__delete_area_cats_from_cidx_nat() \todo function to delete corresponding entry in fidx \todo SFA version of V2__add_area_cats_to_cidx_nat \todo SFA version of V2__add_line_to_topo_nat (C) 2011-2012 by Martin Landa, and 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 Martin Landa */ #include #include #include "local_proto.h" #ifdef HAVE_POSTGRES #include "pg_local_proto.h" #endif #if defined HAVE_OGR || defined HAVE_POSTGRES static void V2__add_line_to_topo_sfa(struct Map_info *, int, const struct line_pnts *, const struct line_cats *); #endif /*! \brief Writes feature on level 2 (OGR/PostGIS interface, pseudo-topological level) \param Map pointer to Map_info structure \param type feature type (see V1_write_line_ogr() for list of supported types) \param points pointer to line_pnts structure (feature geometry) \param cats pointer to line_cats structure (feature categories) \return feature index in offset array (related to pseudo-topology) \return -1 on error */ off_t V2_write_line_sfa(struct Map_info *Map, int type, const struct line_pnts *points, const struct line_cats *cats) { #if defined HAVE_OGR || defined HAVE_POSTGRES int line; off_t offset; struct Plus_head *plus; struct bound_box box; struct Format_info_offset *offset_info; line = 0; plus = &(Map->plus); G_debug(3, "V2_write_line_sfa(): type = %d (format = %d)", type, Map->format); if (Map->format == GV_FORMAT_POSTGIS) { offset_info = &(Map->fInfo.pg.offset); offset = V1_write_line_pg(Map, type, points, cats); } else { offset_info = &(Map->fInfo.pg.offset); offset = V1_write_line_ogr(Map, type, points, cats); } if (offset < 0) return -1; if (!(plus->update_cidx)) { plus->cidx_up_to_date = FALSE; /* category index will be outdated */ } /* Update topology */ if (plus->built >= GV_BUILD_BASE) { dig_line_box(points, &box); line = dig_add_line(plus, type, points, &box, offset); G_debug(3, "\tline added to topo with line = %d", line); if (line == 1) Vect_box_copy(&(plus->box), &box); else Vect_box_extend(&(plus->box), &box); if (type == GV_BOUNDARY) { int ret, cline; long fid; double x, y; struct bound_box box; struct line_pnts *CPoints; /* add virtual centroid to pseudo-topology */ ret = Vect_get_point_in_poly(points, &x, &y); if (ret == 0) { CPoints = Vect_new_line_struct(); Vect_append_point(CPoints, x, y, 0.0); fid = offset_info->array[offset]; dig_line_box(CPoints, &box); cline = dig_add_line(plus, GV_CENTROID, CPoints, &box, fid); G_debug(4, "\tCentroid: x = %f, y = %f, cat = %lu, line = %d", x, y, fid, cline); dig_cidx_add_cat(plus, 1, (int) fid, cline, GV_CENTROID); Vect_destroy_line_struct(CPoints); } else { G_warning(_("Unable to calculate centroid for area")); } } V2__add_line_to_topo_sfa(Map, line, points, cats); } 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 * Write_line_array in write.c */ return line; #else G_fatal_error(_("GRASS is not compiled with OGR/PostgreSQL support")); return -1; #endif } /*! \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) \param points pointer to line_pnts structure (feature geometry) \param cats pointer to line_cats structure feature categories \return feature index in offset array (related to pseudo-topology) \return -1 on error */ off_t V2_rewrite_line_sfa(struct Map_info *Map, off_t line, int type, const struct line_pnts *points, const struct line_cats *cats) { G_debug(3, "V2_rewrite_line_sfa(): line=%d type=%d", (int)line, type); if (line < 1 || line > Map->plus.n_lines) { G_warning(_("Attempt to access feature with invalid id (%d)"), (int)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; } if (V2_delete_line_sfa(Map, line) != 0) return -1; return V2_write_line_sfa(Map, type, points, cats); #else G_fatal_error(_("GRASS is not compiled with OGR/PostgreSQL support")); return -1; #endif } /*! \brief Deletes feature on level 2 (OGR/PostGIS interface) Note: Topology must be built at level >= GV_BUILD_BASE \todo Update fidx \param pointer to Map_info structure \param line feature id to be deleted \return 0 on success \return -1 on error */ int V2_delete_line_sfa(struct Map_info *Map, off_t line) { #if defined HAVE_OGR || defined HAVE_POSTGRES int ret, i, type, first; struct P_line *Line; struct Plus_head *plus; static struct line_cats *Cats = NULL; static struct line_pnts *Points = NULL; G_debug(3, "V2_delete_line_sfa(): line = %d", (int)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)"), (int)line); return -1; } if (!(plus->update_cidx)) { plus->cidx_up_to_date = FALSE; /* category index will be outdated */ } if (plus->built >= GV_BUILD_BASE) { Line = Map->plus.Line[line]; if (Line == NULL) G_fatal_error(_("Attempt to delete dead feature")); type = Line->type; } if (!Cats) { Cats = Vect_new_cats_struct(); } if (!Points) { Points = Vect_new_line_struct(); } 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++) { dig_cidx_del_cat(plus, Cats->field[i], Cats->cat[i], line, type); } } /* Update fidx */ /* TODO */ /* delete the line from coor */ if (Map->format == GV_FORMAT_POSTGIS) ret = V1_delete_line_pg(Map, Line->offset); else ret = V1_delete_line_ogr(Map, Line->offset); if (ret == -1) { return ret; } /* Update topology */ if (plus->built >= GV_BUILD_AREAS && type == GV_BOUNDARY) { /* TODO */ /* remove centroid together with boundary (is really an OGR polygon) */ } /* Delete reference from area */ if (plus->built >= GV_BUILD_CENTROIDS && type == GV_CENTROID) { /* for OGR mapsets, virtual centroid will be removed when * polygon is removed */ } /* 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 (plus->built >= GV_BUILD_AREAS && type == GV_BOUNDARY) { /* maybe not needed VERIFY */ } return ret; #else G_fatal_error(_("GRASS is not compiled with OGR/PostgreSQL support")); return -1; #endif } /*! \brief Writes area on topological level (Simple Features interface, internal use only) \param Map pointer to Map_info structure \param points feature geometry (exterior + interior rings) \param nparts number of parts including exterior ring \param cats feature categories \return feature offset \return -1 on error */ off_t V2__write_area_sfa(struct Map_info *Map, const struct line_pnts **points, int nparts, const struct line_cats *cats) { if (Map->format == GV_FORMAT_OGR) { #ifdef HAVE_OGR return V2__write_area_ogr(Map, points, nparts, cats); #else G_fatal_error(_("GRASS is not compiled with OGR support")); return -1; #endif } else if (Map->format == GV_FORMAT_POSTGIS) { #ifdef HAVE_POSTGRES return V2__write_area_pg(Map, points, nparts, cats); #else G_fatal_error(_("GRASS is not compiled with PostgreSQL support")); return -1; #endif } else { G_warning(_("Unsupported vector map format (%d)"), Map->format); } return -1; } #if defined HAVE_OGR || defined HAVE_POSTGRES /*! \brief Add feature to topo file (internal use only) \param Map pointer to Map_info structure \param line feature id \param points pointer to line_pnts structure (feature geometry) \param cats pointer to line_cats structure (feature categories) */ void V2__add_line_to_topo_sfa(struct Map_info *Map, int line, const struct line_pnts *points, const struct line_cats *cats) { int first, s, i; int type, area, side; struct Plus_head *plus; struct P_line *Line; struct bound_box box, abox; G_debug(3, "V2__add_line_to_topo_sfa(): line = %d npoints = %d", line, points->n_points); 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; if (topo->N1 != topo->N2) { G_warning(_("Boundary is not closed. Skipping.")); return; } /* Build new areas/isles */ 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); } G_debug(4, "Vect_build_line_area(): -> area = %d", area); } /* Attach centroid/isle to the new area */ if (plus->built >= GV_BUILD_ATTACH_ISLES) Vect_attach_isles(Map, &abox); if (plus->built >= GV_BUILD_CENTROIDS) Vect_attach_centroids(Map, &abox); } /* Add category index */ for (i = 0; i < cats->n_cats; i++) { dig_cidx_add_cat_sorted(plus, cats->field[i], cats->cat[i], line, type); } return; } #endif /* HAVE_OGR || HAVE_POSTGRES */