~efargaspro/+junk/codeblocks-16.01-release

« back to all changes in this revision

Viewing changes to src/plugins/contrib/source_exporter/wxPdfDocument/src/pdfgraphics.cpp

  • Committer: damienlmoore at gmail
  • Date: 2016-02-02 02:43:22 UTC
  • Revision ID: damienlmoore@gmail.com-20160202024322-yql5qmtbwdyamdwd
Code::BlocksĀ 16.01

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
///////////////////////////////////////////////////////////////////////////////
 
2
// Name:        pdfgraphics.cpp
 
3
// Purpose:     Implementation of wxPdfDocument graphics primitives
 
4
// Author:      Ulrich Telle
 
5
// Modified by:
 
6
// Created:     2006-01-27
 
7
// Copyright:   (c) Ulrich Telle
 
8
// Licence:     wxWindows licence
 
9
///////////////////////////////////////////////////////////////////////////////
 
10
 
 
11
/// \file pdfgraphics.cpp Implementation of the wxPdfDocument graphics primitives
 
12
 
 
13
// For compilers that support precompilation, includes <wx/wx.h>.
 
14
#include <wx/wxprec.h>
 
15
 
 
16
#ifdef __BORLANDC__
 
17
#pragma hdrstop
 
18
#endif
 
19
 
 
20
#ifndef WX_PRECOMP
 
21
#include <wx/wx.h>
 
22
#endif
 
23
 
 
24
#include <wx/tokenzr.h>
 
25
 
 
26
#include "wx/pdfcoonspatchmesh.h"
 
27
#include "wx/pdfdocument.h"
 
28
#include "wx/pdfgradient.h"
 
29
#include "wx/pdfgraphics.h"
 
30
#include "wx/pdfshape.h"
 
31
#include "wx/pdfutility.h"
 
32
 
 
33
wxPdfExtGState::wxPdfExtGState(double lineAlpha, double fillAlpha, wxPdfBlendMode blendMode)
 
34
{
 
35
  m_lineAlpha = lineAlpha;
 
36
  m_fillAlpha = fillAlpha;
 
37
  m_blendMode = blendMode;
 
38
}
 
39
 
 
40
wxPdfExtGState::~wxPdfExtGState()
 
41
{
 
42
}
 
43
 
 
44
int
 
45
wxPdfDocument::SetAlpha(double lineAlpha, double fillAlpha, wxPdfBlendMode blendMode)
 
46
{
 
47
  int n = 0;
 
48
 
 
49
  // Force alpha into range 0 .. 1
 
50
  if (lineAlpha < 0) lineAlpha = 0;
 
51
  else if (lineAlpha > 1) lineAlpha = 1;
 
52
  if (fillAlpha < 0) fillAlpha = 0;
 
53
  else if (fillAlpha > 1) fillAlpha = 1;
 
54
 
 
55
  // Create state id for lookup map
 
56
  int id = ((int) blendMode) * 100000000 + (int) (lineAlpha * 1000) * 10000 + (int) (fillAlpha * 1000);
 
57
 
 
58
  // Lookup state
 
59
  wxPdfExtGSLookupMap::iterator extGState = (*m_extGSLookup).find(id);
 
60
  if (extGState == (*m_extGSLookup).end())
 
61
  {
 
62
    n = (int) (*m_extGStates).size() + 1;
 
63
    (*m_extGStates)[n] = new wxPdfExtGState(lineAlpha, fillAlpha, blendMode);
 
64
    (*m_extGSLookup)[id] = n;
 
65
  }
 
66
  else
 
67
  {
 
68
    n = extGState->second;
 
69
  }
 
70
 
 
71
  if (n != m_currentExtGState)
 
72
  {
 
73
    SetAlphaState(n);
 
74
  }
 
75
 
 
76
  return n;
 
77
}
 
78
 
 
79
void
 
80
wxPdfDocument::SetAlphaState(int alphaState)
 
81
{
 
82
  if (alphaState > 0 && (size_t) alphaState <= (*m_extGStates).size())
 
83
  {
 
84
    OutAscii(wxString::Format(wxT("/GS%d gs"), alphaState));
 
85
  }
 
86
}
 
87
 
 
88
// ----------------------------------------------------------------------------
 
89
// wxPdfLineStyle: class representing line style for drawing graphics
 
90
// ----------------------------------------------------------------------------
 
91
 
 
92
wxPdfLineStyle::wxPdfLineStyle(double width,
 
93
                               wxPdfLineCap cap, wxPdfLineJoin join,
 
94
                               const wxPdfArrayDouble& dash, double phase,
 
95
                               const wxPdfColour& colour)
 
96
{
 
97
  m_isSet = (width > 0) || (cap >= 0) || (join >= 0) || (dash.GetCount() > 0);
 
98
  m_width = width;
 
99
  m_cap   = cap;
 
100
  m_join  = join;
 
101
  m_dash  = dash;
 
102
  m_phase = phase;
 
103
  m_colour = colour;
 
104
}
 
105
 
 
106
wxPdfLineStyle::~wxPdfLineStyle()
 
107
{
 
108
}
 
109
 
 
110
 
 
111
wxPdfLineStyle::wxPdfLineStyle(const wxPdfLineStyle& lineStyle)
 
112
{
 
113
  m_isSet = lineStyle.m_isSet;
 
114
  m_width = lineStyle.m_width;
 
115
  m_cap   = lineStyle.m_cap;
 
116
  m_join  = lineStyle.m_join;
 
117
  m_dash  = lineStyle.m_dash;
 
118
  m_phase = lineStyle.m_phase;
 
119
  m_colour = lineStyle.m_colour;
 
120
}
 
121
 
 
122
wxPdfLineStyle&
 
123
wxPdfLineStyle::operator= (const wxPdfLineStyle& lineStyle)
 
124
{
 
125
  m_isSet = lineStyle.m_isSet;
 
126
  m_width = lineStyle.m_width;
 
127
  m_cap   = lineStyle.m_cap;
 
128
  m_join  = lineStyle.m_join;
 
129
  m_dash  = lineStyle.m_dash;
 
130
  m_phase = lineStyle.m_phase;
 
131
  m_colour = lineStyle.m_colour;
 
132
  return *this;
 
133
}
 
134
 
 
135
// ---
 
136
 
 
137
wxPdfShape::wxPdfShape()
 
138
{
 
139
  m_subpath = -1;
 
140
  m_index = 0;
 
141
}
 
142
 
 
143
wxPdfShape::~wxPdfShape()
 
144
{
 
145
}
 
146
 
 
147
void
 
148
wxPdfShape::MoveTo(double x, double y)
 
149
{
 
150
  m_subpath = (int) m_x.GetCount();
 
151
  m_types.Add(wxPDF_SEG_MOVETO);
 
152
  m_x.Add(x);
 
153
  m_y.Add(y);
 
154
}
 
155
 
 
156
void
 
157
wxPdfShape::LineTo(double x, double y)
 
158
{
 
159
  if (m_subpath >= 0)
 
160
  {
 
161
    m_types.Add(wxPDF_SEG_LINETO);
 
162
    m_x.Add(x);
 
163
    m_y.Add(y);
 
164
  }
 
165
  else
 
166
  {
 
167
    wxLogError(wxString(wxT("wxPdfShape::LineTo: ")) +
 
168
               wxString(_("Invalid subpath.")));
 
169
  }
 
170
}
 
171
 
 
172
void
 
173
wxPdfShape::CurveTo(double x1, double y1, double x2, double y2, double x3, double y3)
 
174
{
 
175
  if (m_subpath >= 0)
 
176
  {
 
177
    m_types.Add(wxPDF_SEG_CURVETO);
 
178
    m_x.Add(x1);
 
179
    m_y.Add(y1);
 
180
    m_x.Add(x2);
 
181
    m_y.Add(y2);
 
182
    m_x.Add(x3);
 
183
    m_y.Add(y3);
 
184
  }
 
185
  else
 
186
  {
 
187
    wxLogError(wxString(wxT("wxPdfShape::CurveTo: ")) +
 
188
               wxString(_("Invalid subpath.")));
 
189
  }
 
190
}
 
191
 
 
192
void
 
193
wxPdfShape::ClosePath()
 
194
{
 
195
  if (m_subpath >= 0 && m_types.GetCount() > 0 && m_types.Last() != wxPDF_SEG_CLOSE)
 
196
  {
 
197
    m_types.Add(wxPDF_SEG_CLOSE);
 
198
    m_x.Add(m_x[m_subpath]);
 
199
    m_y.Add(m_y[m_subpath]);
 
200
    m_subpath = -1;
 
201
  }
 
202
}
 
203
 
 
204
wxPdfSegmentType
 
205
wxPdfShape::GetSegment(int iterType, int iterPoints, double coords[]) const
 
206
{
 
207
  wxPdfSegmentType segType = wxPDF_SEG_UNDEFINED;
 
208
  if (iterType >= 0 && (size_t) iterType < m_types.GetCount())
 
209
  {
 
210
    int pointCount = (m_types[iterType] == wxPDF_SEG_CURVETO) ? 2 : 0;
 
211
    if (iterPoints >= 0 && (size_t) (iterPoints + pointCount) < m_x.GetCount())
 
212
    {
 
213
      segType = (wxPdfSegmentType) m_types[iterType];
 
214
      switch (segType)
 
215
      {
 
216
        case wxPDF_SEG_CLOSE:
 
217
          coords[0] = m_x[iterPoints];
 
218
          coords[1] = m_y[iterPoints];
 
219
          break;
 
220
 
 
221
        case wxPDF_SEG_MOVETO:
 
222
        case wxPDF_SEG_LINETO:
 
223
          coords[0] = m_x[iterPoints];
 
224
          coords[1] = m_y[iterPoints];
 
225
          break;
 
226
 
 
227
        case wxPDF_SEG_CURVETO:
 
228
          coords[0] = m_x[iterPoints];
 
229
          coords[1] = m_y[iterPoints];
 
230
          iterPoints++;
 
231
          coords[2] = m_x[iterPoints];
 
232
          coords[3] = m_y[iterPoints];
 
233
          iterPoints++;
 
234
          coords[4] = m_x[iterPoints];
 
235
          coords[5] = m_y[iterPoints];
 
236
          break;
 
237
        default:
 
238
          break;
 
239
      }
 
240
    }
 
241
  }
 
242
  return segType;
 
243
}
 
244
 
 
245
wxPdfFlatPath::wxPdfFlatPath(const wxPdfShape* shape, double flatness, int limit)
 
246
{
 
247
  m_shape = shape;
 
248
  m_iterType = 0;
 
249
  m_iterPoints = 0;
 
250
  m_done = false;
 
251
  m_flatnessSq = flatness * flatness;
 
252
  m_recursionLimit = limit;
 
253
 
 
254
  m_stackMaxSize = 6 * m_recursionLimit + /* 6 + 2 */ 8;
 
255
  m_stack = new double[m_stackMaxSize];
 
256
  m_recLevel = new int[m_recursionLimit + 1];
 
257
 
 
258
  FetchSegment();
 
259
}
 
260
 
 
261
wxPdfFlatPath::~wxPdfFlatPath()
 
262
{
 
263
  delete [] m_stack;
 
264
  delete [] m_recLevel;
 
265
}
 
266
 
 
267
void
 
268
wxPdfFlatPath::InitIter()
 
269
{
 
270
  m_done       = false;
 
271
  m_iterType   = 0;
 
272
  m_iterPoints = 0;
 
273
  m_stackSize  = 0;
 
274
  FetchSegment();
 
275
}
 
276
 
 
277
  /**
 
278
   * Fetches the next segment from the source iterator.
 
279
   */
 
280
void
 
281
wxPdfFlatPath::FetchSegment()
 
282
{
 
283
  int sp;
 
284
 
 
285
  if ((size_t) m_iterType >= m_shape->GetSegmentCount())
 
286
  {
 
287
    m_done = true;
 
288
    return;
 
289
  }
 
290
 
 
291
  m_srcSegType = m_shape->GetSegment(m_iterType, m_iterPoints, m_scratch);
 
292
    
 
293
  switch (m_srcSegType)
 
294
  {
 
295
    case wxPDF_SEG_CLOSE:
 
296
      return;
 
297
 
 
298
    case wxPDF_SEG_MOVETO:
 
299
    case wxPDF_SEG_LINETO:
 
300
      m_srcPosX = m_scratch[0];
 
301
      m_srcPosY = m_scratch[1];
 
302
      return;
 
303
 
 
304
    case wxPDF_SEG_CURVETO:
 
305
      if (m_recursionLimit == 0)
 
306
      {
 
307
        m_srcPosX = m_scratch[4];
 
308
        m_srcPosY = m_scratch[5];
 
309
        m_stackSize = 0;
 
310
        return;
 
311
      }
 
312
      sp = 6 * m_recursionLimit;
 
313
      m_stackSize = 1;
 
314
      m_recLevel[0] = 0;
 
315
      m_stack[sp] = m_srcPosX;                  // P1.x
 
316
      m_stack[sp + 1] = m_srcPosY;              // P1.y
 
317
      m_stack[sp + 2] = m_scratch[0];           // C1.x
 
318
      m_stack[sp + 3] = m_scratch[1];           // C1.y
 
319
      m_stack[sp + 4] = m_scratch[2];           // C2.x
 
320
      m_stack[sp + 5] = m_scratch[3];           // C2.y
 
321
      m_srcPosX = m_stack[sp + 6] = m_scratch[4]; // P2.x
 
322
      m_srcPosY = m_stack[sp + 7] = m_scratch[5]; // P2.y
 
323
      SubdivideCubic();
 
324
      return;
 
325
  }
 
326
}
 
327
 
 
328
void
 
329
wxPdfFlatPath::Next()
 
