<commit_before>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Baldur Karlsson
 *
 * 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 "CaptureContext.h"
#include <QApplication>
#include <QDir>
#include <QFileInfo>
#include <QLabel>
#include <QMenu>
#include <QMessageBox>
#include <QMetaObject>
#include <QProgressDialog>
#include <QStandardPaths>
#include <QTimer>
#include "Windows/Dialogs/CaptureDialog.h"
#include "Windows/EventBrowser.h"
#include "Windows/MainWindow.h"
#include "Windows/TextureViewer.h"
#include "QRDUtils.h"

CaptureContext::CaptureContext(QString paramFilename, QString remoteHost, uint32_t remoteIdent,
                               bool temp, PersistantConfig &cfg)
    : Config(cfg)
{
  m_LogLoaded = false;
  m_LoadInProgress = false;

  m_EventID = 0;

  memset(&m_APIProps, 0, sizeof(m_APIProps));

  qApp->setApplicationVersion(RENDERDOC_GetVersionString());

  m_MainWindow = new MainWindow(this);
  m_MainWindow->show();

  if(!paramFilename.isEmpty())
  {
    QFileInfo fi(paramFilename);

    m_MainWindow->LoadFromFilename(paramFilename);
  }
}

CaptureContext::~CaptureContext()
{
  m_Renderer.CloseThread();
  delete m_MainWindow;
}

bool CaptureContext::isRunning()
{
  return m_MainWindow && m_MainWindow->isVisible();
}

QString CaptureContext::ConfigFile(const QString &filename)
{
  QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);

  QDir dir(path);
  if(!dir.exists())
    dir.mkdir(".");

  return QDir::cleanPath(dir.absoluteFilePath(filename));
}

QString CaptureContext::TempLogFilename(QString appname)
{
  QString folder = Config.TemporaryCaptureDirectory;

  QDir dir(folder);

  if(folder == "" || !dir.exists())
    dir = QDir(QDir::tempPath());

  return dir.absoluteFilePath(
      appname + "_" + QDateTime::currentDateTimeUtc().toString("yyyy.MM.dd_HH.mm.ss") + ".rdc");
}

void CaptureContext::LoadLogfile(const QString &logFile, const QString &origFilename,
                                 bool temporary, bool local)
{
  m_Progress = new QProgressDialog(QString("Loading Log"), QString(), 0, 1000, m_MainWindow);
  m_Progress->setWindowTitle("Please Wait");
  m_Progress->setWindowFlags(Qt::CustomizeWindowHint | Qt::Dialog | Qt::WindowTitleHint);
  m_Progress->setWindowIcon(QIcon());
  m_Progress->setMinimumSize(QSize(250, 0));
  m_Progress->setMaximumSize(QSize(250, 10000));
  m_Progress->setCancelButton(NULL);
  m_Progress->setMinimumDuration(0);
  m_Progress->setWindowModality(Qt::ApplicationModal);
  m_Progress->setValue(0);

  QLabel *label = new QLabel(m_Progress);

  label->setText(QString("Loading Log: %1").arg(origFilename));
  label->setAlignment(Qt::AlignCenter);
  label->setWordWrap(true);

  m_Progress->setLabel(label);

  LambdaThread *thread = new LambdaThread([this, logFile, origFilename, temporary, local]() {
    LoadLogfileThreaded(logFile, origFilename, temporary, local);

    GUIInvoke::call([this, origFilename]() {
      delete m_Progress;
      m_Progress = NULL;
    });
  });
  thread->selfDelete(true);
  thread->start();
}

void CaptureContext::LoadLogfileThreaded(const QString &logFile, const QString &origFilename,
                                         bool temporary, bool local)
{
  QFileInfo fi(ConfigFile("UI.config"));

  m_LogFile = origFilename;

  m_LogLocal = local;

  m_LoadInProgress = true;

  if(fi.exists())
    Config.Serialize(fi.absoluteFilePath());

  float loadProgress = 0.0f;
  float postloadProgress = 0.0f;

  QSemaphore progressThread(1);

  LambdaThread progressTickerThread([this, &progressThread, &loadProgress, &postloadProgress]() {
    while(progressThread.available())
    {
      QThread::msleep(30);

      float val = 0.8f * loadProgress + 0.19f * postloadProgress + 0.01f;

      GUIInvoke::call([this, val]() {
        m_Progress->setValue(val * 1000);
        m_MainWindow->setProgress(val);
      });
    }
    GUIInvoke::call([this]() { m_Progress->setValue(1000); });
  });
  progressTickerThread.start();

  // this function call will block until the log is either loaded, or there's some failure
  m_Renderer.OpenCapture(logFile, &loadProgress);

  // if the renderer isn't running, we hit a failure case so display an error message
  if(!m_Renderer.IsRunning())
  {
    QString errmsg = "Unknown error message";
    errmsg = ToQStr(m_Renderer.GetCreateStatus());

    progressThread.acquire();
    progressTickerThread.wait();

    RDDialog::critical(NULL, "Error opening log",
                       QString("%1\nFailed to open logfile for replay: %2.\n\n"
                               "Check diagnostic log in Help menu for more details.")
                           .arg(logFile)
                           .arg(errmsg));

    GUIInvoke::call([this]() {
      m_Progress->setValue(1000);
      m_MainWindow->setProgress(-1.0f);
      m_Progress->hide();
    });

    m_LoadInProgress = false;

    return;
  }

  if(!temporary)
  {
    PersistantConfig::AddRecentFile(Config.RecentLogFiles, origFilename, 10);

    if(fi.exists())
      Config.Serialize(fi.absoluteFilePath());
  }

  m_EventID = 0;

  // fetch initial data like drawcalls, textures and buffers
  m_Renderer.BlockInvoke([this, &postloadProgress](IReplayRenderer *r) {
    r->GetFrameInfo(&m_FrameInfo);

    m_APIProps = r->GetAPIProperties();

    postloadProgress = 0.2f;

    r->GetDrawcalls(&m_Drawcalls);

    postloadProgress = 0.4f;

    r->GetSupportedWindowSystems(&m_WinSystems);

#if defined(RENDERDOC_PLATFORM_WIN32)
    m_CurWinSystem = eWindowingSystem_Win32;
#elif defined(RENDERDOC_PLATFORM_LINUX)
    m_CurWinSystem = eWindowingSystem_Xlib;

    // prefer XCB, if supported
    for(WindowingSystem sys : m_WinSystems)
    {
      if(sys == eWindowingSystem_XCB)
      {
        m_CurWinSystem = eWindowingSystem_XCB;
        break;
      }
    }

    if(m_CurWinSystem == eWindowingSystem_XCB)
      m_XCBConnection = QX11Info::connection();
    else
      m_X11Display = QX11Info::display();
#endif

    r->GetBuffers(&m_BufferList);
    for(FetchBuffer &b : m_BufferList)
      m_Buffers[b.ID] = &b;

    postloadProgress = 0.8f;

    r->GetTextures(&m_TextureList);
    for(FetchTexture &t : m_TextureList)
      m_Textures[t.ID] = &t;

    postloadProgress = 0.9f;

    r->GetD3D11PipelineState(&CurD3D11PipelineState);
    r->GetD3D12PipelineState(&CurD3D12PipelineState);
    r->GetGLPipelineState(&CurGLPipelineState);
    r->GetVulkanPipelineState(&CurVulkanPipelineState);
    CurPipelineState.SetStates(m_APIProps, &CurD3D11PipelineState, &CurD3D12PipelineState,
                               &CurGLPipelineState, &CurVulkanPipelineState);

    UnreadMessageCount = 0;
    AddMessages(m_FrameInfo.debugMessages);

    postloadProgress = 1.0f;
  });

  QThread::msleep(20);

  QDateTime today = QDateTime::currentDateTimeUtc();
  QDateTime compare = today.addDays(-21);

  if(compare > Config.DegradedLog_LastUpdate && m_APIProps.degraded)
  {
    Config.DegradedLog_LastUpdate = today;

    RDDialog::critical(
        NULL, "Degraded support of log",
        QString(
            "%1\nThis log opened with degraded support - "
            "this could mean missing hardware support caused a fallback to software rendering.\n\n"
            "This warning will not appear every time this happens, "
            "check debug errors/warnings window for more details.")
            .arg(origFilename));
  }

  m_LogLoaded = true;

  progressThread.acquire();
  progressTickerThread.wait();

  QVector<ILogViewerForm *> logviewers(m_LogViewers);

  GUIInvoke::blockcall([&logviewers]() {
    // notify all the registers log viewers that a log has been loaded
    for(ILogViewerForm *logviewer : logviewers)
    {
      if(logviewer)
        logviewer->OnLogfileLoaded();
    }
  });

  m_LoadInProgress = false;

  GUIInvoke::call([this]() {
    m_Progress->setValue(1000);
    m_MainWindow->setProgress(1.0f);
    m_Progress->hide();
  });
}

void CaptureContext::CloseLogfile()
{
  if(!m_LogLoaded)
    return;

  m_LogFile = "";

  m_Renderer.CloseThread();

  memset(&m_APIProps, 0, sizeof(m_APIProps));
  memset(&m_FrameInfo, 0, sizeof(m_FrameInfo));
  m_Buffers.clear();
  m_BufferList.clear();
  m_Textures.clear();
  m_TextureList.clear();

  CurD3D11PipelineState = D3D11PipelineState();
  CurD3D12PipelineState = D3D12PipelineState();
  CurGLPipelineState = GLPipelineState();
  CurVulkanPipelineState = VulkanPipelineState();
  CurPipelineState.SetStates(m_APIProps, NULL, NULL, NULL, NULL);

  DebugMessages.clear();
  UnreadMessageCount = 0;

  m_LogLoaded = false;

  QVector<ILogViewerForm *> logviewers(m_LogViewers);

  for(ILogViewerForm *logviewer : logviewers)
  {
    if(logviewer)
      logviewer->OnLogfileClosed();
  }
}

void CaptureContext::SetEventID(ILogViewerForm *exclude, uint32_t eventID, bool force)
{
  m_EventID = eventID;

  m_Renderer.BlockInvoke([this, eventID, force](IReplayRenderer *r) {
    r->SetFrameEvent(eventID, force);
    r->GetD3D11PipelineState(&CurD3D11PipelineState);
    r->GetD3D12PipelineState(&CurD3D12PipelineState);
    r->GetGLPipelineState(&CurGLPipelineState);
    r->GetVulkanPipelineState(&CurVulkanPipelineState);
    CurPipelineState.SetStates(m_APIProps, &CurD3D11PipelineState, &CurD3D12PipelineState,
                               &CurGLPipelineState, &CurVulkanPipelineState);
  });

  for(ILogViewerForm *logviewer : m_LogViewers)
  {
    if(logviewer == exclude)
      continue;

    logviewer->OnEventSelected(eventID);
  }
}

void *CaptureContext::FillWindowingData(WId widget)
{
#if defined(WIN32)

  return (void *)widget;

#elif defined(RENDERDOC_PLATFORM_LINUX)

  static XCBWindowData xcb = {
      m_XCBConnection, (xcb_window_t)widget,
  };

  static XlibWindowData xlib = {m_X11Display, (Drawable)widget};

  if(m_CurWinSystem == eWindowingSystem_XCB)
    return &xcb;
  else
    return &xlib;

#else

#error "Unknown platform"

#endif
}

EventBrowser *CaptureContext::eventBrowser()
{
  if(m_EventBrowser)
    return m_EventBrowser;

  m_EventBrowser = new EventBrowser(this, m_MainWindow);
  m_EventBrowser->setObjectName("eventBrowser");

  return m_EventBrowser;
}

TextureViewer *CaptureContext::textureViewer()
{
  if(m_TextureViewer)
    return m_TextureViewer;

  m_TextureViewer = new TextureViewer(this, m_MainWindow);
  m_TextureViewer->setObjectName("textureViewer");

  return m_TextureViewer;
}

CaptureDialog *CaptureContext::captureDialog()
{
  if(m_CaptureDialog)
    return m_CaptureDialog;

  m_CaptureDialog = new CaptureDialog(
      this,
      [this](const QString &exe, const QString &workingDir, const QString &cmdLine,
             const QList<EnvironmentModification> &env, CaptureOptions opts) {
        return m_MainWindow->OnCaptureTrigger(exe, workingDir, cmdLine, env, opts);
      },
      [this](uint32_t PID, const QList<EnvironmentModification> &env, const QString &name,
             CaptureOptions opts) { return m_MainWindow->OnInjectTrigger(PID, env, name, opts); },
      m_MainWindow);
  m_CaptureDialog->setObjectName("capDialog");

  return m_CaptureDialog;
}

