Back to index

plt-scheme  4.2.1
DC.cc
Go to the documentation of this file.
00001 /*                                                      -*- C++ -*-
00002  *
00003  * Purpose: basic device context
00004  *
00005  * Authors: Markus Holzem and Julian Smart
00006  *
00007  * Copyright: (C) 2004-2009 PLT Scheme Inc.
00008  * Copyright: (C) 1995, AIAI, University of Edinburgh (Julian)
00009  * Copyright: (C) 1995, GNU (Markus)
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00024  * 02110-1301 USA.
00025  */
00026 
00027 #ifdef __GNUG__
00028 #pragma implementation "DC.h"
00029 #endif
00030 
00031 #define  Uses_wxDC
00032 #define  Uses_wxList
00033 #include "wx.h"
00034 
00035 #include <math.h>
00036 
00037 //-----------------------------------------------------------------------------
00038 // create and destroy wxDC
00039 //-----------------------------------------------------------------------------
00040 
00041 wxDC::wxDC(void)
00042 {
00043     wxColour *c;
00044 
00045     __type = wxTYPE_DC;
00046 
00047     device = wxDEVICE_NONE;
00048 
00049     auto_setting = optimize = ok = Colour = FALSE;
00050 
00051     mm_to_pix_x = mm_to_pix_y = 1.0; // to be safe
00052     device_origin_x = device_origin_y = 0.0;
00053     logical_scale_x = logical_scale_y
00054        = user_scale_x = user_scale_y
00055        = scale_x = scale_y = 1.0;
00056 
00057     c = new wxColour(wxWHITE);
00058     current_background_color = c;
00059     current_brush = wxTRANSPARENT_BRUSH;
00060     current_cmap = wxAPP_COLOURMAP;
00061     current_font = wxSWISS_FONT;
00062     current_map_mode = MM_TEXT;
00063     current_pen = wxBLACK_PEN;
00064     current_text_alignment = wxALIGN_TOP_LEFT;
00065     c = new wxColour(wxWHITE);
00066     current_text_bg = c;
00067     current_text_bgmode = wxTRANSPARENT;
00068     c = new wxColour(wxBLACK);
00069     current_text_fg = c;
00070     anti_alias = 0;
00071     current_alpha = 1.0;
00072 }
00073 
00074 wxColour *wxDC::GetBackground(void){
00075   wxColour *c;
00076   c = new wxColour();
00077   c->CopyFrom(current_background_color);
00078   return c;
00079 }
00080 
00081 
00082 #ifdef USE_GL
00083 wxGL *wxDC::GetGL()
00084 {
00085   return NULL;
00086 }
00087 #endif
00088 
00089 //-----------------------------------------------------------------------------
00090 // Set scale and origin
00091 //-----------------------------------------------------------------------------
00092 
00093 void wxDC::ComputeScaleAndOrigin(void)
00094 {
00095     scale_x =  logical_scale_x * user_scale_x;
00096     scale_y =  logical_scale_y * user_scale_y;
00097 }
00098 
00099 void wxDC::SetDeviceOrigin(double x, double y)
00100 {
00101     device_origin_x = x;
00102     device_origin_y = y;
00103     ComputeScaleAndOrigin();
00104 }
00105 
00106 void wxDC::SetLogicalScale(double xs, double ys)
00107 {
00108     logical_scale_x = xs;
00109     logical_scale_y = ys;
00110     ComputeScaleAndOrigin();
00111 }
00112 
00113 void wxDC::SetMapMode(int mode)
00114 {
00115     switch (mode) {
00116     case MM_TWIPS:
00117        SetLogicalScale(twips2mm*mm_to_pix_x, twips2mm*mm_to_pix_y);
00118        break;
00119     case MM_POINTS:
00120        SetLogicalScale(pt2mm*mm_to_pix_x, pt2mm*mm_to_pix_y);
00121        break;
00122     case MM_METRIC:
00123        SetLogicalScale(mm_to_pix_x, mm_to_pix_y);
00124        break;
00125     case MM_LOMETRIC:
00126        SetLogicalScale(mm_to_pix_x/10.0, mm_to_pix_y/10.0);
00127        break;
00128     default:
00129     case MM_TEXT:
00130        SetLogicalScale(1.0, 1.0);
00131        break;
00132     }
00133 }
00134 
00135 void wxDC::SetUserScale(double xs, double ys)
00136 {
00137     user_scale_x = xs;
00138     user_scale_y = ys;
00139     ComputeScaleAndOrigin();
00140     SetFont(current_font);
00141     SetPen(current_pen);
00142 }
00143 
00144 //-----------------------------------------------------------------------------
00145 // lines via list
00146 //-----------------------------------------------------------------------------
00147 
00148 static wxPoint *PointListToArray(wxList *list, int n)
00149 {
00150   int i = 0;
00151   wxPoint *points;
00152   wxPoint *point;
00153   wxNode *node;
00154 
00155   points = new WXGC_ATOMIC wxPoint[n];
00156 
00157   for (node = list->First(); node; node = node->Next()) {
00158     point = (wxPoint *)(node->Data());
00159     points[i].x = point->x;
00160     points[i++].y = point->y;
00161   }
00162 
00163   return points;
00164 }
00165 
00166 void wxDC::DrawLines(wxList *list, double xoffset, double yoffset)
00167 {
00168   int n;
00169   wxPoint *points;
00170 
00171   n = list->Number();
00172   points = PointListToArray(list, n);
00173 
00174   DrawLines(n, points, xoffset, yoffset);
00175 }
00176 
00177 void wxDC::DrawPolygon(wxList *list, double xoffset, double yoffset,int fillStyle)
00178 {
00179   int n;
00180   wxPoint *points;
00181 
00182   n = list->Number();
00183   points = PointListToArray(list, n);
00184 
00185   DrawPolygon(n, points, xoffset, yoffset, fillStyle);
00186 }
00187 
00188 //-----------------------------------------------------------------------------
00189 // spline code, uses protected virtual method DrawOpenSpline, from XFIG
00190 //-----------------------------------------------------------------------------
00191 
00192 /*
00193  * FIG : Facility for Interactive Generation of figures
00194  * Copyright (c) 1985 by Supoj Sutanthavibul
00195  */
00196 
00197 void wxDC::DrawSpline(int n, wxPoint pts[])
00198 {
00199     wxList *list;
00200     list = new wxList;
00201     for (int i=0; i<n; ++i) {
00202       list->Append((wxObject*)&pts[i]);
00203     }
00204     DrawSpline(list);
00205     DELETE_OBJ list;
00206 }
00207 
00208 void wxDC::DrawSpline(wxList *pts)
00209 {
00210     DrawOpenSpline(pts);
00211 }
00212 
00213 void wxDC::DrawSpline(double x1, double y1, double x2, double y2,
00214                     double x3,double y3)
00215 {
00216     wxList *list;
00217     wxPoint *point1, *point2, *point3;
00218 
00219     list = new wxList;
00220 
00221     point1 = new wxPoint;
00222     point1->x = x1; point1->y = y1;
00223     list->Append((wxObject*)point1);
00224 
00225     point2 = new wxPoint;
00226     point2->x = x2; point2->y = y2;
00227     list->Append((wxObject*)point2);
00228 
00229     point3 = new wxPoint;
00230     point3->x = x3; point3->y = y3;
00231     list->Append((wxObject*)point3);
00232 
00233     DrawSpline(list);
00234 
00235     DELETE_OBJ list;
00236 }
00237 
00238 //-----------------------------------------------------------------------------
00239 
00240 int wxDC::GetAntiAlias()
00241 {
00242   return anti_alias;
00243 }
00244 
00245 void wxDC::SetAntiAlias(int v)
00246 {
00247   if (Colour)
00248     anti_alias = v;
00249 }
00250 
00251 void wxDC::SetAlpha(double a)
00252 {
00253   current_alpha = a;
00254 }
00255 
00256 double wxDC::GetAlpha()
00257 {
00258   return current_alpha;
00259 }
00260 
00261 int wxDC::CacheFontMetricsKey()
00262 {
00263   return 0;
00264 }
00265 
00266 //-----------------------------------------------------------------------------
00267 // wxDC::DrawOpenSpline(wxList *pts), may be virtually overridden by any child
00268 //-----------------------------------------------------------------------------
00269 
00270 // defines and static declarations for DrawOpenSpline
00271 
00272 #define half(z1,z2)  (double)((z1+z2)/2.0)
00273 
00274 static void wx_quadratic_spline(double a1, double b1, double a2, double b2,
00275                             double a3, double b3, double a4, double b4);
00276 static void wx_clear_stack(void);
00277 static int  wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
00278                        double *x3, double *y3, double *x4, double *y4);
00279 static void wx_spline_push(double x1, double y1, double x2, double y2,
00280                         double x3, double y3, double x4, double y4);
00281 static Bool wx_spline_add_point(double x, double y);
00282 static void wx_spline_draw_point_array(wxDC *dc);
00283 
00284 static wxList *wx_spline_point_list;
00285 
00286 void wxDC::DrawOpenSpline(wxList *pts)
00287 {
00288     wxPoint *p;
00289     double  cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
00290     double  x1,  y1,  x2 , y2;
00291     wxNode *node;
00292 
00293     node = pts->First();
00294     p = (wxPoint*)node->Data();
00295     x1 = p->x; y1 = p->y;
00296 
00297     node = node->Next();
00298     p = (wxPoint *)node->Data();
00299     x2 = p->x; y2 = p->y;
00300 
00301     cx1 = half(x1, x2);  cy1 = half(y1, y2);
00302     cx2 = half(cx1, x2); cy2 = half(cy1, y2);
00303 
00304     wx_spline_add_point(x1, y1);
00305 
00306     while ((node=node->Next()) != NULL) {
00307         p = (wxPoint*)node->Data();
00308        x1  = x2;           y1  = y2;
00309        x2  = p->x;         y2  = p->y;
00310         cx4 = half(x1, x2);   cy4 = half(y1, y2);
00311         cx3 = half(x1, cx4);  cy3 = half(y1, cy4);
00312 
00313         wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
00314 
00315        cx1 = cx4;          cy1 = cy4;
00316         cx2 = half(cx1, x2);  cy2 = half(cy1, y2);
00317     }
00318     wx_spline_add_point(cx1, cy1);
00319     wx_spline_add_point(x2, y2);
00320     wx_spline_draw_point_array(this);
00321 }
00322 
00323 /********************* CURVES FOR SPLINES *****************************
00324 
00325        The following spline drawing routine is from
00326 
00327        "An Algorithm for High-Speed Curve Generation"
00328        by George Merrill Chaikin,
00329        Computer Graphics and Image Processing, 3, Academic Press,
00330        1974, 346-349.
00331 
00332        and
00333 
00334        "On Chaikin's Algorithm" by R. F. Riesenfeld,
00335        Computer Graphics and Image Processing, 4, Academic Press,
00336        1975, 304-310.
00337 
00338 ***********************************************************************/
00339 
00340 #define THRESHOLD 5
00341 
00342 /* iterative version */
00343 
00344 static void wx_quadratic_spline(double a1, double b1, double a2, double b2,
00345                             double a3, double b3, double a4, double b4)
00346 {
00347     register double  xmid, ymid;
00348     double           x1, y1, x2, y2, x3, y3, x4, y4;
00349     int             counter = 10000; /* At most this many points */
00350 
00351     wx_clear_stack();
00352     wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
00353 
00354     while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
00355         if (!counter--)
00356          break;
00357         xmid = half(x2, x3);
00358         ymid = half(y2, y3);
00359        if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
00360            fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
00361          wx_spline_add_point(x1, y1);
00362          wx_spline_add_point(xmid, ymid);
00363        } else {
00364          wx_spline_push(xmid, ymid, half(xmid, x3), half(ymid, y3),
00365                       half(x3, x4), half(y3, y4), x4, y4);
00366          wx_spline_push(x1, y1, half(x1, x2), half(y1, y2),
00367                       half(x2, xmid), half(y2, ymid), xmid, ymid);
00368        }
00369     }
00370 }
00371 
00372 // utilities used by spline drawing routines
00373 
00374 typedef struct wx_spline_stack_struct {
00375     double  x1, y1, x2, y2, x3, y3, x4, y4;
00376 } Stack;
00377 
00378 #define SPLINE_STACK_DEPTH  20
00379 static Stack  wx_spline_stack[SPLINE_STACK_DEPTH];
00380 static Stack  *wx_stack_top;
00381 static int    wx_stack_count;
00382 
00383 static void wx_clear_stack(void)
00384 {
00385     wx_stack_top = wx_spline_stack;
00386     wx_stack_count = 0;
00387 }
00388 
00389 static void wx_spline_push(double x1, double y1, double x2, double y2,
00390                         double x3, double y3, double x4, double y4)
00391 {
00392     if (wx_stack_count >= SPLINE_STACK_DEPTH) {
00393       /* Just drop it. */
00394       return;
00395     }
00396 
00397     wx_stack_top->x1 = x1;    wx_stack_top->y1 = y1;
00398     wx_stack_top->x2 = x2;    wx_stack_top->y2 = y2;
00399     wx_stack_top->x3 = x3;    wx_stack_top->y3 = y3;
00400     wx_stack_top->x4 = x4;    wx_stack_top->y4 = y4;
00401     wx_stack_top++;
00402     wx_stack_count++;
00403 }
00404 
00405 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
00406                   double *x3, double *y3, double *x4, double *y4)
00407 {
00408     if (wx_stack_count == 0)
00409        return (0);
00410     wx_stack_top--;
00411     wx_stack_count--;
00412     *x1 = wx_stack_top->x1;    *y1 = wx_stack_top->y1;
00413     *x2 = wx_stack_top->x2;    *y2 = wx_stack_top->y2;
00414     *x3 = wx_stack_top->x3;    *y3 = wx_stack_top->y3;
00415     *x4 = wx_stack_top->x4;    *y4 = wx_stack_top->y4;
00416     return (1);
00417 }
00418 
00419 static Bool wx_spline_add_point(double x, double y)
00420 {
00421     wxPoint *point;
00422 
00423     if (!wx_spline_point_list) {
00424       wxREGGLOB(wx_spline_point_list);
00425       wx_spline_point_list = new wxList;
00426     }
00427 
00428     point = new wxPoint;
00429     point->x = x;
00430     point->y = y;
00431     wx_spline_point_list->Append((wxObject*)point);
00432     return TRUE;
00433 }
00434 
00435 static void wx_spline_draw_point_array(wxDC *dc)
00436 {
00437   if (wx_spline_point_list) {
00438     wxNode *node;
00439     dc->DrawLines(wx_spline_point_list, 0.0, 0.0);
00440     node = wx_spline_point_list->First();
00441     while (node) {
00442        wxPoint *point;
00443        point = (wxPoint *)node->Data();
00444        DELETE_OBJ point;
00445        wx_spline_point_list->DeleteNode(node);
00446        node = wx_spline_point_list->First();
00447     }
00448   }
00449 }