plotmapbase.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                         plotmapbase.cpp  -  description
00003                              -------------------
00004     begin                : Tue Jul 22 2003
00005     copyright            : (C) 2003-2006 by Ben Swerts
00006     email                : bswerts@users.sourceforge.net
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 
00019 
00028 
00029 
00030 
00032 
00033 // STL header files
00034 #include <map>
00035 
00036 // C++ header files
00037 #include <cmath>
00038 
00039 // Qt header files
00040 #include <qapplication.h>
00041 #include <qcheckbox.h>
00042 #include <qcolor.h>
00043 #include <qcombobox.h>
00044 #include <qcursor.h>
00045 #include <qfile.h>
00046 #include <qfiledialog.h>
00047 #include <qfileinfo.h>
00048 #include <qimage.h>
00049 #include <qlabel.h>
00050 #include <qlayout.h>
00051 #include <qlineedit.h>
00052 #include <qmessagebox.h>
00053 #include <qnamespace.h>
00054 #include <qpainter.h>
00055 #include <qpoint.h>
00056 #include <qprogressdialog.h>
00057 #include <qpushbutton.h>
00058 #include <qspinbox.h>
00059 #include <qstring.h>
00060 #include <qstringlist.h>
00061 #include <qtextstream.h>
00062 
00063 // Xbrabo header files
00064 #include "colorbutton.h"
00065 #include "plotmapbase.h"
00066 #include "plotmapextensionwidget.h"
00067 #include "plotmaplabel.h"
00068 #include "version.h"
00069 
00073 
00075 PlotMapBase::PlotMapBase(QWidget* parent, const char* name, bool modal, WFlags fl) : PlotMapWidget(parent, name, modal, fl),
00076   loadInProgress(false),
00077   maxValue(1.0),
00078   minValue(-1.0)
00080 {
00081   options = new PlotMapExtensionWidget(this);
00082   options->hide();
00083   PlotMapWidgetLayout->addWidget(options);
00085   options->setFixedHeight(options->height());
00086   options->setMaximumHeight(options->height());
00087   
00089   plotLabel = new PlotMapLabel(this, 0, Qt::WNoAutoErase);
00090   plotLabel->setBackgroundMode(Qt::NoBackground);
00091   plotLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
00092   plotLabel->setFrameShape(QFrame::StyledPanel);
00093   plotLabel->setFrameShadow(QFrame::Sunken); 
00094   plotLabel->setLineWidth(1);
00095   plotLabel->setMouseTracking(true);
00096   PixmapLayout->addWidget(plotLabel);
00097 
00099   makeConnections();
00100   init();
00101 }
00102 
00104 PlotMapBase::~PlotMapBase()
00106 {
00107 
00108 }
00109 
00111 bool PlotMapBase::loadMapFile(const QString filename, const bool noerrors)
00114 {
00116   QFile mapFile(filename);
00117   if(!mapFile.exists())
00118   {
00119     if(!noerrors)
00120       QMessageBox::warning(this, "Loading map file", "The map file does not exist");
00121     return false;
00122   }
00123   if(!mapFile.open(IO_ReadOnly))
00124   {
00125     if(!noerrors)
00126       QMessageBox::warning(this, "Loading map file", "The map file could not ne opened");
00127     return false;
00128   }
00129 
00131   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
00132   loadInProgress = true;
00133   QTextStream stream(&mapFile);
00134 
00135   // read the sizes
00136   stream.readLine(); // ignore the first line
00137   QString line = stream.readLine();
00138   numPoints.setValues(line.mid(0, 5).toUInt(), line.mid(75, 5).toUInt(), 0);
00139   origin.setValues(line.mid(5,10).toDouble() * AUTOANG, line.mid(65,10).toDouble() * AUTOANG, 0.0);
00140   delta.setValues(line.mid(15,10).toDouble() * AUTOANG, line.mid(55,10).toDouble() * AUTOANG, 0.0);
00141   QProgressDialog progress(tr("Loading the data..."), tr("Cancel"), numPoints.y() + numPoints.y()/20, this, 0, true);
00142   if(isVisible())
00143     progress.setCancelButton(0); // no cancelling when rereading
00144       
00145   // read the points
00146   points.clear();
00147   for(unsigned int j = 0; j < numPoints.y(); j++) // y's
00148   {
00149     progress.setProgress(j);
00150     qApp->processEvents();
00151     if(progress.wasCancelled())
00152     {
00153       points.clear();
00154       coords.clear();
00155       numPoints.setValues(0, 0, 0);
00156       numAtoms = 0;
00157       loadInProgress = false;
00158      QApplication::restoreOverrideCursor();  
00159      return false;
00160     }
00161     double tempvar;
00162     vector<double> tempvector;
00163     for(unsigned int i = 0; i < numPoints.x(); i++) // x's
00164     {
00165       stream >> tempvar;
00166       tempvector.push_back(tempvar);
00167     }
00168     points.push_back(tempvector);
00169   }
00171 
00172   loadInProgress = false;
00173   if(stream.atEnd())
00174   {
00175     QApplication::restoreOverrideCursor(); 
00176     QMessageBox::warning(this, tr("Loading map file"), tr("Premature end of file encountered"));
00177     return false; // premature end of file
00178   }
00179 
00180   // read the coordinates
00181   stream >> numAtoms;
00182   coords.clear();
00183   coords.reserve(numAtoms);
00184   Point3D<double> atom;
00185   for(unsigned int i = 0; i < numAtoms; i ++)
00186   {
00187     line = stream.readLine();
00188     atom.setValues(line.left(10).toDouble() * AUTOANG, line.mid(10,10).toDouble() * AUTOANG, line.mid(20,10).toDouble() * AUTOANG);
00189     coords.push_back(atom);
00190   }
00191   
00192   mapFile.close();
00193   plotLabel->setGrid(numPoints, delta);
00194   resize(width(), numPoints.y() + 6); // approximately scale plotLabel to its native size
00195   //plotLabel->resize(numPoints.x(), numPoints.y()); // has no effect
00196 
00198   maxValue = 0.0;
00199   minValue = 0.0;
00200   for(unsigned int j = 0; j < numPoints.y(); j++)
00201   {
00202     progress.setProgress(numPoints.y() + j/20);
00203     for(unsigned int i = 0; i < numPoints.x(); i++)
00204     {
00205       if(points[j][i] > maxValue)
00206         maxValue = points[j][i];
00207       else if(points[j][i] < minValue)
00208         minValue = points[j][i];
00209     }
00210   }
00211  
00212   progress.setProgress(progress.totalSteps());
00213   
00215   setCaption(Version::appName + " - " + tr("Visualizing density map") + " (" + mapFile.name() + ")");
00216 
00218   //TextLabelFilename->setText(filename);
00219   TextLabelGridSizeX->setText(QString::number(numPoints.x()));  
00220   TextLabelGridSizeY->setText(QString::number(numPoints.y()));
00221   TextLabelMaxPos->setText(QString::number(maxValue));
00222   TextLabelMaxNeg->setText(QString::number(minValue));
00223 
00225   options->LineEditMaxPos->setText(QString::number(maxValue));
00226   options->LineEditMaxNeg->setText(QString::number(minValue));
00227   
00229   TextLabelCurrentCoordinate->setText("(" + QString::number(numPoints.x()) + ", " + QString::number(numPoints.y()) + ")"); // largest possible width
00230   TextLabelCurrentCoordinate->setFixedWidth(TextLabelCurrentCoordinate->width());
00231   
00233   TextLabelCurrentCoordinate->setText("none");
00234   TextLabelCurrentValue->setText("none");
00235   TextLabelCurrentCartesian->setText("none");
00236   
00238   resize(width() - plotLabel->contentsRect().width() + numPoints.x(), height() - plotLabel->contentsRect().height() + numPoints.y());
00239 
00241   updateImage();
00242 
00243   QApplication::restoreOverrideCursor();  
00244   return true;
00245 }
00246 
00247 
00251 
00253 bool PlotMapBase::loadMapFile()
00255 {
00256   QString filename = QFileDialog::getOpenFileName(QString::null, "*.map.1", this, 0, tr("Choose a map file to open"));
00257 
00258   if(filename.isEmpty())
00259     return false;  
00260 
00261   return loadMapFile(filename);
00262 }
00263 
00264 
00268 
00270 void PlotMapBase::mousePressEvent(QMouseEvent* e)
00272 {
00273   mousePosition = e->pos();
00274   if(onPixmap(mousePosition))
00275     plotLabel->startDrag(mousePosition - plotLabel->pos());
00276 }
00277 
00279 void PlotMapBase::mouseReleaseEvent(QMouseEvent* e)
00282 {
00283   QPoint mouseEndPosition = e->pos();
00284 
00285   if(onPixmap(mousePosition) && onPixmap(mouseEndPosition))
00286   {
00287     QPoint point1 = mapToImage(mousePosition);
00288     QPoint point2 = mapToImage(mouseEndPosition);
00289     int minX = point1.x() > point2.x() ? point2.x() : point1.x();
00290     int maxX = point1.x() > point2.x() ? point1.x() : point2.x();
00291     int minY = point1.y() > point2.y() ? point2.y() : point1.y();
00292     int maxY = point1.y() > point2.y() ? point1.y() : point2.y();
00293      
00295     double localMaxPosValue = 0.0;
00296     double localMinPosValue = maxValue;
00297     double localMaxNegValue = 0.0;
00298     double localMinNegValue = minValue;
00299     for(int j = minY; j <= maxY; j++)
00300     {
00301       for(int i = minX; i <= maxX; i++)
00302       {
00303         double value = points[j][i];
00304         if(value > 0.0)
00305         {
00306           if(value > localMaxPosValue)
00307             localMaxPosValue = value;
00308           if(value < localMinPosValue)
00309             localMinPosValue = value;
00310         }
00311         else if(value < 0.0)
00312         {
00313           if(value < localMaxNegValue)
00314             localMaxNegValue = value;
00315           if(value > localMinNegValue)
00316             localMinNegValue = value;
00317         }
00318         else
00319           localMinPosValue = localMinNegValue = 0.0; 
00320       }
00321     }  
00322     QString value1, value2, value3, value4;
00323     value1.setNum(localMaxPosValue,'f',5);
00324     value2.setNum(localMinPosValue,'f',5);
00325     value3.setNum(localMaxNegValue,'f',5);
00326     value4.setNum(localMinNegValue,'f',5);
00327     if(localMaxPosValue == localMaxNegValue)
00328     {
00330       value2 = "0.00000";
00331       value4 = "0.00000";
00332     }
00333     else if((localMaxPosValue == 0.0) && (localMinNegValue != 0.0))
00334     {
00336       value1 = tr("none");
00337       value2 = tr("none");
00338     }  
00339     else if((localMaxNegValue == 0.0) && (localMinPosValue != 0.0))
00340     {
00342       value3 = tr("none");
00343       value4 = tr("none");
00344     }  
00345       
00347     QString stats = tr("The selected area has the following statistics:")+"\n";
00348     stats += tr("Maximum positive value: ") + value1 + "\n";
00349     stats += tr("Minimum positive value: ") + value2 + "\n";
00350     stats += tr("Maximum negative value: ") + value3 + "\n";
00351     stats += tr("Minimum negative value: ") + value4;
00352     QMessageBox::information(this, tr("Statistics from selection"), stats);
00353 
00354   }
00355   plotLabel->endDrag();
00356   mousePosition.setX(0);
00357   mousePosition.setY(0);
00358   mouseEndPosition.setX(0);
00359   mouseEndPosition.setY(0);
00360 }
00361 
00362 
00364 void PlotMapBase::mouseMoveEvent(QMouseEvent* e)
00367 {
00368   if(loadInProgress)
00369     return; // this routine reads from the points array but that one is being updated in loadMapFile (re-entry because of qapp->processEvents)
00370 
00372   if(mousePosition.x() && mousePosition.y())
00373     plotLabel->moveDrag(e->pos() - plotLabel->pos());
00374 
00376   if(onPixmap(e->pos()))
00377   {
00379     QPoint position = mapToImage(e->pos());
00380     TextLabelCurrentCoordinate->setText("(" + QString::number(position.x() + 1) + ", " + QString::number(position.y() + 1) + ")");
00381 
00383     QString value0;
00384     value0.setNum(points[position.y()][position.x()],'f', 5);
00385     TextLabelCurrentValue->setText(value0);
00387     position = e->pos() - plotLabel->pos();
00388     /*
00389     int fwidth = plotLabel->frameWidth();
00390     QRect rect = plotLabel->geometry();
00391     rect.setLeft(rect.left() + fwidth);
00392     rect.setRight(rect.right() - fwidth);
00393     rect.setTop(rect.top() + fwidth);
00394     rect.setBottom(rect.bottom() - fwidth);
00395     // rect = plotLabel->contentsRect() ???
00396     double cx = origin.x() + delta.x()*double(numPoints.x())*double(position.x() - fwidth)/double(rect.width());
00397     double cy = origin.y() + delta.y()*double(numPoints.y())*(1.0 - double(position.y() - fwidth)/double(rect.height()));
00398     */
00399     QRect rect = plotLabel->contentsRect(); // if only the size is needed, contentsRect is always correct
00400     double cx = origin.x() + delta.x()*double(numPoints.x())*double(position.x())/double(rect.width());
00401     double cy = origin.y() + delta.y()*double(numPoints.y())*(1.0 - double(position.y())/double(rect.height()));
00402 
00403     QString value1, value2;
00404     value1.setNum(cx,'f',4);
00405     value2.setNum(cy,'f',4);
00406     TextLabelCurrentCartesian->setText("(" + value1 + ", " + value2 + ")");
00407   }
00408   else
00409   {
00410     TextLabelCurrentCoordinate->setText("none");
00411     TextLabelCurrentValue->setText("none");
00412     TextLabelCurrentCartesian->setText("none");
00413   }
00414 }
00415 
00419 
00421 void PlotMapBase::saveImage()
00423 {
00425   QStringList saveFormats = QImage::outputFormatList();
00426   QStringList::Iterator it = saveFormats.begin();
00427   while(it != saveFormats.end())
00428   {
00429     if((*it) == "JPEG")
00430       *it = "JPEG (*.jpg)";
00431     else  
00432       *it += " (*."+(*it).lower()+")";  // 'BMP' -> 'BMP (*.bmp)'
00433     //qDebug( *it );
00434     it++;
00435   }
00436 
00438   QFileDialog saveDialog("", QString::null, this, 0, true);  
00439   saveDialog.setFilters(saveFormats);
00440   saveDialog.setSelectedFilter("PNG (*.png)");
00441   saveDialog.setCaption(tr("Choose a filename and format"));
00442   saveDialog.setMode(QFileDialog::AnyFile);
00443   if(saveDialog.exec() != QDialog::Accepted)
00444     return;
00445   
00447   QString filename = saveDialog.selectedFile();
00448   if(filename.isEmpty())
00449     return;
00450 
00451   QString extension = saveDialog.selectedFilter();
00452   extension = extension.mid(extension.find("."));
00453   extension = extension.remove(")");
00454   //qDebug("extension: "+extension);
00455 
00456   if(filename.contains(extension) == 0)
00457     filename += extension;
00458 
00459   QString format = saveDialog.selectedFilter();
00460   format = format.left(format.find(" "));
00461   
00462   QPixmap pm = QPixmap::grabWidget(plotLabel);
00463   QImage image = pm.convertToImage();
00464   if(!image.save(filename, format))
00465     QMessageBox::warning(this, tr("Save image"), tr("An error occured. Image is not saved")); 
00466 }
00467 
00469 void PlotMapBase::showOptions()
00471 {
00472   if(options->isVisible())
00473   {
00474     int newHeight = plotLabel->height() + 2*plotLabel->pos().y();
00475     QSize oldsize(width(), newHeight); // keep width the same
00476     options->hide();
00477     qApp->processEvents();
00478     resize(oldsize);
00479     PushButtonOptions->setText(tr(">>> Show Options"));
00480   }
00481   else
00482   {
00483     int newHeight = plotLabel->height() + 2*plotLabel->pos().y();
00484     options->show();
00485     newHeight += options->height() + 6; // WHY 6 ?????
00486     resize(width(), newHeight); // keep new width the same
00487     PushButtonOptions->setText(tr("<<< Hide Options"));
00488    }
00489 }
00490 
00492 void PlotMapBase::applyOptions()
00494 {
00495   updateImage();
00496 }
00497 
00499 void PlotMapBase::autoApply(bool state)
00501 {
00502   if(state)
00503   {
00504     connect(this, SIGNAL(optionsChanged()), this, SLOT(applyOptions()));
00505     applyOptions();
00506   }  
00507   else
00508     disconnect(this, SIGNAL(optionsChanged()), this, SLOT(applyOptions()));
00509 }
00510 
00512 void PlotMapBase::resetOptions()
00514 {
00515   options->LineEditMaxPos->setText(QString::number(maxValue));
00516   options->ColorButtonPos->setColor(QColor(0, 0, 255));
00517   options->SpinBoxPos->setValue(10);
00518 
00519   options->LineEditMaxNeg->setText(QString::number(minValue));
00520   options->ColorButtonNeg->setColor(QColor(255, 0, 0));
00521   options->SpinBoxNeg->setValue(10);
00522   
00523   options->CheckBoxAtoms->setChecked(true);
00524   options->LineEditAtoms->setText("0.1");
00525   options->ColorButtonAtoms->setColor(QColor(0, 0, 0));
00526 
00527   options->ColorButtonZero->setColor(QColor(255, 255, 255));
00528 
00529   options->ComboBoxStyle->setCurrentItem(2); // Areas
00530   options->ComboBoxInterpolation->setCurrentItem(0); // Linear interpolation
00531 
00532   updateImage();
00533 }
00534 
00535 
00539 
00541 void PlotMapBase::makeConnections()
00543 {
00545   connect(PushButtonLoadMap, SIGNAL(clicked()), this, SLOT(loadMapFile()));
00546   connect(PushButtonSaveImage, SIGNAL(clicked()), this, SLOT(saveImage()));
00547   connect(PushButtonOptions, SIGNAL(clicked()), this, SLOT(showOptions()));
00548   connect(PushButtonClose, SIGNAL(clicked()), this, SLOT(close())); // with WDestructiveClose
00549 
00551   connect(options->PushButtonApply, SIGNAL(clicked()), this, SLOT(applyOptions()));
00552   connect(options->CheckBoxApply, SIGNAL(toggled(bool)), this, SLOT(autoApply(bool)));
00553   connect(options->PushButtonDefaults, SIGNAL(clicked()), this, SLOT(resetOptions()));
00554   //connect(options->PushButtonClose, SIGNAL(clicked()), options, SLOT(hide()));
00555 
00557   connect(options->LineEditMaxPos, SIGNAL(textChanged(const QString&)), this, SIGNAL(optionsChanged()));
00558   connect(options->ColorButtonPos, SIGNAL(newColor(QColor*)), this, SIGNAL(optionsChanged()));
00559   //connect(options->CheckBoxPos, SIGNAL(toggled(bool)), this, SIGNAL(optionsChanged()));
00560   connect(options->SpinBoxPos, SIGNAL(valueChanged(int)), this, SIGNAL(optionsChanged()));
00561   connect(options->LineEditMaxNeg, SIGNAL(textChanged(const QString&)), this, SIGNAL(optionsChanged()));
00562   connect(options->ColorButtonNeg, SIGNAL(newColor(QColor*)), this, SIGNAL(optionsChanged()));
00563   //connect(options->CheckBoxNeg, SIGNAL(toggled(bool)), this, SIGNAL(optionsChanged()));
00564   connect(options->SpinBoxNeg, SIGNAL(valueChanged(int)), this, SIGNAL(optionsChanged()));
00565   connect(options->CheckBoxAtoms, SIGNAL(toggled(bool)), this, SIGNAL(optionsChanged()));
00566   connect(options->LineEditAtoms, SIGNAL(textChanged(const QString&)), this, SIGNAL(optionsChanged()));
00567   connect(options->ColorButtonAtoms, SIGNAL(newColor(QColor*)), this, SIGNAL(optionsChanged()));
00568   connect(options->ColorButtonZero, SIGNAL(newColor(QColor*)), this, SIGNAL(optionsChanged()));  
00569 }
00570 
00572 void PlotMapBase::init()
00574 {
00575   mousePosition.setX(0);
00576   mousePosition.setY(0);
00577   resetOptions(); 
00578 }
00579 
00581 void PlotMapBase::updateImage()
00583 {
00584   if((numPoints.x() == 0) || (numPoints.y() == 0))
00585     return;
00586 
00587   if(options->ComboBoxStyle->currentItem() == 0)
00588     updatePixmap();
00589   else
00590     updateIsoLines();
00591   if(options->CheckBoxAtoms->isChecked())
00592     updateCrosses();
00593 
00594   plotLabel->setDrawStyle(options->ComboBoxStyle->currentItem(), options->ComboBoxInterpolation->currentItem() == 1); 
00595   plotLabel->setColors(options->ColorButtonZero->color(), options->ColorButtonAtoms->color());
00596   plotLabel->update();
00597 }
00598 
00600 void PlotMapBase::updatePixmap()
00602 {
00603   QPixmap showPixmap(numPoints.x(), numPoints.y());
00604   QPainter painter(&showPixmap);
00605 
00606   const double maxPlotValue = fabs(options->LineEditMaxPos->text().toDouble());
00607   const QColor positiveColor = options->ColorButtonPos->color();
00608   const bool useLevelsPos = options->SpinBoxPos->value() != 255;
00609   const int numLevelsPos = options->SpinBoxPos->value();  
00610   const double minPlotValue = - fabs(options->LineEditMaxNeg->text().toDouble());
00611   const QColor negativeColor = options->ColorButtonNeg->color();
00612   const bool useLevelsNeg = options->SpinBoxNeg->value() != 255;
00613   const int numLevelsNeg = options->SpinBoxNeg->value();    
00614   const QColor backgroundColor = options->ColorButtonZero->color();
00615       
00616   for(unsigned int j = 0; j < numPoints.y(); j++)
00617   {
00618     for(unsigned int i = 0; i < numPoints.x(); i++)
00619     {
00621       QColor pixelColor;
00622       if(points[j][i] > 0.0)
00623       {
00625         double intensity = 1.0;
00626         if(!useLevelsPos)
00627           intensity = points[j][i]/maxPlotValue;
00628         else
00629           intensity = floor(points[j][i]*double(numLevelsPos)/maxPlotValue + 0.5)/double(numLevelsPos);
00631         pixelColor = plotColor(positiveColor, backgroundColor, intensity);        
00632       }
00633       else
00634       {
00635         double intensity = 1.0;
00636         if(!useLevelsNeg)
00637           intensity = points[j][i]/minPlotValue;
00638         else
00639           intensity = floor(points[j][i]*double(numLevelsNeg)/minPlotValue + 0.5)/double(numLevelsNeg);  
00640         pixelColor = plotColor(negativeColor, backgroundColor, intensity);        
00641       }
00642       // set the pixel to that color
00643       painter.setPen(pixelColor);
00644       painter.drawPoint(i, j);
00645     }
00646   }
00647   plotLabel->setDensityPixmap(showPixmap);
00648 }
00649 
00651 void PlotMapBase::updateCrosses()
00653 {
00654   const double showAtomsLimit = options->LineEditAtoms->text().toDouble();
00655       
00656   vector<Point3D<double> > showCoords;
00657   showCoords.reserve(numAtoms);
00658   Point3D<double>newCoord;
00659   if(options->CheckBoxAtoms->isChecked())
00660   {
00661     for(unsigned int i = 0; i < numAtoms; i++)
00662     {
00663       if(fabs(coords[i].z()) > showAtomsLimit)
00664         continue; // do not show atoms too far out of plane
00665 
00666       // substract the origin
00667       newCoord.setValues(coords[i].x() - origin.x(), coords[i].y() - origin.y(), 0.0);
00668       showCoords.push_back(newCoord);
00669     }
00670   }
00671   // give them to plotLabel
00672   plotLabel->setCrosses(showCoords);
00673 }
00674 
00676 void PlotMapBase::updateIsoLines()
00682 {
00683   const double maxPlotValue = fabs(options->LineEditMaxPos->text().toDouble());
00684   const QColor positiveColor = options->ColorButtonPos->color();
00685   const int numLevelsPos = options->SpinBoxPos->value();  
00686   const double minPlotValue = - fabs(options->LineEditMaxNeg->text().toDouble());
00687   const QColor negativeColor = options->ColorButtonNeg->color();
00688   const int numLevelsNeg = options->SpinBoxNeg->value();    
00689   const QColor backgroundColor = options->ColorButtonZero->color();
00690 
00692   // values
00693   vector<double> isoLevels;
00694   isoLevels.reserve(numLevelsPos+numLevelsNeg);
00695   for(int i = 1; i <= numLevelsPos; i++) 
00696     isoLevels.push_back(static_cast<double>(i)/numLevelsPos * maxPlotValue);
00697   for(int i = 1; i <= numLevelsNeg; i++) 
00698     isoLevels.push_back(static_cast<double>(i)/numLevelsNeg * minPlotValue);
00699   // colors
00700   vector<QColor> isoColors;
00701   isoColors.reserve(numLevelsPos+numLevelsNeg);
00702   for(int i = 0; i < numLevelsPos; i++)
00703     isoColors.push_back(plotColor(positiveColor, backgroundColor, isoLevels[i]/maxPlotValue));
00704   for(int i = numLevelsPos; i < numLevelsPos+numLevelsNeg; i++)
00705     isoColors.push_back(plotColor(negativeColor, backgroundColor, isoLevels[i]/minPlotValue));
00706   // colors for isolines 
00707   vector<QColor> lineColors;
00708   lineColors.reserve(numLevelsPos+numLevelsNeg);
00709   for(int i = 0; i < numLevelsPos; i++)
00710     lineColors.push_back(positiveColor);
00711   for(int i = numLevelsPos; i < numLevelsPos+numLevelsNeg; i++)
00712     lineColors.push_back(negativeColor);
00713 
00715   for(unsigned int i = 0; i < isoCurves.size(); i++)
00716     delete isoCurves[i];
00717   isoCurves.clear();
00718 
00720   // the following vector keeps all found isodensity points for each level
00721   vector< vector<Point3D<double> >* > segments;
00722   segments.reserve(isoLevels.size());
00723   // the following maps between segment numbers and indices in the segments vector
00724   vector<map<unsigned int, unsigned int>* > segmentMaps;
00725   segmentMaps.reserve(isoLevels.size());
00726   for(unsigned int i = 0; i < isoLevels.size(); i++)
00727   {
00728     vector<Point3D<double> >* newSegment = new vector<Point3D<double> >();
00729     segments.push_back(newSegment);
00730     map<unsigned int, unsigned int>* newMap = new map<unsigned int, unsigned int>();
00731     segmentMaps.push_back(newMap);
00732   }
00733 
00735   for(unsigned int y = 0; y < numPoints.y(); y++)
00736   {
00737     unsigned int currentSegment = y * (2*numPoints.x()-1);
00738     for(unsigned int x = 0; x < numPoints.x() - 1; x++)
00739     {
00742       for(unsigned int level = 0; level < isoLevels.size(); level++)
00743       {
00744         if( (points[y][x] <= isoLevels[level] && points[y][x+1] > isoLevels[level]) ||
00745             (points[y][x] > isoLevels[level] && points[y][x+1] <= isoLevels[level]) )
00746         {
00748           Point3D<double> point1(static_cast<double>(x), static_cast<double>(y), 0.0);
00749           Point3D<double> point2(static_cast<double>(x+1), static_cast<double>(y), 0.0);
00750           Point3D<double> result = interpolate2D(point1, point2, points[y][x], points[y][x+1], isoLevels[level]);
00751           result.setID(currentSegment);
00752           segments[level]->push_back(result);
00754           segmentMaps[level]->operator[](currentSegment) = segments[level]->size() - 1;
00755         }
00756       }
00757       currentSegment++;
00758     }
00759   }
00761   for(unsigned int y = 0; y < numPoints.y() - 1; y++)
00762   {
00763     unsigned int currentSegment = (2*y + 1)*numPoints.x() - y - 1; //from numPoints.x() - 1 + y * (2*numPoints.x()-1);
00764     for(unsigned int x = 0; x < numPoints.x(); x++)
00765     {
00768       for(unsigned int level = 0; level < isoLevels.size(); level++)
00769       {
00770         if( (points[y][x] <= isoLevels[level] && points[y+1][x] > isoLevels[level]) ||
00771             (points[y][x] > isoLevels[level] && points[y+1][x] <= isoLevels[level]))
00772         {
00774           Point3D<double> point1(static_cast<double>(x), static_cast<double>(y), 0.0);
00775           Point3D<double> point2(static_cast<double>(x), static_cast<double>(y+1), 0.0);
00776           Point3D<double> result = interpolate2D(point1, point2, points[y][x], points[y+1][x], isoLevels[level]);
00777           result.setID(currentSegment);
00778           segments[level]->push_back(result);
00780           segmentMaps[level]->operator[](currentSegment) = segments[level]->size() - 1;
00781         }
00782       }
00783       currentSegment++;
00784     }
00785   }
00786 
00788   const unsigned int totalSegments = (numPoints.x() - 1)*numPoints.y() + numPoints.x()*(numPoints.y() - 1);
00789   //vector<QColor> isoCurveColors; // holds the color for each curve
00790   vector<QColor> lineCurveColors;
00791   vector< vector<Point3D<double> > > isoPolygons; // polygon data for each iso level
00792   isoPolygons.reserve(numLevelsPos+numLevelsNeg); // should equal the size of isoColors and isoLevels
00793   for(unsigned int level = 0; level < isoLevels.size(); level++)
00794   {
00796     vector<bool> segmentVisited;
00797     segmentVisited.reserve(totalSegments);
00798     for(unsigned int i = 0; i < totalSegments; i++)
00799       segmentVisited.push_back(false);
00800 
00801     const unsigned int firstCurve = isoCurves.size(); // index of the first curve of this level
00802     // the top horizontal row
00803     for(unsigned int segment = 0; segment < numPoints.x() - 1; segment++)
00804     {
00805       // find out whether a Point3D exists with this segment ID
00806       if(!segmentVisited[segment] && hasPoint(segment, level, segmentMaps))
00807       {
00808         startSearch(segment, level, false, segmentMaps, segmentVisited, segments);
00809         //isoCurveColors.push_back(isoColors[level]);
00810         lineCurveColors.push_back(lineColors[level]);
00811       }
00812     }
00813     // the rightmost column
00814     for(unsigned int segment = 2*(numPoints.x() - 1); segment < totalSegments; segment += 2*numPoints.x() - 1)
00815     {
00816       if(!segmentVisited[segment] && hasPoint(segment, level, segmentMaps))
00817       {
00818         startSearch(segment, level, false, segmentMaps, segmentVisited, segments);
00819         //isoCurveColors.push_back(isoColors[level]);
00820         lineCurveColors.push_back(lineColors[level]);
00821      }
00822     }
00823     // the bottom horizontal row
00824     for(unsigned int segment = totalSegments - (numPoints.x() - 1); segment < totalSegments; segment++)
00825     {
00826       if(!segmentVisited[segment] && hasPoint(segment, level, segmentMaps))
00827       {
00828         startSearch(segment, level, false, segmentMaps, segmentVisited, segments);
00829         //isoCurveColors.push_back(isoColors[level]);
00830         lineCurveColors.push_back(lineColors[level]);
00831       }
00832     }
00833     // the leftmost column
00834     for(unsigned int segment = numPoints.x() - 1; segment < totalSegments; segment += 2*numPoints.x() - 1)
00835     {
00836       if(!segmentVisited[segment] && hasPoint(segment, level, segmentMaps))
00837       {
00838         startSearch(segment, level, false, segmentMaps, segmentVisited, segments);
00839         //isoCurveColors.push_back(isoColors[level]);
00840         lineCurveColors.push_back(lineColors[level]);
00841      }
00842     }
00843 
00844     const unsigned int firstCircularCurve = isoCurves.size(); // index of the first curve of this level (only circular ones)
00845     // all segments (visited ones will be skipped anyway)
00846     for(unsigned int segment = 0; segment < totalSegments; segment++)
00847     {
00848       if(!segmentVisited[segment] && hasPoint(segment, level, segmentMaps))
00849       {
00850         startSearch(segment, level, true, segmentMaps, segmentVisited, segments);
00851         //isoCurveColors.push_back(isoColors[level]);
00852         lineCurveColors.push_back(lineColors[level]);
00853       }        
00854     }
00855     const unsigned int lastCurve = isoCurves.size(); // index of the last curve of this level
00856     // combine all the generated curves into 1 polygon
00857     vector<Point3D<double> > isoPolygon;
00858     Point3D<double> zeroPoint(0.0, 0.0, 0.0);
00859     // combine all non-circular curves into 1 by adding them in the correct order and 
00860     // by possibly adding corner points
00861     if(firstCurve != firstCircularCurve)
00862     {
00863       //qDebug("started with a point at (0,0) for non-circular curves");
00864       //qDebug("added first curve from (%f,%f) to (%f,%f)",isoCurves[firstCurve]->operator[](0).x(), isoCurves[firstCurve]->operator[](0).y(),
00865       //       isoCurves[firstCurve]->operator[](isoCurves[firstCurve]->size() - 1).x(),isoCurves[firstCurve]->operator[](isoCurves[firstCurve]->size() - 1).y());                                                   
00866       vector<bool> curveAdded;
00867       curveAdded.reserve(firstCircularCurve - firstCurve);
00868       for(unsigned int i = firstCurve; i < firstCircularCurve; i++)
00869         curveAdded.push_back(false);
00870       // always pass by zero
00871       isoPolygon.push_back(zeroPoint);
00872       // add the first curve
00873       isoPolygon.reserve(isoPolygon.size() + isoCurves[firstCurve]->size());
00874       isoPolygon.insert(isoPolygon.end(),isoCurves[firstCurve]->begin(), isoCurves[firstCurve]->end());
00875       curveAdded[0] = true;
00876       // recursively get the next curves until all have been added
00877       continuePolygon(firstCurve, firstCircularCurve, firstCurve, isoPolygon, curveAdded, isoCurves[firstCurve]->operator[](0), false, isoLevels[level]);
00878     }
00879     // add the circular curves
00880     for(unsigned int i = firstCircularCurve; i < lastCurve; i++)
00881     {
00882       // always pass by zero
00883       isoPolygon.push_back(zeroPoint);
00884       // add the contents of the curve (completely thus some extra points are added)
00885       isoPolygon.reserve(isoPolygon.size() + isoCurves[i]->size());
00886       isoPolygon.insert(isoPolygon.end(),isoCurves[i]->begin(), isoCurves[i]->end());
00887     }
00888     //if(firstCurve == lastCurve)
00889       // add a zero so the polygon is not empty
00890       isoPolygon.push_back(zeroPoint);
00891 
00892     // add it to the list
00893     isoPolygons.push_back(isoPolygon);
00894   }
00895 
00896   //plotLabel->setIsoCurves(isoCurves, isoCurveColors, lineCurveColors);
00897   plotLabel->setIsoCurves(isoCurves, lineCurveColors);
00898   plotLabel->setPolygons(isoPolygons, isoColors);
00899 }
00900 
00902 QColor PlotMapBase::plotColor(const QColor foregroundColor, const QColor backgroundColor, const double opaqueness)
00905 {
00906   double intensity = opaqueness;
00907   limitRange(0.0, intensity, 1.0);
00908     
00909   int newRed = 1000, newGreen = 1000, newBlue = 1000;
00910 
00911   if(backgroundColor.red() == foregroundColor.red())
00912     newRed = backgroundColor.red();
00913   else if(backgroundColor.red() < foregroundColor.red())
00914     newRed = backgroundColor.red() + int(double(foregroundColor.red() - backgroundColor.red())*intensity);
00915   else
00916     newRed = foregroundColor.red() + int(double(backgroundColor.red() - foregroundColor.red())*(1.0 - intensity));
00917 
00918   if(backgroundColor.green() == foregroundColor.green())
00919     newGreen = backgroundColor.green();
00920   else if(backgroundColor.green() < foregroundColor.green())
00921     newGreen = backgroundColor.green() + int(double(foregroundColor.green() - backgroundColor.green())*intensity);
00922   else
00923     newGreen = foregroundColor.green() + int(double(backgroundColor.green() - foregroundColor.green())*(1.0 - intensity));
00924 
00925   if(backgroundColor.blue() == foregroundColor.blue())
00926     newBlue = backgroundColor.blue();
00927   else if(backgroundColor.blue() < foregroundColor.blue())
00928     newBlue = backgroundColor.blue() + int(double(foregroundColor.blue() - backgroundColor.blue())*intensity);
00929   else
00930     newBlue = foregroundColor.blue() + int(double(backgroundColor.blue() - foregroundColor.blue())*(1.0 - intensity));
00931 
00932   //qDebug("backColor:  %d, %d, %d frontColor: %d, %d, %d intensity: %f result: %d, %d, %d",backgroundColor.red(), backgroundColor.green(), backgroundColor.blue(),foregroundColor.red(), foregroundColor.green(), foregroundColor.blue(),intensity, newRed, newGreen, newBlue);
00933     
00934   limitRange(0, newRed, 255);
00935   limitRange(0, newGreen, 255);
00936   limitRange(0, newBlue, 255);
00937       
00938   return QColor(newRed, newGreen, newBlue);
00939 }
00940 
00942 bool PlotMapBase::onPixmap(const QPoint position)
00944 {
00945   /*
00946   QRect rect = plotLabel->geometry();
00947   int fwidth = plotLabel->frameWidth();
00948   rect.setLeft(rect.left() + fwidth);
00949   rect.setRight(rect.right() - fwidth);
00950   rect.setTop(rect.top() + fwidth);
00951   rect.setBottom(rect.bottom() - fwidth);
00952   */
00953   QRect rect = labelRect();
00954 
00955 
00956   return rect.contains(position);
00957 }
00958 
00960 QPoint PlotMapBase::mapToImage(const QPoint position)
00963 {
00964   QRect rect = labelRect();
00965   QPoint intermediate = position - rect.topLeft();
00966 
00967   return QPoint( intermediate.x()*numPoints.x()/rect.width(), 
00968                  intermediate.y()*numPoints.y()/rect.height() );
00969 
00970   //int fwidth = plotLabel->frameWidth();
00971   //QPoint intermediate = position - plotLabel->pos();
00972   //return QPoint( (intermediate.x() - fwidth)*numPoints.x()/(plotLabel->geometry().width() - 2*fwidth), 
00973   //               (intermediate.y() - fwidth)*numPoints.y()/(plotLabel->geometry().height() - 2*fwidth) );
00974 }
00975 
00977 Point3D<double> PlotMapBase::interpolate2D(const Point3D<double>& point1, const Point3D<double>& point2, const double density1, const double density2, const double isoLevel)
00981 {
00982   Point3D<double> lowPoint, highPoint;
00983   double lowDensity, highDensity, mu;
00984   if(density1 < density2)
00985   {
00986     lowPoint = point1;
00987     highPoint = point2;
00988     lowDensity = density1;
00989     highDensity = density2;
00990   }
00991   else 
00992   {
00993     lowPoint = point2;
00994     highPoint = point1;
00995     lowDensity = density2;
00996     highDensity = density1;
00997   }
00998 
00999   if(highDensity == lowDensity)
01000     mu = 0.5;
01001   else
01002     mu = (isoLevel - lowDensity)/(highDensity - lowDensity);
01003   const double x = lowPoint.x() + mu*(highPoint.x() - lowPoint.x());
01004   const double y = lowPoint.y() + mu*(highPoint.y() - lowPoint.y());
01005 
01006   return Point3D<double>(x, y, 0.0);
01007 }
01008 
01010 bool PlotMapBase::hasPoint(const unsigned int segment, const unsigned int level, const vector<map<unsigned int, unsigned int>* >& segmentMaps)
01012 {
01013   //map<unsigned int, unsigned int>::iterator it = segmentMaps[level]->find(segment);
01014   return segmentMaps[level]->find(segment) != segmentMaps[level]->end();
01015 
01016 }
01017 
01019 Point3D<double> PlotMapBase::getPoint(const unsigned int segment, const unsigned int level, const vector<map<unsigned int, unsigned int>* >& segmentMaps, const vector< vector<Point3D<double> >* >& segments)
01021 {
01022   map<unsigned int, unsigned int>::iterator it = segmentMaps[level]->find(segment);
01023   if(it != segmentMaps[level]->end())
01024   {
01025     // verify the returned point has the same ID as the requested segment
01026     if(segment != segments[level]->at(it->second).id())
01027     {
01028       qDebug("asked for point corresponding to segment %d", segment);
01029       qDebug("returned point with ID %d", segments[level]->at(it->second).id());
01030     }
01031 
01032     return segments[level]->at(it->second);
01033   }
01034   else
01035     return Point3D<double>();
01036 }
01037 
01039 void PlotMapBase::startSearch(const unsigned int segment, const unsigned int level, const bool circular, const vector<map<unsigned int, unsigned int>* >& segmentMaps, vector<bool>& segmentVisited, const vector< vector<Point3D<double> >* >& segments)
01041 {
01043   vector<Point3D<double> >* newCurve = new vector<Point3D<double> >();
01044   isoCurves.push_back(newCurve);
01046   Point3D<double> firstPoint = getPoint(segment, level, segmentMaps, segments);
01047   newCurve->push_back(firstPoint);
01049   if(!circular)
01050     newCurve->push_back(firstPoint);
01052   segmentVisited[segment] = true;
01053   unsigned int oldSegment = segment;
01054   unsigned int newSegment = segment;
01055   if(circular)
01056   {
01057     // set up a previously visited segment for a circular curve to proceed succesfully
01058     // go down for horizontal segments and go right for vertical segments by defining
01059     // the previous segment being 1 smaller than the current segment
01060     oldSegment--;
01061   }
01062 
01063   //bool print = false;
01064   //if(isoCurves.size() == 1)
01065   //  print = true;
01066 
01067   //qDebug("starting a new curve at segment %d (%f, %f) for level %d ", segment, firstPoint.x(), firstPoint.y(), level);
01068 
01069   Point3D<double> newPoint = firstPoint;
01070   unsigned int segment1, segment2, segment3;
01071   while(true)
01072   {
01075     if(!getNeighbours(newSegment, oldSegment, segment1, segment2, segment3))
01076     {
01077       if(circular)
01078         qDebug("end of curve reached although a circular curve is searched");
01079       // edge segment
01080       // the final point of a non-circular curve has been reached
01081       // so add this point again and return
01082       newCurve->push_back(newPoint);
01083       //if(print) qDebug("last point of noncircular curve: point %u: (%f, %f)", newCurve->size() - 1, newPoint.x(), newPoint.y());
01084       return;           
01085     }
01086     else
01087     {
01088       // check which of the neighbouring segments have a Point3D
01089       bool segment1HasPoint = hasPoint(segment1, level, segmentMaps) && !segmentVisited[segment1];
01090       bool segment2HasPoint = hasPoint(segment2, level, segmentMaps) && !segmentVisited[segment2];
01091       bool segment3HasPoint = hasPoint(segment3, level, segmentMaps) && !segmentVisited[segment3];
01092 
01093       /*
01094       qDebug("possible new directions: segment %d, segment %d or segment %d", segment1, segment2, segment3);
01095       QString test = " have a Point3D associated: ";
01096       if(hasPoint(segment1, level, segmentMaps))
01097         test += "segment1 ";
01098       if(hasPoint(segment2, level, segmentMaps))
01099         test += "segment2 ";
01100       if(hasPoint(segment3, level, segmentMaps))
01101         test += "segment3 ";
01102       qDebug(test);
01103       test = " are not visited yet: ";
01104       if(!segmentVisited[segment1])
01105         test += "segment1 ";
01106       if(!segmentVisited[segment2])
01107         test += "segment2 ";
01108       if(!segmentVisited[segment3])
01109         test += "segment3 ";
01110       qDebug(test);
01111       */
01112 
01113       if(segment1HasPoint && segment2HasPoint && segment3HasPoint)
01114       {
01115         // 3 connecting segments have been found
01116         // we have a problem because this leaves us with 2
01117         // choices for the next segment (segment1 or segment3)
01118         // => choose segment1 as a test
01119         oldSegment = newSegment;
01120         newSegment = segment1;
01121         newPoint = getPoint(newSegment, level, segmentMaps, segments);
01122         newCurve->push_back(newPoint);
01123         segmentVisited[newSegment] = true;
01124         //if(print) qDebug("next point of curve (ambiguous case): point %u: (%f, %f)", newCurve->size() - 1, newPoint.x(), newPoint.y());
01125       }
01126       else if(!segment1HasPoint && !segment2HasPoint && !segment3HasPoint)
01127       {
01128         // no possibilities left so this must be the end of a circular line
01129         if(circular)
01130         {
01131           //qDebug("last point of circular line. closing with first point");
01132           newCurve->push_back(firstPoint);
01133           // while drawing check whether the ID of the first and last points are identical for closed curves
01134           return;
01135         }
01136         else
01137         {
01138           // a non-circular curve ended in the middle of the grid => shouldn't happen
01139           newCurve->push_back(newPoint);
01140           
01141           qDebug(" double last point : point %d: (%f, %f)", static_cast<int>(newCurve->size() - 1), newPoint.x(), newPoint.y());
01142           qDebug("end of non-circular curve reached in the middle of the field");
01143           qDebug(" current segment = %d, possibly next segments: %d, %d and %d", newSegment, segment1, segment2, segment3);
01144           qDebug(" point of current segment: (%f, %f)",newPoint.x(), newPoint.y());
01145           if(isHorizontal(newSegment))
01146             qDebug(" current segment is horizontal");
01147           else
01148             qDebug(" current segment is vertical");
01149           if(hasPoint(segment1, level, segmentMaps))
01150             qDebug(" segment1 has a point but is already visited");
01151           if(hasPoint(segment2, level, segmentMaps))
01152             qDebug(" segment2 has a point but is already visited");
01153           if(hasPoint(segment3, level, segmentMaps))
01154             qDebug(" segment3 has a point but is already visited");
01155           
01156           return;
01157         }
01158       }
01159       else
01160       {
01161         // only 1 segment is left (2 is impossible as segments are taken away from cells in pairs
01162         oldSegment = newSegment;
01163         if(segment1HasPoint)
01164           newSegment = segment1;
01165         else if(segment2HasPoint)
01166           newSegment = segment2;
01167         else
01168           newSegment = segment3;
01169         newPoint = getPoint(newSegment, level, segmentMaps, segments);
01170         newCurve->push_back(newPoint);
01171         segmentVisited[newSegment] = true;
01172         //if(print) qDebug("next point of curve: point %u: (%f, %f)", newCurve->size() - 1, newPoint.x(), newPoint.y());
01173 
01174       }      
01175     }
01176   }
01177 }
01178 
01180 bool PlotMapBase::getNeighbours(const unsigned int currentSegment, const unsigned int previousSegment, unsigned int& segment1, unsigned int& segment2, unsigned int& segment3)
01182 {
01184   if(currentSegment == previousSegment)
01185   {
01186     // this is an edge segment at the start of a curve
01187     if(isHorizontal(currentSegment))
01188     {
01189       // top or bottom row
01190       if(currentSegment < numPoints.x() - 1)
01191       {
01192         // top row segment so return belowleft, below and belowright
01193         segment1 = currentSegment + numPoints.x() - 1;
01194         segment2 = currentSegment + 2*numPoints.x() - 1;
01195         segment3 = currentSegment + numPoints.x();
01196         return true;
01197       }
01198       else
01199       {
01200         // bottom row segment so return aboveleft, above and aboveright
01201         segment1 = currentSegment - numPoints.x();
01202         segment2 = currentSegment + 1 - 2*numPoints.x();
01203         segment3 = currentSegment + 1 - numPoints.x();
01204         return true;
01205       }
01206     }
01207     else
01208     {
01209       // first or last column
01210       if((currentSegment + 1 - numPoints.x()) % numPoints.x() == 0)
01211       {
01212         // first column segment so return above right, right, belowright
01213         segment1 = currentSegment + 1 - numPoints.x();
01214         segment2 = currentSegment + 1;
01215         segment3 = currentSegment + numPoints.x();
01216         return true;
01217       }
01218       else
01219       {
01220         // last column segment so return above left, left, belowleft
01221         segment1 = currentSegment - numPoints.x();
01222         segment2 = currentSegment - 1;
01223         segment3 = currentSegment + numPoints.x() - 1;
01224       }
01225     }
01226   }
01227   else
01228   {
01229     // the currentSegment is not at the start of a curve 
01230     // check in which direction should be searched
01231     if(isHorizontal(currentSegment))
01232     {
01233       if(previousSegment < currentSegment)
01234       {
01235         // check out the cell below (below left, below, below right
01236         // first check currentSegment is not an edge
01237         if(currentSegment >= (2*numPoints.x() - 1)*(numPoints.y() - 1))
01238           return false;
01239         else
01240         {
01241           segment1 = currentSegment + numPoints.x() - 1;
01242           segment2 = currentSegment + 2*numPoints.x() - 1;
01243           segment3 = currentSegment + numPoints.x();
01244           return true;
01245         }
01246       }
01247       else
01248       {
01249         // check out the cell above
01250         if(currentSegment < numPoints.x())
01251           return false;
01252         else
01253         {
01254           segment1 = currentSegment - numPoints.x();
01255           segment2 = currentSegment + 1 - 2*numPoints.x();
01256           segment3 = currentSegment + 1 - numPoints.x();
01257           return true;
01258         }
01259       }
01260     }
01261     else
01262     {
01263       // vertical segment
01264       if(previousSegment == currentSegment - 1 || previousSegment == currentSegment - numPoints.x() || previousSegment == currentSegment + numPoints.x() - 1)
01265       {
01266         // check out the right cell
01267         if((currentSegment - 2*(numPoints.x() - 1)) % (2*numPoints.x() - 1) == 0)
01268           return false;
01269         else
01270         {
01271           segment1 = currentSegment + 1 - numPoints.x();
01272           segment2 = currentSegment + 1;
01273           segment3 = currentSegment + numPoints.x();
01274           return true;
01275         }
01276       }
01277       else
01278       {
01279         // check out the left cell
01280         if((currentSegment - (numPoints.x() - 1)) % (2*numPoints.x() - 1) == 0)
01281           return false;
01282         else
01283         {
01284           segment1 = currentSegment - numPoints.x();
01285           segment2 = currentSegment - 1;
01286           segment3 = currentSegment + numPoints.x() - 1;
01287           return true;
01288         }
01289       }
01290     }
01291   }
01292   return true;
01293 }
01294 
01296 bool PlotMapBase::isHorizontal(const unsigned int segment)
01298 {
01299   unsigned int currentSegment = 0;
01300   for(unsigned int y = 0; y < numPoints.y(); y++)
01301   {
01302     if(segment >= currentSegment && segment < currentSegment + numPoints.x() - 1)
01303       return true;
01304     currentSegment += 2*numPoints.x() - 1;
01305   }
01306   return false;
01307 }
01308 
01310 void PlotMapBase::continuePolygon(const unsigned int startCurve, const unsigned int endCurve, unsigned int currentCurve, vector<Point3D<double> >& isoPolygon, vector<bool>& curveAdded, const Point3D<double>& startPoint, const bool fromStart, const double isoLevel)
01312 {  
01314   // get the starting point
01315   Point3D<double> checkPoint;
01316   if(fromStart)
01317     checkPoint = isoCurves[currentCurve]->operator[](0);
01318   else
01319     checkPoint = isoCurves[currentCurve]->operator[](isoCurves[currentCurve]->size() - 1);
01320   //qDebug("continuePolygon: checking point (%f, %f)",checkPoint.x(), checkPoint.y());
01321   //qDebug("because fromStart  = %d",fromStart);
01322   //qDebug("end points are (%f,%f) and (%f,%f)",isoCurves[currentCurve]->operator[](0).x(),isoCurves[currentCurve]->operator[](0).y(),
01323   //    isoCurves[currentCurve]->operator[](isoCurves[currentCurve]->size() - 1).x(),isoCurves[currentCurve]->operator[](isoCurves[currentCurve]->size() - 1).y());
01324   // on which edge?
01325   if(static_cast<int>(checkPoint.y()) == 0)
01326   {
01327     // top row -> go left or right?
01328     if(fabs(points[0][static_cast<int>(checkPoint.x())]) > fabs(isoLevel))
01329     {
01330       // go left -> counterclockwise direction
01331       //qDebug("searching left on top row");
01332       nextPolygonCCWT(startCurve, endCurve, isoPolygon, curveAdded, startPoint, checkPoint, isoLevel);
01333     }
01334     else
01335     {
01336       // go right -> clockwise
01337       //qDebug("searching right on top row");
01338       nextPolygonCWT(startCurve, endCurve, isoPolygon, curveAdded, startPoint, checkPoint, isoLevel);
01339     }
01340   }
01341   else if(static_cast<unsigned int>(checkPoint.x()) == numPoints.x() - 1)
01342   {
01343     // right column -> go up or down
01344     if(fabs(points[static_cast<int>(checkPoint.y())][numPoints.x() - 1]) > fabs(isoLevel))
01345     {
01346       // go up -> counterclockwise direction
01347       //qDebug("searching up on right column");
01348       nextPolygonCCWR(startCurve, endCurve, isoPolygon, curveAdded, startPoint, checkPoint, isoLevel);
01349     }
01350     else
01351     {
01352       // go down -> clockwise
01353       //qDebug("searching down on right column");
01354       nextPolygonCWR(startCurve, endCurve, isoPolygon, curveAdded, startPoint, checkPoint, isoLevel);
01355     }
01356   }
01357   else if(static_cast<unsigned int>(checkPoint.y()) == numPoints.y() - 1)
01358   {
01359     /*{
01360       unsigned int x = static_cast<int>(checkPoint.x());
01361       unsigned int y = numPoints.y() - 1;
01362       //qDebug("bottom row, checking left point (%d,%d)=%f vs level %f",x,y,points[y][x],isoLevel); 
01363       //qDebug("surrounding points: x-1, x, x+1, x+2: %f, %f, %f, %f",points[y][x-1],points[y][x],points[y][x+1],points[y][x+2]);
01364     }*/
01365     // bottom row -> go left or right?
01366     if(fabs(points[numPoints.y() - 1][static_cast<int>(checkPoint.x())]) > fabs(isoLevel))
01367     {
01368       // go left -> clockwise direction
01369       //qDebug("searching left on bottom row");
01370       nextPolygonCWB(startCurve, endCurve, isoPolygon, curveAdded, startPoint, checkPoint, isoLevel);
01371     }
01372     else
01373     {
01374       // go right -> counterclockwise
01375       //qDebug("searching right on bottom row");
01376       nextPolygonCCWB(startCurve, endCurve, isoPolygon, curveAdded, startPoint, checkPoint, isoLevel);
01377     }
01378   }
01379   else if(static_cast<int>(checkPoint.x()) == 0)
01380   {
01381     // left column -> go up or down
01382     if(fabs(points[static_cast<int>(checkPoint.y())][0]) > fabs(isoLevel))
01383     {
01384       // go up -> clockwise direction
01385       //qDebug("searching up on left column");
01386       nextPolygonCWL(startCurve, endCurve, isoPolygon, curveAdded, startPoint, checkPoint, isoLevel);
01387     }
01388     else
01389     {
01390       // go down -> counterclockwise
01391       //qDebug("searching down on left column");
01392       nextPolygonCCWL(startCurve, endCurve, isoPolygon, curveAdded, startPoint, checkPoint, isoLevel);
01393     }
01394   }
01395 }
01396 
01398 void PlotMapBase::nextPolygonCCWT(const unsigned int startCurve, const unsigned int endCurve, vector<Point3D<double> >& isoPolygon, vector<bool>& curveAdded, const Point3D<double>& startPoint, const Point3D<double>& refPoint, const double isoLevel)
01400 {
01401   //qDebug("entering nextPolygonCCWT");
01402   unsigned int nearestCurve = endCurve;
01403   Point3D<double> nearestPoint;
01404   bool nearestStart = false;
01405   for(unsigned int curve = startCurve; curve < endCurve; curve++)
01406   {
01407     if(!curveAdded[curve - startCurve])
01408     {
01409       Point3D<double> firstPoint = isoCurves[curve]->operator[](0); 
01410       Point3D<double> lastPoint = isoCurves[curve]->operator[](isoCurves[curve]->size() - 1); 
01411       if(static_cast<int>(firstPoint.y()) == 0 && firstPoint.x() < refPoint.x())
01412       {
01413         // curve found -> check whether it's the nearest
01414         if(nearestCurve == endCurve || firstPoint.x() > nearestPoint.x())
01415         {
01416           // no previous curve specified or nearer than nearestCurve
01417           nearestCurve = curve;
01418           nearestPoint = firstPoint;
01419           nearestStart = true;
01420         }
01421       }
01422       else if(static_cast<int>(lastPoint.y()) == 0 && lastPoint.x() < refPoint.x())
01423       {
01424         if(nearestCurve == endCurve || lastPoint.x() > nearestPoint.x())
01425         {
01426           nearestCurve = curve;
01427           nearestPoint = lastPoint;
01428           nearestStart = false;
01429         }
01430       }
01431     }
01432   }
01433   // now the nearest curve and point are defined
01434   if(nearestCurve == endCurve)
01435   {
01436     // no curve found so check whether all curves have been assigned
01437     bool allVisited = true;
01438     for(unsigned int i = 0; i < endCurve - startCurve; i++)
01439     {
01440       if(!curveAdded[i])
01441       {
01442         allVisited = false;
01443         break;
01444       }
01445     }
01446     if(allVisited)
01447     {
01448       // only return if the starting point is on the same edge as the current end
01449       if(static_cast<int>(startPoint.y()) == 0)
01450       {
01451         isoPolygon.push_back(startPoint);
01452         return;
01453       }
01454     }
01455     // if not add the (0,0) corner point and search down along the left column 
01456     Point3D<double> zeroPoint(0.0, 0.0, 0.0);
01457     isoPolygon.push_back(zeroPoint);
01458     nextPolygonCCWL(startCurve, endCurve, isoPolygon, curveAdded, startPoint, zeroPoint, isoLevel);
01459   }
01460   else
01461   {
01462     // a new curve is found
01463     curveAdded[nearestCurve - startCurve] = true;
01464     isoPolygon.reserve(isoPolygon.size() + isoCurves[nearestCurve]->size());
01465     if(nearestStart)
01466     {
01467       // the new curve should be added from the start
01468       isoPolygon.insert(isoPolygon.end(),isoCurves[nearestCurve]->begin(), isoCurves[nearestCurve]->end());
01469     }
01470     else
01471     {
01472       // the new curve should be added from the end
01473       isoPolygon.insert(isoPolygon.end(),isoCurves[nearestCurve]->rbegin(), isoCurves[nearestCurve]->rend());
01474     }
01475     // continue this polygon
01476     continuePolygon(startCurve, endCurve, nearestCurve, isoPolygon, curveAdded, startPoint, !nearestStart, isoLevel);
01477   }
01478 }
01479 
01481 void PlotMapBase::nextPolygonCWT(const unsigned int startCurve, const unsigned int endCurve, vector<Point3D<double> >& isoPolygon, vector<bool>& curveAdded, const Point3D<double>& startPoint, const Point3D<double>& refPoint, const double isoLevel)
01483 {  
01484   //qDebug("entering nextPolygonCWT");
01485   unsigned int nearestCurve = endCurve;
01486   Point3D<double> nearestPoint;
01487   bool nearestStart = false;
01488   for(unsigned int curve = startCurve; curve < endCurve; curve++)
01489   {
01490     if(!curveAdded[curve - startCurve])
01491     {
01492       Point3D<double> firstPoint = isoCurves[curve]->operator[](0); 
01493       Point3D<double> lastPoint = isoCurves[curve]->operator[](isoCurves[curve]->size() - 1); 
01494       if(static_cast<int>(firstPoint.y()) == 0 && firstPoint.x() > refPoint.x())
01495       {
01496         // curve found -> check whether it's the nearest
01497         if(nearestCurve == endCurve || firstPoint.x() < nearestPoint.x())
01498         {
01499           // no previous curve specified or nearer than nearestCurve
01500           nearestCurve = curve;
01501           nearestPoint = firstPoint;
01502           nearestStart = true;
01503         }
01504       }
01505       else if(static_cast<int>(lastPoint.y()) == 0 && lastPoint.x() > refPoint.x())
01506       {
01507         if(nearestCurve == endCurve || lastPoint.x() < nearestPoint.x())
01508         {
01509           nearestCurve = curve;
01510           nearestPoint = lastPoint;
01511           nearestStart = false;
01512         }
01513       }
01514     }
01515   }
01516   // now the nearest curve and point are defined
01517   if(nearestCurve == endCurve)
01518   {
01519     // no curve found so check whether all curves have been assigned
01520     bool allVisited = true;
01521     for(unsigned int i = 0; i < endCurve - startCurve; i++)
01522     {
01523       if(!curveAdded[i])
01524       {
01525         allVisited = false;
01526         break;
01527       }
01528     }
01529     if(allVisited)
01530     {
01531       // only return if the starting point is on the same edge as the current end
01532       if(static_cast<int>(startPoint.y()) == 0)
01533       {
01534         isoPolygon.push_back(startPoint);
01535         return;
01536       }
01537     }
01538     // if not add the (xmax,0) corner point and search down along the right column 
01539     Point3D<double> cornerPoint(static_cast<double>(numPoints.x() - 1), 0.0, 0.0);
01540     isoPolygon.push_back(cornerPoint);
01541     nextPolygonCWR(startCurve, endCurve, isoPolygon, curveAdded, startPoint, cornerPoint, isoLevel);
01542   }
01543   else
01544   {
01545     // a new curve is found
01546     curveAdded[nearestCurve - startCurve] = true;
01547     isoPolygon.reserve(isoPolygon.size() + isoCurves[nearestCurve]->size());
01548     if(nearestStart)
01549     {
01550       // the new curve should be added from the start
01551       isoPolygon.insert(isoPolygon.end(),isoCurves[nearestCurve]->begin(), isoCurves[nearestCurve]->end());
01552     }
01553     else
01554     {
01555       // the new curve should be added from the end
01556       isoPolygon.insert(isoPolygon.end(),isoCurves[nearestCurve]->rbegin(), isoCurves[nearestCurve]->rend());
01557     }
01558     // continue this polygon
01559     continuePolygon(startCurve, endCurve, nearestCurve, isoPolygon, curveAdded, startPoint, !nearestStart, isoLevel);
01560   }
01561 }
01562 
01564 void PlotMapBase::nextPolygonCCWR(const unsigned int startCurve, const unsigned int endCurve, vector<Point3D<double> >& isoPolygon, vector<bool>& curveAdded, const Point3D<double>& startPoint, const Point3D<double>& refPoint, const double isoLevel)
01566 {  
01567   //qDebug("entering nextPolygonCCWR");
01568   unsigned int nearestCurve = endCurve;
01569   Point3D<double> nearestPoint;
01570   bool nearestStart = false;
01571   for(unsigned int curve = startCurve; curve < endCurve; curve++)
01572   {
01573     if(!curveAdded[curve - startCurve])
01574     {
01575       Point3D<double> firstPoint = isoCurves[curve]->operator[](0); 
01576       Point3D<double> lastPoint = isoCurves[curve]->operator[](isoCurves[curve]->size() - 1); 
01577       if(static_cast<unsigned int>(firstPoint.x()) == numPoints.x() - 1 && firstPoint.y() < refPoint.y())
01578       {
01579         // curve found -> check whether it's the nearest
01580         if(nearestCurve == endCurve || firstPoint.y() > nearestPoint.y())
01581         {
01582           // no previous curve specified or nearer than nearestCurve
01583           nearestCurve = curve;
01584           nearestPoint = firstPoint;
01585           nearestStart = true;
01586         }
01587       }
01588       else if(static_cast<unsigned int>(lastPoint.x()) == numPoints.x() - 1 && lastPoint.y() < refPoint.y())
01589       {
01590         if(nearestCurve == endCurve || lastPoint.y() > nearestPoint.y())
01591         {
01592           nearestCurve = curve;
01593           nearestPoint = lastPoint;
01594           nearestStart = false;
01595         }
01596       }
01597     }
01598   }
01599   // now the nearest curve and point are defined
01600   if(nearestCurve == endCurve)
01601   {
01602     //qDebug("nextPolygonCCWR: no curve found");
01603     // no curve found so check whether all curves have been assigned
01604     bool allVisited = true;
01605     for(unsigned int i = 0; i < endCurve - startCurve; i++)
01606     {
01607       if(!curveAdded[i])
01608       {
01609         allVisited = false;
01610         break;
01611       }
01612     }
01613     if(allVisited)
01614     {
01615       // only return if the starting point is on the same edge as the current end
01616       if(static_cast<unsigned int>(startPoint.x()) == numPoints.x() - 1)
01617       {
01618         isoPolygon.push_back(startPoint);
01619         return;
01620       }
01621     }
01622     // if not add the (xmax,0) corner point and search left along the top row
01623     //qDebug("nextPolygonCCWR: adding corner point and calling nextPolygonCCWT");
01624     Point3D<double> cornerPoint(static_cast<double>(numPoints.x() - 1), 0.0, 0.0);
01625     isoPolygon.push_back(cornerPoint);
01626     nextPolygonCCWT(startCurve, endCurve, isoPolygon, curveAdded, startPoint, cornerPoint, isoLevel);
01627   }
01628   else
01629   {
01630     //qDebug("nextPolygonCCWR: curve %d added",nearestCurve - startCurve);
01631     // a new curve is found
01632     curveAdded[nearestCurve - startCurve] = true;
01633     isoPolygon.reserve(isoPolygon.size() + isoCurves[nearestCurve]->size());
01634     if(nearestStart)
01635     {
01636       // the new curve should be added from the start
01637       isoPolygon.insert(isoPolygon.end(),isoCurves[nearestCurve]->begin(), isoCurves[nearestCurve]->end());
01638     }
01639     else
01640     {
01641       // the new curve should be added from the end
01642       isoPolygon.insert(isoPolygon.end(),isoCurves[nearestCurve]->rbegin(), isoCurves[nearestCurve]->rend());
01643     }
01644     // continue this polygon
01645     continuePolygon(startCurve, endCurve, nearestCurve, isoPolygon, curveAdded, startPoint, !nearestStart, isoLevel);
01646   }
01647 }
01648 
01650 void PlotMapBase::nextPolygonCWR(const unsigned int startCurve, const unsigned int endCurve, vector<Point3D<double> >& isoPolygon, vector<bool>& curveAdded, const Point3D<double>& startPoint, const Point3D<double>& refPoint, const double isoLevel)
01652 {  
01653   //qDebug("entering nextPolygonCWR");
01654   unsigned int nearestCurve = endCurve;
01655   Point3D<double> nearestPoint;
01656   bool nearestStart = false;
01657   for(unsigned int curve = startCurve; curve < endCurve; curve++)
01658   {
01659     if(!curveAdded[curve - startCurve])
01660     {
01661       Point3D<double> firstPoint = isoCurves[curve]->operator[](0); 
01662       Point3D<double> lastPoint = isoCurves[curve]->operator[](isoCurves[curve]->size() - 1); 
01663       if(static_cast<unsigned int>(firstPoint.x()) == numPoints.x() - 1 && firstPoint.y() > refPoint.y())
01664       {
01665         // curve found -> check whether it's the nearest
01666         if(nearestCurve == endCurve || firstPoint.y() < nearestPoint.y())
01667         {
01668           // no previous curve specified or nearer than nearestCurve
01669           nearestCurve = curve;
01670           nearestPoint = firstPoint;
01671           nearestStart = true;
01672         }
01673       }
01674       else if(static_cast<unsigned int>(lastPoint.x()) == numPoints.x() - 1 && lastPoint.y() > refPoint.y())
01675       {
01676         if(nearestCurve == endCurve || lastPoint.y() < nearestPoint.y())
01677         {
01678           nearestCurve = curve;
01679           nearestPoint = lastPoint;
01680           nearestStart = false;
01681         }
01682       }
01683     }
01684   }
01685   // now the nearest curve and point are defined
01686   if(nearestCurve == endCurve)
01687   {
01688     // no curve found so check whether all curves have been assigned
01689     bool allVisited = true;
01690     for(unsigned int i = 0; i < endCurve - startCurve; i++)
01691     {
01692       if(!curveAdded[i])
01693       {
01694         allVisited = false;
01695         break;
01696       }
01697     }
01698     if(allVisited)
01699     {
01700       // only return if the starting point is on the same edge as the current end
01701       if(static_cast<unsigned int>(startPoint.x()) == numPoints.x() - 1)
01702       {
01703         isoPolygon.push_back(startPoint);
01704         return;
01705       }
01706     }
01707     // if not add the (xmax,ymax) corner point and search left along the bottom row
01708     Point3D<double> cornerPoint(static_cast<double>(numPoints.x() - 1), static_cast<double>(numPoints.y() - 1), 0.0);
01709     isoPolygon.push_back(cornerPoint);
01710     nextPolygonCWB(startCurve, endCurve, isoPolygon, curveAdded, startPoint, cornerPoint, isoLevel);
01711   }
01712   else
01713   {
01714     // a new curve is found
01715     curveAdded[nearestCurve - startCurve] = true;
01716     isoPolygon.reserve(isoPolygon.size() + isoCurves[nearestCurve]->size());
01717     if(nearestStart)
01718     {
01719       // the new curve should be added from the start
01720       isoPolygon.insert(isoPolygon.end(),isoCurves[nearestCurve]->begin(), isoCurves[nearestCurve]->end());
01721     }
01722     else
01723     {
01724       // the new curve should be added from the end
01725       isoPolygon.insert(isoPolygon.end(),isoCurves[nearestCurve]->rbegin(), isoCurves[nearestCurve]->rend());
01726     }
01727     // continue this polygon
01728     continuePolygon(startCurve, endCurve, nearestCurve, isoPolygon, curveAdded, startPoint, !nearestStart, isoLevel);
01729   }
01730 }
01731 
01733 void PlotMapBase::nextPolygonCCWB(const unsigned int startCurve, const unsigned int endCurve, vector<Point3D<double> >& isoPolygon, vector<bool>& curveAdded, const Point3D<double>& startPoint, const Point3D<double>& refPoint, const double isoLevel)
01735 {  
01736   //qDebug("entering nextPolygonCCWB");
01737   unsigned int nearestCurve = endCurve;
01738   Point3D<double> nearestPoint;
01739   bool nearestStart = false;
01740   for(unsigned int curve = startCurve; curve < endCurve; curve++)
01741   {
01742     if(!curveAdded[curve - startCurve])
01743     {
01744       Point3D<double> firstPoint = isoCurves[curve]->operator[](0); 
01745       Point3D<double> lastPoint = isoCurves[curve]->operator[](isoCurves[curve]->size() - 1); 
01746       if(static_cast<unsigned int>(firstPoint.y()) == numPoints.y() - 1 && firstPoint.x() > refPoint.x())
01747       {
01748         // curve found -> check whether it's the nearest
01749         if(nearestCurve == endCurve || firstPoint.x() < nearestPoint.x())
01750         {
01751           // no previous curve specified or nearer than nearestCurve
01752           nearestCurve = curve;
01753           nearestPoint = firstPoint;
01754           nearestStart = true;
01755         }
01756       }
01757       else if(static_cast<unsigned int>(lastPoint.y()) == numPoints.y() - 1 && lastPoint.x() > refPoint.x())
01758       {
01759         if(nearestCurve == endCurve || lastPoint.x() > nearestPoint.x())
01760         {
01761           nearestCurve = curve;
01762           nearestPoint = lastPoint;
01763           nearestStart = false;
01764         }
01765       }
01766     }
01767   }
01768   // now the nearest curve and point are defined
01769   if(nearestCurve == endCurve)
01770   {
01771     // no curve found so check whether all curves have been assigned
01772     bool allVisited = true;
01773     for(unsigned int i = 0; i < endCurve - startCurve; i++)
01774     {
01775       if(!curveAdded[i])
01776       {
01777         allVisited = false;
01778         break;
01779       }
01780     }
01781     if(allVisited)
01782     {
01783       // only return if the starting point is on the same edge as the current end
01784       if(static_cast<unsigned int>(startPoint.y()) == numPoints.y() - 1)
01785       {
01786         isoPolygon.push_back(startPoint);
01787         return;
01788       }
01789     }
01790     // if not add the (xmax,ymax) corner point and search up along the right column 
01791     Point3D<double> zeroPoint(static_cast<double>(numPoints.x() - 1), static_cast<double>(numPoints.y() - 1), 0.0);
01792     isoPolygon.push_back(zeroPoint);
01793     nextPolygonCCWR(startCurve, endCurve, isoPolygon, curveAdded, startPoint, zeroPoint, isoLevel);
01794   }
01795   else
01796   {
01797     // a new curve is found
01798     curveAdded[nearestCurve - startCurve] = true;
01799     isoPolygon.reserve(isoPolygon.size() + isoCurves[nearestCurve]->size());
01800     if(nearestStart)
01801     {
01802       // the new curve should be added from the start
01803       isoPolygon.insert(isoPolygon.end(),isoCurves[nearestCurve]->begin(), isoCurves[nearestCurve]->end());
01804     }
01805     else
01806     {
01807       // the new curve should be added from the end
01808       isoPolygon.insert(isoPolygon.end(),isoCurves[nearestCurve]->rbegin(), isoCurves[nearestCurve]->rend());
01809     }
01810     // continue this polygon
01811     continuePolygon(startCurve, endCurve, nearestCurve, isoPolygon, curveAdded, startPoint, !nearestStart, isoLevel);
01812   }
01813 }
01814 
01816 void PlotMapBase::nextPolygonCWB(const unsigned int startCurve, const unsigned int endCurve, vector<Point3D<double> >& isoPolygon, vector<bool>& curveAdded, const Point3D<double>& startPoint, const Point3D<double>& refPoint, const double isoLevel)
01818 {  
01819   //qDebug("entering nextPolygonCWB");
01820   unsigned int nearestCurve = endCurve;
01821   Point3D<double> nearestPoint;
01822   bool nearestStart = false;
01823   for(unsigned int curve = startCurve; curve < endCurve; curve++)
01824   {
01825     if(!curveAdded[curve - startCurve])
01826     {
01827       Point3D<double> firstPoint = isoCurves[curve]->operator[](0); 
01828       Point3D<double> lastPoint = isoCurves[curve]->operator[](isoCurves[curve]->size() - 1); 
01829       if(static_cast<unsigned int>(firstPoint.y()) == numPoints.y() - 1 && firstPoint.x() < refPoint.x())
01830       {
01831         // curve found -> check whether it's the nearest
01832         if(nearestCurve == endCurve || firstPoint.x() > nearestPoint.x())
01833         {
01834           // no previous curve specified or nearer than nearestCurve
01835           nearestCurve = curve;
01836           nearestPoint = firstPoint;
01837           nearestStart = true;
01838         }
01839       }
01840       else if(static_cast<unsigned int>(lastPoint.y()) == numPoints.y() - 1 && lastPoint.x() < refPoint.x())
01841       {
01842         if(nearestCurve == endCurve || lastPoint.x() > nearestPoint.x())
01843         {
01844           nearestCurve = curve;
01845           nearestPoint = lastPoint;
01846           nearestStart = false;
01847         }
01848       }
01849     }
01850   }
01851   // now the nearest curve and point are defined
01852   if(nearestCurve == endCurve)
01853   {
01854     // no curve found so check whether all curves have been assigned
01855     bool allVisited = true;
01856     for(unsigned int i = 0; i < endCurve - startCurve; i++)
01857     {
01858       if(!curveAdded[i])
01859       {
01860         allVisited = false;
01861         break;
01862       }
01863     }
01864     if(allVisited)
01865     {
01866       // only return if the starting point is on the same edge as the current end
01867       if(static_cast<unsigned int>(startPoint.y()) == numPoints.y() - 1)
01868       {
01869         isoPolygon.push_back(startPoint);
01870         return;
01871       }
01872     }
01873     // if not add the (0,ymax) corner point and search up along the left column 
01874     Point3D<double> cornerPoint(0.0, static_cast<double>(numPoints.y() - 1), 0.0);
01875     isoPolygon.push_back(cornerPoint);
01876     nextPolygonCWL(startCurve, endCurve, isoPolygon, curveAdded, startPoint, cornerPoint, isoLevel);
01877   }
01878   else
01879   {
01880     // a new curve is found
01881     curveAdded[nearestCurve - startCurve] = true;
01882     isoPolygon.reserve(isoPolygon.size() + isoCurves[nearestCurve]->size());
01883     if(nearestStart)
01884     {
01885       // the new curve should be added from the start
01886       isoPolygon.insert(isoPolygon.end(),isoCurves[nearestCurve]->begin(), isoCurves[nearestCurve]->end());
01887     }
01888     else
01889     {
01890       // the new curve should be added from the end
01891       isoPolygon.insert(isoPolygon.end(),isoCurves[nearestCurve]->rbegin(), isoCurves[nearestCurve]->rend());
01892     }
01893     // continue this polygon
01894     continuePolygon(startCurve, endCurve, nearestCurve, isoPolygon, curveAdded, startPoint, !nearestStart, isoLevel);
01895   }
01896 }
01897 
01899 void PlotMapBase::nextPolygonCCWL(const unsigned int startCurve, const unsigned int endCurve, vector<Point3D<double> >& isoPolygon, vector<bool>& curveAdded, const Point3D<double>& startPoint, const Point3D<double>& refPoint, const double isoLevel)
01901 {  
01902   //qDebug("entering nextPolygonCCWL");
01903   unsigned int nearestCurve = endCurve;
01904   Point3D<double> nearestPoint;
01905   bool nearestStart = false;
01906   for(unsigned int curve = startCurve; curve < endCurve; curve++)
01907   {
01908     if(!curveAdded[curve - startCurve])
01909     {
01910       Point3D<double> firstPoint = isoCurves[curve]->operator[](0); 
01911       Point3D<double> lastPoint = isoCurves[curve]->operator[](isoCurves[curve]->size() - 1); 
01912       if(static_cast<int>(firstPoint.x()) == 0 && firstPoint.y() > refPoint.y())
01913       {
01914         // curve found -> check whether it's the nearest
01915         if(nearestCurve == endCurve || firstPoint.y() < nearestPoint.y())
01916         {
01917           // no previous curve specified or nearer than nearestCurve
01918           nearestCurve = curve;
01919           nearestPoint = firstPoint;
01920           nearestStart = true;
01921         }
01922       }
01923       else if(static_cast<int>(lastPoint.x()) == 0 && lastPoint.y() > refPoint.y())
01924       {
01925         if(nearestCurve == endCurve || lastPoint.y() < nearestPoint.y())
01926         {
01927           nearestCurve = curve;
01928           nearestPoint = lastPoint;
01929           nearestStart = false;
01930         }
01931       }
01932     }
01933   }
01934   // now the nearest curve and point are defined
01935   if(nearestCurve == endCurve)
01936   {
01937     // no curve found so check whether all curves have been assigned
01938     bool allVisited = true;
01939     for(unsigned int i = 0; i < endCurve - startCurve; i++)
01940     {
01941       if(!curveAdded[i])
01942       {
01943         allVisited = false;
01944         break;
01945       }
01946     }
01947     if(allVisited)
01948     {
01949       // only return if the starting point is on the same edge as the current end
01950       if(static_cast<int>(startPoint.x()) == 0)
01951       {
01952         isoPolygon.push_back(startPoint);
01953         return;
01954       }
01955     }
01956     // if not add the (0,ymax) corner point and search right along the bottom row
01957     Point3D<double> cornerPoint(0.0, static_cast<double>(numPoints.y() - 1), 0.0);
01958     isoPolygon.push_back(cornerPoint);
01959     nextPolygonCCWB(startCurve, endCurve, isoPolygon, curveAdded, startPoint, cornerPoint, isoLevel);
01960   }
01961   else
01962   {
01963     //qDebug("nextPolygonCCWL: found a new curve",nearestCurve);
01964     //qDebug("curve's first point = (%f,%f), last point = (%f,%f)",isoCurves[nearestCurve]->operator[](0).x(),isoCurves[nearestCurve]->operator[](0).y(),
01965     //  isoCurves[nearestCurve]->operator[](isoCurves[nearestCurve]->size() - 1).x(),isoCurves[nearestCurve]->operator[](isoCurves[nearestCurve]->size() - 1).y());
01966     // a new curve is found
01967     curveAdded[nearestCurve - startCurve] = true;
01968     isoPolygon.reserve(isoPolygon.size() + isoCurves[nearestCurve]->size());
01969     if(nearestStart)
01970     {
01971       //qDebug("adding curve from start to end");
01972       // the new curve should be added from the start
01973       isoPolygon.insert(isoPolygon.end(),isoCurves[nearestCurve]->begin(), isoCurves[nearestCurve]->end());
01974     }
01975     else
01976     {
01977       //qDebug("adding curve from end to start");
01978       // the new curve should be added from the end
01979       isoPolygon.insert(isoPolygon.end(),isoCurves[nearestCurve]->rbegin(), isoCurves[nearestCurve]->rend());
01980     }
01981     // continue this polygon
01982     continuePolygon(startCurve, endCurve, nearestCurve, isoPolygon, curveAdded, startPoint, !nearestStart, isoLevel);
01983   }
01984 }
01985 
01987 void PlotMapBase::nextPolygonCWL(const unsigned int startCurve, const unsigned int endCurve, vector<Point3D<double> >& isoPolygon, vector<bool>& curveAdded, const Point3D<double>& startPoint, const Point3D<double>& refPoint, const double isoLevel)
01989 {  
01990   //qDebug("entering nextPolygonCWL");
01991   unsigned int nearestCurve = endCurve;
01992   Point3D<double> nearestPoint;
01993   bool nearestStart = false;
01994   for(unsigned int curve = startCurve; curve < endCurve; curve++)
01995   {
01996     if(!curveAdded[curve - startCurve])
01997     {
01998       Point3D<double> firstPoint = isoCurves[curve]->operator[](0); 
01999       Point3D<double> lastPoint = isoCurves[curve]->operator[](isoCurves[curve]->size() - 1); 
02000       if(static_cast<int>(firstPoint.x()) == 0 && firstPoint.y() < refPoint.y())
02001       {
02002         // curve found -> check whether it's the nearest
02003         if(nearestCurve == endCurve || firstPoint.y() > nearestPoint.y())
02004         {
02005           // no previous curve specified or nearer than nearestCurve
02006           nearestCurve = curve;
02007           nearestPoint = firstPoint;
02008           nearestStart = true;
02009         }
02010       }
02011       else if(static_cast<int>(lastPoint.x()) == 0 && lastPoint.y() < refPoint.y())
02012       {
02013         if(nearestCurve == endCurve || lastPoint.y() > nearestPoint.y())
02014         {
02015           nearestCurve = curve;
02016           nearestPoint = lastPoint;
02017           nearestStart = false;
02018         }
02019       }
02020     }
02021   }
02022   // now the nearest curve and point are defined
02023   if(nearestCurve == endCurve)
02024   {
02025     // no curve found so check whether all curves have been assigned
02026     bool allVisited = true;
02027     for(unsigned int i = 0; i < endCurve - startCurve; i++)
02028     {
02029       if(!curveAdded[i])
02030       {
02031         allVisited = false;
02032         break;
02033       }
02034     }
02035     if(allVisited)
02036     {
02037       // only return if the starting point is on the same edge as the current end
02038       if(static_cast<int>(startPoint.x()) == 0)
02039       {
02040         isoPolygon.push_back(startPoint);
02041         return;
02042       }
02043     }
02044     // if not add the (0,0) corner point and search left along the top row
02045     Point3D<double> cornerPoint(0.0, 0.0, 0.0);
02046     isoPolygon.push_back(cornerPoint);
02047     nextPolygonCWT(startCurve, endCurve, isoPolygon, curveAdded, startPoint, cornerPoint, isoLevel);
02048   }
02049   else
02050   {
02051     // a new curve is found
02052     curveAdded[nearestCurve - startCurve] = true;
02053     isoPolygon.reserve(isoPolygon.size() + isoCurves[nearestCurve]->size());
02054     if(nearestStart)
02055     {
02056       // the new curve should be added from the start
02057       isoPolygon.insert(isoPolygon.end(),isoCurves[nearestCurve]->begin(), isoCurves[nearestCurve]->end());
02058     }
02059     else
02060     {
02061       // the new curve should be added from the end
02062       isoPolygon.insert(isoPolygon.end(),isoCurves[nearestCurve]->rbegin(), isoCurves[nearestCurve]->rend());
02063     }
02064     // continue this polygon
02065     continuePolygon(startCurve, endCurve, nearestCurve, isoPolygon, curveAdded, startPoint, !nearestStart, isoLevel);
02066   }
02067 }
02068 
02070 QRect PlotMapBase::labelRect() const
02074 {
02075   // uncorrected rectangle
02076   QRect rect(plotLabel->geometry().topLeft() + plotLabel->contentsRect().topLeft(), plotLabel->contentsRect().size());
02077   
02078   // aspect ratio correction
02079   const double aspectRatio = static_cast<double>(numPoints.x()) / numPoints.y();
02080   if(aspectRatio > static_cast<double>(rect.width()) / rect.height())
02081     rect.setHeight(static_cast<int>(rect.width() / aspectRatio));
02082   else
02083     rect.setWidth(static_cast<int>(rect.height() * aspectRatio));
02084 
02085   // the result
02086   return rect;
02087 }
02088 
02090 template<typename T> void PlotMapBase::limitRange(const T& min, T& value, const T& max)
02092 {
02093   if(min < max)
02094   {
02095     if(value < min)
02096       value = min;
02097     else if(value > max)
02098       value = max;
02099   }
02100   else
02101   { // when wrong input is given, still do correct limiting
02102     if(value < max)
02103       value = max;
02104     else if(value > min)
02105       value = min;
02106   }
02107 }
02108 
02112 const double PlotMapBase::AUTOANG = 1.0/1.889726342;
02113 

Generated on Fri May 19 14:31:55 2006 for Brabosphere by  doxygen 1.4.6-NO