~ubuntu-branches/ubuntu/wily/grass/wily

« back to all changes in this revision

Viewing changes to lib/vector/Vlib/write_nat.c

Tags: 7.0.0~rc1+ds1-1~exp1
* New upstream release candidate.
* Repack upstream tarball, remove precompiled Python objects.
* Add upstream metadata.
* Update gbp.conf and Vcs-Git URL to use the experimental branch.
* Update watch file for GRASS 7.0.
* Drop build dependencies for Tcl/Tk, add build dependencies:
  python-numpy, libnetcdf-dev, netcdf-bin, libblas-dev, liblapack-dev
* Update Vcs-Browser URL to use cgit instead of gitweb.
* Update paths to use grass70.
* Add configure options: --with-netcdf, --with-blas, --with-lapack,
  remove --with-tcltk-includes.
* Update patches for GRASS 7.
* Update copyright file, changes:
  - Update copyright years
  - Group files by license
  - Remove unused license sections
* Add patches for various typos.
* Fix desktop file with patch instead of d/rules.
* Use minimal dh rules.
* Bump Standards-Version to 3.9.6, no changes.
* Use dpkg-maintscript-helper to replace directories with symlinks.
  (closes: #776349)
* Update my email to use @debian.org address.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*!
2
 
   \file write_nat.c
 
2
   \file lib/vector/Vlib/write_nat.c
3
3
 
4
 
   \brief Vector library - write vector feature (native format)
 
4
   \brief Vector library - write/modify/delete vector feature (native format)
5
5
 
6
6
   Higher level functions for reading/writing/manipulating vectors.
7
7
 
8
 
   Operations:
9
 
    - Add feature
10
 
    - Rewrite feature
11
 
    - Delete feature
12
 
    - Restore feature
13
 
 
14
 
   (C) 2001-2008 by the GRASS Development Team
 
8
   (C) 2001-2013 by the GRASS Development Team
15
9
 
16
10
   This program is free software under the GNU General Public License
17
11
   (>=v2). Read the file COPYING that comes with GRASS for details.
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)
22
 
 
23
 
   \date 2001
24
16
 */
25
17
 
26
18
#include <stdio.h>
27
19
#include <stdlib.h>
28
20
#include <math.h>
29
21
 
30
 
#include <grass/gis.h>
31
 
#include <grass/Vect.h>
 
22
#include <grass/vector.h>
32
23
#include <grass/glocale.h>
33
24
 
34
 
/*!
35
 
  \brief Deletes area (i.e. centroid) categories from category index
36
 
 
37
 
  \param Map pointer to vector map
38
 
  \param area area id
39
 
*/
40
 
static void delete_area_cats_from_cidx(struct Map_info *Map, int area)
41
 
{
42
 
    int i;
43
 
    P_AREA *Area;
44
 
    static struct line_cats *Cats = NULL;
45
 
 
46
 
    G_debug(3, "delete_area_cats_from_cidx() area = %d", area);
47
 
 
48
 
    Area = Map->plus.Area[area];
49
 
    if (!Area)
50
 
        G_fatal_error(_("%s: Area %d does not exist"),
51
 
                      "delete_area_cats_from_cidx()", area);
52
 
    
53
 
    if (Area->centroid == 0) /* no centroid found */
54
 
        return;
55
 
 
56
 
    if (!Cats)
57
 
        Cats = Vect_new_cats_struct();
58
 
 
59
 
    V2_read_line_nat(Map, NULL, Cats, Area->centroid);
60
 
 
61
 
    for (i = 0; i < Cats->n_cats; i++) {
62
 
        dig_cidx_del_cat(&(Map->plus), Cats->field[i], Cats->cat[i], area,
63
 
                         GV_AREA);
64
 
    }
65
 
}
66
 
 
67
 
/*!
68
 
  \brief Adds area (i.e. centroid) categories from category index
69
 
 
70
 
  \param Map pointer to vector map
71
 
  \param area area id
72
 
*/
73
 
static void add_area_cats_to_cidx(struct Map_info *Map, int area)
74
 
{
75
 
    int i;
76
 
    P_AREA *Area;
77
 
    static struct line_cats *Cats = NULL;
78
 
 
79
 
    G_debug(3, "add_area_cats_to_cidx() area = %d", area);
80
 
 
81
 
    Area = Map->plus.Area[area];
82
 
    if (!Area)
83
 
        G_fatal_error(_("%s: Area %d does not exist"),
84
 
                      "add_area_cats_to_cidx():", area);
85
 
 
86
 
    if (Area->centroid == 0) /* no centroid found */
87
 
        return;
88
 
 
89
 
    if (!Cats)
90
 
        Cats = Vect_new_cats_struct();
91
 
 
92
 
    V2_read_line_nat(Map, NULL, Cats, Area->centroid);
93
 
 
94
 
    for (i = 0; i < Cats->n_cats; i++) {
95
 
        dig_cidx_add_cat_sorted(&(Map->plus), Cats->field[i], Cats->cat[i],
96
 
                                area, GV_AREA);
97
 
    }
98
 
}
99
 
 
100
 
/*!
101
 
  \brief Add line to topo file
102
 
 
103
 
  Update areas. Areas are modified if: 
104
 
   
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
108
 
 
109
 
   Question: may be by adding line created new area/isle which doesn't go through nodes of this line
110
 
 
111
 
   <pre>
112
 
             old         new line 
113
 
         +----+----+                    +----+----+                 +----+----+ 
114
 
         | A1 | A2 |  +      /      ->  | A1 |   /|   or +   \   -> | A1 | A2 | \
115
 
         |    |    |                    |    |    |                 |    |    |
116
 
         +----+----+                    +----+----+                 +----+----+
117
 
           I1   I1                        I1   I1                      
118
 
   </pre>        
119
 
 
120
 
   - reattache all centroids/isles inside new area(s)
121
 
   - attach new isle to area outside
122
 
 
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
128
 
    
129
 
    Note that 1) and 2) is done by the same code.
130
 
*/
131
 
static void add_line_to_topo(struct Map_info *Map, int line,
132
 
                             struct line_pnts *points, struct line_cats *cats)
133
 
