<commit_before>/*=============================================================================

  Program:   Visualization Toolkit
  Module:    vtkGeoTerrain.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=============================================================================*/
/*-------------------------------------------------------------------------
  Copyright 2008 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
-------------------------------------------------------------------------*/
#include "vtkObjectFactory.h"
#include "vtkGeoCamera.h"
#include "vtkGeoTerrainGlobeSource.h"
#include "vtkGeoTerrainNode.h"
#include "vtkGeoTerrainSource.h"
#include "vtkGeoTerrain.h"
#include "vtkPolyDataWriter.h"
#include "vtkPolyData.h"
#include "vtkMutexLock.h"

// For vtkSleep
#include "vtkWindows.h"
#include <ctype.h>
#include <time.h>

vtkCxxRevisionMacro(vtkGeoTerrain, "1.3");
vtkStandardNewMacro(vtkGeoTerrain);
#if _WIN32
#include "windows.h"
#endif
#include "vtkTimerLog.h"

//-----------------------------------------------------------------------------
// Cross platform sleep
inline void vtkSleep(double duration)
{
  duration = duration; // avoid warnings
  // sleep according to OS preference
#ifdef _WIN32
  Sleep((int)(1000*duration));
#elif defined(__FreeBSD__) || defined(__linux__) || defined(sgi)
  struct timespec sleep_time, dummy;
  sleep_time.tv_sec = (int)duration;
  sleep_time.tv_nsec = (int)(1000000000*(duration-sleep_time.tv_sec));
  nanosleep(&sleep_time,&dummy);
#endif
}

//-----------------------------------------------------------------------------
VTK_THREAD_RETURN_TYPE vtkGeoTerrainThreadStart( void *arg )
{
//   int threadId = ((vtkMultiThreader::ThreadInfo *)(arg))->ThreadID;
//   int threadCount = ((vtkMultiThreader::ThreadInfo *)(arg))->NumberOfThreads;

  vtkGeoTerrain* self;
  self = (vtkGeoTerrain*)
    (((vtkMultiThreader::ThreadInfo *)(arg))->UserData);

 self->ThreadStart();
  return VTK_THREAD_RETURN_VALUE;
}

//----------------------------------------------------------------------------
vtkGeoTerrain::vtkGeoTerrain()
{
  // It is OK to have a default,
  // but the use should be able to change the .
  vtkSmartPointer<vtkGeoTerrainSource> source;
  source = vtkSmartPointer<vtkGeoTerrainGlobeSource>::New();
  this->SetTerrainSource(source);

  this->Threader = vtkSmartPointer<vtkMultiThreader>::New();
  this->WaitForRequestMutex1 = vtkSmartPointer<vtkMutexLock>::New();
  this->WaitForRequestMutex1->Lock();

  this->TreeMutex = vtkSmartPointer<vtkMutexLock>::New();
  this->TreeLock = 0;

  // Spawn a thread to update the tree.
  this->ThreadId = this->Threader->SpawnThread( vtkGeoTerrainThreadStart, this);
}

