//Grotius CNC Machines B.V.
//February 2019. 

//1. C code dxf file input, at this moment the file name is fixed to                   : read.dxf
//2. G-code file output, at this moment the file name is fixed to :                    : read.ngc
//3. Compile code with geany, or type in terminal                                      : gcc -Wall -o "read" "read.c"
//4. The conversion from read.dxf to read.ngc (g-code) start's when type in terminal   : ./read
//5. A file read.ngc file output is now in the same directory as the read file
//6. The output of this code is printed in terminal window and is writed to read.ngc simultaneously

// This code is in development, only use this code for testing purposes
// This code is looping very fast. At some cases we first collect data, do some calculations before we write data to the ngc file.
// This code is powerfull C code. Please use it wisely.
// This code can be expanded with autonesting in the future. 
// Expanded code like this can make a connection to OpenGL for visualisation and edit the Cam process.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


    //line section :           //LINE
    int x_start;               //10
    int y_start;               //20
    int z_start;	           //30
    int x_end;                 //11
    int y_end;                 //21
    int z_end;	               //31
	int linenumber = 0;        
    int linetrigger = 0;       //LINE
    int lineblock = 0;         // every line has one lineblock, that block holds values : x_start to z_end.

    //circle section :         //CIRCLE || ARC  subword : AcDbEntity, includes circle layer
    int x_center;              //10
    int y_center;              //20
    int z_center;              //30
    int radius;                //40
    int start_angle;           //50  degrees 0=horizontal right, 90=vertical up, 180=horizontal left, 270=vertical down
    int end_angle;             //51  degrees comment as above
    int end;                   //  0 end of circle section (2 empty spaces)
    int circletrigger = 0;     //CIRCLE 
    int circlesubtrigger = 0;  //sub AcDbEntity, includes circle layer
    int circleblock = 0;
    
    int arctrigger = 0;        //ARC 
    int arcsubtrigger = 0;
    int arcblock = 0;
    
    //circle section, collect all data of one circle block first, after that print g-code line. This is done this way to calculate circle startpoint.
    int x_float_collector = 0; //All items declared in circle section are also used for arc section.
    int y_float_collector = 0;
    int z_float_collector = 0; 
    int radius_float_collector = 0; 
    float temp_x_center;       
    float temp_y_center;
    float temp_z_center;
    float temp_radius;  
    
    // Visualisation how dxf cicles are defined :
    //
    //              90 Y-Axis
    //               | Circle J value (g-code vertical)
    //               |       
    //               |
    //               |
    //  180__________|x_center______ 0   X-Axis
    //  (S)          |y_center       360 Circle I value (g-code horizontal)
    //               |
    //               |
    //               |       
    //               |
    //              270
    //
    //  At (S) we program our startpoint for g-code, we start with G02 circle command's
    //  For g-code we use the x_center and y_center, this correspondents to the dxf file values 10 and 20
    //  For I in g-code we calculate : radius*-1 => This will set our circle startpoint from center to the (S)
    //  Later on we do lead in's and edit startpoints.
    
    //arc section :
    float temp_start_angle;    //for arc's, calculation and conversion to g-code todo
    float temp_end_angle;   
    int start_angle_float_collector = 0;
    int end_angle_float_collector = 0;
    
    // Visualisation how dxf arc's are defined :
    //
    //              90 Y-Axis
    //               |
    //       **      |      *
    //               |
    //               |
    //  180__________|x_center______ 0   X-Axis
    //               |y_center       360
    //               |
    //               |
    //       ***     |      ****
    //               |
    //              270
    //
    //  *    = start_angle = 0   up to end_angle = 90 
    //  **   = start_angle = 90  up to end_angle = 180  
    //  ***  = start_angle = 180 up to end_angle = 270 
    //  **** = start_angle = 270 up toend_angle = 360 
    
    //polygon section :        //LWPOLYLINE  //Do a autocad list commando to check parameters.
    int poly_x_point;          //10
    int poly_y_point;          //20
    int polytrigger = 0;       //LWPOLYLINE
    int polysubtrigger = 0;
    int polyblock = 0;
    int polyitem  = 0;         //value of separete lines inside of polyblock
    
    int layer;                 //8
      
    char count[100]={0x0};     // hold's the string of one text file line
    
    int write_stop = 0;
    int printlinenumber = 0;  

    