{
134
 
    int first, s, n, i;
135
 
    int type, node, next_line, area, side, sel_area, new_area[2];
136
 
 
137
 
    struct Plus_head *plus;
138
 
    P_LINE *Line, *NLine;
139
 
    P_NODE *Node;
140
 
    P_AREA *Area;
141
 
    
142
 
    BOUND_BOX box, abox;
143
 
    
144
 
    plus = &(Map->plus);
145
 
    Line = plus->Line[line];
146
 
    type = Line->type;
147
 
 
148
 
    if (plus->built >= GV_BUILD_AREAS) {
149
 
        if (type == GV_BOUNDARY) {
150
 
            /* Delete neighbour areas/isles */
151
 
            first = 1;
152
 
            for (s = 1; s < 3; s++) {   /* for each node */
153
 
                if (s == 1)
154
 
                    node = Line->N1;    /* Node 1 */
155
 
                else
156
 
                    node = Line->N2;
157
 
                G_debug(3,
158
 
                        "  delete neighbour areas/iseles: side = %d node = %d",
159
 
                        s, node);
160
 
                Node = plus->Node[node];
161
 
                n = 0;
162
 
                for (i = 0; i < Node->n_lines; i++) {
163
 
                    NLine = plus->Line[abs(Node->lines[i])];
164
 
                    if (NLine->type == GV_BOUNDARY)
165
 
                        n++;
166
 
                }
167
 
 
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 */
172
 
                    if (s == 1)
173
 
                        next_line =
174
 
                            dig_angle_next_line(plus, line, GV_RIGHT,
175
 
                                                GV_BOUNDARY);
176
 
                    else
177
 
                        next_line =
178
 
                            dig_angle_next_line(plus, -line, GV_RIGHT,
179
 
                                                GV_BOUNDARY);
180
 
 
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 */
186
 
                            area = NLine->left;
187
 
 
188
 
                        G_debug(3, "  next_line = %d area = %d", next_line,
189
 
                                area);
190
 
                        if (area > 0) { /* is area */
191
 
                            Vect_get_area_box(Map, area, &box);
192
 
                            if (first) {
193
 
                                Vect_box_copy(&abox, &box);
194
 
                                first = 0;
195
 
                            }
196
 
                            else
197
 
                                Vect_box_extend(&abox, &box);
198
 
 
199
 
                            if (plus->update_cidx) {
200
 
                                delete_area_cats_from_cidx(Map, area);
201
 
                            }
202
 
                            dig_del_area(plus, area);
203
 
                        }
204
 
                        else if (area < 0) {    /* is isle */
205
 
                            dig_del_isle(plus, -area);
206
 
                        }
207
 
                    }
208
 
                }
209
 
            }
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++) {
214
 
                if (s == 1)
215
 
                    side = GV_LEFT;
216
 
                else
217
 
                    side = GV_RIGHT;
218
 
                G_debug(3, "  build area/isle on side = %d", side);
219
 
 
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);
225
 
                    if (first) {
226
 
                        Vect_box_copy(&abox, &box);
227
 
                        first = 0;
228
 
                    }
229
 
                    else
230
 
                        Vect_box_extend(&abox, &box);
231
 
                }
232
 
                else if (area < 0) {
233
 
                    /* isle -> must be attached -> add to abox */
234
 
                    Vect_get_isle_box(Map, -area, &box);
235
 
                    if (first) {
236
 
                        Vect_box_copy(&abox, &box);
237
 
                        first = 0;
238
 
                    }
239
 
                    else
240
 
                        Vect_box_extend(&abox, &box);
241
 
                }
242
 
                new_area[s - 1] = area;
243
 
            }
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);
250
 
 
251
 
                /* Reattach centroids */
252
 
                if (plus->built >= GV_BUILD_CENTROIDS)
253
 
                    Vect_attach_centroids(Map, &abox);
254
 
            }
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]);
260
 
                    }
261
 
                }
262
 
            }
263
 
        }
264
 
    }
265
 
 
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);
271
 
            if (sel_area > 0) {
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);
280
 
                    }
281
 
                }
282
 
                else {          /* duplicate centroid */
283
 
                    G_debug(3,
284
 
                            "  duplicate centroid -> do not attach to area");
285
 
                    Line->left = -sel_area;
286
 
                }
287
 
            }
288
 
        }
289
 
    }
290
 
 
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,
294
 
                                type);
295
 
    }
296
 
 
297
 
    return;
298
 
}
299
 
 
300
 
long V1__rewrite_line_nat(struct Map_info *Map, long offset, int type,
301
 
                          struct line_pnts *points, struct line_cats *cats);
302
 
 
303
 
/*!
304
 
  \brief Writes feature to 'coor' file
 
25
#include "local_proto.h"
 
26
 
 
27
static struct line_cats *Cats;
 
28
static struct line_pnts *Points;
 
29
 
 
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);
 
34
 
 
35
/*!
 
36
  \brief Writes feature to 'coor' file at level 1 (internal use only)
305
37
  
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
310
42
  
311
43
  \return feature offset into file
312
44
  \return -1 on error
313
45
*/
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)
316
48
{
317
 
    long offset;
 
49
    off_t offset;
318
50
 
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 */
320
52
        return -1;
321
53
 
322
54
    offset = dig_ftell(&(Map->dig_fp));
 
55
    G_debug(3, "V1_write_line_nat(): offset = %lu", offset);
323
56
    if (offset == -1)
324
57
        return -1;
325
58
 
327
60
}
328
61
 
329
62
/*!
330
 
  \brief Writes feature to 'coor' file (topology level)
 
63
  \brief Writes feature to 'coor' file at topological level (internal use only)
 
64
 
 
65
  Note: Function returns feature id, but is defined as off_t for
 
66
  compatibility with level 1 functions.
331
67
  
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
336
72
  
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
339
76
*/
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)
342
79
{
343
 
    int line;
344
 
    long offset;
345
 
    struct Plus_head *plus;
346
 
    BOUND_BOX box;
 
80
    off_t offset;
347
81
 
348
 
    line = 0;
 
82
    G_debug(3, "V2_write_line_nat(): type=%d", type);
349
83
    
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);
352
86
    if (offset < 0)
353
87
        return -1;
354
88
 