//-----------------------------------------------------------------------------
vtkGeoTerrain::~vtkGeoTerrain()
{
  this->RequestTerminate();
  this->Threader->TerminateThread(this->ThreadId);
  this->ThreadId = -1;
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::StartEdit()
{
  this->NewNodes.clear();
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::AddNode(vtkGeoTerrainNode* node)
{
  this->NewNodes.push_back(node);
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::FinishEdit()
{
  this->Nodes = this->NewNodes;
  this->NewNodes.clear();
}

//-----------------------------------------------------------------------------
int vtkGeoTerrain::GetNumberOfNodes()
{
  return static_cast<int>(this->Nodes.size());
}

//-----------------------------------------------------------------------------
vtkGeoTerrainNode* vtkGeoTerrain::GetNode(int idx)
{
  return this->Nodes[idx];
}

//-----------------------------------------------------------------------------
bool vtkGeoTerrain::Update(vtkGeoCamera* camera)
{
  bool returnValue = this->Update(this, camera);
  // I am putting the request second so that it will not block the Update.
  this->Request(camera);

  return returnValue;
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::SetTerrainSource(vtkGeoTerrainSource* source)
{
  if ( !source )
    {
    return;
    }

  this->TerrainSource = source;
  this->WesternHemisphere = vtkSmartPointer<vtkGeoTerrainNode>::New();
  this->EasternHemisphere = vtkSmartPointer<vtkGeoTerrainNode>::New();
  this->WesternHemisphere->SetId(0);
  this->EasternHemisphere->SetId(1);

  // Id is a bitmap representation of the branch trace.
  this->WesternHemisphere->SetLongitudeRange(-180.0,0.0);
  this->WesternHemisphere->SetLatitudeRange(-90.0,90.0);
  source->GenerateTerrainForNode(this->WesternHemisphere);
  this->EasternHemisphere->SetLongitudeRange(0.0,180.0);
  this->EasternHemisphere->SetLatitudeRange(-90.0,90.0);
  source->GenerateTerrainForNode(this->EasternHemisphere);
}

//-----------------------------------------------------------------------------
// This could be done in a separate thread.
int vtkGeoTerrain::RefineNode(vtkGeoTerrainNode* node)
{
  // Create the four children.
  if (node->GetChild(0))
    { // This node is already refined.
    return VTK_OK;
    }

  if (node->CreateChildren() == VTK_ERROR)
    {
    return VTK_ERROR;
    }

  this->TerrainSource->GenerateTerrainForNode(node->GetChild(0));
  this->TerrainSource->GenerateTerrainForNode(node->GetChild(1));
  this->TerrainSource->GenerateTerrainForNode(node->GetChild(2));
  this->TerrainSource->GenerateTerrainForNode(node->GetChild(3));

  return VTK_OK;
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::InitializeTerrain(vtkGeoTerrain* terrain)
{
  terrain->StartEdit();
  terrain->AddNode(this->WesternHemisphere);
  terrain->AddNode(this->EasternHemisphere);
  terrain->FinishEdit();
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::Request(vtkGeoTerrainNode* node, vtkGeoCamera* cam)
{
  int evaluation = this->EvaluateNode(node, cam);
  if (evaluation > 0)
    { // refine the node.  Add the 4 children.
    // For simplicity, lets just refine one level per update.
    if ( node->GetChild(0) == 0)
      { // Temporarily refine here.  Later we will have asynchronous refinement.
      this->RefineNode(node);
      }
    else
      {
      this->Request(node->GetChild(0), cam);
      this->Request(node->GetChild(1), cam);
      this->Request(node->GetChild(2), cam);
      this->Request(node->GetChild(3), cam);
      }
    }
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::ThreadStart()
{
  // Use mutex to avoid a busy loop.  Select on a socket will be better.
  while (1)
    {
    // Stupid gating a thread via mutex guntlet.
    this->WaitForRequestMutex1->Lock();
    this->WaitForRequestMutex1->Unlock();

    if (this->Camera == 0)
      { // terminate
      return;
      }

    // Variable to manage whoe has access to reading and changing tree.
    // This thread never keeps this lock for long.
    // We do not want to block the client.
    this->GetWriteLock();
    this->Request(this->WesternHemisphere, this->Camera);
    this->Request(this->EasternHemisphere, this->Camera);
    this->ReleaseWriteLock();
    }
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::Request(vtkGeoCamera* camera)
{
  if (camera == 0)
    {
    return;
    }

  double t = vtkTimerLog::GetUniversalTime();

  this->TreeMutex->Lock();
  // If a request is already in progress.  I do not want to block.
  if (this->TreeLock == 0)
    { // The request thread is idle.
    this->Camera = camera;
    this->WaitForRequestMutex1->Unlock();
    vtkSleep(0.01);
    this->WaitForRequestMutex1->Lock();
    }
  this->TreeMutex->Unlock();

  t = vtkTimerLog::GetUniversalTime() - t;
  if (t > 0.1)
    {
    cerr << "request took : " << t << endl;
    }
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::RequestTerminate()
{
  this->Camera = 0;
  this->WaitForRequestMutex1->Unlock();
  vtkSleep(0.01);
  this->WaitForRequestMutex1->Lock();
}

//-----------------------------------------------------------------------------
bool vtkGeoTerrain::GetReadLock()
{
  this->TreeMutex->Lock();
  if (this->TreeLock)
    { // The background thread is writeing to the tree..
    this->TreeMutex->Unlock();
    return false;
    }

  // Keep the mutex lock until we are finished.
  return true;
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::ReleaseReadLock()
{
  this->TreeMutex->Unlock();
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::GetWriteLock()
{
  this->TreeMutex->Lock();
  this->TreeLock = 1;
  this->TreeMutex->Unlock();
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::ReleaseWriteLock()
{
  this->TreeMutex->Lock();
  this->TreeLock = 0;
  this->TreeMutex->Unlock();
}

//-----------------------------------------------------------------------------
bool vtkGeoTerrain::Update(vtkGeoTerrain* terrain, vtkGeoCamera* camera)
{
  vtkGeoTerrainNode* node;
  bool changedFlag = false;
  int maxLevel = 0;

  int hackCount = 0; // Do not change too many tiles at once.

  double t1 = vtkTimerLog::GetUniversalTime();

  // If we cannot get a lock, we should return immediately and not wait.
  // Since the cache owns the terrain tree, it is responsible
  // For managing the access to the tree from multiple threads.
  if (this->GetReadLock() == false)
    {
    return false;
    }
  if (terrain->GetNumberOfNodes() == 0 )
    {
    // The terrain always covers the entire globe.  If we have no nodes,
    // then we need to initialize this terrain to have the lowest two
    // nodes (East and west hemisphere).
    changedFlag = true;
    this->InitializeTerrain(terrain);
    }

  // Start a new list of nodes.
  terrain->StartEdit();

  // Create a new list of nodes and copy/refine old list to the new list.
  // The order of nodes traces a strict depth first search.
  // This makes merging nodes to a lower resolution simpler.
  int numInNodes = terrain->GetNumberOfNodes();
  int evaluation;
  int outIdx = 0;
  int inIdx = 0;
  while (inIdx < numInNodes)
    {
    node = terrain->GetNode(inIdx);
    vtkGeoTerrainNode* parent = node->GetParent();
    evaluation = this->EvaluateNode(node, camera);

    // Just a test to even out model changes over multiple renders.
    //if (hackCount > 20)
    //  {
    //  evaluation = 0;
    //  }

    if (evaluation < 0)
      { // Do not merge the children if the parent would want to split;
      // I am trying to avoid oscilations.
      if (parent && this->EvaluateNode(parent, camera) > 0)
        {
        evaluation = 0;
        }
      }
    // We cannot split if there are no children.
    if (evaluation > 0 && node->GetChild(0) == 0)
      {
      evaluation = 0;
      }

    if (evaluation > 0)
      { // refine the node.  Add the 4 children.
      // For simplicity, lets just refine one level per update.
      if ( node->GetChild(0) == 0)
        { // sanity check.  We checked for this above.
        terrain->AddNode(node);
        ++outIdx;
        if (node->GetLevel() > maxLevel) { maxLevel = node->GetLevel();}
        }
      else
        {
        //newList[outIdx++] = node->GetChild(0);
        vtkGeoTerrainNode* child;
        child = node->GetChild(0);
        terrain->AddNode(child);
        child = node->GetChild(1);
        terrain->AddNode(child);
        child = node->GetChild(2);
        terrain->AddNode(child);
        child = node->GetChild(3);
        terrain->AddNode(child);
        // Just for debugging.
        if (child->GetLevel() > maxLevel) { maxLevel = child->GetLevel();}
        hackCount += 4;

        changedFlag = true;
        }
      ++inIdx;
      }
    else if (evaluation < 0 && node->GetLevel() > 0 && node->GetWhichChildAreYou() == 0)
      { // Only merge if the first child wants to.
      // TODO: Change this to use the "IsDescendantOf" method.
      unsigned long parentId = parent->GetId();
      // Now remove all nodes until we get to a node that is not a
      // decendant of the parent node.
      // All decendents will have the first N bits in their Id.
      unsigned long mask = ((node->GetLevel() * 2) - 1);
      mask = (1 << mask) - 1;
      // No need to test heritage of first child.
      unsigned long tmp = parentId;
      // This leaves the inIdx point to the next node so
      // other paths need to increment the inIdx at their end.
      while ((tmp == parentId) && inIdx < numInNodes)
        {
        ++inIdx;
        // This while structure of this loop makes termination sort of complicated.
        // We can go right past the end of the list here.
        if (inIdx < numInNodes)
          {
          node = terrain->GetNode(inIdx);
          tmp = node->GetId();
          tmp = tmp & mask;
          }
        }
      // Just add the parent for all the nodes we skipped.
      if (parent->GetLevel() > maxLevel) { maxLevel = parent->GetLevel();} // Just for debugging
      terrain->AddNode(parent);
      hackCount += 1;
      ++outIdx;
      changedFlag = true;
      }
    else
      { // Just pass the node through unchanged.
      //newList[outIdx++] = node;
      if (node->GetLevel() > maxLevel) { maxLevel = node->GetLevel();} // Just for debugging
      terrain->AddNode(node);
      ++inIdx;
      }
    }

  if (changedFlag)
    {
    terrain->FinishEdit();
    }

  this->ReleaseReadLock();

  t1 = vtkTimerLog::GetUniversalTime() - t1;
  if (t1 > 0.1)
    {
    cerr << "Update took : " << t1 << endl;
    }

  return changedFlag;
}

//-----------------------------------------------------------------------------
// Returns 0 if there should be no change, -1 if the node resolution is too
// high, and +1 if the nodes resolution is too low.
int vtkGeoTerrain::EvaluateNode(vtkGeoTerrainNode* node, vtkGeoCamera* cam)
{
  double sphereViewSize;

  if (cam == 0)
    {
    return 0;
    }

  // Size of the sphere in view area units (0 -> 1)
  sphereViewSize = cam->GetNodeCoverage(node);

  // Arbitrary tresholds
  if (sphereViewSize > 0.75)
    {
    return 1;
    }
  if (sphereViewSize < 0.2)
    {
    return -1;
    }
  // Do not change the node.
  return 0;
}
<commit_msg>COMP:Fixed old-style cast warning.<commit_after>/*=============================================================================

  Program:   Visualization Toolkit
  Module:    vtkGeoTerrain.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=============================================================================*/
/*-------------------------------------------------------------------------
  Copyright 2008 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
-------------------------------------------------------------------------*/
#include "vtkObjectFactory.h"
#include "vtkGeoCamera.h"
#include "vtkGeoTerrainGlobeSource.h"
#include "vtkGeoTerrainNode.h"
#include "vtkGeoTerrainSource.h"
#include "vtkGeoTerrain.h"
#include "vtkPolyDataWriter.h"
#include "vtkPolyData.h"
#include "vtkMutexLock.h"

// For vtkSleep
#include "vtkWindows.h"
#include <ctype.h>
#include <time.h>

vtkCxxRevisionMacro(vtkGeoTerrain, "1.4");
vtkStandardNewMacro(vtkGeoTerrain);
#if _WIN32
#include "windows.h"
#endif
#include "vtkTimerLog.h"

//-----------------------------------------------------------------------------
// Cross platform sleep
inline void vtkSleep(double duration)
{
  duration = duration; // avoid warnings
  // sleep according to OS preference
#ifdef _WIN32
  Sleep((int)(1000*duration));
#elif defined(__FreeBSD__) || defined(__linux__) || defined(sgi)
  struct timespec sleep_time, dummy;
  sleep_time.tv_sec = static_cast<int>(duration);
  sleep_time.tv_nsec = static_cast<int>(1000000000*(duration-sleep_time.tv_sec));
  nanosleep(&sleep_time,&dummy);
#endif
}

//-----------------------------------------------------------------------------
VTK_THREAD_RETURN_TYPE vtkGeoTerrainThreadStart( void *arg )
{
//   int threadId = ((vtkMultiThreader::ThreadInfo *)(arg))->ThreadID;
//   int threadCount = ((vtkMultiThreader::ThreadInfo *)(arg))->NumberOfThreads;

  vtkGeoTerrain* self;
  self = static_cast<vtkGeoTerrain *>
    (static_cast<vtkMultiThreader::ThreadInfo *>(arg)->UserData);

 self->ThreadStart();
  return VTK_THREAD_RETURN_VALUE;
}

//----------------------------------------------------------------------------
vtkGeoTerrain::vtkGeoTerrain()
{
  // It is OK to have a default,
  // but the use should be able to change the .
  vtkSmartPointer<vtkGeoTerrainSource> source;
  source = vtkSmartPointer<vtkGeoTerrainGlobeSource>::New();
  this->SetTerrainSource(source);

  this->Threader = vtkSmartPointer<vtkMultiThreader>::New();
  this->WaitForRequestMutex1 = vtkSmartPointer<vtkMutexLock>::New();
  this->WaitForRequestMutex1->Lock();

  this->TreeMutex = vtkSmartPointer<vtkMutexLock>::New();
  this->TreeLock = 0;

  // Spawn a thread to update the tree.
  this->ThreadId = this->Threader->SpawnThread( vtkGeoTerrainThreadStart, this);
}

//-----------------------------------------------------------------------------
vtkGeoTerrain::~vtkGeoTerrain()
{
  this->RequestTerminate();
  this->Threader->TerminateThread(this->ThreadId);
  this->ThreadId = -1;
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::StartEdit()
{
  this->NewNodes.clear();
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::AddNode(vtkGeoTerrainNode* node)
{
  this->NewNodes.push_back(node);
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::FinishEdit()
{
  this->Nodes = this->NewNodes;
  this->NewNodes.clear();
}

//-----------------------------------------------------------------------------
int vtkGeoTerrain::GetNumberOfNodes()
{
  return static_cast<int>(this->Nodes.size());
}

//-----------------------------------------------------------------------------
vtkGeoTerrainNode* vtkGeoTerrain::GetNode(int idx)
{
  return this->Nodes[idx];
}

//-----------------------------------------------------------------------------
bool vtkGeoTerrain::Update(vtkGeoCamera* camera)
{
  bool returnValue = this->Update(this, camera);
  // I am putting the request second so that it will not block the Update.
  this->Request(camera);

  return returnValue;
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::SetTerrainSource(vtkGeoTerrainSource* source)
{
  if ( !source )
    {
    return;
    }

  this->TerrainSource = source;
  this->WesternHemisphere = vtkSmartPointer<vtkGeoTerrainNode>::New();
  this->EasternHemisphere = vtkSmartPointer<vtkGeoTerrainNode>::New();
  this->WesternHemisphere->SetId(0);
  this->EasternHemisphere->SetId(1);

  // Id is a bitmap representation of the branch trace.
  this->WesternHemisphere->SetLongitudeRange(-180.0,0.0);
  this->WesternHemisphere->SetLatitudeRange(-90.0,90.0);
  source->GenerateTerrainForNode(this->WesternHemisphere);
  this->EasternHemisphere->SetLongitudeRange(0.0,180.0);
  this->EasternHemisphere->SetLatitudeRange(-90.0,90.0);
  source->GenerateTerrainForNode(this->EasternHemisphere);
}

//-----------------------------------------------------------------------------
// This could be done in a separate thread.
int vtkGeoTerrain::RefineNode(vtkGeoTerrainNode* node)
{
  // Create the four children.
  if (node->GetChild(0))
    { // This node is already refined.
    return VTK_OK;
    }

  if (node->CreateChildren() == VTK_ERROR)
    {
    return VTK_ERROR;
    }

  this->TerrainSource->GenerateTerrainForNode(node->GetChild(0));
  this->TerrainSource->GenerateTerrainForNode(node->GetChild(1));
  this->TerrainSource->GenerateTerrainForNode(node->GetChild(2));
  this->TerrainSource->GenerateTerrainForNode(node->GetChild(3));

  return VTK_OK;
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::InitializeTerrain(vtkGeoTerrain* terrain)
{
  terrain->StartEdit();
  terrain->AddNode(this->WesternHemisphere);
  terrain->AddNode(this->EasternHemisphere);
  terrain->FinishEdit();
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::Request(vtkGeoTerrainNode* node, vtkGeoCamera* cam)
{
  int evaluation = this->EvaluateNode(node, cam);
  if (evaluation > 0)
    { // refine the node.  Add the 4 children.
    // For simplicity, lets just refine one level per update.
    if ( node->GetChild(0) == 0)
      { // Temporarily refine here.  Later we will have asynchronous refinement.
      this->RefineNode(node);
      }
    else
      {
      this->Request(node->GetChild(0), cam);
      this->Request(node->GetChild(1), cam);
      this->Request(node->GetChild(2), cam);
      this->Request(node->GetChild(3), cam);
      }
    }
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::ThreadStart()
{
  // Use mutex to avoid a busy loop.  Select on a socket will be better.
  while (1)
    {
    // Stupid gating a thread via mutex guntlet.
    this->WaitForRequestMutex1->Lock();
    this->WaitForRequestMutex1->Unlock();

    if (this->Camera == 0)
      { // terminate
      return;
      }

    // Variable to manage whoe has access to reading and changing tree.
    // This thread never keeps this lock for long.
    // We do not want to block the client.
    this->GetWriteLock();
    this->Request(this->WesternHemisphere, this->Camera);
    this->Request(this->EasternHemisphere, this->Camera);
    this->ReleaseWriteLock();
    }
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::Request(vtkGeoCamera* camera)
{
  if (camera == 0)
    {
    return;
    }

  double t = vtkTimerLog::GetUniversalTime();

  this->TreeMutex->Lock();
  // If a request is already in progress.  I do not want to block.
  if (this->TreeLock == 0)
    { // The request thread is idle.
    this->Camera = camera;
    this->WaitForRequestMutex1->Unlock();
    vtkSleep(0.01);
    this->WaitForRequestMutex1->Lock();
    }
  this->TreeMutex->Unlock();

  t = vtkTimerLog::GetUniversalTime() - t;
  if (t > 0.1)
    {
    cerr << "request took : " << t << endl;
    }
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::RequestTerminate()
{
  this->Camera = 0;
  this->WaitForRequestMutex1->Unlock();
  vtkSleep(0.01);
  this->WaitForRequestMutex1->Lock();
}

//-----------------------------------------------------------------------------
bool vtkGeoTerrain::GetReadLock()
{
  this->TreeMutex->Lock();
  if (this->TreeLock)
    { // The background thread is writeing to the tree..
    this->TreeMutex->Unlock();
    return false;
    }

  // Keep the mutex lock until we are finished.
  return true;
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::ReleaseReadLock()
{
  this->TreeMutex->Unlock();
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::GetWriteLock()
{
  this->TreeMutex->Lock();
  this->TreeLock = 1;
  this->TreeMutex->Unlock();
}

//-----------------------------------------------------------------------------
void vtkGeoTerrain::ReleaseWriteLock()
{
  this->TreeMutex->Lock();
  this->TreeLock = 0;
  this->TreeMutex->Unlock();
}

//-----------------------------------------------------------------------------
bool vtkGeoTerrain::Update(vtkGeoTerrain* terrain, vtkGeoCamera* camera)
{
  vtkGeoTerrainNode* node;
  bool changedFlag = false;
  int maxLevel = 0;

  int hackCount = 0; // Do not change too many tiles at once.

  double t1 = vtkTimerLog::GetUniversalTime();

  // If we cannot get a lock, we should return immediately and not wait.
  // Since the cache owns the terrain tree, it is responsible
  // For managing the access to the tree from multiple threads.
  if (this->GetReadLock() == false)
    {
    return false;
    }
  if (terrain->GetNumberOfNodes() == 0 )
    {
    // The terrain always covers the entire globe.  If we have no nodes,
    // then we need to initialize this terrain to have the lowest two
    // nodes (East and west hemisphere).
    changedFlag = true;
    this->InitializeTerrain(terrain);
    }

  // Start a new list of nodes.
  terrain->StartEdit();

  // Create a new list of nodes and copy/refine old list to the new list.
  // The order of nodes traces a strict depth first search.
  // This makes merging nodes to a lower resolution simpler.
  int numInNodes = terrain->GetNumberOfNodes();
  int evaluation;
  int outIdx = 0;
  int inIdx = 0;
  while (inIdx < numInNodes)
    {
    node = terrain->GetNode(inIdx);
    vtkGeoTerrainNode* parent = node->GetParent();
    evaluation = this->EvaluateNode(node, camera);

    // Just a test to even out model changes over multiple renders.
    //if (hackCount > 20)
    //  {
    //  evaluation = 0;
    //  }

    if (evaluation < 0)
      { // Do not merge the children if the parent would want to split;
      // I am trying to avoid oscilations.
      if (parent && this->EvaluateNode(parent, camera) > 0)
        {
        evaluation = 0;
        }
      }
    // We cannot split if there are no children.
    if (evaluation > 0 && node->GetChild(0) == 0)
      {
      evaluation = 0;
      }

    if (evaluation > 0)
      { // refine the node.  Add the 4 children.
      // For simplicity, lets just refine one level per update.
      if ( node->GetChild(0) == 0)
        { // sanity check.  We checked for this above.
        terrain->AddNode(node);
        ++outIdx;
        if (node->GetLevel() > maxLevel) { maxLevel = node->GetLevel();}
        }
      else
        {
        //newList[outIdx++] = node->GetChild(0);
        vtkGeoTerrainNode* child;
        child = node->GetChild(0);
        terrain->AddNode(child);
        child = node->GetChild(1);
        terrain->AddNode(child);
        child = node->GetChild(2);
        terrain->AddNode(child);
        child = node->GetChild(3);
        terrain->AddNode(child);
        // Just for debugging.
        if (child->GetLevel() > maxLevel) { maxLevel = child->GetLevel();}
        hackCount += 4;

        changedFlag = true;
        }
      ++inIdx;
      }
    else if (evaluation < 0 && node->GetLevel() > 0 && node->GetWhichChildAreYou() == 0)
      { // Only merge if the first child wants to.
      // TODO: Change this to use the "IsDescendantOf" method.
      unsigned long parentId = parent->GetId();
      // Now remove all nodes until we get to a node that is not a
      // decendant of the parent node.
      // All decendents will have the first N bits in their Id.
      unsigned long mask = ((node->GetLevel() * 2) - 1);
      mask = (1 << mask) - 1;
      // No need to test heritage of first child.
      unsigned long tmp = parentId;
      // This leaves the inIdx point to the next node so
      // other paths need to increment the inIdx at their end.
      while ((tmp == parentId) && inIdx < numInNodes)
        {
        ++inIdx;
        // This while structure of this loop makes termination sort of complicated.
        // We can go right past the end of the list here.
        if (inIdx < numInNodes)
          {
          node = terrain->GetNode(inIdx);
          tmp = node->GetId();
          tmp = tmp & mask;
          }
        }
      // Just add the parent for all the nodes we skipped.
      if (parent->GetLevel() > maxLevel) { maxLevel = parent->GetLevel();} // Just for debugging
      terrain->AddNode(parent);
      hackCount += 1;
      ++outIdx;
      changedFlag = true;
      }
    else
      { // Just pass the node through unchanged.
      //newList[outIdx++] = node;
      if (node->GetLevel() > maxLevel) { maxLevel = node->GetLevel();} // Just for debugging
      terrain->AddNode(node);
      ++inIdx;
      }
    }

  if (changedFlag)
    {
    terrain->FinishEdit();
    }

  this->ReleaseReadLock();

  t1 = vtkTimerLog::GetUniversalTime() - t1;
  if (t1 > 0.1)
    {
    cerr << "Update took : " << t1 << endl;
    }

  return changedFlag;
}

//-----------------------------------------------------------------------------
// Returns 0 if there should be no change, -1 if the node resolution is too
// high, and +1 if the nodes resolution is too low.
int vtkGeoTerrain::EvaluateNode(vtkGeoTerrainNode* node, vtkGeoCamera* cam)
{
  double sphereViewSize;

  if (cam == 0)
    {
    return 0;
    }

  // Size of the sphere in view area units (0 -> 1)
  sphereViewSize = cam->GetNodeCoverage(node);

  // Arbitrary tresholds
  if (sphereViewSize > 0.75)
    {
    return 1;
    }
  if (sphereViewSize < 0.2)
    {
    return -1;
    }
  // Do not change the node.
  return 0;
}
<|endoftext|>


<commit_before>#pragma once

#include <cassert>
#include <map>
#include <omp.h>

#include "global_config.hpp"

namespace mocc {
    /**
     * The \ref Timer class provides functionality for measuring the amount of
     * runtime spent on various tasks. Each \ref Timer can have a number of
     * "children," which comprise sub-\ref Timer for individual tasks of
     * interest.
     *
     * Every \ref Timer maintains a total elapsed time, which may be accessed
     * via the \ref Timer::time() method. A \ref Timer can be thought of as a
     * stopwatch that is started with the \ref Timer::tic() method, and stopped
     * with the \ref Timer::toc() method. The elapsed time is a sum of all time
     * spent between calls the \ref Timer::tic() and \ref Timer::toc().
     *
     * There is a global \ref RootTimer, which is treated as the parent \ref
     * Timer for the entire executable.
     */
    class Timer {
    public:
        /**
         * \brief Create a new \ref Timer object.
         */
        Timer(std::string name);

        /**
         * \brief Create a new \ref Timer object and possibly start it.
         *
         * \param name the name of the \ref Timer
         * \param start whether or not to start the timer at construction-time.
         *
         * This will create a new \ref Timer and possibly start the \ref Timer
         * automatically if \p start is \c true. This is useful for
         * instrumenting constructor time for objects with lots of heavy lifting
         * to do in their initialization list. In such cases, starting the \ref
         * Timer in the body of the initializer will miss much of the time spent
         * constructing the objects in the initializer list. Placing a \ref
         * Timer object at the top of the initializer list will allow
         * measurement of this type of code.
         */
        Timer(std::string name, bool start );

        /**
         * \brief Start the \ref Timer
         *
         * This starts the \ref Timer "running," by logging the wall time at
         * which the \ref tic() function was called. The timer can then be
         * stopped with a call to \ref toc().
         */
        void tic();

        /**
         * \brief Stop the \ref Timer
         *
         * This stops the \ref Timer and returns the amount of time that elapsed
         * between the calls to \ref tic() and the \ref toc(). The running
         * sum of time for the \ref Timer is also incremented by this duration.
         */
        real_t toc();

        /**
         * \brief Return the time accumulated so far for the timer.
         *
         * If the timer is currently running, this will not include time since
         * last call to \ref tic().
         */
        real_t time() const {
            return time_;
        }

        /**
         * \brief Return a reference the child Timer of the passed name
         */
        Timer &operator[]( const std::string &name ) {
            return children_.at(name);
        }

        /**
         * \brief Return a const reference the child Timer of the passed name
         */
        const Timer &operator[]( const std::string &name ) const {
            return children_.at(name);
        }

        /**
         * \brief Print the entire \ref Timer tree to the provided output
         * stream.
         */
        void print( std::ostream &os, int level=0 ) const;

        /**
         * \brief Create a new child \ref Timer and return a reference to it.
         */
        Timer &new_timer( const std::string &name ) {
            children_.emplace( name, Timer(name) );
            return children_.at(name);
        }

        /**
         * \brief Create and return a new child \ref Timer, possibly starting it
         * automatically
         */
        Timer &new_timer( const std::string &name, bool start ) {
            children_.emplace( name, Timer(name, start) );
            return children_.at(name);
        }

        friend std::ostream &operator<<( std::ostream &os,
                const Timer &timer );

    private:
        std::string name_;
        real_t time_;
        bool running_;
        real_t wtime_;
        std::map<std::string, Timer> children_;
    };

    extern Timer RootTimer;

}
<commit_msg>Make time() work right when Timer is running<commit_after>#pragma once

#include <cassert>
#include <map>
#include <omp.h>

#include "global_config.hpp"

namespace mocc {
    /**
     * The \ref Timer class provides functionality for measuring the amount of
     * runtime spent on various tasks. Each \ref Timer can have a number of
     * "children," which comprise sub-\ref Timer for individual tasks of
     * interest.
     *
     * Every \ref Timer maintains a total elapsed time, which may be accessed
     * via the \ref Timer::time() method. A \ref Timer can be thought of as a
     * stopwatch that is started with the \ref Timer::tic() method, and stopped
     * with the \ref Timer::toc() method. The elapsed time is a sum of all time
     * spent between calls the \ref Timer::tic() and \ref Timer::toc().
     *
     * There is a global \ref RootTimer, which is treated as the parent \ref
     * Timer for the entire executable.
     */
    class Timer {
    public:
        /**
         * \brief Create a new \ref Timer object.
         */
        Timer(std::string name);

        /**
         * \brief Create a new \ref Timer object and possibly start it.
         *
         * \param name the name of the \ref Timer
         * \param start whether or not to start the timer at construction-time.
         *
         * This will create a new \ref Timer and possibly start the \ref Timer
         * automatically if \p start is \c true. This is useful for
         * instrumenting constructor time for objects with lots of heavy lifting
         * to do in their initialization list. In such cases, starting the \ref
         * Timer in the body of the initializer will miss much of the time spent
         * constructing the objects in the initializer list. Placing a \ref
         * Timer object at the top of the initializer list will allow
         * measurement of this type of code.
         */
        Timer(std::string name, bool start );

        /**
         * \brief Start the \ref Timer
         *
         * This starts the \ref Timer "running," by logging the wall time at
         * which the \ref tic() function was called. The timer can then be
         * stopped with a call to \ref toc().
         */
        void tic();

        /**
         * \brief Stop the \ref Timer
         *
         * This stops the \ref Timer and returns the amount of time that elapsed
         * between the calls to \ref tic() and the \ref toc(). The running
         * sum of time for the \ref Timer is also incremented by this duration.
         */
        real_t toc();

        /**
         * \brief Return the time accumulated so far for the timer.
         *
         */
        real_t time() const {
            if( running_ ) {
                return time_ + omp_get_wtime() - wtime_;
            } else {
                return time_;
            }
        }

        /**
         * \brief Return a reference the child Timer of the passed name
         */
        Timer &operator[]( const std::string &name ) {
            return children_.at(name);
        }

        /**
         * \brief Return a const reference the child Timer of the passed name
         */
        const Timer &operator[]( const std::string &name ) const {
            return children_.at(name);
        }

        /**
         * \brief Print the entire \ref Timer tree to the provided output
         * stream.
         */
        void print( std::ostream &os, int level=0 ) const;

        /**
         * \brief Create a new child \ref Timer and return a reference to it.
         */
        Timer &new_timer( const std::string &name ) {
            children_.emplace( name, Timer(name) );
            return children_.at(name);
        }

        /**
         * \brief Create and return a new child \ref Timer, possibly starting it
         * automatically
         */
        Timer &new_timer( const std::string &name, bool start ) {
            children_.emplace( name, Timer(name, start) );
            return children_.at(name);
        }

        friend std::ostream &operator<<( std::ostream &os,
                const Timer &timer );

    private:
        std::string name_;
        real_t time_;
        bool running_;
        real_t wtime_;
        std::map<std::string, Timer> children_;
    };

    extern Timer RootTimer;

}
<|endoftext|>


<commit_before>#include "ClassWrapper.h"
#include "JavaClassUtils.h"
#include "JavaExceptionUtils.h"
#include "JniWeakGlobalRef.h"
#include <string.h>

namespace spotify {
namespace jni {

ClassWrapper::~ClassWrapper() {
  // TODO: Delete mappings
}

bool ClassWrapper::isInitialized() const {
  return _clazz.get() != NULL;
}

const char* ClassWrapper::getSimpleName() const {
  const char* lastSlash = strrchr(getCanonicalName(), '/');
  return lastSlash != NULL ? lastSlash + 1 : getCanonicalName();
}

void ClassWrapper::merge(const ClassWrapper *globalInstance) {
  _clazz = globalInstance->_clazz;
  _methods = globalInstance->_methods;
  _fields = globalInstance->_fields;
  _constructor = globalInstance->_constructor;
}

bool ClassWrapper::persist(JNIEnv *env, jobject javaThis) {
  if (isPersisted()) {
    if (javaThis == NULL) {
      JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalArgumentException,
        "Cannot persist object without corresponding Java instance");
      return false;
    }
    jlong resultPtr = reinterpret_cast<jlong>(this);
    env->SetLongField(javaThis, getField(PERSIST_FIELD_NAME), resultPtr);
    return true;
  }
  return false;
}

bool ClassWrapper::isPersisted() const {
  // TODO: Need test for this
  if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(JavaThreadUtils::getEnvForCurrentThread(),
      kTypeIllegalStateException,
      "Cannot call isPersisted without class info (forgot to merge?)");
    return false;
  }

  // We expect the persisted field to be cached, otherwise searching for persisted
  // fields in non-persisted classes will throw java.lang.NoSuchField exception. :(
  const std::string key(PERSIST_FIELD_NAME);
  FieldMap::const_iterator mapFindIter = _fields.find(key);
  return mapFindIter != _fields.end();
}

ClassWrapper* ClassWrapper::getPersistedInstance(JNIEnv *env, jobject javaThis) const {
  if (isPersisted()) {
    jlong resultPtr = env->GetLongField(javaThis, getField(PERSIST_FIELD_NAME));
    return reinterpret_cast<ClassWrapper*>(resultPtr);
  } else {
    return NULL;
  }
}

void ClassWrapper::destroy(JNIEnv *env, jobject javaThis) {
  if (isPersisted()) {
    if (javaThis == NULL) {
      JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalArgumentException,
        "Cannot destroy persisted object without corresponding Java instance");
      return;
    }

    jfieldID persistField = getField(PERSIST_FIELD_NAME);
    if (persistField == NULL) {
      JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalStateException,
        "Cannot destroy, object lacks persist field");
      return;
    }

    jlong resultPtr = env->GetLongField(javaThis, persistField);
    ClassWrapper *instance = reinterpret_cast<ClassWrapper*>(resultPtr);
    if (instance != NULL) {
      delete instance;
      env->SetLongField(javaThis, persistField, 0);
    }
  }
}

void ClassWrapper::setJavaObject(JNIEnv *env, jobject javaThis) {
  // Set up field mappings, if this has not already been done
  if (_field_mappings.empty()) {
    mapFields();
  }

  FieldMap::iterator iter;
  for (iter = _fields.begin(); iter != _fields.end(); ++iter) {
    std::string key = iter->first;
    jfieldID field = iter->second;
    FieldMapping *mapping = _field_mappings[key]; // TODO: Should use getter here, if not null will be inserted
    if (field != NULL && mapping != NULL) {
      if (TYPE_EQUALS(mapping->type, kTypeInt)) {
        int *address = static_cast<int*>(mapping->address);
        *address = env->GetIntField(javaThis, field);
      } else if (TYPE_EQUALS(mapping->type, kTypeShort)) {
        short *address = static_cast<short*>(mapping->address);
        *address = env->GetShortField(javaThis, field);
      } else if (TYPE_EQUALS(mapping->type, kTypeBool)) {
        bool *address = static_cast<bool*>(mapping->address);
        *address = env->GetBooleanField(javaThis, field);
      } else if (TYPE_EQUALS(mapping->type, kTypeFloat)) {
        float *address = static_cast<float*>(mapping->address);
        *address = env->GetFloatField(javaThis, field);
      } else if (TYPE_EQUALS(mapping->type, kTypeDouble)) {
        double *address = static_cast<double*>(mapping->address);
        *address = env->GetDoubleField(javaThis, field);
      } else if (TYPE_EQUALS(mapping->type, kTypeString)) {
        jstring string = (jstring)env->GetObjectField(javaThis, field);
        JavaString *address = static_cast<JavaString*>(mapping->address);
        address->setValue(env, string);
      } else if (TYPE_EQUALS(mapping->type, kTypeByte)) {
        unsigned char *address = static_cast<unsigned char*>(mapping->address);
        *address = env->GetByteField(javaThis, field);
      } else if (TYPE_EQUALS(mapping->type, kTypeChar)) {
        wchar_t *address = static_cast<wchar_t*>(mapping->address);
        *address = env->GetCharField(javaThis, field);
      } else {
        // TODO throw
      }
    }
  }
}

jobject ClassWrapper::toJavaObject(JNIEnv *env) {
  if (_constructor == NULL) {
    JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalStateException,
      "Cannot call toJavaObject without a constructor");
    return NULL;
  } else if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalStateException,
      "Cannot call toJavaObject without registering class info");
    return NULL;
  }

  // Set up field mappings, if this has not already been done
  if (_field_mappings.empty()) {
    mapFields();
  }

  // Create a new Java argument with the default constructor
  // TODO: It would be nice to remove the requirement for a no-arg ctor
  // However, I'm not really sure how to do that without cluttering the interface.
  // Maybe provide an extra argument to setClass()? However, then we would lack
  // the corresponding arguments we'd want to pass in here.
  JniWeakGlobalRef<jobject> result;
  result.set(env->NewObject(_clazz.get(), _constructor));

  FieldMap::iterator iter;
  for (iter = _fields.begin(); iter != _fields.end(); ++iter) {
    std::string key = iter->first;
    jfieldID field = iter->second;
    FieldMapping *mapping = getFieldMapping(key.c_str());
    if (field != NULL && mapping != NULL) {
      if (TYPE_EQUALS(mapping->type, kTypeInt)) {
        int *address = static_cast<int*>(mapping->address);
        env->SetIntField(result, field, *address);
      } else if (TYPE_EQUALS(mapping->type, kTypeShort)) {
        short *address = static_cast<short*>(mapping->address);
        env->SetShortField(result, field, *address);
      } else if (TYPE_EQUALS(mapping->type, kTypeBool)) {
        bool *address = static_cast<bool*>(mapping->address);
        env->SetBooleanField(result, field, *address);
      } else if (TYPE_EQUALS(mapping->type, kTypeFloat)) {
        float *address = static_cast<float*>(mapping->address);
        env->SetFloatField(result, field, *address);
      } else if (TYPE_EQUALS(mapping->type, kTypeDouble)) {
        double *address = static_cast<double*>(mapping->address);
        env->SetDoubleField(result, field, *address);
      } else if (TYPE_EQUALS(mapping->type, kTypeString)) {
        JavaString *address = static_cast<JavaString*>(mapping->address);
        JniLocalRef<jstring> string = address->getJavaString(env);
        env->SetObjectField(result, field, string.get());
      } else if (TYPE_EQUALS(mapping->type, kTypeByte)) {
        unsigned char *address = static_cast<unsigned char*>(mapping->address);
        env->SetByteField(result, field, *address);
      } else if (TYPE_EQUALS(mapping->type, kTypeChar)) {
        wchar_t *address = static_cast<wchar_t*>(mapping->address);
        env->SetCharField(result, field, *address);
      } else {
        // TODO throw
      }
    }
  }

  // Persist the current object address to the Java instance
  persist(env, result);
  return result.leak();
}

JniGlobalRef<jclass> ClassWrapper::getClass() const {
  return _clazz;
}

jmethodID ClassWrapper::getMethod(const char *method_name) const {
  if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(JavaThreadUtils::getEnvForCurrentThread(),
      kTypeIllegalStateException,
      "Cannot call getMethod without class info (forgot to merge?)");
    return NULL;
  }

  const std::string key(method_name);
  MethodMap::const_iterator mapFindIter = _methods.find(key);
  if (mapFindIter == _methods.end()) {
    JavaExceptionUtils::throwExceptionOfType(JavaThreadUtils::getEnvForCurrentThread(),
      kTypeIllegalArgumentException,
      "Method '%s' is not cached in class '%s'", method_name, getCanonicalName());
    return NULL;
  }

  return mapFindIter->second;
}

jfieldID ClassWrapper::getField(const char* field_name) const {
  if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(JavaThreadUtils::getEnvForCurrentThread(),
      kTypeIllegalStateException,
      "Cannot call getField without class info (forgot to merge?)");
    return NULL;
  }

  const std::string key(field_name);
  FieldMap::const_iterator mapFindIter = _fields.find(key);
  if (mapFindIter == _fields.end()) {
    JavaExceptionUtils::throwExceptionOfType(JavaThreadUtils::getEnvForCurrentThread(),
      kTypeIllegalArgumentException,
      "Field '%s' is not cached in class '%s'", field_name, getCanonicalName());
    return NULL;
  }

  return mapFindIter->second;
}

void ClassWrapper::setClass(JNIEnv *env) {
  _clazz.set(env->FindClass(getCanonicalName()));
  JavaExceptionUtils::checkException(env);
  std::string signature;
  JavaClassUtils::makeSignature(signature, kTypeVoid, NULL);
  _constructor = env->GetMethodID(_clazz.get(), "<init>", signature.c_str());
}

void ClassWrapper::cacheMethod(JNIEnv *env, const char* method_name, const char* return_type, ...) {
  if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalStateException,
      "Attempt to call cacheMethod without having set class info");
    return;
  }

  va_list arguments;
  va_start(arguments, return_type);
  std::string signature;
  JavaClassUtils::makeSignatureWithList(signature, return_type, arguments);
  va_end(arguments);

  jmethodID method = env->GetMethodID(_clazz.get(), method_name, signature.c_str());
  JavaExceptionUtils::checkException(env);
  if (method != NULL) {
    _methods[method_name] = method;
  }
}

void ClassWrapper::cacheField(JNIEnv *env, const char *field_name, const char *field_type) {
  if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalStateException,
      "Attempt to call cacheField without having set class info");
    return;
  }

  jfieldID field = env->GetFieldID(_clazz.get(), field_name, field_type);
  JavaExceptionUtils::checkException(env);
  if (field != NULL) {
    _fields[field_name] = field;
  }
}

void ClassWrapper::mapField(const char *field_name, const char *field_type, void *field_ptr) {
  FieldMapping *mapping = new FieldMapping;
  mapping->type = field_type;
  mapping->address = field_ptr;
  _field_mappings[field_name] = mapping;
}

FieldMapping* ClassWrapper::getFieldMapping(const char *key) const {
  std::string keyString(key);
  std::map<std::string, FieldMapping*>::const_iterator findMapIter = _field_mappings.find(keyString);
  return findMapIter != _field_mappings.end() ? findMapIter->second : NULL;
}

void ClassWrapper::addNativeMethod(const char *method_name, void *function, const char *return_type, ...) {
  JNINativeMethod nativeMethod;
  nativeMethod.name = const_cast<char*>(method_name);
  nativeMethod.fnPtr = function;

  va_list arguments;
  va_start(arguments, return_type);
  std::string signature;
  JavaClassUtils::makeSignatureWithList(signature, return_type, arguments);
  nativeMethod.signature = const_cast<char*>(strdup(signature.c_str()));
  va_end(arguments);

  _jni_methods.push_back(nativeMethod);
}

bool ClassWrapper::registerNativeMethods(JNIEnv *env) {
  if (_jni_methods.empty()) {
    return false;
  }

  if (!isInitialized()) {
    JavaExceptionUtils::throwRuntimeException(env, "Could not find cached class for %s", getCanonicalName());
    return false;
  }

  return (env->RegisterNatives(_clazz.get(), &_jni_methods[0], (jint)_jni_methods.size()) < 0);
}

} // namespace jni
} // namespace spotify
<commit_msg>Fix memory leak<commit_after>#include "ClassWrapper.h"
#include "JavaClassUtils.h"
#include "JavaExceptionUtils.h"
#include "JniWeakGlobalRef.h"
#include <string.h>

namespace spotify {
namespace jni {

ClassWrapper::~ClassWrapper() {
  // TODO: Delete mappings
}

bool ClassWrapper::isInitialized() const {
  return _clazz.get() != NULL;
}

const char* ClassWrapper::getSimpleName() const {
  const char* lastSlash = strrchr(getCanonicalName(), '/');
  return lastSlash != NULL ? lastSlash + 1 : getCanonicalName();
}

void ClassWrapper::merge(const ClassWrapper *globalInstance) {
  _clazz = globalInstance->_clazz;
  _methods = globalInstance->_methods;
  _fields = globalInstance->_fields;
  _constructor = globalInstance->_constructor;
}

bool ClassWrapper::persist(JNIEnv *env, jobject javaThis) {
  if (isPersisted()) {
    if (javaThis == NULL) {
      JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalArgumentException,
        "Cannot persist object without corresponding Java instance");
      return false;
    }
    jlong resultPtr = reinterpret_cast<jlong>(this);
    env->SetLongField(javaThis, getField(PERSIST_FIELD_NAME), resultPtr);
    return true;
  }
  return false;
}

bool ClassWrapper::isPersisted() const {
  // TODO: Need test for this
  if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(JavaThreadUtils::getEnvForCurrentThread(),
      kTypeIllegalStateException,
      "Cannot call isPersisted without class info (forgot to merge?)");
    return false;
  }

  // We expect the persisted field to be cached, otherwise searching for persisted
  // fields in non-persisted classes will throw java.lang.NoSuchField exception. :(
  const std::string key(PERSIST_FIELD_NAME);
  FieldMap::const_iterator mapFindIter = _fields.find(key);
  return mapFindIter != _fields.end();
}

ClassWrapper* ClassWrapper::getPersistedInstance(JNIEnv *env, jobject javaThis) const {
  if (isPersisted()) {
    jlong resultPtr = env->GetLongField(javaThis, getField(PERSIST_FIELD_NAME));
    return reinterpret_cast<ClassWrapper*>(resultPtr);
  } else {
    return NULL;
  }
}

void ClassWrapper::destroy(JNIEnv *env, jobject javaThis) {
  if (isPersisted()) {
    if (javaThis == NULL) {
      JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalArgumentException,
        "Cannot destroy persisted object without corresponding Java instance");
      return;
    }

    jfieldID persistField = getField(PERSIST_FIELD_NAME);
    if (persistField == NULL) {
      JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalStateException,
        "Cannot destroy, object lacks persist field");
      return;
    }

    jlong resultPtr = env->GetLongField(javaThis, persistField);
    ClassWrapper *instance = reinterpret_cast<ClassWrapper*>(resultPtr);
    if (instance != NULL) {
      delete instance;
      env->SetLongField(javaThis, persistField, 0);
    }
  }
}

void ClassWrapper::setJavaObject(JNIEnv *env, jobject javaThis) {
  // Set up field mappings, if this has not already been done
  if (_field_mappings.empty()) {
    mapFields();
  }

  FieldMap::iterator iter;
  for (iter = _fields.begin(); iter != _fields.end(); ++iter) {
    std::string key = iter->first;
    jfieldID field = iter->second;
    FieldMapping *mapping = _field_mappings[key]; // TODO: Should use getter here, if not null will be inserted
    if (field != NULL && mapping != NULL) {
      if (TYPE_EQUALS(mapping->type, kTypeInt)) {
        int *address = static_cast<int*>(mapping->address);
        *address = env->GetIntField(javaThis, field);
      } else if (TYPE_EQUALS(mapping->type, kTypeShort)) {
        short *address = static_cast<short*>(mapping->address);
        *address = env->GetShortField(javaThis, field);
      } else if (TYPE_EQUALS(mapping->type, kTypeBool)) {
        bool *address = static_cast<bool*>(mapping->address);
        *address = env->GetBooleanField(javaThis, field);
      } else if (TYPE_EQUALS(mapping->type, kTypeFloat)) {
        float *address = static_cast<float*>(mapping->address);
        *address = env->GetFloatField(javaThis, field);
      } else if (TYPE_EQUALS(mapping->type, kTypeDouble)) {
        double *address = static_cast<double*>(mapping->address);
        *address = env->GetDoubleField(javaThis, field);
      } else if (TYPE_EQUALS(mapping->type, kTypeString)) {
        jstring string = (jstring)env->GetObjectField(javaThis, field);
        JavaString *address = static_cast<JavaString*>(mapping->address);
        address->setValue(env, string);
      } else if (TYPE_EQUALS(mapping->type, kTypeByte)) {
        unsigned char *address = static_cast<unsigned char*>(mapping->address);
        *address = env->GetByteField(javaThis, field);
      } else if (TYPE_EQUALS(mapping->type, kTypeChar)) {
        wchar_t *address = static_cast<wchar_t*>(mapping->address);
        *address = env->GetCharField(javaThis, field);
      } else {
        // TODO throw
      }
    }
  }
}

jobject ClassWrapper::toJavaObject(JNIEnv *env) {
  if (_constructor == NULL) {
    JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalStateException,
      "Cannot call toJavaObject without a constructor");
    return NULL;
  } else if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalStateException,
      "Cannot call toJavaObject without registering class info");
    return NULL;
  }

  // Set up field mappings, if this has not already been done
  if (_field_mappings.empty()) {
    mapFields();
  }

  // Create a new Java argument with the default constructor
  // TODO: It would be nice to remove the requirement for a no-arg ctor
  // However, I'm not really sure how to do that without cluttering the interface.
  // Maybe provide an extra argument to setClass()? However, then we would lack
  // the corresponding arguments we'd want to pass in here.
  JniLocalRef<jobject> result;
  result.set(env->NewObject(_clazz.get(), _constructor));

  FieldMap::iterator iter;
  for (iter = _fields.begin(); iter != _fields.end(); ++iter) {
    std::string key = iter->first;
    jfieldID field = iter->second;
    FieldMapping *mapping = getFieldMapping(key.c_str());
    if (field != NULL && mapping != NULL) {
      if (TYPE_EQUALS(mapping->type, kTypeInt)) {
        int *address = static_cast<int*>(mapping->address);
        env->SetIntField(result, field, *address);
      } else if (TYPE_EQUALS(mapping->type, kTypeShort)) {
        short *address = static_cast<short*>(mapping->address);
        env->SetShortField(result, field, *address);
      } else if (TYPE_EQUALS(mapping->type, kTypeBool)) {
        bool *address = static_cast<bool*>(mapping->address);
        env->SetBooleanField(result, field, *address);
      } else if (TYPE_EQUALS(mapping->type, kTypeFloat)) {
        float *address = static_cast<float*>(mapping->address);
        env->SetFloatField(result, field, *address);
      } else if (TYPE_EQUALS(mapping->type, kTypeDouble)) {
        double *address = static_cast<double*>(mapping->address);
        env->SetDoubleField(result, field, *address);
      } else if (TYPE_EQUALS(mapping->type, kTypeString)) {
        JavaString *address = static_cast<JavaString*>(mapping->address);
        JniLocalRef<jstring> string = address->getJavaString(env);
        env->SetObjectField(result, field, string.get());
      } else if (TYPE_EQUALS(mapping->type, kTypeByte)) {
        unsigned char *address = static_cast<unsigned char*>(mapping->address);
        env->SetByteField(result, field, *address);
      } else if (TYPE_EQUALS(mapping->type, kTypeChar)) {
        wchar_t *address = static_cast<wchar_t*>(mapping->address);
        env->SetCharField(result, field, *address);
      } else {
        // TODO throw
      }
    }
  }

  // Persist the current object address to the Java instance
  persist(env, result);
  return result.leak();
}

JniGlobalRef<jclass> ClassWrapper::getClass() const {
  return _clazz;
}

jmethodID ClassWrapper::getMethod(const char *method_name) const {
  if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(JavaThreadUtils::getEnvForCurrentThread(),
      kTypeIllegalStateException,
      "Cannot call getMethod without class info (forgot to merge?)");
    return NULL;
  }

  const std::string key(method_name);
  MethodMap::const_iterator mapFindIter = _methods.find(key);
  if (mapFindIter == _methods.end()) {
    JavaExceptionUtils::throwExceptionOfType(JavaThreadUtils::getEnvForCurrentThread(),
      kTypeIllegalArgumentException,
      "Method '%s' is not cached in class '%s'", method_name, getCanonicalName());
    return NULL;
  }

  return mapFindIter->second;
}

jfieldID ClassWrapper::getField(const char* field_name) const {
  if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(JavaThreadUtils::getEnvForCurrentThread(),
      kTypeIllegalStateException,
      "Cannot call getField without class info (forgot to merge?)");
    return NULL;
  }

  const std::string key(field_name);
  FieldMap::const_iterator mapFindIter = _fields.find(key);
  if (mapFindIter == _fields.end()) {
    JavaExceptionUtils::throwExceptionOfType(JavaThreadUtils::getEnvForCurrentThread(),
      kTypeIllegalArgumentException,
      "Field '%s' is not cached in class '%s'", field_name, getCanonicalName());
    return NULL;
  }

  return mapFindIter->second;
}

void ClassWrapper::setClass(JNIEnv *env) {
  _clazz.set(env->FindClass(getCanonicalName()));
  JavaExceptionUtils::checkException(env);
  std::string signature;
  JavaClassUtils::makeSignature(signature, kTypeVoid, NULL);
  _constructor = env->GetMethodID(_clazz.get(), "<init>", signature.c_str());
}

void ClassWrapper::cacheMethod(JNIEnv *env, const char* method_name, const char* return_type, ...) {
  if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalStateException,
      "Attempt to call cacheMethod without having set class info");
    return;
  }

  va_list arguments;
  va_start(arguments, return_type);
  std::string signature;
  JavaClassUtils::makeSignatureWithList(signature, return_type, arguments);
  va_end(arguments);

  jmethodID method = env->GetMethodID(_clazz.get(), method_name, signature.c_str());
  JavaExceptionUtils::checkException(env);
  if (method != NULL) {
    _methods[method_name] = method;
  }
}

void ClassWrapper::cacheField(JNIEnv *env, const char *field_name, const char *field_type) {
  if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalStateException,
      "Attempt to call cacheField without having set class info");
    return;
  }

  jfieldID field = env->GetFieldID(_clazz.get(), field_name, field_type);
  JavaExceptionUtils::checkException(env);
  if (field != NULL) {
    _fields[field_name] = field;
  }
}

