1
///////////////////////////////////////////////////////////////////////////////
2
// Name: pdfgraphics.cpp
3
// Purpose: Implementation of wxPdfDocument graphics primitives
4
// Author: Ulrich Telle
7
// Copyright: (c) Ulrich Telle
8
// Licence: wxWindows licence
9
///////////////////////////////////////////////////////////////////////////////
11
/// \file pdfgraphics.cpp Implementation of the wxPdfDocument graphics primitives
13
// For compilers that support precompilation, includes <wx/wx.h>.
14
#include <wx/wxprec.h>
24
#include <wx/tokenzr.h>
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"
33
wxPdfExtGState::wxPdfExtGState(double lineAlpha, double fillAlpha, wxPdfBlendMode blendMode)
35
m_lineAlpha = lineAlpha;
36
m_fillAlpha = fillAlpha;
37
m_blendMode = blendMode;
40
wxPdfExtGState::~wxPdfExtGState()
45
wxPdfDocument::SetAlpha(double lineAlpha, double fillAlpha, wxPdfBlendMode blendMode)
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;
55
// Create state id for lookup map
56
int id = ((int) blendMode) * 100000000 + (int) (lineAlpha * 1000) * 10000 + (int) (fillAlpha * 1000);
59
wxPdfExtGSLookupMap::iterator extGState = (*m_extGSLookup).find(id);
60
if (extGState == (*m_extGSLookup).end())
62
n = (int) (*m_extGStates).size() + 1;
63
(*m_extGStates)[n] = new wxPdfExtGState(lineAlpha, fillAlpha, blendMode);
64
(*m_extGSLookup)[id] = n;
68
n = extGState->second;
71
if (n != m_currentExtGState)
80
wxPdfDocument::SetAlphaState(int alphaState)
82
if (alphaState > 0 && (size_t) alphaState <= (*m_extGStates).size())
84
OutAscii(wxString::Format(wxT("/GS%d gs"), alphaState));
88
// ----------------------------------------------------------------------------
89
// wxPdfLineStyle: class representing line style for drawing graphics
90
// ----------------------------------------------------------------------------
92
wxPdfLineStyle::wxPdfLineStyle(double width,
93
wxPdfLineCap cap, wxPdfLineJoin join,
94
const wxPdfArrayDouble& dash, double phase,
95
const wxPdfColour& colour)
97
m_isSet = (width > 0) || (cap >= 0) || (join >= 0) || (dash.GetCount() > 0);
106
wxPdfLineStyle::~wxPdfLineStyle()
111
wxPdfLineStyle::wxPdfLineStyle(const wxPdfLineStyle& lineStyle)
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;
123
wxPdfLineStyle::operator= (const wxPdfLineStyle& lineStyle)
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;
137
wxPdfShape::wxPdfShape()
143
wxPdfShape::~wxPdfShape()
148
wxPdfShape::MoveTo(double x, double y)
150
m_subpath = (int) m_x.GetCount();
151
m_types.Add(wxPDF_SEG_MOVETO);
157
wxPdfShape::LineTo(double x, double y)
161
m_types.Add(wxPDF_SEG_LINETO);
167
wxLogError(wxString(wxT("wxPdfShape::LineTo: ")) +
168
wxString(_("Invalid subpath.")));
173
wxPdfShape::CurveTo(double x1, double y1, double x2, double y2, double x3, double y3)
177
m_types.Add(wxPDF_SEG_CURVETO);
187
wxLogError(wxString(wxT("wxPdfShape::CurveTo: ")) +
188
wxString(_("Invalid subpath.")));
193
wxPdfShape::ClosePath()
195
if (m_subpath >= 0 && m_types.GetCount() > 0 && m_types.Last() != wxPDF_SEG_CLOSE)
197
m_types.Add(wxPDF_SEG_CLOSE);
198
m_x.Add(m_x[m_subpath]);
199
m_y.Add(m_y[m_subpath]);
205
wxPdfShape::GetSegment(int iterType, int iterPoints, double coords[]) const
207
wxPdfSegmentType segType = wxPDF_SEG_UNDEFINED;
208
if (iterType >= 0 && (size_t) iterType < m_types.GetCount())
210
int pointCount = (m_types[iterType] == wxPDF_SEG_CURVETO) ? 2 : 0;
211
if (iterPoints >= 0 && (size_t) (iterPoints + pointCount) < m_x.GetCount())
213
segType = (wxPdfSegmentType) m_types[iterType];
216
case wxPDF_SEG_CLOSE:
217
coords[0] = m_x[iterPoints];
218
coords[1] = m_y[iterPoints];
221
case wxPDF_SEG_MOVETO:
222
case wxPDF_SEG_LINETO:
223
coords[0] = m_x[iterPoints];
224
coords[1] = m_y[iterPoints];
227
case wxPDF_SEG_CURVETO:
228
coords[0] = m_x[iterPoints];
229
coords[1] = m_y[iterPoints];
231
coords[2] = m_x[iterPoints];
232
coords[3] = m_y[iterPoints];
234
coords[4] = m_x[iterPoints];
235
coords[5] = m_y[iterPoints];
245
wxPdfFlatPath::wxPdfFlatPath(const wxPdfShape* shape, double flatness, int limit)
251
m_flatnessSq = flatness * flatness;
252
m_recursionLimit = limit;
254
m_stackMaxSize = 6 * m_recursionLimit + /* 6 + 2 */ 8;
255
m_stack = new double[m_stackMaxSize];
256
m_recLevel = new int[m_recursionLimit + 1];
261
wxPdfFlatPath::~wxPdfFlatPath()
264
delete [] m_recLevel;
268
wxPdfFlatPath::InitIter()
278
* Fetches the next segment from the source iterator.
281
wxPdfFlatPath::FetchSegment()
285
if ((size_t) m_iterType >= m_shape->GetSegmentCount())
291
m_srcSegType = m_shape->GetSegment(m_iterType, m_iterPoints, m_scratch);
293
switch (m_srcSegType)
295
case wxPDF_SEG_CLOSE:
298
case wxPDF_SEG_MOVETO:
299
case wxPDF_SEG_LINETO:
300
m_srcPosX = m_scratch[0];
301
m_srcPosY = m_scratch[1];
304
case wxPDF_SEG_CURVETO:
305
if (m_recursionLimit == 0)
307
m_srcPosX = m_scratch[4];
308
m_srcPosY = m_scratch[5];
312
sp = 6 * m_recursionLimit;
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
329
wxPdfFlatPath::Next()
336
switch (m_srcSegType)
338
case wxPDF_SEG_CURVETO:
348
if ((size_t) m_iterType < m_shape->GetSegmentCount())
350
switch (m_srcSegType)
352
case wxPDF_SEG_CLOSE:
353
case wxPDF_SEG_MOVETO:
354
case wxPDF_SEG_LINETO:
358
case wxPDF_SEG_CURVETO:
369
wxPdfFlatPath::CurrentSegment(double coords[])
371
switch (m_srcSegType)
373
case wxPDF_SEG_CLOSE:
376
case wxPDF_SEG_MOVETO:
377
case wxPDF_SEG_LINETO:
378
coords[0] = m_srcPosX;
379
coords[1] = m_srcPosY;
382
case wxPDF_SEG_CURVETO:
383
if (m_stackSize == 0)
385
coords[0] = m_srcPosX;
386
coords[1] = m_srcPosY;
390
int sp = m_stackMaxSize - 6 * m_stackSize;
391
coords[0] = m_stack[sp + 4];
392
coords[1] = m_stack[sp + 5];
394
return wxPDF_SEG_LINETO;
397
return wxPDF_SEG_UNDEFINED;
401
SubdivideCubicCurve(double src[], int srcOff,
402
double left[], int leftOff,
403
double right[], int rightOff)
405
// To understand this code, please have a look at the image
406
// "CubicCurve2D-3.png" in the sub-directory "doc-files".
423
double midx; // Mid = left.P2 = right.P1
424
double midy; // Mid = left.P2 = right.P1
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];
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;
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;
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;
474
PointSegmentDistanceSq(double x1, double y1, double x2, double y2, double px, double py)
476
double pd2 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
481
// Points are coincident.
487
double u = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / pd2;
502
x = x1 + u * (x2 - x1);
503
y = y1 + u * (y2 - y1);
507
return (x - px) * (x - px) + (y - py) * (y - py);
511
GetFlatnessSq(double x1, double y1, double cx1, double cy1,
512
double cx2, double cy2, double x2, double y2)
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));
523
GetFlatnessSq(double coords[], int offset)
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]);
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.
536
wxPdfFlatPath::SubdivideCubic()
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))
546
m_recLevel[m_stackSize] = m_recLevel[m_stackSize - 1] = ++level;
548
SubdivideCubicCurve(m_stack, sp, m_stack, sp - 6, m_stack, sp);
555
wxPdfFlatPath::MeasurePathLength()
558
double moveX = 0, moveY = 0;
559
double lastX = 0, lastY = 0;
560
double thisX = 0, thisY = 0;
564
// Save iterator state
565
bool saveDone = m_done;
566
int saveIterType = m_iterType;
567
int saveIterPoints = m_iterPoints;
568
int saveStackSize = m_stackSize;
573
type = CurrentSegment(points);
576
case wxPDF_SEG_MOVETO:
577
moveX = lastX = points[0];
578
moveY = lastY = points[1];
581
case wxPDF_SEG_CLOSE:
586
case wxPDF_SEG_LINETO:
589
double dx = thisX-lastX;
590
double dy = thisY-lastY;
591
total += sqrt(dx*dx + dy*dy);
599
// Restore iterator state
601
m_iterType = saveIterType;
602
m_iterPoints = saveIterPoints;
603
m_stackSize = saveStackSize;
610
wxPdfDocument::ShapedText(const wxPdfShape& shape, const wxString& text, wxPdfShapedTextMode mode)
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);
618
double moveX = 0, moveY = 0;
619
double lastX = 0, lastY = 0;
620
double thisX = 0, thisY = 0;
623
unsigned int currentChar = 0;
624
unsigned int length = (unsigned int) voText.Length();
625
double height = GetFontSize() / GetScaleFactor();
632
double factor = stretchToFit ? it.MeasurePathLength() / DoGetStringWidth(voText) : 1.0;
633
double nextAdvance = 0;
635
while (currentChar < length && !it.IsDone())
637
type = it.CurrentSegment(points);
640
case wxPDF_SEG_MOVETO:
642
moveX = lastX = points[0];
643
moveY = lastY = points[1];
645
nextAdvance = DoGetStringWidth(voText.Mid(currentChar,1)) * 0.5;
650
case wxPDF_SEG_CLOSE:
657
case wxPDF_SEG_LINETO:
661
double dx = thisX-lastX;
662
double dy = thisY-lastY;
663
double distance = sqrt(dx*dx + dy*dy);
664
if (distance >= next)
666
double r = 1.0 / distance;
667
double angle = atan2(-dy, dx) * 45. / atan(1.);
668
while (currentChar < length && distance >= next)
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;
679
SetXY(x-advance,y-height);
680
Write(height, glyph);
682
next += (advance+nextAdvance) * factor;
686
currentChar %= length;
703
wxPdfDocument::SetFillingRule(int rule)
705
if (rule == wxWINDING_RULE || rule == wxODDEVEN_RULE)
712
wxPdfDocument::GetFillingRule()
718
wxPdfDocument::Line(double x1, double y1, double x2, double y2)
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")));
728
wxPdfDocument::Rect(double x, double y, double w, double h, int style)
732
if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILL)
736
else if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILLDRAW)
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);
751
wxPdfDocument::RoundedRect(double x, double y, double w, double h,
752
double r, int roundCorner, int style)
754
if ((roundCorner & wxPDF_CORNER_ALL) == wxPDF_CORNER_NONE)
757
Rect(x, y, w, h, style);
764
if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILL)
770
if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILLDRAW)
780
double myArc = 4. / 3. * (sqrt(2.) - 1.);
783
double xc = x + w - r;
787
if (roundCorner & wxPDF_CORNER_TOP_LEFT)
789
OutCurve(xc + (r * myArc), yc - r, xc + r, yc - (r * myArc), xc + r, yc);
800
if (roundCorner & wxPDF_CORNER_TOP_RIGHT)
802
OutCurve(xc + r, yc + (r * myArc), xc + (r * myArc), yc + r, xc, yc + r);
806
OutLine(x + w, y + h);
813
if (roundCorner & wxPDF_CORNER_BOTTOM_LEFT)
815
OutCurve(xc - (r * myArc), yc + r, xc - r, yc + (r * myArc), xc - r, yc);
826
if (roundCorner & wxPDF_CORNER_BOTTOM_RIGHT)
828
OutCurve(xc - r, yc - (r * myArc), xc - (r * myArc), yc - r, xc, yc - r);
840
wxPdfDocument::Curve(double x0, double y0, double x1, double y1,
841
double x2, double y2, double x3, double y3,
846
if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILL)
848
op = (m_fillRule == wxODDEVEN_RULE) ? wxT("f*") : wxT("f");
852
if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILLDRAW)
854
op = (m_fillRule == wxODDEVEN_RULE) ? wxT("B*") : wxT("B");
863
OutCurve(x1, y1, x2, y2, x3, y3);
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)
876
if ((style & wxPDF_STYLE_DRAWCLOSE) == wxPDF_STYLE_DRAWCLOSE)
878
// Close the path as well
879
if ((style & wxPDF_STYLE_FILL) == wxPDF_STYLE_FILL)
881
op = wxT("b"); // small 'b' means closing the path as well
885
op = wxT("s"); // small 's' means closing the path as well
890
if ((style & wxPDF_STYLE_MASK) == wxPDF_STYLE_FILL)
894
else if ((style & wxPDF_STYLE_MASK) == wxPDF_STYLE_FILLDRAW)
896
op = (doSector) ? wxT("b") : wxT("B");
900
op = (doSector) ? wxT("s") : wxT("S");
915
static double pi = 4. * atan(1.0);
916
astart = pi * astart / 180.;
917
afinish = pi * afinish / 180.;
918
if (m_yAxisOriginTop)
923
double totalAngle = afinish - astart;
925
double dt = totalAngle / nSeg;
932
double a = -(pi * angle / 180.);
933
if (m_yAxisOriginTop)
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")));
948
double t1, a0, b0, c0, d0, a1, b1, c1, d1;
950
a0 = x0 + (rx * cos(t1));
951
b0 = y0 + (ry * sin(t1));
954
OutPoint(a0 / m_k, b0 / m_k);
956
for (i = 1; i <= nSeg; i++)
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));
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,
977
OutLine(x0 / m_k, y0 / m_k);
978
// a0 = x0 + (rx * cos(t1));
979
// b0 = y0 + (ry * sin(t1));
990
wxPdfDocument::Circle(double x0, double y0, double r, double astart, double afinish,
993
Ellipse(x0, y0, r, 0, 0, astart, afinish, style, nSeg);
997
wxPdfDocument::Sector(double xc, double yc, double r, double astart, double afinish,
998
int style, bool clockwise, double origin)
1000
static double pi = 4. * atan(1.);
1001
static double pi2 = 0.5 * pi;
1006
afinish = origin - astart;
1007
astart = origin - d;
1014
astart = fmod(astart, 360.) + 360;
1015
afinish = fmod(afinish, 360.) + 360;
1016
if (astart > afinish)
1020
afinish = afinish / 180. * pi;
1021
astart = astart / 180. * pi;
1022
d = afinish - astart;
1029
if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILL)
1035
if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILLDRAW)
1046
if (sin(d/2) != 0.0)
1048
myArc = 4./3. * (1.-cos(d/2))/sin(d/2) * r;
1054
// first put the center
1056
// put the first point
1057
OutLine(xc+r*cos(astart),yc-r*sin(astart));
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),
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),
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),
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),
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),
1103
// terminate drawing
1108
wxPdfDocument::Polygon(const wxPdfArrayDouble& x, const wxPdfArrayDouble& y, int style)
1110
unsigned int np = (x.GetCount() < y.GetCount()) ? (unsigned int) x.GetCount() : (unsigned int) y.GetCount();
1113
if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILL)
1115
op = (m_fillRule == wxODDEVEN_RULE) ? wxT("f*") : wxT("f");
1119
if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILLDRAW)
1121
op = (m_fillRule == wxODDEVEN_RULE) ? wxT("B*") : wxT("B");
1129
OutPoint(x[0], y[0]);
1131
for (i = 1; i < np; i++)
1133
OutLine(x[i], y[i]);
1135
OutLine(x[0], y[0]);
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)
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);
1157
static double pi = 4. * atan(1.);
1159
wxPdfArrayDouble x, y;
1161
for (i = 0; i < ns; i++)
1163
a = (angle + (i * 360 / ns)) / 180. * pi;
1164
x.Add(x0 + (r * sin(a)));
1165
y.Add(y0 + (r * cos(a)));
1167
Polygon(x, y, style);
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)
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);
1190
visited.SetCount(nv);
1192
for (i = 0; i < nv; i++)
1196
static double pi = 4. * atan(1.);
1198
wxPdfArrayDouble x, y;
1203
a = (angle + (i * 360 / nv)) / 180. * pi;
1204
x.Add(x0 + (r * sin(a)));
1205
y.Add(y0 + (r * cos(a)));
1208
while (visited[i] == 0);
1209
Polygon(x, y, style);
1213
SolveTridiagonalSpecial(const wxPdfArrayDouble& r, wxPdfArrayDouble& x)
1216
size_t n = r.GetCount();
1218
wxPdfArrayDouble gamma;
1221
// Decomposition and forward substitution.
1224
for (i = 1; i < n; ++i)
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;
1231
// Backsubstitution.
1232
for (i = 1; i < n; ++i)
1234
x[n-i-1] -= gamma[n-i] * x[n-i];
1239
GetBezierControlPoints(const wxPdfArrayDouble& x, const wxPdfArrayDouble& y,
1240
wxPdfArrayDouble& x1, wxPdfArrayDouble& y1,
1241
wxPdfArrayDouble& x2, wxPdfArrayDouble& y2)
1244
size_t n = x.GetCount() - 1;
1247
wxLogDebug(wxString(wxT("GetBezierControlPoints: "))+_("n must be greater than 2."));
1251
// Special case: Bezier curve should be a straight line.
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];
1262
// First control point
1266
// Set right hand side X values
1267
for (i = 1; i < n-1; ++i)
1269
r[i] = 4 * x[i] + 2 * x[i+1];
1271
r[0] = x[0] + 2 * x[1];
1272
r[n-1] = (8 * x[n-1] + x[n]) / 2.0;
1275
SolveTridiagonalSpecial(r, x1);
1277
// Set right hand side Y values
1278
for (i = 1; i < n-1; ++i)
1280
r[i] = 4 * y[i] + 2 * y[i+1];
1282
r[0] = y[0] + 2 * y[1];
1283
r[n - 1] = (8 * y[n-1] + y[n]) / 2.0;
1286
SolveTridiagonalSpecial(r, y1);
1288
// Second control point
1291
for (i = 0; i < n; ++i)
1295
x2[i] = 2 * x[i+1] - x1[i+1];
1296
y2[i] = 2 * y[i+1] - y1[i+1];
1300
x2[i] = (x[n] + x1[n-1]) / 2;
1301
y2[i] = (y[n] + y1[n-1]) / 2;
1308
wxPdfDocument::BezierSpline(const wxPdfArrayDouble& x, const wxPdfArrayDouble& y, int style)
1310
size_t n = x.GetCount();
1311
if (n == y.GetCount())
1315
wxPdfArrayDouble x1, y1, x2, y2;
1316
if (GetBezierControlPoints(x, y, x1, y1, x2, y2))
1319
if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILL)
1321
op = (m_fillRule == wxODDEVEN_RULE) ? wxT("f*") : wxT("f");
1325
if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILLDRAW)
1327
op = (m_fillRule == wxODDEVEN_RULE) ? wxT("B*") : wxT("B");
1336
for (j = 0; j < n-1; ++j)
1338
CurveTo(x1[j], y1[j], x2[j], y2[j], x[j+1], y[j+1]);
1345
Line(x[0], y[0], x[1], y[1]);
1351
SolveTridiagonalGeneral(const wxPdfArrayDouble& a, const wxPdfArrayDouble& b,
1352
const wxPdfArrayDouble& c, const wxPdfArrayDouble& r,
1353
wxPdfArrayDouble& u)
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())
1359
wxLogDebug(wxString(wxT("SolveTridiagonal: "))+_("Mismatch of vector sizes."));
1364
wxLogDebug(wxString(wxT("SolveTridiagonal: "))+_("Singular matrix."));
1368
wxPdfArrayDouble gamma;
1372
// Decomposition and forward substitution.
1376
for (j = 1; j < n; ++j)
1378
gamma[j] = c[j-1] / beta;
1379
beta = b[j] - a[j] * gamma[j];
1382
wxLogDebug(wxString(wxT("SolveTridiagonal: "))+_("Singular matrix."));
1385
u[j] = (r[j] - a[j] * u[j - 1]) / beta;
1388
// Backward substitution.
1389
for (j = 1; j < n; ++j)
1391
u[n-j-1] -= gamma[n-j] * u[n-j];
1397
SolveCyclic(const wxPdfArrayDouble& a, const wxPdfArrayDouble& b,
1398
const wxPdfArrayDouble& c, double alpha, double beta,
1399
const wxPdfArrayDouble& r, wxPdfArrayDouble& x)
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())
1406
wxLogDebug(wxString(wxT("SolveCyclic: "))+_("Mismatch of vector sizes."));
1411
wxLogDebug(wxString(wxT("SolveCyclic: "))+_("n must be greater than 2."));
1415
// Set up the diagonal of the modified tridiagonal system.
1416
wxPdfArrayDouble bb;
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)
1425
// Solve A ļæ½ x = rhs.
1427
if (!SolveTridiagonalGeneral(a, bb, c, r, x))
1432
// Set up the vector u.
1438
// Solve A ļæ½ z = u.
1441
if (!SolveTridiagonalGeneral(a, bb, c, u, z))
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)
1450
x[i] -= fact * z[i];
1456
GetCyclicControlPoints(const wxPdfArrayDouble& x, const wxPdfArrayDouble& y,
1457
wxPdfArrayDouble& x1, wxPdfArrayDouble& y1,
1458
wxPdfArrayDouble& x2, wxPdfArrayDouble& y2)
1461
size_t n = x.GetCount();
1462
bool ok = (n == y.GetCount());
1465
wxLogDebug(wxString(wxT("GetCyclicControlPoints: "))+_("n must be greater than 2."));
1469
// Calculate first Bezier control points
1472
wxPdfArrayDouble a, b, c;
1477
// Right hand side vector for points X coordinates.
1480
for (i = 0; i < n; ++i)
1482
j = (i == n-1) ? 0 : i+1;
1483
r[i] = 4 * x[i] + 2 * x[j];
1486
// Solve the system for X.
1488
if (!SolveCyclic(a, b, c, 1.0, 1.0, r, x1))
1493
// Right hand side vector for points Y coordinates.
1494
for (i = 0; i < n; ++i)
1496
j = (i == n - 1) ? 0 : i + 1;
1497
r[i] = 4 * y[i] + 2 * y[j];
1499
// Solve the system for Y.
1501
if (!SolveCyclic(a, b, c, 1, 1, r, y1))
1506
// Second control point.
1509
for (i = 0; i < n; ++i)
1511
x2[i] = 2 * x[i] - x1[i];
1512
y2[i] = 2 * y[i] - y1[i];
1518
wxPdfDocument::ClosedBezierSpline(const wxPdfArrayDouble& x, const wxPdfArrayDouble& y, int style)
1520
size_t n = x.GetCount();
1521
if (n == y.GetCount())
1525
wxPdfArrayDouble x1, y1, x2, y2;
1526
if (GetCyclicControlPoints(x, y, x1, y1, x2, y2))
1529
if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILL)
1531
op = (m_fillRule == wxODDEVEN_RULE) ? wxT("f*") : wxT("f");
1535
if ((style & wxPDF_STYLE_FILLDRAW) == wxPDF_STYLE_FILLDRAW)
1537
op = (m_fillRule == wxODDEVEN_RULE) ? wxT("B*") : wxT("B");
1546
for (j = 1; j < n; ++j)
1548
CurveTo(x1[j-1], y1[j-1], x2[j], y2[j], x[j], y[j]);
1550
CurveTo(x1[n-1], y1[n-1], x2[0], y2[0], x[0], y[0]);
1556
Line(x[0], y[0], x[1], y[1]);
1562
wxPdfDocument::Shape(const wxPdfShape& shape, int style)
1565
if ((style & wxPDF_STYLE_MASK) == wxPDF_STYLE_FILL)
1567
op = (m_fillRule == wxODDEVEN_RULE) ? wxT("f*") : wxT("f");
1571
if ((style & wxPDF_STYLE_MASK) == wxPDF_STYLE_FILLDRAW)
1573
op = (m_fillRule == wxODDEVEN_RULE) ? wxT("B*") : wxT("B");
1575
else if ((style & wxPDF_STYLE_MASK) == (wxPDF_STYLE_DRAWCLOSE | wxPDF_STYLE_FILL))
1577
// small 'b' means closing the path as well
1578
op = (m_fillRule == wxODDEVEN_RULE) ? wxT("b*") : wxT("b");
1580
else if ((style & wxPDF_STYLE_MASK) == wxPDF_STYLE_DRAWCLOSE)
1582
op = wxT("s"); // small 's' means closing the path as well
1593
unsigned int iterType;
1594
unsigned int iterPoints = 0;
1595
unsigned int segCount = shape.GetSegmentCount();
1596
for (iterType = 0; iterType < segCount; iterType++)
1598
int segType = shape.GetSegment(iterType, iterPoints, scratch);
1601
case wxPDF_SEG_CLOSE:
1605
case wxPDF_SEG_MOVETO:
1606
OutPoint(scratch[0], scratch[1]);
1609
case wxPDF_SEG_LINETO:
1610
OutLine(scratch[0], scratch[1]);
1613
case wxPDF_SEG_CURVETO:
1614
OutCurve(scratch[0], scratch[1], scratch[2], scratch[3],scratch[4], scratch[5]);
1622
// ClosePath(style);
1626
wxPdfDocument::ClippingText(double x, double y, const wxString& txt, bool outline)
1628
wxString op = outline ? wxT("5") : wxT("7");
1629
if (m_yAxisOriginTop)
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);
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);
1643
TextEscape(txt,false);
1649
wxPdfDocument::ClippingRect(double x, double y, double w, double h, bool outline)
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);
1661
wxPdfDocument::ClippingEllipse(double x, double y, double rx, double ry, bool outline)
1663
wxString op = outline ? wxT("S") : wxT("n");
1668
double lx = 4./3. * (sqrt(2.)-1.) * rx;
1669
double ly = 4./3. * (sqrt(2.)-1.) * ry;
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")));
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")));
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")));
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);
1705
wxPdfDocument::ClippingPolygon(const wxPdfArrayDouble& x, const wxPdfArrayDouble& y, bool outline)
1707
unsigned int np = (x.GetCount() < y.GetCount()) ? (unsigned int) x.GetCount() : (unsigned int) y.GetCount();
1709
wxString op = outline ? wxT("S") : wxT("n");
1712
OutPoint(x[0], y[0]);
1714
for (i = 1; i < np; i++)
1716
OutLine(x[i], y[i]);
1718
OutLine(x[0], y[0]);
1719
OutAscii(wxString(wxT("h W ")) + op);
1724
wxPdfDocument::ClippingPath()
1731
wxPdfDocument::MoveTo(double x, double y)
1737
wxPdfDocument::LineTo(double x, double y)
1743
wxPdfDocument::CurveTo(double x1, double y1, double x2, double y2, double x3, double y3)
1745
OutCurve(x1, y1, x2, y2, x3, y3);
1749
wxPdfDocument::EndPath(int style)
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;
1763
wxPdfDocument::ClosePath(int style)
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;
1773
OutAscii(wxString(wxT("h W ")) + op);
1777
wxPdfDocument::ClippingPath(const wxPdfShape& shape, int style)
1781
unsigned int iterType;
1782
unsigned int iterPoints = 0;
1783
unsigned int segCount = shape.GetSegmentCount();
1784
for (iterType = 0; iterType < segCount; iterType++)
1786
int segType = shape.GetSegment(iterType, iterPoints, scratch);
1789
case wxPDF_SEG_CLOSE:
1792
case wxPDF_SEG_MOVETO:
1793
MoveTo(scratch[0], scratch[1]);
1796
case wxPDF_SEG_LINETO:
1797
LineTo(scratch[0], scratch[1]);
1800
case wxPDF_SEG_CURVETO:
1801
CurveTo(scratch[0], scratch[1], scratch[2], scratch[3],scratch[4], scratch[5]);
1810
wxPdfDocument::UnsetClipping()
1813
RestoreGraphicState();
1817
wxPdfDocument::ClippedCell(double w, double h, const wxString& txt,
1818
int border, int ln, int align, int fill, const wxPdfLink& link)
1820
bool doPageBreak = (m_yAxisOriginTop) ? (m_y+h > m_pageBreakTrigger) : (m_y-h < m_pageBreakTrigger);
1821
if ((border != wxPDF_BORDER_NONE) || (fill != 0) || doPageBreak)
1823
Cell(w, h, wxT(""), border, 0, wxPDF_ALIGN_LEFT, fill);
1826
ClippingRect(m_x, m_y, w, h);
1827
Cell(w, h, txt, wxPDF_BORDER_NONE, ln, align, 0, link);
1832
wxPdfDocument::SetLineStyle(const wxPdfLineStyle& linestyle)
1834
m_lineStyle = linestyle;
1835
if (linestyle.GetWidth() >= 0)
1837
double width_prev = m_lineWidth;
1838
SetLineWidth(linestyle.GetWidth());
1839
m_lineWidth = width_prev;
1841
switch (linestyle.GetLineCap())
1843
case wxPDF_LINECAP_BUTT:
1844
case wxPDF_LINECAP_ROUND:
1845
case wxPDF_LINECAP_SQUARE:
1846
OutAscii(wxString::Format(wxT("%d J"), linestyle.GetLineCap()));
1851
switch (linestyle.GetLineJoin())
1853
case wxPDF_LINEJOIN_MITER:
1854
case wxPDF_LINEJOIN_ROUND:
1855
case wxPDF_LINEJOIN_BEVEL:
1856
OutAscii(wxString::Format(wxT("%d j"), linestyle.GetLineJoin()));
1862
const wxPdfArrayDouble& dash = linestyle.GetDash();
1865
wxString dashString = wxT("");
1867
for (j = 0; j < dash.GetCount(); j++)
1871
dashString += wxString(wxT(" "));
1873
dashString += wxPdfUtility::Double2String(dash[j]*m_k,2);
1875
double phase = linestyle.GetPhase();
1876
if (phase < 0 || dashString.Length() == 0)
1880
OutAscii(wxString(wxT("[")) + dashString + wxString(wxT("] ")) +
1881
wxPdfUtility::Double2String(phase*m_k,2) + wxString(wxT(" d")));
1883
SetDrawColour(linestyle.GetColour());
1886
const wxPdfLineStyle&
1887
wxPdfDocument::GetLineStyle()
1893
wxPdfDocument::StartTransform()
1895
//save the current graphic state
1902
wxPdfDocument::ScaleX(double sx, double x, double y)
1904
return Scale(sx, 100, x, y);
1908
wxPdfDocument::ScaleY(double sy, double x, double y)
1910
return Scale(100, sy, x, y);
1914
wxPdfDocument::ScaleXY(double s, double x, double y)
1916
return Scale(s, s, x, y);
1920
wxPdfDocument::Scale(double sx, double sy, double x, double y)
1930
if (sx == 0 || sy == 0)
1932
wxLogError(wxString(wxT("wxPdfDocument::Scale: ")) +
1933
wxString(_("Please use values unequal to zero for Scaling.")));
1938
//calculate elements of transformation matrix
1946
tm[4] = x * (1 - sx);
1947
tm[5] = y * (1 - sy);
1948
//scale the coordinate system
1949
if (m_inTransform == 0)
1958
wxPdfDocument::MirrorH(double x)
1960
Scale(-100, 100, x);
1964
wxPdfDocument::MirrorV(double y)
1966
Scale(100, -100, -1, y);
1970
wxPdfDocument::TranslateX(double tx)
1976
wxPdfDocument::TranslateY(double ty)
1982
wxPdfDocument::Translate(double tx, double ty)
1984
if (m_inTransform == 0)
1988
// calculate elements of transformation matrix
1995
tm[5] = (m_yAxisOriginTop) ? ty : -ty;
1996
// translate the coordinate system
2001
wxPdfDocument::Rotate(double angle, double x, double y)
2003
if (m_inTransform == 0)
2017
// calculate elements of transformation matrix
2019
if (m_yAxisOriginTop)
2023
angle *= (atan(1.) / 45.);
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)
2035
wxPdfDocument::Transform( double a, double b, double c, double d, double tx, double ty )
2037
if (m_inTransform == 0)
2041
// copy the elements of transformation matrix
2054
wxPdfDocument::SkewX(double xAngle, double x, double y)
2056
return Skew(xAngle, 0, x, y);
2060
wxPdfDocument::SkewY(double yAngle, double x, double y)
2062
return Skew(0, yAngle, x, y);
2066
wxPdfDocument::Skew(double xAngle, double yAngle, double x, double y)
2076
if (xAngle <= -90 || xAngle >= 90 || yAngle <= -90 || yAngle >= 90)
2078
wxLogError(wxString(wxT("wxPdfDocument::Skew: ")) +
2079
wxString(_("Please use values between -90 and 90 degree for skewing.")));
2084
//calculate elements of transformation matrix
2086
if (m_yAxisOriginTop)
2091
xAngle *= (atan(1.) / 45.);
2092
yAngle *= (atan(1.) / 45.);
2094
tm[1] = tan(yAngle);
2095
tm[2] = tan(xAngle);
2099
//skew the coordinate system
2100
if (m_inTransform == 0)
2109
wxPdfDocument::StopTransform()
2111
//restore previous graphic state
2112
if (m_inTransform > 0)
2116
RestoreGraphicState();
2121
ColourSpaceOk(const wxPdfColour& col1, const wxPdfColour& col2)
2123
return (col1.GetColourType() != wxPDF_COLOURTYPE_SPOT &&
2124
col1.GetColourType() == col2.GetColourType());
2128
wxPdfDocument::LinearGradient(const wxPdfColour& col1, const wxPdfColour& col2,
2129
wxPdfLinearGradientType gradientType)
2131
static double h[] = { 0, 0, 1, 0 };
2132
static double v[] = { 0, 0, 0, 1 };
2133
wxPdfGradient* gradient;
2136
if (ColourSpaceOk(col1, col2))
2138
switch (gradientType)
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);
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);
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);
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);
2152
case wxPDF_LINEAR_GRADIENT_MIDVERTICAL:
2153
gradient = new wxPdfMidAxialGradient(col1, col2, v[0], v[1], v[2], v[3], 0.5, 1);
2155
case wxPDF_LINEAR_GRADIENT_MIDHORIZONTAL:
2156
gradient = new wxPdfMidAxialGradient(col1, col2, h[0], h[1], h[2], h[3], 0.5, 1);
2158
case wxPDF_LINEAR_GRADIENT_VERTICAL:
2159
gradient = new wxPdfAxialGradient(col1, col2, v[0], v[1], v[2], v[3], 1);
2161
case wxPDF_LINEAR_GRADIENT_HORIZONTAL:
2163
gradient = new wxPdfAxialGradient(col1, col2, h[0], h[1], h[2], h[3], 1);
2166
n = (int) (*m_gradients).size()+1;
2167
(*m_gradients)[n] = gradient;
2171
wxLogError(wxString(wxT("wxPdfDocument::LinearGradient: ")) +
2172
wxString(_("Colour spaces do not match.")));
2178
wxPdfDocument::AxialGradient(const wxPdfColour& col1, const wxPdfColour& col2,
2179
double x1, double y1, double x2, double y2,
2183
if (ColourSpaceOk(col1, col2))
2185
n = (int) (*m_gradients).size()+1;
2186
(*m_gradients)[n] = new wxPdfAxialGradient(col1, col2, x1, y1, x2, y2, intexp);
2190
wxLogError(wxString(wxT("wxPdfDocument::AxialGradient: ")) +
2191
wxString(_("Colour spaces do not match.")));
2197
wxPdfDocument::MidAxialGradient(const wxPdfColour& col1, const wxPdfColour& col2,
2198
double x1, double y1, double x2, double y2,
2199
double midpoint, double intexp)
2202
if (ColourSpaceOk(col1, col2))
2204
n = (int) (*m_gradients).size()+1;
2205
(*m_gradients)[n] = new wxPdfMidAxialGradient(col1, col2, x1, y1, x2, y2, midpoint, intexp);
2209
wxLogError(wxString(wxT("wxPdfDocument::MidAxialGradient: ")) +
2210
wxString(_("Colour spaces do not match.")));
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)
2221
if (ColourSpaceOk(col1, col2))
2223
n = (int) (*m_gradients).size()+1;
2224
(*m_gradients)[n] = new wxPdfRadialGradient(col1, col2, x1, y1, r1, x2, y2, r2, intexp);
2228
wxLogError(wxString(wxT("wxPdfDocument::RadialGradient: ")) +
2229
wxString(_("Colour spaces do not match.")));
2235
wxPdfDocument::CoonsPatchGradient(const wxPdfCoonsPatchMesh& mesh, double minCoord, double maxCoord)
2240
n = (int) (*m_gradients).size()+1;
2241
(*m_gradients)[n] = new wxPdfCoonsPatchGradient(mesh, minCoord, maxCoord);
2245
wxLogError(wxString(wxT("wxPdfDocument::CoonsPatchGradient: ")) +
2246
wxString(_("Mesh is invalid.")));
2251
/* draw a marker at a raw point-based coordinate */
2253
wxPdfDocument::Marker(double x, double y, wxPdfMarker markerType, double size)
2255
double saveLineWidth = m_lineWidth;
2256
double halfsize = size * 0.5;
2257
static double b = 4. / 3.;
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);
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);
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);
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);
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);
2302
case wxPDF_MARKER_DIAMOND:
2303
SetLineWidth(size * 0.15);
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);
2312
case wxPDF_MARKER_SQUARE:
2313
SetLineWidth(size * 0.15);
2314
Rect(x - halfsize, y - halfsize, size, size, wxPDF_STYLE_FILLDRAW);
2317
case wxPDF_MARKER_STAR:
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);
2334
case wxPDF_MARKER_STAR4:
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);
2349
case wxPDF_MARKER_PLUS:
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);
2368
case wxPDF_MARKER_CROSS:
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);
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);
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);
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);
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);
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);
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);
2445
case wxPDF_MARKER_ASTERISK:
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);
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);
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);
2480
SetLineWidth(saveLineWidth);
2484
wxPdfDocument::Arrow(double x1, double y1, double x2, double y2, double linewidth, double height, double width)
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;
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")));
2507
SetLineWidth(linewidth);
2508
Line(x1+cosa*linewidth, y1+sina*linewidth, x2-cosa*height, y2-sina*height);
2509
SetLineWidth(saveLineWidth);