<commit_before>//===--- HTMLDiagnostics.cpp - HTML Diagnostics for Paths ----*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the HTMLDiagnostics object.
//
//===----------------------------------------------------------------------===//

#include "clang/Driver/HTMLDiagnostics.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Rewrite/Rewriter.h"
#include "clang/Rewrite/HTMLRewrite.h"
#include "clang/Lex/Lexer.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Streams.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
#include <fstream>

using namespace clang;

//===----------------------------------------------------------------------===//
// Boilerplate.
//===----------------------------------------------------------------------===//

namespace {

class VISIBILITY_HIDDEN HTMLDiagnostics : public PathDiagnosticClient {
  llvm::sys::Path Directory, FilePrefix;
  bool createdDir, noDir;
  Preprocessor* PP;
  PreprocessorFactory* PPF;
  std::vector<const PathDiagnostic*> BatchedDiags;
public:
  HTMLDiagnostics(const std::string& prefix, Preprocessor* pp,
                  PreprocessorFactory* ppf);

  virtual ~HTMLDiagnostics();

  virtual void HandlePathDiagnostic(const PathDiagnostic* D);

  void HandlePiece(Rewriter& R, unsigned BugFileID,
                   const PathDiagnosticPiece& P, unsigned num, unsigned max);

  void HighlightRange(Rewriter& R, unsigned BugFileID, SourceRange Range);

  void ReportDiag(const PathDiagnostic& D);
};

} // end anonymous namespace

HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix, Preprocessor* pp,
                                 PreprocessorFactory* ppf)
  : Directory(prefix), FilePrefix(prefix), createdDir(false), noDir(false),
    PP(pp), PPF(ppf) {

  // All html files begin with "report"
  FilePrefix.appendComponent("report");
}

PathDiagnosticClient*
clang::CreateHTMLDiagnosticClient(const std::string& prefix, Preprocessor* PP,
                                  PreprocessorFactory* PPF) {

  return new HTMLDiagnostics(prefix, PP, PPF);
}

//===----------------------------------------------------------------------===//
// Report processing.
//===----------------------------------------------------------------------===//

void HTMLDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) {
  if (!D)
    return;

  if (D->empty()) {
    delete D;
    return;
  }

  BatchedDiags.push_back(D);
}

HTMLDiagnostics::~HTMLDiagnostics() {

  while (!BatchedDiags.empty()) {
    const PathDiagnostic* D = BatchedDiags.back();
    BatchedDiags.pop_back();
    ReportDiag(*D);
    delete D;
  }
}

void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D) {

  // Create the HTML directory if it is missing.

  if (!createdDir) {
    createdDir = true;
    std::string ErrorMsg;
    Directory.createDirectoryOnDisk(true, &ErrorMsg);

    if (!Directory.isDirectory()) {
      llvm::cerr << "warning: could not create directory '"
                 << Directory.toString() << "'\n"
                 << "reason: " << ErrorMsg << '\n';

      noDir = true;

      return;
    }
  }

  if (noDir)
    return;

  SourceManager& SMgr = D.begin()->getLocation().getManager();

  unsigned FileID = 0;
  bool FileIDInitialized = false;

  // Verify that the entire path is from the same FileID.
  for (PathDiagnostic::const_iterator I=D.begin(), E=D.end(); I != E; ++I) {

    FullSourceLoc L = I->getLocation();

    if (!L.isFileID())
      return; // FIXME: Emit a warning?

    if (!FileIDInitialized) {
      FileID = L.getCanonicalFileID();
      FileIDInitialized = true;
    }
    else if (L.getCanonicalFileID() != FileID)
      return; // FIXME: Emit a warning?

    // Check the source ranges.
    for (PathDiagnosticPiece::range_iterator RI=I->ranges_begin(),
                                             RE=I->ranges_end(); RI!=RE; ++RI) {

      SourceLocation L = RI->getBegin();

      if (!L.isFileID())
        return; // FIXME: Emit a warning?

      if (SMgr.getCanonicalFileID(L) != FileID)
        return; // FIXME: Emit a warning?

      L = RI->getEnd();

      if (!L.isFileID())
        return; // FIXME: Emit a warning?

      if (SMgr.getCanonicalFileID(L) != FileID)
        return; // FIXME: Emit a warning?
    }
  }

  if (!FileIDInitialized)
    return; // FIXME: Emit a warning?

  // Create a new rewriter to generate HTML.
  Rewriter R(SMgr);

  // Process the path.

  unsigned n = D.size();
  unsigned max = n;

  for (PathDiagnostic::const_reverse_iterator I=D.rbegin(), E=D.rend();
        I!=E; ++I, --n) {

    HandlePiece(R, FileID, *I, n, max);
  }

  // Add line numbers, header, footer, etc.

  // unsigned FileID = R.getSourceMgr().getMainFileID();
  html::EscapeText(R, FileID);
  html::AddLineNumbers(R, FileID);

  // If we have a preprocessor, relex the file and syntax highlight.
  // We might not have a preprocessor if we come from a deserialized AST file,
  // for example.

  if (PP) html::SyntaxHighlight(R, FileID, *PP);

  // FIXME: We eventually want to use PPF to create a fresh Preprocessor,
  //  once we have worked out the bugs.
  //
  // if (PPF) html::HighlightMacros(R, FileID, *PPF);
  //
  if (PP) html::HighlightMacros(R, FileID, *PP);

  // Get the full directory name of the analyzed file.

  const FileEntry* Entry = SMgr.getFileEntryForID(FileID);

  // This is a cludge; basically we want to append either the full
  // working directory if we have no directory information.  This is
  // a work in progress.

  std::string DirName = "";

  if (!llvm::sys::Path(Entry->getName()).isAbsolute()) {
    llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory();
    DirName = P.toString() + "/";
  }

  // Add the name of the file as an
 tag.

  {
    std::string s;
    llvm::raw_string_ostream os(s);

    os << "
Bug Summary
\n
\n"
          "
File:	"
       << html::EscapeText(DirName)
       <getName())
       << "
\n
Location:	"
          "line "
       << (*D.rbegin()).getLocation().getLogicalLineNumber()
       << ", column "
       << (*D.rbegin()).getLocation().getLogicalColumnNumber()
       << "
\n"
          "
Description:	"
       << D.getDescription() << "
\n";

    // Output any other meta data.

    for (PathDiagnostic::meta_iterator I=D.meta_begin(), E=D.meta_end();
         I!=E; ++I) {
      os << "
	" << html::EscapeText(*I) << "
\n";
    }

    os << "
\n
Annotated Source Code
\n";

    R.InsertStrBefore(SourceLocation::getFileLoc(FileID, 0), os.str());
  }

  // Embed meta-data tags.

  const std::string& BugDesc = D.getDescription();

  if (!BugDesc.empty()) {
    std::string s;
    llvm::raw_string_ostream os(s);
    os << "\n\n";
    R.InsertStrBefore(SourceLocation::getFileLoc(FileID, 0), os.str());
  }

  const std::string& BugCategory = D.getCategory();

  if (!BugCategory.empty()) {
    std::string s;
    llvm::raw_string_ostream os(s);
    os << "\n\n";
    R.InsertStrBefore(SourceLocation::getFileLoc(FileID, 0), os.str());
  }

  {
    std::string s;
    llvm::raw_string_ostream os(s);
    os << "\n\n";
    R.InsertStrBefore(SourceLocation::getFileLoc(FileID, 0), os.str());
  }

  {
    std::string s;
    llvm::raw_string_ostream os(s);
    os << "\n\n";
    R.InsertStrBefore(SourceLocation::getFileLoc(FileID, 0), os.str());
  }

  {
    std::string s;
    llvm::raw_string_ostream os(s);
    os << "\n\n";
    R.InsertStrBefore(SourceLocation::getFileLoc(FileID, 0), os.str());
  }

  // Add CSS, header, and footer.

  html::AddHeaderFooterInternalBuiltinCSS(R, FileID, Entry->getName());

  // Get the rewrite buffer.
  const RewriteBuffer *Buf = R.getRewriteBufferFor(FileID);

  if (!Buf) {
    llvm::cerr << "warning: no diagnostics generated for main file.\n";
    return;
  }

  // Create the stream to write out the HTML.
  std::ofstream os;

  {
    // Create a path for the target HTML file.
    llvm::sys::Path F(FilePrefix);
    F.makeUnique(false, NULL);

    // Rename the file with an HTML extension.
    llvm::sys::Path H(F);
    H.appendSuffix("html");
    F.renamePathOnDisk(H, NULL);

    os.open(H.toString().c_str());

    if (!os) {
      llvm::cerr << "warning: could not create file '" << F.toString() << "'\n";
      return;
    }
  }

  // Emit the HTML to disk.

  for (RewriteBuffer::iterator I = Buf->begin(), E = Buf->end(); I!=E; ++I)
      os << *I;
}

