Qucs-GUI  0.0.19
/home/travis/build/Qucs/qucs/qucs/qucs/diagrams/graph.cpp
Go to the documentation of this file.
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
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines