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