/*****************************************************************************/ /* */ /* Copyright (C) 2003--2025 M. Held */ /* */ /* This code is not in the public domain. All rights reserved! Please make */ /* sure to read the full copyright statement contained in "README.txt" or in */ /* the "main" file of this code, such as "main.cc". */ /* */ /*****************************************************************************/ /* */ /* Written by: Martin Held */ /* */ /* E-Mail: held@cs.sbg.ac.at */ /* Fax Mail: (+43 662) 8044-611 */ /* Voice Mail: (+43 662) 8044-6304 */ /* Snail Mail: Martin Held */ /* FB Informatik */ /* Universitaet Salzburg */ /* A-5020 Salzburg, Austria */ /* */ /*****************************************************************************/ /* */ /* get standard libraries */ /* */ #include #include #include #include #include #include #include /* */ /* get my header files */ /* */ #include "vronivector.h" #include "vroni_object.h" #include "fpkernel.h" #include "defs.h" #include "ext_appl_defs.h" #include "io_dxf.h" #define LINE_LENGTH 1024 #define NEWLINE '\n' #define CARRIAGE '\r' #define InitBBox \ {\ bb_min.x = bb_min.y = DBL_MAX; \ bb_max.x = bb_max.y = - DBL_MAX; \ } #define IsSpace(x)\ ((x == ' ') || (x == '\t') || (x == '\r') || (x == '\n') || (x == '\f')) #define SkipUntilDXFCode(input, code, string, dxf_code) \ { \ do { \ if (!ReadNewDXFPair(input, code, string, LINE_LENGTH)) \ throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!"); \ } while (atoi(code) != dxf_code); \ } #define SkipUntilDXFString(input, code, string, dxf_string) \ { \ do { \ if (!ReadNewDXFPair(input, code, string, LINE_LENGTH)) \ throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!"); \ } while (strcmp(string, dxf_string)); \ if (!ReadNewDXFPair(input, code, string, LINE_LENGTH)) \ throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!"); \ } vr_bool ReadNewLine(FILE *input, char *line, int size, vr_bool read_string) { char *s; int i; do { s = fgets(line, size, input); if (s == (char*)NULL) return false; i = ((int) strlen(s)) - 1; while((i >= 0) && IsSpace(s[i])) { s[i]='\0'; i--; } if (i >= 0) { while (IsSpace(s[0])) ++s; line = strcpy(line, s); } else if (read_string) { i = 0; } } while (i < 0); if (i < 0) return false; else return true; } vr_bool ReadNewDXFPair(FILE *input, char *code, char *string, int size) { if (!ReadNewLine(input, code, size, false)) return false; if (!ReadNewLine(input, string, size, true)) return false; return true; } /* */ /* This is a >>VERY<< rudimentary interface for reading AutoCAD DXF files. */ /* Note that this interface is not as general as it ought to be. That is, */ /* likely it will cough on lots of DXF files. Currently, it supports POINT, */ /* LINE, ARC, CIRCLE, POLYLINE and LWPOLYLINE entities, including "closed" */ /* flags and bulge factors for the latter two entities. It does not handle */ /* BLOCKs or INSERTs or LAYERs, or any other codes that turn objects on or */ /* off, or that move or resize them. Also, this routine does not care about */ /* z-coordinates, and it does not support binary files. */ /* */ void vroniObject::ReadDXFFile(char input_file[], vr_bool *new_input) { FILE *input; char code[LINE_LENGTH+1]; char string[LINE_LENGTH+1]; int dxf_code, i; double xc1 = 0.0, yc1 = 0.0, xc2 = 0.0, yc2 = 0.0; double rad = 0.0, bulge = 0.0, old_bulge = 0.0, s_a = 0.0, e_a = 0.0; vr_bool xc1_set, yc1_set, xc2_set, yc2_set; vr_bool rad_set, s_a_set, e_a_set; vr_bool pnt_read, seg_read, arc_read, cir_read, poly_closed = false; vr_bool poly_started = false;; *new_input = false; isolated_pnts = false; InitBBox; input = OpenFileVD(input_file, "r"); if (!ReadNewDXFPair(input, code, string, LINE_LENGTH)) return; while (strcmp(string, "EOF")) { if ((!strcmp(string, "POINT")) || (!strcmp(string, "LINE")) || (!strcmp(string, "CIRCLE")) || (!strcmp(string, "ARC"))) { /* */ /* input point, line segment, circle or circular arc. */ /* */ xc1_set = yc1_set = false; xc2_set = yc2_set = false; rad_set = s_a_set = e_a_set = false; pnt_read = seg_read = arc_read = cir_read = false; if (!strcmp(string, "POINT")) pnt_read = true; if (!strcmp(string, "LINE")) seg_read = true; if (!strcmp(string, "ARC")) arc_read = true; if (!strcmp(string, "CIRCLE")) cir_read = true; do { if (!ReadNewDXFPair(input, code, string, LINE_LENGTH)) throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!"); dxf_code = atoi(code); switch(dxf_code) { case 10: xc1 = atof(string); xc1_set = true; break; case 20: yc1 = atof(string); yc1_set = true; break; case 11: xc2 = atof(string); xc2_set = true; break; case 21: yc2 = atof(string); yc2_set = true; break; case 40: rad = atof(string); rad_set = true; break; case 50: s_a = atof(string); s_a_set = true; break; case 51: e_a = atof(string); e_a_set = true; break; default: break; } } while (dxf_code != 0); if (xc1_set && yc1_set) { *new_input = true; if (seg_read && xc2_set && yc2_set) { #ifdef EXT_APPL_SITES HandleSeg(xc1, yc1, xc2, yc2, eas_NIL); #else HandleSeg(xc1, yc1, xc2, yc2); #endif } else if (arc_read && rad_set && s_a_set && e_a_set){ s_a *= M_PI_180; e_a *= M_PI_180; #ifdef EXT_APPL_SITES HandleArc(xc1 + rad * cos(s_a), yc1 + rad * sin(s_a), xc1 + rad * cos(e_a), yc1 + rad * sin(e_a), xc1, yc1, ARC, eas_NIL); #else HandleArc(xc1 + rad * cos(s_a), yc1 + rad * sin(s_a), xc1 + rad * cos(e_a), yc1 + rad * sin(e_a), xc1, yc1, ARC); #endif } else if (cir_read && rad_set) { #ifdef EXT_APPL_SITES HandleArc(xc1 + rad, yc1, xc1 - rad, yc1, xc1, yc1, ARC, eas_NIL); HandleArc(xc1 - rad, yc1, xc1 + rad, yc1, xc1, yc1, ARC, eas_NIL); #else HandleArc(xc1 + rad, yc1, xc1 - rad, yc1, xc1, yc1, ARC); HandleArc(xc1 - rad, yc1, xc1 + rad, yc1, xc1, yc1, ARC); #endif } else if (pnt_read) { #ifdef EXT_APPL_PNTS (void) HandlePnt(xc1, yc1, eap_NIL); #else (void) HandlePnt(xc1, yc1); #endif isolated_pnts = true; } } } else if (!strcmp(string, "LWPOLYLINE")) { /* */ /* "light-weight" polygonal curve. */ /* */ DXFStartPoly(); xc1_set = false; yc1_set = false; bulge = 0.0; poly_closed = false; do { if (!ReadNewDXFPair(input, code, string, LINE_LENGTH)) throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!"); dxf_code = atoi(code); switch(dxf_code) { case 10: case 20: if (dxf_code == 10) { xc1 = atof(string); xc1_set = true; } else { yc1 = atof(string); yc1_set = true; } if (xc1_set && yc1_set) { *new_input = true; DXFAddPolyVertex(xc1, yc1, bulge); xc1_set = false; yc1_set = false; bulge = 0.0; } break; case 42: bulge = atof(string); break; case 70: poly_closed = (vr_bool) (1&atoi(string)); break; default: break; } } while (dxf_code != 0); if (poly_closed) { DXFClosePoly(bulge); bulge = 0.0; } } else if (!strcmp(string, "POLYLINE")) { /* */ /* polygonal curve. */ /* */ poly_closed = false; do { if (!ReadNewDXFPair(input, code, string, LINE_LENGTH)) throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!"); dxf_code = atoi(code); switch(dxf_code) { case 70: poly_closed = (vr_bool) (1&atoi(string)); break; default: break; } } while (dxf_code != 0); if (strcmp(string, "VERTEX")) SkipUntilDXFString(input, code, string, "VERTEX"); DXFStartPoly(); poly_started = true; old_bulge = 0.0; } else if (!strcmp(string, "VERTEX")) { /* */ /* vertex of a polygon. */ /* */ xc1_set = false; yc1_set = false; bulge = 0.0; do { if (!ReadNewDXFPair(input, code, string, LINE_LENGTH)) throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!"); dxf_code = atoi(code); switch(dxf_code) { case 10: xc1 = atof(string); xc1_set = true; break; case 20: yc1 = atof(string); yc1_set = true; break; case 42: bulge = atof(string); break; default: break; } } while (dxf_code != 0); if (poly_started && xc1_set && yc1_set) { *new_input = true; DXFAddPolyVertex(xc1, yc1, old_bulge); old_bulge = bulge; } xc1_set = false; yc1_set = false; } else if (!strcmp(string, "SEQEND")) { if (poly_closed) DXFClosePoly(old_bulge); poly_started = false; if (!ReadNewDXFPair(input, code, string, LINE_LENGTH)) throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!"); } else if (string[0] == '$') { /* */ /* some initialization stuff. we don't care about it. */ /* */ if (!ReadNewDXFPair(input, code, string, LINE_LENGTH)) throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!"); } else if (string[0] == '{') { /* */ /* some application-specific stuff. we don't care about it. */ /* */ i = ((int) strlen(string)) - 1; if (string[i] != '}') { SkipUntilDXFString(input, code, string, "}"); } else { if (!ReadNewDXFPair(input, code, string, LINE_LENGTH)) throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!"); } } else if (!strcmp(string, "LAYER")) { /* */ /* information on a layer. we skip it. */ /* */ SkipUntilDXFCode(input, code, string, 0); } else if (!strcmp(string, "BLOCK")) { /* */ /* information on a block. we skip it. */ /* */ SkipUntilDXFString(input, code, string, "ENDBLK"); } else if (!strcmp(string, "INSERT")) { /* */ /* information on inserting a block. we skip it. */ /* */ SkipUntilDXFCode(input, code, string, 0); } else if (!strcmp(string, "SPLINE")) { /* */ /* information on a spline. we skip it. */ /* */ SkipUntilDXFCode(input, code, string, 0); } else if (!strcmp(string, "ELLIPSE")) { /* */ /* information on an ellipse. we skip it. */ /* */ SkipUntilDXFCode(input, code, string, 0); } else if (!strcmp(string, "TEXT")) { /* */ /* text. we skip it. */ /* */ SkipUntilDXFCode(input, code, string, 0); } else if (!strcmp(string, "DIMENSION")) { /* */ /* dimensons. we skip it. */ /* */ SkipUntilDXFCode(input, code, string, 0); } else if (!strcmp(string, "HATCH")) { /* */ /* information on hatching. we skip it. */ /* */ SkipUntilDXFCode(input, code, string, 0); } else { /* */ /* some dxf code that we don't care about. */ /* */ if (!ReadNewDXFPair(input, code, string, LINE_LENGTH)) throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!"); } } fclose(input); return; } /* */ /* this routines writes the standard start-up DXF lines. */ /* */ void vroniObject::StartDXFFile(FILE *dxf_file) { fprintf(dxf_file, " 0\nSECTION\n 2\nHEADER\n" ); fprintf(dxf_file, " 0\nENDSEC\n" ); fprintf(dxf_file, " 0\nSECTION\n 2\nENTITIES\n" ); return; } /* */ /* this routines writes the standard finishing DXF lines. */ /* */ void vroniObject::FinishDXFFile(FILE *dxf_file) { if (dxf_file != (FILE*)NULL) { fprintf(dxf_file, " 0\nENDSEC\n 0\nEOF\n"); } return; } void vroniObject::WriteDXFEntity(FILE *dxf_file, int color) { // write Handle fprintf(dxf_file, " 5\n%d\n", dxf_handle); dxf_handle++; // write subclass marker (AcDbEntity) fprintf(dxf_file, "100\nAcDbEntity\n"); // write layer name fprintf(dxf_file, " 8\nVRONI\n"); // write color number if (color >= 0) fprintf(dxf_file, " 62\n%3d\n", color); return; } /* */ /* output a 2D line segment in DXF format. */ /* */ void vroniObject::WriteDXFLine(FILE *dxf_file, double_arg xc1, double_arg yc1, double_arg xc2, double_arg yc2, int color) { if (dxf_file != (FILE*)NULL) { fprintf(dxf_file, " 0\nLINE\n" ); WriteDXFEntity(dxf_file, color); fprintf(dxf_file, "100\nAcDbLine\n" ); FP_fprintf(dxf_file, " 10\n%f\n 20\n%f\n 30\n0.0\n", FP_PRNTARG(xc1), FP_PRNTARG(yc1) ); FP_fprintf(dxf_file, " 11\n%f\n 21\n%f\n 31\n0.0\n", FP_PRNTARG(xc2), FP_PRNTARG(yc2) ); } else { throw std::runtime_error("VRONI error: WriteDXFLine() - DXF output file not opened properly!"); } return; } /* */ /* output a 2D point in DXF format. */ /* */ void vroniObject::WriteDXFPoint(FILE *dxf_file, double_arg xc1, double_arg yc1, int color) { if (dxf_file != (FILE*)NULL) { fprintf(dxf_file, " 0\nPOINT\n" ); WriteDXFEntity(dxf_file, color); fprintf(dxf_file, "100\nAcDbPoint\n" ); FP_fprintf(dxf_file, " 10\n%f\n 20\n%f\n 30\n0.0\n", FP_PRNTARG(xc1), FP_PRNTARG(yc1) ); } else { throw std::runtime_error("VRONI error: WriteDXFPoint() - DXF output file not opened properly!"); } return; } /* */ /* output a 2D circle in DXF format. */ /* */ void vroniObject::WriteDXFCircle(FILE *dxf_file, double_arg xc1, double_arg yc1, double_arg radius, int color) { if (dxf_file != (FILE*)NULL) { fprintf(dxf_file, " 0\nCIRCLE\n" ); WriteDXFEntity(dxf_file, color); fprintf(dxf_file, "100\nAcDbCircle\n" ); FP_fprintf(dxf_file, " 10\n%f\n 20\n%f\n 30\n0.0\n", FP_PRNTARG(xc1), FP_PRNTARG(yc1) ); FP_fprintf(dxf_file, " 40\n%f\n", FP_PRNTARG(radius) ); } else { throw std::runtime_error("VRONI error: WriteDXFCircle() - DXF output file not properly opened!"); } return; } /* */ /* output a 2D circular arc in DXF format. */ /* */ void vroniObject::WriteDXFArc(FILE *dxf_file, double_arg xc1, double_arg yc1, double_arg xc2, double_arg yc2, double_arg xc3, double_arg yc3, vr_bool ccw_flag, int color) { double s_a, s_e; double dx, dy, r; if (dxf_file != (FILE*)NULL) { fprintf(dxf_file, " 0\nARC\n" ); WriteDXFEntity(dxf_file, color); fprintf(dxf_file, "100\nAcDbCircle\n" ); FP_fprintf(dxf_file, " 10\n%f\n 20\n%f\n 30\n0.0\n", FP_PRNTARG(xc3), FP_PRNTARG(yc3) ); dx = xc1 - xc3; dy = yc1 - yc3; r = sqrt( dx*dx + dy*dy ); FP_fprintf(dxf_file, " 40\n%f\n", FP_PRNTARG(r) ); s_a = atan2( dy, dx ); s_e = atan2( yc2 - yc3, xc2 - xc3 ); if ( s_a < 0.0 ) s_a += 2*M_PI; if ( s_e < 0.0 ) s_e += 2*M_PI; s_a *= M_180_PI; s_e *= M_180_PI; fprintf(dxf_file, "100\nAcDbArc\n" ); if ( ccw_flag ) FP_fprintf(dxf_file, " 50\n%f\n 51\n%f\n", FP_PRNTARG(s_a), FP_PRNTARG(s_e) ); else FP_fprintf(dxf_file, " 50\n%f\n 51\n%f\n", FP_PRNTARG(s_e), FP_PRNTARG(s_a) ); } else { throw std::runtime_error("VRONI error: WriteDXFArc() - DXF output file not properly opened!"); } return; } /* */ /* output the start code for "LWPOLYLINE" in DXF format. */ /* */ void vroniObject::WriteDXFLWPoly_Start(FILE *dxf_file, vr_bool closed, int color) { if (dxf_file != (FILE*)NULL) { fprintf(dxf_file, " 0\nLWPOLYLINE\n" ); WriteDXFEntity(dxf_file, color); fprintf(dxf_file, "100\nAcDbPolyline\n" ); if (closed) fprintf(dxf_file, " 70\n 1\n" ); else fprintf(dxf_file, " 70\n 0\n" ); fprintf(dxf_file, " 6\nCONTINUOUS\n"); } else { throw std::runtime_error("VRONI error: WriteDXFLWPoly_Start() - DXF output file not properly opened!"); } return; } /* */ /* output the start code for "POLYLINE" in DXF format. */ /* */ void vroniObject::WriteDXFPoly_Start(FILE *dxf_file, vr_bool closed, int color) { if (dxf_file != (FILE*)NULL) { fprintf(dxf_file, " 0\nPOLYLINE\n" ); WriteDXFEntity(dxf_file, color ); fprintf(dxf_file, "100\nAcDb2dPolyline\n" ); if (closed) fprintf(dxf_file, " 70\n 1\n" ); else fprintf(dxf_file, " 70\n 0\n" ); fprintf(dxf_file, " 6\nCONTINUOUS\n"); } else { throw std::runtime_error("VRONI error: WriteDXFPoly_Start() - DXF output file not properly opened!"); } return; } /* */ /* output the end code for "POLYLINE" in DXF format. */ /* */ void vroniObject::WriteDXFPoly_End(FILE *dxf_file) { if (dxf_file != (FILE*)NULL) { fprintf(dxf_file, " 0\nSEQEND\n"); } else { throw std::runtime_error("VRONI error: WriteDXFPoly_End() - DXF output file not properly opened!"); } return; } /* */ /* output one vertex of a "LWPOLYLINE" in DXF format. */ /* */ void vroniObject::WriteDXFLWPoly_Vertex(FILE *dxf_file, double_arg xc1, double_arg yc1, double_arg bulge) { if (dxf_file != (FILE*)NULL) { FP_fprintf(dxf_file, " 10\n%f\n 20\n%f\n 30\n0.0\n", FP_PRNTARG(xc1), FP_PRNTARG(yc1)); if (bulge != 0.0) FP_fprintf(dxf_file, " 42\n%f\n", FP_PRNTARG(bulge)); } else { throw std::runtime_error("VRONI error: WriteDXFLWPoly_Vertex() - DXF output file not properly opened!"); } return; } /* */ /* output one vertex of a "POLYLINE" in DXF format. */ /* */ void vroniObject::WriteDXFPoly_Vertex(FILE *dxf_file, double_arg xc1, double_arg yc1, double_arg bulge) { if (dxf_file != (FILE*)NULL) { fprintf(dxf_file, " 0\nVERTEX\n"); FP_fprintf(dxf_file, " 10\n%f\n 20\n%f\n 30\n0.0\n", FP_PRNTARG(xc1), FP_PRNTARG(yc1)); if (bulge != 0.0) FP_fprintf(dxf_file, " 42\n%f\n", FP_PRNTARG(bulge)); } else { throw std::runtime_error("VRONI error: WriteDXFPoly_Vertex() - DXF output file not properly opened!"); } return; }