void HTMLDiagnostics::HandlePiece(Rewriter& R, unsigned BugFileID,
                                  const PathDiagnosticPiece& P,
                                  unsigned num, unsigned max) {

  // For now, just draw a box above the line in question, and emit the
  // warning.

  FullSourceLoc Pos = P.getLocation();

  if (!Pos.isValid())
    return;

  SourceManager& SM = R.getSourceMgr();
  FullSourceLoc LPos = Pos.getLogicalLoc();
  unsigned FileID = SM.getCanonicalFileID(LPos.getLocation());

  assert (&LPos.getManager() == &SM && "SourceManagers are different!");

  if (LPos.getCanonicalFileID() != BugFileID)
    return;

  const llvm::MemoryBuffer *Buf = SM.getBuffer(FileID);
  const char* FileStart = Buf->getBufferStart();

  // Compute the column number.  Rewind from the current position to the start
  // of the line.

  unsigned ColNo = LPos.getColumnNumber();
  const char *TokLogicalPtr = LPos.getCharacterData();
  const char *LineStart = TokLogicalPtr-ColNo;

  // Only compute LineEnd if we display below a line.
  const char *LineEnd = TokLogicalPtr;

  if (P.getDisplayHint() == PathDiagnosticPiece::Below) {
    const char* FileEnd = Buf->getBufferEnd();

    while (*LineEnd != '\n' && LineEnd != FileEnd)
      ++LineEnd;
  }

  // Compute the margin offset by counting tabs and non-tabs.

  unsigned PosNo = 0;

  for (const char* c = LineStart; c != TokLogicalPtr; ++c)
    PosNo += *c == '\t' ? 8 : 1;

  // Create the html for the message.
  {
    // Get the string and determining its maximum substring.
    const std::string& Msg = P.getString();
    unsigned max_token = 0;
    unsigned cnt = 0;
    unsigned len = Msg.size();

    for (std::string::const_iterator I=Msg.begin(), E=Msg.end(); I!=E; ++I)
      switch (*I) {
        default:
          ++cnt;
          continue;
        case ' ':
        case '\t':
        case '\n':
          if (cnt > max_token) max_token = cnt;
          cnt = 0;
      }

    if (cnt > max_token) max_token = cnt;

    // Next, determine the approximate size of the message bubble in em.
    unsigned em;
    const unsigned max_line = 80;

    if (max_token >= max_line)
      em = max_token / 2;
    else {
      unsigned characters = max_line;
      unsigned lines = len / max_line;

      if (lines > 0) {
        for (; characters > max_token; --characters)
          if (len / characters > lines) {
            ++characters;
            break;
          }
      }

      em = characters / 2;
    }

    // Now generate the message bubble.
    std::string s;
    llvm::raw_string_ostream os(s);

    os << "\n
	<div id=\"";

    if (num == max)
      os << "EndPath";
    else
      os << "Path" << num;

    os << "\" class=\"msg\" style=\"margin-left:" << PosNo << "ex";
    if (em < max_line/2) os << "; max-width:" << em << "em";
    os << "\">";

    if (max > 1)
      os << "[" << num << "] ";

    os << html::EscapeText(Msg) << "

";

    // Insert the new html.
    unsigned DisplayPos = 0;

    switch (P.getDisplayHint()) {
      case PathDiagnosticPiece::Above:
        DisplayPos = LineStart - FileStart;
        break;
      case PathDiagnosticPiece::Below:
        DisplayPos = LineEnd - FileStart;
        break;
      default:
        assert (false && "Unhandled hint.");
    }

    R.InsertStrBefore(SourceLocation::getFileLoc(FileID, DisplayPos), os.str());
  }

  // Now highlight the ranges.

  for (const SourceRange *I = P.ranges_begin(), *E = P.ranges_end();
        I != E; ++I)
    HighlightRange(R, FileID, *I);
}

void HTMLDiagnostics::HighlightRange(Rewriter& R, unsigned BugFileID,
                                     SourceRange Range) {

  SourceManager& SM = R.getSourceMgr();

  SourceLocation LogicalStart = SM.getLogicalLoc(Range.getBegin());
  unsigned StartLineNo = SM.getLineNumber(LogicalStart);

  SourceLocation LogicalEnd = SM.getLogicalLoc(Range.getEnd());
  unsigned EndLineNo = SM.getLineNumber(LogicalEnd);

  if (EndLineNo < StartLineNo)
    return;

  if (SM.getCanonicalFileID(LogicalStart) != BugFileID ||
      SM.getCanonicalFileID(LogicalEnd) != BugFileID)
    return;

  // Compute the column number of the end.
  unsigned EndColNo = SM.getColumnNumber(LogicalEnd);
  unsigned OldEndColNo = EndColNo;

  if (EndColNo) {
    // Add in the length of the token, so that we cover multi-char tokens.
    EndColNo += Lexer::MeasureTokenLength(Range.getEnd(), SM) - 1;
  }

  // Highlight the range.  Make the span tag the outermost tag for the
  // selected range.

  SourceLocation E = LogicalEnd.getFileLocWithOffset(EndColNo - OldEndColNo);

  html::HighlightRange(R, LogicalStart, E,
                       "", "");
}
<commit_msg>Output "REPORTHEADER" and "REPORTSUMMARYEXTRA" tags for use with scan-view.<commit_after>//===--- HTMLDiagnostics.cpp - HTML Diagnostics for Paths ----*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the HTMLDiagnostics object.
//
//===----------------------------------------------------------------------===//

#include "clang/Driver/HTMLDiagnostics.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Rewrite/Rewriter.h"
#include "clang/Rewrite/HTMLRewrite.h"
#include "clang/Lex/Lexer.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Streams.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
#include <fstream>

using namespace clang;

//===----------------------------------------------------------------------===//
// Boilerplate.
//===----------------------------------------------------------------------===//

namespace {

class VISIBILITY_HIDDEN HTMLDiagnostics : public PathDiagnosticClient {
  llvm::sys::Path Directory, FilePrefix;
  bool createdDir, noDir;
  Preprocessor* PP;
  PreprocessorFactory* PPF;
  std::vector<const PathDiagnostic*> BatchedDiags;
public:
  HTMLDiagnostics(const std::string& prefix, Preprocessor* pp,
                  PreprocessorFactory* ppf);

  virtual ~HTMLDiagnostics();

  virtual void HandlePathDiagnostic(const PathDiagnostic* D);

  void HandlePiece(Rewriter& R, unsigned BugFileID,
                   const PathDiagnosticPiece& P, unsigned num, unsigned max);

  void HighlightRange(Rewriter& R, unsigned BugFileID, SourceRange Range);

  void ReportDiag(const PathDiagnostic& D);
};

} // end anonymous namespace

HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix, Preprocessor* pp,
                                 PreprocessorFactory* ppf)
  : Directory(prefix), FilePrefix(prefix), createdDir(false), noDir(false),
    PP(pp), PPF(ppf) {

  // All html files begin with "report"
  FilePrefix.appendComponent("report");
}

PathDiagnosticClient*
clang::CreateHTMLDiagnosticClient(const std::string& prefix, Preprocessor* PP,
                                  PreprocessorFactory* PPF) {

  return new HTMLDiagnostics(prefix, PP, PPF);
}

//===----------------------------------------------------------------------===//
// Report processing.
//===----------------------------------------------------------------------===//

void HTMLDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) {
  if (!D)
    return;

  if (D->empty()) {
    delete D;
    return;
  }

  BatchedDiags.push_back(D);
}

HTMLDiagnostics::~HTMLDiagnostics() {

  while (!BatchedDiags.empty()) {
    const PathDiagnostic* D = BatchedDiags.back();
    BatchedDiags.pop_back();
    ReportDiag(*D);
    delete D;
  }
}

void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D) {

  // Create the HTML directory if it is missing.

  if (!createdDir) {
    createdDir = true;
    std::string ErrorMsg;
    Directory.createDirectoryOnDisk(true, &ErrorMsg);

    if (!Directory.isDirectory()) {
      llvm::cerr << "warning: could not create directory '"
                 << Directory.toString() << "'\n"
                 << "reason: " << ErrorMsg << '\n';

      noDir = true;

      return;
    }
  }

  if (noDir)
    return;

  SourceManager& SMgr = D.begin()->getLocation().getManager();

  unsigned FileID = 0;
  bool FileIDInitialized = false;

  // Verify that the entire path is from the same FileID.
  for (PathDiagnostic::const_iterator I=D.begin(), E=D.end(); I != E; ++I) {

    FullSourceLoc L = I->getLocation();

    if (!L.isFileID())
      return; // FIXME: Emit a warning?

    if (!FileIDInitialized) {
      FileID = L.getCanonicalFileID();
      FileIDInitialized = true;
    }
    else if (L.getCanonicalFileID() != FileID)
      return; // FIXME: Emit a warning?

    // Check the source ranges.
    for (PathDiagnosticPiece::range_iterator RI=I->ranges_begin(),
                                             RE=I->ranges_end(); RI!=RE; ++RI) {

      SourceLocation L = RI->getBegin();

      if (!L.isFileID())
        return; // FIXME: Emit a warning?

      if (SMgr.getCanonicalFileID(L) != FileID)
        return; // FIXME: Emit a warning?

      L = RI->getEnd();

      if (!L.isFileID())
        return; // FIXME: Emit a warning?

      if (SMgr.getCanonicalFileID(L) != FileID)
        return; // FIXME: Emit a warning?
    }
  }

  if (!FileIDInitialized)
    return; // FIXME: Emit a warning?

  // Create a new rewriter to generate HTML.
  Rewriter R(SMgr);

  // Process the path.

  unsigned n = D.size();
  unsigned max = n;

  for (PathDiagnostic::const_reverse_iterator I=D.rbegin(), E=D.rend();
        I!=E; ++I, --n) {

    HandlePiece(R, FileID, *I, n, max);
  }

  // Add line numbers, header, footer, etc.

  // unsigned FileID = R.getSourceMgr().getMainFileID();
  html::EscapeText(R, FileID);
  html::AddLineNumbers(R, FileID);

  // If we have a preprocessor, relex the file and syntax highlight.
  // We might not have a preprocessor if we come from a deserialized AST file,
  // for example.

  if (PP) html::SyntaxHighlight(R, FileID, *PP);

  // FIXME: We eventually want to use PPF to create a fresh Preprocessor,
  //  once we have worked out the bugs.
  //
  // if (PPF) html::HighlightMacros(R, FileID, *PPF);
  //
  if (PP) html::HighlightMacros(R, FileID, *PP);

  // Get the full directory name of the analyzed file.

  const FileEntry* Entry = SMgr.getFileEntryForID(FileID);

  // This is a cludge; basically we want to append either the full
  // working directory if we have no directory information.  This is
  // a work in progress.

  std::string DirName = "";

  if (!llvm::sys::Path(Entry->getName()).isAbsolute()) {
    llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory();
    DirName = P.toString() + "/";
  }

  // Add the name of the file as an
 tag.

  {
    std::string s;
    llvm::raw_string_ostream os(s);

    os << "\n"
       << "
Bug Summary
\n
\n"
          "
File:	"
       << html::EscapeText(DirName)
       <getName())
       << "
\n
Location:	"
          "line "
       << (*D.rbegin()).getLocation().getLogicalLineNumber()
       << ", column "
       << (*D.rbegin()).getLocation().getLogicalColumnNumber()
       << "
\n"
          "
Description:	"
       << D.getDescription() << "
\n";

    // Output any other meta data.

    for (PathDiagnostic::meta_iterator I=D.meta_begin(), E=D.meta_end();
         I!=E; ++I) {
      os << "
	" << html::EscapeText(*I) << "
\n";
    }

    os << "
\n\n"
          "
Annotated Source Code
\n";

    R.InsertStrBefore(SourceLocation::getFileLoc(FileID, 0), os.str());
  }

  // Embed meta-data tags.

  const std::string& BugDesc = D.getDescription();

  if (!BugDesc.empty()) {
    std::string s;
    llvm::raw_string_ostream os(s);
    os << "\n\n";
    R.InsertStrBefore(SourceLocation::getFileLoc(FileID, 0), os.str());
  }

  const std::string& BugCategory = D.getCategory();

  if (!BugCategory.empty()) {
    std::string s;
    llvm::raw_string_ostream os(s);
    os << "\n\n";
    R.InsertStrBefore(SourceLocation::getFileLoc(FileID, 0), os.str());
  }

  {
    std::string s;
    llvm::raw_string_ostream os(s);
    os << "\n\n";
    R.InsertStrBefore(SourceLocation::getFileLoc(FileID, 0), os.str());
  }

  {
    std::string s;
    llvm::raw_string_ostream os(s);
    os << "\n\n";
    R.InsertStrBefore(SourceLocation::getFileLoc(FileID, 0), os.str());
  }

  {
    std::string s;
    llvm::raw_string_ostream os(s);
    os << "\n\n";
    R.InsertStrBefore(SourceLocation::getFileLoc(FileID, 0), os.str());
  }

  // Add CSS, header, and footer.

  html::AddHeaderFooterInternalBuiltinCSS(R, FileID, Entry->getName());

  // Get the rewrite buffer.
  const RewriteBuffer *Buf = R.getRewriteBufferFor(FileID);

  if (!Buf) {
    llvm::cerr << "warning: no diagnostics generated for main file.\n";
    return;
  }

  // Create the stream to write out the HTML.
  std::ofstream os;

  {
    // Create a path for the target HTML file.
    llvm::sys::Path F(FilePrefix);
    F.makeUnique(false, NULL);

    // Rename the file with an HTML extension.
    llvm::sys::Path H(F);
    H.appendSuffix("html");
    F.renamePathOnDisk(H, NULL);

    os.open(H.toString().c_str());

    if (!os) {
      llvm::cerr << "warning: could not create file '" << F.toString() << "'\n";
      return;
    }
  }

  // Emit the HTML to disk.

  for (RewriteBuffer::iterator I = Buf->begin(), E = Buf->end(); I!=E; ++I)
      os << *I;
}

