1 /* **************************************************************
2  *
3  *  MODULE:       v.in.dwg
4  *
5  *  AUTHOR(S):    Radim Blazek
6  *
7  *  PURPOSE:      Import of DWG/DXF files
8  *
9  *  COPYRIGHT:    (C) 2001 by the GRASS Development Team
10  *
11  *                This program is free software under the
12  *                GNU General Public License (>=v2).
13  *                Read the file COPYING that comes with GRASS
14  *                for details.
15  *
16  * In addition, as a special exception, Radim Blazek gives permission
17  * to link the code of this program with the OpenDWG libraries (or with
18  * modified versions of the OpenDWG libraries that use the same license
19  * as OpenDWG libraries), and distribute linked combinations including the two.
20  * You must obey the GNU General Public License in all respects for all
21  * of the code used other than. If you modify this file, you may extend
22  * this exception to your version of the file, but you are not obligated
23  * to do so. If you do not wish to do so, delete this exception statement
24  * from your version.
25  *
26  * **************************************************************/
27 
28 /* Documentation:
29  * http://www.opendwg.org
30  * -> OpenDWG Toolkit Reference
31  *
32  * Unsupported entities must be added in wrentity()
33  *
34  * TODO: 3rd dimension is not functional for CIRCLE and ARC
35  *       -> required updated of transformation in INSERT
36  *          (how to do that??)
37  */
38 
39 #define AD_PROTOTYPES
40 #define AD_VM_PC
41 
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <math.h>
46 #include <fcntl.h>
47 #include <unistd.h>
48 #include <grass/gis.h>
49 #include <grass/dbmi.h>
50 #include <grass/vector.h>
51 #include "ad2.h"
52 #include "global.h"
53 
54 #define exampleprintf printf
55 #define LOCPI M_PI
56 
57 char buf[1000];
58 char buf2[1000];
59 
getEntTypeName(PAD_ENT_HDR adenhd,char * name)60 void getEntTypeName(PAD_ENT_HDR adenhd, char *name)
61 {
62     switch (adenhd->enttype) {
63     case AD_ENT_LINE:
64 	strcpy(name, "LINE");
65 	break;
66     case AD_ENT_POINT:
67 	strcpy(name, "POINT");
68 	break;
69     case AD_ENT_CIRCLE:
70 	strcpy(name, "CIRCLE");
71 	break;
72     case AD_ENT_SHAPE:
73 	strcpy(name, "SHAPE");
74 	break;
75     case AD_ENT_ELLIPSE:
76 	strcpy(name, "ELLIPSE");
77 	break;
78     case AD_ENT_SPLINE:
79 	strcpy(name, "SPLINE");
80 	break;
81     case AD_ENT_TEXT:
82 	strcpy(name, "TEXT");
83 	break;
84     case AD_ENT_ARC:
85 	strcpy(name, "ARC");
86 	break;
87     case AD_ENT_TRACE:
88 	strcpy(name, "TRACE");
89 	break;
90     case AD_ENT_SOLID:
91 	strcpy(name, "SOLID");
92 	break;
93     case AD_ENT_BLOCK:
94 	strcpy(name, "BLOCK");
95 	break;
96     case AD_ENT_ENDBLK:
97 	strcpy(name, "ENDBLK");
98 	break;
99     case AD_ENT_INSERT:
100 	strcpy(name, "INSERT");
101 	break;
102     case AD_ENT_ATTDEF:
103 	strcpy(name, "ATTDEF");
104 	break;
105     case AD_ENT_ATTRIB:
106 	strcpy(name, "ATTRIB");
107 	break;
108     case AD_ENT_SEQEND:
109 	strcpy(name, "SEQEND");
110 	break;
111     case AD_ENT_POLYLINE:
112 	strcpy(name, "POLYLINE");
113 	break;
114     case AD_ENT_VERTEX:
115 	strcpy(name, "VERTEX");
116 	break;
117     case AD_ENT_LINE3D:
118 	strcpy(name, "3DLINE");
119 	break;
120     case AD_ENT_FACE3D:
121 	strcpy(name, "3DFACE");
122 	break;
123     case AD_ENT_DIMENSION:
124 	strcpy(name, "DIMENSION");
125 	break;
126     case AD_ENT_VIEWPORT:
127 	strcpy(name, "VIEWPORT");
128 	break;
129     case AD_ENT_SOLID3D:
130 	strcpy(name, "SOLID3D");
131 	break;
132     case AD_ENT_RAY:
133 	strcpy(name, "RAY");
134 	break;
135     case AD_ENT_XLINE:
136 	strcpy(name, "XLINE");
137 	break;
138     case AD_ENT_MTEXT:
139 	strcpy(name, "MTEXT");
140 	break;
141     case AD_ENT_LEADER:
142 	strcpy(name, "LEADER");
143 	break;
144     case AD_ENT_TOLERANCE:
145 	strcpy(name, "TOLERANCE");
146 	break;
147     case AD_ENT_MLINE:
148 	strcpy(name, "MLINE");
149 	break;
150     case AD_ENT_BODY:
151 	strcpy(name, "BODY");
152 	break;
153     case AD_ENT_REGION:
154 	strcpy(name, "REGION");
155 	break;
156     default:
157 	if (adenhd->enttype == adOle2frameEnttype(dwghandle))
158 	    strcpy(name, "OLE2FRAME");
159 	else if (adenhd->enttype == adLwplineEnttype(dwghandle))
160 	    strcpy(name, "LWPOLYLINE");
161 	else if (adenhd->enttype == adHatchEnttype(dwghandle))
162 	    strcpy(name, "HATCH");
163 	else if (adenhd->enttype == adImageEnttype(dwghandle))
164 	    strcpy(name, "IMAGE");
165 	else if (adenhd->enttype == adArcAlignedTextEnttype(dwghandle))
166 	    strcpy(name, "ArcAlignedText");
167 	else if (adenhd->enttype == adWipeoutEnttype(dwghandle))
168 	    strcpy(name, "Wipeout");
169 	else if (adenhd->enttype == adRtextEnttype(dwghandle))
170 	    strcpy(name, "Rtext");
171 	else {			/* regular proxy */
172 
173 	    G_debug(3, "adenhd->enttype: %d", adenhd->enttype);
174 	    strcpy(name, "Proxy");
175 	}
176 	break;
177     }
178 }
179 
write_line(PAD_ENT_HDR adenhd,int type,int level)180 int write_line(PAD_ENT_HDR adenhd, int type, int level)
181 {
182     int i, l;
183     double x, y, z, r, ang;
184 
185     adSeekLayer(dwghandle, adenhd->entlayerobjhandle, Layer);
186 
187     /* Transformation, go up through all levels of transformation */
188     /* not sure what is the right order of transformation */
189     for (l = level; l >= 0; l--) {
190 	for (i = 0; i < Points->n_points; i++) {
191 	    /* scale */
192 	    x = Points->x[i] * Trans[l].xscale;
193 	    y = Points->y[i] * Trans[l].yscale;
194 	    z = Points->z[i] * Trans[l].zscale;
195 	    /* rotate */
196 	    r = sqrt(x * x + y * y);
197 	    ang = atan2(y, x) + Trans[l].rotang;
198 	    x = r * cos(ang);
199 	    y = r * sin(ang);
200 	    /* move */
201 	    x += Trans[l].dx;
202 	    y += Trans[l].dy;
203 	    z += Trans[l].dz;
204 	    Points->x[i] = x;
205 	    Points->y[i] = y;
206 	    Points->z[i] = z;
207 	}
208     }
209 
210     Vect_reset_cats(Cats);
211     Vect_cat_set(Cats, 1, cat);
212     Vect_write_line(&Map, type, Points, Cats);
213 
214     /* Cat */
215     sprintf(buf, "insert into %s values ( %d", Fi->table, cat);
216     db_set_string(&sql, buf);
217 
218     /* Entity name */
219     getEntTypeName(adenhd, buf2);
220     sprintf(buf, ", '%s'", buf2);
221     db_append_string(&sql, buf);
222 
223     /* Color */
224     sprintf(buf, ", %d", adenhd->entcolor);
225     db_append_string(&sql, buf);
226 
227     /* Weight */
228     sprintf(buf, ", %d", adenhd->lineweight);
229     db_append_string(&sql, buf);
230 
231     /* Layer name */
232     if (!Layer->purgedflag && Layer->name != NULL) {
233 	db_set_string(&str, Layer->name);
234 	db_double_quote_string(&str);
235 	sprintf(buf, ", '%s'", db_get_string(&str));
236     }
237     else {
238 	sprintf(buf, ", ''");
239     }
240     db_append_string(&sql, buf);
241 
242     /* Block name */
243     if (Block != NULL) {
244 	db_set_string(&str, Block);
245 	db_double_quote_string(&str);
246     }
247     else {
248 	db_set_string(&str, "");
249     }
250     sprintf(buf, ", '%s'", db_get_string(&str));
251     db_append_string(&sql, buf);
252 
253     /* Text */
254     if (Txt != NULL) {
255 	db_set_string(&str, Txt);
256 	db_double_quote_string(&str);
257     }
258     else {
259 	db_set_string(&str, "");
260     }
261     sprintf(buf, ", '%s'", db_get_string(&str));
262     db_append_string(&sql, buf);
263 
264     db_append_string(&sql, ")");
265     G_debug(3, db_get_string(&sql));
266 
267     if (db_execute_immediate(driver, &sql) != DB_OK) {
268 	db_close_database(driver);
269 	db_shutdown_driver(driver);
270 	G_fatal_error("Cannot insert new row: %s", db_get_string(&sql));
271     }
272 
273     cat++;
274     return 0;
275 }
276 
277 /* Returns 1 if element has geometry and may be written to vector */
is_low_level(PAD_ENT_HDR adenhd)278 int is_low_level(PAD_ENT_HDR adenhd)
279 {
280     if (adenhd->enttype == AD_ENT_BLOCK || adenhd->enttype == AD_ENT_ENDBLK ||
281 	adenhd->enttype == AD_ENT_SEQEND || adenhd->enttype == AD_ENT_INSERT)
282     {
283 	return 0;
284     }
285     return 1;
286 }
287 
wrentity(PAD_ENT_HDR adenhd,PAD_ENT aden,int level,AD_VMADDR entlist,int circle_as_point)288 void wrentity(PAD_ENT_HDR adenhd, PAD_ENT aden, int level, AD_VMADDR entlist,
289 	      int circle_as_point)
290 {
291     short ret;
292     PAD_BLOB_CTRL bcptr;
293     PAD_ENT_HDR adenhd2;
294     PAD_ENT aden2;
295     OdaLong il;
296     double tempdouble[3], tempbulge, tempwidth[3];
297     double x, y, z, ang;
298     PAD_BLKH adblkh;
299     int layer_found = 1;
300 
301     if (is_low_level(adenhd))
302 	n_elements++;
303 
304     /* Check layer name */
305     if (layers_opt->answers) {
306 	int i = 0;
307 
308 	adSeekLayer(dwghandle, adenhd->entlayerobjhandle, Layer);
309 
310 	layer_found = 0;
311 	if (!Layer->purgedflag) {
312 	    while (layers_opt->answers[i]) {
313 		if (strcmp(Layer->name, layers_opt->answers[i]) == 0) {
314 		    layer_found = 1;
315 		    break;
316 		}
317 		i++;
318 	    }
319 	}
320 
321 	if ((!invert_flag->answer && !layer_found) ||
322 	    (invert_flag->answer && layer_found)) {
323 	    if (is_low_level(adenhd))
324 		n_skipped++;
325 	    if (adenhd->enttype != AD_ENT_INSERT &&
326 		adenhd->enttype != AD_ENT_POLYLINE)
327 		return;
328 	}
329     }
330 
331     getEntTypeName(adenhd, buf);
332     G_debug(1, "Entity: %s", buf);
333 
334     Txt = NULL;
335     adenhd2 = (PAD_ENT_HDR) G_malloc(sizeof(AD_ENT_HDR));
336     aden2 = (PAD_ENT) G_malloc(sizeof(AD_ENT));
337     adblkh = (PAD_BLKH) G_malloc(sizeof(AD_BLKH));
338     Vect_reset_line(Points);
339 
340     /* Check space for lower level */
341     if (level + 1 == atrans) {
342 	atrans += 10;
343 	Trans = (TRANS *) G_realloc(Trans, atrans * sizeof(TRANS));
344     }
345 
346     switch (adenhd->enttype) {
347     case AD_ENT_LINE:
348 	Vect_append_point(Points, aden->line.pt0[0], aden->line.pt0[1],
349 			  aden->line.pt0[2]);
350 	Vect_append_point(Points, aden->line.pt1[0], aden->line.pt1[1],
351 			  aden->line.pt1[2]);
352 	write_line(adenhd, GV_LINE, level);
353 	break;
354 
355     case AD_ENT_FACE3D:
356 	Vect_append_point(Points, aden->face3d.pt0[0], aden->face3d.pt0[1],
357 			  aden->face3d.pt0[2]);
358 	Vect_append_point(Points, aden->face3d.pt1[0], aden->face3d.pt1[1],
359 			  aden->face3d.pt1[2]);
360 	Vect_append_point(Points, aden->face3d.pt2[0], aden->face3d.pt2[1],
361 			  aden->face3d.pt2[2]);
362 	Vect_append_point(Points, aden->face3d.pt3[0], aden->face3d.pt3[1],
363 			  aden->face3d.pt3[2]);
364 	write_line(adenhd, GV_FACE, level);
365 	break;
366 
367     case AD_ENT_SOLID:
368 	Vect_append_point(Points, aden->solid.pt0[0], aden->solid.pt0[1],
369 			  aden->solid.pt0[2]);
370 	Vect_append_point(Points, aden->solid.pt1[0], aden->solid.pt1[1],
371 			  aden->solid.pt1[2]);
372 	Vect_append_point(Points, aden->solid.pt2[0], aden->solid.pt2[1],
373 			  aden->solid.pt2[2]);
374 	Vect_append_point(Points, aden->solid.pt3[0], aden->solid.pt3[1],
375 			  aden->solid.pt3[2]);
376 	write_line(adenhd, GV_FACE, level);
377 	break;
378 
379     case AD_ENT_TEXT:
380 	Txt = aden->text.textstr;
381 	Vect_append_point(Points, aden->text.pt0[0], aden->text.pt0[1],
382 			  aden->line.pt0[2]);
383 	write_line(adenhd, GV_POINT, level);
384 	break;
385 
386 
387     case AD_ENT_POINT:
388 	Vect_append_point(Points, aden->point.pt0[0], aden->point.pt0[1],
389 			  aden->line.pt0[2]);
390 	write_line(adenhd, GV_POINT, level);
391 	break;
392 
393     case AD_ENT_ARC:
394 	for (ang = aden->arc.stang; ang < aden->arc.endang;
395 	     ang += 2 * LOCPI / 360) {
396 	    x = aden->arc.pt0[0] + aden->arc.radius * cos(ang);
397 	    y = aden->arc.pt0[1] + aden->arc.radius * sin(ang);
398 	    z = aden->arc.pt0[2];
399 	    Vect_append_point(Points, x, y, z);
400 	}
401 	x = aden->arc.pt0[0] + aden->arc.radius * cos(aden->arc.endang);
402 	y = aden->arc.pt0[1] + aden->arc.radius * sin(aden->arc.endang);
403 	z = aden->arc.pt0[2];
404 	Vect_append_point(Points, x, y, z);
405 	write_line(adenhd, GV_LINE, level);
406 	break;
407 
408     case AD_ENT_CIRCLE:
409 	if (circle_as_point) {
410 	    Vect_append_point(Points, aden->circle.pt0[0],
411 			      aden->circle.pt0[1], aden->circle.pt0[3]);
412 	    write_line(adenhd, GV_POINT, level);
413 	}
414 	else {
415 	    for (ang = 0; ang < 2 * LOCPI; ang += 2 * LOCPI / 360) {
416 		x = aden->circle.pt0[0] + aden->circle.radius * cos(ang);
417 		y = aden->circle.pt0[1] + aden->circle.radius * sin(ang);
418 		z = aden->circle.pt0[3];
419 		Vect_append_point(Points, x, y, z);
420 	    }
421 	    Vect_append_point(Points, Points->x[0], Points->y[0],
422 			      Points->z[0]);
423 	    write_line(adenhd, GV_LINE, level);
424 	}
425 	break;
426 
427 	/* BLOCK starts block of entities but makes no transformation - is it right ?
428 	 *  -> do nothing just warn for xref */
429     case AD_ENT_BLOCK:
430 	if (aden->block.xrefpath[0]) {
431 	    G_warning
432 		("External reference for block not supported.\n  xref: %s",
433 		 aden->block.xrefpath);
434 	}
435 	Block = G_store(aden->block.name2);
436 	break;
437 
438     case AD_ENT_ENDBLK:	/* endblk - no data */
439 	G_free(Block);
440 	Block = NULL;
441 	break;
442 
443     case AD_ENT_INSERT:	/* insert */
444 	/* get transformation */
445 	/* TODO: fix rotation for CIRCLE and ARC */
446 	G_debug(3, " x,y,z: %f, %f, %f", aden->insert.pt0[0],
447 		aden->insert.pt0[1], aden->insert.pt0[2]);
448 	G_debug(3, " xscale, yscale, zscale: %f, %f, %f", aden->insert.xscale,
449 		aden->insert.yscale, aden->insert.zscale);
450 	G_debug(3, " rotang: %f", aden->insert.rotang);
451 	G_debug(3, " ncols, nrows: %d, %d", aden->insert.numcols,
452 		aden->insert.numrows);
453 	G_debug(3, " coldist, rowdist: %f, %f", aden->insert.coldist,
454 		aden->insert.rowdist);
455 
456 	/* write block entities */
457 	adSeekBlockheader(dwghandle, aden->insert.blockheaderobjhandle,
458 			  adblkh);
459 	if (!adblkh->purgedflag) {
460 	    adStartEntityGet(adblkh->entitylist);
461 	    while (1) {
462 		ret = adGetEntity(adblkh->entitylist, adenhd2, aden2);
463 		if (adenhd2->enttype == AD_ENT_ENDBLK)
464 		    break;
465 		if (ret) {
466 		    /* Set transformation for lower level */
467 		    Trans[level + 1].dx = aden->insert.pt0[0];
468 		    Trans[level + 1].dy = aden->insert.pt0[1];
469 		    Trans[level + 1].dz = aden->insert.pt0[2];
470 		    Trans[level + 1].xscale = aden->insert.xscale;
471 		    Trans[level + 1].yscale = aden->insert.yscale;
472 		    Trans[level + 1].zscale = aden->insert.zscale;
473 		    Trans[level + 1].rotang = aden->insert.rotang;
474 		    wrentity(adenhd2, aden2, level + 1, adblkh->entitylist,
475 			     circle_as_point);
476 		}
477 	    }
478 	}
479 	break;
480 
481     case AD_ENT_SEQEND:	/* seqend */
482 	break;
483 
484     case AD_ENT_POLYLINE:
485 	while (1) {
486 	    ret = adGetEntity(entlist, adenhd2, aden2);
487 	    if (ret != 1) {
488 		G_warning("Cannot get entity: %d: %s.", adError(),
489 			  adErrorStr(adError()));
490 		break;
491 	    }
492 
493 	    if (adenhd2->enttype == AD_ENT_SEQEND)
494 		break;
495 	    if (adenhd2->enttype != AD_ENT_VERTEX) {
496 		getEntTypeName(adenhd2, buf);
497 		G_warning("Expected VERTEX got %s in POLYLINE -> skip", buf);
498 	    }
499 	    else {
500 		Vect_append_point(Points, aden2->vertex.pt0[0],
501 				  aden2->vertex.pt0[1], aden2->vertex.pt0[2]);
502 	    }
503 	};
504 	if ((!invert_flag->answer && layer_found) ||
505 	    (invert_flag->answer && !layer_found))
506 	    write_line(adenhd, GV_LINE, level);
507 	break;
508 
509     default:
510 	if (adenhd->enttype == adLwplineEnttype(dwghandle)) {
511 	    G_debug(3, "Npoints: %ld\n", aden->lwpline.numpoints);
512 	    bcptr = adStartBlobRead(aden->lwpline.ldblob);
513 	    for (il = 0; il < aden->lwpline.numpoints; il++) {
514 		adReadBlob2Double(bcptr, tempdouble);
515 		Vect_append_point(Points, tempdouble[0], tempdouble[1],
516 				  tempdouble[2]);
517 		tempbulge = tempwidth[0] = tempwidth[1] = tempwidth[2] = 0.0;
518 		if (aden->lwpline.flag & AD_LWPLINE_HAS_BULGES) {
519 		    adReadBlobDouble(bcptr, &tempbulge);
520 		}
521 		if (aden->lwpline.flag & AD_LWPLINE_HAS_WIDTHS) {
522 		    adReadBlob2Double(bcptr, tempwidth);
523 		}
524 	    }
525 	    G_debug(3, "flag = %d", aden->lwpline.flag);
526 	    if (aden->lwpline.flag & AD_LWPLINE_IS_CLOSED) {
527 		G_debug(3, "  -> is closed");
528 		Vect_append_point(Points, Points->x[0], Points->y[0],
529 				  Points->z[0]);
530 	    }
531 	    write_line(adenhd, GV_LINE, level);
532 	    adEndBlobRead(bcptr);
533 	}
534 	else {
535 	    getEntTypeName(adenhd, buf);
536 	    G_warning("%s entity not supported", buf);
537 	}
538 	break;
539 
540     }				/* end of switch */
541 
542     G_free(aden2);
543     G_free(adenhd2);
544 }
545