r385: no message
[ctsim.git] / libctgraphics / sgp.cpp
index 1062901737201670c32db960935990d70bc26d5e..ec6b89d4a936dcff1fe103a2a362232525bb4b15 100644 (file)
@@ -7,7 +7,7 @@
 **  This is part of the CTSim program
 **  Copyright (C) 1983-2000 Kevin Rosenberg
 **
-**  $Id: sgp.cpp,v 1.8 2000/07/31 14:48:35 kevin Exp $
+**  $Id: sgp.cpp,v 1.27 2001/01/12 21:53:27 kevin Exp $
 **
 **  This program is free software; you can redistribute it and/or modify
 **  it under the terms of the GNU General Public License (version 2) as
@@ -52,15 +52,14 @@ RGBColor SGP::s_aRGBColor[] =
 int SGP::s_iRGBColorCount = sizeof(s_aRGBColor) / sizeof(class RGBColor);
 
 #ifdef HAVE_WXWINDOWS
-SGPDriver::SGPDriver (wxDC* pDC, const char* szWinTitle = "", int xsize = 640, int ysize = 480)
-  : m_iPhysicalXSize(xsize), m_iPhysicalYSize(ysize), m_sWindowTitle(szWinTitle), m_idDriver(0)
+SGPDriver::SGPDriver (wxDC* pDC, int xsize, int ysize)
+  : m_iPhysicalXSize(xsize), m_iPhysicalYSize(ysize), m_idDriver(0), m_pDC(pDC)
 {
-  m_pDC = pDC;
   m_idDriver |= SGPDRIVER_WXWINDOWS;
 }
 #endif
 