330
{
 
331
  if (m_stackSize > 0)
 
332
  {
 
333
    --m_stackSize;
 
334
    if (m_stackSize > 0)
 
335
    {
 
336
      switch (m_srcSegType)
 
337
      {
 
338
        case wxPDF_SEG_CURVETO:
 
339
          SubdivideCubic();
 
340
          return;
 
341
 
 
342
        default:
 
343
          break;
 
344
      }
 
345
    }
 
346
  }
 
347
 
 
348
  if ((size_t) m_iterType < m_shape->GetSegmentCount())
 
349
  {
 
350
    switch (m_srcSegType)
 
351
    {
 
352
      case wxPDF_SEG_CLOSE:
 
353
      case wxPDF_SEG_MOVETO:
 
354
      case wxPDF_SEG_LINETO:
 
355
        m_iterPoints++;
 
356
        break;
 
357
 
 
358
      case wxPDF_SEG_CURVETO:
 
359
        m_iterPoints += 3;
 
360
        break;
 
361
    }
 
362
    m_iterType++;
 
363
  }
 
364
 
 
365
  FetchSegment();
 
366
}
 
367
 
 
368
int
 
369
wxPdfFlatPath::CurrentSegment(double coords[])
 
370
{
 
371
  switch (m_srcSegType)
 
372
  {
 
373
    case wxPDF_SEG_CLOSE:
 
374
      return m_srcSegType;
 
375
 
 
376
    case wxPDF_SEG_MOVETO:
 
377
    case wxPDF_SEG_LINETO:
 
378
      coords[0] = m_srcPosX;
 
379
      coords[1] = m_srcPosY;
 
380
      return m_srcSegType;
 
381
 
 
382
    case wxPDF_SEG_CURVETO:
 
383
      if (m_stackSize == 0)
 
384
      {
 
385
        coords[0] = m_srcPosX;
 
386
        coords[1] = m_srcPosY;
 
387
      }
 
388
      else
 
389
      {
 
390
        int sp = m_stackMaxSize - 6 * m_stackSize;
 
391
        coords[0] = m_stack[sp + 4];
 
392
        coords[1] = m_stack[sp + 5];
 
393
      }
 
394
      return wxPDF_SEG_LINETO;
 
395
  }
 
396
 
 
397
  return wxPDF_SEG_UNDEFINED;
 
398
}
 
399
 
 
400
static void
 
401
SubdivideCubicCurve(double src[], int srcOff,
 
402
                    double left[], int leftOff,
 
403
                    double right[], int rightOff)
 
404
{
 
405
  // To understand this code, please have a look at the image
 
406
  // "CubicCurve2D-3.png" in the sub-directory "doc-files".
 
407
  double srcC1x;
 
408
  double srcC1y;
 
409
  double srcC2x;
 
410
  double srcC2y;
 
411
  double leftP1x;
 
412
  double leftP1y;
 
413
  double leftC1x;
 
414
  double leftC1y;
 
415
  double leftC2x;
 
416
  double leftC2y;
 
417
  double rightC1x;
 
418
  double rightC1y;
 
419
  double rightC2x;
 
420
  double rightC2y;
 
421
  double rightP2x;
 
422
  double rightP2y;
 
423
  double midx; // Mid = left.P2 = right.P1
 
424
  double midy; // Mid = left.P2 = right.P1
 
425
 
 
426
  leftP1x = src[srcOff];
 
427
  leftP1y = src[srcOff + 1];
 
428
  srcC1x = src[srcOff + 2];
 
429
  srcC1y = src[srcOff + 3];
 
430
  srcC2x = src[srcOff + 4];
 
431
  srcC2y = src[srcOff + 5];
 
432
  rightP2x = src[srcOff + 6];
 
433
  rightP2y = src[srcOff + 7];
 
434
 
 
435
  leftC1x = (leftP1x + srcC1x) / 2;
 
436
  leftC1y = (leftP1y + srcC1y) / 2;
 
437
  rightC2x = (rightP2x + srcC2x) / 2;
 
438
  rightC2y = (rightP2y + srcC2y) / 2;
 
439
  midx = (srcC1x + srcC2x) / 2;
 
440
  midy = (srcC1y + srcC2y) / 2;
 
441
  leftC2x = (leftC1x + midx) / 2;
 
442
  leftC2y = (leftC1y + midy) / 2;
 
443
  rightC1x = (midx + rightC2x) / 2;
 
444
  rightC1y = (midy + rightC2y) / 2;
 
445
  midx = (leftC2x + rightC1x) / 2;
 
446
  midy = (leftC2y + rightC1y) / 2;
 
447
 
 
448
  if (left != NULL)
 
449
  {
 
450
    left[leftOff] = leftP1x;
 
451
    left[leftOff + 1] = leftP1y;
 
452
    left[leftOff + 2] = leftC1x;
 
453
    left[leftOff + 3] = leftC1y;
 
454
    left[leftOff + 4] = leftC2x;
 
455
    left[leftOff + 5] = leftC2y;
 
456
    left[leftOff + 6] = midx;
 
457
    left[leftOff + 7] = midy;
 
458
  }
 
459
 
 
460
  if (right != NULL)
 
461
  {
 
462
    right[rightOff] = midx;
 
463
    right[rightOff + 1] = midy;
 
464
    right[rightOff + 2] = rightC1x;
 
465
    right[rightOff + 3] = rightC1y;
 
466
    right[rightOff + 4] = rightC2x;
 
467
    right[rightOff + 5] = rightC2y;
 
468
    right[rightOff + 6] = rightP2x;
 
469
    right[rightOff + 7] = rightP2y;
 
470
  }
 
471
}
 
472
 
 
473
static double
 
474
PointSegmentDistanceSq(double x1, double y1, double x2, double y2, double px, double py)
 
475
{
 
476
  double pd2 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
 
477
 
 
478
  double x, y;
 
479
  if (pd2 == 0)
 
480
  {
 
481
    // Points are coincident.
 
482
    x = x1;
 
483
    y = y2;
 
484
  }
 
485
  else
 
486
  {
 
487
    double u = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / pd2;
 
488
 
 
489
    if (u < 0)
 
490
    {
 
491
      // "Off the end"
 
492
      x = x1;
 
493
      y = y1;
 
494
    }
 
495
    else if (u > 1.0)
 
496
    {
 
497
      x = x2;
 
498
      y = y2;
 
499
    }
 
500
    else
 
501
    {
 
502
      x = x1 + u * (x2 - x1);
 
503
      y = y1 + u * (y2 - y1);
 
504
    }
 
505
  }
 
506
 
 
507
  return (x - px) * (x - px) + (y - py) * (y - py);
 
508
}
 
509
 
 
510
static double
 
511
GetFlatnessSq(double x1, double y1, double cx1, double cy1,
 
512
              double cx2, double cy2, double x2, double y2)
 
513
{
 
514
 
 
515
  double d1 = PointSegmentDistanceSq(x1, y1, x2, y2, cx1, cy1);
 
516
  double d2 = PointSegmentDistanceSq(x1, y1, x2, y2, cx2, cy2);
 
517
  return (d1 > d2) ? d1 : d2;
 
518
//  return Math.max(Line2D.ptSegDistSq(x1, y1, x2, y2, cx1, cy1),
 
519
//                  Line2D.ptSegDistSq(x1, y1, x2, y2, cx2, cy2));
 
520
}
 
521
 
 
522
static double
 
523
GetFlatnessSq(double coords[], int offset)
 
524
{
 
525
  return GetFlatnessSq(coords[offset+0], coords[offset+1], coords[offset+2],
 
526
                       coords[offset+3], coords[offset+4], coords[offset+5],
 
527
                       coords[offset+6], coords[offset+7]);
 
528
}
 
529
 
 
530
  /**
 
531
   * Repeatedly subdivides the cubic curve segment that is on top
 
532
   * of the stack. The iteration terminates when the recursion limit
 
533
   * has been reached, or when the resulting segment is flat enough.
 
534
   */
 
535
void
 
536
wxPdfFlatPath::SubdivideCubic()
 
537
{
 
538
  int sp;
 
539
  int level;
 
540
 
 
541
  sp = m_stackMaxSize - 6 * m_stackSize - 2;
 
542
  level = m_recLevel[m_stackSize - 1];
 
543
  while ((level < m_recursionLimit)
 
544
         && (GetFlatnessSq(m_stack, sp) >= m_flatnessSq))
 
545
  {
 
546
    m_recLevel[m_stackSize] = m_recLevel[m_stackSize - 1] = ++level;
 
547
      
 
548
    SubdivideCubicCurve(m_stack, sp, m_stack, sp - 6, m_stack, sp);
 
549
    ++m_stackSize;
 
550
    sp -= 6;
 
551
  }
 
552
}
 
553
 
 
554
double
 
555
wxPdfFlatPath::MeasurePathLength()
 
556
{
 
557
  double points[6];
 
558
  double moveX = 0, moveY = 0;
 
559
  double lastX = 0, lastY = 0;
 
560
  double thisX = 0, thisY = 0;
 
561
  int type = 0;
 
562
  double total = 0;
 
563
 
 
564
  // Save iterator state
 
565
  bool saveDone      = m_done;
 
566
  int saveIterType   = m_iterType;
 
567
  int saveIterPoints = m_iterPoints;
 
568
  int saveStackSize  = m_stackSize;
 
569
 
 
570
  InitIter();
 
571
  while (!IsDone())
 
572
  {
 
573
    type = CurrentSegment(points);
 
574
    switch( type )
 
575
    {
 
576
      case wxPDF_SEG_MOVETO:
 
577
        moveX = lastX = points[0];
 
578
        moveY = lastY = points[1];
 
579
        break;
 
580
 
 
581
      case wxPDF_SEG_CLOSE:
 
582
        points[0] = moveX;
 
583
        points[1] = moveY;
 
584
        // Fall into....
 
585
 
 
586
      case wxPDF_SEG_LINETO:
 
587
        thisX = points[0];
 
588
        thisY = points[1];
 
589
        double dx = thisX-lastX;
 
590
        double dy = thisY-lastY;
 
591
        total += sqrt(dx*dx + dy*dy);
 
592
        lastX = thisX;
 
593
        lastY = thisY;
 
594
        break;
 
595
    }
 
596
    Next();
 
597
  }
 
598
 
 
599
  // Restore iterator state
 
600
  m_done       = saveDone;
 
601
  m_iterType   = saveIterType;
 
602
  m_iterPoints = saveIterPoints;
 
603
  m_stackSize  = saveStackSize;
 
604
  FetchSegment();
 
605
 
 
606
  return total;
 
607
}
 
608
 
 
609
void
 
610
wxPdfDocument::ShapedText(const wxPdfShape& shape, const wxString& text, wxPdfShapedTextMode mode)
 
611
{
 
612
  wxString voText = ApplyVisualOrdering(text);
 
613
  bool stretchToFit = (mode == wxPDF_SHAPEDTEXTMODE_STRETCHTOFIT);
 
614
  bool repeat = (mode == wxPDF_SHAPEDTEXTMODE_REPEAT);
 
615
  double flatness = 0.25 / GetScaleFactor();
 
616
  wxPdfFlatPath it(&shape, flatness);
 
617
  double points[6];
 
618
  double moveX = 0, moveY = 0;
 
619
  double lastX = 0, lastY = 0;
 
620
  double thisX = 0, thisY = 0;
 
621
  int type = 0;
 
622
  double next = 0;
 
623
  unsigned int currentChar = 0;
 
624
  unsigned int length = (unsigned int) voText.Length();
 
625
  double height = GetFontSize() / GetScaleFactor();
 
626
 
 
627
  if (length == 0)
 
628
  {
 
629
    return;
 
630
  }
 
631
 
 
632
  double factor = stretchToFit ? it.MeasurePathLength() / DoGetStringWidth(voText) : 1.0;
 
633
  double nextAdvance = 0;
 
634
 
 
635
  while (currentChar < length && !it.IsDone())
 
636
  {
 
637
    type = it.CurrentSegment(points);
 
638
    switch (type)
 
639
    {
 
640
      case wxPDF_SEG_MOVETO:
 
641
      {
 
642
        moveX = lastX = points[0];
 
643
        moveY = lastY = points[1];
 
644
        SetXY(moveX, moveY);
 
645
        nextAdvance = DoGetStringWidth(voText.Mid(currentChar,1)) * 0.5;
 
646
        next = nextAdvance;
 
647
        break;
 
648
      }
 
649
 
 
650
      case wxPDF_SEG_CLOSE:
 
651
      {
 
652
        points[0] = moveX;
 
653
        points[1] = moveY;
 
654
        // Fall into...
 
655
      }
 
656
 
 
657
      case wxPDF_SEG_LINETO:
 
658
      {
 
659
        thisX = points[0];
 
660
        thisY = points[1];
 
661
        double dx = thisX-lastX;
 
662
        double dy = thisY-lastY;
 
663
        double distance = sqrt(dx*dx + dy*dy);
 
664
        if (distance >= next)
 
665
        {
 
666
          double r = 1.0 / distance;
 
667
          double angle = atan2(-dy, dx) * 45. / atan(1.);
 
668
          while (currentChar < length && distance >= next)
 
669
          {
 
670
            wxString glyph = voText.Mid(currentChar, 1);
 
671
            double x = lastX + next*dx*r;
 
672
            double y = lastY + next*dy*r;
 
673
            double advance = nextAdvance;
 
674
            nextAdvance = currentChar < length-1 ? DoGetStringWidth(voText.Mid(currentChar+1,1)) * 0.5 : 
 
675
                                                   (repeat) ? DoGetStringWidth(voText.Mid(0,1)) * 0.5 : 0;
 
676
            SetXY(x, y);
 
677
            StartTransform();
 
678
            Rotate(angle);
 
679
            SetXY(x-advance,y-height);
 
680
            Write(height, glyph);
 
681
            StopTransform();
 
682
            next += (advance+nextAdvance) * factor;
 
683
            currentChar++;
 
684
            if ( repeat )
 
685
            {
 
686
              currentChar %= length;
 
687
            }
 
688
          }
 
689
        }
 
690
        next -= distance;
 
691
        lastX = thisX;
 
692
        lastY = thisY;
 
693
        break;
 
694
      }
 
695
    }
 
696
    it.Next();
 
697
  }
 
698
}
 