void ClassWrapper::mapField(const char *field_name, const char *field_type, void *field_ptr) {
  FieldMapping *mapping = new FieldMapping;
  mapping->type = field_type;
  mapping->address = field_ptr;
  _field_mappings[field_name] = mapping;
}

FieldMapping* ClassWrapper::getFieldMapping(const char *key) const {
  std::string keyString(key);
  std::map<std::string, FieldMapping*>::const_iterator findMapIter = _field_mappings.find(keyString);
  return findMapIter != _field_mappings.end() ? findMapIter->second : NULL;
}

void ClassWrapper::addNativeMethod(const char *method_name, void *function, const char *return_type, ...) {
  JNINativeMethod nativeMethod;
  nativeMethod.name = const_cast<char*>(method_name);
  nativeMethod.fnPtr = function;

  va_list arguments;
  va_start(arguments, return_type);
  std::string signature;
  JavaClassUtils::makeSignatureWithList(signature, return_type, arguments);
  nativeMethod.signature = const_cast<char*>(strdup(signature.c_str()));
  va_end(arguments);

  _jni_methods.push_back(nativeMethod);
}

bool ClassWrapper::registerNativeMethods(JNIEnv *env) {
  if (_jni_methods.empty()) {
    return false;
  }

  if (!isInitialized()) {
    JavaExceptionUtils::throwRuntimeException(env, "Could not find cached class for %s", getCanonicalName());
    return false;
  }

  return (env->RegisterNatives(_clazz.get(), &_jni_methods[0], (jint)_jni_methods.size()) < 0);
}

} // namespace jni
} // namespace spotify
<|endoftext|>


