fix for dxf text import and work on startup messages on missing objects
[dia.git] / plug-ins / dxf / dxf-import.c
blobcea0691ab6663633d62896aaa057ecbbb0d87a99
1 /* -*- Mode: C; c-basic-offset: 4 -*- */
2 /* Dia -- an diagram creation/manipulation program
3 * Copyright (C) 1998 Alexander Larsson
5 * dxf-import.c: dxf import filter for dia
6 * Copyright (C) 2000 Steffen Macke
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.
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.
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.
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <stdio.h>
28 #include <string.h>
29 #include <math.h>
30 #include <glib.h>
31 #include <stdlib.h>
32 #include <locale.h>
34 #include "intl.h"
35 #include "message.h"
36 #include "geometry.h"
37 #include "render.h"
38 #include "filter.h"
39 #include "object.h"
40 #include "properties.h"
41 #include "propinternals.h"
43 static real coord_scale = 5.0;
44 static real width_scale = 10.0;
46 /* maximum line length */
47 #define DXF_LINE_LENGTH 256
49 typedef struct _DxfData
51 char code[DXF_LINE_LENGTH];
52 char value[DXF_LINE_LENGTH];
53 } DxfData;
55 gboolean import_dxf(const gchar *filename, DiagramData *dia, void* user_data);
56 gboolean read_dxf_codes(FILE *filedxf, DxfData *data);
57 void read_entity_line_dxf(FILE *filedxf, DxfData *data, DiagramData *dia);
58 void read_entity_circle_dxf(FILE *filedxf, DxfData *data, DiagramData *dia);
59 void read_entity_ellipse_dxf(FILE *filedxf, DxfData *data, DiagramData *dia);
60 void read_entity_arc_dxf(FILE *filedxf, DxfData *data, DiagramData *dia);
61 void read_entity_text_dxf(FILE *filedxf, DxfData *data, DiagramData *dia);
62 void read_table_layer_dxf(FILE *filedxf, DxfData *data, DiagramData *dia);
63 void read_section_tables_dxf(FILE *filedxf, DxfData *data, DiagramData *dia);
64 void read_section_entities_dxf(FILE *filedxf, DxfData *data, DiagramData *dia);
65 Layer *layer_find_by_name(char *layername, DiagramData *dia);
66 LineStyle get_dia_linestyle_dxf(char *dxflinestyle);
68 /* returns the layer with the given name */
69 /* TODO: merge this with other layer code? */
70 Layer *layer_find_by_name(char *layername, DiagramData *dia) {
71 Layer *matching_layer, *layer;
72 int i;
74 matching_layer = dia->active_layer;
75 for (i=0; i<dia->layers->len; i++) {
76 layer = (Layer *)g_ptr_array_index(dia->layers, i);
77 if(strcmp(layer->name, layername) == 0) {
78 matching_layer = layer;
79 break;
82 return matching_layer;
85 /* returns the matching dia linestyle for a given dxf linestyle */
86 /* if no matching style is found, LINESTYLE solid is returned as a default */
87 LineStyle get_dia_linestyle_dxf(char *dxflinestyle) {
88 if(strcmp(dxflinestyle, "DASH") == 0) {
89 return LINESTYLE_DASHED;
91 if(strcmp(dxflinestyle, "DASHDOT") == 0){
92 return LINESTYLE_DASH_DOT;
94 if(strcmp(dxflinestyle, "DOT") == 0){
95 return LINESTYLE_DOTTED;
97 return LINESTYLE_SOLID;
100 static PropDescription dxf_prop_descs[] = {
101 { "start_point", PROP_TYPE_POINT },
102 { "end_point", PROP_TYPE_POINT },
103 { "line_colour", PROP_TYPE_COLOUR },
104 { "line_width", PROP_TYPE_REAL },
105 { "line_style", PROP_TYPE_LINESTYLE},
106 PROP_DESC_END};
108 /* reads a line entity from the dxf file and creates a line object in dia*/
109 void read_entity_line_dxf(FILE *filedxf, DxfData *data, DiagramData *dia){
110 int codedxf;
111 char *old_locale;
113 /* line data */
114 Point start, end;
116 ObjectType *otype = object_get_type("Standard - Line");
117 Handle *h1, *h2;
119 Object *line_obj;
120 Color line_colour = { 0.0, 0.0, 0.0 };
121 GPtrArray *props;
122 PointProperty *ptprop;
123 LinestyleProperty *lsprop;
124 ColorProperty *cprop;
125 RealProperty *rprop;
127 real line_width = 0.1;
128 LineStyle style = LINESTYLE_SOLID;
129 Layer *layer = NULL;
131 old_locale = setlocale(LC_NUMERIC, "C");
132 do {
133 if(read_dxf_codes(filedxf, data) == FALSE){
134 setlocale(LC_NUMERIC, old_locale);
135 return;
137 codedxf = atoi(data->code);
138 switch(codedxf){
139 case 6: style = get_dia_linestyle_dxf(data->value);
140 break;
141 case 8: layer = layer_find_by_name(data->value, dia);
142 break;
143 case 10:
144 start.x = atof(data->value) / coord_scale;
145 break;
146 case 11:
147 end.x = atof(data->value) / coord_scale;
148 break;
149 case 20:
150 start.y = (-1)*atof(data->value) / coord_scale;
151 break;
152 case 21:
153 end.y = (-1)*atof(data->value) / coord_scale;
154 break;
155 case 39:
156 line_width = atof(data->value) / width_scale;
157 break;
159 } while(codedxf != 0);
160 setlocale(LC_NUMERIC, old_locale);
162 line_obj = otype->ops->create(&start, otype->default_user_data,
163 &h1, &h2);
164 layer_add_object(layer, line_obj);
166 props = prop_list_from_descs(dxf_prop_descs,pdtpp_true);
167 g_assert(props->len == 5);
169 ptprop = g_ptr_array_index(props,0);
170 ptprop->point_data = start;
172 ptprop = g_ptr_array_index(props,1);
173 ptprop->point_data = end;
175 cprop = g_ptr_array_index(props,2);
176 cprop->color_data = line_colour;
178 rprop = g_ptr_array_index(props,3);
179 rprop->real_data = line_width;
181 lsprop = g_ptr_array_index(props,4);
182 lsprop->style = style;
183 lsprop->dash = 1.0;
185 line_obj->ops->set_props(line_obj, props);
187 prop_list_free(props);
190 static PropDescription dxf_ellipse_prop_descs[] = {
191 { "elem_corner", PROP_TYPE_POINT },
192 { "elem_width", PROP_TYPE_REAL },
193 { "elem_height", PROP_TYPE_REAL },
194 { "line_colour", PROP_TYPE_COLOUR },
195 { "line_width", PROP_TYPE_REAL },
196 { "show_background", PROP_TYPE_BOOL},
197 PROP_DESC_END};
199 /* reads a circle entity from the dxf file and creates a circle object in dia*/
200 void read_entity_circle_dxf(FILE *filedxf, DxfData *data, DiagramData *dia){
201 int codedxf;
202 char *old_locale;
204 /* circle data */
205 Point center;
206 real radius = 1.0;
208 ObjectType *otype = object_get_type("Standard - Ellipse");
209 Handle *h1, *h2;
211 Object *ellipse_obj;
212 Color line_colour = { 0.0, 0.0, 0.0 };
214 PointProperty *ptprop;
215 RealProperty *rprop;
216 BoolProperty *bprop;
217 ColorProperty *cprop;
218 GPtrArray *props;
220 real line_width = 0.1;
221 Layer *layer = NULL;
223 old_locale = setlocale(LC_NUMERIC, "C");
224 do {
225 if(read_dxf_codes(filedxf, data) == FALSE){
226 setlocale(LC_NUMERIC, old_locale);
227 return;
229 codedxf = atoi(data->code);
230 switch(codedxf){
231 case 8:
232 layer = layer_find_by_name(data->value, dia);
233 break;
234 case 10:
235 center.x = atof(data->value) / coord_scale;
236 break;
237 case 20:
238 center.y = (-1)*atof(data->value) / coord_scale;
239 break;
240 case 39:
241 line_width = atof(data->value) / width_scale;
242 break;
243 case 40:
244 radius = atof(data->value) / coord_scale;
245 break;
248 } while(codedxf != 0);
249 setlocale(LC_NUMERIC, old_locale);
251 center.x -= radius;
252 center.y -= radius;
253 ellipse_obj = otype->ops->create(&center, otype->default_user_data,
254 &h1, &h2);
255 layer_add_object(layer, ellipse_obj);
257 props = prop_list_from_descs(dxf_ellipse_prop_descs,pdtpp_true);
258 g_assert(props->len == 6);
260 ptprop = g_ptr_array_index(props,0);
261 ptprop->point_data = center;
262 rprop = g_ptr_array_index(props,1);
263 rprop->real_data = radius * 2.0;
264 rprop = g_ptr_array_index(props,2);
265 rprop->real_data = radius * 2.0;
266 cprop = g_ptr_array_index(props,3);
267 cprop->color_data = line_colour;
268 rprop = g_ptr_array_index(props,4);
269 rprop->real_data = line_width;
270 bprop = g_ptr_array_index(props,5);
271 bprop->bool_data = FALSE;
273 ellipse_obj->ops->set_props(ellipse_obj, props);
274 prop_list_free(props);
277 static PropDescription dxf_arc_prop_descs[] = {
278 { "start_point", PROP_TYPE_POINT },
279 { "end_point", PROP_TYPE_POINT },
280 { "curve_distance", PROP_TYPE_REAL },
281 { "line_colour", PROP_TYPE_COLOUR },
282 { "line_width", PROP_TYPE_REAL },
283 PROP_DESC_END};
285 /* reads a circle entity from the dxf file and creates a circle object in dia*/
286 void read_entity_arc_dxf(FILE *filedxf, DxfData *data, DiagramData *dia){
287 int codedxf;
288 char *old_locale;
290 /* arc data */
291 Point start,center,end;
292 real radius = 1.0, start_angle = 0.0, end_angle=360.0;
293 real curve_distance;
295 ObjectType *otype = object_get_type("Standard - Arc");
296 Handle *h1, *h2;
298 Object *arc_obj;
299 Color line_colour = { 0.0, 0.0, 0.0 };
301 ColorProperty *cprop;
302 PointProperty *ptprop;
303 RealProperty *rprop;
304 GPtrArray *props;
306 real line_width = 0.1;
307 Layer *layer = NULL;
309 old_locale = setlocale(LC_NUMERIC, "C");
310 do {
311 if(read_dxf_codes(filedxf, data) == FALSE){
312 setlocale(LC_NUMERIC,old_locale);
313 return;
315 codedxf = atoi(data->code);
316 switch(codedxf){
317 case 8:
318 layer = layer_find_by_name(data->value, dia);
319 break;
320 case 10:
321 center.x = atof(data->value) / coord_scale;
322 break;
323 case 20:
324 center.y = (-1)*atof(data->value) / coord_scale;
325 break;
326 case 39:
327 line_width = atof(data->value) / width_scale;
328 break;
329 case 40:
330 radius = atof(data->value) / coord_scale;
331 break;
332 case 50:
333 start_angle = atof(data->value)*M_PI/180.0;
334 break;
335 case 51:
336 end_angle = atof(data->value)*M_PI/180.0;
337 break;
339 } while(codedxf != 0);
340 setlocale(LC_NUMERIC, old_locale);
342 /* printf("c.x=%f c.y=%f s",center.x,center.y); */
343 start.x = center.x + cos(start_angle) * radius;
344 start.y = center.y - sin(start_angle) * radius;
345 end.x = center.x + cos(end_angle) * radius;
346 end.y = center.y - sin(end_angle) * radius;
347 /*printf("s.x=%f s.y=%f e.x=%f e.y=%f\n",start.x,start.y,end.x,end.y);*/
350 if (end_angle < start_angle) end_angle += 2.0*M_PI;
351 curve_distance = radius * (1 - cos ((end_angle - start_angle)/2));
353 /*printf("start_angle: %f end_angle: %f radius:%f curve_distance:%f\n",
354 start_angle,end_angle,radius,curve_distance);*/
356 arc_obj = otype->ops->create(&center, otype->default_user_data,
357 &h1, &h2);
358 layer_add_object(layer, arc_obj);
360 props = prop_list_from_descs(dxf_arc_prop_descs,pdtpp_true);
361 g_assert(props->len == 5);
363 ptprop = g_ptr_array_index(props,0);
364 ptprop->point_data = start;
365 ptprop = g_ptr_array_index(props,1);
366 ptprop->point_data = end;
367 rprop = g_ptr_array_index(props,2);
368 rprop->real_data = curve_distance;
369 cprop = g_ptr_array_index(props,3);
370 cprop->color_data = line_colour;
371 rprop = g_ptr_array_index(props,4);
372 rprop->real_data = line_width;
374 arc_obj->ops->set_props(arc_obj, props);
375 prop_list_free(props);
378 /* reads an ellipse entity from the dxf file and creates an ellipse object in dia*/
379 void read_entity_ellipse_dxf(FILE *filedxf, DxfData *data, DiagramData *dia){
380 int codedxf;
381 char *old_locale;
383 /* ellipse data */
384 Point center;
385 real width = 1.0;
386 real ratio_width_height = 1.0;
388 ObjectType *otype = object_get_type("Standard - Ellipse");
389 Handle *h1, *h2;
391 Object *ellipse_obj;
392 Color line_colour = { 0.0, 0.0, 0.0 };
393 PointProperty *ptprop;
394 RealProperty *rprop;
395 BoolProperty *bprop;
396 ColorProperty *cprop;
397 GPtrArray *props;
399 real line_width = 0.1;
400 Layer *layer = NULL;
402 old_locale = setlocale(LC_NUMERIC, "C");
403 do {
404 if(read_dxf_codes(filedxf, data) == FALSE){
405 setlocale(LC_NUMERIC, old_locale);
406 return;
408 codedxf = atoi(data->code);
409 switch(codedxf){
410 case 8:
411 layer = layer_find_by_name(data->value, dia);
412 break;
413 case 10:
414 center.x = atof(data->value) / coord_scale;
415 break;
416 case 11:
417 ratio_width_height = atof(data->value) / coord_scale;
418 break;
419 case 20:
420 center.y = (-1)*atof(data->value) / coord_scale;
421 break;
422 case 39:
423 line_width = atof(data->value) / width_scale;
424 break;
425 case 40:
426 width = atof(data->value) * 2; /* XXX what scale */
427 break;
429 } while(codedxf != 0);
430 setlocale(LC_NUMERIC, old_locale);
432 center.x -= width;
433 center.y -= (width*ratio_width_height);
434 ellipse_obj = otype->ops->create(&center, otype->default_user_data,
435 &h1, &h2);
436 layer_add_object(layer, ellipse_obj);
438 props = prop_list_from_descs(dxf_ellipse_prop_descs,pdtpp_true);
439 g_assert(props->len == 6);
441 ptprop = g_ptr_array_index(props,0);
442 ptprop->point_data = center;
443 rprop = g_ptr_array_index(props,1);
444 rprop->real_data = width;
445 rprop = g_ptr_array_index(props,2);
446 rprop->real_data = width * ratio_width_height;
447 cprop = g_ptr_array_index(props,3);
448 cprop->color_data = line_colour;
449 rprop = g_ptr_array_index(props,4);
450 rprop->real_data = line_width;
451 bprop = g_ptr_array_index(props,5);
452 bprop->bool_data = FALSE;
454 ellipse_obj->ops->set_props(ellipse_obj, props);
455 prop_list_free(props);
458 static PropDescription dxf_text_prop_descs[] = {
459 { "text", PROP_TYPE_TEXT },
460 PROP_DESC_END};
462 void read_entity_text_dxf(FILE *filedxf, DxfData *data, DiagramData *dia)
464 int codedxf;
465 char *old_locale;
467 /* text data */
468 Point location;
469 real height = 10.0;
470 Alignment textalignment = ALIGN_LEFT;
471 char *textvalue = NULL;
473 ObjectType *otype = object_get_type("Standard - Text");
474 Handle *h1, *h2;
476 Object *text_obj;
477 Color text_colour = { 0.0, 0.0, 0.0 };
479 TextProperty *tprop;
480 GPtrArray *props;
482 Layer *layer = NULL;
484 old_locale = setlocale(LC_NUMERIC, "C");
485 do {
486 if (read_dxf_codes(filedxf, data) == FALSE) {
487 setlocale(LC_NUMERIC,old_locale);
488 return;
490 codedxf = atoi(data->code);
491 switch (codedxf) {
492 case 1: textvalue = g_strdup(data->value);
493 break;
494 case 8: layer = layer_find_by_name(data->value, dia);
495 break;
496 case 10:
497 location.x = atof(data->value) / coord_scale;
498 break;
499 case 20:
500 location.y = (-1)*atof(data->value) / coord_scale;
501 break;
502 case 40:
503 height = atof(data->value) / coord_scale;
504 break;
505 case 72:
506 switch(atoi(data->value)){
507 case 0: textalignment = ALIGN_LEFT;
508 break;
509 case 1: textalignment = ALIGN_CENTER;
510 break;
511 case 2: textalignment = ALIGN_RIGHT;
512 break;
515 } while(codedxf != 0);
516 setlocale(LC_NUMERIC,old_locale);
518 text_obj = otype->ops->create(&location, otype->default_user_data,
519 &h1, &h2);
520 layer_add_object(layer, text_obj);
521 props = prop_list_from_descs(dxf_text_prop_descs,pdtpp_true);
522 g_assert(props->len == 1);
524 tprop = g_ptr_array_index(props,0);
525 g_free(tprop->text_data);
526 tprop->text_data = textvalue;
527 tprop->attr.alignment = textalignment;
528 tprop->attr.position.x = location.x;
529 tprop->attr.position.y = location.y;
530 tprop->attr.font = font_getfont(_("Courier"));
531 tprop->attr.height = height;
533 text_obj->ops->set_props(text_obj, props);
534 prop_list_free(props);
537 /* reads the layer table from the dxf file and creates the layers */
538 void read_table_layer_dxf(FILE *filedxf, DxfData *data, DiagramData *dia){
539 int codedxf;
540 Layer *layer;
542 do {
543 if(read_dxf_codes(filedxf, data) == FALSE){
544 return;
546 else {
547 codedxf = atoi(data->code);
548 if(codedxf == 2){
549 layer = new_layer(g_strdup(data->value));
550 data_add_layer(dia, layer);
553 } while ((codedxf != 0) || (strcmp(data->value, "ENDTAB") != 0));
556 /* reads the tables section of the dxf file */
557 void read_section_tables_dxf(FILE *filedxf, DxfData *data, DiagramData *dia) {
558 int codedxf;
560 if(read_dxf_codes(filedxf, data) == FALSE){
561 return;
563 do {
564 codedxf = atoi(data->code);
565 if((codedxf == 0) && (strcmp(data->value, "LAYER") == 0)) {
566 read_table_layer_dxf(filedxf, data, dia);
568 else {
569 if(read_dxf_codes(filedxf, data) == FALSE){
570 return;
573 } while ((codedxf != 0) || (strcmp(data->value, "ENDSEC") != 0));
576 /* reads the entities section of the dxf file */
577 void read_section_entities_dxf(FILE *filedxf, DxfData *data, DiagramData *dia) {
578 int codedxf;
580 if (read_dxf_codes(filedxf, data) == FALSE){
581 return;
583 codedxf = atoi(data->code);
584 do {
585 if((codedxf == 0) && (strcmp(data->value, "LINE") == 0)) {
586 read_entity_line_dxf(filedxf, data, dia);
587 } else if((codedxf == 0) && (strcmp(data->value, "CIRCLE") == 0)) {
588 read_entity_circle_dxf(filedxf, data, dia);
589 } else if((codedxf == 0) && (strcmp(data->value, "ELLIPSE") == 0)) {
590 read_entity_ellipse_dxf(filedxf, data, dia);
591 } else if((codedxf == 0) && (strcmp(data->value, "TEXT") == 0)) {
592 read_entity_text_dxf(filedxf, data, dia);
593 } else if((codedxf == 0) && (strcmp(data->value, "ARC") == 0)) {
594 read_entity_arc_dxf(filedxf,data,dia);
595 } else {
596 /* if (codedxf == 0) {
597 g_warning("unknown DXF entity: %s",data->value);
599 if(read_dxf_codes(filedxf, data) == FALSE) {
600 return;
603 codedxf = atoi(data->code);
604 } while((codedxf != 0) || (strcmp(data->value, "ENDSEC") != 0));
607 /* imports the given dxf-file, returns TRUE if successful */
608 gboolean import_dxf(const gchar *filename, DiagramData *dia, void* user_data){
609 FILE *filedxf;
610 DxfData *data;
611 int codedxf;
613 filedxf = fopen(filename,"r");
614 if(filedxf == NULL){
615 message_error(_("Couldn't open: '%s' for reading.\n"), filename);
616 return FALSE;
619 data = g_new(DxfData, 1);
621 do {
622 if(read_dxf_codes(filedxf, data) == FALSE) {
623 g_free(data);
624 return FALSE;
626 else {
627 codedxf = atoi(data->code);
628 if(codedxf == 2) {
629 if(strcmp(data->value, "ENTITIES") == 0) {
630 read_section_entities_dxf(filedxf, data, dia);
632 else if(strcmp(data->value, "TABLES") == 0) {
633 read_section_tables_dxf(filedxf, data, dia);
637 }while((codedxf != 0) || (strcmp(data->value, "EOF") != 0));
639 g_free(data);
641 return TRUE;
644 /* reads a code/value pair from the DXF file */
645 gboolean read_dxf_codes(FILE *filedxf, DxfData *data){
646 int i;
647 char *c;
649 if(fgets(data->code, DXF_LINE_LENGTH, filedxf) == NULL){
650 return FALSE;
652 if(fgets(data->value, DXF_LINE_LENGTH, filedxf) == NULL){
653 return FALSE;
655 c=data->value;
656 for(i=0; i < DXF_LINE_LENGTH; i++){
657 if((c[i] == '\n')||(c[i] == '\r')){
658 c[i] = 0;
659 break;
662 return TRUE;
665 /* interface from filter.h */
667 static const gchar *extensions[] = {"dxf", NULL };
668 DiaImportFilter dxf_import_filter = {
669 N_("Drawing Interchange File"),
670 extensions,
671 import_dxf