void HTMLDiagnostics::HandlePiece(Rewriter& R, unsigned BugFileID,
                                  const PathDiagnosticPiece& P,
                                  unsigned num, unsigned max) {

  // For now, just draw a box above the line in question, and emit the
  // warning.

  FullSourceLoc Pos = P.getLocation();

  if (!Pos.isValid())
    return;

  SourceManager& SM = R.getSourceMgr();
  FullSourceLoc LPos = Pos.getLogicalLoc();
  unsigned FileID = SM.getCanonicalFileID(LPos.getLocation());

  assert (&LPos.getManager() == &SM && "SourceManagers are different!");

  if (LPos.getCanonicalFileID() != BugFileID)
    return;

  const llvm::MemoryBuffer *Buf = SM.getBuffer(FileID);
  const char* FileStart = Buf->getBufferStart();

  // Compute the column number.  Rewind from the current position to the start
  // of the line.

  unsigned ColNo = LPos.getColumnNumber();
  const char *TokLogicalPtr = LPos.getCharacterData();
  const char *LineStart = TokLogicalPtr-ColNo;

  // Only compute LineEnd if we display below a line.
  const char *LineEnd = TokLogicalPtr;

  if (P.getDisplayHint() == PathDiagnosticPiece::Below) {
    const char* FileEnd = Buf->getBufferEnd();

    while (*LineEnd != '\n' && LineEnd != FileEnd)
      ++LineEnd;
  }

  // Compute the margin offset by counting tabs and non-tabs.

  unsigned PosNo = 0;

  for (const char* c = LineStart; c != TokLogicalPtr; ++c)
    PosNo += *c == '\t' ? 8 : 1;

  // Create the html for the message.
  {
    // Get the string and determining its maximum substring.
    const std::string& Msg = P.getString();
    unsigned max_token = 0;
    unsigned cnt = 0;
    unsigned len = Msg.size();

    for (std::string::const_iterator I=Msg.begin(), E=Msg.end(); I!=E; ++I)
      switch (*I) {
        default:
          ++cnt;
          continue;
        case ' ':
        case '\t':
        case '\n':
          if (cnt > max_token) max_token = cnt;
          cnt = 0;
      }

    if (cnt > max_token) max_token = cnt;

    // Next, determine the approximate size of the message bubble in em.
    unsigned em;
    const unsigned max_line = 80;

    if (max_token >= max_line)
      em = max_token / 2;
    else {
      unsigned characters = max_line;
      unsigned lines = len / max_line;

      if (lines > 0) {
        for (; characters > max_token; --characters)
          if (len / characters > lines) {
            ++characters;
            break;
          }
      }

      em = characters / 2;
    }

    // Now generate the message bubble.
    std::string s;
    llvm::raw_string_ostream os(s);

    os << "\n
	<div id=\"";

    if (num == max)
      os << "EndPath";
    else
      os << "Path" << num;

    os << "\" class=\"msg\" style=\"margin-left:" << PosNo << "ex";
    if (em < max_line/2) os << "; max-width:" << em << "em";
    os << "\">";

    if (max > 1)
      os << "[" << num << "] ";

    os << html::EscapeText(Msg) << "

";

    // Insert the new html.
    unsigned DisplayPos = 0;

    switch (P.getDisplayHint()) {
      case PathDiagnosticPiece::Above:
        DisplayPos = LineStart - FileStart;
        break;
      case PathDiagnosticPiece::Below:
        DisplayPos = LineEnd - FileStart;
        break;
      default:
        assert (false && "Unhandled hint.");
    }

    R.InsertStrBefore(SourceLocation::getFileLoc(FileID, DisplayPos), os.str());
  }

  // Now highlight the ranges.

  for (const SourceRange *I = P.ranges_begin(), *E = P.ranges_end();
        I != E; ++I)
    HighlightRange(R, FileID, *I);
}

void HTMLDiagnostics::HighlightRange(Rewriter& R, unsigned BugFileID,
                                     SourceRange Range) {

  SourceManager& SM = R.getSourceMgr();

  SourceLocation LogicalStart = SM.getLogicalLoc(Range.getBegin());
  unsigned StartLineNo = SM.getLineNumber(LogicalStart);

  SourceLocation LogicalEnd = SM.getLogicalLoc(Range.getEnd());
  unsigned EndLineNo = SM.getLineNumber(LogicalEnd);

  if (EndLineNo < StartLineNo)
    return;

  if (SM.getCanonicalFileID(LogicalStart) != BugFileID ||
      SM.getCanonicalFileID(LogicalEnd) != BugFileID)
    return;

  // Compute the column number of the end.
  unsigned EndColNo = SM.getColumnNumber(LogicalEnd);
  unsigned OldEndColNo = EndColNo;

  if (EndColNo) {
    // Add in the length of the token, so that we cover multi-char tokens.
    EndColNo += Lexer::MeasureTokenLength(Range.getEnd(), SM) - 1;
  }

  // Highlight the range.  Make the span tag the outermost tag for the
  // selected range.

  SourceLocation E = LogicalEnd.getFileLocWithOffset(EndColNo - OldEndColNo);

  html::HighlightRange(R, LogicalStart, E,
                       "", "");
}
<|endoftext|>


<commit_before>// @file irc.cpp
// @brief Implementation of the IRC class, which implements the
//        User, Message and Chat abstract classes.
//

#include <sstream> // std::stringstream
#include "irc.h"

std::deque<std::string> Split(std::string pretext, char delim)
{
  std::deque<std::string> sans_delim;
  std::string tokens;
  std::stringstream sstream(pretext);
  while (std::getline(sstream, tokens, delim))
  {
    sans_delim.push_back(tokens);
  }
  return sans_delim;
}

//----------------------------//
// User Class Implementation. //
//----------------------------//
IRCUser::IRCUser(void)
{
  std::cout << "Creating User" << std::endl;
}

  bool
IRCUser::Equals(User *u)
{
  return true;
}

//-------------------------------//
// Message Class Implementation. //
//-------------------------------//
  std::string
IRCMessage::GetString()
{
  return str;
}

IRCMessage::IRCMessage(std::string s)
{
  // We don't know if the prefix is actually present.
  int prefixEnd = -1;

  // The prefix is actually present.
  if (s.at(0) == ':')
  {
    // The end is before the first space.
    prefixEnd = s.find_first_of(' ');
    // Save the prefix. (Note: we ca further segment it later.)
    prefix = s.substr(1, prefixEnd - 1);
    if (prefix.find('!') != prefix.npos)
    {
      nickname = prefix.substr(0, prefix.find('!'));
    }
  }

  size_t trailBegin = s.find(" :");

  // Check if there is a trailing message.
  if (trailBegin != s.npos)
  {
    // Save the trail (char after colon to end of string).
    str = s.substr(trailBegin + 2, s.npos);
  }
  //
  argList = Split(s.substr(prefixEnd + 1, (trailBegin - prefixEnd - 1)), ' '); //we want a list of the arguments so we can seperately address them

  if (!argList.empty())
  {
    command = argList.at(0);
    argList.pop_front();
  }

  // Trim the \r\n
  if (str.length() > 2) {
    str = str.substr(0, str.length() - 2);
  }

}

  IRCUser*