699
 
 
700
// ---
 
701
 
 
702
void
 
703
wxPdfDocument::SetFillingRule(int rule)
 
704
{
 
705
  if (rule == wxWINDING_RULE || rule == wxODDEVEN_RULE)
 
706
  {
 
707
    m_fillRule = rule;
 
708
  }
 
709
}
 
710
 
 
711
int
 
712
wxPdfDocument::GetFillingRule()
 
713
{
 
714
  return m_fillRule;
 
715
}
 
716
 
 
717
void
 
718
wxPdfDocument::Line(double x1, double y1, double x2, double y2)
 
719
{
 
720
  // Draw a line
 
721
  OutAscii(wxPdfUtility::Double2String(x1*m_k,2) + wxString(wxT(" ")) +
 
722
           wxPdfUtility::Double2String(y1*m_k,2) + wxString(wxT(" m ")) +
 
723
           wxPdfUtility::Double2String(x2*m_k,2) + wxString(wxT(" ")) +
 
724
           wxPdfUtility::Double2String(y2*m_k,2) + wxString(wxT(" l S")));
 
725
}
 
726
 
 
727
void
 
728
wxPdfDocument::Rect(double x, double y, double w, double h, int style)
 
729
{
 
730
  wxString op;
 
731
  // Draw a rectangle
 
732
  if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILL)
 
733
  {
 
734
    op = wxT("f");
 
735
  }
 
736
  else if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILLDRAW)
 
737
  {
 
738
    op = wxT("B");
 
739
  }
 
740
  else
 
741
  {
 
742
    op = wxT("S");
 
743
  }
 
744
  OutAscii(wxPdfUtility::Double2String(x*m_k,2) + wxString(wxT(" ")) +
 
745
           wxPdfUtility::Double2String(y*m_k,2) + wxString(wxT(" ")) +
 
746
           wxPdfUtility::Double2String(w*m_k,2) + wxString(wxT(" ")) +
 
747
           wxPdfUtility::Double2String(h*m_k,2) + wxString(wxT(" re ")) + op);
 
748
}
 
749
 
 
750
void
 
751
wxPdfDocument::RoundedRect(double x, double y, double w, double h,
 
752
                           double r, int roundCorner, int style)
 
753
{
 
754
  if ((roundCorner & wxPDF_CORNER_ALL) == wxPDF_CORNER_NONE)
 
755
  {
 
756
    // Not rounded
 
757
    Rect(x, y, w, h, style);
 
758
  }
 
759
  else
 
760
  { 
 
761
    // Rounded
 
762
    wxString op;
 
763
    // Draw a rectangle
 
764
    if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILL)
 
765
    {
 
766
      op = wxT("f");
 
767
    }
 
768
    else
 
769
    {
 
770
      if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILLDRAW)
 
771
      {
 
772
        op = wxT("B");
 
773
      }
 
774
      else
 
775
      {
 
776
        op = wxT("S");
 
777
      }
 
778
    }
 
779
 
 
780
    double myArc = 4. / 3. * (sqrt(2.) - 1.);
 
781
 
 
782
    OutPoint(x + r, y);
 
783
    double xc = x + w - r;
 
784
    double yc = y + r;
 
785
    OutLine(xc, y);
 
786
 
 
787
    if (roundCorner & wxPDF_CORNER_TOP_LEFT)
 
788
    {
 
789
      OutCurve(xc + (r * myArc), yc - r, xc + r, yc - (r * myArc), xc + r, yc);
 
790
    }
 
791
    else
 
792
    {
 
793
      OutLine(x + w, y);
 
794
    }
 
795
 
 
796
    xc = x + w - r ;
 
797
    yc = y + h - r;
 
798
    OutLine(x + w, yc);
 
799
 
 
800
    if (roundCorner & wxPDF_CORNER_TOP_RIGHT)
 
801
    {
 
802
      OutCurve(xc + r, yc + (r * myArc), xc + (r * myArc), yc + r, xc, yc + r);
 
803
    }
 
804
    else
 
805
    {
 
806
      OutLine(x + w, y + h);
 
807
    }
 
808
 
 
809
    xc = x + r;
 
810
    yc = y + h - r;
 
811
    OutLine(xc, y + h);
 
812
 
 
813
    if (roundCorner & wxPDF_CORNER_BOTTOM_LEFT)
 
814
    {
 
815
      OutCurve(xc - (r * myArc), yc + r, xc - r, yc + (r * myArc), xc - r, yc);
 
816
    }
 
817
    else
 
818
    {
 
819
      OutLine(x, y + h);
 
820
    }
 
821
 
 
822
    xc = x + r;
 
823
    yc = y + r;
 
824
    OutLine(x, yc);
 
825
    
 
826
    if (roundCorner & wxPDF_CORNER_BOTTOM_RIGHT)
 
827
    {
 
828
      OutCurve(xc - r, yc - (r * myArc), xc - (r * myArc), yc - r, xc, yc - r);
 
829
    }
 
830
    else
 
831
    {
 
832
      OutLine(x, y);
 
833
      OutLine(x + r, y);
 
834
    }
 
835
    OutAscii(op);
 
836
  }
 
837
}
 
838
 
 
839
void
 
840
wxPdfDocument::Curve(double x0, double y0, double x1, double y1, 
 
841
                     double x2, double y2, double x3, double y3,
 
842
                     int style)
 
843
{
 
844
  wxString op;
 
845
  // Draw a rectangle
 
846
  if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILL)
 
847
  {
 
848
    op = (m_fillRule == wxODDEVEN_RULE) ? wxT("f*") : wxT("f");
 
849
  }
 
850
  else
 
851
  {
 
852
    if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILLDRAW)
 
853
    {
 
854
      op = (m_fillRule == wxODDEVEN_RULE) ? wxT("B*") : wxT("B");
 
855
    }
 
856
    else
 
857
    {
 
858
      op = wxT("S");
 
859
    }
 
860
  }
 
861
 
 
862
  OutPoint(x0, y0);
 
863
  OutCurve(x1, y1, x2, y2, x3, y3);
 
864
  OutAscii(op);
 
865
}
 
866
 
 
867
void
 
868
wxPdfDocument::Ellipse(double x0, double y0, double rx, double ry, 
 
869
                       double angle, double astart, double afinish,
 
870
                       int style, int nSeg, bool doSector)
 
871
{
 
872
  if (rx <= 0) return;
 
873
 
 
874
  wxString op;
 
875
  // Draw an ellipse
 
876
  if ((style & wxPDF_STYLE_DRAWCLOSE) == wxPDF_STYLE_DRAWCLOSE)
 
877
  {
 
878
    // Close the path as well
 
879
    if ((style & wxPDF_STYLE_FILL) == wxPDF_STYLE_FILL)
 
880
    {
 
881
      op = wxT("b"); // small 'b' means closing the path as well
 
882
    }
 
883
    else
 
884
    {
 
885
      op = wxT("s"); // small 's' means closing the path as well
 
886
    }
 
887
  }
 
888
  else
 
889
  {
 
890
    if ((style & wxPDF_STYLE_MASK) == wxPDF_STYLE_FILL)
 
891
    {
 
892
      op = wxT("f");
 
893
    }
 
894
    else if ((style & wxPDF_STYLE_MASK) == wxPDF_STYLE_FILLDRAW)
 
895
    {
 
896
      op = (doSector) ? wxT("b") : wxT("B");
 
897
    }
 
898
    else
 
899
    {
 
900
      op = (doSector) ? wxT("s") : wxT("S");
 
901
    }
 
902
  }
 
903
 
 
904
  if (ry <= 0)
 
905
  {
 
906
    ry = rx;
 
907
  }
 
908
  rx *= m_k;
 
909
  ry *= m_k;
 
910
  if (nSeg < 2)
 
911
  {
 
912
    nSeg = 2;
 
913
  }
 
914
 
 
915
  static double pi = 4. * atan(1.0);
 
916
  astart = pi * astart / 180.;
 
917
  afinish = pi * afinish / 180.;
 
918
  if (m_yAxisOriginTop)
 
919
  {
 
920
    astart *= -1.0;
 
921
    afinish *= -1.0;
 
922
  }
 
923
  double totalAngle = afinish - astart;
 
924
 
 
925
  double dt = totalAngle / nSeg;
 
926
  double dtm = dt / 3;
 
927
 
 
928
  x0 *= m_k;
 
929
  y0 *= m_k;
 
930
  if (angle != 0)
 
931
  {
 
932
    double a = -(pi * angle / 180.);
 
933
    if (m_yAxisOriginTop)
 
934
    {
 
935
      a *= -1.0;
 
936
    }
 
937
    OutAscii(wxString(wxT("q ")) + 
 
938
             wxPdfUtility::Double2String(cos(a),2) + wxString(wxT(" ")) +
 
939
             wxPdfUtility::Double2String(-1 * sin(a),2) + wxString(wxT(" ")) +
 
940
             wxPdfUtility::Double2String(sin(a),2) + wxString(wxT(" ")) +
 
941
             wxPdfUtility::Double2String(cos(a),2) + wxString(wxT(" ")) +
 
942
             wxPdfUtility::Double2String(x0,2) + wxString(wxT(" ")) +
 
943
             wxPdfUtility::Double2String(y0,2) + wxString(wxT(" cm")));
 
944
    x0 = 0;
 
945
    y0 = 0;
 
946
  }
 
947
 
 
948
  double t1, a0, b0, c0, d0, a1, b1, c1, d1;
 
949
  t1 = astart;
 
950
  a0 = x0 + (rx * cos(t1));
 
951
  b0 = y0 + (ry * sin(t1));
 
952
  c0 = -rx * sin(t1);
 
953
  d0 = ry * cos(t1);
 
954
  OutPoint(a0 / m_k, b0 / m_k);
 
955
  int i;
 
956
  for (i = 1; i <= nSeg; i++)
 
957
  {
 
958
    // Draw this bit of the total curve
 
959
    t1 = (i * dt) + astart;
 
960
    a1 = x0 + (rx * cos(t1));
 
961
    b1 = y0 + (ry * sin(t1));
 
962
    c1 = -rx * sin(t1);
 
963
    d1 = ry * cos(t1);
 
964
    OutCurve((a0 + (c0 * dtm)) / m_k,
 
965
             (b0 + (d0 * dtm)) / m_k,
 
966
             (a1 - (c1 * dtm)) / m_k,
 
967
             (b1 - (d1 * dtm)) / m_k,
 
968
             a1 / m_k,
 
969
             b1 / m_k);
 
970
    a0 = a1;
 
971
    b0 = b1;
 
972
    c0 = c1;
 
973
    d0 = d1;
 
974
  }
 
975
  if (doSector)
 
976
  {
 
977
    OutLine(x0 / m_k, y0 / m_k);
 
978
//    a0 = x0 + (rx * cos(t1));
 
979
//    b0 = y0 + (ry * sin(t1));
 
980
//    OutLine(a0, b0);
 
981
  }
 
982
  OutAscii(op);
 
983
  if (angle !=0)
 
984
  {
 
985
    Out("Q");
 
986
  }
 
987
}
 
988
 
 
989
void
 
990
wxPdfDocument::Circle(double x0, double y0, double r, double astart, double afinish,
 
991
                      int style, int nSeg)
 
992
{
 
993
  Ellipse(x0, y0, r, 0, 0, astart, afinish, style, nSeg);
 
994
}
 
995
 
 
996
void
 
997
wxPdfDocument::Sector(double xc, double yc, double r, double astart, double afinish,
 
998
                      int style, bool clockwise, double origin)
 
999
{
 
1000
  static double pi = 4. * atan(1.);
 
1001
  static double pi2 = 0.5 * pi;
 
1002
  double d;
 
1003
  if (clockwise)
 
1004
  {
 
1005
    d = afinish;
 
1006
    afinish = origin - astart;
 
1007
    astart = origin - d;
 
1008
  }
 
1009
  else
 
1010
  {
 
1011
    afinish += origin;
 
1012
    astart += origin;
 
1013
  }
 
1014
  astart = fmod(astart, 360.) + 360;
 
1015
  afinish = fmod(afinish, 360.) + 360;
 
1016
  if (astart > afinish)
 
1017
  {
 
1018
    afinish += 360;
 
1019
  }
 
1020
  afinish = afinish / 180. * pi;
 
1021
  astart = astart / 180. * pi;
 
1022
  d = afinish - astart;
 
1023
  if (d == 0)
 
1024
  {
 
1025
    d = 2 * pi;
 
1026
  }
 
1027
  
 
1028
  wxString op;
 
1029
  if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILL)
 
1030
  {
 
1031
    op = wxT("f");
 
1032
  }
 
1033
  else
 
1034
  {
 
1035
    if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILLDRAW)
 
1036
    {
 
1037
      op = wxT("b");
 
1038
    }
 
1039
    else
 
1040
    {
 
1041
      op = wxT("s");
 
1042
    }
 
1043
  }
 
1044
 
 
1045
  double myArc;
 
1046
  if (sin(d/2) != 0.0)
 
1047
  {
 
1048
    myArc = 4./3. * (1.-cos(d/2))/sin(d/2) * r;
 
1049
  }
 
1050
  else
 
1051
  {
 
1052
    myArc = 0.0;
 
1053
  }
 
1054
  // first put the center
 
