1/***********************************************************************
2 *                                                                     *
3 * $Id: hpgspen.c 298 2006-03-05 18:18:03Z softadm $
4 *                                                                     *
5 * hpgs - HPGl Script, a hpgl/2 interpreter, which uses a Postscript   *
6 *        API for rendering a scene and thus renders to a variety of   *
7 *        devices and fileformats.                                     *
8 *                                                                     *
9 * (C) 2004-2006 ev-i Informationstechnologie GmbH  http://www.ev-i.at *
10 *                                                                     *
11 * Author: Wolfgang Glas                                               *
12 *                                                                     *
13 *  hpgs is free software; you can redistribute it and/or              *
14 * modify it under the terms of the GNU Lesser General Public          *
15 * License as published by the Free Software Foundation; either        *
16 * version 2.1 of the License, or (at your option) any later version.  *
17 *                                                                     *
18 * hpgs is distributed in the hope that it will be useful,             *
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of      *
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   *
21 * Lesser General Public License for more details.                     *
22 *                                                                     *
23 * You should have received a copy of the GNU Lesser General Public    *
24 * License along with this library; if not, write to the               *
25 * Free Software  Foundation, Inc., 59 Temple Place, Suite 330,        *
26 * Boston, MA  02111-1307  USA                                         *
27 *                                                                     *
28 ***********************************************************************
29 *                                                                     *
30 * The implementation of the HPGL reader.                              *
31 *                                                                     *
32 ***********************************************************************/
33
34#include <hpgsreader.h>
35#include <math.h>
36#include <string.h>
37#include <ctype.h>
38
39/*
40  Internal
41*/
42static int hpgs_reader_set_number_of_pens(hpgs_reader *reader, int npens)
43{
44  double *pw =(double *)realloc(reader->pen_widths,npens*sizeof(double));
45
46  if (!pw)
47    return hpgs_set_error(hpgs_i18n("Out of memory growing pen width array."));
48
49  reader->pen_widths = pw;
50
51  hpgs_color *pc = (hpgs_color *)realloc(reader->pen_colors,npens*sizeof(hpgs_color));
52
53  if (!pc)
54    return hpgs_set_error(hpgs_i18n("Out of memory growing pen color array."));
55
56  reader->pen_colors = pc;
57
58  for (;reader->npens<npens;++reader->npens)
59    {
60      reader->pen_widths[reader->npens] = 1.0;
61      reader->pen_colors[reader->npens].r = 0.0;
62      reader->pen_colors[reader->npens].g = 0.0;
63      reader->pen_colors[reader->npens].b = 0.0;
64    }
65
66  return 0;
67}
68
69/*
70  Do the pen select.
71*/
72int hpgs_reader_do_setpen(hpgs_reader *reader, int pen)
73{
74  double width;
75
76  if (hpgs_reader_checkpath(reader)) return -1;
77
78  if (pen < 0)
79    return hpgs_set_error(hpgs_i18n("Illegal pen numer %d."),pen);
80
81  if (pen >= reader->npens)
82    {
83      if (pen < 256)
84        {
85          if (hpgs_reader_set_number_of_pens(reader,pen+1))
86            return -1;
87        }
88      else
89        {
90          if (reader->verbosity)
91            hpgs_log(hpgs_i18n("Illegal pen number %d replaced by %d.\n"),
92                     pen, pen % reader->npens);
93          pen = pen %  reader->npens;
94        }
95    }
96
97  reader->current_pen = pen;
98
99  width = reader->pen_widths[pen];
100
101  if (reader->pen_width_relative)
102    width *= hypot(reader->P2.x-reader->P1.x,
103		   reader->P2.y-reader->P1.y ) * 0.001 * HP_TO_PT;
104  else
105    width *= HP_TO_PT / reader->world_scale;
106
107  width *= reader->page_scale;
108
109  if (hpgs_setlinewidth(reader->device,width*reader->lw_factor))
110    return -1;
111
112  return hpgs_setrgbcolor(reader->device,
113			  &reader->pen_colors[pen]);
114}
115
116/*
117  HPGL command NP (Number of Pens)
118*/
119int hpgs_reader_do_NP (hpgs_reader *reader)
120{
121  int npens=8;
122
123  if (!reader->eoc &&
124      hpgs_reader_read_int(reader,&npens)) return -1;
125
126  if (npens <= reader->npens) return 0;
127
128  return hpgs_reader_set_number_of_pens(reader,npens);
129}
130
131/*
132  HPGL command SP (Set Pen)
133*/
134int hpgs_reader_do_SP (hpgs_reader *reader)
135{
136  int pen=0;
137
138  if (!reader->eoc &&
139      hpgs_reader_read_int(reader,&pen)) return -1;
140
141  return hpgs_reader_do_setpen(reader,pen);
142}
143
144/*
145  HPGL command PC (Pen Color)
146*/
147int hpgs_reader_do_PC (hpgs_reader *reader)
148{
149  int pen=-1;
150  double r=-1.0e20,g=-1.0e20,b=-1.0e20;
151
152  if (!reader->eoc && hpgs_reader_read_int(reader,&pen)) return -1;
153  if (!reader->eoc && hpgs_reader_read_double(reader,&r)) return -1;
154  if (!reader->eoc && hpgs_reader_read_double(reader,&g)) return -1;
155  if (!reader->eoc && hpgs_reader_read_double(reader,&b)) return -1;
156
157  if (pen >= reader->npens)
158    {
159      if (pen < 256)
160        {
161          if (hpgs_reader_set_number_of_pens(reader,pen+1))
162            return -1;
163        }
164      else
165        {
166          if (reader->verbosity)
167            hpgs_log(hpgs_i18n("PC: Illegal pen number %d.\n"),pen);
168
169          return 0;
170        }
171    }
172
173  if (pen < 0)
174    {
175      hpgs_reader_set_std_pen_colors(reader,0,reader->npens);
176      pen = reader->current_pen;
177    }
178  else
179    {
180      if (r==-1.0e20 || g==-1.0e20 || b==-1.0e20)
181        {
182          hpgs_reader_set_std_pen_colors(reader,pen,1);
183        }
184      else
185        {
186          reader->pen_colors[pen].r =
187            (r - reader->min_color.r) / (reader->max_color.r - reader->min_color.r);
188          if (reader->pen_colors[pen].r < 0.0) reader->pen_colors[pen].r = 0.0;
189          if (reader->pen_colors[pen].r > 1.0) reader->pen_colors[pen].r = 1.0;
190
191          reader->pen_colors[pen].g =
192            (g - reader->min_color.g) / (reader->max_color.g - reader->min_color.g);
193          if (reader->pen_colors[pen].g < 0.0) reader->pen_colors[pen].g = 0.0;
194          if (reader->pen_colors[pen].g > 1.0) reader->pen_colors[pen].g = 1.0;
195
196          reader->pen_colors[pen].b =
197            (b - reader->min_color.b) / (reader->max_color.b - reader->min_color.b);
198          if (reader->pen_colors[pen].b < 0.0) reader->pen_colors[pen].b = 0.0;
199          if (reader->pen_colors[pen].b > 1.0) reader->pen_colors[pen].b = 1.0;
200        }
201    }
202
203  if (pen == reader->current_pen)
204    if (hpgs_setrgbcolor(reader->device,
205			 &reader->pen_colors[pen]))
206      return -1;
207
208  return 0;
209}
210
211/*
212  HPGL command CR (Color Range)
213*/
214int hpgs_reader_do_CR (hpgs_reader *reader)
215{
216  reader->min_color.r = 0.0;
217  reader->min_color.g = 0.0;
218  reader->min_color.b = 0.0;
219
220  reader->max_color.r = 255.0;
221  reader->max_color.g = 255.0;
222  reader->max_color.b = 255.0;
223
224  if (!reader->eoc)
225    {
226      if (hpgs_reader_read_double(reader,&reader->min_color.r)) return -1;
227      if (reader->eoc) return -1;
228      if (hpgs_reader_read_double(reader,&reader->max_color.r)) return -1;
229      if (reader->eoc) return -1;
230      if (hpgs_reader_read_double(reader,&reader->min_color.g)) return -1;
231      if (reader->eoc) return -1;
232      if (hpgs_reader_read_double(reader,&reader->max_color.g)) return -1;
233      if (reader->eoc) return -1;
234      if (hpgs_reader_read_double(reader,&reader->min_color.b)) return -1;
235      if (reader->eoc) return -1;
236      if (hpgs_reader_read_double(reader,&reader->max_color.b)) return -1;
237    }
238
239  return 0;
240}
241
242/*
243  HPGL command LA (Line Attributes)
244*/
245int hpgs_reader_do_LA(hpgs_reader *reader)
246{
247  int    kind;
248  int    ivalue;
249  double rvalue;
250
251  static hpgs_line_cap caps[5] =
252    { hpgs_cap_butt,
253      hpgs_cap_butt,
254      hpgs_cap_square,
255      hpgs_cap_round,
256      hpgs_cap_round    };
257
258  static hpgs_line_join joins[7] =
259    { hpgs_join_miter,
260      hpgs_join_miter,
261      hpgs_join_miter,
262      hpgs_join_miter,
263      hpgs_join_round,
264      hpgs_join_bevel,
265      hpgs_join_miter };
266
267  while (!reader->eoc)
268    {
269      if (hpgs_reader_read_int(reader,&kind)) return -1;
270      if (reader->eoc) return -1;
271
272      switch (kind)
273	{
274	case 3:
275	  if (hpgs_reader_read_double(reader,&rvalue)) return -1;
276	  if (hpgs_setmiterlimit(reader->device,rvalue)) return -1;
277	  break;
278	case 1:
279	  if (hpgs_reader_read_int(reader,&ivalue)) return -1;
280	  if (ivalue >= 0 && ivalue < 5 &&
281	      hpgs_setlinecap(reader->device,caps[ivalue])) return -1;
282	  break;
283	case 2:
284	  if (hpgs_reader_read_int(reader,&ivalue)) return -1;
285	  if (ivalue >= 0 && ivalue < 7 &&
286	      hpgs_setlinejoin(reader->device,joins[ivalue])) return -1;
287	  break;
288	default:
289	  return -1;
290	}
291    }
292  return 0;
293}
294
295/*
296  HPGL command LT (Line Type)
297*/
298int hpgs_reader_do_LT(hpgs_reader *reader)
299{
300  float dashes[20];
301  int i,ndash;
302  int linetype=0;
303  double patlen = 4.0;
304  int    mode = 0;
305
306  if (hpgs_reader_checkpath(reader)) return -1;
307
308  if (!reader->eoc &&
309      hpgs_reader_read_int(reader,&linetype)) return -1;
310
311  if (!reader->eoc &&
312      hpgs_reader_read_double(reader,&patlen)) return -1;
313
314  if (!reader->eoc &&
315      hpgs_reader_read_int(reader,&mode)) return -1;
316
317  if (linetype < -8 || linetype > 8)
318    {
319      if (reader->verbosity)
320	hpgs_log(hpgs_i18n("LT: Illegal linetype %d.\n"),linetype);
321      return 0;
322    }
323
324  // line type are store as percentages.
325  patlen *= 0.01;
326
327  if (mode)
328    patlen *= MM_TO_PT;
329  else
330    patlen *= hypot(reader->P2.x-reader->P1.x,
331		    reader->P2.y-reader->P1.y ) * 0.01 * HP_TO_PT;
332
333  ndash = reader->linetype_nsegs[linetype+8];
334  if (ndash > 20) ndash = 20;
335
336  for (i=0;i<ndash;++i)
337    dashes[i] = reader->linetype_segs[linetype+8][i] * patlen;
338
339  return hpgs_setdash(reader->device,
340		      dashes,ndash,0.0);
341}
342
343/*
344  HPGL command PW (Pen Width)
345*/
346int hpgs_reader_do_PW (hpgs_reader *reader)
347{
348  int pen=-1;
349  double width=1.0;
350
351  if (!reader->eoc)
352    if (hpgs_reader_read_double(reader,&width)) return -1;
353  if (!reader->eoc)
354    {
355      if (hpgs_reader_read_int(reader,&pen)) return -1;
356
357      if (pen < 0 || pen >= reader->npens)
358        {
359          if (pen >= reader->npens && pen < 256)
360            {
361              if (hpgs_reader_set_number_of_pens(reader,pen+1))
362                return -1;
363            }
364          else
365            {
366              if (reader->verbosity)
367                hpgs_log(hpgs_i18n("PW: Illegal pen number %d.\n"),pen);
368
369              return 0;
370            }
371        }
372    }
373
374  if (reader->verbosity >= 2)
375    hpgs_log("PW: pen,width,rel = %d,%g,%d.\n",pen,width,reader->pen_width_relative);
376
377  if (reader->pen_width_relative)
378    width *= 10.0;
379  else
380    width *= MM_TO_PT;
381
382  if (pen < 0)
383    {
384      int i;
385      for (i=0;i<reader->npens;++i)
386	reader->pen_widths[i] = width;
387    }
388  else
389    reader->pen_widths[pen] = width;
390
391  if (pen < 0 || pen == reader->current_pen)
392    {
393      if (hpgs_reader_checkpath(reader)) return -1;
394
395      if (reader->pen_width_relative)
396        width *= hypot(reader->P2.x-reader->P1.x,
397                       reader->P2.y-reader->P1.y ) * 0.001 * HP_TO_PT;
398      else
399        width *= HP_TO_PT / reader->world_scale;
400
401      width *= reader->page_scale;
402
403      if (hpgs_setlinewidth(reader->device,width*reader->lw_factor))
404	return -1;
405    }
406
407  return 0;
408}
409
410/*
411  HPGL command WU (Width Unit selection)
412*/
413int hpgs_reader_do_WU (hpgs_reader *reader)
414{
415  reader->pen_width_relative=0;
416
417  if (!reader->eoc &&
418      hpgs_reader_read_int(reader,&reader->pen_width_relative)) return -1;
419  return 0;
420}
421
422