355
 
    /* Update topology */
356
 
    plus = &(Map->plus);
357
 
    /* Add line */
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);
363
 
        if (line == 1)
364
 
            Vect_box_copy(&(plus->box), &box);
365
 
        else
366
 
            Vect_box_extend(&(plus->box), &box);
367
 
    }
368
 
 
369
 
    add_line_to_topo(Map,
370
 
                     line, points, cats);
371
 
 
372
 
    G_debug(3, "updated lines : %d , updated nodes : %d", plus->n_uplines,
373
 
            plus->n_upnodes);
374
 
    
375
 
    return line;
 
89
    /* update topology (build level >= GV_BUILD_BASE) */
 
90
    return V2__add_line_to_topo_nat(Map, offset, type, points, cats, -1, NULL);
376
91
}
377
92
 
378
93
/*!
379
 
  \brief Rewrites feature at the given offset.
380
 
  
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
384
 
  end of the file.
385
 
  
386
 
  Old feature is deleted (marked as dead), new feature written.
387
 
  
388
 
  \param Map pointer to vector map
 
94
  \brief Rewrites feature to 'coor' file at level 1 (internal use only)
 
95
  
 
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.
 
99
  
 
100
  Old feature is deleted (marked as dead), and a new feature written.
 
101
  
 
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
393
108
  
394
109
  \return feature offset (rewriten feature)
395
110
  \return -1 on error
396
111
*/
397
 
long V1_rewrite_line_nat(struct Map_info *Map,
398
 
                         long offset,
399
 
                         int type,
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)
401
114
{
402
115
    int old_type;
403
 
    struct line_pnts *old_points;
404
 
    struct line_cats *old_cats;
405
 
    long new_offset;
 
116
    static struct line_pnts *old_points = NULL;
 
117
    static struct line_cats *old_cats = NULL;
 
118
    off_t new_offset;
406
119
    
 
120
    G_debug(3, "V1_rewrite_line_nat(): line = %d offset = %lu",
 
121
            line, (unsigned long) offset);
 
122
 
407
123
    /* TODO: enable points and cats == NULL  */
408
124
 
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();
 
126
    if (!old_points) {
 
127
        old_points = Vect_new_line_struct();
 
128
        old_cats = Vect_new_cats_struct();
 
129
    }
412
130
 
413
131
    old_type = V1_read_line_nat(Map, old_points, old_cats, offset);
414
132
    if (old_type == -1)
441
159
}
442
160
 
443
161
/*!
444
 
  \brief Rewrites feature (topology level)
445
 
   
446
 
  Old feature is deleted (marked as dead), new feature written.
447
 
  
448
 
  \param Map pointer to vector map
449
 
  \param line feature id
450
 
  \param type feature type
 
162
  \brief Rewrites feature to 'coor' file at topological level (internal use only)
 
163
 
 
164
  Note: Topology must be built at level >= GV_BUILD_BASE
 
165
  
 
166
  Note: Function returns feature id, but is defined as off_t for
 
167
  compatibility with level 1 functions.
 
168
  
 
169
  \param Map pointer to Map_info structure
 
170
  \param type feature type (GV_POINT, GV_LINE, ...)
 
171
  \param line feature id to be rewritten
 
172
  \param old_offset feature offset
451
173
  \param points feature geometry
452
 
  \param cats feature category
 
174
  \param cats feature categories
453
175
  
454
176
  \return new feature id
455
177
  \return -1 on error
456
178
*/
457
 
int V2_rewrite_line_nat(struct Map_info *Map,
458
 
                        int line,
459
 
                        int type,
460
 
                        struct line_pnts *points, struct line_cats *cats)
 
179
off_t V2_rewrite_line_nat(struct Map_info *Map, int line, int type, off_t old_offset,
 
180
                          const struct line_pnts *points, const struct line_cats *cats)
461
181
{
462
182
    /* TODO: this is just quick shortcut because we have already V2_delete_nat()
463
183
     *        and V2_write_nat() this function first deletes old line
465
185
     *        and cats was not changed or topology is not changed (nodes not moved,
466
186
     *        angles not changed etc.) */
467
187
 
468
 
    V2_delete_line_nat(Map, line);
469
 
 
470
 
    return (V2_write_line_nat(Map, type, points, cats));
471
 
}
472
 
 
473
 
/*!
474
 
  \brief Rewrites feature at the given offset.
475
 
  
476
 
  \param Map pointer to vector map
477
 
  \param offset feature offset
478
 
  \param type feature type
 
188
    off_t offset;
 
189
 
 
190
    if (0 != V2_delete_line_nat(Map, line))
 
191
        return -1;
 
192
    
 
193
    G_debug(3, "V2_write_line_nat(), line = %d", line);
 
194
 
 
195
    /* rewrite feature in 'coor' file */
 
196
    offset = V1_rewrite_line_nat(Map, line, type, old_offset, points, cats);
 
197
    if (offset < 0)
 
198
        return -1;
 
199
 
 
200
    /* update topology */
 
201
    return V2__add_line_to_topo_nat(Map, offset, type, points, cats, -1, NULL);
 
202
}
 
203
 
 
204
/*!
 
205
  \brief Deletes feature at level 1 (internal use only)
 
206
  
 
207
  \param Map pointer Map_info structure
 
208
  \param offset feature offset
 
209
  
 
210
  \return  0 on success
 
211
  \return -1 on error
 
212
*/
 
213
int V1_delete_line_nat(struct Map_info *Map, off_t offset)
 
214
{
 
215
    char rhead;
 
216
    struct gvfile *dig_fp;
 
217
 
 
218
    G_debug(3, "V1_delete_line_nat(): offset = %lu", (unsigned long) offset);
 
219
 
 
220
    dig_set_cur_port(&(Map->head.port));
 
221
    dig_fp = &(Map->dig_fp);
 
222
 
 
223
    if (dig_fseek(dig_fp, offset, 0) == -1)
 
224
        return -1;
 
225
 
 
226
    /* read old */
 
227
    if (0 >= dig__fread_port_C(&rhead, 1, dig_fp))
 
228
        return -1;
 
229
 
 
230
    rhead &= 0xFE;
 
231
 
 
232
    if (dig_fseek(dig_fp, offset, 0) == -1)
 
233
        return -1;
 
234
 
 
235
    if (0 >= dig__fwrite_port_C(&rhead, 1, dig_fp))
 
236
        return -1;
 
237
 
 
238
    if (0 != dig_fflush(dig_fp))
 
239
        return -1;
 
240
 
 
241
    return 0;
 
242
}
 
