// ChartObject.cpp: implementation of the ChartObject class. // ////////////////////////////////////////////////////////////////////// #ifdef MULTICHART #include "Phreeqc.h" #ifdef _DEBUG #pragma warning(disable : 4786) // disable truncation warning (Only used by debugger) #endif #include "Utils.h" #include #include "ChartObject.h" #include "Parser.h" #include #include #include #include "phqalloc.h" #include "Form1.h" using namespace zdg_ui2; #if defined(PHREEQCI_GUI) #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// ChartObject::ChartObject(PHRQ_io *io) // // default constructor for cxxExchComp // : cxxNumKeyword(io) { new_ug = false; FirstCallToUSER_GRAPH = true; update_time_chart = 150; PanelHeight = 510; PanelWidth = 640; Symbol_map["Square"] = 0; Symbol_map["Diamond"] = 1; Symbol_map["Triangle"] = 2; Symbol_map["Circle"] = 3; Symbol_map["XCross"] = 4; Symbol_map["Plus"] = 5; Symbol_map["Star"] = 6; Symbol_map["TriangleDown"] = 7; Symbol_map["HDash"] = 8; Symbol_map["VDash"] = 9; Symbol_map["None"] = 10; Color_vector.push_back("Red"); Color_vector.push_back("Green"); Color_vector.push_back("Blue"); Color_vector.push_back("Orange"); Color_vector.push_back("Magenta"); // Color_vector.push_back("Yellow"); Color_vector.push_back("Black"); Color_vector.push_back("Cyan"); Color_vector.push_back("Brown"); Color_vector.push_back("Lime"); Color_vector.push_back("Gray"); chart_title.clear(); axis_titles.clear(); int i; for (i = 0; i < 5; i++) { axis_scale_x[i] = NA; axis_scale_y[i] = NA; axis_scale_y2[i] = NA; } chart_type = 0; graph_initial_solutions = false; shifts_as_points = false; connect_simulations = true; colnr = 0; ColumnOffset = 0; prev_advection_step = 0; prev_transport_step = 0; prev_sim_no = 0; end_timer = false; done = false; curve_added = false; point_added = false; user_graph = new rate; user_graph->commands.clear(); user_graph->name = NULL; user_graph->new_def = 0; user_graph->linebase = user_graph->loopbase = user_graph->varbase = NULL; default_symbol = 0; default_symbol_csv = 0; default_color = 0; default_color_csv = 0; graph_x = NA; graph_y.clear(); secondary_y.clear(); usingResource = 0; form_started = false; active = true; detach = false; batch_background = true; batch_grid = true; batch = ChO_NO_BATCH; } ChartObject::~ChartObject() { while (0 != System::Threading::Interlocked::CompareExchange(this->usingResource, 7, 0)) { System::Threading::Thread::Sleep(5); } this->Rate_free(); delete this->user_graph; std::vector::iterator it; for (it = this->CurvesCSV.begin(); it != CurvesCSV.end(); it++) { delete *it; } for (it = this->Curves.begin(); it != Curves.end(); it++) { delete *it; } } bool ChartObject::Set_axis_scale(CParser & parser) { std::istream::pos_type ptr; std::istream::pos_type next_char; std::string token; LDBLE *scale_ptr = NULL; std::vector string_vector; size_t j = 0; // rereads option parser.copy_token(token, next_char); // reads parameters while ((j < 6) && (parser.copy_token(token, next_char)) != CParser::TT_EMPTY) { string_vector.push_back(token); j++; } if (string_vector.size() == 0) { error_msg("No axis defined for scales", PHRQ_io::OT_CONTINUE); return false; } std::string str = string_vector[0]; std::string type; Utilities::str_tolower(str); if (str.substr(0,2) == "y2" || str.substr(0,1) == "s") { type = "sy"; scale_ptr = this->axis_scale_y2; } else if (str.substr(0,1) == "y") { type = "y"; scale_ptr = this->axis_scale_y; } else if (str.substr(0,1) == "x") { type = "x"; scale_ptr = this->axis_scale_x; } else { std::ostringstream estream; estream << "Found " << str; estream << ", but expect axis type \'x\', \'y\', \'y2\'or \'sy\'."; estream << "\n"; error_msg(estream.str().c_str(), PHRQ_io::OT_CONTINUE); return false; } for (j = 1; j < string_vector.size() && j < 5; j++) { std::string s = string_vector[j]; if (s[0] == 'a' || s[0] == 'A') { scale_ptr[j - 1] = NA; } else if (CParser::token_type(s) == CParser::TT_DIGIT) { scale_ptr[j - 1] = atof(s.c_str()); } else { std::ostringstream estream; estream << "Found " << s; estream << ", but expect number or 'a(uto)'."; estream << "\n"; error_msg(estream.str().c_str(), CONTINUE); return false; } } if (string_vector.size() == 6) { std::string s = string_vector[5]; if (s[0] == 't' || s[0] == 'T' || s[0] == 'l' || s[0] == 'L') { scale_ptr[4] = 10.0; if (((fabs(scale_ptr[0] - NA) > 1e-3) && scale_ptr[0] <=0) || ((fabs(scale_ptr[1] - NA) > 1e-3) && scale_ptr[1] <=0)) { std::ostringstream estream; estream << "MIN and MAX must be > 0 for log " << type << "-scale."; estream << "\n"; error_msg(estream.str().c_str(), CONTINUE); return false; } } } if ((fabs(scale_ptr[0] - NA) > 1e-3) && (fabs(scale_ptr[1] - NA) > 1e-3)) { if (scale_ptr[0] > scale_ptr[1]) { std::ostringstream estream; estream << "Maximum must be larger than minimum of axis_scale " << type << "-scale." << "\n"; estream << "Switching values for MIN and MAX. " << "\n"; warning_msg(estream.str().c_str()); LDBLE t; t = scale_ptr[0]; scale_ptr[0] = scale_ptr[1]; scale_ptr[1] = scale_ptr[0]; return false; } } return true; } bool ChartObject::Read(CParser & parser) { std::istream::pos_type ptr; std::istream::pos_type next_char; std::string token; int opt_save; bool useLastLine(false); bool new_command_lines(false); // if no definitions in USER_GRAPH data block, deactivate plot bool no_def(true); if (this->FirstCallToUSER_GRAPH) { this->new_ug = true; } else { this->ColumnOffset = (int) this->Curves.size(); this->new_ug = true; } this->new_plotxy_curves.clear(); // Read number and description { this->read_number_description(parser); } opt_save = CParser::OPT_DEFAULT; for (;;) { int opt; if (useLastLine == false) { opt = parser.get_option(vopts, next_char); } else { opt = parser.getOptionFromLastLine(vopts, next_char, true); } if (opt == CParser::OPT_DEFAULT) { opt = opt_save; } switch (opt) { case CParser::OPT_EOF: break; case CParser::OPT_KEYWORD: break; case CParser::OPT_ERROR: opt = CParser::OPT_EOF; error_msg("Unknown input in USER_GRAPH keyword.", CONTINUE); error_msg(parser.line().c_str(), CONTINUE); useLastLine = false; break; case 0: /* start */ opt_save = CParser::OPT_DEFAULT; break; case 1: /* end */ opt_save = CParser::OPT_DEFAULT; break; case 2: /* headings */ case 3: /* heading */ this->new_headings.clear(); while (parser.copy_token(token, next_char) != CParser::TT_EMPTY) { this->new_headings.push_back(token); } this->headings_original = this->new_headings; break; case 4: /* chart title */ { std::string tok; parser.get_rest_of_line(tok); std::string::iterator b = tok.begin(); std::string::iterator e = tok.end(); CParser::copy_title(this->chart_title, b, e); } break; case 5: /* axis titles */ { this->axis_titles.clear(); std::string l; parser.get_rest_of_line(l); std::string tok; std::string::iterator b = l.begin(); std::string::iterator e = l.end(); this->axis_titles.clear(); while(parser.copy_title(tok, b, e) != CParser::TT_EMPTY) { this->axis_titles.push_back(tok); } } while (this->axis_titles.size() < 3) this->axis_titles.push_back(""); break; case 6: /* axis scales */ { this->Set_axis_scale(parser); } break; case 7: /* initial_solutions */ this->graph_initial_solutions = parser.get_true_false(next_char, FALSE); break; case 8: /* plot_concentration_vs */ parser.copy_token(token, next_char); Utilities::str_tolower(token); if (token[0] == 'x' || token[0] == 'd') chart_type = 0; else if (token[0] == 't') chart_type = 1; else { std::ostringstream estream; estream << "Found " << token << ", but expect plot type: (\'x\' or \'dist\') for distance, (\'t\') for time."; error_msg(estream.str().c_str(), CONTINUE); } break; case 9: /* shifts_as_points */ this->shifts_as_points = parser.get_true_false(next_char, true); if (this->shifts_as_points) this->chart_type = 0; else this->chart_type = 1; break; case 10: /* grid_offset */ break; case 11: /* connect_simulations */ this->connect_simulations = parser.get_true_false(next_char, true); break; case 12: /* plot_csv_file */ case 17: /* plot_tsv_file */ { std::string file_name; parser.get_rest_of_line(file_name); file_name = trim(file_name); this->OpenCSVFile(file_name); this->csv_file_names.push_back(file_name); } break; case 13: /* clear */ case 14: /* detach */ this->detach = true; break; /* End of modifications */ case 15: /* active */ this->active = parser.get_true_false(next_char, true); if (this->active && this->Get_connect_simulations()) { this->ColumnOffset = 0;//this->Curves.size(); this->new_ug = false; } break; /* End of modifications */ case 16: /* batch */ { this->batch = ChartObject::ChO_BATCH_ONLY; std::string rest_of_line, lc_rest_of_line; parser.get_rest_of_line(rest_of_line); lc_rest_of_line = rest_of_line; Utilities::str_tolower(lc_rest_of_line); std::vector file_types; file_types.push_back(".emf"); file_types.push_back(".png"); file_types.push_back(".jpg"); file_types.push_back(".gif"); file_types.push_back(".tiff"); file_types.push_back(".bmp"); file_types.push_back(".jpeg"); size_t first, last; size_t i; for (i = 0; i < file_types.size(); i++) { first = lc_rest_of_line.rfind(file_types[i].c_str()); if (first != std::string::npos) { break; } } if (i >= file_types.size()) { std::ostringstream estream; estream << "Batch file name must have suffix emf, png, jpg, jpeg, gif, tiff, or bmp."; error_msg(estream.str().c_str(), CONTINUE); break; } switch (i) { case 0: this->batch = ChartObject::ChO_EMF; last = first + 4; break; case 1: this->batch = ChartObject::ChO_PNG; last = first + 4; break; case 2: this->batch = ChartObject::ChO_JPG; last = first + 4; break; case 3: this->batch = ChartObject::ChO_GIF; last = first + 4; break; case 4: this->batch = ChartObject::ChO_TIFF; last = first + 5; break; case 5: this->batch = ChartObject::ChO_BMP; last = first + 4; break; case 6: this->batch = ChartObject::ChO_JPG; last = first + 5; break; } this->batch_fn = rest_of_line.substr(0, last); if (last+1 < rest_of_line.size()) { token = rest_of_line.substr(last); token = trim(token); std::string tf; std::string::iterator b = token.begin(); std::string::iterator e = token.end(); CParser::copy_token(tf, b, e); if (tf.size() > 0) { Utilities::str_tolower(tf); if (tf[0] == 'f') { this->batch_background = false; } } CParser::copy_token(tf, b, e); if (tf.size() > 0) { Utilities::str_tolower(tf); if (tf[0] == 'f') { this->batch_grid = false; } } } } break; case CParser::OPT_DEFAULT: // Read Basic commands { if (!new_command_lines) { this->rate_command_list.clear(); this->rate_command_list_original.clear(); new_command_lines = true; } this->rate_new_def = true; /* read command */ std::string cmd(parser.line()); this->rate_command_list_original.push_back(cmd); std::string cmd_lower = cmd; Utilities::str_tolower(cmd_lower); if ((cmd_lower.find("graph_y") != std::string::npos) || (cmd_lower.find("graph_sy") != std::string::npos)) { //Number of curves not known here //Curves are created in Basic cmds } if (cmd_lower.find("plot_xy") != std::string::npos) { //Curves are created in Basic cmds CurveObject new_curve = ExtractCurveInfo(cmd); // truncates cmd // Add to list of new plotxy curves this->new_plotxy_curves.push_back(new_curve); } this->rate_command_list.push_back(cmd); } opt_save = CParser::OPT_DEFAULT; break; } if (opt == CParser::OPT_EOF || opt == CParser::OPT_KEYWORD) break; no_def = false; } // install new plotxy commands // disable this user_graph if USER_GRAPH block is empty //if (new_command_lines || no_def) this->Set_rate_struct(); if (new_command_lines) this->Set_rate_struct(); if (no_def) this->Set_active(false); return true; } bool ChartObject::OpenCSVFile(std::string file_name) { std::string token; std::ifstream f_csv(file_name.c_str(), std::ifstream::in); if (!f_csv.is_open()) { std::ostringstream estream; estream << "Could not open tsv file for USER_GRAPH " << file_name << "\n Please, give the full path + filename."; error_msg(estream.str().c_str(), CONTINUE); return false; } CParser parser(f_csv, this->Get_io()); parser.set_echo_file(CParser::EO_NONE); /* Get lines */ int linenr = 0; // temporary storage for new CSV curves std::vector headings; std::vector csv_curves; // Read file line by line into temporary curves while (parser.check_line("cvs file", false, true, true, false) != PHRQ_io::LT_EOF) { // Headings line if (linenr == 0) { // Skip x in 1st column parser.get_iss() >> token; // Read rest of headings while (parser.get_iss() >> token) { headings.push_back(token); } // add curves to temporary csv_curves size_t i; for (i = 0; i < headings.size(); i++) { CurveObject *c = new CurveObject; c->Set_id(headings[i]); c->Set_line_w(0); std::string sym = ""; this->Get_legal_symbol_csv(sym); c->Set_symbol(sym); csv_curves.push_back(c); } linenr++; continue; } token = parser.line(); std::string tok1; CParser::TOKEN_TYPE tt = CParser::parse_delimited(token, tok1, "\t"); // Curve properties lines if (linenr < 6 && tt != CParser::TT_DIGIT) { Utilities::str_tolower(tok1); std::string tok2; size_t i=0; while (token.size() != 0 && i < csv_curves.size()) { CParser::parse_delimited(token, tok2, "\t"); tok2 = trim(tok2); if (!strncmp(tok1.c_str(), "color", 5)) { csv_curves[i]->Set_color(tok2); } else if (!strncmp(tok1.c_str(), "symbol", 5) && (strstr(tok1.c_str(), "_si") == NULL) && (strstr(tok1.c_str(), "-si") == NULL)) { csv_curves[i]->Set_symbol(tok2); } else if (!strncmp(tok1.c_str(), "symbol_size", 8) || !strncmp(tok1.c_str(), "symbol-size", 8)) { if (tok2.size() > 0) { csv_curves[i]->Set_symbol_size(atof(tok2.c_str())); } } else if (!strncmp(tok1.c_str(), "line_w", 5) || !strncmp(tok1.c_str(), "line-w", 5)) { csv_curves[i]->Set_line_w(atof(tok2.c_str())); } else if (!strncmp(tok1.c_str(), "y_axis", 5) || !strncmp(tok1.c_str(), "y-axis", 5)) { if (tok2.size() > 0) { csv_curves[i]->Set_y_axis(atoi(tok2.c_str())); } } i++; } linenr++; continue; } // Curve data if (linenr < 6) linenr = 6; if (tt != CParser::TT_DIGIT) { linenr++; continue; } // x value for all curves LDBLE x_value = atof(tok1.c_str()); // y values for curves std::string tok2; size_t i=0; while (token.size() != 0 && i < csv_curves.size()) { CParser::parse_delimited(token, tok2, "\t"); Utilities::squeeze_white(tok2); if (tok2.size() == 0) { //csv_curves[i].Get_x().push_back(NA); //csv_curves[i].Get_y().push_back(NA); } else { csv_curves[i]->Get_x().push_back(x_value); csv_curves[i]->Get_y().push_back(atof(tok2.c_str())); } i++; } linenr++; } // Append new curves std::vector::iterator it = csv_curves.begin(); for (; it != csv_curves.end(); it++) { if ((*it)->Get_x().size() > 0) { std::string col = (*it)->Get_color(); this->Get_color_string_csv(col); (*it)->Set_color(col); this->CurvesCSV.push_back(*it); this->Set_curve_added(true); } } return true; } CurveObject ChartObject::ExtractCurveInfo(std::string & cmd_line) { /* plot_xy x, tot("Cl"), color = Red, symbol = Circle, symbol_size = 0.0, line_w = 1.0, y_axis = 2 */ // Make copy of cmd_line //int curvenr = (int) this->Curves.size(); std::string str_line = cmd_line; // Massage line while (Utilities::replace(" ,",",",str_line)); while (Utilities::replace("\t,",",",str_line)); while (Utilities::replace(",","#",str_line)); while (Utilities::replace("#",", ", str_line)); int sel; std::string token, tok1, tok2; std::string revised_line; std::string::iterator b = str_line.begin(); std::string::iterator e = str_line.end(); // new curve CurveObject new_curve; while (CParser::copy_token(token, b, e) != CParser::TT_EMPTY) { sel = -1; std::string token_save = token; Utilities::str_tolower(token); tok1 = token; if (!strncmp(tok1.c_str(), "color", 5)) { sel = 0; } else if (!strncmp(tok1.c_str(), "symbol", 5) && (strstr(tok1.c_str(), "_si") == NULL) && (strstr(tok1.c_str(), "-si") == NULL)) { sel = 1; } else if (!strncmp(tok1.c_str(), "symbol_size", 8) || !strncmp(tok1.c_str(), "symbol-size", 8)) { sel = 2; } else if (!strncmp(tok1.c_str(), "line_w", 5) || !strncmp(tok1.c_str(), "line-w", 5)) { sel = 3; } else if (!strncmp(tok1.c_str(), "y_axis", 5) || !strncmp(tok1.c_str(), "y-axis", 5)) { sel = 4; } // Append to command line if (sel < 0) { revised_line.append(token_save); revised_line.append(" "); } // Parse plot_xy pair else { // remove preceding comma std::string comma = revised_line.substr(revised_line.size() - 2); if (comma == ", ") { revised_line = revised_line.substr(0, revised_line.size() - 2); revised_line.append(" "); } token = token_save; size_t p1 = token.find("="); std::string tok2; // "=" found if(p1 != std::string::npos) { if (p1 != token.size() - 1) { // color=Red tok2 = token.substr(p1 + 1); } else { // color= Red CParser::copy_token(tok2, b, e); } } else { // no "=" found CParser::copy_token(tok2, b, e); p1 = tok2.find("="); if (tok2 == "=") { // color = Red CParser::copy_token(tok2, b, e); } else if (p1 != std::string::npos) { // color =Red tok2 = tok2.substr(p1 + 1); } else { // color Red tok2 = tok2; } } // remove any commas while(Utilities::replace(",","",tok1)); while(Utilities::replace(",","",tok2)); // tok1 is name, tok2 is value switch (sel) { case 0: new_curve.Set_color(tok2); break; case 1: new_curve.Set_symbol(tok2); break; case 2: new_curve.Set_symbol_size(atof(tok2.c_str())); break; case 3: new_curve.Set_line_w(atof(tok2.c_str())); break; case 4: new_curve.Set_y_axis(atoi(tok2.c_str())); break; } } } cmd_line = revised_line; return new_curve; } void ChartObject::Set_rate_struct(void) { if (rate_command_list.size() == 0) return; std::list::iterator it = rate_command_list.begin(); std::ostringstream oss; for (; it != rate_command_list.end(); it++) { oss << *it << "\n"; } this->Rate_free(); this->user_graph->commands = oss.str().c_str(); this->user_graph->new_def = this->rate_new_def; this->user_graph->loopbase = NULL; this->user_graph->varbase = NULL; this->user_graph->linebase = NULL; this->user_graph->name = NULL; } void ChartObject::Get_legal_symbol(std::string &sym) { std::map::iterator it; if ((it = this->Symbol_map.find(sym)) == this->Symbol_map.end()) { sym = "Default"; for (it = this->Symbol_map.begin(); it != this->Symbol_map.end(); it++) { if (default_symbol == it->second) { sym = it->first; break; } } default_symbol++; default_symbol = default_symbol % this->Symbol_map.size(); } return; } void ChartObject::Get_legal_symbol_csv(std::string &sym) { std::map::iterator it; if ((it = this->Symbol_map.find(sym)) == this->Symbol_map.end()) { sym = "Default"; for (it = this->Symbol_map.begin(); it != this->Symbol_map.end(); it++) { if (this->default_symbol_csv == it->second) { sym = it->first; break; } } default_symbol_csv++; default_symbol_csv = default_symbol_csv % this->Symbol_map.size(); } return; } void ChartObject::Get_color_string(std::string &color) { if (color.size() == 0) { color = Color_vector[this->default_color]; default_color++; default_color = default_color % this->Color_vector.size(); } return; } void ChartObject::Get_color_string_csv(std::string &color) { if (color.size() == 0) { color = Color_vector[this->default_color_csv]; default_color_csv++; default_color_csv = default_color_csv % this->Color_vector.size(); } return; } ZedGraph::SymbolType ChartObject::Return_SymbolType(const std::string sym) { int i; std::map::iterator it; if ((it = this->Symbol_map.find(sym)) != this->Symbol_map.end()) { i = it->second; } else { i = default_symbol++; default_symbol = default_symbol % this->Symbol_map.size(); } switch (i) { case 0: return SymbolType::Square; break; case 1: return SymbolType::Diamond; break; case 2: return SymbolType::Triangle; break; case 3: return SymbolType::Circle; break; case 4: return SymbolType::XCross; break; case 5: return SymbolType::Plus; break; case 6: return SymbolType::Star; break; case 7: return SymbolType::TriangleDown; break; case 8: return SymbolType::HDash; break; case 9: return SymbolType::VDash; break; case 10: return SymbolType::None; break; default: return SymbolType::Default; break; } } void ChartObject::SaveCurvesToFile(std::string &file_name) { // reimplemented in Form // This version not currently used std::ofstream f_out(file_name.c_str(), std::ifstream::out); if (!f_out.is_open()) { std::ostringstream estream; estream << "Could not open csv file for USER_GRAPH " << file_name; error_msg(estream.str().c_str(), CONTINUE); return; } // list of curves std::vector all_curves; size_t i; for (i = 0; i < this->CurvesCSV.size(); i++) { all_curves.push_back(this->CurvesCSV[i]); } for (i = 0; i < this->Curves.size(); i++) { all_curves.push_back(Curves[i]); } // write headings size_t max_points = 0; std::vector::iterator it = all_curves.begin(); f_out.precision(4); i = 0; for ( ; it != all_curves.end(); it++) { f_out.width(12); f_out << "x" << "\t"; f_out.width(12); if ((*it)->Get_id().size() > 0) { f_out << (*it)->Get_id() << "\t"; } else { f_out << "y" << "\t";; } if ((*it)->Get_x().size() > max_points) max_points = (*it)->Get_x().size(); } f_out << "\n"; // write data size_t i2 = 0; f_out << std::scientific; f_out.precision(4); while (i2 < max_points) { for (it = all_curves.begin(); it != all_curves.end(); it++) { if (i2 < (*it)->Get_x().size()) { f_out.width(12); f_out << (*it)->Get_x()[i2] << "\t"; f_out.width(12); f_out << (*it)->Get_y()[i2] << "\t"; } else if (i2 < max_points) { f_out.width(13); f_out << "\t"; f_out.width(13); f_out << "\t"; } } f_out << "\n"; i2++; } f_out.close(); return; } // file only used with MULTICHART bool ChartObject::start_chart(void) { Application::EnableVisualStyles(); Application::SetCompatibleTextRenderingDefault(true); // needed to send ChartObject pointer to thread Thread ^t = gcnew Thread( gcnew ParameterizedThreadStart(Form1::ThreadForm)); t->SetApartmentState(ApartmentState::STA); t->IsBackground = false; t->Priority = ThreadPriority::Normal; ChartObj ^p = gcnew ChartObj(this); t->Start(p); this->form_started = true; //Thread::Sleep( 1 ); /* this when debugging... */ //_beginthread(void (Form1::ThreadForm), 0, NULL); return true; } void ChartObject::Rate_free(void) { if (this->phreeqc_ptr) { user_graph->commands.clear(); } if (user_graph->linebase != NULL) { char cmd[] = "new; quit"; if (this->phreeqc_ptr) { phreeqc_ptr-> basic_run(cmd, user_graph->linebase, user_graph->varbase, user_graph->loopbase); } user_graph->linebase = NULL; user_graph->varbase = NULL; user_graph->loopbase = NULL; } } void ChartObject::Initialize_graph_pts(void) { graph_x = NA; graph_y.clear(); secondary_y.clear(); } void ChartObject::Finalize_graph_pts(void) { if (graph_x != NA) { std::map::iterator it; for (it = graph_y.begin(); it != graph_y.end(); it++) { Curves[it->first]->Get_x().push_back(graph_x); Curves[it->first]->Get_y().push_back(it->second); // Mark added curve for first point, might have been invisible in DefineCurves if (Curves[it->first]->Get_x().size() == 1) this->Set_curve_added(true); } } if (graph_x != NA) { std::map::iterator it; for (it = secondary_y.begin(); it != secondary_y.end(); it++) { Curves[it->first]->Set_y_axis(2); } } } void ChartObject::Add_new_series(void) { std::vector Curves; size_t i; size_t e = this->Curves.size(); for (i = this->ColumnOffset; i < e; i++) { this->Add_curve(false, this->Curves[i]->Get_id(), this->Curves[i]->Get_line_w(), "", this->Curves[i]->Get_symbol_size(), this->Curves[i]->Get_y_axis(), ""); } this->ColumnOffset = (int) e; this->curve_added = true; } void ChartObject::Add_curve(bool plotxy, std::string id, LDBLE line_width, std::string symbol, LDBLE symbol_size, int y_axis, std::string color) { CurveObject *c = new CurveObject; c->Set_id(id); c->Set_line_w(line_width); this->Get_legal_symbol(symbol); c->Set_symbol(symbol); c->Set_symbol_size(symbol_size); if (this->CurvesCSV.size() > this->Curves.size() && !plotxy) { c->Set_symbol_size(0.0); } c->Set_y_axis(y_axis); this->Get_color_string(color); c->Set_color(color); this->Curves.push_back(c); } void ChartObject::Set_rate_new_def(bool tf) { this->rate_new_def = tf; if (this->user_graph != NULL) { if (tf) { this->user_graph->new_def = 1; } else { this->user_graph->new_def = 0; } } } void ChartObject::dump(std::ostream & oss, unsigned int indent) { size_t i; oss.precision(DBL_DIG - 1); std::string indent0(""), indent1(""); for (i = 0; i < indent; ++i) indent0.append(Utilities::INDENT); for (i = 0; i < indent + 1; ++i) indent1.append(Utilities::INDENT); oss << indent0 << "USER_GRAPH " << this->n_user << " " << this->description << "\n"; // chart title oss << indent1 << "-chart_title \"" << this->chart_title << "\"" << "\n"; // axis titles if (this->axis_titles.size() > 0) { oss << indent1 << "-axis_titles "; for (i = 0; i < this->axis_titles.size(); i++) { oss << "\"" << axis_titles[i] << "\" "; } oss << "\n"; } // axis_scale_x LDBLE *scale_ptr = this->axis_scale_x; { oss << indent1 << "-axis_scale x_axis "; for (i = 0; i < 4; i++) { if (scale_ptr[i] == NA) { oss << " auto"; } else { oss << " " << scale_ptr[i]; } } if (scale_ptr[4] == 10.0) { oss << " log"; } oss << "\n"; } // axis_scale_y scale_ptr = this->axis_scale_y; { oss << indent1 << "-axis_scale y_axis "; for (i = 0; i < 4; i++) { if (scale_ptr[i] == NA) { oss << " auto"; } else { oss << " " << scale_ptr[i]; } } if (scale_ptr[4] == 10.0) { oss << " log"; } oss << "\n"; } // axis_scale_sy scale_ptr = this->axis_scale_y2; { oss << indent1 << "-axis_scale sy_axis "; for (i = 0; i < 4; i++) { if (scale_ptr[i] == NA) { oss << " auto"; } else { oss << " " << scale_ptr[i]; } } if (scale_ptr[4] == 10.0) { oss << " log"; } oss << "\n"; } // chart type if (this->chart_type == 0) { oss << indent1 << "-plot_concentration_vs x" << "\n"; } else { oss << indent1 << "-plot_concentration_vs t" << "\n"; } // graph_initial_solutions if (this->graph_initial_solutions) { oss << indent1 << "-initial_solutions true" << "\n"; } else { oss << indent1 << "-initial_solutions false" << "\n"; } // connect_simulations if (this->connect_simulations) { oss << indent1 << "-connect_simulations true" << "\n"; } else { oss << indent1 << "-connect_simulations false" << "\n"; } // csv files for (i = 0; i < this->csv_file_names.size(); i++) { oss << indent1 << "-plot_tsv_file " << this->csv_file_names[i] << "\n"; } // headings if (this->headings_original.size() > 0) { oss << indent1 << "-headings "; for (i = 0; i < this->headings_original.size(); i++) { oss << this->headings_original[i] << " "; } oss << "\n"; } // commands oss << indent1 << "-start" << "\n"; std::list::iterator it = rate_command_list_original.begin(); for (; it != rate_command_list_original.end(); it++) { oss << *it << "\n"; } oss << indent1 << "-end" << "\n"; /* class rate *user_graph; // C++ for rate struct std::string rate_name; std::list rate_command_list; bool rate_new_def; int default_symbol; int default_symbol_csv; int default_color; int default_color_csv; // temporary storage before stored graph_x/y/sy data are stored in curves // Initialize_graph_pts and Finalize_graph_pts use this storage. LDBLE graph_x; std::map graph_y; std::map secondary_y; // temporary plotxy curve definitions before stored in curves // a plotxy curve is copied to Curves when cmdplotxy is encountered // this keeps order correct between plotxy and graph_x/y/sy std::vector new_plotxy_curves; // temporary headings until stored during basic_run std::vector new_headings; bool active; bool detach; bool form_started; */ } const std::vector< std::string >::value_type temp_vopts[] = { std::vector< std::string >::value_type("start"), // 0 std::vector< std::string >::value_type("end"), // 1 std::vector< std::string >::value_type("heading"), // 2 std::vector< std::string >::value_type("headings"), // 3 std::vector< std::string >::value_type("chart_title"), // 4 std::vector< std::string >::value_type("axis_titles"), // 5 std::vector< std::string >::value_type("axis_scale"), // 6 std::vector< std::string >::value_type("initial_solutions"), // 7 std::vector< std::string >::value_type("plot_concentration_vs"), // 8 std::vector< std::string >::value_type("shifts_as_points"), // 9 std::vector< std::string >::value_type("grid_offset"), // 10 std::vector< std::string >::value_type("connect_simulations"), // 11 std::vector< std::string >::value_type("plot_csv_file"), // 12 std::vector< std::string >::value_type("clear"), // 13 std::vector< std::string >::value_type("detach"), // 14 std::vector< std::string >::value_type("active"), // 15 std::vector< std::string >::value_type("batch"), // 16 std::vector< std::string >::value_type("plot_tsv_file") // 17 }; const std::vector< std::string > ChartObject::vopts(temp_vopts, temp_vopts + sizeof temp_vopts / sizeof temp_vopts[0]); #endif // MULTICHART