1/***********************************************************************
2 *                                                                     *
3 * $Id: hpgstransform.c 362 2006-10-16 14:13:48Z 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
37//#define HPGS_DEBUG_XFORM
38
39static void apply_scale(hpgs_reader *reader,
40                        const hpgs_point *p1, const hpgs_point *p2)
41{
42  double xf,yf;
43  double dx = 0.0,dy=0.0;
44  hpgs_point p2u;
45
46  if (reader->sc_type < 0) return;
47
48  // get P2 in old user coordinates
49  p2u.x = reader->frame_x + p2->x * HP_TO_PT;
50  p2u.y = reader->frame_y + p2->y * HP_TO_PT;
51
52  hpgs_matrix_ixform(&p2u,&p2u,&reader->world_matrix);
53
54#ifdef HPGS_DEBUG_XFORM
55    {
56      hpgs_point p1u;
57
58      p1u.x = reader->frame_x + p1->x * HP_TO_PT;
59      p1u.y = reader->frame_y + p1->y * HP_TO_PT;
60
61      hpgs_matrix_ixform(&p1u,&reader->world_matrix,&p1u);
62
63      hpgs_log("SC: P1 = %g,%g.\n",p1->x,p1->y);
64      hpgs_log("SC: P2 = %g,%g.\n",p2->x,p2->y);
65      hpgs_log("SC: p1u = %g,%g.\n",p1u.x,p1u.y);
66      hpgs_log("SC: p2u = %g,%g.\n",p2u.x,p2u.y);
67      hpgs_log("SC: xmin,xmax = %g,%g.\n",reader->sc_xmin,reader->sc_xmax);
68      hpgs_log("SC: ymin,ymax = %g,%g.\n",reader->sc_ymin,reader->sc_ymax);
69    }
70#endif
71
72  switch (reader->sc_type)
73    {
74    case 0:
75      xf = p2u.x / (reader->sc_xmax - reader->sc_xmin);
76      yf = p2u.y / (reader->sc_ymax - reader->sc_ymin);
77      break;
78    case 1:
79      xf = p2u.x / (reader->sc_xmax - reader->sc_xmin);
80      yf = p2u.y / (reader->sc_ymax - reader->sc_ymin);
81
82      if (xf < yf)
83	{
84	  dy = (yf-xf) * (reader->sc_ymax - reader->sc_ymin) * 0.01 * reader->sc_left;
85	  yf = xf;
86	}
87      else
88	{
89	  dx = (xf-yf) * (reader->sc_xmax - reader->sc_xmin) * 0.01 * reader->sc_bottom;
90	  xf = yf;
91	}
92      break;
93
94    case 2:
95      xf = reader->sc_xmax;
96      yf = reader->sc_ymax;
97      break;
98
99    default:
100      return;
101    }
102
103#ifdef HPGS_DEBUG_XFORM
104  hpgs_log("SC: xf,yf = %g,%g.\n",xf,yf);
105#endif
106
107  dx -= reader->sc_xmin * xf;
108  dy -= reader->sc_ymin * yf;
109
110  // concatenate transofrmation matrices.
111  //
112  // | 1    0   0 |  | 1   0   0 |
113  // | x0 mxx mxy |* | dx  xf  0 | =
114  // | y0 myx myy |  | dy  0  yf |
115  //
116  // | 1                     0      0 |
117  // | x0+mxx*dx+mxy*dy mxx*xf mxy*yf |
118  // | y0+myx*dx+myy*dy myx*xf myy*yf |
119  //
120
121  reader->world_matrix.dx += reader->world_matrix.mxx*dx + reader->world_matrix.mxy*dy;
122  reader->world_matrix.dy += reader->world_matrix.myx*dx + reader->world_matrix.myy*dy;
123
124  reader->world_matrix.mxx *= xf;
125  reader->world_matrix.myx *= xf;
126  reader->world_matrix.mxy *= yf;
127  reader->world_matrix.myy *= yf;
128
129#ifdef HPGS_DEBUG_XFORM
130  hpgs_log("SC: %10g %10g %10g\n",reader->world_matrix.dx,reader->world_matrix.mxx,reader->world_matrix.mxy);
131  hpgs_log("SC: %10g %10g %10g\n",reader->world_matrix.dy,reader->world_matrix.myx,reader->world_matrix.myy);
132#endif
133}
134
135void hpgs_reader_set_default_transformation (hpgs_reader *reader)
136{
137  // transformation matrix for user to PS coordinates.
138  int angle = reader->y_size >= reader->x_size ? 90 : 0;
139
140  hpgs_point p1 = reader->P1;
141  hpgs_point p2 = reader->P2;
142
143  angle += reader->rotation;
144
145  if ((angle % 180) == 90)
146    {
147      p2.y -= p1.y;
148      p1.y = 0.0;
149    }
150
151
152  reader->world_matrix.dx = reader->frame_x + p1.x * HP_TO_PT;
153  reader->world_matrix.dy = reader->frame_y + p1.y * HP_TO_PT;
154
155  switch (angle % 360)
156    {
157    case 90:
158      reader->world_matrix.mxx = 0.0;
159      reader->world_matrix.mxy = -HP_TO_PT;
160      reader->world_matrix.myx = HP_TO_PT;
161      reader->world_matrix.myy = 0.0;
162      break;
163    case 180:
164      reader->world_matrix.mxx = -HP_TO_PT;
165      reader->world_matrix.mxy = 0.0;
166      reader->world_matrix.myx = 0.0;
167      reader->world_matrix.myy = -HP_TO_PT;
168      break;
169    case 270:
170      reader->world_matrix.mxx = 0.0;
171      reader->world_matrix.mxy = HP_TO_PT;
172      reader->world_matrix.myx = -HP_TO_PT;
173      reader->world_matrix.myy = 0.0;
174      break;
175    default: // 0
176      reader->world_matrix.mxx = HP_TO_PT;
177      reader->world_matrix.mxy = 0.0;
178      reader->world_matrix.myx = 0.0;
179      reader->world_matrix.myy = HP_TO_PT;
180    }
181
182#ifdef HPGS_DEBUG_XFORM
183  hpgs_log("xform: %10g %10g %10g\n",reader->world_matrix.dx,reader->world_matrix.mxx,reader->world_matrix.mxy);
184  hpgs_log("xform: %10g %10g %10g\n",reader->world_matrix.dy,reader->world_matrix.myx,reader->world_matrix.myy);
185#endif
186
187  apply_scale(reader,&p1,&p2);
188
189  reader->world_scale =
190    sqrt (fabs(reader->world_matrix.mxx * reader->world_matrix.myy -
191               reader->world_matrix.mxy * reader->world_matrix.myx  ) );
192
193  // finally transform from model space to the page.
194  hpgs_matrix_concat(&reader->total_matrix,&reader->page_matrix,&reader->world_matrix);
195
196  reader->total_scale = reader->page_scale * reader->world_scale;
197}
198
199/*
200  HPGL command PS (Plot Size)
201*/
202int hpgs_reader_do_PS (hpgs_reader *reader)
203{
204  double x_size=reader->x_size/HP_TO_PT;
205  double y_size=reader->y_size/HP_TO_PT;
206
207  if (reader->eoc)
208    {
209      // Well it seems, that some oldstyle HPGL files use
210      // PS w/o arguments in order to enforce a coordinate setup
211      // as if a portrait paper size has been selected.
212      // (resulting in a prerotation of 90 degrees).
213      x_size = 33600.0;
214      y_size = 47520.0;
215    }
216  else
217    {
218      if (hpgs_reader_read_double(reader,&x_size)) return -1;
219
220      // set y-size to sqrt(0.5) * x_size in order to prevent
221      // the picture from rotation. This is better then setting
222      // the y-size to the (fictional) hard-clip limit, because
223      // without rotation we definitely can calculate our own plotsize
224      // using -i.
225      if (reader->eoc)
226	y_size = sqrt(0.5) * x_size;
227    }
228
229  if (!reader->eoc &&
230      hpgs_reader_read_double(reader,&y_size)) return -1;
231
232  return hpgs_reader_set_plotsize (reader,x_size,y_size);
233}
234
235/*
236  Actually set the plot size. User by PS command above and by PJL parser.
237*/
238int hpgs_reader_set_plotsize (hpgs_reader *reader, double x_size, double y_size)
239{
240  hpgs_bbox bb = { 0.0,0.0,x_size*HP_TO_PT,y_size*HP_TO_PT };
241
242  reader->x_size = x_size;
243  reader->y_size = y_size;
244
245  if (y_size >= x_size)
246    {
247      reader->P1.x = x_size;
248      reader->P1.y = 0.0;
249      reader->P2.x = 0.0;
250      reader->P2.y = y_size;
251    }
252  else
253    {
254      reader->P1.x = 0.0;
255      reader->P1.y = 0.0;
256      reader->P2.x = x_size;
257      reader->P2.y = y_size;
258    }
259
260  reader->delta_P.x = reader->P2.x - reader->P1.x;
261  reader->delta_P.y = reader->P2.y - reader->P1.y;
262
263  // undo any effects from an RO or SC statement.
264  reader->rotation = 0;
265  reader->sc_type = -1;
266
267  // change the page matrix only, if we don't have a plotsize device.
268  if (!reader->plotsize_device)
269    hpgs_reader_set_page_matrix (reader,&bb);
270
271  hpgs_reader_set_default_transformation(reader);
272
273  // report plot size only if
274  // when we don't have a plotsize device at hands.
275  if (reader->plotsize_device)
276    return 0;
277
278  return hpgs_setplotsize(reader->device,&reader->page_bbox);
279}
280
281/*
282  Change the page matrix according to this content bounding box.
283*/
284void hpgs_reader_set_page_matrix (hpgs_reader *reader, const hpgs_bbox *bb)
285{
286  hpgs_bbox rbb;
287  double xscale,yscale;
288  hpgs_point rcp;
289
290  hpgs_matrix_ixform(&rcp,&reader->current_point,&reader->page_matrix);
291
292  // save the content bounding box for propagating it to the
293  // page_asset function.
294  reader->content_bbox = *bb;
295
296  if  (reader->page_mode == 0)
297    {
298      reader->page_bbox = *bb;
299      hpgs_matrix_set_identity(&reader->page_matrix);
300      reader->page_scale = 1.0;
301      goto restore_cb;
302    }
303
304  reader->page_matrix.mxx =  cos(reader->page_angle * M_PI / 180.0);
305  reader->page_matrix.mxy = -sin(reader->page_angle * M_PI / 180.0);
306
307  reader->page_matrix.myx =  sin(reader->page_angle * M_PI / 180.0);
308  reader->page_matrix.myy =  cos(reader->page_angle * M_PI / 180.0);
309
310  reader->page_matrix.dx = 0.0;
311  reader->page_matrix.dy = 0.0;
312
313  if (reader->page_mode == 2) // dynamic page.
314    {
315      hpgs_matrix_xform_bbox(&rbb,&reader->page_matrix,bb);
316
317      reader->page_bbox.llx = 0.0;
318      reader->page_bbox.lly = 0.0;
319
320      reader->page_bbox.urx = (rbb.urx-rbb.llx) + 2.0 * reader->page_border;
321      reader->page_bbox.ury = (rbb.ury-rbb.lly) + 2.0 * reader->page_border;
322
323      reader->page_matrix.dx = reader->page_border - rbb.llx;
324      reader->page_matrix.dy = reader->page_border - rbb.lly;
325
326      // do we fit on the maximal page size?
327      if ((reader->page_width <= 0.0 || reader->page_bbox.urx <= reader->page_width) &&
328          (reader->page_height <= 0.0 || reader->page_bbox.ury <= reader->page_height) )
329        {
330          reader->page_scale = 1.0;
331          goto restore_cb;
332        }
333
334      if (reader->page_bbox.urx > reader->page_width)
335        xscale = reader->page_width/reader->page_bbox.urx;
336      else
337        xscale = 1.0;
338
339      if (reader->page_bbox.ury> reader->page_height)
340        yscale = reader->page_height/reader->page_bbox.ury;
341      else
342        yscale = 1.0;
343
344      reader->page_scale = HPGS_MIN(xscale,yscale);
345
346      double rscale = 0.0;
347      double xx = 1.0;
348
349      // transform the scale to a human-interceptable scale.
350      do
351        {
352          xx *= 0.1;
353          rscale = floor(reader->page_scale / xx);
354        }
355      while (rscale < 2.0);
356
357      reader->page_scale = rscale * xx;
358
359      reader->page_matrix.mxx *= reader->page_scale;
360      reader->page_matrix.mxy *= reader->page_scale;
361
362      reader->page_matrix.myx *= reader->page_scale;
363      reader->page_matrix.myy *= reader->page_scale;
364
365      reader->page_matrix.dx *= reader->page_scale;
366      reader->page_matrix.dy *= reader->page_scale;
367
368      reader->page_bbox.urx *= reader->page_scale;
369      reader->page_bbox.ury *= reader->page_scale;
370
371      goto restore_cb;
372    }
373
374  // fixed page.
375  reader->page_bbox.llx = 0.0;
376  reader->page_bbox.lly = 0.0;
377
378  reader->page_bbox.urx = reader->page_width;
379  reader->page_bbox.ury = reader->page_height;
380
381  hpgs_matrix_xform_bbox(&rbb,&reader->page_matrix,bb);
382
383  xscale = (reader->page_width - 2.0 * reader->page_border) / (rbb.urx-rbb.llx);
384  yscale = (reader->page_height - 2.0 * reader->page_border) / (rbb.ury-rbb.lly);
385
386  reader->page_scale = HPGS_MIN(xscale,yscale);
387
388  reader->page_matrix.mxx *= reader->page_scale;
389  reader->page_matrix.mxy *= reader->page_scale;
390
391  reader->page_matrix.myx *= reader->page_scale;
392  reader->page_matrix.myy *= reader->page_scale;
393
394  if (reader->page_scale == xscale)
395    {
396      reader->page_matrix.dx = reader->page_border - reader->page_scale * rbb.llx;
397      reader->page_matrix.dy =
398        0.5 * (reader->page_height - reader->page_scale * (rbb.ury-rbb.lly)) - reader->page_scale * rbb.lly;
399    }
400  else
401    {
402      reader->page_matrix.dx =
403        0.5 * (reader->page_width - reader->page_scale * (rbb.urx-rbb.llx)) - reader->page_scale * rbb.llx;
404      reader->page_matrix.dy = reader->page_border - reader->page_scale * rbb.lly;
405    }
406
407 restore_cb:
408  hpgs_matrix_xform(&reader->current_point,&reader->page_matrix,&rcp);
409}
410
411/*
412  HPGL command FR (advance FRame)
413*/
414int hpgs_reader_do_FR (hpgs_reader *reader)
415{
416  double advance = reader->x_size;
417
418  if (!reader->eoc)
419    {
420      if (hpgs_reader_read_double(reader,&advance)) return -1;
421    }
422
423  if (hpgs_reader_checkpath(reader)) return -1;
424
425  while (reader->clipsave_depth > 0)
426    {
427      hpgs_cliprestore(reader->device);
428      --reader->clipsave_depth;
429    }
430
431  if (reader->frame_asset_func)
432    {
433      hpgs_bbox frame_bbox;
434
435      frame_bbox.llx = reader->frame_x == 0.0 ? reader->content_bbox.llx : reader->frame_x;
436      frame_bbox.lly = reader->content_bbox.lly;
437      frame_bbox.urx = reader->frame_x + advance * HP_TO_PT;
438      frame_bbox.ury = reader->content_bbox.ury;
439
440      if (frame_bbox.urx > frame_bbox.llx)
441        {
442          int ipage = reader->current_page;
443
444          if (reader->frame_asset_func(reader->frame_asset_ctxt,
445                                       reader->device,
446                                       &reader->page_matrix,
447                                       &reader->total_matrix,
448                                       &frame_bbox,ipage <= 1 ? 0 : ipage-1) )
449            return -1;
450        }
451    }
452
453  reader->frame_x += advance * HP_TO_PT;
454  reader->P1.x -= advance;
455  reader->P2.x -= advance;
456
457  return 0;
458}
459
460/*
461  HPGL command RO (ROtate)
462*/
463int hpgs_reader_do_RO (hpgs_reader *reader)
464{
465  int rot=0;
466  hpgs_point p1,p2;
467  double dx,dy;
468
469  if (!reader->eoc &&
470      hpgs_reader_read_int(reader,&rot)) return -1;
471
472  switch ((rot - reader->rotation) % 360)
473    {
474    case 90:
475      p1.x = -reader->P1.y;
476      p1.y =  reader->P1.x;
477      p2.x = -reader->P2.y;
478      p2.y =  reader->P2.x;
479      break;
480    case 180:
481      p1.x = -reader->P1.x;
482      p1.y = -reader->P1.y;
483      p2.x = -reader->P2.x;
484      p2.y = -reader->P2.x;
485      break;
486    case 270:
487      p1.x =  reader->P1.y;
488      p1.y = -reader->P1.x;
489      p2.x =  reader->P2.y;
490      p2.y = -reader->P2.x;
491      break;
492    default: /* 0,360 */
493      p1.x = reader->P1.x;
494      p1.y = reader->P1.y;
495      p2.x = reader->P2.x;
496      p2.y = reader->P2.x;
497      break;
498    }
499
500  dx = p1.x < p2.x ? p1.x : p2.x;
501  dy = p1.y < p2.y ? p1.y : p2.y;
502
503#ifdef HPGS_DEBUG_XFORM
504  hpgs_log("RO: rot_old,rot = %d,%d.\n",reader->rotation,rot);
505  hpgs_log("RO: P1 = %g,%g.\n",reader->P1.x,reader->P1.y);
506  hpgs_log("RO: P2 = %g,%g.\n",reader->P2.x,reader->P2.y);
507#endif
508
509  reader->P1.x = p1.x-dx;
510  reader->P1.y = p1.y-dy;
511  reader->P2.x = p2.x-dx;
512  reader->P2.y = p2.y-dy;
513
514#ifdef HPGS_DEBUG_XFORM
515  hpgs_log("RO: P1 = %g,%g.\n",reader->P1.x,reader->P1.y);
516  hpgs_log("RO: P2 = %g,%g.\n",reader->P2.x,reader->P2.y);
517#endif
518
519  reader->rotation = rot;
520
521  hpgs_reader_set_default_transformation(reader);
522
523  return 0;
524}
525
526/*
527  HPGL command SC (SCale)
528*/
529int hpgs_reader_do_SC (hpgs_reader *reader)
530{
531  double xmin,xmax,ymin,ymax,left=50.0,bottom=50.0;
532  int type=0;
533
534  if (reader->eoc)
535    {
536      reader->sc_type = -1;
537      hpgs_reader_set_default_transformation(reader);
538      return 0;
539    }
540
541  if (hpgs_reader_read_double(reader,&xmin)) return -1;
542  if (reader->eoc) return -1;
543  if (hpgs_reader_read_double(reader,&xmax)) return -1;
544  if (reader->eoc) return -1;
545  if (hpgs_reader_read_double(reader,&ymin)) return -1;
546  if (reader->eoc) return -1;
547  if (hpgs_reader_read_double(reader,&ymax)) return -1;
548  if (!reader->eoc &&
549      hpgs_reader_read_int(reader,&type)) return -1;
550
551  if (type == 1 && !reader->eoc)
552    {
553      if (hpgs_reader_read_double(reader,&left)) return -1;
554      if (reader->eoc) return -1;
555      if (hpgs_reader_read_double(reader,&bottom)) return -1;
556    }
557
558  reader->sc_type = type;
559  reader->sc_xmin = xmin;
560  reader->sc_xmax = xmax;
561  reader->sc_ymin = ymin;
562  reader->sc_ymax = ymax;
563  reader->sc_bottom = bottom;
564  reader->sc_left = left;
565
566  hpgs_reader_set_default_transformation(reader);
567  return 0;
568}
569
570/*
571  HPGL command IP (Input Point)
572*/
573int hpgs_reader_do_IP (hpgs_reader *reader)
574{
575  // get default input point.
576  int angle = reader->y_size >= reader->x_size ? 90 : 0;
577
578  angle += reader->rotation;
579
580  switch (angle % 360)
581    {
582    case 90:
583      reader->P1.x = reader->x_size;
584      reader->P1.y = 0.0;
585      reader->P2.x = 0.0;
586      reader->P2.y = reader->y_size;
587      break;
588    case 180:
589      break;
590      reader->P1.x = reader->x_size;
591      reader->P1.y = reader->y_size;
592      reader->P2.x = 0.0;
593      reader->P2.y = 0.0;
594      break;
595    case 270:
596      reader->P1.x = 0.0;
597      reader->P1.y = reader->y_size;
598      reader->P2.x = reader->x_size;
599      reader->P2.y = 0.0;
600      break;
601    default: /* 0 */
602      reader->P1.x = 0.0;
603      reader->P1.y = 0.0;
604      reader->P2.x = reader->x_size;
605      reader->P2.y = reader->y_size;
606    }
607
608
609  // read input point
610  if (!reader->eoc)
611    {
612      if (hpgs_reader_read_double(reader,
613                                  angle%180 ?
614                                  &reader->P1.y :
615                                  &reader->P1.x  )) return -1;
616      if (reader->eoc) return -1;
617      if (hpgs_reader_read_double(reader,angle%180 ?
618                                  &reader->P2.x :
619                                  &reader->P1.y  )) return -1;
620    }
621
622  if (!reader->eoc)
623    {
624      if (hpgs_reader_read_double(reader,
625                                  angle%180 ?
626                                  &reader->P2.y :
627                                  &reader->P2.x  )) return -1;
628      if (reader->eoc) return -1;
629      if (hpgs_reader_read_double(reader,
630                                  angle%180 ?
631                                  &reader->P1.x :
632                                  &reader->P2.y  )) return -1;
633    }
634
635  reader->delta_P.x = reader->P2.x - reader->P1.x;
636  reader->delta_P.y = reader->P2.y - reader->P1.y;
637
638#ifdef HPGS_DEBUG_XFORM
639  hpgs_log("IP: angle = %d.\n",angle);
640  hpgs_log("IP: P1 = %g,%g.\n",reader->P1.x,reader->P1.y);
641  hpgs_log("IP: P2 = %g,%g.\n",reader->P2.x,reader->P2.y);
642#endif
643
644  reader->sc_type = -1;
645  hpgs_reader_set_default_transformation(reader);
646
647  return 0;
648}
649
650/*
651  HPGL command IR (Input point Relative)
652*/
653int hpgs_reader_do_IR (hpgs_reader *reader)
654{
655  // get default input point.
656  double p1x=0.0,p1y=0.0,p2x,p2y;
657
658  int angle = reader->y_size >= reader->x_size ? 90 : 0;
659
660  angle += reader->rotation;
661
662  switch (angle % 360)
663    {
664    case 90:
665      p1x = reader->x_size;
666      p1y = 0.0;
667      p2x = 0.0;
668      p2y = reader->y_size;
669      break;
670    case 180:
671      break;
672      p1x = reader->x_size;
673      p1y = reader->y_size;
674      p2x = 0.0;
675      p2y = 0.0;
676      break;
677    case 270:
678      p1x = 0.0;
679      p1y = reader->y_size;
680      p2x = reader->x_size;
681      p2y = 0.0;
682      break;
683    default:
684      p1x = 0.0;
685      p1y = 0.0;
686      p2x = reader->x_size;
687      p2y = reader->y_size;
688    }
689
690  // read input point
691  if (!reader->eoc)
692    {
693      double x,y;
694
695      if (hpgs_reader_read_double(reader,&x)) return -1;
696      if (hpgs_reader_read_double(reader,&y)) return -1;
697
698      p1x = reader->x_size * x * 0.01;
699      p2x = p1x + reader->delta_P.x;
700      p1y = reader->y_size * y * 0.01;
701      p2y = p1y + reader->delta_P.y;
702    }
703
704  if (!reader->eoc)
705    {
706      if (hpgs_reader_read_double(reader,&p2x)) return -1;
707      if (hpgs_reader_read_double(reader,&p2y)) return -1;
708
709      p2x = reader->x_size * p2x * 0.01;
710      p2y = reader->y_size * p2y * 0.01;
711
712      reader->delta_P.x = p2x - p1x;
713      reader->delta_P.y = p2y - p1y;
714    }
715
716  reader->P1.x = p1x;
717  reader->P1.y = p1y;
718  reader->P2.x = p2x;
719  reader->P2.y = p2y;
720
721#ifdef HPGS_DEBUG_XFORM
722  hpgs_log("IR: P1 = %g,%g.\n",reader->P1.x,reader->P1.y);
723  hpgs_log("IR: P2 = %g,%g.\n",reader->P2.x,reader->P2.y);
724#endif
725
726  hpgs_reader_set_default_transformation(reader);
727
728  return 0;
729}
730
731/*
732  HPGL command IW (Input Window)
733*/
734int hpgs_reader_do_IW (hpgs_reader *reader)
735{
736  // get default input point.
737  hpgs_point ll;
738  hpgs_point ur;
739  hpgs_point p;
740
741  if (hpgs_reader_checkpath(reader)) return -1;
742
743  while (reader->clipsave_depth > 0)
744    {
745      hpgs_cliprestore(reader->device);
746      --reader->clipsave_depth;
747    }
748
749  if (reader->eoc) return 0;
750
751  // read input point
752  if (hpgs_reader_read_point(reader,&ll,1)) return -1;
753  if (hpgs_reader_read_point(reader,&ur,1)) return -1;
754
755  if (hpgs_clipsave(reader->device)) return -1;
756  ++reader->clipsave_depth;
757
758  if (hpgs_newpath(reader->device)) return -1;
759  if (hpgs_moveto(reader->device,&ll)) return -1;
760  p.x = ll.x;
761  p.y = ur.y;
762  if (hpgs_lineto(reader->device,&p)) return -1;
763  if (hpgs_lineto(reader->device,&ur)) return -1;
764  p.x = ur.x;
765  p.y = ll.y;
766  if (hpgs_lineto(reader->device,&p)) return -1;
767  if (hpgs_closepath(reader->device)) return -1;
768  if (hpgs_clip(reader->device,HPGS_TRUE)) return -1;
769
770  reader->have_current_point = 0;
771
772  return hpgs_newpath(reader->device);
773}
774