243
 
 
244
/*!
 
245
  \brief Deletes feature at topological level (internal use only)
 
246
 
 
247
  Note: Topology must be built at level >= GV_BUILD_BASE  
 
248
  
 
249
  \param pointer to Map_info structure
 
250
  \param line feature id
 
251
  
 
252
  \return 0 on success
 
253
  \return -1 on error
 
254
*/
 
255
int V2_delete_line_nat(struct Map_info *Map, int line)
 
256
{
 
257
    int type;
 
258
    struct P_line *Line;
 
259
    struct Plus_head *plus;
 
260
 
 
261
    G_debug(3, "V2_delete_line_nat(): line = %d", line);
 
262
 
 
263
    Line = NULL;
 
264
    plus = &(Map->plus);
 
265
 
 
266
    if (line < 1 || line > plus->n_lines) {
 
267
        G_warning(_("Attempt to access feature with invalid id (%d)"), line);
 
268
        return -1;
 
269
    }
 
270
    
 
271
    Line = Map->plus.Line[line];
 
272
    if (Line == NULL) {
 
273
        G_warning(_("Attempt to access dead feature %d"), line);
 
274
        return -1;
 
275
    }
 
276
 
 
277
    /* read the line */    
 
278
    if (!Points) {
 
279
        Points = Vect_new_line_struct();
 
280
    }
 
281
    if (!Cats) {
 
282
        Cats = Vect_new_cats_struct();
 
283
    }
 
284
    type = V2_read_line_nat(Map, Points, Cats, line);
 
285
    if (type < 0)
 
286
        return -1;
 
287
 
 
288
    /* delete feature from coor file */
 
289
    if (0 != V1_delete_line_nat(Map, Line->offset))
 
290
        return -1;
 
291
 
 
292
    /* delete feature from topology */
 
293
    if (0 != V2__delete_line_from_topo_nat(Map, line, type, Points, Cats))
 
294
        return -1;
 
295
    
 
296
    return 0;
 
297
}
 
298
 
 
299
/*!
 
300
  \brief Restores feature at level 1 (internal use only)
 
301
  
 
302
  \param Map pointer to Map_info structure
 
303
  \param offset feature offset
 
304
  
 
305
  \return  0 on success
 
306
  \return -1 on error
 
307
*/
 
308
int V1_restore_line_nat(struct Map_info *Map, off_t offset)
 
309
{
 
310
    char rhead;
 
311
    struct gvfile *dig_fp;
 
312
    
 
313
    G_debug(3, "V1_restore_line_nat(), offset = %lu", (unsigned long) offset);
 
314
    
 
315
    dig_set_cur_port(&(Map->head.port));
 
316
    dig_fp = &(Map->dig_fp);
 
317
    
 
318
    if (dig_fseek(dig_fp, offset, 0) == -1)
 
319
        return -1;
 
320
    
 
321
    /* read old */
 
322
    if (0 >= dig__fread_port_C(&rhead, 1, dig_fp))
 
323
        return -1;
 
324
 
 
325
    /* mark as alive */
 
326
    rhead |= 1;
 
327
    
 
328
    /* write new */
 
329
    if (dig_fseek(dig_fp, offset, 0) == -1)
 
330
        return -1;
 
331
 
 
332
    if (0 >= dig__fwrite_port_C(&rhead, 1, dig_fp))
 
333
        return -1;
 
334
    
 
335
    if (0 != dig_fflush(dig_fp))
 
336
        return -1;
 
337
    
 
338
    return 0;
 
339
}
 
340
 
 
341
/*!
 
342
  \brief Restores feature at topological level (internal use only)
 
343
 
 
344
  Note: This function requires build level >= GV_BUILD_BASE.
 
345
  
 
346
  \param Map pointer to Map_info structure
 
347
  \param line feature id
 
348
  \param offset feature offset
 
349
  
 
350
  \return 0 on success
 
351
  \return -1 on error
 
352
*/
 
353
int V2_restore_line_nat(struct Map_info *Map, int line, off_t offset)
 
354
{
 
355
    int type;
 
356
    struct Plus_head *plus;
 
357
    struct P_line *Line;
 
358
    
 
359
    plus = &(Map->plus);
 
360
 
 
361
    G_debug(3, "V2_restore_line_nat(), line = %d", line);
 
362
 
 
363
    if (line < 1 || line > plus->n_lines) {
 
364
        G_warning(_("Attempt to access feature with invalid id (%d)"), line);
 
365
        return -1;
 
366
    }
 
367
    
 
368
    Line = Map->plus.Line[line];
 
369
    if (Line != NULL) {
 
370
        G_warning(_("Attempt to access alive feature %d"), line);
 
371
        return -1;
 
372
    }
 
373
    
 
374
    /* restore feature in 'coor' file */
 
375
    if (0 != V1_restore_line_nat(Map, offset))
 
376
        return -1;
 
377
 
 
378
 
 
379
    /* read feature geometry */    
 
380
    if (!Points)
 
381
        Points = Vect_new_line_struct();
 
382
    if (!Cats)
 
383
        Cats = Vect_new_cats_struct();
 
384
    type = V1_read_line_nat(Map, Points, Cats, offset);
 
385
    if (type < 0)
 
386
        return -1;
 
387
 
 
388
    /* update topology */
 
389
    return V2__add_line_to_topo_nat(Map, offset, type, Points, Cats, line, NULL) > 0 ? 0 : -1;
 
390
}
 
391
 
 
392
/*** static or internal subroutines bellow ****/
 
393
 
 
394
/*!
 
395
  \brief Rewrites feature at the given offset 
 
396
  
 
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
481
402
  
482
403
  \return feature offset
483
404
  \return -1 on error
484
405
*/
485
 