IRCMessage::GetUser()
{
  return new IRCUser;
}

  IRCMessage*
IRCMessage::Respond(std::string s)
{
  return new IRCMessage(s);
}

//----------------------------//
// Chat Class Implementation. //
//----------------------------//
IRCChat::IRCChat(void)
{
  std::cout << "Creating Chat" << std::endl;
}

  void
IRCChat::Connect(std::string server,
    std::string port,
    std::string user,
    std::string password)
{
  socket = new Socket(server, port);
  socket->Send("PASS PASSWORD\r\n");
  socket->Send("NICK BlueBot\r\n");
  socket->Send("USER BlueBot localhost servername :GreenBot\r\n");
  socket->Send("JOIN #greenbot\r\n");
}

  IRCMessage*
IRCChat::GetMessage()
{
  IRCMessage *m = NULL;
  while (!m)
  {
    m = new IRCMessage(socket->Recv());
    if (m->command == "PING")
    {
      socket->Send("PONG :" + m->str + "\r\n");
      delete m;
    }
  }
  return m;
}

  void
IRCChat::SendMessage(Message *m)
{
  return;
}

<commit_msg>fixed comment location<commit_after>// @file irc.cpp
// @brief Implementation of the IRC class, which implements the
//        User, Message and Chat abstract classes.
//

#include <sstream> // std::stringstream
#include "irc.h"

std::deque<std::string> Split(std::string pretext, char delim)
{
  std::deque<std::string> sans_delim;
  std::string tokens;
  std::stringstream sstream(pretext);
  while (std::getline(sstream, tokens, delim))
  {
    sans_delim.push_back(tokens);
  }
  return sans_delim;
}

//----------------------------//
// User Class Implementation. //
//----------------------------//
IRCUser::IRCUser(void)
{
  std::cout << "Creating User" << std::endl;
}

  bool
IRCUser::Equals(User *u)
{
  return true;
}

//-------------------------------//
// Message Class Implementation. //
//-------------------------------//
  std::string
IRCMessage::GetString()
{
  return str;
}

IRCMessage::IRCMessage(std::string s)
{
  // We don't know if the prefix is actually present.
  int prefixEnd = -1;

  // The prefix is actually present.
  if (s.at(0) == ':')
  {
    // The end is before the first space.
    prefixEnd = s.find_first_of(' ');
    // Save the prefix. (Note: we ca further segment it later.)
    prefix = s.substr(1, prefixEnd - 1);
    if (prefix.find('!') != prefix.npos)
    {
      nickname = prefix.substr(0, prefix.find('!'));
    }
  }

  size_t trailBegin = s.find(" :");

  // Check if there is a trailing message.
  if (trailBegin != s.npos)
  {
    // Save the trail (char after colon to end of string).
    str = s.substr(trailBegin + 2, s.npos);
  }
  // We get a list of the arguments.
  argList = Split(s.substr(prefixEnd + 1, (trailBegin - prefixEnd - 1)), ' ');

  if (!argList.empty())
  {
    command = argList.at(0);
    argList.pop_front();
  }

  // Trim the \r\n
  if (str.length() > 2) {
    str = str.substr(0, str.length() - 2);
  }

}

  IRCUser*
IRCMessage::GetUser()
{
  return new IRCUser;
}

  IRCMessage*
IRCMessage::Respond(std::string s)
{
  return new IRCMessage(s);
}

//----------------------------//
// Chat Class Implementation. //
//----------------------------//
IRCChat::IRCChat(void)
{
  std::cout << "Creating Chat" << std::endl;
}

  void
IRCChat::Connect(std::string server,
    std::string port,
    std::string user,
    std::string password)
{
  socket = new Socket(server, port);
  socket->Send("PASS PASSWORD\r\n");
  socket->Send("NICK BlueBot\r\n");
  socket->Send("USER BlueBot localhost servername :GreenBot\r\n");
  socket->Send("JOIN #greenbot\r\n");
}

  IRCMessage*
IRCChat::GetMessage()
{
  IRCMessage *m = NULL;
  while (!m)
  {
    m = new IRCMessage(socket->Recv());
    if (m->command == "PING")
    {
      socket->Send("PONG :" + m->str + "\r\n");
      delete m;
    }
  }
  return m;
}

  void
IRCChat::SendMessage(Message *m)
{
  return;
}

<|endoftext|>


<commit_before>// Copyright (c) 2009 libmv authors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

#include "libmv/correspondence/feature_matching.h"

#include "libmv/correspondence/ArrayMatcher.h"
#include "libmv/correspondence/ArrayMatcher_BruteForce.h"
#include "libmv/correspondence/ArrayMatcher_Kdtree_Flann.h"
#include "libmv/correspondence/ArrayMatcher_Kdtree.h"

// Compute candidate matches between 2 sets of features.  Two features A and B
// are a candidate match if A is the nearest neighbor of B and B is the nearest
// neighbor of A.
void FindCandidateMatches(const FeatureSet &left,
                          const FeatureSet &right,
                          Matches *matches,
                          eLibmvMatchMethod eMatchMethod) {
  if (left.features.size() == 0 ||
      right.features.size() == 0 )  {
    return;
  }
  int descriptorSize = left.features[0].descriptor.coords.size();

  correspondence::ArrayMatcher<float> * pArrayMatcherA = NULL;
  correspondence::ArrayMatcher<float> * pArrayMatcherB = NULL;
  switch (eMatchMethod)
  {
  case eMATCH_KDTREE:
    {
      // Build the arrays matcher in order to compute matches pair.
      pArrayMatcherA = new correspondence::ArrayMatcher_Kdtree<float>;
      pArrayMatcherB = new correspondence::ArrayMatcher_Kdtree<float>;
    }
    break;
    case eMATCH_KDTREE_FLANN:
    {
      // Build the arrays matcher in order to compute matches pair.
      pArrayMatcherA = new correspondence::ArrayMatcher_Kdtree_Flann<float>;
      pArrayMatcherB = new correspondence::ArrayMatcher_Kdtree_Flann<float>;
    }
    break;
    case eMATCH_LINEAR:
    {
      // Build the arrays matcher in order to compute matches pair.
      pArrayMatcherA = new correspondence::ArrayMatcher_BruteForce<float>;
      pArrayMatcherB = new correspondence::ArrayMatcher_BruteForce<float>;
    }
    break;
  };

  if (pArrayMatcherA != NULL && pArrayMatcherB != NULL) {

    // Paste the necessary data in contiguous arrays.
    float * arrayA = FeatureSet::FeatureSetDescriptorsToContiguousArray(left);
    float * arrayB = FeatureSet::FeatureSetDescriptorsToContiguousArray(right);

    libmv::vector<int> indices, indicesReverse;
    libmv::vector<float> distances, distancesReverse;

    bool breturn = false;
    if (pArrayMatcherA->build(arrayA,left.features.size(),descriptorSize) &&
        pArrayMatcherB->build(arrayB,right.features.size(),descriptorSize) )  {

      const int NN = 1;
      breturn =
        pArrayMatcherB->searchNeighbours(arrayA,left.features.size(),
          &indices, &distances, NN) &&
        pArrayMatcherA->searchNeighbours(arrayB,right.features.size(),
          &indicesReverse, &distancesReverse, NN);
    }
    delete pArrayMatcherA;
    delete pArrayMatcherB;

    delete [] arrayA;
    delete [] arrayB;

    // From putative matches get symmetric matches.
    if (breturn)  {
      //TODO(pmoulon) clear previous matches.
      int max_track_number = 0;
      for (size_t i = 0; i < indices.size(); ++i) {
        // Add the matche only if we have a symetric result.
        if (i == indicesReverse[indices[i]])  {
          matches->Insert(0, max_track_number, &left.features[i]);
          matches->Insert(1, max_track_number, &right.features[indices[i]]);
          ++max_track_number;
        }
      }
    }
    else  {
      LOG(INFO) << "[FindCandidateMatches] Cannot compute symmetric matches.";
    }
  }
  else  {
    LOG(INFO) << "[FindCandidateMatches] Unknow input match method.";
  }
}

float * FeatureSet::FeatureSetDescriptorsToContiguousArray
  ( const FeatureSet & featureSet ) {

  if (featureSet.features.size() == 0)  {
    return NULL;
  }
  int descriptorSize = featureSet.features[0].descriptor.coords.size();
  // Allocate and paste the necessary data.
  float * array = new float[featureSet.features.size()*descriptorSize];

  //-- Paste data in the contiguous array :
  for (int i = 0; i < (int)featureSet.features.size(); ++i) {
    for (int j = 0;j < descriptorSize; ++j)
      array[descriptorSize*i + j] = (float)featureSet.features[i][j];
  }
  return array;
}