int main(int argc, char **argv)
{

    FILE *file=fopen("read.dxf", "r");
	file=fopen("read.dxf", "r");    
	
	FILE *file_write=fopen("read.ngc", "w");
	file_write=fopen("read.ngc", "w");  
	
	while(file && fgets(count, sizeof(count), file)){ 
		

//LINE SECTION///////////////////////////////////////////////////////////////////////////////////////	
		// read for linenumber where "LINE" appear's, when LINE is found, next, search for 10 (x_start),20 (y_start) ,30 (z_start), 11 (x_end), 21 (y_end), 31 (z_end) 
        // avoid searching LINE inside of a word like : $PLINEWID etc, exclude strings like this by ! sign and $PLINEWID....
	    if( (strstr(count, "LINE")) && (!strstr(count, "LWPOLYLINE")) && (!strstr(count, "$PLINEWID")) && (!strstr(count, "$SPLINETYPE")) && (!strstr(count, "$SPLINESEGS")) && (!strstr(count, "$PLINEGEN")) && (!strstr(count, "ACAD_MLINESTYLE"))&& (!strstr(count, "MLINESTYLE"))){	
			printf("\nLINE at %d ", linenumber);   
			linetrigger = 1; 
			lineblock = lineblock + 1;  // for check's, lineblock's printed out, every line is one lineblock, a square/reqtengular consists of 4 lineblocks. :
			printf("\nLineblock %d ", lineblock);  		
		    }	
	    if ((linetrigger == 1) && (strstr(count, " 10"))){       
			printf("\n 10 at %d ", linenumber);
			x_start = linenumber + 2;  //set your linenumber for x_start, _10 is found, the value is one line below 10. 
			}		
	    if ((linetrigger == 1) && (strstr(count, " 20"))){       
			printf("\n 20 at %d ", linenumber);
			y_start = linenumber + 2;
			}    
	    if ((linetrigger == 1) && (strstr(count, " 30"))){       
			printf("\n 30 at %d ", linenumber);
			z_start = linenumber + 2;
			}  	    
	    if ((linetrigger == 1) && (strstr(count, " 11"))){       
			printf("\n 11 at %d ", linenumber);
			x_end = linenumber + 2;
			}  	    
	    if ((linetrigger == 1) && (strstr(count, " 21"))){       
			printf("\n 21 at %d ", linenumber);
			y_end = linenumber + 2;
			}  
		if ((linetrigger == 1) && (strstr(count, " 31"))){       
			printf("\n 31 at %d ", linenumber);
			z_end = linenumber + 2;
			linetrigger = 0; // use this to finish your search after "LINE" is triggered. 
			} 
			
//CIRCLE SECTION///////////////////////////////////////////////////////////////////////////////////////

        if ((strstr(count, "CIRCLE")))  {  // search for circle
			circletrigger = 1;
			}
        if ((circletrigger == 1) && (strstr(count, "AcDbEntity")) ) {// search inside circle block, subtrigger 		
			circleblock = circleblock + 1;
			printf("\nCircleblock %d ", circleblock); 		
            circlesubtrigger = 1;
			}		
	    if ((circletrigger == 1) && (strstr(count, " 10")) && (circlesubtrigger == 1) ){   
			printf("\n 10 at %d ", linenumber);
			x_center = linenumber + 2; 
		    }
		if ((circletrigger == 1) && (strstr(count, " 20")) && (circlesubtrigger == 1) ){   
			printf("\n 20 at %d ", linenumber);
			y_center = linenumber + 2; 
		    }
		if ((circletrigger == 1) && (strstr(count, " 30")) && (circlesubtrigger == 1) ){   
			printf("\n 30 at %d ", linenumber);
			z_center = linenumber + 2; 
		    }
		if ((circletrigger == 1) && (strstr(count, " 40")) && (circlesubtrigger == 1) ){   
			printf("\n 40 at %d ", linenumber);
			radius = linenumber + 2; 
		    }
		if ((circletrigger == 1) && (strstr(count, " 50")) && (circlesubtrigger == 1) ){   
			printf("\n 50 at %d ", linenumber);
			start_angle = linenumber + 2; 
		    }
		if ((circletrigger == 1) && (strstr(count, " 51")) && (circlesubtrigger == 1) ){   
			printf("\n 51 at %d ", linenumber);
			end_angle = linenumber + 2; 
		    }
		if ((circletrigger == 1) && (strstr(count, "  0")) && (circlesubtrigger == 1) ){   
			end = linenumber;         
			circlesubtrigger = 0;
		    }
		if (((circletrigger == 1) && (strstr(count, "ARC"))) || ((circletrigger == 1) && (strstr(count, "LINE"))) || ((circletrigger == 1) && (strstr(count, "LWPOLYLINE"))) || ((circletrigger == 1) && (strstr(count, "ENDSEC")))){   
			end = linenumber;       
			circletrigger = 0;      
			circlesubtrigger = 0;
		    }			    
		    
//ARC SECTION///////////////////////////////////////////////////////////////////////////////////////

        if ((strstr(count, "ARC")))  {  // search for arc
			arctrigger = 1;
			}
        if ((arctrigger == 1) && (strstr(count, "AcDbEntity")) ) {// search inside circle block, subtrigger 		
			arcblock = arcblock + 1;
			printf("\nArc %d ", arcblock); 		
            arcsubtrigger = 1;
			}		
	    if ((arctrigger == 1) && (strstr(count, " 10")) && (arcsubtrigger == 1) ){   
			printf("\n 10 at %d ", linenumber);
			x_center = linenumber + 2; 
		    }
		if ((arctrigger == 1) && (strstr(count, " 20")) && (arcsubtrigger == 1) ){   
			printf("\n 20 at %d ", linenumber);
			y_center = linenumber + 2; 
		    }
		if ((arctrigger == 1) && (strstr(count, " 30")) && (arcsubtrigger == 1) ){   
			printf("\n 30 at %d ", linenumber);
			z_center = linenumber + 2; 
		    }
		if ((arctrigger == 1) && (strstr(count, " 40")) && (arcsubtrigger == 1) ){   
			printf("\n 40 at %d ", linenumber);
			radius = linenumber + 2; 
		    }
		if ((arctrigger == 1) && (strstr(count, " 50")) && (arcsubtrigger == 1) ){   
			printf("\n 50 at %d ", linenumber);
			start_angle = linenumber + 2; 
		    }
		if ((arctrigger == 1) && (strstr(count, " 51")) && (arcsubtrigger == 1) ){   
			printf("\n 51 at %d ", linenumber);
			end_angle = linenumber + 2; 
		    }
		if ((arctrigger == 1) && (strstr(count, "  0")) && (arcsubtrigger == 1) ){   
			end = linenumber;         
			arcsubtrigger = 0;
		    }
		if ((arctrigger == 1) && (strstr(count, "ENDSEC")) ){   
			end = linenumber;       
			arctrigger = 0;      
			arcsubtrigger = 0;
		    }	
		if (((arctrigger == 1) && (strstr(count, "CIRCLE"))) || ((arctrigger == 1) && (strstr(count, "LINE"))) || ((arctrigger == 1) && (strstr(count, "LWPOLYLINE"))) || ((arctrigger == 1) && (strstr(count, "ENDSEC"))) ){   
			end = linenumber;       
			arctrigger = 0;      
			arcsubtrigger = 0;
		    }	
		    
//LWPOLYLINE SECTION///////////////////////////////////////////////////////////////////////////////////////
        if ((strstr(count, "LWPOLYLINE")))  {  // search for lwpolyline
			polytrigger = 1;
			}
        if ((polytrigger == 1) && (strstr(count, "AcDbEntity")) ) {// search inside polyline block, subtrigger 		
			polyblock = polyblock + 1;
			printf("\nPolyblock %d ", polyblock); 		
            polysubtrigger = 1;
			}		
	    if ((polytrigger == 1) && (strstr(count, " 10")) && (polysubtrigger == 1) ){   
			polyitem = polyitem + 1;
			printf("\n 10 at %d polyitem %d", linenumber, polyitem);    
			poly_x_point = linenumber + 2; 
	
		    }
		if ((polytrigger == 1) && (strstr(count, " 20")) && (polysubtrigger == 1) ){   
			printf("\n 20 at %d ", linenumber);
			poly_y_point = linenumber + 2; 
		    }	  
		if ((polytrigger == 1) && (strstr(count, "  0")) && (polysubtrigger == 1) ){   
			end = linenumber;         
			polysubtrigger = 0;
			polyitem = 0;
		    }	
		if (((polytrigger == 1) && (strstr(count, "CIRCLE"))) || ((polytrigger == 1) && (strstr(count, "ARC"))) || ((polytrigger == 1) && (strstr(count, "ENDSEC"))) ){   
			end = linenumber;       
			polytrigger = 0;      
			polysubtrigger = 0;
		    }		  
 
		  
		linenumber++;	
		
//WRITE G-CODE FILE SECTION///////////////////////////////////////////////////////////////////////////////////////	

        if(write_stop == 0){ //NGC startup code :
        char intro[500]={"(GROTIUS CNC MACHINES B.V. 2019 DXF2GODE C-coded Converter)\nG21      (Units: Metric)\nG40      (Compensation off)\nG90      (Absolute distance mode)\nF1       (Feed)\nS10      (Power)\nG64P0.01 (Accuracy)\n#1 = #<_hal[feed]>  (G1 Feedrate)\n#2 = #<_hal[power]> (Plasma Power)\n\nF#<_hal[feed]>\nS#<_hal[power]>\n\n"};
        fprintf(file_write,"%s\n",intro);
        
        printlinenumber++;
        
        //char G0[100]={" G0 X0 Y0 Z0 F10000\n"};
        
        // first step to do is, compare lineblock's for closed contour...check if a lineblock x_end is the begin of a x_start lineblock... then group them as object.... Nice man...   
        //fprintf(file_write,"\n%d",printlinenumber);
        //fprintf(file_write,"%s",G0);

        write_stop = 1;   //prevent writing intro multiple times.
        
        // Real g-code ....

	    }
		    
//TERMINAL AND FILE PRINT SECTION///////////////////////////////////////////////////////////////////////////////////////		
     
        //count is the text line buffer of type char, we converse it here to float.
        float linebuffer = atof(count);
      
		// LINE 
		if (linetrigger == 1){
		if (linenumber == x_start){printf("\nX_start %s", count); fprintf(file_write,"\nG01 X%f ", linebuffer); }	
		if (linenumber == y_start){printf("\nY_start %s", count); fprintf(file_write,"Y%f ", linebuffer); }	
		if (linenumber == z_start){printf("\nZ_start %s", count); fprintf(file_write,"Z%f ", linebuffer); }
		if (linenumber == x_end){printf("\nX_end %s", count); fprintf(file_write,"\nG01 X%f ", linebuffer); }
		if (linenumber == y_end){printf("\nY_end %s", count); fprintf(file_write,"Y%f ", linebuffer); }
		if (linenumber == z_end){printf("\nZ_end %s", count); fprintf(file_write,"Z%f ", linebuffer); }		
	    }
	    
	    // CIRCLE & ARC value's G2 & G3 must be specified with G40,G41,G42 later on trough closed contour calculation
	    // G02 clockwise, G03 counter-clockwise, I horizontal center, J vertical center, F speed
	    // Lets start with a clockwise circle G2 code and start at center left. I use the (radius*-1) to get the startpoint on left side of circle lead in is easy to integrate later on
	    // For programming lead in's i prefer to connect the python coded linuxcnc user gui to this program
	    
        // We need to do a calculation to make the circle startpoint at the edge of the circle. We store the linebuffer until we got all value's related to the circle
        // After all value's are stored, we write the g-code line at once
        
        // CIRCLE (full circle)
        // Only print circle values. If we don't use circletrigger or circlesubtrigger it can be that arc value's are printed because we use terms like x_center for circle's but also for arc's
        if (circlesubtrigger == 1){
		if (linenumber == x_center){printf("\nX_center %s", count); temp_x_center = linebuffer; x_float_collector=1;}			
		if (linenumber == y_center){printf("\nY_center %s", count); temp_y_center = linebuffer; y_float_collector=1;}	
		if (linenumber == z_center){printf("\nZ_center %s", count); temp_z_center = linebuffer; z_float_collector=1;}	
		if (linenumber == radius){printf("\nRadius %s", count); temp_radius = linebuffer; radius_float_collector=1;}	
		// Data is collected, write g-code to file :
	    if(x_float_collector==1 && y_float_collector==1 && z_float_collector==1 && radius_float_collector==1){fprintf(file_write,"\nG02 X%f Y%f Z%f I%f", temp_y_center, temp_x_center, temp_z_center, temp_radius*-1); x_float_collector=0; y_float_collector=0; z_float_collector=0; radius_float_collector=0;}
	    }
	    
	    // ARC (circle segment with start and end angle)
	    if (arcsubtrigger == 1){
		if (linenumber == x_center){printf("\nX_center %s", count); temp_x_center = linebuffer; x_float_collector=1;}			
		if (linenumber == y_center){printf("\nY_center %s", count); temp_y_center = linebuffer; y_float_collector=1;}	
		if (linenumber == z_center){printf("\nZ_center %s", count); temp_z_center = linebuffer; z_float_collector=1;}	
		if (linenumber == radius){printf("\nRadius %s", count); temp_radius = linebuffer; radius_float_collector=1;}			
		if (linenumber == start_angle){printf("\nStart_angle %s", count); temp_start_angle = linebuffer; start_angle_float_collector=1;}	
		if (linenumber == end_angle){printf("\nEnd_angle %s", count); temp_end_angle = linebuffer; end_angle_float_collector=1;}
		// Data is collected, write g-code to file :
		if(x_float_collector==1 && y_float_collector==1 && z_float_collector==1 && radius_float_collector==1 && start_angle_float_collector==1 && end_angle_float_collector==1){fprintf(file_write,"\nG02 X%f Y%f Z%f I%f (START%f END%f)", temp_y_center, temp_x_center, temp_z_center, temp_radius*-1, temp_start_angle, temp_end_angle); x_float_collector=0; y_float_collector=0; z_float_collector=0; radius_float_collector=0; start_angle_float_collector=0; end_angle_float_collector=0;}
	    }		
	
		// POLY value's :
		if (linenumber == poly_x_point){printf("\nPoly_x_point %s", count); }	
		if (linenumber == poly_y_point){printf("\nPoly_y_point %s", count); }		
		
//INFO///////////////////////////////////////////////////////////////////////////////////////		
    
		   
    	
    }
	        
    fclose(file);
    printf("\n\nfile to read closed");
    
    fclose(file_write);
    printf("\n\nfile to write closed");		
    return 0;
}



