1 /*---------------------------------------------------------------------------*\
2 gpsmanshp.c
3
4 A layer for writing GPS data to Shapefile format files
5 using shapelib from Tcl
6
7 This program was developed for use in
8 gpsman --- GPS Manager: a manager for GPS receiver data
9
10 Copyright (c) 2003-2013 Miguel Filgueiras (migfilg@t-online.de)
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program.
24
25 ------
26 This program uses
27 - shapelib, Copyright (c) 1999 by Frank Warmerdam <warmerda@home.com>
28
29 and was based on
30 - gpstr2shp.c, Copyright (c) 2002 Miguel Filgueiras (mig@ncc.up.pt)
31 that translates files in GPStrans format to Shapefile
32
33 This program provides the Tcl gpsmanshp package defining the following
34 Tcl commands:
35 GSHPOpenInputFiles BASEPATH
36 GSHPInfoFrom ID
37 GSHPGetObj ID INDEX
38 GSHPReadNextPoint ID
39 GSHPCreateFiles BASEPATH TYPE DIM
40 GSHPWriteWP ID X Y ?Z? NAME COMMENT DATE
41 GSHPCreateRT DIM RTID COMMENT
42 GSHPForgetRT
43 GSHPAddWPToRT X Y ?Z?
44 GSHPWriteRT ID FORGET
45 GSHPCreateTR DIM NAME COMMENT
46 GSHPForgetTR
47 GSHPAddTPToTR X Y ?Z?
48 GSHPWriteTR ID FORGET
49 GSHPCloseFiles ID
50
51 -----
52 Revision history:
53 1.2.3 06-Oct-13
54 change of author email address
55 1.2.2 15-Jul-13
56 change of author email address
57 1.2.1 08-Jun-11
58 path to shapefil.h
59 change of author email address
60 1.2 05-Jul-04, reads .dbf fields for WP and UNKNOWN from files not written
61 by gpsmanshp
62 1.1 17-Nov-03, reads POLYGON/Z Shapes as UNKNOWN, and ARCM and POLYGONM as
63 UNKNOWN in 2 dimensions; reads/writes part (segment) information for
64 polylines (TR or UNKNOWN) and polygons (read only)
65 1.0.3 08-Nov-03, avoids warning in gcc with -Wall
66 1.0.2 07-Mar-03, avoids warnings in gcc with -Wall
67 1.0.1 27-Jun-02, avoids warnings in gcc
68 1.0 12-Jun-02
69
70 \*---------------------------------------------------------------------------*/
71
72 /* File: gpsmanshp.c *\
73 \* Last modified: 15 July 2013 */
74
75 #include <stdlib.h>
76 #include <string.h>
77 #include <shapefil.h>
78 #include <tcl.h>
79
80 #define VERSION "1.2.3"
81
82 // #define DEBUG 1
83
84 /* lengths of strings */
85 #define WPNAMEWD 50
86 #define WPCOMMTWD 128
87 #define WPDATEWD 25
88 #define RTIDWD 50
89 #define RTCOMMTWD 128
90 #define TRNAMEWD 50
91 #define TRCOMMTWD 128
92 #define MAXBUFFER 1024
93
94 typedef struct wpstrt {
95 char wpname[WPNAMEWD], wpcommt[WPCOMMTWD], wpdate[WPDATEWD];
96 double wpx, wpy, wpz;
97 struct wpstrt *wpnext;
98 } WPDATA, *WPLIST;
99
100 typedef struct {
101 char rtid[RTIDWD], rtcommt[RTCOMMTWD];
102 int rtdim;
103 double *rtxs, *rtys, *rtzs;
104 WPLIST rtwps;
105 } RTDATA;
106
107 RTDATA RT;
108 int RTBuilding = 0, RTCount = 0, RTLgth;
109 WPLIST RTLastWP;
110
111 typedef struct tpstrt {
112 double tpx, tpy, tpz;
113 struct tpstrt *tpnext;
114 } TPDATA, *TPLIST;
115
116 typedef struct {
117 char trname[TRNAMEWD], trcommt[TRCOMMTWD];
118 int trdim, trnsegs, *trsegstarts, trsegsmax;
119 double *trxs, *trys, *trzs;
120 TPLIST trpts;
121 } TRDATA;
122
123 TRDATA TR;
124 int TRBuilding = 0, TRCount = 0, TRLgth;
125 TPLIST TRLastTP;
126
127 int RTRepr = 0, TRRepr = 0;
128
129 #define WPTYPE3 SHPT_POINTZ
130 #define RTTYPE3 SHPT_ARCZ
131 #define TRTYPE3 SHPT_ARCZ
132
133 #define WPTYPE2 SHPT_POINT
134 #define RTTYPE2 SHPT_ARC
135 #define TRTYPE2 SHPT_ARC
136
137 typedef enum {WPs, RTs, TRs, UNKNOWN} GPSTYPE;
138
139 /* the following 3 arrays must be kept aligned */
140 int SHPTypes[] = {SHPT_POINTZ, SHPT_ARCZ, SHPT_POINT, SHPT_ARC,
141 SHPT_POLYGONZ, SHPT_POLYGON, SHPT_ARCM, SHPT_POLYGONM},
142 SHPTypeDim[] = {3, 3, 2, 2, 3, 2, 2, 2},
143 NSHPTypes = 8;
144
145 GPSTYPE SHPGPSType[] = {WPs, UNKNOWN, WPs, UNKNOWN, UNKNOWN, UNKNOWN,
146 UNKNOWN, UNKNOWN};
147
148 /* to be indexed by GPSTYPE (not UNKNOWN) and 0,1 for 2 or 3 dimensions */
149 int SHPType[][2] = {{WPTYPE2, WPTYPE3}, {RTTYPE2, RTTYPE3},
150 {TRTYPE2, TRTYPE3}};
151
152 /* max number of fields in gpsmanshp-generated .dbf files and in others*/
153 #define NFIELDS 3
154 #define MAXFIELDS 50
155
156 typedef struct shpfset {
157 int id, settype, dim, input, field[NFIELDS], index;
158 GPSTYPE gpstype;
159 SHPHandle SHPFile; DBFHandle DBFFile;
160 SHPObject *shpobj;
161 struct shpfset *nextset;
162 } SHPFILESET, *SHPFSETLIST;
163
164 SHPFSETLIST FileSets = NULL;
165 int FileSetCount = 0;
166
167 #define CHECKPARAMNO(number,mess) \
168 if (objc != number+1) { \
169 Tcl_WrongNumArgs(interp,1,objv,mess); \
170 return TCL_ERROR; \
171 }
172 #define CHECKPARAMNOS(min,max,mess) \
173 if (objc <= min || objc > max+1) { \
174 Tcl_WrongNumArgs(interp,1,objv,mess); \
175 return TCL_ERROR; \
176 }
177 #define GETINTPARAM(index,var) \
178 if (Tcl_GetIntFromObj(interp,objv[index],&var) != TCL_OK) { \
179 return TCL_ERROR; \
180 }
181 #define GETDOUBLEPARAM(index,var) \
182 if (Tcl_GetDoubleFromObj(interp,objv[index],&var) != TCL_OK) { \
183 return TCL_ERROR; \
184 }
185 #define GETSTRINGPARAM(index) Tcl_GetString(objv[index]);
186 #define RETURNINT(value) \
187 Tcl_SetObjResult(interp,Tcl_NewIntObj(value)); \
188 return TCL_OK;
189 #define RETURNLIST(number,vec) \
190 Tcl_SetObjResult(interp,Tcl_NewListObj(number,vec)); \
191 return TCL_OK;
192
193
cpstrclean(char * s,char * dest,int n)194 void cpstrclean(char *s, char *dest, int n)
195 /* copy string of length at most n, set to zero trailing chars */
196 {
197 while ((*dest++=*s++) && n--);
198 if (! n) *--dest = 0;
199 else while (n--) *dest++ = 0;
200 }
201
findset(int id)202 SHPFSETLIST findset(int id)
203 { SHPFSETLIST p = FileSets;
204
205 while (p != NULL) {
206 if (p->id == id) return p;
207 p = p->nextset;
208 }
209 return NULL;
210 }
211
nodbffields(SHPFSETLIST p)212 int nodbffields(SHPFSETLIST p)
213 { DBFHandle df = p->DBFFile;
214 // GSHPOpenInputFiles must be revised if there is any change in these fields
215 // the same is obviously true of the GSHPWrite... functions
216 switch (p->gpstype) {
217 case WPs:
218 return ((p->field[0]=DBFAddField(df,"name",FTString,WPNAMEWD,0)) == -1 ||
219 (p->field[1]=DBFAddField(df,"commt",FTString,WPCOMMTWD,0))
220 == -1 ||
221 (p->field[2]=DBFAddField(df,"date",FTString,WPDATEWD,0)) == -1);
222 case RTs:
223 return ((p->field[0]=DBFAddField(df,"id",FTString,RTIDWD,0)) == -1 ||
224 (p->field[1]=DBFAddField(df,"commt",FTString,RTCOMMTWD,0)) == -1);
225 case TRs:
226 return ((p->field[0]=DBFAddField(df,"name",FTString,TRNAMEWD,0)) == -1 ||
227 (p->field[1]=DBFAddField(df,"commt",FTString,TRCOMMTWD,0)) == -1);
228 default:
229 return 1;
230 }
231 return 1;
232 }
233
getdbfotherfields(DBFHandle df,int n,int oix)234 Tcl_Obj *getdbfotherfields(DBFHandle df, int n, int oix)
235 { int i;
236 Tcl_Obj *ov[MAXFIELDS];
237
238 #ifdef DEBUG
239 printf(">getdbfotherfields n=%d oix=%d\n",n,oix);
240 #endif
241
242 if (df == NULL || n <= 0) return NULL;
243 for (i=0; i<n; i++)
244 ov[i] = Tcl_NewStringObj(DBFReadStringAttribute(df,oix,i),-1);
245
246 #ifdef DEBUG
247 printf(">returning from getdbfotherfields");
248 #endif
249
250 return Tcl_NewListObj(n,ov);
251 }
252
getdbffields(SHPFSETLIST p,int oix,Tcl_Obj * ov[],Tcl_Obj ** eflst)253 int getdbffields(SHPFSETLIST p, int oix, Tcl_Obj *ov[], Tcl_Obj **eflst)
254 { DBFHandle df = p->DBFFile;
255 int n = 2, i;
256
257 if (p->gpstype == UNKNOWN) {
258 *eflst = getdbfotherfields(df,-p->field[0],oix);
259 return 0;
260 }
261 if (p->gpstype == WPs) {
262 *eflst = getdbfotherfields(df,-p->field[0],oix);
263 n = 3;
264 }
265 if (df == NULL)
266 for (i=0; i<n; i++) ov[i] = Tcl_NewStringObj("",-1);
267 else
268 for (i=0; i<n; i++)
269 ov[i] = Tcl_NewStringObj(DBFReadStringAttribute(df,oix,p->field[i]),-1);
270 return n;
271 }
272
GSHPCreateFiles(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])273 int GSHPCreateFiles(ClientData clientData,Tcl_Interp *interp,
274 int objc,Tcl_Obj *CONST objv[])
275 /* GSHPCreateFiles BASEPATH TYPE DIM */
276 { SHPFSETLIST p = FileSets, q;
277 int id, shptype, dim;
278 char *basename, *type;
279 SHPHandle sf; DBFHandle df;
280 GPSTYPE gpstype;
281
282 #ifdef DEBUG
283 printf(">GSHPCreateFiles, %d args\n",objc-1);
284 #endif
285
286 CHECKPARAMNO(3,"BASEPATH TYPE DIM")
287 basename = GETSTRINGPARAM(1); type = GETSTRINGPARAM(2);
288 GETINTPARAM(3,dim)
289 if (dim < 2 || dim > 3) {
290 RETURNINT(-2)
291 }
292 if (! strcmp(type,"WP")) gpstype = WPs;
293 else if (! strcmp(type,"RT")) gpstype = RTs;
294 else if (! strcmp(type,"TR")) gpstype = TRs;
295 else {
296 RETURNINT(-1)
297 }
298 shptype = SHPType[gpstype][dim-2];
299 if ((df=DBFCreate(basename)) == NULL ||
300 (sf=SHPCreate(basename,shptype)) == NULL) {
301 RETURNINT(0)
302 }
303 if ((q=(SHPFSETLIST) malloc(sizeof(SHPFILESET))) == NULL) {
304 RETURNINT(-4)
305 }
306 if (p != NULL) {
307 while (p->nextset != NULL) p = p->nextset;
308 p->nextset = q;
309 } else FileSets = q;
310 id = q->id = ++FileSetCount;
311 q->settype = shptype; q->dim = dim; q->input = 0;
312 q->gpstype = gpstype;
313 q->SHPFile = sf; q->DBFFile = df; q->shpobj = NULL;
314 q->nextset = NULL;
315 if (nodbffields(q)) {
316 if (p != NULL) p->nextset = NULL;
317 else FileSets = NULL;
318 free(q);
319 RETURNINT(-3)
320 }
321 RETURNINT(id)
322 }
323
GSHPOpenInputFiles(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])324 int GSHPOpenInputFiles(ClientData clientData,Tcl_Interp *interp,
325 int objc,Tcl_Obj *CONST objv[])
326 /* GSHPOpenInputFiles BASEPATH */
327 { SHPFSETLIST p = FileSets, q;
328 int id, shptype, dim, nents, i, f[NFIELDS], usefs;
329 char *basename;
330 SHPHandle sf; DBFHandle df;
331 GPSTYPE gpstype;
332
333 #ifdef DEBUG
334 printf(">GSHPOpenInputFiles, %d args\n",objc-1);
335 #endif
336
337 CHECKPARAMNO(1,"BASEPATH")
338 basename = GETSTRINGPARAM(1);
339 if ((sf=SHPOpen(basename,"rb")) == NULL) {
340 RETURNINT(0)
341 }
342 SHPGetInfo(sf,&nents,&shptype,NULL,NULL);
343 if (nents == 0) {
344 RETURNINT(-1)
345 }
346 for (i=0; i<NSHPTypes; i++)
347 if (shptype == SHPTypes[i]) {
348 dim = SHPTypeDim[i]; gpstype = SHPGPSType[i];
349 break;
350 }
351 if (i == NSHPTypes) {
352 RETURNINT(-2)
353 }
354 if ((df=DBFOpen(basename,"rb")) != NULL) {
355 if (DBFGetRecordCount(df) == nents) {
356 usefs = 0;
357 switch ((i = DBFGetFieldCount(df))) {
358 case 3:
359 if (gpstype != WPs ||
360 (f[0]=DBFGetFieldIndex(df,"name")) == -1 ||
361 (f[1]=DBFGetFieldIndex(df,"commt")) == -1 ||
362 (f[2]=DBFGetFieldIndex(df,"date")) == -1)
363 usefs = 1;
364 break;
365 case 2:
366 if ((f[1]=DBFGetFieldIndex(df,"commt")) == -1)
367 usefs = 1;
368 else if ((f[0]=DBFGetFieldIndex(df,"id")) == -1)
369 if ((f[0]=DBFGetFieldIndex(df,"name")) == -1) usefs = 1;
370 else gpstype = TRs;
371 else gpstype = RTs;
372 break;
373 case 0:
374 df = NULL;
375 default:
376 usefs = 1;
377 }
378 if (usefs) {
379 if (i > MAXFIELDS) f[0] = -MAXFIELDS;
380 f[0] = -i;
381 }
382 } else df = NULL;
383 }
384 if ((q=(SHPFSETLIST) malloc(sizeof(SHPFILESET))) == NULL) {
385 RETURNINT(-3)
386 }
387 if (p != NULL) {
388 while (p->nextset != NULL) p = p->nextset;
389 p->nextset = q;
390 } else FileSets = q;
391 id = q->id = ++FileSetCount;
392 q->settype = shptype; q->dim = dim;
393 // this must be non-zero; otherwise the set can be taken as an output one
394 q->input = nents; q->index = -1;
395 // gpstype may be UNKNOWN (an ARC/Z Shape without gpsmanshp written .dbf,
396 // or a POLIGON/Z)
397 q->gpstype = gpstype;
398 q->SHPFile = sf; q->DBFFile = df;
399 q->shpobj = NULL;
400 q->nextset = NULL;
401 for (i=0; i<NFIELDS; i++) q->field[i] = f[i];
402 #ifdef DEBUG
403 printf("set %d:\n\tshptype=%d gpstype=%d dim=%d nents=%d dbf=%d usefs=%d\n",
404 id,shptype,gpstype,dim,nents,df!=NULL,usefs);
405 #endif
406 RETURNINT(id)
407 }
408
GSHPInfoFrom(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])409 int GSHPInfoFrom(ClientData clientData,Tcl_Interp *interp,
410 int objc,Tcl_Obj *CONST objv[])
411 /* GSHPInfoFrom ID */
412 { SHPFSETLIST p;
413 int id, n, i, k, j;
414 Tcl_Obj *ov[7], *fov[2*MAXFIELDS];
415 char buffer[MAXBUFFER];
416 DBFHandle df;
417
418 #ifdef DEBUG
419 printf(">GSHPInfoFrom, %d args\n",objc-1);
420 #endif
421
422 CHECKPARAMNO(1,"FILES_ID")
423 GETINTPARAM(1,id)
424 if ((p=findset(id)) == NULL || ! p->input) {
425 RETURNINT(0)
426 }
427 n = 4;
428 switch (p->gpstype) {
429 case WPs: ov[0] = Tcl_NewStringObj("WP",-1); n = 3; break;
430 case RTs: ov[0] = Tcl_NewStringObj("RT",-1); break;
431 case TRs: ov[0] = Tcl_NewStringObj("TR",-1); break;
432 case UNKNOWN: ov[0] = Tcl_NewStringObj("UNKNOWN",-1);
433 }
434 ov[1] = Tcl_NewIntObj(p->input); ov[2] = Tcl_NewIntObj(p->dim);
435 if (n == 4) ov[3] = Tcl_NewIntObj(p->index);
436 if ((df = p->DBFFile) == NULL) {
437 ov[n++] = Tcl_NewIntObj(0);
438 ov[n++] = Tcl_NewListObj(0,NULL);
439 } else if ((i = -p->field[0]) > 0) {
440 // get field names and precisions
441 for (k=j=0; k<i; k++) {
442 if (DBFGetFieldInfo(df,k,buffer,NULL,&id) == FTInvalid) {
443 *buffer = 0; id = 0;
444 }
445 fov[j++] = Tcl_NewStringObj(buffer,-1);
446 fov[j++] = Tcl_NewIntObj(id);
447 }
448 ov[n++] = Tcl_NewIntObj(i);
449 ov[n++] = Tcl_NewListObj(j,fov);
450 }
451 RETURNLIST(n,ov)
452 }
453
GSHPGetObj(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])454 int GSHPGetObj(ClientData clientData,Tcl_Interp *interp,
455 int objc,Tcl_Obj *CONST objv[])
456 /* GSHPGetObj ID INDEX */
457 { SHPFSETLIST p;
458 int id, oix, n, nsegs, *segstart, i, k;
459 Tcl_Obj *ov[6], *eflst, **ppov, **ppovnxt;
460
461 #ifdef DEBUG
462 printf(">GSHPGetObj, %d args\n",objc-1);
463 #endif
464
465 CHECKPARAMNO(2,"FILES_ID INDEX")
466 GETINTPARAM(1,id) GETINTPARAM(2,oix)
467 if ((p=findset(id)) == NULL || ! p->input) {
468 RETURNINT(-1)
469 }
470 p->index = -1;
471 if (p->shpobj != NULL) {
472 SHPDestroyObject(p->shpobj);
473 p->shpobj = NULL;
474 }
475 if (oix < 0 || oix >= p->input ||
476 (p->shpobj=SHPReadObject(p->SHPFile,oix)) == NULL) {
477 RETURNINT(-2)
478 }
479 if (p->shpobj->nSHPType == SHPT_NULL) {
480 SHPDestroyObject(p->shpobj);
481 p->shpobj = NULL;
482 RETURNLIST(0,NULL)
483 }
484 n = 0;
485 switch (p->gpstype) {
486 case WPs:
487 n = getdbffields(p,oix,ov,&eflst);
488 ov[n++] = Tcl_NewDoubleObj(p->shpobj->padfX[0]);
489 ov[n++] = Tcl_NewDoubleObj(p->shpobj->padfY[0]);
490 if (p->dim == 3)
491 ov[n++] = Tcl_NewDoubleObj(p->shpobj->padfZ[0]);
492 if (eflst != NULL) ov[n++] = eflst;
493 break;
494 case RTs:
495 n = getdbffields(p,oix,ov,NULL);
496 ov[n++] = Tcl_NewIntObj(p->shpobj->nVertices);
497 p->index = 0;
498 break;
499 case TRs:
500 n = getdbffields(p,oix,ov,NULL);
501 case UNKNOWN:
502 ov[n++] = Tcl_NewIntObj(p->shpobj->nVertices);
503 if ((nsegs=p->shpobj->nParts) != 0) {
504 if ((ppov = (Tcl_Obj **) malloc(nsegs*sizeof(Tcl_Obj *))) == NULL) {
505 RETURNINT(-3)
506 }
507 segstart = p->shpobj->panPartStart;
508 ppovnxt = ppov; i = 0;
509 do
510 if ((k = (*segstart++)) > 0) {
511 *ppovnxt++ = Tcl_NewIntObj(k);
512 #ifdef DEBUG
513 printf(">GSHPGetObj, segment starter: %d\n",i); fflush(stdout);
514 #endif
515 i++;
516 }
517 while (--nsegs);
518 if (i != 0) {
519 ov[n++] = Tcl_NewListObj(i,ppov);
520 }
521
522 #ifdef DEBUG
523 printf(">GSHPGetObj, about freeing memory\n"); fflush(stdout);
524 #endif
525
526 free(ppov);
527 }
528 if (p->gpstype == UNKNOWN) {
529 getdbffields(p,oix,NULL,&eflst);
530 if (eflst != NULL) {
531 if (n == 1) ov[n++] = Tcl_NewListObj(0,NULL);
532 ov[n++] = eflst;
533 }
534 }
535 p->index = 0;
536 }
537 RETURNLIST(n,ov)
538 }
539
GSHPReadNextPoint(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])540 int GSHPReadNextPoint(ClientData clientData,Tcl_Interp *interp,
541 int objc,Tcl_Obj *CONST objv[])
542 /* GSHPReadNextPoint ID */
543 { SHPFSETLIST p;
544 int id, eix, n = 2;
545 Tcl_Obj *ov[3];
546
547 #ifdef DEBUG
548 printf(">GSHPReadNextPoint, %d args\n",objc-1);
549 #endif
550
551 CHECKPARAMNO(1,"FILES_ID")
552 GETINTPARAM(1,id)
553 if ((p=findset(id)) == NULL || ! p->input) {
554 RETURNINT(0)
555 }
556 if ((eix=p->index) < 0) {
557 RETURNINT(-1)
558 }
559 if (eix == p->shpobj->nVertices) {
560 p->index = -1;
561 SHPDestroyObject(p->shpobj);
562 p->shpobj = NULL;
563 RETURNINT(-2)
564 }
565 ov[0] = Tcl_NewDoubleObj(p->shpobj->padfX[eix]);
566 ov[1] = Tcl_NewDoubleObj(p->shpobj->padfY[eix]);
567 if (p->dim == 3)
568 ov[n++] = Tcl_NewDoubleObj(p->shpobj->padfZ[eix]);
569 p->index++;
570 RETURNLIST(n,ov)
571 }
572
GSHPCloseFiles(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])573 int GSHPCloseFiles(ClientData clientData,Tcl_Interp *interp,
574 int objc,Tcl_Obj *CONST objv[])
575 /* GSHPCloseFiles ID */
576 { SHPFSETLIST p = FileSets, q = NULL;
577 int id;
578
579 #ifdef DEBUG
580 printf(">GSHPCloseFiles, %d args\n",objc-1);
581 #endif
582
583 CHECKPARAMNO(1,"FILES_ID")
584 GETINTPARAM(1,id)
585 while (p != NULL && p->id != id) {
586 q = p; p = p->nextset;
587 }
588 if (p == NULL) {
589 RETURNINT(0)
590 }
591 SHPClose(p->SHPFile);
592 if (p->DBFFile != NULL) DBFClose(p->DBFFile);
593 if (p->shpobj != NULL) SHPDestroyObject(p->shpobj);
594 if (q != NULL) q->nextset = p->nextset;
595 else FileSets = p->nextset;
596 free(p);
597 RETURNINT(1)
598 }
599
GSHPWriteWP(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])600 int GSHPWriteWP(ClientData clientData,Tcl_Interp *interp,
601 int objc,Tcl_Obj *CONST objv[])
602 /* GSHPWriteWP ID X Y ?Z? NAME COMMENT DATE */
603 { SHPFSETLIST p;
604 int id, entno, dim;
605 double x, y, z;
606 char *name, *commt, *date;
607 SHPObject *pwpo;
608 DBFHandle df;
609
610 #ifdef DEBUG
611 printf(">GSHPWriteWP, %d args\n",objc-1);
612 #endif
613
614 CHECKPARAMNOS(6,7,"FILES_ID X Y ?Z? NAME COMMENT DATE")
615 dim = objc-5;
616 GETINTPARAM(1,id)
617 GETDOUBLEPARAM(2,x) GETDOUBLEPARAM(3,y)
618 if (dim == 3) {
619 GETDOUBLEPARAM(4,z)
620 name = GETSTRINGPARAM(5) commt = GETSTRINGPARAM(6)
621 date = GETSTRINGPARAM(7)
622 } else {
623 z = 0;
624 name = GETSTRINGPARAM(4) commt = GETSTRINGPARAM(5)
625 date = GETSTRINGPARAM(6)
626 }
627 if ((p=findset(id)) == NULL || p->input) {
628 RETURNINT(-1)
629 }
630 if (p->settype != SHPType[WPs][dim-2]) {
631 RETURNINT(-2)
632 }
633
634 #ifdef DEBUG
635 if (dim == 3)
636 printf("W\t%s\t%s\t%s\t%lf\t%lf\t%lf\n",name,commt,date,x,y,z);
637 else
638 printf("W\t%s\t%s\t%s\t%lf\t%lf\n",name,commt,date,x,y);
639 #endif
640
641 if ((pwpo=SHPCreateSimpleObject(p->settype,1,&x,&y,&z)) == NULL) {
642 RETURNINT(-3)
643 }
644 entno = SHPWriteObject(p->SHPFile,-1,pwpo);
645 SHPDestroyObject(pwpo);
646 df = p->DBFFile;
647 if (DBFWriteStringAttribute(df,entno,p->field[0],name) == 0 ||
648 DBFWriteStringAttribute(df,entno,p->field[1],commt) == 0 ||
649 DBFWriteStringAttribute(df,entno,p->field[2],date) == 0) {
650 RETURNINT(-4)
651 }
652 RETURNINT(1)
653 }
654
GSHPCreateRT(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])655 int GSHPCreateRT(ClientData clientData,Tcl_Interp *interp,
656 int objc,Tcl_Obj *CONST objv[])
657 /* GSHPCreateRT DIM RTID COMMENT */
658 { char *name, *commt;
659 int dim;
660
661 #ifdef DEBUG
662 printf(">GSHPCreateRT, %d args\n",objc-1);
663 #endif
664
665 CHECKPARAMNO(3,"DIM RTID COMMENT")
666 GETINTPARAM(1,dim)
667 if (dim < 2 || dim > 3) {
668 RETURNINT(-1)
669 }
670 name = GETSTRINGPARAM(2) commt = GETSTRINGPARAM(3)
671 if (RTBuilding) {
672 RETURNINT(0)
673 }
674 RTBuilding = 1;
675 cpstrclean(name,RT.rtid,RTIDWD);
676 cpstrclean(commt,RT.rtcommt,RTCOMMTWD);
677 RT.rtwps = NULL; RT.rtxs = NULL; RT.rtys = NULL; RT.rtzs = NULL;
678 RT.rtdim = dim;
679 RTLgth = 0;
680 RETURNINT(1)
681 }
682
forgetRT()683 void forgetRT()
684 { WPLIST p, q;
685
686 RTBuilding = 0;
687 p = RT.rtwps;
688 while (p != NULL) {
689 q = p; p = p->wpnext; free(q);
690 }
691 if (RT.rtxs != NULL) {
692 free(RT.rtxs); free(RT.rtys); free(RT.rtzs);
693 }
694 }
695
GSHPForgetRT(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])696 int GSHPForgetRT(ClientData clientData,Tcl_Interp *interp,
697 int objc,Tcl_Obj *CONST objv[])
698 /* GSHPForgetRT */
699 {
700 #ifdef DEBUG
701 printf(">GSHPForgetRT, %d args\n",objc-1);
702 #endif
703
704 CHECKPARAMNO(0,NULL)
705 if (! RTBuilding) {
706 RETURNINT(0)
707 }
708 forgetRT();
709 RETURNINT(1)
710 }
711
GSHPAddWPToRT(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])712 int GSHPAddWPToRT(ClientData clientData,Tcl_Interp *interp,
713 int objc,Tcl_Obj *CONST objv[])
714 /* GSHPAddWPToRT X Y ?Z? */
715 { double x, y, z;
716 WPLIST wpp;
717 int dim;
718
719 #ifdef DEBUG
720 printf(">GSHPAddWPToRT, %d args\n",objc-1);
721 #endif
722
723 CHECKPARAMNOS(2,3,"X Y ?Z?")
724 dim = objc-1;
725 GETDOUBLEPARAM(1,x) GETDOUBLEPARAM(2,y)
726 if (dim == 3) {
727 GETDOUBLEPARAM(3,z)
728 } else z = 0;
729 if (! RTBuilding || dim != RT.rtdim) {
730 RETURNINT(-1)
731 }
732 if ((wpp=(WPLIST) malloc(sizeof(WPDATA))) == NULL) {
733 RETURNINT(-2)
734 }
735 wpp->wpx = x; wpp->wpy = y; wpp->wpz = z;
736 wpp->wpnext = NULL;
737 if (RTLgth++) RTLastWP->wpnext = wpp;
738 else RT.rtwps = wpp;
739 if (RT.rtxs != NULL) {
740 free(RT.rtxs); free(RT.rtys); free(RT.rtzs);
741 RT.rtxs = NULL;
742 }
743 RTLastWP = wpp;
744 RETURNINT(1)
745 }
746
GSHPWriteRT(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])747 int GSHPWriteRT(ClientData clientData,Tcl_Interp *interp,
748 int objc,Tcl_Obj *CONST objv[])
749 /* GSHPWriteRT ID FORGET */
750 { SHPFSETLIST p;
751 int id, forget, entno, i, dim;
752 WPLIST wpp;
753 SHPObject *prto;
754 DBFHandle df;
755
756 #ifdef DEBUG
757 printf(">GSHPWriteRT, %d args\n",objc-1);
758 #endif
759
760 CHECKPARAMNO(2,"FILES_ID FORGET")
761 GETINTPARAM(1,id) GETINTPARAM(2,forget)
762 if (! RTBuilding) {
763 RETURNINT(-1)
764 }
765 if (RTLgth == 0) {
766 RETURNINT(-2)
767 }
768 if ((p=findset(id)) == NULL || p->input) {
769 RETURNINT(-3)
770 }
771 dim = RT.rtdim;
772 if (p->settype != SHPType[RTs][dim-2]) {
773 RETURNINT(-4)
774 }
775
776 #ifdef DEBUG
777 printf("R\t%s\t%s\n",RT.rtid,RT.rtcommt);
778 wpp = RT.rtwps;
779 while (wpp != NULL) {
780 if (dim == 2)
781 printf("W\t\t\t\t%lf\t%lf\n",wpp->wpx,wpp->wpy);
782 else printf("W\t\t\t\t%lf\t%lf\t%lf\n",wpp->wpx,wpp->wpy,wpp->wpz);
783 wpp = wpp->wpnext;
784 }
785 #endif
786
787 if (RT.rtxs == NULL) {
788 if ((RT.rtxs=(double *) malloc(RTLgth*sizeof(double))) == NULL) {
789 RETURNINT(-5)
790 }
791 if ((RT.rtys=(double *) malloc(RTLgth*sizeof(double))) == NULL ||
792 (dim == 3 &&
793 (RT.rtzs=(double *) malloc(RTLgth*sizeof(double))) == NULL)) {
794 free(RT.rtxs); free(RT.rtys);
795 RT.rtxs = NULL;
796 RETURNINT(-5)
797 }
798 wpp = RT.rtwps;
799 for(i=0; wpp != NULL; i++) {
800 RT.rtxs[i] = wpp->wpx; RT.rtys[i] = wpp->wpy;
801 if (dim == 3) RT.rtzs[i] = wpp->wpz;
802 wpp = wpp->wpnext;
803 }
804 }
805 if ((prto=SHPCreateObject(p->settype,RTCount,0,NULL,NULL,RTLgth,
806 RT.rtxs,RT.rtys,RT.rtzs,NULL)) == NULL) {
807 RETURNINT(-5)
808 }
809 entno = SHPWriteObject(p->SHPFile,-1,prto);
810 SHPDestroyObject(prto);
811 RTCount++;
812
813 df = p->DBFFile;
814 if (DBFWriteStringAttribute(df,entno,p->field[0],RT.rtid) == 0 ||
815 DBFWriteStringAttribute(df,entno,p->field[1],RT.rtcommt) == 0) {
816 RETURNINT(-6)
817 }
818 if (forget) forgetRT();
819 RETURNINT(1)
820 }
821
GSHPCreateTR(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])822 int GSHPCreateTR(ClientData clientData,Tcl_Interp *interp,
823 int objc,Tcl_Obj *CONST objv[])
824 /* GSHPCreateTR DIM NAME COMMENT */
825 { char *name, *commt;
826 int dim, nsegs, *segstarts, *segnxt, i, k, kp;
827 Tcl_Obj **objvPtr;
828
829 #ifdef DEBUG
830 printf(">GSHPCreateTR, %d args\n",objc-1);
831 #endif
832
833 CHECKPARAMNOS(3,4,"DIM NAME COMMENT ?SEGSTARTERS?")
834 GETINTPARAM(1,dim)
835 if (dim < 2 || dim > 3) {
836 RETURNINT(-1)
837 }
838 if (TRBuilding) {
839 RETURNINT(0)
840 }
841 name = GETSTRINGPARAM(2) commt = GETSTRINGPARAM(3)
842 kp = 0;
843 if (objc-1 == 3) {
844 nsegs = 0; segstarts = NULL;
845 } else {
846 if (Tcl_ListObjGetElements(interp,objv[4],&nsegs,&objvPtr) != TCL_OK)
847 return TCL_ERROR;
848 #ifdef DEBUG
849 printf(">GSHPCreateTR, %d segs\n",nsegs);
850 #endif
851 if (nsegs == 0) {
852 segstarts = NULL;
853 } else {
854 if ((segstarts = (int *) malloc(++nsegs*sizeof(int))) == NULL) {
855 RETURNINT(-2)
856 }
857 #ifdef DEBUG
858 printf(">GSHPCreateTR, memory allocated for %d segs\n",nsegs);
859 #endif
860 segnxt = segstarts;
861 // make sure 0 is the first one
862 *segnxt++ = 0;
863 for (i=1; i<nsegs; i++) {
864 if (Tcl_GetIntFromObj(interp,*objvPtr,&k) != TCL_OK || k <= kp) {
865 free(segstarts);
866 RETURNINT(-3)
867 }
868 #ifdef DEBUG
869 printf(">GSHPCreateTR, adding %d seg start\n",k);
870 #endif
871 objvPtr++;
872 *segnxt++ = kp = k;
873 }
874 }
875 }
876 TRBuilding = 1;
877 cpstrclean(name,TR.trname,TRNAMEWD);
878 cpstrclean(commt,TR.trcommt,TRCOMMTWD);
879 TR.trnsegs = nsegs; TR.trsegstarts = segstarts; TR.trsegsmax = kp;
880 TR.trpts = NULL; TR.trxs = NULL; TR.trys = NULL; TR.trzs = NULL;
881 TR.trdim = dim;
882 TRLgth = 0;
883 RETURNINT(1)
884 }
885
forgetTR()886 void forgetTR()
887 { TPLIST p, q;
888
889 TRBuilding = 0;
890 p = TR.trpts;
891 while (p != NULL) {
892 q = p; p = p->tpnext; free(q);
893 }
894 if (TR.trnsegs != 0) free(TR.trsegstarts);
895 if (TR.trxs != NULL) {
896 free(TR.trxs); free(TR.trys); free(TR.trzs);
897 }
898 }
899
GSHPForgetTR(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])900 int GSHPForgetTR(ClientData clientData,Tcl_Interp *interp,
901 int objc,Tcl_Obj *CONST objv[])
902 /* GSHPForgetTR */
903 {
904 #ifdef DEBUG
905 printf(">GSHPForgetTR, %d args\n",objc-1);
906 #endif
907
908 CHECKPARAMNO(0,NULL)
909 if (! TRBuilding) {
910 RETURNINT(0)
911 }
912 forgetTR();
913 RETURNINT(1)
914 }
915
GSHPAddTPToTR(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])916 int GSHPAddTPToTR(ClientData clientData,Tcl_Interp *interp,
917 int objc,Tcl_Obj *CONST objv[])
918 /* GSHPAddTPToTR X Y ?Z? */
919 { double x, y, z;
920 TPLIST tpp;
921 int dim;
922
923 #ifdef DEBUG
924 printf(">GSHPAddTPToTR, %d args\n",objc-1);
925 #endif
926
927 CHECKPARAMNOS(2,3,"X Y ?Z?")
928 dim = objc-1;
929 GETDOUBLEPARAM(1,x) GETDOUBLEPARAM(2,y)
930 if (dim == 3) {
931 GETDOUBLEPARAM(3,z)
932 } else z = 0;
933 if (! TRBuilding || TR.trdim != dim) {
934 RETURNINT(-1)
935 }
936 if ((tpp=(TPLIST) malloc(sizeof(TPDATA))) == NULL) {
937 RETURNINT(-2)
938 }
939 tpp->tpx = x; tpp->tpy = y; tpp->tpz = z;
940 tpp->tpnext = NULL;
941 if (TRLgth++) TRLastTP->tpnext = tpp;
942 else TR.trpts = tpp;
943 if (TR.trxs != NULL) {
944 free(TR.trxs); free(TR.trys); free(TR.trzs);
945 TR.trxs = NULL;
946 }
947 TRLastTP = tpp;
948 RETURNINT(1)
949 }
950
GSHPWriteTR(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])951 int GSHPWriteTR(ClientData clientData,Tcl_Interp *interp,
952 int objc,Tcl_Obj *CONST objv[])
953 /* GSHPWriteTR ID FORGET */
954 { SHPFSETLIST p;
955 int id, forget, entno, i, dim;
956 TPLIST tpp;
957 SHPObject *ptro;
958 DBFHandle df;
959
960 #ifdef DEBUG
961 int *segs, nsegs, k;
962 printf(">GSHPWriteTR, %d args\n",objc-1);
963 #endif
964
965 CHECKPARAMNO(2,"FILES_ID FORGET")
966 GETINTPARAM(1,id) GETINTPARAM(2,forget)
967 if (! TRBuilding) {
968 RETURNINT(-1)
969 }
970 if (TRLgth == 0) {
971 RETURNINT(-2)
972 }
973 if (TRLgth-1 < TR.trsegsmax) {
974 RETURNINT(-7)
975 }
976 if ((p=findset(id)) == NULL || p->input) {
977 RETURNINT(-3)
978 }
979 dim = TR.trdim;
980 if (p->settype != SHPType[TRs][dim-2]) {
981 RETURNINT(-4)
982 }
983
984 #ifdef DEBUG
985 printf("TR\t%s\t%s\t%d\n",TR.trname,TR.trcommt,TR.trnsegs);
986 tpp = TR.trpts; i = 0;
987 if ((nsegs = TR.trnsegs) == 0)
988 k = -1;
989 else {
990 segs = TR.trsegstarts;
991 k = *segs++;
992 }
993 while (tpp != NULL) {
994 if (dim == 3)
995 printf("T\t\t%lf\t%lf\t%lf",tpp->tpx,tpp->tpy,tpp->tpz);
996 else printf("T\t\t%lf\t%lf",tpp->tpx,tpp->tpy);
997 tpp = tpp->tpnext;
998 if (i++ == k) {
999 printf("\t; segment starter\n");
1000 if (--nsegs == 0)
1001 k = -1;
1002 else k = *segs++;
1003 } else putchar('\n');
1004 }
1005 #endif
1006
1007 if (TR.trxs == NULL) {
1008 if ((TR.trxs=(double *) malloc(TRLgth*sizeof(double))) == NULL) {
1009 RETURNINT(-5)
1010 }
1011 if ((TR.trys=(double *) malloc(TRLgth*sizeof(double))) == NULL ||
1012 (dim == 3 &&
1013 (TR.trzs=(double *) malloc(TRLgth*sizeof(double))) == NULL)) {
1014 free(TR.trxs); free(TR.trys);
1015 TR.trxs = NULL;
1016 RETURNINT(-5)
1017 }
1018 tpp = TR.trpts;
1019 for(i=0; tpp != NULL; i++) {
1020 TR.trxs[i] = tpp->tpx; TR.trys[i] = tpp->tpy;
1021 if (dim == 3) TR.trzs[i] = tpp->tpz;
1022 tpp = tpp->tpnext;
1023 }
1024 }
1025 if ((ptro=SHPCreateObject(p->settype,TRCount,TR.trnsegs,TR.trsegstarts,NULL,
1026 TRLgth,TR.trxs,TR.trys,TR.trzs,NULL)) == NULL) {
1027 RETURNINT(-5)
1028 }
1029 entno = SHPWriteObject(p->SHPFile,-1,ptro);
1030 SHPDestroyObject(ptro);
1031 TRCount++;
1032
1033 df = p->DBFFile;
1034 if (DBFWriteStringAttribute(df,entno,p->field[0],TR.trname) == 0 ||
1035 DBFWriteStringAttribute(df,entno,p->field[1],TR.trcommt) == 0) {
1036 RETURNINT(-6)
1037 }
1038 if (forget) forgetTR();
1039 RETURNINT(1)
1040 }
1041
1042 /* Tcl interface */
1043
1044 int Gpsmanshp_Init(Tcl_Interp *interp);
1045
Tclgpsmanshp_Init(Tcl_Interp * interp)1046 int Tclgpsmanshp_Init(Tcl_Interp *interp)
1047 {
1048 return Gpsmanshp_Init(interp);
1049 }
1050
Gpsmanshp_Init(Tcl_Interp * interp)1051 int Gpsmanshp_Init(Tcl_Interp *interp)
1052 {
1053 Tcl_CreateObjCommand(interp,"GSHPCreateFiles",GSHPCreateFiles,
1054 (ClientData)NULL,NULL);
1055 Tcl_CreateObjCommand(interp,"GSHPOpenInputFiles",GSHPOpenInputFiles,
1056 (ClientData)NULL,NULL);
1057 Tcl_CreateObjCommand(interp,"GSHPInfoFrom",GSHPInfoFrom,
1058 (ClientData)NULL,NULL);
1059 Tcl_CreateObjCommand(interp,"GSHPGetObj",GSHPGetObj,
1060 (ClientData)NULL,NULL);
1061 Tcl_CreateObjCommand(interp,"GSHPReadNextPoint",GSHPReadNextPoint,
1062 (ClientData)NULL,NULL);
1063 Tcl_CreateObjCommand(interp,"GSHPCloseFiles",GSHPCloseFiles,
1064 (ClientData)NULL,NULL);
1065 Tcl_CreateObjCommand(interp,"GSHPWriteWP",GSHPWriteWP,
1066 (ClientData)NULL,NULL);
1067 Tcl_CreateObjCommand(interp,"GSHPCreateRT",GSHPCreateRT,
1068 (ClientData)NULL,NULL);
1069 Tcl_CreateObjCommand(interp,"GSHPForgetRT",GSHPForgetRT,
1070 (ClientData)NULL,NULL);
1071 Tcl_CreateObjCommand(interp,"GSHPAddWPToRT",GSHPAddWPToRT,
1072 (ClientData)NULL,NULL);
1073 Tcl_CreateObjCommand(interp,"GSHPWriteRT",GSHPWriteRT,(ClientData)NULL,NULL);
1074 Tcl_CreateObjCommand(interp,"GSHPCreateTR",GSHPCreateTR,
1075 (ClientData)NULL,NULL);
1076 Tcl_CreateObjCommand(interp,"GSHPForgetTR",GSHPForgetTR,
1077 (ClientData)NULL,NULL);
1078 Tcl_CreateObjCommand(interp,"GSHPAddTPToTR",GSHPAddTPToTR,
1079 (ClientData)NULL,NULL);
1080 Tcl_CreateObjCommand(interp,"GSHPWriteTR",GSHPWriteTR,(ClientData)NULL,NULL);
1081
1082 Tcl_PkgProvide(interp,"gpsmanshp",VERSION);
1083 return TCL_OK;
1084 }
1085
1086