QWidget *CaptureContext::createToolWindow(const QString &objectName)
{
  if(objectName == "textureViewer")
  {
    return textureViewer();
  }
  else if(objectName == "eventBrowser")
  {
    return eventBrowser();
  }
  else if(objectName == "capDialog")
  {
    return captureDialog();
  }

  return NULL;
}

void CaptureContext::windowClosed(QWidget *window)
{
  if((QWidget *)m_EventBrowser == window)
    m_EventBrowser = NULL;
  else if((QWidget *)m_TextureViewer == window)
    m_TextureViewer = NULL;
  else if((QWidget *)m_CaptureDialog == window)
    m_CaptureDialog = NULL;
  else
    qCritical() << "Unrecognised window being closed: " << window;
}
<commit_msg>Set XCB/Xlib data every time<commit_after>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Baldur Karlsson
 *
 * 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 "CaptureContext.h"
#include <QApplication>
#include <QDir>
#include <QFileInfo>
#include <QLabel>
#include <QMenu>
#include <QMessageBox>
#include <QMetaObject>
#include <QProgressDialog>
#include <QStandardPaths>
#include <QTimer>
#include "Windows/Dialogs/CaptureDialog.h"
#include "Windows/EventBrowser.h"
#include "Windows/MainWindow.h"
#include "Windows/TextureViewer.h"
#include "QRDUtils.h"

CaptureContext::CaptureContext(QString paramFilename, QString remoteHost, uint32_t remoteIdent,
                               bool temp, PersistantConfig &cfg)
    : Config(cfg)
{
  m_LogLoaded = false;
  m_LoadInProgress = false;

  m_EventID = 0;

  memset(&m_APIProps, 0, sizeof(m_APIProps));

  qApp->setApplicationVersion(RENDERDOC_GetVersionString());

  m_MainWindow = new MainWindow(this);
  m_MainWindow->show();

  if(!paramFilename.isEmpty())
  {
    QFileInfo fi(paramFilename);

    m_MainWindow->LoadFromFilename(paramFilename);
  }
}

CaptureContext::~CaptureContext()
{
  m_Renderer.CloseThread();
  delete m_MainWindow;
}

bool CaptureContext::isRunning()
{
  return m_MainWindow && m_MainWindow->isVisible();
}

QString CaptureContext::ConfigFile(const QString &filename)
{
  QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);

  QDir dir(path);
  if(!dir.exists())
    dir.mkdir(".");

  return QDir::cleanPath(dir.absoluteFilePath(filename));
}

QString CaptureContext::TempLogFilename(QString appname)
{
  QString folder = Config.TemporaryCaptureDirectory;

  QDir dir(folder);

  if(folder == "" || !dir.exists())
    dir = QDir(QDir::tempPath());

  return dir.absoluteFilePath(
      appname + "_" + QDateTime::currentDateTimeUtc().toString("yyyy.MM.dd_HH.mm.ss") + ".rdc");
}

void CaptureContext::LoadLogfile(const QString &logFile, const QString &origFilename,
                                 bool temporary, bool local)
{
  m_Progress = new QProgressDialog(QString("Loading Log"), QString(), 0, 1000, m_MainWindow);
  m_Progress->setWindowTitle("Please Wait");
  m_Progress->setWindowFlags(Qt::CustomizeWindowHint | Qt::Dialog | Qt::WindowTitleHint);
  m_Progress->setWindowIcon(QIcon());
  m_Progress->setMinimumSize(QSize(250, 0));
  m_Progress->setMaximumSize(QSize(250, 10000));
  m_Progress->setCancelButton(NULL);
  m_Progress->setMinimumDuration(0);
  m_Progress->setWindowModality(Qt::ApplicationModal);
  m_Progress->setValue(0);

  QLabel *label = new QLabel(m_Progress);

  label->setText(QString("Loading Log: %1").arg(origFilename));
  label->setAlignment(Qt::AlignCenter);
  label->setWordWrap(true);

  m_Progress->setLabel(label);

  LambdaThread *thread = new LambdaThread([this, logFile, origFilename, temporary, local]() {
    LoadLogfileThreaded(logFile, origFilename, temporary, local);

    GUIInvoke::call([this, origFilename]() {
      delete m_Progress;
      m_Progress = NULL;
    });
  });
  thread->selfDelete(true);
  thread->start();
}

void CaptureContext::LoadLogfileThreaded(const QString &logFile, const QString &origFilename,
                                         bool temporary, bool local)
{
  QFileInfo fi(ConfigFile("UI.config"));

  m_LogFile = origFilename;

  m_LogLocal = local;

  m_LoadInProgress = true;

  if(fi.exists())
    Config.Serialize(fi.absoluteFilePath());

  float loadProgress = 0.0f;
  float postloadProgress = 0.0f;

  QSemaphore progressThread(1);

  LambdaThread progressTickerThread([this, &progressThread, &loadProgress, &postloadProgress]() {
    while(progressThread.available())
    {
      QThread::msleep(30);

      float val = 0.8f * loadProgress + 0.19f * postloadProgress + 0.01f;

      GUIInvoke::call([this, val]() {
        m_Progress->setValue(val * 1000);
        m_MainWindow->setProgress(val);
      });
    }
    GUIInvoke::call([this]() { m_Progress->setValue(1000); });
  });
  progressTickerThread.start();

  // this function call will block until the log is either loaded, or there's some failure
  m_Renderer.OpenCapture(logFile, &loadProgress);

  // if the renderer isn't running, we hit a failure case so display an error message
  if(!m_Renderer.IsRunning())
  {
    QString errmsg = "Unknown error message";
    errmsg = ToQStr(m_Renderer.GetCreateStatus());

    progressThread.acquire();
    progressTickerThread.wait();

    RDDialog::critical(NULL, "Error opening log",
                       QString("%1\nFailed to open logfile for replay: %2.\n\n"
                               "Check diagnostic log in Help menu for more details.")
                           .arg(logFile)
                           .arg(errmsg));

    GUIInvoke::call([this]() {
      m_Progress->setValue(1000);
      m_MainWindow->setProgress(-1.0f);
      m_Progress->hide();
    });

    m_LoadInProgress = false;

    return;
  }

  if(!temporary)
  {
    PersistantConfig::AddRecentFile(Config.RecentLogFiles, origFilename, 10);

    if(fi.exists())
      Config.Serialize(fi.absoluteFilePath());
  }

  m_EventID = 0;

  // fetch initial data like drawcalls, textures and buffers
  m_Renderer.BlockInvoke([this, &postloadProgress](IReplayRenderer *r) {
    r->GetFrameInfo(&m_FrameInfo);

    m_APIProps = r->GetAPIProperties();

    postloadProgress = 0.2f;

    r->GetDrawcalls(&m_Drawcalls);

    postloadProgress = 0.4f;

    r->GetSupportedWindowSystems(&m_WinSystems);

#if defined(RENDERDOC_PLATFORM_WIN32)
    m_CurWinSystem = eWindowingSystem_Win32;
#elif defined(RENDERDOC_PLATFORM_LINUX)
    m_CurWinSystem = eWindowingSystem_Xlib;

    // prefer XCB, if supported
    for(WindowingSystem sys : m_WinSystems)
    {
      if(sys == eWindowingSystem_XCB)
      {
        m_CurWinSystem = eWindowingSystem_XCB;
        break;
      }
    }

    if(m_CurWinSystem == eWindowingSystem_XCB)
      m_XCBConnection = QX11Info::connection();
    else
      m_X11Display = QX11Info::display();
#endif

    r->GetBuffers(&m_BufferList);
    for(FetchBuffer &b : m_BufferList)
      m_Buffers[b.ID] = &b;

    postloadProgress = 0.8f;

    r->GetTextures(&m_TextureList);
    for(FetchTexture &t : m_TextureList)
      m_Textures[t.ID] = &t;

    postloadProgress = 0.9f;

    r->GetD3D11PipelineState(&CurD3D11PipelineState);
    r->GetD3D12PipelineState(&CurD3D12PipelineState);
    r->GetGLPipelineState(&CurGLPipelineState);
    r->GetVulkanPipelineState(&CurVulkanPipelineState);
    CurPipelineState.SetStates(m_APIProps, &CurD3D11PipelineState, &CurD3D12PipelineState,
                               &CurGLPipelineState, &CurVulkanPipelineState);

    UnreadMessageCount = 0;
    AddMessages(m_FrameInfo.debugMessages);

    postloadProgress = 1.0f;
  });

  QThread::msleep(20);

  QDateTime today = QDateTime::currentDateTimeUtc();
  QDateTime compare = today.addDays(-21);

  if(compare > Config.DegradedLog_LastUpdate && m_APIProps.degraded)
  {
    Config.DegradedLog_LastUpdate = today;

    RDDialog::critical(
        NULL, "Degraded support of log",
        QString(
            "%1\nThis log opened with degraded support - "
            "this could mean missing hardware support caused a fallback to software rendering.\n\n"
            "This warning will not appear every time this happens, "
            "check debug errors/warnings window for more details.")
            .arg(origFilename));
  }

  m_LogLoaded = true;

  progressThread.acquire();
  progressTickerThread.wait();

  QVector<ILogViewerForm *> logviewers(m_LogViewers);

  GUIInvoke::blockcall([&logviewers]() {
    // notify all the registers log viewers that a log has been loaded
    for(ILogViewerForm *logviewer : logviewers)
    {
      if(logviewer)
        logviewer->OnLogfileLoaded();
    }
  });

  m_LoadInProgress = false;

  GUIInvoke::call([this]() {
    m_Progress->setValue(1000);
    m_MainWindow->setProgress(1.0f);
    m_Progress->hide();
  });
}

void CaptureContext::CloseLogfile()
{
  if(!m_LogLoaded)
    return;

  m_LogFile = "";

  m_Renderer.CloseThread();

  memset(&m_APIProps, 0, sizeof(m_APIProps));
  memset(&m_FrameInfo, 0, sizeof(m_FrameInfo));
  m_Buffers.clear();
  m_BufferList.clear();
  m_Textures.clear();
  m_TextureList.clear();

  CurD3D11PipelineState = D3D11PipelineState();
  CurD3D12PipelineState = D3D12PipelineState();
  CurGLPipelineState = GLPipelineState();
  CurVulkanPipelineState = VulkanPipelineState();
  CurPipelineState.SetStates(m_APIProps, NULL, NULL, NULL, NULL);

  DebugMessages.clear();
  UnreadMessageCount = 0;

  m_LogLoaded = false;

  QVector<ILogViewerForm *> logviewers(m_LogViewers);

  for(ILogViewerForm *logviewer : logviewers)
  {
    if(logviewer)
      logviewer->OnLogfileClosed();
  }
}

void CaptureContext::SetEventID(ILogViewerForm *exclude, uint32_t eventID, bool force)
{
  m_EventID = eventID;

  m_Renderer.BlockInvoke([this, eventID, force](IReplayRenderer *r) {
    r->SetFrameEvent(eventID, force);
    r->GetD3D11PipelineState(&CurD3D11PipelineState);
    r->GetD3D12PipelineState(&CurD3D12PipelineState);
    r->GetGLPipelineState(&CurGLPipelineState);
    r->GetVulkanPipelineState(&CurVulkanPipelineState);
    CurPipelineState.SetStates(m_APIProps, &CurD3D11PipelineState, &CurD3D12PipelineState,
                               &CurGLPipelineState, &CurVulkanPipelineState);
  });

  for(ILogViewerForm *logviewer : m_LogViewers)
  {
    if(logviewer == exclude)
      continue;

    logviewer->OnEventSelected(eventID);
  }
}

void *CaptureContext::FillWindowingData(WId widget)
{
#if defined(WIN32)

  return (void *)widget;

#elif defined(RENDERDOC_PLATFORM_LINUX)

  static XCBWindowData xcb;
  static XlibWindowData xlib;

  if(m_CurWinSystem == eWindowingSystem_XCB)
  {
    xcb.connection = m_XCBConnection;
    xcb.window = (xcb_window_t)widget;
    return &xcb;
  }
  else
  {
    xlib.display = m_X11Display;
    xlib.window = (Drawable)widget;
    return &xlib;
  }

#else

#error "Unknown platform"

#endif
}