// Compute candidate matches between 2 sets of features with a ratio.
void FindCandidateMatches_Ratio(const FeatureSet &left,
                          const FeatureSet &right,
                          Matches *matches,
                          eLibmvMatchMethod eMatchMethod,
                          float fRatio) {

  if (left.features.size() == 0 ||
      right.features.size() == 0 )  {
    return;
  }
  int descriptorSize = left.features[0].descriptor.coords.size();

  correspondence::ArrayMatcher<float> * pArrayMatcherA = NULL;
  switch (eMatchMethod)
  {
  case eMATCH_KDTREE:
    {
      // Build the arrays matcher in order to compute matches pair.
      pArrayMatcherA = new correspondence::ArrayMatcher_Kdtree<float>;
    }
    break;
    case eMATCH_KDTREE_FLANN:
    {
      // Build the arrays matcher in order to compute matches pair.
      pArrayMatcherA = new correspondence::ArrayMatcher_Kdtree_Flann<float>;
    }
    break;
    case eMATCH_LINEAR:
    {
      // Build the arrays matcher in order to compute matches pair.
      LOG(INFO) << "Not yet implemented.";
      return;
    }
    break;
  };

  const int NN = 2;
  if (pArrayMatcherA != NULL) {

    // Paste the necessary data in contiguous arrays.
    float * arrayA = FeatureSet::FeatureSetDescriptorsToContiguousArray(left);
    float * arrayB = FeatureSet::FeatureSetDescriptorsToContiguousArray(right);

    libmv::vector<int> indices;
    libmv::vector<float> distances;

    bool breturn = false;
    if (pArrayMatcherA->build(arrayB,right.features.size(),descriptorSize))  {
      breturn =
        pArrayMatcherA->searchNeighbours(arrayA,left.features.size(),
          &indices, &distances, NN);
    }
    delete pArrayMatcherA;
    delete [] arrayA;
    delete [] arrayB;

    // From putative matches get matches that fit the "Ratio" heuristic.
    if (breturn)  {
      //TODO(pmoulon) clear previous matches.
      int max_track_number = 0;

      for (size_t i = 0; i < left.features.size(); ++i) {
        // Test distance ratio :
        float distance0 = distances[i*NN];
        float distance1 = distances[i*NN+NN-1];

        if (distance0 < fRatio * distance1) {
          matches->Insert(0, max_track_number, &left.features[i]);
          matches->Insert(1, max_track_number, &right.features[indices[i*NN]]);
          ++max_track_number;
        }
      }
    }
    else  {
      LOG(INFO) << "[FindCandidateMatches_Ratio] Cannot compute matches.";
    }
  }
  else  {
    LOG(INFO) << "[FindCandidateMatches_Ratio] Unknow input match method.";
  }
}

// Compute correspondences that match between 2 sets of features with a ratio.
void FindCorrespondences(const FeatureSet &left,
                         const FeatureSet &right,
                         std::map<size_t, size_t> *correspondences,
                         eLibmvMatchMethod eMatchMethod,
                         float fRatio) {
  if (left.features.size() == 0 ||
      right.features.size() == 0 )  {
    return;
  }
  int descriptorSize = left.features[0].descriptor.coords.size();

  correspondence::ArrayMatcher<float> * pArrayMatcherA = NULL;
  switch (eMatchMethod)
  {
  case eMATCH_KDTREE:
    {
      // Build the arrays matcher in order to compute matches pair.
      pArrayMatcherA = new correspondence::ArrayMatcher_Kdtree<float>;
    }
    break;
    case eMATCH_KDTREE_FLANN:
    {
      // Build the arrays matcher in order to compute matches pair.
      pArrayMatcherA = new correspondence::ArrayMatcher_Kdtree_Flann<float>;
    }
    break;
    case eMATCH_LINEAR:
    {
      // Build the arrays matcher in order to compute matches pair.
      LOG(INFO) << "Not yet implemented.";
      return;
    }
    break;
  };

  const int NN = 2;
  if (pArrayMatcherA != NULL) {

    // Paste the necessary data in contiguous arrays.
    float * arrayA = FeatureSet::FeatureSetDescriptorsToContiguousArray(left);
    float * arrayB = FeatureSet::FeatureSetDescriptorsToContiguousArray(right);

    libmv::vector<int> indices;
    libmv::vector<float> distances;

    bool breturn = false;
    if (pArrayMatcherA->build(arrayB,right.features.size(),descriptorSize))  {
      breturn =
        pArrayMatcherA->searchNeighbours(arrayA,left.features.size(),
          &indices, &distances, NN);
    }
    delete pArrayMatcherA;
    delete [] arrayA;
    delete [] arrayB;

    // From putative matches get matches that fit the "Ratio" heuristic.
    if (breturn)  {
      for (size_t i = 0; i < left.features.size(); ++i) {
        // Test distance ratio :
        float distance0 = distances[i*NN];
        float distance1 = distances[i*NN+NN-1];

        if (distance0 < fRatio * distance1) {
          (*correspondences)[i] = indices[i*NN];
        }
      }
    }
    else  {
      LOG(INFO) << "[FindCandidateMatches_Ratio] Cannot compute matches.";
    }
  }
  else  {
    LOG(INFO) << "[FindCandidateMatches_Ratio] Unknow input match method.";
  }
}<commit_msg>Fixed a small logging typo<commit_after>// Copyright (c) 2009 libmv authors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

#include "libmv/correspondence/feature_matching.h"

#include "libmv/correspondence/ArrayMatcher.h"
#include "libmv/correspondence/ArrayMatcher_BruteForce.h"
#include "libmv/correspondence/ArrayMatcher_Kdtree_Flann.h"
#include "libmv/correspondence/ArrayMatcher_Kdtree.h"

// Compute candidate matches between 2 sets of features.  Two features A and B
// are a candidate match if A is the nearest neighbor of B and B is the nearest
// neighbor of A.
void FindCandidateMatches(const FeatureSet &left,
                          const FeatureSet &right,
                          Matches *matches,
                          eLibmvMatchMethod eMatchMethod) {
  if (left.features.size() == 0 ||
      right.features.size() == 0 )  {
    return;
  }
  int descriptorSize = left.features[0].descriptor.coords.size();

  correspondence::ArrayMatcher<float> * pArrayMatcherA = NULL;
  correspondence::ArrayMatcher<float> * pArrayMatcherB = NULL;
  switch (eMatchMethod)
  {
  case eMATCH_KDTREE:
    {
      // Build the arrays matcher in order to compute matches pair.
      pArrayMatcherA = new correspondence::ArrayMatcher_Kdtree<float>;
      pArrayMatcherB = new correspondence::ArrayMatcher_Kdtree<float>;
    }
    break;
    case eMATCH_KDTREE_FLANN:
    {
      // Build the arrays matcher in order to compute matches pair.
      pArrayMatcherA = new correspondence::ArrayMatcher_Kdtree_Flann<float>;
      pArrayMatcherB = new correspondence::ArrayMatcher_Kdtree_Flann<float>;
    }
    break;
    case eMATCH_LINEAR:
    {
      // Build the arrays matcher in order to compute matches pair.
      pArrayMatcherA = new correspondence::ArrayMatcher_BruteForce<float>;
      pArrayMatcherB = new correspondence::ArrayMatcher_BruteForce<float>;
    }
    break;
  };

  if (pArrayMatcherA != NULL && pArrayMatcherB != NULL) {

    // Paste the necessary data in contiguous arrays.
    float * arrayA = FeatureSet::FeatureSetDescriptorsToContiguousArray(left);
    float * arrayB = FeatureSet::FeatureSetDescriptorsToContiguousArray(right);

    libmv::vector<int> indices, indicesReverse;
    libmv::vector<float> distances, distancesReverse;

    bool breturn = false;
    if (pArrayMatcherA->build(arrayA,left.features.size(),descriptorSize) &&
        pArrayMatcherB->build(arrayB,right.features.size(),descriptorSize) )  {

      const int NN = 1;
      breturn =
        pArrayMatcherB->searchNeighbours(arrayA,left.features.size(),
          &indices, &distances, NN) &&
        pArrayMatcherA->searchNeighbours(arrayB,right.features.size(),
          &indicesReverse, &distancesReverse, NN);
    }
    delete pArrayMatcherA;
    delete pArrayMatcherB;

    delete [] arrayA;
    delete [] arrayB;

    // From putative matches get symmetric matches.
    if (breturn)  {
      //TODO(pmoulon) clear previous matches.
      int max_track_number = 0;
      for (size_t i = 0; i < indices.size(); ++i) {
        // Add the matche only if we have a symetric result.
        if (i == indicesReverse[indices[i]])  {
          matches->Insert(0, max_track_number, &left.features[i]);
          matches->Insert(1, max_track_number, &right.features[indices[i]]);
          ++max_track_number;
        }
      }
    }
    else  {
      LOG(INFO) << "[FindCandidateMatches] Cannot compute symmetric matches.";
    }
  }
  else  {
    LOG(INFO) << "[FindCandidateMatches] Unknown input match method.";
  }
}

float * FeatureSet::FeatureSetDescriptorsToContiguousArray
  ( const FeatureSet & featureSet ) {

  if (featureSet.features.size() == 0)  {
    return NULL;
  }
  int descriptorSize = featureSet.features[0].descriptor.coords.size();
  // Allocate and paste the necessary data.
  float * array = new float[featureSet.features.size()*descriptorSize];

  //-- Paste data in the contiguous array :
  for (int i = 0; i < (int)featureSet.features.size(); ++i) {
    for (int j = 0;j < descriptorSize; ++j)
      array[descriptorSize*i + j] = (float)featureSet.features[i][j];
  }
  return array;
}