<commit_before>/*
    This file is part of KAddressbook.
    Copyright (c) 2004 Tobias Koenig <tokoe@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <qcheckbox.h>
#include <qcombobox.h>
#include <qdatetimeedit.h>
#include <qlayout.h>
#include <qobjectlist.h>
#include <qspinbox.h>
#include <qwidgetfactory.h>

#include <kdatepicker.h>
#include <kdatetimewidget.h>
#include <kdialog.h>
#include <klineedit.h>
#include <kstandarddirs.h>

#include "advancedcustomfields.h"

static void splitField( const QString&, QString&, QString&, QString& );

AdvancedCustomFields::AdvancedCustomFields( const QString &uiFile, KABC::AddressBook *ab,
                                            QWidget *parent, const char *name )
  : KAB::ContactEditorWidget( ab, parent, name )
{
  initGUI( uiFile );
}

void AdvancedCustomFields::loadContact( KABC::Addressee *addr )
{
  QStringList customs = addr->customs();

  QStringList::ConstIterator it;
  for ( it = customs.begin(); it != customs.end(); ++it ) {
    QString app, name, value;
    splitField( *it, app, name, value );

    if ( app == "KADDRESSBOOK" ) {
      QMap<QString, QWidget*>::Iterator it = mWidgets.find( name );
      if ( it != mWidgets.end() ) {
        if ( it.data()->isA( "QLineEdit" ) || it.data()->isA( "KLineEdit" ) ) {
          QLineEdit *wdg = static_cast<QLineEdit*>( it.data() );
          wdg->setText( value );
        } else if ( it.data()->isA( "QSpinBox" ) ) {
          QSpinBox *wdg = static_cast<QSpinBox*>( it.data() );
          wdg->setValue( value.toInt() );
        } else if ( it.data()->isA( "QCheckBox" ) ) {
          QCheckBox *wdg = static_cast<QCheckBox*>( it.data() );
          wdg->setChecked( value == "true" || value == "1" );
        } else if ( it.data()->isA( "QDateTimeEdit" ) ) {
          QDateTimeEdit *wdg = static_cast<QDateTimeEdit*>( it.data() );
          wdg->setDateTime( QDateTime::fromString( value, Qt::ISODate ) );
        } else if ( it.data()->isA( "KDateTimeWidget" ) ) {
          KDateTimeWidget *wdg = static_cast<KDateTimeWidget*>( it.data() );
          wdg->setDateTime( QDateTime::fromString( value, Qt::ISODate ) );
        } else if ( it.data()->isA( "KDatePicker" ) ) {
          KDatePicker *wdg = static_cast<KDatePicker*>( it.data() );
          wdg->setDate( QDate::fromString( value, Qt::ISODate ) );
        } else if ( it.data()->isA( "QComboBox" ) ) {
          QComboBox *wdg = static_cast<QComboBox*>( it.data() );
          wdg->setCurrentText( value );
        }
      }
    }
  }
}

void AdvancedCustomFields::storeContact( KABC::Addressee *addr )
{
  QMap<QString, QWidget*>::Iterator it;
  for ( it = mWidgets.begin(); it != mWidgets.end(); ++it ) {
    QString value;
    if ( it.data()->isA( "QLineEdit" ) || it.data()->isA( "KLineEdit" ) ) {
      QLineEdit *wdg = static_cast<QLineEdit*>( it.data() );
      value = wdg->text();
    } else if ( it.data()->isA( "QSpinBox" ) ) {
      QSpinBox *wdg = static_cast<QSpinBox*>( it.data() );
      value = QString::number( wdg->value() );
    } else if ( it.data()->isA( "QCheckBox" ) ) {
      QCheckBox *wdg = static_cast<QCheckBox*>( it.data() );
      value = ( wdg->isChecked() ? "true" : "false" );
    } else if ( it.data()->isA( "QDateTimeEdit" ) ) {
      QDateTimeEdit *wdg = static_cast<QDateTimeEdit*>( it.data() );
      value = wdg->dateTime().toString( Qt::ISODate );
    } else if ( it.data()->isA( "KDateTimeWidget" ) ) {
      KDateTimeWidget *wdg = static_cast<KDateTimeWidget*>( it.data() );
      value = wdg->dateTime().toString( Qt::ISODate );
    } else if ( it.data()->isA( "KDatePicker" ) ) {
      KDatePicker *wdg = static_cast<KDatePicker*>( it.data() );
      value = wdg->date().toString( Qt::ISODate );
    } else if ( it.data()->isA( "QComboBox" ) ) {
      QComboBox *wdg = static_cast<QComboBox*>( it.data() );
      value = wdg->currentText();
    }

    addr->insertCustom( "KADDRESSBOOK", it.key(), value );
  }
}

void AdvancedCustomFields::setReadOnly( bool readOnly )
{
  QMap<QString, QWidget*>::Iterator it;
  for ( it = mWidgets.begin(); it != mWidgets.end(); ++it )
    it.data()->setEnabled( !readOnly );
}

void AdvancedCustomFields::initGUI( const QString &uiFile )
{
  QVBoxLayout *layout = new QVBoxLayout( this, KDialog::marginHint(),
                                         KDialog::spacingHint() );

  QWidget *wdg = QWidgetFactory::create( uiFile, 0, this );
  if ( !wdg ) {
    kdError() << "No ui file found" << endl;
    return;
  }

  mTitle = wdg->caption();
  mIdentifier = wdg->name();

  layout->addWidget( wdg );

  QObjectList *list = wdg->queryList( "QWidget" );
  QObjectListIt it( *list );

  QStringList allowedTypes;
  allowedTypes << "QLineEdit"
               << "QSpinBox"
               << "QCheckBox"
               << "QComboBox"
               << "QDateTimeEdit"
               << "KLineEdit"
               << "KDateTimeWidget"
               << "KDatePicker";

  while ( it.current() ) {
    if ( allowedTypes.contains( it.current()->className() ) ) {
      QString name = it.current()->name();
      if ( name.startsWith( "X_" ) ) {
        name = name.mid( 2 );
        if ( !name.isEmpty() )
          mWidgets.insert( name, static_cast<QWidget*>( it.current() ) );

        if ( it.current()->isA( "QLineEdit" ) ||
             it.current()->isA( "KLineEdit" ) )
          connect( it.current(), SIGNAL( textChanged( const QString& ) ),
                   this, SIGNAL( changed() ) );
        else if ( it.current()->isA( "QSpinBox" ) )
          connect( it.current(), SIGNAL( valueChanged( int ) ),
                   this, SIGNAL( changed() ) );
        else if ( it.current()->isA( "QCheckBox" ) )
          connect( it.current(), SIGNAL( toggled( bool ) ),
                   this, SIGNAL( changed() ) );
        else if ( it.current()->isA( "QComboBox" ) )
          connect( it.current(), SIGNAL( activated( const QString& ) ),
                   this, SIGNAL( changed() ) );
        else if ( it.current()->isA( "QDateTimeEdit" ) )
          connect( it.current(), SIGNAL( valueChanged( const QDateTime& ) ),
                   this, SIGNAL( changed() ) );
        else if ( it.current()->isA( "KDateTimeWidget" ) )
          connect( it.current(), SIGNAL( valueChanged( const QDateTime& ) ),
                   this, SIGNAL( changed() ) );
        else if ( it.current()->isA( "KDatePicker" ) )
          connect( it.current(), SIGNAL( dateChanged( QDate ) ),
                   this, SIGNAL( changed() ) );
      }
    }

    ++it;
  }
}

QString AdvancedCustomFields::pageIdentifier() const
{
  return mIdentifier;
}

QString AdvancedCustomFields::pageTitle() const
{
  return mTitle;
}

static void splitField( const QString &str, QString &app, QString &name, QString &value )
{
  int colon = str.find( ':' );
  if ( colon != -1 ) {
    QString tmp = str.left( colon );
    value = str.mid( colon + 1 );

    int dash = tmp.find( '-' );
    if ( dash != -1 ) {
      app = tmp.left( dash );
      name = tmp.mid( dash + 1 );
    }
  }
}

#include "advancedcustomfields.moc"
<commit_msg>Remove an rmpty item from the address book<commit_after>/*
    This file is part of KAddressbook.
    Copyright (c) 2004 Tobias Koenig <tokoe@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <qcheckbox.h>
#include <qcombobox.h>
#include <qdatetimeedit.h>
#include <qlayout.h>
#include <qobjectlist.h>
#include <qspinbox.h>
#include <qwidgetfactory.h>

#include <kdatepicker.h>
#include <kdatetimewidget.h>
#include <kdialog.h>
#include <klineedit.h>
#include <kstandarddirs.h>

#include "advancedcustomfields.h"

static void splitField( const QString&, QString&, QString&, QString& );

AdvancedCustomFields::AdvancedCustomFields( const QString &uiFile, KABC::AddressBook *ab,
                                            QWidget *parent, const char *name )
  : KAB::ContactEditorWidget( ab, parent, name )
{
  initGUI( uiFile );
}

void AdvancedCustomFields::loadContact( KABC::Addressee *addr )
{
  QStringList customs = addr->customs();

  QStringList::ConstIterator it;
  for ( it = customs.begin(); it != customs.end(); ++it ) {
    QString app, name, value;
    splitField( *it, app, name, value );

    if ( app == "KADDRESSBOOK" ) {
      QMap<QString, QWidget*>::Iterator it = mWidgets.find( name );
      if ( it != mWidgets.end() ) {
        if ( it.data()->isA( "QLineEdit" ) || it.data()->isA( "KLineEdit" ) ) {
          QLineEdit *wdg = static_cast<QLineEdit*>( it.data() );
          wdg->setText( value );
        } else if ( it.data()->isA( "QSpinBox" ) ) {
          QSpinBox *wdg = static_cast<QSpinBox*>( it.data() );
          wdg->setValue( value.toInt() );
        } else if ( it.data()->isA( "QCheckBox" ) ) {
          QCheckBox *wdg = static_cast<QCheckBox*>( it.data() );
          wdg->setChecked( value == "true" || value == "1" );
        } else if ( it.data()->isA( "QDateTimeEdit" ) ) {
          QDateTimeEdit *wdg = static_cast<QDateTimeEdit*>( it.data() );
          wdg->setDateTime( QDateTime::fromString( value, Qt::ISODate ) );
        } else if ( it.data()->isA( "KDateTimeWidget" ) ) {
          KDateTimeWidget *wdg = static_cast<KDateTimeWidget*>( it.data() );
          wdg->setDateTime( QDateTime::fromString( value, Qt::ISODate ) );
        } else if ( it.data()->isA( "KDatePicker" ) ) {
          KDatePicker *wdg = static_cast<KDatePicker*>( it.data() );
          wdg->setDate( QDate::fromString( value, Qt::ISODate ) );
        } else if ( it.data()->isA( "QComboBox" ) ) {
          QComboBox *wdg = static_cast<QComboBox*>( it.data() );
          wdg->setCurrentText( value );
        }
      }
    }
  }
}

void AdvancedCustomFields::storeContact( KABC::Addressee *addr )
{
  QMap<QString, QWidget*>::Iterator it;
  for ( it = mWidgets.begin(); it != mWidgets.end(); ++it ) {
    QString value;
    if ( it.data()->isA( "QLineEdit" ) || it.data()->isA( "KLineEdit" ) ) {
      QLineEdit *wdg = static_cast<QLineEdit*>( it.data() );
      value = wdg->text();
    } else if ( it.data()->isA( "QSpinBox" ) ) {
      QSpinBox *wdg = static_cast<QSpinBox*>( it.data() );
      value = QString::number( wdg->value() );
    } else if ( it.data()->isA( "QCheckBox" ) ) {
      QCheckBox *wdg = static_cast<QCheckBox*>( it.data() );
      value = ( wdg->isChecked() ? "true" : "false" );
    } else if ( it.data()->isA( "QDateTimeEdit" ) ) {
      QDateTimeEdit *wdg = static_cast<QDateTimeEdit*>( it.data() );
      value = wdg->dateTime().toString( Qt::ISODate );
    } else if ( it.data()->isA( "KDateTimeWidget" ) ) {
      KDateTimeWidget *wdg = static_cast<KDateTimeWidget*>( it.data() );
      value = wdg->dateTime().toString( Qt::ISODate );
    } else if ( it.data()->isA( "KDatePicker" ) ) {
      KDatePicker *wdg = static_cast<KDatePicker*>( it.data() );
      value = wdg->date().toString( Qt::ISODate );
    } else if ( it.data()->isA( "QComboBox" ) ) {
      QComboBox *wdg = static_cast<QComboBox*>( it.data() );
      value = wdg->currentText();
    }

    if ( value.isEmpty() )
      addr->removeCustom( "KADDRESSBOOK", it.key() );
    else
      addr->insertCustom( "KADDRESSBOOK", it.key(), value );
  }
}

void AdvancedCustomFields::setReadOnly( bool readOnly )
{
  QMap<QString, QWidget*>::Iterator it;
  for ( it = mWidgets.begin(); it != mWidgets.end(); ++it )
    it.data()->setEnabled( !readOnly );
}

void AdvancedCustomFields::initGUI( const QString &uiFile )
{
  QVBoxLayout *layout = new QVBoxLayout( this, KDialog::marginHint(),
                                         KDialog::spacingHint() );

  QWidget *wdg = QWidgetFactory::create( uiFile, 0, this );
  if ( !wdg ) {
    kdError() << "No ui file found" << endl;
    return;
  }

  mTitle = wdg->caption();
  mIdentifier = wdg->name();

  layout->addWidget( wdg );

  QObjectList *list = wdg->queryList( "QWidget" );
  QObjectListIt it( *list );

  QStringList allowedTypes;
  allowedTypes << "QLineEdit"
               << "QSpinBox"
               << "QCheckBox"
               << "QComboBox"
               << "QDateTimeEdit"
               << "KLineEdit"
               << "KDateTimeWidget"
               << "KDatePicker";

  while ( it.current() ) {
    if ( allowedTypes.contains( it.current()->className() ) ) {
      QString name = it.current()->name();
      if ( name.startsWith( "X_" ) ) {
        name = name.mid( 2 );
        if ( !name.isEmpty() )
          mWidgets.insert( name, static_cast<QWidget*>( it.current() ) );

        if ( it.current()->isA( "QLineEdit" ) ||
             it.current()->isA( "KLineEdit" ) )
          connect( it.current(), SIGNAL( textChanged( const QString& ) ),
                   this, SIGNAL( changed() ) );
        else if ( it.current()->isA( "QSpinBox" ) )
          connect( it.current(), SIGNAL( valueChanged( int ) ),
                   this, SIGNAL( changed() ) );
        else if ( it.current()->isA( "QCheckBox" ) )
          connect( it.current(), SIGNAL( toggled( bool ) ),
                   this, SIGNAL( changed() ) );
        else if ( it.current()->isA( "QComboBox" ) )
          connect( it.current(), SIGNAL( activated( const QString& ) ),
                   this, SIGNAL( changed() ) );
        else if ( it.current()->isA( "QDateTimeEdit" ) )
          connect( it.current(), SIGNAL( valueChanged( const QDateTime& ) ),
                   this, SIGNAL( changed() ) );
        else if ( it.current()->isA( "KDateTimeWidget" ) )
          connect( it.current(), SIGNAL( valueChanged( const QDateTime& ) ),
                   this, SIGNAL( changed() ) );
        else if ( it.current()->isA( "KDatePicker" ) )
          connect( it.current(), SIGNAL( dateChanged( QDate ) ),
                   this, SIGNAL( changed() ) );
      }
    }

    ++it;
  }
}

QString AdvancedCustomFields::pageIdentifier() const
{
  return mIdentifier;
}

QString AdvancedCustomFields::pageTitle() const
{
  return mTitle;
}

static void splitField( const QString &str, QString &app, QString &name, QString &value )
{
  int colon = str.find( ':' );
  if ( colon != -1 ) {
    QString tmp = str.left( colon );
    value = str.mid( colon + 1 );

    int dash = tmp.find( '-' );
    if ( dash != -1 ) {
      app = tmp.left( dash );
      name = tmp.mid( dash + 1 );
    }
  }
}

#include "advancedcustomfields.moc"
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    $RCSfile: NeighborhoodIterators6.cxx,v $
  Language:  C++
  Date:      $Date: 2005/02/08 03:59:00 $
  Version:   $Revision: 1.18 $

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif
#include "otbImage.h"
#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"
#include "itkRescaleIntensityImageFilter.h"
#include "itkNeighborhoodIterator.h"
#include "itkFastMarchingImageFilter.h"
#include "itkNumericTraits.h"
#include "itkRandomImageSource.h"
#include "itkAddImageFilter.h"

//  Software Guide : BeginCommandLineArgs
//    OUTPUTS: {NeighborhoodIterators6a.png}
//    100 100
//  Software Guide : EndCommandLineArgs

//  Software Guide : BeginCommandLineArgs
//    OUTPUTS: {NeighborhoodIterators6b.png}
//    50 150
//  Software Guide : EndCommandLineArgs

//  Software Guide : BeginCommandLineArgs
//    OUTPUTS: {NeighborhoodIterators6c.png}
//    150 50
//  Software Guide : EndCommandLineArgs

// Software Guide : BeginLatex
//
// Some image processing routines do not need to visit every pixel in an
// image. Flood-fill and connected-component algorithms, for example, only
// visit pixels that are locally connected to one another.  Algorithms
// such as these can be efficiently written using the random access
// capabilities of the neighborhood iterator.
//
// The following example finds local minima.  Given a seed point, we can search
// the neighborhood of that point and pick the smallest value $m$.  While $m$
// is not at the center of our current neighborhood, we move in the direction
// of $m$ and repeat the analysis.  Eventually we discover a local minimum and
// stop.  This algorithm is made trivially simple in ND using an ITK
// neighborhood iterator.
//
// To illustrate the process, we create an image that descends everywhere to a
// single minimum:  a positive distance transform to a point.  The details of
// creating the distance transform are not relevant to the discussion of
// neighborhood iterators, but can be found in the source code of this
// example. Some noise has been added to the distance transform image for
// additional interest.
//
// Software Guide : EndLatex

int main( int argc, char *argv[] )
{
  if ( argc < 4 )
    {
    std::cerr << "Missing parameters. " << std::endl;
    std::cerr << "Usage: " << std::endl;
    std::cerr << argv[0]
              << " outputImageFile startX startY"
              << std::endl;
    return -1;
    }

  typedef double PixelType;
  typedef otb::Image< PixelType, 2 > ImageType;
  typedef itk::NeighborhoodIterator< ImageType > NeighborhoodIteratorType;

  typedef itk::FastMarchingImageFilter<ImageType, ImageType>  FastMarchingFilterType;

  FastMarchingFilterType::Pointer fastMarching = FastMarchingFilterType::New();

  typedef FastMarchingFilterType::NodeContainer  NodeContainer;
  typedef FastMarchingFilterType::NodeType       NodeType;

  NodeContainer::Pointer seeds = NodeContainer::New();

  ImageType::IndexType  seedPosition;

  seedPosition[0] = 128;
  seedPosition[1] = 128;
  const double initialDistance = 1.0;

  NodeType node;

  const double seedValue = - initialDistance;

  ImageType::SizeType size = {{256, 256}};

  node.SetValue( seedValue );
  node.SetIndex( seedPosition );
  seeds->Initialize();
  seeds->InsertElement( 0, node );

  fastMarching->SetTrialPoints(  seeds  );
  fastMarching->SetSpeedConstant( 1.0 );

  itk::AddImageFilter<ImageType, ImageType, ImageType>::Pointer adder
    = itk::AddImageFilter<ImageType, ImageType, ImageType>::New();
  itk::RandomImageSource<ImageType>::Pointer noise
    = itk::RandomImageSource<ImageType>::New();

  noise->SetSize(size.m_Size);
  noise->SetMin(-.7);
  noise->SetMax(.8);
  adder->SetInput1(noise->GetOutput());
  adder->SetInput2(fastMarching->GetOutput());

  try
    {
    fastMarching->SetOutputSize( size );
    fastMarching->Update();

    adder->Update();

    }
  catch( itk::ExceptionObject & excep )
    {
    std::cerr << "Exception caught !" << std::endl;
    std::cerr << excep << std::endl;
    }

  ImageType::Pointer input = adder->GetOutput();

// Software Guide : BeginLatex
//
// The variable \code{input} is the pointer to the distance transform image.
// The local minimum algorithm is initialized with a seed point read from the
// command line.
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  ImageType::IndexType index;
  index[0] = ::atoi(argv[2]);
  index[1] = ::atoi(argv[3]);
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
// Next we create the neighborhood iterator and position it at the seed point.
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  NeighborhoodIteratorType::RadiusType radius;
  radius.Fill(1);
  NeighborhoodIteratorType it(radius, input, input->GetRequestedRegion());

  it.SetLocation(index);
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
// Searching for the local minimum involves finding the minimum in the current
// neighborhood, then shifting the neighborhood in the direction of that
// minimum.  The \code{for} loop below records the \doxygen{itk}{Offset} of the
// minimum neighborhood pixel.  The neighborhood iterator is then moved using
// that offset.  When a local minimum is detected, \code{flag} will remain
// false and the \code{while} loop will exit.  Note that this code is
// valid for an image of any dimensionality.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  bool flag = true;
  while ( flag == true )
    {
    NeighborhoodIteratorType::OffsetType nextMove;
    nextMove.Fill(0);

    flag = false;

    PixelType min = it.GetCenterPixel();
    for (unsigned i = 0; i < it.Size(); i++)
      {
      if ( it.GetPixel(i) < min )
        {
        min = it.GetPixel(i);
        nextMove = it.GetOffset(i);
        flag = true;
        }
      }
    it.SetCenterPixel( 255.0 );
    it += nextMove;
    }
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
// Figure~\ref{fig:NeighborhoodExample6} shows the results of the algorithm
// for several seed points.  The white line is the path of the iterator from
// the seed point to the minimum in the center of the image.  The effect of the
// additive noise is visible as the small perturbations in the paths.
//
// \begin{figure} \centering
// \includegraphics[width=0.3\textwidth]{NeighborhoodIterators6a.eps}
// \includegraphics[width=0.3\textwidth]{NeighborhoodIterators6b.eps}
// \includegraphics[width=0.3\textwidth]{NeighborhoodIterators6c.eps}
// \itkcaption[Finding local minima]{Paths traversed by the neighborhood
// iterator from different seed points to the local minimum.
// The true minimum is at the center
// of the image.  The path of the iterator is shown in white. The effect of
// noise in the image is seen as small perturbations in each path. }
// \protect\label{fig:NeighborhoodExample6} \end{figure}
//
// Software Guide : EndLatex

  typedef unsigned char WritePixelType;
  typedef otb::Image< WritePixelType, 2 > WriteImageType;
  typedef otb::ImageFileWriter< WriteImageType > WriterType;

  typedef itk::RescaleIntensityImageFilter< ImageType,
    WriteImageType > RescaleFilterType;

  RescaleFilterType::Pointer rescaler = RescaleFilterType::New();

  rescaler->SetOutputMinimum(   0 );
  rescaler->SetOutputMaximum( 255 );
  rescaler->SetInput( input );

  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName( argv[1] );
  writer->SetInput( rescaler->GetOutput() );
  try
    {
    writer->Update();
    }
  catch ( itk::ExceptionObject &err)
    {
    std::cout << "ExceptionObject caught !" << std::endl;
    std::cout << err << std::endl;
    return -1;
    }
  return 0;
}
<commit_msg>float ou double-> juste un pixel<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    $RCSfile: NeighborhoodIterators6.cxx,v $
  Language:  C++
  Date:      $Date: 2005/02/08 03:59:00 $
  Version:   $Revision: 1.18 $

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif
#include "otbImage.h"
#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"
#include "itkRescaleIntensityImageFilter.h"
#include "itkNeighborhoodIterator.h"
#include "itkFastMarchingImageFilter.h"
#include "itkNumericTraits.h"
#include "itkRandomImageSource.h"
#include "itkAddImageFilter.h"

//  Software Guide : BeginCommandLineArgs
//    OUTPUTS: {NeighborhoodIterators6a.png}
//    100 100
//  Software Guide : EndCommandLineArgs

//  Software Guide : BeginCommandLineArgs
//    OUTPUTS: {NeighborhoodIterators6b.png}
//    50 150
//  Software Guide : EndCommandLineArgs

//  Software Guide : BeginCommandLineArgs
//    OUTPUTS: {NeighborhoodIterators6c.png}
//    150 50
//  Software Guide : EndCommandLineArgs

// Software Guide : BeginLatex
//
// Some image processing routines do not need to visit every pixel in an
// image. Flood-fill and connected-component algorithms, for example, only
// visit pixels that are locally connected to one another.  Algorithms
// such as these can be efficiently written using the random access
// capabilities of the neighborhood iterator.
//
// The following example finds local minima.  Given a seed point, we can search
// the neighborhood of that point and pick the smallest value $m$.  While $m$
// is not at the center of our current neighborhood, we move in the direction
// of $m$ and repeat the analysis.  Eventually we discover a local minimum and
// stop.  This algorithm is made trivially simple in ND using an ITK
// neighborhood iterator.
//
// To illustrate the process, we create an image that descends everywhere to a
// single minimum:  a positive distance transform to a point.  The details of
// creating the distance transform are not relevant to the discussion of
// neighborhood iterators, but can be found in the source code of this
// example. Some noise has been added to the distance transform image for
// additional interest.
//
// Software Guide : EndLatex

int main( int argc, char *argv[] )
{
  if ( argc < 4 )
    {
    std::cerr << "Missing parameters. " << std::endl;
    std::cerr << "Usage: " << std::endl;
    std::cerr << argv[0]
              << " outputImageFile startX startY"
              << std::endl;
    return -1;
    }

  typedef float PixelType;
  typedef otb::Image< PixelType, 2 > ImageType;
  typedef itk::NeighborhoodIterator< ImageType > NeighborhoodIteratorType;

  typedef itk::FastMarchingImageFilter<ImageType, ImageType>  FastMarchingFilterType;

  FastMarchingFilterType::Pointer fastMarching = FastMarchingFilterType::New();

  typedef FastMarchingFilterType::NodeContainer  NodeContainer;
  typedef FastMarchingFilterType::NodeType       NodeType;

  NodeContainer::Pointer seeds = NodeContainer::New();

  ImageType::IndexType  seedPosition;

  seedPosition[0] = 128;
  seedPosition[1] = 128;
  const double initialDistance = 1.0;

  NodeType node;

  const double seedValue = - initialDistance;

  ImageType::SizeType size = {{256, 256}};

  node.SetValue( seedValue );
  node.SetIndex( seedPosition );
  seeds->Initialize();
  seeds->InsertElement( 0, node );

  fastMarching->SetTrialPoints(  seeds  );
  fastMarching->SetSpeedConstant( 1.0 );

  itk::AddImageFilter<ImageType, ImageType, ImageType>::Pointer adder
    = itk::AddImageFilter<ImageType, ImageType, ImageType>::New();
  itk::RandomImageSource<ImageType>::Pointer noise
    = itk::RandomImageSource<ImageType>::New();

  noise->SetSize(size.m_Size);
  noise->SetMin(-.7);
  noise->SetMax(.8);
  adder->SetInput1(noise->GetOutput());
  adder->SetInput2(fastMarching->GetOutput());

  try
    {
    fastMarching->SetOutputSize( size );
    fastMarching->Update();

    adder->Update();

    }
  catch( itk::ExceptionObject & excep )
    {
    std::cerr << "Exception caught !" << std::endl;
    std::cerr << excep << std::endl;
    }

  ImageType::Pointer input = adder->GetOutput();

// Software Guide : BeginLatex
//
// The variable \code{input} is the pointer to the distance transform image.
// The local minimum algorithm is initialized with a seed point read from the
// command line.
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  ImageType::IndexType index;
  index[0] = ::atoi(argv[2]);
  index[1] = ::atoi(argv[3]);
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
// Next we create the neighborhood iterator and position it at the seed point.
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  NeighborhoodIteratorType::RadiusType radius;
  radius.Fill(1);
  NeighborhoodIteratorType it(radius, input, input->GetRequestedRegion());

  it.SetLocation(index);
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
// Searching for the local minimum involves finding the minimum in the current
// neighborhood, then shifting the neighborhood in the direction of that
// minimum.  The \code{for} loop below records the \doxygen{itk}{Offset} of the
// minimum neighborhood pixel.  The neighborhood iterator is then moved using
// that offset.  When a local minimum is detected, \code{flag} will remain
// false and the \code{while} loop will exit.  Note that this code is
// valid for an image of any dimensionality.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
  bool flag = true;
  while ( flag == true )
    {
    NeighborhoodIteratorType::OffsetType nextMove;
    nextMove.Fill(0);

    flag = false;

    PixelType min = it.GetCenterPixel();
    for (unsigned i = 0; i < it.Size(); i++)
      {
      if ( it.GetPixel(i) < min )
        {
        min = it.GetPixel(i);
        nextMove = it.GetOffset(i);
        flag = true;
        }
      }
    it.SetCenterPixel( 255.0 );
    it += nextMove;
    }
// Software Guide : EndCodeSnippet

// Software Guide : BeginLatex
//
// Figure~\ref{fig:NeighborhoodExample6} shows the results of the algorithm
// for several seed points.  The white line is the path of the iterator from
// the seed point to the minimum in the center of the image.  The effect of the
// additive noise is visible as the small perturbations in the paths.
//
// \begin{figure} \centering
// \includegraphics[width=0.3\textwidth]{NeighborhoodIterators6a.eps}
// \includegraphics[width=0.3\textwidth]{NeighborhoodIterators6b.eps}
// \includegraphics[width=0.3\textwidth]{NeighborhoodIterators6c.eps}
// \itkcaption[Finding local minima]{Paths traversed by the neighborhood
// iterator from different seed points to the local minimum.
// The true minimum is at the center
// of the image.  The path of the iterator is shown in white. The effect of
// noise in the image is seen as small perturbations in each path. }
// \protect\label{fig:NeighborhoodExample6} \end{figure}
//
// Software Guide : EndLatex

  typedef unsigned char WritePixelType;
  typedef otb::Image< WritePixelType, 2 > WriteImageType;
  typedef otb::ImageFileWriter< WriteImageType > WriterType;

  typedef itk::RescaleIntensityImageFilter< ImageType,
    WriteImageType > RescaleFilterType;

  RescaleFilterType::Pointer rescaler = RescaleFilterType::New();

  rescaler->SetOutputMinimum(   0 );
  rescaler->SetOutputMaximum( 255 );
  rescaler->SetInput( input );

  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName( argv[1] );
  writer->SetInput( rescaler->GetOutput() );
  try
    {
    writer->Update();
    }
  catch ( itk::ExceptionObject &err)
    {
    std::cout << "ExceptionObject caught !" << std::endl;
    std::cout << err << std::endl;
    return -1;
    }
  return 0;
}
<|endoftext|>