EventBrowser *CaptureContext::eventBrowser()
{
  if(m_EventBrowser)
    return m_EventBrowser;

  m_EventBrowser = new EventBrowser(this, m_MainWindow);
  m_EventBrowser->setObjectName("eventBrowser");

  return m_EventBrowser;
}

TextureViewer *CaptureContext::textureViewer()
{
  if(m_TextureViewer)
    return m_TextureViewer;

  m_TextureViewer = new TextureViewer(this, m_MainWindow);
  m_TextureViewer->setObjectName("textureViewer");

  return m_TextureViewer;
}

CaptureDialog *CaptureContext::captureDialog()
{
  if(m_CaptureDialog)
    return m_CaptureDialog;

  m_CaptureDialog = new CaptureDialog(
      this,
      [this](const QString &exe, const QString &workingDir, const QString &cmdLine,
             const QList<EnvironmentModification> &env, CaptureOptions opts) {
        return m_MainWindow->OnCaptureTrigger(exe, workingDir, cmdLine, env, opts);
      },
      [this](uint32_t PID, const QList<EnvironmentModification> &env, const QString &name,
             CaptureOptions opts) { return m_MainWindow->OnInjectTrigger(PID, env, name, opts); },
      m_MainWindow);
  m_CaptureDialog->setObjectName("capDialog");

  return m_CaptureDialog;
}

QWidget *CaptureContext::createToolWindow(const QString &objectName)
{
  if(objectName == "textureViewer")
  {
    return textureViewer();
  }
  else if(objectName == "eventBrowser")
  {
    return eventBrowser();
  }
  else if(objectName == "capDialog")
  {
    return captureDialog();
  }

  return NULL;
}

void CaptureContext::windowClosed(QWidget *window)
{
  if((QWidget *)m_EventBrowser == window)
    m_EventBrowser = NULL;
  else if((QWidget *)m_TextureViewer == window)
    m_TextureViewer = NULL;
  else if((QWidget *)m_CaptureDialog == window)
    m_CaptureDialog = NULL;
  else
    qCritical() << "Unrecognised window being closed: " << window;
}
<|endoftext|>


<commit_before>#include "HeatConductionMaterial.h"
#include<iostream>
using std::cout;
using std::endl;

template<>
InputParameters validParams<HeatConductionMaterial>()
{
  InputParameters params = validParams<Material>();

  params.addRequiredCoupledVar("temperature", "Coupled Temperature");
  params.addParam<std::vector<Real> >("t_list", "The vector of temperature values for building the piecewise function");
  params.addParam<std::vector<Real> >("roe_list", "The vector of rho values for building the piecewise function");
  params.addParam<std::vector<Real> >("k_list", "The vector of thermal conductivity values for building the piecewise function");
  params.addParam<std::vector<Real> >("cp_list", "The vector of specific heat values for building the piecewise function");
  params.addParam<Real>("sigma", "sigma");
  params.addParam<std::string>("property_file","The name of the property file");
  return params;
}

HeatConductionMaterial::HeatConductionMaterial(const std::string & name, InputParameters parameters) :
      Material(name, parameters),
    _property_file(isParamValid("property_file") ? getParam<std::string>("property_file") : "" ),
    _temperature(coupledValue("temperature")),
    _k(declareProperty<Real>("thermal_conductivity")),
    _k_dT(declareProperty<Real>("thermal_conductivity_dT")),
    _cp(declareProperty<Real>("specific_heat")),
    _cp_dT( declareProperty<Real>("specific_heat_dT")),
    _rho(declareProperty<Real>("density")),
    _rho_dT( declareProperty<Real>("density_dT")),
	_sigma( declareProperty<Real>("sigma"))

{
		if (_property_file == "")
		{
			_roe_list= getParam<std::vector<Real> >("roe_list");
			_T_list = getParam<std::vector<Real> >("t_list");
			_cp_list= getParam<std::vector<Real> >("cp_list");
			_k_list = getParam<std::vector<Real> > ("k_list");
			_sigmanum = getParam<Real> ("sigma");
//		_func_k_T=LinearInterpolation(getParam<std::vector<Real> >("t_list"), getParam<std::vector<Real> >("k_list"));
//		_func_cp_T=LinearInterpolation(getParam<std::vector<Real> >("t_list"), getParam<std::vector<Real> >("cp_list"));
		}
		else
		{
			readFile();
		}
	_func_roe_T =  LinearInterpolation(_T_list, _roe_list);
	_func_k_T =  LinearInterpolation(_T_list, _k_list);
	_func_cp_T =  LinearInterpolation(_T_list, _cp_list);
}

void HeatConductionMaterial::readFile()
{
	    using namespace std;
//        cout <<"reading file"<<endl;
		ifstream read_file(_property_file.c_str());
		if(!read_file.good())
		    mooseError("Error opening file '" +_property_file + "' from qc data.");

		    string line;
			getline(read_file, line);
			vector<Real> num;
			istringstream iss(line);
			Real f;
			while(iss >> f)
			{
			 num.push_back(f);
            }
			_tpoint = num[0];
			_sigmanum = num[1];
			for(int i = 0; i < _tpoint; ++i)
			{
				int j=0;
				vector<Real> data;
				getline(read_file, line);
				istringstream iss(line);
				Real f;
				while(iss >> f)
				{
				 data.push_back(f);
//				 cout<<"data["<<j<<"]="<<data[j]<<endl;
				  j+=1;
				}
                _T_list.push_back(data[0]);
                _roe_list.push_back(data[1]);
                _k_list.push_back(data[2]);
                _cp_list.push_back(data[3]);
//				cout<<"T["<<i<<"]= "<<_T_list[i]<<endl;
//				cout<<"roe["<<i<<"]= "<<_roe_list[i]<<endl;
//				cout<<"k["<<i<<"]= "<<_k_list[i]<<endl;
//				cout<<"cp["<<i<<"]= "<<_cp_list[i]<<endl;
			}

			check();
}

void HeatConductionMaterial::computeProperties()
{
  Real epsi = 1E-08;
  for (unsigned int qp(0); qp < _qrule->n_points(); ++qp)
  {
    _k[qp] = _func_k_T.sample(_temperature[qp]);
    _k_dT[qp] =  (_func_k_T.sample(_temperature[qp]+epsi) - _func_k_T.sample(_temperature[qp]-epsi))/2/epsi ;
    _cp[qp] =  _func_cp_T.sample(_temperature[qp]);
    _cp_dT[qp] = (_func_cp_T.sample(_temperature[qp]+epsi) - _func_cp_T.sample(_temperature[qp]-epsi))/2/epsi ;
    _rho[qp] = _func_roe_T.sample(_temperature[qp]);
    _rho_dT[qp] = (_func_roe_T.sample(_temperature[qp]+epsi) - _func_roe_T.sample(_temperature[qp]-epsi))/2/epsi ;
    _sigma[qp]= _sigmanum ;
  }
}

void HeatConductionMaterial::check()
{
	if(_tpoint != _T_list.size() )
		mooseError("温度点个数不匹配");
}
<commit_msg>Cp和k的读取顺序反了<commit_after>#include "HeatConductionMaterial.h"
#include<iostream>
using std::cout;
using std::endl;

template<>
InputParameters validParams<HeatConductionMaterial>()
{
  InputParameters params = validParams<Material>();

  params.addRequiredCoupledVar("temperature", "Coupled Temperature");
  params.addParam<std::vector<Real> >("t_list", "The vector of temperature values for building the piecewise function");
  params.addParam<std::vector<Real> >("roe_list", "The vector of rho values for building the piecewise function");
  params.addParam<std::vector<Real> >("k_list", "The vector of thermal conductivity values for building the piecewise function");
  params.addParam<std::vector<Real> >("cp_list", "The vector of specific heat values for building the piecewise function");
  params.addParam<Real>("sigma", "sigma");
  params.addParam<std::string>("property_file","The name of the property file");
  return params;
}

HeatConductionMaterial::HeatConductionMaterial(const std::string & name, InputParameters parameters) :
      Material(name, parameters),
    _property_file(isParamValid("property_file") ? getParam<std::string>("property_file") : "" ),
    _temperature(coupledValue("temperature")),
    _k(declareProperty<Real>("thermal_conductivity")),
    _k_dT(declareProperty<Real>("thermal_conductivity_dT")),
    _cp(declareProperty<Real>("specific_heat")),
    _cp_dT( declareProperty<Real>("specific_heat_dT")),
    _rho(declareProperty<Real>("density")),
    _rho_dT( declareProperty<Real>("density_dT")),
	_sigma( declareProperty<Real>("sigma"))

{
		if (_property_file == "")
		{
			_roe_list= getParam<std::vector<Real> >("roe_list");
			_T_list = getParam<std::vector<Real> >("t_list");
			_cp_list= getParam<std::vector<Real> >("cp_list");
			_k_list = getParam<std::vector<Real> > ("k_list");
			_sigmanum = getParam<Real> ("sigma");
//		_func_k_T=LinearInterpolation(getParam<std::vector<Real> >("t_list"), getParam<std::vector<Real> >("k_list"));
//		_func_cp_T=LinearInterpolation(getParam<std::vector<Real> >("t_list"), getParam<std::vector<Real> >("cp_list"));
		}
		else
		{
			readFile();
		}
	_func_roe_T =  LinearInterpolation(_T_list, _roe_list);
	_func_k_T =  LinearInterpolation(_T_list, _k_list);
	_func_cp_T =  LinearInterpolation(_T_list, _cp_list);
}

void HeatConductionMaterial::readFile()
{
	    using namespace std;
//        cout <<"reading file"<<endl;
		ifstream read_file(_property_file.c_str());
		if(!read_file.good())
		    mooseError("Error opening file '" +_property_file + "' from qc data.");

		    string line;
			getline(read_file, line);
			vector<Real> num;
			istringstream iss(line);
			Real f;
			while(iss >> f)
			{
			 num.push_back(f);
            }
			_tpoint = num[0];
			_sigmanum = num[1];
			for(int i = 0; i < _tpoint; ++i)
			{
				int j=0;
				vector<Real> data;
				getline(read_file, line);
				istringstream iss(line);
				Real f;
				while(iss >> f)
				{
				 data.push_back(f);
//				 cout<<"data["<<j<<"]="<<data[j]<<endl;
				  j+=1;
				}
                _T_list.push_back(data[0]);
                _roe_list.push_back(data[1]);
                _cp_list.push_back(data[2]);
                _k_list.push_back(data[3]);

//				cout<<"T["<<i<<"]= "<<_T_list[i]<<endl;
//				cout<<"roe["<<i<<"]= "<<_roe_list[i]<<endl;
//				cout<<"k["<<i<<"]= "<<_k_list[i]<<endl;
//				cout<<"cp["<<i<<"]= "<<_cp_list[i]<<endl;
			}

			check();
}

void HeatConductionMaterial::computeProperties()
{
  Real epsi = 1E-08;
  for (unsigned int qp(0); qp < _qrule->n_points(); ++qp)
  {
    _k[qp] = _func_k_T.sample(_temperature[qp]);
    _k_dT[qp] =  (_func_k_T.sample(_temperature[qp]+epsi) - _func_k_T.sample(_temperature[qp]-epsi))/2/epsi ;
    _cp[qp] =  _func_cp_T.sample(_temperature[qp]);
    _cp_dT[qp] = (_func_cp_T.sample(_temperature[qp]+epsi) - _func_cp_T.sample(_temperature[qp]-epsi))/2/epsi ;
    _rho[qp] = _func_roe_T.sample(_temperature[qp]);
    _rho_dT[qp] = (_func_roe_T.sample(_temperature[qp]+epsi) - _func_roe_T.sample(_temperature[qp]-epsi))/2/epsi ;
    _sigma[qp]= _sigmanum ;
  }
}

void HeatConductionMaterial::check()
{
	if(_tpoint != _T_list.size() )
		mooseError("温度点个数不匹配");
}
<|endoftext|>


<commit_before>/**
 * @file em_fit_impl.hpp
 * @author Ryan Curtin
 *
 * Implementation of EM algorithm for fitting GMMs.
 */
#ifndef __MLPACK_METHODS_GMM_EM_FIT_IMPL_HPP
#define __MLPACK_METHODS_GMM_EM_FIT_IMPL_HPP

// In case it hasn't been included yet.
#include "em_fit.hpp"

// Definition of phi().
#include "phi.hpp"

