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