// Compute candidate matches between 2 sets of features with a ratio.
void FindCandidateMatches_Ratio(const FeatureSet &left,
                          const FeatureSet &right,
                          Matches *matches,
                          eLibmvMatchMethod eMatchMethod,
                          float fRatio) {

  if (left.features.size() == 0 ||
      right.features.size() == 0 )  {
    return;
  }
  int descriptorSize = left.features[0].descriptor.coords.size();

  correspondence::ArrayMatcher<float> * pArrayMatcherA = NULL;
  switch (eMatchMethod)
  {
  case eMATCH_KDTREE:
    {
      // Build the arrays matcher in order to compute matches pair.
      pArrayMatcherA = new correspondence::ArrayMatcher_Kdtree<float>;
    }
    break;
    case eMATCH_KDTREE_FLANN:
    {
      // Build the arrays matcher in order to compute matches pair.
      pArrayMatcherA = new correspondence::ArrayMatcher_Kdtree_Flann<float>;
    }
    break;
    case eMATCH_LINEAR:
    {
      // Build the arrays matcher in order to compute matches pair.
      LOG(INFO) << "Not yet implemented.";
      return;
    }
    break;
  };

  const int NN = 2;
  if (pArrayMatcherA != NULL) {

    // Paste the necessary data in contiguous arrays.
    float * arrayA = FeatureSet::FeatureSetDescriptorsToContiguousArray(left);
    float * arrayB = FeatureSet::FeatureSetDescriptorsToContiguousArray(right);

    libmv::vector<int> indices;
    libmv::vector<float> distances;

    bool breturn = false;
    if (pArrayMatcherA->build(arrayB,right.features.size(),descriptorSize))  {
      breturn =
        pArrayMatcherA->searchNeighbours(arrayA,left.features.size(),
          &indices, &distances, NN);
    }
    delete pArrayMatcherA;
    delete [] arrayA;
    delete [] arrayB;

    // From putative matches get matches that fit the "Ratio" heuristic.
    if (breturn)  {
      //TODO(pmoulon) clear previous matches.
      int max_track_number = 0;

      for (size_t i = 0; i < left.features.size(); ++i) {
        // Test distance ratio :
        float distance0 = distances[i*NN];
        float distance1 = distances[i*NN+NN-1];

        if (distance0 < fRatio * distance1) {
          matches->Insert(0, max_track_number, &left.features[i]);
          matches->Insert(1, max_track_number, &right.features[indices[i*NN]]);
          ++max_track_number;
        }
      }
    }
    else  {
      LOG(INFO) << "[FindCandidateMatches_Ratio] Cannot compute matches.";
    }
  }
  else  {
    LOG(INFO) << "[FindCandidateMatches_Ratio] Unknow input match method.";
  }
}

// Compute correspondences that match between 2 sets of features with a ratio.
void FindCorrespondences(const FeatureSet &left,
                         const FeatureSet &right,
                         std::map<size_t, size_t> *correspondences,
                         eLibmvMatchMethod eMatchMethod,
                         float fRatio) {
  if (left.features.size() == 0 ||
      right.features.size() == 0 )  {
    return;
  }
  int descriptorSize = left.features[0].descriptor.coords.size();

  correspondence::ArrayMatcher<float> * pArrayMatcherA = NULL;
  switch (eMatchMethod)
  {
  case eMATCH_KDTREE:
    {
      // Build the arrays matcher in order to compute matches pair.
      pArrayMatcherA = new correspondence::ArrayMatcher_Kdtree<float>;
    }
    break;
    case eMATCH_KDTREE_FLANN:
    {
      // Build the arrays matcher in order to compute matches pair.
      pArrayMatcherA = new correspondence::ArrayMatcher_Kdtree_Flann<float>;
    }
    break;
    case eMATCH_LINEAR:
    {
      // Build the arrays matcher in order to compute matches pair.
      LOG(INFO) << "Not yet implemented.";
      return;
    }
    break;
  };

  const int NN = 2;
  if (pArrayMatcherA != NULL) {

    // Paste the necessary data in contiguous arrays.
    float * arrayA = FeatureSet::FeatureSetDescriptorsToContiguousArray(left);
    float * arrayB = FeatureSet::FeatureSetDescriptorsToContiguousArray(right);

    libmv::vector<int> indices;
    libmv::vector<float> distances;

    bool breturn = false;
    if (pArrayMatcherA->build(arrayB,right.features.size(),descriptorSize))  {
      breturn =
        pArrayMatcherA->searchNeighbours(arrayA,left.features.size(),
          &indices, &distances, NN);
    }
    delete pArrayMatcherA;
    delete [] arrayA;
    delete [] arrayB;

    // From putative matches get matches that fit the "Ratio" heuristic.
    if (breturn)  {
      for (size_t i = 0; i < left.features.size(); ++i) {
        // Test distance ratio :
        float distance0 = distances[i*NN];
        float distance1 = distances[i*NN+NN-1];

        if (distance0 < fRatio * distance1) {
          (*correspondences)[i] = indices[i*NN];
        }
      }
    }
    else  {
      LOG(INFO) << "[FindCandidateMatches_Ratio] Cannot compute matches.";
    }
  }
  else  {
    LOG(INFO) << "[FindCandidateMatches_Ratio] Unknow input match method.";
  }
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: seekableinput.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: hr $ $Date: 2004-05-10 17:33:49 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _COMPHELPER_STREAM_SEEKABLEINPUT_HXX_
#define _COMPHELPER_STREAM_SEEKABLEINPUT_HXX_

#ifndef _OSL_MUTEX_HXX_ //autogen wg. ::osl::Mutex
#include <osl/mutex.hxx>
#endif

#ifndef _COM_SUN_STAR_UNO_REFERENCE_HXX_
#include <com/sun/star/uno/Reference.hxx>
#endif

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif

#ifndef _COM_SUN_STAR_IO_XINPUTSTREAM_HPP_
#include <com/sun/star/io/XInputStream.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XSEEKABLE_HPP_
#include <com/sun/star/io/XSeekable.hpp>
#endif

#ifndef _CPPUHELPER_IMPLBASE2_HXX_
#include <cppuhelper/implbase2.hxx>
#endif

namespace comphelper
{

class OSeekableInputWrapper : public ::cppu::WeakImplHelper2< ::com::sun::star::io::XInputStream,
                                                                ::com::sun::star::io::XSeekable >
{
    ::osl::Mutex    m_aMutex;

    ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > m_xFactory;

    ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > m_xOriginalStream;

    ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > m_xCopyInput;
    ::com::sun::star::uno::Reference< ::com::sun::star::io::XSeekable > m_xCopySeek;

private:
    void PrepareCopy_Impl();

public:
    OSeekableInputWrapper(
                const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xInStream,
                const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xFactory );

    virtual ~OSeekableInputWrapper();

    static ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > CheckSeekableCanWrap(
                        const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xInStream,
                        const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xFactory );

// XInputStream
    virtual sal_Int32 SAL_CALL readBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual sal_Int32 SAL_CALL readSomeBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual sal_Int32 SAL_CALL available() throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL closeInput() throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);

// XSeekable
    virtual void SAL_CALL seek( sal_Int64 location ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual sal_Int64 SAL_CALL getPosition() throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual sal_Int64 SAL_CALL getLength() throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);

};

}   // namespace comphelper

#endif

<commit_msg>INTEGRATION: CWS visibility02 (1.2.82); FILE MERGED 2005/01/26 18:49:56 mhu 1.2.82.1: #i38608# More classes / symbols need to be exported.<commit_after>/*************************************************************************
 *
 *  $RCSfile: seekableinput.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: vg $ $Date: 2005-02-16 16:01:00 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _COMPHELPER_STREAM_SEEKABLEINPUT_HXX_
#define _COMPHELPER_STREAM_SEEKABLEINPUT_HXX_

#ifndef _OSL_MUTEX_HXX_ //autogen wg. ::osl::Mutex
#include <osl/mutex.hxx>
#endif

#ifndef _COM_SUN_STAR_UNO_REFERENCE_HXX_
#include <com/sun/star/uno/Reference.hxx>
#endif

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif

#ifndef _COM_SUN_STAR_IO_XINPUTSTREAM_HPP_
#include <com/sun/star/io/XInputStream.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XSEEKABLE_HPP_
#include <com/sun/star/io/XSeekable.hpp>
#endif

#ifndef _CPPUHELPER_IMPLBASE2_HXX_
#include <cppuhelper/implbase2.hxx>
#endif

#ifndef INCLUDED_COMPHELPERDLLAPI_H
#include "comphelper/comphelperdllapi.h"
#endif

namespace comphelper
{

class COMPHELPER_DLLPUBLIC OSeekableInputWrapper : public ::cppu::WeakImplHelper2< ::com::sun::star::io::XInputStream,
                                                                ::com::sun::star::io::XSeekable >
{
    ::osl::Mutex    m_aMutex;

    ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > m_xFactory;

    ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > m_xOriginalStream;

    ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > m_xCopyInput;
    ::com::sun::star::uno::Reference< ::com::sun::star::io::XSeekable > m_xCopySeek;

private:
    COMPHELPER_DLLPRIVATE void PrepareCopy_Impl();

public:
    OSeekableInputWrapper(
                const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xInStream,
                const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xFactory );

    virtual ~OSeekableInputWrapper();

    static ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > CheckSeekableCanWrap(
                        const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xInStream,
                        const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xFactory );

// XInputStream
    virtual sal_Int32 SAL_CALL readBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual sal_Int32 SAL_CALL readSomeBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual sal_Int32 SAL_CALL available() throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL closeInput() throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);

// XSeekable
    virtual void SAL_CALL seek( sal_Int64 location ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual sal_Int64 SAL_CALL getPosition() throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual sal_Int64 SAL_CALL getLength() throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);

};

}   // namespace comphelper

#endif

<|endoftext|>


<commit_before>// Copyright (c) 2011 libmv authors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

#include <cstdio>

#include "libmv/logging/logging.h"
#include "libmv/simple_pipeline/bundle.h"
#include "libmv/simple_pipeline/intersect.h"
#include "libmv/simple_pipeline/resect.h"
#include "libmv/simple_pipeline/reconstruction.h"
#include "libmv/simple_pipeline/tracks.h"
#include "libmv/simple_pipeline/camera_intrinsics.h"

namespace libmv {
namespace {

// These are "strategy" classes which make it possible to use the same code for
// both projective and euclidean reconstruction.
// FIXME(MatthiasF): OOP would achieve the same goal while avoiding
// template bloat and making interface changes much easier.
struct EuclideanPipelineRoutines {
  typedef EuclideanReconstruction Reconstruction;
  typedef EuclideanCamera Camera;
  typedef EuclideanPoint Point;

  static void Bundle(const Tracks &tracks,
                     EuclideanReconstruction *reconstruction) {
    EuclideanBundle(tracks, reconstruction);
  }

