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