/** * \file plus_line.c * * \brief Vector library - update topo for lines (lower level functions) * * Lower level functions for reading/writing/manipulating vectors. * * This program is free software under the GNU General Public License * (>=v2). Read the file COPYING that comes with GRASS for details. * * \author CERL (probably Dave Gerdes), Radim Blazek * * \date 2001-2008 */ #include #include #include #include static int add_line(struct Plus_head *plus, int lineid, int type, const struct line_pnts *Points, const struct bound_box *box, off_t offset) { int node, lp, node_new; struct P_line *line; plus->Line[lineid] = dig_alloc_line(); line = plus->Line[lineid]; line->type = type; line->offset = offset; dig_spidx_add_line(plus, lineid, box); if (plus->uplist.do_uplist) { dig_line_add_updated(plus, lineid, offset); } if (type & GV_POINT) { line->topo = NULL; return (lineid); } line->topo = dig_alloc_topo(type); if (type & GV_CENTROID) { struct P_topo_c *topo = (struct P_topo_c *)line->topo; topo->area = 0; return (lineid); } /* Add nodes for lines */ G_debug(3, "Register node: type = %d, %f,%f", type, Points->x[0], Points->y[0]); /* Start node */ node = dig_find_node(plus, Points->x[0], Points->y[0], Points->z[0]); G_debug(3, "node = %d", node); if (node == 0) { node = dig_add_node(plus, Points->x[0], Points->y[0], Points->z[0]); G_debug(3, "Add new node: %d", node); node_new = TRUE; } else { G_debug(3, "Old node found: %d", node); node_new = FALSE; } if (type == GV_LINE) { struct P_topo_l *topo = (struct P_topo_l *)line->topo; topo->N1 = node; topo->N2 = 0; } else if (type == GV_BOUNDARY) { struct P_topo_b *topo = (struct P_topo_b *)line->topo; topo->N1 = node; topo->N2 = 0; topo->left = 0; topo->right = 0; } dig_node_add_line(plus, node, lineid, Points, type); if (plus->uplist.do_uplist) dig_node_add_updated(plus, node_new ? -node : node); /* End node */ lp = Points->n_points - 1; G_debug(3, "Register node %f,%f", Points->x[lp], Points->y[lp]); node = dig_find_node(plus, Points->x[lp], Points->y[lp], Points->z[lp]); G_debug(3, "node = %d", node); if (node == 0) { node = dig_add_node(plus, Points->x[lp], Points->y[lp], Points->z[lp]); G_debug(3, "Add new node: %d", node); node_new = TRUE; } else { G_debug(3, "Old node found: %d", node); node_new = FALSE; } if (type == GV_LINE) { struct P_topo_l *topo = (struct P_topo_l *)line->topo; topo->N2 = node; } else if (type == GV_BOUNDARY) { struct P_topo_b *topo = (struct P_topo_b *)line->topo; topo->N2 = node; } dig_node_add_line(plus, node, -lineid, Points, type); if (plus->uplist.do_uplist) dig_node_add_updated(plus, node_new ? -node : node); return (lineid); } /*! * \brief Add new line to Plus_head structure. * * \param[in,out] plus pointer to Plus_head structure * \param type feature type * \param Points line geometry * \param box bounding box * \param offset line offset * * \return -1 on error * \return line id */ int dig_add_line(struct Plus_head *plus, int type, const struct line_pnts *Points, const struct bound_box *box, off_t offset) { int ret; /* First look if we have space in array of pointers to lines * and reallocate if necessary */ if (plus->n_lines >= plus->alloc_lines) { /* array is full */ if (dig_alloc_lines(plus, 1000) == -1) return -1; } ret = add_line(plus, plus->n_lines + 1, type, Points, box, offset); if (ret == -1) return ret; plus->n_lines++; switch (type) { case GV_POINT: plus->n_plines++; break; case GV_LINE: plus->n_llines++; break; case GV_BOUNDARY: plus->n_blines++; break; case GV_CENTROID: plus->n_clines++; break; case GV_FACE: plus->n_flines++; break; case GV_KERNEL: plus->n_klines++; break; } return ret; } /*! * \brief Restore line in Plus_head structure. * * \param[in,out] plus pointer to Plus_head structure * \param type feature type * \param Points line geometry * \param box bounding box * \param offset line offset * * \return -1 on error * \return line id */ int dig_restore_line(struct Plus_head *plus, int lineid, int type, const struct line_pnts *Points, const struct bound_box *box, off_t offset) { if (lineid < 1 || lineid > plus->n_lines) { return -1; } return add_line(plus, lineid, type, Points, box, offset); } /*! * \brief Delete line from Plus_head structure. * * Doesn't update area/isle references (dig_del_area() or dig_del_isle()) must be * run before the line is deleted if the line is part of such * structure). Update is info about line in nodes. If this line is * last in node then node is deleted. * * \param[in,out] plus pointer to Plus_head structure * \param[in] line line id * \param[in] x,y,z coordinates * * \return -1 on error * \return 0 OK * */ int dig_del_line(struct Plus_head *plus, int line, double x, double y, double z) { int i; plus_t N1 = 0, N2 = 0; struct P_line *Line; struct P_node *Node; G_debug(3, "dig_del_line() line = %d", line); Line = plus->Line[line]; dig_spidx_del_line(plus, line, x, y, z); if (plus->uplist.do_uplist) { dig_line_add_updated(plus, line, -Line->offset); } if (!(Line->type & GV_LINES)) { /* Delete line */ dig_free_line(Line); plus->Line[line] = NULL; return 0; } /* Delete from nodes (and nodes) */ if (Line->type == GV_LINE) { struct P_topo_l *topo = (struct P_topo_l *)Line->topo; N1 = topo->N1; } else if (Line->type == GV_BOUNDARY) { struct P_topo_b *topo = (struct P_topo_b *)Line->topo; N1 = topo->N1; } Node = plus->Node[N1]; i = 0; while (i < Node->n_lines && Node->lines[i] != line) i++; if (i == Node->n_lines) { G_fatal_error(_("Attempt to delete not registered line %d from node %d"), line, N1); } i++; while (i < Node->n_lines) { Node->lines[i - 1] = Node->lines[i]; Node->angles[i - 1] = Node->angles[i]; i++; } Node->n_lines--; if (plus->uplist.do_uplist) { dig_node_add_updated(plus, Node->n_lines > 0 ? N1 : -N1); } if (Node->n_lines == 0) { G_debug(3, " node %d has 0 lines -> delete", N1); dig_spidx_del_node(plus, N1); /* free structures */ dig_free_node(Node); plus->Node[N1] = NULL; } if (Line->type == GV_LINE) { struct P_topo_l *topo = (struct P_topo_l *)Line->topo; N2 = topo->N2; } else if (Line->type == GV_BOUNDARY) { struct P_topo_b *topo = (struct P_topo_b *)Line->topo; N2 = topo->N2; } Node = plus->Node[N2]; i = 0; while (i < Node->n_lines && Node->lines[i] != -line) i++; if (i == Node->n_lines) { G_fatal_error(_("Attempt to delete not registered line %d from node %d"), -line, N2); } i++; while (i < Node->n_lines) { Node->lines[i - 1] = Node->lines[i]; Node->angles[i - 1] = Node->angles[i]; i++; } Node->n_lines--; if (plus->uplist.do_uplist) { dig_node_add_updated(plus, Node->n_lines > 0 ? N2 : -N2); } if (Node->n_lines == 0) { G_debug(3, " node %d has 0 lines -> delete", N2); dig_spidx_del_node(plus, N2); /* free structures */ dig_free_node(Node); plus->Node[N2] = NULL; } /* Delete line */ dig_free_line(Line); plus->Line[line] = NULL; return 0; } /*! * \brief Get area number on line side. * * \param[in] plus pointer Plus_head structure * \param[in] line line id * \param[in] side side id (GV_LEFT || GV_RIGHT) * * \return area number * \return 0 no area * \return -1 on error */ plus_t dig_line_get_area(struct Plus_head * plus, plus_t line, int side) { struct P_line *Line; struct P_topo_b *topo; Line = plus->Line[line]; if (!Line) /* dead */ return -1; if (Line->type != GV_BOUNDARY) return -1; topo = (struct P_topo_b *)Line->topo; if (side == GV_LEFT) { G_debug(3, "dig_line_get_area(): line = %d, side = %d (left), area = %d", line, side, topo->left); return (topo->left); } if (side == GV_RIGHT) { G_debug(3, "dig_line_get_area(): line = %d, side = %d (right), area = %d", line, side, topo->right); return (topo->right); } return (-1); } /*! * \brief Set area number on line side * * \param[in] plus pointer Plus_head structure * \param[in] line line id * \param[in] side side id (GV_LEFT || GV_RIGHT) * \param[in] area area id * * \return 1 */ int dig_line_set_area(struct Plus_head *plus, plus_t line, int side, plus_t area) { struct P_line *Line; struct P_topo_b *topo; Line = plus->Line[line]; if (Line->type != GV_BOUNDARY) return (0); topo = (struct P_topo_b *)Line->topo; if (side == GV_LEFT) { topo->left = area; } else if (side == GV_RIGHT) { topo->right = area; } return (1); } /*! * \brief Set line bounding box * * \param[in] plus pointer Plus_head structure * \param[in] line line id * \param[in] Box bounding box * * \return 1 */ /* int dig_line_set_box(struct Plus_head *plus, plus_t line, struct bound_box * Box) { struct P_line *Line; Line = plus->Line[line]; Line->N = Box->N; Line->S = Box->S; Line->E = Box->E; Line->W = Box->W; Line->T = Box->T; Line->B = Box->B; return (1); } */ /*! * \brief Get line bounding box saved in topo * * \param[in] plus pointer Plus_head structure * \param[in] line line id * \param[in,out] Box bounding box * * \return 1 */ /* int dig_line_get_box(struct Plus_head *plus, plus_t line, struct bound_box * Box) { struct P_line *Line; Line = plus->Line[line]; Box->N = Line->N; Box->S = Line->S; Box->E = Line->E; Box->W = Line->W; Box->T = Line->T; Box->B = Line->B; return (1); } */