// CLASS DxfWrite 
//
// Purpose : Save Java graphic output in dxf format
//
// Permission to use and/or modify this code freely for
// *any* purpose is hearby granted, provided that
// this copyright notice is both kept unmodified and
// reasonable acknowledgment is given.
//
// V0.1b 31/7/96 Ted Dunstone (copyright 1996)
// (ted@cps.com.au & http://www.cps.com.au/ted) 
//
// Ex-portability
//    * works well with the import filter in Micrographics Designer V4.1 & above
//    * others ?, Please send successes and problem reports to above address
//
// Known bugs
// 1) line thickness does not work currently
// 2) ovals and arcs must have a constant radius (taken to be equal to 
//          the width). There is apparently no way to stretch these
//			using dxf primitives. To fully implement AWT Graphics
//          one would need to construct polyline objects (a la DS4).
//
// Things to be	done
//   * provide support for more AWT primitives
//   * fix above bugs
//   * improve DXF formatting
//
// Postscript 
//    If you find this freeware useful please send me some email.
//


import java.awt.*;
import java.io.*;
import java.util.*;
import java.lang.*;

public class DxfWrite {    

  PrintStream dxf_file;		  // the output file
  FileOutputStream dxff;	  // the output stream
  boolean write_on;			  // if we are writing
  Font font;

  double lineThickness=5.0;
  double scale=2.0;
  final int YMAX = 1000;
  String lineType="CONTINUOUS";

  // define line type strings

  final public byte    CONTINUOUS = 0,DASHED=1,HIDDEN=2,DOT=4;
  final String strCont="LTYPE:2:CONTINUOUS:70:64:3:Solid line:72:65:73:0:40:0.10:0:",
			   strDash		 ="LTYPE:2:DASHED:70:64:3:__ __ __ __ __ __ __ __ __ __ __ __ __ __ __:72:65:73:2:40:0.000351:49:0.000234:49:-0.000117:0:",
		       strHidden	 ="LTYPE:2:HIDDEN:70:64:3:_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _:72:65:73:2:40:0.000175:49:0.000117:49:-0.000058:0:",
		       strDot		 ="LTYPE:2:DOT:70:64:3:...............................................:72:65:73:2:40:0.000117:49:0.000000:49:-0.000117:0:";


  DxfWrite() {}

  /** Open the dxf file "Filename" for writing 
  */
  DxfWrite(String Filename)	throws IOException
  {
	 dxfOpen(Filename);
  }
   
  /** Open the Dxf file "Filename" for writing 
  */
  public void dxfOpen(String Filename) throws IOException
  {                  
	try {
	  write_on = true;
		dxff = new FileOutputStream(Filename); 
		dxf_file = new PrintStream(dxff); 
		String	header    = "0:SECTION:2:HEADER:9:$EXTMIN:10:0:20:0:9:$EXTMAX:10:2000:20:2000:9:" +
                            "$LTSCALE:40:0.01:9:$PDMODE:70:35:9:$PDSIZE:40:0.037417:0:ENDSEC:0:",
				setLineDef= "SECTION:2:TABLES:0:TABLE:2:",
				endLineDef= "ENDTAB:0:ENDSEC:0:",
				beginDiag = "SECTION:2:ENTITIES:0:";

		output(header + 
			   setLineDef + strCont + strDash + strHidden + strDot + endLineDef + 
			   beginDiag);
     }
     catch (IOException e) {
      write_on = false;   
	  throw e;
     }
  }
  

  /** Close the Dxf file 
  */
  public void dxfClose() throws IOException
  {               
    if (write_on)
     {
		output("ENDSEC:0:EOF");
		write_on = false;
		dxf_file.flush();
		dxff.close();
      }
  }

  
/** Cleanup when disposed 
  */
protected void finalize() throws Throwable {
	 dxfClose();
  }
  
/** internal function to output DXF string to file
  */
private void output(String strCont)
  {
    if (write_on) {
		String outStr="";
		StringTokenizer st = new StringTokenizer(strCont,":");
		while (st.hasMoreTokens()) 
		{
			String tok=st.nextToken();
			if (tok!=null && tok!=" ") outStr+=tok+"\n";
		}
	  dxf_file.print(outStr);
	}
  }
  
  /** internal function to translate viewing coords
  */
  private double ytrans(int y)
  {
    return (double)(YMAX-y)/scale; // must invert
  }
  
  /** internal function to translate viewing coords
  */
  private double xtrans(int x)
  {
    return (double)x/scale;
  }
  
  /** set the line type, one of : CONTINUOUS,DASHED,DOT,HIDDEN
  */
  public void setLineType(int type) {
    switch(type) {
        case   0: lineType="CONTINUOUS";break;
        case   2: lineType="DASHED";break;
        case   1: lineType="DOT";break;
        case   3: lineType="HIDDEN";break;
        default : lineType="CONTINUOUS";
    }
  }               