long V1__rewrite_line_nat(struct Map_info *Map,
486
 
                          long offset,
487
 
                          int type,
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)
489
409
{
490
410
    int i, n_points;
491
411
    char rhead, nc;
492
412
    short field;
493
 
    GVFILE *dig_fp;
 
413
    struct gvfile *dig_fp;
494
414
 
495
415
    dig_set_cur_port(&(Map->head.port));
496
416
    dig_fp = &(Map->dig_fp);
517
437
    }
518
438
 
519
439
    if (cats->n_cats > 0) {
520
 
        if (Map->head.Version_Minor == 1) {     /* coor format 5.1 */
 
440
        if (Map->head.coor_version.minor == 1) {        /* coor format 5.1 */
521
441
            if (0 >= dig__fwrite_port_I(&(cats->n_cats), 1, dig_fp))
522
442
                return -1;
523
443
        }
528
448
        }
529
449
 
530
450
        if (cats->n_cats > 0) {
531
 
            if (Map->head.Version_Minor == 1) { /* coor format 5.1 */
 
451
            if (Map->head.coor_version.minor == 1) {    /* coor format 5.1 */
532
452
                if (0 >=
533
453
                    dig__fwrite_port_I(cats->field, cats->n_cats, dig_fp))
534
454
                    return -1;
570
490
    return offset;
571
491
}
572
492
 
573
 
/*!
574
 
  \brief Deletes feature at the given offset.
575
 
  
576
 
  \param Map pointer to vector map
577
 
  \param offset feature offset
578
 
  
579
 
  \return  0 on success
580
 
  \return -1 on error
581
 
*/
582
 
int V1_delete_line_nat(struct Map_info *Map, long offset)
583
 
{
584
 
    char rhead;
585
 
    GVFILE *dig_fp;
586
 
 
587
 
    G_debug(3, "V1_delete_line_nat(), offset = %ld", offset);
588
 
 
589
 
    dig_set_cur_port(&(Map->head.port));
590
 
    dig_fp = &(Map->dig_fp);
591
 
 
592
 
    if (dig_fseek(dig_fp, offset, 0) == -1)
593
 
        return -1;
594
 
 
595
 
    /* read old */
596
 
    if (0 >= dig__fread_port_C(&rhead, 1, dig_fp))
597
 
        return (-1);
598
 
 
599
 
    rhead &= 0xFE;
600
 
 
601
 
    if (dig_fseek(dig_fp, offset, 0) == -1)
602
 
        return -1;
603
 
 
604
 
    if (0 >= dig__fwrite_port_C(&rhead, 1, dig_fp))
605
 
        return -1;
606
 
 
607
 
    if (0 != dig_fflush(dig_fp))
608
 
        return -1;
609
 
 
610
 
    return 0;
611
 
}
612
 
 
613
 
/*!
614
 
  \brief Deletes feature (topology level).
615
 
  
616
 
  \param pointer to vector map
617
 
  \param line feature id
618
 
  
 
493
/*! 
 
494
  \brief Deletes area (i.e. centroid) categories from category
 
495
  index (internal use only)
 
496
 
 
497
  Call G_fatal_error() when area do not exits.
 
498
  
 
499
  \param Map pointer to Map_info structure
 
500
  \param area area id
 
501
*/
 
502
void V2__delete_area_cats_from_cidx_nat(struct Map_info *Map, int area)
 
503
{
 
504
    int i;
 
505
    struct P_area *Area;
 
506
    static struct line_cats *Cats = NULL;
 
507
 
 
508
    G_debug(3, "V2__delete_area_cats_from_cidx_nat(), area = %d", area);
 
509
 
 
510
    Area = Map->plus.Area[area];
 
511
    if (!Area)
 
512
        G_fatal_error(_("%s: Area %d does not exist"),
 
513
                      "delete_area_cats_from_cidx()", area);
 
514
    
 
515
    if (Area->centroid == 0) /* no centroid found */
 
516
        return;
 
517
 
 
518
    if (!Cats)
 
519
        Cats = Vect_new_cats_struct();
 
520
 
 
521
    Vect_read_line(Map, NULL, Cats, Area->centroid);
 
522
 
 
523
    for (i = 0; i < Cats->n_cats; i++) {
 
524
        dig_cidx_del_cat(&(Map->plus), Cats->field[i], Cats->cat[i], area,
 
525
                         GV_AREA);
 
526
    }
 
527
}
 
528
 
 
529
/*! 
 
530
  \brief Adds area (i.e. centroid) categories from category index
 
531
  (internal use only)
 
532
 
 
533
  Call G_fatal_error() when area do not exits.
 
534
  
 
535
  \param Map pointer to Map_info structure
 
536
  \param area area id
 
537
*/
 
538
void V2__add_area_cats_to_cidx_nat(struct Map_info *Map, int area)
 
539
{
 
540
    int i;
 
541
    struct P_area *Area;
 
542
    static struct line_cats *Cats = NULL;
 
543
 
 
544
    G_debug(3, "V2__add_area_cats_to_cidx_nat(), area = %d", area);
 
545
 
 
546
    Area = Map->plus.Area[area];
 
547
    if (!Area)
 
548
        G_fatal_error(_("%s: Area %d does not exist"),
 
549
                      "add_area_cats_to_cidx():", area);
 
550
 
 
551
    if (Area->centroid == 0) /* no centroid found */
 
552
        return;
 
553
 
 
554
    if (!Cats)
 
555
        Cats = Vect_new_cats_struct();
 
556
 
 
557
    V2_read_line_nat(Map, NULL, Cats, Area->centroid);
 
558
 
 
559
    for (i = 0; i < Cats->n_cats; i++) {
 
560
        dig_cidx_add_cat_sorted(&(Map->plus), Cats->field[i], Cats->cat[i],
 
561
                                area, GV_AREA);
 
562
    }
 
563
}
 
564
 
 
565
/*!
 
566
  \brief Delete feature from topology (internal use only)
 
567
 
 
568
  Note: This function requires build level >= GV_BUILD_BASE.
 
569
 
 
570
  Also updates category index if requested.
 
571
 
 
572
  Calls G_warning() on error.
 
573
  
 
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)
 
578
 
619
579
  \return 0 on success
620
 
  \return -1 on error
621
 
*/
622
 
int V2_delete_line_nat(struct Map_info *Map, int line)
 
580
  \return -1 on failure
 
581
 */
 
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)
623
584
{
624
 
    int ret, i, side, type = 0, first = 0, next_line, area;
625
 
    P_LINE *Line = NULL;
626
 
    P_AREA *Area;
 
585
    int i, first;
 
586
    int adjacent[4], n_adjacent;
 
587
    
 
588
    struct bound_box box, abox;
627
589
    struct Plus_head *plus;
628
 
    BOUND_BOX box, abox;
629
 
    int adjacent[4], n_adjacent = 0;
630
 
    static struct line_cats *Cats = NULL;
631
 
 
632
 
    G_debug(3, "V2_delete_line_nat(), line = %d", line);
633
 
 
 
590
    struct P_line *Line;
 
591
    
 
592
    n_adjacent = 0;
 
593
    
634
594
    plus = &(Map->plus);
635
 
 
636
 
    if (plus->built >= GV_BUILD_BASE) {
637
 
        Line = Map->plus.Line[line];
638
 
 
639
 
        if (Line == NULL)
640
 
            G_fatal_error(_("Attempt to delete dead feature"));
641
 
        type = Line->type;
642
 
    }
643
 
 
644
 
    if (!Cats) {
645
 
        Cats = Vect_new_cats_struct();
646
 
    }
647
 
 
648
 
    /* Update category index */
649
 
    if (plus->update_cidx) {
650
 
        type = V2_read_line_nat(Map, NULL, Cats, line);
651
 
 
652
 
        for (i = 0; i < Cats->n_cats; i++) {
653
 
            dig_cidx_del_cat(plus, Cats->field[i], Cats->cat[i], line, type);
654
 
        }
655
 
    }
656
 
 
657
 
    /* delete the line from coor */
658
 
    ret = V1_delete_line_nat(Map, Line->offset);
659
 
 
660
 
    if (ret == -1) {
661
 
        return ret;
662
 
    }
663
 
 
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 */
 
595
    
 
596
    if (line < 1 || line > plus->n_lines) {
 
597
        G_warning(_("Attempt to access feature with invalid id (%d)"), line);
 
598
        return -1;
 
599
    }
 
600
    
 
601
    Line = Map->plus.Line[line];
 
602
    if (!Line) {
 
603
        G_warning(_("Attempt to access dead feature %d"), line);
 
604
        return -1;
 
605
    }
 
606
 
 
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);
 
611
        }
 
612
    }
 