1055
  OutPoint(xc,yc);
 
1056
  // put the first point
 
1057
  OutLine(xc+r*cos(astart),yc-r*sin(astart));
 
1058
  // draw the arc
 
1059
  if (d < pi2)
 
1060
  {
 
1061
    OutCurve(xc+r*cos(astart)+myArc*cos(pi2+astart),
 
1062
             yc-r*sin(astart)-myArc*sin(pi2+astart),
 
1063
             xc+r*cos(afinish)+myArc*cos(afinish-pi2),
 
1064
             yc-r*sin(afinish)-myArc*sin(afinish-pi2),
 
1065
             xc+r*cos(afinish),
 
1066
             yc-r*sin(afinish));
 
1067
  }
 
1068
  else
 
1069
  {
 
1070
    afinish = astart + d/4;
 
1071
    myArc = 4./3. * (1.-cos(d/8))/sin(d/8) * r;
 
1072
    OutCurve(xc+r*cos(astart)+myArc*cos(pi2+astart),
 
1073
             yc-r*sin(astart)-myArc*sin(pi2+astart),
 
1074
             xc+r*cos(afinish)+myArc*cos(afinish-pi2),
 
1075
             yc-r*sin(afinish)-myArc*sin(afinish-pi2),
 
1076
             xc+r*cos(afinish),
 
1077
             yc-r*sin(afinish));
 
1078
    astart = afinish;
 
1079
    afinish = astart + d/4;
 
1080
    OutCurve(xc+r*cos(astart)+myArc*cos(pi2+astart),
 
1081
             yc-r*sin(astart)-myArc*sin(pi2+astart),
 
1082
             xc+r*cos(afinish)+myArc*cos(afinish-pi2),
 
1083
             yc-r*sin(afinish)-myArc*sin(afinish-pi2),
 
1084
             xc+r*cos(afinish),
 
1085
             yc-r*sin(afinish));
 
1086
    astart = afinish;
 
1087
    afinish = astart + d/4;
 
1088
    OutCurve(xc+r*cos(astart)+myArc*cos(pi2+astart),
 
1089
             yc-r*sin(astart)-myArc*sin(pi2+astart),
 
1090
             xc+r*cos(afinish)+myArc*cos(afinish-pi2),
 
1091
             yc-r*sin(afinish)-myArc*sin(afinish-pi2),
 
1092
             xc+r*cos(afinish),
 
1093
             yc-r*sin(afinish));
 
1094
    astart = afinish;
 
1095
    afinish = astart + d/4;
 
1096
    OutCurve(xc+r*cos(astart)+myArc*cos(pi2+astart),
 
1097
             yc-r*sin(astart)-myArc*sin(pi2+astart),
 
1098
             xc+r*cos(afinish)+myArc*cos(afinish-pi2),
 
1099
             yc-r*sin(afinish)-myArc*sin(afinish-pi2),
 
1100
             xc+r*cos(afinish),
 
1101
             yc-r*sin(afinish));
 
1102
  }
 
1103
  // terminate drawing
 
1104
  OutAscii(op);
 
1105
}
 
1106
 
 
1107
void
 
1108
wxPdfDocument::Polygon(const wxPdfArrayDouble& x, const wxPdfArrayDouble& y, int style)
 
1109
{
 
1110
  unsigned int np = (x.GetCount() < y.GetCount()) ? (unsigned int) x.GetCount() : (unsigned int) y.GetCount();
 
1111
 
 
1112
  wxString op;
 
1113
  if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILL)
 
1114
  {
 
1115
    op = (m_fillRule == wxODDEVEN_RULE) ? wxT("f*") : wxT("f");
 
1116
  }
 
1117
  else
 
1118
  {
 
1119
    if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILLDRAW)
 
1120
    {
 
1121
      op = (m_fillRule == wxODDEVEN_RULE) ? wxT("B*") : wxT("B");
 
1122
    }
 
1123
    else
 
1124
    {
 
1125
      op = wxT("S");
 
1126
    }
 
1127
  }
 
1128
 
 
1129
  OutPoint(x[0], y[0]);
 
1130
  unsigned int i;
 
1131
  for (i = 1; i < np; i++)
 
1132
  {
 
1133
    OutLine(x[i], y[i]);
 
1134
  }
 
1135
  OutLine(x[0], y[0]);
 
1136
  OutAscii(op);
 
1137
}
 
1138
 
 
1139
void
 
1140
wxPdfDocument::RegularPolygon(double x0, double y0, double r, int ns, double angle, bool circle, int style, 
 
1141
                              int circleStyle, const wxPdfLineStyle& circleLineStyle, const wxPdfColour& circleFillColour)
 
1142
{
 
1143
  if (ns < 3)
 
1144
  {
 
1145
    ns = 3;
 
1146
  }
 
1147
  if (circle)
 
1148
  {
 
1149
    wxPdfLineStyle saveStyle = GetLineStyle();
 
1150
    SetLineStyle(circleLineStyle);
 
1151
    wxPdfColour saveColour = GetFillColour();
 
1152
    SetFillColour(circleFillColour);
 
1153
    Circle(x0, y0, r, 0, 360, circleStyle);
 
1154
    SetLineStyle(saveStyle);
 
1155
    SetFillColour(saveColour);
 
1156
  }
 
1157
  static double pi = 4. * atan(1.);
 
1158
  double a;
 
1159
  wxPdfArrayDouble x, y;
 
1160
  int i;
 
1161
  for (i = 0; i < ns; i++)
 
1162
  {
 
1163
    a = (angle + (i * 360 / ns)) / 180. * pi;
 
1164
    x.Add(x0 + (r * sin(a)));
 
1165
    y.Add(y0 + (r * cos(a)));
 
1166
  }
 
1167
  Polygon(x, y, style);
 
1168
}
 
1169
 
 
1170
 
 
1171
void
 
1172
wxPdfDocument::StarPolygon(double x0, double y0, double r, int nv, int ng, double angle, bool circle, int style, 
 
1173
                           int circleStyle, const wxPdfLineStyle& circleLineStyle, const wxPdfColour& circleFillColour)
 
1174
{
 
1175
  if (nv < 2)
 
1176
  {
 
1177
    nv = 2;
 
1178
  }
 
1179
  if (circle)
 
1180
  {
 
1181
    wxPdfLineStyle saveStyle = GetLineStyle();
 
1182
    SetLineStyle(circleLineStyle);
 
1183
    wxPdfColour saveColour = GetFillColour();
 
1184
    SetFillColour(circleFillColour);
 
1185
    Circle(x0, y0, r, 0, 360, circleStyle);
 
1186
    SetLineStyle(saveStyle);
 
1187
    SetFillColour(saveColour);
 
1188
  }
 
1189
  wxArrayInt visited;
 
1190
  visited.SetCount(nv);
 
1191
  int i;
 
1192
  for (i = 0; i < nv; i++)
 
1193
  {
 
1194
    visited[i] = 0;
 
1195
  }
 
1196
  static double pi = 4. * atan(1.);
 
1197
  double a;
 
1198
  wxPdfArrayDouble x, y;
 
1199
  i = 0;
 
1200
  do
 
1201
  {
 
1202
    visited[i] = 1;
 
1203
    a = (angle + (i * 360 / nv)) / 180. * pi;
 
1204
    x.Add(x0 + (r * sin(a)));
 
1205
    y.Add(y0 + (r * cos(a)));
 
1206
    i = (i + ng) % nv;
 
1207
  }
 
1208
  while (visited[i] == 0);
 
1209
  Polygon(x, y, style);
 
1210
}
 
1211
 
 
1212
static void
 
1213
SolveTridiagonalSpecial(const wxPdfArrayDouble& r, wxPdfArrayDouble& x)
 
1214
{
 
1215
  size_t i;
 
1216
  size_t n = r.GetCount();
 
1217
  x.SetCount(n);
 
1218
  wxPdfArrayDouble gamma;
 
1219
  gamma.SetCount(n);
 
1220
 
 
1221
  // Decomposition and forward substitution.
 
1222
  double beta = 2.0;
 
1223
  x[0] = r[0] / beta;
 
1224
  for (i = 1; i < n; ++i)
 
1225
  {
 
1226
    gamma[i] = 1 / beta;
 
1227
    beta = (i < n-1 ? 4.0 : 3.5) - gamma[i];
 
1228
    x[i] = (r[i] - x[i-1]) / beta;
 
1229
  }
 
1230
 
 
1231
  // Backsubstitution.
 
1232
  for (i = 1; i < n; ++i)
 
1233
  {
 
1234
    x[n-i-1] -= gamma[n-i] * x[n-i];
 
1235
  }
 
1236
}
 
1237
 
 
1238
static bool
 
1239
GetBezierControlPoints(const wxPdfArrayDouble& x, const wxPdfArrayDouble& y,
 
1240
                       wxPdfArrayDouble& x1, wxPdfArrayDouble& y1,
 
1241
                       wxPdfArrayDouble& x2, wxPdfArrayDouble& y2)
 
1242
{
 
1243
  size_t i;
 
1244
  size_t n = x.GetCount() - 1;
 
1245
  if (n <= 1)
 
1246
  {
 
1247
    wxLogDebug(wxString(wxT("GetBezierControlPoints: "))+_("n must be greater than 2."));
 
1248
    return false;
 
1249
  }
 
1250
#if 0
 
1251
  // Special case: Bezier curve should be a straight line.
 
1252
  if (n == 1)
 
1253
  {
 
1254
    x1[0] = (2 * x[0] + x[1]) / 3;
 
1255
    y1[0] = (2 * y[0] + y[1]) / 3;
 
1256
    x2[0] = 2 * x1[0] - x[0];
 
1257
    y2[0] = 2 * y1[0] - y[0];
 
1258
    return true;
 
1259
  }
 
1260
#endif
 
1261
 
 
1262
  // First control point
 
1263
  wxPdfArrayDouble r;
 
1264
  r.SetCount(n);
 
1265
 
 
1266
  // Set right hand side X values
 
1267
  for (i = 1; i < n-1; ++i)
 
1268
  {
 
1269
    r[i] = 4 * x[i] + 2 * x[i+1];
 
1270
  }
 
1271
  r[0] = x[0] + 2 * x[1];
 
1272
  r[n-1] = (8 * x[n-1] + x[n]) / 2.0;
 
1273
 
 
1274
  x1.SetCount(n);
 
1275
  SolveTridiagonalSpecial(r, x1);
 
1276
 
 
1277
  // Set right hand side Y values
 
1278
  for (i = 1; i < n-1; ++i)
 
1279
  {
 
1280
    r[i] = 4 * y[i] + 2 * y[i+1];
 
1281
  }
 
1282
  r[0] = y[0] + 2 * y[1];
 
1283
  r[n - 1] = (8 * y[n-1] + y[n]) / 2.0;
 
1284
 
 
1285
  y1.SetCount(n);
 
1286
  SolveTridiagonalSpecial(r, y1);
 
1287
 
 
1288
  // Second control point
 
1289
  x2.SetCount(n);
 
1290
  y2.SetCount(n);
 
1291
  for (i = 0; i < n; ++i)
 
1292
  {
 
1293
    if (i < n - 1)
 
1294
    {
 
1295
      x2[i] = 2 * x[i+1] - x1[i+1];
 
1296
      y2[i] = 2 * y[i+1] - y1[i+1];
 
1297
    }
 
1298
    else
 
1299
    {
 
1300
      x2[i] = (x[n] + x1[n-1]) / 2;
 
1301
      y2[i] = (y[n] + y1[n-1]) / 2;
 
1302
    }
 
1303
  }
 
1304
  return true;
 
1305
}
 
1306
 
 
1307
void
 
1308
wxPdfDocument::BezierSpline(const wxPdfArrayDouble& x, const wxPdfArrayDouble& y, int style)
 
1309
{
 
1310
  size_t n = x.GetCount();
 
1311
  if (n == y.GetCount())
 
1312
  {
 
1313
    if (n > 2)
 
1314
    {
 
1315
      wxPdfArrayDouble x1, y1, x2, y2;
 
1316
      if (GetBezierControlPoints(x, y, x1, y1, x2, y2))
 
1317
      {
 
1318
        wxString op;
 
1319
        if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILL)
 
1320
        {
 
1321
          op = (m_fillRule == wxODDEVEN_RULE) ? wxT("f*") : wxT("f");
 
1322
        }
 
1323
        else
 
1324
        {
 
1325
          if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILLDRAW)
 
1326
          {
 
1327
            op = (m_fillRule == wxODDEVEN_RULE) ? wxT("B*") : wxT("B");
 
1328
          }
 
1329
          else
 
1330
          {
 
1331
            op = wxT("S");
 
1332
          }
 
1333
        }
 
1334
        MoveTo(x[0], y[0]);
 
1335
        size_t j;
 
1336
        for (j = 0; j < n-1; ++j)
 
1337
        {
 
1338
          CurveTo(x1[j], y1[j], x2[j], y2[j], x[j+1], y[j+1]);
 
1339
        }
 
1340
        OutAscii(op);
 
1341
      }
 
1342
    }
 
1343
    else
 
1344
    {
 
1345
      Line(x[0], y[0], x[1], y[1]);
 
1346
    }
 
1347
  }
 
1348
}
 
1349
 
 
1350
static bool
 
1351
SolveTridiagonalGeneral(const wxPdfArrayDouble& a, const wxPdfArrayDouble& b, 
 
1352
                        const wxPdfArrayDouble& c, const wxPdfArrayDouble& r,
 
1353
                        wxPdfArrayDouble& u)
 
