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