  static bool Resect(const vector<Marker> &markers,
                     EuclideanReconstruction *reconstruction, bool final_pass) {
    return EuclideanResect(markers, reconstruction, final_pass);
  }

  static bool Intersect(const vector<Marker> &markers,
                        EuclideanReconstruction *reconstruction) {
    return EuclideanIntersect(markers, reconstruction);
  }

  static Marker ProjectMarker(const EuclideanPoint &point,
                              const EuclideanCamera &camera,
                              const CameraIntrinsics &intrinsics) {
    Vec3 projected = camera.R * point.X + camera.t;
    projected /= projected(2);

    Marker reprojected_marker;
    intrinsics.ApplyIntrinsics(projected(0),
                               projected(1),
                               &reprojected_marker.x,
                               &reprojected_marker.y);

    reprojected_marker.image = camera.image;
    reprojected_marker.track = point.track;
    return reprojected_marker;
  }
};

struct ProjectivePipelineRoutines {
  typedef ProjectiveReconstruction Reconstruction;
  typedef ProjectiveCamera Camera;
  typedef ProjectivePoint Point;

  static void Bundle(const Tracks &tracks,
                     ProjectiveReconstruction *reconstruction) {
    ProjectiveBundle(tracks, reconstruction);
  }

  static bool Resect(const vector<Marker> &markers,
                     ProjectiveReconstruction *reconstruction, bool final_pass) {
    return ProjectiveResect(markers, reconstruction);
  }

  static bool Intersect(const vector<Marker> &markers,
                        ProjectiveReconstruction *reconstruction) {
    return ProjectiveIntersect(markers, reconstruction);
  }

  static Marker ProjectMarker(const ProjectivePoint &point,
                              const ProjectiveCamera &camera,
                              const CameraIntrinsics &intrinsics) {
    Vec3 projected = camera.P * point.X;
    projected /= projected(2);

    Marker reprojected_marker;
    intrinsics.ApplyIntrinsics(projected(0),
                               projected(1),
                               &reprojected_marker.x,
                               &reprojected_marker.y);

    reprojected_marker.image = camera.image;
    reprojected_marker.track = point.track;
    return reprojected_marker;
  }
};

}  // namespace

template<typename PipelineRoutines>
void InternalCompleteReconstruction(
    const Tracks &tracks,
    typename PipelineRoutines::Reconstruction *reconstruction) {
  int max_track = tracks.MaxTrack();
  int max_image = tracks.MaxImage();
  int num_resects = -1;
  int num_intersects = -1;
  LG << "Max track: " << max_track;
  LG << "Max image: " << max_image;
  LG << "Number of markers: " << tracks.NumMarkers();
  while (num_resects != 0 || num_intersects != 0) {
    // Do all possible intersections.
    num_intersects = 0;
    for (int track = 0; track <= max_track; ++track) {
      if (reconstruction->PointForTrack(track)) {
        LG << "Skipping point: " << track;
        continue;
      }
      vector<Marker> all_markers = tracks.MarkersForTrack(track);
      LG << "Got " << all_markers.size() << " markers for track " << track;

      vector<Marker> reconstructed_markers;
      for (int i = 0; i < all_markers.size(); ++i) {
        if (reconstruction->CameraForImage(all_markers[i].image)) {
          reconstructed_markers.push_back(all_markers[i]);
        }
      }
      LG << "Got " << reconstructed_markers.size()
         << " reconstructed markers for track " << track;
      if (reconstructed_markers.size() >= 2) {
        PipelineRoutines::Intersect(reconstructed_markers, reconstruction);
        num_intersects++;
        LG << "Ran Intersect() for track " << track;
      }
    }
    if (num_intersects) {
      PipelineRoutines::Bundle(tracks, reconstruction);
      LG << "Ran Bundle() after intersections.";
    }
    LG << "Did " << num_intersects << " intersects.";

    // Do all possible resections.
    num_resects = 0;
    for (int image = 0; image <= max_image; ++image) {
      if (reconstruction->CameraForImage(image)) {
        LG << "Skipping frame: " << image;
        continue;
      }
      vector<Marker> all_markers = tracks.MarkersInImage(image);
      LG << "Got " << all_markers.size() << " markers for image " << image;

      vector<Marker> reconstructed_markers;
      for (int i = 0; i < all_markers.size(); ++i) {
        if (reconstruction->PointForTrack(all_markers[i].track)) {
          reconstructed_markers.push_back(all_markers[i]);
        }
      }
      LG << "Got " << reconstructed_markers.size()
         << " reconstructed markers for image " << image;
      if (reconstructed_markers.size() >= 5) {
        if (PipelineRoutines::Resect(reconstructed_markers, reconstruction, false)) {
          num_resects++;
          LG << "Ran Resect() for image " << image;
        } else {
          LG << "Failed Resect() for image " << image;
        }
      }
    }
    if (num_resects) {
      PipelineRoutines::Bundle(tracks, reconstruction);
    }
    LG << "Did " << num_resects << " resects.";
  }

  // One last pass...
  num_resects = 0;
  for (int image = 0; image <= max_image; ++image) {
    if (reconstruction->CameraForImage(image)) {
      LG << "Skipping frame: " << image;
      continue;
    }
    vector<Marker> all_markers = tracks.MarkersInImage(image);

    vector<Marker> reconstructed_markers;
    for (int i = 0; i < all_markers.size(); ++i) {
      if (reconstruction->PointForTrack(all_markers[i].track)) {
        reconstructed_markers.push_back(all_markers[i]);
      }
    }
    if (reconstructed_markers.size() >= 5) {
      if (PipelineRoutines::Resect(reconstructed_markers, reconstruction, true)) {
        num_resects++;
        LG << "Ran Resect() for image " << image;
      } else {
        LG << "Failed Resect() for image " << image;
      }
    }
  }
  if (num_resects) {
    PipelineRoutines::Bundle(tracks, reconstruction);
  }
}

template<typename PipelineRoutines>
double InternalReprojectionError(const Tracks &image_tracks,
                                 const typename PipelineRoutines::Reconstruction &reconstruction,
                                 const CameraIntrinsics &intrinsics) {
  int num_skipped = 0;
  int num_reprojected = 0;
  double total_error = 0.0;
  vector<Marker> markers = image_tracks.AllMarkers();
  for (int i = 0; i < markers.size(); ++i) {
    const typename PipelineRoutines::Camera *camera =
        reconstruction.CameraForImage(markers[i].image);
    const typename PipelineRoutines::Point *point =
        reconstruction.PointForTrack(markers[i].track);
    if (!camera || !point) {
      num_skipped++;
      continue;
    }
    num_reprojected++;

    Marker reprojected_marker =
        PipelineRoutines::ProjectMarker(*point, *camera, intrinsics);
    double ex = reprojected_marker.x - markers[i].x;
    double ey = reprojected_marker.y - markers[i].y;

    const int N = 100;
    char line[N];
    snprintf(line, N,
           "image %-3d track %-3d "
           "x %7.1f y %7.1f "
           "rx %7.1f ry %7.1f "
           "ex %7.1f ey %7.1f"
           "    e %7.1f",
           markers[i].image,
           markers[i].track,
           markers[i].x,
           markers[i].y,
           reprojected_marker.x,
           reprojected_marker.y,
           ex,
           ey,
           sqrt(ex*ex + ey*ey));
    //LG << line;
    total_error += sqrt(ex*ex + ey*ey);
  }
  LG << "Skipped " << num_skipped << " markers.";
  LG << "Reprojected " << num_reprojected << " markers.";
  LG << "Total error: " << total_error;
  LG << "Average error: " << (total_error / num_reprojected) << " [pixels].";
  return total_error / num_reprojected;
}

double EuclideanReprojectionError(const Tracks &image_tracks,
                                  const EuclideanReconstruction &reconstruction,
                                  const CameraIntrinsics &intrinsics) {
  return InternalReprojectionError<EuclideanPipelineRoutines>(image_tracks,
                                                              reconstruction,
                                                              intrinsics);
}

double ProjectiveReprojectionError(
    const Tracks &image_tracks,
    const ProjectiveReconstruction &reconstruction,
    const CameraIntrinsics &intrinsics) {
  return InternalReprojectionError<ProjectivePipelineRoutines>(image_tracks,
                                                               reconstruction,
                                                               intrinsics);
}

void EuclideanCompleteReconstruction(const Tracks &tracks,
                                     EuclideanReconstruction *reconstruction) {
  InternalCompleteReconstruction<EuclideanPipelineRoutines>(tracks,
                                                            reconstruction);
}

void ProjectiveCompleteReconstruction(const Tracks &tracks,
                                      ProjectiveReconstruction *reconstruction) {
  InternalCompleteReconstruction<ProjectivePipelineRoutines>(tracks,
                                                             reconstruction);
}

void InvertIntrinsicsForTracks(const Tracks &raw_tracks,
                               const CameraIntrinsics &camera_intrinsics,
                               Tracks *calibrated_tracks) {
  vector<Marker> markers = raw_tracks.AllMarkers();
  for (int i = 0; i < markers.size(); ++i) {
    camera_intrinsics.InvertIntrinsics(markers[i].x,
                                       markers[i].y,
                                       &(markers[i].x),
                                       &(markers[i].y));
  }
  *calibrated_tracks = Tracks(markers);
}

}  // namespace libmv
<commit_msg>Fix compilation with MSVC where snprintf function is declared as unsafe and _snprintf should be used instead.<commit_after>// Copyright (c) 2011 libmv authors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

#include <cstdio>

#include "libmv/logging/logging.h"
#include "libmv/simple_pipeline/bundle.h"
#include "libmv/simple_pipeline/intersect.h"
#include "libmv/simple_pipeline/resect.h"
#include "libmv/simple_pipeline/reconstruction.h"
#include "libmv/simple_pipeline/tracks.h"
#include "libmv/simple_pipeline/camera_intrinsics.h"

#ifdef _MSC_VER
#  define snprintf _snprintf
#endif

