X-Git-Url: http://git.kpe.io/?p=ctsim.git;a=blobdiff_plain;f=libctgraphics%2Fsgp.cpp;h=9757fe9fb03449e911e7d0fcee351488be47540a;hp=cc87671d0c45388327cba801bc1c69b2a0cce518;hb=f7ee98f7d964ed361068179f0e7ea4475ed1abdf;hpb=37ccf79b1044c04db41f5cf924f63c75be1c2366 diff --git a/libctgraphics/sgp.cpp b/libctgraphics/sgp.cpp index cc87671..9757fe9 100644 --- a/libctgraphics/sgp.cpp +++ b/libctgraphics/sgp.cpp @@ -1,13 +1,13 @@ /***************************************************************************** ** FILE IDENTIFICATION ** -** Name: sgp.c Simple Graphics Package -** Programmer: Kevin Rosenberg +** Name: sgp.cpp Simple Graphics Package +** Programmer: Kevin Rosenberg ** ** This is part of the CTSim program -** Copyright (C) 1983-2000 Kevin Rosenberg +** Copyright (c) 1983-2001 Kevin Rosenberg ** -** $Id: sgp.cpp,v 1.3 2000/06/19 19:16:17 kevin Exp $ +** $Id$ ** ** 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 @@ -29,585 +29,959 @@ #include "sgp.h" -static SGP_ID _sgp2_cwin = NULL; +SGP_RGBColor SGP::s_aRGBColor[] = +{ + SGP_RGBColor (0, 0, 0), + SGP_RGBColor (0, 0, 128), + SGP_RGBColor (0, 128, 0), + SGP_RGBColor (0, 128, 128), + SGP_RGBColor (128, 0, 0), + SGP_RGBColor (128, 0, 128), + SGP_RGBColor (128, 128, 0), + SGP_RGBColor (80, 80, 80), + SGP_RGBColor (160, 160, 160), + SGP_RGBColor (0, 0, 255), + SGP_RGBColor (0, 255, 0), + SGP_RGBColor (0, 255, 255), + SGP_RGBColor (255, 0, 0), + SGP_RGBColor (255, 0, 255), + SGP_RGBColor (255, 255, 0), + SGP_RGBColor (255, 255, 255), +}; -extern CHARSPEC cspec; +int SGP::s_iRGBColorCount = sizeof(s_aRGBColor) / sizeof(class SGP_RGBColor); +#ifdef HAVE_WXWINDOWS +SGPDriver::SGPDriver (wxDC* pDC, int xsize, int ysize) + : m_iPhysicalXSize(xsize), m_iPhysicalYSize(ysize), m_idDriver(0), m_pDC(pDC) +{ + m_idDriver |= SGPDRIVER_WXWINDOWS; +} +#endif -/* NAME - * sgp2_init Initialize 2 graphics system - * - * SYNOPSIS - * sgp2_init() - */ +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 + m_idG2 = g2_open_X11X (m_iPhysicalXSize, m_iPhysicalYSize, 10, 10, const_cast(szWinTitle), const_cast(szWinTitle), NULL, -1, -1); + m_idDriver |= SGPDRIVER_G2; +#endif +} -SGP_ID -sgp2_init (int xsize, int ysize, const char *win_title ) +SGPDriver::~SGPDriver () { - SGP_ID gid; +#if HAVE_G2_H + if (isG2()) + g2_close (m_idG2); +#endif +} - gid = new SGP_WINDOW; - _sgp2_cwin = gid; - - if (xsize <= 0) - xsize = 640; - if (ysize <= 0) - ysize = 480; - gid->pw_xsize = xsize; - gid->pw_ysize = ysize; - strncpy(gid->title, win_title, sizeof(gid->title)); +// NAME +// SGP::SGP Constructor for Simple Graphics Package - gid->recalc_mc_to_ndc = TRUE; - gid->recalc_ndc_to_mc = TRUE; - ident_gmtx_2 (gid->wc_to_ndc_x); - ident_gmtx_2 (gid->mc_to_ndc_x); - ident_gmtx_2 (gid->ndc_to_mc_x); - ident_gmtx_2 (gid->ctm_2_x); +SGP::SGP (const SGPDriver& driver) + : m_driver (driver) +{ + m_iPhysicalXSize = m_driver.getPhysicalXSize(); + m_iPhysicalYSize = m_driver.getPhysicalYSize(); - sgp2_window (0., 0., 1., 1.); - sgp2_viewport (0., 0., 1., 1.); - ctm_clr_2 (); - sgp2_move_abs (0., 0.); + wc_to_ndc.setIdentity (); + mc_to_ndc.setIdentity(); + ndc_to_mc.setIdentity(); + m_ctm.setIdentity(); -#if HAVE_G2_H - gid->g2_id = g2_open_X11X (gid->pw_xsize, gid->pw_ysize, 10, 10, gid->title, gid->title, NULL, -1, -1); +#ifdef HAVE_WXWINDOWS + initFromDC (driver.idWX()); #endif - _sgp2_init_dev (_sgp2_cwin); - - return (gid); + setWindow (0., 0., 1., 1.); + setViewport (0., 0., 1., 1.); + moveAbs (0., 0.); + stylusNDC (0., 0., false); + + setTextAngle (0.); + setTextPointSize (12); + setColor (C_BLACK); + setLineStyle (LS_SOLID); + setMarker (MARKER_POINT); } +#ifdef HAVE_WXWINDOWS void -sgp2_close (SGP_ID gid) -{ -#if HAVE_G2_H - g2_close (gid->g2_id); +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 - if (gid == _sgp2_cwin) - _sgp2_cwin = NULL; + m_driver.idWX()->SetFont (*m_pFont); + double dTestCharHeight = m_driver.idWX()->GetCharHeight(); + m_dPointsPerPixel = iTestPointSize / dTestCharHeight; + m_driver.idWX()->SetBackground (*wxWHITE_BRUSH); + } +} +#endif + - delete gid; +SGP::~SGP() +{ +#if HAVE_WXWINDOWS + if (m_driver.isWX()) { + // m_driver.idWX()->SetFont (wxNullFont); + delete m_pFont; + } +#endif } void -sgp2_set_active_win (SGP_ID gid) +SGP::stylusNDC (double x, double y, bool beam) { - _sgp2_cwin = gid; + int xp = static_cast(x * (m_iPhysicalXSize - 1) + 0.5); + int yp = static_cast(y * (m_iPhysicalYSize - 1) + 0.5); + if (m_driver.isWX()) + yp = m_iPhysicalYSize - yp; + + if (beam) { +#if HAVE_WXWINDOWS + 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); +#endif + } + m_iCurrentPhysicalX = xp; + m_iCurrentPhysicalY = yp; +} + +void +SGP::markerNDC (double x, double y) +{ + int xp = static_cast(x * (m_iPhysicalXSize - 1) + 0.5); + int yp = static_cast(y * (m_iPhysicalYSize - 1) + 0.5); + if (m_driver.isWX()) + yp = m_iPhysicalYSize - yp; + +#if HAVE_WXWINDOWS + if (m_driver.isWX()) { + m_driver.idWX()->DrawPoint (xp, yp); + m_driver.idWX()->DrawPoint (xp-1, yp-1); + m_driver.idWX()->DrawPoint (xp+1, yp+1); + m_driver.idWX()->DrawPoint (xp+1, yp-1); + m_driver.idWX()->DrawPoint (xp-1, yp+1); + } +#endif + m_iCurrentPhysicalX = xp; + m_iCurrentPhysicalY = yp; } -SGP_ID -sgp2_get_active_win (void) +void +SGP::pointNDC (double x, double y) { - return (_sgp2_cwin); + int xp = static_cast(x * (m_iPhysicalXSize - 1) + 0.5); + int yp = static_cast(y * (m_iPhysicalYSize - 1) + 0.5); + if (m_driver.isWX()) + yp = m_iPhysicalYSize - yp; + +#if HAVE_WXWINDOWS + if (m_driver.isWX()) + m_driver.idWX()->DrawPoint (xp, yp); +#endif + m_iCurrentPhysicalX = xp; + m_iCurrentPhysicalY = yp; } -/* NAME - * sgp2_clear Clear window - */ +// NAME +// clear Clear Window -void -sgp2_clear () +void +SGP::eraseWindow () { -#if HAVE_G2 - if (_sgp_cwin != NULL) - g2_clear (gid->g2_id); +#if HAVE_G2_H + if (m_driver.isG2()) + g2_clear (m_driver.idG2()); +#endif +#if HAVE_WXWINDOWS + 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 } -/* NAME - * sgp2_window Set window in world coordinates - */ +// NAME +// sgp2_window Set window in world coordinates + void -sgp2_window (double xmin, double ymin, double xmax, double ymax) +SGP::setWindow (double xmin, double ymin, double xmax, double ymax) { - if (_sgp2_cwin == NULL) - return; - - if (xmin >= xmax || ymin >= ymax) { - sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_window]"); - return; - } + if (xmin >= xmax || ymin >= ymax) { + sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_window]"); + return; + } - _sgp2_cwin->xw_min = xmin; - _sgp2_cwin->yw_min = ymin; - _sgp2_cwin->xw_max = xmax; - _sgp2_cwin->yw_max = ymax; - calc_wc_to_ndc(); + xw_min = xmin; + yw_min = ymin; + xw_max = xmax; + yw_max = ymax; + m_bRecalcTransform = true; } -/* NAME - * sgp2_viewport Set viewport in NDC - */ +// NAME +// sgp2_viewport Set viewport in NDC void -sgp2_viewport (double xmin, double ymin, double xmax, double ymax) +SGP::setViewport (double xmin, double ymin, double xmax, double ymax) { - if (_sgp2_cwin == NULL) - return; + if (xmin >= xmax || ymin >= ymax) { + sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_viewport]"); + return; + } - if (xmin >= xmax || ymin >= ymax) { - sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_viewport]"); - return; - } - - _sgp2_cwin->xv_min = xmin; - _sgp2_cwin->yv_min = ymin; - _sgp2_cwin->xv_max = xmax; - _sgp2_cwin->yv_max = ymax; - calc_wc_to_ndc(); - - _sgp2_cwin->view[0] = xmin; /* Array for clip_rect() */ - _sgp2_cwin->view[1] = ymin; - _sgp2_cwin->view[2] = xmax; - _sgp2_cwin->view[3] = ymax; -} + xv_min = xmin; + yv_min = ymin; + xv_max = xmax; + yv_max = ymax; + m_bRecalcTransform = true; - -/* NAME - * sgp2_frame_vpt draw box around viewport - */ + viewNDC[0] = xmin; // Array for clip_rect() + viewNDC[1] = ymin; + viewNDC[2] = xmax; + viewNDC[3] = ymax; +} void -sgp2_frame_vpt (void) +SGP::getViewport (double& xmin, double& ymin, double& xmax, double& ymax) { - if (_sgp2_cwin == NULL) - return; + xmin = xv_min; + ymin = yv_min; + xmax = xv_max; + ymax = yv_max; +} - _sgp2_stylus (_sgp2_cwin, _sgp2_cwin->xv_min, _sgp2_cwin->yv_min, 0); - _sgp2_stylus (_sgp2_cwin, _sgp2_cwin->xv_max, _sgp2_cwin->yv_min, 1); - _sgp2_stylus (_sgp2_cwin, _sgp2_cwin->xv_max, _sgp2_cwin->yv_max, 1); - _sgp2_stylus (_sgp2_cwin, _sgp2_cwin->xv_min, _sgp2_cwin->yv_max, 1); - _sgp2_stylus (_sgp2_cwin, _sgp2_cwin->xv_min, _sgp2_cwin->yv_min, 1); +void +SGP::getWindow (double& xmin, double& ymin, double& xmax, double& ymax) +{ + xmin = xw_min; + ymin = yw_min; + xmax = xw_max; + ymax = yw_max; } -/* NAME - * calc_wc_to_ndc Calculate transform matrix - */ +// NAME +// frameViewport draw box around viewport void -calc_wc_to_ndc (void) +SGP::frameViewport (void) { - double sx, sy; - - if (_sgp2_cwin == NULL) - return; - - sx = (_sgp2_cwin->xv_max - _sgp2_cwin->xv_min) / (_sgp2_cwin->xw_max - _sgp2_cwin->xw_min); - sy = (_sgp2_cwin->yv_max - _sgp2_cwin->yv_min) / (_sgp2_cwin->yw_max - _sgp2_cwin->yw_min); - - ident_gmtx_2 (_sgp2_cwin->wc_to_ndc_x); - _sgp2_cwin->wc_to_ndc_x[0][0] = sx; - _sgp2_cwin->wc_to_ndc_x[2][0] = _sgp2_cwin->xv_min - sx * _sgp2_cwin->xw_min; - _sgp2_cwin->wc_to_ndc_x[1][1] = sy; - _sgp2_cwin->wc_to_ndc_x[2][1] = _sgp2_cwin->yv_min - sy * _sgp2_cwin->yw_min; - - _sgp2_cwin->recalc_mc_to_ndc = TRUE; - _sgp2_cwin->recalc_ndc_to_mc = TRUE; + 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 -calc_ndc_to_mc (void) +void +SGP::setColor (int icol) { - if (_sgp2_cwin == NULL) - return; + if (icol >= 0 && icol < s_iRGBColorCount) { +#if HAVE_G2_H + if (m_driver.isG2()) { + int iInk = g2_ink (m_driver.idG2(), s_aRGBColor[icol].getRed() / 255., s_aRGBColor[icol].getGreen() / 255., s_aRGBColor[icol].getBlue() / 255.); + g2_pen (m_driver.idG2(), iInk); + } +#endif +#if HAVE_WXWINDOWS + if (m_driver.isWX()) { + wxColor colour (s_aRGBColor[icol].getRed(), s_aRGBColor[icol].getGreen(), s_aRGBColor[icol].getBlue()); + m_pen.SetColour (colour); + m_driver.idWX()->SetPen (m_pen); + } +#endif + } +} - if (_sgp2_cwin->recalc_mc_to_ndc) { - mult_gmtx_2 (_sgp2_cwin->ctm_2_x, _sgp2_cwin->wc_to_ndc_x, _sgp2_cwin->mc_to_ndc_x); - _sgp2_cwin->recalc_mc_to_ndc = FALSE; +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); } - - invert_gmtx_2 (_sgp2_cwin->mc_to_ndc_x, _sgp2_cwin->ndc_to_mc_x); - _sgp2_cwin->recalc_ndc_to_mc = FALSE; +#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 +} -/* NAME - * wc_to_ndc Map from world coordinates to NDC - */ -void -wc_to_ndc (double xw, double yw, double *xn, double *yn) +void +SGP::setMarker (int idMarker) { - if (_sgp2_cwin == NULL) - return; + m_iMarker = idMarker; +} - if (_sgp2_cwin->recalc_mc_to_ndc) { - mult_gmtx_2 (_sgp2_cwin->ctm_2_x, _sgp2_cwin->wc_to_ndc_x, _sgp2_cwin->mc_to_ndc_x); - _sgp2_cwin->recalc_mc_to_ndc = FALSE; +//============================================================== +// set line style. Pass 16 bit repeating pattern +//============================================================== +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; } - - *xn = xw * _sgp2_cwin->mc_to_ndc_x[0][0] + yw * _sgp2_cwin->mc_to_ndc_x[1][0] + _sgp2_cwin->mc_to_ndc_x[2][0]; - *yn = xw * _sgp2_cwin->mc_to_ndc_x[0][1] + yw * _sgp2_cwin->mc_to_ndc_x[1][1] + _sgp2_cwin->mc_to_ndc_x[2][1]; + m_driver.idWX()->SetPen (m_pen); + } +#endif } +//============================================================== +// absolute draw to +//*============================================================== -/*==============================================================*/ -/* map from normalized device coords. to world coordinates */ -/*==============================================================*/ void -ndc_to_wc (double xn, double yn, double *xw, double *yw) +SGP::lineAbs (double x, double y) { - if (_sgp2_cwin == NULL) - return; + if (m_bRecalcTransform) + calc_transform(); - if (_sgp2_cwin->recalc_ndc_to_mc) { - calc_ndc_to_mc(); - _sgp2_cwin->recalc_ndc_to_mc = FALSE; - } + double x1 = m_dCurrentWorldX; + double y1 = m_dCurrentWorldY; + mc_to_ndc.transformPoint (&x1, &y1); + + double x2 = x; + double y2 = y; + mc_to_ndc.transformPoint (&x2, &y2); - *xw = xn * _sgp2_cwin->ndc_to_mc_x[0][0] + yn * _sgp2_cwin->ndc_to_mc_x[1][0] + _sgp2_cwin->ndc_to_mc_x[2][0]; - *yw = xn * _sgp2_cwin->ndc_to_mc_x[0][1] + yn * _sgp2_cwin->ndc_to_mc_x[1][1] + _sgp2_cwin->ndc_to_mc_x[2][1]; + if (clip_rect (x1, y1, x2, y2, viewNDC) == true) { // clip to viewport + stylusNDC (x1, y1, false); // move to first point + stylusNDC (x2, y2, true); // draw to second point + } + + m_dCurrentWorldX = x; + m_dCurrentWorldY = y; } +void +SGP::moveAbs (double x, double y) +{ + m_dCurrentWorldX = x; + m_dCurrentWorldY = y; /* moves are not clipped */ +} -/*==============================================================*/ -/* set the color */ -/*==============================================================*/ -void -sgp2_color (int icol) +void +SGP::lineRel (double x, double y) { - setcolor(icol); + lineAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY); } -/*==============================================================*/ -/* set line style. Pass 16 bit repeating pattern */ -/*==============================================================*/ -void -sgp2_line_style (int style) +void +SGP::moveRel (double x, double y) { - setlinestyle(style); + moveAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY); } -/*==============================================================*/ -/* absolute draw to */ -/*==============================================================*/ -void -sgp2_line_abs (double x, double y) + +// Height is in master coordinates +void +SGP::setTextSize (double height) { - double x1, y1, x2, y2; + 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(dHeightPoints)); + m_driver.idWX()->SetFont (*m_pFont); + } +#endif +} - if (_sgp2_cwin == NULL) - return; +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(dHeightPixels)); +#endif +#if HAVE_WXWINDOWS + if (m_driver.isWX()) { + double dHeightPoints = dHeightPixels * m_dPointsPerPixel; + m_pFont->SetPointSize (nearest(dHeightPoints)); + m_driver.idWX()->SetFont (*m_pFont); + } +#endif +} - wc_to_ndc (_sgp2_cwin->curx, _sgp2_cwin->cury, &x1, &y1); - wc_to_ndc (x, y, &x2, &y2); +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(height+0.5); + m_pFont->SetPointSize (m_iTextPointSize); + m_driver.idWX()->SetFont (*m_pFont); + } +#endif +} - if (clip_rect (x1, y1, x2, y2, _sgp2_cwin->view) == TRUE) { /* clip to viewport */ - _sgp2_stylus (_sgp2_cwin, x1, y1, 0); /* move to first point */ - _sgp2_stylus (_sgp2_cwin, x2, y2, 1); /* draw to second point */ +void +SGP::getTextExtent (const char* szText, double* worldW, double* worldH) +{ +#if HAVE_WXWINDOWS + if (m_driver.isWX()) { + wxCoord deviceW, deviceH; + m_driver.idWX()->GetTextExtent (wxConvCurrent->cMB2WC(szText), &deviceW, &deviceH); + if (m_dTextAngle == 90 || m_dTextAngle == -90) { + wxCoord temp = deviceW; + deviceW = deviceH; + deviceH = temp; } - - _sgp2_cwin->curx = x; - _sgp2_cwin->cury = y; + *worldW = (xw_max - xw_min) * deviceW / static_cast(m_iPhysicalXSize);; + *worldH = (yw_max - yw_min) * deviceH / static_cast(m_iPhysicalYSize); + } +#endif } -/*==============================================================*/ -/* absolute move to */ -/*==============================================================*/ -void -sgp2_move_abs (double x, double y) +double +SGP::getCharHeight () { - if (_sgp2_cwin == NULL) - return; + double dHeight = (1. / 25.); - _sgp2_cwin->curx = x; - _sgp2_cwin->cury = y; /* moves are not clipped */ +#if HAVE_WXWINDOWS + if (m_driver.isWX()) { + dHeight = m_driver.idWX()->GetCharHeight(); + dHeight /= static_cast(m_iPhysicalYSize); + dHeight /= (yv_max - yv_min); // scale to viewport; + } +#endif + dHeight *= (yw_max - yw_min); // scale to world coordinates + return dHeight; } -/*==============================================================*/ -/* vector draw */ -/*==============================================================*/ -void -sgp2_line_rel (double x, double y) +double +SGP::getCharWidth () { - if (_sgp2_cwin != NULL) - sgp2_line_abs (x + _sgp2_cwin->curx, y + _sgp2_cwin->cury); + double dWidth = (1. / 80.); + +#if HAVE_WXWINDOWS + if (m_driver.isWX()) { + dWidth = m_driver.idWX()->GetCharWidth(); + dWidth /= static_cast(m_iPhysicalXSize); + dWidth /= (xv_max - xv_min); // scale to viewport + } +#endif + dWidth *= (xw_max - xw_min); //scale to world coordinates + return dWidth; } -/*==============================================================*/ -/* vector move */ -/*==============================================================*/ -void -sgp2_move_rel (double x, double y) +void +SGP::setTextAngle (double angle) { - if (_sgp2_cwin != NULL) - sgp2_move_abs (x + _sgp2_cwin->curx, y + _sgp2_cwin->cury); + m_dTextAngle = convertRadiansToDegrees(angle); } -/*==============================================================*/ -/* draw text */ -/*==============================================================*/ -void -sgp2_draw_text (char *message) +void +SGP::polylineAbs (double x[], double y[], int n) +{ + if (m_bRecalcTransform) + calc_transform(); + + double x1 = x[0], y1 = y[0]; + mc_to_ndc.transformPoint (&x1, &y1); + double x2 = x[1], y2 = y[1]; + mc_to_ndc.transformPoint (&x2, &y2); + + double xt = x2; // don't pass (x2,y2) to clip, we need them + double yt = y2; // as the beginning point of the next line + + if (clip_rect (x1, y1, xt, yt, viewNDC)) { + stylusNDC (x1, y1, false); + stylusNDC (xt, yt, true); + } + + for (int i = 2; i < n; i++) { + x1 = x2; y1 = y2; // NDC endpoint of last line + x2 = x[i]; y2 = y[i]; + mc_to_ndc.transformPoint (&x2, &y2); + xt = x2; + yt = y2; + if (clip_rect (x1, y1, xt, yt, viewNDC)) { + stylusNDC (x1, y1, false); + stylusNDC (xt, yt, true); + } + } +} + + +void +SGP::markerAbs (double x, double y) { - double sx,sy; - if (_sgp2_cwin == NULL) - return; + if (m_bRecalcTransform) + calc_transform(); - wc_to_ndc (_sgp2_cwin->curx, _sgp2_cwin->cury, &sx, &sy); - _sgp2_stylus (_sgp2_cwin, sx, sy, 0); /* move to location */ - _sgp2_dev_text (_sgp2_cwin, message); + double xndc = x; + double yndc = y; + mc_to_ndc.transformPoint (&xndc, &yndc); + markerNDC (xndc, yndc); + m_dCurrentWorldX = x; + m_dCurrentWorldY = y; } + void -charsize (double wid, double height) +SGP::markerRel (double x, double y) { - _sgp2_set_text (_sgp2_cwin, wid, height, cspec.textangle, cspec.font); + markerAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY); } + void -textangle (double angle) +SGP::pointAbs (double x, double y) { - _sgp2_set_text (_sgp2_cwin, cspec.width, cspec.height, angle, cspec.font); + if (m_bRecalcTransform) + calc_transform(); + double xndc = x, yndc = y; + mc_to_ndc.transformPoint (&xndc, &yndc); + pointNDC (xndc, yndc); + m_dCurrentWorldX = x; + m_dCurrentWorldY = y; } -void -sgp2_polyline_abs (double x[], double y[], int n) + +void +SGP::pointRel (double x, double y) { - double x1, y1, x2, y2; - int i; - double xt, yt; + pointAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY); +} - if (_sgp2_cwin == NULL || n < 2) - return; - wc_to_ndc (x[0], y[0], &x1, &y1); - wc_to_ndc (x[1], y[1], &x2, &y2); +void +SGP::drawText (const std::string& rsMessage) +{ + drawText (rsMessage.c_str()); +} - xt = x2; /* don't pass (x2,y2) to clip, we need them */ - yt = y2; /* as the beginning point of the next line */ +void +SGP::drawText (const char *pszMessage) +{ + if (m_bRecalcTransform) + calc_transform(); - if (clip_rect (x1, y1, xt, yt, _sgp2_cwin->view) == TRUE) { - _sgp2_stylus (_sgp2_cwin, x1, y1, 0); - _sgp2_stylus (_sgp2_cwin, xt, yt, 1); - } + double xndc = m_dCurrentWorldX; + double yndc = m_dCurrentWorldY; + mc_to_ndc.transformPoint (&xndc, &yndc); - for (i = 2; i < n; i++) { - x1 = x2; /* NDC endpoint of last line */ - y1 = y2; - wc_to_ndc (x[i], y[i], &x2, &y2); - xt = x2; - yt = y2; - if (clip_rect (x1, y1, xt, yt, _sgp2_cwin->view) == TRUE) { - _sgp2_stylus (_sgp2_cwin, x1, y1, 0); - _sgp2_stylus (_sgp2_cwin, xt, yt, 1); - } - } + stylusNDC (xndc, yndc, false); // move to location + +#if HAVE_G2_H + if (m_driver.isG2()) { + g2_string (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, const_cast(pszMessage)); + } +#endif +#if HAVE_WXWINDOWS + if (m_driver.isWX()) { + m_driver.idWX()->DrawRotatedText (wxConvCurrent->cMB2WC(pszMessage), m_iCurrentPhysicalX, m_iCurrentPhysicalY, m_dTextAngle); + } +#endif } -void -sgp2_mark_abs (double x, double y) +// NAME +// drawRect Draw box in graphics mode +// +// SYNOPSIS +// drawbox (xmin, ymin, xmax, ymax) +// double xmin, ymin Lower left corner of box +// double xmax, ymax Upper left corner of box +// +// NOTES +// This routine leaves the current position of graphic cursor at lower +// left corner of box. + +void +SGP::drawRect (double xmin, double ymin, double xmax, double ymax) { - double xndc, yndc; + moveAbs (xmin, ymin); + lineAbs (xmax, ymin); + lineAbs (xmax, ymax); + lineAbs (xmin, ymax); + lineAbs (xmin, ymin); +} - if (_sgp2_cwin == NULL) - return; +// FUNCTION +// sgp2_circle - draw circle of radius r at current center - wc_to_ndc (x, y, &xndc, &yndc); - markndc (_sgp2_cwin, xndc, yndc); - _sgp2_cwin->curx = x; - _sgp2_cwin->cury = y; +void +SGP::drawCircle (const double r) +{ + drawArc (r, 0.0, TWOPI); } +//============================================================== +// draw arc around current center. angles in radius +//============================================================== -void -sgp2_mark_rel (double x, double y) +void +SGP::drawArc (const double r, double start, double stop) { - sgp2_mark_abs (x + _sgp2_cwin->curx, y + _sgp2_cwin->cury); + if (start > stop) { + double temp = start; + start = stop; + stop = temp; + } + + double xCent = m_dCurrentWorldX; + double yCent = m_dCurrentWorldY; + + double x = r * cos (start); + double y = r * sin (start); + moveAbs (xCent + x, yCent + y); // move from center to start of arc + + const double thetaIncrement = (5 * (TWOPI / 360)); // 5 degree increments + double cosTheta = cos (thetaIncrement); + double sinTheta = sin (thetaIncrement); + + double angle; + for (angle = start; angle < stop; angle += thetaIncrement) { + double xp = cosTheta * x - sinTheta * y; // translate point by thetaIncrement + double yp = sinTheta * x + cosTheta * y; + lineAbs (xCent + xp, yCent + yp); + x = xp; y = yp; + } + + double c = cos (stop - angle); + double s = sin (stop - angle); + double xp = c * x - s * y; + double yp = s * x + c * y; + lineAbs (xCent + xp, yCent + yp); + + moveAbs (xCent, yCent); // move back to center of circle } -void -sgp2_point_abs (double x, double y) + +/////////////////////////////////////////////////////////////////////// +// Coordinate Transformations +/////////////////////////////////////////////////////////////////////// + + +void +SGP::transformNDCtoMC (double* x, double* y) { - double xndc, yndc; + if (m_bRecalcTransform) + calc_transform(); + ndc_to_mc.transformPoint (x, y); +} - if (_sgp2_cwin == NULL) - return;; - wc_to_ndc (x, y, &xndc, &yndc); - pntndc (_sgp2_cwin, xndc, yndc); - _sgp2_cwin->curx = x; - _sgp2_cwin->cury = y; +void +SGP::transformMCtoNDC (double* x, double* y) +{ + if (m_bRecalcTransform) + calc_transform(); + mc_to_ndc.transformPoint (x, y); } -void -sgp2_point_rel (double x, double y) +void +SGP::transformMCtoNDC (double xIn, double yIn, double* x, double* y) { - sgp2_point_abs (x + _sgp2_cwin->curx, y + _sgp2_cwin->cury); + if (m_bRecalcTransform) + calc_transform(); + *x = xIn; + *y = yIn; + mc_to_ndc.transformPoint (x, y); } -/* NAME - * sgp2_draw_rect Draw box in graphics mode - * - * SYNOPSIS - * drawbox (xmin, ymin, xmax, ymax) - * double xmin, ymin Lower left corner of box - * double xmax, ymax Upper left corner of box - * - * NOTES - * This routine leaves the current position of graphic cursor at lower - * left corner of box. - */ +// NAME +// calc_transform Calculate transform matrices void -sgp2_draw_rect(double xmin, double ymin, double xmax, double ymax) +SGP::calc_transform () { - sgp2_move_abs (xmin, ymin); - sgp2_line_abs (xmax, ymin); - sgp2_line_abs (xmax, ymax); - sgp2_line_abs (xmin, ymax); - sgp2_line_abs (xmin, ymin); + double scaleX = (xv_max - xv_min) / (xw_max - xw_min); + double scaleY = (yv_max - yv_min) / (yw_max - yw_min); + + wc_to_ndc.setIdentity(); + wc_to_ndc.mtx[0][0] = scaleX; + wc_to_ndc.mtx[2][0] = xv_min - scaleX * xw_min; + wc_to_ndc.mtx[1][1] = scaleY; + wc_to_ndc.mtx[2][1] = yv_min - scaleY * yw_min; + + mc_to_ndc = m_ctm * wc_to_ndc; + ndc_to_mc = mc_to_ndc.invert(); + + m_bRecalcTransform = false; } -/* FUNCTION - * sgp2_circle - draw circle of radius r at current center - */ +void +SGP::ctmClear () +{ + m_ctm.setIdentity(); + calc_transform(); +} -void -sgp2_draw_circle (const double r) +void +SGP::ctmSet (const TransformationMatrix2D& m) { - sgp2_draw_arc (0.0, 7.0, r); + m_ctm = m; + calc_transform(); } -/*==============================================================*/ -/* draw arc around current center. pass angles and radius */ -/*==============================================================*/ -void -sgp2_draw_arc (double start, double stop, const double r) +void +SGP::preTranslate (double x, double y) { - double c, s, theta, angle; - float x, y, xp, yp; + TransformationMatrix2D m; + + m.setTranslate (x, y); + ctmSet (m * m_ctm); +} - if ((stop-start) > 2 * PI) - stop = start + 2 * PI; - if ((start-stop) > 2 * PI) - stop = start + 2 * PI; - while (start >= stop) - stop += 2*PI; - x = r * cos ((double) start); - y = r * sin ((double) start); - sgp2_move_rel (x, y); /* move from center to start of arc */ +void +SGP::postTranslate (double x, double y) +{ + TransformationMatrix2D m; - theta = 5 * PI / 180; - c = cos(theta); - s = sin(theta); + m.setTranslate (x, y); + ctmSet (m_ctm * m); +} - for (angle = start; angle < stop - theta; angle += theta) { - xp = c * x - s * y; - yp = s * x + c * y; - sgp2_line_rel (xp - x, yp - y); - x = xp; y = yp; - } - c = cos (stop - angle); - s = sin (stop - angle); - xp = c * x - s * y; - yp = s * x + c * y; - sgp2_line_rel (xp - x, yp - y); +void +SGP::preScale (double sx, double sy) +{ + TransformationMatrix2D m; - x = r * cos ((double) stop); - y = r * sin ((double) stop); - sgp2_move_rel (-x, -y); /* move back to center of circle */ + m.setScale (sx, sy); + ctmSet (m * m_ctm); } -/*----------------------------------------------------------------------*/ -/* Current Transformation Matrix Routine */ -/*----------------------------------------------------------------------*/ +void +SGP::postScale (double sx, double sy) +{ + TransformationMatrix2D m; + m.setScale (sx, sy); + m_ctm = m_ctm * m; + ctmSet (m_ctm * m); +} -/* NAME - * ctm_clr_2 Clear current transformation matrix - * - * SYNOPSIS - * ctm_clr_2() - */ -void -ctm_clr_2 (void) +void +SGP::preRotate (double theta) { - GRFMTX_2D m; + TransformationMatrix2D m; - ident_gmtx_2 (m); - ctm_set_2 (m); + m.setRotate (theta); + m_ctm = m * m_ctm; + ctmSet (m * m_ctm); } -/* NAME - * ctm_get_2 Get ctm - * - * SYNOPSIS - * ctm_get_2 (m) - * OUT GRFMTX_2D m Copy of ctm - */ - -void -ctm_get_2 (GRFMTX_2D m) +void +SGP::postRotate (double theta) { - int x, y; - - if (_sgp2_cwin == NULL) - return; + TransformationMatrix2D m; - for (x = 0; x < 3; x++) - for (y = 0; y < 3; y++) - m[x][y] = _sgp2_cwin->ctm_2_x[x][y]; + m.setRotate (theta); + ctmSet (m_ctm * m); } -/* NAME - * ctm_set_2 Set ctm to a matrix - * - * SYNOPSIS - * ctm_get_ctm_2 (m) - * IN GRFMTX m New ctm - */ - -void -ctm_set_2 (GRFMTX_2D m) +void +SGP::preShear (double shrx, double shry) { - int x, y; - if (_sgp2_cwin == NULL) - return; - - for (x = 0; x < 3; x++) - for (y = 0; y < 3; y++) - _sgp2_cwin->ctm_2_x[x][y] = m[x][y]; + TransformationMatrix2D m; - _sgp2_cwin->recalc_ndc_to_mc = TRUE; - _sgp2_cwin->recalc_mc_to_ndc = TRUE; + m.setShear (shrx, shry); + ctmSet (m * m_ctm); } -void -ctm_pre_mult_2 (GRFMTX_2D m) +void +SGP::postShear (double shrx, double shry) { - GRFMTX_2D new_ctm; + TransformationMatrix2D m; - mult_gmtx_2 (m, _sgp2_cwin->ctm_2_x, new_ctm); - ctm_set_2 (new_ctm); + m.setShear (shrx, shry); + ctmSet (m_ctm * m); } -void -ctm_post_mult_2 (GRFMTX_2D m) +//////////////////////////////////////////////////////////////////////// +// Bitmap Markers +//////////////////////////////////////////////////////////////////////// + +// Pixel patterns of marker symbols (1x1 to 5x5 matrix) +const unsigned char SGP::MARKER_BITMAP[MARK_COUNT][5] = { - GRFMTX_2D new_ctm; + {'\000', '\000', '\010', '\000', '\000'}, // small dot + {'\000', '\034', '\024', '\034', '\000'}, // empty square + {'\000', '\034', '\034', '\034', '\000'}, // filled square + {'\000', '\010', '\024', '\010', '\000'}, // empty diamond + {'\000', '\010', '\034', '\010', '\000'}, // filled diamond + {'\010', '\010', '\076', '\010', '\010'}, // cross + {'\000', '\024', '\010', '\024', '\000'}, // X + {'\034', '\042', '\042', '\042', '\034'}, // open circle + {'\034', '\076', '\076', '\076', '\034'}, // filled circle + {'\076', '\042', '\042', '\042', '\076'}, // big open square + {'\010', '\024', '\042', '\024', '\010'}, // big open diamond +}; + - mult_gmtx_2 (_sgp2_cwin->ctm_2_x, m, new_ctm); - ctm_set_2 (new_ctm); +#if HAVE_WXWINDOWS +void +SGP::setDC (wxDC* pDC) +{ + if (m_driver.isWX()) { + m_driver.setDC(pDC); + initFromDC (pDC); + setTextPointSize (m_iTextPointSize); + } } +#endif