/* ivoc - ivoc@ipfn.ist.utl.pt Description: this set of functions can be used in sequence (or in separate) to draw an automatic SVG Graphic given any x/y set of point in two separate vectors first use DualVectorSort to sort the values, then use RemoveRepeatedValues to remove the repeated points. After this use OptimalDisplayFromVectors for obtaining the optimal zoom parameters for GetGraphSVG, wich writes a FString containing SVG code for the grafic reminder: there is no < and > at the begining and by the end on the code becaus it is intended to be used in a ::ProcessHttpMessage(HttpStream &hStream) with hmStream.SSPrintf(HtmlTagStreamMode, temp_string_1.Buffer()); that contains the <> tags */ #include "SVGGraphicSupport.h" // SVG graph properties #define MAJOR_TICK_LIMIT_NUMBER 20 #define MINOR_TICK_LIMIT_NUMBER 10 #define MINIMUM_WIDTH 100 #define MINIMUM_HEIGHT 100 #define MINIMUM_VECTOR_DIM 2 SVGGraphicSupport::SVGGraphicSupport(){ } SVGGraphicSupport::~SVGGraphicSupport(){ } bool SVGGraphicSupport::GetGraphSVG(FString * SVG_FString,char instance_name[],int vector_dim,float * vector_x,float * vector_y, int width,int height,float x_min,float y_min,float x_max,float y_max,float major_tick_x,float major_tick_y,int number_of_sub_ticks_x,int number_of_sub_ticks_y,bool legend_on_major_tick_x,bool legend_on_major_tick_y) { if(vector_dim < MINIMUM_VECTOR_DIM) { CStaticAssertErrorCondition(InitialisationError,"SVGGraphicSupport.h:: %s !!! GetGraphSVG -> vector_dim < MINIMUM_VECTOR_DIM, vector_dim =%d",instance_name,vector_dim); return False; } if(x_min >= x_max) { CStaticAssertErrorCondition(InitialisationError,"SVGGraphicSupport.h:: %s !!! GetGraphSVG -> x_min >= x_max",instance_name); return False; } if(y_min >= y_max) { CStaticAssertErrorCondition(InitialisationError,"SVGGraphicSupport.h:: %s !!! GetGraphSVG -> y_min >= y_max",instance_name); return False; } float number_of_major_ticks_x = (x_max - x_min)/major_tick_x; float number_of_major_ticks_y = (y_max - y_min)/major_tick_y; if(number_of_major_ticks_x > MAJOR_TICK_LIMIT_NUMBER) { CStaticAssertErrorCondition(InitialisationError,"SVGGraphicSupport.h:: %s !!! GetGraphSVG -> major_tick_x > MAJOR_TICK_LIMIT_NUMBER, number_of_major_ticks_x = %f",instance_name,number_of_major_ticks_x); return False; } if(number_of_major_ticks_y > MAJOR_TICK_LIMIT_NUMBER) { CStaticAssertErrorCondition(InitialisationError,"SVGGraphicSupport.h:: %s !!! GetGraphSVG -> major_tick_y > MAJOR_TICK_LIMIT_NUMBER,number_of_major_ticks_y = %f",instance_name,number_of_major_ticks_y); return False; } if(number_of_sub_ticks_x > MINOR_TICK_LIMIT_NUMBER) { CStaticAssertErrorCondition(InitialisationError,"SVGGraphicSupport.h:: %s !!! GetGraphSVG -> number_of_sub_ticks_x > MINOR_TICK_LIMIT_NUMBER, number_of_sub_ticks_x = %d",instance_name,number_of_sub_ticks_x); return False; } if(number_of_sub_ticks_y > MINOR_TICK_LIMIT_NUMBER) { CStaticAssertErrorCondition(InitialisationError,"SVGGraphicSupport.h:: %s !!! GetGraphSVG -> number_of_sub_ticks_y > MINOR_TICK_LIMIT_NUMBER, number_of_sub_ticks_y = %d",instance_name,number_of_sub_ticks_y); return False; } if(width < MINIMUM_WIDTH && width != -1) { CStaticAssertErrorCondition(InitialisationError,"SVGGraphicSupport.h:: %s !!! GetGraphSVG -> width < MINIMUM_WIDTH || width != -1, width = %d",instance_name, width); return False; } if(height < MINIMUM_HEIGHT) { CStaticAssertErrorCondition(InitialisationError,"SVGGraphicSupport.h:: %s !!! GetGraphSVG -> height < MINIMUM_HEIGHT, height = %d",instance_name,height); return False; } FString temp_string_2; FString buffer_fstring; float temp_cursor; float small_tick; float position; int j; int k; float pos_x; float pos_xx; float pos_y; float pos_yy; if (width == -1) { // width = 100% -> html code for % is % temp_string_2.Printf("svg width=\"100%\" height=\"%d\">\n", height); // if not x_min <= 0 <= x_max if( x_min*x_max > 0) { temp_cursor = x_min; //first grey line to be drawn small_tick = major_tick_x / (number_of_sub_ticks_x+1); while (temp_cursor < x_max) { position = 2+((temp_cursor-x_min)*((100-2)/(x_max-x_min))); buffer_fstring.Printf("\n", position, position, (height-10)); // text with the major ticks legend if(legend_on_major_tick_x) { buffer_fstring.Printf("%.2f\n",position, (height-1),temp_cursor); } for (k=0; k < number_of_sub_ticks_x; k++) { position = 2+((temp_cursor+(k+1)*small_tick-x_min)*((100-2)/(x_max-x_min))); buffer_fstring.Printf("\n", position, position, (height-10)); } temp_cursor += major_tick_x; } } else { temp_cursor = 0; //first grey line to be drawn small_tick = major_tick_x / (number_of_sub_ticks_x+1); while (temp_cursor < x_max) { position = 2+((temp_cursor-x_min)*((100-2)/(x_max-x_min))); buffer_fstring.Printf("\n", position, position, (height-10)); // text with the major ticks legend if(legend_on_major_tick_x) { buffer_fstring.Printf("%.2f\n",position, (height-1),temp_cursor); } for (k=0; k < number_of_sub_ticks_x; k++) { position = 2+((temp_cursor+(k+1)*small_tick-x_min)*((100-2)/(x_max-x_min))); buffer_fstring.Printf("\n", position, position, (height-10)); } temp_cursor += major_tick_x; } temp_cursor = 0; while (temp_cursor > x_min) { position = 2+((temp_cursor-x_min)*((100-2)/(x_max-x_min))); buffer_fstring.Printf("\n", position, position, (height-10)); // text with the major ticks legend if(legend_on_major_tick_x) { buffer_fstring.Printf("%.2f\n",position, (height-1),temp_cursor); } for (k=0; k < number_of_sub_ticks_x; k++) { position = 2+((temp_cursor-(k+1)*small_tick-x_min)*((100-2)/(x_max-x_min))); if ((temp_cursor-(k+1)*small_tick) > x_min) { buffer_fstring.Printf("\n", position, position, (height-10)); } } temp_cursor -= major_tick_x; } //dark xx axes temp_cursor = 0; position = 2+((temp_cursor-x_min)*((100-2)/(x_max-x_min))); buffer_fstring.Printf("\n", position, position, (height-10)); } // if not y_min <= 0 <= y_max if( y_min*y_max > 0) { temp_cursor = y_min; //first grey line to be drawn small_tick = major_tick_y / (number_of_sub_ticks_y+1); while (temp_cursor < y_max) { position = (y_max-temp_cursor)*((height-10)/(y_max-y_min)); buffer_fstring.Printf("\n", position, position); if(legend_on_major_tick_y) { // text with the major ticks legend buffer_fstring.Printf("%.1f\n",(position-4),temp_cursor); } for (k=0; k < number_of_sub_ticks_x; k++) { position = (y_max-temp_cursor-(k+1)*small_tick)*((height-10)/(y_max-y_min)); buffer_fstring.Printf("\n", position, position); } temp_cursor += major_tick_y; } } else { temp_cursor = 0; //first grey line to be drawn small_tick = major_tick_y / (number_of_sub_ticks_y+1); while (temp_cursor < y_max) { position = (y_max-temp_cursor)*((height-10)/(y_max-y_min)); buffer_fstring.Printf("\n", position, position); if(legend_on_major_tick_y) { // text with the major ticks legend buffer_fstring.Printf("%.1f\n",(position-4),temp_cursor); } for (k=0; k < number_of_sub_ticks_x; k++) { position = (y_max-temp_cursor-(k+1)*small_tick)*((height-10)/(y_max-y_min)); buffer_fstring.Printf("\n", position, position); } temp_cursor += major_tick_y; } temp_cursor = 0; while (temp_cursor > y_min) { position = (y_max-temp_cursor)*((height-10)/(y_max-y_min)); buffer_fstring.Printf("\n", position, position); if(legend_on_major_tick_y) { // text with the major ticks legend buffer_fstring.Printf("%.1f\n",(position-4),temp_cursor); } for (k=0; k < number_of_sub_ticks_x; k++) { position = (y_max-temp_cursor+(k+1)*small_tick)*((height-10)/(y_max-y_min)); if((temp_cursor-(k+1)*small_tick) > y_min) { buffer_fstring.Printf("\n", position, position); } } temp_cursor -= major_tick_y; } // dark yy axes temp_cursor = 0; position = (y_max-temp_cursor)*((height-10)/(y_max-y_min)); buffer_fstring.Printf("\n", position, position); } pos_x = 2+(((*(vector_x))-x_min)*((100-2)/(x_max-x_min))); pos_y = (y_max-(*(vector_y)))*((height-10)/(y_max-y_min)); // Now draw the waveform for (j=1; j < (vector_dim); j++) { pos_xx = 2+(((*(vector_x + j))-x_min)*((100-2)/(x_max-x_min))); pos_yy = (y_max-(*(vector_y + j)))*((height-10)/(y_max-y_min)); buffer_fstring.Printf("\n",pos_x,pos_y,pos_xx,pos_yy); pos_x = pos_xx; pos_y = pos_yy; } // Draw the outter part of the graph buffer_fstring.Printf("\n\ \n\ \n\ ",(height-10),(height-10),(height-10),(height-10)); temp_string_2 += buffer_fstring.Buffer(); temp_string_2 += "\n",width, height); // if not x_min <= 0 <= x_max if( x_min*x_max > 0) { temp_cursor = x_min; //first grey line to be drawn small_tick = major_tick_x / (number_of_sub_ticks_x+1); while (temp_cursor < x_max) { position = 10+((temp_cursor-x_min)*((width-10)/(x_max-x_min))); buffer_fstring.Printf("\n", position, position, (height-10)); // text with the major ticks legend if(legend_on_major_tick_x) { buffer_fstring.Printf("%.2f\n",position, (height-1),temp_cursor); } for (k=0; k < number_of_sub_ticks_x; k++) { position = 10+((temp_cursor+(k+1)*small_tick-x_min)*((width-10)/(x_max-x_min))); buffer_fstring.Printf("\n", position, position, (height-10)); } temp_cursor += major_tick_x; } } else { temp_cursor = 0; //first grey line to be drawn small_tick = major_tick_x / (number_of_sub_ticks_x+1); while (temp_cursor < x_max) { position = 10+((temp_cursor-x_min)*((width-10)/(x_max-x_min))); buffer_fstring.Printf("\n", position, position, (height-10)); // text with the major ticks legend if(legend_on_major_tick_x) { buffer_fstring.Printf("%.2f\n",position, (height-1),temp_cursor); } for (k=0; k < number_of_sub_ticks_x; k++) { position = 10+((temp_cursor+(k+1)*small_tick-x_min)*((width-10)/(x_max-x_min))); buffer_fstring.Printf("\n", position, position, (height-10)); } temp_cursor += major_tick_x; } temp_cursor = 0; while (temp_cursor > x_min) { position = 10+((temp_cursor-x_min)*((width-10)/(x_max-x_min))); buffer_fstring.Printf("\n", position, position, (height-10)); // text with the major ticks legend if(legend_on_major_tick_x) { buffer_fstring.Printf("%.2f\n",position, (height-1),temp_cursor); } for (k=0; k < number_of_sub_ticks_x; k++) { position = 10+((temp_cursor-(k+1)*small_tick-x_min)*((width-10)/(x_max-x_min))); if ((temp_cursor-(k+1)*small_tick) > x_min) { buffer_fstring.Printf("\n", position, position, (height-10)); } } temp_cursor -= major_tick_x; } //dark xx axes temp_cursor = 0; position = 10+((temp_cursor-x_min)*((width-10)/(x_max-x_min))); buffer_fstring.Printf("\n", position, position, (height-10)); } // if not y_min <= 0 <= y_max if( y_min*y_max > 0) { temp_cursor = y_min; //first grey line to be drawn small_tick = major_tick_y / (number_of_sub_ticks_y+1); while (temp_cursor < y_max) { position = (y_max-temp_cursor)*((height-10)/(y_max-y_min)); buffer_fstring.Printf("\n", position, width, position); if(legend_on_major_tick_y) { // text with the major ticks legend buffer_fstring.Printf("%.1f\n",(position-4),temp_cursor); } for (k=0; k < number_of_sub_ticks_x; k++) { position = (y_max-temp_cursor-(k+1)*small_tick)*((height-10)/(y_max-y_min)); buffer_fstring.Printf("\n", position, width, position); } temp_cursor += major_tick_y; } } else { temp_cursor = 0; //first grey line to be drawn small_tick = major_tick_y / (number_of_sub_ticks_y+1); while (temp_cursor < y_max) { position = (y_max-temp_cursor)*((height-10)/(y_max-y_min)); buffer_fstring.Printf("\n", position, width, position); if(legend_on_major_tick_y) { // text with the major ticks legend buffer_fstring.Printf("%.1f\n",(position-4),temp_cursor); } for (k=0; k < number_of_sub_ticks_x; k++) { position = (y_max-temp_cursor-(k+1)*small_tick)*((height-10)/(y_max-y_min)); buffer_fstring.Printf("\n", position, width, position); } temp_cursor += major_tick_y; } temp_cursor = 0; while (temp_cursor > y_min) { position = (y_max-temp_cursor)*((height-10)/(y_max-y_min)); buffer_fstring.Printf("\n", position, width, position); if(legend_on_major_tick_y) { // text with the major ticks legend buffer_fstring.Printf("%.1f\n",(position-4),temp_cursor); } for (k=0; k < number_of_sub_ticks_x; k++) { position = (y_max-temp_cursor+(k+1)*small_tick)*((height-10)/(y_max-y_min)); if((temp_cursor-(k+1)*small_tick) > y_min) { buffer_fstring.Printf("\n", position, width, position); } } temp_cursor -= major_tick_y; } // dark yy axes temp_cursor = 0; position = (y_max-temp_cursor)*((height-10)/(y_max-y_min)); buffer_fstring.Printf("\n", position, width, position); } pos_x = 10+(((*(vector_x))-x_min)*((width-10)/(x_max-x_min))); pos_y = (y_max-(*(vector_y)))*((height-10)/(y_max-y_min)); // Now draw the waveform for (j=1; j < (vector_dim); j++) { pos_xx = 10+(((*(vector_x + j))-x_min)*((width-10)/(x_max-x_min))); pos_yy = (y_max-(*(vector_y + j)))*((height-10)/(y_max-y_min)); buffer_fstring.Printf("\n",pos_x,pos_y,pos_xx,pos_yy); pos_x = pos_xx; pos_y = pos_yy; } // Draw the outter part of the graph buffer_fstring.Printf("\n\ \n\ \n\ ", width, (height-10), width,(height-10),(height-10), width, width,(height-10)); temp_string_2 += buffer_fstring.Buffer(); temp_string_2 += "\n\ \n\ %s\n\ \n\ \n\ \n\ \n\ %s\n\ \n", SVG_height); for (footer_i = 0; footer_i < n_images; footer_i++) { footer_str.Printf("\n",(image_x+image_width*footer_i), image_y,image_width, image_height, image_link); } footer_str.Printf("Name:\n\ Version:\n\ Date:\n\ Author:\n\ Description:\n\ %s\n\ %s\n\ %s\n\ %s\n\ %s\n\ \n", text_x1, text_y[0],text_x1, text_y[1],text_x1, text_y[2],text_x1, text_y[3],text_x1, text_y[4], text_x2, text_y[0],gam_name,text_x2, text_y[1],version,text_x2, text_y[2],lastdate,text_x2, text_y[3],author,text_x2, text_y[4], description); footer_str.Printf("\n\ xmax) xmax = *(vector_x+i); if (*(vector_x+i)ymax) ymax = *(vector_y+i); if (*(vector_y+i) 12 || diff < 6){ if (diff>12){ if ((diff/10) < 6 ){ diff = diff / 2; majortickx = majortickx * 2; } else { diff = diff / 10; majortickx = majortickx * 10; } } else if(diff < 6){ if ((diff*10) > 12){ diff = diff * 2; majortickx = majortickx / 2; } else { diff = diff * 10; majortickx = majortickx / 10; } } } *number_of_sub_ticks_x = 4; // if (diff < 7) *number_of_sub_ticks_x = 9; diff = ymax-ymin; while (diff > 12 || diff < 6){ if (diff>12){ if ((diff/10) < 6 ){ diff = diff / 2; majorticky = majorticky * 2; } else { diff = diff / 10; majorticky = majorticky * 10; } } else if(diff < 6){ if ((diff*10) > 12){ diff = diff * 2; majorticky = majorticky / 2; } else { diff = diff * 10; majorticky = majorticky / 10; } } } *number_of_sub_ticks_y = 4; // if (diff < 7) *number_of_sub_ticks_y = 9; *x_min = xmin - 0.01*(xmax-xmin); *x_max = xmax + 0.01*(xmax-xmin); *y_min = ymin - 0.01*(ymax-ymin); *y_max = ymax + 0.01*(ymax-ymin); if((*x_min) * (*x_max) > 0 ){ if (x_min > 0){ *x_min = (float) (majortickx * ((int) (*x_min/majortickx))); } else { *x_min = (float) ((majortickx * ((int) (*x_min/majortickx)))-majortickx); } } if((*y_min) * (*y_max) >0 ){ if (y_min > 0){ *y_min = (float) (majorticky * ((int) (*y_min/majorticky))); } else { *y_min = (float) ((majorticky * ((int) (*y_min/majorticky)))-majorticky); } } *major_tick_x = majortickx; *major_tick_y = majorticky; return True; } bool SVGGraphicSupport::HorizontalBarSVG ( FString * SVGFString){ FString temp_str; temp_str.Printf("svg width=\"100%\" height=\"15\">\n\ \n\ \n\ \n\ \n\