1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "dc.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
27 #include "wx/dialog.h"
31 #include "wx/dcprint.h"
32 #include "wx/msw/private.h"
37 #if wxUSE_COMMON_DIALOGS
57 #if !USE_SHARED_LIBRARY
58 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
61 // Declarations local to this file
63 #define YSCALE(y) (yorigin - (y))
65 // #define wx_round(a) (int)((a)+.5)
67 // Default constructor
70 m_minX
= 0; m_minY
= 0; m_maxX
= 0; m_maxY
= 0;
80 m_minX
= 0; m_minY
= 0; m_maxX
= 0; m_maxY
= 0;
85 m_logicalScaleX
= 1.0;
86 m_logicalScaleY
= 1.0;
93 m_mappingMode
= MM_TEXT
;
98 m_windowExtX
= VIEWPORT_EXTENT
;
99 m_windowExtY
= VIEWPORT_EXTENT
;
100 m_logicalFunction
= -1;
102 m_backgroundBrush
= *wxWHITE_BRUSH
;
104 m_textForegroundColour
= *wxBLACK
;
105 m_textBackgroundColour
= *wxWHITE
;
107 m_colour
= wxColourDisplay();
116 SelectOldObjects(m_hDC
);
118 if ( m_canvas
== NULL
)
119 ::DeleteDC((HDC
)m_hDC
);
121 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), (HDC
)m_hDC
);
127 // This will select current objects out of the DC,
128 // which is what you have to do before deleting the
130 void wxDC::SelectOldObjects(WXHDC dc
)
136 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
137 if (m_selectedBitmap
.Ok())
139 m_selectedBitmap
.SetSelectedInto(NULL
);
145 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
150 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
155 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
160 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
);
165 m_brush
= wxNullBrush
;
167 m_palette
= wxNullPalette
;
169 m_backgroundBrush
= wxNullBrush
;
170 m_selectedBitmap
= wxNullBitmap
;
173 void wxDC::SetClippingRegion(long cx
, long cy
, long cw
, long ch
)
178 m_clipX2
= (int)(cx
+ cw
);
179 m_clipY2
= (int)(cy
+ ch
);
181 DoClipping((WXHDC
) m_hDC
);
184 void wxDC::DoClipping(WXHDC dc
)
186 if (m_clipping
&& dc
)
188 IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
),
189 XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
));
193 void wxDC::DestroyClippingRegion(void)
195 if (m_clipping
&& m_hDC
)
197 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
198 SelectClipRgn((HDC
) m_hDC
, rgn
);
204 bool wxDC::CanDrawBitmap(void) const
209 bool wxDC::CanGetTextExtent(void) const
211 // What sort of display is it?
212 int technology
= ::GetDeviceCaps((HDC
) m_hDC
, TECHNOLOGY
);
216 if (technology
!= DT_RASDISPLAY
&& technology
!= DT_RASPRINTER
)
223 void wxDC::SetPalette(const wxPalette
& palette
)
225 // Set the old object temporarily, in case the assignment deletes an object
226 // that's not yet selected out.
229 ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_oldPalette
, TRUE
);
233 m_palette
= m_palette
;
237 // Setting a NULL colourmap is a way of restoring
238 // the original colourmap
241 ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_oldPalette
, TRUE
);
248 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
250 HPALETTE oldPal
= ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
252 m_oldPalette
= (WXHPALETTE
) oldPal
;
254 ::RealizePalette((HDC
) m_hDC
);
258 void wxDC::Clear(void)
262 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
263 else if (m_selectedBitmap
.Ok())
265 rect
.left
= 0; rect
.top
= 0;
266 rect
.right
= m_selectedBitmap
.GetWidth();
267 rect
.bottom
= m_selectedBitmap
.GetHeight();
269 (void) ::SetMapMode((HDC
) m_hDC
, MM_TEXT
);
271 DWORD colour
= GetBkColor((HDC
) m_hDC
);
272 HBRUSH brush
= CreateSolidBrush(colour
);
273 FillRect((HDC
) m_hDC
, &rect
, brush
);
276 ::SetMapMode((HDC
) m_hDC
, MM_ANISOTROPIC
);
277 ::SetViewportExtEx((HDC
) m_hDC
, VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
278 ::SetWindowExtEx((HDC
) m_hDC
, m_windowExtX
, m_windowExtY
, NULL
);
279 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
280 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
283 void wxDC::FloodFill(long x
, long y
, const wxColour
& col
, int style
)
285 (void)ExtFloodFill((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
287 style
==wxFLOOD_SURFACE
?
288 FLOODFILLSURFACE
:FLOODFILLBORDER
291 CalcBoundingBox(x
, y
);
294 bool wxDC::GetPixel(long x
, long y
, wxColour
*col
) const
296 // added by steve 29.12.94 (copied from DrawPoint)
297 // returns TRUE for pixels in the color of the current pen
298 // and FALSE for all other pixels colors
299 // if col is non-NULL return the color of the pixel
301 // get the color of the pixel
302 COLORREF pixelcolor
= ::GetPixel((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
));
303 // get the color of the pen
304 COLORREF pencolor
= 0x00ffffff;
307 pencolor
= m_pen
.GetColour().GetPixel() ;
310 // return the color of the pixel
312 col
->Set(GetRValue(pixelcolor
),GetGValue(pixelcolor
),GetBValue(pixelcolor
));
314 // check, if color of the pixels is the same as the color
315 // of the current pen
316 return(pixelcolor
==pencolor
);
319 void wxDC::CrossHair(long x
, long y
)
321 // We suppose that our screen is 2000x2000 max.
327 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
328 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
), YLOG2DEV(y
));
330 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
331 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y2
));
333 CalcBoundingBox(x1
, y1
);
334 CalcBoundingBox(x2
, y2
);
337 void wxDC::DrawLine(long x1
, long y1
, long x2
, long y2
)
339 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
340 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
), YLOG2DEV(y2
));
342 /* MATTHEW: [6] New normalization */
343 #if WX_STANDARD_GRAPHICS
344 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
347 CalcBoundingBox(x1
, y1
);
348 CalcBoundingBox(x2
, y2
);
351 void wxDC::DrawArc(long x1
,long y1
,long x2
,long y2
, long xc
, long yc
)
355 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
356 if (x1
==x2
&& x2
==y2
)
358 DrawEllipse(xc
,yc
,(double)(radius
*2.0),(double)(radius
*2)) ;
362 long xx1
= XLOG2DEV(x1
) ;
363 long yy1
= YLOG2DEV(y1
) ;
364 long xx2
= XLOG2DEV(x2
) ;
365 long yy2
= YLOG2DEV(y2
) ;
366 long xxc
= XLOG2DEV(xc
) ;
367 long yyc
= YLOG2DEV(yc
) ;
368 long ray
= (long) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
))) ;
370 (void)MoveToEx((HDC
) m_hDC
, (int) xx1
, (int) yy1
, NULL
);
371 long xxx1
= (long) (xxc
-ray
);
372 long yyy1
= (long) (yyc
-ray
);
373 long xxx2
= (long) (xxc
+ray
);
374 long yyy2
= (long) (yyc
+ray
);
375 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
377 // Have to add 1 to bottom-right corner of rectangle
378 // to make semi-circles look right (crooked line otherwise).
379 // Unfortunately this is not a reliable method, depends
380 // on the size of shape.
381 // TODO: figure out why this happens!
382 Pie((HDC
) m_hDC
,xxx1
,yyy1
,xxx2
+1,yyy2
+1,
386 Arc((HDC
) m_hDC
,xxx1
,yyy1
,xxx2
,yyy2
,
389 CalcBoundingBox((xc
-radius
), (yc
-radius
));
390 CalcBoundingBox((xc
+radius
), (yc
+radius
));
393 void wxDC::DrawPoint(long x
, long y
)
395 COLORREF color
= 0x00ffffff;
398 color
= m_pen
.GetColour().GetPixel() ;
401 SetPixel((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), color
);
403 CalcBoundingBox(x
, y
);
406 void wxDC::DrawPolygon(int n
, wxPoint points
[], long xoffset
, long yoffset
,int fillStyle
)
408 // Do things less efficiently if we have offsets
409 if (xoffset
!= 0 || yoffset
!= 0)
411 POINT
*cpoints
= new POINT
[n
];
413 for (i
= 0; i
< n
; i
++)
415 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
416 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
418 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
420 int prev
= SetPolyFillMode((HDC
) m_hDC
,fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
) ;
421 (void)Polygon((HDC
) m_hDC
, cpoints
, n
);
422 SetPolyFillMode((HDC
) m_hDC
,prev
) ;
428 for (i
= 0; i
< n
; i
++)
429 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
431 int prev
= SetPolyFillMode((HDC
) m_hDC
,fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
) ;
432 (void)Polygon((HDC
) m_hDC
, (POINT
*) points
, n
);
433 SetPolyFillMode((HDC
) m_hDC
,prev
) ;
437 void wxDC::DrawLines(int n
, wxPoint points
[], long xoffset
, long yoffset
)
439 // Do things less efficiently if we have offsets
440 if (xoffset
!= 0 || yoffset
!= 0)
442 POINT
*cpoints
= new POINT
[n
];
444 for (i
= 0; i
< n
; i
++)
446 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
447 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
449 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
451 (void)Polyline((HDC
) m_hDC
, cpoints
, n
);
457 for (i
= 0; i
< n
; i
++)
458 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
460 (void)Polyline((HDC
) m_hDC
, (POINT
*) points
, n
);
464 void wxDC::DrawRectangle(long x
, long y
, long width
, long height
)
467 long y2
= y
+ height
;
469 /* MATTHEW: [6] new normalization */
470 #if WX_STANDARD_GRAPHICS
471 bool do_brush
, do_pen
;
473 do_brush
= m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
;
474 do_pen
= m_pen
.Ok() && m_pen
.GetStyle() != wxTRANSPARENT
;
477 HPEN orig_pen
= NULL
;
479 if (do_pen
|| !m_pen
.Ok())
480 orig_pen
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
) ::GetStockObject(NULL_PEN
));
482 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
483 XLOG2DEV(x2
) + 1, YLOG2DEV(y2
) + 1);
485 if (do_pen
|| !m_pen
.Ok())
486 ::SelectObject((HDC
) m_hDC
, orig_pen
);
489 HBRUSH orig_brush
= NULL
;
491 if (do_brush
|| !m_brush
.Ok())
492 orig_brush
= (HBRUSH
) ::SelectObject((HDC
) m_hDC
, (HBRUSH
) ::GetStockObject(NULL_BRUSH
));
494 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
495 XLOG2DEV(x2
), YLOG2DEV(y2
));
497 if (do_brush
|| !m_brush
.Ok())
498 ::SelectObject((HDC
) m_hDC
, orig_brush
);
501 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
504 CalcBoundingBox(x
, y
);
505 CalcBoundingBox(x2
, y2
);
508 void wxDC::DrawRoundedRectangle(long x
, long y
, long width
, long height
, double radius
)
510 // Now, a negative radius value is interpreted to mean
511 // 'the proportion of the smallest X or Y dimension'
515 double smallest
= 0.0;
520 radius
= (- radius
* smallest
);
524 long y2
= (y
+height
);
526 (void)RoundRect((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
527 YLOG2DEV(y2
), 2*XLOG2DEV(radius
), 2*YLOG2DEV(radius
));
529 CalcBoundingBox(x
, y
);
530 CalcBoundingBox(x2
, y2
);
533 void wxDC::DrawEllipse(long x
, long y
, long width
, long height
)
536 long y2
= (y
+height
);
538 (void)Ellipse((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
540 CalcBoundingBox(x
, y
);
541 CalcBoundingBox(x2
, y2
);
544 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
545 void wxDC::DrawEllipticArc(long x
,long y
,long w
,long h
,double sa
,double ea
)
550 const double deg2rad
= 3.14159265359 / 180.0;
551 int rx1
= XLOG2DEV(x
+w
/2);
552 int ry1
= YLOG2DEV(y
+h
/2);
555 rx1
+= (int)(100.0 * abs(w
) * cos(sa
* deg2rad
));
556 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
* deg2rad
));
557 rx2
+= (int)(100.0 * abs(w
) * cos(ea
* deg2rad
));
558 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
* deg2rad
));
560 // draw pie with NULL_PEN first and then outline otherwise a line is
561 // drawn from the start and end points to the centre
562 HPEN orig_pen
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
) ::GetStockObject(NULL_PEN
));
565 (void)Pie((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
570 (void)Pie((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
571 rx1
, ry1
-1, rx2
, ry2
-1);
573 ::SelectObject((HDC
) m_hDC
, orig_pen
);
574 (void)Arc((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
577 CalcBoundingBox(x
, y
);
578 CalcBoundingBox(x2
, y2
);
581 void wxDC::DrawIcon(const wxIcon
& icon
, long x
, long y
)
583 ::DrawIcon((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON());
584 CalcBoundingBox(x
, y
);
585 CalcBoundingBox(x
+icon
.GetWidth(), y
+icon
.GetHeight());
588 void wxDC::SetFont(const wxFont
& the_font
)
590 // Set the old object temporarily, in case the assignment deletes an object
591 // that's not yet selected out.
594 ::SelectObject((HDC
) m_hDC
, (HFONT
) m_oldFont
);
603 ::SelectObject((HDC
) m_hDC
, (HFONT
) m_oldFont
);
607 if (m_font
.Ok() && m_font
.GetResourceHandle())
609 HFONT f
= (HFONT
) ::SelectObject((HDC
) m_hDC
, (HFONT
) m_font
.GetResourceHandle());
612 wxDebugMsg("::SelectObject failed in wxDC::SetFont.");
615 m_oldFont
= (WXHFONT
) f
;
619 void wxDC::SetPen(const wxPen
& pen
)
621 // Set the old object temporarily, in case the assignment deletes an object
622 // that's not yet selected out.
625 ::SelectObject((HDC
) m_hDC
, (HPEN
) m_oldPen
);
634 ::SelectObject((HDC
) m_hDC
, (HPEN
) m_oldPen
);
640 if (m_pen
.GetResourceHandle())
642 HPEN p
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
)m_pen
.GetResourceHandle()) ;
644 m_oldPen
= (WXHPEN
) p
;
649 void wxDC::SetBrush(const wxBrush
& brush
)
651 // Set the old object temporarily, in case the assignment deletes an object
652 // that's not yet selected out.
655 ::SelectObject((HDC
) m_hDC
, (HBRUSH
) m_oldBrush
);
664 ::SelectObject((HDC
) m_hDC
, (HBRUSH
) m_oldBrush
);
670 if (m_brush
.GetResourceHandle())
673 b
= (HBRUSH
) ::SelectObject((HDC
) m_hDC
, (HBRUSH
)m_brush
.GetResourceHandle()) ;
675 m_oldBrush
= (WXHBRUSH
) b
;
680 void wxDC::DrawText(const wxString
& text
, long x
, long y
, bool use16bit
)
682 // Should be unnecessary: SetFont should have done this already.
684 if (m_font
.Ok() && m_font
.GetResourceHandle())
686 HFONT f
= (HFONT
) ::SelectObject((HDC
) m_hDC
, (HFONT
) m_font
.GetResourceHandle());
688 m_oldFont
= (WXHFONT
) f
;
692 if (m_textForegroundColour
.Ok())
693 SetTextColor((HDC
) m_hDC
, m_textForegroundColour
.GetPixel() ) ;
695 DWORD old_background
= 0;
696 if (m_textBackgroundColour
.Ok())
698 old_background
= SetBkColor((HDC
) m_hDC
, m_textBackgroundColour
.GetPixel() ) ;
701 if (m_backgroundMode
== wxTRANSPARENT
)
702 SetBkMode((HDC
) m_hDC
, TRANSPARENT
);
704 SetBkMode((HDC
) m_hDC
, OPAQUE
);
706 (void)TextOut((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (char *) (const char *)text
, strlen((const char *)text
));
708 if (m_textBackgroundColour
.Ok())
709 (void)SetBkColor((HDC
) m_hDC
, old_background
);
711 CalcBoundingBox(x
, y
);
714 GetTextExtent(text
, &w
, &h
);
715 CalcBoundingBox((x
+ w
), (y
+ h
));
718 void wxDC::SetBackground(const wxBrush
& brush
)
720 m_backgroundBrush
= brush
;
722 if (!m_backgroundBrush
.Ok())
727 bool customColours
= TRUE
;
728 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
729 // change background colours from the control-panel specified colours.
730 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
731 customColours
= FALSE
;
735 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
737 m_canvas
->m_backgroundTransparent
= TRUE
;
741 m_canvas
->SetBackgroundColour(m_backgroundBrush
.GetColour());
742 m_canvas
->m_backgroundTransparent
= FALSE
;
746 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel() ;
748 (void)SetBkColor((HDC
) m_hDC
, new_color
);
752 void wxDC::SetBackgroundMode(int mode
)
754 m_backgroundMode
= mode
;
756 if (m_backgroundMode
== wxTRANSPARENT
)
757 ::SetBkMode((HDC
) m_hDC
, TRANSPARENT
);
759 ::SetBkMode((HDC
) m_hDC
, OPAQUE
);
762 void wxDC::SetLogicalFunction(int function
)
764 m_logicalFunction
= function
;
766 SetRop((WXHDC
) m_hDC
);
769 void wxDC::SetRop(WXHDC dc
)
771 if (!dc
|| m_logicalFunction
< 0)
775 // These may be wrong
776 switch (m_logicalFunction
)
778 // case wxXOR: c_rop = R2_XORPEN; break;
779 case wxXOR
: c_rop
= R2_NOTXORPEN
; break;
780 case wxINVERT
: c_rop
= R2_NOT
; break;
781 case wxOR_REVERSE
: c_rop
= R2_MERGEPENNOT
; break;
782 case wxAND_REVERSE
: c_rop
= R2_MASKPENNOT
; break;
783 case wxCLEAR
: c_rop
= R2_WHITE
; break;
784 case wxSET
: c_rop
= R2_BLACK
; break;
785 case wxSRC_INVERT
: c_rop
= R2_NOTCOPYPEN
; break;
786 case wxOR_INVERT
: c_rop
= R2_MERGENOTPEN
; break;
787 case wxAND
: c_rop
= R2_MASKPEN
; break;
788 case wxOR
: c_rop
= R2_MERGEPEN
; break;
789 case wxAND_INVERT
: c_rop
= R2_MASKNOTPEN
; break;
794 c_rop
= R2_COPYPEN
; break;
796 SetROP2((HDC
) dc
, c_rop
);
799 bool wxDC::StartDoc(const wxString
& message
)
801 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
805 docinfo
.cbSize
= sizeof(DOCINFO
);
806 docinfo
.lpszDocName
= (const char *)message
;
808 if (m_filename
.IsEmpty())
809 docinfo
.lpszOutput
= NULL
;
811 docinfo
.lpszOutput
= (const char *)m_filename
;
813 #if defined(__WIN95__)
814 docinfo
.lpszDatatype
= NULL
;
823 ::StartDoc((HDC
) m_hDC
, &docinfo
);
826 ::StartDocW((HDC
) m_hDC
, &docinfo
);
828 ::StartDocA((HDC
) m_hDC
, &docinfo
);
834 DWORD lastError
= GetLastError();
835 wxDebugMsg("wxDC::StartDoc failed with error: %d\n", lastError
);
840 void wxDC::EndDoc(void)
842 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
844 if (m_hDC
) ::EndDoc((HDC
) m_hDC
);
847 void wxDC::StartPage(void)
849 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
852 ::StartPage((HDC
) m_hDC
);
855 void wxDC::EndPage(void)
857 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
860 ::EndPage((HDC
) m_hDC
);
863 long wxDC::GetCharHeight(void) const
865 TEXTMETRIC lpTextMetric
;
867 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
869 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
872 long wxDC::GetCharWidth(void) const
874 TEXTMETRIC lpTextMetric
;
876 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
878 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
881 void wxDC::GetTextExtent(const wxString
& string
, long *x
, long *y
,
882 long *descent
, long *externalLeading
, wxFont
*theFont
, bool use16bit
) const
884 wxFont
*fontToUse
= (wxFont
*) theFont
;
886 fontToUse
= (wxFont
*) &m_font
;
891 GetTextExtentPoint((HDC
) m_hDC
, (char *)(const char *) string
, strlen((char *)(const char *) string
), &sizeRect
);
892 GetTextMetrics((HDC
) m_hDC
, &tm
);
894 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
895 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
896 if (descent
) *descent
= tm
.tmDescent
;
897 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
900 void wxDC::SetMapMode(int mode
)
902 m_mappingMode
= mode
;
905 int pixel_height
= 0;
909 pixel_width
= GetDeviceCaps((HDC
) m_hDC
, HORZRES
);
910 pixel_height
= GetDeviceCaps((HDC
) m_hDC
, VERTRES
);
911 mm_width
= GetDeviceCaps((HDC
) m_hDC
, HORZSIZE
);
912 mm_height
= GetDeviceCaps((HDC
) m_hDC
, VERTSIZE
);
914 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
919 double mm2pixelsX
= pixel_width
/mm_width
;
920 double mm2pixelsY
= pixel_height
/mm_height
;
926 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
927 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
932 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
933 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
938 m_logicalScaleX
= mm2pixelsX
;
939 m_logicalScaleY
= mm2pixelsY
;
944 m_logicalScaleX
= (mm2pixelsX
/10.0);
945 m_logicalScaleY
= (mm2pixelsY
/10.0);
951 m_logicalScaleX
= 1.0;
952 m_logicalScaleY
= 1.0;
957 if (::GetMapMode((HDC
) m_hDC
) != MM_ANISOTROPIC
)
958 ::SetMapMode((HDC
) m_hDC
, MM_ANISOTROPIC
);
960 SetViewportExtEx((HDC
) m_hDC
, VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
961 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
962 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
963 ::SetWindowExtEx((HDC
) m_hDC
, m_windowExtX
, m_windowExtY
, NULL
);
964 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
965 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
968 void wxDC::SetUserScale(double x
, double y
)
973 SetMapMode(m_mappingMode
);
976 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
978 m_signX
= xLeftRight
? 1 : -1;
979 m_signY
= yBottomUp
? -1 : 1;
981 SetMapMode(m_mappingMode
);
984 void wxDC::SetSystemScale(double x
, double y
)
989 SetMapMode(m_mappingMode
);
992 void wxDC::SetLogicalOrigin(long x
, long y
)
994 m_logicalOriginX
= x
;
995 m_logicalOriginY
= y
;
997 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1000 void wxDC::SetDeviceOrigin(long x
, long y
)
1002 m_deviceOriginX
= x
;
1003 m_deviceOriginY
= y
;
1005 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1008 long wxDC::DeviceToLogicalX(long x
) const
1010 return (long) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) - m_logicalOriginX
) ;
1013 long wxDC::DeviceToLogicalXRel(long x
) const
1015 return (long) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
)) ;
1018 long wxDC::DeviceToLogicalY(long y
) const
1020 return (long) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) - m_logicalOriginY
) ;
1023 long wxDC::DeviceToLogicalYRel(long y
) const
1025 return (long) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
)) ;
1028 long wxDC::LogicalToDeviceX(long x
) const
1030 return (long) (floor((x
) - m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
+ m_deviceOriginX
) ;
1033 long wxDC::LogicalToDeviceXRel(long x
) const
1035 return (long) (floor(x
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) ;
1038 long wxDC::LogicalToDeviceY(long y
) const
1040 return (long) (floor((y
) - m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
+ m_deviceOriginY
);
1043 long wxDC::LogicalToDeviceYRel(long y
) const
1045 return (long) (floor(y
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) ;
1048 // This group of functions may not do any conversion
1049 // if m_scaleGDI is TRUE, since the HDC does the
1050 // conversion automatically.
1052 long wxDC::ImplDeviceToLogicalX(long x
) const
1054 // return (m_scaleGDI ? x : DeviceToLogicalX(x));
1058 long wxDC::ImplDeviceToLogicalY(long y
) const
1060 // return (m_scaleGDI ? y : DeviceToLogicalY(y));
1064 long wxDC::ImplDeviceToLogicalXRel(long x
) const
1066 // return (m_scaleGDI ? x : DeviceToLogicalXRel(x));
1070 long wxDC::ImplDeviceToLogicalYRel(long y
) const
1072 // return (m_scaleGDI ? y : DeviceToLogicalYRel(y));
1076 long wxDC::ImplLogicalToDeviceX(long x
) const
1078 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceX(x));
1082 long wxDC::ImplLogicalToDeviceY(long y
) const
1084 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceY(y));
1088 long wxDC::ImplLogicalToDeviceXRel(long x
) const
1090 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceXRel(x));
1094 long wxDC::ImplLogicalToDeviceYRel(long y
) const
1096 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceYRel(y));
1100 bool wxDC::Blit(long xdest
, long ydest
, long width
, long height
,
1101 wxDC
*source
, long xsrc
, long ysrc
, int rop
, bool useMask
)
1103 long xdest1
= xdest
;
1104 long ydest1
= ydest
;
1108 // Chris Breeze 18/5/98: use text foreground/background colours
1109 // when blitting from 1-bit bitmaps
1110 COLORREF old_textground
= ::GetTextColor((HDC
)m_hDC
);
1111 COLORREF old_background
= ::GetBkColor((HDC
)m_hDC
);
1112 if (m_textForegroundColour
.Ok())
1114 ::SetTextColor((HDC
) m_hDC
, m_textForegroundColour
.GetPixel() ) ;
1116 if (m_textBackgroundColour
.Ok())
1118 ::SetBkColor((HDC
) m_hDC
, m_textBackgroundColour
.GetPixel() ) ;
1121 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1122 rop
== wxCLEAR
? WHITENESS
:
1123 rop
== wxSET
? BLACKNESS
:
1124 rop
== wxINVERT
? DSTINVERT
:
1125 rop
== wxAND
? MERGECOPY
:
1126 rop
== wxOR
? MERGEPAINT
:
1127 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1128 rop
== wxXOR
? SRCINVERT
:
1129 rop
== wxOR_REVERSE
? MERGEPAINT
:
1130 rop
== wxAND_REVERSE
? SRCERASE
:
1131 rop
== wxSRC_OR
? SRCPAINT
:
1132 rop
== wxSRC_AND
? SRCAND
:
1135 bool success
= TRUE
;
1136 if (useMask
&& source
->m_selectedBitmap
.Ok() && source
->m_selectedBitmap
.GetMask())
1140 // Not implemented under Win95 (or maybe a specific device?)
1141 if (MaskBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1142 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap(),
1152 HDC dc_mask
= CreateCompatibleDC((HDC
) source
->m_hDC
);
1153 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1154 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1155 dc_mask
, xsrc1
, ysrc1
, 0x00220326 /* NOTSRCAND */) != 0);
1156 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1157 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, SRCPAINT
) != 0);
1158 ::SelectObject(dc_mask
, 0);
1159 ::DeleteDC(dc_mask
);
1161 // New code from Chris Breeze, 15/7/98
1162 // Blit bitmap with mask
1164 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1166 // If we are printing source colours are screen colours
1167 // not printer colours and so we need copy the bitmap
1170 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1171 HDC dc_src
= (HDC
) source
->m_hDC
;
1173 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1174 for (int x
= 0; x
< width
; x
++)
1176 for (int y
= 0; y
< height
; y
++)
1178 COLORREF cref
= ::GetPixel(dc_mask
, x
, y
);
1181 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1182 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1183 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1184 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1185 ::DeleteObject(brush
);
1189 ::SelectObject(dc_mask
, 0);
1190 ::DeleteDC(dc_mask
);
1194 // create a temp buffer bitmap and DCs to access it and the mask
1195 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1196 HDC dc_buffer
= ::CreateCompatibleDC((HDC
) m_hDC
);
1197 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap((HDC
) m_hDC
, width
, height
);
1198 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1199 ::SelectObject(dc_buffer
, buffer_bmap
);
1201 // copy dest to buffer
1202 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1203 (HDC
) m_hDC
, xdest1
, ydest1
, SRCCOPY
);
1205 // copy src to buffer using selected raster op
1206 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1207 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, dwRop
);
1209 // set masked area in buffer to BLACK (pixel value 0)
1210 COLORREF prevBkCol
= ::SetBkColor((HDC
) m_hDC
, RGB(255, 255, 255));
1211 COLORREF prevCol
= ::SetTextColor((HDC
) m_hDC
, RGB(0, 0, 0));
1212 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1213 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1215 // set unmasked area in dest to BLACK
1216 ::SetBkColor((HDC
) m_hDC
, RGB(0, 0, 0));
1217 ::SetTextColor((HDC
) m_hDC
, RGB(255, 255, 255));
1218 ::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1219 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1220 ::SetBkColor((HDC
) m_hDC
, prevBkCol
); // restore colours to original values
1221 ::SetTextColor((HDC
) m_hDC
, prevCol
);
1223 // OR buffer to dest
1224 success
= (::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1225 dc_buffer
, 0, 0, SRCPAINT
) != 0);
1227 // tidy up temporary DCs and bitmap
1228 ::SelectObject(dc_mask
, 0);
1229 ::DeleteDC(dc_mask
);
1230 ::SelectObject(dc_buffer
, 0);
1231 ::DeleteDC(dc_buffer
);
1232 ::DeleteObject(buffer_bmap
);
1238 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1240 // If we are printing source colours are screen colours
1241 // not printer colours and so we need copy the bitmap
1243 HDC dc_src
= (HDC
) source
->m_hDC
;
1245 for (int x
= 0; x
< width
; x
++)
1247 for (int y
= 0; y
< height
; y
++)
1249 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1250 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1251 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1252 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1253 ::DeleteObject(brush
);
1259 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
, (HDC
) source
->m_hDC
,
1260 xsrc1
, ysrc1
, dwRop
) != 0);
1263 ::SetTextColor((HDC
)m_hDC
, old_textground
);
1264 ::SetBkColor((HDC
)m_hDC
, old_background
);
1269 void wxDC::GetSize(int* width
, int* height
) const
1271 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZRES
);
1272 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTRES
);
1277 void wxDC::GetSizeMM(long *width
, long *height
) const
1279 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZSIZE
);
1280 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTSIZE
);
1285 void wxDC::DrawPolygon(wxList
*list
, long xoffset
, long yoffset
,int fillStyle
)
1287 int n
= list
->Number();
1288 wxPoint
*points
= new wxPoint
[n
];
1291 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1292 wxPoint
*point
= (wxPoint
*)node
->Data();
1293 points
[i
].x
= point
->x
;
1294 points
[i
++].y
= point
->y
;
1296 DrawPolygon(n
, points
, xoffset
, yoffset
,fillStyle
);
1300 void wxDC::DrawLines(wxList
*list
, long xoffset
, long yoffset
)
1302 int n
= list
->Number();
1303 wxPoint
*points
= new wxPoint
[n
];
1306 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1307 wxPoint
*point
= (wxPoint
*)node
->Data();
1308 points
[i
].x
= point
->x
;
1309 points
[i
++].y
= point
->y
;
1311 DrawLines(n
, points
, xoffset
, yoffset
);
1315 void wxDC::SetTextForeground(const wxColour
& colour
)
1317 m_textForegroundColour
= colour
;
1320 void wxDC::SetTextBackground(const wxColour
& colour
)
1322 m_textBackgroundColour
= colour
;
1325 // For use by wxWindows only, unless custom units are required.
1326 void wxDC::SetLogicalScale(double x
, double y
)
1328 m_logicalScaleX
= x
;
1329 m_logicalScaleY
= y
;
1332 void wxDC::CalcBoundingBox(long x
, long y
)
1334 if (x
< m_minX
) m_minX
= x
;
1335 if (y
< m_minY
) m_minY
= y
;
1336 if (x
> m_maxX
) m_maxX
= x
;
1337 if (y
> m_maxY
) m_maxY
= y
;
1340 void wxDC::GetClippingBox(long *x
,long *y
,long *w
,long *h
) const
1346 *w
= (m_clipX2
- m_clipX1
) ;
1347 *h
= (m_clipY2
- m_clipY1
) ;
1350 *x
= *y
= *w
= *h
= 0 ;
1353 #if WXWIN_COMPATIBILITY
1354 void wxDC::GetTextExtent(const wxString
& string
, float *x
, float *y
,
1355 float *descent
, float *externalLeading
,
1356 wxFont
*theFont
, bool use16bit
) const
1358 long x1
, y1
, descent1
, externalLeading1
;
1359 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1362 *descent
= descent1
;
1363 if (externalLeading
)
1364 *externalLeading
= externalLeading1
;
1368 int wxDC::GetDepth(void) const
1370 return (int) ::GetDeviceCaps((HDC
) m_hDC
,BITSPIXEL
);
1375 // Make a 3-point spline
1376 void wxDC::DrawSpline(long x1
, long y1
, long x2
, long y2
, long x3
, long y3
)
1378 wxList
*point_list
= new wxList
;
1380 wxPoint
*point1
= new wxPoint
;
1381 point1
->x
= x1
; point1
->y
= y1
;
1382 point_list
->Append((wxObject
*)point1
);
1384 wxPoint
*point2
= new wxPoint
;
1385 point2
->x
= x2
; point2
->y
= y2
;
1386 point_list
->Append((wxObject
*)point2
);
1388 wxPoint
*point3
= new wxPoint
;
1389 point3
->x
= x3
; point3
->y
= y3
;
1390 point_list
->Append((wxObject
*)point3
);
1392 DrawSpline(point_list
);
1394 for(wxNode
*node
= point_list
->First(); node
; node
= node
->Next()) {
1395 wxPoint
*p
= (wxPoint
*)node
->Data();
1401 ////#define wx_round(a) (int)((a)+.5)
1402 //#define wx_round(a) (a)
1404 class wxSpline
: public wxObject
1410 wxSpline(wxList
*list
);
1411 void DeletePoints(void);
1413 // Doesn't delete points
1417 void wxDC::DrawSpline(int n
, wxPoint points
[])
1421 for (i
=0; i
< n
; i
++)
1422 list
.Append((wxObject
*)&points
[i
]);
1423 DrawSpline((wxList
*)&list
);
1426 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1428 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1429 double a3
, double b3
, double a4
, double b4
);
1430 void wx_clear_stack(void);
1431 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1432 double *y3
, double *x4
, double *y4
);
1433 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1434 double x4
, double y4
);
1435 static bool wx_spline_add_point(double x
, double y
);
1436 static void wx_spline_draw_point_array(wxDC
*dc
);
1437 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1439 void wxDC::DrawSpline(wxList
*list
)
1441 wxSpline
spline(list
);
1443 wx_draw_open_spline(this, &spline
);
1447 wxList wx_spline_point_list
;
1449 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1452 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1453 double x1
, y1
, x2
, y2
;
1455 wxNode
*node
= spline
->points
->First();
1456 p
= (wxPoint
*)node
->Data();
1461 node
= node
->Next();
1462 p
= (wxPoint
*)node
->Data();
1466 cx1
= (double)((x1
+ x2
) / 2);
1467 cy1
= (double)((y1
+ y2
) / 2);
1468 cx2
= (double)((cx1
+ x2
) / 2);
1469 cy2
= (double)((cy1
+ y2
) / 2);
1471 wx_spline_add_point(x1
, y1
);
1473 while ((node
= node
->Next()) != NULL
)
1475 p
= (wxPoint
*)node
->Data();
1480 cx4
= (double)(x1
+ x2
) / 2;
1481 cy4
= (double)(y1
+ y2
) / 2;
1482 cx3
= (double)(x1
+ cx4
) / 2;
1483 cy3
= (double)(y1
+ cy4
) / 2;
1485 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1489 cx2
= (double)(cx1
+ x2
) / 2;
1490 cy2
= (double)(cy1
+ y2
) / 2;
1493 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1494 wx_spline_add_point(x2
, y2
);
1496 wx_spline_draw_point_array(dc
);
1500 /********************* CURVES FOR SPLINES *****************************
1502 The following spline drawing routine is from
1504 "An Algorithm for High-Speed Curve Generation"
1505 by George Merrill Chaikin,
1506 Computer Graphics and Image Processing, 3, Academic Press,
1511 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1512 Computer Graphics and Image Processing, 4, Academic Press,
1515 ***********************************************************************/
1517 #define half(z1, z2) ((z1+z2)/2.0)
1520 /* iterative version */
1522 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1525 register double xmid
, ymid
;
1526 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1529 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1531 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1532 xmid
= (double)half(x2
, x3
);
1533 ymid
= (double)half(y2
, y3
);
1534 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1535 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1536 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1537 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1539 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1540 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1541 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1542 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1548 /* utilities used by spline drawing routines */
1551 typedef struct wx_spline_stack_struct
{
1552 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1556 #define SPLINE_STACK_DEPTH 20
1557 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1558 static Stack
*wx_stack_top
;
1559 static int wx_stack_count
;
1561 void wx_clear_stack(void)
1563 wx_stack_top
= wx_spline_stack
;
1567 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1569 wx_stack_top
->x1
= x1
;
1570 wx_stack_top
->y1
= y1
;
1571 wx_stack_top
->x2
= x2
;
1572 wx_stack_top
->y2
= y2
;
1573 wx_stack_top
->x3
= x3
;
1574 wx_stack_top
->y3
= y3
;
1575 wx_stack_top
->x4
= x4
;
1576 wx_stack_top
->y4
= y4
;
1581 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1582 double *x3
, double *y3
, double *x4
, double *y4
)
1584 if (wx_stack_count
== 0)
1588 *x1
= wx_stack_top
->x1
;
1589 *y1
= wx_stack_top
->y1
;
1590 *x2
= wx_stack_top
->x2
;
1591 *y2
= wx_stack_top
->y2
;
1592 *x3
= wx_stack_top
->x3
;
1593 *y3
= wx_stack_top
->y3
;
1594 *x4
= wx_stack_top
->x4
;
1595 *y4
= wx_stack_top
->y4
;
1599 static bool wx_spline_add_point(double x
, double y
)
1601 wxPoint
*point
= new wxPoint
;
1604 wx_spline_point_list
.Append((wxObject
*)point
);
1608 static void wx_spline_draw_point_array(wxDC
*dc
)
1610 dc
->DrawLines(&wx_spline_point_list
, (double)0.0, (double)0.0);
1611 wxNode
*node
= wx_spline_point_list
.First();
1614 wxPoint
*point
= (wxPoint
*)node
->Data();
1617 node
= wx_spline_point_list
.First();
1621 wxSpline::wxSpline(wxList
*list
)
1626 wxSpline::~wxSpline(void)
1630 void wxSpline::DeletePoints(void)
1632 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1634 wxPoint
*point
= (wxPoint
*)node
->Data();
1642 #endif // wxUSE_SPLINES