namespace mlpack {
namespace gmm {

//! Constructor.
template<typename InitialClusteringType, typename CovarianceConstraintPolicy>
EMFit<InitialClusteringType, CovarianceConstraintPolicy>::EMFit(
    const size_t maxIterations,
    const double tolerance,
    InitialClusteringType clusterer,
    CovarianceConstraintPolicy constraint) :
    maxIterations(maxIterations),
    tolerance(tolerance),
    clusterer(clusterer),
    constraint(constraint)
{ /* Nothing to do. */ }

template<typename InitialClusteringType, typename CovarianceConstraintPolicy>
void EMFit<InitialClusteringType, CovarianceConstraintPolicy>::Estimate(
    const arma::mat& observations,
    std::vector<arma::vec>& means,
    std::vector<arma::mat>& covariances,
    arma::vec& weights,
    const bool useInitialModel)
{
  // Only perform initial clustering if the user wanted it.
  if (!useInitialModel)
    InitialClustering(observations, means, covariances, weights);

  double l = LogLikelihood(observations, means, covariances, weights);

  Log::Debug << "EMFit::Estimate(): initial clustering log-likelihood: "
      << l << std::endl;

  double lOld = -DBL_MAX;
  arma::mat condProb(observations.n_cols, means.size());

  // Iterate to update the model until no more improvement is found.
  size_t iteration = 1;
  while (std::abs(l - lOld) > tolerance && iteration != maxIterations)
  {
    Log::Info << "EMFit::Estimate(): iteration " << iteration << ", "
        << "log-likelihood " << l << "." << std::endl;

    // Calculate the conditional probabilities of choosing a particular
    // Gaussian given the observations and the present theta value.
    for (size_t i = 0; i < means.size(); i++)
    {
      // Store conditional probabilities into condProb vector for each
      // Gaussian.  First we make an alias of the condProb vector.
      arma::vec condProbAlias = condProb.unsafe_col(i);
      phi(observations, means[i], covariances[i], condProbAlias);
      condProbAlias *= weights[i];
    }

    // Normalize row-wise.
    for (size_t i = 0; i < condProb.n_rows; i++)
    {
      // Avoid dividing by zero; if the probability for everything is 0, we
      // don't want to make it NaN.
      const double probSum = accu(condProb.row(i));
      if (probSum != 0.0)
        condProb.row(i) /= probSum;
    }

    // Store the sum of the probability of each state over all the observations.
    arma::vec probRowSums = trans(arma::sum(condProb, 0 /* columnwise */));

    // Calculate the new value of the means using the updated conditional
    // probabilities.
    for (size_t i = 0; i < means.size(); i++)
    {
      // Don't update if there's no probability of the Gaussian having points.
      if (probRowSums[i] != 0)
        means[i] = (observations * condProb.col(i)) / probRowSums[i];

      // Calculate the new value of the covariances using the updated
      // conditional probabilities and the updated means.
      arma::mat tmp = observations - (means[i] *
          arma::ones<arma::rowvec>(observations.n_cols));
      arma::mat tmpB = tmp % (arma::ones<arma::vec>(observations.n_rows) *
          trans(condProb.col(i)));

      // Don't update if there's no probability of the Gaussian having points.
      if (probRowSums[i] != 0.0)
        covariances[i] = (tmp * trans(tmpB)) / probRowSums[i];

      // Apply covariance constraint.
      constraint.ApplyConstraint(covariances[i]);
    }

    // Calculate the new values for omega using the updated conditional
    // probabilities.
    weights = probRowSums / observations.n_cols;

    // Update values of l; calculate new log-likelihood.
    lOld = l;
    l = LogLikelihood(observations, means, covariances, weights);

    iteration++;
  }
}

template<typename InitialClusteringType, typename CovarianceConstraintPolicy>
void EMFit<InitialClusteringType, CovarianceConstraintPolicy>::Estimate(
    const arma::mat& observations,
    const arma::vec& probabilities,
    std::vector<arma::vec>& means,
    std::vector<arma::mat>& covariances,
    arma::vec& weights,
    const bool useInitialModel)
{
  if (!useInitialModel)
    InitialClustering(observations, means, covariances, weights);

  double l = LogLikelihood(observations, means, covariances, weights);

  Log::Debug << "EMFit::Estimate(): initial clustering log-likelihood: "
      << l << std::endl;

  double lOld = -DBL_MAX;
  arma::mat condProb(observations.n_cols, means.size());

  // Iterate to update the model until no more improvement is found.
  size_t iteration = 1;
  while (std::abs(l - lOld) > tolerance && iteration != maxIterations)
  {
    // Calculate the conditional probabilities of choosing a particular
    // Gaussian given the observations and the present theta value.
    for (size_t i = 0; i < means.size(); i++)
    {
      // Store conditional probabilities into condProb vector for each
      // Gaussian.  First we make an alias of the condProb vector.
      arma::vec condProbAlias = condProb.unsafe_col(i);
      phi(observations, means[i], covariances[i], condProbAlias);
      condProbAlias *= weights[i];
    }

    // Normalize row-wise.
    for (size_t i = 0; i < condProb.n_rows; i++)
    {
      // Avoid dividing by zero; if the probability for everything is 0, we
      // don't want to make it NaN.
      const double probSum = accu(condProb.row(i));
      if (probSum != 0.0)
        condProb.row(i) /= probSum;
    }

    // This will store the sum of probabilities of each state over all the
    // observations.
    arma::vec probRowSums(means.size());

    // Calculate the new value of the means using the updated conditional
    // probabilities.
    for (size_t i = 0; i < means.size(); i++)
    {
      // Calculate the sum of probabilities of points, which is the
      // conditional probability of each point being from Gaussian i
      // multiplied by the probability of the point being from this mixture
      // model.
      probRowSums[i] = accu(condProb.col(i) % probabilities);

      means[i] = (observations * (condProb.col(i) % probabilities)) /
        probRowSums[i];

      // Calculate the new value of the covariances using the updated
      // conditional probabilities and the updated means.
      arma::mat tmp = observations - (means[i] *
          arma::ones<arma::rowvec>(observations.n_cols));
      arma::mat tmpB = tmp % (arma::ones<arma::vec>(observations.n_rows) *
          trans(condProb.col(i) % probabilities));

      covariances[i] = (tmp * trans(tmpB)) / probRowSums[i];

      // Apply covariance constraint.
      constraint.ApplyConstraint(covariances[i]);
    }

    // Calculate the new values for omega using the updated conditional
    // probabilities.
    weights = probRowSums / accu(probabilities);

    // Update values of l; calculate new log-likelihood.
    lOld = l;
    l = LogLikelihood(observations, means, covariances, weights);

    iteration++;
  }
}

template<typename InitialClusteringType, typename CovarianceConstraintPolicy>
void EMFit<InitialClusteringType, CovarianceConstraintPolicy>::
InitialClustering(const arma::mat& observations,
                  std::vector<arma::vec>& means,
                  std::vector<arma::mat>& covariances,
                  arma::vec& weights)
{
  // Assignments from clustering.
  arma::Col<size_t> assignments;

  // Run clustering algorithm.
  clusterer.Cluster(observations, means.size(), assignments);

  // Now calculate the means, covariances, and weights.
  weights.zeros();
  for (size_t i = 0; i < means.size(); ++i)
  {
    means[i].zeros();
    covariances[i].zeros();
  }

  // From the assignments, generate our means, covariances, and weights.
  for (size_t i = 0; i < observations.n_cols; ++i)
  {
    const size_t cluster = assignments[i];

    // Add this to the relevant mean.
    means[cluster] += observations.col(i);

    // Add this to the relevant covariance.
//    covariances[cluster] += observations.col(i) * trans(observations.col(i));

    // Now add one to the weights (we will normalize).
    weights[cluster]++;
  }

  // Now normalize the mean and covariance.
  for (size_t i = 0; i < means.size(); ++i)
  {
//    covariances[i] -= means[i] * trans(means[i]);

    means[i] /= (weights[i] > 1) ? weights[i] : 1;
//    covariances[i] /= (weights[i] > 1) ? weights[i] : 1;
  }

  for (size_t i = 0; i < observations.n_cols; ++i)
  {
    const size_t cluster = assignments[i];
    const arma::vec normObs = observations.col(i) - means[cluster];
    covariances[cluster] += normObs * normObs.t();
  }

  for (size_t i = 0; i < means.size(); ++i)
  {
    covariances[i] /= (weights[i] > 1) ? weights[i] : 1;

    // Apply constraints to covariance matrix.
    constraint.ApplyConstraint(covariances[i]);
  }

  // Finally, normalize weights.
  weights /= accu(weights);
}

template<typename InitialClusteringType, typename CovarianceConstraintPolicy>
double EMFit<InitialClusteringType, CovarianceConstraintPolicy>::LogLikelihood(
    const arma::mat& observations,
    const std::vector<arma::vec>& means,
    const std::vector<arma::mat>& covariances,
    const arma::vec& weights) const
{
  double logLikelihood = 0;

  arma::vec phis;
  arma::mat likelihoods(means.size(), observations.n_cols);
  for (size_t i = 0; i < means.size(); ++i)
  {
    phi(observations, means[i], covariances[i], phis);
    likelihoods.row(i) = weights(i) * trans(phis);
  }

  // Now sum over every point.
  for (size_t j = 0; j < observations.n_cols; ++j)
  {
    if (accu(likelihoods.col(j)) == 0)
      Log::Info << "Likelihood of point " << j << " is 0!  It is probably an "
          << "outlier." << std::endl;
    logLikelihood += log(accu(likelihoods.col(j)));
  }

  return logLikelihood;
}

}; // namespace gmm
}; // namespace mlpack

#endif
<commit_msg>Changes to work with new, hierarchical GMMs<commit_after>/**
 * @file em_fit_impl.hpp
 * @author Ryan Curtin
 * @author Michael Fox
 *
 * Implementation of EM algorithm for fitting GMMs.
 */
#ifndef __MLPACK_METHODS_GMM_EM_FIT_IMPL_HPP
#define __MLPACK_METHODS_GMM_EM_FIT_IMPL_HPP

// In case it hasn't been included yet.
#include "em_fit.hpp"