1354
{
 
1355
  size_t n = r.GetCount();
 
1356
  // a, b, c and rhs vectors must have the same size.
 
1357
  if (n != a.GetCount() || n != b.GetCount() || n != c.GetCount())
 
1358
  {
 
1359
    wxLogDebug(wxString(wxT("SolveTridiagonal: "))+_("Mismatch of vector sizes."));
 
1360
    return false;
 
1361
  }
 
1362
  if (b[0] == 0.0)
 
1363
  {
 
1364
    wxLogDebug(wxString(wxT("SolveTridiagonal: "))+_("Singular matrix."));
 
1365
    return false;
 
1366
  }
 
1367
 
 
1368
  wxPdfArrayDouble gamma;
 
1369
  gamma.SetCount(n);
 
1370
  u.SetCount(n);
 
1371
 
 
1372
  // Decomposition and forward substitution.
 
1373
  double beta = b[0];
 
1374
  u[0] = r[0] / beta;
 
1375
  size_t j;
 
1376
  for (j = 1; j < n; ++j)
 
1377
  {
 
1378
    gamma[j] = c[j-1] / beta;
 
1379
    beta = b[j] - a[j] * gamma[j];
 
1380
    if (beta == 0.0)
 
1381
    {
 
1382
      wxLogDebug(wxString(wxT("SolveTridiagonal: "))+_("Singular matrix."));
 
1383
      return false;
 
1384
    }
 
1385
    u[j] = (r[j] - a[j] * u[j - 1]) / beta;
 
1386
  }
 
1387
 
 
1388
  // Backward substitution.
 
1389
  for (j = 1; j < n; ++j)
 
1390
  {
 
1391
    u[n-j-1] -= gamma[n-j] * u[n-j];
 
1392
  }
 
1393
  return true;
 
1394
}
 
1395
 
 
1396
static bool
 
1397
SolveCyclic(const wxPdfArrayDouble& a, const wxPdfArrayDouble& b, 
 
1398
            const wxPdfArrayDouble& c, double alpha, double beta, 
 
1399
            const wxPdfArrayDouble& r, wxPdfArrayDouble& x)
 
1400
{
 
1401
  size_t i;
 
1402
  size_t n = r.GetCount();
 
1403
  // a, b, c and rhs vectors must have the same size.
 
1404
  if (n != a.GetCount() || n != b.GetCount() || n != c.GetCount())
 
1405
  {
 
1406
    wxLogDebug(wxString(wxT("SolveCyclic: "))+_("Mismatch of vector sizes."));
 
1407
    return false;
 
1408
  }
 
1409
  if (n <= 2)
 
1410
  {
 
1411
    wxLogDebug(wxString(wxT("SolveCyclic: "))+_("n must be greater than 2."));
 
1412
    return false;
 
1413
  }
 
1414
 
 
1415
  // Set up the diagonal of the modified tridiagonal system.
 
1416
  wxPdfArrayDouble bb;
 
1417
  bb.SetCount(n);
 
1418
  double gamma = -b[0];
 
1419
  bb[0] = b[0] - gamma;
 
1420
  bb[n-1] = b[n-1] - alpha * beta / gamma;
 
1421
  for (i = 1; i < n-1; ++i)
 
1422
  {
 
1423
    bb[i] = b[i];
 
1424
  }
 
1425
  // Solve A ļæ½ x = rhs.
 
1426
  x.SetCount(n);
 
1427
  if (!SolveTridiagonalGeneral(a, bb, c, r, x))
 
1428
  {
 
1429
    return false;
 
1430
  }
 
1431
 
 
1432
  // Set up the vector u.
 
1433
  wxPdfArrayDouble u;
 
1434
  u.SetCount(n, 0.0);
 
1435
  u[0] = gamma;
 
1436
  u[n-1] = alpha;
 
1437
 
 
1438
  // Solve A ļæ½ z = u.
 
1439
  wxPdfArrayDouble z;
 
1440
  z.SetCount(n);
 
1441
  if (!SolveTridiagonalGeneral(a, bb, c, u, z))
 
1442
  {
 
1443
    return false;
 
1444
  }
 
1445
 
 
1446
  // Calculate solution vector x.
 
1447
  double fact = (x[0] + beta * x[n-1] / gamma) / (1.0 + z[0] + beta * z[n-1] / gamma);
 
1448
  for (i = 0; i < n; ++i)
 
1449
  {
 
1450
    x[i] -= fact * z[i];
 
1451
  }
 
1452
  return true;
 
1453
 
1454
 
 
1455
static bool
 
1456
GetCyclicControlPoints(const wxPdfArrayDouble& x, const wxPdfArrayDouble& y,
 
1457
                       wxPdfArrayDouble& x1, wxPdfArrayDouble& y1,
 
1458
                       wxPdfArrayDouble& x2, wxPdfArrayDouble& y2)
 
1459
{
 
1460
  size_t i, j;
 
1461
  size_t n = x.GetCount();
 
1462
  bool ok = (n == y.GetCount());
 
1463
  if (n <= 2 || !ok)
 
1464
  {
 
1465
    wxLogDebug(wxString(wxT("GetCyclicControlPoints: "))+_("n must be greater than 2."));
 
1466
    return false;
 
1467
  }
 
1468
 
 
1469
  // Calculate first Bezier control points
 
1470
 
 
1471
  // The matrix.
 
1472
  wxPdfArrayDouble a, b, c;
 
1473
  a.SetCount(n, 1.0);
 
1474
  b.SetCount(n, 4.0);
 
1475
  c.SetCount(n, 1.0);
 
1476
 
 
1477
  // Right hand side vector for points X coordinates.
 
1478
  wxPdfArrayDouble r;
 
1479
  r.SetCount(n);
 
1480
  for (i = 0; i < n; ++i)
 
1481
  {
 
1482
    j = (i == n-1) ? 0 : i+1;
 
1483
    r[i] = 4 * x[i] + 2 * x[j];
 
1484
  }
 
1485
 
 
1486
  // Solve the system for X.
 
1487
  x1.SetCount(n);
 
1488
  if (!SolveCyclic(a, b, c, 1.0, 1.0, r, x1))
 
1489
  {
 
1490
    return false;
 
1491
  }
 
1492
 
 
1493
  // Right hand side vector for points Y coordinates.
 
1494
  for (i = 0; i < n; ++i)
 
1495
  {
 
1496
    j = (i == n - 1) ? 0 : i + 1;
 
1497
    r[i] = 4 * y[i] + 2 * y[j];
 
1498
  }
 
1499
  // Solve the system for Y.
 
1500
  y1.SetCount(n);
 
1501
  if (!SolveCyclic(a, b, c, 1, 1, r, y1))
 
1502
  {
 
1503
    return false;
 
1504
  }
 
1505
 
 
1506
  // Second control point.
 
1507
  x2.SetCount(n);
 
1508
  y2.SetCount(n);
 
1509
  for (i = 0; i < n; ++i)
 
1510
  {
 
1511
    x2[i] = 2 * x[i] - x1[i];
 
1512
    y2[i] = 2 * y[i] - y1[i];
 
1513
  }
 
1514
  return true;
 
1515
}
 
1516
 
 
1517
void
 
1518
wxPdfDocument::ClosedBezierSpline(const wxPdfArrayDouble& x, const wxPdfArrayDouble& y, int style)
 
1519
{
 
1520
  size_t n = x.GetCount();
 
1521
  if (n == y.GetCount())
 
1522
  {
 
1523
    if (n > 2)
 
1524
    {
 
1525
      wxPdfArrayDouble x1, y1, x2, y2;
 
1526
      if (GetCyclicControlPoints(x, y, x1, y1, x2, y2))
 
1527
      {
 
1528
        wxString op;
 
1529
        if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILL)
 
1530
        {
 
1531
          op = (m_fillRule == wxODDEVEN_RULE) ? wxT("f*") : wxT("f");
 
1532
        }
 
1533
        else
 
1534
        {
 
1535
          if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILLDRAW)
 
1536
          {
 
1537
            op = (m_fillRule == wxODDEVEN_RULE) ? wxT("B*") : wxT("B");
 
1538
          }
 
1539
          else
 
1540
          {
 
1541
            op = wxT("S");
 
1542
          }
 
1543
        }
 
1544
        MoveTo(x[0], y[0]);
 
1545
        size_t j;
 
1546
        for (j = 1; j < n; ++j)
 
1547
        {
 
1548
          CurveTo(x1[j-1], y1[j-1], x2[j], y2[j], x[j], y[j]);
 
1549
        }
 
1550
        CurveTo(x1[n-1], y1[n-1], x2[0], y2[0], x[0], y[0]);
 
1551
        OutAscii(op);
 
1552
      }
 
1553
    }
 
1554
    else
 
1555
    {
 
1556
      Line(x[0], y[0], x[1], y[1]);
 
1557
    }
 
1558
  }
 
1559
}
 
1560
 
 
1561
void
 
1562
wxPdfDocument::Shape(const wxPdfShape& shape, int style)
 
1563
{
 
1564
  wxString op;
 
1565
  if ((style & wxPDF_STYLE_MASK) == wxPDF_STYLE_FILL)
 
1566
  {
 
1567
    op = (m_fillRule == wxODDEVEN_RULE) ? wxT("f*") : wxT("f");
 
1568
  }
 
1569
  else
 
1570
  {
 
1571
    if ((style & wxPDF_STYLE_MASK) == wxPDF_STYLE_FILLDRAW)
 
1572
    {
 
1573
      op = (m_fillRule == wxODDEVEN_RULE) ? wxT("B*") : wxT("B");
 
1574
    }
 
1575
    else if ((style & wxPDF_STYLE_MASK) == (wxPDF_STYLE_DRAWCLOSE | wxPDF_STYLE_FILL))
 
1576
    {
 
1577
      // small 'b' means closing the path as well
 
1578
      op = (m_fillRule == wxODDEVEN_RULE) ? wxT("b*") : wxT("b");
 
1579
    }
 
1580
    else if ((style & wxPDF_STYLE_MASK) == wxPDF_STYLE_DRAWCLOSE)
 
1581
    {
 
1582
      op = wxT("s"); // small 's' means closing the path as well
 
1583
    }
 
1584
    else
 
1585
    {
 
1586
      op = wxT("S");
 
1587
    }
 
1588
  }
 
1589
 
 
1590
  Out("q");
 
1591
 
 
1592
  double scratch[6];
 
1593
  unsigned int iterType;
 
1594
  unsigned int iterPoints = 0;
 
1595
  unsigned int segCount = shape.GetSegmentCount();
 
1596
  for (iterType = 0; iterType < segCount; iterType++)
 
1597
  {
 
1598
    int segType = shape.GetSegment(iterType, iterPoints, scratch);
 
1599
    switch (segType)
 
1600
    {
 
1601
      case wxPDF_SEG_CLOSE:
 
1602
        Out("h");
 
1603
        iterPoints++;
 
1604
        break;
 
1605
      case wxPDF_SEG_MOVETO:
 
1606
        OutPoint(scratch[0], scratch[1]);
 
1607
        iterPoints++;
 
1608
        break;
 
1609
      case wxPDF_SEG_LINETO:
 
1610
        OutLine(scratch[0], scratch[1]);
 
1611
        iterPoints++;
 
1612
        break;
 
1613
      case wxPDF_SEG_CURVETO:
 
1614
        OutCurve(scratch[0], scratch[1], scratch[2], scratch[3],scratch[4], scratch[5]);
 
1615
        iterPoints += 3;
 
1616
        break;
 
1617
    }
 
1618
  }
 
1619
  OutAscii(op);
 
1620
  Out("Q");
 
1621
 
 
1622
//  ClosePath(style);
 
1623
}
 
1624
 
 
1625
void
 
1626
wxPdfDocument::ClippingText(double x, double y, const wxString& txt, bool outline)
 
1627
{
 
1628
  wxString op = outline ? wxT("5") : wxT("7");
 
1629
  if (m_yAxisOriginTop)
 
1630
  {
 
1631
    OutAscii(wxString(wxT("q BT 1 0 0 -1 ")) +
 
1632
             wxPdfUtility::Double2String(x*m_k,2) + wxString(wxT(" ")) +
 
1633
             wxPdfUtility::Double2String(y*m_k,2) + wxString(wxT(" Tm ")) +
 
1634
             op + wxString(wxT(" Tr (")),false);
 
1635
  }
 
1636
  else
 
1637
  {
 
1638
    OutAscii(wxString(wxT("q BT ")) +
 
1639
             wxPdfUtility::Double2String(x*m_k,2) + wxString(wxT(" ")) +
 
1640
             wxPdfUtility::Double2String(y*m_k,2) + wxString(wxT(" Td ")) +
 
1641
             op + wxString(wxT(" Tr (")),false);
 
1642
  }
 
1643
  TextEscape(txt,false);
 
1644
  Out(") Tj ET");
 
1645
  SaveGraphicState();
 
1646
}
 
1647
 
 
1648
void
 
1649
wxPdfDocument::ClippingRect(double x, double y, double w, double h, bool outline)
 
1650
{
 
1651
  wxString op = outline ? wxT("S") : wxT("n");
 
1652
  OutAscii(wxString(wxT("q ")) +
 
1653
           wxPdfUtility::Double2String(x*m_k,2) + wxString(wxT(" ")) +
 
1654
           wxPdfUtility::Double2String(y*m_k,2) + wxString(wxT(" ")) +
 
1655
           wxPdfUtility::Double2String(w*m_k,2) + wxString(wxT(" ")) +
 
1656
           wxPdfUtility::Double2String(h*m_k,2) + wxString(wxT(" re W ")) + op);
 
1657
  SaveGraphicState();
 
1658
}
 
1659
 
 
1660
void
 
1661
wxPdfDocument::ClippingEllipse(double x, double y, double rx, double ry, bool outline)
 
