1 /* -*- Mode: C; c-basic-offset: 4 -*- */
2 /* Dia -- an diagram creation/manipulation program
3  * Copyright (C) 1998 Alexander Larsson
4  *
5  * dxf-export.c: dxf export filter for dia
6  * Copyright (C) 2000,2004 Steffen Macke
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <stdio.h>
28 #include <string.h>
29 #include <math.h>
30 #include <glib.h>
31 #include <errno.h>
32 #include <glib/gstdio.h>
33 
34 #include "autocad_pal.h"
35 
36 #include "intl.h"
37 #include "message.h"
38 #include "geometry.h"
39 #include "diarenderer.h"
40 #include "filter.h"
41 
42 #define DXF_TYPE_RENDERER           (dxf_renderer_get_type ())
43 #define DXF_RENDERER(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), DXF_TYPE_RENDERER, DxfRenderer))
44 #define DXF_RENDERER_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST ((klass), DXF_TYPE_RENDERER, DxfRendererClass))
45 #define DXF_IS_RENDERER(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DXF_TYPE_RENDERER))
46 #define DXF_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DXF_TYPE_RENDERER, DxfRendererClass))
47 
48 GType dxf_renderer_get_type (void) G_GNUC_CONST;
49 
50 typedef struct _DxfRenderer DxfRenderer;
51 typedef struct _DxfRendererClass DxfRendererClass;
52 
53 struct _DxfRendererClass
54 {
55   DiaRendererClass parent_class;
56 };
57 
58 #define IS_ODD(n) (n & 0x01)
59 
60 /* --- dxf line attributes --- */
61 typedef struct _LineAttrdxf
62 {
63     int         cap;
64     int         join;
65     char    	*style;
66     real        width;
67     Color       color;
68 
69 } LineAttrdxf;
70 
71 /* --- dxf File/Edge attributes --- */
72 typedef struct _FillEdgeAttrdxf
73 {
74 
75    int          fill_style;          /* Fill style */
76    Color        fill_color;          /* Fill color */
77 
78    int          edgevis;             /* Edge visibility */
79    int          cap;                 /* Edge cap */
80    int          join;                /* Edge join */
81    char         *style;               /* Edge style */
82    real         width;               /* Edge width */
83    Color        color;               /* Edge color */
84 
85 } FillEdgeAttrdxf;
86 
87 
88 /* --- dxf Text attributes --- */
89 typedef struct _TextAttrdxf
90 {
91    int          font_num;
92    real         font_height;
93    Color        color;
94 
95 } TextAttrdxf;
96 
97 
98 /* --- the renderer --- */
99 
100 struct _DxfRenderer
101 {
102     DiaRenderer parent_instance;
103 
104     FILE *file;
105 
106     DiaFont *font;
107 
108     real y0, y1;
109 
110     LineAttrdxf  lcurrent, linfile;
111 
112     FillEdgeAttrdxf fcurrent, finfile;
113 
114     TextAttrdxf    tcurrent, tinfile;
115 
116     char *layername;
117 
118 };
119 
120 
121 static void begin_render(DiaRenderer *self);
122 static void end_render(DiaRenderer *self);
123 static void set_linewidth(DiaRenderer *self, real linewidth);
124 static void set_linecaps(DiaRenderer *self, LineCaps mode);
125 static void set_linejoin(DiaRenderer *self, LineJoin mode);
126 static void set_linestyle(DiaRenderer *self, LineStyle mode);
127 static void set_dashlength(DiaRenderer *self, real length);
128 static void set_fillstyle(DiaRenderer *self, FillStyle mode);
129 static void set_font(DiaRenderer *self, DiaFont *font, real height);
130 static void draw_line(DiaRenderer *self,
131 		      Point *start, Point *end,
132 		      Color *line_colour);
133 static void draw_polyline(DiaRenderer *self,
134                           Point *points, int num_points,
135                           Color *color);
136 static void fill_rect (DiaRenderer *renderer,
137                        Point *ul_corner, Point *lr_corner,
138                        Color *color);
139 static void fill_polygon (DiaRenderer *renderer,
140                           Point *points, int num_points,
141                           Color *color);
142 static void draw_arc(DiaRenderer *self,
143 		     Point *center,
144 		     real width, real height,
145 		     real angle1, real angle2,
146 		     Color *colour);
147 static void fill_arc(DiaRenderer *self,
148 		     Point *center,
149 		     real width, real height,
150 		     real angle1, real angle2,
151 		     Color *colour);
152 static void draw_ellipse(DiaRenderer *self,
153 			 Point *center,
154 			 real width, real height,
155 			 Color *colour);
156 static void fill_ellipse(DiaRenderer *self,
157 			 Point *center,
158 			 real width, real height,
159 			 Color *colour);
160 static void draw_string(DiaRenderer *self,
161 			const char *text,
162 			Point *pos, Alignment alignment,
163 			Color *colour);
164 static void draw_image(DiaRenderer *self,
165 		       Point *point,
166 		       real width, real height,
167 		       DiaImage *image);
168 
169 static void dxf_renderer_class_init (DxfRendererClass *klass);
170 
171 static gpointer parent_class = NULL;
172 
173 GType
dxf_renderer_get_type(void)174 dxf_renderer_get_type (void)
175 {
176   static GType object_type = 0;
177 
178   if (!object_type)
179     {
180       static const GTypeInfo object_info =
181       {
182         sizeof (DxfRendererClass),
183         (GBaseInitFunc) NULL,
184         (GBaseFinalizeFunc) NULL,
185         (GClassInitFunc) dxf_renderer_class_init,
186         NULL,           /* class_finalize */
187         NULL,           /* class_data */
188         sizeof (DxfRenderer),
189         0,              /* n_preallocs */
190 	NULL            /* init */
191       };
192 
193       object_type = g_type_register_static (DIA_TYPE_RENDERER,
194                                             "DxfRenderer",
195                                             &object_info, 0);
196     }
197 
198   return object_type;
199 }
200 
201 static void
dxf_renderer_finalize(GObject * object)202 dxf_renderer_finalize (GObject *object)
203 {
204   G_OBJECT_CLASS (parent_class)->finalize (object);
205 }
206 
207 static void
dxf_renderer_class_init(DxfRendererClass * klass)208 dxf_renderer_class_init (DxfRendererClass *klass)
209 {
210   GObjectClass *object_class = G_OBJECT_CLASS (klass);
211   DiaRendererClass *renderer_class = DIA_RENDERER_CLASS (klass);
212 
213   parent_class = g_type_class_peek_parent (klass);
214 
215   object_class->finalize = dxf_renderer_finalize;
216 
217   renderer_class->begin_render = begin_render;
218   renderer_class->end_render = end_render;
219 
220   renderer_class->set_linewidth = set_linewidth;
221   renderer_class->set_linecaps = set_linecaps;
222   renderer_class->set_linejoin = set_linejoin;
223   renderer_class->set_linestyle = set_linestyle;
224   renderer_class->set_dashlength = set_dashlength;
225   renderer_class->set_fillstyle = set_fillstyle;
226   renderer_class->set_font = set_font;
227 
228   renderer_class->draw_line = draw_line;
229   renderer_class->draw_polyline = draw_polyline;
230   renderer_class->fill_rect = fill_rect;
231   renderer_class->fill_polygon = fill_polygon;
232 
233   renderer_class->draw_arc = draw_arc;
234   renderer_class->fill_arc = fill_arc;
235 
236   renderer_class->draw_ellipse = draw_ellipse;
237   renderer_class->fill_ellipse = fill_ellipse;
238 
239   renderer_class->draw_string = draw_string;
240 
241   renderer_class->draw_image = draw_image;
242 }
243 
244 
245 static void
init_attributes(DxfRenderer * renderer)246 init_attributes( DxfRenderer *renderer )
247 {
248     renderer->lcurrent.style = renderer->fcurrent.style = "CONTINUOUS";
249 }
250 
251 static void
begin_render(DiaRenderer * self)252 begin_render(DiaRenderer *self)
253 {
254 }
255 
256 static void
end_render(DiaRenderer * self)257 end_render(DiaRenderer *self)
258 {
259     DxfRenderer *renderer = DXF_RENDERER(self);
260 
261     fprintf(renderer->file, "0\nENDSEC\n0\nEOF\n");
262     fclose(renderer->file);
263 }
264 
265 static void
set_linewidth(DiaRenderer * self,real linewidth)266 set_linewidth(DiaRenderer *self, real linewidth)
267 {
268     DxfRenderer *renderer = DXF_RENDERER(self);
269 
270         /* update current line and edge width */
271     renderer->lcurrent.width = renderer->fcurrent.width = linewidth;
272 }
273 
274 static void
set_linecaps(DiaRenderer * self,LineCaps mode)275 set_linecaps(DiaRenderer *self, LineCaps mode)
276 {
277 }
278 
279 static void
set_linejoin(DiaRenderer * self,LineJoin mode)280 set_linejoin(DiaRenderer *self, LineJoin mode)
281 {
282 }
283 
284 static void
set_linestyle(DiaRenderer * self,LineStyle mode)285 set_linestyle(DiaRenderer *self, LineStyle mode)
286 {
287     DxfRenderer *renderer = DXF_RENDERER(self);
288     char   *style;
289 
290     switch(mode)
291     {
292     case LINESTYLE_DASHED:
293        style = "DASH";
294        break;
295     case LINESTYLE_DASH_DOT:
296        style = "DASHDOT";
297        break;
298     case LINESTYLE_DASH_DOT_DOT:
299        style = "DASHDOT";
300        break;
301     case LINESTYLE_DOTTED:
302        style = "DOT";
303        break;
304     case LINESTYLE_SOLID:
305     default:
306        style = "CONTINUOUS";
307        break;
308     }
309     renderer->lcurrent.style = renderer->fcurrent.style = style;
310 }
311 
312 static void
set_dashlength(DiaRenderer * self,real length)313 set_dashlength(DiaRenderer *self, real length)
314 {
315 }
316 
317 static void
set_fillstyle(DiaRenderer * self,FillStyle mode)318 set_fillstyle(DiaRenderer *self, FillStyle mode)
319 {
320 }
321 
322 static void
set_font(DiaRenderer * self,DiaFont * font,real height)323 set_font(DiaRenderer *self, DiaFont *font, real height)
324 {
325     DxfRenderer *renderer = DXF_RENDERER(self);
326 
327     renderer->tcurrent.font_height = height;
328 }
329 
330 static int
dxf_color(const Color * color)331 dxf_color (const Color *color)
332 {
333     /* Fixed colors
334      * 0 - black ?
335      * 1 - red
336      * 2 - yellow
337      * 3 - green
338      * 4 - cyan
339      * 5 - blue
340      * 6 - purple
341      * 7 - white
342      * 8 - gray
343      * ...
344      */
345     RGB_t rgb = {color->red*255, color->green*255, color->blue*255};
346     return pal_get_index (rgb);
347 }
348 
349 static void
draw_line(DiaRenderer * self,Point * start,Point * end,Color * line_colour)350 draw_line(DiaRenderer *self,
351 	  Point *start, Point *end,
352 	  Color *line_colour)
353 {
354     DxfRenderer *renderer = DXF_RENDERER(self);
355 
356     fprintf(renderer->file, "  0\nLINE\n");
357     fprintf(renderer->file, "  8\n%s\n", renderer->layername);
358     fprintf(renderer->file, "  6\n%s\n", renderer->lcurrent.style);
359     fprintf(renderer->file, " 10\n%f\n", start->x);
360     fprintf(renderer->file, " 20\n%f\n", (-1)*start->y);
361     fprintf(renderer->file, " 11\n%f\n", end->x);
362     fprintf(renderer->file, " 21\n%f\n", (-1)*end->y);
363     fprintf(renderer->file, " 39\n%d\n", (int)(renderer->lcurrent.width)); /* Thickness */
364     fprintf(renderer->file, " 62\n%d\n", dxf_color (line_colour));
365 }
366 
367 static void
draw_polyline(DiaRenderer * self,Point * points,int num_points,Color * color)368 draw_polyline(DiaRenderer *self,
369               Point *points, int num_points,
370               Color *color)
371 {
372     DxfRenderer *renderer = DXF_RENDERER(self);
373     int i;
374 
375     fprintf(renderer->file, "  0\nPOLYLINE\n");
376     fprintf(renderer->file, "  6\n%s\n", renderer->lcurrent.style);
377     fprintf(renderer->file, "  8\n%s\n", renderer->layername);
378     /* start and end width are the same */
379     fprintf(renderer->file, " 41\n%f\n", renderer->lcurrent.width);
380     fprintf(renderer->file, " 41\n%f\n", renderer->lcurrent.width);
381     fprintf(renderer->file, " 62\n%d\n", dxf_color (color));
382     /* vertices-follow flag */
383     fprintf(renderer->file, " 66\n1\n");
384 
385     for (i = 0; i < num_points; ++i)
386         fprintf(renderer->file, "  0\nVERTEX\n 10\n%f\n 20\n%f\n",
387 	        points[i].x, -points[i].y);
388 
389     fprintf(renderer->file, "  0\nSEQEND\n");
390 }
391 
392 static void
fill_rect(DiaRenderer * self,Point * ul_corner,Point * lr_corner,Color * color)393 fill_rect (DiaRenderer *self,
394            Point *ul_corner, Point *lr_corner,
395            Color *color)
396 {
397   DxfRenderer *renderer = DXF_RENDERER(self);
398   Point pts[4] = {
399     {ul_corner->x, -lr_corner->y},
400     {ul_corner->x, -ul_corner->y},
401     {lr_corner->x, -lr_corner->y},
402     {lr_corner->x, -ul_corner->y}
403   };
404   int i;
405 
406   fprintf(renderer->file, "  0\nSOLID\n");
407   fprintf(renderer->file, " 62\n%d\n", dxf_color (color));
408   for (i = 0; i < 4; ++i)
409     fprintf(renderer->file, " %d\n%f\n %d\n%f\n", 10+i, pts[i].x, 20+i, pts[i].y);
410 }
411 
412 static void
fill_polygon(DiaRenderer * renderer,Point * points,int num_points,Color * color)413 fill_polygon (DiaRenderer *renderer,
414               Point *points, int num_points,
415               Color *color)
416 {
417   /* not implemented, but no complaints by base class either */
418 }
419 
420 static void
draw_arc(DiaRenderer * self,Point * center,real width,real height,real angle1,real angle2,Color * colour)421 draw_arc(DiaRenderer *self,
422 	 Point *center,
423 	 real width, real height,
424 	 real angle1, real angle2,
425 	 Color *colour)
426 {
427     DxfRenderer *renderer = DXF_RENDERER(self);
428 
429     if(height != 0.0){
430         fprintf(renderer->file, "  0\nARC\n");
431         fprintf(renderer->file, "  8\n%s\n", renderer->layername);
432         fprintf(renderer->file, "  6\n%s\n", renderer->lcurrent.style);
433         fprintf(renderer->file, " 10\n%f\n", center->x);
434         fprintf(renderer->file, " 20\n%f\n", (-1)*center->y);
435         fprintf(renderer->file, " 40\n%f\n", width/2); /* radius */
436         fprintf(renderer->file, " 39\n%d\n", (int)(10*renderer->lcurrent.width)); /* Thickness */
437         fprintf(renderer->file, " 50\n%f\n", (angle1/360 ) * 2 * M_PI); /*start angle */
438         fprintf(renderer->file, " 51\n%f\n", (angle2/360 ) * 2 * M_PI); /* end angle */
439     }
440 }
441 
442 static void
fill_arc(DiaRenderer * self,Point * center,real width,real height,real angle1,real angle2,Color * colour)443 fill_arc(DiaRenderer *self,
444 	 Point *center,
445 	 real width, real height,
446 	 real angle1, real angle2,
447 	 Color *colour)
448 {
449     draw_arc(self, center, width, height, angle1, angle2, colour);
450 }
451 
452 static void
draw_ellipse(DiaRenderer * self,Point * center,real width,real height,Color * colour)453 draw_ellipse(DiaRenderer *self,
454 	     Point *center,
455 	     real width, real height,
456 	     Color *colour)
457 {
458     DxfRenderer *renderer = DXF_RENDERER(self);
459 
460     /* draw a circle instead of an ellipse, if it's one */
461     if(width == height){
462         fprintf(renderer->file, "  0\nCIRCLE\n");
463         fprintf(renderer->file, "  8\n%s\n", renderer->layername);
464         fprintf(renderer->file, "  6\n%s\n", renderer->lcurrent.style);
465         fprintf(renderer->file, " 10\n%f\n", center->x);
466         fprintf(renderer->file, " 20\n%f\n", (-1)*center->y);
467         fprintf(renderer->file, " 40\n%f\n", height/2);
468         fprintf(renderer->file, " 39\n%d\n", (int)(10*renderer->lcurrent.width)); /* Thickness */
469     }
470     else if(height != 0.0){
471         fprintf(renderer->file, "  0\nELLIPSE\n");
472         fprintf(renderer->file, "  8\n%s\n", renderer->layername);
473         fprintf(renderer->file, "  6\n%s\n", renderer->lcurrent.style);
474         fprintf(renderer->file, " 10\n%f\n", center->x);
475         fprintf(renderer->file, " 20\n%f\n", (-1)*center->y);
476         fprintf(renderer->file, " 11\n%f\n", width/2); /* Endpoint major axis relative to center X*/
477         fprintf(renderer->file, " 40\n%f\n", height/width); /*Ratio major/minor axis*/
478         fprintf(renderer->file, " 39\n%d\n", (int)(10*renderer->lcurrent.width)); /* Thickness */
479         fprintf(renderer->file, " 41\n%f\n", 0.0); /*Start Parameter full ellipse */
480         fprintf(renderer->file, " 42\n%f\n", 2.0*3.14); /* End Parameter full ellipse */
481     }
482 }
483 
484 static void
fill_ellipse(DiaRenderer * self,Point * center,real width,real height,Color * colour)485 fill_ellipse(DiaRenderer *self,
486 	     Point *center,
487 	     real width, real height,
488 	     Color *colour)
489 {
490     draw_ellipse(self, center, width, height, colour);
491 }
492 
493 
494 static void
draw_string(DiaRenderer * self,const char * text,Point * pos,Alignment alignment,Color * colour)495 draw_string(DiaRenderer *self,
496 	    const char *text,
497 	    Point *pos, Alignment alignment,
498 	    Color *colour)
499 {
500     DxfRenderer *renderer = DXF_RENDERER(self);
501 
502     fprintf(renderer->file, "  0\nTEXT\n");
503     fprintf(renderer->file, "  8\n%s\n", renderer->layername);
504     fprintf(renderer->file, "  6\n%s\n", renderer->lcurrent.style);
505     fprintf(renderer->file, " 10\n%f\n", pos->x);
506     fprintf(renderer->file, " 20\n%f\n", (-1)*pos->y);
507     fprintf(renderer->file, " 40\n%f\n", renderer->tcurrent.font_height); /* Text height */
508     fprintf(renderer->file, " 50\n%f\n", 0.0); /* Text rotation */
509     switch(alignment) {
510     case ALIGN_LEFT :
511 	fprintf(renderer->file, " 72\n%d\n", 0);
512         break;
513     case ALIGN_RIGHT :
514    	fprintf(renderer->file, " 72\n%d\n", 2);
515         break;
516     case ALIGN_CENTER :
517     default:
518    	fprintf(renderer->file, " 72\n%d\n", 1);
519         break;
520     }
521     fprintf(renderer->file, "  7\n%s\n", "0"); /* Text style */
522     fprintf(renderer->file, "  1\n%s\n", text);
523     fprintf(renderer->file, " 39\n%d\n", (int)(10*renderer->lcurrent.width)); /* Thickness */
524     fprintf(renderer->file, " 62\n%d\n", dxf_color(colour));
525 }
526 
527 static void
draw_image(DiaRenderer * self,Point * point,real width,real height,DiaImage * image)528 draw_image(DiaRenderer *self,
529 	   Point *point,
530 	   real width, real height,
531 	   DiaImage *image)
532 {
533 }
534 
535 static void
export_dxf(DiagramData * data,const gchar * filename,const gchar * diafilename,void * user_data)536 export_dxf(DiagramData *data, const gchar *filename,
537            const gchar *diafilename, void* user_data)
538 {
539     DxfRenderer *renderer;
540     FILE *file;
541     int i;
542     Layer *layer;
543 
544     file = g_fopen(filename, "w");
545 
546     if (file == NULL) {
547 	message_error(_("Can't open output file %s: %s\n"),
548 		      dia_message_filename(filename), strerror(errno));
549 	return;
550     }
551 
552     renderer = g_object_new(DXF_TYPE_RENDERER, NULL);
553 
554     renderer->file = file;
555 
556     /* drawing limits */
557     fprintf(file, "  0\nSECTION\n  2\nHEADER\n");
558     fprintf(file, "  9\n$EXTMIN\n 10\n%f\n 20\n%f\n",
559       data->extents.left, -data->extents.bottom);
560     fprintf(file, "  9\n$EXTMAX\n 10\n%f\n 20\n%f\n",
561       data->extents.right, -data->extents.top);
562     fprintf(file, "  0\nENDSEC\n");
563 
564     /* write layer description */
565     fprintf(file,"0\nSECTION\n2\nTABLES\n0\nTABLE\n");
566     for (i=0; i<data->layers->len; i++) {
567       layer = (Layer *) g_ptr_array_index(data->layers, i);
568       fprintf(file,"0\nLAYER\n2\n%s\n",layer->name);
569       if(layer->visible){
570 		fprintf(file,"62\n%d\n",i+1);
571       }
572       else {
573       	fprintf(file,"62\n%d\n",(-1)*(i+1));
574       }
575   	}
576     fprintf(file, "0\nENDTAB\n0\nENDSEC\n");
577 
578     /* write graphics */
579     fprintf(file,"0\nSECTION\n2\nENTITIES\n");
580 
581     init_attributes(renderer);
582 
583     DIA_RENDERER_GET_CLASS(renderer)->begin_render(DIA_RENDERER(renderer));
584 
585     for (i=0; i<data->layers->len; i++) {
586         layer = (Layer *) g_ptr_array_index(data->layers, i);
587 	    renderer->layername = layer->name;
588         layer_render(layer, DIA_RENDERER(renderer), NULL, NULL, data, 0);
589     }
590 
591     DIA_RENDERER_GET_CLASS(renderer)->end_render(DIA_RENDERER(renderer));
592 
593     g_object_unref(renderer);
594 }
595 
596 static const gchar *extensions[] = { "dxf", NULL };
597 DiaExportFilter dxf_export_filter = {
598     N_("Drawing Interchange File"),
599     extensions,
600     export_dxf
601 };
602