namespace mlpack {
namespace gmm {

//! Constructor.
template<typename InitialClusteringType, typename CovarianceConstraintPolicy>
EMFit<InitialClusteringType, CovarianceConstraintPolicy>::EMFit(
    const size_t maxIterations,
    const double tolerance,
    InitialClusteringType clusterer,
    CovarianceConstraintPolicy constraint) :
    maxIterations(maxIterations),
    tolerance(tolerance),
    clusterer(clusterer),
    constraint(constraint)
{ /* Nothing to do. */ }

template<typename InitialClusteringType, typename CovarianceConstraintPolicy>
void EMFit<InitialClusteringType, CovarianceConstraintPolicy>::Estimate(
    const arma::mat& observations,
    std::vector<distribution::GaussianDistribution>& dists,
    arma::vec& weights,
    const bool useInitialModel)
{
  // Only perform initial clustering if the user wanted it.
  if (!useInitialModel)
    InitialClustering(observations, dists, weights);

  double l = LogLikelihood(observations, dists, weights);

  Log::Debug << "EMFit::Estimate(): initial clustering log-likelihood: "
      << l << std::endl;

  double lOld = -DBL_MAX;
  arma::mat condProb(observations.n_cols, dists.size());

  // Iterate to update the model until no more improvement is found.
  size_t iteration = 1;
  while (std::abs(l - lOld) > tolerance && iteration != maxIterations)
  {
    Log::Info << "EMFit::Estimate(): iteration " << iteration << ", "
        << "log-likelihood " << l << "." << std::endl;

    // Calculate the conditional probabilities of choosing a particular
    // Gaussian given the observations and the present theta value.
    for (size_t i = 0; i < dists.size(); i++)
    {
      // Store conditional probabilities into condProb vector for each
      // Gaussian.  First we make an alias of the condProb vector.
      arma::vec condProbAlias = condProb.unsafe_col(i);
      dists[i].Probability(observations, condProbAlias);
      condProbAlias *= weights[i];
    }

    // Normalize row-wise.
    for (size_t i = 0; i < condProb.n_rows; i++)
    {
      // Avoid dividing by zero; if the probability for everything is 0, we
      // don't want to make it NaN.
      const double probSum = accu(condProb.row(i));
      if (probSum != 0.0)
        condProb.row(i) /= probSum;
    }

    // Store the sum of the probability of each state over all the observations.
    arma::vec probRowSums = trans(arma::sum(condProb, 0 /* columnwise */));

    // Calculate the new value of the means using the updated conditional
    // probabilities.
    for (size_t i = 0; i < dists.size(); i++)
    {
      // Don't update if there's no probability of the Gaussian having points.
      if (probRowSums[i] != 0)
        dists[i].Mean() = (observations * condProb.col(i)) / probRowSums[i];

      // Calculate the new value of the covariances using the updated
      // conditional probabilities and the updated means.
      arma::mat tmp = observations - (dists[i].Mean() *
          arma::ones<arma::rowvec>(observations.n_cols));
      arma::mat tmpB = tmp % (arma::ones<arma::vec>(observations.n_rows) *
          trans(condProb.col(i)));

      // Don't update if there's no probability of the Gaussian having points.
      if (probRowSums[i] != 0.0)
        dists[i].Covariance() = (tmp * trans(tmpB)) / probRowSums[i];

      // Apply covariance constraint.
      constraint.ApplyConstraint(dists[i].Covariance());
    }

    // Calculate the new values for omega using the updated conditional
    // probabilities.
    weights = probRowSums / observations.n_cols;

    // Update values of l; calculate new log-likelihood.
    lOld = l;
    l = LogLikelihood(observations, dists, weights);

    iteration++;
  }
}

template<typename InitialClusteringType, typename CovarianceConstraintPolicy>
void EMFit<InitialClusteringType, CovarianceConstraintPolicy>::Estimate(
    const arma::mat& observations,
    const arma::vec& probabilities,
    std::vector<distribution::GaussianDistribution>& dists,
    arma::vec& weights,
    const bool useInitialModel)
{
  if (!useInitialModel)
    InitialClustering(observations, dists, weights);

  double l = LogLikelihood(observations, dists, weights);

  Log::Debug << "EMFit::Estimate(): initial clustering log-likelihood: "
      << l << std::endl;

  double lOld = -DBL_MAX;
  arma::mat condProb(observations.n_cols, dists.size());

  // Iterate to update the model until no more improvement is found.
  size_t iteration = 1;
  while (std::abs(l - lOld) > tolerance && iteration != maxIterations)
  {
    // Calculate the conditional probabilities of choosing a particular
    // Gaussian given the observations and the present theta value.
    for (size_t i = 0; i < dists.size(); i++)
    {
      // Store conditional probabilities into condProb vector for each
      // Gaussian.  First we make an alias of the condProb vector.
      arma::vec condProbAlias = condProb.unsafe_col(i);
      dists[i].Probability(observations, condProbAlias);
      condProbAlias *= weights[i];
    }

    // Normalize row-wise.
    for (size_t i = 0; i < condProb.n_rows; i++)
    {
      // Avoid dividing by zero; if the probability for everything is 0, we
      // don't want to make it NaN.
      const double probSum = accu(condProb.row(i));
      if (probSum != 0.0)
        condProb.row(i) /= probSum;
    }

    // This will store the sum of probabilities of each state over all the
    // observations.
    arma::vec probRowSums(dists.size());

    // Calculate the new value of the means using the updated conditional
    // probabilities.
    for (size_t i = 0; i < dists.size(); i++)
    {
      // Calculate the sum of probabilities of points, which is the
      // conditional probability of each point being from Gaussian i
      // multiplied by the probability of the point being from this mixture
      // model.
      probRowSums[i] = accu(condProb.col(i) % probabilities);

      dists[i].Mean() = (observations * (condProb.col(i) % probabilities)) /
        probRowSums[i];

      // Calculate the new value of the covariances using the updated
      // conditional probabilities and the updated means.
      arma::mat tmp = observations - (dists[i].Mean() *
          arma::ones<arma::rowvec>(observations.n_cols));
      arma::mat tmpB = tmp % (arma::ones<arma::vec>(observations.n_rows) *
          trans(condProb.col(i) % probabilities));

      dists[i].Covariance() = (tmp * trans(tmpB)) / probRowSums[i];

      // Apply covariance constraint.
      constraint.ApplyConstraint(dists[i].Covariance());
    }

    // Calculate the new values for omega using the updated conditional
    // probabilities.
    weights = probRowSums / accu(probabilities);

    // Update values of l; calculate new log-likelihood.
    lOld = l;
    l = LogLikelihood(observations, dists, weights);

    iteration++;
  }
}

template<typename InitialClusteringType, typename CovarianceConstraintPolicy>
void EMFit<InitialClusteringType, CovarianceConstraintPolicy>::
InitialClustering(const arma::mat& observations,
                  std::vector<distribution::GaussianDistribution>& dists,
                  arma::vec& weights)
{
  // Assignments from clustering.
  arma::Col<size_t> assignments;

  // Run clustering algorithm.
  clusterer.Cluster(observations, dists.size(), assignments);

  // Now calculate the means, covariances, and weights.
  weights.zeros();
  for (size_t i = 0; i < dists.size(); ++i)
  {
    dists[i].Mean().zeros();
    dists[i].Covariance().zeros();
  }

  // From the assignments, generate our means, covariances, and weights.
  for (size_t i = 0; i < observations.n_cols; ++i)
  {
    const size_t cluster = assignments[i];

    // Add this to the relevant mean.
    dists[cluster].Mean() += observations.col(i);

    // Add this to the relevant covariance.
    dists[cluster].Covariance() += observations.col(i) *
        trans(observations.col(i));

    // Now add one to the weights (we will normalize).
    weights[cluster]++;
  }

  // Now normalize the mean and covariance.
  for (size_t i = 0; i < dists.size(); ++i)
  {
    dists[i].Mean() /= (weights[i] > 1) ? weights[i] : 1;
  }

  for (size_t i = 0; i < observations.n_cols; ++i)
  {
    const size_t cluster = assignments[i];
    const arma::vec normObs = observations.col(i) - dists[cluster].Mean();
    dists[cluster].Covariance() += normObs * normObs.t();
  }

  for (size_t i = 0; i < dists.size(); ++i)
  {
    dists[i].Covariance() /= (weights[i] > 1) ? weights[i] : 1;

    // Apply constraints to covariance matrix.
    constraint.ApplyConstraint(dists[i].Covariance());
  }

  // Finally, normalize weights.
  weights /= accu(weights);
}

template<typename InitialClusteringType, typename CovarianceConstraintPolicy>
double EMFit<InitialClusteringType, CovarianceConstraintPolicy>::LogLikelihood(
    const arma::mat& observations,
    const std::vector<distribution::GaussianDistribution>& dists,
    const arma::vec& weights) const
{
  double logLikelihood = 0;

  arma::vec phis;
  arma::mat likelihoods(dists.size(), observations.n_cols);

  for (size_t i = 0; i < dists.size(); ++i)
  {
    dists[i].Probability(observations, phis);
    likelihoods.row(i) = weights(i) * trans(phis);
  }
  // Now sum over every point.
  for (size_t j = 0; j < observations.n_cols; ++j)
  {
    if (accu(likelihoods.col(j)) == 0)
      Log::Info << "Likelihood of point " << j << " is 0!  It is probably an "
          << "outlier." << std::endl;
    logLikelihood += log(accu(likelihoods.col(j)));
  }

  return logLikelihood;
}

}; // namespace gmm
}; // namespace mlpack

#endif
<|endoftext|>


<commit_before>#include <getopt.h>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include "dla.hpp"

void print_usage();

int main(int argc, char *argv[]) {
    if (argc < 4) {
        print_usage();
        return 0;
    }

    int c;
    int grid_width, grid_height;
    char *outfile;
    bool verbose = false;

    // Parse args
    opterr = 0;
    while ((c = getopt(argc, argv, "w:h:o:v")) != EOF) {
        switch (c) {
            case 'w':
                grid_width = std::atoi(optarg);
                break;
            case 'h':
                grid_height = std::atoi(optarg);
                break;
            case 'o':
                outfile = optarg;
                break;
            case 'v':
                verbose = true;
                break;
            default:
                print_usage();
                return 1;
        }
    }

    std::cout << "Grid width      : " << grid_width << "\n";
    std::cout << "Grid height     : " << grid_height << "\n";
    std::cout << "Output filename : " << outfile << "\n";

    Dla dla = Dla(grid_width, grid_height, verbose);
    dla.simulate();
    //dla.print_grid();
    dla.write_grid_to_file(outfile);
    return 0;
}

void print_usage() {
    std::cout << "Usage: ./simulate -w grid_width -h grid_height -o output_filename [-v]\n";
}
<commit_msg>Removed redundant <cstring> include<commit_after>#include <getopt.h>
#include <cstdlib>
#include <iostream>
#include "dla.hpp"

void print_usage();

int main(int argc, char *argv[]) {
    if (argc < 4) {
        print_usage();
        return 0;
    }

    int c;
    int grid_width, grid_height;
    char *outfile;
    bool verbose = false;

    // Parse args
    opterr = 0;
    while ((c = getopt(argc, argv, "w:h:o:v")) != EOF) {
        switch (c) {
            case 'w':
                grid_width = std::atoi(optarg);
                break;
            case 'h':
                grid_height = std::atoi(optarg);
                break;
            case 'o':
                outfile = optarg;
                break;
            case 'v':
                verbose = true;
                break;
            default:
                print_usage();
                return 1;
        }
    }

    std::cout << "Grid width      : " << grid_width << "\n";
    std::cout << "Grid height     : " << grid_height << "\n";
    std::cout << "Output filename : " << outfile << "\n";

    Dla dla = Dla(grid_width, grid_height, verbose);
    dla.simulate();
    //dla.print_grid();
    dla.write_grid_to_file(outfile);
    return 0;
}

void print_usage() {
    std::cout << "Usage: ./simulate -w grid_width -h grid_height -o output_filename [-v]\n";
}
<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 * Point Cloud Library (PCL) - www.pointclouds.org
 * Copyright (c) 2009-2011, Willow Garage, Inc.
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above
 *   copyright notice, this list of conditions and the following
 *   disclaimer in the documentation and/or other materials provided
 *   with the distribution.
 * * Neither the name of Willow Garage, Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 *
 */

#ifndef PCL_SURFACE_IMPL_MLS_H_
#define PCL_SURFACE_IMPL_MLS_H_