613
    
 
614
    /* update areas when deleting boundary from topology */
 
615
    if (plus->built >= GV_BUILD_AREAS && Line->type == GV_BOUNDARY) {
 
616
        int next_line;
 
617
        
 
618
        struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
 
619
 
 
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 */
668
622
        n_adjacent = 0;
669
623
 
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;
674
628
            n_adjacent++;
675
629
        }
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;
680
634
            n_adjacent++;
681
635
        }
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;
686
640
            n_adjacent++;
687
641
        }
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;
692
646
            n_adjacent++;
693
647
        }
694
648
 
695
 
        /* Delete area(s) and islands this line forms */
 
649
        /* delete area(s) and islands this line forms */
696
650
        first = 1;
697
 
        if (Line->left > 0) {   /* delete area */
698
 
            Vect_get_area_box(Map, Line->left, &box);
699
 
            if (first) {
700
 
                Vect_box_copy(&abox, &box);
701
 
                first = 0;
702
 
            }
703
 
            else
704
 
                Vect_box_extend(&abox, &box);
705
 
 
706
 
            if (plus->update_cidx) {
707
 
                delete_area_cats_from_cidx(Map, Line->left);
708
 
            }
709
 
            dig_del_area(plus, Line->left);
710
 
        }
711
 
        else if (Line->left < 0) {      /* delete isle */
712
 
            dig_del_isle(plus, -Line->left);
713
 
        }
714
 
        if (Line->right > 0) {  /* delete area */
715
 
            Vect_get_area_box(Map, Line->right, &box);
716
 
            if (first) {
717
 
                Vect_box_copy(&abox, &box);
718
 
                first = 0;
719
 
            }
720
 
            else
721
 
                Vect_box_extend(&abox, &box);
722
 
 
723
 
            if (plus->update_cidx) {
724
 
                delete_area_cats_from_cidx(Map, Line->right);
725
 
            }
726
 
            dig_del_area(plus, Line->right);
727
 
        }
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);
 
653
            if (first) {
 
654
                Vect_box_copy(&abox, &box);
 
655
                first = 0;
 
656
            }
 
657
            else
 
658
                Vect_box_extend(&abox, &box);
 
659
 
 
660
            if (plus->update_cidx) {
 
661
                V2__delete_area_cats_from_cidx_nat(Map, topo->left);
 
662
            }
 
663
            dig_del_area(plus, topo->left);
 
664
        }
 
665
        else if (topo->left < 0) {      /* delete isle */
 
666
            dig_del_isle(plus, -topo->left);
 
667
        }
 
668
        if (topo->right > 0) {  /* delete area */
 
669
            Vect_get_area_box(Map, topo->right, &box);
 
670
            if (first) {
 
671
                Vect_box_copy(&abox, &box);
 
672
                first = 0;
 
673
            }
 
674
            else
 
675
                Vect_box_extend(&abox, &box);
 
676
 
 
677
            if (plus->update_cidx) {
 
678
                V2__delete_area_cats_from_cidx_nat(Map, topo->right);
 
679
            }
 
680
            dig_del_area(plus, topo->right);
 
681
        }
 
682
        else if (topo->right < 0) {     /* delete isle */
 
683
            dig_del_isle(plus, -topo->right);
730
684
        }
731
685
    }
732
686
 
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) {
 
689
        struct P_area *Area;
 
690
        
 
691
        struct P_topo_c *topo = (struct P_topo_c *)Line->topo;
 
692
 
 
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);
739
697
            }
740
 
            Area = Map->plus.Area[Line->left];
741
 
            Area->centroid = 0;
 
698
            Area = Map->plus.Area[topo->area];
 
699
            if (Area) 
 
700
                Area->centroid = 0;
 
701
            else
 
