1 /*
2 Copyright (C) 2018-2021, Dirk Krause
3 SPDX-License-Identifier: BSD-3-Clause
4 */
5 
6 /*
7 	WARNING: This file was generated by the dkct program (see
8 	http://dktools.sourceforge.net/ for details).
9 	Changes you make here will be lost if dkct is run again!
10 	You should modify the original source and run dkct on it.
11 	Original source: wxd2lout.ctr
12 */
13 
14 /**	@file wxd2lout.c The wxd2lout module.
15 */
16 
17 
18 #ifndef	WXD2LAT_H_INCLUDED
19 #include <wxd2lat/wxd2lat.h>
20 #endif
21 
22 
23 
24 
25 
26 
27 
28 static const dkChar *kwnl[] = {
29 /* 0 */
30 dkT(".tex"),
31 
32 NULL
33 
34 };
35 
36 
37 
38 double
wxd2lout_convert_x(wxd_drawing_t * drw,wxd2lat_job_t * job,double x)39 wxd2lout_convert_x(wxd_drawing_t *drw, wxd2lat_job_t *job, double x)
40 {
41 #if	TRACE_DEBUG
42 	double	back;
43 
44 	back = ((9.0 * (x - drw->bbxl)) / 2032000.0) + job->shiftx;
45 
46 	return back;
47 #else
48 	return (((9.0 * (x - drw->bbxl)) / 2032000.0) + job->shiftx);
49 #endif
50 }
51 
52 
53 
54 double
wxd2lout_convert_y(wxd_drawing_t * drw,wxd2lat_job_t * job,double y)55 wxd2lout_convert_y(wxd_drawing_t *drw, wxd2lat_job_t *job, double y)
56 {
57 #if	TRACE_DEBUG
58 	double	back;
59 
60 	back = ((9.0 * (y - drw->bbyb)) / 2032000.0) + job->shifty;
61 
62 	return back;
63 #else
64 	return (((9.0 * (y - drw->bbyb)) / 2032000.0) + job->shifty);
65 #endif
66 }
67 
68 
69 
70 /**	Convert distance value from WXD coordinates to bp.
71 	@param	r	Distance to convert
72 	@return	Conversion result.
73 */
74 double
wxd2lout_convert_r(double r)75 wxd2lout_convert_r(double r)
76 {
77 #if	TRACE_DEBUG
78 	double	back;
79 
80 	back = ((9.0 * r) / 2032000.0);
81 
82 	return back;
83 #else
84 	return ((9.0 * r) / 2032000.0);
85 #endif
86 }
87 
88 
89 
90 
91 /**	Prepare job structure, calculate coordinates transformations
92 	and create output file name.
93 	@param	drw	Drawing to convert.
94 	@param	job	Job structure.
95 	@param	fn	File name.
96 	@return	1 on success (output possible), 0 on error.
97 */
98 static
99 int
wxd2lout_prepare_job(wxd_drawing_t * drw,wxd2lat_job_t * job,const dkChar * fn)100 wxd2lout_prepare_job(wxd_drawing_t *drw, wxd2lat_job_t *job, const dkChar *fn)
101 {
102 	dkChar		*ptr;
103 	double		dwidth;
104 	double		dheight;
105 	double		cwidth;
106 	double		cheight;
107 	int			back		= 1;
108 
109 	dwidth  = (9.0 * (drw->bbxr - drw->bbxl)) / 2032000.0;
110 	dheight = (9.0 * (drw->bbyt - drw->bbyb)) / 2032000.0;
111 	cwidth  = ceil(dwidth);
112 	cheight = ceil(dheight);
113 	if (cwidth > dwidth) {
114 		job->shiftx = (cwidth - dwidth) / 2.0;
115 
116 	}
117 	if (cheight > dheight) {
118 		job->shifty = (cheight - dheight) / 2.0;
119 
120 	}
121 	if ((0 == dk4ma_is_finite(dwidth)) || (0 == dk4ma_is_finite(cwidth))) {
122 		back = 0;
123 		/* ERROR: Numeric overflow in width calculation */
124 		dk4app_log_1(
125 			job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 36
126 		);
127 	}
128 	if ((0 == dk4ma_is_finite(dheight)) || (0 == dk4ma_is_finite(cheight))) {
129 		back = 0;
130 		/* ERROR: Numeric overflow in height calculation */
131 		dk4app_log_1(
132 			job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 36
133 		);
134 	}
135 	if ((double)(SIZE_MAX) < cwidth) {
136 		back = 0;
137 		/* ERROR: Numeric overflow in width calculation */
138 		dk4app_log_1(
139 			job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 36
140 		);
141 	}
142 	else {
143 		job->szwidth = (size_t)cwidth;
144 
145 	}
146 	if ((double)(SIZE_MAX) < cheight) {
147 		back = 0;
148 		/* ERROR: Numeric overflow in height calculation */
149 		dk4app_log_1(
150 			job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 36
151 		);
152 	}
153 	else {
154 		job->szheight = (size_t)cheight;
155 
156 	}
157 	if (0 != dk4str_cpy_s(job->fno1, job->szfnb, fn, NULL)) {
158 		ptr = dk4path_get_suffix(job->fno1, NULL);
159 		if (NULL != ptr) { *ptr = dkT('\0'); }
160 		if (0 == dk4str_cat_s(job->fno1, job->szfnb, kwnl[0], NULL)) {
161 			back = 0;
162 			/* ERROR: File name too long */
163 			dk4app_log_1(
164 				job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 37
165 			);
166 		}
167 	}
168 	else {
169 		/* ERROR: File name too long */
170 		dk4app_log_1(
171 			job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 37
172 		);
173 		back = 0;
174 	}
175 
176 	return back;
177 }
178 
179 
180 
181 /**	Set clip region to used coordinates ranges.
182 	@param	drw	Drawing to convert.
183 	@param	job	Job structure.
184 	@return	1 on success, 0 on error.
185 */
186 static
187 int
wxd2lout_clip_to_used_region(wxd2lat_job_t * job)188 wxd2lout_clip_to_used_region(wxd2lat_job_t *job)
189 {
190 	dk4_er_t	er;
191 	int		 	back = 1;
192 	double	 	xl;
193 	double	 	xr;
194 	double	 	yb;
195 	double	 	yt;
196 
197 	if ((0.0 < job->shiftx) || (0.0 < job->shifty)) {
198 		xl = job->shiftx;
199 		if (0.0 > xl) { xl = 0.0; }
200 		xr = (double)(job->szwidth) - job->shiftx;
201 		yb = job->shifty;
202 		if (0.0 > yb) { yb = 0.0; }
203 		yt = (double)(job->szheight) - job->shifty;
204 		dk4error_init(&er);
205 		dk4pppt_newpath_moveto(job->ppp, xl, yb, NULL, &back, &er);
206 		dk4pppt_lineto(job->ppp, xr, yb, NULL, &back, &er);
207 		dk4pppt_lineto(job->ppp, xr, yt, NULL, &back, &er);
208 		dk4pppt_lineto(job->ppp, xl, yt, NULL, &back, &er);
209 		dk4pppt_lineto(job->ppp, xl, yb, NULL, &back, &er);
210 		dk4pppt_closepath(job->ppp, &back, &er);
211 		dk4pppt_clip(job->ppp, &back, &er);
212 		if (0 == back) {
213 			/* ERROR: Failed to clip region */
214 			dk4app_log_1(
215 				job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 38
216 			);
217 		}
218 	}
219 
220 	return back;
221 }
222 
223 
224 
225 /**	Set stroke RGB colour.
226 	@param	job		Job structure.
227 	@param	pobj	Current object.
228 	@param	backptr	Address of success variable to reset on errors.
229 	@param	erp		Error report, may be NULL.
230 	@return	1 on success, 0 on error.
231 */
232 static
233 void
wxd2lout_stroke_rgb(wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_er_t * erp)234 wxd2lout_stroke_rgb(
235 	wxd2lat_job_t	*job,
236 	wxd_object_t	*pobj,
237 	int				*backptr,
238 	dk4_er_t		*erp
239 )
240 {
241 
242 	dk4pppt_set_stroke_rgb(
243 		job->ppp,
244 		(((double)(pobj->sc[0])) / 255.0),
245 		(((double)(pobj->sc[1])) / 255.0),
246 		(((double)(pobj->sc[2])) / 255.0),
247 		backptr, erp
248 	);
249 
250 
251 }
252 
253 
254 
255 /**	Set stroke line width.
256 	@param	drw		Drawing structure.
257 	@param	job		Job structure.
258 	@param	pobj	Current object.
259 	@param	backptr	Address of success variable to reset on errors.
260 	@param	erp		Error report, may be NULL.
261 	@return	1 on success, 0 on error.
262 */
263 static
264 void
wxd2lout_line_width(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_er_t * erp)265 wxd2lout_line_width(
266 	wxd_drawing_t	*drw,
267 	wxd2lat_job_t	*job,
268 	wxd_object_t	*pobj,
269 	int				*backptr,
270 	dk4_er_t		*erp
271 )
272 {
273 
274 	dk4pppt_set_line_width(
275 		job->ppp, wxd2lat_object_linewidth(pobj, drw, job),
276 		backptr, erp
277 	);
278 
279 
280 }
281 
282 
283 
284 /**	Set stroke line style.
285 	@param	drw		Drawing structure.
286 	@param	job		Job structure.
287 	@param	pobj	Current object.
288 	@param	backptr	Address of success variable to reset on errors.
289 	@param	erp		Error report, may be NULL.
290 	@return	1 on success, 0 on error.
291 */
292 static
293 void
wxd2lout_line_style(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_er_t * erp)294 wxd2lout_line_style(
295 	wxd_drawing_t	*drw,
296 	wxd2lat_job_t	*job,
297 	wxd_object_t	*pobj,
298 	int				*backptr,
299 	dk4_er_t		*erp
300 )
301 {
302 	double			sv;
303 	dk4_gra_ls_t	ls = DK4_GRA_LS_SOLID;
304 
305 	switch (pobj->ls) {
306 		case WXD_LS_SOLID : {
307 			ls = DK4_GRA_LS_SOLID;
308 		} break;
309 		case WXD_LS_DASH : {
310 			ls = DK4_GRA_LS_DASH;
311 		} break;
312 		case WXD_LS_DOT : {
313 			ls = DK4_GRA_LS_DOT;
314 		} break;
315 		case WXD_LS_DASH_DOT : {
316 			ls = DK4_GRA_LS_DASH_DOT;
317 		} break;
318 		case WXD_LS_DASH_DOT_DOT : {
319 			ls = DK4_GRA_LS_DASH_DOT_DOT;
320 		} break;
321 		case WXD_LS_DASH_DOT_DOT_DOT : {
322 			ls = DK4_GRA_LS_DASH_DOT_DOT_DOT;
323 		} break;
324 	}
325 	sv = (double)(pobj->sl) * wxd2lat_object_linewidth(pobj, drw, job);
326 	dk4pppt_set_line_style(job->ppp, ls, sv, backptr, erp);
327 
328 
329 }
330 
331 
332 
333 /**	Set stroke line cap.
334 	@param	job		Job structure.
335 	@param	pobj	Current object.
336 	@param	backptr	Address of success variable to reset on errors.
337 	@param	erp		Error report, may be NULL.
338 	@return	1 on success, 0 on error.
339 */
340 static
341 void
wxd2lout_line_cap(wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_er_t * erp)342 wxd2lout_line_cap(
343 	wxd2lat_job_t	*job,
344 	wxd_object_t	*pobj,
345 	int				*backptr,
346 	dk4_er_t		*erp
347 )
348 {
349 	dk4_gra_lc_t	 lc	= DK4_GRA_LC_BUTTED;
350 
351 	switch (pobj->csfs) {
352 		case WXD_LC_BUTTED : {
353 			lc = DK4_GRA_LC_BUTTED;
354 		} break;
355 		case WXD_LC_ROUNDED : {
356 			lc = DK4_GRA_LC_ROUNDED;
357 		} break;
358 		case WXD_LC_PROJECTING : {
359 			lc = DK4_GRA_LC_PROJECTING;
360 		} break;
361 	}
362 	dk4pppt_set_line_cap(job->ppp, lc, backptr, erp);
363 
364 
365 }
366 
367 
368 
369 /**	Set stroke line join.
370 	@param	job		Job structure.
371 	@param	pobj	Current object.
372 	@param	backptr	Address of success variable to reset on errors.
373 	@param	erp		Error report, may be NULL.
374 	@return	1 on success, 0 on error.
375 */
376 static
377 void
wxd2lout_line_join(wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_er_t * erp)378 wxd2lout_line_join(
379 	wxd2lat_job_t	*job,
380 	wxd_object_t	*pobj,
381 	int				*backptr,
382 	dk4_er_t		*erp
383 )
384 {
385 	dk4_gra_lj_t	lj	= DK4_GRA_LJ_MITERED;
386 
387 	switch ( (int)(pobj->ot) ) {
388 		case WXD_OT_O_ARC : case WXD_OT_C_ARC :
389 		case WXD_OT_CIRCLE : case WXD_OT_ELLIPSE : {
390 			lj = DK4_GRA_LJ_ROUNDED;
391 		} break;
392 		default : {
393 			switch (pobj->js) {
394 				case WXD_LJ_MITERED : {
395 					lj = DK4_GRA_LJ_MITERED;
396 				} break;
397 				case WXD_LJ_ROUNDED : {
398 					lj = DK4_GRA_LJ_ROUNDED;
399 				} break;
400 				case WXD_LJ_BEVELED : {
401 					lj = DK4_GRA_LJ_BEVELED;
402 				} break;
403 			}
404 		} break;
405 	}
406 
407 
408 
409 	if ((uint8_t)0U == pobj->ml) { pobj->ml = (uint8_t)1U; }
410 	dk4pppt_set_line_join(job->ppp, lj, (double)(pobj->ml), backptr, erp);
411 
412 
413 }
414 
415 
416 
417 /**	Set fill RGB colour.
418 	@param	job		Job structure.
419 	@param	pobj	Current object.
420 	@param	backptr	Address of success variable to reset on errors.
421 	@param	erp		Error report, may be NULL.
422 	@return	1 on success, 0 on error.
423 */
424 static
425 void
wxd2lout_fill_rgb(wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_er_t * erp)426 wxd2lout_fill_rgb(
427 	wxd2lat_job_t	*job,
428 	wxd_object_t	*pobj,
429 	int				*backptr,
430 	dk4_er_t		*erp
431 )
432 {
433 
434 
435 
436 
437 
438 
439 
440 
441 
442 	dk4pppt_set_fill_rgb(
443 		job->ppp,
444 		(((double)(pobj->fc[0])) / 255.0),
445 		(((double)(pobj->fc[1])) / 255.0),
446 		(((double)(pobj->fc[2])) / 255.0),
447 		backptr, erp
448 	);
449 
450 
451 }
452 
453 
454 
455 /**	Set fill attributes.
456 	@param	job		Job structure.
457 	@param	pobj	Current object.
458 	@param	backptr	Address of success variable to reset on errors.
459 	@param	erp		Error report, may be NULL.
460 	@return	1 on success, 0 on error.
461 */
462 static
463 void
wxd2lout_attributes_fill(wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_er_t * erp)464 wxd2lout_attributes_fill(
465 	wxd2lat_job_t	*job,
466 	wxd_object_t	*pobj,
467 	int				*backptr,
468 	dk4_er_t		*erp
469 )
470 {
471 	/*	Fill colour
472 	*/
473 
474 	wxd2lout_fill_rgb(job, pobj, backptr, erp);
475 
476 
477 }
478 
479 
480 
481 /**	Return pattern for object.
482 	@param	pobj	Object to pattern.
483 	@return	Pattern number as dk4_gra_pattern_t.
484 */
485 static
486 dk4_gra_pattern_t
wxd2lout_find_pattern(wxd_object_t * pobj)487 wxd2lout_find_pattern(wxd_object_t *pobj)
488 {
489 	dk4_gra_pattern_t	back	= DK4_GRA_PATTERN_30_DEGREE_LEFT;
490 
491 	switch (pobj->csfs) {
492 		case WXD_FS_30_DEGREE_LEFT : {
493 			back = DK4_GRA_PATTERN_30_DEGREE_LEFT;
494 		} break;
495 		case WXD_FS_30_DEGREE_RIGHT : {
496 			back = DK4_GRA_PATTERN_30_DEGREE_RIGHT;
497 		} break;
498 		case WXD_FS_30_DEGREE_SIEVE : {
499 			back = DK4_GRA_PATTERN_30_DEGREE_SIEVE;
500 		} break;
501 		case WXD_FS_45_DEGREE_LEFT : {
502 			back = DK4_GRA_PATTERN_45_DEGREE_LEFT;
503 		} break;
504 		case WXD_FS_45_DEGREE_RIGHT : {
505 			back = DK4_GRA_PATTERN_45_DEGREE_RIGHT;
506 		} break;
507 		case WXD_FS_45_DEGREE_SIEVE : {
508 			back = DK4_GRA_PATTERN_45_DEGREE_SIEVE;
509 		} break;
510 		case WXD_FS_HORIZONTAL_BRICKS : {
511 			back = DK4_GRA_PATTERN_HORIZONTAL_BRICKS;
512 		} break;
513 		case WXD_FS_VERTICAL_BRICKS : {
514 			back = DK4_GRA_PATTERN_VERTICAL_BRICKS;
515 		} break;
516 		case WXD_FS_HORIZONTAL_LINES : {
517 			back = DK4_GRA_PATTERN_HORIZONTAL_LINES;
518 		} break;
519 		case WXD_FS_VERTICAL_LINES : {
520 			back = DK4_GRA_PATTERN_VERTICAL_LINES;
521 		} break;
522 		case WXD_FS_HORIZONTAL_VERTICAL_SIEVE : {
523 			back = DK4_GRA_PATTERN_HORIZONTAL_VERTICAL_SIEVE;
524 		} break;
525 		case WXD_FS_HORIZONTAL_SHINGLES_LEFT : {
526 			back = DK4_GRA_PATTERN_HORIZONTAL_SHINGLES_LEFT;
527 		} break;
528 		case WXD_FS_HORIZONTAL_SHINGLES_RIGHT : {
529 			back = DK4_GRA_PATTERN_HORIZONTAL_SHINGLES_RIGHT;
530 		} break;
531 		case WXD_FS_VERTICAL_SHINGLES_1 : {
532 			back = DK4_GRA_PATTERN_VERTICAL_SHINGLES_1;
533 		} break;
534 		case WXD_FS_VERTICAL_SHINGLES_2 : {
535 			back = DK4_GRA_PATTERN_VERTICAL_SHINGLES_2;
536 		} break;
537 		case WXD_FS_LARGE_FISH_SCALES : {
538 			back = DK4_GRA_PATTERN_LARGE_FISH_SCALES;
539 		} break;
540 		case WXD_FS_SMALL_FISH_SCALES : {
541 			back = DK4_GRA_PATTERN_SMALL_FISH_SCALES;
542 		} break;
543 		case WXD_FS_CIRCLES : {
544 			back = DK4_GRA_PATTERN_CIRCLES;
545 		} break;
546 		case WXD_FS_HEXAGONS : {
547 			back = DK4_GRA_PATTERN_HEXAGONS;
548 		} break;
549 		case WXD_FS_OCTAGONS : {
550 			back = DK4_GRA_PATTERN_OCTAGONS;
551 		} break;
552 		case WXD_FS_HORIZONTAL_TIRES : {
553 			back = DK4_GRA_PATTERN_HORIZONTAL_TIRES;
554 		} break;
555 		case WXD_FS_VERTICAL_TIRES : {
556 			back = DK4_GRA_PATTERN_VERTICAL_TIRES;
557 		} break;
558 
559 	}
560 
561 	return back;
562 }
563 
564 
565 
566 /**	Set stroke attributes.
567 	@param	drw		Drawing structure.
568 	@param	job		Job structure.
569 	@param	pobj	Current object.
570 	@param	backptr	Address of success variable to reset on errors.
571 	@param	use_lc	Flag: Also set line cap.
572 	@param	use_lj	Flag: Use join style and miter limit.
573 	@param	erp		Error report, may be NULL.
574 	@return	1 on success, 0 on error.
575 */
576 static
577 void
wxd2lout_attributes_stroke(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,int use_lc,dk4_er_t * erp)578 wxd2lout_attributes_stroke(
579 	wxd_drawing_t	*drw,
580 	wxd2lat_job_t	*job,
581 	wxd_object_t	*pobj,
582 	int				*backptr,
583 	int				 use_lc,
584 	dk4_er_t		*erp
585 )
586 {
587 
588 	/*	Stroke colour
589 	*/
590 	wxd2lout_stroke_rgb(job, pobj, backptr, erp);
591 
592 	/*
593 		Line width
594 	*/
595 	wxd2lout_line_width(drw, job, pobj, backptr, erp);
596 
597 	/*
598 		Line style and dash length
599 	*/
600 	wxd2lout_line_style(drw, job, pobj, backptr, erp);
601 
602 	/*
603 		Line cap
604 	*/
605 	if (0 != use_lc) {
606 		wxd2lout_line_cap(job, pobj, backptr, erp);
607 
608 	}
609 	/*
610 		Line join
611 	*/
612 	switch (pobj->ot) {
613 		case WXD_OT_POLYLINE : case WXD_OT_O_SPLINE :
614 		case WXD_OT_POLYGON :  case WXD_OT_C_SPLINE :
615 		case WXD_OT_C_ARC: case WXD_OT_BOX : {
616 			wxd2lout_line_join(job, pobj, backptr, erp);
617 		} break;
618 	}
619 
620 
621 }
622 
623 
624 
625 /**	Create polygon or polyline without arrowheads path.
626 	@param	job		Job structure.
627 	@param	pobj	Object to create path for.
628 	@param	backptr	Address of success variable to reset on error.
629 	@param	pbb		Bounding box for path, may be NULL.
630 	@param	erp		Error report, may be NULL.
631 	@param	iscl	Flag: Closed path.
632 */
633 static
634 void
wxd2lout_path_pl_no_arrows(wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_bb_t * pbb,dk4_er_t * erp,int iscl)635 wxd2lout_path_pl_no_arrows(
636 	wxd2lat_job_t	*job,
637 	wxd_object_t	*pobj,
638 	int				*backptr,
639 	dk4_bb_t		*pbb,
640 	dk4_er_t		*erp,
641 	int				 iscl
642 )
643 {
644 	uint16_t		i;
645 
646 	dk4pppt_newpath_moveto(
647 		job->ppp, ((pobj->det).p.p)[0].x, ((pobj->det).p.p)[0].y,
648 		pbb, backptr, erp
649 	);
650 	for (i = 1; i < (pobj->det).p.n; i++) {
651 		dk4pppt_lineto(
652 			job->ppp, ((pobj->det).p.p)[i].x, ((pobj->det).p.p)[i].y,
653 			pbb, backptr, erp
654 		);
655 	}
656 	if (0 != iscl) {
657 		dk4pppt_lineto(
658 			job->ppp, ((pobj->det).p.p)[0].x, ((pobj->det).p.p)[0].y,
659 			pbb, backptr, erp
660 		);
661 		dk4pppt_closepath(job->ppp, backptr, erp);
662 	}
663 
664 }
665 
666 
667 
668 /**	Create Bezier segments for one X-spline segment.
669 	The X-spline segment is drawn completely, 8 Bezier segments
670 	are used per X-spline segment.
671 	@param	job		Job structure.
672 	@param	xs		X-spline structure, control points are set up.
673 	@param	ib		Index of point B (0 for first segment).
674 	@param	backptr	Address of success variable to reset on error.
675 	@param	pbb		Bounding box for path, may be NULL.
676 	@param	erp		Error report, may be NULL.
677 */
678 static
679 void
wxd2lout_path_spline_segment_normal(wxd2lat_job_t * job,dk4_xsp_2d_t * xs,uint16_t ib,int * backptr,dk4_bb_t * pbb,dk4_er_t * erp)680 wxd2lout_path_spline_segment_normal(
681 	wxd2lat_job_t	*job,
682 	dk4_xsp_2d_t	*xs,
683 	uint16_t		 ib,
684 	int				*backptr,
685 	dk4_bb_t		*pbb,
686 	dk4_er_t		*erp
687 )
688 {
689 	double		v0[4];
690 	double		v1[4];
691 	double		t;
692 	double		divisor;
693 	unsigned	i;
694 
695 	divisor = 3.0 * (double)((job->grco).xsss);
696 	if (0 != dk4xsp2d_calculate_value_derivative(v0, xs, 0.0, erp)) {
697 		v0[1] = v0[1] / divisor;
698 		v0[3] = v0[3] / divisor;
699 		if ((uint16_t)0U == ib) {
700 			dk4pppt_newpath_moveto(job->ppp, v0[0], v0[2], pbb, backptr, erp);
701 		}
702 		for (i = 1; i <= (job->grco).xsss; i++) {
703 			t = (double)i / (double)((job->grco).xsss);
704 			if ((job->grco).xsss == i) { t = 1.0; }
705 			if (0 != dk4xsp2d_calculate_value_derivative(v1, xs, t, erp)) {
706 				v1[1] = v1[1] / divisor;
707 				v1[3] = v1[3] / divisor;
708 				dk4pppt_curveto(
709 					job->ppp,
710 					(v0[0]+v0[1]), (v0[2]+v0[3]),
711 					(v1[0]-v1[1]), (v1[2]-v1[3]),
712 					v1[0], v1[2],
713 					pbb, backptr, erp
714 				);
715 				DK4_MEMCPY(v0,v1,sizeof(v0));
716 			}
717 			else {
718 				if (NULL != backptr) { *backptr = 0; }
719 				/* ERROR: X-spline calculation failed */
720 				dk4app_log_1(
721 					job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 39
722 				);
723 			}
724 		}
725 	}
726 	else {
727 		if (NULL != backptr) { *backptr = 0; }
728 		/* ERROR: X-spline calculation failed */
729 		dk4app_log_1(
730 			job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 39
731 		);
732 	}
733 
734 }
735 
736 
737 
738 /**	Create spline path for closed spline or open spline without arrowheads.
739 	@param	job		Job structure.
740 	@param	pobj	Object to create path for.
741 	@param	backptr	Address of success variable to reset on error.
742 	@param	pbb		Bounding box for path, may be NULL.
743 	@param	erp		Error report, may be NULL.
744 	@param	iscl	Flag: Closed path.
745 */
746 static
747 void
wxd2lout_path_spline_no_arrows(wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_bb_t * pbb,dk4_er_t * erp,int iscl)748 wxd2lout_path_spline_no_arrows(
749 	wxd2lat_job_t	*job,
750 	wxd_object_t	*pobj,
751 	int				*backptr,
752 	dk4_bb_t		*pbb,
753 	dk4_er_t		*erp,
754 	int				 iscl
755 )
756 {
757 	dk4_xsp_2d_t	xs;			/* X-spline */
758 	uint16_t		sgn;		/* Current segment to process */
759 #if	VERSION_BEFORE_20190110
760 	uint16_t		ia;			/* Index of point A */
761 	uint16_t		id;			/* Index of point D */
762 #endif
763 	uint16_t		ib;			/* Index of point B */
764 	uint16_t		ic;			/* Index of point C */
765 
766 	dk4xsp2d_reset(&xs);
767 	for (sgn = 0; sgn < (pobj->det).s.n - 1; sgn++) {
768 		ib = sgn;
769 		ic = (uint16_t)(ib + 1U);
770 		if (
771 			(1.0e-8 > fabs(((pobj->det).s.p)[ib].s))
772 			&& (1.0e-8 > fabs(((pobj->det).s.p)[ic].s))
773 		) {
774 			if (0 == sgn) {
775 				dk4pppt_newpath_moveto(
776 					job->ppp,
777 					((pobj->det).s.p)[ib].x, ((pobj->det).s.p)[ib].y,
778 					pbb, backptr, erp
779 				);
780 			}
781 			dk4pppt_lineto(
782 				job->ppp,
783 				((pobj->det).s.p)[ic].x, ((pobj->det).s.p)[ic].y,
784 				pbb, backptr, erp
785 			);
786 		}
787 		else {
788 #if	VERSION_BEFORE_20190110
789 			id = ib + (uint16_t)2U;
790 			ia = ib - (uint16_t)1U;
791 			dk4xsp2d_reset_points(&xs);
792 			dk4xsp2d_set_point(
793 				&xs,
794 				((pobj->det).s.p)[ib].x, ((pobj->det).s.p)[ib].y,
795 				((pobj->det).s.p)[ib].s, 1
796 			);
797 			dk4xsp2d_set_point(
798 				&xs,
799 				((pobj->det).s.p)[ic].x, ((pobj->det).s.p)[ic].y,
800 				((pobj->det).s.p)[ic].s, 2
801 			);
802 			if ((uint16_t)0U != ib) {
803 				dk4xsp2d_set_point(
804 					&xs,
805 					((pobj->det).s.p)[ia].x, ((pobj->det).s.p)[ia].y,
806 					((pobj->det).s.p)[ia].s, 0
807 				);
808 			}
809 			else {
810 				if (0 != iscl) {
811 					ia = (pobj->det).s.n - (uint16_t)1U;
812 					dk4xsp2d_set_point(
813 						&xs,
814 						((pobj->det).s.p)[ia].x, ((pobj->det).s.p)[ia].y,
815 						((pobj->det).s.p)[ia].s, 0
816 					);
817 				}
818 			}
819 			if (id < (pobj->det).s.n) {
820 				dk4xsp2d_set_point(
821 					&xs,
822 					((pobj->det).s.p)[id].x, ((pobj->det).s.p)[id].y,
823 					((pobj->det).s.p)[id].s, 3
824 				);
825 			}
826 			else {
827 				if (0 != iscl) {
828 					id = (uint16_t)0U;
829 					dk4xsp2d_set_point(
830 						&xs,
831 						((pobj->det).s.p)[id].x, ((pobj->det).s.p)[id].y,
832 						((pobj->det).s.p)[id].s, 3
833 					);
834 				}
835 			}
836 #else
837 			wxd2lxs_set_xspline(&xs, pobj, ib);
838 #endif
839 			wxd2lout_path_spline_segment_normal(
840 				job, &xs, sgn, backptr, pbb, erp
841 			);
842 		}
843 	}
844 	if (0 != iscl) {
845 		ib = (uint16_t)((pobj->det).s.n - 1U);
846 		ic = (uint16_t)0U;
847 		if (
848 			(1.0e-8 > fabs(((pobj->det).s.p)[ib].s))
849 			&& (1.0e-8 > fabs(((pobj->det).s.p)[ic].s))
850 		) {
851 			dk4pppt_lineto(
852 				job->ppp,
853 				((pobj->det).s.p)[ic].x, ((pobj->det).s.p)[ic].y,
854 				pbb, backptr, erp
855 			);
856 		}
857 		else {
858 #if	VERSION_BEFORE_20190110
859 			ia = (pobj->det).s.n - (uint16_t)2U;
860 			id = (uint16_t)1U;
861 			dk4xsp2d_reset_points(&xs);
862 			dk4xsp2d_set_point(
863 				&xs,
864 				((pobj->det).s.p)[ia].x, ((pobj->det).s.p)[ia].y,
865 				((pobj->det).s.p)[ia].s, 0
866 			);
867 			dk4xsp2d_set_point(
868 				&xs,
869 				((pobj->det).s.p)[ib].x, ((pobj->det).s.p)[ib].y,
870 				((pobj->det).s.p)[ib].s, 1
871 			);
872 			dk4xsp2d_set_point(
873 				&xs,
874 				((pobj->det).s.p)[ic].x, ((pobj->det).s.p)[ic].y,
875 				((pobj->det).s.p)[ic].s, 2
876 			);
877 			dk4xsp2d_set_point(
878 				&xs,
879 				((pobj->det).s.p)[id].x, ((pobj->det).s.p)[id].y,
880 				((pobj->det).s.p)[id].s, 3
881 			);
882 #else
883 			wxd2lxs_set_xspline(&xs, pobj, ib);
884 #endif
885 			wxd2lout_path_spline_segment_normal(
886 				job, &xs, ib, backptr, pbb, erp
887 			);
888 		}
889 		dk4pppt_closepath(job->ppp, backptr, erp);
890 	}
891 
892 }
893 
894 
895 
896 /**	Create arc path for given start and end angle.
897 	@param	drw		Drawing structure.
898 	@param	job		Job structure.
899 	@param	pobj	Object to create path for.
900 	@param	alpha	Start angle in radians.
901 	@param	beta	End angle in radians.
902 	@param	backptr	Address of success variable to reset on error.
903 	@param	pbb		Bounding box for path, may be NULL.
904 	@param	erp		Error report, may be NULL.
905 	@param	iscl	Flag: Closed path.
906 */
907 static
908 void
wxd2lout_path_arc_angles(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj,double alpha,double beta,int * backptr,dk4_bb_t * pbb,dk4_er_t * erp,int iscl)909 wxd2lout_path_arc_angles(
910 	wxd_drawing_t	*drw,
911 	wxd2lat_job_t	*job,
912 	wxd_object_t	*pobj,
913 	double			 alpha,
914 	double			 beta,
915 	int				*backptr,
916 	dk4_bb_t		*pbb,
917 	dk4_er_t		*erp,
918 	int				 iscl
919 )
920 {
921 	double		 v0[4];		/* Start point of current segment */
922 	double		 v1[4];		/* End point of current segment */
923 	double		 angle;		/* Complete arc angle */
924 	double		 pos;		/* Angle position at end of current segment */
925 	double		 kappa;		/* Kappa value */
926 	double		 segan;		/* Segment angle */
927 	size_t		 nsegs;		/* Number of segments */
928 	size_t		 i;			/* Current segment */
929 
930 	if (0 != (pobj->det).a.d) {
931 		/*
932 			Real arc.
933 		*/
934 		angle = beta - alpha;
935 
936 		nsegs = (size_t)ceil(4.0 * fabs(angle) / M_PI);
937 		if (1 > nsegs) { nsegs = 1; }
938 
939 		segan = angle / (double)nsegs;
940 
941 		kappa = dk4gratool_kappa_for_angle(fabs(segan));
942 
943 		v0[0] = (pobj->det).a.x + (pobj->det).a.r * cos(alpha);
944 		v0[1] = (pobj->det).a.y + (pobj->det).a.r * sin(alpha);
945 		v0[2] = -1.0 * kappa * segan * (pobj->det).a.r * sin(alpha);
946 		v0[3] =        kappa * segan * (pobj->det).a.r * cos(alpha);
947 		for (i = 0; i < nsegs; i++) {
948 			if (0 == i) {
949 				dk4pppt_newpath_moveto(
950 					job->ppp, v0[0], v0[1], NULL, backptr, erp
951 				);
952 			}
953 			if (i < (nsegs - 1)) {
954 				pos = alpha
955 					+ ((angle * (double)(i + (size_t)1U)) / (double)nsegs);
956 			}
957 			else {
958 				pos = beta;
959 			}
960 			v1[0] = (pobj->det).a.x + (pobj->det).a.r * cos(pos);
961 			v1[1] = (pobj->det).a.y + (pobj->det).a.r * sin(pos);
962 			v1[2] = -1.0 * kappa * segan * (pobj->det).a.r * sin(pos);
963 			v1[3] =        kappa * segan * (pobj->det).a.r * cos(pos);
964 			dk4pppt_curveto(
965 				job->ppp,
966 				(v0[0] + v0[2]), (v0[1] + v0[3]),
967 				(v1[0] - v1[2]), (v1[1] - v1[3]),
968 				v1[0], v1[1],
969 				pbb, backptr, erp
970 			);
971 			DK4_MEMCPY(v0,v1,sizeof(v0));
972 		}
973 		if (0 != iscl) {
974 			dk4pppt_lineto(
975 				job->ppp, (pobj->det).a.x, (pobj->det).a.y, pbb, backptr, erp
976 			);
977 			v0[0] = (pobj->det).a.x + (pobj->det).a.r * cos(alpha);
978 			v0[1] = (pobj->det).a.y + (pobj->det).a.r * sin(alpha);
979 			dk4pppt_lineto(
980 				job->ppp, v0[0], v0[1], pbb, backptr, erp
981 			);
982 		}
983 	}
984 	else {
985 		/*	Malformed arc, points either on one line or equal.
986 		*/
987 		dk4pppt_newpath_moveto(
988 			job->ppp,
989 			wxd2lout_convert_x(drw, job, (double)((pobj->det).a.x1)),
990 			wxd2lout_convert_y(drw, job, (double)((pobj->det).a.y1)),
991 			NULL, backptr, erp
992 		);
993 		dk4pppt_lineto(
994 			job->ppp,
995 			wxd2lout_convert_x(drw, job, (double)((pobj->det).a.x2)),
996 			wxd2lout_convert_y(drw, job, (double)((pobj->det).a.y2)),
997 			NULL, backptr, erp
998 		);
999 		dk4pppt_lineto(
1000 			job->ppp,
1001 			wxd2lout_convert_x(drw, job, (double)((pobj->det).a.x3)),
1002 			wxd2lout_convert_y(drw, job, (double)((pobj->det).a.y3)),
1003 			NULL, backptr, erp
1004 		);
1005 		if (0 != iscl) {
1006 			dk4pppt_lineto(
1007 				job->ppp,
1008 				wxd2lout_convert_x(drw, job, (double)((pobj->det).a.x1)),
1009 				wxd2lout_convert_y(drw, job, (double)((pobj->det).a.y1)),
1010 				NULL, backptr, erp
1011 			);
1012 			dk4pppt_closepath(job->ppp, backptr, erp);
1013 		}
1014 	}
1015 
1016 }
1017 
1018 
1019 
1020 /**	Create arc path for closed arcs or open arcs without arrowheads.
1021 	@param	drw		Drawing structure.
1022 	@param	job		Job structure.
1023 	@param	pobj	Object to create path for.
1024 	@param	backptr	Address of success variable to reset on error.
1025 	@param	pbb		Bounding box for path, may be NULL.
1026 	@param	erp		Error report, may be NULL.
1027 	@param	iscl	Flag: Closed path.
1028 */
1029 static
1030 void
wxd2lout_path_arc_no_arrows(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_bb_t * pbb,dk4_er_t * erp,int iscl)1031 wxd2lout_path_arc_no_arrows(
1032 	wxd_drawing_t	*drw,
1033 	wxd2lat_job_t	*job,
1034 	wxd_object_t	*pobj,
1035 	int				*backptr,
1036 	dk4_bb_t		*pbb,
1037 	dk4_er_t		*erp,
1038 	int				 iscl
1039 )
1040 {
1041 
1042 	wxd2lout_path_arc_angles(
1043 		drw, job, pobj, (pobj->det).a.a, (pobj->det).a.b,
1044 		backptr, pbb, erp, iscl
1045 	);
1046 
1047 }
1048 
1049 
1050 
1051 /**	Create polyline with arrowheads path.
1052 	@param	job		Job structure.
1053 	@param	pobj	Object to create path for.
1054 	@param	backptr	Address of success variable to reset on error.
1055 	@param	pbb		Bounding box for path, may be NULL.
1056 	@param	erp		Error report, may be NULL.
1057 */
1058 static
1059 void
wxd2lout_path_pl_with_arrows(wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_bb_t * pbb,dk4_er_t * erp)1060 wxd2lout_path_pl_with_arrows(
1061 	wxd2lat_job_t	*job,
1062 	wxd_object_t	*pobj,
1063 	int				*backptr,
1064 	dk4_bb_t		*pbb,
1065 	dk4_er_t		*erp
1066 )
1067 {
1068 	double			x0;		/* X coordinate first/last point */
1069 	double			y0;		/* Y coordinate first/last point */
1070 	double			x1;		/* X coordinate second/penultimate point */
1071 	double			y1;		/* Y coordinate second/penultimate point */
1072 	double			sl;		/* Segment length */
1073 	double			cl;		/* Cut length */
1074 	double			nl;		/* Non-cut length */
1075 	uint16_t		i;		/* Current inner point */
1076 
1077 	/*
1078 		Move to first point
1079 	*/
1080 	x0 = ((pobj->det).p.p)[0].x;
1081 	y0 = ((pobj->det).p.p)[0].y;
1082 
1083 	if (0 != (pobj->ab).type) {
1084 		x1 = ((pobj->det).p.p)[1].x;
1085 		y1 = ((pobj->det).p.p)[1].y;
1086 		sl = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
1087 		cl = (pobj->ab).cut;
1088 		nl = sl - cl;
1089 		x0 = ((x0 * nl) + (x1 * cl)) / sl;
1090 		y0 = ((y0 * nl) + (y1 * cl)) / sl;
1091 	}
1092 
1093 	dk4pppt_newpath_moveto(job->ppp, x0, y0, pbb, backptr, erp);
1094 	/*
1095 		Lines to inner points
1096 	*/
1097 	if ((uint16_t)2U < (pobj->det).p.n) {
1098 		for (i = (uint16_t)1U; i < ((pobj->det).p.n) - (uint16_t)1U; i++) {
1099 
1100 			dk4pppt_lineto(
1101 				job->ppp, ((pobj->det).p.p)[i].x, ((pobj->det).p.p)[i].y,
1102 				pbb, backptr, erp
1103 			);
1104 		}
1105 	}
1106 	/*	Line to last point
1107 	*/
1108 	x0 = ((pobj->det).p.p)[(pobj->det).p.n - (uint16_t)1U].x;
1109 	y0 = ((pobj->det).p.p)[(pobj->det).p.n - (uint16_t)1U].y;
1110 
1111 	if (0 != (pobj->af).type) {
1112 		x1 = ((pobj->det).p.p)[(pobj->det).p.n - (uint16_t)2U].x;
1113 		y1 = ((pobj->det).p.p)[(pobj->det).p.n - (uint16_t)2U].y;
1114 		sl = sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0));
1115 		cl = (pobj->af).cut;
1116 		nl = sl - cl;
1117 		x0 = (x0 * nl + x1 * cl) / sl;
1118 		y0 = (y0 * nl + y1 * cl) / sl;
1119 	}
1120 
1121 	dk4pppt_lineto(job->ppp, x0, y0, pbb, backptr, erp);
1122 
1123 }
1124 
1125 
1126 
1127 /**	Create spline path for open spline with arrowheads.
1128 	@param	job			Job structure.
1129 	@param	pobj		Object to create path for.
1130 	@param	ts			Start parameter t.
1131 	@param	te			End parameter t.
1132 	@param	npmoveto	Flag: Start new path and move to first point.
1133 	@param	fullseg		Flag: This is a full segment.
1134 	@param	backptr		Address of success variable to reset on error.
1135 	@param	pbb			Bounding box for path, may be NULL.
1136 	@param	erp			Error report, may be NULL.
1137 	@param	iscl		Flag: Closed path.
1138 */
1139 static
1140 void
wxd2lout_spline_seg(wxd2lat_job_t * job,wxd_object_t * pobj,double ts,double te,int npmoveto,int fullseg,int * backptr,dk4_bb_t * pbb,dk4_er_t * erp)1141 wxd2lout_spline_seg(
1142 	wxd2lat_job_t	*job,
1143 	wxd_object_t	*pobj,
1144 	double			 ts,
1145 	double			 te,
1146 	int				 npmoveto,
1147 	int				 fullseg,
1148 	int				*backptr,
1149 	dk4_bb_t		*pbb,
1150 	dk4_er_t		*erp
1151 )
1152 {
1153 	double			 v0[4];		/* Start of segment */
1154 	double			 v1[4];		/* End of segment */
1155 	dk4_xsp_2d_t	 xs;		/* X-spline structure */
1156 	double			 diff;		/* Parameter t difference start to end */
1157 	double			 coeff;		/* Coefficient for derivatives */
1158 	double			 t;			/* Current parameter t in range 0 to 1 */
1159 	unsigned		 nsubs;		/* Number of sub segments */
1160 	unsigned		 i;			/* Current sub segment */
1161 	int				 res;		/* Step calculation result */
1162 	uint16_t		 ib;		/* X-spline segment index */
1163 
1164 	ib = (uint16_t)floor(ts);
1165 	wxd2lxs_set_xspline(&xs, pobj, ib);
1166 	diff  = te - ts;
1167 	nsubs = (job->grco).xsss;
1168 	if (0 != fullseg) {
1169 		nsubs = (unsigned)ceil(fabs(diff * (double)nsubs));
1170 		if (0U == nsubs) { nsubs = 1U; }
1171 	}
1172 	coeff = diff / (3.0 * (double)nsubs);
1173 	t = ts - (double)ib;
1174 	res = dk4xsp2d_calculate_value_derivative(v0, &xs, t, erp);
1175 	if (0 != res) {
1176 		v0[1] *= coeff; v0[3] *= coeff;
1177 		for (i = 0U; i < nsubs; i++) {
1178 			if ((nsubs - 1U) == i) {
1179 				t = te;
1180 			}
1181 			else {
1182 				t = ts + ((diff * (double)(i + 1U)) / (double)nsubs);
1183 			}
1184 			t = t - (double)ib;
1185 			res = dk4xsp2d_calculate_value_derivative(v1, &xs, t, erp);
1186 			if (0 != res) {
1187 				v1[1] *= coeff; v1[3] *= coeff;
1188 				if ((0U == i) && (0 != npmoveto)) {
1189 					dk4pppt_newpath_moveto(
1190 						job->ppp, v0[0], v0[2], pbb, backptr, erp
1191 					);
1192 				}
1193 				dk4pppt_curveto(
1194 					job->ppp, (v0[0]+v0[1]), (v0[2]+v0[3]), (v1[0]-v1[1]),
1195 					(v1[2]-v1[3]), v1[0], v1[2], pbb, backptr, erp
1196 				);
1197 			}
1198 			else {
1199 				*backptr = 0;
1200 				/* ERROR: Calculation failed */
1201 				dk4app_log_1(
1202 					job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 39
1203 				);
1204 			}
1205 			DK4_MEMCPY(v0,v1,sizeof(v0));
1206 		}
1207 	}
1208 	else {
1209 		*backptr = 0;
1210 		/* ERROR: Calculation failed */
1211 		dk4app_log_1(
1212 			job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 39
1213 		);
1214 	}
1215 
1216 }
1217 
1218 
1219 /**	Create spline path for open spline with arrowheads.
1220 	@param	drw		Drawing structure.
1221 	@param	job		Job structure.
1222 	@param	pobj	Object to create path for.
1223 	@param	backptr	Address of success variable to reset on error.
1224 	@param	pbb		Bounding box for path, may be NULL.
1225 	@param	erp		Error report, may be NULL.
1226 	@param	iscl	Flag: Closed path.
1227 */
1228 static
1229 void
wxd2lout_path_spline_with_arrows(wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_bb_t * pbb,dk4_er_t * erp)1230 wxd2lout_path_spline_with_arrows(
1231 	wxd2lat_job_t	*job,
1232 	wxd_object_t	*pobj,
1233 	int				*backptr,
1234 	dk4_bb_t		*pbb,
1235 	dk4_er_t		*erp
1236 )
1237 {
1238 	uint16_t		ss;
1239 	uint16_t		se;
1240 	uint16_t		i;
1241 
1242 	ss = (uint16_t)floor((pobj->det).s.ts);
1243 	se = (uint16_t)floor((pobj->det).s.te);
1244 	if (0 != (pobj->ab).type) {
1245 		if (0 != (pobj->af).type) {
1246 			if (se > ss) {
1247 				wxd2lout_spline_seg(
1248 					job, pobj, (pobj->det).s.ts, (double)(ss + 1), 1, 0,
1249 					backptr, pbb, erp
1250 				);
1251 				for (i = (uint16_t)(ss + 1U); i < se; i++) {
1252 					wxd2lout_spline_seg(
1253 						job, pobj, (double)i, (double)(i + 1), 0, 1,
1254 						backptr, pbb, erp
1255 					);
1256 				}
1257 				if ((pobj->det).s.te > floor((pobj->det).s.te)) {
1258 					wxd2lout_spline_seg(
1259 						job, pobj, (double)se, (pobj->det).s.te, 0, 0,
1260 						backptr, pbb, erp
1261 					);
1262 				}
1263 			}
1264 			else {
1265 				wxd2lout_spline_seg(
1266 					job, pobj, (pobj->det).s.ts, (pobj->det).s.te, 1, 0,
1267 					backptr, pbb, erp
1268 				);
1269 			}
1270 		}
1271 		else {
1272 			wxd2lout_spline_seg(
1273 				job, pobj, (pobj->det).s.ts, (double)(ss + 1), 1, 0,
1274 				backptr, pbb, erp
1275 			);
1276 			for (i = (uint16_t)(ss + 1U); i < (pobj->det).s.n - 1; i++) {
1277 				wxd2lout_spline_seg(
1278 					job, pobj, (double)i, (double)(i + 1), 0, 1,
1279 					backptr, pbb, erp
1280 				);
1281 			}
1282 		}
1283 	}
1284 	else {
1285 		if (0 != (pobj->af).type) {
1286 			for (i = 0; i < se; i++) {
1287 				wxd2lout_spline_seg(
1288 					job, pobj, (double)i, (double)(i + 1),
1289 					((0 == i) ? 1 : 0), 1, backptr, pbb, erp
1290 				);
1291 			}
1292 			if ((pobj->det).s.te > floor((pobj->det).s.te)) {
1293 				wxd2lout_spline_seg(
1294 					job, pobj, (double)se, (pobj->det).s.te, 0, 0,
1295 					backptr, pbb, erp
1296 				);
1297 			}
1298 		}
1299 		else {
1300 			wxd2lout_path_spline_no_arrows(job, pobj, backptr, pbb, erp, 0);
1301 		}
1302 	}
1303 
1304 }
1305 
1306 
1307 
1308 /**	Create arc path for open arcs with at least one arrowhead.
1309 	@param	drw		Drawing structure.
1310 	@param	job		Job structure.
1311 	@param	pobj	Object to create path for.
1312 	@param	backptr	Address of success variable to reset on error.
1313 	@param	pbb		Bounding box for path, may be NULL.
1314 	@param	erp		Error report, may be NULL.
1315 	@param	iscl	Flag: Closed path.
1316 */
1317 static
1318 void
wxd2lout_path_arc_with_arrows(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_bb_t * pbb,dk4_er_t * erp,int iscl)1319 wxd2lout_path_arc_with_arrows(
1320 	wxd_drawing_t	*drw,
1321 	wxd2lat_job_t	*job,
1322 	wxd_object_t	*pobj,
1323 	int				*backptr,
1324 	dk4_bb_t		*pbb,
1325 	dk4_er_t		*erp,
1326 	int				 iscl
1327 )
1328 {
1329 	double	alpha;		/* Start angle */
1330 	double	beta;		/* End angle */
1331 	double	x1;			/* X coordinate point 1 */
1332 	double	y1;			/* Y coordinate point 1 */
1333 	double	x2;			/* X coordinate point 2 */
1334 	double	y2;			/* Y coordinate point 2 */
1335 	double	x3;			/* X coordinate point 3 */
1336 	double	y3;			/* Y coordinate point 3 */
1337 	double	sl;			/* Segment length */
1338 	double	cl;			/* Cut length */
1339 	double	nl;			/* Non-cut length */
1340 
1341 	if (0 != (pobj->det).a.d) {
1342 		alpha = (pobj->det).a.a;
1343 		beta  = (pobj->det).a.b;
1344 
1345 
1346 		if (0 < (pobj->det).a.d) {
1347 			if (0 != (pobj->ab).type) {
1348 
1349 				alpha += (pobj->ab).cut / (pobj->det).a.r;
1350 
1351 			}
1352 			if (0 != (pobj->af).type) {
1353 
1354 				beta  -= (pobj->af).cut / (pobj->det).a.r;
1355 
1356 			}
1357 		}
1358 		else {
1359 			if (0 != (pobj->ab).type) {
1360 
1361 				alpha -= (pobj->ab).cut / (pobj->det).a.r;
1362 
1363 			}
1364 			if (0 != (pobj->af).type) {
1365 
1366 				beta  += (pobj->af).cut / (pobj->det).a.r;
1367 
1368 			}
1369 		}
1370 		wxd2lout_path_arc_angles(
1371 			drw, job, pobj, alpha, beta, backptr, pbb, erp, iscl
1372 		);
1373 	}
1374 	else {
1375 		/*	Malformed arc as polygon, cut ends for arrows.
1376 		*/
1377 		x1 = wxd2lout_convert_x(drw, job, (double)((pobj->det).a.x1));
1378 		x2 = wxd2lout_convert_x(drw, job, (double)((pobj->det).a.x2));
1379 		x3 = wxd2lout_convert_x(drw, job, (double)((pobj->det).a.x3));
1380 		y1 = wxd2lout_convert_y(drw, job, (double)((pobj->det).a.y1));
1381 		y2 = wxd2lout_convert_y(drw, job, (double)((pobj->det).a.y2));
1382 		y3 = wxd2lout_convert_y(drw, job, (double)((pobj->det).a.y3));
1383 		if (0 != (pobj->ab).type) {
1384 			sl = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
1385 			cl = (pobj->ab).cut;
1386 			nl = sl - cl;
1387 			x1 = (x1 * nl + x2 * cl) / sl;
1388 			y1 = (y1 * nl + y2 * cl) / sl;
1389 		}
1390 		dk4pppt_newpath_moveto(job->ppp, x1, y1, pbb, backptr, erp);
1391 		dk4pppt_lineto(job->ppp, x2, y2, pbb, backptr, erp);
1392 		if (0 != (pobj->af).type) {
1393 			sl = sqrt((x2 - x3) * (x2 - x3) + (y2 - y3) * (y2 - y3));
1394 			cl = (pobj->af).cut;
1395 			nl = sl - cl;
1396 			x3 = (x3 * nl + x2 * cl) / sl;
1397 			y3 = (y3 * nl + y2 * cl) / sl;
1398 		}
1399 		dk4pppt_lineto(job->ppp, x3, y3, pbb, backptr, erp);
1400 	}
1401 
1402 }
1403 
1404 
1405 
1406 /**	Create polyline or polygon path.
1407 	@param	job		Job structure.
1408 	@param	pobj	Object to create path for.
1409 	@param	backptr	Address of success variable to reset on error.
1410 	@param	pbb		Bounding box for path, may be NULL.
1411 	@param	erp		Error report, may be NULL.
1412 	@param	iscl	Flag: Closed path.
1413 */
1414 static
1415 void
wxd2lout_path_polyline(wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_bb_t * pbb,dk4_er_t * erp,int iscl)1416 wxd2lout_path_polyline(
1417 	wxd2lat_job_t	*job,
1418 	wxd_object_t	*pobj,
1419 	int				*backptr,
1420 	dk4_bb_t		*pbb,
1421 	dk4_er_t		*erp,
1422 	int				 iscl
1423 )
1424 {
1425 
1426 	if (
1427 		(0 != iscl)
1428 		|| (((uint8_t)0U == pobj->af.type) && ((uint8_t)0U == pobj->ab.type))
1429 	) {
1430 		/*	Closed polygon or polyline without arrows.
1431 		*/
1432 		wxd2lout_path_pl_no_arrows(job, pobj, backptr, pbb, erp, iscl);
1433 	}
1434 	else {
1435 		/*	Polyline with at least one arrow.
1436 		*/
1437 		wxd2lout_path_pl_with_arrows(job, pobj, backptr, pbb, erp);
1438 	}
1439 
1440 }
1441 
1442 
1443 
1444 /**	Create spline path.
1445 	@param	job		Job structure.
1446 	@param	pobj	Object to create path for.
1447 	@param	backptr	Address of success variable to reset on error.
1448 	@param	pbb		Bounding box for path, may be NULL.
1449 	@param	erp		Error report, may be NULL.
1450 	@param	iscl	Flag: Closed path.
1451 */
1452 static
1453 void
wxd2lout_path_spline(wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_bb_t * pbb,dk4_er_t * erp,int iscl)1454 wxd2lout_path_spline(
1455 	wxd2lat_job_t	*job,
1456 	wxd_object_t	*pobj,
1457 	int				*backptr,
1458 	dk4_bb_t		*pbb,
1459 	dk4_er_t		*erp,
1460 	int				 iscl
1461 )
1462 {
1463 
1464 	if (
1465 		(0 != iscl)
1466 		|| (((uint8_t)0U == pobj->af.type) && ((uint8_t)0U == pobj->ab.type))
1467 	) {
1468 		/*	Closed spline or open spline without arrowheads.
1469 		*/
1470 		wxd2lout_path_spline_no_arrows(job, pobj, backptr, pbb, erp, iscl);
1471 	}
1472 	else {
1473 		/*	Open spline with at least one arrowhead.
1474 		*/
1475 		wxd2lout_path_spline_with_arrows(job, pobj, backptr, pbb, erp);
1476 	}
1477 
1478 }
1479 
1480 
1481 
1482 /**	Create arc path.
1483 	@param	drw		Drawing structure.
1484 	@param	job		Job structure.
1485 	@param	pobj	Object to create path for.
1486 	@param	backptr	Address of success variable to reset on error.
1487 	@param	pbb		Bounding box for path, may be NULL.
1488 	@param	erp		Error report, may be NULL.
1489 	@param	iscl	Flag: Closed path.
1490 */
1491 static
1492 void
wxd2lout_path_arc(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_bb_t * pbb,dk4_er_t * erp,int iscl)1493 wxd2lout_path_arc(
1494 	wxd_drawing_t	*drw,
1495 	wxd2lat_job_t	*job,
1496 	wxd_object_t	*pobj,
1497 	int				*backptr,
1498 	dk4_bb_t		*pbb,
1499 	dk4_er_t		*erp,
1500 	int				 iscl
1501 )
1502 {
1503 
1504 	if (
1505 		(0 != iscl)
1506 		|| (((uint8_t)0U == pobj->af.type) && ((uint8_t)0U == pobj->ab.type))
1507 	) {
1508 		/*	Closed arc or open arc without arrowheads.
1509 		*/
1510 		wxd2lout_path_arc_no_arrows(drw,job,pobj,backptr,pbb,erp,iscl);
1511 	}
1512 	else {
1513 		/*	Open arc with at least one arrowhead.
1514 		*/
1515 		wxd2lout_path_arc_with_arrows(drw,job,pobj,backptr,pbb,erp,iscl);
1516 	}
1517 
1518 }
1519 
1520 
1521 
1522 /**	Create circle path.
1523 	@param	job		Job structure.
1524 	@param	pobj	Object to create path for.
1525 	@param	backptr	Address of success variable to reset on error.
1526 	@param	pbb		Bounding box for path, may be NULL.
1527 	@param	erp		Error report, may be NULL.
1528 */
1529 static
1530 void
wxd2lout_path_circle(wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_bb_t * pbb,dk4_er_t * erp)1531 wxd2lout_path_circle(
1532 	wxd2lat_job_t	*job,
1533 	wxd_object_t	*pobj,
1534 	int				*backptr,
1535 	dk4_bb_t		*pbb,
1536 	dk4_er_t		*erp
1537 )
1538 {
1539 
1540 
1541 
1542 
1543 	dk4pppt_circle(
1544 		job->ppp,
1545 		(pobj->det).e.x, (pobj->det).e.y, (pobj->det).e.rx,
1546 		pbb, backptr, erp
1547 	);
1548 
1549 }
1550 
1551 
1552 
1553 /**	Create ellipse path.
1554 	@param	job		Job structure.
1555 	@param	pobj	Object to create path for.
1556 	@param	backptr	Address of success variable to reset on error.
1557 	@param	pbb		Bounding box for path, may be NULL.
1558 	@param	erp		Error report, may be NULL.
1559 */
1560 static
1561 void
wxd2lout_path_ellipse(wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_bb_t * pbb,dk4_er_t * erp)1562 wxd2lout_path_ellipse(
1563 	wxd2lat_job_t	*job,
1564 	wxd_object_t	*pobj,
1565 	int				*backptr,
1566 	dk4_bb_t		*pbb,
1567 	dk4_er_t		*erp
1568 )
1569 {
1570 
1571 	dk4pppt_ellipse(
1572 		job->ppp,
1573 		(pobj->det).e.x, (pobj->det).e.y, (pobj->det).e.rx, (pobj->det).e.ry,
1574 		(pobj->det).e.a, pbb, backptr, erp
1575 	);
1576 
1577 }
1578 
1579 
1580 
1581 /**	Create box path.
1582 	@param	job		Job structure.
1583 	@param	pobj	Object to create path for.
1584 	@param	backptr	Address of success variable to reset on error.
1585 	@param	pbb		Bounding box for path, may be NULL.
1586 	@param	erp		Error report, may be NULL.
1587 */
1588 static
1589 void
wxd2lout_path_box(wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_bb_t * pbb,dk4_er_t * erp)1590 wxd2lout_path_box(
1591 	wxd2lat_job_t	*job,
1592 	wxd_object_t	*pobj,
1593 	int				*backptr,
1594 	dk4_bb_t		*pbb,
1595 	dk4_er_t		*erp
1596 )
1597 {
1598 
1599 	dk4pppt_rectangle(
1600 		job->ppp,
1601 		(pobj->det).b.xl, (pobj->det).b.xr,
1602 		(pobj->det).b.yb, (pobj->det).b.yt,
1603 		((0.0 < (pobj->det).b.r) ? ((pobj->det).b.r) : (-1.0)),
1604 		pbb, backptr, erp
1605 	);
1606 
1607 }
1608 
1609 
1610 
1611 /**	Create dot path.
1612 	@param	job		Job structure.
1613 	@param	pobj	Object to create path for.
1614 	@param	backptr	Address of success variable to reset on error.
1615 	@param	pbb		Bounding box for path, may be NULL.
1616 	@param	erp		Error report, may be NULL.
1617 */
1618 static
1619 void
wxd2lout_path_dot(wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_bb_t * pbb,dk4_er_t * erp)1620 wxd2lout_path_dot(
1621 	wxd2lat_job_t	*job,
1622 	wxd_object_t	*pobj,
1623 	int				*backptr,
1624 	dk4_bb_t		*pbb,
1625 	dk4_er_t		*erp
1626 )
1627 {
1628 
1629 	dk4pppt_circle(
1630 		job->ppp, (pobj->det).d.x, (pobj->det).d.y, ((pobj->det).d.d / 2.0),
1631 		pbb, backptr, erp
1632 	);
1633 
1634 }
1635 
1636 
1637 
1638 
1639 /**	Create object path.
1640 	@param	drw		Drawing structure.
1641 	@param	job		Job structure.
1642 	@param	pobj	Object to create path for.
1643 	@param	backptr	Address of success variable to reset on error.
1644 	@param	pbb		Bounding box for path, may be NULL.
1645 	@param	erp		Error report, may be NULL.
1646 */
1647 static
1648 void
wxd2lout_object_path(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj,int * backptr,dk4_bb_t * pbb,dk4_er_t * erp)1649 wxd2lout_object_path(
1650 	wxd_drawing_t	*drw,
1651 	wxd2lat_job_t	*job,
1652 	wxd_object_t	*pobj,
1653 	int				*backptr,
1654 	dk4_bb_t		*pbb,
1655 	dk4_er_t		*erp
1656 )
1657 {
1658 
1659 	switch (pobj->ot) {
1660 		case WXD_OT_POLYLINE : {
1661 			wxd2lout_path_polyline(job, pobj, backptr, pbb, erp, 0);
1662 		} break;
1663 		case WXD_OT_O_SPLINE : {
1664 			wxd2lout_path_spline(job, pobj, backptr, pbb, erp, 0);
1665 		} break;
1666 		case WXD_OT_O_ARC : {
1667 			wxd2lout_path_arc(drw, job, pobj, backptr, pbb, erp, 0);
1668 		} break;
1669 		case WXD_OT_POLYGON : {
1670 			wxd2lout_path_polyline(job, pobj, backptr, pbb, erp, 1);
1671 		} break;
1672 		case WXD_OT_C_SPLINE : {
1673 			wxd2lout_path_spline(job, pobj, backptr, pbb, erp, 1);
1674 		} break;
1675 		case WXD_OT_C_ARC : {
1676 			wxd2lout_path_arc(drw, job, pobj, backptr, pbb, erp, 1);
1677 		} break;
1678 		case WXD_OT_CIRCLE : {
1679 			wxd2lout_path_circle(job, pobj, backptr, pbb, erp);
1680 		} break;
1681 		case WXD_OT_ELLIPSE : {
1682 			wxd2lout_path_ellipse(job, pobj, backptr, pbb, erp);
1683 		} break;
1684 		case WXD_OT_BOX : {
1685 			wxd2lout_path_box(job, pobj, backptr, pbb, erp);
1686 		} break;
1687 		case WXD_OT_DOT_FILLED : {
1688 			wxd2lout_path_dot(job, pobj, backptr, pbb, erp);
1689 		} break;
1690 		case WXD_OT_DOT_WHITE : {
1691 			wxd2lout_path_dot(job, pobj, backptr, pbb, erp);
1692 		} break;
1693 	}
1694 
1695 }
1696 
1697 
1698 
1699 static
1700 dk4_text_align_h_t
wxd2lout_h_text_align(uint8_t a)1701 wxd2lout_h_text_align(uint8_t a)
1702 {
1703 	dk4_text_align_h_t	back = DK4_TEXT_ALIGN_H_LEFT;
1704 	switch ((int)a) {
1705 		case 1: {
1706 			back = DK4_TEXT_ALIGN_H_CENTERED;
1707 		} break;
1708 		case 2: {
1709 			back = DK4_TEXT_ALIGN_H_RIGHT;
1710 		} break;
1711 	}
1712 	return back;
1713 }
1714 
1715 
1716 
1717 /**	Create output for one text object.
1718 	@param	job		Job structure containing the output structure.
1719 	@param	pobj	Object to process.
1720 	@return	1 on success, 0 on error.
1721 */
1722 static
1723 int
wxd2lout_text_object(wxd2lat_job_t * job,wxd_object_t * pobj)1724 wxd2lout_text_object(
1725 	wxd2lat_job_t	*job,
1726 	wxd_object_t	*pobj
1727 )
1728 {
1729 	dkChar				 buf[2048];
1730 	dk4_er_t			 er;
1731 	int			 		 back	= 1;
1732 	int					 res;
1733 	dk4_gra_tf_t		 fonttype	=	DK4_GRA_TF_SIMILAR_SIZE;
1734 
1735 	if (DK4_GRA_PURPOSE_DOCUMENT == (job->grco).purpose) {
1736 		fonttype = DK4_GRA_TF_EXACT_SIZE;
1737 	}
1738 	dk4error_init(&er);
1739 	res = dk4recode_c8_to_dk(
1740 		buf, DK4_SIZEOF(buf,dkChar), dk4app_get_encoding(job->app),
1741 		(pobj->det).t.t, DK4_ENCODING_UTF8, &er
1742 	);
1743 	if (0 != res) {
1744 		wxd2lout_fill_rgb(job, pobj, &back, &er);
1745 		if (0 != back) {
1746 			if (0x00 != (0x01 & ((pobj->det).t.fl))) {
1747 				/*
1748 					Special text
1749 				*/
1750 				fonttype = DK4_GRA_TF_NONE_NONE;
1751 				dk4pppt_special_text(
1752 					job->ppp, (pobj->det).t.x, (pobj->det).t.y, (pobj->det).t.a,
1753 					(pobj->det).t.t, NULL,
1754 					wxd2lout_h_text_align((pobj->det).t.al),
1755 					DK4_TEXT_ALIGN_V_BASELINE, (int)((pobj->det).t.find),
1756 					(double)((pobj->det).t.fsz), fonttype, 0, &back, &er
1757 				);
1758 			}
1759 			else {
1760 				/*	Normal text
1761 				*/
1762 				dk4pppt_simple_utf8_text(
1763 					job->ppp, (pobj->det).t.x, (pobj->det).t.y, (pobj->det).t.a,
1764 					(pobj->det).t.t, NULL,
1765 					wxd2lout_h_text_align((pobj->det).t.al),
1766 					DK4_TEXT_ALIGN_V_BASELINE,
1767 					(int)((pobj->det).t.find), (double)((pobj->det).t.fsz),
1768 					fonttype, job->uc2l, 0, &back, &er
1769 				);
1770 			}
1771 			if (0 == back) {
1772 				/* ERROR: Failed to write text */
1773 				dk4app_log_1(
1774 					job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 40
1775 				);
1776 			}
1777 		}
1778 		else {
1779 			/* ERROR: Failed to set fill colour */
1780 			dk4app_log_1(
1781 				job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 41
1782 			);
1783 		}
1784 	}
1785 	else {
1786 		back = 0;
1787 		/* ERROR: UTF-8 decoding failed */
1788 		dk4app_log_1(
1789 			job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 42
1790 		);
1791 	}
1792 
1793 	return back;
1794 }
1795 
1796 
1797 
1798 /**	Create output for one open path object probably with arrowheads attached.
1799 	@param	drw		Original drawing.
1800 	@param	job		Job structure containing the output structure.
1801 	@param	pobj	Object to process.
1802 	@return	1 on success, 0 on error.
1803 */
1804 static
1805 int
wxd2lout_open_path_object(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj)1806 wxd2lout_open_path_object(
1807 	wxd_drawing_t	*drw,
1808 	wxd2lat_job_t	*job,
1809 	wxd_object_t	*pobj
1810 )
1811 {
1812 	dk4_er_t	 er;
1813 	int			 myback;
1814 	int			 back	= 1;
1815 
1816 	dk4error_init(&er);
1817 	if (0.0 < pobj->lw) {
1818 		wxd2lout_attributes_stroke(drw, job, pobj, &back, 1, &er);
1819 
1820 		dk4pppt_prepare_stroke(job->ppp, &back, &er);
1821 
1822 		wxd2lout_object_path(drw, job, pobj, &back, NULL, &er);
1823 
1824 		dk4pppt_stroke(job->ppp, &back, &er);
1825 
1826 		if (0 == back) {
1827 			/* ERROR: Failed to create graphics object */
1828 			dk4app_log_1(
1829 				job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 43
1830 			);
1831 		}
1832 		if ((uint8_t)0U != (pobj->af).type) {
1833 			myback = 1;
1834 			wxd2lah_arrowhead(&(pobj->af), drw, job, pobj, 0, &myback, &er);
1835 			if (0 == myback) {
1836 				back = 0;
1837 				/* ERROR: Failed to create forward arrowhead */
1838 				dk4app_log_1(
1839 					job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 44
1840 				);
1841 			}
1842 
1843 		}
1844 		if ((uint8_t)0U != (pobj->ab).type) {
1845 			myback = 1;
1846 			wxd2lah_arrowhead(&(pobj->ab), drw, job, pobj, 1, &myback, &er);
1847 			if (0 == myback) {
1848 				back = 0;
1849 				/* ERROR: Failed to create backward arrowhead */
1850 				dk4app_log_1(
1851 					job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 45
1852 				);
1853 			}
1854 
1855 		}
1856 	}
1857 	else {
1858 		/* Object skipped */
1859 		/* INFO: Skipping object due to non-positive line-width */
1860 		dk4app_log_1(
1861 			job->app, job->msg, job->sz_msg, DK4_LL_INFO, 46
1862 		);
1863 	}
1864 
1865 	return back;
1866 }
1867 
1868 
1869 
1870 /**	Create output for one closed path object, probably filled or pattern filled.
1871 	@param	drw		Original drawing.
1872 	@param	job		Job structure containing the output structure.
1873 	@param	pobj	Object to process.
1874 	@return	1 on success, 0 on error.
1875 */
1876 static
1877 int
wxd2lout_closed_path_object(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj)1878 wxd2lout_closed_path_object(
1879 	wxd_drawing_t	*drw,
1880 	wxd2lat_job_t	*job,
1881 	wxd_object_t	*pobj
1882 )
1883 {
1884 	dk4_bb_t	 pbb;
1885 	dk4_er_t	 er;
1886 	int			 back	= 1;
1887 	int			 must_stroke	= 0;
1888 	int			 must_fill		= 0;
1889 	int			 must_pattern	= 0;
1890 	int			 combined		= 0;
1891 
1892 	dk4bb_init(&pbb);
1893 	dk4error_init(&er);
1894 	if (0.0 < pobj->lw) {
1895 		must_stroke = 1;
1896 	}
1897 	if ((uint8_t)(WXD_FS_NONE) != pobj->csfs) {
1898 		must_fill = 1;
1899 	}
1900 	if ((uint8_t)(WXD_FS_PURE) < pobj->csfs) {
1901 		must_pattern = 1;
1902 	}
1903 	if ((0 != must_stroke) && (0 != must_fill)) {
1904 		if (0 != dk4pppt_can_fill_and_stroke(job->ppp)) {
1905 			combined = 1;
1906 		}
1907 	}
1908 	if (0 != combined) {
1909 		wxd2lout_attributes_fill(job, pobj, &back, &er);
1910 
1911 		wxd2lout_attributes_stroke(drw, job, pobj, &back, 0, &er);
1912 
1913 		dk4pppt_prepare_fill_and_stroke(job->ppp, &back, &er);
1914 
1915 		wxd2lout_object_path(drw, job, pobj, &back, NULL, &er);
1916 
1917 		dk4pppt_fill_and_stroke(job->ppp, &back, &er);
1918 
1919 		if (0 != must_pattern) {
1920 			dk4pppt_gsave(job->ppp, &back, &er);
1921 
1922 			wxd2lout_object_path(drw, job, pobj, &back, &pbb, &er);
1923 
1924 			dk4pppt_clip(job->ppp, &back, &er);
1925 
1926 			dk4pppt_pattern(
1927 				job->ppp, pbb.xmin, pbb.xmax, pbb.ymin, pbb.ymax,
1928 				wxd2lout_find_pattern(pobj), &back, &er
1929 			);
1930 
1931 			dk4pppt_grestore(job->ppp, &back, &er);
1932 
1933 		}
1934 	}
1935 	else {
1936 		if (0 != must_fill) {
1937 			wxd2lout_attributes_fill(job, pobj, &back, &er);
1938 
1939 			dk4pppt_prepare_fill(job->ppp, &back, &er);
1940 
1941 			wxd2lout_object_path(drw, job, pobj, &back, NULL, &er);
1942 
1943 			dk4pppt_fill(job->ppp, &back, &er);
1944 
1945 		}
1946 		if (0 != must_pattern) {
1947 			dk4pppt_gsave(job->ppp, &back, &er);
1948 
1949 			wxd2lout_object_path(drw, job, pobj, &back, &pbb, &er);
1950 
1951 			dk4pppt_clip(job->ppp, &back, &er);
1952 
1953 			dk4pppt_pattern(
1954 				job->ppp, pbb.xmin, pbb.xmax, pbb.ymin, pbb.ymax,
1955 				wxd2lout_find_pattern(pobj), &back, &er
1956 			);
1957 
1958 			dk4pppt_grestore(job->ppp, &back, &er);
1959 
1960 		}
1961 		if (0 != must_stroke) {
1962 			wxd2lout_attributes_stroke(drw, job, pobj, &back, 0, &er);
1963 
1964 			dk4pppt_prepare_stroke(job->ppp, &back, &er);
1965 
1966 			wxd2lout_object_path(drw, job, pobj, &back, NULL, &er);
1967 
1968 			dk4pppt_stroke(job->ppp, &back, &er);
1969 
1970 		}
1971 	}
1972 	if (0 == back) {
1973 		/* ERROR: Failed to create graphics object */
1974 		dk4app_log_1(
1975 			job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 43
1976 		);
1977 	}
1978 
1979 	return back;
1980 }
1981 
1982 
1983 
1984 /**	Create output for one dot object.
1985 	@param	drw		Original drawing.
1986 	@param	job		Job structure containing the output structure.
1987 	@param	pobj	Object to process.
1988 	@return	1 on success, 0 on error.
1989 */
1990 static
1991 int
wxd2lout_dot_object(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj)1992 wxd2lout_dot_object(
1993 	wxd_drawing_t	*drw,
1994 	wxd2lat_job_t	*job,
1995 	wxd_object_t	*pobj
1996 )
1997 {
1998 	dk4_er_t	 er;
1999 	double		 lw;
2000 	int			 back	= 1;
2001 
2002 	dk4error_init(&er);
2003 
2004 	switch (pobj->ot) {
2005 		case WXD_OT_DOT_FILLED : {
2006 			wxd2lout_attributes_fill(job, pobj, &back, &er);
2007 			if (1 == back) {
2008 				dk4pppt_prepare_fill(job->ppp, &back, &er);
2009 				if (1 == back) {
2010 					dk4pppt_circle(
2011 						job->ppp, (pobj->det).d.x, (pobj->det).d.y,
2012 						((pobj->det).d.d / 2.0), NULL, &back, &er
2013 					);
2014 					dk4pppt_fill(job->ppp, &back, &er);
2015 					if (0 == back) {
2016 						/* ERROR: Failed to create filled circle */
2017 						dk4app_log_1(
2018 							job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 47
2019 						);
2020 					}
2021 				}
2022 				else {
2023 					/* ERROR: Failed to set up filling */
2024 					dk4app_log_1(
2025 						job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 48
2026 					);
2027 				}
2028 			}
2029 			else {
2030 				/* ERROR: Failed to set up filling */
2031 				dk4app_log_1(
2032 					job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 48
2033 				);
2034 			}
2035 		} break;
2036 		case WXD_OT_DOT_WHITE : {
2037 			lw = wxd2lat_object_linewidth(pobj, drw, job);
2038 			if (lw >= (pobj->det).d.d) {
2039 				dk4pppt_set_fill_rgb(
2040 					job->ppp,
2041 					(((double)(pobj->sc[0])) / 255.0),
2042 					(((double)(pobj->sc[1])) / 255.0),
2043 					(((double)(pobj->sc[2])) / 255.0),
2044 					&back, &er
2045 				);
2046 				dk4pppt_prepare_fill(job->ppp, &back, &er);
2047 				dk4pppt_circle(
2048 					job->ppp, (pobj->det).d.x, (pobj->det).d.y,
2049 					((lw + (pobj->det).d.d) / 2.0), NULL, &back, &er
2050 				);
2051 				dk4pppt_fill(job->ppp, &back, &er);
2052 			}
2053 			else {
2054 				if (0 != dk4pppt_can_fill_and_stroke(job->ppp)) {
2055 					wxd2lout_attributes_fill(job, pobj, &back, &er);
2056 					wxd2lout_attributes_stroke(drw, job, pobj, &back, 0, &er);
2057 					dk4pppt_prepare_fill_and_stroke(job->ppp, &back, &er);
2058 					if (1 == back) {
2059 						dk4pppt_circle(
2060 							job->ppp, (pobj->det).d.x, (pobj->det).d.y,
2061 							((pobj->det).d.d / 2.0), NULL, &back, &er
2062 						);
2063 						dk4pppt_fill_and_stroke(job->ppp, &back, &er);
2064 						if (0 == back) {
2065 							/* ERROR: Failed to create filled circle */
2066 							dk4app_log_1(
2067 								job->app,job->msg,job->sz_msg,DK4_LL_ERROR,47
2068 							);
2069 						}
2070 
2071 					}
2072 					else {
2073 						/* ERROR: Failed to set up fill and stroke */
2074 						dk4app_log_1(
2075 							job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 49
2076 						);
2077 					}
2078 				}
2079 				else {
2080 					wxd2lout_attributes_fill(job, pobj, &back, &er);
2081 					dk4pppt_prepare_fill(job->ppp, &back, &er);
2082 					if (0 != back) {
2083 						dk4pppt_circle(
2084 							job->ppp, (pobj->det).d.x, (pobj->det).d.y,
2085 							((pobj->det).d.d / 2.0), NULL, &back, &er
2086 						);
2087 						dk4pppt_fill(job->ppp, &back, &er);
2088 						if (0 != back) {
2089 							wxd2lout_attributes_stroke(
2090 								drw, job, pobj, &back, 0, &er
2091 							);
2092 							dk4pppt_prepare_stroke(job->ppp, &back, &er);
2093 							if (0 != back) {
2094 								dk4pppt_circle(
2095 									job->ppp, (pobj->det).d.x, (pobj->det).d.y,
2096 									((pobj->det).d.d / 2.0), NULL, &back, &er
2097 								);
2098 								dk4pppt_stroke(job->ppp, &back, &er);
2099 								if (0 == back) {
2100 									/* ERROR: Failed to stroke circle */
2101 									dk4app_log_1(
2102 										job->app, job->msg, job->sz_msg,
2103 										DK4_LL_ERROR, 36
2104 									);
2105 
2106 								}
2107 							}
2108 							else {
2109 								/* ERROR: Failed to set up stroke */
2110 								dk4app_log_1(
2111 									job->app, job->msg, job->sz_msg,
2112 									DK4_LL_ERROR, 51
2113 								);
2114 							}
2115 						}
2116 						else {
2117 							/* Failed to create filled circle */
2118 							dk4app_log_1(
2119 								job->app,job->msg,job->sz_msg,DK4_LL_ERROR,47
2120 							);
2121 						}
2122 					}
2123 					else {
2124 						/* ERROR: Failed to set up fill */
2125 						dk4app_log_1(
2126 							job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 48
2127 						);
2128 					}
2129 				}
2130 			}
2131 		} break;
2132 	}
2133 
2134 	return back;
2135 }
2136 
2137 
2138 
2139 /**	Create output for one image object.
2140 	@param	job		Job structure containing the output structure.
2141 	@param	pobj	Object to process.
2142 	@return	1 on success, 0 on error.
2143 */
2144 static
2145 int
wxd2lout_image_object(wxd2lat_job_t * job,wxd_object_t * pobj)2146 wxd2lout_image_object(
2147 	wxd2lat_job_t	*job,
2148 	wxd_object_t	*pobj
2149 )
2150 {
2151 	dkChar	 			 fnb[DK4_MAX_PATH];		/* File name buffer */
2152 	dk4_px_t			 bg[4];					/* Background colour */
2153 	dk4_cs_conv_ctx_t	 ctx;					/* RGB to gray conv context */
2154 	dk4_er_t			 er;					/* Error report */
2155 	dk4_bif_t			*pbif	= NULL;			/* Bitmap image */
2156 	int		 			 back	= 1;			/* Function result */
2157 	int					 ifl	= 0;			/* Image flags */
2158 	int					 fbg	= 0;			/* Flag: Force background */
2159 	int					 res	= 0;			/* Step result */
2160 
2161 	DK4_MEMCPY(&ctx,&((job->grco).ctx),sizeof(dk4_cs_conv_ctx_t));
2162 	bg[0] = (dk4_px_t)(pobj->fc[0]);
2163 	bg[1] = (dk4_px_t)(pobj->fc[1]);
2164 	bg[2] = (dk4_px_t)(pobj->fc[2]);
2165 	if (DK4_CS_CONV_RGB_TO_GRAY_MIN <= (pobj->det).i.r2g) {
2166 		if (DK4_CS_CONV_RGB_TO_GRAY_MAX >= (pobj->det).i.r2g) {
2167 			ctx.rgb_to_gray = (dk4_cs_conv_rgb_to_gray_t)((pobj->det).i.r2g);
2168 		}
2169 	}
2170 	if (0x00 != (0x20 & ((pobj->det).i.fl))) {
2171 		fbg = 1;
2172 	}
2173 	if (0x00 != (0x02 & ((pobj->det).i.fl))) {
2174 		/* Alpha mix */
2175 		ctx.alpha = DK4_CS_CONV_ALPHA_MIX;
2176 	}
2177 	else {
2178 		/* Alpha ignore */
2179 		ctx.alpha = DK4_CS_CONV_ALPHA_FOREGROUND;
2180 	}
2181 	if (0 != (job->grco).color) {
2182 		ifl |= DK4_GRA_IMG_FLAG_COLOR;
2183 	}
2184 	if (0 != (job->grco).ps_lzw) {
2185 		ifl |= DK4_GRA_IMG_FLAG_LZW;
2186 	}
2187 	if (0x00 != (0x08 & ((pobj->det).i.fl))) {
2188 		ifl |= DK4_GRA_IMG_FLAG_DCT;
2189 	}
2190 	if (0x00 != (0x04 & ((pobj->det).i.fl))) {
2191 		ifl |= DK4_GRA_IMG_FLAG_INTERPOLATION;
2192 	}
2193 	if (0x00 != (0x10 & ((pobj->det).i.fl))) {
2194 		ifl |= DK4_GRA_IMG_FLAG_DCT_INTERPOLATION;
2195 	}
2196 	ifl |= DK4_GRA_IMG_FLAG_ANALYZE_BPC;
2197 	ifl |= DK4_GRA_IMG_FLAG_ANALYZE_COLOR;
2198 	ifl |= DK4_GRA_IMG_FLAG_ANALYZE_ALPHA;
2199 	if (0x00 == (0x01 & ((pobj->det).i.fl))) {
2200 		ifl |= DK4_GRA_IMG_FLAG_IGNORE_ASPECT_RATIO;
2201 	}
2202 	res = dk4recode_c8_to_dk(
2203 		fnb, DK4_SIZEOF(fnb,dkChar), dk4app_get_encoding(job->app),
2204 		(pobj->det).i.fn, DK4_ENCODING_UTF8, &er
2205 	);
2206 	if (0 != res) {
2207 		if (0 <= dk4bif_type_for_suffix(fnb)) {
2208 			pbif = dk4bif_open_app(fnb, 0, &ctx, job->app);
2209 			if (NULL != pbif) {
2210 				dk4error_init(&er);
2211 				dk4bif_set_background(pbif, bg, 3, 8, fbg);
2212 				dk4pppt_bif_image(
2213 					job->ppp, (pobj->det).i.x,
2214 					((pobj->det).i.x + (pobj->det).i.w),
2215 					(pobj->det).i.y,
2216 					((pobj->det).i.y + (pobj->det).i.h), pbif, fnb,
2217 					(size_t)0U, ifl, NULL, &back, &er
2218 				);
2219 				dk4bif_close(pbif);
2220 				if (0 == back) {
2221 					/* ERROR: Failed to add bitmap image */
2222 					dk4app_log_1(
2223 						job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 52
2224 					);
2225 				}
2226 			}
2227 			else {
2228 				back = 0;
2229 				/* ERROR: Failed to open file */
2230 			}
2231 		}
2232 		else {
2233 			back = 0;
2234 			/* ERROR: Not a supported bitmap type */
2235 			dk4app_log_1(
2236 				job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 53
2237 			);
2238 		}
2239 	}
2240 	else {
2241 		back = 0;
2242 		/* ERROR: Failed to decode file name! */
2243 		dk4app_log_1(
2244 			job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 54
2245 		);
2246 	}
2247 
2248 	return back;
2249 }
2250 
2251 
2252 
2253 /**	Check one text object if information is complete and object
2254 	can be drawn.
2255 	@param	job		Job structure.
2256 	@param	pobj	Object to check.
2257 	@return	1 on success (further handling possible), 0 otherwise.
2258 */
2259 static
2260 int
wxd2lout_check_one_text_object(wxd2lat_job_t * job,wxd_object_t * pobj)2261 wxd2lout_check_one_text_object(
2262 	wxd2lat_job_t	*job,
2263 	wxd_object_t	*pobj
2264 )
2265 {
2266 	int		back = 0;
2267 
2268 	if (NULL != (pobj->det).t.t) {
2269 		if ((uint16_t)0U != (pobj->det).t.fsz) {
2270 			back = 1;
2271 		}
2272 		else {
2273 			if ((uint8_t)0x00 != ((uint8_t)0x01 & (pobj->det).t.fl)) {
2274 				back = 1;
2275 			}
2276 			else {
2277 				/* ERROR: Font size 0 */
2278 				dk4app_log_1(
2279 					job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 55
2280 				);
2281 			}
2282 		}
2283 	}
2284 	else {
2285 		/* ERROR: No text on object */
2286 		dk4app_log_1(
2287 			job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 56
2288 		);
2289 	}
2290 
2291 	return back;
2292 }
2293 
2294 
2295 
2296 /**	Check one polyline/polygon object if information is complete and object
2297 	can be drawn.
2298 	@param	job		Job structure.
2299 	@param	pobj	Object to check.
2300 	@return	1 on success (further handling possible), 0 otherwise.
2301 */
2302 static
2303 int
wxd2lout_check_one_polyline_object(wxd2lat_job_t * job,wxd_object_t * pobj)2304 wxd2lout_check_one_polyline_object(
2305 	wxd2lat_job_t	*job,
2306 	wxd_object_t	*pobj
2307 )
2308 {
2309 	double	 x0;			/* Coordinate of first point */
2310 	double	 y0;			/* Coordinate of first point */
2311 	double	 x1;			/* Coordinate of second point */
2312 	double	 y1;			/* Coordinate of second point */
2313 	double	 lseg;			/* Segment length */
2314 	size_t	 lp;			/* Index of last point */
2315 	int		 back = 0;
2316 
2317 	if (NULL != (pobj->det).p.p) {
2318 		if ((uint16_t)1U < (pobj->det).p.n) {
2319 			back = 1;
2320 			/*
2321 				For polyline check whether first and last segment
2322 				are long enough for arrowhead cuts.
2323 			*/
2324 			if (WXD_OT_POLYLINE == pobj->ot) {
2325 				lseg = 0.0;
2326 				if (0 != (pobj->ab).type) {
2327 					x0 = ((pobj->det).p.p)[0].x;
2328 					x1 = ((pobj->det).p.p)[1].x;
2329 					y0 = ((pobj->det).p.p)[0].y;
2330 					y1 = ((pobj->det).p.p)[1].y;
2331 					x1 = x1 - x0;
2332 					y1 = y1 - y0;
2333 					lseg = sqrt(x1 * x1 + y1 * y1);
2334 					if (lseg <= (pobj->ab).cut) {
2335 						back = 0;
2336 						/* ERROR: First segment too short */
2337 						dk4app_log_1(
2338 							job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 57
2339 						);
2340 					}
2341 				}
2342 				if (0 != (pobj->af).type) {
2343 					lp = (pobj->det).p.n - 1U;
2344 					x0 = ((pobj->det).p.p)[lp].x;
2345 					x1 = ((pobj->det).p.p)[lp - 1].x;
2346 					y0 = ((pobj->det).p.p)[lp].y;
2347 					y1 = ((pobj->det).p.p)[lp - 1].y;
2348 					x1 = x1 - x0;
2349 					y1 = y1 - y0;
2350 					/*
2351 						Just one segment or multiple segments?
2352 					*/
2353 					if ((uint16_t)2U == (pobj->det).p.n) {
2354 						/*
2355 							If the polyline has just one segment (only
2356 							2 points) the cuts for forward and backward
2357 							arrow are both applied to the same segment.
2358 							So the segment must be longer than the summary
2359 							of the two cuts.
2360 						*/
2361 						lseg += sqrt(x1 * x1 + y1 * y1);
2362 					}
2363 					else {
2364 						/*	Polyline has more than one segments, the
2365 							final segment is cutted for the forward
2366 							arrowhead only.
2367 						*/
2368 						lseg = sqrt(x1 * x1 + y1 * y1);
2369 					}
2370 					if (lseg <= (pobj->af).cut) {
2371 						back = 0;
2372 						/* ERROR: Last segment too short */
2373 						dk4app_log_1(
2374 							job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 58
2375 						);
2376 					}
2377 				}
2378 			}
2379 		}
2380 		else {
2381 			/* ERROR: Too few points */
2382 			dk4app_log_1(
2383 				job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 59
2384 			);
2385 		}
2386 	}
2387 	else {
2388 		/* ERROR: No points for object */
2389 		dk4app_log_1(
2390 			job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 60
2391 		);
2392 	}
2393 
2394 	return back;
2395 }
2396 
2397 
2398 /**	Check one spline object if information is complete and object
2399 	can be drawn.
2400 	@param	drw		Drawing structure.
2401 	@param	job		Job structure.
2402 	@param	pobj	Object to check.
2403 	@return	1 on success (further handling possible), 0 otherwise.
2404 */
2405 static
2406 int
wxd2lout_check_one_spline_object(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj)2407 wxd2lout_check_one_spline_object(
2408 	wxd_drawing_t	*drw,
2409 	wxd2lat_job_t	*job,
2410 	wxd_object_t	*pobj
2411 )
2412 {
2413 	double		 cutl;			/* Length to cut, length of arrowhead */
2414 	int			 back = 0;
2415 
2416 	if (NULL != (pobj->det).s.p) {
2417 		if ((uint16_t)1U < (pobj->det).s.n) {
2418 			back = 1;
2419 			/*
2420 				For open spline object check whether spline
2421 				is long enough for arrowhead cuts.
2422 			*/
2423 			if (WXD_OT_O_SPLINE == pobj->ot) {
2424 				if (
2425 					(0 != (pobj->af).type)
2426 					|| (0 != (pobj->ab).type)
2427 				) {
2428 					cutl = 0.0;
2429 					if (0 != (pobj->af).type) {
2430 						cutl += ((pobj->af).cut + (pobj->af).cuttol);
2431 					}
2432 					if (0 != (pobj->ab).type) {
2433 						cutl += ((pobj->ab).cut + (pobj->ab).cuttol);
2434 					}
2435 					if (cutl >= (pobj->det).s.suml) {
2436 						back = 0;
2437 						/* ERROR: Spline too short */
2438 						dk4app_log_1(
2439 							job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 61
2440 						);
2441 					}
2442 					if (0 != (pobj->af).type) {
2443 						cutl = (pobj->af).offset
2444 							 + (double)((pobj->af).length)
2445 							 * wxd2lat_object_linewidth(pobj, drw, job);
2446 						if (cutl >= (pobj->det).s.suml) {
2447 							back = 0;
2448 							/* ERROR: Forward arrow too long */
2449 							dk4app_log_1(
2450 								job->app, job->msg, job->sz_msg,
2451 								DK4_LL_ERROR, 62
2452 							);
2453 						}
2454 					}
2455 					if (0 != (pobj->ab).type) {
2456 						cutl = (pobj->ab).offset
2457 							 + (double)((pobj->ab).length)
2458 							 * wxd2lat_object_linewidth(pobj, drw, job);
2459 						if (cutl >= (pobj->det).s.suml) {
2460 							back = 0;
2461 							/* ERROR: Backward arrow too long */
2462 							dk4app_log_1(
2463 								job->app, job->msg, job->sz_msg,
2464 								DK4_LL_ERROR, 63
2465 							);
2466 						}
2467 					}
2468 				}
2469 			}
2470 		}
2471 		else {
2472 			/* ERROR: Too few points */
2473 			dk4app_log_1(
2474 				job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 59
2475 			);
2476 		}
2477 	}
2478 	else {
2479 		/* ERROR: No points for object */
2480 		dk4app_log_1(
2481 			job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 60
2482 		);
2483 	}
2484 
2485 	return back;
2486 }
2487 
2488 
2489 
2490 /**	Check one arc object if information is complete and object
2491 	can be drawn.
2492 	@param	drw		Drawing structure.
2493 	@param	job		Job structure.
2494 	@param	pobj	Object to check.
2495 	@return	1 on success (further handling possible), 0 otherwise.
2496 */
2497 static
2498 int
wxd2lout_check_one_arc_object(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj)2499 wxd2lout_check_one_arc_object(
2500 	wxd_drawing_t	*drw,
2501 	wxd2lat_job_t	*job,
2502 	wxd_object_t	*pobj
2503 )
2504 {
2505 
2506 	double	 	 x0;			/* Coordinate of first point */
2507 	double	 	 y0;			/* Coordinate of first point */
2508 	double	 	 x1;			/* Coordinate of second point */
2509 	double	 	 y1;			/* Coordinate of second point */
2510 	double		 cutl;			/* Length to cut, length of arrowhead */
2511 	double		 lseg;			/* Segment length */
2512 	int			 back	= 0;
2513 
2514 	/*
2515 		For open arc object check whether arc is long enough
2516 		for arrowhead cuts.
2517 		For malformed arc check whether segments are long enough
2518 		for the arrowhead cuts.
2519 	*/
2520 	back = 1;
2521 	if (WXD_OT_O_ARC == pobj->ot) {
2522 		if ((0 != (pobj->af).type) || (0 != (pobj->ab).type)) {
2523 			if (0 != (pobj->det).a.d) {
2524 				/*
2525 					Real arc
2526 				*/
2527 				lseg = fabs(
2528 					(pobj->det).a.r
2529 					* ((pobj->det).a.b - (pobj->det).a.a)
2530 				);
2531 				cutl = 0.0;
2532 				if (0 != (pobj->af).type) {
2533 					cutl = (pobj->af).cut;
2534 				}
2535 				if (0 != (pobj->ab).type) {
2536 					cutl += (pobj->ab).cut;
2537 				}
2538 				if (cutl > lseg) {
2539 					back = 0;
2540 					/* ERROR: Arc too short for arrows */
2541 					dk4app_log_1(
2542 						job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 64
2543 					);
2544 				}
2545 				if (0 != (pobj->af).type) {
2546 					cutl = (pobj->af).offset
2547 					 	+ (double)((pobj->af).length)
2548 					 	* wxd2lat_object_linewidth(pobj, drw, job);
2549 					if (cutl > lseg) {
2550 						back = 0;
2551 						/* ERROR: Forward arrow too long */
2552 						dk4app_log_1(
2553 							job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 62
2554 						);
2555 					}
2556 				}
2557 				if (0 != (pobj->ab).type) {
2558 					cutl = (pobj->ab).offset
2559 					 	+ (double)((pobj->ab).length)
2560 					 	* wxd2lat_object_linewidth(pobj, drw, job);
2561 					if (cutl > lseg) {
2562 						back = 0;
2563 						/* ERROR: Backward arrow too long */
2564 						dk4app_log_1(
2565 							job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 63
2566 						);
2567 					}
2568 				}
2569 			}
2570 			else {
2571 				/*	Malformed arc drawn as polyline
2572 				*/
2573 				if (0 != (pobj->af).type) {
2574 					x0 = wxd2lout_convert_x(drw,job,(double)((pobj->det).a.x2));
2575 					y0 = wxd2lout_convert_y(drw,job,(double)((pobj->det).a.y2));
2576 					x1 = wxd2lout_convert_x(drw,job,(double)((pobj->det).a.x3));
2577 					y1 = wxd2lout_convert_y(drw,job,(double)((pobj->det).a.y3));
2578 					x1 = x1 - x0;
2579 					y1 = y1 - y0;
2580 					lseg = sqrt(x1 * x1 + y1 * y1);
2581 					if (lseg <= (pobj->af).cut) {
2582 						back = 0;
2583 						/* ERROR: Forward arrow too long */
2584 						dk4app_log_1(
2585 							job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 62
2586 						);
2587 					}
2588 				}
2589 				if (0 != (pobj->ab).type) {
2590 					x0 = wxd2lout_convert_x(drw,job,(double)((pobj->det).a.x2));
2591 					y0 = wxd2lout_convert_y(drw,job,(double)((pobj->det).a.y2));
2592 					x1 = wxd2lout_convert_x(drw,job,(double)((pobj->det).a.x1));
2593 					y1 = wxd2lout_convert_y(drw,job,(double)((pobj->det).a.y1));
2594 					x1 = x1 - x0;
2595 					y1 = y1 - y0;
2596 					lseg = sqrt(x1 * x1 + y1 * y1);
2597 					if (lseg <= (pobj->ab).cut) {
2598 						back = 0;
2599 						/* ERROR: Backward arrow too long */
2600 						dk4app_log_1(
2601 							job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 63
2602 						);
2603 					}
2604 				}
2605 			}
2606 		}
2607 	}
2608 
2609 	return back;
2610 }
2611 
2612 
2613 
2614 /**	Check one circle object if information is complete and object
2615 	can be drawn.
2616 	@param	job		Job structure.
2617 	@param	pobj	Object to check.
2618 	@return	1 on success (further handling possible), 0 otherwise.
2619 */
2620 static
2621 int
wxd2lout_check_one_circle_object(wxd2lat_job_t * job,wxd_object_t * pobj)2622 wxd2lout_check_one_circle_object(
2623 	wxd2lat_job_t	*job,
2624 	wxd_object_t	*pobj
2625 )
2626 {
2627 	int		 	 back	= 0;
2628 
2629 	if (0.0 < (pobj->det).e.rx) {
2630 		back = 1;
2631 	}
2632 	else {
2633 		/* ERROR: Radius 0 */
2634 		dk4app_log_1(
2635 			job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 65
2636 		);
2637 	}
2638 
2639 	return back;
2640 }
2641 
2642 
2643 
2644 /**	Check one ellipse object if information is complete and object
2645 	can be drawn.
2646 	@param	job		Job structure.
2647 	@param	pobj	Object to check.
2648 	@return	1 on success (further handling possible), 0 otherwise.
2649 */
2650 static
2651 int
wxd2lout_check_one_ellipse_object(wxd2lat_job_t * job,wxd_object_t * pobj)2652 wxd2lout_check_one_ellipse_object(
2653 	wxd2lat_job_t	*job,
2654 	wxd_object_t	*pobj
2655 )
2656 {
2657 	int			 back	= 0;
2658 
2659 	if ((0.0 < (pobj->det).e.rx) && (0.0 < (pobj->det).e.ry)) {
2660 		back = 1;
2661 	}
2662 	else {
2663 		/* ERROR: Radius 0 */
2664 		dk4app_log_1(
2665 			job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 65
2666 		);
2667 	}
2668 
2669 	return back;
2670 }
2671 
2672 
2673 
2674 /**	Check one box object if information is complete and object
2675 	can be drawn.
2676 	@param	job		Job structure.
2677 	@param	pobj	Object to check.
2678 	@return	1 on success (further handling possible), 0 otherwise.
2679 */
2680 static
2681 int
wxd2lout_check_one_box_object(wxd2lat_job_t * job,wxd_object_t * pobj)2682 wxd2lout_check_one_box_object(
2683 	wxd2lat_job_t	*job,
2684 	wxd_object_t	*pobj
2685 )
2686 {
2687 	double		 w;
2688 	double		 h;
2689 	int			 back	= 1;
2690 
2691 	w = fabs((pobj->det).b.xr - (pobj->det).b.xl);
2692 	h = fabs((pobj->det).b.yt - (pobj->det).b.yb);
2693 	if (h < w) {
2694 		w = h;
2695 	}
2696 	if ((pobj->det).b.r > (w / 2.0)) {
2697 		back = 0;
2698 		/* ERROR: Box radius too large */
2699 		dk4app_log_1(
2700 			job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 66
2701 		);
2702 	}
2703 
2704 	return back;
2705 }
2706 
2707 
2708 
2709 /**	Check one dot object if information is complete and object
2710 	can be drawn.
2711 	@param	job		Job structure.
2712 	@param	pobj	Object to check.
2713 	@return	1 on success (further handling possible), 0 otherwise.
2714 */
2715 static
2716 int
wxd2lout_check_one_dot_object(wxd2lat_job_t * job,wxd_object_t * pobj)2717 wxd2lout_check_one_dot_object(
2718 	wxd2lat_job_t	*job,
2719 	wxd_object_t	*pobj
2720 )
2721 {
2722 	int			 back	= 0;
2723 
2724 	if (0.0 < (pobj->det).d.d) {
2725 		back = 1;
2726 	}
2727 	else {
2728 		/* ERROR: Diameter 0 */
2729 		dk4app_log_1(
2730 			job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 67
2731 		);
2732 	}
2733 
2734 	return back;
2735 }
2736 
2737 
2738 
2739 /**	Check one image object if information is complete and object
2740 	can be drawn.
2741 	@param	job		Job structure.
2742 	@param	pobj	Object to check.
2743 	@return	1 on success (further handling possible), 0 otherwise.
2744 */
2745 static
2746 int
wxd2lout_check_one_image_object(wxd2lat_job_t * job,wxd_object_t * pobj)2747 wxd2lout_check_one_image_object(
2748 	wxd2lat_job_t	*job,
2749 	wxd_object_t	*pobj
2750 )
2751 {
2752 	int			 back	= 0;
2753 
2754 	if (NULL != (pobj->det).i.fn) {
2755 		if ((0.0 < (pobj->det).i.w) && (0.0 < (pobj->det).i.h)) {
2756 			back = 1;
2757 		}
2758 		else {
2759 			/* ERROR: Width and height must be positive */
2760 			dk4app_log_1(
2761 				job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 68
2762 			);
2763 		}
2764 	}
2765 	else {
2766 		/* ERROR: No file name */
2767 		dk4app_log_1(
2768 			job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 69
2769 		);
2770 	}
2771 
2772 	return back;
2773 }
2774 
2775 
2776 
2777 /**	Check one graphics object if information is complete and object
2778 	can be drawn.
2779 	@param	drw		Drawing structure.
2780 	@param	job		Job structure.
2781 	@param	pobj	Object to check.
2782 	@return	1 on success (further handling possible), 0 otherwise.
2783 */
2784 static
2785 int
wxd2lout_check_one_graphics_object(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj)2786 wxd2lout_check_one_graphics_object(
2787 	wxd_drawing_t	*drw,
2788 	wxd2lat_job_t	*job,
2789 	wxd_object_t	*pobj
2790 )
2791 {
2792 	int		 back	= 0;
2793 
2794 	switch (pobj->ot) {
2795 		case WXD_OT_TEXT : {
2796 			back = wxd2lout_check_one_text_object(job, pobj);
2797 		} break;
2798 		case WXD_OT_POLYLINE : case WXD_OT_POLYGON : {
2799 			back = wxd2lout_check_one_polyline_object(job, pobj);
2800 		} break;
2801 		case WXD_OT_O_SPLINE : case WXD_OT_C_SPLINE : {
2802 			back = wxd2lout_check_one_spline_object(drw, job, pobj);
2803 		} break;
2804 		case WXD_OT_O_ARC : case WXD_OT_C_ARC : {
2805 			back = wxd2lout_check_one_arc_object(drw, job, pobj);
2806 		} break;
2807 		case WXD_OT_CIRCLE : {
2808 			back = wxd2lout_check_one_circle_object(job, pobj);
2809 		} break;
2810 		case WXD_OT_ELLIPSE : {
2811 			back = wxd2lout_check_one_ellipse_object(job, pobj);
2812 		} break;
2813 		case WXD_OT_BOX : {
2814 			back = wxd2lout_check_one_box_object(job, pobj);
2815 		} break;
2816 		case WXD_OT_DOT_FILLED : case WXD_OT_DOT_WHITE : {
2817 			back = wxd2lout_check_one_dot_object(job, pobj);
2818 		} break;
2819 		case WXD_OT_IMAGE : {
2820 			back = wxd2lout_check_one_image_object(job, pobj);
2821 		} break;
2822 		default : {
2823 			/* ERROR: Illegal object type */
2824 			dk4app_log_1(
2825 				job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 70
2826 			);
2827 		} break;
2828 	}
2829 	if (0 == back) {
2830 		/* ERROR: Object check failed */
2831 		dk4app_log_1(
2832 			job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 71
2833 		);
2834 	}
2835 
2836 	return back;
2837 }
2838 
2839 
2840 
2841 static
2842 int
wxd2lout_is_abnormal_circle(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj)2843 wxd2lout_is_abnormal_circle(
2844 	wxd_drawing_t	*drw,
2845 	wxd2lat_job_t	*job,
2846 	wxd_object_t	*pobj
2847 )
2848 {
2849 	double	 lw;
2850 	int		 back = 0;
2851 
2852 	lw = wxd2lat_object_linewidth(pobj, drw, job);
2853 	if ((pobj->det).e.rx <= (lw / 2.0)) {
2854 		back = 1;
2855 	}
2856 
2857 	return back;
2858 }
2859 
2860 
2861 
2862 /**	Check whether circle is abnormal (diameter smaller than line width).
2863 	@param	drw		Drawing structure.
2864 	@param	job		Job structure.
2865 	@param	pobj	Object to check.
2866 	@return	1 for abnormal circle, 0 for normal circle.
2867 */
2868 static
2869 int
wxd2lout_abnormal_circle(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj)2870 wxd2lout_abnormal_circle(
2871 	wxd_drawing_t	*drw,
2872 	wxd2lat_job_t	*job,
2873 	wxd_object_t	*pobj
2874 )
2875 {
2876 	dk4_er_t	er;
2877 	double		lw;
2878 	int		 	back = 1;
2879 
2880 	lw = wxd2lat_object_linewidth(pobj, drw, job);
2881 	dk4error_init(&er);
2882 	dk4pppt_set_fill_rgb(
2883 		job->ppp,
2884 		(((double)(pobj->sc[0])) / 255.0),
2885 		(((double)(pobj->sc[1])) / 255.0),
2886 		(((double)(pobj->sc[2])) / 255.0),
2887 		&back, &er
2888 	);
2889 	dk4pppt_prepare_fill(job->ppp, &back, &er);
2890 	dk4pppt_circle(
2891 		job->ppp, (pobj->det).e.x, (pobj->det).e.y,
2892 		((pobj->det).e.rx + lw / 2.0), NULL, &back, &er
2893 	);
2894 	dk4pppt_fill(job->ppp, &back, &er);
2895 
2896 	return back;
2897 }
2898 
2899 
2900 
2901 /**	Draw abnormal stroked circle as filled circle.
2902 	@param	drw		Drawing structure.
2903 	@param	job		Job structure.
2904 	@param	pobj	Circle object to draw.
2905 	@return	1 on success, 0 on error.
2906 */
2907 static
2908 int
wxd2lout_is_abnormal_ellipse(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj)2909 wxd2lout_is_abnormal_ellipse(
2910 	wxd_drawing_t	*drw,
2911 	wxd2lat_job_t	*job,
2912 	wxd_object_t	*pobj
2913 )
2914 {
2915 	double	 lw;
2916 	int		 back = 0;
2917 
2918 	lw = wxd2lat_object_linewidth(pobj, drw, job) / 2.0;
2919 	if (((pobj->det).e.rx <= lw) || ((pobj->det).e.ry <= lw)) {
2920 		back = 1;
2921 	}
2922 
2923 	return back;
2924 }
2925 
2926 
2927 
2928 /**	Check whether ellipse is abnormal (one diameter smaller than line width).
2929 	@param	drw		Drawing structure.
2930 	@param	job		Job structure.
2931 	@param	pobj	Ellipse object to check.
2932 	@return	1 for abnormal ellipse, 0 for normal ellipse.
2933 */
2934 static
2935 int
wxd2lout_abnormal_ellipse(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj)2936 wxd2lout_abnormal_ellipse(
2937 	wxd_drawing_t	*drw,
2938 	wxd2lat_job_t	*job,
2939 	wxd_object_t	*pobj
2940 )
2941 {
2942 	dk4_er_t	er;
2943 	double		lw;
2944 	int		 	back = 1;
2945 
2946 	lw = wxd2lat_object_linewidth(pobj, drw, job);
2947 	dk4error_init(&er);
2948 	dk4pppt_set_fill_rgb(
2949 		job->ppp,
2950 		(((double)(pobj->sc[0])) / 255.0),
2951 		(((double)(pobj->sc[1])) / 255.0),
2952 		(((double)(pobj->sc[2])) / 255.0),
2953 		&back, &er
2954 	);
2955 	dk4pppt_prepare_fill(job->ppp, &back, &er);
2956 	dk4pppt_ellipse(
2957 		job->ppp, (pobj->det).e.x, (pobj->det).e.y,
2958 		((pobj->det).e.rx + lw / 2.0), ((pobj->det).e.ry + lw / 2.0),
2959 		(pobj->det).e.a, NULL, &back, &er
2960 	);
2961 	dk4pppt_fill(job->ppp, &back, &er);
2962 
2963 	return back;
2964 }
2965 
2966 
2967 
2968 static
2969 int
wxd2lout_is_abnormal_box(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj)2970 wxd2lout_is_abnormal_box(
2971 	wxd_drawing_t	*drw,
2972 	wxd2lat_job_t	*job,
2973 	wxd_object_t	*pobj
2974 )
2975 {
2976 	double	 lw;
2977 	int		 back = 0;
2978 
2979 	lw = wxd2lat_object_linewidth(pobj, drw, job);
2980 	if (
2981 		(lw >= fabs((pobj->det).b.xr - (pobj->det).b.xl))
2982 		|| (lw >= fabs((pobj->det).b.yt - (pobj->det).b.yb))
2983 	) {
2984 		back = 1;
2985 	}
2986 
2987 	return back;
2988 }
2989 
2990 
2991 
2992 static
2993 int
wxd2lout_abnormal_box(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj)2994 wxd2lout_abnormal_box(
2995 	wxd_drawing_t	*drw,
2996 	wxd2lat_job_t	*job,
2997 	wxd_object_t	*pobj
2998 )
2999 {
3000 	dk4_er_t	er;
3001 	double	 	lw;
3002 	double		xl;
3003 	double		xr;
3004 	double		yt;
3005 	double		yb;
3006 	double		ra;
3007 	double		dx;
3008 	double		dy;
3009 	int		 	back = 1;
3010 
3011 	lw = wxd2lat_object_linewidth(pobj, drw, job) / 2.0;
3012 	dk4error_init(&er);
3013 	dk4pppt_set_fill_rgb(
3014 		job->ppp,
3015 		(((double)(pobj->sc[0])) / 255.0),
3016 		(((double)(pobj->sc[1])) / 255.0),
3017 		(((double)(pobj->sc[2])) / 255.0),
3018 		&back, &er
3019 	);
3020 
3021 	dk4pppt_prepare_fill(job->ppp, &back, &er);
3022 
3023 	if ((pobj->det).b.xr >= (pobj->det).b.xl) {
3024 		xl = (pobj->det).b.xl - lw;
3025 		xr = (pobj->det).b.xr + lw;
3026 	}
3027 	else {
3028 		xl = (pobj->det).b.xr - lw;
3029 		xr = (pobj->det).b.xl + lw;
3030 	}
3031 	if ((pobj->det).b.yt >= (pobj->det).b.yb) {
3032 		yb = (pobj->det).b.yb - lw;
3033 		yt = (pobj->det).b.yt + lw;
3034 	}
3035 	else {
3036 		yb = (pobj->det).b.yt - lw;
3037 		yt = (pobj->det).b.yb + lw;
3038 	}
3039 	if (0.0 < (pobj->det).b.r) {
3040 		ra = (pobj->det).b.r + lw;
3041 		dx = fabs(xr - xl);
3042 		dy = fabs(yb - yt);
3043 		if (dy < dx) { dx = dy; }
3044 		dx *= 0.4998;
3045 		if (dx < ra) {
3046 			ra = dx;
3047 		}
3048 	}
3049 	else {
3050 		ra = -1.0;
3051 	}
3052 	dk4pppt_rectangle(job->ppp, xl, xr, yb, yt, ra, NULL, &back, &er);
3053 
3054 	dk4pppt_fill(job->ppp, &back, &er);
3055 
3056 	return back;
3057 }
3058 
3059 
3060 
3061 
3062 /**	Draw one graphics object.
3063 	@param	drw		Drawing structure.
3064 	@param	job		Job structure.
3065 	@param	pobj	Graphics object to draw.
3066 	@return	1 on success, 0 on error.
3067 */
3068 static
3069 int
wxd2lout_one_graphics_object(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj)3070 wxd2lout_one_graphics_object(
3071 	wxd_drawing_t	*drw,
3072 	wxd2lat_job_t	*job,
3073 	wxd_object_t	*pobj
3074 )
3075 {
3076 	int			 back	= 1;
3077 
3078 
3079 	if (0 != wxd2lout_check_one_graphics_object(drw, job, pobj)) {
3080 		switch (pobj->ot) {
3081 			case WXD_OT_TEXT : {
3082 				back = wxd2lout_text_object(job, pobj);
3083 			} break;
3084 			case WXD_OT_POLYLINE : case WXD_OT_O_SPLINE : case WXD_OT_O_ARC : {
3085 				back = wxd2lout_open_path_object(drw, job, pobj);
3086 			} break;
3087 			case WXD_OT_POLYGON : case WXD_OT_C_SPLINE : case WXD_OT_C_ARC : {
3088 				back = wxd2lout_closed_path_object(drw, job, pobj);
3089 			} break;
3090 			case WXD_OT_CIRCLE : {
3091 				if (0 != wxd2lout_is_abnormal_circle(drw, job, pobj)) {
3092 					back = wxd2lout_abnormal_circle(drw, job, pobj);
3093 				}
3094 				else {
3095 					back = wxd2lout_closed_path_object(drw, job, pobj);
3096 				}
3097 			} break;
3098 			case WXD_OT_ELLIPSE : {
3099 				if (0 != wxd2lout_is_abnormal_ellipse(drw, job, pobj)) {
3100 					back = wxd2lout_abnormal_ellipse(drw, job, pobj);
3101 				}
3102 				else {
3103 					back = wxd2lout_closed_path_object(drw, job, pobj);
3104 				}
3105 			} break;
3106 			case WXD_OT_BOX : {
3107 				if (0 != wxd2lout_is_abnormal_box(drw, job, pobj)) {
3108 					back = wxd2lout_abnormal_box(drw, job, pobj);
3109 				}
3110 				else {
3111 					back = wxd2lout_closed_path_object(drw, job, pobj);
3112 				}
3113 			} break;
3114 			case WXD_OT_DOT_FILLED : case WXD_OT_DOT_WHITE : {
3115 
3116 				back = wxd2lout_dot_object(drw, job, pobj);
3117 			} break;
3118 			case WXD_OT_IMAGE : {
3119 				back = wxd2lout_image_object(job, pobj);
3120 			} break;
3121 		}
3122 		if (0 == back) {
3123 			/* ERROR: Failed to write graphics object */
3124 			dk4app_log_1(
3125 				job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 72
3126 			);
3127 		}
3128 	}
3129 	else {
3130 		back = 0;
3131 	}
3132 
3133 	return back;
3134 }
3135 
3136 
3137 
3138 /**	Create output for all graphics objects in a drawing.
3139 	@param	drw		Original drawing.
3140 	@param	job		Job structure containing the output structure.
3141 	@return	1 on success, 0 on error.
3142 */
3143 static
3144 int
wxd2lout_all_graphics_objects(wxd_drawing_t * drw,wxd2lat_job_t * job)3145 wxd2lout_all_graphics_objects(
3146 	wxd_drawing_t	*drw,
3147 	wxd2lat_job_t	*job
3148 )
3149 {
3150 	wxd_object_t	*pobj;
3151 	dk4_um_t		 oldline;
3152 	int				 back	= 1;
3153 
3154 
3155 	oldline = dk4app_get_log_source_line(job->app);
3156 	dk4sto_it_reset(drw->i_flat);
3157 	do {
3158 		pobj = (wxd_object_t *)dk4sto_it_next(drw->i_flat);
3159 		if (NULL != pobj) {
3160 			dk4app_set_log_source_line(job->app, pobj->lino);
3161 			if (0 == wxd2lout_one_graphics_object(drw, job, pobj)) {
3162 				back = 0;
3163 			}
3164 		}
3165 	} while (NULL != pobj);
3166 	dk4app_set_log_source_line(job->app, oldline);
3167 
3168 	return back;
3169 }
3170 
3171 
3172 
3173 static
3174 int
wxd2lout_check_arrows(wxd_drawing_t * drw,wxd2lat_job_t * job,wxd_object_t * pobj)3175 wxd2lout_check_arrows(
3176 	wxd_drawing_t	*drw,
3177 	wxd2lat_job_t	*job,
3178 	wxd_object_t	*pobj
3179 )
3180 {
3181 	int		 back = 1;
3182 
3183 	if ((uint8_t)0U != (pobj->af).type) {
3184 		if (0 == wxd2lah_one_arrowhead(&(pobj->af), pobj, drw, job)) {
3185 			back = 0;
3186 			/* ERROR: Forward arrow calculation failed */
3187 			dk4app_log_1(
3188 				job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 73
3189 			);
3190 		}
3191 	}
3192 	if ((uint8_t)0U != (pobj->ab).type) {
3193 		if (0 == wxd2lah_one_arrowhead(&(pobj->ab), pobj, drw, job)) {
3194 			back = 0;
3195 			/* ERROR: Backward arrow calculation failed */
3196 			dk4app_log_1(
3197 				job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 74
3198 			);
3199 		}
3200 	}
3201 
3202 	return back;
3203 }
3204 
3205 
3206 
3207 static
3208 int
wxd2out_all_calculations(wxd_drawing_t * drw,wxd2lat_job_t * job)3209 wxd2out_all_calculations(wxd_drawing_t *drw, wxd2lat_job_t *job)
3210 {
3211 	wxd_object_t	*pobj;
3212 	dk4_um_t		 oldline;
3213 	int				 back	= 1;
3214 	int				 myback	= 0;
3215 	uint16_t		 u16;
3216 
3217 	oldline = dk4app_get_log_source_line(job->app);
3218 	dk4sto_it_reset(drw->i_flat);
3219 	do {
3220 		pobj = (wxd_object_t *)dk4sto_it_next(drw->i_flat);
3221 		if (NULL != pobj) {
3222 			dk4app_set_log_source_line(job->app, pobj->lino);
3223 			switch (pobj->ot) {
3224 				case WXD_OT_TEXT : {
3225 					(pobj->det).t.x =
3226 					wxd2lout_convert_x(drw, job, (pobj->det).t.x);
3227 					(pobj->det).t.y =
3228 					wxd2lout_convert_y(drw, job, (pobj->det).t.y);
3229 #if	0
3230 					(pobj->det).t.a = (M_PI * (pobj->det).t.a) / 180.0;
3231 #endif
3232 				} break;
3233 				case WXD_OT_POLYLINE : {
3234 					u16 = (uint16_t)0U;
3235 					if ((NULL != (pobj->det).p.p) && (u16 < (pobj->det).p.n)) {
3236 						for (u16 = (uint16_t)0U; u16 < (pobj->det).p.n; u16++) {
3237 							((pobj->det).p.p)[u16].x =
3238 							wxd2lout_convert_x(
3239 								drw, job, ((pobj->det).p.p)[u16].x
3240 							);
3241 							((pobj->det).p.p)[u16].y =
3242 							wxd2lout_convert_y(
3243 								drw, job, ((pobj->det).p.p)[u16].y
3244 							);
3245 						}
3246 					}
3247 					if (0 == wxd2lout_check_arrows(drw, job, pobj)) {
3248 						/* Errors already reported */
3249 						back = 0;
3250 					}
3251 				} break;
3252 				case WXD_OT_O_SPLINE : {
3253 					u16 = (uint16_t)0U;
3254 					if ((NULL != (pobj->det).s.p) && (u16 < (pobj->det).s.n)) {
3255 						for (u16 = (uint16_t)0U; u16 < (pobj->det).s.n; u16++) {
3256 							((pobj->det).s.p)[u16].x =
3257 							wxd2lout_convert_x(
3258 								drw, job, ((pobj->det).s.p)[u16].x
3259 							);
3260 							((pobj->det).s.p)[u16].y =
3261 							wxd2lout_convert_y(
3262 								drw, job, ((pobj->det).s.p)[u16].y
3263 							);
3264 						}
3265 					}
3266 					if (0 == wxd2lout_check_arrows(drw, job, pobj)) {
3267 						/* Errors already reported */
3268 						back = 0;
3269 					}
3270 					if (
3271 						((uint8_t)0U != (pobj->af).type)
3272 						|| ((uint8_t)0U != (pobj->ab).type)
3273 					) {
3274 						(pobj->det).s.ts = -1.0;
3275 						(pobj->det).s.te = -1.0;
3276 						myback = 1;
3277 						wxd2lxs_calculate_spline_segments(job, pobj, &myback);
3278 						if (0 == myback) {
3279 							back = 0;
3280 							/* ERROR: Spline segment calculation failed */
3281 							dk4app_log_1(
3282 								job->app, job->msg, job->sz_msg,
3283 								DK4_LL_ERROR, 75
3284 							);
3285 						}
3286 					}
3287 				} break;
3288 				case WXD_OT_O_ARC : {
3289 					(pobj->det).a.x =
3290 					wxd2lout_convert_x(drw, job, (pobj->det).a.x);
3291 					(pobj->det).a.y =
3292 					wxd2lout_convert_y(drw, job, (pobj->det).a.y);
3293 
3294 					(pobj->det).a.r =
3295 					wxd2lout_convert_r((pobj->det).a.r);
3296 					if (0 == wxd2lout_check_arrows(drw, job, pobj)) {
3297 						/* Errors already reported */
3298 						back = 0;
3299 					}
3300 				} break;
3301 				case WXD_OT_POLYGON : {
3302 					u16 = (uint16_t)0U;
3303 					if ((NULL != (pobj->det).p.p) && (u16 < (pobj->det).p.n)) {
3304 						for (u16 = (uint16_t)0U; u16 < (pobj->det).p.n; u16++) {
3305 							((pobj->det).p.p)[u16].x =
3306 							wxd2lout_convert_x(
3307 								drw, job, ((pobj->det).p.p)[u16].x
3308 							);
3309 							((pobj->det).p.p)[u16].y =
3310 							wxd2lout_convert_y(
3311 								drw, job, ((pobj->det).p.p)[u16].y
3312 							);
3313 						}
3314 					}
3315 				} break;
3316 				case WXD_OT_C_SPLINE : {
3317 					u16 = (uint16_t)0U;
3318 					if ((NULL != (pobj->det).s.p) && (u16 < (pobj->det).s.n)) {
3319 						for (u16 = (uint16_t)0U; u16 < (pobj->det).s.n; u16++) {
3320 							((pobj->det).s.p)[u16].x =
3321 							wxd2lout_convert_x(
3322 								drw, job, ((pobj->det).s.p)[u16].x
3323 							);
3324 							((pobj->det).s.p)[u16].y =
3325 							wxd2lout_convert_y(
3326 								drw, job, ((pobj->det).s.p)[u16].y
3327 							);
3328 						}
3329 					}
3330 				} break;
3331 				case WXD_OT_C_ARC : {
3332 					(pobj->det).a.x =
3333 					wxd2lout_convert_x(drw, job, (pobj->det).a.x);
3334 					(pobj->det).a.y =
3335 					wxd2lout_convert_y(drw, job, (pobj->det).a.y);
3336 
3337 					(pobj->det).a.r =
3338 					wxd2lout_convert_r((pobj->det).a.r);
3339 				} break;
3340 				case WXD_OT_CIRCLE : case WXD_OT_ELLIPSE : {
3341 					(pobj->det).e.x =
3342 					wxd2lout_convert_x(drw, job, (pobj->det).e.x);
3343 					(pobj->det).e.y =
3344 					wxd2lout_convert_y(drw, job, (pobj->det).e.y);
3345 
3346 					(pobj->det).e.rx =
3347 					wxd2lout_convert_r((pobj->det).e.rx);
3348 
3349 
3350 					(pobj->det).e.ry =
3351 					wxd2lout_convert_r((pobj->det).e.ry);
3352 
3353 				} break;
3354 				case WXD_OT_BOX : {
3355 
3356 
3357 
3358 
3359 
3360 					(pobj->det).b.xl =
3361 					wxd2lout_convert_x(drw, job, (pobj->det).b.xl);
3362 					(pobj->det).b.xr =
3363 					wxd2lout_convert_x(drw, job, (pobj->det).b.xr);
3364 					(pobj->det).b.yb =
3365 					wxd2lout_convert_y(drw, job, (pobj->det).b.yb);
3366 					(pobj->det).b.yt =
3367 					wxd2lout_convert_y(drw, job, (pobj->det).b.yt);
3368 					if (0.0 < (pobj->det).b.r) {
3369 
3370 						(pobj->det).b.r = wxd2lout_convert_r((pobj->det).b.r);
3371 					}
3372 
3373 
3374 
3375 
3376 
3377 				} break;
3378 				case WXD_OT_IMAGE : {
3379 					(pobj->det).i.x =
3380 					wxd2lout_convert_x(drw, job, (pobj->det).i.x);
3381 					(pobj->det).i.y =
3382 					wxd2lout_convert_y(drw, job, (pobj->det).i.y);
3383 
3384 
3385 					(pobj->det).i.w = wxd2lout_convert_r((pobj->det).i.w);
3386 					(pobj->det).i.h = wxd2lout_convert_r((pobj->det).i.h);
3387 
3388 				} break;
3389 				case WXD_OT_DOT_FILLED : case WXD_OT_DOT_WHITE : {
3390 					(pobj->det).d.x =
3391 					wxd2lout_convert_x(drw, job, (pobj->det).d.x);
3392 					(pobj->det).d.y =
3393 					wxd2lout_convert_y(drw, job, (pobj->det).d.y);
3394 
3395 					if (0.0 < job->baselw) {
3396 						(pobj->det).d.d *= job->baselw;
3397 					}
3398 					else {
3399 						(pobj->det).d.d *= drw->baselw;
3400 					}
3401 
3402 				} break;
3403 			}
3404 		}
3405 	} while (NULL != pobj);
3406 	dk4app_set_log_source_line(job->app, oldline);
3407 
3408 	return back;
3409 }
3410 
3411 
3412 
3413 void
wxd2lat_output(wxd_drawing_t * drw,wxd2lat_job_t * job,const dkChar * fn)3414 wxd2lat_output(wxd_drawing_t *drw, wxd2lat_job_t *job, const dkChar *fn)
3415 {
3416 	dk4_er_t	 		er;
3417 	dk4_pppt_driver_t	dr;
3418 	int					flags	= 0;
3419 	int			 		ok		= 0;
3420 
3421 
3422 	/*
3423 		Calculate image width and coordinates shift values.
3424 	*/
3425 	if (0 == wxd2lout_prepare_job(drw, job, fn)) {
3426 		/* All errors already reported */
3427 		job->exval = EXIT_FAILURE;
3428 		goto finished;
3429 	}
3430 	/*	Convert coordinates to bp, pre-calculate arrowhead data.
3431 	*/
3432 	if (0 == wxd2out_all_calculations(drw, job)) {
3433 		/* All errors already reported */
3434 		job->exval = EXIT_FAILURE;
3435 		goto finished;
3436 	}
3437 	/*	Open output structure
3438 	*/
3439 	dr = DK4_PPPT_DR_PDF_TEX;
3440 	switch ((job->grco).driver) {
3441 #if 0
3442 		case DK4_GRA_DRIVER_PDF : {
3443 			dr = DK4_PPPT_DR_PDF_TEX;
3444 		} break;
3445 #endif
3446 		case DK4_GRA_DRIVER_PS : case DK4_GRA_DRIVER_EPS : {
3447 			dr = DK4_PPPT_DR_EPS_TEX;
3448 		} break;
3449 		case DK4_GRA_DRIVER_PGF : {
3450 			dr = DK4_PPPT_DR_PGF;
3451 		} break;
3452 	}
3453 	if (0 == job->whitebg) {
3454 		flags |= DK4_GRA_PAGE_FLAG_NO_BG;
3455 	}
3456 	if (0 == (job->grco).color) {
3457 		flags |= DK4_GRA_DOC_FLAG_FORCE_GRAY;
3458 	}
3459 	if (DK4_PPPT_DR_EPS_TEX == dr) {
3460 		if (2 == (job->grco).ps_level) {
3461 			flags |= DK4_GRA_DOC_FLAG_PS2;
3462 		}
3463 		if (0 != (job->grco).ps_dsc) {
3464 			flags |= DK4_GRA_DOC_FLAG_PS_DSC;
3465 		}
3466 		if (DK4_GRA_DRIVER_EPS == (job->grco).driver) {
3467 			flags |= DK4_GRA_DOC_FLAG_EPS;
3468 		}
3469 	}
3470 	dk4error_init(&er);
3471 	job->ppp = dk4pppt_open(
3472 		job->fno1, dr,
3473 		((DK4_GRA_PURPOSE_DOCUMENT == (job->grco).purpose) ? (1) : (0)),
3474 		flags, job->szwidth, job->szheight, &er
3475 	);
3476 	if (NULL == job->ppp) {
3477 		/* ERROR: Failed to open output structure */
3478 		dk4app_log_1(
3479 			job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 76
3480 		);
3481 		job->exval = EXIT_FAILURE;
3482 		goto finished;
3483 	}
3484 	dk4pppt_set_gs_for_pattern_only(job->ppp, 1, NULL);
3485 	if (0.0 < job->patlw) {
3486 		dk4pppt_set_pattern_line_width(job->ppp, job->patlw);
3487 	}
3488 	else {
3489 		dk4pppt_set_pattern_line_width(job->ppp, 0.45);
3490 	}
3491 	/*
3492 		Clip if shiftx and/or shifty is used
3493 	*/
3494 	if (0 == wxd2lout_clip_to_used_region(job)) {
3495 		/* All errors already reported */
3496 		job->exval = EXIT_FAILURE;
3497 		goto finished;
3498 	}
3499 	/*	Draw all graphics objects
3500 	*/
3501 	if (0 == wxd2lout_all_graphics_objects(drw, job)) {
3502 		/* All errors already reported */
3503 		job->exval = EXIT_FAILURE;
3504 		goto finished;
3505 	}
3506 
3507 	/*	Finally indicate success
3508 	*/
3509 	ok = 1;
3510 
3511 	/*	Produce output files if success so far, clean up
3512 	*/
3513 	finished:
3514 	if (NULL != job->ppp) {
3515 		if (0 != ok) {
3516 			dk4error_init(&er);
3517 			ok = dk4pppt_write_and_close(job->ppp, &er);
3518 			if (0 == ok) {
3519 				/* ERROR: Failed to write output */
3520 				dk4app_log_1(
3521 					job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 77
3522 				);
3523 				job->exval = EXIT_FAILURE;
3524 			}
3525 		}
3526 		else {
3527 			dk4pppt_close(job->ppp);
3528 			/* ERROR: Skipping output due to previous errors */
3529 			dk4app_log_1(
3530 				job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 78
3531 			);
3532 			job->exval = EXIT_FAILURE;
3533 		}
3534 	}
3535 	job->ppp = NULL;
3536 
3537 }
3538 
3539 
3540 
3541 /* vim: set ai sw=4 ts=4 : */
3542 
3543