1662
{
 
1663
  wxString op = outline ? wxT("S") : wxT("n");
 
1664
  if (ry <= 0)
 
1665
  {
 
1666
    ry = rx;
 
1667
  }
 
1668
  double lx = 4./3. * (sqrt(2.)-1.) * rx;
 
1669
  double ly = 4./3. * (sqrt(2.)-1.) * ry;
 
1670
 
 
1671
  OutAscii(wxString(wxT("q ")) +
 
1672
           wxPdfUtility::Double2String((x+rx)*m_k,2) + wxString(wxT(" ")) +
 
1673
           wxPdfUtility::Double2String(y*m_k,2) + wxString(wxT(" m ")) +
 
1674
           wxPdfUtility::Double2String((x+rx)*m_k,2) + wxString(wxT(" ")) +
 
1675
           wxPdfUtility::Double2String((y-ly)*m_k,2) + wxString(wxT(" ")) +
 
1676
           wxPdfUtility::Double2String((x+lx)*m_k,2) + wxString(wxT(" ")) +
 
1677
           wxPdfUtility::Double2String((y-ry)*m_k,2) + wxString(wxT(" ")) +
 
1678
           wxPdfUtility::Double2String(x*m_k,2) + wxString(wxT(" ")) +
 
1679
           wxPdfUtility::Double2String((y-ry)*m_k,2) + wxString(wxT(" c")));
 
1680
 
 
1681
  OutAscii(wxPdfUtility::Double2String((x-lx)*m_k,2) + wxString(wxT(" ")) +
 
1682
           wxPdfUtility::Double2String((y-ry)*m_k,2) + wxString(wxT(" ")) +
 
1683
           wxPdfUtility::Double2String((x-rx)*m_k,2) + wxString(wxT(" ")) +
 
1684
           wxPdfUtility::Double2String((y-ly)*m_k,2) + wxString(wxT(" ")) +
 
1685
           wxPdfUtility::Double2String((x-rx)*m_k,2) + wxString(wxT(" ")) +
 
1686
           wxPdfUtility::Double2String(y*m_k,2) + wxString(wxT(" c")));
 
1687
 
 
1688
  OutAscii(wxPdfUtility::Double2String((x-rx)*m_k,2) + wxString(wxT(" ")) +
 
1689
           wxPdfUtility::Double2String((y+ly)*m_k,2) + wxString(wxT(" ")) +
 
1690
           wxPdfUtility::Double2String((x-lx)*m_k,2) + wxString(wxT(" ")) +
 
1691
           wxPdfUtility::Double2String((y+ry)*m_k,2) + wxString(wxT(" ")) +
 
1692
           wxPdfUtility::Double2String(x*m_k,2) + wxString(wxT(" ")) +
 
1693
           wxPdfUtility::Double2String((y+ry)*m_k,2) + wxString(wxT(" c")));
 
1694
 
 
1695
  OutAscii(wxPdfUtility::Double2String((x+lx)*m_k,2) + wxString(wxT(" ")) +
 
1696
           wxPdfUtility::Double2String((y+ry)*m_k,2) + wxString(wxT(" ")) +
 
1697
           wxPdfUtility::Double2String((x+rx)*m_k,2) + wxString(wxT(" ")) +
 
1698
           wxPdfUtility::Double2String((y+ly)*m_k,2) + wxString(wxT(" ")) +
 
1699
           wxPdfUtility::Double2String((x+rx)*m_k,2) + wxString(wxT(" ")) +
 
1700
           wxPdfUtility::Double2String(y*m_k,2) + wxString(wxT(" c W ")) + op);
 
1701
  SaveGraphicState();
 
1702
}
 
1703
 
 
1704
void
 
1705
wxPdfDocument::ClippingPolygon(const wxPdfArrayDouble& x, const wxPdfArrayDouble& y, bool outline)
 
1706
{
 
1707
  unsigned int np = (x.GetCount() < y.GetCount()) ? (unsigned int) x.GetCount() : (unsigned int) y.GetCount();
 
1708
 
 
1709
  wxString op = outline ? wxT("S") : wxT("n");
 
1710
 
 
1711
  Out("q");
 
1712
  OutPoint(x[0], y[0]);
 
1713
  unsigned int i;
 
1714
  for (i = 1; i < np; i++)
 
1715
  {
 
1716
    OutLine(x[i], y[i]);
 
1717
  }
 
1718
  OutLine(x[0], y[0]);
 
1719
  OutAscii(wxString(wxT("h W ")) + op);
 
1720
  SaveGraphicState();
 
1721
}
 
1722
 
 
1723
void
 
1724
wxPdfDocument::ClippingPath()
 
1725
{
 
1726
  Out("q");
 
1727
  SaveGraphicState();
 
1728
}
 
1729
 
 
1730
void
 
1731
wxPdfDocument::MoveTo(double x, double y)
 
1732
{
 
1733
  OutPoint(x, y);
 
1734
}
 
1735
 
 
1736
void
 
1737
wxPdfDocument::LineTo(double x, double y)
 
1738
{
 
1739
  OutLine(x, y);
 
1740
}
 
1741
 
 
1742
void
 
1743
wxPdfDocument::CurveTo(double x1, double y1, double x2, double y2, double x3, double y3)
 
1744
{
 
1745
  OutCurve(x1, y1, x2, y2, x3, y3);
 
1746
}
 
1747
 
 
1748
void
 
1749
wxPdfDocument::EndPath(int style)
 
1750
{
 
1751
  wxString op;
 
1752
  switch (style)
 
1753
  {
 
1754
    case wxPDF_STYLE_FILL:     op = (m_fillRule == wxODDEVEN_RULE) ? wxT("f*") : wxT("f"); break;
 
1755
    case wxPDF_STYLE_FILLDRAW: op = (m_fillRule == wxODDEVEN_RULE) ? wxT("B*") : wxT("B"); break;
 
1756
    case wxPDF_STYLE_DRAW:
 
1757
    default:                   op = wxT("S"); break;
 
1758
  }
 
1759
  OutAscii(op);
 
1760
}
 
1761
 
 
1762
void
 
1763
wxPdfDocument::ClosePath(int style)
 
1764
{
 
1765
  wxString op;
 
1766
  switch (style)
 
1767
  {
 
1768
    case wxPDF_STYLE_DRAW:     op = wxT("S"); break;
 
1769
    case wxPDF_STYLE_FILL:     op = (m_fillRule == wxODDEVEN_RULE) ? wxT("f*") : wxT("f"); break;
 
1770
    case wxPDF_STYLE_FILLDRAW: op = (m_fillRule == wxODDEVEN_RULE) ? wxT("B*") : wxT("B"); break;
 
1771
    default:                   op = wxT("n"); break;
 
1772
  }
 
1773
  OutAscii(wxString(wxT("h W ")) + op);
 
1774
}
 
1775
 
 
1776
void
 
1777
wxPdfDocument::ClippingPath(const wxPdfShape& shape, int style)
 
1778
{
 
1779
  ClippingPath();
 
1780
  double scratch[6];
 
1781
  unsigned int iterType;
 
1782
  unsigned int iterPoints = 0;
 
1783
  unsigned int segCount = shape.GetSegmentCount();
 
1784
  for (iterType = 0; iterType < segCount; iterType++)
 
1785
  {
 
1786
    int segType = shape.GetSegment(iterType, iterPoints, scratch);
 
1787
    switch (segType)
 
1788
    {
 
1789
      case wxPDF_SEG_CLOSE:
 
1790
        iterPoints++;
 
1791
        break;
 
1792
      case wxPDF_SEG_MOVETO:
 
1793
        MoveTo(scratch[0], scratch[1]);
 
1794
        iterPoints++;
 
1795
        break;
 
1796
      case wxPDF_SEG_LINETO:
 
1797
        LineTo(scratch[0], scratch[1]);
 
1798
        iterPoints++;
 
1799
        break;
 
1800
      case wxPDF_SEG_CURVETO:
 
1801
        CurveTo(scratch[0], scratch[1], scratch[2], scratch[3],scratch[4], scratch[5]);
 
1802
        iterPoints += 3;
 
1803
        break;
 
1804
    }
 
1805
  }
 
1806
  ClosePath(style);
 
1807
}
 
1808
 
 
1809
void
 
1810
wxPdfDocument::UnsetClipping()
 
1811
{
 
1812
  Out("Q");
 
1813
  RestoreGraphicState();
 
1814
}
 
1815
 
 
1816
void
 
1817
wxPdfDocument::ClippedCell(double w, double h, const wxString& txt,
 
1818
                           int border, int ln, int align, int fill, const wxPdfLink& link)
 
1819
{
 
1820
  bool doPageBreak = (m_yAxisOriginTop) ? (m_y+h > m_pageBreakTrigger) : (m_y-h < m_pageBreakTrigger);
 
1821
  if ((border != wxPDF_BORDER_NONE) || (fill != 0) || doPageBreak)
 
1822
  {
 
1823
    Cell(w, h, wxT(""), border, 0, wxPDF_ALIGN_LEFT, fill);
 
1824
    m_x -= w;
 
1825
  }
 
1826
  ClippingRect(m_x, m_y, w, h);
 
1827
  Cell(w, h, txt, wxPDF_BORDER_NONE, ln, align, 0, link);
 
1828
  UnsetClipping();
 
1829
}
 
1830
 
 
1831
void
 
1832
wxPdfDocument::SetLineStyle(const wxPdfLineStyle& linestyle)
 
1833
{
 
1834
  m_lineStyle = linestyle;
 
1835
  if (linestyle.GetWidth() >= 0)
 
1836
  {
 
1837
    double width_prev = m_lineWidth;
 
1838
    SetLineWidth(linestyle.GetWidth());
 
1839
    m_lineWidth = width_prev;
 
1840
  }
 
1841
  switch (linestyle.GetLineCap())
 
1842
  {
 
1843
    case wxPDF_LINECAP_BUTT:
 
1844
    case wxPDF_LINECAP_ROUND:
 
1845
    case wxPDF_LINECAP_SQUARE:
 
1846
      OutAscii(wxString::Format(wxT("%d  J"), linestyle.GetLineCap()));
 
1847
      break;
 
1848
    default:
 
1849
      break;
 
1850
  }
 
1851
  switch (linestyle.GetLineJoin())
 
1852
  {
 
1853
    case wxPDF_LINEJOIN_MITER:
 
1854
    case wxPDF_LINEJOIN_ROUND:
 
1855
    case wxPDF_LINEJOIN_BEVEL:
 
1856
      OutAscii(wxString::Format(wxT("%d  j"), linestyle.GetLineJoin()));
 
1857
      break;
 
1858
    default:
 
1859
      break;
 
1860
  }
 
1861
 
 
1862
  const wxPdfArrayDouble& dash = linestyle.GetDash();
 
1863
  if (&dash != NULL)
 
1864
  {
 
1865
    wxString dashString = wxT("");
 
1866
    size_t j;
 
1867
    for (j = 0; j < dash.GetCount(); j++)
 
1868
    {
 
1869
      if (j > 0)
 
1870
      {
 
1871
        dashString += wxString(wxT(" "));
 
1872
      }
 
1873
      dashString += wxPdfUtility::Double2String(dash[j]*m_k,2);
 
1874
    }
 
1875
    double phase = linestyle.GetPhase();
 
1876
    if (phase < 0 || dashString.Length() == 0)
 
1877
    {
 
1878
      phase = 0;
 
1879
    }
 
1880
    OutAscii(wxString(wxT("[")) + dashString + wxString(wxT("] ")) +
 
1881
             wxPdfUtility::Double2String(phase*m_k,2) + wxString(wxT(" d")));
 
1882
  }
 
1883
  SetDrawColour(linestyle.GetColour());
 
1884
}
 
1885
 
 
1886
const wxPdfLineStyle&
 
1887
wxPdfDocument::GetLineStyle()
 
1888
{
 
1889
  return m_lineStyle;
 
1890
}
 
1891
 
 
1892
void
 
1893
wxPdfDocument::StartTransform()
 
1894
{
 
1895
  //save the current graphic state
 
1896
  m_inTransform++;
 
1897
  Out("q");
 
1898
  SaveGraphicState();
 
1899
}
 
1900
 
 
1901
bool
 
1902
wxPdfDocument::ScaleX(double sx, double x, double y)
 
1903
{
 
1904
  return Scale(sx, 100, x, y);
 
1905
}
 
1906
 
 
1907
bool
 
1908
wxPdfDocument::ScaleY(double sy, double x, double y)
 
1909
{
 
1910
  return Scale(100, sy, x, y);
 
1911
}
 
1912
 
 
1913
bool
 
1914
wxPdfDocument::ScaleXY(double s, double x, double y)
 
1915
{
 
1916
  return Scale(s, s, x, y);
 
1917
}
 
1918
 
 
1919
bool
 
1920
wxPdfDocument::Scale(double sx, double sy, double x, double y)
 
1921
{
 
1922
  if (x < 0)
 
1923
  {
 
1924
    x = m_x;
 
1925
  }
 
1926
  if (y < 0)
 
1927
  {
 
1928
    y = m_y;
 
1929
  }
 
1930
  if (sx == 0 || sy == 0)
 
1931
  {
 
1932
    wxLogError(wxString(wxT("wxPdfDocument::Scale: ")) +
 
1933
               wxString(_("Please use values unequal to zero for Scaling.")));
 
1934
    return false;
 
1935
  }
 
1936
  y *= m_k;
 
1937
  x *= m_k;
 
1938
  //calculate elements of transformation matrix
 
1939
  sx /= 100;
 
1940
  sy /= 100;
 
1941
  double tm[6];
 
1942
  tm[0] = sx;
 
1943
  tm[1] = 0;
 
1944
  tm[2] = 0;
 
1945
  tm[3] = sy;
 
1946
  tm[4] = x * (1 - sx);
 
1947
  tm[5] = y * (1 - sy);
 
1948
  //scale the coordinate system
 
1949
  if (m_inTransform == 0)
 
1950
  {
 
1951
    StartTransform();
 
1952
  }
 
1953
  Transform(tm);
 
1954
  return true;
 
1955
}
 
