void wxSVGFileDCImpl::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea) { /* Draws an arc of an ellipse. The current pen is used for drawing the arc and the current brush is used for drawing the pie. This function is currently only available for X window and PostScript device contexts. x and y specify the x and y coordinates of the upper-left corner of the rectangle that contains the ellipse. width and height specify the width and height of the rectangle that contains the ellipse. start and end specify the start and end of the arc relative to the three-o'clock position from the center of the rectangle. Angles are specified in degrees (360 is a complete circle). Positive values mean counter-clockwise motion. If start is equal to end, a complete ellipse will be drawn. */ //known bug: SVG draws with the current pen along the radii, but this does not happen in wxMSW NewGraphicsIfNeeded(); wxString s; //radius double rx = w / 2; double ry = h / 2; // center double xc = x + rx; double yc = y + ry; double xs, ys, xe, ye; xs = xc + rx * cos (DegToRad(sa)); xe = xc + rx * cos (DegToRad(ea)); ys = yc - ry * sin (DegToRad(sa)); ye = yc - ry * sin (DegToRad(ea)); ///now same as circle arc... double theta1 = atan2(ys-yc, xs-xc); double theta2 = atan2(ye-yc, xe-xc); int fArc; // flag for large or small arc 0 means less than 180 degrees if ( (theta2 - theta1) > 0 ) fArc = 1; else fArc = 0; int fSweep; if ( fabs(theta2 - theta1) > M_PI) fSweep = 1; else fSweep = 0; s.Printf ( wxT("<path d=\"M%d %d A%d %d 0.0 %d %d %d %d L %d %d z "), int(xs), int(ys), int(rx), int(ry), fArc, fSweep, int(xe), int(ye), int(xc), int(yc) ); s += wxT(" \" /> \n"); if (m_OK) { write(s); } }
void wxSVGFileDCImpl::DoDrawBitmap(const class wxBitmap & bmp, wxCoord x, wxCoord y , bool WXUNUSED(bTransparent) /*=0*/ ) { NewGraphicsIfNeeded(); // If we don't have any bitmap handler yet, use the default one. if ( !m_bmp_handler ) m_bmp_handler = new wxSVGBitmapFileHandler(); m_bmp_handler->ProcessBitmap(bmp, x, y, *m_outfile); }
void wxSVGFileDCImpl::DoDrawPoint (wxCoord x1, wxCoord y1) { wxString s; NewGraphicsIfNeeded(); s = wxT("<g style = \"stroke-linecap:round;\" > \n"); write(s); DoDrawLine ( x1,y1,x1,y1 ); s = wxT("</g>"); write(s); }
void wxSVGFileDCImpl::Clear() { { wxDCBrushChanger setBackground(*GetOwner(), m_backgroundBrush); wxDCPenChanger setTransp(*GetOwner(), *wxTRANSPARENT_PEN); DoDrawRectangle(0, 0, m_width, m_height); } NewGraphicsIfNeeded(); }
void wxSVGFileDCImpl::DoDrawLine (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2) { NewGraphicsIfNeeded(); wxString s; s.Printf ( wxT("<path d=\"M%d %d L%d %d\" /> \n"), x1,y1,x2,y2 ); if (m_OK) { write(s); } CalcBoundingBox(x1, y1); CalcBoundingBox(x2, y2); }
void wxSVGFileDCImpl::DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2) { NewGraphicsIfNeeded(); wxString s; s = wxString::Format(wxS(" <path %sd=\"M%d %d L%d %d\"/>\n"), wxGetPenPattern(m_pen), x1, y1, x2, y2); write(s); CalcBoundingBox(x1, y1); CalcBoundingBox(x2, y2); }
void wxSVGFileDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius) { NewGraphicsIfNeeded(); wxString s; s = wxString::Format(wxS(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%s\"%s"), x, y, width, height, NumStr(radius), wxGetBrushFill(m_brush)); s += wxS("/>\n"); write(s); CalcBoundingBox(x, y); CalcBoundingBox(x + width, y + height); }
void wxSVGFileDCImpl::DoDrawArc(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc) { /* Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1) and ending at (x2, y2). The current pen is used for the outline and the current brush for filling the shape. The arc is drawn in an anticlockwise direction from the start point to the end point. Might be better described as Pie drawing */ NewGraphicsIfNeeded(); wxString s; // we need the radius of the circle which has two estimates double r1 = sqrt ( double( (x1-xc)*(x1-xc) ) + double( (y1-yc)*(y1-yc) ) ); double r2 = sqrt ( double( (x2-xc)*(x2-xc) ) + double( (y2-yc)*(y2-yc) ) ); wxASSERT_MSG( (fabs ( r2-r1 ) <= 3), wxT("wxSVGFileDC::DoDrawArc Error in getting radii of circle")); if ( fabs ( r2-r1 ) > 3 ) //pixels { s = wxT("<!--- wxSVGFileDC::DoDrawArc Error in getting radii of circle --> \n"); write(s); } double theta1 = atan2((double)(yc-y1),(double)(x1-xc)); if ( theta1 < 0 ) theta1 = theta1 + M_PI * 2; double theta2 = atan2((double)(yc-y2), (double)(x2-xc)); if ( theta2 < 0 ) theta2 = theta2 + M_PI * 2; if ( theta2 < theta1 ) theta2 = theta2 + M_PI *2; int fArc; // flag for large or small arc 0 means less than 180 degrees if ( fabs(theta2 - theta1) > M_PI ) fArc = 1; else fArc = 0; int fSweep = 0; // flag for sweep always 0 s.Printf ( wxT("<path d=\"M%d %d A%s %s 0.0 %d %d %d %d L%d %d z "), x1,y1, NumStr(r1), NumStr(r2), fArc, fSweep, x2, y2, xc, yc ); // the z means close the path and fill s += wxT(" \" /> \n"); if (m_OK) { write(s); } }
void wxSVGFileDCImpl::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height) { NewGraphicsIfNeeded(); int rh = height / 2; int rw = width / 2; wxString s; s = wxString::Format(wxS(" <ellipse cx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\""), x + rw, y + rh, rw, rh); s += wxS("/>\n"); write(s); CalcBoundingBox(x, y); CalcBoundingBox(x + width, y + height); }
void wxSVGFileDCImpl::DoDrawBitmap(const class wxBitmap & bmp, wxCoord x, wxCoord y , bool WXUNUSED(bTransparent) /*=0*/ ) { NewGraphicsIfNeeded(); wxString sTmp, s, sPNG; if ( wxImage::FindHandler(wxBITMAP_TYPE_PNG) == NULL ) wxImage::AddHandler(new wxPNGHandler); // create suitable file name sTmp.Printf ( wxT("_image%d.png"), m_sub_images); sPNG = m_filename.BeforeLast(wxT('.')) + sTmp; while (wxFile::Exists(sPNG) ) { m_sub_images ++; sTmp.Printf ( wxT("_image%d.png"), m_sub_images); sPNG = m_filename.BeforeLast(wxT('.')) + sTmp; } //create copy of bitmap (wxGTK doesn't like saving a constant bitmap) wxBitmap myBitmap = bmp; //save it bool bPNG_OK = myBitmap.SaveFile(sPNG,wxBITMAP_TYPE_PNG); // reference the bitmap from the SVG doc // only use filename & ext sPNG = sPNG.AfterLast(wxFileName::GetPathSeparator()); // reference the bitmap from the SVG doc int w = myBitmap.GetWidth(); int h = myBitmap.GetHeight(); sTmp.Printf ( wxT(" <image x=\"%d\" y=\"%d\" width=\"%dpx\" height=\"%dpx\" "), x,y,w,h ); s += sTmp; sTmp.Printf ( wxT(" xlink:href=\"%s\"> \n"), sPNG.c_str() ); s += sTmp + wxT("<title>Image from wxSVG</title> </image>") + wxT("\n"); if (m_OK && bPNG_OK) { write(s); } m_OK = m_outfile->IsOk() && bPNG_OK; }
void wxSVGFileDCImpl::DoDrawLines(int n, const wxPoint points[], wxCoord xoffset, wxCoord yoffset) { if (n > 1) { NewGraphicsIfNeeded(); wxString s; s = wxS(" <path ") + wxGetPenPattern(m_pen); s += wxString::Format(wxS("d=\"M%d %d"), (points[0].x + xoffset), (points[0].y + yoffset)); CalcBoundingBox(points[0].x + xoffset, points[0].y + yoffset); for (int i = 1; i < n; ++i) { s += wxString::Format(wxS(" L%d %d"), (points[i].x + xoffset), (points[i].y + yoffset)); CalcBoundingBox(points[i].x + xoffset, points[i].y + yoffset); } s += wxS("\" style=\"fill:none\"/>\n"); write(s); } }
void wxSVGFileDCImpl::DoDrawPolygon(int n, const wxPoint points[], wxCoord xoffset, wxCoord yoffset, wxPolygonFillMode fillStyle) { NewGraphicsIfNeeded(); wxString s, sTmp; s = wxT("<polygon style=\""); if ( fillStyle == wxODDEVEN_RULE ) s += wxT("fill-rule:evenodd; "); else s += wxT("fill-rule:nonzero; "); s += wxT("\" \npoints=\""); for (int i = 0; i < n; i++) { sTmp.Printf ( wxT("%d,%d"), points [i].x+xoffset, points[i].y+yoffset ); s += sTmp + wxT("\n"); CalcBoundingBox ( points [i].x+xoffset, points[i].y+yoffset); } s += wxT("\" /> \n"); write(s); }
void wxSVGFileDCImpl::DoDrawRotatedText(const wxString& sText, wxCoord x, wxCoord y, double angle) { //known bug; if the font is drawn in a scaled DC, it will not behave exactly as wxMSW NewGraphicsIfNeeded(); wxString s, sTmp; // calculate bounding box wxCoord w, h, desc; DoGetTextExtent(sText, &w, &h, &desc); double rad = wxDegToRad(angle); // wxT("upper left") and wxT("upper right") CalcBoundingBox(x, y); CalcBoundingBox((wxCoord)(x + w*cos(rad)), (wxCoord)(y - h*sin(rad))); // wxT("bottom left") and wxT("bottom right") CalcBoundingBox((wxCoord)(x + h*sin(rad)), (wxCoord)(y + h*cos(rad))); CalcBoundingBox((wxCoord)(x + h*sin(rad) + w*cos(rad)), (wxCoord)(y + h*cos(rad) - w*sin(rad))); if (m_backgroundMode == wxBRUSHSTYLE_SOLID) { // draw background first // just like DoDrawRectangle except we pass the text color to it and set the border to a 1 pixel wide text background sTmp.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" "), x, y, w, h ); s = sTmp + wxT("style=\"") + wxBrushString(m_textBackgroundColour); s += wxT("stroke-width:1; ") + wxPenString(m_textBackgroundColour); sTmp.Printf ( wxT("\" transform=\"rotate( %s %d %d ) \" />"), NumStr(-angle), x,y ); s += sTmp + wxT("\n"); write(s); } // convert x,y to SVG text x,y (the coordinates of the text baseline) x = (wxCoord)(x + (h-desc)*sin(rad)); y = (wxCoord)(y + (h-desc)*cos(rad)); //now do the text itself s.Printf (wxT(" <text x=\"%d\" y=\"%d\" "),x,y ); sTmp = m_font.GetFaceName(); if (sTmp.Len() > 0) s += wxT("style=\"font-family:") + sTmp + wxT("; "); else s += wxT("style=\" "); wxString fontweights [3] = { wxT("normal"), wxT("lighter"), wxT("bold") }; s += wxT("font-weight:") + fontweights[m_font.GetWeight() - wxNORMAL] + wxT("; "); wxString fontstyles [5] = { wxT("normal"), wxT("style error"), wxT("style error"), wxT("italic"), wxT("oblique") }; s += wxT("font-style:") + fontstyles[m_font.GetStyle() - wxNORMAL] + wxT("; "); sTmp.Printf (wxT("font-size:%dpt; "), m_font.GetPointSize() ); s += sTmp; //text will be solid, unless alpha value isn't opaque in the foreground colour s += wxBrushString(m_textForegroundColour) + wxPenString(m_textForegroundColour); sTmp.Printf ( wxT("stroke-width:0;\" transform=\"rotate( %s %d %d ) \" >"), NumStr(-angle), x,y ); s += sTmp + wxMarkupParser::Quote(sText) + wxT("</text> ") + wxT("\n"); if (m_OK) { write(s); } }
void wxSVGFileDCImpl::DoDrawEllipticArc(wxCoord x, wxCoord y, wxCoord w, wxCoord h, double sa, double ea) { /* Draws an arc of an ellipse. The current pen is used for drawing the arc and the current brush is used for drawing the pie. x and y specify the x and y coordinates of the upper-left corner of the rectangle that contains the ellipse. width and height specify the width and height of the rectangle that contains the ellipse. start and end specify the start and end of the arc relative to the three-o'clock position from the center of the rectangle. Angles are specified in degrees (360 is a complete circle). Positive values mean counter-clockwise motion. If start is equal to end, a complete ellipse will be drawn. */ //radius double rx = w / 2.0; double ry = h / 2.0; // center double xc = x + rx; double yc = y + ry; // start and end coords double xs, ys, xe, ye; xs = xc + rx * cos (wxDegToRad(sa)); xe = xc + rx * cos (wxDegToRad(ea)); ys = yc - ry * sin (wxDegToRad(sa)); ye = yc - ry * sin (wxDegToRad(ea)); // svg arcs have 0 degrees at 12-o'clock instead of 3-o'clock double start = (sa - 90); if (start < 0) start += 360; while (abs(start) > 360) start -= (start / abs(start)) * 360; double end = (ea - 90); if (end < 0) end += 360; while (abs(end) > 360) end -= (end / abs(end)) * 360; // svg arcs are in clockwise direction, reverse angle double angle = end - start; if (angle <= 0) angle += 360; int fArc = angle > 180 ? 1 : 0; // flag for large or small arc int fSweep = 0; // flag for sweep always 0 wxString arcPath; if (angle == 360) { // Drawing full circle fails with default arc. Draw two half arcs instead. fArc = 1; arcPath = wxString::Format(wxS(" <path d=\"M%s %s a%s %s 0 %d %d %s %s a%s %s 0 %d %d %s %s"), NumStr(x), NumStr(y + ry), NumStr(rx), NumStr(ry), fArc, fSweep, NumStr( rx * 2), NumStr(0), NumStr(rx), NumStr(ry), fArc, fSweep, NumStr(-rx * 2), NumStr(0)); } else { arcPath = wxString::Format(wxS(" <path d=\"M%s %s A%s %s 0 %d %d %s %s"), NumStr(xs), NumStr(ys), NumStr(rx), NumStr(ry), fArc, fSweep, NumStr(xe), NumStr(ye)); } // Workaround so SVG does not draw an extra line from the centre of the drawn arc // to the start point of the arc. // First draw the arc with the current brush, without a border, // then draw the border without filling the arc. if (GetBrush().GetStyle() != wxBRUSHSTYLE_TRANSPARENT) { wxDCPenChanger setTransp(*GetOwner(), *wxTRANSPARENT_PEN); NewGraphicsIfNeeded(); wxString arcFill = arcPath; arcFill += wxString::Format(wxS(" L%s %s z"), NumStr(xc), NumStr(yc)); arcFill += wxS("\"/>\n"); write(arcFill); } wxDCBrushChanger setTransp(*GetOwner(), *wxTRANSPARENT_BRUSH); NewGraphicsIfNeeded(); wxString arcLine = arcPath + wxS("\"/>\n"); write(arcLine); }
void wxSVGFileDCImpl::DoDrawArc(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc) { /* Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1) and ending at (x2, y2). The current pen is used for the outline and the current brush for filling the shape. The arc is drawn in an anticlockwise direction from the start point to the end point. Might be better described as Pie drawing */ NewGraphicsIfNeeded(); wxString s; // we need the radius of the circle which has two estimates double r1 = sqrt ( double( (x1-xc)*(x1-xc) ) + double( (y1-yc)*(y1-yc) ) ); double r2 = sqrt ( double( (x2-xc)*(x2-xc) ) + double( (y2-yc)*(y2-yc) ) ); wxASSERT_MSG( (fabs ( r2-r1 ) <= 3), wxS("wxSVGFileDC::DoDrawArc Error in getting radii of circle")); if ( fabs ( r2-r1 ) > 3 ) //pixels { s = wxS("<!--- wxSVGFileDC::DoDrawArc Error in getting radii of circle -->\n"); write(s); } double theta1 = atan2((double)(yc - y1), (double)(x1 - xc)); if (theta1 < 0) theta1 = theta1 + M_PI * 2; double theta2 = atan2((double)(yc - y2), (double)(x2 - xc)); if (theta2 < 0) theta2 = theta2 + M_PI * 2; if (theta2 < theta1) theta2 = theta2 + M_PI * 2; int fArc; // flag for large or small arc 0 means less than 180 degrees if (fabs(theta2 - theta1) > M_PI) fArc = 1; else fArc = 0; int fSweep = 0; // flag for sweep always 0 if (x1 == x2 && y1 == y2) { // drawing full circle fails with default arc. Draw two half arcs instead. s = wxString::Format(wxS(" <path d=\"M%d %d a%s %s 0 %d %d %s %s a%s %s 0 %d %d %s %s"), x1, y1, NumStr(r1), NumStr(r2), fArc, fSweep, NumStr( r1 * 2), NumStr(0), NumStr(r1), NumStr(r2), fArc, fSweep, NumStr(-r1 * 2), NumStr(0)); } else { // comply to wxDC specs by drawing closing line if brush is not transparent wxString line; if (GetBrush().GetStyle() != wxBRUSHSTYLE_TRANSPARENT) line = wxString::Format(wxS("L%d %d z"), xc, yc); s = wxString::Format(wxS(" <path d=\"M%d %d A%s %s 0 %d %d %d %d %s"), x1, y1, NumStr(r1), NumStr(r2), fArc, fSweep, x2, y2, line); } s += wxS("\"/>\n"); write(s); }
void wxSVGFileDCImpl::DoDrawRotatedText(const wxString& sText, wxCoord x, wxCoord y, double angle) { //known bug; if the font is drawn in a scaled DC, it will not behave exactly as wxMSW NewGraphicsIfNeeded(); wxString s; // Get extent of whole text. wxCoord w, h, heightLine; GetOwner()->GetMultiLineTextExtent(sText, &w, &h, &heightLine); // Compute the shift for the origin of the next line. const double rad = wxDegToRad(angle); const double dx = heightLine * sin(rad); const double dy = heightLine * cos(rad); // wxS("upper left") and wxS("upper right") CalcBoundingBox(x, y); CalcBoundingBox((wxCoord)(x + w*cos(rad)), (wxCoord)(y - h*sin(rad))); // wxS("bottom left") and wxS("bottom right") CalcBoundingBox((wxCoord)(x + h*sin(rad)), (wxCoord)(y + h*cos(rad))); CalcBoundingBox((wxCoord)(x + h*sin(rad) + w*cos(rad)), (wxCoord)(y + h*cos(rad) - w*sin(rad))); if (m_backgroundMode == wxBRUSHSTYLE_SOLID) { // draw background first // just like DoDrawRectangle except we pass the text color to it and set the border to a 1 pixel wide text background s += wxString::Format(wxS(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" "), x, y, w, h); s += wxS("style=\"") + wxBrushString(m_textBackgroundColour); s += wxS("stroke-width:1; ") + wxPenString(m_textBackgroundColour); s += wxString::Format(wxS("\" transform=\"rotate(%s %d %d)\"/>"), NumStr(-angle), x, y); s += wxS("\n"); write(s); } // Draw all text line by line const wxArrayString lines = wxSplit(sText, '\n', '\0'); for (size_t lineNum = 0; lineNum < lines.size(); lineNum++) { // convert x,y to SVG text x,y (the coordinates of the text baseline) wxCoord ww, hh, desc; DoGetTextExtent(lines[lineNum], &ww, &hh, &desc); int xx = x + wxRound(lineNum * dx) + (hh - desc) * sin(rad); int yy = y + wxRound(lineNum * dy) + (hh - desc) * cos(rad); //now do the text itself s += wxString::Format(wxS(" <text x=\"%d\" y=\"%d\" textLength=\"%d\" "), xx, yy, ww); wxString fontName(m_font.GetFaceName()); if (fontName.Len() > 0) s += wxS("style=\"font-family:") + fontName + wxS("; "); else s += wxS("style=\" "); wxString fontweight; switch (m_font.GetWeight()) { case wxFONTWEIGHT_MAX: wxFAIL_MSG(wxS("invalid font weight value")); wxFALLTHROUGH; case wxFONTWEIGHT_NORMAL: fontweight = wxS("normal"); break; case wxFONTWEIGHT_LIGHT: fontweight = wxS("lighter"); break; case wxFONTWEIGHT_BOLD: fontweight = wxS("bold"); break; } wxASSERT_MSG(!fontweight.empty(), wxS("unknown font weight value")); s += wxS("font-weight:") + fontweight + wxS("; "); wxString fontstyle; switch (m_font.GetStyle()) { case wxFONTSTYLE_MAX: wxFAIL_MSG(wxS("invalid font style value")); wxFALLTHROUGH; case wxFONTSTYLE_NORMAL: fontstyle = wxS("normal"); break; case wxFONTSTYLE_ITALIC: fontstyle = wxS("italic"); break; case wxFONTSTYLE_SLANT: fontstyle = wxS("oblique"); break; } wxASSERT_MSG(!fontstyle.empty(), wxS("unknown font style value")); s += wxS("font-style:") + fontstyle + wxS("; "); wxString textDecoration; if (m_font.GetUnderlined()) textDecoration += wxS(" underline"); if (m_font.GetStrikethrough()) textDecoration += wxS(" line-through"); if (textDecoration.IsEmpty()) textDecoration = wxS(" none"); s += wxS("text-decoration:") + textDecoration + wxS("; "); s += wxString::Format(wxS("font-size:%dpt; "), m_font.GetPointSize()); //text will be solid, unless alpha value isn't opaque in the foreground colour s += wxBrushString(m_textForegroundColour) + wxPenString(m_textForegroundColour); s += wxString::Format(wxS("stroke-width:0;\" transform=\"rotate(%s %d %d)\""), NumStr(-angle), xx, yy); s += wxS(" xml:space=\"preserve\">"); s += wxMarkupParser::Quote(lines[lineNum]) + wxS("</text>\n"); write(s); } }