1 /* output-dxf.c: utility routines for DXF output.
2
3 Copyright (C) 1999, 2000, 2001 Dietmar Kovar
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public License
7 as published by the Free Software Foundation; either version 2.1 of
8 the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18 USA. */
19
20 /* mail comments and suggestions to kovar@t-online.de */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif /* Def: HAVE_CONFIG_H */
25
26 #include "types.h"
27 #include "spline.h"
28 #include "color.h"
29 #include "output-dxf.h"
30 #include "xstd.h"
31 #include "autotrace.h"
32 #include <math.h>
33 #include <time.h>
34 #include <string.h>
35
36 #define SIGN(x) ((x) > 0 ? 1 : (x) < 0 ? -1 : 0)
37 #define ROUND(x) ((int) ((int) (x) + .5 * SIGN (x)))
38
39 /* Output macros. */
40
41 /* This should be used for outputting a string S on a line by itself. */
42 #define OUT_LINE(s) \
43 fprintf (dxf_file, "%s\n", s)
44
45 /* These output their arguments, preceded by the indentation. */
46 #define OUT1(s, e) \
47 fprintf (dxf_file, s, e)
48
49 #define color_check false
50
51 /**************************************************************************************
52 Definitions for spline to line transformation
53 **************************************************************************************/
54
55 typedef enum { NATURAL, TANGENT, PERIODIC, CYCLIC, ANTICYCLIC
56 } SPLINE_END_TYPE;
57
58
59 #define MAX_VERTICES 10000
60 #define RESOLUTION 10000 /* asume no pixels bigger than 1000000.0 */
61 #define RADIAN 57.295779513082
62
63 typedef struct xypnt_t {
64 int xp, yp;
65 } xypnt;
66
67
68 typedef struct xypnt_point_t {
69 xypnt point;
70 struct xypnt_point_t *next_point;
71 } xypnt_point_rec;
72
73 typedef struct xypnt_head_t {
74 xypnt_point_rec *first_point, *last_point,
75 *current_point;
76 struct xypnt_head_t *next_head;
77 } xypnt_head_rec;
78
79 typedef struct Colors_t {
80 int red, green, blue;
81 } Colors;
82
83
84 /* RGB to layer transformation table follows */
85
86 #define MAX_COLORS 255
87
88 struct Colors_t dxftable[MAX_COLORS] =
89 {
90 /* 1 */ {255, 0, 0},
91 /* 2 */ {255, 255, 0},
92 /* 3 */ { 0, 255, 0},
93 /* 4 */ { 0, 255, 255},
94 /* 5 */ { 0, 0, 255},
95 /* 6 */ {255, 0, 255},
96 /* 7 */ {255, 255, 255},
97 /* 8 */ {255, 255, 255},
98 /* 9 */ {255, 255, 255},
99 /* 10 */ {255, 9, 0},
100 /* 11 */ {255, 128, 128},
101 /* 12 */ {166, 0, 0},
102 /* 13 */ {166, 83, 83},
103 /* 14 */ {128, 0, 0},
104 /* 15 */ {128, 64, 64},
105 /* 16 */ { 77, 0, 0},
106 /* 17 */ { 77, 38, 38},
107 /* 18 */ { 38, 0, 0},
108 /* 19 */ { 38, 19, 19},
109 /* 20 */ {255, 64, 0},
110 /* 21 */ {255, 160, 128},
111 /* 22 */ {166, 42, 0},
112 /* 23 */ {166, 104, 83},
113 /* 24 */ {128, 32, 0},
114 /* 25 */ {128, 80, 64},
115 /* 26 */ { 77, 19, 0},
116 /* 27 */ { 77, 48, 38},
117 /* 28 */ { 38, 10, 0},
118 /* 29 */ { 38, 24, 19},
119 /* 30 */ {256, 128, 0},
120 /* 31 */ {256, 192, 0},
121 /* 32 */ {166, 83, 0},
122 /* 33 */ {166, 125, 83},
123 /* 34 */ {128, 64, 0},
124 /* 35 */ {128, 96, 64},
125 /* 36 */ { 77, 38, 0},
126 /* 37 */ { 77, 58, 38},
127 /* 38 */ { 38, 19, 0},
128 /* 39 */ { 38, 29, 19},
129 /* 40 */ {255, 192, 0},
130 /* 41 */ {255, 224, 128},
131 /* 42 */ {166, 125, 0},
132 /* 43 */ {166, 146, 83},
133 /* 44 */ {128, 96, 0},
134 /* 45 */ {128, 112, 64},
135 /* 46 */ { 77, 58, 0},
136 /* 47 */ { 77, 67, 38},
137 /* 48 */ { 38, 29, 0},
138 /* 49 */ { 38, 34, 19},
139 /* 50 */ {255, 255, 0},
140 /* 51 */ {255, 255, 128},
141 /* 52 */ {166, 166, 0},
142 /* 53 */ {166, 166, 83},
143 /* 54 */ {128, 128, 0},
144 /* 55 */ {128, 128, 64},
145 /* 56 */ { 77, 77, 0},
146 /* 57 */ { 77, 77, 38},
147 /* 58 */ { 38, 38, 0},
148 /* 59 */ { 38, 38, 19},
149 /* 60 */ {192, 255, 0},
150 /* 61 */ {224, 255, 128},
151 /* 62 */ {125, 166, 0},
152 /* 63 */ {146, 166, 83},
153 /* 64 */ { 96, 128, 0},
154 /* 65 */ {112, 128, 64},
155 /* 66 */ { 58, 77, 0},
156 /* 67 */ { 67, 77, 38},
157 /* 68 */ { 29, 38, 0},
158 /* 69 */ { 34, 38, 19},
159 /* 70 */ {128, 255, 0},
160 /* 71 */ {192, 255, 128},
161 /* 72 */ { 83, 166, 0},
162 /* 73 */ {125, 166, 83},
163 /* 74 */ { 64, 128, 0},
164 /* 75 */ { 96, 128, 64},
165 /* 76 */ { 38, 77, 0},
166 /* 77 */ { 58, 77, 38},
167 /* 78 */ { 19, 38, 0},
168 /* 79 */ { 29, 38, 19},
169 /* 80 */ { 64, 255, 0},
170 /* 81 */ {160, 255, 128},
171 /* 82 */ { 42, 160, 0},
172 /* 83 */ {104, 160, 80},
173 /* 84 */ { 32, 128, 0},
174 /* 85 */ { 80, 128, 64},
175 /* 86 */ { 19, 77, 0},
176 /* 87 */ { 48, 77, 38},
177 /* 88 */ { 10, 38, 0},
178 /* 89 */ { 24, 38, 19},
179 /* 90 */ { 0, 255, 0},
180 /* 91 */ {128, 255, 128},
181 /* 92 */ { 0, 166, 0},
182 /* 93 */ { 83, 166, 83},
183 /* 94 */ { 0, 128, 0},
184 /* 95 */ { 64, 128, 64},
185 /* 96 */ { 0, 77, 0},
186 /* 97 */ { 38, 77, 38},
187 /* 98 */ { 0, 38, 0},
188 /* 99 */ { 19, 38, 19},
189 /* 100 */ { 0, 255, 64},
190 /* 101 */ {128, 255, 160},
191 /* 102 */ { 0, 166, 42},
192 /* 103 */ { 83, 166, 118},
193 /* 104 */ { 0, 128, 32},
194 /* 105 */ { 64, 128, 80},
195 /* 106 */ { 0, 77, 19},
196 /* 107 */ { 38, 77, 48},
197 /* 108 */ { 0, 38, 10},
198 /* 109 */ { 19, 38, 24},
199 /* 110 */ { 0, 255, 128},
200 /* 111 */ {128, 255, 192},
201 /* 112 */ { 0, 166, 83},
202 /* 113 */ { 83, 166, 125},
203 /* 114 */ { 0, 128, 64},
204 /* 115 */ { 64, 128, 96},
205 /* 116 */ { 0, 77, 38},
206 /* 117 */ { 38, 77, 58},
207 /* 118 */ { 0, 38, 19},
208 /* 119 */ { 19, 38, 29},
209 /* 120 */ { 0, 255, 192},
210 /* 121 */ {128, 255, 224},
211 /* 122 */ { 0, 166, 125},
212 /* 123 */ { 83, 166, 146},
213 /* 124 */ { 0, 128, 96},
214 /* 125 */ { 64, 128, 112},
215 /* 125 */ { 0, 77, 58},
216 /* 127 */ { 38, 77, 67},
217 /* 128 */ { 0, 38, 29},
218 /* 129 */ { 19, 38, 34},
219 /* 130 */ { 0, 255, 255},
220 /* 131 */ {128, 255, 255},
221 /* 132 */ { 0, 166, 166},
222 /* 133 */ { 83, 166, 166},
223 /* 134 */ { 0, 128, 128},
224 /* 135 */ { 64, 128, 128},
225 /* 136 */ { 0, 77, 77},
226 /* 137 */ { 38, 77, 77},
227 /* 138 */ { 0, 38, 38},
228 /* 139 */ { 19, 38, 38},
229 /* 140 */ { 0, 192, 255},
230 /* 141 */ {128, 224, 255},
231 /* 142 */ { 0, 125, 166},
232 /* 143 */ { 83, 146, 166},
233 /* 144 */ { 0, 96, 128},
234 /* 145 */ { 64, 112, 128},
235 /* 146 */ { 0, 58, 77},
236 /* 147 */ { 38, 67, 77},
237 /* 148 */ { 0, 29, 38},
238 /* 149 */ { 19, 34, 38},
239 /* 150 */ { 0, 128, 255},
240 /* 151 */ {128, 192, 255},
241 /* 152 */ { 0, 83, 166},
242 /* 153 */ { 83, 125, 166},
243 /* 154 */ { 0, 64, 128},
244 /* 155 */ { 64, 96, 128},
245 /* 156 */ { 0, 38, 77},
246 /* 157 */ { 38, 58, 77},
247 /* 158 */ { 0, 19, 38},
248 /* 159 */ { 19, 29, 38},
249 /* 160 */ { 0, 64, 255},
250 /* 161 */ {128, 160, 255},
251 /* 162 */ { 0, 42, 166},
252 /* 163 */ { 83, 104, 166},
253 /* 164 */ { 0, 32, 128},
254 /* 165 */ { 64, 80, 128},
255 /* 166 */ { 0, 19, 77},
256 /* 167 */ { 38, 48, 77},
257 /* 168 */ { 0, 10, 38},
258 /* 169 */ { 19, 24, 38},
259 /* 170 */ { 0, 0, 255},
260 /* 171 */ {128, 128, 255},
261 /* 172 */ { 0, 0, 166},
262 /* 173 */ { 83, 83, 166},
263 /* 174 */ { 0, 0, 128},
264 /* 175 */ { 64, 64, 128},
265 /* 176 */ { 0, 0, 77},
266 /* 177 */ { 38, 38, 77},
267 /* 178 */ { 0, 0, 38},
268 /* 179 */ { 19, 19, 38},
269 /* 180 */ { 64, 0, 255},
270 /* 181 */ {160, 128, 255},
271 /* 182 */ { 42, 0, 166},
272 /* 183 */ {104, 83, 166},
273 /* 184 */ { 32, 0, 128},
274 /* 185 */ { 80, 64, 128},
275 /* 186 */ { 19, 0, 77},
276 /* 187 */ { 48, 38, 77},
277 /* 188 */ { 10, 0, 38},
278 /* 189 */ { 24, 19, 38},
279 /* 190 */ {128, 0, 255},
280 /* 191 */ {192, 128, 255},
281 /* 192 */ { 83, 0, 166},
282 /* 193 */ {125, 83, 166},
283 /* 194 */ { 64, 0, 128},
284 /* 195 */ { 96, 64, 128},
285 /* 196 */ { 38, 0, 77},
286 /* 197 */ { 58, 38, 77},
287 /* 198 */ { 19, 0, 38},
288 /* 199 */ { 29, 19, 38},
289 /* 200 */ {192, 0, 255},
290 /* 201 */ {224, 128, 255},
291 /* 202 */ {125, 0, 166},
292 /* 203 */ {146, 83, 166},
293 /* 204 */ { 96, 0, 128},
294 /* 205 */ {112, 64, 128},
295 /* 206 */ { 58, 0, 77},
296 /* 207 */ { 67, 38, 77},
297 /* 208 */ { 29, 0, 38},
298 /* 209 */ { 34, 19, 38},
299 /* 210 */ {255, 0, 255},
300 /* 211 */ {255, 128, 255},
301 /* 212 */ {166, 0, 166},
302 /* 213 */ {166, 83, 166},
303 /* 214 */ {128, 0, 128},
304 /* 215 */ {128, 64, 128},
305 /* 216 */ { 77, 0, 77},
306 /* 217 */ { 77, 38, 77},
307 /* 218 */ { 38, 0, 38},
308 /* 219 */ { 38, 19, 38},
309 /* 220 */ {255, 0, 192},
310 /* 221 */ {255, 128, 224},
311 /* 222 */ {166, 0, 125},
312 /* 223 */ {166, 83, 146},
313 /* 224 */ {128, 0, 96},
314 /* 225 */ {128, 64, 112},
315 /* 226 */ { 77, 0, 58},
316 /* 227 */ { 77, 38, 67},
317 /* 228 */ { 38, 0, 29},
318 /* 229 */ { 38, 19, 34},
319 /* 230 */ {255, 0, 128},
320 /* 231 */ {255, 128, 192},
321 /* 232 */ {166, 0, 83},
322 /* 233 */ {166, 83, 125},
323 /* 234 */ {128, 0, 64},
324 /* 235 */ {128, 64, 96},
325 /* 236 */ { 77, 0, 38},
326 /* 237 */ { 77, 38, 58},
327 /* 238 */ { 38, 0, 19},
328 /* 239 */ { 38, 19, 29},
329 /* 240 */ {255, 0, 64},
330 /* 241 */ {255, 128, 160},
331 /* 242 */ {166, 0, 42},
332 /* 243 */ {166, 83, 104},
333 /* 244 */ {128, 0, 32},
334 /* 245 */ {128, 64, 80},
335 /* 246 */ { 77, 0, 19},
336 /* 247 */ { 77, 38, 48},
337 /* 248 */ { 38, 0, 10},
338 /* 249 */ { 38, 19, 24},
339 /* 250 */ { 84, 84, 84},
340 /* 251 */ {119, 119, 119},
341 /* 252 */ {153, 153, 153},
342 /* 253 */ {187, 187, 187},
343 /* 254 */ {222, 222, 222},
344 /* 255 */ {255, 255, 255}
345 };
346
347 /******************************************************************************
348 * Moves the current_point pointer to the next point in the list.
349 * If current_point is at last point then it becomes NULL.
350 * finished is 1 if coord_point has not been set, that is current_point is NULL.
351 */
xypnt_next_pnt(xypnt_head_rec * head_xypnt,xypnt * coord_point,char * finished)352 void xypnt_next_pnt (xypnt_head_rec *head_xypnt /* */,
353 xypnt *coord_point /* */,
354 char *finished /* */)
355 {
356 if (head_xypnt && head_xypnt->current_point)
357 {
358 head_xypnt->current_point = head_xypnt->current_point->next_point;
359 if (head_xypnt->current_point == NULL)
360 *finished = 1;
361 else
362 {
363 *coord_point = head_xypnt->current_point->point;
364 *finished = 0;
365 }
366 }
367 else
368 *finished = 1;
369 }
370
371
372 /******************************************************************************
373 * Moves the current_point pointer to the begining of the list
374 */
xypnt_first_pnt(xypnt_head_rec * head_xypnt,xypnt * coord_point,char * finished)375 void xypnt_first_pnt (xypnt_head_rec *head_xypnt /* */,
376 xypnt *coord_point /* */,
377 char *finished /* */)
378 {
379 if (head_xypnt)
380 {
381 head_xypnt->current_point = head_xypnt->first_point;
382 if (head_xypnt->current_point == NULL)
383 *finished = 1;
384 else
385 {
386 *coord_point = head_xypnt->current_point->point;
387 *finished = 0;
388 }
389 }
390 else
391 *finished = 1;
392 }
393
394
395 /******************************************************************************
396 * This routine will add the "coord_point" to the end of the xypnt list
397 * which is specified by the "head_xypnt". Does not change current_point.
398 */
xypnt_add_pnt(xypnt_head_rec * head_xypnt,xypnt coord_point)399 void xypnt_add_pnt (xypnt_head_rec *head_xypnt /* */,
400 xypnt coord_point /* */)
401 {
402 xypnt_point_rec *temp_point;
403
404 if (!head_xypnt)
405 return;
406 temp_point=(struct xypnt_point_t *)calloc(1,sizeof(struct xypnt_point_t));
407 temp_point->point = coord_point;
408 temp_point->next_point = NULL;
409 if (head_xypnt->first_point == NULL)
410 head_xypnt->first_point = temp_point;
411 else
412 head_xypnt->last_point->next_point = temp_point;
413 head_xypnt->last_point = temp_point;
414 }
415
416
417 /******************************************************************************
418 * This routine will dispose a list of points and the head pointer to
419 * which they are connected to. The pointer is returned as a NIL.
420 */
xypnt_dispose_list(xypnt_head_rec ** head_xypnt)421 void xypnt_dispose_list (xypnt_head_rec **head_xypnt /* */)
422 {
423 xypnt_point_rec *p, *old;
424 if (head_xypnt && *head_xypnt)
425 {
426 if ((*head_xypnt)->last_point && (*head_xypnt)->first_point)
427 {
428 p = (*head_xypnt)->first_point;
429 while (p)
430 {
431 old = p;
432 p = p->next_point;
433 free(old);
434 }
435 }
436 }
437 }
438
439
440 /******************************************************************************
441 * Searches color by closest rgb values (distance of 2 3D points)
442 * not os specific.
443 * returns: index of color
444 */
GetIndexByRGBValue(int red,int green,int blue)445 int GetIndexByRGBValue(int red /* */,
446 int green /* */,
447 int blue /* */)
448 {
449 int savdis=1, i;
450 double psav = 10000000, pnew, px, py, pz;
451 int nred, ngreen, nblue;
452
453 for (i = 0; i < MAX_COLORS; i++)
454 {
455 nred = dxftable[i].red;
456 ngreen = dxftable[i].green;
457 nblue = dxftable[i].blue;
458 /* compute shortest distance between rgb colors */
459 px = red*red - 2*nred*red + nred*nred;
460 py = green*green - 2*ngreen*green + ngreen*ngreen;
461 pz = blue*blue - 2*nblue*blue + nblue*nblue;
462 pnew = sqrt(px+py+pz);
463 if (pnew < psav)
464 {
465 psav = pnew;
466 savdis = i;
467 }
468 }
469 return(savdis+1);
470 }
471
472
473
474 /******************************************************************************
475 * Moves the current_point pointer to the end of the list
476 */
xypnt_last_pnt(xypnt_head_rec * head_xypnt,xypnt * coord_point,char * finished)477 void xypnt_last_pnt (xypnt_head_rec *head_xypnt /* */,
478 xypnt *coord_point /* */,
479 char *finished /* */)
480 {
481 if (head_xypnt)
482 {
483 head_xypnt->current_point = head_xypnt->last_point;
484 if (head_xypnt->current_point == NULL)
485 *finished = 1;
486 else
487 {
488 *coord_point = head_xypnt->current_point->point;
489 *finished = 0;
490 }
491 }
492 else
493 *finished = 1;
494 }
495
496
497
498
499 /******************************************************************************
500 * computes the distance between p1 and p2
501 *
502 * returns:
503 */
distpt2pt(xypnt p1,xypnt p2)504 double distpt2pt(xypnt p1 /* */,
505 xypnt p2 /* */)
506 {
507 double dx, dy;
508
509 dx = p2.xp - p1.xp;
510 dy = p2.yp - p1.yp;
511 if (p1.xp==p2.xp)
512 return (fabs (dy));
513 else if (p1.yp==p2.yp)
514 return (fabs (dx));
515 else
516 return (sqrt(dx*dx + dy*dy));
517 }
518
519
520 /******************************************************************************
521 * returns: length of all vectors in vertex list
522 */
get_total_length(xypnt_head_rec * vtx_list)523 static double get_total_length(xypnt_head_rec *vtx_list /* */)
524 {
525 double total_length;
526 xypnt curr_pnt, next_pnt;
527 char end_of_list;
528
529 total_length = 0.0;
530 xypnt_first_pnt(vtx_list, &curr_pnt, &end_of_list);
531 while (!end_of_list)
532 {
533 xypnt_next_pnt(vtx_list, &next_pnt, &end_of_list);
534 total_length += distpt2pt(curr_pnt, next_pnt);
535 curr_pnt = next_pnt;
536 }
537 return (total_length);
538 }
539
540
541
542
543 /******************************************************************************
544 * Convert B-Spline to list of lines.
545 */
bspline_to_lines(xypnt_head_rec * vtx_list,xypnt_head_rec ** new_vtx_list,int vtx_count,int spline_order,int spline_resolution)546 int bspline_to_lines(xypnt_head_rec *vtx_list /* */,
547 xypnt_head_rec **new_vtx_list /* */,
548 int vtx_count /* */,
549 int spline_order /* */,
550 int spline_resolution /* */)
551 {
552 int i, j, knot_index, number_of_segments, knot[MAX_VERTICES + 1],n,m;
553 double spline_step, total_length, t, spline_pnt_x, spline_pnt_y, r,
554 *weight;
555 xypnt curr_pnt, spline_pnt;
556 char end_of_list;
557
558 *new_vtx_list = (struct xypnt_head_t *) calloc(1, sizeof (struct xypnt_head_t));
559 if (vtx_list)
560 {
561 n = vtx_count + spline_order+1;
562 m = spline_order + 1;
563 weight = (double *) malloc( n*m* sizeof(double));
564
565 for (i = 0; i < vtx_count + spline_order; i++)
566 knot[i] = (i < spline_order) ? 0 :
567 (i > vtx_count) ? knot[i-1] : knot[i-1] + 1;
568 total_length = get_total_length(vtx_list);
569 r = (spline_resolution==0) ? sqrt(total_length) :
570 total_length/spline_resolution;
571 number_of_segments = ROUND(r);
572 spline_step = ((double)knot[vtx_count+spline_order-1]) /
573 number_of_segments;
574 for (knot_index=spline_order-1; knot_index<vtx_count; knot_index++)
575 {
576 for (i = 0; i <= vtx_count + spline_order - 2; i++)
577 weight[i] = (i==knot_index && knot[i]!=knot[i+1]);
578 t = knot[knot_index];
579 while (t < knot[knot_index+1] - spline_step / 2.0)
580 {
581 spline_pnt_x = 0.0;
582 spline_pnt_y = 0.0;
583 for (j = 2; j <= spline_order; j++)
584 {
585 i = 0;
586 xypnt_first_pnt(vtx_list, &curr_pnt, &end_of_list);
587 while (!end_of_list)
588 {
589 weight[(j-1)*n + i] = 0;
590 if (weight[(j-2)*n+i])
591 weight[(j-1)*n+i] += (t-knot[i]) * weight[(j-2)*n+i] /
592 (knot[i+j-1] - knot[i]);
593 if (weight[(j-2)*n + i+1])
594 weight[(j-1)*n+i] += (knot[i+j]-t)*weight[(j-2)*n+i+1]/
595 (knot[i+j] - knot[i+1]);
596 if (j == spline_order)
597 {
598 spline_pnt_x += curr_pnt.xp * weight[(j-1)*n+i];
599 spline_pnt_y += curr_pnt.yp * weight[(j-1)*n+i];
600 }
601 i++;
602 xypnt_next_pnt(vtx_list, &curr_pnt, &end_of_list);
603 }
604 weight[(j-1)*n+i] = 0;
605 }
606 spline_pnt.xp = ROUND(spline_pnt_x);
607 spline_pnt.yp = ROUND(spline_pnt_y);
608 xypnt_add_pnt(*new_vtx_list, spline_pnt);
609 t += spline_step;
610 }
611 }
612 xypnt_last_pnt(vtx_list, &spline_pnt, &end_of_list);
613 xypnt_add_pnt(*new_vtx_list, spline_pnt);
614
615 free(weight);
616 }
617
618 return(0);
619 }
620
621
622 /******************************************************************************
623 * This function outputs the DXF code which produces the polylines
624 */
out_splines(FILE * dxf_file,spline_list_array_type shape)625 static void out_splines (FILE * dxf_file, spline_list_array_type shape)
626 {
627 unsigned this_list;
628 double startx, starty;
629 xypnt_head_rec *vec, *res;
630 xypnt pnt, pnt1, pnt_old = {0,0};
631 char fin, new_layer=0, layerstr[10];
632 int i, first_seg = 1, idx;
633
634 strcpy(layerstr, "C1");
635 for (this_list = 0; this_list < SPLINE_LIST_ARRAY_LENGTH (shape);
636 this_list++)
637 {
638 unsigned this_spline;
639 color_type last_color = {0,0,0};
640
641 spline_list_type list = SPLINE_LIST_ARRAY_ELT (shape, this_list);
642 spline_type first = SPLINE_LIST_ELT (list, 0);
643 color_type curr_color = curr_color = (list.clockwise && shape.background_color != NULL)? *(shape.background_color) : list.color;
644
645 if (this_list == 0 || !COLOR_EQUAL(curr_color, last_color))
646 {
647 if (!(curr_color.r==0 && curr_color.g==0 && curr_color.b==0) || !color_check)
648 {
649 idx = GetIndexByRGBValue(curr_color.r, curr_color.g, curr_color.b);
650 sprintf(layerstr, "C%d", idx);
651 new_layer = 1;
652 last_color = curr_color;
653 }
654 }
655 startx = START_POINT (first).x;
656 starty = START_POINT (first).y;
657 if (!first_seg)
658 {
659 if (ROUND(startx*RESOLUTION) != pnt_old.xp || ROUND(starty*RESOLUTION) != pnt_old.yp || new_layer)
660 {
661 /* must begin new polyline */
662 new_layer = 0;
663 fprintf(dxf_file, " 0\nSEQEND\n 8\n%s\n", layerstr);
664 fprintf(dxf_file, " 0\nPOLYLINE\n 8\n%s\n 66\n1\n 10\n%f\n 20\n%f\n",
665 layerstr, startx, starty);
666 fprintf(dxf_file, " 0\nVERTEX\n 8\n%s\n 10\n%f\n 20\n%f\n",
667 layerstr, startx, starty);
668 pnt_old.xp = ROUND(startx*RESOLUTION);
669 pnt_old.yp = ROUND(starty*RESOLUTION);
670 }
671 }
672 else
673 {
674 fprintf(dxf_file, " 0\nPOLYLINE\n 8\n%s\n 66\n1\n 10\n%f\n 20\n%f\n",
675 layerstr, startx, starty);
676 fprintf(dxf_file, " 0\nVERTEX\n 8\n%s\n 10\n%f\n 20\n%f\n",
677 layerstr, startx, starty);
678 pnt_old.xp = ROUND(startx*RESOLUTION);
679 pnt_old.yp = ROUND(starty*RESOLUTION);
680 }
681 for (this_spline = 0; this_spline < SPLINE_LIST_LENGTH (list);
682 this_spline++)
683 {
684 spline_type s = SPLINE_LIST_ELT (list, this_spline);
685
686 if (SPLINE_DEGREE (s) == LINEARTYPE)
687 {
688
689 if (ROUND(startx*RESOLUTION) != pnt_old.xp || ROUND(starty*RESOLUTION) != pnt_old.yp || new_layer)
690 {
691 /* must begin new polyline */
692 new_layer = 0;
693 fprintf(dxf_file, " 0\nSEQEND\n 8\n%s\n", layerstr);
694 fprintf(dxf_file, " 0\nPOLYLINE\n 8\n%s\n 66\n1\n 10\n%f\n 20\n%f\n",
695 layerstr, startx, starty);
696 fprintf(dxf_file, " 0\nVERTEX\n 8\n%s\n 10\n%f\n 20\n%f\n",
697 layerstr, startx, starty);
698 }
699 fprintf(dxf_file, " 0\nVERTEX\n 8\n%s\n 10\n%f\n 20\n%f\n",
700 layerstr, END_POINT(s).x, END_POINT (s).y);
701
702 startx = END_POINT(s).x;
703 starty = END_POINT(s).y;
704 pnt_old.xp = ROUND(startx*RESOLUTION);
705 pnt_old.yp = ROUND(starty*RESOLUTION);
706 }
707 else
708 {
709 vec = (struct xypnt_head_t *)calloc(1, sizeof (struct xypnt_head_t));
710
711 pnt.xp = ROUND(startx*RESOLUTION); pnt.yp = ROUND(starty*RESOLUTION);
712 xypnt_add_pnt(vec, pnt);
713 pnt.xp = ROUND(CONTROL1(s).x*RESOLUTION); pnt.yp = ROUND(CONTROL1 (s).y*RESOLUTION);
714 xypnt_add_pnt(vec, pnt);
715 pnt.xp = ROUND(CONTROL2(s).x*RESOLUTION); pnt.yp = ROUND(CONTROL2 (s).y*RESOLUTION);
716 xypnt_add_pnt(vec, pnt);
717 pnt.xp = ROUND(END_POINT(s).x*RESOLUTION); pnt.yp = ROUND(END_POINT (s).y*RESOLUTION);
718 xypnt_add_pnt(vec, pnt);
719
720 res = NULL;
721
722 /* Note that spline order can be max. 4 since we have only 4 spline control points */
723 bspline_to_lines(vec, &res, 4, 4, 10000);
724
725
726 xypnt_first_pnt(res, &pnt, &fin);
727
728 if (pnt.xp != pnt_old.xp || pnt.yp != pnt_old.yp || new_layer)
729 {
730 /* must begin new polyline */
731 new_layer = 0;
732 fprintf(dxf_file, " 0\nSEQEND\n 8\n%s\n", layerstr);
733 fprintf(dxf_file, " 0\nPOLYLINE\n 8\n%s\n 66\n1\n 10\n%f\n 20\n%f\n",
734 layerstr, (double)pnt.xp/RESOLUTION, (double)pnt.yp/RESOLUTION);
735 fprintf(dxf_file, " 0\nVERTEX\n 8\n%s\n 10\n%f\n 20\n%f\n",
736 layerstr, (double)pnt.xp/RESOLUTION, (double)pnt.yp/RESOLUTION);
737 }
738 i = 0;
739 while (!fin)
740 {
741 if (i)
742 {
743 fprintf(dxf_file, " 0\nVERTEX\n 8\n%s\n 10\n%f\n 20\n%f\n",
744 layerstr, (double)pnt.xp/RESOLUTION, (double)pnt.yp/RESOLUTION);
745 }
746 pnt1 = pnt;
747 xypnt_next_pnt(res, &pnt, &fin);
748 i++;
749 }
750
751 pnt_old = pnt;
752
753 xypnt_dispose_list(&vec);
754 xypnt_dispose_list(&res);
755
756 startx = END_POINT(s).x;
757 starty = END_POINT(s).y;
758
759 free(res);
760 free(vec);
761 }
762 }
763 first_seg = 0;
764 last_color = curr_color;
765 }
766
767 fprintf(dxf_file, " 0\nSEQEND\n 8\n0\n");
768
769 }
770
771
772 /******************************************************************************
773 * This function outputs a complete layer table for all 255 colors.
774 */
output_layer(FILE * dxf_file,spline_list_array_type shape)775 void output_layer(FILE *dxf_file,
776 spline_list_array_type shape)
777 {
778 int i, idx;
779 char layerlist[256];
780 unsigned this_list;
781 color_type last_color = {0,0,0};
782
783 memset(layerlist, 0, sizeof(layerlist));
784 for (this_list = 0; this_list < SPLINE_LIST_ARRAY_LENGTH (shape);
785 this_list++)
786 {
787 spline_list_type list = SPLINE_LIST_ARRAY_ELT (shape, this_list);
788 color_type curr_color = (list.clockwise && shape.background_color != NULL) ? *(shape.background_color) : list.color;
789
790 if (this_list == 0 || !COLOR_EQUAL(curr_color, last_color))
791 {
792 if (!(curr_color.r==0 && curr_color.g==0 && curr_color.b==0) || !color_check)
793 {
794 idx = GetIndexByRGBValue(curr_color.r, curr_color.g, curr_color.b);
795 layerlist[idx-1] = 1;
796 last_color = curr_color;
797 }
798 }
799 }
800
801 OUT_LINE(" 0");
802 OUT_LINE("SECTION");
803 OUT_LINE(" 2");
804 OUT_LINE("TABLES");
805 OUT_LINE(" 0");
806 OUT_LINE("TABLE");
807 OUT_LINE(" 2");
808 OUT_LINE("LAYER");
809 OUT_LINE(" 70");
810 OUT_LINE(" 2048");
811
812 OUT_LINE(" 0");
813 OUT_LINE("LAYER");
814 OUT_LINE(" 2");
815 OUT_LINE("0");
816 OUT_LINE(" 70");
817 OUT_LINE(" 0");
818 OUT_LINE(" 62");
819 OUT_LINE(" 7");
820 OUT_LINE(" 6");
821 OUT_LINE("CONTINUOUS");
822
823 for (i=1; i<256; i++)
824 {
825 if (layerlist[i-1])
826 {
827 OUT_LINE(" 0");
828 OUT_LINE("LAYER");
829 OUT_LINE(" 2");
830 OUT1 ("C%d\n", i);
831 OUT_LINE(" 70");
832 OUT_LINE(" 64");
833 OUT_LINE(" 62");
834 OUT1 ("%d\n", i);
835 OUT_LINE(" 6");
836 OUT_LINE("CONTINUOUS");
837 }
838 }
839
840 OUT_LINE(" 0");
841 OUT_LINE("ENDTAB");
842 OUT_LINE (" 0");
843 OUT_LINE ("ENDSEC");
844
845 }
846
847
848 /******************************************************************************
849 * DXF output function.
850 */
output_dxf12_writer(FILE * dxf_file,at_string name,int llx,int lly,int urx,int ury,at_output_opts_type * opts,spline_list_array_type shape,at_msg_func msg_func,at_address msg_data)851 int output_dxf12_writer(FILE* dxf_file, at_string name,
852 int llx, int lly, int urx, int ury,
853 at_output_opts_type * opts,
854 spline_list_array_type shape,
855 at_msg_func msg_func,
856 at_address msg_data)
857 {
858 OUT_LINE (" 0");
859 OUT_LINE ("SECTION");
860 OUT_LINE (" 2");
861 OUT_LINE ("HEADER");
862 OUT_LINE (" 9");
863 OUT_LINE ("$ACADVER");
864 OUT_LINE (" 1");
865 OUT_LINE ("AC1009");
866 OUT_LINE (" 9");
867 OUT_LINE ("$EXTMIN");
868 OUT_LINE (" 10");
869 OUT1 (" %f\n", (double)llx);
870 OUT_LINE (" 20");
871 OUT1 (" %f\n", (double)lly);
872 OUT_LINE (" 30");
873 OUT_LINE (" 0.000000");
874 OUT_LINE (" 9");
875 OUT_LINE ("$EXTMAX");
876 OUT_LINE (" 10");
877 OUT1 (" %f\n", (double)urx);
878 OUT_LINE (" 20");
879 OUT1 (" %f\n", (double)ury);
880 OUT_LINE (" 30");
881 OUT_LINE (" 0.000000");
882 OUT_LINE (" 0");
883 OUT_LINE ("ENDSEC");
884
885 output_layer(dxf_file, shape);
886
887 OUT_LINE (" 0");
888 OUT_LINE ("SECTION");
889 OUT_LINE (" 2");
890 OUT_LINE ("ENTITIES");
891
892 out_splines(dxf_file, shape);
893
894 OUT_LINE (" 0");
895 OUT_LINE ("ENDSEC");
896 OUT_LINE (" 0");
897 OUT_LINE ("EOF");
898 return 0;
899 }
900
901