1 
2 /**
3  * \file plus_line.c
4  *
5  * \brief Vector library - update topo for lines (lower level functions)
6  *
7  * Lower level functions for reading/writing/manipulating vectors.
8  *
9  * This program is free software under the GNU General Public License
10  * (>=v2). Read the file COPYING that comes with GRASS for details.
11  *
12  * \author CERL (probably Dave Gerdes), Radim Blazek
13  *
14  * \date 2001-2008
15  */
16 
17 #include <sys/types.h>
18 #include <stdlib.h>
19 #include <grass/vector.h>
20 #include <grass/glocale.h>
21 
add_line(struct Plus_head * plus,int lineid,int type,const struct line_pnts * Points,const struct bound_box * box,off_t offset)22 static int add_line(struct Plus_head *plus, int lineid, int type, const struct line_pnts *Points,
23 		    const struct bound_box *box, off_t offset)
24 {
25     int node, lp, node_new;
26     struct P_line *line;
27 
28     plus->Line[lineid] = dig_alloc_line();
29     line = plus->Line[lineid];
30 
31     line->type = type;
32     line->offset = offset;
33 
34     dig_spidx_add_line(plus, lineid, box);
35     if (plus->uplist.do_uplist) {
36 	dig_line_add_updated(plus, lineid, offset);
37     }
38 
39     if (type & GV_POINT) {
40 	line->topo = NULL;
41 	return (lineid);
42     }
43 
44     line->topo = dig_alloc_topo(type);
45 
46     if (type & GV_CENTROID) {
47 	struct P_topo_c *topo = (struct P_topo_c *)line->topo;
48 
49 	topo->area = 0;
50 	return (lineid);
51     }
52 
53     /* Add nodes for lines */
54     G_debug(3, "Register node: type = %d,  %f,%f", type, Points->x[0],
55 	    Points->y[0]);
56 
57     /* Start node */
58     node = dig_find_node(plus, Points->x[0], Points->y[0], Points->z[0]);
59     G_debug(3, "node = %d", node);
60     if (node == 0) {
61 	node = dig_add_node(plus, Points->x[0], Points->y[0], Points->z[0]);
62 	G_debug(3, "Add new node: %d", node);
63         node_new = TRUE;
64     }
65     else {
66         G_debug(3, "Old node found: %d", node);
67         node_new = FALSE;
68     }
69 
70     if (type == GV_LINE) {
71 	struct P_topo_l *topo = (struct P_topo_l *)line->topo;
72 
73 	topo->N1 = node;
74 	topo->N2 = 0;
75     }
76     else if (type == GV_BOUNDARY) {
77 	struct P_topo_b *topo = (struct P_topo_b *)line->topo;
78 
79 	topo->N1 = node;
80 	topo->N2 = 0;
81 	topo->left = 0;
82 	topo->right = 0;
83     }
84 
85     dig_node_add_line(plus, node, lineid, Points, type);
86     if (plus->uplist.do_uplist)
87 	dig_node_add_updated(plus, node_new ? -node : node);
88 
89     /* End node */
90     lp = Points->n_points - 1;
91     G_debug(3, "Register node %f,%f", Points->x[lp], Points->y[lp]);
92     node = dig_find_node(plus, Points->x[lp], Points->y[lp],
93 			 Points->z[lp]);
94     G_debug(3, "node = %d", node);
95     if (node == 0) {
96 	node = dig_add_node(plus, Points->x[lp], Points->y[lp],
97 			    Points->z[lp]);
98 	G_debug(3, "Add new node: %d", node);
99         node_new = TRUE;
100     }
101     else {
102 	G_debug(3, "Old node found: %d", node);
103         node_new = FALSE;
104     }
105     if (type == GV_LINE) {
106 	struct P_topo_l *topo = (struct P_topo_l *)line->topo;
107 
108 	topo->N2 = node;
109     }
110     else if (type == GV_BOUNDARY) {
111 	struct P_topo_b *topo = (struct P_topo_b *)line->topo;
112 
113 	topo->N2 = node;
114     }
115 
116     dig_node_add_line(plus, node, -lineid, Points, type);
117     if (plus->uplist.do_uplist)
118 	dig_node_add_updated(plus, node_new ? -node : node);
119 
120     return (lineid);
121 }
122 
123 /*!
124  * \brief Add new line to Plus_head structure.
125  *
126  * \param[in,out] plus pointer to Plus_head structure
127  * \param type feature type
128  * \param Points line geometry
129  * \param box bounding box
130  * \param offset line offset
131  *
132  * \return -1 on error
133  * \return line id
134  */
135 int
dig_add_line(struct Plus_head * plus,int type,const struct line_pnts * Points,const struct bound_box * box,off_t offset)136 dig_add_line(struct Plus_head *plus, int type, const struct line_pnts *Points,
137              const struct bound_box *box, off_t offset)
138 {
139     int ret;
140 
141     /* First look if we have space in array of pointers to lines
142      *  and reallocate if necessary */
143     if (plus->n_lines >= plus->alloc_lines) {	/* array is full */
144 	if (dig_alloc_lines(plus, 1000) == -1)
145 	    return -1;
146     }
147 
148     ret = add_line(plus, plus->n_lines + 1, type, Points, box, offset);
149 
150     if (ret == -1)
151 	return ret;
152 
153     plus->n_lines++;
154 
155     switch (type) {
156     case GV_POINT:
157 	plus->n_plines++;
158 	break;
159     case GV_LINE:
160 	plus->n_llines++;
161 	break;
162     case GV_BOUNDARY:
163 	plus->n_blines++;
164 	break;
165     case GV_CENTROID:
166 	plus->n_clines++;
167 	break;
168     case GV_FACE:
169 	plus->n_flines++;
170 	break;
171     case GV_KERNEL:
172 	plus->n_klines++;
173 	break;
174     }
175 
176     return ret;
177 }
178 
179 /*!
180  * \brief Restore line in Plus_head structure.
181  *
182  * \param[in,out] plus pointer to Plus_head structure
183  * \param type feature type
184  * \param Points line geometry
185  * \param box bounding box
186  * \param offset line offset
187  *
188  * \return -1 on error
189  * \return line id
190  */
191 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)192 dig_restore_line(struct Plus_head *plus, int lineid,
193 		 int type, const struct line_pnts *Points,
194 		 const struct bound_box *box, off_t offset)
195 {
196     if (lineid < 1 || lineid > plus->n_lines) {
197 	return -1;
198     }
199 
200     return add_line(plus, lineid, type, Points, box, offset);
201 }
202 
203 /*!
204  * \brief Delete line from Plus_head structure.
205  *
206  * Doesn't update area/isle references (dig_del_area() or dig_del_isle()) must be
207  * run before the line is deleted if the line is part of such
208  * structure). Update is info about line in nodes. If this line is
209  * last in node then node is deleted.
210  *
211  * \param[in,out] plus pointer to Plus_head structure
212  * \param[in] line line id
213  * \param[in] x,y,z coordinates
214  *
215  * \return -1 on error
216  * \return  0 OK
217  *
218  */
dig_del_line(struct Plus_head * plus,int line,double x,double y,double z)219 int dig_del_line(struct Plus_head *plus, int line, double x, double y, double z)
220 {
221     int i;
222     plus_t N1 = 0, N2 = 0;
223     struct P_line *Line;
224     struct P_node *Node;
225 
226     G_debug(3, "dig_del_line() line =  %d", line);
227 
228     Line = plus->Line[line];
229     dig_spidx_del_line(plus, line, x, y, z);
230 
231     if (plus->uplist.do_uplist) {
232 	dig_line_add_updated(plus, line, -Line->offset);
233     }
234 
235     if (!(Line->type & GV_LINES)) {
236 	/* Delete line */
237 	dig_free_line(Line);
238 	plus->Line[line] = NULL;
239 
240 	return 0;
241     }
242 
243     /* Delete from nodes (and nodes) */
244     if (Line->type == GV_LINE) {
245 	struct P_topo_l *topo = (struct P_topo_l *)Line->topo;
246 
247 	N1 = topo->N1;
248     }
249     else if (Line->type == GV_BOUNDARY) {
250 	struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
251 
252 	N1 = topo->N1;
253     }
254 
255     Node = plus->Node[N1];
256 
257     i = 0;
258     while (i < Node->n_lines && Node->lines[i] != line)
259 	i++;
260 
261     if (i == Node->n_lines) {
262 	G_fatal_error(_("Attempt to delete not registered line %d from node %d"),
263 		      line, N1);
264     }
265 
266     i++;
267     while (i < Node->n_lines) {
268 	Node->lines[i - 1] = Node->lines[i];
269 	Node->angles[i - 1] = Node->angles[i];
270 	i++;
271     }
272     Node->n_lines--;
273 
274     if (plus->uplist.do_uplist) {
275         dig_node_add_updated(plus, Node->n_lines > 0 ? N1 : -N1);
276     }
277     if (Node->n_lines == 0) {
278 	G_debug(3, "    node %d has 0 lines -> delete", N1);
279 	dig_spidx_del_node(plus, N1);
280 	/* free structures */
281 	dig_free_node(Node);
282 	plus->Node[N1] = NULL;
283     }
284 
285     if (Line->type == GV_LINE) {
286 	struct P_topo_l *topo = (struct P_topo_l *)Line->topo;
287 
288 	N2 = topo->N2;
289     }
290     else if (Line->type == GV_BOUNDARY) {
291 	struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
292 
293 	N2 = topo->N2;
294     }
295 
296     Node = plus->Node[N2];
297     i = 0;
298     while (i < Node->n_lines && Node->lines[i] != -line)
299 	i++;
300 
301     if (i == Node->n_lines) {
302 	G_fatal_error(_("Attempt to delete not registered line %d from node %d"),
303 		      -line, N2);
304     }
305 
306     i++;
307     while (i < Node->n_lines) {
308 	Node->lines[i - 1] = Node->lines[i];
309 	Node->angles[i - 1] = Node->angles[i];
310 	i++;
311     }
312     Node->n_lines--;
313 
314     if (plus->uplist.do_uplist) {
315         dig_node_add_updated(plus, Node->n_lines > 0 ? N2 : -N2);
316     }
317     if (Node->n_lines == 0) {
318 	G_debug(3, "    node %d has 0 lines -> delete", N2);
319 	dig_spidx_del_node(plus, N2);
320 	/* free structures */
321 	dig_free_node(Node);
322 	plus->Node[N2] = NULL;
323     }
324 
325     /* Delete line */
326     dig_free_line(Line);
327     plus->Line[line] = NULL;
328 
329     return 0;
330 }
331 
332 /*!
333  * \brief Get area number on line side.
334  *
335  * \param[in] plus pointer Plus_head structure
336  * \param[in] line line id
337  * \param[in] side side id (GV_LEFT || GV_RIGHT)
338  *
339  * \return  area number
340  * \return  0 no area
341  * \return -1 on error
342  */
dig_line_get_area(struct Plus_head * plus,plus_t line,int side)343 plus_t dig_line_get_area(struct Plus_head * plus, plus_t line, int side)
344 {
345     struct P_line *Line;
346     struct P_topo_b *topo;
347 
348     Line = plus->Line[line];
349     if (!Line) /* dead */
350 	return -1;
351 
352     if (Line->type != GV_BOUNDARY)
353 	return -1;
354 
355     topo = (struct P_topo_b *)Line->topo;
356     if (side == GV_LEFT) {
357 	G_debug(3,
358 		"dig_line_get_area(): line = %d, side = %d (left), area = %d",
359 		line, side, topo->left);
360 	return (topo->left);
361     }
362     if (side == GV_RIGHT) {
363 	G_debug(3,
364 		"dig_line_get_area(): line = %d, side = %d (right), area = %d",
365 		line, side, topo->right);
366 
367 	return (topo->right);
368     }
369 
370     return (-1);
371 }
372 
373 /*!
374  * \brief Set area number on line side
375  *
376  * \param[in] plus pointer Plus_head structure
377  * \param[in] line line id
378  * \param[in] side side id (GV_LEFT || GV_RIGHT)
379  * \param[in] area area id
380  *
381  * \return 1
382  */
383 int
dig_line_set_area(struct Plus_head * plus,plus_t line,int side,plus_t area)384 dig_line_set_area(struct Plus_head *plus, plus_t line, int side, plus_t area)
385 {
386     struct P_line *Line;
387     struct P_topo_b *topo;
388 
389     Line = plus->Line[line];
390     if (Line->type != GV_BOUNDARY)
391 	return (0);
392 
393     topo = (struct P_topo_b *)Line->topo;
394 
395     if (side == GV_LEFT) {
396 	topo->left = area;
397     }
398     else if (side == GV_RIGHT) {
399 	topo->right = area;
400     }
401 
402     return (1);
403 }
404 
405 /*!
406  * \brief Set line bounding box
407  *
408  * \param[in] plus pointer Plus_head structure
409  * \param[in] line line id
410  * \param[in] Box  bounding box
411  *
412  * \return 1
413  */
414 /*
415 int dig_line_set_box(struct Plus_head *plus, plus_t line, struct bound_box * Box)
416 {
417     struct P_line *Line;
418 
419     Line = plus->Line[line];
420 
421     Line->N = Box->N;
422     Line->S = Box->S;
423     Line->E = Box->E;
424     Line->W = Box->W;
425     Line->T = Box->T;
426     Line->B = Box->B;
427 
428     return (1);
429 }
430 */
431 
432 /*!
433  * \brief Get line bounding box saved in topo
434  *
435  * \param[in] plus pointer Plus_head structure
436  * \param[in] line line id
437  * \param[in,out] Box bounding box
438  *
439  * \return 1
440  */
441 /*
442 int dig_line_get_box(struct Plus_head *plus, plus_t line, struct bound_box * Box)
443 {
444     struct P_line *Line;
445 
446     Line = plus->Line[line];
447 
448     Box->N = Line->N;
449     Box->S = Line->S;
450     Box->E = Line->E;
451     Box->W = Line->W;
452     Box->T = Line->T;
453     Box->B = Line->B;
454 
455     return (1);
456 }
457 */
458