#include "pcl/surface/mls.h"
#include <pcl/common/io.h>
#include <pcl/common/centroid.h>
#include <pcl/common/eigen.h>

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename NormalOutT> void
pcl::MovingLeastSquares<PointInT, NormalOutT>::reconstruct (PointCloudIn &output)
{
  // check if normals have to be computed/saved
  if (normals_)
  {
    // Copy the header
    normals_->header = input_->header;
    // Clear the fields in case the method exits before computation
    normals_->width = normals_->height = 0;
    normals_->points.clear ();
  }

  // Copy the header
  output.header = input_->header;

  if (search_radius_ <= 0 || sqr_gauss_param_ <= 0)
  {
    PCL_ERROR ("[pcl::%s::reconstruct] Invalid search radius (%f) or Gaussian parameter (%f)!\n", getClassName ().c_str (), search_radius_, sqr_gauss_param_);
    output.width = output.height = 0;
    output.points.clear ();
    return;
  }

  if (!initCompute ())
  {
    output.width = output.height = 0;
    output.points.clear ();
    return;
  }

  // Initialize the spatial locator
  if (!tree_)
  {
    KdTreePtr tree;
    if (input_->isOrganized ())
      tree.reset (new pcl::search::OrganizedNeighbor<PointInT> ());
    else
      tree.reset (new pcl::search::KdTree<PointInT> (false));
    setSearchMethod (tree);
  }

  // Send the surface dataset to the spatial locator
  tree_->setInputCloud (input_, indices_);

/// DON'T NEED THESE ANYMORE, BECAUSE WE HAVE UPSAMPLING
//  // Use original point positions for fitting
//  // \note no up/down/adapting-sampling or hole filling possible like this
//  output.points.resize (indices_->size ());
//  // Check if fake indices were used, otherwise the output loses its organized structure
//  if (!fake_indices_)
//    pcl::copyPointCloud (*input_, *indices_, output);
//  else
//    output = *input_;
//
//  // Resize the output normal dataset
//  if (normals_)
//  {
//    normals_->points.resize (output.points.size ());
//    normals_->width    = output.width;
//    normals_->height   = output.height;
//    normals_->is_dense = output.is_dense;
//  }

  // Perform the actual surface reconstruction
  performReconstruction (output);

  deinitCompute ();
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename NormalOutT> void
pcl::MovingLeastSquares<PointInT, NormalOutT>::computeMLSPointNormal (int index,
                                                                      const PointCloudIn &input,
                                                                      const std::vector<int> &nn_indices,
                                                                      std::vector<float> &nn_sqr_dists,
                                                                      PointCloudIn &projected_points,
                                                                      NormalCloudOut &projected_points_normals)
{
  // Compute the plane coefficients
  //pcl::computePointNormal<PointInT> (*input_, nn_indices, model_coefficients, curvature);
  EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix;
  Eigen::Vector4f xyz_centroid;

  // Estimate the XYZ centroid
  pcl::compute3DCentroid (input, nn_indices, xyz_centroid);

  // Compute the 3x3 covariance matrix
  pcl::computeCovarianceMatrix (input, nn_indices, xyz_centroid, covariance_matrix);

  // Get the plane normal
  EIGEN_ALIGN16 Eigen::Vector3f::Scalar eigen_value = -1;
  EIGEN_ALIGN16 Eigen::Vector3f eigen_vector;
  Eigen::Vector4f model_coefficients;
  pcl::eigen33 (covariance_matrix, eigen_value, eigen_vector);
  model_coefficients.head<3> () = eigen_vector;
  model_coefficients[3] = -1 * model_coefficients.dot (xyz_centroid);

  // Projected query point
  Eigen::Vector3f point = input[index].getVector3fMap ();
  float distance = point.dot (model_coefficients.head<3> ()) + model_coefficients[3];
  point -= distance * model_coefficients.head<3> ();

  float curvature = covariance_matrix.trace ();
  // Compute the curvature surface change
  if (curvature != 0)
    curvature = fabs (eigen_value / curvature);

  // Get a copy of the plane normal easy access
  Eigen::Vector3d plane_normal = model_coefficients.head<3> ().cast<double> ();
  // Vector in which the polynomial coefficients will be put
  Eigen::VectorXd c_vec;
  // Local coordinate system (Darboux frame)
  Eigen::Vector3d v, u;

  // Perform polynomial fit to update point and normal
  ////////////////////////////////////////////////////
  if (polynomial_fit_ && (int)nn_indices.size () >= nr_coeff_)
  {
    // Update neighborhood, since point was projected, and computing relative
    // positions. Note updating only distances for the weights for speed
    std::vector<Eigen::Vector3d> de_meaned (nn_indices.size ());
    for (size_t ni = 0; ni < nn_indices.size (); ++ni)
    {
      de_meaned[ni][0] = input_->points[nn_indices[ni]].x - point[0];
      de_meaned[ni][1] = input_->points[nn_indices[ni]].y - point[1];
      de_meaned[ni][2] = input_->points[nn_indices[ni]].z - point[2];
      nn_sqr_dists[ni] = de_meaned[ni].dot (de_meaned[ni]);
    }

    // Allocate matrices and vectors to hold the data used for the polynomial fit
    Eigen::VectorXd weight_vec (nn_indices.size ());
    Eigen::MatrixXd P (nr_coeff_, nn_indices.size ());
    Eigen::VectorXd f_vec (nn_indices.size ());
    Eigen::MatrixXd P_weight; // size will be (nr_coeff_, nn_indices.size ());
    Eigen::MatrixXd P_weight_Pt (nr_coeff_, nr_coeff_);

    // Get local coordinate system (Darboux frame)
    v = plane_normal.unitOrthogonal ();
    u = plane_normal.cross (v);

    // Go through neighbors, transform them in the local coordinate system,
    // save height and the evaluation of the polynome's terms
    double u_coord, v_coord, u_pow, v_pow;
    for (size_t ni = 0; ni < nn_indices.size (); ++ni)
    {
      // (re-)compute weights
      weight_vec (ni) = exp (-nn_sqr_dists[ni] / sqr_gauss_param_);

      // transforming coordinates
      u_coord = de_meaned[ni].dot (u);
      v_coord = de_meaned[ni].dot (v);
      f_vec (ni) = de_meaned[ni].dot (plane_normal);

      // compute the polynomial's terms at the current point
      int j = 0;
      u_pow = 1;
      for (int ui = 0; ui <= order_; ++ui)
      {
        v_pow = 1;
        for (int vi = 0; vi <= order_ - ui; ++vi)
        {
          P (j++, ni) = u_pow * v_pow;
          v_pow *= v_coord;
        }
        u_pow *= u_coord;
      }
    }

    // Computing coefficients
    P_weight = P * weight_vec.asDiagonal ();
    P_weight_Pt = P_weight * P.transpose ();
    c_vec = P_weight * f_vec;
    P_weight_Pt.llt ().solveInPlace (c_vec);
  }

  switch (upsample_method_)
  {
    case (NONE):
    {
      printf ("NONE");
      Eigen::Vector3d normal = plane_normal;

      if (c_vec.size () != 0)
      {
        // Projection onto MLS surface along Darboux normal to the height at (0,0)
        if (pcl_isfinite (c_vec[0]))
        {
          point += (c_vec[0] * plane_normal).cast<float> ();

          // Compute tangent vectors using the partial derivates evaluated at (0,0) which is c_vec[order_+1] and c_vec[1]
          if (normals_)
            normal = plane_normal - c_vec[order_ + 1] * u - c_vec[1] * v;
        }
      }

      PointInT aux;
      aux.x = point[0];
      aux.y = point[1];
      aux.z = point[2];
      projected_points.push_back (aux);

      NormalOutT aux_normal;
      aux_normal.normal_x = normal[0];
      aux_normal.normal_y = normal[1];
      aux_normal.normal_z = normal[2];
      aux_normal.curvature = curvature;
      projected_points_normals.push_back (aux_normal);

      break;
    }

    case (SAMPLE_LOCAL_PLANE):
    {
      // Uniformly sample a circle around the query point using the radius and step parameters
      for (float u_disp = -upsampling_radius_; u_disp <= upsampling_radius_; u_disp += upsampling_step_)
        for (float v_disp = -upsampling_radius_; v_disp <= upsampling_radius_; v_disp += upsampling_step_)
          if (u_disp*u_disp + v_disp*v_disp < upsampling_radius_*upsampling_radius_)
          {
            // If polynomial fitting was done, calculate the displacement along the normal
            double n_disp = 0.0f;
            double d_u = 0.0f, d_v = 0.0f;
            if (c_vec.size () != 0)
            {
              // Compute the displacement along the normal using the fitted polynomial
              // and compute the partial derivatives needed for estimating the normal
              int j = 0;
              float u_pow = 1, v_pow = 1;
              for (int ui = 0; ui <= order_; ++ui)
              {
                v_pow = 1;
                for (int vi = 0; vi <= order_ - ui; ++vi)
                {
                  n_disp += u_pow * v_pow * c_vec[j++];

                  // Compute partial derivatives
                  if (ui >= 1)
                    d_u += c_vec[j-1] * ui * u_pow / u_disp * v_pow;
                  if (vi >= 1)
                    d_v += c_vec[j-1] * vi * u_pow * v_pow / v_disp;

                  v_pow *= v_disp;
                }
                u_pow *= u_disp;
              }
            }

            PointInT aux;
            aux.x = point[0] + u[0] * u_disp + v[0] * v_disp + plane_normal[0] * n_disp;
            aux.y = point[1] + u[1] * u_disp + v[1] * v_disp + plane_normal[1] * n_disp;
            aux.z = point[2] + u[2] * u_disp + v[2] * v_disp + plane_normal[2] * n_disp;

            Eigen::Vector3d normal = plane_normal - d_u * u - d_v * v;

            NormalOutT aux_normal;
            aux_normal.normal_x = normal[0];
            aux_normal.normal_y = normal[1];
            aux_normal.normal_z = normal[2];
            aux_normal.curvature = curvature;

            projected_points.push_back (aux);
            projected_points_normals.push_back (aux_normal);
          }
    }
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename NormalOutT> void
pcl::MovingLeastSquares<PointInT, NormalOutT>::performReconstruction (PointCloudIn &output)
{
  // Compute the number of coefficients
  nr_coeff_ = (order_ + 1) * (order_ + 2) / 2;

  // Allocate enough space to hold the results of nearest neighbor searches
  // \note resize is irrelevant for a radiusSearch ().
  std::vector<int> nn_indices;
  std::vector<float> nn_sqr_dists;

  // For all points
  for (size_t cp = 0; cp < indices_->size (); ++cp)
  {
    // Get the initial estimates of point positions and their neighborhoods
    if (!searchForNeighbors ((*indices_)[cp], nn_indices, nn_sqr_dists))
      continue;

    // Check the number of nearest neighbors for normal estimation (and later
    // for polynomial fit as well)
    if (nn_indices.size () < 3)
      continue;

    PointCloudIn projected_points;
    NormalCloudOut projected_points_normals;
    // Get a plane approximating the local surface's tangent and project point onto it
    computeMLSPointNormal ((*indices_)[cp], *input_, nn_indices, nn_sqr_dists, projected_points, projected_points_normals);

    // Append projected points to output
    output.insert (output.end (), projected_points.begin (), projected_points.end ());
    normals_->insert (normals_->end (), projected_points_normals.begin (), projected_points_normals.end ());
  }

  // Set proper widths and heights for the clouds
  if (upsample_method_ == NONE && fake_indices_)
  {
    normals_->width = input_->width;
    normals_->height = input_->height;
    output.width = input_->width;
    output.height = input_->height;
  }
  else
  {
    normals_->height = 1;
    normals_->width = normals_->size ();
    output.height = 1;
    output.width = output.size ();
  }
  printf ("output size %d %d %d\n", output.width, output.height, output.size ());
  printf ("Normals size %d %d %d\n", normals_->width, normals_->height, normals_->size ());
}

#define PCL_INSTANTIATE_MovingLeastSquares(T,OutT) template class PCL_EXPORTS pcl::MovingLeastSquares<T,OutT>;

#endif    // PCL_SURFACE_IMPL_MLS_H_

<commit_msg>don't leave printfs in the code<commit_after>/*
 * Software License Agreement (BSD License)
 *
 * Point Cloud Library (PCL) - www.pointclouds.org
 * Copyright (c) 2009-2011, Willow Garage, Inc.
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above
 *   copyright notice, this list of conditions and the following
 *   disclaimer in the documentation and/or other materials provided
 *   with the distribution.
 * * Neither the name of Willow Garage, Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 *
 */

#ifndef PCL_SURFACE_IMPL_MLS_H_
#define PCL_SURFACE_IMPL_MLS_H_

#include "pcl/surface/mls.h"
#include <pcl/common/io.h>
#include <pcl/common/centroid.h>
#include <pcl/common/eigen.h>

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename NormalOutT> void
pcl::MovingLeastSquares<PointInT, NormalOutT>::reconstruct (PointCloudIn &output)
{
  // check if normals have to be computed/saved
  if (normals_)
  {
    // Copy the header
    normals_->header = input_->header;
    // Clear the fields in case the method exits before computation
    normals_->width = normals_->height = 0;
    normals_->points.clear ();
  }

  // Copy the header
  output.header = input_->header;

  if (search_radius_ <= 0 || sqr_gauss_param_ <= 0)
  {
    PCL_ERROR ("[pcl::%s::reconstruct] Invalid search radius (%f) or Gaussian parameter (%f)!\n", getClassName ().c_str (), search_radius_, sqr_gauss_param_);
    output.width = output.height = 0;
    output.points.clear ();
    return;
  }

  if (!initCompute ())
  {
    output.width = output.height = 0;
    output.points.clear ();
    return;
  }

  // Initialize the spatial locator
  if (!tree_)
  {
    KdTreePtr tree;
    if (input_->isOrganized ())
      tree.reset (new pcl::search::OrganizedNeighbor<PointInT> ());
    else
      tree.reset (new pcl::search::KdTree<PointInT> (false));
    setSearchMethod (tree);
  }

  // Send the surface dataset to the spatial locator
  tree_->setInputCloud (input_, indices_);

/// DON'T NEED THESE ANYMORE, BECAUSE WE HAVE UPSAMPLING
//  // Use original point positions for fitting
//  // \note no up/down/adapting-sampling or hole filling possible like this
//  output.points.resize (indices_->size ());
//  // Check if fake indices were used, otherwise the output loses its organized structure
//  if (!fake_indices_)
//    pcl::copyPointCloud (*input_, *indices_, output);
//  else
//    output = *input_;
//
//  // Resize the output normal dataset
//  if (normals_)
//  {
//    normals_->points.resize (output.points.size ());
//    normals_->width    = output.width;
//    normals_->height   = output.height;
//    normals_->is_dense = output.is_dense;
//  }

  // Perform the actual surface reconstruction
  performReconstruction (output);

  deinitCompute ();
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename NormalOutT> void
pcl::MovingLeastSquares<PointInT, NormalOutT>::computeMLSPointNormal (int index,
                                                                      const PointCloudIn &input,
                                                                      const std::vector<int> &nn_indices,
                                                                      std::vector<float> &nn_sqr_dists,
                                                                      PointCloudIn &projected_points,
                                                                      NormalCloudOut &projected_points_normals)
{
  // Compute the plane coefficients
  //pcl::computePointNormal<PointInT> (*input_, nn_indices, model_coefficients, curvature);
  EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix;
  Eigen::Vector4f xyz_centroid;

  // Estimate the XYZ centroid
  pcl::compute3DCentroid (input, nn_indices, xyz_centroid);

  // Compute the 3x3 covariance matrix
  pcl::computeCovarianceMatrix (input, nn_indices, xyz_centroid, covariance_matrix);

  // Get the plane normal
  EIGEN_ALIGN16 Eigen::Vector3f::Scalar eigen_value = -1;
  EIGEN_ALIGN16 Eigen::Vector3f eigen_vector;
  Eigen::Vector4f model_coefficients;
  pcl::eigen33 (covariance_matrix, eigen_value, eigen_vector);
  model_coefficients.head<3> () = eigen_vector;
  model_coefficients[3] = -1 * model_coefficients.dot (xyz_centroid);

  // Projected query point
  Eigen::Vector3f point = input[index].getVector3fMap ();
  float distance = point.dot (model_coefficients.head<3> ()) + model_coefficients[3];
  point -= distance * model_coefficients.head<3> ();

  float curvature = covariance_matrix.trace ();
  // Compute the curvature surface change
  if (curvature != 0)
    curvature = fabs (eigen_value / curvature);

  // Get a copy of the plane normal easy access
  Eigen::Vector3d plane_normal = model_coefficients.head<3> ().cast<double> ();
  // Vector in which the polynomial coefficients will be put
  Eigen::VectorXd c_vec;
  // Local coordinate system (Darboux frame)
  Eigen::Vector3d v, u;

  // Perform polynomial fit to update point and normal
  ////////////////////////////////////////////////////
  if (polynomial_fit_ && (int)nn_indices.size () >= nr_coeff_)
  {
    // Update neighborhood, since point was projected, and computing relative
    // positions. Note updating only distances for the weights for speed
    std::vector<Eigen::Vector3d> de_meaned (nn_indices.size ());
    for (size_t ni = 0; ni < nn_indices.size (); ++ni)
    {
      de_meaned[ni][0] = input_->points[nn_indices[ni]].x - point[0];
      de_meaned[ni][1] = input_->points[nn_indices[ni]].y - point[1];
      de_meaned[ni][2] = input_->points[nn_indices[ni]].z - point[2];
      nn_sqr_dists[ni] = de_meaned[ni].dot (de_meaned[ni]);
    }

    // Allocate matrices and vectors to hold the data used for the polynomial fit
    Eigen::VectorXd weight_vec (nn_indices.size ());
    Eigen::MatrixXd P (nr_coeff_, nn_indices.size ());
    Eigen::VectorXd f_vec (nn_indices.size ());
    Eigen::MatrixXd P_weight; // size will be (nr_coeff_, nn_indices.size ());
    Eigen::MatrixXd P_weight_Pt (nr_coeff_, nr_coeff_);

    // Get local coordinate system (Darboux frame)
    v = plane_normal.unitOrthogonal ();
    u = plane_normal.cross (v);

    // Go through neighbors, transform them in the local coordinate system,
    // save height and the evaluation of the polynome's terms
    double u_coord, v_coord, u_pow, v_pow;
    for (size_t ni = 0; ni < nn_indices.size (); ++ni)
    {
      // (re-)compute weights
      weight_vec (ni) = exp (-nn_sqr_dists[ni] / sqr_gauss_param_);

      // transforming coordinates
      u_coord = de_meaned[ni].dot (u);
      v_coord = de_meaned[ni].dot (v);
      f_vec (ni) = de_meaned[ni].dot (plane_normal);

      // compute the polynomial's terms at the current point
      int j = 0;
      u_pow = 1;
      for (int ui = 0; ui <= order_; ++ui)
      {
        v_pow = 1;
        for (int vi = 0; vi <= order_ - ui; ++vi)
        {
          P (j++, ni) = u_pow * v_pow;
          v_pow *= v_coord;
        }
        u_pow *= u_coord;
      }
    }

    // Computing coefficients
    P_weight = P * weight_vec.asDiagonal ();
    P_weight_Pt = P_weight * P.transpose ();
    c_vec = P_weight * f_vec;
    P_weight_Pt.llt ().solveInPlace (c_vec);
  }

  switch (upsample_method_)
  {
    case (NONE):
    {
      printf ("NONE");
      Eigen::Vector3d normal = plane_normal;

      if (c_vec.size () != 0)
      {
        // Projection onto MLS surface along Darboux normal to the height at (0,0)
        if (pcl_isfinite (c_vec[0]))
        {
          point += (c_vec[0] * plane_normal).cast<float> ();

          // Compute tangent vectors using the partial derivates evaluated at (0,0) which is c_vec[order_+1] and c_vec[1]
          if (normals_)
            normal = plane_normal - c_vec[order_ + 1] * u - c_vec[1] * v;
        }
      }

      PointInT aux;
      aux.x = point[0];
      aux.y = point[1];
      aux.z = point[2];
      projected_points.push_back (aux);

      NormalOutT aux_normal;
      aux_normal.normal_x = normal[0];
      aux_normal.normal_y = normal[1];
      aux_normal.normal_z = normal[2];
      aux_normal.curvature = curvature;
      projected_points_normals.push_back (aux_normal);

      break;
    }

    case (SAMPLE_LOCAL_PLANE):
    {
      // Uniformly sample a circle around the query point using the radius and step parameters
      for (float u_disp = -upsampling_radius_; u_disp <= upsampling_radius_; u_disp += upsampling_step_)
        for (float v_disp = -upsampling_radius_; v_disp <= upsampling_radius_; v_disp += upsampling_step_)
          if (u_disp*u_disp + v_disp*v_disp < upsampling_radius_*upsampling_radius_)
          {
            // If polynomial fitting was done, calculate the displacement along the normal
            double n_disp = 0.0f;
            double d_u = 0.0f, d_v = 0.0f;
            if (c_vec.size () != 0)
            {
              // Compute the displacement along the normal using the fitted polynomial
              // and compute the partial derivatives needed for estimating the normal
              int j = 0;
              float u_pow = 1, v_pow = 1;
              for (int ui = 0; ui <= order_; ++ui)
              {
                v_pow = 1;
                for (int vi = 0; vi <= order_ - ui; ++vi)
                {
                  n_disp += u_pow * v_pow * c_vec[j++];

                  // Compute partial derivatives
                  if (ui >= 1)
                    d_u += c_vec[j-1] * ui * u_pow / u_disp * v_pow;
                  if (vi >= 1)
                    d_v += c_vec[j-1] * vi * u_pow * v_pow / v_disp;

                  v_pow *= v_disp;
                }
                u_pow *= u_disp;
              }
            }

            PointInT aux;
            aux.x = point[0] + u[0] * u_disp + v[0] * v_disp + plane_normal[0] * n_disp;
            aux.y = point[1] + u[1] * u_disp + v[1] * v_disp + plane_normal[1] * n_disp;
            aux.z = point[2] + u[2] * u_disp + v[2] * v_disp + plane_normal[2] * n_disp;

            Eigen::Vector3d normal = plane_normal - d_u * u - d_v * v;

            NormalOutT aux_normal;
            aux_normal.normal_x = normal[0];
            aux_normal.normal_y = normal[1];
            aux_normal.normal_z = normal[2];
            aux_normal.curvature = curvature;

            projected_points.push_back (aux);
            projected_points_normals.push_back (aux_normal);
          }
    }
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename NormalOutT> void
pcl::MovingLeastSquares<PointInT, NormalOutT>::performReconstruction (PointCloudIn &output)
{
  // Compute the number of coefficients
  nr_coeff_ = (order_ + 1) * (order_ + 2) / 2;

  // Allocate enough space to hold the results of nearest neighbor searches
  // \note resize is irrelevant for a radiusSearch ().
  std::vector<int> nn_indices;
  std::vector<float> nn_sqr_dists;

  // For all points
  for (size_t cp = 0; cp < indices_->size (); ++cp)
  {
    // Get the initial estimates of point positions and their neighborhoods
    if (!searchForNeighbors ((*indices_)[cp], nn_indices, nn_sqr_dists))
      continue;

    // Check the number of nearest neighbors for normal estimation (and later
    // for polynomial fit as well)
    if (nn_indices.size () < 3)
      continue;

    PointCloudIn projected_points;
    NormalCloudOut projected_points_normals;
    // Get a plane approximating the local surface's tangent and project point onto it
    computeMLSPointNormal ((*indices_)[cp], *input_, nn_indices, nn_sqr_dists, projected_points, projected_points_normals);

    // Append projected points to output
    output.insert (output.end (), projected_points.begin (), projected_points.end ());
    normals_->insert (normals_->end (), projected_points_normals.begin (), projected_points_normals.end ());
  }

  // Set proper widths and heights for the clouds
  if (upsample_method_ == NONE && fake_indices_)
  {
    normals_->width = input_->width;
    normals_->height = input_->height;
    output.width = input_->width;
    output.height = input_->height;
  }
  else
  {
    normals_->height = 1;
    normals_->width = normals_->size ();
    output.height = 1;
    output.width = output.size ();
  }
  //printf ("output size %d %d %d\n", output.width, output.height, output.size ());
  //printf ("Normals size %d %d %d\n", normals_->width, normals_->height, normals_->size ());
}

#define PCL_INSTANTIATE_MovingLeastSquares(T,OutT) template class PCL_EXPORTS pcl::MovingLeastSquares<T,OutT>;

#endif    // PCL_SURFACE_IMPL_MLS_H_

<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
#include "oox/ole/axbinarywriter.hxx"

#include "oox/ole/olehelper.hxx"

namespace oox {
namespace ole {

// ============================================================================

namespace {

const sal_uInt32 AX_STRING_SIZEMASK         = 0x7FFFFFFF;
const sal_uInt32 AX_STRING_COMPRESSED       = 0x80000000;

} // namespace

// ============================================================================

AxAlignedOutputStream::AxAlignedOutputStream( BinaryOutputStream& rOutStrm ) :
    BinaryStreamBase( false ),
    mpOutStrm( &rOutStrm ),
    mnStrmPos( 0 ),
    mnStrmSize( rOutStrm.getRemaining() ),
    mnWrappedBeginPos( rOutStrm.tell() )
{
    mbEof = mbEof || rOutStrm.isEof();
}

sal_Int64 AxAlignedOutputStream::size() const
{
    return mpOutStrm ? mnStrmSize : -1;
}

sal_Int64 AxAlignedOutputStream::tell() const
{
    return mpOutStrm ? mnStrmPos : -1;
}

void AxAlignedOutputStream::seek( sal_Int64 nPos )
{
    mbEof = (nPos < 0);
    if( !mbEof )
    {
        mpOutStrm->seek( static_cast< sal_Int32 >( mnWrappedBeginPos + nPos  ) );
        mnStrmPos = mpOutStrm->tell() - mnWrappedBeginPos;
    }
}

void AxAlignedOutputStream::close()
{
    mpOutStrm = 0;
    mbEof = true;
}

void AxAlignedOutputStream::writeData( const StreamDataSequence& orData, size_t nAtomSize )
{
    mpOutStrm->writeData( orData, nAtomSize );
    mnStrmPos = mpOutStrm->tell() - mnWrappedBeginPos;
}

void AxAlignedOutputStream::writeMemory( const void* opMem, sal_Int32 nBytes, size_t nAtomSize )
{
    mpOutStrm->writeMemory( opMem, nBytes, nAtomSize );
    mnStrmPos = mpOutStrm->tell() - mnWrappedBeginPos;
}

void AxAlignedOutputStream::pad( sal_Int32 nBytes, size_t nAtomSize )
{
   //PRESUMABELY we need to pad with 0's here as appropriate
   com::sun::star::uno::Sequence< sal_Int8 > aData( nBytes );
   // ok we could be padding with rubbish here, but really that shouldn't matter
   // set to 0(s), easier to not get fooled by 0's when looking at
   // binary content......
   memset( static_cast<void*>( aData.getArray() ), 0, nBytes );
   mpOutStrm->writeData( aData, nAtomSize );
   mnStrmPos = mpOutStrm->tell() - mnWrappedBeginPos;
}

void AxAlignedOutputStream::align( size_t nSize )
{
    pad( static_cast< sal_Int32 >( (nSize - (mnStrmPos % nSize)) % nSize ) );
}

// ============================================================================

namespace {

void lclWriteString( AxAlignedOutputStream& rOutStrm, OUString& rValue, sal_uInt32 nSize, bool bArrayString )
{
    bool bCompressed = getFlag( nSize, AX_STRING_COMPRESSED );
    rOutStrm.writeCompressedUnicodeArray( rValue, bCompressed || bArrayString );
}

} // namespace

// ----------------------------------------------------------------------------

AxBinaryPropertyWriter::ComplexProperty::~ComplexProperty()
{
}

bool AxBinaryPropertyWriter::PairProperty::writeProperty( AxAlignedOutputStream& rOutStrm )
{
    rOutStrm << mrPairData.first << mrPairData.second;
    return true;
}

bool AxBinaryPropertyWriter::StringProperty::writeProperty( AxAlignedOutputStream& rOutStrm )
{
    lclWriteString( rOutStrm, mrValue, mnSize, false );
    return true;
}

// ----------------------------------------------------------------------------

AxBinaryPropertyWriter::AxBinaryPropertyWriter( BinaryOutputStream& rOutStrm, bool b64BitPropFlags ) :
    maOutStrm( rOutStrm ),
    mnPropFlags( 0x0 ),
    mbValid( true ),
    mb64BitPropFlags( b64BitPropFlags )
{
    sal_uInt16 nId( 0x0200 );
    maOutStrm << nId;
    mnBlockSize = 0; // will be filled in the finalize method

    maOutStrm << nId;
    mnPropFlagsStart = maOutStrm.tell();

    if( mb64BitPropFlags )
        maOutStrm << mnPropFlags;
    else
        maOutStrm << sal_uInt32( mnPropFlags );
    mnNextProp = 1;
}

void AxBinaryPropertyWriter::writeBoolProperty( bool orbValue, bool bReverse )
{
    // orbValue ^ bReverse true then we want to set the bit, e.g. don't skip
    startNextProperty(  !( ( orbValue ^ bReverse ) >= 1 ) );
}

void AxBinaryPropertyWriter::writePairProperty( AxPairData& orPairData )
{
    if( startNextProperty() )
        maLargeProps.push_back( ComplexPropVector::value_type( new PairProperty( orPairData ) ) );
}

void AxBinaryPropertyWriter::writeStringProperty( OUString& orValue, bool bCompressed )
{
    sal_uInt32 nSize = orValue.getLength();
    if ( bCompressed )
        setFlag(  nSize, AX_STRING_COMPRESSED );
    else
        nSize *= 2;
    maOutStrm.writeAligned< sal_uInt32 >( nSize );
    maLargeProps.push_back( ComplexPropVector::value_type( new StringProperty( orValue, nSize ) ) );
    startNextProperty();
}

bool AxBinaryPropertyWriter::finalizeExport()
{
    // write large properties
    maOutStrm.align( 4 );
    if( !maLargeProps.empty() )
    {
        for( ComplexPropVector::iterator aIt = maLargeProps.begin(), aEnd = maLargeProps.end(); ensureValid() && (aIt != aEnd); ++aIt )
        {
            (*aIt)->writeProperty( maOutStrm );
            maOutStrm.align( 4 );
        }
    }

    mnBlockSize = maOutStrm.tell() - mnPropFlagsStart;

    // write stream properties (no stream alignment between properties!)
    if( !maStreamProps.empty() )
        for( ComplexPropVector::iterator aIt = maStreamProps.begin(), aEnd = maStreamProps.end(); ensureValid() && (aIt != aEnd); ++aIt )
           (*aIt)->writeProperty( maOutStrm );

    sal_Int64 nPos = maOutStrm.tell();
    maOutStrm.seek( mnPropFlagsStart - sizeof( mnBlockSize ) );

    maOutStrm << mnBlockSize;

    if( mb64BitPropFlags )
        maOutStrm << mnPropFlags;
    else
        maOutStrm << sal_uInt32( mnPropFlags );

    maOutStrm.seek( nPos );
    return true;
}

bool AxBinaryPropertyWriter::ensureValid( bool bCondition )
{
    mbValid = mbValid && bCondition && !maOutStrm.isEof();
    return mbValid;
}

bool AxBinaryPropertyWriter::startNextProperty( bool bSkip )
{
    // if we are skipping then we clear the flag
    setFlag( mnPropFlags, mnNextProp, !bSkip );
    mnNextProp <<= 1;
    return true;
}

// ============================================================================

} // namespace exp
} // namespace ole

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>-Werror,-Wunused-const-variable<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
#include "oox/ole/axbinarywriter.hxx"

#include "oox/ole/olehelper.hxx"

namespace oox {
namespace ole {

// ============================================================================

namespace {

const sal_uInt32 AX_STRING_COMPRESSED       = 0x80000000;

} // namespace

// ============================================================================

AxAlignedOutputStream::AxAlignedOutputStream( BinaryOutputStream& rOutStrm ) :
    BinaryStreamBase( false ),
    mpOutStrm( &rOutStrm ),
    mnStrmPos( 0 ),
    mnStrmSize( rOutStrm.getRemaining() ),
    mnWrappedBeginPos( rOutStrm.tell() )
{
    mbEof = mbEof || rOutStrm.isEof();
}

sal_Int64 AxAlignedOutputStream::size() const
{
    return mpOutStrm ? mnStrmSize : -1;
}

sal_Int64 AxAlignedOutputStream::tell() const
{
    return mpOutStrm ? mnStrmPos : -1;
}

void AxAlignedOutputStream::seek( sal_Int64 nPos )
{
    mbEof = (nPos < 0);
    if( !mbEof )
    {
        mpOutStrm->seek( static_cast< sal_Int32 >( mnWrappedBeginPos + nPos  ) );
        mnStrmPos = mpOutStrm->tell() - mnWrappedBeginPos;
    }
}

void AxAlignedOutputStream::close()
{
    mpOutStrm = 0;
    mbEof = true;
}

void AxAlignedOutputStream::writeData( const StreamDataSequence& orData, size_t nAtomSize )
{
    mpOutStrm->writeData( orData, nAtomSize );
    mnStrmPos = mpOutStrm->tell() - mnWrappedBeginPos;
}

void AxAlignedOutputStream::writeMemory( const void* opMem, sal_Int32 nBytes, size_t nAtomSize )
{
    mpOutStrm->writeMemory( opMem, nBytes, nAtomSize );
    mnStrmPos = mpOutStrm->tell() - mnWrappedBeginPos;
}

void AxAlignedOutputStream::pad( sal_Int32 nBytes, size_t nAtomSize )
{
   //PRESUMABELY we need to pad with 0's here as appropriate
   com::sun::star::uno::Sequence< sal_Int8 > aData( nBytes );
   // ok we could be padding with rubbish here, but really that shouldn't matter
   // set to 0(s), easier to not get fooled by 0's when looking at
   // binary content......
   memset( static_cast<void*>( aData.getArray() ), 0, nBytes );
   mpOutStrm->writeData( aData, nAtomSize );
   mnStrmPos = mpOutStrm->tell() - mnWrappedBeginPos;
}

void AxAlignedOutputStream::align( size_t nSize )
{
    pad( static_cast< sal_Int32 >( (nSize - (mnStrmPos % nSize)) % nSize ) );
}

// ============================================================================

namespace {

void lclWriteString( AxAlignedOutputStream& rOutStrm, OUString& rValue, sal_uInt32 nSize, bool bArrayString )
{
    bool bCompressed = getFlag( nSize, AX_STRING_COMPRESSED );
    rOutStrm.writeCompressedUnicodeArray( rValue, bCompressed || bArrayString );
}

} // namespace

// ----------------------------------------------------------------------------

AxBinaryPropertyWriter::ComplexProperty::~ComplexProperty()
{
}

bool AxBinaryPropertyWriter::PairProperty::writeProperty( AxAlignedOutputStream& rOutStrm )
{
    rOutStrm << mrPairData.first << mrPairData.second;
    return true;
}

bool AxBinaryPropertyWriter::StringProperty::writeProperty( AxAlignedOutputStream& rOutStrm )
{
    lclWriteString( rOutStrm, mrValue, mnSize, false );
    return true;
}

// ----------------------------------------------------------------------------

AxBinaryPropertyWriter::AxBinaryPropertyWriter( BinaryOutputStream& rOutStrm, bool b64BitPropFlags ) :
    maOutStrm( rOutStrm ),
    mnPropFlags( 0x0 ),
    mbValid( true ),
    mb64BitPropFlags( b64BitPropFlags )
{
    sal_uInt16 nId( 0x0200 );
    maOutStrm << nId;
    mnBlockSize = 0; // will be filled in the finalize method

    maOutStrm << nId;
    mnPropFlagsStart = maOutStrm.tell();

    if( mb64BitPropFlags )
        maOutStrm << mnPropFlags;
    else
        maOutStrm << sal_uInt32( mnPropFlags );
    mnNextProp = 1;
}

void AxBinaryPropertyWriter::writeBoolProperty( bool orbValue, bool bReverse )
{
    // orbValue ^ bReverse true then we want to set the bit, e.g. don't skip
    startNextProperty(  !( ( orbValue ^ bReverse ) >= 1 ) );
}

void AxBinaryPropertyWriter::writePairProperty( AxPairData& orPairData )
{
    if( startNextProperty() )
        maLargeProps.push_back( ComplexPropVector::value_type( new PairProperty( orPairData ) ) );
}

void AxBinaryPropertyWriter::writeStringProperty( OUString& orValue, bool bCompressed )
{
    sal_uInt32 nSize = orValue.getLength();
    if ( bCompressed )
        setFlag(  nSize, AX_STRING_COMPRESSED );
    else
        nSize *= 2;
    maOutStrm.writeAligned< sal_uInt32 >( nSize );
    maLargeProps.push_back( ComplexPropVector::value_type( new StringProperty( orValue, nSize ) ) );
    startNextProperty();
}

bool AxBinaryPropertyWriter::finalizeExport()
{
    // write large properties
    maOutStrm.align( 4 );
    if( !maLargeProps.empty() )
    {
        for( ComplexPropVector::iterator aIt = maLargeProps.begin(), aEnd = maLargeProps.end(); ensureValid() && (aIt != aEnd); ++aIt )
        {
            (*aIt)->writeProperty( maOutStrm );
            maOutStrm.align( 4 );
        }
    }

    mnBlockSize = maOutStrm.tell() - mnPropFlagsStart;

    // write stream properties (no stream alignment between properties!)
    if( !maStreamProps.empty() )
        for( ComplexPropVector::iterator aIt = maStreamProps.begin(), aEnd = maStreamProps.end(); ensureValid() && (aIt != aEnd); ++aIt )
           (*aIt)->writeProperty( maOutStrm );

    sal_Int64 nPos = maOutStrm.tell();
    maOutStrm.seek( mnPropFlagsStart - sizeof( mnBlockSize ) );

    maOutStrm << mnBlockSize;

    if( mb64BitPropFlags )
        maOutStrm << mnPropFlags;
    else
        maOutStrm << sal_uInt32( mnPropFlags );

    maOutStrm.seek( nPos );
    return true;
}

bool AxBinaryPropertyWriter::ensureValid( bool bCondition )
{
    mbValid = mbValid && bCondition && !maOutStrm.isEof();
    return mbValid;
}

bool AxBinaryPropertyWriter::startNextProperty( bool bSkip )
{
    // if we are skipping then we clear the flag
    setFlag( mnPropFlags, mnNextProp, !bSkip );
    mnNextProp <<= 1;
    return true;
}

// ============================================================================

} // namespace exp
} // namespace ole

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>