1 /*
2 
3  dxf_writer.c -- implements DXF support
4  [exporting a DXF]
5 
6  version 5.0, 2020 August 1
7 
8  Author: Sandro Furieri a.furieri@lqt.it
9 
10  -----------------------------------------------------------------------------
11 
12  Version: MPL 1.1/GPL 2.0/LGPL 2.1
13 
14  The contents of this file are subject to the Mozilla Public License Version
15  1.1 (the "License"); you may not use this file except in compliance with
16  the License. You may obtain a copy of the License at
17  http://www.mozilla.org/MPL/
18 
19 Software distributed under the License is distributed on an "AS IS" basis,
20 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
21 for the specific language governing rights and limitations under the
22 License.
23 
24 The Original Code is the SpatiaLite library
25 
26 The Initial Developer of the Original Code is Alessandro Furieri
27 
28 Portions created by the Initial Developer are Copyright (C) 2008-2021
29 the Initial Developer. All Rights Reserved.
30 
31 Contributor(s):
32 
33 Alternatively, the contents of this file may be used under the terms of
34 either the GNU General Public License Version 2 or later (the "GPL"), or
35 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
36 in which case the provisions of the GPL or the LGPL are applicable instead
37 of those above. If you wish to allow use of your version of this file only
38 under the terms of either the GPL or the LGPL, and not to allow others to
39 use your version of this file under the terms of the MPL, indicate your
40 decision by deleting the provisions above and replace them with the notice
41 and other provisions required by the GPL or the LGPL. If you do not delete
42 the provisions above, a recipient may use your version of this file under
43 the terms of any one of the MPL, the GPL or the LGPL.
44 
45 */
46 
47 /*
48 
49 CREDITS:
50 
51 inital development of the DXF module has been funded by:
52 Regione Toscana - Settore Sistema Informativo Territoriale ed Ambientale
53 
54 */
55 
56 #include <stdlib.h>
57 #include <stdio.h>
58 #include <string.h>
59 
60 #if defined(_WIN32) && !defined(__MINGW32__)
61 #include "config-msvc.h"
62 #else
63 #include "config.h"
64 #endif
65 
66 #include <spatialite/sqlite.h>
67 #include <spatialite/debug.h>
68 
69 #include <spatialite/gaiageo.h>
70 #include <spatialite/gaiaaux.h>
71 #include <spatialite/gg_dxf.h>
72 #include <spatialite.h>
73 #include <spatialite_private.h>
74 
75 #include "dxf_private.h"
76 
77 #if defined(_WIN32) && !defined(__MINGW32__)
78 #define strcasecmp	_stricmp
79 #endif /* not WIN32 */
80 
81 GAIAGEO_DECLARE int
gaiaDxfWriterInit(gaiaDxfWriterPtr dxf,FILE * out,int precision,int version)82 gaiaDxfWriterInit (gaiaDxfWriterPtr dxf, FILE * out, int precision, int version)
83 {
84 /* initializing a DXF Output object */
85     if (dxf == NULL)
86 	return 0;
87     dxf->error = 0;
88     dxf->precision = precision;
89     if (precision < 0)
90 	dxf->precision = 0;
91     if (precision > 10)
92 	dxf->precision = 10;
93     if (version != GAIA_DXF_V12)
94 	dxf->error = 1;
95     else
96 	dxf->version = GAIA_DXF_V12;
97     if (out == NULL)
98 	dxf->error = 1;
99     else
100 	dxf->out = out;
101     dxf->count = 0;
102     return 1;
103 }
104 
105 GAIAGEO_DECLARE int
gaiaDxfWriteHeader(gaiaDxfWriterPtr dxf,double minx,double miny,double minz,double maxx,double maxy,double maxz)106 gaiaDxfWriteHeader (gaiaDxfWriterPtr dxf, double minx, double miny, double minz,
107 		    double maxx, double maxy, double maxz)
108 {
109 /* printing the DXF HEADER */
110     char format[128];
111     if (dxf == NULL)
112 	return 0;
113     if (dxf->error)
114 	return 0;
115     if (dxf->out == NULL)
116 	return 0;
117 
118     fprintf (dxf->out, "%3d\r\nSECTION\r\n%3d\r\nHEADER\r\n", 0, 2);
119     fprintf (dxf->out, "%3d\r\n$EXTMIN\r\n", 9);
120     sprintf (format,
121 	     "%%3d\r\n%%1.%df\r\n%%3d\r\n%%1.%df\r\n%%3d\r\n%%1.%df\r\n",
122 	     dxf->precision, dxf->precision, dxf->precision);
123     fprintf (dxf->out, format, 10, minx, 20, miny, 30, minz);
124     fprintf (dxf->out, "%3d\r\n$EXTMAX\r\n", 9);
125     sprintf (format,
126 	     "%%3d\r\n%%1.%df\r\n%%3d\r\n%%1.%df\r\n%%3d\r\n%%1.%df\r\n",
127 	     dxf->precision, dxf->precision, dxf->precision);
128     fprintf (dxf->out, format, 10, maxx, 20, maxy, 30, maxz);
129     fprintf (dxf->out, "%3d\r\nENDSEC\r\n", 0);
130     return 1;
131 }
132 
133 GAIAGEO_DECLARE int
gaiaDxfWriteTables(gaiaDxfWriterPtr dxf)134 gaiaDxfWriteTables (gaiaDxfWriterPtr dxf)
135 {
136 /* printing the DXF TABLES section header */
137     if (dxf == NULL)
138 	return 0;
139     if (dxf->error)
140 	return 0;
141     if (dxf->out == NULL)
142 	return 0;
143     fprintf (dxf->out, "%3d\r\nSECTION\r\n%3d\r\nTABLES\r\n", 0, 2);
144     return 1;
145 }
146 
147 GAIAGEO_DECLARE int
gaiaDxfWriteLayer(gaiaDxfWriterPtr dxf,const char * layer)148 gaiaDxfWriteLayer (gaiaDxfWriterPtr dxf, const char *layer)
149 {
150 /* printing a DXF TABLE/LAYER definition */
151     if (dxf == NULL)
152 	return 0;
153     if (dxf->error)
154 	return 0;
155     if (dxf->out == NULL)
156 	return 0;
157     fprintf (dxf->out, "%3d\r\nTABLE\r\n%3d\r\nLAYER\r\n", 0, 2);
158     fprintf (dxf->out, "%3d\r\n%3d\r\n%3d\r\nLAYER\r\n%3d\r\n%s\r\n", 70, 1, 0,
159 	     2, layer);
160     fprintf (dxf->out, "%3d\r\n%d\r\n%3d\r\n%d\r\n%3d\r\nCONTINUOUS\r\n", 70,
161 	     64, 62, 7, 6);
162     fprintf (dxf->out, "%3d\r\nENDTAB\r\n", 0);
163     return 1;
164 }
165 
166 GAIAGEO_DECLARE int
gaiaDxfWriteFooter(gaiaDxfWriterPtr dxf)167 gaiaDxfWriteFooter (gaiaDxfWriterPtr dxf)
168 {
169 /* printing the DXF footer */
170     if (dxf == NULL)
171 	return 0;
172     if (dxf->error)
173 	return 0;
174     if (dxf->out == NULL)
175 	return 0;
176     fprintf (dxf->out, "%3d\r\nEOF\r\n", 0);
177     return 1;
178 }
179 
180 GAIAGEO_DECLARE int
gaiaDxfWriteEntities(gaiaDxfWriterPtr dxf)181 gaiaDxfWriteEntities (gaiaDxfWriterPtr dxf)
182 {
183 /* printing the DXF ENTITIES section header */
184     if (dxf == NULL)
185 	return 0;
186     if (dxf->error)
187 	return 0;
188     if (dxf->out == NULL)
189 	return 0;
190     fprintf (dxf->out, "%3d\r\nSECTION\r\n%3d\r\nENTITIES\r\n", 0, 2);
191     return 1;
192 }
193 
194 GAIAGEO_DECLARE int
gaiaDxfWriteEndSection(gaiaDxfWriterPtr dxf)195 gaiaDxfWriteEndSection (gaiaDxfWriterPtr dxf)
196 {
197 /* printing a DXF ENDSEC */
198     if (dxf == NULL)
199 	return 0;
200     if (dxf->error)
201 	return 0;
202     if (dxf->out == NULL)
203 	return 0;
204     fprintf (dxf->out, "%3d\r\nENDSEC\r\n", 0);
205     return 1;
206 }
207 
208 GAIAGEO_DECLARE int
gaiaDxfWritePoint(gaiaDxfWriterPtr dxf,const char * layer,double x,double y,double z)209 gaiaDxfWritePoint (gaiaDxfWriterPtr dxf, const char *layer, double x, double y,
210 		   double z)
211 {
212 /* printing a DXF POINT */
213     char format[128];
214     if (dxf == NULL)
215 	return 0;
216     if (dxf->error)
217 	return 0;
218     if (dxf->out == NULL)
219 	return 0;
220     fprintf (dxf->out, "%3d\r\nPOINT\r\n%3d\r\n%s\r\n", 0, 8, layer);
221     sprintf (format,
222 	     "%%3d\r\n%%1.%df\r\n%%3d\r\n%%1.%df\r\n%%3d\r\n%%1.%df\r\n",
223 	     dxf->precision, dxf->precision, dxf->precision);
224     fprintf (dxf->out, format, 10, x, 20, y, 30, z);
225     dxf->count++;
226     return 1;
227 }
228 
229 GAIAGEO_DECLARE int
gaiaDxfWriteText(gaiaDxfWriterPtr dxf,const char * layer,double x,double y,double z,const char * label,double text_height,double angle)230 gaiaDxfWriteText (gaiaDxfWriterPtr dxf, const char *layer, double x, double y,
231 		  double z, const char *label, double text_height, double angle)
232 {
233 /* printing a DXF TEXT */
234     char format[128];
235     if (dxf == NULL)
236 	return 0;
237     if (dxf->error)
238 	return 0;
239     if (dxf->out == NULL)
240 	return 0;
241     fprintf (dxf->out, "%3d\r\nTEXT\r\n%3d\r\n%s\r\n", 0, 8, layer);
242     sprintf (format,
243 	     "%%3d\r\n%%1.%df\r\n%%3d\r\n%%1.%df\r\n%%3d\r\n%%1.%df\r\n",
244 	     dxf->precision, dxf->precision, dxf->precision);
245     fprintf (dxf->out, format, 10, x, 20, y, 30, z);
246     sprintf (format, "%%3d\r\n%%1.%df\r\n%%3d\r\n%%1.%df\r\n%%3d\r\n%%s\r\n",
247 	     dxf->precision, dxf->precision);
248     fprintf (dxf->out, format, 40, text_height, 50, angle, 1, label);
249     dxf->count++;
250     return 1;
251 }
252 
253 GAIAGEO_DECLARE int
gaiaDxfWriteLine(gaiaDxfWriterPtr dxf,const char * layer,gaiaLinestringPtr line)254 gaiaDxfWriteLine (gaiaDxfWriterPtr dxf, const char *layer,
255 		  gaiaLinestringPtr line)
256 {
257 /* printing a DXF POLYLINE (opened) */
258     int iv;
259     double x;
260     double y;
261     double z;
262     double m;
263     char format[128];
264     if (dxf == NULL)
265 	return 0;
266     if (dxf->error)
267 	return 0;
268     if (dxf->out == NULL)
269 	return 0;
270     fprintf (dxf->out, "%3d\r\nPOLYLINE\r\n%3d\r\n%s\r\n%3d\r\n%6d\r\n", 0, 8,
271 	     layer, 66, 1);
272     fprintf (dxf->out, "%3d\r\n%6d\r\n", 70, 0);
273     for (iv = 0; iv < line->Points; iv++)
274       {
275 	  /* exporting all vertices */
276 	  m = 0.0;
277 	  z = 0.0;
278 	  if (line->DimensionModel == GAIA_XY_Z)
279 	    {
280 		gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
281 	    }
282 	  else if (line->DimensionModel == GAIA_XY_M)
283 	    {
284 		gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
285 	    }
286 	  else if (line->DimensionModel == GAIA_XY_Z_M)
287 	    {
288 		gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
289 	    }
290 	  else
291 	    {
292 		gaiaGetPoint (line->Coords, iv, &x, &y);
293 	    }
294 	  fprintf (dxf->out, "%3d\r\nVERTEX\r\n%3d\r\n%s\r\n", 0, 8, layer);
295 	  sprintf (format,
296 		   "%%3d\r\n%%1.%df\r\n%%3d\r\n%%1.%df\r\n%%3d\r\n%%1.%df\r\n",
297 		   dxf->precision, dxf->precision, dxf->precision);
298 	  fprintf (dxf->out, format, 10, x, 20, y, 30, z);
299       }
300     fprintf (dxf->out, "%3d\r\nSEQEND\r\n%3d\r\n%s\r\n", 0, 8, layer);
301     dxf->count++;
302     return 1;
303 }
304 
305 GAIAGEO_DECLARE int
gaiaDxfWriteRing(gaiaDxfWriterPtr dxf,const char * layer,gaiaRingPtr ring)306 gaiaDxfWriteRing (gaiaDxfWriterPtr dxf, const char *layer, gaiaRingPtr ring)
307 {
308 /* printing a DXF POLYLINE (closed) */
309     int iv;
310     double x;
311     double y;
312     double z;
313     double m;
314     char format[128];
315     if (dxf == NULL)
316 	return 0;
317     if (dxf->error)
318 	return 0;
319     if (dxf->out == NULL)
320 	return 0;
321     fprintf (dxf->out, "%3d\r\nPOLYLINE\r\n%3d\r\n%s\r\n%3d\r\n%6d\r\n", 0, 8,
322 	     layer, 66, 1);
323     fprintf (dxf->out, "%3d\r\n%6d\r\n", 70, 1);
324     for (iv = 0; iv < ring->Points - 1; iv++)
325       {
326 	  /* sandro 2013-10-19
327 	     exporting all vertices except the last one
328 	     because accordingly to DXF specifications the
329 	     Ring closure is always implicitly assumed, so
330 	     there is no need at all to explicitly export
331 	     a last vertex identical to the first one */
332 	  m = 0.0;
333 	  z = 0.0;
334 	  if (ring->DimensionModel == GAIA_XY_Z)
335 	    {
336 		gaiaGetPointXYZ (ring->Coords, iv, &x, &y, &z);
337 	    }
338 	  else if (ring->DimensionModel == GAIA_XY_M)
339 	    {
340 		gaiaGetPointXYM (ring->Coords, iv, &x, &y, &m);
341 	    }
342 	  else if (ring->DimensionModel == GAIA_XY_Z_M)
343 	    {
344 		gaiaGetPointXYZM (ring->Coords, iv, &x, &y, &z, &m);
345 	    }
346 	  else
347 	    {
348 		gaiaGetPoint (ring->Coords, iv, &x, &y);
349 	    }
350 	  fprintf (dxf->out, "%3d\r\nVERTEX\r\n%3d\r\n%s\r\n", 0, 8, layer);
351 	  sprintf (format,
352 		   "%%3d\r\n%%1.%df\r\n%%3d\r\n%%1.%df\r\n%%3d\r\n%%1.%df\r\n",
353 		   dxf->precision, dxf->precision, dxf->precision);
354 	  fprintf (dxf->out, format, 10, x, 20, y, 30, z);
355       }
356     fprintf (dxf->out, "%3d\r\nSEQEND\r\n%3d\r\n%s\r\n", 0, 8, layer);
357     dxf->count++;
358     return 1;
359 }
360 
361 GAIAGEO_DECLARE int
gaiaDxfWriteGeometry(gaiaDxfWriterPtr dxf,const char * layer,const char * label,double text_height,double text_rotation,gaiaGeomCollPtr geom)362 gaiaDxfWriteGeometry (gaiaDxfWriterPtr dxf, const char *layer,
363 		      const char *label, double text_height,
364 		      double text_rotation, gaiaGeomCollPtr geom)
365 {
366 /* exporting a whole Geometry into the DXF */
367     gaiaPointPtr pt;
368     gaiaLinestringPtr ln;
369     gaiaPolygonPtr pg;
370     gaiaRingPtr rng;
371     int ib;
372     if (dxf == NULL)
373 	return 0;
374     if (dxf->error)
375 	return 0;
376     if (dxf->out == NULL)
377 	return 0;
378     pt = geom->FirstPoint;
379     while (pt != NULL)
380       {
381 	  if (label == NULL)
382 	      gaiaDxfWritePoint (dxf, layer, pt->X, pt->Y, pt->Z);
383 	  else
384 	      gaiaDxfWriteText (dxf, layer, pt->X, pt->Y, pt->Z, label,
385 				text_height, text_rotation);
386 	  pt = pt->Next;
387       }
388     ln = geom->FirstLinestring;
389     while (ln != NULL)
390       {
391 	  gaiaDxfWriteLine (dxf, layer, ln);
392 	  ln = ln->Next;
393       }
394     pg = geom->FirstPolygon;
395     while (pg != NULL)
396       {
397 	  rng = pg->Exterior;
398 	  gaiaDxfWriteRing (dxf, layer, rng);
399 	  for (ib = 0; ib < pg->NumInteriors; ib++)
400 	    {
401 		rng = pg->Interiors + ib;
402 		gaiaDxfWriteRing (dxf, layer, rng);
403 	    }
404 	  pg = pg->Next;
405       }
406     return 1;
407 }
408 
409 static gaiaDxfExportLayerPtr
alloc_aux_layer(const char * layer,gaiaGeomCollPtr geom)410 alloc_aux_layer (const char *layer, gaiaGeomCollPtr geom)
411 {
412 /* allocating and initializing an helper Layer */
413     int len;
414     gaiaDxfExportLayerPtr lyr = malloc (sizeof (gaiaDxfExportLayer));
415     len = strlen (layer);
416     lyr->layer_name = malloc (len + 1);
417     strcpy (lyr->layer_name, layer), lyr->minx = geom->MinX;
418     lyr->miny = geom->MinY;
419     lyr->maxx = geom->MaxX;
420     lyr->maxy = geom->MaxY;
421     lyr->next = NULL;
422     return lyr;
423 }
424 
425 static void
destroy_aux_layer(gaiaDxfExportLayerPtr lyr)426 destroy_aux_layer (gaiaDxfExportLayerPtr lyr)
427 {
428 /* destroying a DXF Helper Layer */
429     if (lyr == NULL)
430 	return;
431     if (lyr->layer_name != NULL)
432 	free (lyr->layer_name);
433     free (lyr);
434 }
435 
436 static gaiaDxfExportPtr
alloc_aux_exporter()437 alloc_aux_exporter ()
438 {
439 /* allocating and initializing the helper Exporter */
440     gaiaDxfExportPtr aux = malloc (sizeof (gaiaDxfExport));
441     aux->first = NULL;
442     aux->last = NULL;
443     return aux;
444 }
445 
446 static void
destroy_aux_exporter(gaiaDxfExportPtr aux)447 destroy_aux_exporter (gaiaDxfExportPtr aux)
448 {
449 /* memory cleanup - destroying the helper Exporter */
450     gaiaDxfExportLayerPtr lyr;
451     gaiaDxfExportLayerPtr n_lyr;
452     if (aux == NULL)
453 	return;
454     lyr = aux->first;
455     while (lyr != NULL)
456       {
457 	  n_lyr = lyr->next;
458 	  destroy_aux_layer (lyr);
459 	  lyr = n_lyr;
460       }
461     free (aux);
462 }
463 
464 static void
update_aux_exporter(gaiaDxfExportPtr aux,const char * layer,gaiaGeomCollPtr geom)465 update_aux_exporter (gaiaDxfExportPtr aux, const char *layer,
466 		     gaiaGeomCollPtr geom)
467 {
468 /* updating the Helper Exporter */
469     gaiaDxfExportLayerPtr lyr = aux->first;
470     while (lyr != NULL)
471       {
472 	  if (strcasecmp (layer, lyr->layer_name) == 0)
473 	    {
474 		/* updating an already defined layer */
475 		if (geom->MinX < lyr->minx)
476 		    lyr->minx = geom->MinX;
477 		if (geom->MinY < lyr->miny)
478 		    lyr->miny = geom->MinY;
479 		if (geom->MaxX > lyr->maxx)
480 		    lyr->maxx = geom->MaxX;
481 		if (geom->MaxY > lyr->maxy)
482 		    lyr->maxy = geom->MaxY;
483 		if (geom->MinX < aux->minx)
484 		    aux->minx = geom->MinX;
485 		if (geom->MinY < aux->miny)
486 		    aux->miny = geom->MinY;
487 		if (geom->MaxX > aux->maxx)
488 		    aux->maxx = geom->MaxX;
489 		if (geom->MaxY > aux->maxy)
490 		    aux->maxy = geom->MaxY;
491 		return;
492 	    }
493 	  lyr = lyr->next;
494       }
495 /* inserting a new Layer */
496     lyr = alloc_aux_layer (layer, geom);
497     if (aux->first == NULL)
498       {
499 	  aux->first = lyr;
500 	  aux->minx = geom->MinX;
501 	  aux->miny = geom->MinY;
502 	  aux->maxx = geom->MaxX;
503 	  aux->maxy = geom->MaxY;
504       }
505     if (aux->last != NULL)
506 	aux->last->next = lyr;
507     aux->last = lyr;
508 }
509 
510 GAIAGEO_DECLARE int
gaiaExportDxf(gaiaDxfWriterPtr dxf,sqlite3 * db_handle,const char * sql,const char * layer_col_name,const char * geom_col_name,const char * label_col_name,const char * text_height_col_name,const char * text_rotation_col_name,gaiaGeomCollPtr geom_filter)511 gaiaExportDxf (gaiaDxfWriterPtr dxf, sqlite3 * db_handle,
512 	       const char *sql, const char *layer_col_name,
513 	       const char *geom_col_name, const char *label_col_name,
514 	       const char *text_height_col_name,
515 	       const char *text_rotation_col_name, gaiaGeomCollPtr geom_filter)
516 {
517 /* exporting a complex DXF by executing an arbitrary SQL query */
518     sqlite3_stmt *stmt = NULL;
519     int ret;
520     int params;
521     int first_row = 1;
522     int layer_col = -1;
523     int geom_col = -1;
524     int label_col = -1;
525     int text_height_col = -1;
526     int text_rotation_col = -1;
527     int i;
528     unsigned char *p_blob;
529     const unsigned char *blob;
530     int len;
531     const char *layer;
532     const char *label = NULL;
533     gaiaGeomCollPtr geom;
534     gaiaDxfExportPtr aux = NULL;
535     gaiaDxfExportLayerPtr lyr;
536     if (dxf == NULL)
537 	return 0;
538     if (dxf->error)
539 	return 0;
540     if (dxf->out == NULL)
541 	return 0;
542     if (db_handle == NULL)
543 	return 0;
544     if (sql == NULL)
545 	return 0;
546     if (layer_col_name == NULL)
547 	return 0;
548     if (geom_col_name == NULL)
549 	return 0;
550 
551 /* attempting to create the SQL prepared statement */
552     ret = sqlite3_prepare_v2 (db_handle, sql, strlen (sql), &stmt, NULL);
553     if (ret != SQLITE_OK)
554       {
555 	  spatialite_e ("exportDXF - CREATE STATEMENT error: %s\n",
556 			sqlite3_errmsg (db_handle));
557 	  goto stop;
558       }
559     params = sqlite3_bind_parameter_count (stmt);
560 
561     if (params > 0 && geom_filter != NULL)
562       {
563 	  /* parameter binding - Spatial Filter */
564 	  sqlite3_reset (stmt);
565 	  sqlite3_clear_bindings (stmt);
566 	  for (i = 1; i <= params; i++)
567 	    {
568 		gaiaToSpatiaLiteBlobWkb (geom_filter, &p_blob, &len);
569 		ret = sqlite3_bind_blob (stmt, i, p_blob, len, free);
570 		if (ret != SQLITE_OK)
571 		  {
572 		      spatialite_e ("exportDXF - parameter BIND error: %s\n",
573 				    sqlite3_errmsg (db_handle));
574 		      goto stop;
575 		  }
576 	    }
577       }
578 
579 /* pass #1 - sniffing the result set */
580     while (1)
581       {
582 	  /* scrolling the result set rows */
583 	  ret = sqlite3_step (stmt);
584 	  if (ret == SQLITE_DONE)
585 	      break;		/* end of result set */
586 	  if (ret == SQLITE_ROW)
587 	    {
588 		if (first_row)
589 		  {
590 		      /* this one is the first row of the resultset */
591 		      for (i = 0; i < sqlite3_column_count (stmt); i++)
592 			{
593 			    /* attempting to identify the resultset columns */
594 			    if (strcasecmp
595 				(layer_col_name,
596 				 sqlite3_column_name (stmt, i)) == 0)
597 				layer_col = i;
598 			    if (strcasecmp
599 				(geom_col_name,
600 				 sqlite3_column_name (stmt, i)) == 0)
601 				geom_col = i;
602 			    if (label_col_name != NULL)
603 			      {
604 				  if (strcasecmp
605 				      (label_col_name,
606 				       sqlite3_column_name (stmt, i)) == 0)
607 				      label_col = i;
608 			      }
609 			    if (text_height_col_name != NULL)
610 			      {
611 				  if (strcasecmp
612 				      (text_height_col_name,
613 				       sqlite3_column_name (stmt, i)) == 0)
614 				      text_height_col = i;
615 			      }
616 			    if (text_rotation_col_name != NULL)
617 			      {
618 				  if (strcasecmp
619 				      (text_rotation_col_name,
620 				       sqlite3_column_name (stmt, i)) == 0)
621 				      text_rotation_col = i;
622 			      }
623 			}
624 		      if (layer_col < 0)
625 			{
626 			    spatialite_e
627 				("exportDXF - Layer Column not found into the resultset\n");
628 			    goto stop;
629 			}
630 		      if (geom_col < 0)
631 			{
632 			    spatialite_e
633 				("exportDXF - Geometry Column not found into the resultset\n");
634 			    goto stop;
635 			}
636 		      first_row = 0;
637 		      aux = alloc_aux_exporter ();
638 		  }
639 		layer = (const char *) sqlite3_column_text (stmt, layer_col);
640 		blob = sqlite3_column_blob (stmt, geom_col);
641 		len = sqlite3_column_bytes (stmt, geom_col);
642 		geom = gaiaFromSpatiaLiteBlobWkb (blob, len);
643 		if (geom)
644 		  {
645 		      update_aux_exporter (aux, layer, geom);
646 		      gaiaFreeGeomColl (geom);
647 		  }
648 	    }
649       }
650 
651 /* pass #2 - exporting the DXF file */
652     gaiaDxfWriteHeader (dxf, aux->minx, aux->miny, 0, aux->maxx, aux->maxy, 0);
653     gaiaDxfWriteTables (dxf);
654     lyr = aux->first;
655     while (lyr != NULL)
656       {
657 	  gaiaDxfWriteLayer (dxf, lyr->layer_name);
658 	  lyr = lyr->next;
659       }
660     gaiaDxfWriteEndSection (dxf);
661     gaiaDxfWriteEntities (dxf);
662 
663     sqlite3_reset (stmt);
664     while (1)
665       {
666 	  /* scrolling the result set rows */
667 	  int ival;
668 	  double height = 10.0;
669 	  double rotation = 0.0;
670 	  ret = sqlite3_step (stmt);
671 	  if (ret == SQLITE_DONE)
672 	      break;		/* end of result set */
673 	  if (ret == SQLITE_ROW)
674 	    {
675 		layer = (const char *) sqlite3_column_text (stmt, layer_col);
676 		if (label_col >= 0)
677 		    label =
678 			(const char *) sqlite3_column_text (stmt, label_col);
679 		if (text_height_col >= 0)
680 		  {
681 		      if (sqlite3_column_type (stmt, text_height_col) ==
682 			  SQLITE_INTEGER)
683 			{
684 			    ival = sqlite3_column_int (stmt, text_height_col);
685 			    height = ival;
686 			}
687 		      if (sqlite3_column_type (stmt, text_height_col) ==
688 			  SQLITE_FLOAT)
689 			  height =
690 			      sqlite3_column_double (stmt, text_height_col);
691 		  }
692 		if (text_rotation_col >= 0)
693 		  {
694 		      if (sqlite3_column_type (stmt, text_rotation_col) ==
695 			  SQLITE_INTEGER)
696 			{
697 			    ival = sqlite3_column_int (stmt, text_rotation_col);
698 			    rotation = ival;
699 			}
700 		      if (sqlite3_column_type (stmt, text_height_col) ==
701 			  SQLITE_FLOAT)
702 			  rotation =
703 			      sqlite3_column_double (stmt, text_rotation_col);
704 		  }
705 		blob = sqlite3_column_blob (stmt, geom_col);
706 		len = sqlite3_column_bytes (stmt, geom_col);
707 		geom = gaiaFromSpatiaLiteBlobWkb (blob, len);
708 		if (geom)
709 		  {
710 		      gaiaDxfWriteGeometry (dxf, layer, label, height, rotation,
711 					    geom);
712 		      gaiaFreeGeomColl (geom);
713 		  }
714 	    }
715       }
716     gaiaDxfWriteEndSection (dxf);
717     gaiaDxfWriteFooter (dxf);
718 
719     sqlite3_finalize (stmt);
720     if (aux != NULL)
721 	destroy_aux_exporter (aux);
722     return dxf->count;
723 
724   stop:
725     if (stmt != NULL)
726 	sqlite3_finalize (stmt);
727     if (aux != NULL)
728 	destroy_aux_exporter (aux);
729     return 0;
730 }
731