702
                G_warning(_("Attempt to access dead area %d"), topo->area);
742
703
        }
743
704
    }
744
705
 
745
706
    /* delete the line from topo */
746
 
    dig_del_line(plus, line);
747
 
 
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]))
 
708
        return -1;
 
709
    
 
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;
 
712
        int i, side, area;
 
713
        int new_areas[4], nnew_areas = 0;
751
714
 
752
 
        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++) {
756
 
            if (adjacent[i] > 0)
757
 
                side = GV_RIGHT;
758
 
            else
759
 
                side = GV_LEFT;
 
717
            side = (adjacent[i] > 0 ? GV_RIGHT : GV_LEFT);
760
718
 
761
719
            G_debug(3, "Build area for line = %d, side = %d", adjacent[i],
762
720
                    side);
785
743
                    Vect_box_extend(&abox, &box);
786
744
            }
787
745
        }
 
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 */
 
749
            /* reattach isles */
 
750
            if (plus->built >= GV_BUILD_ATTACH_ISLES)
 
751
                Vect_attach_isles(Map, &abox);
 
752
 
 
753
            /* reattach centroids */
 
754
            if (plus->built >= GV_BUILD_CENTROIDS)
 
755
                Vect_attach_centroids(Map, &abox);
 
756
        }
 
757
 
 
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]);
 
761
            }
 
762
        }
 
763
    }
 
764
 
 
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);
 
768
    }
 
769
 
 
770
    return 0;
 
771
}
 
772
 
 
773
/*!
 
774
  \brief Add feature (line) to topology (internal use only)
 
775
 
 
776
  Also updates category index if requested.
 
777
 
 
778
  Update areas. Areas are modified if: 
 
779
   
 
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
 
783
 
 
784
   Question: may be by adding line created new area/isle which doesn't go through nodes of this line
 
785
 
 
786
   <pre>
 
787
             old         new line 
 
788
         +----+----+                    +----+----+                 +----+----+ 
 
789
         | A1 | A2 |  +      /      ->  | A1 |   /|   or +   \   -> | A1 | A2 | \
 
790
         |    |    |                    |    |    |                 |    |    |
 
791
         +----+----+                    +----+----+                 +----+----+
 
792
           I1   I1                        I1   I1                      
 
793
   </pre>        
 
794
 
 
795
   - re-attach all centroids/isles inside new area(s)
 
796
   - attach new isle to area outside
 
797
 
 
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
 
803
    
 
804
    Note that 1) and 2) is done by the same code.
 
805
 
 
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)
 
811
 
 
812
    \return feature id to be added
 
813
    \return 0 nothing to do (build level must be >= GV_BUILD_BASE) 
 
814
    \return -1 on error 
 
815
*/
 
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,
 
818
                             int restore_line,
 
819
                             int (*external_routine) (const struct Map_info *, int))
 
820
{
 
821
    int first, s, n, i, line;
 
822
    int node, next_line, area, side, sel_area, new_area[2];
 
823
 
 
824
    struct Plus_head *plus;
 
825
    struct P_line *Line, *NLine;
 
826
    struct P_node *Node;
 
827
    struct P_area *Area;
 
828
    
 
829
    struct bound_box box, abox;
 
830
 
 
831
    plus = &(Map->plus);
 
832
    
 
833
    G_debug(3, "V2__add_line_to_topo_nat(): offset = %ld (build level = %d)", offset, plus->built);
 
834
 
 
835
    if (plus->built < GV_BUILD_BASE) /* nothing to build */
 
836
        return 0;
 
837
    
 
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);
 
842
    else
 
843
        line = dig_add_line(plus, type, points, &box, offset);
 
844
    G_debug(3, "  line added to topo with id = %d", line);
 
845
    
 
846
    Line = plus->Line[line];
 
847
    
 
848
    /* extend map bounding box */
 
849
    if (line == 1)
 
850
        Vect_box_copy(&(plus->box), &box);
 
851
    else
 
852
        Vect_box_extend(&(plus->box), &box);
 
853
 
 
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;
 
858
        
 
859
        /* delete neighbour areas/isles */
 
860
        first = TRUE;
 
861
        for (s = 0; s < 2; s++) {       /* for each node */
 
862
            node = (s == 0 ? topo->N1 : topo->N2);
 
863
            G_debug(3,
 
864
                    "  delete neighbour areas/isles: %s node = %d",
 
865
                    (s == 0 ? "first" : "second"), node);
 
866
            Node = plus->Node[node];
 
867
            n = 0;
 
868
            for (i = 0; i < Node->n_lines; i++) {
 
869
                NLine = plus->Line[abs(Node->lines[i])];
 
870
                if (NLine->type == GV_BOUNDARY)
 
871
                    n++;
 
872
            }
 
873
            
 
874
            G_debug(3, "  number of boundaries at node = %d", n);
 
875
            if (n > 2) {
 
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
 
879
                   same to the left */
 
880
                if (!s)
 
881
                    next_line =
 
882
                        dig_angle_next_line(plus, line, GV_RIGHT,
 
883
                                            GV_BOUNDARY, NULL);
 
884
                else
 
885
                    next_line =
 
886
                        dig_angle_next_line(plus, -line, GV_RIGHT,
 
887
                                            GV_BOUNDARY, NULL);
 
888
                
 
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) */
 
894
                        area = topo->right;     
 
895
                    else if (next_line < 0)     /* the boundary is connected by 2. node */
 
896
                        area = topo->left;
 
897
                    
 
898
                    G_debug(3, "  next_line = %d area = %d", next_line,
 
899
                            area);
 
900
                    if (area > 0) {     /* is area */
 
901
                        Vect_get_area_box(Map, area, &box);
 
902
                        if (first) {
 
903
                            Vect_box_copy(&abox, &box);
 
904
                            first = FALSE;
 
905
                        }
 
906
                        else
 
907
                            Vect_box_extend(&abox, &box);
 
908
                        
 
909
                        if (plus->update_cidx) {
 
910
                            V2__delete_area_cats_from_cidx_nat(Map, area);
 
911
                        }
 
912
                        dig_del_area(plus, area);
 
913
                        if (external_routine) /* call external subroutine if defined */
 
914
                            external_routine(Map, area);
 
915
                    }
 
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);
 
