home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / pstoedit.zip / source.zip / pstoedit.2.50 / src / drvcgm.cpp < prev    next >
C/C++ Source or Header  |  1996-10-29  |  16KB  |  545 lines

  1. /* 
  2.    drvCGM.cpp : This file is part of pstoedit
  3.    Backend for CGM format
  4.  
  5.    Copyright (C) 1993,1994,1995,1996 Wolfgang Glunz, Wolfgang.Glunz@zfe.siemens.de
  6.  
  7.     This program is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU General Public License as published by
  9.     the Free Software Foundation; either version 2 of the License, or
  10.     (at your option) any later version.
  11.  
  12.     This program is distributed in the hope that it will be useful,
  13.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.     GNU General Public License for more details.
  16.  
  17.     You should have received a copy of the GNU General Public License
  18.     along with this program; if not, write to the Free Software
  19.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  
  21. */
  22.  
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <stdlib.h>
  26. #include "drvcgm.h"
  27.  
  28. #include "cd.h"
  29.  
  30. #ifdef __TCPLUSPLUS__
  31. #include <alloc.h>
  32. #endif
  33. // for sin and cos
  34. #include <math.h>
  35.  
  36. // static const unsigned int imageHeight = 850;
  37. // static const unsigned int imageWidth  = 600;
  38.  
  39. // predefined Fonts from CD-library
  40. static const char *CGM_CD_Fonts[] = { 
  41.         // although the cd-library uses the names without - we need it here
  42.         // in order to recognize the PostScript names
  43.         // !!! order of -Bold and -Italic is reversed wrt. ASC_Fonts !!!
  44.     "Times-Roman", 
  45.     "Times-Bold",
  46.     "Times-Italic", 
  47.     "Times-BoldItalic", 
  48.     "Helvetica", 
  49.     "Helvetica-Bold",
  50.     "Helvetica-Oblique", 
  51.     "Helvetica-BoldOblique",
  52.     "Courier", 
  53.     "Courier-Bold",
  54.     "Courier-Oblique", 
  55.     "Courier-BoldOblique", 
  56.     "Symbol",
  57.     0
  58. };
  59.  
  60. // for the ASCII - backend
  61. static const char *CGM_ASC_Fonts[] = { 
  62.     "Times-Roman", 
  63.     "Times-Italic", 
  64.     "Times-Bold",
  65.     "Times-BoldItalic", 
  66.     "Helvetica", 
  67.     "Helvetica-Oblique", 
  68.     "Helvetica-Bold",
  69.     "Helvetica-BoldOblique", 
  70.     "Courier", 
  71.     "Courier-Oblique", 
  72.     "Courier-Bold",
  73.     "Courier-BoldOblique", 
  74.     "Symbol" ,
  75.     0
  76. };
  77.  
  78. const char * const *    drvCGM::knownFontNames() const 
  79. {
  80.     if (binary_) {
  81.         return CGM_CD_Fonts;
  82.     } else {
  83.         return CGM_ASC_Fonts;
  84.     }
  85. }
  86.  
  87. static int getFontNumber(const char * const fontname,const char * Fnames[]) {
  88.     const unsigned int fntlength = strlen(fontname);
  89.     const char * const * fiter = Fnames;
  90.     int index = 0;
  91.     while (*fiter) {
  92.     //for (unsigned int i=0; i < numberOfFonts; i++) 
  93.         const unsigned int cgmFntLengh = strlen(*fiter);
  94.     if (fntlength == cgmFntLengh ) { 
  95.         if (strncmp(fontname,*fiter,fntlength) == 0) {
  96.         return index + 1; // cgm counts from 1
  97.         }
  98.     }
  99.     fiter++; index++;
  100.     }
  101.     return -1;
  102. }
  103.  
  104. #define cdcall(func,params) if (! func params)  {\
  105.     errf << "call to cd-library " #func " failed" << endl;\
  106.     return ; \
  107.     }
  108.  
  109. drvCGM::drvCGM(const char * driveroptions_p,ostream & theoutStream,ostream & theerrStream,bool binary):
  110.     drvbase(driveroptions_p,theoutStream,theerrStream,(!binary),0,1),
  111.     // only ascii version supports subpaths so far
  112.     binary_(binary),
  113.     cdpoints(0),
  114.     cgmimage(0)
  115. {
  116.     scale = 10.0; // only logical scale to avoid rounding problems
  117. // creating the image deffered to open_page, because we need access to the DeviceWidth/Height
  118. // but these are only available after the PostScript interpreter has finished.
  119. }
  120.  
  121. drvCGM::~drvCGM() 
  122. {
  123.     if (binary_) {
  124.         // free points, so new memory is there for the 
  125.         // cd write functions
  126.         delete [] cdpoints;
  127.  
  128.         if (cdImageCgm) {
  129.             FILE * outfile = tmpfile();
  130.             cdcall(cdImageCgm,(cgmimage, outfile));
  131.             cdcall(cdImageDestroy,(cgmimage));
  132.             cgmimage = 0;
  133.  
  134.             rewind(outfile);
  135.             filebuf outbuf(fileno(outfile));
  136.             outf << &outbuf; // This copies outbuf to outf
  137.         } else {
  138.             errf << "No image created " << endl;
  139.         }
  140.     } else {
  141.         cdcall(cdImageDestroy,(cgmimage));
  142.         outf << "EndMF;\n";
  143.     }
  144.  
  145. //static float rnd(const float f,const float roundnumber)
  146. //{
  147. //    return ((long int) ( (f * roundnumber) + 0.5 )) / roundnumber;
  148. //}
  149. // static inline float RND3(const float f) { return rnd(f,1000);}
  150. static inline int RND(const float f) { return (int) (f+0.5);}
  151.  
  152. void drvCGM::print_coords()
  153. {
  154. #if 0
  155.     for (unsigned int n = 0; n < numberOfElementsInPath(); n++) {
  156.         const Point & p = pathElement(n).getPoint(0);
  157.         outf << " (" << (int)( p.x_ + x_offset) << ',' 
  158.             << (int)( p.y_ + y_offset) << ')';
  159.     }
  160. #else
  161.     bool newpath = true;
  162.     bool lastwasclosepath = false;
  163.     Point lastMoveto(0.0f,0.0f);
  164.     unsigned int lastelemnr = numberOfElementsInPath();
  165.     for (unsigned int n = 0; n < lastelemnr; n++) {
  166.     const basedrawingelement & elem = pathElement(n);
  167.     if (newpath) {
  168.             switch (currentShowType() ) {
  169.          case drvbase::stroke : 
  170.                   // draw as line
  171.             // terminate and start a new Line;
  172.                 outf << " Line " ;
  173.                   break;
  174.         case drvbase::fill :
  175.             // draw each segment as a polygon
  176.             outf << " Polygon " ;
  177.             break;
  178.         case drvbase::eofill :
  179.             // dump the whole path as a large polygon set
  180.                 outf << " PolygonSet " ;
  181.             break;
  182.         default: 
  183.             // cannot happen
  184.             errf << "unexpected ShowType " << (int) currentShowType() << " in drvcgm.cc" << endl;
  185.             exit(1);
  186.             break;
  187.         }
  188.         newpath = 0;
  189.     }
  190.     switch (elem.getType()) {
  191.     case moveto: 
  192.         if ( (n != 0) && (n != lastelemnr -1) ) {
  193.         // ignore moveto, if it's the first
  194.         // or the last part
  195.                 switch (currentShowType() ) {
  196.              case drvbase::stroke : 
  197.                       // draw as line
  198.                 // terminate and start a new Line;
  199.                 outf << " ;\n";
  200.                     outf << " Line " ;
  201.                       break;
  202.             case drvbase::fill :
  203.                 // draw each segment as a polygon
  204.                 outf << " ;\n";
  205.                 outf << " Polygon " ;
  206.                 break;
  207.             case drvbase::eofill :
  208.                 // dump the whole path as a large polygon set
  209.                 if (!lastwasclosepath) {
  210.                     outf << " closeinvis ";
  211.                 }
  212.                 break;
  213.             default: 
  214.                 // cannot happen
  215.                 errf << "unexpected ShowType " << (int) currentShowType() << " in drvcgm.cc" << endl;
  216.                 exit(1);
  217.                 break;
  218.             }
  219.         }
  220.         if ( n != lastelemnr -1 ) {
  221.             const Point & p = elem.getPoint(0);
  222.             lastMoveto=p;
  223.             outf      << RND(p.x_ + x_offset) << " " 
  224.                      << RND(p.y_ + y_offset) << " " ;
  225.         }
  226.         break;
  227.     case lineto: 
  228.         if (currentShowType() == drvbase::eofill) {
  229.             outf << "  vis ";
  230.         } else {
  231.             outf << "  ";
  232.         }
  233.         {
  234.             const Point & p = elem.getPoint(0);
  235.                 outf  << RND(p.x_ + x_offset) << " " 
  236.                      << RND(p.y_ + y_offset) << " " ;
  237.         }
  238.         break;
  239.     case closepath: 
  240.         switch (currentShowType() ) {
  241.         case drvbase::stroke : 
  242.             // draw a line to the start of the current line 
  243.             // and prepare for a new line
  244.                 outf << RND(lastMoveto.x_ + x_offset) << " " 
  245.                       << RND(lastMoveto.y_ + y_offset) << " " ;
  246.                 outf << ";\n";
  247.             newpath=1;
  248.             break;
  249.         case drvbase::fill :
  250.             // close and prepare for a new path.
  251.             outf << " ;\n";
  252.             newpath=1;
  253.             break;
  254.         case drvbase::eofill :
  255.             // normal close
  256.             outf << " closevis ";
  257.             break;
  258.         default: 
  259.             // cannot happen
  260.             errf << "unexpected ShowType " << (int) currentShowType() << " in drvcgm.cc" << endl;
  261.             exit(1);
  262.             break;
  263.             }
  264.         break;
  265.  
  266.     case curveto:
  267.         errf << "Fatal: unexpected case in drvcgm " << endl;
  268.         exit(1);
  269.         break;
  270.     default:
  271.         errf << "Fatal: unexpected case in drvcgm " << endl;
  272.         exit(1);
  273.         break;
  274.     }
  275.     outf << '\n';
  276.  
  277.     lastwasclosepath = (elem.getType() == closepath);
  278.     }
  279.     if (lastwasclosepath) {
  280. // a closepath was the last statement, so the path is really closed
  281. // except in the case of an eofilled path
  282.        if (currentShowType() == drvbase::eofill) {
  283.             outf << " ;\n" ;
  284.     }
  285.     } else {
  286. // implicit close path
  287.         if (currentShowType() == drvbase::stroke) {
  288.         outf << " ;\n";
  289.     } else {
  290.         outf << " ;\n";
  291.     }
  292.     }
  293. #endif
  294. }
  295.  
  296. void drvCGM::open_page()
  297. {
  298. // creating the image deffered to here, because we need access to the DeviceWidth/Height
  299. // but these are only available after the PostScript interpreter has finished.
  300.  
  301. // we allocate a cdImage also for the ascii backend, because we use
  302. // the color functions from the cd library
  303.     if (!cgmimage) { // no image so far
  304. //     errf  << "W " << currentDeviceWidth << " H " << currentDeviceHeight << endl;
  305.     cgmimage = cdImageCreate(RND(currentDeviceWidth), RND(currentDeviceHeight));
  306. //    cgmimage = cdImageCreate(RND(300), RND(400));
  307.     // cgmimage = cdImageCreate(imageWidth, imageHeight);
  308.     if (binary_) {
  309.         cdImageColorAllocate(cgmimage,255,255,255); // set background color
  310.         cdpoints = new cdPoint[maxElements];
  311.         if (!cdpoints) {
  312.             errf << "Could not allocate space for points" << endl;
  313.             exit(1);
  314.         }
  315.     } else {
  316.         outf << "BegMF \"picture made with pstoedit\";\n";
  317.         outf << "MFVersion 1;\n";
  318.         outf << "mfelemlist 'DRAWINGPLUS';\n";
  319.         outf << "colrprec 255;\n";
  320.         outf << "colrindexprec 127;\n";
  321.         outf << "maxcolrindex 255;\n";
  322.         outf << "fontlist " << endl;
  323.         const char * const * fontiter = CGM_ASC_Fonts;
  324.         while (*fontiter) {
  325.             outf << "'" << *fontiter << "'"; 
  326.             fontiter++;
  327.             if (*fontiter) { 
  328.                 outf << "," << endl; 
  329.             }  else {
  330.                 outf << ";" << endl; 
  331.             }
  332.         }
  333.     }
  334.     }
  335.     if (binary_ ) {
  336.         if (currentPageNumber > 1) {
  337.                  // we have to re-allocate the colors as well 
  338.                 cdcall(cdCgmNewPic,(cgmimage, 0));
  339.      
  340.                     // allocate some colors (Again!) 
  341.                     // the first color allocated is the background color 
  342.             cdImageColorAllocate(cgmimage,255,255,255); // set background color
  343.         }
  344.     } else {
  345.         outf << " BegPic \"page:  " << currentPageNumber << " \";\n";
  346.         // outf << " vdcext (0,0) (" << imageWidth << ',' << imageHeight << ");\n";
  347.         outf << " vdcext (0,0) (" << RND(currentDeviceWidth) << ',' << RND(currentDeviceHeight) << ");\n";
  348.         outf << " colrmode indexed;\n";
  349.         outf << " linewidthmode abstract;\n";
  350. //ralcgm does not like vdc        outf << " edgewidthmode vdc;\n";
  351.         outf << " edgewidthmode abstract;\n";
  352. //    outf << " ScaleMode Metric 0.1;\n";
  353.         outf << " BegPicBody;\n";
  354.         getcdcolor(1.0f,1.0f,1.0f); // write white color index
  355.             outf << " edgevis on;\n"; // needed, otherwise vis/invis has no effect
  356.     }
  357. }
  358.  
  359. void drvCGM::close_page()
  360. {
  361.     if (binary_) {
  362.     } else {
  363.         outf << " EndPic;\n";
  364.     }
  365. }
  366. unsigned int drvCGM::getcdcolor(float R, float G, float B)
  367. {
  368.     const unsigned int r = (unsigned int) (255 * R);
  369.     const unsigned int g = (unsigned int) (255 * G) ;
  370.     const unsigned int b = (unsigned int) (255 * B) ;
  371.     int cdcolor = cdImageColorExact(cgmimage,r,g,b);
  372.     if (cdcolor < 0)  {
  373.         // not stored so far
  374.         cdcolor = cdImageColorAllocate(cgmimage,r,g,b);
  375.         if (cdcolor < 0)  {
  376.             cdcolor = cdImageColorClosest(cgmimage,r,g,b);
  377.         } else {
  378.             // newly allocated color
  379.             if (! binary_) {
  380.                   outf << " colrtable " << cdcolor << ' ' 
  381.                     << cdImageRed(cgmimage,cdcolor) << ' ' 
  382.                      << cdImageGreen(cgmimage,cdcolor) << ' '
  383.                     << cdImageBlue(cgmimage,cdcolor) << ";\n";
  384.             }
  385.         }
  386.         }
  387.     return cdcolor;
  388. }
  389.  
  390. void drvCGM::show_text(const TextInfo & textinfo)
  391. {
  392.     const unsigned int cdcolor = getcdcolor(textinfo.currentR,textinfo.currentG,textinfo.currentB);
  393.     const float toRadians = 3.14159265359f / 180.0f;
  394.     const float angleInRadians = textinfo.currentFontAngle * toRadians;
  395.     const int xbase = (int) (1000*cos(angleInRadians));
  396.     const int ybase = (int) (1000*sin(angleInRadians));
  397.     const int xup=-ybase;
  398.     const int yup=xbase;
  399.  
  400.     if (binary_) {
  401.         int CGMFontNum = getFontNumber(textinfo.currentFontName.value(),CGM_CD_Fonts);
  402.         if (CGMFontNum == -1) {
  403.             CGMFontNum = 1;
  404.             errf << "replacing font: " << textinfo.currentFontName.value() << " with " << CGM_CD_Fonts[CGMFontNum] << endl;
  405.         }
  406.         // errf << "Using "  << CGMFontNum << " for " << textinfo.currentFontName.value() << endl;
  407.         const int height = RND(textinfo.currentFontSize);
  408.         cdSetTextAttrib(cgmimage,CGMFontNum,cdcolor,height);
  409.         cdSetTextOrient(cgmimage,xup,yup,xbase,ybase);
  410.         cdText(cgmimage,RND(textinfo.x),RND(textinfo.y),textinfo.thetext);
  411.     } else {
  412.         int CGMFontNum = getFontNumber(textinfo.currentFontName.value(),CGM_ASC_Fonts);
  413.         if (CGMFontNum == -1) {
  414.             CGMFontNum = 1;
  415.             errf << "replacing font: " << textinfo.currentFontName.value() << " with " << CGM_ASC_Fonts[CGMFontNum] << endl;
  416.         }
  417.         outf << "  textcolr " << cdcolor << ";\n";
  418.         outf << "  charheight " << textinfo.currentFontSize << ";\n";
  419.         outf << "  charori " << xup << ' ' << yup << ' ' << xbase << ' ' << ybase << ";\n";
  420.         outf << "  TEXT (" << RND(textinfo.x)  << ',' << RND(textinfo.y)  << ") final '" ;
  421.         {     const char * cp = textinfo.thetext;
  422.             while (*cp) {
  423.                 if (*cp == '\'') outf << '\'';
  424.                 outf << *cp;
  425.                 cp++;
  426.             }
  427.         }
  428.         outf << "';\n";
  429.     }
  430. }
  431.  
  432. void drvCGM::show_path()
  433. {
  434.     const unsigned int cdedgecolor = getcdcolor(edgeR(),edgeG(),edgeB());
  435.     const unsigned int cdfillcolor = getcdcolor(fillR(),fillG(),fillB());
  436. //    errf << "EdgeColor " << cdedgecolor << " FillColor " << cdfillcolor << endl;
  437.     if (binary_) {
  438.         for (unsigned int n = 0; n < numberOfElementsInPath(); n++) {
  439.             const Point & p = pathElement(n).getPoint(0);
  440.             cdpoints[n].x =  RND(p.x_);
  441.             cdpoints[n].y =  RND(p.y_);
  442.         }
  443.  
  444. //#ifdef __TCPLUSPLUS__
  445. //        if (verbose) errf << "core left " << coreleft() << " " << farcoreleft() << endl;
  446. //#endif
  447.         const unsigned int cdLineWidth = (unsigned int) RND(currentLineWidth());
  448.         const bool visible = (currentLineWidth() > 0.0);
  449. //        const int solid_line = 1;
  450. //        const int dashed_line = 2;
  451.         const int hollow_fill = 0;
  452.         const int solid_fill  = 1;
  453.  
  454.         const int linestyle = (int) currentLineType() + 1; // what a luck, the encoding is simple
  455.         switch ( currentShowType() ) {
  456.         case  drvbase::stroke:
  457.             cdcall(cdSetLineAttrib,(cgmimage,linestyle,cdLineWidth,cdedgecolor));
  458.             // we have to set the ShapeFillAttrib as well in case
  459.             // the drawing is done via cdPolygon
  460.             cdcall(cdSetShapeFillAttrib,(cgmimage,hollow_fill,cdfillcolor,1));
  461.             if (isPolygon()) {
  462.                 // errf << "cdPolygon " << numberOfElementsInPath()-1 << endl;
  463.                 cdcall(cdPolygon,(cgmimage,cdpoints,numberOfElementsInPath()-1));
  464.             } else {
  465.                 // errf << "cdPolyLine " << numberOfElementsInPath() << endl;
  466.                 cdcall(cdPolyLine,(cgmimage,cdpoints,numberOfElementsInPath()));
  467.             }
  468.             break;
  469.         case  drvbase::eofill:
  470.             // This may be wrong (treating fill same as eofill), but there is no other way 
  471.             // at the moment
  472.         case  drvbase::fill:
  473.             cdcall(cdSetLineAttrib,(cgmimage,linestyle,cdLineWidth,cdedgecolor));
  474.             cdcall(cdSetShapeFillAttrib,(cgmimage,solid_fill,cdfillcolor,1));
  475.             cdcall(cdSetShapeEdgeAttrib,(cgmimage,linestyle,cdLineWidth,cdedgecolor,visible));
  476.             if (isPolygon()) {
  477.                 // errf << "cdPolygon " << numberOfElementsInPath()-1 << endl;
  478.                 cdcall(cdPolygon,(cgmimage,cdpoints,numberOfElementsInPath()-1));
  479.             } else {
  480.                 // errf << "cdPolyLine " << numberOfElementsInPath() << endl;
  481.                 // draw a non closed/filled polyline as polygon
  482.                 cdcall(cdPolygon,(cgmimage,cdpoints,numberOfElementsInPath()));
  483.             }
  484.             break;
  485.         default:
  486.             errf << "Unexpected case in drvcgm.cc " << endl;
  487.             break;
  488.         }
  489.  
  490.     } else {
  491.         switch ( currentShowType() ) {
  492.         case  drvbase::stroke:
  493.             outf << " intstyle solid;\n";
  494.             break;
  495.         case  drvbase::fill:
  496.             outf << " intstyle solid;\n";
  497.             break;
  498.         case  drvbase::eofill:
  499.             outf << " intstyle solid;\n";
  500.             break;
  501.         default:
  502.             break;
  503.         }
  504.         outf << " linecolr " << cdedgecolor << ";\n";
  505.         outf << " fillcolr " << cdfillcolor << ";\n";
  506.         outf << " linewidth " <<  currentLineWidth() << ";\n";
  507.         outf << " edgewidth " <<  currentLineWidth() << ";\n";
  508.         if (currentLineWidth() >0 ) {
  509.             outf << " edgevis on;\n";
  510.         } else {
  511.             outf << " edgevis off;\n";
  512.             
  513.         }
  514.  
  515. #if 0
  516. // no subpaths
  517.         if (isPolygon) {
  518.             numberOfElementsInPath()--; // CGM does not need end=start
  519.         outf << " Polygon";
  520.         print_coords();
  521.         outf << ";\n";
  522.         numberOfElementsInPath()++; // restore old value for proper cleanup
  523.     } else { 
  524.         outf << " Line";
  525.         print_coords();
  526.         outf << ";\n";
  527.     }
  528. #else
  529.         // dump with subpaths
  530.         print_coords();
  531. #endif
  532.     }
  533. }
  534.  
  535. void drvCGM::show_rectangle(const float llx, const float lly, const float urx, const float ury)
  536. {
  537.     // just do show_polyline for a first guess
  538.     unused(&llx);
  539.     unused(&lly);
  540.     unused(&urx);
  541.     unused(&ury);
  542.     show_path();
  543. }
  544.