1956
 
 
1957
void
 
1958
wxPdfDocument::MirrorH(double x)
 
1959
{
 
1960
  Scale(-100, 100, x);
 
1961
}
 
1962
 
 
1963
void
 
1964
wxPdfDocument::MirrorV(double y)
 
1965
{
 
1966
  Scale(100, -100, -1, y);
 
1967
}
 
1968
 
 
1969
void
 
1970
wxPdfDocument::TranslateX(double tx)
 
1971
{
 
1972
  Translate(tx, 0);
 
1973
}
 
1974
 
 
1975
void
 
1976
wxPdfDocument::TranslateY(double ty)
 
1977
{
 
1978
  Translate(0, ty);
 
1979
}
 
1980
 
 
1981
void
 
1982
wxPdfDocument::Translate(double tx, double ty)
 
1983
{
 
1984
  if (m_inTransform == 0)
 
1985
  {
 
1986
    StartTransform();
 
1987
  }
 
1988
  // calculate elements of transformation matrix
 
1989
  double tm[6];
 
1990
  tm[0] = 1;
 
1991
  tm[1] = 0;
 
1992
  tm[2] = 0;
 
1993
  tm[3] = 1;
 
1994
  tm[4] = tx;
 
1995
  tm[5] = (m_yAxisOriginTop) ? ty : -ty;
 
1996
  // translate the coordinate system
 
1997
  Transform(tm);
 
1998
}
 
1999
 
 
2000
void
 
2001
wxPdfDocument::Rotate(double angle, double x, double y)
 
2002
{
 
2003
  if (m_inTransform == 0)
 
2004
  {
 
2005
    StartTransform();
 
2006
  }
 
2007
  if (x < 0)
 
2008
  {
 
2009
    x = m_x;
 
2010
  }
 
2011
  if (y < 0)
 
2012
  {
 
2013
    y = m_y;
 
2014
  }
 
2015
  y *= m_k;
 
2016
  x *= m_k;
 
2017
  // calculate elements of transformation matrix
 
2018
  double tm[6];
 
2019
  if (m_yAxisOriginTop)
 
2020
  {
 
2021
    angle *= -1.0;
 
2022
  }
 
2023
  angle *= (atan(1.) / 45.);
 
2024
  tm[0] = cos(angle);
 
2025
  tm[1] = sin(angle);
 
2026
  tm[2] = -tm[1];
 
2027
  tm[3] = tm[0];
 
2028
  tm[4] = x + tm[1] * y - tm[0] * x;
 
2029
  tm[5] = y - tm[0] * y - tm[1] * x;
 
2030
  //rotate the coordinate system around ($x,$y)
 
2031
  Transform(tm);
 
2032
}
 
2033
 
 
2034
void
 
2035
wxPdfDocument::Transform( double a, double b, double c, double d, double tx, double ty )
 
2036
{
 
2037
  if (m_inTransform == 0)
 
2038
  {
 
2039
    StartTransform();
 
2040
  }
 
2041
  // copy the elements of transformation matrix
 
2042
  double tm[6];
 
2043
  tm[0] = a;
 
2044
  tm[1] = b;
 
2045
  tm[2] = c;
 
2046
  tm[3] = d;
 
2047
  tm[4] = tx;
 
2048
  tm[5] = ty;
 
2049
 
 
2050
  Transform(tm);
 
2051
}
 
2052
 
 
2053
bool
 
2054
wxPdfDocument::SkewX(double xAngle, double x, double y)
 
2055
{
 
2056
  return Skew(xAngle, 0, x, y);
 
2057
}
 
2058
 
 
2059
bool
 
2060
wxPdfDocument::SkewY(double yAngle, double x, double y)
 
2061
{
 
2062
  return Skew(0, yAngle, x, y);
 
2063
}
 
2064
 
 
2065
bool
 
2066
wxPdfDocument::Skew(double xAngle, double yAngle, double x, double y)
 
2067
{
 
2068
  if (x < 0)
 
2069
  {
 
2070
    x = m_x;
 
2071
  }
 
2072
  if (y < 0)
 
2073
  {
 
2074
    y = m_y;
 
2075
  }
 
2076
  if (xAngle <= -90 || xAngle >= 90 || yAngle <= -90 || yAngle >= 90)
 
2077
  {
 
2078
    wxLogError(wxString(wxT("wxPdfDocument::Skew: ")) +
 
2079
               wxString(_("Please use values between -90 and 90 degree for skewing.")));
 
2080
    return false;
 
2081
  }
 
2082
  x *= m_k;
 
2083
  y *= m_k;
 
2084
  //calculate elements of transformation matrix
 
2085
  double tm[6];
 
2086
  if (m_yAxisOriginTop)
 
2087
  {
 
2088
    xAngle *= -1.0;
 
2089
    yAngle *= -1.0;
 
2090
  }
 
2091
  xAngle *= (atan(1.) / 45.);
 
2092
  yAngle *= (atan(1.) / 45.);
 
2093
  tm[0] = 1;
 
2094
  tm[1] = tan(yAngle);
 
2095
  tm[2] = tan(xAngle);
 
2096
  tm[3] = 1;
 
2097
  tm[4] = -tm[2] * y;
 
2098
  tm[5] = -tm[1] * x;
 
2099
  //skew the coordinate system
 
2100
  if (m_inTransform == 0)
 
2101
  {
 
2102
    StartTransform();
 
2103
  }
 
2104
  Transform(tm);
 
2105
  return true;
 
2106
}
 
2107
 
 
2108
void
 
2109
wxPdfDocument::StopTransform()
 
2110
{
 
2111
  //restore previous graphic state
 
2112
  if (m_inTransform > 0)
 
2113
  {
 
2114
    m_inTransform--;
 
2115
    Out("Q");
 
2116
    RestoreGraphicState();
 
2117
  }
 
2118
}
 
2119
 
 
2120
static bool
 
2121
ColourSpaceOk(const wxPdfColour& col1, const wxPdfColour& col2)
 
2122
{
 
2123
  return (col1.GetColourType() != wxPDF_COLOURTYPE_SPOT &&
 
2124
          col1.GetColourType() == col2.GetColourType());
 
2125
}
 
2126
 
 
2127
int
 
2128
wxPdfDocument::LinearGradient(const wxPdfColour& col1, const wxPdfColour& col2,
 
2129
                              wxPdfLinearGradientType gradientType)
 
2130
{
 
2131
  static double h[] = { 0, 0, 1, 0 };
 
2132
  static double v[] = { 0, 0, 0, 1 };
 
2133
  wxPdfGradient* gradient;
 
2134
 
 
2135
  int n = 0;
 
2136
  if (ColourSpaceOk(col1, col2))
 
2137
  {
 
2138
    switch (gradientType)
 
2139
    {
 
2140
      case wxPDF_LINEAR_GRADIENT_REFLECTION_TOP:
 
2141
        gradient = new wxPdfMidAxialGradient(col1, col2, v[0], v[1], v[2], v[3], 0.67, 0.7);
 
2142
        break;
 
2143
      case wxPDF_LINEAR_GRADIENT_REFLECTION_BOTTOM:
 
2144
        gradient = new wxPdfMidAxialGradient(col1, col2, v[0], v[1], v[2], v[3], 0.33, 0.7);
 
2145
        break;
 
2146
      case wxPDF_LINEAR_GRADIENT_REFLECTION_LEFT:
 
2147
        gradient = new wxPdfMidAxialGradient(col1, col2, h[0], h[1], h[2], h[3], 0.33, 0.7);
 
2148
        break;
 
2149
      case wxPDF_LINEAR_GRADIENT_REFLECTION_RIGHT:
 
2150
        gradient = new wxPdfMidAxialGradient(col1, col2, h[0], h[1], h[2], h[3], 0.67, 0.7);
 
2151
        break;
 
2152
      case wxPDF_LINEAR_GRADIENT_MIDVERTICAL:
 
2153
        gradient = new wxPdfMidAxialGradient(col1, col2, v[0], v[1], v[2], v[3], 0.5, 1);
 
2154
        break;
 
2155
      case wxPDF_LINEAR_GRADIENT_MIDHORIZONTAL:
 
2156
        gradient = new wxPdfMidAxialGradient(col1, col2, h[0], h[1], h[2], h[3], 0.5, 1);
 
2157
        break;
 
2158
      case wxPDF_LINEAR_GRADIENT_VERTICAL:
 
2159
        gradient = new wxPdfAxialGradient(col1, col2, v[0], v[1], v[2], v[3], 1);
 
2160
        break;
 
2161
      case wxPDF_LINEAR_GRADIENT_HORIZONTAL:
 
2162
      default:
 
2163
        gradient = new wxPdfAxialGradient(col1, col2, h[0], h[1], h[2], h[3], 1);
 
2164
        break;
 
2165
    }
 
2166
    n = (int) (*m_gradients).size()+1;
 
2167
    (*m_gradients)[n] = gradient;
 
2168
  }
 
2169
  else
 
2170
  {
 
2171
    wxLogError(wxString(wxT("wxPdfDocument::LinearGradient: ")) +
 
2172
               wxString(_("Colour spaces do not match.")));
 
2173
  }
 
2174
  return n;
 
2175
}
 
2176
 
 
2177
int
 
2178
wxPdfDocument::AxialGradient(const wxPdfColour& col1, const wxPdfColour& col2,
 
2179
                             double x1, double y1, double x2, double y2,
 
2180
                             double intexp)
 
2181
{
 
2182
  int n = 0;
 
2183
  if (ColourSpaceOk(col1, col2))
 
2184
  {
 
2185
    n = (int) (*m_gradients).size()+1;
 
2186
    (*m_gradients)[n] = new wxPdfAxialGradient(col1, col2, x1, y1, x2, y2, intexp);
 
2187
  }
 
2188
  else
 
2189
  {
 
2190
    wxLogError(wxString(wxT("wxPdfDocument::AxialGradient: ")) +
 
2191
               wxString(_("Colour spaces do not match.")));
 
2192
  }
 
2193
  return n;
 
2194
}
 
2195
 
 
2196
int
 
2197
wxPdfDocument::MidAxialGradient(const wxPdfColour& col1, const wxPdfColour& col2,
 
2198
                               double x1, double y1, double x2, double y2,
 
2199
                               double midpoint, double intexp)
 
2200
{
 
2201
  int n = 0;
 
2202
  if (ColourSpaceOk(col1, col2))
 
2203
  {
 
2204
    n = (int) (*m_gradients).size()+1;
 
2205
    (*m_gradients)[n] = new wxPdfMidAxialGradient(col1, col2, x1, y1, x2, y2, midpoint, intexp);
 
2206
  }
 
2207
  else
 
2208
  {
 
2209
    wxLogError(wxString(wxT("wxPdfDocument::MidAxialGradient: ")) +
 
2210
               wxString(_("Colour spaces do not match.")));
 
2211
  }
 
2212
  return n;
 
2213
}
 
2214
 
 
2215
int
 
2216
wxPdfDocument::RadialGradient(const wxPdfColour& col1, const wxPdfColour& col2,
 
2217
                              double x1, double y1, double r1,
 
2218
                              double x2, double y2, double r2, double intexp)
 
2219
{
 
2220
  int n = 0;
 
2221
  if (ColourSpaceOk(col1, col2))
 
2222
  {
 
2223
    n = (int) (*m_gradients).size()+1;
 
2224
    (*m_gradients)[n] = new wxPdfRadialGradient(col1, col2, x1, y1, r1, x2, y2, r2, intexp);
 
2225
  }
 
2226
  else
 
2227
  {
 
2228
    wxLogError(wxString(wxT("wxPdfDocument::RadialGradient: ")) +
 
2229
               wxString(_("Colour spaces do not match.")));
 
2230
  }
 
2231
  return n;
 
2232
}
 
2233
 
 
2234
int
 
2235
wxPdfDocument::CoonsPatchGradient(const wxPdfCoonsPatchMesh& mesh, double minCoord, double maxCoord)
 
2236
{
 
2237
  int n = 0;
 
2238
  if (mesh.Ok())
 
2239
  {
 
2240
    n = (int) (*m_gradients).size()+1;
 
2241
    (*m_gradients)[n] = new wxPdfCoonsPatchGradient(mesh, minCoord, maxCoord);
 
2242
  }
 
2243
  else
 
2244
  {
 
2245
    wxLogError(wxString(wxT("wxPdfDocument::CoonsPatchGradient: ")) +
 
2246
               wxString(_("Mesh is invalid.")));
 
2247
  }
 
2248
  return n;
 
2249
}
 
2250
 
 
2251
/* draw a marker at a raw point-based coordinate */
 
2252
void
 
2253
wxPdfDocument::Marker(double x, double y, wxPdfMarker markerType, double size)
 
