/*****************************************************************************/ /* */ /* F I S T : Fast, Industrial-Strength Triangulation */ /* */ /*****************************************************************************/ /* */ /* (C) Martin Held */ /* (C) Universitaet Salzburg, Salzburg, Austria */ /* */ /* This code is not in the public domain. All rights reserved! Please make */ /* sure to read the full copyright statement contained in api_functions.cpp. */ /* */ /*****************************************************************************/ /* */ /* get standard libraries */ /* */ #include #include #include #include #include #include /* */ /* get my header files */ /* */ #include "fpkernel.h" #include "martin.h" #include "defs.h" #include "list.h" #include "basic.h" #include "header.h" #include "ipe_io.h" #include "io_dxf.h" /* */ /* function prototypes of functions provided in this file */ /* */ void ReadPolygon(global_struct *all); void ReadPoly(global_struct *all); void ReadPolyLines(global_struct *all); void WritePolygon(global_struct *all, char output_file[]); void WriteFacesDXF(global_struct *all, char output_file[]); /* Writes into Triangle's .poly file format or also Qi Meng's GPU-DT format */ /* switched can be using hard-coded ifdefs */ /* ONLY FOR Qi Meng's GPU-DT Code: (needs POLYSTARTINDEX 0) */ #define QiMeng //#undef QiMeng #define POLYSTARTINDEX 0 void WritePolyFormat(global_struct *all); void ReadContour(global_struct *all, FILE *input) { int i, number, orientation, attr = 0, last_attr = 0; double xc0, yc0, xc1, yc1, xc2, yc2; double start_x, start_y, center_x, center_y; #ifdef EXT_APPL_SITES eas_type eas_data; #endif xc0 = yc0 = start_x = start_y = center_x = center_y = C_0_0; /* */ /* get the number of contour elements */ /* */ if (!ReadNumber(input, &number)) throw EOF_ENCOUNTERED; StartPoly(all); InitStoragePnts(&all->c_data, number); InitStorageList(&all->c_list, number+1); if (number < 0) number = - number; if (number < 2) { FIST_Warning("ReadContour() - less than two vertices!\n"); throw INSUFFICENT_INPUT; } /* */ /* read the orientation of the contour (we don't trust it, though) */ /* */ if (!ReadOptionalNumber(input, &orientation)) throw EOF_ENCOUNTERED; for (i = 1; i <= number; ++i) { /* */ /* read next vertex of polygon */ /* */ if (!ReadOptionalNumber(input, &attr)) throw EOF_ENCOUNTERED; #ifdef EXT_APPL_SITES if (!ReadPntData(input, &xc1, &yc1, &eas_data)) #else if (!ReadPntData(input, &xc1, &yc1)) #endif throw EOF_ENCOUNTERED; if (i == 1) { xc0 = xc1; yc0 = yc1; } if (last_attr != 0) { #ifdef EXT_APPL_SITES HandleArc(all, start_x, start_y, xc1, yc1, center_x, center_y, last_attr, eas_NIL); #else HandleArc(all, start_x, start_y, xc1, yc1, center_x, center_y, last_attr); #endif last_attr = 0; } if (!ReadOptionalCoord(input, &xc2)) throw EOF_ENCOUNTERED; if (!ReadOptionalCoord(input, &yc2)) throw EOF_ENCOUNTERED; if (attr == 0) { #ifdef EXT_APPL_SITES AddPolyVertex(all, xc1, yc1, eas_data); #else AddPolyVertex(all, xc1, yc1); #endif last_attr = 0; } else { last_attr = attr; start_x = xc1; start_y = yc1; center_x = xc2; center_y = yc2; } } if (last_attr != 0) { #ifdef EXT_APPL_SITES HandleArc(all, start_x, start_y, xc0, yc0, center_x, center_y, last_attr, eas_NIL); #else HandleArc(all, start_x, start_y, xc0, yc0, center_x, center_y, last_attr); #endif } CloseCurrentPoly(all); return; } /* */ /* this function reads a simply-connected or multiply-connected polygon */ /* specified in my .dat format for curvilinear data. if EXT_APPL_SITES is */ /* defined at compile-time, and if the functions for parsing the file are */ /* properly redefined in io_parse.c, then the same routine can be used to */ /* parse .dat data with application-specific data added in the file. */ /* */ void ReadPolygon(global_struct *all) { double xc1, yc1, xc2, yc2; int i, number; FILE *input; input = OpenFile(all->rt_opt.input_file, "r"); /* */ /* read enclosing bounding box (we don't trust it, though) */ /* */ if (!ReadOptionalCoord(input, &xc1)) throw EOF_ENCOUNTERED; if (!ReadOptionalCoord(input, &yc1)) throw EOF_ENCOUNTERED; if (!ReadOptionalCoord(input, &xc2)) throw EOF_ENCOUNTERED; if (!ReadOptionalCoord(input, &yc2)) throw EOF_ENCOUNTERED; all->bb_min.x = all->bb_min.y = fpkernel_DBL_MAX; all->bb_max.x = all->bb_max.y = - fpkernel_DBL_MAX; /* */ /* get the number of contours */ /* */ if (!ReadNumber(input, &number)) throw EOF_ENCOUNTERED; InitStorageLoops(&all->c_list, number); for (i = 0; i < number; ++i) { ReadContour(all, input);\ } fclose(input); all->new_input = true; return; } /* */ /* this function reads a simply-connected polygon specified in my simplified */ /* format for polygons. similar to ReadPolygon(), if EXT_APPL_SITES is */ /* defined at compile-time, and if the functions for parsing the file are */ /* properly redefined in io_parse.c, then the same routine can be used to */ /* parse .poly data with application-specific data added in the file. */ /* */ void ReadPoly(global_struct *all) { double xc1, yc1; int i, number; FILE *input; #ifdef EXT_APPL_SITES eas_type eas_data; #endif input = OpenFile(all->rt_opt.input_file, "r"); all->bb_min.x = all->bb_min.y = fpkernel_DBL_MAX; all->bb_max.x = all->bb_max.y = - fpkernel_DBL_MAX; InitStorageLoops(&all->c_list, 1); StartPoly(all); /* */ /* get the number of contour elements */ /* */ if (!ReadNumber(input, &number)) throw EOF_ENCOUNTERED; InitStoragePnts(&all->c_data, number); InitStorageList(&all->c_list, number+1); if (number < 3) throw INSUFFICENT_INPUT; all->new_input = true; for (i = 1; i <= number; ++i) { /* */ /* read next vertex of polygon */ /* */ #ifdef EXT_APPL_SITES if (!ReadPntData(input, &xc1, &yc1, &eas_data)) #else if (!ReadPntData(input, &xc1, &yc1)) #endif throw EOF_ENCOUNTERED; #ifdef EXT_APPL_SITES AddPolyVertex(all, xc1, yc1, eas_data); #else AddPolyVertex(all, xc1, yc1); #endif } CloseCurrentPoly(all); fclose(input); return; } /* */ /* this function reads several polygons specified in my .lines format for */ /* polygons. note that the .lines format requires the first and last point */ /* of every polygon to be identical! */ /* similar to ReadPolygon(), if EXT_APPL_SITES is defined at compile-time, */ /* and if the functions for parsing the file are properly redefined in */ /* io_parse.c, then the same routine can be used to parse .lines data with */ /* application-specific data added in the file. */ /* */ void ReadPolyLines(global_struct *all) { double xc1, yc1, xc0, yc0; int i, number; FILE *input; #ifdef EXT_APPL_SITES eas_type eas_data; #endif input = OpenFile(all->rt_opt.input_file, "r"); all->bb_min.x = all->bb_min.y = fpkernel_DBL_MAX; all->bb_max.x = all->bb_max.y = - fpkernel_DBL_MAX; /* */ /* get the number of contour elements for this polygon */ /* */ while (ReadNumber(input, &number)) { StartPoly(all); if (number < 4) throw INSUFFICENT_INPUT; all->new_input = true; /* */ /* read first vertex of polygon */ /* */ #ifdef EXT_APPL_SITES if (!ReadPntData(input, &xc0, &yc0, &eas_data)) #else if (!ReadPntData(input, &xc0, &yc0)) #endif throw EOF_ENCOUNTERED; #ifdef EXT_APPL_SITES AddPolyVertex(all, xc0, yc0, eas_data); #else AddPolyVertex(all, xc0, yc0); #endif for (i = 2; i < number; ++i) { /* */ /* read next vertex of polygon */ /* */ #ifdef EXT_APPL_SITES if (!ReadPntData(input, &xc1, &yc1, &eas_data)) #else if (!ReadPntData(input, &xc1, &yc1)) #endif throw EOF_ENCOUNTERED; #ifdef EXT_APPL_SITES AddPolyVertex(all, xc1, yc1, eas_data); #else AddPolyVertex(all, xc1, yc1); #endif } /* */ /* check whether the first vertex equals the last vertex */ /* */ #ifdef EXT_APPL_SITES if (!ReadPntData(input, &xc1, &yc1, &eas_data)) #else if (!ReadPntData(input, &xc1, &yc1)) #endif throw EOF_ENCOUNTERED; if ((xc0 != xc1) || (yc0 != yc1)) { FIST_Warning("ReadPolyLines() - input does not conform to .line standard!\n"); #ifdef EXT_APPL_SITES AddPolyVertex(all, xc1, yc1, eas_data); #else AddPolyVertex(all, xc1, yc1); #endif } CloseCurrentPoly(all); } fclose(input); return; } #undef WRITE_MY_POLYGONS #undef WRITE_MY_POLY_LINES /* #define WRITE_MY_POLYGONS */ #define WRITE_MY_POLY_LINES /* */ /* this function writes a simply-connected or multiply-connected polygon */ /* specified in my format for curvilinear data. */ /* */ #ifndef WRITE_MY_POLY_LINES #ifndef WRITE_MY_POLYGONS void WritePolygon(global_struct *all, char output_file[]) { int i; FILE *output; void WriteContour(FILE *output, list_ind ind1); output = OpenFile(output_file, "w"); WriteVectorData(output, all->bb_min.x, all->bb_min.y); WriteVectorData(output, all->bb_max.x, all->bb_max.y); WriteNumber(output, list->num_loops); for (i = 0; i < list->num_loops; ++i) { WriteContour(all, output, list->loops[i]); } fclose(output); return; } #else void WritePolygon(global_struct *all, char output_file[]) { int i, j, index, num_ele, ind1; FILE *output; double delta_x, delta_y, scale_factor; double x, y; char number[5]; char name[1000]; for (j = 0; j < list->num_loops; ++j) { number[0] = '\0'; sprintf(number, "%05d", j); name[0] = '\0'; strcat(name, output_file); strcat(name, number); strcat(name, ".poly"); output = OpenFile(name, "w"); ind1 = list->loops[j]; num_ele = CountListElements(ind1); WriteNumber(output, num_ele); for (i = 0; i < num_ele; ++i) { ind1 = GetNextNode(list,ind1); index = GetIndex(list,ind1); x = data->points[index].x; y = data->points[index].y; WriteVectorData(output, TO_MDOUBLE(x), TO_MDOUBLE(y)); } fclose(output); } return; } #endif #else void WritePolygon(global_struct *all, char output_file[]) { listdef *list = &all->c_list; datadef *data = &all->c_data; int i, j, index, num_ele, ind1; FILE *output; double x, y; if (!data->data_scaled) { data->shift.x = C_0_0; data->shift.y = C_0_0; data->scale_factor = C_1_0; } output = OpenFile(output_file, "w"); for (j = 0; j < list->num_loops; ++j) { ind1 = list->loops[j]; num_ele = CountListElements(list, ind1); WriteNumber(output, num_ele + 1); for (i = 0; i < num_ele; ++i) { ind1 = GetNextNode(list, ind1); index = GetIndex(list, ind1); x = UnscaleX(data,data->points[index].x); y = UnscaleY(data,data->points[index].y); WriteVectorData(output, TO_MDOUBLE(x), TO_MDOUBLE(y)); } ind1 = list->loops[j]; ind1 = GetNextNode(list, ind1); index = GetIndex(list, ind1); x = UnscaleX(data, data->points[index].x); y = UnscaleY(data, data->points[index].y); WriteVectorData(output, TO_MDOUBLE(x), TO_MDOUBLE(y)); } fclose(output); return; } #endif /* WritePolyFormat() writes the cleaned contour into triangle's * .poly format: * First line: <# of vertices> * <# of attributes> <# of boundary markers (0 or 1)> * Following lines: [attributes] [boundary marker] * One line: <# of segments> <# of boundary markers (0 or 1)> * Following lines: [boundary marker] * One line: <# of holes> * Following lines: * Optional line: <# of regional attributes and/or area constraints> * Optional following lines: */ void WritePolyFormat(global_struct *all) { listdef *list = &all->c_list; datadef *data = &all->c_data; rt_options *rt_opt = &all->rt_opt; FILE *output; list_ind ind1, ind_start; int index, cnt, loop_cnt; double x, y; output = OpenFile(rt_opt->c2p_file, "w"); if (output != NULL) { if (!data->data_scaled) { data->shift.x = C_0_0; data->shift.y = C_0_0; data->scale_factor = C_1_0; } loop_cnt = index = cnt = 0; for (int j = 0; j < list->num_loops; ++j) { ind1 = list->loops[j]; cnt += CountListElements(list, ind1); } /* First line: <# of vertices> * * <# of attributes> <# of boundary markers (0 or 1)> */ #ifdef QiMeng fprintf(output, "%d\n", cnt); #else fprintf(output, "%d 2 1 0\n", cnt); #endif /* Following lines: [attributes] [boundary marker] */ loop_cnt = POLYSTARTINDEX; for (int j = 0; j < list->num_loops; ++j) { ind_start = ind1 = list->loops[j]; do { index = GetIndex(list, ind1); x = UnscaleX(data,data->points[index].x); y = UnscaleY(data,data->points[index].y); fprintf(output, "%d ", loop_cnt); WriteVectorData(output, TO_MDOUBLE(x), TO_MDOUBLE(y)); ++loop_cnt; ind1 = GetNextNode(list, ind1); } while(ind1 != ind_start); } #ifdef QiMeng fclose(output); rt_opt->c2p_file[strlen(rt_opt->c2p_file)+1] = rt_opt->c2p_file[strlen(rt_opt->c2p_file)]; rt_opt->c2p_file[strlen(rt_opt->c2p_file)] = 'c'; output = OpenFile(rt_opt->c2p_file, "w"); fprintf(output, "%d\n", cnt); #else /* One line: <# of segments> <# of boundary markers (0 or 1)> */ fprintf(output, "%d 0\n", cnt); #endif /* Following lines: [boundary marker] */ loop_cnt = POLYSTARTINDEX; for (int j = 0; j < list->num_loops; ++j) { ind_start = ind1 = list->loops[j]; cnt = loop_cnt; do { index = GetIndex(list, ind1); x = UnscaleX(data,data->points[index].x); y = UnscaleY(data,data->points[index].y); if(GetNextNode(list,ind1) != ind_start) { fprintf(output, "%d %d %d\n", loop_cnt, loop_cnt, loop_cnt+1); } else { fprintf(output, "%d %d %d\n", loop_cnt, loop_cnt, cnt); } ++loop_cnt; ind1 = GetNextNode(list, ind1); } while(ind1 != ind_start); } #ifdef QiMeng fprintf(output, "\n"); #else /* One line: <# of holes> */ fprintf(output, "0\n"); #endif fclose(output); } else { if (rt_opt->verbose) { fprintf(stdout, "The file %s could not be opened!\n", rt_opt->c2p_file); fflush(stdout); } } } void WriteContour(global_struct *all, FILE *output, list_ind ind1) { datadef *data = &all->c_data; listdef *list = &all->c_list; int i, index, num_ele; int orientation = 1; int attr = 0; double xc2 = 0.0, yc2 = 0.0; num_ele = CountListElements(list, ind1); WriteNumber(output, num_ele); WriteNumber(output, orientation); for (i = 0; i < num_ele; ++i) { ind1 = GetNextNode(list,ind1); index = GetIndex(list,ind1); WriteNumber(output, attr); WriteVectorData(output, TO_MDOUBLE(data->points[index].x), TO_MDOUBLE(data->points[index].y)); #ifdef EXT_APPL_SITES WritePntData(output, TO_MDOUBLE(xc2), TO_MDOUBLE(yc2), &data->points[index].ext_appl); #else WritePntData(output, TO_MDOUBLE(xc2), TO_MDOUBLE(yc2)); #endif } return; } void WriteFacesDXF(global_struct *all, char output_file[]) { vertexdef *vert = &all->c_vertex; int i; /* */ /* open output file and write .dxf start-up commands */ /* */ StartDXFFile(all, output_file); /* */ /* output all triangles */ /* */ for (i = 0; i < vert->num_triangles; ++i) { #ifdef PARTITION_FIST if(vert->triangles[i].disabled) continue; #endif assert(InVertexList(vert, vert->triangles[i].v1)); assert(InVertexList(vert, vert->triangles[i].v2)); assert(InVertexList(vert, vert->triangles[i].v3)); WriteDXFPoly_Start(all, true, DXF_RED); WriteDXFPoly_Vertex(all, TO_MDOUBLE(vert->vertices[vert->triangles[i].v1].x), TO_MDOUBLE(vert->vertices[vert->triangles[i].v1].y), 0.0); WriteDXFPoly_Vertex(all, TO_MDOUBLE(vert->vertices[vert->triangles[i].v2].x), TO_MDOUBLE(vert->vertices[vert->triangles[i].v2].y), 0.0); WriteDXFPoly_Vertex(all, TO_MDOUBLE(vert->vertices[vert->triangles[i].v3].x), TO_MDOUBLE(vert->vertices[vert->triangles[i].v3].y), 0.0); WriteDXFPoly_End(all); } /* */ /* output all quads (if there are any) */ /* */ for (i = 0; i < vert->num_quads; ++i) { assert(InVertexList(vert, vert->quads[i].v1)); assert(InVertexList(vert, vert->quads[i].v2)); assert(InVertexList(vert, vert->quads[i].v3)); assert(InVertexList(vert, vert->quads[i].v4)); WriteDXFPoly_Start(all, true, DXF_RED); WriteDXFPoly_Vertex(all, TO_MDOUBLE(vert->vertices[vert->quads[i].v1].x), TO_MDOUBLE(vert->vertices[vert->quads[i].v1].y), 0.0); WriteDXFPoly_Vertex(all, TO_MDOUBLE(vert->vertices[vert->quads[i].v2].x), TO_MDOUBLE(vert->vertices[vert->quads[i].v2].y), 0.0); WriteDXFPoly_Vertex(all, TO_MDOUBLE(vert->vertices[vert->quads[i].v3].x), TO_MDOUBLE(vert->vertices[vert->quads[i].v3].y), 0.0); WriteDXFPoly_Vertex(all, TO_MDOUBLE(vert->vertices[vert->quads[i].v4].x), TO_MDOUBLE(vert->vertices[vert->quads[i].v4].y), 0.0); WriteDXFPoly_End(all); } /* */ /* write .dxf end commands */ /* */ FinishDXFFile(all); return; }