/* drvCGM.cc : This file is part of pstoedit Backend for CGM format Copyright (C) 1993,1994,1995,1996 Wolfgang Glunz, Wolfgang.Glunz@zfe.siemens.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include "drvcgm.h" #include "cd/cd.h" #ifdef __TCPLUSPLUS__ #include #endif // for sin and cos #include static const unsigned int imageHeight = 1000; static const unsigned int imageWidth = 1000; #define cdcall(func,params) if (! func params) {\ cerr << "call to cd-library " #func " failed" << endl;\ return ; \ } drvCGM::drvCGM(ostream & theoutStream,bool binary): drvbase(theoutStream,(!binary),0,1), // only ascii version supports subpaths so far binary_(binary), cdpoints(0), cgmimage(0) { // we allocate a cdImage also for the ascii backend, because we use // the color functions from the cd library cgmimage = cdImageCreate(imageWidth, imageHeight); if (binary_) { cdImageColorAllocate(cgmimage,255,255,255); // set background color cdpoints = new cdPoint[maxElements]; if (!cdpoints) { cerr << "Could not allocate space for points" << endl; exit(1); } } else { outf << "BegMF \"picture made with pstoedit\";\n"; outf << "MFVersion 1;\n"; outf << "mfelemlist 'DRAWINGPLUS';\n"; outf << "colrprec 255;\n"; outf << "colrindexprec 127;\n"; outf << "maxcolrindex 255;\n"; } } drvCGM::~drvCGM() { if (binary_) { // free points, so new memory is there for the // cd write functions delete [] cdpoints; FILE * outfile = tmpfile(); cdcall(cdImageCgm,(cgmimage, outfile)); cdcall(cdImageDestroy,(cgmimage)); cgmimage = 0; rewind(outfile); filebuf outbuf(fileno(outfile)); outf << &outbuf; // This copies outbuf to outf } else { cdcall(cdImageDestroy,(cgmimage)); outf << "EndMF;\n"; } } static float rnd(const float f,const float roundnumber) { return ((long int) ( (f * roundnumber) + 0.5 )) / roundnumber; } static inline float RND3(const float f) { return rnd(f,1000);} static inline int RND(const float f) { return f;} void drvCGM::print_coords() { #if 0 for (unsigned int n = 0; n < numberOfElementsInPath(); n++) { const Point & p = pathElement(n).getPoint(0); outf << " (" << (int)( p.x_ + x_offset) << ',' << (int)( p.y_ + y_offset) << ')'; } #else bool first = true; bool newpath = true; bool lastwasclosepath = false; Point lastMoveto(0,0); for (unsigned int n = 0; n < numberOfElementsInPath(); n++) { const basedrawingelement & elem = pathElement(n); lastwasclosepath = (elem.getType() == closepath); if (newpath) { switch (currentShowType() ) { case drvbase::stroke : // draw as line // terminate and start a new Line; outf << " Line " ; break; case drvbase::fill : // draw each segment as a polygon outf << " Polygon " ; break; case drvbase::eofill : // dump the whole path as a large polygon set outf << " PolygonSet " ; break; default: // cannot happen cerr << "unexpected ShowType " << (int) currentShowType() << endl; exit(1); break; } newpath = 0; } switch (elem.getType()) { case moveto: if (first) { first = 0; } else { switch (currentShowType() ) { case drvbase::stroke : // draw as line // terminate and start a new Line; outf << " ;\n"; outf << " Line " ; break; case drvbase::fill : // draw each segment as a polygon outf << " ;\n"; outf << " Polygon " ; break; case drvbase::eofill : // dump the whole path as a large polygon set outf << " closeinvis "; break; default: // cannot happen cerr << "unexpected ShowType " << (int) currentShowType() << endl; exit(1); break; } } { const Point & p = elem.getPoint(0); lastMoveto=p; outf << RND(p.x_ + x_offset) << " " << RND(p.y_ + y_offset) << " " ; } break; case lineto: if (currentShowType() == drvbase::eofill) { outf << " vis "; } else { outf << " "; } { const Point & p = elem.getPoint(0); outf << RND(p.x_ + x_offset) << " " << RND(p.y_ + y_offset) << " " ; } break; case closepath: switch (currentShowType() ) { case drvbase::stroke : // draw a line to the start of the current line // and prepare for a new line outf << RND(lastMoveto.x_ + x_offset) << " " << RND(lastMoveto.y_ + y_offset) << " " ; outf << ";\n"; newpath=1; break; case drvbase::fill : // close and prepare for a new path. outf << " ;\n"; newpath=1; break; case drvbase::eofill : // normal close outf << " closevis "; break; default: // cannot happen cerr << "unexpected ShowType " << (int) currentShowType() << endl; exit(1); break; } break; case curveto: cerr << "Fatal: unexpected case in drvpdf " << endl; exit(1); break; default: cerr << "Fatal: unexpected case in drvpdf " << endl; exit(1); break; } outf << '\n'; } if (lastwasclosepath) { // a closepath was the last statement, so the path is really closed // except in the case of an eofilled path if (currentShowType() == drvbase::eofill) { outf << " ;\n" ; } } else { // implicit close path if (currentShowType() == drvbase::stroke) { outf << " ;\n"; } else { outf << " ;\n"; } } #endif } void drvCGM::open_page() { if (binary_) { } else { outf << " BegPic \"page: " << currentPageNumber << " \";\n"; outf << " vdcext (0,0) (" << imageWidth << ',' << imageHeight << ");\n"; outf << " colrmode indexed;\n"; outf << " linewidthmode vdc;\n"; outf << " edgewidthmode vdc;\n"; // outf << " ScaleMode Metric 0.1;\n"; outf << " BegPicBody;\n"; getcdcolor(1.0,1.0,1.0); // write white color index outf << " edgevis on;\n"; // needed, otherwise vis/invis has no effect } } void drvCGM::close_page() { if (binary_) { } else { outf << " EndPic;\n"; } } const char *CGMFonts[] = { " ", // because they start with index 1 "Times-Roman", "Times-Roman", "Times-Italic", "Times-Bold", "Times-BoldItalic", "Helvetica", "Helvetica-Oblique", "Helvetica-Bold", "Helvetica-BoldOblique", "Courier", "Courier-Oblique", "Courier-Bold", "Courier-BoldOblique", "Symbol" }; unsigned int drvCGM::getcdcolor(float R, float G, float B) { const unsigned int r = R * 255; const unsigned int g = G * 255; const unsigned int b = B * 255; int cdcolor = cdImageColorExact(cgmimage,r,g,b); if (cdcolor < 0) { // not stored so far cdcolor = cdImageColorAllocate(cgmimage,r,g,b); if (cdcolor < 0) { cdcolor = cdImageColorClosest(cgmimage,r,g,b); } else { // newly allocated color if (! binary_) { outf << " colrtable " << cdcolor << ' ' << cdImageRed(cgmimage,cdcolor) << ' ' << cdImageGreen(cgmimage,cdcolor) << ' ' << cdImageBlue(cgmimage,cdcolor) << ";\n"; } } } return cdcolor; } void drvCGM::show_text(const TextInfo & textinfo) { const unsigned int cdcolor = getcdcolor(textinfo.currentR,textinfo.currentG,textinfo.currentB); const float toRadians = 3.14159265359 / 180.0; const float angleInRadians = textinfo.currentFontAngle * toRadians; const int xbase = 1000*cos(angleInRadians); const int ybase = 1000*sin(angleInRadians); const int xup=-ybase; const int yup=xbase; if (binary_) { const unsigned int fontnr = 5; const int height = textinfo.currentFontSize; cdSetTextAttrib(cgmimage,fontnr,cdcolor,height); cdSetTextOrient(cgmimage,xup,yup,xbase,ybase); cdText(cgmimage,textinfo.x,textinfo.y,textinfo.thetext); } else { int MAXFNTNUM,CGMFontNum,fntlength; MAXFNTNUM = sizeof(CGMFonts)/(sizeof(char *)) - 1; CGMFontNum = 1; fntlength = strlen(textinfo.currentFontName); for (unsigned int i=0; i<=MAXFNTNUM; i++) { if (fntlength == strlen(CGMFonts[i])) { if (strncmp(textinfo.currentFontName,CGMFonts[i],fntlength) == 0) CGMFontNum = i; } } outf << " charheight " << textinfo.currentFontSize << ";\n"; outf << " charori " << xup << ' ' << yup << ' ' << xbase << ' ' << ybase << ";\n"; outf << " TEXT (" << textinfo.x << ',' << textinfo.y << ") final '" ; { const char * cp = textinfo.thetext; while (*cp) { if (*cp == '\'') outf << '\''; outf << *cp; cp++; } } outf << "';\n"; } } void drvCGM::show_path() { const unsigned int cdedgecolor = getcdcolor(edgeR(),edgeG(),edgeB()); const unsigned int cdfillcolor = getcdcolor(fillR(),fillG(),fillB()); if (binary_) { for (unsigned int n = 0; n < numberOfElementsInPath(); n++) { const Point & p = pathElement(n).getPoint(0); cdpoints[n].x = p.x_; cdpoints[n].y = p.y_; } #ifdef __TCPLUSPLUS__ if (verbose) cerr << "core left " << coreleft() << " " << farcoreleft() << endl; #endif const unsigned int cdLineWidth = currentLineWidth(); const bool visible = (currentLineWidth() > 0.0); const int solid = 1; switch ( currentShowType() ) { case drvbase::stroke: cdcall(cdSetLineAttrib,(cgmimage,solid,cdLineWidth,cdedgecolor)); break; case drvbase::fill: // cdcall(cdSetFillStyle,(cgmimage, solid)); // cdcall(cdSetFillColor,(cgmimage, cdfillcolor)); // cdcall(cdSetFillHatch,(cgmimage, 1)); cdcall(cdSetShapeFillAttrib,(cgmimage,solid,cdfillcolor,1)); // cdcall(cdSetEdgeType,(cgmimage, solid)); // cdcall(cdSetEdgeWidth,(cgmimage, cdLineWidth)); // cdcall(cdSetEdgeColor,(cgmimage, cdedgecolor)); // cdcall(cdSetEdgeVis,(cgmimage, visible)); cdcall(cdSetShapeEdgeAttrib,(cgmimage,solid,cdLineWidth,cdedgecolor,visible)); break; case drvbase::eofill: // This may be wrong, but there is no other way // at the moment // cdcall(cdSetFillStyle,(cgmimage, solid)); // cdcall(cdSetFillColor,(cgmimage, cdfillcolor)); // cdcall(cdSetFillHatch,(cgmimage, 1)); cdcall(cdSetShapeFillAttrib,(cgmimage,solid,cdfillcolor,1)); // cdcall(cdSetEdgeType,(cgmimage, solid)); // cdcall(cdSetEdgeWidth,(cgmimage, cdLineWidth)); // cdcall(cdSetEdgeColor,(cgmimage, cdedgecolor)); // cdcall(cdSetEdgeVis,(cgmimage, visible)); cdcall(cdSetShapeEdgeAttrib,(cgmimage,solid,cdLineWidth,cdedgecolor,visible)); break; default: break; } if (isPolygon()) { cdcall(cdPolygon,(cgmimage,cdpoints,numberOfElementsInPath()-1)); } else { cdcall(cdPolyLine,(cgmimage,cdpoints,numberOfElementsInPath())); } } else { switch ( currentShowType() ) { case drvbase::stroke: outf << " intstyle solid;\n"; break; case drvbase::fill: outf << " intstyle solid;\n"; break; case drvbase::eofill: outf << " intstyle solid;\n"; break; default: break; } outf << " linecolr " << cdedgecolor << ";\n"; outf << " fillcolr " << cdfillcolor << ";\n"; outf << " linewidth " << currentLineWidth() << ";\n"; outf << " edgewidth " << currentLineWidth() << ";\n"; if (currentLineWidth() >0 ) { outf << " edgevis on;\n"; } else { outf << " edgevis off;\n"; } #if 0 // no subpaths if (isPolygon) { numberOfElementsInPath()--; // CGM does not need end=start outf << " Polygon"; print_coords(); outf << ";\n"; numberOfElementsInPath()++; // restore old value for proper cleanup } else { outf << " Line"; print_coords(); outf << ";\n"; } #else // dump with subpaths print_coords(); #endif } } void drvCGM::show_rectangle(const float llx, const float lly, const float urx, const float ury) { // just do show_polyline for a first guess show_path(); }