00001
00002
00003
00004
00005
00006
00007 #include "DocumentModelSegments.h"
00008 #include "EngaugeAssert.h"
00009 #include <iostream>
00010 #include "Logger.h"
00011 #include "mmsubs.h"
00012 #include <qdebug.h>
00013 #include <QFile>
00014 #include <QGraphicsScene>
00015 #include <qmath.h>
00016 #include <QTextStream>
00017 #include "QtToString.h"
00018 #include "Segment.h"
00019 #include "SegmentLine.h"
00020
00021 Segment::Segment(QGraphicsScene &scene,
00022 int y,
00023 bool isGnuplot) :
00024 m_scene (scene),
00025 m_yLast (y),
00026 m_length (0),
00027 m_isGnuplot (isGnuplot)
00028 {
00029 LOG4CPP_INFO_S ((*mainCat)) << "Segment::Segment"
00030 << " address=0x" << hex << (quintptr) this;
00031 }
00032
00033 Segment::~Segment()
00034 {
00035 LOG4CPP_INFO_S ((*mainCat)) << "Segment::~Segment"
00036 << " address=0x" << hex << (quintptr) this;
00037
00038 QList<SegmentLine*>::iterator itr;
00039 for (itr = m_lines.begin(); itr != m_lines.end(); itr++) {
00040
00041 SegmentLine *segmentLine = *itr;
00042 m_scene.removeItem (segmentLine);
00043 }
00044 }
00045
00046 void Segment::appendColumn(int x,
00047 int y,
00048 const DocumentModelSegments &modelSegments)
00049 {
00050 int xOld = x - 1;
00051 int yOld = m_yLast;
00052 int xNew = x;
00053 int yNew = y;
00054
00055 LOG4CPP_DEBUG_S ((*mainCat)) << "Segment::appendColumn"
00056 << " segment=0x" << std::hex << (quintptr) this << std::dec
00057 << " adding ("
00058 << xOld << "," << yOld << ") to ("
00059 << xNew << "," << yNew << ")";
00060
00061 SegmentLine* line = new SegmentLine(m_scene,
00062 modelSegments,
00063 this);
00064 ENGAUGE_CHECK_PTR(line);
00065 line->setLine(QLineF (xOld,
00066 yOld,
00067 xNew,
00068 yNew));
00069
00070
00071
00072 m_lines.append(line);
00073
00074
00075 m_length += qSqrt((1.0) * (1.0) + (y - m_yLast) * (y - m_yLast));
00076
00077 m_yLast = y;
00078 }
00079
00080 void Segment::createAcceptablePoint(bool *pFirst,
00081 QList<QPoint> *pList,
00082 double *xPrev,
00083 double *yPrev,
00084 double x,
00085 double y)
00086 {
00087 int iOld = (int) (*xPrev + 0.5);
00088 int jOld = (int) (*yPrev + 0.5);
00089 int i = (int) (x + 0.5);
00090 int j = (int) (y + 0.5);
00091
00092 if (*pFirst || (iOld != i) || (jOld != j)) {
00093 *xPrev = x;
00094 *yPrev = y;
00095
00096 ENGAUGE_CHECK_PTR(pList);
00097 pList->append(QPoint(i, j));
00098 }
00099
00100 *pFirst = false;
00101 }
00102
00103 void Segment::dumpToGnuplot (QTextStream &strDump,
00104 int xInt,
00105 int yInt,
00106 const SegmentLine *lineOld,
00107 const SegmentLine *lineNew) const
00108 {
00109
00110 if (mainCat->getPriority() == log4cpp::Priority::DEBUG) {
00111
00112
00113
00114 QString label = QString ("Old: (%1,%2) to (%3,%4), New: (%5,%6) to (%7,%8)")
00115 .arg (lineOld->line().x1())
00116 .arg (lineOld->line().y1())
00117 .arg (lineOld->line().x2())
00118 .arg (lineOld->line().y2())
00119 .arg (lineNew->line().x1())
00120 .arg (lineNew->line().y1())
00121 .arg (lineNew->line().x2())
00122 .arg (lineNew->line().y2());
00123
00124 strDump << "unset label\n";
00125 strDump << "set label \"" << label << "\" at graph 0, graph 0.02\n";
00126 strDump << "set grid xtics\n";
00127 strDump << "set grid ytics\n";
00128
00129
00130 int rows = 0, cols = 0;
00131 QList<SegmentLine*>::const_iterator itr;
00132 for (itr = m_lines.begin(); itr != m_lines.end(); itr++) {
00133
00134 SegmentLine *line = *itr;
00135 ENGAUGE_CHECK_PTR (line);
00136
00137 int x1 = line->line().x1();
00138 int y1 = line->line().y1();
00139 int x2 = line->line().x2();
00140 int y2 = line->line().y2();
00141
00142 rows = qMax (rows, y1 + 1);
00143 rows = qMax (rows, y2 + 1);
00144 cols = qMax (cols, x1 + 1);
00145 cols = qMax (cols, x2 + 1);
00146 }
00147
00148
00149
00150 int halfWidthX = 1.5 * qMax (qAbs (lineOld->line().dx()),
00151 qAbs (lineNew->line().dx()));
00152 int halfWidthY = 1.5 * qMax (qAbs (lineOld->line().dy()),
00153 qAbs (lineNew->line().dy()));
00154
00155
00156 strDump << "set xrange [" << (xInt - halfWidthX - 1) << ":" << (xInt + halfWidthX + 1) << "]\n";
00157 strDump << "set yrange [" << (yInt - halfWidthY - 1) << ":" << (yInt + halfWidthY + 1) << "]\n";
00158
00159
00160
00161
00162 strDump << "plot \\\n"
00163 << "\"-\" title \"\" with lines, \\\n"
00164 << "\"-\" title \"\" with lines, \\\n"
00165 << "\"-\" title \"Replacement\" with lines, \\\n"
00166 << "\"-\" title \"Segment pixels Even\" with linespoints, \\\n"
00167 << "\"-\" title \"Segment pixels Odd\" with linespoints\n"
00168 << xInt << " " << (yInt - halfWidthY) << "\n"
00169 << xInt << " " << (yInt + halfWidthY) << "\n"
00170 << "end\n"
00171 << (xInt - halfWidthX) << " " << yInt << "\n"
00172 << (xInt + halfWidthY) << " " << yInt << "\n"
00173 << "end\n"
00174 << lineOld->line().x1() << " " << lineOld->line().y1() << "\n"
00175 << lineNew->line().x2() << " " << lineNew->line().y2() << "\n"
00176 << "end\n";
00177
00178
00179 QString even, odd;
00180 QTextStream strEven (&even), strOdd (&odd);
00181 for (int index = 0; index < m_lines.count(); index++) {
00182
00183 SegmentLine *line = m_lines.at (index);
00184 int x1 = line->line().x1();
00185 int y1 = line->line().y1();
00186 int x2 = line->line().x2();
00187 int y2 = line->line().y2();
00188
00189 if (index % 2 == 0) {
00190 strEven << x1 << " " << y1 << "\n";
00191 strEven << x2 << " " << y2 << "\n";
00192 strEven << "\n";
00193 } else {
00194 strOdd << x1 << " " << y1 << "\n";
00195 strOdd << x2 << " " << y2 << "\n";
00196 strOdd << "\n";
00197 }
00198 }
00199
00200 strDump << even << "\n";
00201 strDump << "end\n";
00202 strDump << odd << "\n";
00203 strDump << "end\n";
00204 strDump << "pause -1 \"Hit Enter to continue\"\n";
00205 strDump << flush;
00206 }
00207 }
00208
00209 QList<QPoint> Segment::fillPoints(const DocumentModelSegments &modelSegments)
00210 {
00211 LOG4CPP_INFO_S ((*mainCat)) << "Segment::fillPoints";
00212
00213 if (modelSegments.fillCorners()) {
00214 return fillPointsFillingCorners(modelSegments);
00215 } else {
00216 return fillPointsWithoutFillingCorners(modelSegments);
00217 }
00218 }
00219
00220 QList<QPoint> Segment::fillPointsFillingCorners(const DocumentModelSegments &modelSegments)
00221 {
00222 QList<QPoint> list;
00223
00224 if (m_lines.count() > 0) {
00225
00226 double xLast = m_lines.first()->line().x1();
00227 double yLast = m_lines.first()->line().y1();
00228 double x, xNext;
00229 double y, yNext;
00230 double distanceCompleted = 0.0;
00231
00232
00233 bool firstPoint = true;
00234 double xPrev = m_lines.first()->line().x1();
00235 double yPrev = m_lines.first()->line().y1();
00236
00237 QList<SegmentLine*>::iterator itr;
00238 for (itr = m_lines.begin(); itr != m_lines.end(); itr++) {
00239
00240 SegmentLine *line = *itr;
00241
00242 ENGAUGE_CHECK_PTR(line);
00243 xNext = (double) line->line().x2();
00244 yNext = (double) line->line().y2();
00245
00246 double xStart = (double) line->line().x1();
00247 double yStart = (double) line->line().y1();
00248 if (isCorner (yPrev, yStart, yNext)) {
00249
00250
00251 createAcceptablePoint(&firstPoint, &list, &xPrev, &yPrev, xStart, yStart);
00252 distanceCompleted = 0.0;
00253 }
00254
00255
00256 double segmentLength = sqrt((xNext - xLast) * (xNext - xLast) + (yNext - yLast) * (yNext - yLast));
00257 if (segmentLength > 0.0) {
00258
00259
00260
00261 while (distanceCompleted <= segmentLength) {
00262
00263 double s = distanceCompleted / segmentLength;
00264
00265
00266 x = (1.0 - s) * xLast + s * xNext;
00267 y = (1.0 - s) * yLast + s * yNext;
00268
00269 createAcceptablePoint(&firstPoint, &list, &xPrev, &yPrev, x, y);
00270
00271 distanceCompleted += modelSegments.pointSeparation();
00272 }
00273
00274 distanceCompleted -= segmentLength;
00275 }
00276
00277 xLast = xNext;
00278 yLast = yNext;
00279 }
00280 }
00281
00282 return list;
00283 }
00284
00285 QPointF Segment::firstPoint () const
00286 {
00287 LOG4CPP_INFO_S ((*mainCat)) << "Segment::firstPoint"
00288 << " lineCount=" << m_lines.count();
00289
00290
00291 ENGAUGE_ASSERT (m_lines.count () > 0);
00292
00293 SegmentLine *line = m_lines.first();
00294 QPointF pos = line->line().p1();
00295
00296 LOG4CPP_INFO_S ((*mainCat)) << "Segment::firstPoint"
00297 << " pos=" << QPointFToString (pos).toLatin1().data();
00298
00299 return pos;
00300 }
00301
00302 void Segment::forwardMousePress()
00303 {
00304 LOG4CPP_INFO_S ((*mainCat)) << "Segment::forwardMousePress"
00305 << " segmentLines=" << m_lines.count();
00306
00307 emit signalMouseClickOnSegment (firstPoint ());
00308 }
00309
00310 bool Segment::isCorner (double yLast,
00311 double yPrev,
00312 double yNext) const
00313 {
00314
00315 double deltaYBefore = yPrev - yLast;
00316 double deltaYAfter = yNext - yPrev;
00317 bool upThenAcrossOrDown = (deltaYBefore > 0) && (deltaYAfter <= 0);
00318 bool downThenAcrossOrUp = (deltaYBefore < 0) && (deltaYAfter >= 0);
00319
00320 return upThenAcrossOrDown || downThenAcrossOrUp;
00321 }
00322
00323 QList<QPoint> Segment::fillPointsWithoutFillingCorners(const DocumentModelSegments &modelSegments)
00324 {
00325 QList<QPoint> list;
00326
00327 if (m_lines.count() > 0) {
00328
00329 double xLast = m_lines.first()->line().x1();
00330 double yLast = m_lines.first()->line().y1();
00331 double x, xNext;
00332 double y, yNext;
00333 double distanceCompleted = 0.0;
00334
00335
00336 bool firstPoint = true;
00337 double xPrev = m_lines.first()->line().x1();
00338 double yPrev = m_lines.first()->line().y1();
00339
00340 QList<SegmentLine*>::iterator itr;
00341 for (itr = m_lines.begin(); itr != m_lines.end(); itr++) {
00342
00343 SegmentLine *line = *itr;
00344
00345 ENGAUGE_CHECK_PTR(line);
00346 xNext = (double) line->line().x2();
00347 yNext = (double) line->line().y2();
00348
00349
00350 double segmentLength = sqrt((xNext - xLast) * (xNext - xLast) + (yNext - yLast) * (yNext - yLast));
00351 if (segmentLength > 0.0) {
00352
00353
00354
00355 while (distanceCompleted <= segmentLength) {
00356
00357 double s = distanceCompleted / segmentLength;
00358
00359
00360 x = (1.0 - s) * xLast + s * xNext;
00361 y = (1.0 - s) * yLast + s * yNext;
00362
00363 createAcceptablePoint(&firstPoint, &list, &xPrev, &yPrev, x, y);
00364
00365 distanceCompleted += modelSegments.pointSeparation();
00366 }
00367
00368 distanceCompleted -= segmentLength;
00369 }
00370
00371 xLast = xNext;
00372 yLast = yNext;
00373 }
00374 }
00375
00376 return list;
00377 }
00378
00379 double Segment::length() const
00380 {
00381 return m_length;
00382 }
00383
00384 int Segment::lineCount() const
00385 {
00386 return m_lines.count();
00387 }
00388
00389 bool Segment::pointIsCloseToLine(double xLeft,
00390 double yLeft,
00391 double xInt,
00392 double yInt,
00393 double xRight,
00394 double yRight)
00395 {
00396 double xProj, yProj, projectedDistanceOutsideLine, distanceToLine;
00397 projectPointOntoLine(xInt, yInt, xLeft, yLeft, xRight, yRight, &xProj, &yProj, &projectedDistanceOutsideLine, &distanceToLine);
00398
00399 return (
00400 (xInt - xProj) * (xInt - xProj) +
00401 (yInt - yProj) * (yInt - yProj) < 0.5 * 0.5);
00402 }
00403
00404 bool Segment::pointsAreCloseToLine(double xLeft,
00405 double yLeft,
00406 QList<QPoint> removedPoints,
00407 double xRight,
00408 double yRight)
00409 {
00410 QList<QPoint>::iterator itr;
00411 for (itr = removedPoints.begin(); itr != removedPoints.end(); ++itr) {
00412 if (!pointIsCloseToLine(xLeft, yLeft, (double) (*itr).x(), (double) (*itr).y(), xRight, yRight)) {
00413 return false;
00414 }
00415 }
00416
00417 return true;
00418 }
00419
00420 void Segment::removeUnneededLines (int *foldedLines)
00421 {
00422 LOG4CPP_INFO_S ((*mainCat)) << "Segment::removeUnneededLines";
00423
00424 QFile *fileDump = 0;
00425 QTextStream *strDump = 0;
00426 if (m_isGnuplot) {
00427
00428 QString filename ("segment.gnuplot");
00429
00430 std::cout << "Writing gnuplot file: " << filename.toLatin1().data() << "\n";
00431
00432 fileDump = new QFile (filename);
00433 fileDump->open (QIODevice::WriteOnly | QIODevice::Text);
00434 strDump = new QTextStream (fileDump);
00435
00436 }
00437
00438
00439
00440
00441
00442 SegmentLine *linePrevious = 0;
00443 QList<SegmentLine*>::iterator itr, itrPrevious;
00444 QList<QPoint> removedPoints;
00445 for (itr = m_lines.begin(); itr != m_lines.end(); itr++) {
00446
00447 SegmentLine *line = *itr;
00448 ENGAUGE_CHECK_PTR(line);
00449
00450 if (linePrevious != 0) {
00451
00452 double xLeft = linePrevious->line().x1();
00453 double yLeft = linePrevious->line().y1();
00454 double xInt = linePrevious->line().x2();
00455 double yInt = linePrevious->line().y2();
00456
00457
00458
00459 if (linePrevious->line().p2() == line->line().p1()) {
00460
00461 double xRight = line->line().x2();
00462 double yRight = line->line().y2();
00463
00464 if (pointIsCloseToLine(xLeft, yLeft, xInt, yInt, xRight, yRight) &&
00465 pointsAreCloseToLine(xLeft, yLeft, removedPoints, xRight, yRight)) {
00466
00467 if (m_isGnuplot) {
00468
00469
00470 dumpToGnuplot (*strDump,
00471 xInt,
00472 yInt,
00473 linePrevious,
00474 line);
00475 }
00476
00477
00478 ++(*foldedLines);
00479
00480 LOG4CPP_DEBUG_S ((*mainCat)) << "Segment::removeUnneededLines"
00481 << " segment=0x" << std::hex << (quintptr) this << std::dec
00482 << " removing ("
00483 << linePrevious->line().x1() << "," << linePrevious->line().y1() << ") to ("
00484 << linePrevious->line().x2() << "," << linePrevious->line().y2() << ") "
00485 << " and modifying ("
00486 << line->line().x1() << "," << line->line().y1() << ") to ("
00487 << line->line().x2() << "," << line->line().y2() << ") into ("
00488 << xLeft << "," << yLeft << ") to ("
00489 << xRight << "," << yRight << ")";
00490
00491 removedPoints.append(QPoint((int) xInt, (int) yInt));
00492 m_lines.erase (itrPrevious);
00493 delete linePrevious;
00494
00495
00496 line->setLine (xLeft, yLeft, xRight, yRight);
00497
00498 } else {
00499
00500
00501 removedPoints.clear();
00502 }
00503 }
00504 }
00505
00506 linePrevious = line;
00507 itrPrevious = itr;
00508
00509
00510 if (itr == m_lines.end()) {
00511 break;
00512 }
00513 }
00514
00515 if (strDump != 0) {
00516
00517
00518 *strDump << "set terminal x11 persist\n";
00519 fileDump->close ();
00520 delete strDump;
00521 delete fileDump;
00522
00523 }
00524 }
00525
00526 void Segment::slotHover (bool hover)
00527 {
00528 LOG4CPP_INFO_S ((*mainCat)) << "Segment::slotHover";
00529
00530 QList<SegmentLine*>::iterator itr, itrPrevious;
00531 for (itr = m_lines.begin(); itr != m_lines.end(); itr++) {
00532
00533 SegmentLine *line = *itr;
00534 line->setHover(hover);
00535 }
00536 }
00537
00538 void Segment::updateModelSegment(const DocumentModelSegments &modelSegments)
00539 {
00540 LOG4CPP_INFO_S ((*mainCat)) << "Segment::updateModelSegment";
00541
00542 QList<SegmentLine*>::iterator itr;
00543 for (itr = m_lines.begin(); itr != m_lines.end(); itr++) {
00544
00545 SegmentLine *line = *itr;
00546 line->updateModelSegment (modelSegments);
00547 }
00548 }