Qucs-GUI
0.0.19
|
00001 /*************************************************************************** 00002 graph.cpp - description 00003 ------------------- 00004 begin : Thu Oct 2 2003 00005 copyright : (C) 2003 by Michael Margraf 00006 email : michael.margraf@alumni.tu-berlin.de 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * * 00011 * This program is free software; you can redistribute it and/or modify * 00012 * it under the terms of the GNU General Public License as published by * 00013 * the Free Software Foundation; either version 2 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 ***************************************************************************/ 00017 #include "graph.h" 00018 00019 #include <stdlib.h> 00020 #include <iostream> 00021 00022 #include <QPainter> 00023 #include <QDebug> 00024 00025 class Diagram; 00026 00027 Graph::Graph(Diagram const* d, const QString& _Line) : 00028 Element(), 00029 Style(GRAPHSTYLE_SOLID), 00030 diagram(d) 00031 { 00032 Type = isGraph; 00033 00034 Var = _Line; 00035 countY = 0; // no points in graph 00036 Thick = numMode = 0; 00037 Color = 0x0000ff; // blue 00038 Precision = 3; 00039 isSelected = false; 00040 yAxisNo = 0; // left y axis 00041 00042 cPointsY = 0; 00043 } 00044 00045 Graph::~Graph() 00046 { 00047 if(cPointsY != 0) 00048 delete[] cPointsY; 00049 } 00050 00051 // --------------------------------------------------------------------- 00052 void Graph::createMarkerText() const 00053 { 00054 for(auto pm : Markers) { 00055 pm->createText(); 00056 } 00057 } 00058 00059 // --------------------------------------------------------------------- 00060 void Graph::paint(ViewPainter *p, int x0, int y0) 00061 { 00062 if(!ScrPoints.size()) 00063 return; 00064 00065 if(isSelected) { 00066 p->Painter->setPen(QPen(Qt::darkGray,Thick*p->PrintScale+4)); 00067 paintLines(p, x0, y0); 00068 00069 p->Painter->setPen(QPen(Qt::white, Thick*p->PrintScale, Qt::SolidLine)); 00070 paintLines(p, x0, y0); 00071 return; 00072 } 00073 00074 // **** not selected **** 00075 p->Painter->setPen(QPen(QColor(Color), Thick*p->PrintScale, Qt::SolidLine)); 00076 paintLines(p, x0, y0); 00077 } 00078 00079 // --------------------------------------------------------------------- 00080 void Graph::paintLines(ViewPainter *p, int x0, int y0) 00081 { 00082 switch(Style) { 00083 case GRAPHSTYLE_STAR: 00084 drawStarSymbols(x0, y0, p); 00085 break; 00086 case GRAPHSTYLE_CIRCLE: 00087 drawCircleSymbols(x0, y0, p); 00088 break; 00089 case GRAPHSTYLE_ARROW: 00090 drawArrowSymbols(x0, y0, p); 00091 break; 00092 default: 00093 drawLines(x0, y0, p); 00094 } 00095 } 00096 00097 // --------------------------------------------------------------------- 00098 QString Graph::save() 00099 { 00100 QString s = "\t<\""+Var+"\" "+Color.name()+ 00101 " "+QString::number(Thick)+" "+QString::number(Precision)+ 00102 " "+QString::number(numMode)+" "+QString::number(Style)+ 00103 " "+QString::number(yAxisNo)+">"; 00104 00105 foreach(Marker *pm, Markers) 00106 s += "\n\t "+pm->save(); 00107 00108 return s; 00109 } 00110 00111 // --------------------------------------------------------------------- 00112 bool Graph::load(const QString& _s) 00113 { 00114 bool ok; 00115 QString s = _s; 00116 00117 if(s.at(0) != '<') return false; 00118 if(s.at(s.length()-1) != '>') return false; 00119 s = s.mid(1, s.length()-2); // cut off start and end character 00120 00121 Var = s.section('"',1,1); // Var 00122 00123 QString n; 00124 n = s.section(' ',1,1); // Color 00125 Color.setNamedColor(n); 00126 if(!Color.isValid()) return false; 00127 00128 n = s.section(' ',2,2); // Thick 00129 Thick = n.toInt(&ok); 00130 if(!ok) return false; 00131 00132 n = s.section(' ',3,3); // Precision 00133 Precision = n.toInt(&ok); 00134 if(!ok) return false; 00135 00136 n = s.section(' ',4,4); // numMode 00137 numMode = n.toInt(&ok); 00138 if(!ok) return false; 00139 00140 n = s.section(' ',5,5); // Style 00141 int st = n.toInt(&ok); 00142 if(!ok) return false; 00143 Style = toGraphStyle(st); 00144 if(Style==GRAPHSTYLE_INVALID) return false; 00145 00146 n = s.section(' ',6,6); // yAxisNo 00147 if(n.isEmpty()) return true; // backward compatible 00148 yAxisNo = n.toInt(&ok); 00149 if(!ok) return false; 00150 00151 return true; 00152 } 00153 00154 // ----------------------------------------------------------------------- 00164 int Graph::getSelected(int x, int y) 00165 { 00166 auto pp = ScrPoints.begin(); 00167 if(pp == ScrPoints.end()) return -1; 00168 00169 int A, z=0; 00170 int dx, dx2, x1; 00171 int dy, dy2, y1; 00172 00173 int countX = cPointsX.at(0)->count; 00174 if(pp->isStrokeEnd()) { 00175 if(pp->isBranchEnd()) z++; 00176 pp++; 00177 if(pp->isBranchEnd()) { 00178 if(pp->isGraphEnd()) return -1; // not even one point ? 00179 z++; 00180 pp++; 00181 if(pp->isGraphEnd()) return -1; // not even one point ? 00182 } 00183 } 00184 00185 if(Style >= GRAPHSTYLE_STAR) { 00186 // for graph symbols 00187 while(!pp->isGraphEnd()) { 00188 if(!pp->isStrokeEnd()) { 00189 dx = x - int((pp)->getScrX()); 00190 dy = y - int((pp++)->getScrY()); 00191 00192 if(dx < -5) continue; 00193 if(dx > 5) continue; 00194 if(dy < -5) continue; 00195 if(dy > 5) continue; 00196 return z*countX; // points on graph symbol 00197 } 00198 else { 00199 z++; // next branch 00200 pp++; 00201 } 00202 } 00203 return -1; 00204 } 00205 00206 // for graph lines 00207 while(!pp->isGraphEnd()) { 00208 while(!pp->isBranchEnd()) { 00209 x1 = int(pp->getScrX()); 00210 y1 = int((pp++)->getScrY()); 00211 dx = x - x1; 00212 dy = y - y1; 00213 00214 if(pp->isPt()){ 00215 dx2 = int(pp->getScrX()); 00216 }else if(pp->isBranchEnd()) { 00217 break; 00218 }else if(pp->isStrokeEnd()) { 00219 pp++; 00220 dx2 = int(pp->getScrX()); // go on as graph can also be selected between strokes 00221 if(pp->isBranchEnd()) break; 00222 } 00223 if(dx < -5) { if(x < dx2-5) continue; } // point between x coordinates ? 00224 else { if(x > 5) if(x > dx2+5) continue; } 00225 00226 dy2 = int(pp->getScrY()); 00227 if(dy < -5) { if(y < dy2-5) continue; } // point between y coordinates ? 00228 else { if(y > 5) if(y > dy2+5) continue; } 00229 00230 dx2 -= x1; 00231 dy2 -= y1; 00232 00233 A = dx2*dy - dx*dy2; // calculate the rectangle area spanned 00234 A *= A; // avoid the need for square root 00235 A -= 25*(dx2*dx2 + dy2*dy2); // substract selectable area 00236 00237 if(A <= 0) return z*countX; // lies x/y onto the graph line ? 00238 } 00239 pp++; 00240 z++; 00241 } 00242 00243 return -1; 00244 } 00245 00246 // ----------------------------------------------------------------------- 00247 // Creates a new graph and copies all the properties into it. 00248 Graph* Graph::sameNewOne() 00249 { 00250 Graph *pg = new Graph(diagram, Var); 00251 00252 pg->Color = Color; 00253 pg->Thick = Thick; 00254 pg->Style = Style; 00255 00256 pg->Precision = Precision; 00257 pg->numMode = numMode; 00258 pg->yAxisNo = yAxisNo; 00259 00260 foreach(Marker *pm, Markers) 00261 pg->Markers.append(pm->sameNewOne(pg)); 00262 00263 return pg; 00264 } 00265 00269 std::pair<double,double> Graph::findSample(std::vector<double>& VarPos) const 00270 { 00271 DataX const* pD; 00272 unsigned nVarPos=0; 00273 unsigned n=0; 00274 unsigned m=1; 00275 00276 for(unsigned ii=0; (pD=axis(ii)); ++ii) { 00277 double* pp = pD->Points; 00278 double v = VarPos[nVarPos]; 00279 for(unsigned i=pD->count; i>1; i--) { // find appropiate marker position 00280 if(fabs(v-(*pp)) < fabs(v-(*(pp+1)))) break; 00281 pp++; 00282 n += m; 00283 } 00284 00285 m *= pD->count; 00286 VarPos[nVarPos++] = *pp; 00287 } 00288 00289 return std::pair<double,double>(cPointsY[2*n], cPointsY[2*n+1]); 00290 } 00291 00292 // ----------------------------------------------------------------------- 00293 // meaning of the values in a graph "Points" list 00294 #define STROKEEND -2 00295 #define BRANCHEND -10 00296 #define GRAPHEND -100 00297 // ----------------------------------------------------------------------- 00298 // screen points pseudo iterator implementation. 00299 void Graph::ScrPt::setStrokeEnd() 00300 { 00301 ScrX = STROKEEND; 00302 } 00303 void Graph::ScrPt::setBranchEnd() 00304 { 00305 ScrX = BRANCHEND; 00306 } 00307 void Graph::ScrPt::setGraphEnd() 00308 { 00309 ScrX = GRAPHEND; 00310 } 00311 bool Graph::ScrPt::isPt() const{return ScrX>=0.;} 00312 bool Graph::ScrPt::isStrokeEnd() const{return ScrX<=STROKEEND;} 00313 bool Graph::ScrPt::isBranchEnd() const{return ScrX<=BRANCHEND;} 00314 bool Graph::ScrPt::isGraphEnd() const{return ScrX<=GRAPHEND;} 00315 00322 void Graph::ScrPt::setScrX(float x) 00323 { 00324 if(x<0){ 00325 std::cerr << "dangerous: negative screen coordinate" << x; 00326 } 00327 if(ScrX<0){ 00328 std::cerr << "dangerous: (maybe) overwriting control token" << x; 00329 } 00330 ScrX = x; 00331 } 00332 void Graph::ScrPt::setScrY(float x) 00333 { 00334 if(x<0){ // need to investigate... 00335 qDebug() << "setting negative screen coordinate" << x << "at" << ScrX; 00336 } 00337 ScrY = x; 00338 } 00339 void Graph::ScrPt::setScr(float x, float y) 00340 { 00341 setScrX(x); 00342 setScrY(y); 00343 } 00344 void Graph::ScrPt::setIndep(double x) 00345 { 00346 assert(ScrX>=0); 00347 indep = x; 00348 } 00349 void Graph::ScrPt::setDep(double x) 00350 { 00351 assert(ScrX>=0); 00352 dep = x; 00353 } 00354 float Graph::ScrPt::getScrX() const 00355 { 00356 if(ScrX<0){ 00357 std::cerr << "dangerous: returning negative screen coordinate" << ScrX; 00358 } 00359 return ScrX; 00360 } 00361 float Graph::ScrPt::getScrY() const 00362 { 00363 return ScrY; 00364 } 00365 double Graph::ScrPt::getIndep() const 00366 { 00367 assert(ScrX>=0); 00368 return indep; 00369 } 00370 double Graph::ScrPt::getDep() const 00371 { 00372 assert(ScrX>=0); 00373 return dep; 00374 } 00375 00376 // vim:ts=8:sw=2:et