-SGPDriver::SGPDriver (const char* szWinTitle = "", int xsize = 640, int ysize = 480)
+SGPDriver::SGPDriver (const char* szWinTitle, int xsize, int ysize)
   : m_iPhysicalXSize(xsize), m_iPhysicalYSize(ysize), m_sWindowTitle(szWinTitle), m_idDriver(0)
 {
 #ifdef HAVE_G2_H
@@ -71,8 +70,10 @@ SGPDriver::SGPDriver (const char* szWinTitle = "", int xsize = 640, int ysize =
 
 SGPDriver::~SGPDriver ()
 {
+#if HAVE_G2_H
   if (isG2()) 
     g2_close (m_idG2);
+#endif
 }
 
 
@@ -80,7 +81,7 @@ SGPDriver::~SGPDriver ()
 //   SGP::SGP        Constructor for Simple Graphics Package
 
 SGP::SGP (const SGPDriver& driver)
-    : m_driver (driver)
+  : m_driver (driver)
 {
   m_iPhysicalXSize = m_driver.getPhysicalXSize();
   m_iPhysicalYSize = m_driver.getPhysicalYSize();
@@ -90,16 +91,59 @@ SGP::SGP (const SGPDriver& driver)
   ndc_to_mc.setIdentity();
   m_ctm.setIdentity();
 
+#ifdef HAVE_WXWINDOWS
+  initFromDC (driver.idWX());
+#endif
+
   setWindow (0., 0., 1., 1.);
   setViewport (0., 0., 1., 1.);
   moveAbs (0., 0.);
   stylusNDC (0., 0., false);
+  
   setTextAngle (0.);
-  setTextSize (1. / 25.);
+  setTextPointSize (12);
   setColor (C_BLACK);
+  setLineStyle (LS_SOLID);
+}
+
+
+#ifdef HAVE_WXWINDOWS
+void
+SGP::initFromDC (wxDC* pDC)
+{
+  m_pen.SetWidth (1);
+
+  if (m_driver.isWX()) {
+    static const double dScreenDPI = 82;
+    static const double dPointsPerInch = 72.;
+    m_dPointsPerPixel = dPointsPerInch / dScreenDPI;
+    const int iTestPointSize = 12;
+    m_pFont = new wxFont (wxROMAN, wxNORMAL, wxNORMAL, wxNORMAL);
+    m_pFont->SetPointSize (iTestPointSize);
+    m_pFont->SetWeight (wxNORMAL);
+    m_pFont->SetStyle (wxNORMAL);
+    m_pFont->SetFamily (wxROMAN);
+#ifdef MSVC
+    m_pFont->SetFaceName(wxString("times new roman"));
+#endif
+    m_driver.idWX()->SetFont (*m_pFont);
+    double dTestCharHeight = m_driver.idWX()->GetCharHeight();
+    m_dPointsPerPixel = iTestPointSize / dTestCharHeight;
+       m_driver.idWX()->SetBackground (*wxWHITE_BRUSH);
+  }
 }
+#endif
+
 
+SGP::~SGP()
+{
+#if HAVE_WXWINDOWS
+  if (m_driver.isWX()) {
+ //   m_driver.idWX()->SetFont (wxNullFont);
+    delete m_pFont;
+  }
+#endif
+}
 
 void
 SGP::stylusNDC (double x, double y, bool beam)
@@ -111,12 +155,12 @@ SGP::stylusNDC (double x, double y, bool beam)
 
   if (beam) {
 #if HAVE_WXWINDOWS
-      if (m_driver.isWX())
-         m_driver.idWX()->DrawLine (m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
+    if (m_driver.isWX())
+      m_driver.idWX()->DrawLine (m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
 #endif
 #if HAVE_G2_H
-      if (m_driver.isG2())
-         g2_line (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
+    if (m_driver.isG2())
+      g2_line (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
 #endif
   }
   m_iCurrentPhysicalX = xp;
@@ -145,8 +189,20 @@ SGP::eraseWindow ()
     g2_clear (m_driver.idG2());
 #endif
 #if HAVE_WXWINDOWS
-  if (m_driver.isWX())
-    m_driver.idWX()->Clear();
+  if (m_driver.isWX()) {
+       wxBrush brushWhite;
+       brushWhite.SetColour(255,255,255);
+       m_driver.idWX()->SetBackground(brushWhite);
+       m_driver.idWX()->Clear();
+       m_driver.idWX()->SetBackground(wxNullBrush);
+#if 1
+       wxPen pen;
+       pen.SetColour(255,255,255);
+       m_driver.idWX()->SetBrush (brushWhite);
+       m_driver.idWX()->DrawRectangle (0, 0, m_iPhysicalXSize, m_iPhysicalYSize);
+       m_driver.idWX()->SetBrush (wxNullBrush);
+#endif
+  }
 #endif
 }
 
@@ -193,6 +249,24 @@ SGP::setViewport (double xmin, double ymin, double xmax, double ymax)
   viewNDC[3] = ymax;
 }
 
+void
+SGP::getViewport (double& xmin, double& ymin, double& xmax, double& ymax)
+{
+    xmin = xv_min;
+    ymin = yv_min;
+    xmax = xv_max;
+    ymax = yv_max;
+}
+
+void
+SGP::getWindow (double& xmin, double& ymin, double& xmax, double& ymax)
+{
+    xmin = xw_min;
+    ymin = yw_min;
+    xmax = xw_max;
+    ymax = yw_max;
+}
+
 
 // NAME
 //     frameViewport           draw box around viewport
@@ -200,16 +274,28 @@ SGP::setViewport (double xmin, double ymin, double xmax, double ymax)
 void
 SGP::frameViewport (void)
 {
-  stylusNDC (xv_min, yv_min, 0);
-  stylusNDC (xv_max, yv_min, 1);
-  stylusNDC (xv_max, yv_max, 1);
-  stylusNDC (xv_min, yv_max, 1);
-  stylusNDC (xv_min, yv_min, 1);
+  stylusNDC (xv_min, yv_min, false);
+  stylusNDC (xv_max, yv_min, true);
+  stylusNDC (xv_max, yv_max, true);
+  stylusNDC (xv_min, yv_max, true);
+  stylusNDC (xv_min, yv_min, true);
 }
 
 void
 SGP::setTextColor (int iFGcolor, int iBGcolor)
 {
+#if HAVE_WXWINDOWS
+  if (m_driver.isWX()) {
+    if (iFGcolor >= 0) {
+      wxColor colour (s_aRGBColor[iFGcolor].getRed(), s_aRGBColor[iFGcolor].getGreen(), s_aRGBColor[iFGcolor].getBlue());
+      m_driver.idWX()->SetTextForeground (colour);
+    }
+    if (iBGcolor >= 0) {
+      wxColor colour (s_aRGBColor[iBGcolor].getRed(), s_aRGBColor[iBGcolor].getGreen(), s_aRGBColor[iBGcolor].getBlue());
+      m_driver.idWX()->SetTextBackground (colour);
+    }
+  }
+#endif
 }
 
 void 
@@ -225,13 +311,89 @@ SGP::setColor (int icol)
 #if HAVE_WXWINDOWS
     if (m_driver.isWX()) {
       wxColor colour (s_aRGBColor[icol].getRed(), s_aRGBColor[icol].getGreen(), s_aRGBColor[icol].getBlue());
-      wxPen pen (colour, 1, wxSOLID);
-      m_driver.idWX()->SetPen (pen);
+      m_pen.SetColour (colour);
+      m_driver.idWX()->SetPen (m_pen);
     }
 #endif
   }
 }
 
+void 
+SGP::setPenWidth (int iWidth)
+{
+  if (iWidth >= 0) {
+#if HAVE_WXWINDOWS
+    if (m_driver.isWX()) {
+      m_pen.SetWidth (iWidth);
+      m_driver.idWX()->SetPen (m_pen);
+    }
+#endif
+  }
+}
+
+void
+SGP::setRasterOp (int ro)
+{
+#if HAVE_WXWINDOWS
+  if (m_driver.isWX()) {
+    int wxFxn = -1;
+    switch (ro) {
+    case RO_AND:
+      wxFxn = wxAND;
+      break;
+    case RO_AND_INVERT:
+      wxFxn = wxAND_INVERT;
+      break;
+    case RO_AND_REVERSE:
+      wxFxn = wxAND_REVERSE;
+      break;
+    case RO_CLEAR:
+      wxFxn = wxCLEAR;
+      break;
+    case RO_COPY:
+      wxFxn = wxCOPY;
+      break;
+    case RO_EQUIV:
+      wxFxn = wxEQUIV;
+      break;
+    case RO_INVERT:
+      wxFxn = wxINVERT;
+      break;
+    case RO_NAND:
+      wxFxn = wxNAND;
+      break;
+    case RO_NOR:
+      wxFxn = wxNOR;
+      break;
+    case RO_NO_OP:
+      wxFxn = wxNO_OP;
+      break;
+    case RO_OR:
+      wxFxn = wxOR;
+      break;
+    case RO_OR_INVERT:
+      wxFxn = wxOR_INVERT;
+      break;
+    case RO_OR_REVERSE:
+      wxFxn = wxOR_REVERSE;
+      break;
+    case RO_SET:
+      wxFxn = wxSET;
+      break;
+    case RO_SRC_INVERT:
+      wxFxn = wxSRC_INVERT;
+      break;
+    case RO_XOR:
+      wxFxn = wxXOR;
+      break;
+    }
+    if (wxFxn >= 0)
+      m_driver.idWX()->SetLogicalFunction (wxFxn);
+  }
+#endif
+}
+
+
 void
 SGP::setMarker (int idMarke, int iColor)
 {
@@ -243,6 +405,36 @@ SGP::setMarker (int idMarke, int iColor)
 void 
 SGP::setLineStyle (int style)
 {
+  m_iLinestyle = style;
+
+#if HAVE_WXWINDOWS
+  if (m_driver.isWX()) {
+    switch (m_iLinestyle) {
+    case LS_SOLID:
+      m_pen.SetStyle (wxSOLID);
+      break;
+    case LS_DASH1:
+      m_pen.SetStyle (wxLONG_DASH);
+      break;
+    case LS_DASH2:
+      m_pen.SetStyle (wxSHORT_DASH);
+      break;
+    case LS_DASH3:
+      m_pen.SetStyle (wxDOT_DASH);
+      break;
+    case LS_DASH4:
+      m_pen.SetStyle (wxCROSS_HATCH);
+      break;
+    case LS_DOTTED:
+      m_pen.SetStyle (wxDOT);
+      break;
+    default:
+      m_pen.SetStyle (wxSOLID);
+      break;
+    }
+    m_driver.idWX()->SetPen (m_pen);
+  }
+#endif
 }
 
 //==============================================================
@@ -264,8 +456,8 @@ SGP::lineAbs (double x, double y)
   mc_to_ndc.transformPoint (&x2, &y2);
   
   if (clip_rect (x1, y1, x2, y2, viewNDC) == true) { // clip to viewport 
-    stylusNDC (x1, y1, 0);  // move to first point
-    stylusNDC (x2, y2, 1);  // draw to second point 
+    stylusNDC (x1, y1, false);  // move to first point
+    stylusNDC (x2, y2, true);  // draw to second point 
   }
 
   m_dCurrentWorldX = x;
@@ -291,17 +483,114 @@ SGP::moveRel (double x, double y)
   moveAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
 }
 
+
+// Height is in master coordinates
 void
 SGP::setTextSize (double height)
 {
+    height /= (yw_max - yw_min);  // convert to NDC
+#if HAVE_G2_H
   if (m_driver.isG2())
     g2_set_font_size(m_driver.idG2(), (height * m_iPhysicalYSize));
+#endif
+#if HAVE_WXWINDOWS
+  if (m_driver.isWX()) {
+      double dHeightPixels = height * m_iPhysicalYSize;
+      double dHeightPoints = dHeightPixels * m_dPointsPerPixel;
+      m_pFont->SetPointSize (nearest<int>(dHeightPoints));
+      m_driver.idWX()->SetFont (*m_pFont);
+  }
+#endif
+}
+
+void
+SGP::setTextNDCSize (double height)
+{
+    double dHeightPixels = height * m_iPhysicalYSize;
+#if HAVE_G2_H
+  if (m_driver.isG2())
+    g2_set_font_size(m_driver.idG2(), nearest<int>(dHeightPixels));
+#endif
+#if HAVE_WXWINDOWS
+  if (m_driver.isWX()) {
+      double dHeightPoints = dHeightPixels * m_dPointsPerPixel;
+      m_pFont->SetPointSize (nearest<int>(dHeightPoints));
+      m_driver.idWX()->SetFont (*m_pFont);
+  }
+#endif
+}
+
+void
+SGP::setTextPointSize (double height)
+{
+#if HAVE_G2_H
+    //  if (m_driver.isG2())
+    //    g2_set_font_size(m_driver.idG2(), (height * m_iPhysicalYSize));
+#endif
+#if HAVE_WXWINDOWS
+  if (m_driver.isWX()) {
+    m_iTextPointSize = static_cast<int>(height+0.5);
+      m_pFont->SetPointSize (m_iTextPointSize);
+      m_driver.idWX()->SetFont (*m_pFont);
+  }
+#endif
+}
+
+void
+SGP::getTextExtent (const char* szText, double* worldW, double* worldH)
+{
+#if HAVE_WXWINDOWS
+  if (m_driver.isWX()) {
+    wxString sText (szText);
+    wxCoord deviceW, deviceH;
+    m_driver.idWX()->GetTextExtent (sText, &deviceW, &deviceH);
+    if (m_dTextAngle == 90 || m_dTextAngle == -90) {
+      wxCoord temp = deviceW;
+      deviceW = deviceH;
+      deviceH = temp;
+    }
+    *worldW = (xw_max - xw_min) * deviceW / static_cast<double>(m_iPhysicalXSize);;
+    *worldH = (yw_max - yw_min) * deviceH / static_cast<double>(m_iPhysicalYSize);
+  }
+#endif
+}
+
+double
+SGP::getCharHeight ()
+{
+  double dHeight = (1. / 25.);
+
+#if HAVE_WXWINDOWS
+  if (m_driver.isWX()) {
+    dHeight = m_driver.idWX()->GetCharHeight();
+    dHeight /= static_cast<double>(m_iPhysicalYSize);
+       dHeight /= (yv_max - yv_min); // scale to viewport;
+  }
+#endif
+  dHeight *= (yw_max - yw_min);  // scale to world coordinates
+  return dHeight;
+}
+
+double
+SGP::getCharWidth ()
+{
+  double dWidth = (1. / 80.);
+
+#if HAVE_WXWINDOWS
+  if (m_driver.isWX()) {
+    dWidth = m_driver.idWX()->GetCharWidth();
+    dWidth /= static_cast<double>(m_iPhysicalXSize);
+       dWidth /= (xv_max - xv_min); // scale to viewport
+  }
+#endif
+  dWidth *= (xw_max - xw_min); //scale to world coordinates
+  return dWidth;
 }
 
 void
 SGP::setTextAngle (double angle)
 {
-  m_dTextAngle = angle;
+  m_dTextAngle = convertRadiansToDegrees(angle);
 }
 
 void 
@@ -319,8 +608,8 @@ SGP::polylineAbs (double x[], double y[], int n)
   double yt = y2;      // as the beginning point of the next line 
 
   if (clip_rect (x1, y1, xt, yt, viewNDC)) {
-    stylusNDC (x1, y1, 0);
-    stylusNDC (xt, yt, 1);
+    stylusNDC (x1, y1, false);
+    stylusNDC (xt, yt, true);
   }
   
   for (int i = 2; i < n; i++) {
@@ -330,8 +619,8 @@ SGP::polylineAbs (double x[], double y[], int n)
     xt = x2;
     yt = y2;
     if (clip_rect (x1, y1, xt, yt, viewNDC)) {
-      stylusNDC (x1, y1, 0);
-      stylusNDC (xt, yt, 1);
+      stylusNDC (x1, y1, false);
+      stylusNDC (xt, yt, true);
     }
   }
 }
@@ -382,7 +671,7 @@ SGP::pointRel (double x, double y)
 
 
 void
-SGP::drawText (const string& rsMessage)
+SGP::drawText (const std::string& rsMessage)
 {
   drawText (rsMessage.c_str());
 }
@@ -441,47 +730,46 @@ SGP::drawRect (double xmin, double ymin, double xmax, double ymax)
 void 
 SGP::drawCircle (const double r)
 {
-       drawArc (0.0, 7.0, r);
+       drawArc (r, 0.0, TWOPI);
 }
 
-// =============================================================
-// draw arc around current center.  pass angles and radius     
+//==============================================================
+// draw arc around current center.  angles in radius   
 //==============================================================
 
 void 
-SGP::drawArc (double start, double stop, const double r)
+SGP::drawArc (const double r, double start, double stop)
 {
-  if ((stop-start) > 2 * PI)
-    stop = start + 2 * PI;
-  if ((start-stop) > 2 * PI)
-    stop = start + 2 * PI;
-  while (start >= stop)
-    stop += 2*PI;
+  if (start > stop) {
+    double temp = start;
+    start = stop;
+    stop = temp;
+  }
 
   double x = r * cos ((double) start);
   double y = r * sin ((double) start);
   moveRel (x, y);          // move from center to start of arc 
 
-  double theta = 5 * PI / 180;
-  double c = cos(theta);
-  double s = sin(theta);
+  const double thetaIncrement = (5 * (TWOPI / 360)); 
+  double cosTheta = cos(thetaIncrement);
+  double sinTheta = sin(thetaIncrement);
 
   double angle, xp, yp;
-  for (angle = start; angle < stop - theta; angle += theta) {
-    xp = c * x - s * y;
-    yp = s * x + c * y;
-    lineRel (xp - x, yp - y);
+  for (angle = start; angle < stop - thetaIncrement; angle += thetaIncrement) {
+    xp = cosTheta * x - sinTheta * y; // translate point by thetaIncrement
+    yp = sinTheta * x + cosTheta * y;
+    lineAbs (xp, yp);
     x = xp; y = yp;
   }
 
-  c = cos (stop - angle);
-  s = sin (stop - angle);
+  double c = cos (stop - angle);
+  double s = sin (stop - angle);
   xp = c * x - s * y;
   yp = s * x + c * y;
-  lineRel (xp - x, yp - y);
+  lineAbs (xp, yp);
 
-  x = r * cos ((double) stop);
-  y = r * sin ((double) stop);
+  x = r * cos (stop);
+  y = r * sin (stop);
   moveRel (-x, -y);            // move back to center of circle 
 }
 
@@ -658,3 +946,16 @@ const unsigned char SGP::MARKER_BITMAP[MARK_COUNT][5] =
     {'\076', '\042', '\042', '\042', '\076'},    // big open square 
     {'\010', '\024', '\042', '\024', '\010'},    // big open diamond 
 };
+
+
+#if HAVE_WXWINDOWS
+void
+SGP::setDC (wxDC* pDC)
+{
+  if (m_driver.isWX()) {
+    m_driver.setDC(pDC);
+    initFromDC (pDC);
+    setTextPointSize (m_iTextPointSize);
+  }
+}
+#endif