2254
{
 
2255
  double saveLineWidth = m_lineWidth;
 
2256
  double halfsize = size * 0.5;
 
2257
  static double b = 4. / 3.;
 
2258
 
 
2259
  Out("q");
 
2260
  switch (markerType) 
 
2261
  {
 
2262
    case wxPDF_MARKER_CIRCLE:
 
2263
      SetLineWidth(size * 0.15);
 
2264
      OutPoint(x - halfsize, y);
 
2265
      OutCurve(x - halfsize, y + b * halfsize, x + halfsize, y + b * halfsize, x + halfsize, y);
 
2266
      OutCurve(x + halfsize, y - b * halfsize, x - halfsize, y - b * halfsize, x - halfsize, y);
 
2267
      Out("h");
 
2268
      Out("B");
 
2269
      break;
 
2270
    case wxPDF_MARKER_TRIANGLE_UP:
 
2271
      SetLineWidth(size * 0.15);
 
2272
      OutPoint(x, y - size * 0.6667);
 
2273
      OutLineRelative(-size / 1.7321, size);
 
2274
      OutLineRelative(1.1546 * size, 0.0);
 
2275
      Out("h");
 
2276
      Out("B");
 
2277
      break;
 
2278
    case wxPDF_MARKER_TRIANGLE_DOWN:
 
2279
      SetLineWidth(size * 0.15);
 
2280
      OutPoint(x, y + size * 0.6667);
 
2281
      OutLineRelative(-size / 1.7321, -size);
 
2282
      OutLineRelative(1.1546 * size, 0.0);
 
2283
      Out("h");
 
2284
      Out("B");
 
2285
      break;
 
2286
    case wxPDF_MARKER_TRIANGLE_LEFT:
 
2287
      SetLineWidth(size * 0.15);
 
2288
      OutPoint(x - size * 0.6667, y);
 
2289
      OutLineRelative(size, -size / 1.7321);
 
2290
      OutLineRelative(0.0, 1.1546 * size);
 
2291
      Out("h");
 
2292
      Out("B");
 
2293
      break;
 
2294
    case wxPDF_MARKER_TRIANGLE_RIGHT:
 
2295
      SetLineWidth(size * 0.15);
 
2296
      OutPoint(x + size * 0.6667, y);
 
2297
      OutLineRelative(-size, -size / 1.7321);
 
2298
      OutLineRelative(0.0, 1.1546 * size);
 
2299
      Out("h");
 
2300
      Out("B");
 
2301
      break;
 
2302
    case wxPDF_MARKER_DIAMOND:
 
2303
      SetLineWidth(size * 0.15);
 
2304
      size *= 0.9;
 
2305
      OutPoint( x, y+size/1.38);
 
2306
      OutLineRelative( 0.546 * size, -size / 1.38);
 
2307
      OutLineRelative(-0.546 * size, -size / 1.38);
 
2308
      OutLineRelative(-0.546 * size,  size / 1.38);
 
2309
      Out("h");
 
2310
      Out("B");
 
2311
      break;
 
2312
    case wxPDF_MARKER_SQUARE:
 
2313
      SetLineWidth(size * 0.15);
 
2314
      Rect(x - halfsize, y - halfsize, size, size, wxPDF_STYLE_FILLDRAW);
 
2315
      Out("B");
 
2316
      break;
 
2317
    case wxPDF_MARKER_STAR:
 
2318
      size *= 1.2;
 
2319
      halfsize = 0.5 * size;
 
2320
      SetLineWidth(size * 0.09);
 
2321
      OutPoint(x, y + size * 0.5);
 
2322
      OutLine(x + 0.112255 * size, y + 0.15451 * size);
 
2323
      OutLine(x + 0.47552  * size, y + 0.15451 * size);
 
2324
      OutLine(x + 0.181635 * size, y - 0.05902 * size);
 
2325
      OutLine(x + 0.29389  * size, y - 0.40451 * size);
 
2326
      OutLine(x, y - 0.19098 * size);
 
2327
      OutLine(x - 0.29389  * size, y - 0.40451 * size);
 
2328
      OutLine(x - 0.181635 * size, y - 0.05902 * size);
 
2329
      OutLine(x - 0.47552  * size, y + 0.15451 * size);
 
2330
      OutLine(x - 0.112255 * size, y + 0.15451 * size);
 
2331
      Out("h");
 
2332
      Out("B");
 
2333
      break;
 
2334
    case wxPDF_MARKER_STAR4:
 
2335
      size *= 1.2;
 
2336
      halfsize = 0.5 * size;
 
2337
      SetLineWidth(size * 0.09);
 
2338
      OutPoint(x, y + size * 0.5);
 
2339
      OutLine(x + 0.125 * size, y + 0.125 * size);
 
2340
      OutLine(x + size * 0.5, y);
 
2341
      OutLine(x + 0.125 * size, y - 0.125 * size);
 
2342
      OutLine(x, y - size * 0.5);
 
2343
      OutLine(x - 0.125 * size, y - 0.125 * size);
 
2344
      OutLine(x - size * 0.5, y);
 
2345
      OutLine(x - 0.125 * size, y + 0.125 * size);
 
2346
      Out("h");
 
2347
      Out("B");
 
2348
      break;
 
2349
    case wxPDF_MARKER_PLUS:
 
2350
      size *= 1.2;
 
2351
      halfsize = 0.5 * size;
 
2352
      SetLineWidth(size * 0.1);
 
2353
      OutPoint(x + 0.125 * size, y + size * 0.5);
 
2354
      OutLine(x + 0.125 * size, y + 0.125 * size);
 
2355
      OutLine(x + size * 0.5, y + 0.125 * size);
 
2356
      OutLine(x + size * 0.5, y - 0.125 * size);
 
2357
      OutLine(x + 0.125 * size, y - 0.125 * size);
 
2358
      OutLine(x + 0.125 * size, y - size * 0.5);
 
2359
      OutLine(x - 0.125 * size, y - size * 0.5);
 
2360
      OutLine(x - 0.125 * size, y - 0.125 * size);
 
2361
      OutLine(x - size * 0.5, y - 0.125 * size);
 
2362
      OutLine(x - size * 0.5, y + 0.125 * size);
 
2363
      OutLine(x - 0.125 * size, y + 0.125 * size);
 
2364
      OutLine(x - 0.125 * size, y + size * 0.5);
 
2365
      Out("h");
 
2366
      Out("B");
 
2367
      break;
 
2368
    case wxPDF_MARKER_CROSS:
 
2369
      size *= 1.2;
 
2370
      halfsize = 0.5 * size;
 
2371
      SetLineWidth(size * 0.1);
 
2372
      OutPoint(x, y + 0.176777 * size);
 
2373
      OutLine(x + 0.265165 * size, y + 0.441941 * size);
 
2374
      OutLine(x + 0.441941 * size, y + 0.265165 * size);
 
2375
      OutLine(x + 0.176777 * size, y);
 
2376
      OutLine(x + 0.441941 * size, y - 0.265165 * size);
 
2377
      OutLine(x + 0.265165 * size, y - 0.441941 * size);
 
2378
      OutLine(x, y - 0.176777 * size);
 
2379
      OutLine(x - 0.265165 * size, y - 0.441941 * size);
 
2380
      OutLine(x - 0.441941 * size, y - 0.265165 * size);
 
2381
      OutLine(x - 0.176777 * size, y);
 
2382
      OutLine(x - 0.441941 * size, y + 0.265165 * size);
 
2383
      OutLine(x - 0.265165 * size, y + 0.441941 * size);
 
2384
      Out("h");
 
2385
      Out("B");
 
2386
      break;
 
2387
    case wxPDF_MARKER_PENTAGON_UP:
 
2388
      SetLineWidth(size * 0.15);
 
2389
      OutPoint(x + 0.5257 * size, y - size * 0.1708);
 
2390
      OutLineRelative(-0.5257 * size, -0.382  * size);
 
2391
      OutLineRelative(-0.5257 * size, 0.382  * size);
 
2392
      OutLineRelative(0.2008 * size, 0.6181 * size);
 
2393
      OutLineRelative(0.6499 * size,  0.0);
 
2394
      Out("h");
 
2395
      Out("B");
 
2396
      break;
 
2397
    case wxPDF_MARKER_PENTAGON_DOWN:
 
2398
      SetLineWidth(size * 0.15);
 
2399
      OutPoint(x - 0.5257 * size, y + size * 0.1708);
 
2400
      OutLineRelative( 0.5257 * size,  0.382  * size);
 
2401
      OutLineRelative( 0.5257 * size, -0.382  * size);
 
2402
      OutLineRelative(-0.2008 * size, -0.6181 * size);
 
2403
      OutLineRelative(-0.6499 * size,  0.0);
 
2404
      Out("h");
 
2405
      Out("B");
 
2406
      break;
 
2407
    case wxPDF_MARKER_PENTAGON_LEFT:
 
2408
      SetLineWidth(size * 0.15);
 
2409
      OutPoint(x - size * 0.1708, y + 0.5257 * size);
 
2410
      OutLineRelative(-0.382  * size, -0.5257 * size);
 
2411
      OutLineRelative( 0.382  * size, -0.5257 * size);
 
2412
      OutLineRelative( 0.6181 * size,  0.2008 * size);
 
2413
      OutLineRelative( 0.0,            0.6499 * size);
 
2414
      Out("h");
 
2415
      Out("B");
 
2416
      break;
 
2417
    case wxPDF_MARKER_PENTAGON_RIGHT:
 
2418
      SetLineWidth(size * 0.15);
 
2419
      OutPoint(x + size * 0.1708, y - 0.5257 * size);
 
2420
      OutLineRelative( 0.382  * size,  0.5257 * size);
 
2421
      OutLineRelative(-0.382  * size,  0.5257 * size);
 
2422
      OutLineRelative(-0.6181 * size, -0.2008 * size);
 
2423
      OutLineRelative( 0.0,           -0.6499 * size);
 
2424
      Out("h");
 
2425
      Out("B");
 
2426
      break;
 
2427
    case wxPDF_MARKER_BOWTIE_HORIZONTAL:
 
2428
      SetLineWidth(size * 0.13);
 
2429
      OutPoint(x - 0.5 * size, y - 0.5 * size);
 
2430
      OutLine(x + 0.5 * size, y + 0.5 * size);
 
2431
      OutLine(x + 0.5 * size, y - 0.5 * size);
 
2432
      OutLine(x - 0.5 * size, y + 0.5 * size);
 
2433
      Out("h");
 
2434
      Out("B");
 
2435
      break;
 
2436
    case wxPDF_MARKER_BOWTIE_VERTICAL:
 
2437
      SetLineWidth(size * 0.13);
 
2438
      OutPoint(x - 0.5 * size, y - 0.5 * size);
 
2439
      OutLine(x + 0.5 * size, y + 0.5 * size);
 
2440
      OutLine(x - 0.5 * size, y + 0.5 * size);
 
2441
      OutLine(x + 0.5 * size, y - 0.5 * size);
 
2442
      Out("h");
 
2443
      Out("B");
 
2444
      break;
 
2445
    case wxPDF_MARKER_ASTERISK:
 
2446
      size *= 1.05;
 
2447
      SetLineWidth(size * 0.15);
 
2448
      OutPoint( x, y + size * 0.5);
 
2449
      OutLineRelative(0.0, -size);
 
2450
      OutPoint( x + 0.433 * size, y + 0.25 * size);
 
2451
      OutLine(x - 0.433 * size, y - 0.25 * size);
 
2452
      OutPoint(x + 0.433 * size, y - 0.25 * size);
 
2453
      OutLine(x - 0.433 * size, y + 0.25 * size);
 
2454
      Out("S");
 
2455
      break;
 
2456
    case wxPDF_MARKER_SUN:
 
2457
      SetLineWidth(size * 0.15);
 
2458
      halfsize = size * 0.25;
 
2459
      OutPoint(x - halfsize, y);
 
2460
      OutCurve(x - halfsize, y + b * halfsize, x + halfsize, y + b * halfsize, x + halfsize, y);
 
2461
      OutCurve(x + halfsize, y - b * halfsize, x - halfsize, y - b * halfsize, x - halfsize, y);
 
2462
      Out("h");
 
2463
      OutPoint(x + size * 0.5, y);
 
2464
      OutLine(x + size * 0.25, y);
 
2465
      OutPoint(x - size * 0.5, y);
 
2466
      OutLine(x - size * 0.25, y);
 
2467
      OutPoint(x, y - size * 0.5);
 
2468
      OutLine(x, y - size * 0.25);
 
2469
      OutPoint(x, y + size * 0.5);
 
2470
      OutLine(x, y + size * 0.25);
 
2471
      Out("B");
 
2472
      break;
 
2473
 
 
2474
    default:
 
2475
      break;
 
2476
  }
 
2477
  Out("Q");
 
2478
  m_x = x;
 
2479
  m_y = y;
 
2480
  SetLineWidth(saveLineWidth);
 
2481
}
 
2482
 
 
2483
void
 
2484
wxPdfDocument::Arrow(double x1, double y1, double x2, double y2, double linewidth, double height, double width)
 
2485
{
 
2486
  double saveLineWidth = m_lineWidth;
 
2487
  double dx = x2 - x1;
 
2488
  double dy = y2 - y1;
 
2489
  double dz = sqrt (dx*dx+dy*dy);
 
2490
  double sina = dy / dz;
 
2491
  double cosa = dx / dz;
 
2492
  double x3 = x2 - cosa * height + sina * width;
 
2493
  double y3 = y2 - sina * height - cosa * width;
 
2494
  double x4 = x2 - cosa * height - sina * width;
 
2495
  double y4 = y2 - sina * height + cosa * width;
 
2496
 
 
2497
  SetLineWidth(0.2);
 
2498
 
 
2499
  //Draw a arrow head
 
2500
  OutAscii(wxPdfUtility::Double2String( x2*m_k,2) + wxString(wxT(" ")) +
 
2501
           wxPdfUtility::Double2String( y2*m_k,2) + wxString(wxT(" m ")) +
 
2502
           wxPdfUtility::Double2String( x3*m_k,2) + wxString(wxT(" ")) +
 
2503
           wxPdfUtility::Double2String( y3*m_k,2) + wxString(wxT(" l ")) +
 
2504
           wxPdfUtility::Double2String( x4*m_k,2) + wxString(wxT(" ")) +
 
2505
           wxPdfUtility::Double2String( y4*m_k,2) + wxString(wxT(" l b")));
 
2506
 
 
2507
  SetLineWidth(linewidth);
 
2508
  Line(x1+cosa*linewidth, y1+sina*linewidth, x2-cosa*height, y2-sina*height);
 
2509
  SetLineWidth(saveLineWidth);
 
2510
}