namespace libmv {
namespace {

// These are "strategy" classes which make it possible to use the same code for
// both projective and euclidean reconstruction.
// FIXME(MatthiasF): OOP would achieve the same goal while avoiding
// template bloat and making interface changes much easier.
struct EuclideanPipelineRoutines {
  typedef EuclideanReconstruction Reconstruction;
  typedef EuclideanCamera Camera;
  typedef EuclideanPoint Point;

  static void Bundle(const Tracks &tracks,
                     EuclideanReconstruction *reconstruction) {
    EuclideanBundle(tracks, reconstruction);
  }

  static bool Resect(const vector<Marker> &markers,
                     EuclideanReconstruction *reconstruction, bool final_pass) {
    return EuclideanResect(markers, reconstruction, final_pass);
  }

  static bool Intersect(const vector<Marker> &markers,
                        EuclideanReconstruction *reconstruction) {
    return EuclideanIntersect(markers, reconstruction);
  }

  static Marker ProjectMarker(const EuclideanPoint &point,
                              const EuclideanCamera &camera,
                              const CameraIntrinsics &intrinsics) {
    Vec3 projected = camera.R * point.X + camera.t;
    projected /= projected(2);

    Marker reprojected_marker;
    intrinsics.ApplyIntrinsics(projected(0),
                               projected(1),
                               &reprojected_marker.x,
                               &reprojected_marker.y);

    reprojected_marker.image = camera.image;
    reprojected_marker.track = point.track;
    return reprojected_marker;
  }
};

struct ProjectivePipelineRoutines {
  typedef ProjectiveReconstruction Reconstruction;
  typedef ProjectiveCamera Camera;
  typedef ProjectivePoint Point;

  static void Bundle(const Tracks &tracks,
                     ProjectiveReconstruction *reconstruction) {
    ProjectiveBundle(tracks, reconstruction);
  }

  static bool Resect(const vector<Marker> &markers,
                     ProjectiveReconstruction *reconstruction, bool final_pass) {
    return ProjectiveResect(markers, reconstruction);
  }

  static bool Intersect(const vector<Marker> &markers,
                        ProjectiveReconstruction *reconstruction) {
    return ProjectiveIntersect(markers, reconstruction);
  }

  static Marker ProjectMarker(const ProjectivePoint &point,
                              const ProjectiveCamera &camera,
                              const CameraIntrinsics &intrinsics) {
    Vec3 projected = camera.P * point.X;
    projected /= projected(2);

    Marker reprojected_marker;
    intrinsics.ApplyIntrinsics(projected(0),
                               projected(1),
                               &reprojected_marker.x,
                               &reprojected_marker.y);

    reprojected_marker.image = camera.image;
    reprojected_marker.track = point.track;
    return reprojected_marker;
  }
};

}  // namespace

template<typename PipelineRoutines>
void InternalCompleteReconstruction(
    const Tracks &tracks,
    typename PipelineRoutines::Reconstruction *reconstruction) {
  int max_track = tracks.MaxTrack();
  int max_image = tracks.MaxImage();
  int num_resects = -1;
  int num_intersects = -1;
  LG << "Max track: " << max_track;
  LG << "Max image: " << max_image;
  LG << "Number of markers: " << tracks.NumMarkers();
  while (num_resects != 0 || num_intersects != 0) {
    // Do all possible intersections.
    num_intersects = 0;
    for (int track = 0; track <= max_track; ++track) {
      if (reconstruction->PointForTrack(track)) {
        LG << "Skipping point: " << track;
        continue;
      }
      vector<Marker> all_markers = tracks.MarkersForTrack(track);
      LG << "Got " << all_markers.size() << " markers for track " << track;

      vector<Marker> reconstructed_markers;
      for (int i = 0; i < all_markers.size(); ++i) {
        if (reconstruction->CameraForImage(all_markers[i].image)) {
          reconstructed_markers.push_back(all_markers[i]);
        }
      }
      LG << "Got " << reconstructed_markers.size()
         << " reconstructed markers for track " << track;
      if (reconstructed_markers.size() >= 2) {
        PipelineRoutines::Intersect(reconstructed_markers, reconstruction);
        num_intersects++;
        LG << "Ran Intersect() for track " << track;
      }
    }
    if (num_intersects) {
      PipelineRoutines::Bundle(tracks, reconstruction);
      LG << "Ran Bundle() after intersections.";
    }
    LG << "Did " << num_intersects << " intersects.";

    // Do all possible resections.
    num_resects = 0;
    for (int image = 0; image <= max_image; ++image) {
      if (reconstruction->CameraForImage(image)) {
        LG << "Skipping frame: " << image;
        continue;
      }
      vector<Marker> all_markers = tracks.MarkersInImage(image);
      LG << "Got " << all_markers.size() << " markers for image " << image;

      vector<Marker> reconstructed_markers;
      for (int i = 0; i < all_markers.size(); ++i) {
        if (reconstruction->PointForTrack(all_markers[i].track)) {
          reconstructed_markers.push_back(all_markers[i]);
        }
      }
      LG << "Got " << reconstructed_markers.size()
         << " reconstructed markers for image " << image;
      if (reconstructed_markers.size() >= 5) {
        if (PipelineRoutines::Resect(reconstructed_markers, reconstruction, false)) {
          num_resects++;
          LG << "Ran Resect() for image " << image;
        } else {
          LG << "Failed Resect() for image " << image;
        }
      }
    }
    if (num_resects) {
      PipelineRoutines::Bundle(tracks, reconstruction);
    }
    LG << "Did " << num_resects << " resects.";
  }

  // One last pass...
  num_resects = 0;
  for (int image = 0; image <= max_image; ++image) {
    if (reconstruction->CameraForImage(image)) {
      LG << "Skipping frame: " << image;
      continue;
    }
    vector<Marker> all_markers = tracks.MarkersInImage(image);

    vector<Marker> reconstructed_markers;
    for (int i = 0; i < all_markers.size(); ++i) {
      if (reconstruction->PointForTrack(all_markers[i].track)) {
        reconstructed_markers.push_back(all_markers[i]);
      }
    }
    if (reconstructed_markers.size() >= 5) {
      if (PipelineRoutines::Resect(reconstructed_markers, reconstruction, true)) {
        num_resects++;
        LG << "Ran Resect() for image " << image;
      } else {
        LG << "Failed Resect() for image " << image;
      }
    }
  }
  if (num_resects) {
    PipelineRoutines::Bundle(tracks, reconstruction);
  }
}

template<typename PipelineRoutines>
double InternalReprojectionError(const Tracks &image_tracks,
                                 const typename PipelineRoutines::Reconstruction &reconstruction,
                                 const CameraIntrinsics &intrinsics) {
  int num_skipped = 0;
  int num_reprojected = 0;
  double total_error = 0.0;
  vector<Marker> markers = image_tracks.AllMarkers();
  for (int i = 0; i < markers.size(); ++i) {
    const typename PipelineRoutines::Camera *camera =
        reconstruction.CameraForImage(markers[i].image);
    const typename PipelineRoutines::Point *point =
        reconstruction.PointForTrack(markers[i].track);
    if (!camera || !point) {
      num_skipped++;
      continue;
    }
    num_reprojected++;

    Marker reprojected_marker =
        PipelineRoutines::ProjectMarker(*point, *camera, intrinsics);
    double ex = reprojected_marker.x - markers[i].x;
    double ey = reprojected_marker.y - markers[i].y;

    const int N = 100;
    char line[N];
    snprintf(line, N,
           "image %-3d track %-3d "
           "x %7.1f y %7.1f "
           "rx %7.1f ry %7.1f "
           "ex %7.1f ey %7.1f"
           "    e %7.1f",
           markers[i].image,
           markers[i].track,
           markers[i].x,
           markers[i].y,
           reprojected_marker.x,
           reprojected_marker.y,
           ex,
           ey,
           sqrt(ex*ex + ey*ey));
    //LG << line;
    total_error += sqrt(ex*ex + ey*ey);
  }
  LG << "Skipped " << num_skipped << " markers.";
  LG << "Reprojected " << num_reprojected << " markers.";
  LG << "Total error: " << total_error;
  LG << "Average error: " << (total_error / num_reprojected) << " [pixels].";
  return total_error / num_reprojected;
}

double EuclideanReprojectionError(const Tracks &image_tracks,
                                  const EuclideanReconstruction &reconstruction,
                                  const CameraIntrinsics &intrinsics) {
  return InternalReprojectionError<EuclideanPipelineRoutines>(image_tracks,
                                                              reconstruction,
                                                              intrinsics);
}

double ProjectiveReprojectionError(
    const Tracks &image_tracks,
    const ProjectiveReconstruction &reconstruction,
    const CameraIntrinsics &intrinsics) {
  return InternalReprojectionError<ProjectivePipelineRoutines>(image_tracks,
                                                               reconstruction,
                                                               intrinsics);
}

void EuclideanCompleteReconstruction(const Tracks &tracks,
                                     EuclideanReconstruction *reconstruction) {
  InternalCompleteReconstruction<EuclideanPipelineRoutines>(tracks,
                                                            reconstruction);
}

void ProjectiveCompleteReconstruction(const Tracks &tracks,
                                      ProjectiveReconstruction *reconstruction) {
  InternalCompleteReconstruction<ProjectivePipelineRoutines>(tracks,
                                                             reconstruction);
}

void InvertIntrinsicsForTracks(const Tracks &raw_tracks,
                               const CameraIntrinsics &camera_intrinsics,
                               Tracks *calibrated_tracks) {
  vector<Marker> markers = raw_tracks.AllMarkers();
  for (int i = 0; i < markers.size(); ++i) {
    camera_intrinsics.InvertIntrinsics(markers[i].x,
                                       markers[i].y,
                                       &(markers[i].x),
                                       &(markers[i].y));
  }
  *calibrated_tracks = Tracks(markers);
}

}  // namespace libmv
<|endoftext|>