19
13
\author Original author CERL, probably Dave Gerdes or Mike Higgins.
20
14
\author Update to GRASS 5.7 Radim Blazek and David D. Gray.
21
15
\author V*_restore_line() by Martin Landa <landa.martin gmail.com> (2008)
27
19
#include <stdlib.h>
30
#include <grass/gis.h>
31
#include <grass/Vect.h>
22
#include <grass/vector.h>
32
23
#include <grass/glocale.h>
35
\brief Deletes area (i.e. centroid) categories from category index
37
\param Map pointer to vector map
40
static void delete_area_cats_from_cidx(struct Map_info *Map, int area)
44
static struct line_cats *Cats = NULL;
46
G_debug(3, "delete_area_cats_from_cidx() area = %d", area);
48
Area = Map->plus.Area[area];
50
G_fatal_error(_("%s: Area %d does not exist"),
51
"delete_area_cats_from_cidx()", area);
53
if (Area->centroid == 0) /* no centroid found */
57
Cats = Vect_new_cats_struct();
59
V2_read_line_nat(Map, NULL, Cats, Area->centroid);
61
for (i = 0; i < Cats->n_cats; i++) {
62
dig_cidx_del_cat(&(Map->plus), Cats->field[i], Cats->cat[i], area,
68
\brief Adds area (i.e. centroid) categories from category index
70
\param Map pointer to vector map
73
static void add_area_cats_to_cidx(struct Map_info *Map, int area)
77
static struct line_cats *Cats = NULL;
79
G_debug(3, "add_area_cats_to_cidx() area = %d", area);
81
Area = Map->plus.Area[area];
83
G_fatal_error(_("%s: Area %d does not exist"),
84
"add_area_cats_to_cidx():", area);
86
if (Area->centroid == 0) /* no centroid found */
90
Cats = Vect_new_cats_struct();
92
V2_read_line_nat(Map, NULL, Cats, Area->centroid);
94
for (i = 0; i < Cats->n_cats; i++) {
95
dig_cidx_add_cat_sorted(&(Map->plus), Cats->field[i], Cats->cat[i],
101
\brief Add line to topo file
103
Update areas. Areas are modified if:
105
1) first or/and last point are existing nodes ->
106
- drop areas/islands whose boundaries are neighbour to this boundary at these nodes
107
- try build areas and islands for this boundary and neighbour boundaries going through these nodes
109
Question: may be by adding line created new area/isle which doesn't go through nodes of this line
113
+----+----+ +----+----+ +----+----+
114
| A1 | A2 | + / -> | A1 | /| or + \ -> | A1 | A2 | \
116
+----+----+ +----+----+ +----+----+
120
- reattache all centroids/isles inside new area(s)
121
- attach new isle to area outside
123
2) line is closed ring (node at the end is new, so it is not case above)
124
- build new area/isle
125
- check if it is island or contains island(s)
126
- re-attach all centroids/isles inside new area(s)
127
- attach new isle to area outside
129
Note that 1) and 2) is done by the same code.
131
static void add_line_to_topo(struct Map_info *Map, int line,
132
struct line_pnts *points, struct line_cats *cats)
135
int type, node, next_line, area, side, sel_area, new_area[2];
137
struct Plus_head *plus;
138
P_LINE *Line, *NLine;
145
Line = plus->Line[line];
148
if (plus->built >= GV_BUILD_AREAS) {
149
if (type == GV_BOUNDARY) {
150
/* Delete neighbour areas/isles */
152
for (s = 1; s < 3; s++) { /* for each node */
154
node = Line->N1; /* Node 1 */
158
" delete neighbour areas/iseles: side = %d node = %d",
160
Node = plus->Node[node];
162
for (i = 0; i < Node->n_lines; i++) {
163
NLine = plus->Line[abs(Node->lines[i])];
164
if (NLine->type == GV_BOUNDARY)
168
G_debug(3, " number of boundaries at node = %d", n);
169
if (n > 2) { /* more than 2 boundaries at node ( >= 2 old + 1 new ) */
170
/* Line above (to the right), it is enough to check to the right, because if area/isle
171
* exists it is the same to the left */
174
dig_angle_next_line(plus, line, GV_RIGHT,
178
dig_angle_next_line(plus, -line, GV_RIGHT,
181
if (next_line != 0) { /* there is a boundary to the right */
182
NLine = plus->Line[abs(next_line)];
183
if (next_line > 0) /* the boundary is connected by 1. node */
184
area = NLine->right; /* we are interested just in this side (close to our line) */
185
else if (next_line < 0) /* the boundary is connected by 2. node */
188
G_debug(3, " next_line = %d area = %d", next_line,
190
if (area > 0) { /* is area */
191
Vect_get_area_box(Map, area, &box);
193
Vect_box_copy(&abox, &box);
197
Vect_box_extend(&abox, &box);
199
if (plus->update_cidx) {
200
delete_area_cats_from_cidx(Map, area);
202
dig_del_area(plus, area);
204
else if (area < 0) { /* is isle */
205
dig_del_isle(plus, -area);
210
/* Build new areas/isles. Thas true that we deleted also adjacent areas/isles, but if
211
* they form new one our boundary must participate, so we need to build areas/isles
212
* just for our boundary */
213
for (s = 1; s < 3; s++) {
218
G_debug(3, " build area/isle on side = %d", side);
220
G_debug(3, "Build area for line = %d, side = %d", line, side);
221
area = Vect_build_line_area(Map, line, side);
222
G_debug(3, "Build area for line = %d, side = %d", line, side);
223
if (area > 0) { /* area */
224
Vect_get_area_box(Map, area, &box);
226
Vect_box_copy(&abox, &box);
230
Vect_box_extend(&abox, &box);
233
/* isle -> must be attached -> add to abox */
234
Vect_get_isle_box(Map, -area, &box);
236
Vect_box_copy(&abox, &box);
240
Vect_box_extend(&abox, &box);
242
new_area[s - 1] = area;
244
/* Reattach all centroids/isles in deleted areas + new area.
245
* Because isles are selected by box it covers also possible new isle created above */
246
if (!first) { /* i.e. old area/isle was deleted or new one created */
247
/* Reattache isles */
248
if (plus->built >= GV_BUILD_ATTACH_ISLES)
249
Vect_attach_isles(Map, &abox);
251
/* Reattach centroids */
252
if (plus->built >= GV_BUILD_CENTROIDS)
253
Vect_attach_centroids(Map, &abox);
255
/* Add to category index */
256
if (plus->update_cidx) {
257
for (s = 1; s < 3; s++) {
258
if (new_area[s - 1] > 0) {
259
add_area_cats_to_cidx(Map, new_area[s - 1]);
266
/* Attach centroid */
267
if (plus->built >= GV_BUILD_CENTROIDS) {
268
if (type == GV_CENTROID) {
269
sel_area = Vect_find_area(Map, points->x[0], points->y[0]);
270
G_debug(3, " new centroid %d is in area %d", line, sel_area);
272
Area = plus->Area[sel_area];
273
Line = plus->Line[line];
274
if (Area->centroid == 0) { /* first centroid */
275
G_debug(3, " first centroid -> attach to area");
276
Area->centroid = line;
277
Line->left = sel_area;
278
if (plus->update_cidx) {
279
add_area_cats_to_cidx(Map, sel_area);
282
else { /* duplicate centroid */
284
" duplicate centroid -> do not attach to area");
285
Line->left = -sel_area;
291
/* Add cetegory index */
292
for (i = 0; i < cats->n_cats; i++) {
293
dig_cidx_add_cat_sorted(plus, cats->field[i], cats->cat[i], line,
300
long V1__rewrite_line_nat(struct Map_info *Map, long offset, int type,
301
struct line_pnts *points, struct line_cats *cats);
304
\brief Writes feature to 'coor' file
25
#include "local_proto.h"
27
static struct line_cats *Cats;
28
static struct line_pnts *Points;
30
static off_t V1__rewrite_line_nat(struct Map_info *, off_t, int,
31
const struct line_pnts *, const struct line_cats *);
32
static void V2__delete_area_cats_from_cidx_nat(struct Map_info *, int);
33
static void V2__add_area_cats_to_cidx_nat(struct Map_info *, int);
36
\brief Writes feature to 'coor' file at level 1 (internal use only)
306
\param Map pointer to vector map
307
\param type feature type
38
\param Map pointer to Map_info structure
39
\param type feature type (GV_POINT, GV_LINE, ...)
308
40
\param points feature geometry
309
41
\param cats feature categories
311
43
\return feature offset into file
312
44
\return -1 on error
314
long V1_write_line_nat(struct Map_info *Map,
315
int type, struct line_pnts *points, struct line_cats *cats)
46
off_t V1_write_line_nat(struct Map_info *Map, int type,
47
const struct line_pnts *points, const struct line_cats *cats)
319
if (dig_fseek(&(Map->dig_fp), 0L, SEEK_END) == -1) /* set to end of file */
51
if (dig_fseek(&(Map->dig_fp), 0L, SEEK_END) == -1) /* set to end of file */
322
54
offset = dig_ftell(&(Map->dig_fp));
55
G_debug(3, "V1_write_line_nat(): offset = %lu", offset);
330
\brief Writes feature to 'coor' file (topology level)
63
\brief Writes feature to 'coor' file at topological level (internal use only)
65
Note: Function returns feature id, but is defined as off_t for
66
compatibility with level 1 functions.
332
\param Map pointer to vector map
333
\param type feature type
68
\param Map pointer to Map_info structure
69
\param type feature type (GV_POINT, GV_LINE, ...)
334
70
\param points feature geometry
335
71
\param cats feature categories
337
\return new feature id
73
\return new feature id
74
\return 0 topology is not requested to be built (build level < GV_BUILD_BASE)
338
75
\return -1 on error
340
long V2_write_line_nat(struct Map_info *Map,
341
int type, struct line_pnts *points, struct line_cats *cats)
77
off_t V2_write_line_nat(struct Map_info *Map, int type,
78
const struct line_pnts *points, const struct line_cats *cats)
345
struct Plus_head *plus;
82
G_debug(3, "V2_write_line_nat(): type=%d", type);
350
G_debug(3, "V2_write_line_nat()");
84
/* write feature to 'coor' file */
351
85
offset = V1_write_line_nat(Map, type, points, cats);
355
/* Update topology */
358
if (plus->built >= GV_BUILD_BASE) {
359
line = dig_add_line(plus, type, points, offset);
360
G_debug(3, " line added to topo with id = %d", line);
361
dig_line_box(points, &box);
362
dig_line_set_box(plus, line, &box);
364
Vect_box_copy(&(plus->box), &box);
366
Vect_box_extend(&(plus->box), &box);
369
add_line_to_topo(Map,
372
G_debug(3, "updated lines : %d , updated nodes : %d", plus->n_uplines,
89
/* update topology (build level >= GV_BUILD_BASE) */
90
return V2__add_line_to_topo_nat(Map, offset, type, points, cats, -1, NULL);
379
\brief Rewrites feature at the given offset.
381
If the number of points or cats differs from the original one or
382
the type is changed: GV_POINTS -> GV_LINES or GV_LINES ->
383
GV_POINTS, the old one is deleted and the new is appended to the
386
Old feature is deleted (marked as dead), new feature written.
388
\param Map pointer to vector map
94
\brief Rewrites feature to 'coor' file at level 1 (internal use only)
96
If the number of points or cats differs from the original one or the
97
type is changed: GV_POINTS -> GV_LINES or GV_LINES -> GV_POINTS, the
98
old one is deleted and the new is appended to the end of the file.
100
Old feature is deleted (marked as dead), and a new feature written.
102
\param Map pointer to Map_info structure
103
\param line feature id to be rewritten
389
104
\param offset feature offset
390
\param type feature type
105
\param type feature type (GV_POINT, GV_LINE, ...)
391
106
\param points feature geometry
392
107
\param cats feature categories
394
109
\return feature offset (rewriten feature)
395
110
\return -1 on error
397
long V1_rewrite_line_nat(struct Map_info *Map,
400
struct line_pnts *points, struct line_cats *cats)
112
off_t V1_rewrite_line_nat(struct Map_info *Map, int line, int type, off_t offset,
113
const struct line_pnts *points, const struct line_cats *cats)
403
struct line_pnts *old_points;
404
struct line_cats *old_cats;
116
static struct line_pnts *old_points = NULL;
117
static struct line_cats *old_cats = NULL;
120
G_debug(3, "V1_rewrite_line_nat(): line = %d offset = %lu",
121
line, (unsigned long) offset);
407
123
/* TODO: enable points and cats == NULL */
409
125
/* First compare numbers of points and cats with tha old one */
410
old_points = Vect_new_line_struct();
411
old_cats = Vect_new_cats_struct();
127
old_points = Vect_new_line_struct();
128
old_cats = Vect_new_cats_struct();
413
131
old_type = V1_read_line_nat(Map, old_points, old_cats, offset);
414
132
if (old_type == -1)
465
185
* and cats was not changed or topology is not changed (nodes not moved,
466
186
* angles not changed etc.) */
468
V2_delete_line_nat(Map, line);
470
return (V2_write_line_nat(Map, type, points, cats));
474
\brief Rewrites feature at the given offset.
476
\param Map pointer to vector map
477
\param offset feature offset
478
\param type feature type
190
if (0 != V2_delete_line_nat(Map, line))
193
G_debug(3, "V2_write_line_nat(), line = %d", line);
195
/* rewrite feature in 'coor' file */
196
offset = V1_rewrite_line_nat(Map, line, type, old_offset, points, cats);
200
/* update topology */
201
return V2__add_line_to_topo_nat(Map, offset, type, points, cats, -1, NULL);
205
\brief Deletes feature at level 1 (internal use only)
207
\param Map pointer Map_info structure
208
\param offset feature offset
213
int V1_delete_line_nat(struct Map_info *Map, off_t offset)
216
struct gvfile *dig_fp;
218
G_debug(3, "V1_delete_line_nat(): offset = %lu", (unsigned long) offset);
220
dig_set_cur_port(&(Map->head.port));
221
dig_fp = &(Map->dig_fp);
223
if (dig_fseek(dig_fp, offset, 0) == -1)
227
if (0 >= dig__fread_port_C(&rhead, 1, dig_fp))
232
if (dig_fseek(dig_fp, offset, 0) == -1)
235
if (0 >= dig__fwrite_port_C(&rhead, 1, dig_fp))
238
if (0 != dig_fflush(dig_fp))
245
\brief Deletes feature at topological level (internal use only)
247
Note: Topology must be built at level >= GV_BUILD_BASE
249
\param pointer to Map_info structure
250
\param line feature id
255
int V2_delete_line_nat(struct Map_info *Map, int line)
259
struct Plus_head *plus;
261
G_debug(3, "V2_delete_line_nat(): line = %d", line);
266
if (line < 1 || line > plus->n_lines) {
267
G_warning(_("Attempt to access feature with invalid id (%d)"), line);
271
Line = Map->plus.Line[line];
273
G_warning(_("Attempt to access dead feature %d"), line);
279
Points = Vect_new_line_struct();
282
Cats = Vect_new_cats_struct();
284
type = V2_read_line_nat(Map, Points, Cats, line);
288
/* delete feature from coor file */
289
if (0 != V1_delete_line_nat(Map, Line->offset))
292
/* delete feature from topology */
293
if (0 != V2__delete_line_from_topo_nat(Map, line, type, Points, Cats))
300
\brief Restores feature at level 1 (internal use only)
302
\param Map pointer to Map_info structure
303
\param offset feature offset
308
int V1_restore_line_nat(struct Map_info *Map, off_t offset)
311
struct gvfile *dig_fp;
313
G_debug(3, "V1_restore_line_nat(), offset = %lu", (unsigned long) offset);
315
dig_set_cur_port(&(Map->head.port));
316
dig_fp = &(Map->dig_fp);
318
if (dig_fseek(dig_fp, offset, 0) == -1)
322
if (0 >= dig__fread_port_C(&rhead, 1, dig_fp))
329
if (dig_fseek(dig_fp, offset, 0) == -1)
332
if (0 >= dig__fwrite_port_C(&rhead, 1, dig_fp))
335
if (0 != dig_fflush(dig_fp))
342
\brief Restores feature at topological level (internal use only)
344
Note: This function requires build level >= GV_BUILD_BASE.
346
\param Map pointer to Map_info structure
347
\param line feature id
348
\param offset feature offset
353
int V2_restore_line_nat(struct Map_info *Map, int line, off_t offset)
356
struct Plus_head *plus;
361
G_debug(3, "V2_restore_line_nat(), line = %d", line);
363
if (line < 1 || line > plus->n_lines) {
364
G_warning(_("Attempt to access feature with invalid id (%d)"), line);
368
Line = Map->plus.Line[line];
370
G_warning(_("Attempt to access alive feature %d"), line);
374
/* restore feature in 'coor' file */
375
if (0 != V1_restore_line_nat(Map, offset))
379
/* read feature geometry */
381
Points = Vect_new_line_struct();
383
Cats = Vect_new_cats_struct();
384
type = V1_read_line_nat(Map, Points, Cats, offset);
388
/* update topology */
389
return V2__add_line_to_topo_nat(Map, offset, type, Points, Cats, line, NULL) > 0 ? 0 : -1;
392
/*** static or internal subroutines bellow ****/
395
\brief Rewrites feature at the given offset
397
\param Map pointer to Map_info structure
398
\param offset feature offset
399
\param type feature type (GV_POINT, GV_LINE, ...)
479
400
\param points feature geometry
480
401
\param cats feature categories
482
403
\return feature offset
483
404
\return -1 on error
485
long V1__rewrite_line_nat(struct Map_info *Map,
488
struct line_pnts *points, struct line_cats *cats)
406
off_t V1__rewrite_line_nat(struct Map_info *Map,
407
off_t offset, int type,
408
const struct line_pnts *points, const struct line_cats *cats)
413
struct gvfile *dig_fp;
495
415
dig_set_cur_port(&(Map->head.port));
496
416
dig_fp = &(Map->dig_fp);
574
\brief Deletes feature at the given offset.
576
\param Map pointer to vector map
577
\param offset feature offset
582
int V1_delete_line_nat(struct Map_info *Map, long offset)
587
G_debug(3, "V1_delete_line_nat(), offset = %ld", offset);
589
dig_set_cur_port(&(Map->head.port));
590
dig_fp = &(Map->dig_fp);
592
if (dig_fseek(dig_fp, offset, 0) == -1)
596
if (0 >= dig__fread_port_C(&rhead, 1, dig_fp))
601
if (dig_fseek(dig_fp, offset, 0) == -1)
604
if (0 >= dig__fwrite_port_C(&rhead, 1, dig_fp))
607
if (0 != dig_fflush(dig_fp))
614
\brief Deletes feature (topology level).
616
\param pointer to vector map
617
\param line feature id
494
\brief Deletes area (i.e. centroid) categories from category
495
index (internal use only)
497
Call G_fatal_error() when area do not exits.
499
\param Map pointer to Map_info structure
502
void V2__delete_area_cats_from_cidx_nat(struct Map_info *Map, int area)
506
static struct line_cats *Cats = NULL;
508
G_debug(3, "V2__delete_area_cats_from_cidx_nat(), area = %d", area);
510
Area = Map->plus.Area[area];
512
G_fatal_error(_("%s: Area %d does not exist"),
513
"delete_area_cats_from_cidx()", area);
515
if (Area->centroid == 0) /* no centroid found */
519
Cats = Vect_new_cats_struct();
521
Vect_read_line(Map, NULL, Cats, Area->centroid);
523
for (i = 0; i < Cats->n_cats; i++) {
524
dig_cidx_del_cat(&(Map->plus), Cats->field[i], Cats->cat[i], area,
530
\brief Adds area (i.e. centroid) categories from category index
533
Call G_fatal_error() when area do not exits.
535
\param Map pointer to Map_info structure
538
void V2__add_area_cats_to_cidx_nat(struct Map_info *Map, int area)
542
static struct line_cats *Cats = NULL;
544
G_debug(3, "V2__add_area_cats_to_cidx_nat(), area = %d", area);
546
Area = Map->plus.Area[area];
548
G_fatal_error(_("%s: Area %d does not exist"),
549
"add_area_cats_to_cidx():", area);
551
if (Area->centroid == 0) /* no centroid found */
555
Cats = Vect_new_cats_struct();
557
V2_read_line_nat(Map, NULL, Cats, Area->centroid);
559
for (i = 0; i < Cats->n_cats; i++) {
560
dig_cidx_add_cat_sorted(&(Map->plus), Cats->field[i], Cats->cat[i],
566
\brief Delete feature from topology (internal use only)
568
Note: This function requires build level >= GV_BUILD_BASE.
570
Also updates category index if requested.
572
Calls G_warning() on error.
574
\param Map pointer to Map_info struct
575
\param line feature id to be removed
576
\param Points feature geometry (pointer to line_pnts struct)
577
\param external_routine external subroutine to execute (used by PostGIS Topology)
619
579
\return 0 on success
622
int V2_delete_line_nat(struct Map_info *Map, int line)
580
\return -1 on failure
582
int V2__delete_line_from_topo_nat(struct Map_info *Map, int line, int type,
583
const struct line_pnts *points, const struct line_cats *cats)
624
int ret, i, side, type = 0, first = 0, next_line, area;
586
int adjacent[4], n_adjacent;
588
struct bound_box box, abox;
627
589
struct Plus_head *plus;
629
int adjacent[4], n_adjacent = 0;
630
static struct line_cats *Cats = NULL;
632
G_debug(3, "V2_delete_line_nat(), line = %d", line);
634
594
plus = &(Map->plus);
636
if (plus->built >= GV_BUILD_BASE) {
637
Line = Map->plus.Line[line];
640
G_fatal_error(_("Attempt to delete dead feature"));
645
Cats = Vect_new_cats_struct();
648
/* Update category index */
649
if (plus->update_cidx) {
650
type = V2_read_line_nat(Map, NULL, Cats, line);
652
for (i = 0; i < Cats->n_cats; i++) {
653
dig_cidx_del_cat(plus, Cats->field[i], Cats->cat[i], line, type);
657
/* delete the line from coor */
658
ret = V1_delete_line_nat(Map, Line->offset);
664
/* Update topology */
665
if (plus->built >= GV_BUILD_AREAS && type == GV_BOUNDARY) {
666
/* Store adjacent boundaries at nodes (will be used to rebuild area/isle) */
667
/* Adjacent are stored: > 0 - we want right side; < 0 - we want left side */
596
if (line < 1 || line > plus->n_lines) {
597
G_warning(_("Attempt to access feature with invalid id (%d)"), line);
601
Line = Map->plus.Line[line];
603
G_warning(_("Attempt to access dead feature %d"), line);
607
/* delete feature from category index */
608
if (plus->update_cidx && cats) {
609
for (i = 0; i < cats->n_cats; i++) {
610
dig_cidx_del_cat(plus, cats->field[i], cats->cat[i], line, type);
614
/* update areas when deleting boundary from topology */
615
if (plus->built >= GV_BUILD_AREAS && Line->type == GV_BOUNDARY) {
618
struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
620
/* store adjacent boundaries at nodes (will be used to rebuild area/isle) */
621
/* adjacent are stored: > 0 - we want right side; < 0 - we want left side */
670
next_line = dig_angle_next_line(plus, line, GV_RIGHT, GV_BOUNDARY);
624
next_line = dig_angle_next_line(plus, line, GV_RIGHT, GV_BOUNDARY, NULL);
671
625
if (next_line != 0 && abs(next_line) != line) {
672
626
/* N1, to the right -> we want the right side for > 0 and left for < 0 */
673
627
adjacent[n_adjacent] = next_line;
676
next_line = dig_angle_next_line(plus, line, GV_LEFT, GV_BOUNDARY);
630
next_line = dig_angle_next_line(plus, line, GV_LEFT, GV_BOUNDARY, NULL);
677
631
if (next_line != 0 && abs(next_line) != line) {
678
632
/* N1, to the left -> we want the left side for > 0 and right for < 0 */
679
633
adjacent[n_adjacent] = -next_line;
682
next_line = dig_angle_next_line(plus, -line, GV_RIGHT, GV_BOUNDARY);
636
next_line = dig_angle_next_line(plus, -line, GV_RIGHT, GV_BOUNDARY, NULL);
683
637
if (next_line != 0 && abs(next_line) != line) {
684
638
/* N2, to the right -> we want the right side for > 0 and left for < 0 */
685
639
adjacent[n_adjacent] = next_line;
688
next_line = dig_angle_next_line(plus, -line, GV_LEFT, GV_BOUNDARY);
642
next_line = dig_angle_next_line(plus, -line, GV_LEFT, GV_BOUNDARY, NULL);
689
643
if (next_line != 0 && abs(next_line) != line) {
690
644
/* N2, to the left -> we want the left side for > 0 and right for < 0 */
691
645
adjacent[n_adjacent] = -next_line;
695
/* Delete area(s) and islands this line forms */
649
/* delete area(s) and islands this line forms */
697
if (Line->left > 0) { /* delete area */
698
Vect_get_area_box(Map, Line->left, &box);
700
Vect_box_copy(&abox, &box);
704
Vect_box_extend(&abox, &box);
706
if (plus->update_cidx) {
707
delete_area_cats_from_cidx(Map, Line->left);
709
dig_del_area(plus, Line->left);
711
else if (Line->left < 0) { /* delete isle */
712
dig_del_isle(plus, -Line->left);
714
if (Line->right > 0) { /* delete area */
715
Vect_get_area_box(Map, Line->right, &box);
717
Vect_box_copy(&abox, &box);
721
Vect_box_extend(&abox, &box);
723
if (plus->update_cidx) {
724
delete_area_cats_from_cidx(Map, Line->right);
726
dig_del_area(plus, Line->right);
728
else if (Line->right < 0) { /* delete isle */
729
dig_del_isle(plus, -Line->right);
651
if (topo->left > 0) { /* delete area */
652
Vect_get_area_box(Map, topo->left, &box);
654
Vect_box_copy(&abox, &box);
658
Vect_box_extend(&abox, &box);
660
if (plus->update_cidx) {
661
V2__delete_area_cats_from_cidx_nat(Map, topo->left);
663
dig_del_area(plus, topo->left);
665
else if (topo->left < 0) { /* delete isle */
666
dig_del_isle(plus, -topo->left);
668
if (topo->right > 0) { /* delete area */
669
Vect_get_area_box(Map, topo->right, &box);
671
Vect_box_copy(&abox, &box);
675
Vect_box_extend(&abox, &box);
677
if (plus->update_cidx) {
678
V2__delete_area_cats_from_cidx_nat(Map, topo->right);
680
dig_del_area(plus, topo->right);
682
else if (topo->right < 0) { /* delete isle */
683
dig_del_isle(plus, -topo->right);
733
/* Delete reference from area */
734
if (plus->built >= GV_BUILD_CENTROIDS && type == GV_CENTROID) {
735
if (Line->left > 0) {
736
G_debug(3, "Remove centroid %d from area %d", line, Line->left);
687
/* delete reference from area */
688
if (plus->built >= GV_BUILD_CENTROIDS && Line->type == GV_CENTROID) {
691
struct P_topo_c *topo = (struct P_topo_c *)Line->topo;
693
if (topo->area > 0) {
694
G_debug(3, "Remove centroid %d from area %d", (int) line, topo->area);
737
695
if (plus->update_cidx) {
738
delete_area_cats_from_cidx(Map, Line->left);
696
V2__delete_area_cats_from_cidx_nat(Map, topo->area);
740
Area = Map->plus.Area[Line->left];
698
Area = Map->plus.Area[topo->area];
702
G_warning(_("Attempt to access dead area %d"), topo->area);
745
706
/* delete the line from topo */
746
dig_del_line(plus, line);
748
/* Rebuild areas/isles and attach centroids and isles */
707
if (0 != dig_del_line(plus, line, points->x[0], points->y[0], points->z[0]))
710
/* rebuild areas/isles and attach centroids and isles */
749
711
if (plus->built >= GV_BUILD_AREAS && type == GV_BOUNDARY) {
750
int *new_areas, nnew_areas;
713
int new_areas[4], nnew_areas = 0;
753
new_areas = (int *)G_malloc(2 * n_adjacent * sizeof(int));
754
715
/* Rebuild areas/isles */
755
716
for (i = 0; i < n_adjacent; i++) {
717
side = (adjacent[i] > 0 ? GV_RIGHT : GV_LEFT);
761
719
G_debug(3, "Build area for line = %d, side = %d", adjacent[i],
785
743
Vect_box_extend(&abox, &box);
746
/* reattach all centroids/isles in deleted areas + new area.
747
* because isles are selected by box it covers also possible new isle created above */
748
if (!first) { /* i.e. old area/isle was deleted or new one created */
750
if (plus->built >= GV_BUILD_ATTACH_ISLES)
751
Vect_attach_isles(Map, &abox);
753
/* reattach centroids */
754
if (plus->built >= GV_BUILD_CENTROIDS)
755
Vect_attach_centroids(Map, &abox);
758
if (plus->update_cidx) {
759
for (i = 0; i < nnew_areas; i++) {
760
V2__add_area_cats_to_cidx_nat(Map, new_areas[i]);
765
if (plus->uplist.do_uplist) {
766
G_debug(3, "updated lines : %d , updated nodes : %d", plus->uplist.n_uplines,
767
plus->uplist.n_upnodes);
774
\brief Add feature (line) to topology (internal use only)
776
Also updates category index if requested.
778
Update areas. Areas are modified if:
780
1) first or/and last point are existing nodes ->
781
- drop areas/islands whose boundaries are neighbour to this boundary at these nodes
782
- try build areas and islands for this boundary and neighbour boundaries going through these nodes
784
Question: may be by adding line created new area/isle which doesn't go through nodes of this line
788
+----+----+ +----+----+ +----+----+
789
| A1 | A2 | + / -> | A1 | /| or + \ -> | A1 | A2 | \
791
+----+----+ +----+----+ +----+----+
795
- re-attach all centroids/isles inside new area(s)
796
- attach new isle to area outside
798
2) line is closed ring (node at the end is new, so it is not case above)
799
- build new area/isle
800
- check if it is island or contains island(s)
801
- re-attach all centroids/isles inside new area(s)
802
- attach new isle to area outside
804
Note that 1) and 2) is done by the same code.
806
\param Map pointer to Map_info structure
807
\param line feature id to be added
808
\param points pointer to line_pnts structure (feature's geometry)
809
\param cats pointer to line_cats structure (feature's categories)
810
\param external_routine pointer to external routine (used by PostGIS Topology)
812
\return feature id to be added
813
\return 0 nothing to do (build level must be >= GV_BUILD_BASE)
816
int V2__add_line_to_topo_nat(struct Map_info *Map, off_t offset, int type,
817
const struct line_pnts *points, const struct line_cats *cats,
819
int (*external_routine) (const struct Map_info *, int))
821
int first, s, n, i, line;
822
int node, next_line, area, side, sel_area, new_area[2];
824
struct Plus_head *plus;
825
struct P_line *Line, *NLine;
829
struct bound_box box, abox;
833
G_debug(3, "V2__add_line_to_topo_nat(): offset = %ld (build level = %d)", offset, plus->built);
835
if (plus->built < GV_BUILD_BASE) /* nothing to build */
838
/* add line to topology */
839
dig_line_box(points, &box);
840
if (restore_line > 0)
841
line = dig_restore_line(plus, restore_line, type, points, &box, offset);
843
line = dig_add_line(plus, type, points, &box, offset);
844
G_debug(3, " line added to topo with id = %d", line);
846
Line = plus->Line[line];
848
/* extend map bounding box */
850
Vect_box_copy(&(plus->box), &box);
852
Vect_box_extend(&(plus->box), &box);
854
/* build areas on left/right side */
855
if (plus->built >= GV_BUILD_AREAS &&
856
type == GV_BOUNDARY) {
857
struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
859
/* delete neighbour areas/isles */
861
for (s = 0; s < 2; s++) { /* for each node */
862
node = (s == 0 ? topo->N1 : topo->N2);
864
" delete neighbour areas/isles: %s node = %d",
865
(s == 0 ? "first" : "second"), node);
866
Node = plus->Node[node];
868
for (i = 0; i < Node->n_lines; i++) {
869
NLine = plus->Line[abs(Node->lines[i])];
870
if (NLine->type == GV_BOUNDARY)
874
G_debug(3, " number of boundaries at node = %d", n);
876
/* more than 2 boundaries at node ( >= 2 old + 1 new ) */
877
/* Line above (to the right), it is enough to check to
878
the right, because if area/isle exists it is the
882
dig_angle_next_line(plus, line, GV_RIGHT,
886
dig_angle_next_line(plus, -line, GV_RIGHT,
889
if (next_line != 0) { /* there is a boundary to the right */
890
NLine = plus->Line[abs(next_line)];
891
topo = (struct P_topo_b *)NLine->topo;
892
if (next_line > 0) /* the boundary is connected by 1. node */
893
/* we are interested just in this side (close to our line) */
895
else if (next_line < 0) /* the boundary is connected by 2. node */
898
G_debug(3, " next_line = %d area = %d", next_line,
900
if (area > 0) { /* is area */
901
Vect_get_area_box(Map, area, &box);
903
Vect_box_copy(&abox, &box);
907
Vect_box_extend(&abox, &box);
909
if (plus->update_cidx) {
910
V2__delete_area_cats_from_cidx_nat(Map, area);
912
dig_del_area(plus, area);
913
if (external_routine) /* call external subroutine if defined */
914
external_routine(Map, area);
916
else if (area < 0) { /* is isle */
917
dig_del_isle(plus, -area);
918
if (external_routine) /* call external subroutine if defined */
919
external_routine(Map, area);
925
/* Build new areas/isles.
926
* It's true that we deleted also adjacent areas/isles, but
927
* if they form new one our boundary must participate, so
928
* we need to build areas/isles just for our boundary */
929
for (s = 0; s < 2; s++) {
930
side = (s == 0 ? GV_LEFT : GV_RIGHT);
931
area = Vect_build_line_area(Map, line, side);
933
if (area > 0) { /* area */
934
Vect_get_area_box(Map, area, &box);
936
Vect_box_copy(&abox, &box);
940
Vect_box_extend(&abox, &box);
943
/* isle -> must be attached -> add to abox */
944
Vect_get_isle_box(Map, -area, &box);
946
Vect_box_copy(&abox, &box);
950
Vect_box_extend(&abox, &box);
788
954
/* Reattach all centroids/isles in deleted areas + new area.
789
* Because isles are selected by box it covers also possible new isle created above */
790
if (!first) { /* i.e. old area/isle was deleted or new one created */
791
/* Reattache isles */
955
* Because isles are selected by box it covers also possible
956
* new isle created above */
957
if (!first) { /* i.e. old area/isle was deleted or new one created */
792
959
if (plus->built >= GV_BUILD_ATTACH_ISLES)
793
960
Vect_attach_isles(Map, &abox);
795
962
/* Reattach centroids */
796
963
if (plus->built >= GV_BUILD_CENTROIDS)
797
964
Vect_attach_centroids(Map, &abox);
966
/* Add to category index */
800
967
if (plus->update_cidx) {
801
for (i = 0; i < nnew_areas; i++) {
802
add_area_cats_to_cidx(Map, new_areas[i]);
807
G_debug(3, "updated lines : %d , updated nodes : %d", plus->n_uplines,
813
\brief Restores feature at the given offset.
815
\param Map pointer to vector map
816
\param offset feature offset
821
int V1_restore_line_nat(struct Map_info *Map, long offset)
826
G_debug(3, "V1_restore_line_nat(), offset = %ld", offset);
828
dig_set_cur_port(&(Map->head.port));
829
dig_fp = &(Map->dig_fp);
831
if (dig_fseek(dig_fp, offset, 0) == -1)
835
if (0 >= dig__fread_port_C(&rhead, 1, dig_fp))
842
if (dig_fseek(dig_fp, offset, 0) == -1)
845
if (0 >= dig__fwrite_port_C(&rhead, 1, dig_fp))
848
if (0 != dig_fflush(dig_fp))
855
\brief Restores feature (topology level)
857
\param Map pointer to vector map
858
\param line feature id
859
\param offset feature offset
864
int V2_restore_line_nat(struct Map_info *Map, int line, long offset)
868
struct Plus_head *plus;
871
static struct line_pnts *points = NULL;
872
static struct line_cats *cats = NULL;
877
G_debug(3, "V2_restore_line_nat(), line = %d", line);
881
if (plus->built >= GV_BUILD_BASE) {
882
Line = Map->plus.Line[line];
885
G_fatal_error(_("Attempt to restore alive feature"));
889
points = Vect_new_line_struct();
893
cats = Vect_new_cats_struct();
896
/* restore the line in coor */
897
ret = V1_restore_line_nat(Map, offset);
903
/* read feature geometry */
904
type = V1_read_line_nat(Map, points, cats, offset);
909
/* update category index */
910
if (plus->update_cidx) {
911
for (i = 0; i < cats->n_cats; i++) {
912
dig_cidx_add_cat(plus, cats->field[i], cats->cat[i], line, type);
916
/* restore the line from topo */
917
if (plus->built >= GV_BUILD_BASE) {
918
dig_restore_line(plus, line, type, points, offset);
919
G_debug(3, " line restored in topo with id = %d", line);
920
dig_line_box(points, &box);
921
dig_line_set_box(plus, line, &box);
922
Vect_box_extend(&(plus->box), &box);
925
add_line_to_topo(Map,
928
G_debug(3, "updated lines : %d , updated nodes : %d", plus->n_uplines,
968
for (s = 0; s < 2; s++) {
969
if (new_area[s] > 0) {
970
V2__add_area_cats_to_cidx_nat(Map, new_area[s]);
976
/* attach centroid */
977
if (plus->built >= GV_BUILD_CENTROIDS) {
978
struct P_topo_c *topo;
980
if (type == GV_CENTROID) {
981
sel_area = Vect_find_area(Map, points->x[0], points->y[0]);
982
G_debug(3, " new centroid %d is in area %d", line, sel_area);
984
Area = plus->Area[sel_area];
985
Line = plus->Line[line];
986
topo = (struct P_topo_c *)Line->topo;
987
if (Area->centroid == 0) { /* first centroid */
988
G_debug(3, " first centroid -> attach to area");
989
Area->centroid = line;
990
topo->area = sel_area;
991
if (plus->update_cidx) {
992
V2__add_area_cats_to_cidx_nat(Map, sel_area);
995
else { /* duplicate centroid */
997
" duplicate centroid -> do not attach to area");
998
topo->area = -sel_area;
1004
/* add category index */
1005
if (plus->update_cidx && cats) {
1006
for (i = 0; i < cats->n_cats; i++) {
1007
dig_cidx_add_cat_sorted(plus, cats->field[i], cats->cat[i], line,
1012
if (plus->uplist.do_uplist) {
1013
G_debug(3, "updated lines : %d , updated nodes : %d", plus->uplist.n_uplines,
1014
plus->uplist.n_upnodes);