00001
00002 #include <iostream>
00003 #include <math.h>
00004 #include <vector>
00005 #include <list>
00006
00007 #include "SketchSpace.h"
00008 #include "Sketch.h"
00009 #include "Region.h"
00010 #include "visops.h"
00011
00012 #include "ShapeSpace.h"
00013 #include "ShapeRoot.h"
00014
00015 #include "PointData.h"
00016 #include "LineData.h"
00017 #include "ShapeLine.h"
00018
00019 #ifdef PLATFORM_APERIOS
00020
00021 template<typename T> static inline int signbit(T x) { return x<0; }
00022 #endif
00023
00024 using namespace std;
00025
00026 namespace DualCoding {
00027
00028 DATASTUFF_CC(LineData);
00029
00030 const float LineData::DEFAULT_MIN_LENGTH = 0.025f;
00031
00032
00033 const Point LineData::origin_pt = Point(0,0);
00034
00035 LineData::LineData(ShapeSpace& _space, const Point &p1, orientation_t orient)
00036 : BaseData(_space,getStaticType()), end1_pt(p1), end2_pt(),
00037 rho_norm(0), theta_norm(0), orientation(0), length(0) {
00038 int const width = space->getDualSpace().getWidth();
00039 int const height = space->getDualSpace().getHeight();
00040
00041
00042
00043
00044 float p2x=0, p2y=0;
00045 if ( fabs(orient-M_PI/2) < 0.001 ) {
00046 p2x = p1.coordX();
00047 p2y = p1.coordY() > height/2 ? 0 : height-1;
00048 } else {
00049 float slope = tan(orient);
00050 float intcpt = p1.coordY() - p1.coordX()*slope;
00051 p2x = p1.coordX() >= width/2 ? 0 : width-1;
00052 p2y = p2x * slope + intcpt;
00053 if ( p2y > height-1 ) {
00054 p2y = height-1;
00055 p2x = (p2y-intcpt) / slope;
00056 } else if ( p2y < 0 ) {
00057 p2y = 0;
00058 p2x = -intcpt/slope;
00059 }
00060 }
00061 end2_pt = Point(p2x,p2y);
00062 end1_pt.setValid(false);
00063 end1_pt.setActive(false);
00064 end2_pt.setValid(false);
00065 end2_pt.setActive(false);
00066 update_derived_properties();
00067 }
00068
00069 LineData::LineData(const LineData& other)
00070 : BaseData(other),
00071 end1_pt(other.end1_pt), end2_pt(other.end2_pt),
00072 rho_norm(other.rho_norm), theta_norm(other.theta_norm),
00073 orientation(other.orientation), length(other.length) {}
00074
00075 Point LineData::getCentroid() const { return (end1Pt()+end2Pt())*0.5f; }
00076
00077 void LineData::setInfinite(bool value) {
00078 end1_pt.setActive(!value);
00079 end2_pt.setActive(!value);
00080 }
00081
00082 #define NORMPOINT_MATCH_DISTSQ 400
00083 #define LINE_MATCH_OVERLAP -20
00084 #define LINE_ORIENTATION_MATCH M_PI/12
00085 #define LINE_PERPDIST 30
00086
00087
00088 bool LineData::isMatchFor(const ShapeRoot& other) const {
00089 if (!(isSameTypeAs(other) && isSameColorAs(other)))
00090 return false;
00091 else {
00092 const Shape<LineData>& other_ln = ShapeRootTypeConst(other,LineData);
00093 return isMatchFor(other_ln.getData());
00094 }
00095 }
00096
00097 bool LineData::isMatchFor(const LineData& other_line) const {
00098
00099
00100
00101
00102 AngPi theta_diff = float(theta_norm) - float(other_line.theta_norm);
00103 if ( (orientation_t)theta_diff > (orientation_t)M_PI/2 )
00104 theta_diff = (orientation_t)M_PI - theta_diff;
00105
00106
00107
00108
00109
00110 float const linePerpDist =
00111 space->getRefFrameType() == camcentric ? 20 : 100;
00112 AngPi const lineOrientationMatch =
00113 space->getRefFrameType() == camcentric ? M_PI/6 : M_PI/4;
00114
00115
00116
00117
00118 return
00119 theta_diff < lineOrientationMatch
00120 && (perpendicularDistanceFrom(other_line.getCentroid()) < linePerpDist || other_line.perpendicularDistanceFrom(getCentroid()) < linePerpDist)
00121 && isOverlappedWith(other_line,LINE_MATCH_OVERLAP);
00122 }
00123
00124 bool LineData::isOverlappedWith(const LineData& otherline, int amount) const {
00125 fmat::Column<3> thisVec = end2_pt.coords - end1_pt.coords;
00126 fmat::Column<2> v = fmat::SubMatrix<2,1>(thisVec);
00127 float theta = atan2(v[1],v[0]);
00128 fmat::Matrix<2,2> rot = fmat::rotation2D(-theta);
00129 v = rot * v;
00130 fmat::Column<3> otherPt1 = otherline.end1_pt.coords - end1_pt.coords;
00131 fmat::Column<3> otherPt2 = otherline.end2_pt.coords - end1_pt.coords;
00132 fmat::Column<2> op1 = rot * fmat::SubMatrix<2,1>(otherPt1);
00133 fmat::Column<2> op2 = rot * fmat::SubMatrix<2,1>(otherPt2);
00134 float thisMin = min(0.f, v[0]);
00135 float thisMax = max(0.f, v[0]);
00136 float otherMin = min(op1[0], op2[0]);
00137 float otherMax = max(op1[0], op2[0]);
00138 return (thisMin < otherMin) ? (otherMin+amount <= thisMax) : (thisMin+amount <= otherMax);
00139 }
00140
00141 void LineData::mergeWith(const ShapeRoot& other) {
00142 const Shape<LineData>& other_line = ShapeRootTypeConst(other,LineData);
00143 if (other_line->confidence <= 0)
00144 return;
00145
00146
00147
00148 float const totalLengthSq = length * length + other_line->length * other_line->length;
00149 EndPoint new_end1_pt = (end1_pt*length*length/totalLengthSq + other_line->end1Pt()*other_line->length*other_line->length/totalLengthSq);
00150 EndPoint new_end2_pt = (end2_pt*length*length/totalLengthSq + other_line->end2Pt()*other_line->length*other_line->length/totalLengthSq);
00151 new_end1_pt.valid = end1_pt.isValid() && other_line->end1Pt().isValid();
00152 new_end2_pt.valid = end2_pt.isValid() && other_line->end2Pt().isValid();
00153 end1_pt = new_end1_pt;
00154 end2_pt = new_end2_pt;
00155 update_derived_properties();
00156 }
00157
00158 bool LineData::isValidUpdate(coordinate_t c1_cur, coordinate_t c2_cur, coordinate_t c1_new, coordinate_t c2_new) {
00159 const float c1_noise = 10 + std::abs(c1_cur+c1_new) / 20.f;
00160 const float c2_noise = 10 + std::abs(c2_cur+c2_new) / 20.f;
00161 return (c1_new-c1_noise < c1_cur && c2_cur < c2_new+c2_noise);
00162 }
00163
00164
00165
00166 bool LineData::updateParams(const ShapeRoot& ground_root, bool force) {
00167 const Shape<LineData>& ground_line = ShapeRootTypeConst(ground_root,LineData);
00168
00169
00170
00171
00172
00173 const coordinate_t c1_cur = firstPtCoord();
00174 const coordinate_t c2_cur = secondPtCoord();
00175
00176 Point _end1_pt = firstPt();
00177 Point _end2_pt = secondPt();
00178
00179 updateLinePt(firstPt(), firstPtCoord(), firstPt(ground_line), firstPtCoord(ground_line), -1);
00180 updateLinePt(secondPt(), secondPtCoord(), secondPt(ground_line), secondPtCoord(ground_line), +1);
00181
00182
00183
00184 const coordinate_t c1_new = firstPtCoord();
00185 const coordinate_t c2_new = secondPtCoord();
00186
00187 if (isValidUpdate(c1_cur, c2_cur, c1_new, c2_new) || force){
00188
00189
00190 update_derived_properties();
00191 return true;
00192 }
00193
00194
00195 setEndPts(_end1_pt, _end2_pt);
00196 return false;
00197 }
00198
00199 void LineData::updateLinePt(EndPoint& localPt, coordinate_t local_coord,
00200 const EndPoint& groundPt, coordinate_t ground_coord,
00201 int sign) {
00202 if ( groundPt.isValid() ) {
00203 if ( localPt.isValid() )
00204 localPt.updateParams(groundPt);
00205 else
00206 localPt = groundPt;
00207 }
00208 else if ( (ground_coord - local_coord)*sign > 0 )
00209 localPt = groundPt;
00210 }
00211
00212 bool LineData::isAdmissible() const {
00213 if (end1Pt().isValid() && end2Pt().isValid())
00214 return length >= 70.0;
00215 else
00216 return length >= 40.0;
00217 }
00218
00219
00220 void LineData::printParams() const {
00221 cout << "Type = " << getTypeName() << " ID=" << getId() << " ParentID=" << getParentId() << endl;
00222 cout << " end1{" << end1Pt().coordX() << ", " << end1Pt().coordY() << "}"
00223 << " active=" << end1Pt().isActive()
00224 << " valid=" << end1Pt().isValid() << endl;
00225
00226 cout << " end2{" << end2Pt().coordX() << ", " << end2Pt().coordY() << "}"
00227 << " active=" << end2Pt().isActive()
00228 << " valid=" << end2Pt().isValid() << std::endl;
00229
00230 cout << " rho_norm=" << rho_norm
00231 << ", theta_norm=" << theta_norm
00232 << ", orientation=" << getOrientation()
00233 << ", length=" << getLength() << endl;
00234
00235 printf(" color = %d %d %d\n",getColor().red,getColor().green,getColor().blue);
00236
00237 cout << " mobile=" << getMobile()
00238 << ", viewable=" << isViewable() << endl;
00239
00240 vector<float> abc = lineEquation_abc();
00241 printf(" equ = %f %f %f\n",abc[0],abc[1],abc[2]);
00242 }
00243
00244 void LineData::printEnds() const {
00245 cout << " end1{" << end1Pt().coordX() << ", " << end1Pt().coordY() << "}";
00246 cout << " active=" << end1Pt().isActive() << ", valid=" << end1Pt().isValid() << endl;
00247 cout << " end2{" << end2Pt().coordX() << ", " << end2Pt().coordY() << "}";
00248 cout << " active=" << end2Pt().isActive() << ", valid=" << end2Pt().isValid() << endl;
00249
00250 }
00251
00252
00253
00254
00255
00256
00257 void LineData::applyTransform(const fmat::Transform& Tmat, const ReferenceFrameType_t newref) {
00258 end1Pt().applyTransform(Tmat,newref);
00259 end2Pt().applyTransform(Tmat,newref);
00260 update_derived_properties();
00261 }
00262
00263 void LineData::projectToGround(const fmat::Transform& camToBase, const PlaneEquation& groundplane) {
00264 end1Pt().projectToGround(camToBase,groundplane);
00265 end2Pt().projectToGround(camToBase,groundplane);
00266 update_derived_properties();
00267 }
00268
00269
00270
00271
00272 EndPoint& LineData::leftPt() { return end1Pt().isLeftOf(end2Pt()) ? end1_pt : end2_pt; }
00273 const EndPoint& LineData::leftPt() const { return end1Pt().isLeftOf(end2Pt()) ? end1_pt : end2_pt; }
00274 EndPoint& LineData::rightPt() { return end1Pt().isLeftOf(end2Pt()) ? end2_pt : end1_pt; }
00275 const EndPoint& LineData::rightPt() const { return end1Pt().isLeftOf(end2Pt()) ? end2_pt : end1_pt; }
00276 EndPoint& LineData::topPt() { return end1Pt().isAbove(end2Pt()) ? end1_pt : end2_pt; }
00277 const EndPoint& LineData::topPt() const { return end1Pt().isAbove(end2Pt()) ? end1_pt : end2_pt; }
00278 EndPoint& LineData::bottomPt() { return end1Pt().isAbove(end2Pt()) ? end2_pt : end1_pt; }
00279 const EndPoint& LineData::bottomPt() const { return end1Pt().isAbove(end2Pt()) ? end2_pt : end1_pt; }
00280
00281 Shape<PointData> LineData::leftPtShape() {
00282 Shape<PointData> result(new PointData(*space, leftPt()));
00283 result->setName("leftPt");
00284 result->inheritFrom(*this);
00285 result->setViewable(false);
00286 return result;
00287 }
00288
00289 Shape<PointData> LineData::rightPtShape() {
00290 Shape<PointData> result(new PointData(*space, rightPt()));
00291 result->setName("rightPt");
00292 result->inheritFrom(*this);
00293 result->setViewable(false);
00294 return result;
00295 }
00296
00297 Shape<PointData> LineData::topPtShape() {
00298 Shape<PointData> result(new PointData(*space, topPt()));
00299 result->setName("topPt");
00300 result->inheritFrom(*this);
00301 result->setViewable(false);
00302 return result;
00303 }
00304
00305 Shape<PointData> LineData::bottomPtShape() {
00306 Shape<PointData> result(new PointData(*space, bottomPt()));
00307 result->setName("bottomPt");
00308 result->inheritFrom(*this);
00309 result->setViewable(false);
00310 return result;
00311 }
00312
00313 EndPoint& LineData::firstPt() {
00314 if ( isNotVertical() )
00315 if ( end1Pt().coordX() < end2Pt().coordX() )
00316 return end1Pt();
00317 else return end2Pt();
00318 else
00319 if ( end1Pt().coordY() < end2Pt().coordY() )
00320 return end1Pt();
00321 else return end2Pt();
00322 }
00323
00324 const EndPoint& LineData::firstPt() const {
00325 if ( isNotVertical() )
00326 if ( end1Pt().coordX() < end2Pt().coordX() )
00327 return end1Pt();
00328 else return end2Pt();
00329 else
00330 if ( end1Pt().coordY() < end2Pt().coordY() )
00331 return end1Pt();
00332 else return end2Pt();
00333 }
00334
00335 const EndPoint& LineData::firstPt(const Shape<LineData> &otherline) const {
00336 if ( isNotVertical() )
00337 if ( otherline->end1Pt().coordX() < otherline->end2Pt().coordX() )
00338 return otherline->end1Pt();
00339 else return otherline->end2Pt();
00340 else
00341 if ( otherline->end1Pt().coordY() < otherline->end2Pt().coordY() )
00342 return otherline->end1Pt();
00343 else return otherline->end2Pt();
00344 }
00345
00346 EndPoint& LineData::secondPt() {
00347 if ( isNotVertical() )
00348 if ( end1Pt().coordX() > end2Pt().coordX() )
00349 return end1Pt();
00350 else return end2Pt();
00351 else
00352 if ( end1Pt().coordY() > end2Pt().coordY() )
00353 return end1Pt();
00354 else return end2Pt();
00355 }
00356
00357 const EndPoint& LineData::secondPt() const {
00358 if ( isNotVertical() )
00359 if ( end1Pt().coordX() > end2Pt().coordX() )
00360 return end1Pt();
00361 else return end2Pt();
00362 else
00363 if ( end1Pt().coordY() > end2Pt().coordY() )
00364 return end1Pt();
00365 else return end2Pt();
00366 }
00367
00368 const EndPoint& LineData::secondPt(const Shape<LineData> &otherline) const {
00369 if ( isNotVertical() )
00370 if ( otherline->end1Pt().coordX() > otherline->end2Pt().coordX() )
00371 return otherline->end1Pt();
00372 else return otherline->end2Pt();
00373 else
00374 if ( otherline->end1Pt().coordY() > otherline->end2Pt().coordY() )
00375 return otherline->end1Pt();
00376 else return otherline->end2Pt();
00377 }
00378
00379 Shape<PointData> LineData::firstPtShape() {
00380 Shape<PointData> result(new PointData(*space, firstPt()));
00381 result->setName("firstPt");
00382 result->inheritFrom(*this);
00383 result->setViewable(false);
00384 return result;
00385 }
00386
00387 Shape<PointData> LineData::secondPtShape() {
00388 Shape<PointData> result(new PointData(*space, secondPt()));
00389 result->setName("secondPt");
00390 result->inheritFrom(*this);
00391 result->setViewable(false);
00392 return result;
00393 }
00394
00395 coordinate_t LineData::firstPtCoord() const {
00396 return isNotVertical() ? firstPt().coordX() : firstPt().coordY();
00397 }
00398
00399 coordinate_t LineData::firstPtCoord(const Shape<LineData> &otherline) const {
00400 return isNotVertical() ?
00401 firstPt(otherline).coordX() :
00402 firstPt(otherline).coordY();
00403 }
00404
00405 coordinate_t LineData::secondPtCoord() const {
00406 return isNotVertical() ? secondPt().coordX() : secondPt().coordY();
00407 }
00408
00409 coordinate_t LineData::secondPtCoord(const Shape<LineData> &otherline) const {
00410 return isNotVertical() ?
00411 secondPt(otherline).coordX() :
00412 secondPt(otherline).coordY();
00413 }
00414
00415
00416
00417
00418 void LineData::setEndPts(const EndPoint& _end1_pt, const EndPoint& _end2_pt) {
00419 end1_pt.setCoords(_end1_pt);
00420 end1_pt.setActive(_end1_pt.isActive());
00421 end1_pt.setValid(_end1_pt.isValid());
00422 end1_pt.setNumUpdates(_end1_pt.numUpdates());
00423
00424 end2_pt.setCoords(_end2_pt);
00425 end2_pt.setActive(_end2_pt.isActive());
00426 end2_pt.setValid(_end2_pt.isValid());
00427 end2_pt.setNumUpdates(_end2_pt.numUpdates());
00428
00429 update_derived_properties();
00430 }
00431
00432
00433
00434
00435 std::pair<float,float> LineData::lineEquation_mb() const {
00436 float m;
00437 if ((fabs(end2Pt().coordX() - end1Pt().coordX()) * BIG_SLOPE)
00438 <= fabs(end2Pt().coordY() - end2Pt().coordY()))
00439 m = BIG_SLOPE;
00440 else
00441 m = (end2Pt().coordY() - end1Pt().coordY())/(end2Pt().coordX() - end1Pt().coordX());
00442 float b = end1Pt().coordY() - m * end1Pt().coordX();
00443 return pair<float,float>(m,b);
00444 }
00445
00446
00447
00448 std::vector<float> LineData::lineEquation_abc_xz() const {
00449 float dx = end2Pt().coordX() - end1Pt().coordX();
00450 float dz = end2Pt().coordZ() - end1Pt().coordZ();
00451
00452 std::vector<float> abc(3,1);
00453 float& a = abc[0];
00454 float& b = abc[1];
00455 float& c = abc[2];
00456
00457
00458 if((dx == 0)
00459 || (dz/dx > BIG_SLOPE)) {
00460 a = 1;
00461 b = 0;
00462 c = end1Pt().coordX();
00463 }
00464
00465
00466 else if((dz == 0)
00467 || (dx/dz > BIG_SLOPE)) {
00468 a = 0;
00469 b = 1;
00470 c = end1Pt().coordZ();
00471 }
00472
00473
00474 else {
00475 a = 1;
00476 b = (end1Pt().coordX() - end2Pt().coordX())
00477 / (end2Pt().coordZ() - end1Pt().coordZ());
00478 c = end1Pt().coordX() + b*end1Pt().coordZ();
00479 }
00480
00481 return(abc);
00482
00483 }
00484
00485
00486 std::vector<float> LineData::lineEquation_abc() const {
00487 float dx = end2Pt().coordX() - end1Pt().coordX();
00488 float dy = end2Pt().coordY() - end1Pt().coordY();
00489
00490 std::vector<float> abc(3,1);
00491 float& a = abc[0];
00492 float& b = abc[1];
00493 float& c = abc[2];
00494
00495
00496 if( std::abs(dx) < 1.0e-6f || Slope(dy/dx) > BIG_SLOPE) {
00497 a = 1;
00498 b = 0;
00499 c = end1Pt().coordX();
00500 }
00501
00502
00503 else if ( std::abs(dy) < 1.0e-6f || Slope(dx/dy) > BIG_SLOPE ) {
00504 a = 0;
00505 b = 1;
00506 c = end1Pt().coordY();
00507 }
00508
00509
00510 else {
00511 a = 1;
00512
00513
00514 b = -dx / dy;
00515 c = end1Pt().coordX() + b*end1Pt().coordY();
00516 }
00517
00518 return(abc);
00519 }
00520
00521
00522
00523
00524 void LineData::update_derived_properties() {
00525 rho_norm = perpendicularDistanceFrom(origin_pt);
00526 const vector<float> abc = lineEquation_abc();
00527 const float& a1 = abc[0];
00528 const float& b1 = abc[1];
00529 const float& c1 = abc[2];
00530 const float c1sign = (c1 >= 0) ? 1 : -1;
00531 theta_norm = atan2(b1*c1sign, a1*c1sign);
00532 orientation = theta_norm + AngPi((orientation_t)M_PI/2);
00533 length = end1Pt().distanceFrom(end2Pt());
00534 const ReferenceFrameType_t ref = getRefFrameType();
00535 end1_pt.setRefFrameType(ref);
00536 end2_pt.setRefFrameType(ref);
00537 deleteRendering();
00538 }
00539
00540 bool LineData::isNotVertical() const {
00541 const AngPi threshold = (orientation_t)M_PI / 3;
00542 const AngPi orient = getOrientation();
00543 return (orient <= threshold) || (orient >= (orientation_t)M_PI - threshold);
00544 }
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575 bool LineData::pointIsLeftOf(const Point& pt) const {
00576 const EndPoint &p1 =
00577 ( getRefFrameType() == camcentric )
00578 ? ((end1_pt.coordY() < end2_pt.coordY()) ? end1_pt : end2_pt)
00579 : ((end1_pt.coordX() < end2_pt.coordX()) ? end1_pt : end2_pt);
00580 const EndPoint &p2 = (&p1 == &end1_pt) ? end2_pt : end1_pt;
00581 if ( (getRefFrameType()==camcentric) ? (p1.coordY() == p2.coordY()) : (p1.coordX() == p2.coordX()) )
00582 return false;
00583 else
00584 return ( (p2.coordX() - p1.coordX()) * (pt.coordY() - p1.coordY()) -
00585 (p2.coordY() - p1.coordY()) * (pt.coordX() - p1.coordX()) ) > 0;
00586 }
00587
00588 bool LineData::pointIsRightOf(const Point& pt) const {
00589 const EndPoint &p1 =
00590 ( getRefFrameType() == camcentric )
00591 ? ((end1_pt.coordY() < end2_pt.coordY()) ? end1_pt : end2_pt)
00592 : ((end1_pt.coordX() < end2_pt.coordX()) ? end1_pt : end2_pt);
00593 const EndPoint &p2 = (&p1 == &end1_pt) ? end2_pt : end1_pt;
00594 if ( (getRefFrameType()==camcentric) ? (p1.coordY() == p2.coordY()) : (p1.coordX() == p2.coordX()) )
00595 return false;
00596 else
00597 return ( (p2.coordX() - p1.coordX()) * (pt.coordY() - p1.coordY()) -
00598 (p2.coordY() - p1.coordY()) * (pt.coordX() - p1.coordX()) ) < 0;
00599 }
00600
00601 bool LineData::pointIsAbove(const Point& pt) const {
00602 const EndPoint &p1 =
00603 ( getRefFrameType() == camcentric )
00604 ? ((end1_pt.coordX() < end2_pt.coordX()) ? end1_pt : end2_pt)
00605 : ((end1_pt.coordY() < end2_pt.coordY()) ? end1_pt : end2_pt);
00606 const EndPoint &p2 = (&p1 == &end1_pt) ? end2_pt : end1_pt;
00607 if ( (getRefFrameType()==camcentric) ? (p1.coordX() == p2.coordX()) : (p1.coordY() == p2.coordY()) )
00608 return false;
00609 else
00610 return ( (p2.coordX() - p1.coordX()) * (pt.coordY() - p1.coordY()) -
00611 (p2.coordY() - p1.coordY()) * (pt.coordX() - p1.coordX()) ) > 0;
00612 }
00613
00614 bool LineData::pointIsBelow(const Point& pt) const {
00615 const EndPoint &p1 =
00616 ( getRefFrameType() == camcentric )
00617 ? ((end1_pt.coordX() < end2_pt.coordX()) ? end1_pt : end2_pt)
00618 : ((end1_pt.coordY() < end2_pt.coordY()) ? end1_pt : end2_pt);
00619 const EndPoint &p2 = (&p1 == &end1_pt) ? end2_pt : end1_pt;
00620 if ( (getRefFrameType()==camcentric) ? (p1.coordX() == p2.coordX()) : (p1.coordY() == p2.coordY()) )
00621 return false;
00622 else
00623 return ( (p2.coordX() - p1.coordX()) * (pt.coordY() - p1.coordY()) -
00624 (p2.coordY() - p1.coordY()) * (pt.coordX() - p1.coordX()) ) < 0;
00625 }
00626
00627
00628
00629 bool LineData::isLongerThan(const Shape<LineData>& other) const {
00630 return length > other->length; }
00631
00632 bool LineData::isLongerThan(float ref_length) const {
00633 return length > ref_length; }
00634
00635 bool LineData::isShorterThan(const Shape<LineData>& other) const {
00636 return length < other->length; }
00637
00638 bool LineData::isShorterThan(float ref_length) const {
00639 return length < ref_length; }
00640
00641 bool LineData::isBetween(const Point &p, const LineData &other) const {
00642 if (getOrientation() == other.getOrientation()) {
00643 float dl = perpendicularDistanceFrom(other.end1Pt());
00644 return (perpendicularDistanceFrom(p) <= dl && other.perpendicularDistanceFrom(p) <= dl);
00645 }
00646 else {
00647 bool b;
00648 const LineData p_line (*space, p,
00649 intersectionWithLine(other, b, b));
00650 const AngPi theta_pline = p_line.getOrientation();
00651 const AngPi theta_greater =
00652 (getOrientation() > other.getOrientation()) ? getOrientation() : other.getOrientation();
00653 const AngPi theta_smaller =
00654 (getOrientation() < other.getOrientation()) ? getOrientation() : other.getOrientation();
00655 if (theta_greater - theta_smaller > M_PI/2)
00656 return (theta_pline >= theta_greater || theta_pline <= theta_smaller);
00657 else
00658 return (theta_pline <= theta_greater && theta_pline >= theta_smaller);
00659 }
00660 }
00661
00662
00663
00664
00665 bool
00666 LineData::intersectsLine(const Shape<LineData>& other) const {
00667 return intersectsLine(other.getData());
00668 }
00669
00670 bool
00671 LineData::intersectsLine(const LineData& other) const {
00672
00673 pair<float,float> F = lineEquation_mb();
00674
00675
00676 pair<float,float> G = other.lineEquation_mb();
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696 float r3 = F.first * other.end1Pt().coordX() + F.second - other.end1Pt().coordY();
00697
00698
00699 float r4 = F.first * other.end2Pt().coordX() + F.second - other.end2Pt().coordY();
00700
00701
00702
00703
00704
00705
00706 if((r3 != 0)
00707 && (r4 != 0)
00708 && (signbit(r3) == signbit(r4))
00709 )
00710 return false;
00711
00712
00713
00714
00715
00716 float r1 = G.first * end1Pt().coordX() + G.second - end1Pt().coordY();
00717
00718
00719 float r2 = G.first * end2Pt().coordX() + G.second - end2Pt().coordY();
00720
00721
00722
00723
00724
00725
00726 if((r1 != 0)
00727 && (r2 != 0)
00728 && (signbit(r1) == signbit(r2))
00729 )
00730 return false;
00731
00732
00733 return true;
00734 }
00735
00736
00737 Point LineData::intersectionWithLine(const Shape<LineData>& other,
00738 bool& intersection_on_this,
00739 bool& intersection_on_other) const {
00740 return intersectionWithLine(other.getData(), intersection_on_this,intersection_on_other);
00741 }
00742
00743 Point
00744 LineData::intersectionWithLine(const LineData& other,
00745 bool& intersection_on_this, bool& intersection_on_other) const {
00746
00747
00748
00749
00750
00751
00752 float x1, x2, x3, x4, y1, y2, y3, y4;
00753 x1 = end1Pt().coordX();
00754 x2 = end2Pt().coordX();
00755 x3 = other.end1Pt().coordX();
00756 x4 = other.end2Pt().coordX();
00757 y1 = end1Pt().coordY();
00758 y2 = end2Pt().coordY();
00759 y3 = other.end1Pt().coordY();
00760 y4 = other.end2Pt().coordY();
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773 float denom = ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));
00774 float u_a_numerator = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3));
00775 float u_b_numerator = ((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3));
00776
00777
00778 if(denom == 0.0) {
00779 if (u_a_numerator == 0.0 && u_b_numerator == 0.0) {
00780
00781
00782
00783 return(end1Pt());
00784 }
00785 else {
00786 cout << x1 << " " << x2 << " " << x3 << " " << x4 << " "
00787 << y1 << " " << y2 << " " << y3 << " " << y4 << endl;
00788 cout << "this theta; " << getOrientation() << ", other theta: " << other.getOrientation() << endl;
00789 cerr << "ERROR in intersectionWithLine: lines are parallel!\n";
00790 return(Point(-9999.0f,-99999.0f));
00791 }
00792 }
00793
00794 else {
00795 float u_a = u_a_numerator / denom;
00796 float u_b = u_b_numerator / denom;
00797
00798
00799 if(0<=u_a && u_a<=1)
00800 intersection_on_this = true;
00801 else
00802 intersection_on_this = false;
00803
00804
00805 if(0<=u_b && u_b<=1)
00806 intersection_on_other = true;
00807 else
00808 intersection_on_other = false;
00809
00810 return(Point((x1+u_a*(x2-x1)),
00811 (y1+u_a*(y2-y1))));
00812 }
00813 }
00814
00815
00816
00817
00818 float LineData::perpendicularDistanceFrom(const Point& otherPt) const {
00819
00820
00821
00822
00823 vector<float> abc = lineEquation_abc();
00824 float& a = abc[0];
00825 float& b = abc[1];
00826 float& c = abc[2];
00827
00828
00829
00830
00831
00832 float d = fabs((a * otherPt.coordX() + b * otherPt.coordY() - c)/sqrt(a*a + b*b));
00833
00834 return(d);
00835 }
00836
00837
00838
00839
00840
00841
00842
00843
00844 #define EXTRACT_LINE_MIN_AREA 60
00845
00846 #define BEG_DIST_THRESH 2
00847 #define END_DIST_THRESH 2
00848
00849 #define EXTRACT_LINE_MIN_SCORE 60
00850 #define BIG_SLOPE_CS 5000.0
00851
00852
00853 bool LineData::pointsOnPerimeterOfWindow(Sketch<bool> const& sketch, double t, double r, Point& pt1, Point& pt2) {
00854 const int width = sketch->getWidth(), height = sketch->getHeight();
00855 r -= RSIZE / 2;
00856 t *= M_PI/180;
00857
00858 pt1.setCoords(cos(t), sin(t));
00859 pt1 *= r;
00860 t += M_PI/2.0;
00861 pt2.setCoords(cos(t), sin(t));
00862 pt2 *= 10;
00863 pt2 += pt1;
00864
00865
00866 if (fabs(pt2.coordX() - pt1.coordX()) <= 0.001) {
00867 pt2.setCoords(pt1.coordX(), height);
00868 return true;
00869 }
00870
00871 double m = (pt2.coordY() - pt1.coordY()) / (pt2.coordX() - pt1.coordX());
00872 double b = pt1.coordY() - m*pt1.coordX();
00873
00874 static vector<Point> accOfPoints;
00875 accOfPoints.clear();
00876
00877
00878 if (b >= 0 && b <= height)
00879 accOfPoints.push_back(Point(0, b));
00880
00881
00882 if ((m*width + b) >= 0 && (m*width + b) <= height)
00883 accOfPoints.push_back(Point( width, m*width + b));
00884
00885
00886 if ((height-b)/m >= 0 && (height-b)/m <= width)
00887 accOfPoints.push_back(Point((height-b)/m, height));
00888
00889
00890 if (-b/m >= 0 && -b/m <= width)
00891 accOfPoints.push_back(Point( -b/m, 0));
00892
00893
00894 if (accOfPoints.size() != 2)
00895 return false;
00896
00897 pt1 = accOfPoints[0];
00898 pt2 = accOfPoints[1];
00899 return true;
00900 }
00901
00902 double LineData::getScore(int t, int r, int height, short hough[TSIZE][RSIZE], float ptsArray[TSIZE][RSIZE]) {
00903 int tally = hough[t][r];
00904
00905
00906
00907
00908
00909 if(ptsArray[t][r] == 0)
00910 return 0;
00911 double scale = min((height / ptsArray[t][r]), 1.0f);
00912 if(tally * scale > 15)
00913 return tally * scale;
00914 return 0;
00915 }
00916
00917 vector<Shape<LineData> > LineData::houghExtractLines(Sketch<bool> const& sketch, Sketch<bool> const& occluders, const int num_lines) {
00918 const int width = sketch->getWidth(), height = sketch->getHeight();
00919 SketchSpace &SkS = sketch->getSpace();
00920 ShapeSpace &ShS = SkS.getDualSpace();
00921
00922
00923
00924 NEW_SKETCH_N(skelDist,uint,visops::mdist(sketch));
00925
00926 short hough[TSIZE][RSIZE];
00927 float ptsArray[TSIZE][RSIZE];
00928
00929
00930 memset(hough, 0, TSIZE*RSIZE*sizeof(short));
00931 memset(ptsArray, 0, TSIZE*RSIZE*sizeof(float));
00932 Point pt1, pt2;
00933 for (int t = 0; t < TSIZE; t++)
00934 for (int r = 0; r < RSIZE; r++)
00935 if (pointsOnPerimeterOfWindow(sketch, t, r, pt1, pt2))
00936 ptsArray[t][r] = (pt1-pt2).xyNorm();
00937
00938
00939 NEW_SKETCH_N(edges, bool, visops::non_bounds(sketch, 2));
00940
00941
00942 for(int x = 0; x < width; x++) {
00943 for(int y = 0; y < height; y++) {
00944 if(edges(x,y)) {
00945 for(int t = 0; t < TSIZE; t++) {
00946 double theta = M_PI/180.0 * t;
00947 int r = int(x*cos(theta) + y*sin(theta) + RSIZE/2);
00948 hough[t][r]++;
00949 }
00950 }
00951 }
00952 }
00953
00954
00955 for(int t = 0; t < TSIZE; t++) {
00956 for(int r = 0; r < RSIZE; r++) {
00957 hough[t][r] = (short)getScore(t, r, height, hough, ptsArray);
00958 }
00959 }
00960
00961 const int tRange = 10;
00962 const int rRange = 20;
00963 vector<Shape<LineData> > lines_vec;
00964 for (int k = 0; k < num_lines; k++) {
00965 int maxScore = 0;
00966 int maxT = 0;
00967 int maxR = 0;
00968 for (int i = 0; i < TSIZE; i++)
00969 for(int j = 0; j < RSIZE; j++)
00970 if (hough[i][j] > maxScore) {
00971 maxScore = hough[i][j];
00972 maxT = i;
00973 maxR = j;
00974 }
00975 if (maxScore < EXTRACT_LINE_MIN_SCORE) break;
00976
00977 if(!pointsOnPerimeterOfWindow(sketch, maxT, maxR, pt1, pt2)) {
00978
00979 continue;
00980 }
00981
00982
00983 float x_normpoint = (maxR -RSIZE/2)*cos(maxT * M_PI/180.0);
00984 float y_normpoint = (maxR -RSIZE/2)*sin(maxT * M_PI/180.0);
00985
00986 float m = std::max(std::min(std::tan((maxT * M_PI/180.0)+AngPi((orientation_t)M_PI/2)), BIG_SLOPE_CS), -BIG_SLOPE_CS);
00987 float b = y_normpoint - m*x_normpoint;
00988 Point pt(0, b);
00989 AngPi orientation = atan(m);
00990 Shape<LineData> extracted_line(ShS, pt, orientation);
00991 if ( std::abs(m) <= 1 )
00992 extracted_line->scanHorizForEndPts(skelDist,occluders,m,b);
00993 else
00994 extracted_line->scanVertForEndPts(skelDist,occluders,m,b);
00995
00996 extracted_line->setColor(sketch->getColor());
00997 extracted_line->setParentId(sketch->getViewableId());
00998 extracted_line->firstPt().checkValidity(width,height,BEG_DIST_THRESH);
00999 extracted_line->secondPt().checkValidity(width,height,BEG_DIST_THRESH);
01000
01001 SkS.applyTmatinv(extracted_line->firstPt().getCoords());
01002 SkS.applyTmatinv(extracted_line->secondPt().getCoords());
01003 extracted_line->update_derived_properties();
01004 bool matched = false;
01005 for ( vector<Shape<LineData> >::iterator ln_it = lines_vec.begin(); ln_it != lines_vec.end(); ln_it++ ) {
01006 Shape<LineData> &ln = *ln_it;
01007 if ( extracted_line->isMatchFor(ln) ) {
01008 matched = true;
01009 extracted_line.deleteShape();
01010 k--;
01011 break;
01012 }
01013 }
01014 if (matched == false)
01015 lines_vec.push_back(extracted_line);
01016
01017
01018 for (int i = maxT-tRange; i <= maxT+tRange; i++ )
01019 for (int j = maxR-rRange; j <= maxR+rRange; j++ )
01020 if (i >=0 && i < TSIZE && j >=0 && j < RSIZE) {
01021
01022 hough[i][j] = 0;
01023 }
01024 }
01025 return lines_vec;
01026 }
01027
01028 Shape<LineData> LineData::extractLine(Sketch<bool>& sketch) {
01029
01030 NEW_SKETCH_N(occluders, bool, visops::copy(sketch));
01031 return houghExtractLines(sketch, occluders, 1)[0];
01032
01033
01034 }
01035
01036 Shape<LineData> LineData::extractLine(Sketch<bool>& sketch, const Sketch<bool>& occlusions) {
01037
01038
01039
01040
01041 return houghExtractLines(sketch, occlusions, 1)[0];
01042 }
01043
01044 vector<Shape<LineData> > LineData::extractLines(Sketch<bool> const& sketch, const int num_lines) {
01045
01046 NEW_SKETCH_N(occluders, bool, visops::copy(sketch));
01047 return houghExtractLines(sketch, occluders, num_lines);
01048
01049
01050 }
01051
01052 vector<Shape<LineData> > LineData::extractLines(Sketch<bool> const& sketch, Sketch<bool> const& occluders, const int num_lines) {
01053
01054
01055
01056
01057 return houghExtractLines(sketch, occluders, num_lines);
01058 }
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202 Shape<LineData> LineData::splitLine(ShapeSpace &ShS, Region &skelchunk,
01203 Sketch<bool> &skeleton, const Sketch<bool> &occlusions) {
01204
01205 Point bounds[4] = {skelchunk.findTopBoundPoint(), skelchunk.findLeftBoundPoint(),
01206 skelchunk.findRightBoundPoint(), skelchunk.findBotBoundPoint()};
01207
01208
01209
01210
01211 for (int i = 0; i < 4; i++) {
01212 for (int j = i+1; j < 4; j++) {
01213 if (bounds[i].distanceFrom(bounds[j]) > 20 && ! skelchunk.isContained((bounds[i]+bounds[j])/2.f, 3)) {
01214
01215 LineData ln(ShS,bounds[i],bounds[j]);
01216 Point most_distant(skelchunk.mostDistantPtFrom(ln));
01217 ShS.getDualSpace().applyTmat(most_distant.getCoords());
01218 int const clear_dist = 15;
01219 int x1 = max(0, int(most_distant.coordX() - clear_dist));
01220 int x2 = min(skeleton.width-1, int(most_distant.coordX() + clear_dist));
01221 int y1 = max(0, int(most_distant.coordY() - clear_dist));
01222 int y2 = min(skeleton.height-1, int(most_distant.coordY() + clear_dist));
01223 for (int x = x1; x <= x2; x++)
01224 for (int y = y1; y <= y2; y++)
01225 skeleton(x,y) = false;
01226 return extractLine(skeleton, occlusions);
01227 }
01228 }
01229 }
01230 ShapeRoot invalid;
01231 return ShapeRootType(invalid,LineData);
01232 }
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264 void LineData::scanHorizForEndPts(const Sketch<uint>& skelDist,
01265 const Sketch<bool>& occlusions,
01266 float m, float b) {
01267
01268 bool on_line = false;
01269 int beg_dist_thresh = BEG_DIST_THRESH;
01270 int end_dist_thresh = END_DIST_THRESH;
01271 int curxstart = -1;
01272 int possxstop = -1;
01273 int bestxstart = -1;
01274 int bestxstop = -1;
01275 int bestlength = -1;
01276 for (int x = 0, y, dist=0; x < skelDist.width; x++) {
01277 y = int(m*x+b);
01278
01279
01280 if (y >= 0 && y < skelDist.height) {
01281 dist = skelDist(x,y);
01282
01283 if (on_line == false) {
01284 if (dist <= beg_dist_thresh) {
01285
01286 on_line = true;
01287 curxstart = x - dist;
01288
01289 int curystart;
01290 bool backupflag = false;
01291 while ( curxstart >= 0 && (curystart=int(m*curxstart+b)) >= 0 && curystart < skelDist.height )
01292 if ( occlusions(curxstart,curystart) || skelDist(curxstart,curystart) == 0 ) {
01293 --curxstart;
01294 backupflag = true;
01295 } else {
01296 curxstart += backupflag;
01297 break;
01298 }
01299 if ( curxstart < 0)
01300 curxstart = 0;
01301 }
01302 }
01303 else {
01304 const bool occ = occlusions(x,y);
01305
01306 if ( dist <= end_dist_thresh || occ ) {
01307 if ( occ )
01308 possxstop = x;
01309 else
01310 possxstop = x - dist;
01311
01312 if ( possxstop-curxstart > bestlength ) {
01313 bestxstart = curxstart;
01314 bestxstop = possxstop;
01315 bestlength = bestxstop-bestxstart;
01316
01317 }
01318 }
01319 else if ( dist > extractorGapTolerance ) {
01320
01321 on_line = false;
01322
01323 };
01324
01325 }
01326 }
01327 }
01328
01329
01330 float y1 = m*bestxstart + b;
01331 float y2 = m*bestxstop + b;
01332 setEndPts(Point(bestxstart,y1), Point(bestxstop,y2));
01333
01334 balanceEndPointHoriz(end1_pt,occlusions,m,b);
01335 balanceEndPointHoriz(end2_pt,occlusions,m,b);
01336 }
01337
01338 void LineData::scanVertForEndPts(const Sketch<uint>& skelDist,
01339 const Sketch<bool>& occlusions,
01340 float m, float b) {
01341
01342 bool on_line = false;
01343 int beg_dist_thresh = BEG_DIST_THRESH;
01344 int end_dist_thresh = END_DIST_THRESH;
01345 int curystart = -1;
01346 int possystop = -1;
01347 int bestystart = -1;
01348 int bestystop = -1;
01349 int bestlength = -1;
01350 for (int x, y = 0, dist=0; y < skelDist.height; y++) {
01351 x = int((y-b)/m);
01352
01353
01354 if (x >= 0 && x < skelDist.width) {
01355 dist = int(skelDist(x,y));
01356
01357 if (on_line == false) {
01358 if (dist <= beg_dist_thresh) {
01359
01360 on_line = true;
01361 curystart = y - dist;
01362
01363 int curxstart;
01364 bool backupflag = false;
01365 while ( curystart >= 0 && (curxstart=int((curystart-b)/m)) >= 0 && curxstart < skelDist.width )
01366 if ( occlusions(curxstart,curystart) || skelDist(curxstart,curystart) == 0 ){
01367 --curystart;
01368 backupflag = true;
01369 } else {
01370 curystart += backupflag;
01371 break;
01372 }
01373 if ( curystart < 0)
01374 curystart = 0;
01375 }
01376 }
01377 else {
01378 const bool occ = occlusions(x,y);
01379
01380 if ( dist <= end_dist_thresh || occ ) {
01381 if ( occ )
01382 possystop = y;
01383 else
01384 possystop = y - dist;
01385
01386 if ( possystop-curystart > bestlength ) {
01387 bestystart = curystart;
01388 bestystop = possystop;
01389 bestlength = bestystop-bestystart;
01390
01391 }
01392 }
01393 else if ( dist > extractorGapTolerance ) {
01394
01395 on_line = false;
01396
01397 };
01398
01399 }
01400 }
01401 }
01402
01403 float x1 = (bestystart-b)/m;
01404 float x2 = (bestystop-b)/m;
01405
01406 setEndPts(Point(x1,bestystart), Point(x2,bestystop));
01407
01408 balanceEndPointVert(end1_pt,occlusions,m,b);
01409 balanceEndPointVert(end2_pt,occlusions,m,b);
01410 }
01411
01412 void LineData::balanceEndPointHoriz(EndPoint &, Sketch<bool> const &, float, float) {
01413
01414
01415
01416
01417
01418
01419 return;
01420 }
01421
01422 void LineData::balanceEndPointVert(EndPoint &pt, Sketch<bool> const &occluders, float m, float b) {
01423 int ystep = ( pt.coordY() < max(end1_pt.coordY(),end2_pt.coordY()) ? +1 : -1 );
01424 int leftpix = 0, rightpix = 0;
01425 int const balance_rows = 8;
01426 int const row_samples = 10;
01427
01428 for ( int y = (int)pt.coordY(), ycnt=balance_rows ;
01429 y>= 0 && y<occluders.height && ycnt-- > 0 ; y+=ystep ) {
01430 int const xstart = (int) ((y-b)/m);
01431 for ( int x = xstart-row_samples; x < xstart; x++ )
01432 if ( x >= 0 )
01433 leftpix += occluders(x,y);
01434 for ( int x = xstart+row_samples; x > xstart; x-- )
01435 if ( x < occluders.width )
01436 rightpix += occluders(x,y);
01437
01438 }
01439 float const new_x = pt.coordX() + (rightpix-leftpix)/(2*balance_rows);
01440
01441 pt.setCoords(new_x, pt.coordY());
01442 }
01443
01444
01445
01446
01447
01448
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509
01510
01511
01512
01513 void LineData::clearLine(Sketch<bool>& sketch) {
01514 const Sketch<bool>& line_rendering = getRendering();
01515 uint const clear_dist = 5;
01516 Sketch<bool> not_too_close = (visops::mdist(line_rendering) >= clear_dist);
01517 sketch &= not_too_close;
01518 }
01519
01520
01521
01522
01523
01524
01525
01526 Sketch<bool>& LineData::getRendering() {
01527 if ( ! end1Pt().rendering_valid || ! end2Pt().rendering_valid )
01528 deleteRendering();
01529 if ( rendering_sketch == NULL )
01530 rendering_sketch = render();
01531 return *rendering_sketch;
01532 }
01533
01534
01535
01536 Sketch<bool>* LineData::render() const {
01537 SketchSpace &renderspace = space->getDualSpace();
01538 int const width = renderspace.getWidth();
01539 int const height = renderspace.getHeight();
01540 float x1,y1,x2,y2;
01541 setDrawCoords(x1, y1, x2, y2, width, height);
01542 Sketch<bool>* draw_result =
01543 new Sketch<bool>(renderspace, "render("+getName()+")");
01544
01545
01546 (*draw_result)->inheritFrom(*this);
01547 *draw_result = 0;
01548 drawline2d(*draw_result, (int)x1, (int)y1, (int)x2, (int)y2);
01549 end1Pt().rendering_valid = true;
01550 end2Pt().rendering_valid = true;
01551 return draw_result;
01552 }
01553
01554
01555
01556 void LineData::setDrawCoords(float& x1,float& y1, float& x2, float& y2,
01557 const int width, const int height) const {
01558 EndPoint e1(end1Pt());
01559 EndPoint e2(end2Pt());
01560
01561 space->getDualSpace().applyTmat(e1.getCoords());
01562 space->getDualSpace().applyTmat(e2.getCoords());
01563 const EndPoint &left_point = e1.coordX() <= e2.coordX() ? e1 : e2;
01564 const EndPoint &right_point = e1.coordX() <= e2.coordX() ? e2 : e1;
01565
01566
01567
01568 if( left_point.coordY() == right_point.coordY()) {
01569 if (!left_point.isActive())
01570 x1 = 0;
01571 else x1 = max(0.0f,min(width-1.0f,left_point.coordX()));
01572
01573 if (!right_point.isActive())
01574 x2 = width-1;
01575 else x2 = max(0.0f,min(width-1.0f,right_point.coordX()));
01576
01577 y1 = left_point.coordY();
01578 y2 = y1;
01579 }
01580 else if ( left_point.coordX() == right_point.coordX()) {
01581
01582 const EndPoint &top_point = e1.coordY() <= e2.coordY() ? e1 : e2;
01583 const EndPoint &bottom_point = e1.coordY() <= e2.coordY() ? e2 : e1;
01584
01585
01586 if(!top_point.isActive())
01587 y1 = 0;
01588 else y1 = max(0.0f,min(height-1.0f,top_point.coordY()));
01589
01590 if (!bottom_point.isActive())
01591 y2 = height-1;
01592 else y2 = max(0.f,min(height-1.0f,bottom_point.coordY()));
01593
01594 x1 = left_point.coordX();
01595 x2 = x1;
01596 }
01597
01598 else {
01599 float const m = (right_point.coordY()-left_point.coordY())/(right_point.coordX()-left_point.coordX());
01600 float const b = left_point.coordY() - m*left_point.coordX();
01601
01602
01603 int const i0x = (int)((0-b)/m);
01604 int const ihx = (int)(((height-1)-b)/m);
01605 int const i0y = (int)(m*0+b);
01606 int const iwy = (int)(m*(width-1)+b);
01607
01608
01609 if ( left_point.isActive() ) {
01610 x1 = left_point.coordX();
01611 y1 = left_point.coordY();
01612 }
01613
01614
01615 else {
01616
01617
01618 if ( i0y >= 0 && i0y < height ) {
01619 x1 = 0;
01620 y1 = i0y;
01621 }
01622
01623
01624 else {
01625
01626
01627 if ( i0x < ihx ) {
01628 x1 = i0x;
01629 y1 = 0;
01630 }
01631
01632
01633 else {
01634 x1 = ihx;
01635 y1 = height-1;
01636 }
01637 }
01638 }
01639
01640
01641 if ( right_point.isActive() ) {
01642 x2 = right_point.coordX();
01643 y2 = right_point.coordY();
01644 }
01645 else {
01646 if ( iwy >= 0 && iwy < height ) {
01647 x2 = width-1;
01648 y2 = iwy;
01649 }
01650 else {
01651 if ( i0x > ihx ) {
01652 x2 = i0x;
01653 y2 = 0;
01654 }
01655 else {
01656 x2 = ihx;
01657 y2 = height-1;
01658 }
01659 }
01660 }
01661 }
01662 }
01663
01664 void LineData::drawline2d(Sketch<bool>& canvas, int x0, int y0, int x1, int y1) {
01665 int width = canvas->getWidth();
01666 int height = canvas->getHeight();
01667
01668
01669
01670
01671 int dx = x1-x0, ax = abs(dx)<<1, sx = signbit(dx) ? -1 : 1;
01672 int dy = y1-y0, ay = abs(dy)<<1, sy = signbit(dy) ? -1 : 1;
01673 int d, x=x0, y=y0;
01674
01675 if ( ax > ay ) {
01676
01677 d = ay-(ax>>1);
01678 for (;;) {
01679 if (x >= 0 && y >= 0 && x < width && y < height)
01680 canvas(x,y) = true;
01681
01682 if (x==x1)
01683 return;
01684
01685 if ( d >= 0 ) {
01686 y += sy;
01687 d -= ax;
01688 }
01689
01690 x += sx;
01691 d += ay;
01692 }
01693 }
01694 else {
01695
01696 d = ax-(ay>>1);
01697 for (;;) {
01698 if (x >= 0 && y >= 0 && x < width && y < height)
01699 canvas(x,y) = true;
01700
01701 if ( y == y1 )
01702 return;
01703
01704 if ( d >= 0 ) {
01705 x += sx;
01706 d -= ay;
01707 }
01708
01709 y += sy;
01710 d += ax;
01711 }
01712 }
01713 }
01714
01715
01716
01717 std::vector<Shape<LineData> > LineData::houghTransform(const Sketch<bool>& fat,
01718 const Sketch<bool>& skinny,
01719 const Sketch<bool>& occlusions,
01720 const size_t num_lines, int minLength)
01721 {
01722 if ( minLength == -1 )
01723 minLength = static_cast<int>(fat->getWidth() * DEFAULT_MIN_LENGTH);
01724 std::vector<Shape<LineData> > result;
01725 ShapeSpace& ShS = fat->getSpace().getDualSpace();
01726
01727 const int width = fat->getWidth(), height = fat->getHeight();
01728 const int numR = 120, numTheta = 120;
01729 const int numRf = 40, numThetaf = 40;
01730 int hsize = numR*numTheta, hsizef = numRf * numThetaf;
01731 int htab[hsize], hfine[hsizef];
01732 float minTheta = 0, maxTheta = 2*(float)M_PI;
01733 float minR = 0, maxR = std::sqrt((float)width*(float)width+(float)height*(float)height);
01734 float thetaSpread = maxTheta - minTheta;
01735 float rSpread = maxR - minR;
01736
01737
01738 for (int i = 0; i < hsize; i++)
01739 htab[i] = 0;
01740
01741
01742 float theta, r;
01743 int ridx;
01744 for (int x = 0; x < width; x++) {
01745 for (int y = 0; y < height; y++) {
01746 if (fat(x,y) == true) {
01747 for (int tidx = 0; tidx < numTheta ; tidx++) {
01748 theta = minTheta + tidx*thetaSpread/numTheta;
01749 r = (float)x*cos(theta)+(float)y*sin(theta);
01750 ridx = (int)((r-minR)*(float)numR/rSpread);
01751 if (ridx >= 0 && ridx < numR)
01752 htab[ridx+tidx*numR]++;
01753 }
01754 }
01755 }
01756 }
01757
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778 int max_val = -1, max_i = 0;
01779 while(result.size() < num_lines) {
01780
01781
01782 max_val = -1;
01783 max_i = 0;
01784 for (int i = 0; i < numR*numTheta; i++) {
01785 if (max_val < htab[i]) {
01786 max_val = htab[i];
01787 max_i = i;
01788 }
01789 }
01790
01791
01792 if (max_val < minLength)
01793 break;
01794
01795
01796 float bestR = (max_i%numR)*rSpread/numR + minR;
01797 float bestTheta = (max_i/numR)*thetaSpread/numTheta + minTheta;
01798
01799
01800 const float fthetaSpread = (float)M_PI/40.f;
01801 const float frSpread = maxR/40.f;
01802 float fminTheta = bestTheta-fthetaSpread/2.f;
01803 float fminR = bestR-frSpread/2.f;
01804
01805 for (int i = 0; i < hsizef; i++)
01806 hfine[i] = 0;
01807
01808
01809 float thetaf, rf;
01810 int ridxf;
01811 for (int x = 0; x < width; x++) {
01812 for (int y = 0; y < height; y++) {
01813 if (skinny(x,y) == true) {
01814 for (int tidx = 0; tidx < numThetaf ; tidx++) {
01815 thetaf = fminTheta + tidx*fthetaSpread/numThetaf;
01816 rf = (float)x*cos(thetaf)+(float)y*sin(thetaf);
01817 ridxf = (int)((rf-fminR)*(float)numRf/frSpread);
01818 if (ridxf >= 0 && ridxf < numRf)
01819 hfine[ridxf+tidx*numRf]++;
01820 }
01821 }
01822 }
01823 }
01824
01825
01826
01827 int max_val_f = -1, max_i_f = 0;
01828 for (int i = 0; i < numRf*numThetaf; i++) {
01829 if (max_val_f < hfine[i]) {
01830 max_val_f = hfine[i];
01831 max_i_f = i;
01832 }
01833 }
01834 float bestRf = (max_i_f%numRf)*frSpread/numRf + fminR;
01835 float bestThetaf = (max_i_f/numRf)*fthetaSpread/numThetaf + fminTheta;
01836
01837
01838
01839 float lineLen = 500;
01840
01841 const float x1 = bestRf*cos(bestThetaf), y1 = bestRf*sin(bestThetaf);
01842 const float x2 = x1+lineLen*std::cos(bestThetaf+(float)M_PI_2), y2 = y1+lineLen*std::sin(bestThetaf+(float)M_PI_2);
01843 const float x3 = x1-lineLen*std::cos(bestThetaf+(float)M_PI_2), y3 = y1-lineLen*std::sin(bestThetaf+(float)M_PI_2);
01844
01845 Point e1(x3,y3), e2(x2,y2);
01846 Shape<LineData> line(ShS,e1,e2);
01847
01848
01849 line->setColor(skinny->getColor());
01850 line->setParentId(skinny->getViewableId());
01851
01852
01853 float m = (y1 != 0) ? -(x1/y1) : BIG_SLOPE;
01854 float b = y1 - m*x1;
01855
01856 NEW_SKETCH_N(skelDist,uint,visops::mdist(skinny));
01857 if ( abs(m) <= 1 )
01858 line->scanHorizForEndPts(skelDist,occlusions,m,b);
01859 else
01860 line->scanVertForEndPts(skelDist,occlusions,m,b);
01861
01862
01863
01864 line->end1_pt.checkValidity(width,height,BEG_DIST_THRESH);
01865 line->end2_pt.checkValidity(width,height,BEG_DIST_THRESH);
01866
01867
01868
01869
01870
01871 float len = line->getLength();
01872 EndPoint start = line->end1_pt;
01873 EndPoint dx = (line->end2_pt - start)/len;
01874 float onCount = 0;
01875 for (float i=0; i<len; i++) {
01876 EndPoint cur = start+dx*i;
01877 if (skinny((int)(cur.coordX()), (int)(cur.coordY()))) {
01878 onCount++;
01879 }
01880 }
01881
01882
01883 std::cout<<"Line with "<<onCount<<" / "<<len<<" pixels";
01884 if (line->isLongerThan(minLength) && (onCount / len) > .5 )
01885 {
01886 std::cout<<" accepted";
01887 result.push_back(line);
01888 }
01889 std::cout<<std::endl;
01890
01891
01892
01893
01894 for(int row = -5; row <= 5; row++)
01895 {
01896 for (int col = -(5-abs(row)); col <=5-abs(row); col++)
01897 {
01898
01899
01900 htab[(max_i - (max_i%numR) + ((max_i+col)%numR)+row*numR + numR*numTheta)%(numR*numTheta)] = 0;
01901 }
01902
01903 }
01904
01905 }
01906
01907 return result;
01908 }
01909
01910 bool LineData::linesParallel(Shape<LineData> l1, Shape<LineData>l2)
01911 {
01912 const float maxDTheta = .15f, minDThetaR = 10.0f;
01913 float dTheta = l1->getOrientation() - l2->getOrientation();
01914 if (dTheta > (float)M_PI_2)
01915 dTheta = dTheta - (float)M_PI;
01916 if (std::abs(dTheta) < maxDTheta)
01917 {
01918 if (std::abs (100*dTheta + (l1->rho_norm - l2->rho_norm)) > minDThetaR)
01919 return true;
01920 }
01921 return false;
01922 }
01923
01924 LineData& LineData::operator=(const LineData& other) {
01925 if (&other == this)
01926 return *this;
01927 BaseData::operator=(other);
01928 end1_pt = other.end1_pt;
01929 end2_pt = other.end2_pt;
01930 rho_norm = other.rho_norm;
01931 theta_norm = other.theta_norm;
01932 orientation = other.orientation;
01933 length = other.length;
01934 return *this;
01935 }
01936
01937
01938
01939 bool LineData::pointsOnSameSide(const Point& p1, const Point& p2)
01940 {
01941 float dx = end2_pt.coordX() - end1_pt.coordX();
01942 float dy = end2_pt.coordY() - end1_pt.coordY();
01943
01944 float p1val = (p1.coordY() - end1_pt.coordY())*dx - (p1.coordX() - end1_pt.coordX())*dy;
01945 float p2val = (p2.coordY() - end1_pt.coordY())*dx - (p2.coordX() - end1_pt.coordX())*dy;
01946
01947 return (p1val>0) == (p2val>0);
01948 }
01949
01950
01951
01952 bool LineData::pointOnLine(const Point& p)
01953 {
01954 const float BOUNDS_EXTEND = 1;
01955 float dx = end2_pt.coordX() - end1_pt.coordX();
01956 float dy = end2_pt.coordY() - end1_pt.coordY();
01957 float val = (p.coordY() - end1_pt.coordY())*dx - (p.coordX() - end1_pt.coordX())*dy;
01958 val /= length;
01959 bool inBounds = (p.coordX() >= (leftPt().coordX() - BOUNDS_EXTEND)) &&
01960 (p.coordX() <= (rightPt().coordX() + BOUNDS_EXTEND)) &&
01961 (p.coordY() >= (topPt().coordY() - BOUNDS_EXTEND)) &&
01962 (p.coordY() <= (bottomPt().coordY() + BOUNDS_EXTEND));
01963 return (val > -1) && (val < 1) && inBounds;
01964 }
01965
01966
01967
01968
01969 bool LineData::LineDataLengthLessThan::operator() (const LineData &line1, const LineData &line2) const {
01970 return line1.getLength() < line2.getLength();
01971 }
01972
01973 bool LineData::LengthLessThan::operator() (const Shape<LineData> &line1, const Shape<LineData> &line2) const {
01974 return line1->getLength() < line2->getLength();
01975 }
01976
01977 bool LineData::ParallelTest::operator() (const Shape<LineData> &line1, const Shape<LineData> &line2) const {
01978 return angdist(line1->getOrientation(),line2->getOrientation()) <= tolerance;
01979 }
01980
01981 bool LineData::PerpendicularTest::operator() (const Shape<LineData> &line1, const Shape<LineData> &line2) const {
01982 return angdist(angdist(line1->getOrientation(),line2->getOrientation()), (orientation_t)M_PI/2) <= tolerance;
01983 }
01984
01985 bool LineData::ColinearTest::operator() (const Shape<LineData> &line1, const Shape<LineData> &line2) const {
01986 return ParallelTest(ang_tol)(line1,line2) &&
01987 abs( line1->getRhoNorm() - line2->getRhoNorm() ) <= dist_tol;
01988 }
01989
01990 bool LineData::IsHorizontal::operator() (const Shape<LineData> &line) const {
01991 const AngPi orient = line->getOrientation();
01992 return (orient <= threshold) || (orient >= M_PI - threshold);
01993 }
01994
01995 bool LineData::IsVertical::operator() (const Shape<LineData> &line) const {
01996 const AngPi orient = line->getOrientation();
01997 return (orient >= threshold) && (orient <= M_PI - threshold);
01998 }
01999
02000 }