00001
00022 #include "panoinc_WX.h"
00023 #include "panoinc.h"
00024
00025 #include "PreviewLayoutLinesTool.h"
00026 #include <config.h>
00027
00028 #include "base_wx/platform.h"
00029 #include "MainFrame.h"
00030 #include "GreatCircles.h"
00031
00032 #include <wx/platform.h>
00033 #ifdef __WXMAC__
00034 #include <OpenGL/gl.h>
00035 #include <OpenGL/glu.h>
00036 #else
00037 #include <GL/gl.h>
00038 #include <GL/glu.h>
00039 #endif
00040
00041 #include <cfloat>
00042 #include <cmath>
00043
00044
00045 #define rect_ts 64
00046
00047
00048
00049
00050
00051
00052
00053 #define SAMPLE_FREQUENCY 12
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069 #define MIN_SAMPLE_OVERLAPS 16
00070
00072 class PosMap
00073 {
00074 public:
00075 hugin_utils::FDiff2D data[SAMPLE_FREQUENCY][SAMPLE_FREQUENCY];
00076 hugin_utils::FDiff2D * operator[](std::size_t index)
00077 {
00078 return data[index];
00079 }
00080 };
00081
00082 PreviewLayoutLinesTool::PreviewLayoutLinesTool(ToolHelper *helper)
00083 : Tool(helper),
00084 m_updateStatistics(true),
00085 m_nearestLine(-1),
00086 m_useNearestLine(false),
00087 m_holdOnNear(false)
00088 {
00089 helper->GetPanoramaPtr()->addObserver(this);
00090
00091
00092 glGenTextures(1, (GLuint*) &m_rectangleBorderTex);
00093
00094
00095
00096
00097
00098
00099
00100
00101 unsigned char rect_tex_data[rect_ts][rect_ts][2];
00102
00103 for (unsigned int x = 0; x < rect_ts; x++)
00104 {
00105 for (unsigned int y = 0; y < rect_ts; y++)
00106 {
00107 rect_tex_data[x][y][0] = 255;
00108 }
00109 }
00110
00111 for (unsigned int x = 2; x < rect_ts - 2; x++)
00112 {
00113 for (unsigned int y = 2; y < rect_ts - 2; y++)
00114 {
00115 rect_tex_data[x][y][1] = 31;
00116 }
00117 }
00118
00119 for (unsigned int d = 1; d < rect_ts - 1; d++)
00120 {
00121 rect_tex_data[d][1][1] = 255;
00122 rect_tex_data[d][rect_ts - 2][1] = 255;
00123 rect_tex_data[1][d][1] = 255;
00124 rect_tex_data[rect_ts - 2][d][1] = 255;
00125 }
00126
00127 for (unsigned int d = 0; d < rect_ts; d++)
00128 {
00129 rect_tex_data[d][0][1] = 0;
00130 rect_tex_data[d][rect_ts - 1][1] = 0;
00131 rect_tex_data[0][d][1] = 0;
00132 rect_tex_data[rect_ts - 1][d][1] = 0;
00133 }
00134 glBindTexture(GL_TEXTURE_2D, m_rectangleBorderTex);
00135 gluBuild2DMipmaps(GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, rect_ts, rect_ts,
00136 GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, rect_tex_data);
00137 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
00138 GL_LINEAR_MIPMAP_LINEAR);
00139
00140 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00141 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00142 }
00143 PreviewLayoutLinesTool::~PreviewLayoutLinesTool()
00144 {
00145
00146 glDeleteTextures(1, (GLuint*) &m_rectangleBorderTex);
00147
00148
00149 while (!m_transforms.empty())
00150 {
00151 delete m_transforms.back();
00152 m_transforms.pop_back();
00153 }
00154
00155
00156 helper->GetPanoramaPtr()->removeObserver(this);
00157 }
00158
00159 void PreviewLayoutLinesTool::panoramaChanged(HuginBase::PanoramaData &pano)
00160 {
00161 m_updateStatistics = true;
00162 }
00163 void PreviewLayoutLinesTool::panoramaImagesChanged(HuginBase::PanoramaData&,
00164 const HuginBase::UIntSet&)
00165 {
00166 m_updateStatistics = true;
00167 }
00168
00169 void PreviewLayoutLinesTool::Activate()
00170 {
00171
00172 helper->NotifyMe(PreviewToolHelper::MOUSE_MOVE, this);
00173 helper->NotifyMe(PreviewToolHelper::DRAW_UNDER_IMAGES, this);
00174 helper->NotifyMe(PreviewToolHelper::DRAW_OVER_IMAGES, this);
00175 helper->NotifyMe(PreviewToolHelper::MOUSE_PRESS, this);
00176
00177 helper->SetStatusMessage(_("Click a connection to edit control points."));
00178 }
00179
00180 void PreviewLayoutLinesTool::MouseMoveEvent(double x, double y, wxMouseEvent & e)
00181 {
00182
00183
00184
00185 if (m_lines.empty())
00186 {
00187 return;
00188 }
00189
00190 if (!(helper->IsMouseOverPano())) {
00191 if (m_useNearestLine) {
00192 m_useNearestLine = false;
00193 helper->GetVisualizationStatePtr()->ForceRequireRedraw();
00194 helper->GetVisualizationStatePtr()->Redraw();
00195 }
00196 return;
00197 }
00198
00199 if (e.Dragging() && !m_holdOnNear) {
00200 return;
00201 }
00202
00203
00204 double minDistance = DBL_MAX;
00205 unsigned int nearestLineOld = m_nearestLine;
00206 for (unsigned int i = 0; i < m_lines.size(); i++)
00207 {
00208 if (m_lines[i].dud) continue;
00209 double lineDistance = m_lines[i].getDistance(helper->GetMousePanoPosition());
00210 if (lineDistance < minDistance)
00211 {
00212
00213 minDistance = lineDistance;
00214 m_nearestLine = i;
00215 }
00216 }
00217
00218
00219 bool oldUseNearestLine = m_useNearestLine;
00220
00221
00222 double scale = helper->GetVisualizationStatePtr()->GetScale();
00223 scale *= scale;
00224 m_useNearestLine = minDistance < 4900.0 / scale;
00225
00226 if (oldUseNearestLine != m_useNearestLine || m_nearestLine != nearestLineOld)
00227 {
00228 LineDetails & line = m_lines[m_nearestLine];
00229
00230
00231 helper->NotifyMeBeforeDrawing(line.image1, this);
00232 helper->NotifyMeBeforeDrawing(line.image2, this);
00233
00234
00235
00236 helper->GetVisualizationStatePtr()->ForceRequireRedraw();
00237 helper->GetVisualizationStatePtr()->Redraw();
00238 }
00239 }
00240
00241 void PreviewLayoutLinesTool::BeforeDrawImagesEvent()
00242 {
00243
00244 if (m_updateStatistics)
00245 {
00246 m_updateStatistics = false;
00247
00248
00249 updateImageCentres();
00250 updateLineInformation();
00251
00252 if (m_nearestLine >= m_lines.size())
00253 {
00254
00255
00256 m_nearestLine = 0;
00257 }
00258 }
00259
00260
00261 glEnable(GL_LINE_SMOOTH);
00262 helper->GetViewStatePtr()->GetTextureManager()->DisableTexture();
00263 for (unsigned int i = 0; i < m_lines.size(); i++)
00264 {
00265 m_lines[i].draw(m_useNearestLine && i == m_nearestLine);
00266 }
00267 glDisable(GL_LINE_SMOOTH);
00268 glEnable(GL_TEXTURE_2D);
00269
00270 glColor3ub(255, 255, 255);
00271 glLineWidth(1.0);
00272 }
00273
00274 void PreviewLayoutLinesTool::AfterDrawImagesEvent()
00275 {
00276
00277
00278
00279
00280 if (m_lines.empty() || !m_useNearestLine) return;
00281
00282
00283 unsigned int image1 = m_lines[m_nearestLine].image1;
00284 unsigned int image2 = m_lines[m_nearestLine].image2;
00285 helper->GetViewStatePtr()->GetTextureManager()->DrawImage(image1,
00286 helper->GetVisualizationStatePtr()->GetMeshDisplayList(image1));
00287 helper->GetViewStatePtr()->GetTextureManager()->DrawImage(image2,
00288 helper->GetVisualizationStatePtr()->GetMeshDisplayList(image2));
00289
00290
00291 glEnable(GL_BLEND);
00292 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00293
00294 helper->GetViewStatePtr()->GetTextureManager()->DisableTexture(true);
00295 glBindTexture(GL_TEXTURE_2D, m_rectangleBorderTex);
00296
00297 glMatrixMode(GL_TEXTURE);
00298
00299
00300 drawIdentificationBorder(image1);
00301 drawIdentificationBorder(image2);
00302
00303
00304 glMatrixMode(GL_MODELVIEW);
00305 glDisable(GL_BLEND);
00306 }
00307
00308 void PreviewLayoutLinesTool::drawIdentificationBorder(unsigned int image)
00309 {
00310
00311 glPushMatrix();
00312 const HuginBase::SrcPanoImage & src = *(helper->GetViewStatePtr()->
00313 GetSrcImage(image));
00314 int width = src.getSize().width(), height = src.getSize().height();
00315 vigra::Rect2D crop_region = src.getCropRect();
00316
00317 switch (src.getCropMode())
00318 {
00319 case HuginBase::SrcPanoImage::CROP_CIRCLE:
00320 case HuginBase::SrcPanoImage::CROP_RECTANGLE:
00321
00322
00323 crop_region &= vigra::Rect2D(src.getSize());
00324 glScalef((float) width / (float) crop_region.width(),
00325 (float) height / (float) crop_region.height(),
00326 1.0);
00327 glTranslatef(-(float) crop_region.left() / (float) width,
00328 -(float) crop_region.top() / (float) height,
00329 0.0);
00330 break;
00331 case HuginBase::SrcPanoImage::NO_CROP:
00332 break;
00333 }
00334
00335 glMatrixMode(GL_MODELVIEW);
00336 glCallList(helper->GetVisualizationStatePtr()->GetMeshDisplayList(image));
00337 glMatrixMode(GL_TEXTURE);
00338
00339 glPopMatrix();
00340 }
00341
00342 bool PreviewLayoutLinesTool::BeforeDrawImageEvent(unsigned int image)
00343 {
00344 if (m_lines.empty() || !m_useNearestLine)
00345 {
00346
00347
00348 helper->DoNotNotifyMeBeforeDrawing(image, this);
00349 return true;
00350 }
00351
00352 LineDetails & line = m_lines[m_nearestLine];
00353 if (image == line.image1 || image == line.image2) return false;
00354
00355 helper->DoNotNotifyMeBeforeDrawing(image, this);
00356 return true;
00357 }
00358
00359 void PreviewLayoutLinesTool::MouseButtonEvent(wxMouseEvent & e)
00360 {
00361
00362
00363 if ( e.LeftDown() && !m_lines.empty() && m_useNearestLine)
00364 {
00365 m_holdOnNear = true;
00366 }
00367
00368 if (m_holdOnNear && e.LeftUp() && m_useNearestLine) {
00369 m_holdOnNear = false;
00370 LineDetails & line = m_lines[m_nearestLine];
00371 MainFrame::Get()->ShowCtrlPointEditor(line.image1, line.image2);
00372 MainFrame::Get()->Raise();
00373 }
00374
00375 if (m_useNearestLine && e.LeftUp()) {
00376 m_useNearestLine = false;
00377 }
00378 }
00379
00380 void PreviewLayoutLinesTool::updateLineInformation()
00381 {
00382 m_lines.clear();
00383 const PT::Panorama & pano = *(helper->GetPanoramaPtr());
00384 unsigned int numberOfImages = pano.getNrOfImages();
00385 HuginBase::UIntSet active_images = pano.getActiveImages();
00386
00387
00388 m_lines.resize(numberOfImages * numberOfImages);
00389 unsigned int numberOfControlPoints = pano.getNrOfCtrlPoints();
00390
00391 for (unsigned int cpi = 0 ; cpi < numberOfControlPoints ; cpi++)
00392 {
00393 const ControlPoint & cp = pano.getCtrlPoint(cpi);
00394 unsigned int low_index, high_index;
00395 if (cp.image1Nr < cp.image2Nr)
00396 {
00397 low_index = cp.image1Nr;
00398 high_index = cp.image2Nr;
00399 } else {
00400 low_index = cp.image2Nr;
00401 high_index = cp.image1Nr;
00402 }
00403
00404
00405
00406 LineDetails & line = m_lines[low_index * numberOfImages + high_index];
00407
00408 line.numberOfControlPoints++;
00409
00410 line.totalError += cp.error;
00411 if (cp.error > line.worstError)
00412 {
00413 line.worstError = cp.error;
00414 }
00415 }
00416
00417
00418
00419
00420
00427 std::vector<PosMap> positions(pano.getNrOfImages() - 1);
00428 for (unsigned int i = 0; i < numberOfImages - 1; i++)
00429 {
00430 const HuginBase::SrcPanoImage & img = pano.getImage(i);
00431 for (unsigned int x = 0; x < SAMPLE_FREQUENCY; x++)
00432 {
00433 for (unsigned int y = 0; y < SAMPLE_FREQUENCY; y++)
00434 {
00435
00436
00437 vigra::Rect2D c = img.getCropRect();
00441 double xc = double (x) / double (SAMPLE_FREQUENCY)
00442 * double(c.width()) + c.left();
00443 double yc = double (y) / double (SAMPLE_FREQUENCY)
00444 * double(c.height()) + c.top();
00445
00446
00447 m_transforms[i]->transformImgCoord (
00448 positions[i][x][y].x, positions[i][x][y].y,
00449 xc, yc );
00450 }
00451 }
00452 }
00453
00454
00455 for (unsigned int i = 0; i < numberOfImages; i++)
00456 {
00457 for (unsigned int j = 0; j < numberOfImages; j++)
00458 {
00459 LineDetails & line = m_lines[i * numberOfImages + j];
00460 line.image1 = i;
00461 line.image2 = j;
00463 if (!(set_contains(active_images, i) &&
00464 set_contains(active_images, j)))
00465 {
00466
00467 line.dud = true;
00468 }
00469 else if (line.numberOfControlPoints > 0)
00470 {
00471 line.dud = false;
00472 } else if (i >= j) {
00473
00474
00475 line.dud = true;
00476 } else {
00477
00478 HuginBase::PTools::Transform transform;
00479 ViewState & viewState = *helper->GetViewStatePtr();
00480 HuginBase::SrcPanoImage & src = *viewState.GetSrcImage(j);
00481 transform.createTransform(src, *(viewState.GetOptions()));
00482 unsigned int overlapingSamples = 0;
00483 for (unsigned int x = 0; x < SAMPLE_FREQUENCY; x++)
00484 {
00485 for (unsigned int y = 0; y < SAMPLE_FREQUENCY; y++)
00486 {
00487
00488
00489
00490 double dx, dy;
00491 transform.transformImgCoord (
00492 dx, dy,
00493 positions[i][x][y].x,
00494 positions[i][x][y].y
00495 );
00496 if (src.isInside(vigra::Point2D((int) dx, (int) dy)))
00497 {
00498
00499 overlapingSamples++;
00500 }
00501 }
00502 }
00503
00504 line.dud = (overlapingSamples < MIN_SAMPLE_OVERLAPS);
00505 }
00506
00507 if (!line.dud)
00508 {
00509 line.arc = GreatCircleArc(m_imageCentresSpherical[i].x,
00510 m_imageCentresSpherical[i].y,
00511 m_imageCentresSpherical[j].x,
00512 m_imageCentresSpherical[j].y,
00513 *(helper->GetVisualizationStatePtr()));
00514 }
00515 }
00516 }
00517 }
00518
00519 void PreviewLayoutLinesTool::updateImageCentres()
00520 {
00521 unsigned int numberOfImages = helper->GetPanoramaPtr()->getNrOfImages();
00522
00523
00524
00525 while (m_transforms.size() > numberOfImages)
00526 {
00527 delete m_transforms.back();
00528 m_transforms.pop_back();
00529 }
00530 m_transforms.reserve(numberOfImages);
00531 while (m_transforms.size() < numberOfImages)
00532 {
00533 m_transforms.insert(m_transforms.end(), new HuginBase::PTools::Transform);
00534 }
00535 m_imageCentres.resize(helper->GetPanoramaPtr()->getNrOfImages());
00536 m_imageCentresSpherical.resize(m_imageCentres.size());
00537
00538 HuginBase::PanoramaOptions spherical_pano_opts;
00539 spherical_pano_opts.setProjection(HuginBase::PanoramaOptions::EQUIRECTANGULAR);
00540 spherical_pano_opts.setWidth(360);
00541 spherical_pano_opts.setHeight(180);
00542 spherical_pano_opts.setHFOV(360);
00543
00544 for (unsigned int image_number = 0;
00545 image_number < helper->GetPanoramaPtr()->getNrOfImages();
00546 image_number++)
00547 {
00548
00549 m_transforms[image_number]->createInvTransform (
00550 *(helper->GetViewStatePtr()->GetSrcImage(image_number)),
00551 *(helper->GetViewStatePtr()->GetOptions())
00552 );
00553 HuginBase::PTools::Transform to_spherical;
00554 to_spherical.createInvTransform (
00555 *(helper->GetViewStatePtr()->GetSrcImage(image_number)),
00556 spherical_pano_opts
00557 );
00558 const vigra::Size2D & s = helper->GetViewStatePtr()->GetSrcImage(image_number)->getSize();
00559
00560 m_transforms[image_number]->transformImgCoord (
00561 m_imageCentres[image_number].x,
00562 m_imageCentres[image_number].y,
00563 double(s.x) / 2.0, double(s.y) / 2.0
00564 );
00565 to_spherical.transformImgCoord(
00566 m_imageCentresSpherical[image_number].x,
00567 m_imageCentresSpherical[image_number].y,
00568 double(s.x) / 2.0, double(s.y) / 2.0
00569 );
00570 }
00571 }
00572
00573 void PreviewLayoutLinesTool::LineDetails::draw(bool highlight)
00574 {
00575 if (dud)
00576 {
00577
00578 return;
00579 }
00580
00581 if (highlight)
00582 {
00583 glColor3ub(255, 255, 255);
00584 } else if (numberOfControlPoints == 0) {
00585
00586 glColor3ub(170, 170, 170);
00587 }else {
00588 double red, green, blue;
00589 hugin_utils::ControlPointErrorColour(worstError,red,green,blue);
00590 glColor3d(red, green, blue);
00591 }
00592
00593 double lineWidth = numberOfControlPoints / 5.0 + 1.0;
00594 if (lineWidth > 5.0) lineWidth = 5.0;
00595
00596
00597 arc.draw(false, lineWidth);
00598 }
00599
00600 PreviewLayoutLinesTool::LineDetails::LineDetails()
00601 : numberOfControlPoints(0),
00602 worstError(0),
00603 totalError(0)
00604 {
00605
00606 }
00607
00608 float PreviewLayoutLinesTool::LineDetails::getDistance(hugin_utils::FDiff2D point)
00609 {
00610 if (dud)
00611 {
00612
00613 return FLT_MAX;
00614 }
00615 else
00616 {
00617 return arc.squareDistance(point);
00618 }
00619 }
00620