920
                    }
 
921
                }
 
922
            }
 
923
        }
 
924
        
 
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);
 
932
            
 
933
            if (area > 0) {     /* area */
 
934
                Vect_get_area_box(Map, area, &box);
 
935
                if (first) {
 
936
                    Vect_box_copy(&abox, &box);
 
937
                    first = FALSE;
 
938
                }
 
939
                else
 
940
                    Vect_box_extend(&abox, &box);
 
941
            }
 
942
            else if (area < 0) {
 
943
                /* isle -> must be attached -> add to abox */
 
944
                Vect_get_isle_box(Map, -area, &box);
 
945
                if (first) {
 
946
                    Vect_box_copy(&abox, &box);
 
947
                    first = FALSE;
 
948
                }
 
949
                else
 
950
                    Vect_box_extend(&abox, &box);
 
951
            }
 
952
            new_area[s] = area;
 
953
        }
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 */
 
958
            /* Reattach isles */
792
959
            if (plus->built >= GV_BUILD_ATTACH_ISLES)
793
960
                Vect_attach_isles(Map, &abox);
794
 
 
 
961
            
795
962
            /* Reattach centroids */
796
963
            if (plus->built >= GV_BUILD_CENTROIDS)
797
964
                Vect_attach_centroids(Map, &abox);
798
965
        }
799
 
 
 
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]);
803
 
            }
804
 
        }
805
 
    }
806
 
 
807
 
    G_debug(3, "updated lines : %d , updated nodes : %d", plus->n_uplines,
808
 
            plus->n_upnodes);
809
 
    return ret;
810
 
}
811
 
 
812
 
/*!
813
 
  \brief Restores feature at the given offset.
814
 
  
815
 
  \param Map pointer to vector map
816
 
  \param offset feature offset
817
 
  
818
 
  \return  0 on success
819
 
  \return -1 on error
820
 
*/
821
 
int V1_restore_line_nat(struct Map_info *Map, long offset)
822
 
{
823
 
    char rhead;
824
 
    GVFILE *dig_fp;
825
 
    
826
 
    G_debug(3, "V1_restore_line_nat(), offset = %ld", offset);
827
 
    
828
 
    dig_set_cur_port(&(Map->head.port));
829
 
    dig_fp = &(Map->dig_fp);
830
 
    
831
 
    if (dig_fseek(dig_fp, offset, 0) == -1)
832
 
        return -1;
833
 
    
834
 
    /* read old */
835
 
    if (0 >= dig__fread_port_C(&rhead, 1, dig_fp))
836
 
        return (-1);
837
 
 
838
 
    /* mark as alive */
839
 
    rhead |= 1;
840
 
    
841
 
    /* write new */
842
 
    if (dig_fseek(dig_fp, offset, 0) == -1)
843
 
        return -1;
844
 
 
845
 
    if (0 >= dig__fwrite_port_C(&rhead, 1, dig_fp))
846
 
        return -1;
847
 
    
848
 
    if (0 != dig_fflush(dig_fp))
849
 
        return -1;
850
 
    
851
 
    return 0;
852
 
}
853
 
 
854
 
/*!
855
 
  \brief Restores feature (topology level)
856
 
  
857
 
  \param Map pointer to vector map
858
 
  \param line feature id
859
 
  \param offset feature offset
860
 
  
861
 
  \return 0 on success
862
 
  \return -1 on error
863
 
*/
864
 
int V2_restore_line_nat(struct Map_info *Map, int line, long offset)
865
 
{
866
 
    int i, ret, type;
867
 
    P_LINE *Line;
868
 
    struct Plus_head *plus;
869
 
    BOUND_BOX box;
870
 
    
871
 
    static struct line_pnts *points = NULL;
872
 
    static struct line_cats *cats = NULL;
873
 
    
874
 
    Line = NULL;
875
 
    type = 0;
876
 
    
877
 
    G_debug(3, "V2_restore_line_nat(), line = %d", line);
878
 
 
879
 
    plus = &(Map->plus);
880
 
 
881
 
    if (plus->built >= GV_BUILD_BASE) {
882
 
        Line = Map->plus.Line[line];
883
 
 
884
 
        if (Line != NULL)
885
 
            G_fatal_error(_("Attempt to restore alive feature"));
886
 
    }
887
 
 
888
 
    if (!points) {
889
 
        points = Vect_new_line_struct();
890
 
    }
891
 
 
892
 
    if (!cats) {
893
 
        cats = Vect_new_cats_struct();
894
 
    }
895
 
 
896
 
    /* restore the line in coor */
897
 
    ret = V1_restore_line_nat(Map, offset);
898
 
 
899
 
    if (ret == -1) {
900
 
        return ret;
901
 
    }
902
 
    
903
 
    /* read feature geometry */
904
 
    type = V1_read_line_nat(Map, points, cats, offset);
905
 
    if (type < 0) {
906
 
        return -1;
907
 
    }
908
 
 
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);
913
 
        }
914
 
    }
915
 
    
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);
923
 
    }
924
 
    
925
 
    add_line_to_topo(Map,
926
 
                     line, points, cats);
927
 
 
928
 
    G_debug(3, "updated lines : %d , updated nodes : %d", plus->n_uplines,
929
 
            plus->n_upnodes);
930
 
    
931
 
 
932
 
    return ret;
 
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]);
 
971
                }
 
972
            }
 
973
        }
 
974
    }
 
975
    
 
976
    /* attach centroid */
 
977
    if (plus->built >= GV_BUILD_CENTROIDS) {
 
978
        struct P_topo_c *topo;
 
979
 
 
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);
 
983
            if (sel_area > 0) {
 
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);
 
993
                    }
 
994
                }
 
995
                else {          /* duplicate centroid */
 
996
                    G_debug(3,
 
997
                            "  duplicate centroid -> do not attach to area");
 
998
                    topo->area = -sel_area;
 
999
                }
 
1000
            }
 
1001
        }
 
1002
    }
 
1003
 
 
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,
 
1008
                                    type);
 
1009
        }
 
1010
    }
 
1011
 
 
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);
 
1015
    }
 
1016
    
 
1017
    return line;
933
1018
}