00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include <algorithm>
00043 #include <cmath>
00044 #include <cstdlib>
00045
00046 #include <qgarlib/AbstractGenPointChain.H>
00047 #include <qgarlib/image.H>
00048 #include <qgarlib/math.H>
00049 #include <qgarlib/primitives.H>
00050 #include <qgarlib/WDSegmentList.H>
00051
00052
00053
00054 namespace qgar
00055 {
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065 static const int WALLDANIELSSONSEGMENTLIST_MAX_DIR_CHANGE = 1;
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087 WDSegment::WDSegment()
00088
00089 : _sqrLength(0),
00090 _approxFactor(0)
00091
00092 {
00093
00094 }
00095
00096
00097
00098
00099 WDSegment::WDSegment(GenPoint<int>& orig,
00100 int deltaX,
00101 int deltaY,
00102 QGEdirection d)
00103
00104 : Segment(orig, orig),
00105 _sqrLength(deltaX * deltaX + deltaY * deltaY),
00106 _approxFactor(0),
00107 _direction(d)
00108
00109 {
00110 _target.translate(deltaX, deltaY);
00111 }
00112
00113
00114
00115
00116 WDSegment::WDSegment(const WDSegment& aSeg)
00117 {
00118 _source = aSeg._source;
00119 _target = aSeg._target;
00120 _sqrLength = aSeg._sqrLength;
00121 _approxFactor = aSeg._approxFactor;
00122 _direction = aSeg._direction;
00123 }
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133 void
00134 WDSegment::set(const WDSegment& aSeg)
00135 {
00136 _source = aSeg._source;
00137 _target = aSeg._target;
00138 _sqrLength = aSeg._sqrLength;
00139 _approxFactor = aSeg._approxFactor;
00140 _direction = aSeg._direction;
00141 }
00142
00143
00144
00145
00146 void
00147 WDSegment::set(GenPoint<int>& orig,
00148 int deltaX,
00149 int deltaY,
00150 QGEdirection d)
00151 {
00152 _source = orig;
00153 _target = orig;
00154 _target.translate(deltaX, deltaY);
00155 _sqrLength = deltaX * deltaX + deltaY * deltaY;
00156 _approxFactor = 0;
00157 _direction = d;
00158 }
00159
00160
00161
00162
00163 void WDSegment::translateTarget(GenPoint<int>& translation)
00164 {
00165 _target += translation;
00166
00167
00168 Point p0 = _target - _source;
00169 _sqrLength = p0.x() * p0.x() + p0.y() * p0.y();
00170
00171 int b1 = (abs(p0.x()) > (2 * abs(p0.y())));
00172 int b2 = (abs(p0.y()) > (2 * abs(p0.x())));
00173
00174 _direction = (p0.x() > 0)
00175 ? (p0.y() > 0)
00176 ? (b1) ? QGE_DIRECTION_E : (b2) ? QGE_DIRECTION_S : QGE_DIRECTION_SE
00177 : (b1) ? QGE_DIRECTION_E : (b2) ? QGE_DIRECTION_N : QGE_DIRECTION_NE
00178 : (p0.y() > 0)
00179 ? (b1) ? QGE_DIRECTION_W : (b2) ? QGE_DIRECTION_S : QGE_DIRECTION_SE
00180 : (b1) ? QGE_DIRECTION_W : (b2) ? QGE_DIRECTION_N : QGE_DIRECTION_NW;
00181 }
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191 WDSegment&
00192 WDSegment::operator=(const WDSegment& w)
00193 {
00194 _sqrLength = w._sqrLength;
00195 _approxFactor = w._approxFactor;
00196 _direction = w._direction;
00197 setSource(w.source());
00198 setTarget(w.target());
00199 return *this;
00200 }
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223 WDSegmentList::WDSegmentList(AbstractGenPointChain<int>& chain,
00224 int wdThreshold)
00225 {
00226 PRIVATEperform(chain, wdThreshold);
00227 }
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237 WDSegmentList::~WDSegmentList()
00238 {
00239
00240 }
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253 void
00254 WDSegmentList::PRIVATEperform(AbstractGenPointChain<int>& aChain,
00255 int wdThreshold)
00256 {
00257 int ddist;
00258 int f;
00259 int l2;
00260 Point relativeCoords;
00261 WDSegment currseg;
00262
00263 if (aChain.empty()) return;
00264
00265
00266 aChain.setToBegin();
00267
00268
00269 Point currpoint = aChain.current();
00270 WDSegment wdtmp(currpoint, 0, 0, QGE_DIRECTION_E);
00271
00272
00273
00274 currseg = wdtmp;
00275 _cutSeg.setSource(currpoint);
00276 _cutSeg.setTarget(currpoint);
00277 _cutSeg.setApproxFactor(0);
00278 _cutSeg.setSqrLength(0);
00279 _cutSeg.setDirection(QGE_DIRECTION_E);
00280
00281 while (aChain.hasNext())
00282 {
00283 Point prevpoint = currpoint;
00284 aChain.moveNext();
00285 currpoint = aChain.current();
00286
00287 int dx = currpoint.x() - prevpoint.x();
00288 int dy = currpoint.y() - prevpoint.y();
00289
00290 QGEdirection dir = qgDirection(dx, dy);
00291 Point translation = Point(dx, dy);
00292
00293
00294 if(currseg.sqrLength() != 0)
00295 {
00296 relativeCoords = currpoint - currseg.source();
00297 f = currseg.approxFactor() +
00298 (relativeCoords.x() * translation.y() -
00299 relativeCoords.y() * translation.x());
00300
00301 l2 = relativeCoords.x() * relativeCoords.x() +
00302 relativeCoords.y() * relativeCoords.y();
00303
00304
00305
00306 if ( (std::abs(f) <= Math::QG_SQRT_MAX_INT16b)
00307 && ((f * f) < (l2 * wdThreshold)))
00308 {
00309
00310
00311 int oldf = currseg.approxFactor();
00312 int oldl2 = currseg.sqrLength();
00313 QGEdirection olddir = currseg.direction();
00314
00315 currseg.translateTarget(translation);
00316 currseg.setApproxFactor(f);
00317
00318 ddist = std::abs(((int) dir) - ((int) olddir));
00319 if (std::min(ddist,(8-ddist)) >
00320 WALLDANIELSSONSEGMENTLIST_MAX_DIR_CHANGE)
00321 {
00322
00323
00324 if (_cutSeg.target() != prevpoint)
00325 {
00326
00327
00328 _newSeg.translateTarget(translation);
00329
00330 Point newRelativeCoord = currpoint - _newSeg.source();
00331
00332 _newSeg.setApproxFactor(_newSeg.approxFactor() +
00333 (newRelativeCoord.x() * translation.y() -
00334 newRelativeCoord.y() * translation.x()));
00335 }
00336 else
00337 {
00338
00339
00340 _newSeg.setSource(prevpoint);
00341 _newSeg.setTarget(prevpoint);
00342 _newSeg.translateTarget(translation);
00343 _newSeg.setApproxFactor(0);
00344
00345
00346 _cutSeg.setTarget(prevpoint);
00347 _cutSeg.setSqrLength(oldl2);
00348 _cutSeg.setApproxFactor(oldf);
00349 _cutSeg.setDirection(olddir);
00350 }
00351 }
00352
00353 else
00354 _cutSeg.setTarget(currpoint);
00355 }
00356 else
00357 {
00358
00359
00360
00361 if (_cutSeg.target() == prevpoint)
00362 {
00363
00364
00365 push_back(currseg);
00366
00367 currseg.set(prevpoint, translation.x(), translation.y(), dir);
00368 }
00369 else
00370 {
00371
00372
00373 push_back(_cutSeg);
00374
00375
00376 currseg = _newSeg;
00377
00378 relativeCoords = currpoint - currseg.source();
00379
00380 f = currseg.approxFactor() +
00381 (relativeCoords.x() * translation.y() -
00382 relativeCoords.y() * translation.x());
00383
00384
00385 l2 = relativeCoords.x() * relativeCoords.x() +
00386 relativeCoords.y() * relativeCoords.y();
00387
00388 if ((l2 == 0) ||
00389 ((std::abs(f) <= Math::QG_SQRT_MAX_INT16b)
00390 && ((f * f) < (l2 * wdThreshold))))
00391
00392 {
00393
00394
00395 currseg.translateTarget(translation);
00396 currseg.setApproxFactor(f);
00397
00398 }
00399
00400 else
00401 {
00402
00403
00404 push_back(_newSeg);
00405 currseg.set(prevpoint, translation.x(),
00406 translation.y(), dir);
00407
00408 }
00409 }
00410
00411 _cutSeg.setTarget(currpoint);
00412 _cutSeg.setSource(currseg.source());
00413 }
00414 }
00415 else
00416 {
00417 currseg.setSource(prevpoint);
00418 currseg.setTarget(currpoint);
00419 currseg.setSqrLength(translation.x() * translation.x() +
00420 translation.y() * translation.y());
00421 currseg.setApproxFactor(0);
00422 currseg.setDirection(dir);
00423 _cutSeg = currseg;
00424 }
00425 }
00426
00427
00428
00429
00430 if (aChain.front() == aChain.back())
00431 {
00432
00433 WDSegment firstseg = front();
00434
00435 ddist = std::abs((int) currseg.direction() - (int) firstseg.direction());
00436 if ((currseg != firstseg)
00437 && (std::min(ddist,(8-ddist)) <= WALLDANIELSSONSEGMENTLIST_MAX_DIR_CHANGE))
00438 {
00439
00440
00441
00442
00443
00444
00445 f = (firstseg.source().x() - currseg.source().x()) *
00446 (firstseg.target().y() - firstseg.source().y()) -
00447 (firstseg.source().y() - currseg.source().y()) *
00448 (firstseg.target().x() - firstseg.source().x());
00449 f += firstseg.approxFactor() + currseg.approxFactor();
00450
00451 relativeCoords = firstseg.target() - currseg.source();
00452
00453 l2 = relativeCoords.x() * relativeCoords.x() +
00454 relativeCoords.y() * relativeCoords.y();
00455
00456
00457
00458 if ((std::abs(f) <= Math::QG_SQRT_MAX_INT16b)
00459 && (f*f < (l2*wdThreshold)))
00460 {
00461
00462 firstseg.setSource(currseg.source());
00463 firstseg.setTarget(currseg.source());
00464 firstseg.translateTarget(relativeCoords);
00465 firstseg.setApproxFactor(f);
00466
00467
00468 }
00469 else
00470
00471 push_back(currseg);
00472 }
00473 else
00474 push_back(currseg);
00475 }
00476 else
00477 push_back(currseg);
00478 }
00479
00480
00481
00482 }