00001
00002 #include <iostream>
00003 #include <math.h>
00004 #include <vector>
00005 #include <list>
00006
00007 #include "Macrodefs.h"
00008
00009 #include "SketchSpace.h"
00010 #include "Sketch.h"
00011 #include "Region.h"
00012 #include "visops.h"
00013
00014 #include "ShapeSpace.h"
00015 #include "ShapeRoot.h"
00016
00017 #include "PointData.h"
00018 #include "LineData.h"
00019 #include "ShapeLine.h"
00020
00021 namespace DualCoding {
00022
00023 DATASTUFF_CC(LineData);
00024
00025 const Point LineData::origin_pt = Point(0,0);
00026
00027 LineData::LineData(ShapeSpace& _space, const Point &p1, orientation_t orient)
00028 : BaseData(_space,getStaticType()), end1_pt(p1), end2_pt(),
00029 rho_norm(0), theta_norm(0), orientation(0), length(0) {
00030 int const width = space->getDualSpace().getWidth();
00031 int const height = space->getDualSpace().getHeight();
00032
00033
00034
00035
00036 float p2x=0, p2y=0;
00037 if ( fabs(orient-M_PI/2) < 0.001 ) {
00038 p2x = p1.coordX();
00039 p2y = p1.coordY() > height/2 ? 0 : height-1;
00040 } else {
00041 float slope = tan(orient);
00042 float intcpt = p1.coordY() - p1.coordX()*slope;
00043 p2x = p1.coordX() >= width/2 ? 0.0 : width-1;
00044 p2y = p2x * slope + intcpt;
00045 if ( p2y > height-1 ) {
00046 p2x = (height - intcpt) / slope;
00047 p2y = height;
00048 } else if ( p2y < 0 ) {
00049 p2x = -intcpt / slope;
00050 p2y = 0;
00051 }
00052 }
00053 end2_pt = Point(p2x,p2y);
00054 end1_pt.setValid(false);
00055 end1_pt.setActive(false);
00056 end2_pt.setValid(false);
00057 end2_pt.setActive(false);
00058 update_derived_properties();
00059 }
00060
00061 Point LineData::getCentroid() const { return (end1Pt()+end2Pt())*0.5; }
00062
00063 void LineData::setInfinite(bool value) {
00064 end1_pt.setActive(!value);
00065 end2_pt.setActive(!value);
00066 }
00067
00068 #define NORMPOINT_MATCH_DISTSQ 3500
00069 #define LINE_MATCH_OVERLAP -10
00070 #define LINE_ORIENTATION_MATCH M_PI/6
00071
00072 bool LineData::isMatchFor(const ShapeRoot& other) const {
00073 if (!(isSameTypeAs(other) && isSameColorAs(other)))
00074 return false;
00075 else {
00076 const Shape<LineData>& other_ln = ShapeRootTypeConst(other,LineData);
00077 return isMatchFor(other_ln.getData());
00078 }
00079 }
00080
00081 bool LineData::isMatchFor(const LineData& other_line) const {
00082 float const px = rho_norm*cos(theta_norm),
00083 py = rho_norm*sin(theta_norm);
00084 float const qx = other_line.rho_norm*cos(other_line.theta_norm),
00085 qy = other_line.rho_norm*sin(other_line.theta_norm);
00086 AngPi theta_diff = float(theta_norm) - float(other_line.theta_norm);
00087 if ( theta_diff > M_PI/2 )
00088 theta_diff = M_PI - theta_diff;
00089 float normpointdistsq = (px-qx)*(px-qx) + (py-qy)*(py-qy);
00090
00091
00092
00093
00094 return normpointdistsq < NORMPOINT_MATCH_DISTSQ
00095 && theta_diff < LINE_ORIENTATION_MATCH
00096 && perpendicularDistanceFrom(other_line.getCentroid()) < 100
00097 && isOverlappedWith(other_line,LINE_MATCH_OVERLAP);
00098 }
00099
00100 bool LineData::isOverlappedWith(const LineData& otherline, int amount) const {
00101 if ( firstPtCoord() <= otherline.firstPtCoord() )
00102 return secondPtCoord()-amount >= otherline.firstPtCoord();
00103 else
00104 return firstPtCoord()+amount <= otherline.secondPtCoord();
00105 }
00106
00107
00108 void LineData::mergeWith(const ShapeRoot& other) {
00109 const Shape<LineData>& other_line = ShapeRootTypeConst(other,LineData);
00110 if (other_line->confidence <= 0)
00111 return;
00112 const int other_conf = other_line->confidence;
00113 confidence += other_conf;
00114 end1_pt = (end1_pt*confidence + other_line->end1Pt()*other_conf) / (confidence+other_conf);
00115 end2_pt = (end2_pt*confidence + other_line->end2Pt()*other_conf) / (confidence+other_conf);
00116 update_derived_properties();
00117 }
00118
00119
00120 bool LineData::isValidUpdate(coordinate_t c1_cur, coordinate_t c2_cur, coordinate_t c1_new, coordinate_t c2_new) {
00121 const float c1_noise = 10.0 + fabs(c1_cur+c1_new) / 20.0;
00122 const float c2_noise = 10.0 + fabs(c2_cur+c2_new) / 20.0;
00123 return (c1_new-c1_noise < c1_cur && c2_cur < c2_new+c2_noise);
00124 }
00125
00126
00127
00128 bool LineData::updateParams(const ShapeRoot& ground_root, bool force) {
00129 const Shape<LineData>& ground_line = ShapeRootTypeConst(ground_root,LineData);
00130
00131
00132
00133
00134
00135 const coordinate_t c1_cur = firstPtCoord();
00136 const coordinate_t c2_cur = secondPtCoord();
00137
00138 Point _end1_pt = firstPt();
00139 Point _end2_pt = secondPt();
00140
00141 updateLinePt(firstPt(), firstPtCoord(), firstPt(ground_line), firstPtCoord(ground_line), -1);
00142 updateLinePt(secondPt(), secondPtCoord(), secondPt(ground_line), secondPtCoord(ground_line), +1);
00143
00144
00145
00146 const coordinate_t c1_new = firstPtCoord();
00147 const coordinate_t c2_new = secondPtCoord();
00148
00149 if (isValidUpdate(c1_cur, c2_cur, c1_new, c2_new) || force){
00150
00151
00152 update_derived_properties();
00153 return true;
00154 }
00155
00156
00157 setEndPts(_end1_pt, _end2_pt);
00158 return false;
00159 }
00160
00161 void LineData::updateLinePt(EndPoint& localPt, coordinate_t local_coord,
00162 const EndPoint& groundPt, coordinate_t ground_coord,
00163 int sign) {
00164 if ( groundPt.isValid() ) {
00165 if ( localPt.isValid() )
00166 localPt.updateParams(groundPt);
00167 else
00168 localPt = groundPt;
00169 }
00170 else if ( (ground_coord - local_coord)*sign > 0 )
00171 localPt = groundPt;
00172 }
00173
00174 bool LineData::isAdmissible() const {
00175 if (end1Pt().isValid() && end2Pt().isValid())
00176 return length >= 70.0;
00177 else
00178 return length >= 40.0;
00179 }
00180
00181
00182 void LineData::printParams() const {
00183 cout << "Type = " << getTypeName() << " ID=" << getId() << " ParentID=" << getParentId() << endl;
00184 cout << "end1{" << end1Pt().coordX() << ", " << end1Pt().coordY() << "}";
00185 cout << " active=" << end1Pt().isActive();
00186 cout << " valid=" << end1Pt().isValid() << endl;
00187
00188 cout << "end2{" << end2Pt().coordX() << ", " << end2Pt().coordY() << "}";
00189 cout << " active=" << end2Pt().isActive();
00190 cout << " valid=" << end2Pt().isValid() << std::endl;
00191
00192 cout << "rho_norm=" << rho_norm << " theta_norm=" << theta_norm;
00193 cout << " orientation=" << getOrientation()
00194 << " length=" << getLength() << endl;
00195
00196 printf("color = %d %d %d\n",getColor().red,getColor().green,getColor().blue);
00197
00198 cout << " mobile=" << isMobile() << endl;
00199 cout << " viewable=" << isViewable() << endl;
00200
00201 vector<float> abc = lineEquation_abc();
00202 printf("equ = %f %f %f\n",abc[0],abc[1],abc[2]);
00203 }
00204
00205 void LineData::printEnds() const {
00206 cout << " end1{" << end1Pt().coordX() << ", " << end1Pt().coordY() << "}";
00207 cout << " active=" << end1Pt().isActive() << ", valid=" << end1Pt().isValid() << endl;
00208 cout << " end2{" << end2Pt().coordX() << ", " << end2Pt().coordY() << "}";
00209 cout << " active=" << end2Pt().isActive() << ", valid=" << end2Pt().isValid() << endl;
00210
00211 }
00212
00213
00214
00215
00216
00217
00218 void LineData::applyTransform(const NEWMAT::Matrix& Tmat) {
00219 end1Pt().applyTransform(Tmat);
00220 end2Pt().applyTransform(Tmat);
00221 update_derived_properties();
00222 }
00223
00224 void LineData::projectToGround(const NEWMAT::Matrix& camToBase,
00225 const NEWMAT::ColumnVector& groundplane) {
00226 end1Pt().projectToGround(camToBase,groundplane);
00227 end2Pt().projectToGround(camToBase,groundplane);
00228 update_derived_properties();
00229 }
00230
00231
00232
00233
00234 EndPoint& LineData::leftPt() { return end1Pt().isLeftOf(end2Pt()) ? end1_pt : end2_pt; }
00235 EndPoint& LineData::rightPt() { return end1Pt().isLeftOf(end2Pt()) ? end2_pt : end1_pt; }
00236 EndPoint& LineData::topPt() { return end1Pt().isAbove(end2Pt()) ? end1_pt : end2_pt; }
00237 EndPoint& LineData::bottomPt() { return end1Pt().isAbove(end2Pt()) ? end2_pt : end1_pt; }
00238
00239 Shape<PointData> LineData::leftPtShape() {
00240 Shape<PointData> result(new PointData(*space, leftPt()));
00241 result->setName("leftPt");
00242 result->inheritFrom(*this);
00243 result->setViewable(false);
00244 return result;
00245 }
00246
00247 Shape<PointData> LineData::rightPtShape() {
00248 Shape<PointData> result(new PointData(*space, leftPt()));
00249 result->setName("rightPt");
00250 result->inheritFrom(*this);
00251 result->setViewable(false);
00252 return result;
00253 }
00254
00255 Shape<PointData> LineData::topPtShape() {
00256 Shape<PointData> result(new PointData(*space, leftPt()));
00257 result->setName("topPt");
00258 result->inheritFrom(*this);
00259 result->setViewable(false);
00260 return result;
00261 }
00262
00263 Shape<PointData> LineData::bottomPtShape() {
00264 Shape<PointData> result(new PointData(*space, leftPt()));
00265 result->setName("bottomPt");
00266 result->inheritFrom(*this);
00267 result->setViewable(false);
00268 return result;
00269 }
00270
00271 EndPoint& LineData::firstPt() {
00272 if ( isNotVertical() )
00273 if ( end1Pt().coordX() < end2Pt().coordX() )
00274 return end1Pt();
00275 else return end2Pt();
00276 else
00277 if ( end1Pt().coordY() < end2Pt().coordY() )
00278 return end1Pt();
00279 else return end2Pt();
00280 }
00281
00282 EndPoint& LineData::firstPt(const Shape<LineData> &otherline) const {
00283 if ( isNotVertical() )
00284 if ( otherline->end1Pt().coordX() < otherline->end2Pt().coordX() )
00285 return otherline->end1Pt();
00286 else return otherline->end2Pt();
00287 else
00288 if ( otherline->end1Pt().coordY() < otherline->end2Pt().coordY() )
00289 return otherline->end1Pt();
00290 else return otherline->end2Pt();
00291 }
00292
00293 EndPoint& LineData::secondPt() {
00294 if ( isNotVertical() )
00295 if ( end1Pt().coordX() > end2Pt().coordX() )
00296 return end1Pt();
00297 else return end2Pt();
00298 else
00299 if ( end1Pt().coordY() > end2Pt().coordY() )
00300 return end1Pt();
00301 else return end2Pt();
00302 }
00303
00304 EndPoint& LineData::secondPt(const Shape<LineData> &otherline) const {
00305 if ( isNotVertical() )
00306 if ( otherline->end1Pt().coordX() > otherline->end2Pt().coordX() )
00307 return otherline->end1Pt();
00308 else return otherline->end2Pt();
00309 else
00310 if ( otherline->end1Pt().coordY() > otherline->end2Pt().coordY() )
00311 return otherline->end1Pt();
00312 else return otherline->end2Pt();
00313 }
00314
00315 coordinate_t LineData::firstPtCoord() const {
00316 return isNotVertical() ?
00317 const_cast<LineData*>(this)->firstPt().coordX() :
00318 const_cast<LineData*>(this)->firstPt().coordY();
00319 }
00320
00321 coordinate_t LineData::firstPtCoord(const Shape<LineData> &otherline) const {
00322 return isNotVertical() ?
00323 firstPt(otherline).coordX() :
00324 firstPt(otherline).coordY();
00325 }
00326
00327 coordinate_t LineData::secondPtCoord() const {
00328 return isNotVertical() ?
00329 const_cast<LineData*>(this)->secondPt().coordX() :
00330 const_cast<LineData*>(this)->secondPt().coordY();
00331 }
00332
00333 coordinate_t LineData::secondPtCoord(const Shape<LineData> &otherline) const {
00334 return isNotVertical() ?
00335 secondPt(otherline).coordX() :
00336 secondPt(otherline).coordY();
00337 }
00338
00339
00340
00341
00342
00343 void LineData::setEndPts(const EndPoint& _end1_pt, const EndPoint& _end2_pt) {
00344 end1_pt.setCoords(_end1_pt);
00345 end1_pt.setActive(_end1_pt.isActive());
00346 end1_pt.setValid(_end1_pt.isValid());
00347 end1_pt.setNumUpdates(_end1_pt.numUpdates());
00348
00349 end2_pt.setCoords(_end2_pt);
00350 end2_pt.setActive(_end2_pt.isActive());
00351 end2_pt.setValid(_end2_pt.isValid());
00352 end2_pt.setNumUpdates(_end2_pt.numUpdates());
00353
00354 update_derived_properties();
00355 }
00356
00357
00358
00359
00360
00361 std::pair<float,float> LineData::lineEquation_mb() const {
00362 float m;
00363 if ((fabs(end2Pt().coordX() - end1Pt().coordX()) * BIG_SLOPE)
00364 <= fabs(end2Pt().coordY() - end2Pt().coordY()))
00365 m = BIG_SLOPE;
00366 else
00367 m = (end2Pt().coordY() - end1Pt().coordY())/(end2Pt().coordX() - end1Pt().coordX());
00368 float b = end1Pt().coordY() - m * end1Pt().coordX();
00369 return pair<float,float>(m,b);
00370 }
00371
00372
00373
00374 std::vector<float> LineData::lineEquation_abc_xz() const {
00375 float dx = end2Pt().coordX() - end1Pt().coordX();
00376 float dz = end2Pt().coordZ() - end1Pt().coordZ();
00377
00378 std::vector<float> abc;
00379 abc.resize(3, 1.0);
00380 float& a = abc[0];
00381 float& b = abc[1];
00382 float& c = abc[2];
00383
00384
00385 if((dx == 0.0)
00386 || (dz/dx > BIG_SLOPE)) {
00387 a = 1.0;
00388 b = 0.0;
00389 c = end1Pt().coordX();
00390 }
00391
00392
00393 else if((dz == 0.0)
00394 || (dx/dz > BIG_SLOPE)) {
00395 a = 0.0;
00396 b = 1.0;
00397 c = end1Pt().coordZ();
00398 }
00399
00400
00401 else {
00402 a = 1.0;
00403 b = (end1Pt().coordX() - end2Pt().coordX())
00404 / (end2Pt().coordZ() - end1Pt().coordZ());
00405 c = end1Pt().coordX() + b*end1Pt().coordZ();
00406 }
00407
00408 return(abc);
00409
00410 }
00411
00412
00413
00414 std::vector<float> LineData::lineEquation_abc() const {
00415 float dx = end2Pt().coordX() - end1Pt().coordX();
00416 float dy = end2Pt().coordY() - end1Pt().coordY();
00417
00418 std::vector<float> abc;
00419 abc.resize(3, 1.0);
00420 float& a = abc[0];
00421 float& b = abc[1];
00422 float& c = abc[2];
00423
00424
00425 if( fabs(dx) < 1.0e-6 || dy/dx > BIG_SLOPE) {
00426 a = 1.0;
00427 b = 0.0;
00428 c = end1Pt().coordX();
00429 }
00430
00431
00432 else if ( fabs(dy) < 1.0e-6 || dx/dy > BIG_SLOPE ) {
00433 a = 0.0;
00434 b = 1.0;
00435 c = end1Pt().coordY();
00436 }
00437
00438
00439 else {
00440 a = 1.0;
00441
00442
00443 b = -dx / dy;
00444 c = end1Pt().coordX() + b*end1Pt().coordY();
00445 }
00446
00447 return(abc);
00448 }
00449
00450
00451
00452
00453
00454 void LineData::update_derived_properties() {
00455 rho_norm = perpendicularDistanceFrom(origin_pt);
00456 const vector<float> abc = lineEquation_abc();
00457 const float& a1 = abc[0];
00458 const float& b1 = abc[1];
00459 const float& c1 = abc[2];
00460 const float c1sign = (c1 >= 0) ? 1.0 : -1.0;
00461 theta_norm = atan2(b1*c1sign, a1*c1sign);
00462 orientation = theta_norm + AngPi(M_PI/2);
00463 length = end1Pt().distanceFrom(end2Pt());
00464 const ReferenceFrameType_t ref = getRefFrameType();
00465 end1_pt.setRefFrameType(ref);
00466 end2_pt.setRefFrameType(ref);
00467 deleteRendering();
00468 }
00469
00470 bool LineData::isNotVertical() const {
00471 const AngPi threshold = M_PI / 3;
00472 const AngPi orient = getOrientation();
00473 return (orient <= threshold) || (orient >= M_PI - threshold);
00474 }
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496 bool LineData::isLongerThan(const Shape<LineData>& other) const {
00497 return length > other->length; }
00498
00499 bool LineData::isLongerThan(float ref_length) const {
00500 return length > ref_length; }
00501
00502 bool LineData::isShorterThan(const Shape<LineData>& other) const {
00503 return length < other->length; }
00504
00505 bool LineData::isShorterThan(float ref_length) const {
00506 return length < ref_length; }
00507
00508
00509 bool LineData::isBetween(const Point &p, const LineData &other) const {
00510 if (getOrientation() == other.getOrientation()) {
00511 float dl = perpendicularDistanceFrom(other.end1Pt());
00512 return (perpendicularDistanceFrom(p) <= dl && other.perpendicularDistanceFrom(p) <= dl);
00513 }
00514 else {
00515 bool b;
00516 const LineData p_line (*space, p,
00517 intersectionWithLine(other, b, b));
00518 const AngPi theta_pline = p_line.getOrientation();
00519 const AngPi theta_greater =
00520 (getOrientation() > other.getOrientation()) ? getOrientation() : other.getOrientation();
00521 const AngPi theta_smaller =
00522 (getOrientation() < other.getOrientation()) ? getOrientation() : other.getOrientation();
00523 if (theta_greater - theta_smaller > M_PI/2)
00524 return (theta_pline >= theta_greater || theta_pline <= theta_smaller);
00525 else
00526 return (theta_pline <= theta_greater && theta_pline >= theta_smaller);
00527 }
00528 }
00529
00530
00531
00532 bool
00533 LineData::intersectsLine(const Shape<LineData>& other) const {
00534 return intersectsLine(other.getData());
00535 }
00536
00537 bool
00538 LineData::intersectsLine(const LineData& other) const {
00539
00540 pair<float,float> F = lineEquation_mb();
00541
00542
00543 pair<float,float> G = other.lineEquation_mb();
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563 float r3 = F.first * other.end1Pt().coordX() + F.second - other.end1Pt().coordY();
00564
00565
00566 float r4 = F.first * other.end2Pt().coordX() + F.second - other.end2Pt().coordY();
00567
00568
00569
00570
00571
00572
00573 if((r3 != 0)
00574 && (r4 != 0)
00575 && (SGN(r3) == SGN(r4))
00576 )
00577 return false;
00578
00579
00580
00581
00582
00583 float r1 = G.first * end1Pt().coordX() + G.second - end1Pt().coordY();
00584
00585
00586 float r2 = G.first * end2Pt().coordX() + G.second - end2Pt().coordY();
00587
00588
00589
00590
00591
00592
00593 if((r1 != 0)
00594 && (r2 != 0)
00595 && (SGN(r1) == SGN(r2))
00596 )
00597 return false;
00598
00599
00600 return true;
00601 }
00602
00603
00604 Point LineData::intersectionWithLine(const Shape<LineData>& other,
00605 bool& intersection_on_this,
00606 bool& intersection_on_other) const {
00607 return intersectionWithLine(other.getData(), intersection_on_this,intersection_on_other);
00608 }
00609
00610 Point
00611 LineData::intersectionWithLine(const LineData& other,
00612 bool& intersection_on_this, bool& intersection_on_other) const {
00613
00614
00615
00616
00617
00618
00619
00620 float x1, x2, x3, x4, y1, y2, y3, y4;
00621 x1 = end1Pt().coordX();
00622 x2 = end2Pt().coordX();
00623 x3 = other.end1Pt().coordX();
00624 x4 = other.end2Pt().coordX();
00625
00626
00627 y1 = end1Pt().coordY();
00628 y2 = end2Pt().coordY();
00629 y3 = other.end1Pt().coordY();
00630 y4 = other.end2Pt().coordY();
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645 float denom = ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));
00646 float u_a_numerator = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3));
00647 float u_b_numerator = ((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3));
00648
00649
00650 if(denom == 0.0) {
00651 if (u_a_numerator == 0.0 && u_b_numerator == 0.0) {
00652 PRINTF("intersectionWithLine: lines are coincident!\n");
00653 return(end1Pt());
00654 }
00655 else {
00656 cout << x1 << " " << x2 << " " << x3 << " " << x4 << " "
00657 << y1 << " " << y2 << " " << y3 << " " << y4 << endl;
00658 cout << "this theta; " << getOrientation() << ", other theta: " << other.getOrientation() << endl;
00659 PRINTF("ERROR in intersectionWithLine: lines are parallel!\n");
00660 return(Point(-9999.0,-99999.0));
00661 }
00662 }
00663
00664 else {
00665 float u_a = u_a_numerator / denom;
00666 float u_b = u_b_numerator / denom;
00667
00668
00669 if(0.0 <= u_a <=1.0)
00670 intersection_on_this = true;
00671 else
00672 intersection_on_this = false;
00673
00674
00675 if(0.0 <= u_b <=1.0)
00676 intersection_on_other = true;
00677 else
00678 intersection_on_other = false;
00679
00680 return(Point((x1+u_a*(x2-x1)),
00681 (y1+u_a*(y2-y1))));
00682 }
00683 }
00684
00685
00686
00687
00688 float LineData::perpendicularDistanceFrom(const Point& otherPt) const {
00689
00690
00691
00692
00693 vector<float> abc = lineEquation_abc();
00694 float& a = abc[0];
00695 float& b = abc[1];
00696 float& c = abc[2];
00697
00698
00699
00700
00701
00702 float d = fabs((a * otherPt.coordX() + b * otherPt.coordY() - c)/sqrt(a*a + b*b));
00703
00704 return(d);
00705 }
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718 #define BEG_DIST_THRESH 2
00719 #define END_DIST_THRESH 2
00720
00721 Shape<LineData> LineData::extractLine(Sketch<bool>& sketch) {
00722 NEW_SKETCH_N(fatmask,bool,visops::fillin(sketch,1,2,8));
00723 NEW_SKETCH_N(skel,bool,visops::skel(fatmask));
00724 return extractLine(skel, sketch);
00725 }
00726
00727 Shape<LineData> LineData::extractLine(Sketch<bool>& skeleton,
00728 const Sketch<bool>& occlusions) {
00729 const int width = skeleton->getWidth(), height = skeleton->getHeight();
00730 SketchSpace &SkS = skeleton->getSpace();
00731 ShapeSpace &ShS = SkS.getDualSpace();
00732
00733
00734 NEW_SKETCH_N(labels,usint,visops::oldlabelcc(skeleton,visops::EightWayConnect));
00735 list<Region> regions = Region::extractRegions(labels,EXTRACT_LINE_MIN_AREA);
00736 if ( regions.empty() ) {
00737 ShapeRoot invalid;
00738 return ShapeRootType(invalid,LineData);
00739 }
00740 Region skelchunk = regions.front();
00741 AngPi orientation(skelchunk.findPrincipalAxisOrientation());
00742 Point centroid(skelchunk.findCentroid());
00743
00744 if (! skelchunk.isContained(centroid, 3) ) {
00745 Shape<LineData> result(splitLine(ShS, skelchunk, skeleton, occlusions));
00746 if ( result.isValid() )
00747 return result;
00748 }
00749
00750
00751 Shape<LineData> extracted_line(ShS, centroid, orientation);
00752 extracted_line->setColor(skeleton->getColor());
00753 extracted_line->setParentId(skeleton->getViewableId());
00754
00755
00756
00757
00758 float x_normpoint = extracted_line->rho_norm*cos(extracted_line->theta_norm);
00759 float y_normpoint = extracted_line->rho_norm*sin(extracted_line->theta_norm);
00760
00761
00762
00763 float m = max(min(tan(extracted_line->theta_norm+AngPi(M_PI/2)), (float)BIG_SLOPE), (float)(-BIG_SLOPE));
00764 float b = y_normpoint - m*x_normpoint;
00765
00766
00767
00768 NEW_SKETCH_N(skelDist,usint,visops::edist(skeleton));
00769 if ( abs(m) <= 1 )
00770 extracted_line->scanHorizForEndPts(skelDist,occlusions,m,b);
00771 else
00772 extracted_line->scanVertForEndPts(skelDist,occlusions,m,b);
00773
00774
00775
00776 extracted_line->end1_pt.checkValidity(width,height,BEG_DIST_THRESH);
00777 extracted_line->end2_pt.checkValidity(width,height,BEG_DIST_THRESH);
00778
00779
00780 SkS.applyTmatinv(extracted_line->end1_pt.getCoords());
00781 SkS.applyTmatinv(extracted_line->end2_pt.getCoords());
00782 extracted_line->update_derived_properties();
00783 return extracted_line;
00784 }
00785
00786
00787
00788 Shape<LineData> LineData::splitLine(ShapeSpace &ShS, Region &skelchunk,
00789 Sketch<bool> &skeleton, const Sketch<bool> &occlusions) {
00790
00791 Point bounds[4] = {skelchunk.findTopBoundPoint(), skelchunk.findLeftBoundPoint(),
00792 skelchunk.findRightBoundPoint(), skelchunk.findBotBoundPoint()};
00793
00794
00795
00796
00797 for (int i = 0; i < 4; i++) {
00798 for (int j = i+1; j < 4; j++) {
00799 if (bounds[i].distanceFrom(bounds[j]) > 20 && ! skelchunk.isContained((bounds[i]+bounds[j])/2.0, 3)) {
00800
00801 LineData ln(ShS,bounds[i],bounds[j]);
00802 PointData most_distant_pt(ShS, skelchunk.mostDistantPtFrom(ln));
00803
00804 const Sketch<bool>& point_rendering = most_distant_pt.getRendering();
00805 usint const clear_dist = 10;
00806 NEW_SKETCH_N(not_too_close, bool, visops::edist(point_rendering) >= clear_dist);
00807 skeleton &= not_too_close;
00808 return extractLine(skeleton, occlusions);
00809 }
00810 }
00811 }
00812 ShapeRoot invalid;
00813 return ShapeRootType(invalid,LineData);
00814 }
00815
00816 void LineData::scanHorizForEndPts(const Sketch<usint>& skelDist,
00817 const Sketch<bool>& occlusions,
00818 float m, float b) {
00819
00820 bool on_line = false;
00821 int beg_dist_thresh = BEG_DIST_THRESH;
00822 int end_dist_thresh = END_DIST_THRESH;
00823 int curxstart = -1;
00824 int possxstop = -1;
00825 int bestxstart = -1;
00826 int bestxstop = -1;
00827 int bestlength = -1;
00828 for (int x = 0, y, dist=0; x < skelDist.width; x++) {
00829 y = int(m*x+b);
00830
00831
00832 if (y >= 0 && y < skelDist.height) {
00833 dist = skelDist(x,y);
00834
00835 if (on_line == false) {
00836 if (dist <= beg_dist_thresh) {
00837
00838 on_line = true;
00839 curxstart = x - dist;
00840
00841 int curystart;
00842 bool backupflag = false;
00843 while ( curxstart >= 0 && (curystart=int(m*curxstart+b)) >= 0 && curystart < skelDist.height )
00844 if ( occlusions(curxstart,curystart) || skelDist(curxstart,curystart) == 0 ) {
00845 --curxstart;
00846 backupflag = true;
00847 } else {
00848 curxstart += backupflag;
00849 break;
00850 }
00851 if ( curxstart < 0)
00852 curxstart = 0;
00853 }
00854 }
00855 else {
00856 const bool occ = occlusions(x,y);
00857
00858 if ( dist <= end_dist_thresh || occ ) {
00859 if ( occ )
00860 possxstop = x;
00861 else
00862 possxstop = x - dist;
00863
00864 if ( possxstop-curxstart > bestlength ) {
00865 bestxstart = curxstart;
00866 bestxstop = possxstop;
00867 bestlength = bestxstop-bestxstart;
00868
00869 }
00870 }
00871 else if ( dist > extractorGapTolerance ) {
00872
00873 on_line = false;
00874
00875 };
00876
00877 }
00878 }
00879 }
00880
00881
00882 float y1 = m*bestxstart + b;
00883 float y2 = m*bestxstop + b;
00884 setEndPts(Point(bestxstart,y1), Point(bestxstop,y2));
00885
00886 balanceEndPointHoriz(end1_pt,occlusions,m,b);
00887 balanceEndPointHoriz(end2_pt,occlusions,m,b);
00888 }
00889
00890 void LineData::scanVertForEndPts(const Sketch<usint>& skelDist,
00891 const Sketch<bool>& occlusions,
00892 float m, float b) {
00893
00894 bool on_line = false;
00895 int beg_dist_thresh = BEG_DIST_THRESH;
00896 int end_dist_thresh = END_DIST_THRESH;
00897 int curystart = -1;
00898 int possystop = -1;
00899 int bestystart = -1;
00900 int bestystop = -1;
00901 int bestlength = -1;
00902 for (int x, y = 0, dist=0; y < skelDist.height; y++) {
00903 x = int((y-b)/m);
00904
00905
00906 if (x >= 0 && x < skelDist.width) {
00907 dist = int(skelDist(x,y));
00908
00909 if (on_line == false) {
00910 if (dist <= beg_dist_thresh) {
00911
00912 on_line = true;
00913 curystart = y - dist;
00914
00915 int curxstart;
00916 bool backupflag = false;
00917 while ( curystart >= 0 && (curxstart=int((curystart-b)/m)) >= 0 && curxstart < skelDist.width )
00918 if ( occlusions(curxstart,curystart) || skelDist(curxstart,curystart) == 0 ){
00919 --curystart;
00920 backupflag = true;
00921 } else {
00922 curystart += backupflag;
00923 break;
00924 }
00925 if ( curystart < 0)
00926 curystart = 0;
00927 }
00928 }
00929 else {
00930 const bool occ = occlusions(x,y);
00931
00932 if ( dist <= end_dist_thresh || occ ) {
00933 if ( occ )
00934 possystop = y;
00935 else
00936 possystop = y - dist;
00937
00938 if ( possystop-curystart > bestlength ) {
00939 bestystart = curystart;
00940 bestystop = possystop;
00941 bestlength = bestystop-bestystart;
00942
00943 }
00944 }
00945 else if ( dist > extractorGapTolerance ) {
00946
00947 on_line = false;
00948
00949 };
00950
00951 }
00952 }
00953 }
00954
00955 float x1 = (bestystart-b)/m;
00956 float x2 = (bestystop-b)/m;
00957
00958 setEndPts(Point(x1,bestystart), Point(x2,bestystop));
00959
00960 balanceEndPointVert(end1_pt,occlusions,m,b);
00961 balanceEndPointVert(end2_pt,occlusions,m,b);
00962 }
00963
00964 void LineData::balanceEndPointHoriz(EndPoint &, Sketch<bool> const &, float, float) {
00965
00966
00967
00968
00969
00970
00971 return;
00972 }
00973
00974 void LineData::balanceEndPointVert(EndPoint &pt, Sketch<bool> const &occluders, float m, float b) {
00975 int ystep = ( pt.coordY() < max(end1_pt.coordY(),end2_pt.coordY()) ? +1 : -1 );
00976 int leftpix = 0, rightpix = 0;
00977 int const balance_rows = 8;
00978 int const row_samples = 10;
00979
00980 for ( int y = (int)pt.coordY(), ycnt=balance_rows ;
00981 y>= 0 && y<occluders.height && ycnt-- > 0 ; y+=ystep ) {
00982 int const xstart = (int) ((y-b)/m);
00983 for ( int x = xstart-row_samples; x < xstart; x++ )
00984 if ( x >= 0 )
00985 leftpix += occluders(x,y);
00986 for ( int x = xstart+row_samples; x > xstart; x-- )
00987 if ( x < occluders.width )
00988 rightpix += occluders(x,y);
00989
00990 }
00991 float const new_x = pt.coordX() + (rightpix-leftpix)/(2*balance_rows);
00992
00993 pt.setCoords(new_x, pt.coordY());
00994 }
00995
00996 vector<Shape<LineData> > LineData::extractLines(Sketch<bool> const& sketch,
00997 const int num_lines) {
00998 NEW_SKETCH_N(fatmask,bool,visops::fillin(sketch,1,2,8));
00999 NEW_SKETCH_N(skel,bool,visops::skel(fatmask));
01000 return extractLines(skel, sketch, num_lines);
01001 }
01002
01003 vector<Shape<LineData> > LineData::extractLines(Sketch<bool> const& skel,
01004 Sketch<bool> const& occluders,
01005 const int num_lines) {
01006 vector<Shape<LineData> > lines_vec;
01007 NEW_SKETCH_N(temp,bool,visops::copy(skel))
01008 for (int gloop = 0; gloop<num_lines; gloop++) {
01009 Shape<LineData> newline(extractLine(temp,occluders));
01010 if ( !newline.isValid() ) break;
01011 newline->clearLine(temp);
01012 if (newline->isLongerThan(DEFAULT_MIN_LENGTH)) {
01013 lines_vec.push_back(newline);
01014 }
01015 }
01016
01017
01018 return lines_vec;
01019 }
01020
01021
01022 void LineData::clearLine(Sketch<bool>& sketch) {
01023 const Sketch<bool>& line_rendering = getRendering();
01024 usint const clear_dist = 5;
01025 Sketch<bool> not_too_close = (visops::edist(line_rendering) >= clear_dist);
01026 sketch &= not_too_close;
01027 }
01028
01029
01030
01031
01032
01033
01034
01035
01036 Sketch<bool>& LineData::getRendering() {
01037 if ( ! end1Pt().rendering_valid || ! end2Pt().rendering_valid )
01038 deleteRendering();
01039 if ( rendering_sketch == NULL )
01040 rendering_sketch = render();
01041 return *rendering_sketch;
01042 }
01043
01044
01045
01046 Sketch<bool>* LineData::render() const {
01047 SketchSpace &renderspace = space->getDualSpace();
01048 int const width = renderspace.getWidth();
01049 int const height = renderspace.getHeight();
01050 float x1,y1,x2,y2;
01051 setDrawCoords(x1, y1, x2, y2, width, height);
01052 Sketch<bool>* draw_result =
01053 new Sketch<bool>(renderspace, "render("+getName()+")");
01054 (*draw_result)->setParentId(getViewableId());
01055 (*draw_result)->setColor(getColor());
01056 *draw_result = 0;
01057 drawline2d(*draw_result, (int)x1, (int)y1, (int)x2, (int)y2);
01058 const_cast<LineData*>(this)->end1Pt().rendering_valid = true;
01059 const_cast<LineData*>(this)->end2Pt().rendering_valid = true;
01060 return draw_result;
01061 }
01062
01063
01064
01065 void LineData::setDrawCoords(float& x1,float& y1, float& x2, float& y2,
01066 const int width, const int height) const {
01067 EndPoint e1(end1Pt());
01068 EndPoint e2(end2Pt());
01069 space->getDualSpace().applyTmat(e1.getCoords());
01070 space->getDualSpace().applyTmat(e2.getCoords());
01071 const EndPoint &left_point = e1.coordX() <= e2.coordX() ? e1 : e2;
01072 const EndPoint &right_point = e1.coordX() <= e2.coordX() ? e2 : e1;
01073
01074
01075 if((int)left_point.coordY() == (int)right_point.coordY()) {
01076 if (!left_point.isActive())
01077 x1 = 0;
01078 else x1 = max(0,(int)left_point.coordX());
01079
01080 if (!right_point.isActive())
01081 x2 = width-1;
01082 else x2 = min(width-1, (int)right_point.coordX());
01083
01084 y1 = (int)left_point.coordY();
01085 y2 = y1;
01086 }
01087 else
01088 if ((int)left_point.coordX() == (int)right_point.coordX()) {
01089
01090 x1 = (int)left_point.coordX();
01091 x2 = x1;
01092
01093 const EndPoint &top_point = end1Pt().coordY() <= end2Pt().coordY() ? end1Pt() : end2Pt();
01094 const EndPoint &bottom_point = end1Pt().coordY() <= end2Pt().coordY() ? end2Pt() : end1Pt();
01095
01096 if(!top_point.isActive())
01097 y1 = 0;
01098 else y1 = max(0,(int)top_point.coordY());
01099
01100 if (!bottom_point.isActive())
01101 y2 = height-1;
01102 else y2 = min(height-1,(int)bottom_point.coordY());
01103 }
01104
01105 else {
01106 float m = (right_point.coordY()-left_point.coordY())/(right_point.coordX()-left_point.coordX());
01107 float b = left_point.coordY() - m*left_point.coordX();
01108
01109
01110 int i0x = (int)((0-b)/m);
01111 int ihx = (int)(((height-1)-b)/m);
01112 int i0y = (int)(m*0+b);
01113 int iwy = (int)(m*(width-1)+b);
01114
01115
01116 if(left_point.isActive()) {
01117 x1 = (int)left_point.coordX();
01118 y1 = (int)left_point.coordY();
01119 }
01120
01121
01122 else {
01123
01124
01125 if(i0y >= 0 && i0y < height) {
01126 x1 = 0;
01127 y1 = i0y;
01128 }
01129
01130
01131 else {
01132
01133
01134 if (i0x < ihx) {
01135 x1 = i0x;
01136 y1 = 0;
01137 }
01138
01139
01140 else {
01141 x1 = ihx;
01142 y1 = height-1;
01143 }
01144 }
01145 }
01146
01147
01148 if(right_point.isActive()) {
01149 x2 = (int)right_point.coordX();
01150 y2 = (int)right_point.coordY();
01151 }
01152 else {
01153 if(iwy >= 0 && iwy < height) {
01154 x2 = width-1;
01155 y2 = iwy;
01156 }
01157 else {
01158 if (i0x > ihx) {
01159 x2 = i0x;
01160 y2 = 0;
01161 }
01162 else {
01163 x2 = ihx;
01164 y2 = height-1;
01165 }
01166 }
01167 }
01168 }
01169 }
01170
01171 void LineData::drawline2d(Sketch<bool>& canvas, int x0, int y0, int x1, int y1) {
01172 int width = canvas->getWidth();
01173 int height = canvas->getHeight();
01174
01175
01176 int d, x, y, ax, ay, sx, sy, dx, dy;
01177 dx = x1-x0; ax = abs(dx)<<1; sx = SGN(dx);
01178 dy = y1-y0; ay = abs(dy)<<1; sy = SGN(dy);
01179
01180 x = x0;
01181 y = y0;
01182 if ( ax > ay ) {
01183 d = ay-(ax>>1);
01184 for (;;) {
01185 if (x >= 0 && y >= 0 && x < width && y < height)
01186 canvas(x,y) = true;
01187
01188 if (x==x1)
01189 return;
01190
01191 if ( d >= 0 ) {
01192 y += sy;
01193 d -= ax;
01194 }
01195
01196 x += sx;
01197 d += ay;
01198 }
01199 }
01200 else {
01201 d = ax-(ay>>1);
01202 for (;;) {
01203 if (x >= 0 && y >= 0 && x < width && y < height)
01204 canvas(x,y) = true;
01205
01206 if ( y == y1 )
01207 return;
01208
01209 if ( d >= 0 ) {
01210 x += sx;
01211 d -= ay;
01212 }
01213
01214 y += sy;
01215 d += ax;
01216 }
01217 }
01218 }
01219
01220
01221
01222 std::vector<Shape<LineData> > LineData::houghTransform(const Sketch<bool>& fat,
01223 const Sketch<bool>& skinny,
01224 const Sketch<bool>& occlusions,
01225 const size_t num_lines, int minLength)
01226 {
01227 std::vector<Shape<LineData> > result;
01228 ShapeSpace& ShS = fat->getSpace().getDualSpace();
01229
01230 const int width = fat->getWidth(), height = fat->getHeight();
01231 const int numR = 120, numTheta = 120;
01232 const int numRf = 40, numThetaf = 40;
01233 int hsize = numR*numTheta, hsizef = numRf * numThetaf;
01234 int htab[hsize], hfine[hsizef];
01235 float minTheta = 0.0, maxTheta = 2*M_PI;
01236 float minR = 0.000, maxR = sqrt((float)width*width+(float)height*height);
01237 float thetaSpread = maxTheta - minTheta;
01238 float rSpread = maxR - minR;
01239
01240
01241 for (int i = 0; i < hsize; i++)
01242 htab[i] = 0;
01243
01244
01245 float theta, r;
01246 int ridx;
01247 for (int x = 0; x < width; x++) {
01248 for (int y = 0; y < height; y++) {
01249 if (fat(x,y) == true) {
01250 for (int tidx = 0; tidx < numTheta ; tidx++) {
01251 theta = minTheta + tidx*thetaSpread/numTheta;
01252 r = (float)x*cos(theta)+(float)y*sin(theta);
01253 ridx = (int)((r-minR)*(float)numR/rSpread);
01254 if (ridx >= 0 && ridx < numR)
01255 htab[ridx+tidx*numR]++;
01256 }
01257 }
01258 }
01259 }
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281 int max_val = -1, max_i = 0;
01282 while(result.size() < num_lines) {
01283
01284
01285 max_val = -1;
01286 max_i = 0;
01287 for (int i = 0; i < numR*numTheta; i++) {
01288 if (max_val < htab[i]) {
01289 max_val = htab[i];
01290 max_i = i;
01291 }
01292 }
01293
01294
01295 if (max_val < minLength)
01296 break;
01297
01298
01299 float bestR = (max_i%numR)*rSpread/numR + minR;
01300 float bestTheta = (max_i/numR)*thetaSpread/numTheta + minTheta;
01301
01302
01303 const float fthetaSpread = M_PI/40.0;
01304 const float frSpread = maxR/40.0;
01305 float fminTheta = bestTheta-fthetaSpread/2.0;
01306 float fminR = bestR-frSpread/2.0;
01307
01308 for (int i = 0; i < hsizef; i++)
01309 hfine[i] = 0;
01310
01311
01312 float thetaf, rf;
01313 int ridxf;
01314 for (int x = 0; x < width; x++) {
01315 for (int y = 0; y < height; y++) {
01316 if (skinny(x,y) == true) {
01317 for (int tidx = 0; tidx < numThetaf ; tidx++) {
01318 thetaf = fminTheta + tidx*fthetaSpread/numThetaf;
01319 rf = (float)x*cos(thetaf)+(float)y*sin(thetaf);
01320 ridxf = (int)((rf-fminR)*(float)numRf/frSpread);
01321 if (ridxf >= 0 && ridxf < numRf)
01322 hfine[ridxf+tidx*numRf]++;
01323 }
01324 }
01325 }
01326 }
01327
01328
01329
01330 int max_val_f = -1, max_i_f = 0;
01331 for (int i = 0; i < numRf*numThetaf; i++) {
01332 if (max_val_f < hfine[i]) {
01333 max_val_f = hfine[i];
01334 max_i_f = i;
01335 }
01336 }
01337 float bestRf = (max_i_f%numRf)*frSpread/numRf + fminR;
01338 float bestThetaf = (max_i_f/numRf)*fthetaSpread/numThetaf + fminTheta;
01339
01340
01341
01342 float lineLen = 500;
01343
01344 const float x1 = bestRf*cos(bestThetaf), y1 = bestRf*sin(bestThetaf);
01345 const float x2 = x1+lineLen*cos(bestThetaf+M_PI/2), y2 = y1+lineLen*sin(bestThetaf+M_PI/2);
01346 const float x3 = x1-lineLen*cos(bestThetaf+M_PI/2), y3 = y1-lineLen*sin(bestThetaf+M_PI/2);
01347
01348 Point e1(x3,y3), e2(x2,y2);
01349 Shape<LineData> line(ShS,e1,e2);
01350
01351
01352 line->setColor(skinny->getColor());
01353 line->setParentId(skinny->getViewableId());
01354
01355
01356 float m = (y1 != 0) ? -(x1/y1) : BIG_SLOPE;
01357 float b = y1 - m*x1;
01358
01359 NEW_SKETCH_N(skelDist,usint,visops::edist(skinny));
01360 if ( abs(m) <= 1 )
01361 line->scanHorizForEndPts(skelDist,occlusions,m,b);
01362 else
01363 line->scanVertForEndPts(skelDist,occlusions,m,b);
01364
01365
01366
01367 line->end1_pt.checkValidity(width,height,BEG_DIST_THRESH);
01368 line->end2_pt.checkValidity(width,height,BEG_DIST_THRESH);
01369
01370
01371
01372
01373
01374 float len = line->getLength();
01375 EndPoint start = line->end1_pt;
01376 EndPoint dx = (line->end2_pt - start)/len;
01377 float onCount = 0;
01378 for (float i=0; i<len; i++) {
01379 EndPoint cur = start+dx*i;
01380 if (skinny((int)(cur.coordX()), (int)(cur.coordY()))) {
01381 onCount++;
01382 }
01383 }
01384
01385
01386 std::cout<<"Line with "<<onCount<<" / "<<len<<" pixels";
01387 if (line->isLongerThan(minLength) && (onCount / len) > .5 )
01388 {
01389 std::cout<<" accepted";
01390 result.push_back(line);
01391 }
01392 std::cout<<std::endl;
01393
01394
01395
01396
01397 for(int row = -5; row <= 5; row++)
01398 {
01399 for (int col = -(5-abs(row)); col <=5-abs(row); col++)
01400 {
01401
01402
01403 htab[(max_i - (max_i%numR) + ((max_i+col)%numR)+row*numR + numR*numTheta)%(numR*numTheta)] = 0;
01404 }
01405
01406 }
01407
01408 }
01409
01410 return result;
01411 }
01412
01413 bool LineData::linesParallel(Shape<LineData> l1, Shape<LineData>l2)
01414 {
01415 const float maxDTheta = .15, minDThetaR = 10.0;
01416 float dTheta = l1->getOrientation() - l2->getOrientation();
01417 if (dTheta > M_PI_2)
01418 dTheta = dTheta - M_PI;
01419 if (abs(dTheta) < maxDTheta)
01420 {
01421 if (abs (100*dTheta + (l1->rho_norm - l2->rho_norm)) > minDThetaR)
01422 return true;
01423 }
01424 return false;
01425 }
01426
01427 LineData& LineData::operator=(const LineData& other) {
01428 if (&other == this)
01429 return *this;
01430 BaseData::operator=(other);
01431 end1_pt = other.end1_pt;
01432 end2_pt = other.end2_pt;
01433 rho_norm = other.rho_norm;
01434 theta_norm = other.theta_norm;
01435 orientation = other.orientation;
01436 length = other.length;
01437 return *this;
01438 }
01439
01440
01441
01442 bool LineData::pointsOnSameSide(const Point& p1, const Point& p2)
01443 {
01444 float dx = end2_pt.coordX() - end1_pt.coordX();
01445 float dy = end2_pt.coordY() - end1_pt.coordY();
01446
01447 float p1val = (p1.coordY() - end1_pt.coordY())*dx - (p1.coordX() - end1_pt.coordX())*dy;
01448 float p2val = (p2.coordY() - end1_pt.coordY())*dx - (p2.coordX() - end1_pt.coordX())*dy;
01449
01450 return (p1val>0) == (p2val>0);
01451 }
01452
01453
01454
01455 bool LineData::pointOnLine(const Point& p)
01456 {
01457 const float BOUNDS_EXTEND = 1.0;
01458 float dx = end2_pt.coordX() - end1_pt.coordX();
01459 float dy = end2_pt.coordY() - end1_pt.coordY();
01460 float val = (p.coordY() - end1_pt.coordY())*dx - (p.coordX() - end1_pt.coordX())*dy;
01461 val /= length;
01462 bool inBounds = (p.coordX() >= (leftPt().coordX() - BOUNDS_EXTEND)) &&
01463 (p.coordX() <= (rightPt().coordX() + BOUNDS_EXTEND)) &&
01464 (p.coordY() >= (topPt().coordY() - BOUNDS_EXTEND)) &&
01465 (p.coordY() <= (bottomPt().coordY() + BOUNDS_EXTEND));
01466 return (val > -1) && (val < 1) && inBounds;
01467 }
01468
01469
01470
01471
01472 bool LineData::LengthLessThan::operator() (const Shape<LineData> &line1, const Shape<LineData> &line2) const {
01473 return line1->getLength() < line2->getLength();
01474 }
01475
01476 bool LineData::ParallelTest::operator() (const Shape<LineData> &line1, const Shape<LineData> &line2) const {
01477 return angdist(line1->getOrientation(),line2->getOrientation()) <= tolerance;
01478 }
01479
01480 bool LineData::PerpendicularTest::operator() (const Shape<LineData> &line1, const Shape<LineData> &line2) const {
01481 return angdist(angdist(line1->getOrientation(),line2->getOrientation()), M_PI/2) <= tolerance;
01482 }
01483
01484 bool LineData::ColinearTest::operator() (const Shape<LineData> &line1, const Shape<LineData> &line2) const {
01485 return ParallelTest(ang_tol)(line1,line2) &&
01486 abs( line1->getRhoNorm() - line2->getRhoNorm() ) <= dist_tol;
01487 }
01488
01489 bool LineData::IsHorizontal::operator() (const Shape<LineData> &line) {
01490 const AngPi orient = line->getOrientation();
01491 return (orient <= threshold) || (orient >= M_PI - threshold);
01492 }
01493
01494 }