  /* ******************************************************* */
  //  standard graphics functions as per AWT

  /** set the font, curently only text size is used 
  */
  public void setFont(Font f) {
		font = f;
  }

  /** get the curent font 
  */
  public Font getFont() {
		return font;
  }

  /** set the graphics scaling 
  */
  public void setScale(double scale) {
	  this.scale=scale;
  }

  /** Set line thickness. Dosn't work currently.
  */
  public void setThickness(double lineThickness) {
	  this.lineThickness=lineThickness;
  }

  /** internal function to part of a polygon or line
  */
  private void drawLineto(int x,int y)
  {               
       double yd=ytrans(y);
       double xd=xtrans(x);
       output("VERTEX:8:0:62:0:6:"+lineType+":10:"+xd+":20:"+yd+":0:"); 
  }

  public void drawLine(int x,int y,int x2,int y2)
  {               
        output("POLYLINE:8:0:62:0:6:"+lineType+":66:1:40:"+0.007+":41:"+ 0.007 + ":0:");
		drawLineto(x,y);
		drawLineto(x2,y2);
		output("SEQEND:8:0:0");
  }

  public void drawPolygon(int[] x,int[] y,int n)
  {                                   
	 output("POLYLINE:8:0:62:0:6:"+lineType+":66:1:40:"+0.007+":41:"+ 0.007 + ":0:");
     for (int i=0;i<n;i++)
		drawLineto(x[i],y[i]);
     output("SEQEND:8:0:0");
  }
  
  public void drawRect(int x,int y,int x2,int y2)
  {               
       drawLine(x,y,x,y+y2);
       drawLine(x,y,x+x2,y);
       drawLine(x+x2,y+y2,x,y+y2);
       drawLine(x+x2,y+y2,x+x2,y);
  }

  /** currently value of y2 is ignored so arc must lie on a circle
  */
  public void drawArc(int x,int y,int x2,int y2,int begin,int end)
  {
       double r=xtrans(x2);
       double y1  = ytrans(y);
       double x1  = xtrans(x);
       r=r/2;                        
       x1 +=r;                        
       y1 -=r;
       int end2=begin+end;                
       output("ARC:8:0:39:" + lineThickness + ":62:0:6:"+lineType+":");
	   output("10:" + x1 + ":20:" + y1 + ":40:" + r + ":50:" + begin + ":51:" + end2 + ":0:");    
  }
  
  /** currently value of y2 is ignored, x1 = radius
  */
  public void drawOval(int x,int y,int x1,int y1)
  {               
       double yd=ytrans(y),
              y1d=ytrans(y1),
              xd=xtrans(x),
              x1d=xtrans(x1),
              r=x1d/2.0;      
       xd = (xd+r);                        
       yd = (yd-r);
       output("CIRCLE:8:0:39:" + lineThickness + ":62:0:6:"+lineType+":");
       output("10:" + xd + ":20:" + yd + ":40:" + r + ":0:");    
  }

  public void drawString(String s,int x,int y)
  {               
     // 
	    double textSize=10.0;
		double yd=ytrans(y),
               xd=xtrans(x);
		output("TEXT:8:0:1:"+s+":62:0:6:"+"CONTINUOUS:");
		if (font!=null)
			textSize=(double)font.getSize();
		output("10:" + xd + ":20:" + yd + ":40:"+ textSize/scale + ":0:");
  }

  
  /** Provides an example of the classes use.
  Sends sample output to file print.dxf.
  */
  public void main(String[] args)
  {						  
	try {
	   DxfWrite dg = new DxfWrite();
	   
	   dg.dxfOpen("print.dxf");  
	   dg.setLineType(dg.CONTINUOUS);
	   dg.drawRect(5,5,60,60);
	   dg.setLineType(dg.DASHED);
	   dg.drawRect(10,10,50,50);
       dg.drawOval(10,10,50,50);
	   dg.setLineType(dg.HIDDEN);
	   dg.drawLine(35,10,35,60);
	   dg.drawLine(10,35,60,35);
	   dg.setFont(new Font("Helvetica",Font.PLAIN,10));
	   dg.drawString("test",25,25);
	   dg.setFont(new Font("Helvetica",Font.PLAIN,20));
	   dg.drawString("TITLE",0,0);
	   dg.setLineType(dg.CONTINUOUS);
	   dg.drawArc(10,10,80,80,90,90);
	   dg.drawArc(-20,10,80,80,0,90);
	   dg.dxfClose();			  // close the file

     } catch(IOException e)
     {
      System.out.println(e);
     }

  }
}


