<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2009 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/
/**
  \file    uvfUVFMetadata.cpp
  \author  Tom Fogal
           SCI Institute
           University of Utah
  \brief   UVF-specific implementation of metadata.
*/

#include <algorithm>
#include "uvfMetadata.h"

namespace tuvok {

UVFMetadata::UVFMetadata() :
  m_pVolumeDataBlock(NULL),
  m_pMaxMinData(NULL)
{
}

UVFMetadata::UVFMetadata(RasterDataBlock* pVolumeDataBlock,
                         MaxMinDataBlock* pMaxMinData, bool bIsSameEndianness):
  m_pVolumeDataBlock(pVolumeDataBlock),
  m_pMaxMinData(pMaxMinData),
  m_bIsSameEndianness(bIsSameEndianness)
{
  std::vector<double> vfScale;
  size_t iSize = m_pVolumeDataBlock->ulDomainSize.size();

  // we require the data to be at least 3D
  assert(iSize >= 3);

  // we also assume that x,y,z are in the first 3 components and
  // we have no anisotropy (i.e. ulLODLevelCount.size=1)
  m_iLODLevel = static_cast<size_t>(m_pVolumeDataBlock->ulLODLevelCount[0]);
  for (size_t i = 0;i<3;i++) {
    m_aOverlap[i] = m_pVolumeDataBlock->ulBrickOverlap[i];
    m_aMaxBrickSize[i] = m_pVolumeDataBlock->ulBrickSize[i];
    m_aScale[i] = m_pVolumeDataBlock->dDomainTransformation[i+(iSize+1)*i];
  }

  m_vvaBrickSize.resize(m_iLODLevel);
  if (m_pMaxMinData) m_vvaMaxMin.resize(m_iLODLevel);

  for (size_t j = 0;j<m_iLODLevel;j++) {
    std::vector<UINT64> vLOD;  vLOD.push_back(j);
    std::vector<UINT64> vDomSize = m_pVolumeDataBlock->GetLODDomainSize(vLOD);
    m_aDomainSize.push_back(UINT64VECTOR3(vDomSize[0], vDomSize[1],
                                          vDomSize[2]));

    std::vector<UINT64> vBrickCount = m_pVolumeDataBlock->GetBrickCount(vLOD);
    m_vaBrickCount.push_back(UINT64VECTOR3(vBrickCount[0], vBrickCount[1],
                                           vBrickCount[2]));

    m_vvaBrickSize[j].resize(m_vaBrickCount[j].x);
    if (m_pMaxMinData) {
      m_vvaMaxMin[j].resize(m_vaBrickCount[j].x);
    }
    for (UINT64 x=0; x < m_vaBrickCount[j].x; x++) {
      m_vvaBrickSize[j][x].resize(m_vaBrickCount[j].y);
      if (m_pMaxMinData) {
        m_vvaMaxMin[j][x].resize(m_vaBrickCount[j].y);
      }

      for (UINT64 y=0; y < m_vaBrickCount[j].y; y++) {
        if (m_pMaxMinData) {
          m_vvaMaxMin[j][x][y].resize(m_vaBrickCount[j].z);
        }

        for (UINT64 z=0; z < m_vaBrickCount[j].z; z++) {
          std::vector<UINT64> vBrick;
          vBrick.push_back(x);
          vBrick.push_back(y);
          vBrick.push_back(z);
          std::vector<UINT64> vBrickSize =
            m_pVolumeDataBlock->GetBrickSize(vLOD, vBrick);

          m_vvaBrickSize[j][x][y].push_back(UINT64VECTOR3(vBrickSize[0],
                                                          vBrickSize[1],
                                                          vBrickSize[2]));
        }
      }
    }
  }

  size_t iSerializedIndex = 0;
  if (m_pMaxMinData) {
    for (size_t lod=0; lod < m_iLODLevel; lod++) {
      for (UINT64 z=0; z < m_vaBrickCount[lod].z; z++) {
        for (UINT64 y=0; y < m_vaBrickCount[lod].y; y++) {
          for (UINT64 x=0; x < m_vaBrickCount[lod].x; x++) {
            // for four-component data we use the fourth component
            // (presumably the alpha channel); for all other data we use
            // the first component
            /// \todo we may have to change this if we add support for other
            /// kinds of multicomponent data.
            m_vvaMaxMin[lod][x][y][z] =
              m_pMaxMinData->GetValue(iSerializedIndex++,
                 (m_pVolumeDataBlock->ulElementDimensionSize[0] == 4) ? 3 : 0
              );
          }
        }
      }
    }
  }

  // Use a minimum of 3 elements, which ...
  size_t n_elems = std::max(static_cast<size_t>(3),
                            m_pVolumeDataBlock->ulDomainSemantics.size());
  std::vector<double> rescale(n_elems);
  for (size_t i=0; i < n_elems; i++) {
    rescale[i] = 1.0;
  }
  // ... allows us to assume we can deref the first 3 elements here.
  this->SetRescaleFactors(DOUBLEVECTOR3(rescale[0],rescale[1],rescale[2]));
}

// Return the number of bricks in the given LoD, along each axis.
UINT64VECTOR3 UVFMetadata::GetBrickCount(const UINT64 lod) const
{
  return m_vaBrickCount[lod];
}

// Size of the brick in logical space.
UINT64VECTOR3 UVFMetadata::GetBrickSize(const NDBrickKey &k) const
{
  const UINT64 lod = k.first[0];
  const size_t vBrick[3] = {
    static_cast<size_t>(k.second[0].x),
    static_cast<size_t>(k.second[0].y),
    static_cast<size_t>(k.second[0].z)
  };
  return m_vvaBrickSize[lod][vBrick[0]][vBrick[1]][vBrick[2]];
}

// Gives the size of a brick in real space.
UINT64VECTOR3 UVFMetadata::GetEffectiveBrickSize(const NDBrickKey &k) const
{
  const UINT64 iLOD = k.first[0];
  const size_t vBrick[3] = {
    static_cast<size_t>(k.second[0].x),
    static_cast<size_t>(k.second[0].y),
    static_cast<size_t>(k.second[0].z)
  };
  UINT64VECTOR3 vBrickSize(
    m_vvaBrickSize[iLOD][vBrick[0]][vBrick[1]][vBrick[2]].x,
    m_vvaBrickSize[iLOD][vBrick[0]][vBrick[1]][vBrick[2]].y,
    m_vvaBrickSize[iLOD][vBrick[0]][vBrick[1]][vBrick[2]].z
  );

  if (m_vaBrickCount[iLOD].x > 1) {
    if (vBrick[0] > 0) vBrickSize.x -= m_aOverlap.x/2.0f;
    if (vBrick[0] < m_vaBrickCount[iLOD].x-1) vBrickSize.x -= m_aOverlap.x/2.0f;
  }
  if (m_vaBrickCount[iLOD].y > 1) {
    if (vBrick[1] < m_vaBrickCount[iLOD].y-1) vBrickSize.y -= m_aOverlap.y/2.0f;
    if (vBrick[1] > 0) vBrickSize.y -= m_aOverlap.y/2.0f;
  }
  if (m_vaBrickCount[iLOD].z > 1) {
    if (vBrick[2] < m_vaBrickCount[iLOD].z-1) vBrickSize.z -= m_aOverlap.z/2.0f;
    if (vBrick[2] > 0) vBrickSize.z -= m_aOverlap.z/2.0f;
  }

  return vBrickSize;
}

UINT64VECTOR3 UVFMetadata::GetDomainSize(const UINT64 lod) const
{
  return m_aDomainSize[lod];
}

UINT64VECTOR3 UVFMetadata::GetMaxBrickSize() const
{
  return m_aMaxBrickSize;
}

UINT64VECTOR3 UVFMetadata::GetBrickOverlapSize() const
{
  return m_aOverlap;
}

UINT64 UVFMetadata::GetLODLevelCount() const
{
  return m_iLODLevel;
}

DOUBLEVECTOR3 UVFMetadata::GetScale() const
{
  double rescale[3];
  this->GetRescaleFactors(rescale);
  return m_aScale * DOUBLEVECTOR3(rescale[0], rescale[1], rescale[2]);
}

/// \todo change this if we want to support data where elements are of
// different size
UINT64 UVFMetadata::GetBitWidth() const
{
  return m_pVolumeDataBlock->ulElementBitSize[0][0];
}

UINT64 UVFMetadata::GetComponentCount() const
{
  return m_pVolumeDataBlock->ulElementDimensionSize[0];
}

/// \todo change this if we want to support data where elements are of
/// different type
bool UVFMetadata::GetIsSigned() const
{
  return m_pVolumeDataBlock->bSignedElement[0][0];
}

/// \todo change this if we want to support data where elements are of
///  different type
bool UVFMetadata::GetIsFloat() const
{
  return GetBitWidth() != m_pVolumeDataBlock->ulElementBitSize[0][0];
}

bool UVFMetadata::IsSameEndianness() const
{
  return m_bIsSameEndianness;
}

const std::vector<UINT64>&
UVFMetadata::GetBrickCountND(const std::vector<UINT64>& vLOD) const
{
  return m_pVolumeDataBlock->GetBrickCount(vLOD);
}

const std::vector<UINT64>&
UVFMetadata::GetBrickSizeND(const std::vector<UINT64>& vLOD,
                            const std::vector<UINT64>& vBrick) const
{
  return m_pVolumeDataBlock->GetBrickSize(vLOD, vBrick);
}

const std::vector<UINT64>& UVFMetadata::GetDomainSizeND() const
{
  return m_pVolumeDataBlock->ulDomainSize;
}

const std::vector<UINT64>& UVFMetadata::GetMaxBrickSizeND() const
{
  return m_pVolumeDataBlock->ulBrickSize;
}

const std::vector<UINT64>& UVFMetadata::GetBrickOverlapSizeND() const
{
  return m_pVolumeDataBlock->ulBrickOverlap;
}

const std::vector<UINT64>& UVFMetadata::GetLODLevelCountND() const
{
  return m_pVolumeDataBlock->ulLODLevelCount;
}

const std::vector<double> UVFMetadata::GetScaleND() const
{
  std::vector<double> vfScale;

  const DOUBLEVECTOR3 rescale = this->GetRescaleFactors();
  const size_t iSize = m_pVolumeDataBlock->ulDomainSize.size();

  for (size_t i=0; i < iSize; i++) {
    vfScale.push_back(m_pVolumeDataBlock->dDomainTransformation[i+(iSize+1)*i]
                      * rescale[i]);
  }

  return vfScale;
}

bool UVFMetadata::ContainsData(const NDBrickKey &k, double isoval) const
{
  // if we have no max min data we have to assume that every block is visible
  if(NULL == m_pMaxMinData) {
    return true;
  }

  const size_t vBrick[3] = {
    static_cast<size_t>(k.second[0].x),
    static_cast<size_t>(k.second[0].y),
    static_cast<size_t>(k.second[0].z)
  };
  const InternalMaxMinElement& maxMinElement = m_vvaMaxMin[k.first[0]]
                                                          [vBrick[0]]
                                                          [vBrick[1]]
                                                          [vBrick[2]];
  return (isoval <= maxMinElement.maxScalar);
}

bool UVFMetadata::ContainsData(const NDBrickKey &k,
                               double fMin,double fMax) const
{
  // if we have no max min data we have to assume that every block is visible
  if(NULL == m_pMaxMinData) {
    return true;
  }

  const size_t vBrick[3] = {
    static_cast<size_t>(k.second[0].x),
    static_cast<size_t>(k.second[0].y),
    static_cast<size_t>(k.second[0].z)
  };
  const InternalMaxMinElement& maxMinElement = m_vvaMaxMin[k.first[0]]
                                                          [vBrick[0]]
                                                          [vBrick[1]]
                                                          [vBrick[2]];
  return (fMax >= maxMinElement.minScalar && fMin <= maxMinElement.maxScalar);
}
bool UVFMetadata::ContainsData(const NDBrickKey &k, double fMin,double fMax,
                               double fMinGradient,double fMaxGradient) const
{
  // if we have no max min data we have to assume that every block is visible
  if(NULL == m_pMaxMinData) {
    return true;
  }

  const size_t vBrick[3] = {
    static_cast<size_t>(k.second[0].x),
    static_cast<size_t>(k.second[0].y),
    static_cast<size_t>(k.second[0].z)
  };
  const InternalMaxMinElement& maxMinElement = m_vvaMaxMin[k.first[0]]
                                                          [vBrick[0]]
                                                          [vBrick[1]]
                                                          [vBrick[2]];
  return (fMax >= maxMinElement.minScalar &&
          fMin <= maxMinElement.maxScalar)
                         &&
         (fMaxGradient >= maxMinElement.minGradient &&
          fMinGradient <= maxMinElement.maxGradient);
}

}; // namespace tuvok
<commit_msg>Minor cleanup to brick size calculation with overlaps.<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2009 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/
/**
  \file    uvfUVFMetadata.cpp
  \author  Tom Fogal
           SCI Institute
           University of Utah
  \brief   UVF-specific implementation of metadata.
*/

#include <algorithm>
#include "uvfMetadata.h"

namespace tuvok {

UVFMetadata::UVFMetadata() :
  m_pVolumeDataBlock(NULL),
  m_pMaxMinData(NULL)
{
}

UVFMetadata::UVFMetadata(RasterDataBlock* pVolumeDataBlock,
                         MaxMinDataBlock* pMaxMinData, bool bIsSameEndianness):
  m_pVolumeDataBlock(pVolumeDataBlock),
  m_pMaxMinData(pMaxMinData),
  m_bIsSameEndianness(bIsSameEndianness)
{
  std::vector<double> vfScale;
  size_t iSize = m_pVolumeDataBlock->ulDomainSize.size();

  // we require the data to be at least 3D
  assert(iSize >= 3);

  // we also assume that x,y,z are in the first 3 components and
  // we have no anisotropy (i.e. ulLODLevelCount.size=1)
  m_iLODLevel = static_cast<size_t>(m_pVolumeDataBlock->ulLODLevelCount[0]);
  for (size_t i = 0;i<3;i++) {
    m_aOverlap[i] = m_pVolumeDataBlock->ulBrickOverlap[i];
    m_aMaxBrickSize[i] = m_pVolumeDataBlock->ulBrickSize[i];
    m_aScale[i] = m_pVolumeDataBlock->dDomainTransformation[i+(iSize+1)*i];
  }

  m_vvaBrickSize.resize(m_iLODLevel);
  if (m_pMaxMinData) m_vvaMaxMin.resize(m_iLODLevel);

  for (size_t j = 0;j<m_iLODLevel;j++) {
    std::vector<UINT64> vLOD;  vLOD.push_back(j);
    std::vector<UINT64> vDomSize = m_pVolumeDataBlock->GetLODDomainSize(vLOD);
    m_aDomainSize.push_back(UINT64VECTOR3(vDomSize[0], vDomSize[1],
                                          vDomSize[2]));

    std::vector<UINT64> vBrickCount = m_pVolumeDataBlock->GetBrickCount(vLOD);
    m_vaBrickCount.push_back(UINT64VECTOR3(vBrickCount[0], vBrickCount[1],
                                           vBrickCount[2]));

    m_vvaBrickSize[j].resize(m_vaBrickCount[j].x);
    if (m_pMaxMinData) {
      m_vvaMaxMin[j].resize(m_vaBrickCount[j].x);
    }
    for (UINT64 x=0; x < m_vaBrickCount[j].x; x++) {
      m_vvaBrickSize[j][x].resize(m_vaBrickCount[j].y);
      if (m_pMaxMinData) {
        m_vvaMaxMin[j][x].resize(m_vaBrickCount[j].y);
      }

      for (UINT64 y=0; y < m_vaBrickCount[j].y; y++) {
        if (m_pMaxMinData) {
          m_vvaMaxMin[j][x][y].resize(m_vaBrickCount[j].z);
        }

        for (UINT64 z=0; z < m_vaBrickCount[j].z; z++) {
          std::vector<UINT64> vBrick;
          vBrick.push_back(x);
          vBrick.push_back(y);
          vBrick.push_back(z);
          std::vector<UINT64> vBrickSize =
            m_pVolumeDataBlock->GetBrickSize(vLOD, vBrick);

          m_vvaBrickSize[j][x][y].push_back(UINT64VECTOR3(vBrickSize[0],
                                                          vBrickSize[1],
                                                          vBrickSize[2]));
        }
      }
    }
  }

  size_t iSerializedIndex = 0;
  if (m_pMaxMinData) {
    for (size_t lod=0; lod < m_iLODLevel; lod++) {
      for (UINT64 z=0; z < m_vaBrickCount[lod].z; z++) {
        for (UINT64 y=0; y < m_vaBrickCount[lod].y; y++) {
          for (UINT64 x=0; x < m_vaBrickCount[lod].x; x++) {
            // for four-component data we use the fourth component
            // (presumably the alpha channel); for all other data we use
            // the first component
            /// \todo we may have to change this if we add support for other
            /// kinds of multicomponent data.
            m_vvaMaxMin[lod][x][y][z] =
              m_pMaxMinData->GetValue(iSerializedIndex++,
                 (m_pVolumeDataBlock->ulElementDimensionSize[0] == 4) ? 3 : 0
              );
          }
        }
      }
    }
  }

  // Use a minimum of 3 elements, which ...
  size_t n_elems = std::max(static_cast<size_t>(3),
                            m_pVolumeDataBlock->ulDomainSemantics.size());
  std::vector<double> rescale(n_elems);
  for (size_t i=0; i < n_elems; i++) {
    rescale[i] = 1.0;
  }
  // ... allows us to assume we can deref the first 3 elements here.
  this->SetRescaleFactors(DOUBLEVECTOR3(rescale[0],rescale[1],rescale[2]));
}

// Return the number of bricks in the given LoD, along each axis.
UINT64VECTOR3 UVFMetadata::GetBrickCount(const UINT64 lod) const
{
  return m_vaBrickCount[lod];
}

// Size of the brick in logical space.
UINT64VECTOR3 UVFMetadata::GetBrickSize(const NDBrickKey &k) const
{
  const UINT64 lod = k.first[0];
  const size_t vBrick[3] = {
    static_cast<size_t>(k.second[0].x),
    static_cast<size_t>(k.second[0].y),
    static_cast<size_t>(k.second[0].z)
  };
  return m_vvaBrickSize[lod][vBrick[0]][vBrick[1]][vBrick[2]];
}

// One dimensional brick shrinking for internal bricks that have some overlap
// with neighboring bricks.  Assumes overlap is constant per dataset: this
// brick's overlap with the brick to its right is the same as the overlap with
// the right brick's overlap with the brick to the left.
/// @param v        original brick size for this dimension
/// @param nbrick   which brick this is
/// @param count    number of bricks for this dimension
/// @param overlap  amount of per-brick overlap.
static void fix_overlap(UINT64& v, UINT64 nbrick, UINT64 count,
                        UINT64 overlap) {
  if(nbrick > 0) {
    v -= static_cast<size_t>(overlap/2.0f);
  }
  if(nbrick < count) {
    v -= static_cast<size_t>(overlap/2.0f);
  }
}

// Gives the size of a brick in real space.
UINT64VECTOR3 UVFMetadata::GetEffectiveBrickSize(const NDBrickKey &k) const
{
  const UINT64 iLOD = k.first[0];
  const size_t vBrick[3] = {
    static_cast<size_t>(k.second[0].x),
    static_cast<size_t>(k.second[0].y),
    static_cast<size_t>(k.second[0].z)
  };
  UINT64VECTOR3 vBrickSize(
    m_vvaBrickSize[iLOD][vBrick[0]][vBrick[1]][vBrick[2]].x,
    m_vvaBrickSize[iLOD][vBrick[0]][vBrick[1]][vBrick[2]].y,
    m_vvaBrickSize[iLOD][vBrick[0]][vBrick[1]][vBrick[2]].z
  );

  // If this is an internal brick, the size is a bit smaller based on the
  // amount of overlap per-brick.
  if (m_vaBrickCount[iLOD].x > 1) {
    fix_overlap(vBrickSize.x, vBrick[0], m_vaBrickCount[iLOD].x-1,
                m_aOverlap.x);
  }
  if (m_vaBrickCount[iLOD].y > 1) {
    fix_overlap(vBrickSize.y, vBrick[1], m_vaBrickCount[iLOD].y-1,
                m_aOverlap.y);
  }
  if (m_vaBrickCount[iLOD].z > 1) {
    fix_overlap(vBrickSize.z, vBrick[2], m_vaBrickCount[iLOD].z-1,
                m_aOverlap.z);
  }

  return vBrickSize;
}

UINT64VECTOR3 UVFMetadata::GetDomainSize(const UINT64 lod) const
{
  return m_aDomainSize[lod];
}

UINT64VECTOR3 UVFMetadata::GetMaxBrickSize() const
{
  return m_aMaxBrickSize;
}

UINT64VECTOR3 UVFMetadata::GetBrickOverlapSize() const
{
  return m_aOverlap;
}

UINT64 UVFMetadata::GetLODLevelCount() const
{
  return m_iLODLevel;
}

DOUBLEVECTOR3 UVFMetadata::GetScale() const
{
  double rescale[3];
  this->GetRescaleFactors(rescale);
  return m_aScale * DOUBLEVECTOR3(rescale[0], rescale[1], rescale[2]);
}

/// \todo change this if we want to support data where elements are of
// different size
UINT64 UVFMetadata::GetBitWidth() const
{
  return m_pVolumeDataBlock->ulElementBitSize[0][0];
}

UINT64 UVFMetadata::GetComponentCount() const
{
  return m_pVolumeDataBlock->ulElementDimensionSize[0];
}

/// \todo change this if we want to support data where elements are of
/// different type
bool UVFMetadata::GetIsSigned() const
{
  return m_pVolumeDataBlock->bSignedElement[0][0];
}

/// \todo change this if we want to support data where elements are of
///  different type
bool UVFMetadata::GetIsFloat() const
{
  return GetBitWidth() != m_pVolumeDataBlock->ulElementBitSize[0][0];
}

bool UVFMetadata::IsSameEndianness() const
{
  return m_bIsSameEndianness;
}

const std::vector<UINT64>&
UVFMetadata::GetBrickCountND(const std::vector<UINT64>& vLOD) const
{
  return m_pVolumeDataBlock->GetBrickCount(vLOD);
}

const std::vector<UINT64>&
UVFMetadata::GetBrickSizeND(const std::vector<UINT64>& vLOD,
                            const std::vector<UINT64>& vBrick) const
{
  return m_pVolumeDataBlock->GetBrickSize(vLOD, vBrick);
}

const std::vector<UINT64>& UVFMetadata::GetDomainSizeND() const
{
  return m_pVolumeDataBlock->ulDomainSize;
}

const std::vector<UINT64>& UVFMetadata::GetMaxBrickSizeND() const
{
  return m_pVolumeDataBlock->ulBrickSize;
}

const std::vector<UINT64>& UVFMetadata::GetBrickOverlapSizeND() const
{
  return m_pVolumeDataBlock->ulBrickOverlap;
}

const std::vector<UINT64>& UVFMetadata::GetLODLevelCountND() const
{
  return m_pVolumeDataBlock->ulLODLevelCount;
}

const std::vector<double> UVFMetadata::GetScaleND() const
{
  std::vector<double> vfScale;

  const DOUBLEVECTOR3 rescale = this->GetRescaleFactors();
  const size_t iSize = m_pVolumeDataBlock->ulDomainSize.size();

  for (size_t i=0; i < iSize; i++) {
    vfScale.push_back(m_pVolumeDataBlock->dDomainTransformation[i+(iSize+1)*i]
                      * rescale[i]);
  }

  return vfScale;
}

bool UVFMetadata::ContainsData(const NDBrickKey &k, double isoval) const
{
  // if we have no max min data we have to assume that every block is visible
  if(NULL == m_pMaxMinData) {
    return true;
  }

  const size_t vBrick[3] = {
    static_cast<size_t>(k.second[0].x),
    static_cast<size_t>(k.second[0].y),
    static_cast<size_t>(k.second[0].z)
  };
  const InternalMaxMinElement& maxMinElement = m_vvaMaxMin[k.first[0]]
                                                          [vBrick[0]]
                                                          [vBrick[1]]
                                                          [vBrick[2]];
  return (isoval <= maxMinElement.maxScalar);
}

bool UVFMetadata::ContainsData(const NDBrickKey &k,
                               double fMin,double fMax) const
{
  // if we have no max min data we have to assume that every block is visible
  if(NULL == m_pMaxMinData) {
    return true;
  }

  const size_t vBrick[3] = {
    static_cast<size_t>(k.second[0].x),
    static_cast<size_t>(k.second[0].y),
    static_cast<size_t>(k.second[0].z)
  };
  const InternalMaxMinElement& maxMinElement = m_vvaMaxMin[k.first[0]]
                                                          [vBrick[0]]
                                                          [vBrick[1]]
                                                          [vBrick[2]];
  return (fMax >= maxMinElement.minScalar && fMin <= maxMinElement.maxScalar);
}
bool UVFMetadata::ContainsData(const NDBrickKey &k, double fMin,double fMax,
                               double fMinGradient,double fMaxGradient) const
{
  // if we have no max min data we have to assume that every block is visible
  if(NULL == m_pMaxMinData) {
    return true;
  }

  const size_t vBrick[3] = {
    static_cast<size_t>(k.second[0].x),
    static_cast<size_t>(k.second[0].y),
    static_cast<size_t>(k.second[0].z)
  };
  const InternalMaxMinElement& maxMinElement = m_vvaMaxMin[k.first[0]]
                                                          [vBrick[0]]
                                                          [vBrick[1]]
                                                          [vBrick[2]];
  return (fMax >= maxMinElement.minScalar &&
          fMin <= maxMinElement.maxScalar)
                         &&
         (fMaxGradient >= maxMinElement.minGradient &&
          fMinGradient <= maxMinElement.maxGradient);
}

}; // namespace tuvok
<|endoftext|>


<commit_before>/***********************************************************************
KCalendar support for OpenSync kdepim-sync plugin
Copyright (C) 2004 Conectiva S. A.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation;

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*************************************************************************/
/**
 * @autor Eduardo Pereira Habkost <ehabkost@conectiva.com.br>
 */

#include <libkcal/calendarresources.h>
#include <libkcal/icalformat.h>
#include <libkcal/calendarlocal.h>
#include <kdeversion.h>

#include "osyncbase.h"
#include "kcal.h"

KCalDataSource::KCalDataSource(OSyncMember *member, OSyncHashTable *hashtable)
    : hashtable(hashtable), member(member)
{
}

bool KCalDataSource::connect(OSyncContext *ctx)
{
    calendar = new KCal::CalendarResources();
    if (!calendar) {
        osync_context_report_error(ctx, OSYNC_ERROR_GENERIC, "Can't open KDE calendar");
        return false;
    }
#if KDE_IS_VERSION(3,3,0)
    /* On KDE 3.2, there was no readConfig() and load(): the data
     * was loaded automatically on the CalendarResources() constructor
     */
    calendar->readConfig();
    calendar->load();
#endif
    osync_debug("kcal", 3, "Calendar: %d events", calendar->events().size());
    /*FIXME: We don't lock the data */
    //saveTicket = calendar->requestSaveTicket();
    if (!saveTicket) {
        osync_context_report_error(ctx, OSYNC_ERROR_GENERIC, "Couldn't request write to the KDE calendar");
        return false;
    }
    return true;
}

bool KCalDataSource::disconnect(OSyncContext *)
{
    // We are not locking the data
    //calendar->save(saveTicket);
    delete calendar;
    calendar = NULL;
    return true;
}

static QString calc_hash(const KCal::Incidence *e)
{
    QDateTime d = e->lastModified();
    if (!d.isValid())
        d = QDateTime::currentDateTime();
    /*FIXME: not i18ned string */
    return d.toString();
}

/** Report a list of calendar incidences (events or to-dos), with the
 * right objtype and objformat.
 *
 * This function exists because the logic for converting the events or to-dos
 * is the same, only the objtype and format is different.
 */
bool KCalDataSource::report_incidence(OSyncContext *ctx, KCal::Incidence *e, const char *objtype, const char *objformat)
{
	osync_debug("kcal", 3, "One calendar incidence (%s)", objtype);
	QString hash = calc_hash(e);

	QString uid = e->uid();

	/* Build a local calendar for the incidence data */
	KCal::CalendarLocal cal(calendar->timeZoneId());
	osync_debug("kcal", 3, "timezoneid: %s\n", (const char*)cal.timeZoneId().local8Bit());
	cal.addIncidence(e->clone());

	/* Convert the data to vcalendar */
	KCal::ICalFormat format;
	/* Ugly workaround to a ICalFormat bug, format.toString()
	 * doesn't work, but if save() or load() is called before
	 * toString(), the segmentation fault will not happen (as
	 * the mCalendar private field will be set)
	 *
	format.save(&cal, "");*/
	QCString datastr = format.toString(&cal).local8Bit();
	const char *data = datastr;

	osync_debug("kcal", 3, "UID: %s\n", (const char*)uid.local8Bit());
	OSyncChange *chg = osync_change_new();
	osync_change_set_uid(chg, uid.local8Bit());
	osync_change_set_member(chg, member);

	// object type and format
	osync_change_set_objtype_string(chg, objtype);
	osync_change_set_objformat_string(chg, objformat);
	osync_change_set_data(chg, strdup(data), strlen(data), 1);

	// Use the hash table to check if the object
	// needs to be reported
	osync_change_set_hash(chg, hash.data());
	if (osync_hashtable_detect_change(hashtable, chg)) {
		osync_context_report_change(ctx, chg);
		osync_hashtable_update_hash(hashtable, chg);
	}

    return true;
}

bool KCalDataSource::get_changeinfo_events(OSyncContext *ctx)
{
    KCal::Event::List events = calendar->events();
    osync_debug("kcal", 3, "Number of events: %d", events.size());

    for (KCal::Event::List::ConstIterator i = events.begin(); i != events.end(); i++) {
        if (!report_incidence(ctx, *i, "event", "vevent"))
            return false;
    }

    osync_hashtable_report_deleted(hashtable, ctx, "event");

    return true;
}

bool KCalDataSource::get_changeinfo_todos(OSyncContext *ctx)
{
    KCal::Todo::List todos = calendar->todos();

    osync_debug("kcal", 3, "Number of to-dos: %d", todos.size());

    for (KCal::Todo::List::ConstIterator i = todos.begin(); i != todos.end(); i++) {
        osync_debug("kcal", 3, "%p: doesFloat: %d", *i, (*i)->doesFloat());
        if (!report_incidence(ctx, *i, "todo", "vtodo"))
            return false;
    }

    osync_hashtable_report_deleted(hashtable, ctx, "todo");

    return true;

}

void KCalDataSource::get_data(OSyncContext *ctx, OSyncChange *)
{
    osync_context_report_error(ctx, OSYNC_ERROR_NOT_SUPPORTED, "Not implemented yet");
}

/** Add or change a incidence on the calendar. This function
 * is used for events and to-dos
 */
bool KCalDataSource::__access(OSyncContext *ctx, OSyncChange *chg)
{
    OSyncChangeType type = osync_change_get_changetype(chg);
    osync_debug("kcal", 3, "%s", __FUNCTION__);
    switch (type) {
        case CHANGE_DELETED:
            {
                KCal::Event *e = calendar->event(osync_change_get_uid(chg));
                if (!e) {
                    osync_context_report_error(ctx, OSYNC_ERROR_FILE_NOT_FOUND, "Event not found while deleting");
                    return false;
                }
                calendar->deleteEvent(e);
            }
        break;
        case CHANGE_ADDED:
        case CHANGE_MODIFIED:
        {
            KCal::ICalFormat format;

            /* First, parse to a temporary calendar, because
             * we should set the uid on the events
             */
            KCal::CalendarLocal cal;
            QString data = QString::fromLocal8Bit(osync_change_get_data(chg), osync_change_get_datasize(chg));
            /* Ugly workaround to a ICalFormat bug, format.toString()
             * doesn't work, but if save() or load() is called before
             * toString(), the segmentation fault will not happen (as
             * the mCalendar private field will be set)
             *
            format.save(&cal, ""); */
            if (!format.fromString(&cal, data)) {
                osync_context_report_error(ctx, OSYNC_ERROR_CONVERT, "Couldn't import calendar data");
                return false;
            }

            /*FIXME: The event/to-do will be overwritten. But I can't differentiate
             * between a field being removed and a missing field because
             * the other device don't support them, because OpenSync currently
             * doesn't have support for it. Yes, it is risky, but unfortunately
             * CalendarResources don't have support for changing an event
             * from vcard data, and not adding it.
             */
            KCal::Incidence *oldevt = calendar->incidence(osync_change_get_uid(chg));
            if (oldevt)
                calendar->deleteIncidence(oldevt);

            /* Add the events from the temporary calendar, setting the UID
             *
             * We iterate over the list, but it should have only one event.
             */
            KCal::Incidence::List evts = cal.incidences();
            for (KCal::Incidence::List::ConstIterator i = evts.begin(); i != evts.end(); i++) {
                KCal::Incidence *e = (*i)->clone();
                e->setUid(osync_change_get_uid(chg));

                osync_debug("kcal", 3, "Writing incidence: uid: %s, summary: %s",
                                (const char*)e->uid().local8Bit(), (const char*)e->summary().local8Bit());
                calendar->addIncidence(e);
            }

        }
        break;
        default:
            osync_context_report_error(ctx, OSYNC_ERROR_NOT_SUPPORTED, "Invalid or unsupported change type");
            return false;
    }

    /* Save the changes */
    calendar->save();

    return true;
}

bool KCalDataSource::event_access(OSyncContext *ctx, OSyncChange *chg)
{
    // We use the same function for events and to-do
    if (!__access(ctx, chg))
        return false;

    osync_context_report_success(ctx);
    return true;
}

bool KCalDataSource::event_commit_change(OSyncContext *ctx, OSyncChange *chg)
{
    // We use the same function for events and to-do
    if ( !__access(ctx, chg) )
        return false;
    osync_hashtable_update_hash(hashtable, chg);
    osync_context_report_success(ctx);
    return true;
}

bool KCalDataSource::todo_access(OSyncContext *ctx, OSyncChange *chg)
{
    // We use the same function for calendar and to-do
    if (!__access(ctx, chg))
        return false;

    osync_context_report_success(ctx);
    return true;
}

bool KCalDataSource::todo_commit_change(OSyncContext *ctx, OSyncChange *chg)
{
    // We use the same function for calendar and to-do
    if ( !__access(ctx, chg) )
        return false;
    osync_hashtable_update_hash(hashtable, chg);
    osync_context_report_success(ctx);
    return true;
}
<commit_msg>Removing VCalFormat bug workarounds<commit_after>/***********************************************************************
KCalendar support for OpenSync kdepim-sync plugin
Copyright (C) 2004 Conectiva S. A.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation;

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*************************************************************************/
/**
 * @autor Eduardo Pereira Habkost <ehabkost@conectiva.com.br>
 */

#include <libkcal/calendarresources.h>
#include <libkcal/icalformat.h>
#include <libkcal/calendarlocal.h>
#include <kdeversion.h>

#include "osyncbase.h"
#include "kcal.h"

KCalDataSource::KCalDataSource(OSyncMember *member, OSyncHashTable *hashtable)
    : hashtable(hashtable), member(member)
{
}

bool KCalDataSource::connect(OSyncContext *ctx)
{
    calendar = new KCal::CalendarResources();
    if (!calendar) {
        osync_context_report_error(ctx, OSYNC_ERROR_GENERIC, "Can't open KDE calendar");
        return false;
    }
#if KDE_IS_VERSION(3,3,0)
    /* On KDE 3.2, there was no readConfig() and load(): the data
     * was loaded automatically on the CalendarResources() constructor
     */
    calendar->readConfig();
    calendar->load();
#endif
    osync_debug("kcal", 3, "Calendar: %d events", calendar->events().size());
    /*FIXME: We don't lock the data */
    //saveTicket = calendar->requestSaveTicket();
    if (!saveTicket) {
        osync_context_report_error(ctx, OSYNC_ERROR_GENERIC, "Couldn't request write to the KDE calendar");
        return false;
    }
    return true;
}

bool KCalDataSource::disconnect(OSyncContext *)
{
    // We are not locking the data
    //calendar->save(saveTicket);
    delete calendar;
    calendar = NULL;
    return true;
}

static QString calc_hash(const KCal::Incidence *e)
{
    QDateTime d = e->lastModified();
    if (!d.isValid())
        d = QDateTime::currentDateTime();
    /*FIXME: not i18ned string */
    return d.toString();
}

/** Report a list of calendar incidences (events or to-dos), with the
 * right objtype and objformat.
 *
 * This function exists because the logic for converting the events or to-dos
 * is the same, only the objtype and format is different.
 */
bool KCalDataSource::report_incidence(OSyncContext *ctx, KCal::Incidence *e, const char *objtype, const char *objformat)
{
	osync_debug("kcal", 3, "One calendar incidence (%s)", objtype);
	QString hash = calc_hash(e);

	QString uid = e->uid();

	/* Build a local calendar for the incidence data */
	KCal::CalendarLocal cal(calendar->timeZoneId());
	osync_debug("kcal", 3, "timezoneid: %s\n", (const char*)cal.timeZoneId().local8Bit());
	cal.addIncidence(e->clone());

	/* Convert the data to vcalendar */
	KCal::ICalFormat format;
	QCString datastr = format.toString(&cal).local8Bit();
	const char *data = datastr;

	osync_debug("kcal", 3, "UID: %s\n", (const char*)uid.local8Bit());
	OSyncChange *chg = osync_change_new();
	osync_change_set_uid(chg, uid.local8Bit());
	osync_change_set_member(chg, member);

	// object type and format
	osync_change_set_objtype_string(chg, objtype);
	osync_change_set_objformat_string(chg, objformat);
	osync_change_set_data(chg, strdup(data), strlen(data), 1);

	// Use the hash table to check if the object
	// needs to be reported
	osync_change_set_hash(chg, hash.data());
	if (osync_hashtable_detect_change(hashtable, chg)) {
		osync_context_report_change(ctx, chg);
		osync_hashtable_update_hash(hashtable, chg);
	}

    return true;
}

bool KCalDataSource::get_changeinfo_events(OSyncContext *ctx)
{
    KCal::Event::List events = calendar->events();
    osync_debug("kcal", 3, "Number of events: %d", events.size());

    for (KCal::Event::List::ConstIterator i = events.begin(); i != events.end(); i++) {
        if (!report_incidence(ctx, *i, "event", "vevent"))
            return false;
    }

    osync_hashtable_report_deleted(hashtable, ctx, "event");

    return true;
}

bool KCalDataSource::get_changeinfo_todos(OSyncContext *ctx)
{
    KCal::Todo::List todos = calendar->todos();

    osync_debug("kcal", 3, "Number of to-dos: %d", todos.size());

    for (KCal::Todo::List::ConstIterator i = todos.begin(); i != todos.end(); i++) {
        osync_debug("kcal", 3, "%p: doesFloat: %d", *i, (*i)->doesFloat());
        if (!report_incidence(ctx, *i, "todo", "vtodo"))
            return false;
    }

    osync_hashtable_report_deleted(hashtable, ctx, "todo");

    return true;

}

void KCalDataSource::get_data(OSyncContext *ctx, OSyncChange *)
{
    osync_context_report_error(ctx, OSYNC_ERROR_NOT_SUPPORTED, "Not implemented yet");
}

/** Add or change a incidence on the calendar. This function
 * is used for events and to-dos
 */
bool KCalDataSource::__access(OSyncContext *ctx, OSyncChange *chg)
{
    OSyncChangeType type = osync_change_get_changetype(chg);
    osync_debug("kcal", 3, "%s", __FUNCTION__);
    switch (type) {
        case CHANGE_DELETED:
            {
                KCal::Event *e = calendar->event(osync_change_get_uid(chg));
                if (!e) {
                    osync_context_report_error(ctx, OSYNC_ERROR_FILE_NOT_FOUND, "Event not found while deleting");
                    return false;
                }
                calendar->deleteEvent(e);
            }
        break;
        case CHANGE_ADDED:
        case CHANGE_MODIFIED:
        {
            KCal::ICalFormat format;

            /* First, parse to a temporary calendar, because
             * we should set the uid on the events
             */
            KCal::CalendarLocal cal;
            QString data = QString::fromLocal8Bit(osync_change_get_data(chg), osync_change_get_datasize(chg));
            if (!format.fromString(&cal, data)) {
                osync_context_report_error(ctx, OSYNC_ERROR_CONVERT, "Couldn't import calendar data");
                return false;
            }

            /*FIXME: The event/to-do will be overwritten. But I can't differentiate
             * between a field being removed and a missing field because
             * the other device don't support them, because OpenSync currently
             * doesn't have support for it. Yes, it is risky, but unfortunately
             * CalendarResources don't have support for changing an event
             * from vcard data, and not adding it.
             */
            KCal::Incidence *oldevt = calendar->incidence(osync_change_get_uid(chg));
            if (oldevt)
                calendar->deleteIncidence(oldevt);

            /* Add the events from the temporary calendar, setting the UID
             *
             * We iterate over the list, but it should have only one event.
             */
            KCal::Incidence::List evts = cal.incidences();
            for (KCal::Incidence::List::ConstIterator i = evts.begin(); i != evts.end(); i++) {
                KCal::Incidence *e = (*i)->clone();
                e->setUid(osync_change_get_uid(chg));

                osync_debug("kcal", 3, "Writing incidence: uid: %s, summary: %s",
                                (const char*)e->uid().local8Bit(), (const char*)e->summary().local8Bit());
                calendar->addIncidence(e);
            }

        }
        break;
        default:
            osync_context_report_error(ctx, OSYNC_ERROR_NOT_SUPPORTED, "Invalid or unsupported change type");
            return false;
    }

    /* Save the changes */
    calendar->save();

    return true;
}

bool KCalDataSource::event_access(OSyncContext *ctx, OSyncChange *chg)
{
    // We use the same function for events and to-do
    if (!__access(ctx, chg))
        return false;

    osync_context_report_success(ctx);
    return true;
}

bool KCalDataSource::event_commit_change(OSyncContext *ctx, OSyncChange *chg)
{
    // We use the same function for events and to-do
    if ( !__access(ctx, chg) )
        return false;
    osync_hashtable_update_hash(hashtable, chg);
    osync_context_report_success(ctx);
    return true;
}

bool KCalDataSource::todo_access(OSyncContext *ctx, OSyncChange *chg)
{
    // We use the same function for calendar and to-do
    if (!__access(ctx, chg))
        return false;

    osync_context_report_success(ctx);
    return true;
}

bool KCalDataSource::todo_commit_change(OSyncContext *ctx, OSyncChange *chg)
{
    // We use the same function for calendar and to-do
    if ( !__access(ctx, chg) )
        return false;
    osync_hashtable_update_hash(hashtable, chg);
    osync_context_report_success(ctx);
    return true;
}
<|endoftext|>


<commit_before>/*
 * arcemu MMORPG Server
 * Copyright (C) 2005-2008 arcemu Team <http://www.arcemuemu.com/>
 *
 * Circular Buffer Class
 * Based on the Bip Buffer concept, from http://www.codeproject.com/KB/IP/bipbuffer.aspx
 * Implementation Copyright (c) 2008 Burlex
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "../Common.h"
#include "CircularBuffer.h"

/** Constructor
 */
CircularBuffer::CircularBuffer()
{
	m_buffer = m_bufferEnd = m_regionAPointer = m_regionBPointer = NULL;
	m_regionASize = m_regionBSize = 0;
}

/** Destructor
 */
CircularBuffer::~CircularBuffer()
{
	free(m_buffer);
}

/** Read bytes from the buffer
 * @param destination pointer to destination where bytes will be written
 * @param bytes number of bytes to read
 * @return true if there was enough data, false otherwise
 */
bool CircularBuffer::Read(void * destination, size_t bytes)
{
	// copy as much out of region a
	size_t cnt = bytes;
	size_t aRead = 0, bRead = 0;
	if( (m_regionASize + m_regionBSize) < bytes )
		return false;

	// If we have both region A and region B, always "finish" off region A first, as
	// this will contain the "oldest" data
	if( m_regionASize > 0 )
	{
		aRead = (cnt > m_regionASize) ? m_regionASize : cnt;
		memcpy(destination, m_regionAPointer, aRead);
		m_regionASize -= aRead;
		m_regionAPointer += aRead;
		cnt -= aRead;
	}

	// Data left over? read the data from buffer B
	if( cnt > 0 && m_regionBSize > 0 )
	{
		bRead = (cnt > m_regionBSize) ? m_regionBSize : cnt;
		memcpy((char*)destination + aRead, m_regionBPointer, bRead);
		m_regionBSize -= bRead;
		m_regionBPointer += bRead;
		cnt -= bRead;
	}

	// is buffer A empty? move buffer B to buffer A, to increase future performance
	if( m_regionASize == 0 )
	{
		if( m_regionBSize > 0 )
		{
			// push it all to the start of the buffer.
			if( m_regionBPointer != m_buffer )
				memmove(m_buffer, m_regionBPointer, m_regionBSize);

			m_regionAPointer = m_buffer;
			m_regionASize = m_regionBSize;
			m_regionBPointer = NULL;
			m_regionBSize = 0;
		}
		else
		{
			// no data in region b
			m_regionBPointer = NULL;
			m_regionBSize = 0;
			m_regionAPointer = m_buffer;
			m_regionASize = 0;
		}
	}

	return true;
}

void CircularBuffer::AllocateB()
{
	//printf("[allocating B]\n");
	m_regionBPointer = m_buffer;
}

/** Write bytes to the buffer
 * @param data pointer to the data to be written
 * @param bytes number of bytes to be written
 * @return true if was successful, otherwise false
 */
bool CircularBuffer::Write(const void * data, size_t bytes)
{
	// If buffer B exists, write to it.
	if( m_regionBPointer != NULL )
	{
		if( GetBFreeSpace() < bytes )
			return false;

		memcpy(&m_regionBPointer[m_regionBSize], data, bytes);
		m_regionBSize += bytes;
		return true;
	}

	// Otherwise, write to buffer A, or initialize buffer B depending on which has more space.
	if( GetAFreeSpace() < GetSpaceBeforeA() )
	{
		AllocateB();
		if( GetBFreeSpace() < bytes )
			return false;

		memcpy(&m_regionBPointer[m_regionBSize], data, bytes);
		m_regionBSize += bytes;
		return true;
	}
	else
	{
		if( GetAFreeSpace() < bytes )
			return false;

		memcpy(&m_regionAPointer[m_regionASize], data, bytes);
		m_regionASize += bytes;
		return true;
	}
}

/** Returns the number of available bytes left.
 */
size_t CircularBuffer::GetSpace()
{
	if( m_regionBPointer != NULL )
		return GetBFreeSpace();
	else
	{
		// would allocating buffer B get us more data?
		if( GetAFreeSpace() < GetSpaceBeforeA() )
		{
			AllocateB();
			return GetBFreeSpace();
		}

		// or not?
		return GetAFreeSpace();
	}
}

/** Returns the number of bytes currently stored in the buffer.
 */
size_t CircularBuffer::GetSize()
{
	return m_regionASize + m_regionBSize;
}

/** Returns the number of contiguous bytes (that can be pushed out in one operation)
 */
size_t CircularBuffer::GetContiguiousBytes()
{
	if( m_regionASize )			// A before B
		return m_regionASize;
	else
		return m_regionBSize;
}

/** Removes len bytes from the front of the buffer
 * @param len the number of bytes to "cut"
 */
void CircularBuffer::Remove(size_t len)
{
	// remove from A first before we remove from b
	size_t cnt = len;
	size_t aRem, bRem;

	// If we have both region A and region B, always "finish" off region A first, as
	// this will contain the "oldest" data
	if( m_regionASize > 0 )
	{
		aRem = (cnt > m_regionASize) ? m_regionASize : cnt;
		m_regionASize -= aRem;
		m_regionAPointer += aRem;
		cnt -= aRem;
	}

	// Data left over? cut the data from buffer B
	if( cnt > 0 && m_regionBSize > 0 )
	{
		bRem = (cnt > m_regionBSize) ? m_regionBSize : cnt;
		m_regionBSize -= bRem;
		m_regionBPointer += bRem;
		cnt -= bRem;
	}

	// is buffer A empty? move buffer B to buffer A, to increase future performance
	if( m_regionASize == 0 )
	{
		if( m_regionBSize > 0 )
		{
			// push it all to the start of the buffer.
			if( m_regionBPointer != m_buffer )
				memmove(m_buffer, m_regionBPointer, m_regionBSize);

			m_regionAPointer = m_buffer;
			m_regionASize = m_regionBSize;
			m_regionBPointer = NULL;
			m_regionBSize = 0;
		}
		else
		{
			// no data in region b
			m_regionBPointer = NULL;
			m_regionBSize = 0;
			m_regionAPointer = m_buffer;
			m_regionASize = 0;
		}
	}
}

/** Returns a pointer at the "end" of the buffer, where new data can be written
 */
void * CircularBuffer::GetBuffer()
{
	if( m_regionBPointer != NULL )
		return m_regionBPointer + m_regionBSize;
	else
		return m_regionAPointer + m_regionASize;
}

/** Allocate the buffer with room for size bytes
 * @param size the number of bytes to allocate
 */
void CircularBuffer::Allocate(size_t size)
{
	m_buffer = (uint8*)malloc(size);
	m_bufferEnd = m_buffer + size;
	m_regionAPointer = m_buffer;		// reset A to the start
}

/** Increments the "writen" pointer forward len bytes
 * @param len number of bytes to step
 */
void CircularBuffer::IncrementWritten(size_t len)			// known as "commit"
{
	if( m_regionBPointer != NULL )
		m_regionBSize += len;
	else
		m_regionASize += len;
}

/** Returns a pointer at the "beginning" of the buffer, where data can be pulled from
 */
void * CircularBuffer::GetBufferStart()
{
	if( m_regionASize > 0 )
		return m_regionAPointer;
	else
		return m_regionBPointer;

}
<commit_msg>NULL checks<commit_after>/*
 * arcemu MMORPG Server
 * Copyright (C) 2005-2008 arcemu Team <http://www.arcemuemu.com/>
 *
 * Circular Buffer Class
 * Based on the Bip Buffer concept, from http://www.codeproject.com/KB/IP/bipbuffer.aspx
 * Implementation Copyright (c) 2008 Burlex
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "../Common.h"
#include "CircularBuffer.h"

/** Constructor
 */
CircularBuffer::CircularBuffer()
{
	m_buffer = m_bufferEnd = m_regionAPointer = m_regionBPointer = NULL;
	m_regionASize = m_regionBSize = 0;
}

/** Destructor
 */
CircularBuffer::~CircularBuffer()
{
	free(m_buffer);
}

/** Read bytes from the buffer
 * @param destination pointer to destination where bytes will be written
 * @param bytes number of bytes to read
 * @return true if there was enough data, false otherwise
 */
bool CircularBuffer::Read(void * destination, size_t bytes)
{
	if (m_buffer == NULL)
		return false;

	// copy as much out of region a
	size_t cnt = bytes;
	size_t aRead = 0, bRead = 0;
	if( (m_regionASize + m_regionBSize) < bytes )
		return false;

	// If we have both region A and region B, always "finish" off region A first, as
	// this will contain the "oldest" data
	if( m_regionASize > 0 )
	{
		aRead = (cnt > m_regionASize) ? m_regionASize : cnt;
		memcpy(destination, m_regionAPointer, aRead);
		m_regionASize -= aRead;
		m_regionAPointer += aRead;
		cnt -= aRead;
	}

	// Data left over? read the data from buffer B
	if( cnt > 0 && m_regionBSize > 0 )
	{
		bRead = (cnt > m_regionBSize) ? m_regionBSize : cnt;
		memcpy((char*)destination + aRead, m_regionBPointer, bRead);
		m_regionBSize -= bRead;
		m_regionBPointer += bRead;
		cnt -= bRead;
	}

	// is buffer A empty? move buffer B to buffer A, to increase future performance
	if( m_regionASize == 0 )
	{
		if( m_regionBSize > 0 )
		{
			// push it all to the start of the buffer.
			if( m_regionBPointer != m_buffer )
				memmove(m_buffer, m_regionBPointer, m_regionBSize);

			m_regionAPointer = m_buffer;
			m_regionASize = m_regionBSize;
			m_regionBPointer = NULL;
			m_regionBSize = 0;
		}
		else
		{
			// no data in region b
			m_regionBPointer = NULL;
			m_regionBSize = 0;
			m_regionAPointer = m_buffer;
			m_regionASize = 0;
		}
	}

	return true;
}

void CircularBuffer::AllocateB()
{
	//printf("[allocating B]\n");
	m_regionBPointer = m_buffer;
}

/** Write bytes to the buffer
 * @param data pointer to the data to be written
 * @param bytes number of bytes to be written
 * @return true if was successful, otherwise false
 */
bool CircularBuffer::Write(const void * data, size_t bytes)
{
	if (m_buffer == NULL)
		return false;

	// If buffer B exists, write to it.
	if( m_regionBPointer != NULL )
	{
		if( GetBFreeSpace() < bytes )
			return false;

		memcpy(&m_regionBPointer[m_regionBSize], data, bytes);
		m_regionBSize += bytes;
		return true;
	}

	// Otherwise, write to buffer A, or initialize buffer B depending on which has more space.
	if( GetAFreeSpace() < GetSpaceBeforeA() )
	{
		AllocateB();
		if( GetBFreeSpace() < bytes )
			return false;

		memcpy(&m_regionBPointer[m_regionBSize], data, bytes);
		m_regionBSize += bytes;
		return true;
	}
	else
	{
		if( GetAFreeSpace() < bytes )
			return false;

		memcpy(&m_regionAPointer[m_regionASize], data, bytes);
		m_regionASize += bytes;
		return true;
	}
}

/** Returns the number of available bytes left.
 */
size_t CircularBuffer::GetSpace()
{
	if( m_regionBPointer != NULL )
		return GetBFreeSpace();
	else
	{
		// would allocating buffer B get us more data?
		if( GetAFreeSpace() < GetSpaceBeforeA() )
		{
			AllocateB();
			return GetBFreeSpace();
		}

		// or not?
		return GetAFreeSpace();
	}
}

/** Returns the number of bytes currently stored in the buffer.
 */
size_t CircularBuffer::GetSize()
{
	return m_regionASize + m_regionBSize;
}

/** Returns the number of contiguous bytes (that can be pushed out in one operation)
 */
size_t CircularBuffer::GetContiguiousBytes()
{
	if( m_regionASize )			// A before B
		return m_regionASize;
	else
		return m_regionBSize;
}

/** Removes len bytes from the front of the buffer
 * @param len the number of bytes to "cut"
 */
void CircularBuffer::Remove(size_t len)
{
	// remove from A first before we remove from b
	size_t cnt = len;
	size_t aRem, bRem;

	// If we have both region A and region B, always "finish" off region A first, as
	// this will contain the "oldest" data
	if( m_regionASize > 0 )
	{
		aRem = (cnt > m_regionASize) ? m_regionASize : cnt;
		m_regionASize -= aRem;
		m_regionAPointer += aRem;
		cnt -= aRem;
	}

	// Data left over? cut the data from buffer B
	if( cnt > 0 && m_regionBSize > 0 )
	{
		bRem = (cnt > m_regionBSize) ? m_regionBSize : cnt;
		m_regionBSize -= bRem;
		m_regionBPointer += bRem;
		cnt -= bRem;
	}

	// is buffer A empty? move buffer B to buffer A, to increase future performance
	if( m_regionASize == 0 )
	{
		if( m_regionBSize > 0 )
		{
			// push it all to the start of the buffer.
			if( m_regionBPointer != m_buffer )
				memmove(m_buffer, m_regionBPointer, m_regionBSize);

			m_regionAPointer = m_buffer;
			m_regionASize = m_regionBSize;
			m_regionBPointer = NULL;
			m_regionBSize = 0;
		}
		else
		{
			// no data in region b
			m_regionBPointer = NULL;
			m_regionBSize = 0;
			m_regionAPointer = m_buffer;
			m_regionASize = 0;
		}
	}
}

/** Returns a pointer at the "end" of the buffer, where new data can be written
 */
void * CircularBuffer::GetBuffer()
{
	if( m_regionBPointer != NULL )
		return m_regionBPointer + m_regionBSize;
	else
		return m_regionAPointer + m_regionASize;
}

/** Allocate the buffer with room for size bytes
 * @param size the number of bytes to allocate
 */
void CircularBuffer::Allocate(size_t size)
{
	m_buffer = (uint8*)malloc(size);
	m_bufferEnd = m_buffer + size;
	m_regionAPointer = m_buffer;		// reset A to the start
}

/** Increments the "writen" pointer forward len bytes
 * @param len number of bytes to step
 */
void CircularBuffer::IncrementWritten(size_t len)			// known as "commit"
{
	if( m_regionBPointer != NULL )
		m_regionBSize += len;
	else
		m_regionASize += len;
}

/** Returns a pointer at the "beginning" of the buffer, where data can be pulled from
 */
void * CircularBuffer::GetBufferStart()
{
	if( m_regionASize > 0 )
		return m_regionAPointer;
	else
		return m_regionBPointer;

}
<|endoftext|>


<commit_before>/*
    Copyright (C) 1998 by Jorrit Tyberghein

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

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

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "cssysdef.h"
#include "util.h"
#include "isound/loader.h"
#include "soundraw.h"
#include "sndload.h"

// Microsoft Wav file loader
//  support 8 and 16 bits PCM (RIFF)

class csSoundLoader_WAV : public iSoundLoader
{
public:
  DECLARE_IBASE;

  csSoundLoader_WAV(iBase *p) {
    CONSTRUCT_IBASE(p);
  }
  virtual bool Initialize(iSystem *) {
    return true;
  }
  virtual iSoundData *LoadSound(void *Buffer, unsigned long Size) const;
};

IMPLEMENT_IBASE(csSoundLoader_WAV)
  IMPLEMENTS_INTERFACE(iSoundLoader)
  IMPLEMENTS_INTERFACE(iPlugIn)
IMPLEMENT_IBASE_END;

IMPLEMENT_FACTORY(csSoundLoader_WAV);

struct _WAVchk
{
  char chunk[4];
  unsigned long len;
} wavchk;

struct _WAVhdr
{
  char format[4];
  unsigned long f_len;
  char fmt[8];
  unsigned long fmt_len;
  unsigned short fmt_tag;
  unsigned short channel;
  unsigned long samples_per_sec;
  unsigned long avg_bytes_per_sec;
  unsigned short blk_align;
  unsigned short bits_per_sample;
} wavhdr;

#define setStream(x) {if(x>size) {goto exit_read;} else {index=x;}}
#define canAddStream(x) {if((index+x)>size) goto exit_read;}
#define addStream(x) {if((index+x)>size) {goto exit_read;} else {index+=x;}}
#define Stream buf[index]

iSoundData *csSoundLoader_WAV::LoadSound(void *databuf, ULong size) const {
  UByte *buf = (UByte*) databuf;
  int index=0;

  csSoundDataRaw *sb= NULL;
  char *data=NULL;
  UByte *ptr;
  UByte *ptr_end;

  memset(&wavhdr, 0, sizeof(wavhdr));
  if(size<sizeof(wavhdr)) goto exit_read;

  if(memcpy(&wavhdr, &Stream, sizeof(wavhdr))==NULL)
    goto exit_read;
  canAddStream(sizeof(wavhdr));
  addStream(sizeof(wavhdr));

  if(memcmp(wavhdr.format, "RIFF", 4))
    goto exit_read;

  if(memcmp(wavhdr.fmt, "WAVEfmt ", 8))
    goto exit_read;

#ifdef CS_BIG_ENDIAN
  wavhdr.f_len = ByteSwap32bit( wavhdr.f_len );
  wavhdr.fmt_len = ByteSwap32bit( wavhdr.fmt_len );
  wavhdr.fmt_tag = ByteSwap16bit( wavhdr.fmt_tag );
  wavhdr.channel = ByteSwap16bit( wavhdr.channel );
  wavhdr.samples_per_sec = ByteSwap32bit( wavhdr.samples_per_sec );
  wavhdr.avg_bytes_per_sec = ByteSwap32bit( wavhdr.avg_bytes_per_sec );
  wavhdr.blk_align = ByteSwap16bit( wavhdr.blk_align );
  wavhdr.bits_per_sample = ByteSwap16bit( wavhdr.bits_per_sample );
#endif // CS_BIG_ENDIAN

  if(!((wavhdr.channel == 1) || (wavhdr.channel == 2)))
    goto exit_read;

  ptr=&Stream;
  ptr_end=ptr+size;
  while(ptr<ptr_end)
  {
    memcpy(&wavchk, ptr, sizeof(wavchk));
#ifdef CS_BIG_ENDIAN
    wavchk.len = ByteSwap32bit( wavchk.len );
#endif // CS_BIG_ENDIAN

    ptr+=sizeof(wavchk);
    if(memcmp(wavchk.chunk, "data", 4)==0)
      break;
    ptr+=wavchk.len;
  }

  data=new char[wavchk.len];
  if(data==NULL)
    goto exit_read;

  if(memcpy(data, ptr, wavchk.len)==NULL)
    goto exit_read;

#ifdef CS_BIG_ENDIAN
  if ( wavhdr.bits_per_sample==16 ) {
    ByteSwap16bitBuffer( (unsigned short *)data, wavchk.len / 2 );
  }
#endif // CS_BIG_ENDIAN

  csSoundFormat Format;
  Format.Freq=wavhdr.samples_per_sec;
  Format.Bits=wavhdr.bits_per_sample;
  Format.Channels=wavhdr.channel;
  sb=new csSoundDataRaw(NULL, data,
    (wavhdr.bits_per_sample==16)?(wavchk.len/2)-1:wavchk.len-1, Format);

  goto exit_ok;
exit_read:
  if(data) delete [] data;

exit_ok:
  return sb;
}
<commit_msg>Corrected the include to util.h and fixed a very freaky compile error it generated in VC6. :-)<commit_after>/*
    Copyright (C) 1998 by Jorrit Tyberghein

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

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

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "cssysdef.h"
#include "csutil/util.h"
#include "isound/loader.h"
#include "soundraw.h"
#include "sndload.h"

// Microsoft Wav file loader
//  support 8 and 16 bits PCM (RIFF)

class csSoundLoader_WAV : public iSoundLoader
{
public:
  DECLARE_IBASE;

  csSoundLoader_WAV(iBase *p) {
    CONSTRUCT_IBASE(p);
  }
  virtual bool Initialize(iSystem *) {
    return true;
  }
  virtual iSoundData *LoadSound(void *Buffer, unsigned long Size) const;
};

IMPLEMENT_IBASE(csSoundLoader_WAV)
  IMPLEMENTS_INTERFACE(iSoundLoader)
  IMPLEMENTS_INTERFACE(iPlugIn)
IMPLEMENT_IBASE_END;

IMPLEMENT_FACTORY(csSoundLoader_WAV);

struct _WAVchk
{
  char chunk[4];
  unsigned long len;
} wavchk;

struct _WAVhdr
{
  char format[4];
  unsigned long f_len;
  char fmt[8];
  unsigned long fmt_len;
  unsigned short fmt_tag;
  unsigned short channel;
  unsigned long samples_per_sec;
  unsigned long avg_bytes_per_sec;
  unsigned short blk_align;
  unsigned short bits_per_sample;
} wavhdr;

#define setStream(x) {if(x>size) {goto exit_read;} else {index=x;}}
#define canAddStream(x) {if((index+x)>size) goto exit_read;}
#define addStream(x) {if((index+x)>size) {goto exit_read;} else {index+=x;}}
#define Stream buf[index]

iSoundData *csSoundLoader_WAV::LoadSound(void *databuf, ULong size) const {
  UByte *buf = (UByte*) databuf;
  int index=0;

  csSoundDataRaw *sb= NULL;
  char *data=NULL;
  UByte *ptr;
  UByte *ptr_end;

  memset(&wavhdr, 0, sizeof(wavhdr));
  if(size<sizeof(wavhdr)) goto exit_read;

  if(memcpy(&wavhdr, &Stream, sizeof(wavhdr))==NULL)
    goto exit_read;
  canAddStream(sizeof(wavhdr));
  addStream(sizeof(wavhdr));

  if(memcmp(wavhdr.format, "RIFF", 4))
    goto exit_read;

  if(memcmp(wavhdr.fmt, "WAVEfmt ", 8))
    goto exit_read;

#ifdef CS_BIG_ENDIAN
  wavhdr.f_len = ByteSwap32bit( wavhdr.f_len );
  wavhdr.fmt_len = ByteSwap32bit( wavhdr.fmt_len );
  wavhdr.fmt_tag = ByteSwap16bit( wavhdr.fmt_tag );
  wavhdr.channel = ByteSwap16bit( wavhdr.channel );
  wavhdr.samples_per_sec = ByteSwap32bit( wavhdr.samples_per_sec );
  wavhdr.avg_bytes_per_sec = ByteSwap32bit( wavhdr.avg_bytes_per_sec );
  wavhdr.blk_align = ByteSwap16bit( wavhdr.blk_align );
  wavhdr.bits_per_sample = ByteSwap16bit( wavhdr.bits_per_sample );
#endif // CS_BIG_ENDIAN

  if(!((wavhdr.channel == 1) || (wavhdr.channel == 2)))
    goto exit_read;

  ptr=&Stream;
  ptr_end=ptr+size;
  while(ptr<ptr_end)
  {
    memcpy(&wavchk, ptr, sizeof(wavchk));
#ifdef CS_BIG_ENDIAN
    wavchk.len = ByteSwap32bit( wavchk.len );
#endif // CS_BIG_ENDIAN

    ptr+=sizeof(wavchk);
    if(memcmp(wavchk.chunk, "data", 4)==0)
      break;
    ptr+=wavchk.len;
  }

  data=new char[wavchk.len];
  if(data==NULL)
    goto exit_read;

  if(memcpy(data, ptr, wavchk.len)==NULL)
    goto exit_read;

#ifdef CS_BIG_ENDIAN
  if ( wavhdr.bits_per_sample==16 ) {
    ByteSwap16bitBuffer( (unsigned short *)data, wavchk.len / 2 );
  }
#endif // CS_BIG_ENDIAN

  csSoundFormat Format;
  Format.Freq=wavhdr.samples_per_sec;
  Format.Bits=wavhdr.bits_per_sample;
  Format.Channels=wavhdr.channel;
  sb=new csSoundDataRaw(NULL, data,
    (wavhdr.bits_per_sample==16)?(wavchk.len/2)-1:wavchk.len-1, Format);

  goto exit_ok;
exit_read:
  if(data) delete [] data;

exit_ok:
  return sb;
}
<|endoftext|>


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

  This source file is part of the tomviz project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

******************************************************************************/
#include "HistogramWidget.h"

#include "ActiveObjects.h"
#include "DataSource.h"
#include "ModuleContour.h"
#include "ModuleManager.h"
#include "QVTKGLWidget.h"
#include "Utilities.h"

#include "vtkChartHistogramColorOpacityEditor.h"

#include <vtkContextScene.h>
#include <vtkContextView.h>
#include <vtkControlPointsItem.h>
#include <vtkEventQtSlotConnect.h>
#include <vtkPiecewiseFunction.h>
#include <vtkRenderWindow.h>
#include <vtkVector.h>

#include <pqApplicationCore.h>
#include <pqCoreUtilities.h>
#include <pqPresetDialog.h>
#include <pqRescaleRange.h>
#include <pqResetScalarRangeReaction.h>
#include <pqServerManagerModel.h>
#include <pqView.h>

#include <vtkPVDiscretizableColorTransferFunction.h>
#include <vtkSMPropertyHelper.h>
#include <vtkSMTransferFunctionManager.h>
#include <vtkSMTransferFunctionProxy.h>
#include <vtkSMViewProxy.h>

#include <QCheckBox>
#include <QColorDialog>
#include <QHBoxLayout>
#include <QToolButton>
#include <QVBoxLayout>

#include <QDebug>

namespace tomviz {

HistogramWidget::HistogramWidget(QWidget* parent)
  : QWidget(parent), m_qvtk(new QVTKGLWidget(this))
{
  // Set up our little chart.
  m_histogramView->SetRenderWindow(m_qvtk->GetRenderWindow());
  m_histogramView->SetInteractor(m_qvtk->GetInteractor());
  m_histogramView->GetScene()->AddItem(m_histogramColorOpacityEditor.Get());

  // Connect events from the histogram color/opacity editor.
  m_eventLink->Connect(m_histogramColorOpacityEditor.Get(),
                       vtkCommand::CursorChangedEvent,
                       this,
                       SLOT(histogramClicked(vtkObject*)));
  m_eventLink->Connect(m_histogramColorOpacityEditor.Get(),
                       vtkCommand::EndEvent,
                       this,
                       SLOT(onScalarOpacityFunctionChanged()));
  m_eventLink->Connect(m_histogramColorOpacityEditor.Get(),
                       vtkControlPointsItem::CurrentPointEditEvent,
                       this,
                       SLOT(onCurrentPointEditEvent()));

  auto hLayout = new QHBoxLayout(this);
  hLayout->addWidget(m_qvtk);
  auto vLayout = new QVBoxLayout;
  hLayout->addLayout(vLayout);
  hLayout->setContentsMargins(0, 0, 5, 0);

  vLayout->setContentsMargins(0, 0, 0, 0);
  vLayout->addStretch(1);

  auto button = new QToolButton;
  button->setIcon(QIcon(":/icons/pqResetRange.png"));
  button->setToolTip("Reset data range");
  connect(button, SIGNAL(clicked()), this, SLOT(onResetRangeClicked()));
  vLayout->addWidget(button);

  button = new QToolButton;
  button->setIcon(QIcon(":/icons/pqResetRangeCustom.png"));
  button->setToolTip("Specify data range");
  connect(button, SIGNAL(clicked()), this, SLOT(onCustomRangeClicked()));
  vLayout->addWidget(button);

  button = new QToolButton;
  button->setIcon(QIcon(":/icons/pqInvert.png"));
  button->setToolTip("Invert color map");
  connect(button, SIGNAL(clicked()), this, SLOT(onInvertClicked()));
  vLayout->addWidget(button);

  button = new QToolButton;
  button->setIcon(QIcon(":/icons/pqFavorites.png"));
  button->setToolTip("Choose preset color map");
  connect(button, SIGNAL(clicked()), this, SLOT(onPresetClicked()));
  vLayout->addWidget(button);

  button = new QToolButton;
  m_colorLegendToolButton = button;
  button->setIcon(QIcon(":/pqWidgets/Icons/pqScalarBar24.png"));
  button->setToolTip("Show color legend in the 3D window.");
  button->setCheckable(true);
  connect(button, SIGNAL(toggled(bool)), this, SIGNAL(colorLegendToggled(bool)));
  button->setChecked(false);
  vLayout->addWidget(button);

  vLayout->addStretch(1);

  connect(&ActiveObjects::instance(), SIGNAL(viewChanged(vtkSMViewProxy*)),
          this, SLOT(updateUI()));
  connect(this, SIGNAL(colorMapUpdated()), this, SLOT(updateUI()));

  setLayout(hLayout);
}

HistogramWidget::~HistogramWidget() = default;

void HistogramWidget::setLUT(vtkPVDiscretizableColorTransferFunction* lut)
{
  if (m_LUT != lut) {
    if (m_scalarOpacityFunction) {
      m_eventLink->Disconnect(m_scalarOpacityFunction,
                              vtkCommand::ModifiedEvent,
                              this,
                              SLOT(onScalarOpacityFunctionChanged()));
    }
    m_LUT = lut;
    m_scalarOpacityFunction = m_LUT->GetScalarOpacityFunction();
    m_eventLink->Connect(m_scalarOpacityFunction,
                         vtkCommand::ModifiedEvent,
                         this,
                         SLOT(onScalarOpacityFunctionChanged()));
    emit colorMapUpdated();
  }
}

void HistogramWidget::setLUTProxy(vtkSMProxy* proxy)
{
  if (m_LUTProxy != proxy) {
    m_LUTProxy = proxy;
    vtkPVDiscretizableColorTransferFunction* lut =
      vtkPVDiscretizableColorTransferFunction::SafeDownCast(
        proxy->GetClientSideObject());
    setLUT(lut);

    auto view = ActiveObjects::instance().activeView();

    // Update widget to reflect scalar bar visibility.
    if (m_LUTProxy) {
      auto sbProxy = getScalarBarRepresentation(view);
      if (sbProxy) {
        bool visible = vtkSMPropertyHelper(sbProxy, "Visibility").GetAsInt() == 1;
        m_colorLegendToolButton->setChecked(visible);
      }
    }
  }
}

void HistogramWidget::setInputData(vtkTable* table,
                                   const char* x_,
                                   const char* y_)
{
  m_histogramColorOpacityEditor->SetHistogramInputData(table, x_, y_);
  m_histogramColorOpacityEditor->SetOpacityFunction(m_scalarOpacityFunction);
  if (m_LUT && table) {
    m_histogramColorOpacityEditor->SetScalarVisibility(true);
    m_histogramColorOpacityEditor->SetColorTransferFunction(m_LUT);
    m_histogramColorOpacityEditor->SelectColorArray("image_extents");
  }
  m_histogramView->Render();
}

vtkSMProxy* HistogramWidget::getScalarBarRepresentation(vtkSMProxy* view)
{
  if (!view) {
    return nullptr;
  }

  vtkSMTransferFunctionProxy* tferProxy =
    vtkSMTransferFunctionProxy::SafeDownCast(m_LUTProxy);
  Q_ASSERT(tferProxy);

  auto sbProxy = tferProxy->FindScalarBarRepresentation(view);
  if (!sbProxy) {
    // No scalar bar representation exists yet, create it and initialize it
    // with some default settings.
    vtkNew<vtkSMTransferFunctionManager> tferManager;
    sbProxy = tferManager->GetScalarBarRepresentation(m_LUTProxy, view);
    vtkSMPropertyHelper(sbProxy, "Visibility").Set(0);
    vtkSMPropertyHelper(sbProxy, "Enabled").Set(0);
    vtkSMPropertyHelper(sbProxy, "Title").Set("");
    vtkSMPropertyHelper(sbProxy, "ComponentTitle").Set("");
    sbProxy->UpdateVTKObjects();
  }

  return sbProxy;
}

void HistogramWidget::onScalarOpacityFunctionChanged()
{
  auto core = pqApplicationCore::instance();
  auto smModel = core->getServerManagerModel();
  QList<pqView*> views = smModel->findItems<pqView*>();
  foreach (pqView* view, views) {
    view->render();
  }

  // Update the histogram
  m_histogramView->GetRenderWindow()->Render();

  // Update the scalar opacity function proxy as it does not update it's
  // internal state when the VTK object changes.
  if (!m_LUTProxy) {
    return;
  }

  vtkSMProxy* opacityMapProxy =
    vtkSMPropertyHelper(m_LUTProxy, "ScalarOpacityFunction", true).GetAsProxy();
  if (!opacityMapProxy) {
    return;
  }

  vtkSMPropertyHelper pointsHelper(opacityMapProxy, "Points");
  vtkObjectBase* opacityMapObject = opacityMapProxy->GetClientSideObject();
  auto pwf = vtkPiecewiseFunction::SafeDownCast(opacityMapObject);
  if (pwf) {
    pointsHelper.SetNumberOfElements(4 * pwf->GetSize());
    for (int i = 0; i < pwf->GetSize(); ++i) {
      double value[4];
      pwf->GetNodeValue(i, value);
      pointsHelper.Set(4 * i + 0, value[0]);
      pointsHelper.Set(4 * i + 1, value[1]);
      pointsHelper.Set(4 * i + 2, value[2]);
      pointsHelper.Set(4 * i + 3, value[3]);
    }
  }

  emit opacityChanged();
}

void HistogramWidget::onCurrentPointEditEvent()
{
  double rgb[3];
  if (m_histogramColorOpacityEditor->GetCurrentControlPointColor(rgb)) {
    QColor color =
      QColorDialog::getColor(QColor::fromRgbF(rgb[0], rgb[1], rgb[2]),
                             this,
                             "Select Color for Control Point",
                             QColorDialog::DontUseNativeDialog);
    if (color.isValid()) {
      rgb[0] = color.redF();
      rgb[1] = color.greenF();
      rgb[2] = color.blueF();
      m_histogramColorOpacityEditor->SetCurrentControlPointColor(rgb);
      onScalarOpacityFunctionChanged();
    }
  }
}

void HistogramWidget::histogramClicked(vtkObject*)
{
  auto activeDataSource = ActiveObjects::instance().activeDataSource();
  Q_ASSERT(activeDataSource);

  auto view = ActiveObjects::instance().activeView();
  if (!view) {
    return;
  }

  // Use active ModuleContour is possible. Otherwise, find the first existing
  // ModuleContour instance or just create a new one, if none exists.
  typedef ModuleContour ModuleContourType;

  auto contour =
    qobject_cast<ModuleContourType*>(ActiveObjects::instance().activeModule());
  if (!contour) {
    QList<ModuleContourType*> contours =
      ModuleManager::instance().findModules<ModuleContourType*>(
        activeDataSource, view);
    if (contours.size() == 0) {
      contour = qobject_cast<ModuleContourType*>(
        ModuleManager::instance().createAndAddModule(
          "Contour", activeDataSource, view));
    } else {
      contour = contours[0];
    }
    ActiveObjects::instance().setActiveModule(contour);
  }
  Q_ASSERT(contour);
  contour->setIsoValue(m_histogramColorOpacityEditor->GetContourValue());
  tomviz::convert<pqView*>(view)->render();
}

void HistogramWidget::onResetRangeClicked()
{
  pqResetScalarRangeReaction::resetScalarRangeToData(nullptr);
}

void HistogramWidget::onCustomRangeClicked()
{
  vtkVector2d range;
  vtkDiscretizableColorTransferFunction* discFunc =
    vtkDiscretizableColorTransferFunction::SafeDownCast(
      m_LUTProxy->GetClientSideObject());
  if (!discFunc) {
    return;
  }
  discFunc->GetRange(range.GetData());
  pqRescaleRange dialog(pqCoreUtilities::mainWidget());
  dialog.setRange(range[0], range[1]);
  if (dialog.exec() == QDialog::Accepted) {
    vtkSMTransferFunctionProxy::RescaleTransferFunction(
      m_LUTProxy, dialog.minimum(), dialog.maximum());
  }
  renderViews();
  emit colorMapUpdated();
}

void HistogramWidget::onInvertClicked()
{
  vtkSMTransferFunctionProxy::InvertTransferFunction(m_LUTProxy);
  renderViews();
  emit colorMapUpdated();
}

void HistogramWidget::onPresetClicked()
{
  pqPresetDialog dialog(pqCoreUtilities::mainWidget(),
                        pqPresetDialog::SHOW_NON_INDEXED_COLORS_ONLY);
  dialog.setCustomizableLoadColors(true);
  dialog.setCustomizableLoadOpacities(true);
  dialog.setCustomizableUsePresetRange(true);
  dialog.setCustomizableLoadAnnotations(false);
  connect(&dialog,
          SIGNAL(applyPreset(const Json::Value&)),
          SLOT(applyCurrentPreset()));
  dialog.exec();
}

void HistogramWidget::applyCurrentPreset()
{
  auto dialog = qobject_cast<pqPresetDialog*>(sender());
  Q_ASSERT(dialog);

  vtkSMProxy* lut = m_LUTProxy;
  if (!lut) {
    return;
  }

  if (dialog->loadColors() || dialog->loadOpacities()) {
    vtkSMProxy* sof =
      vtkSMPropertyHelper(lut, "ScalarOpacityFunction", true).GetAsProxy();
    if (dialog->loadColors()) {
      vtkSMTransferFunctionProxy::ApplyPreset(
        lut, dialog->currentPreset(), !dialog->usePresetRange());
    }
    if (dialog->loadOpacities()) {
      if (sof) {
        vtkSMTransferFunctionProxy::ApplyPreset(
          sof, dialog->currentPreset(), !dialog->usePresetRange());
      } else {
        qWarning("Cannot load opacities since 'ScalarOpacityFunction' is not "
                 "present.");
      }
    }

    // We need to take extra care to avoid the color and opacity function ranges
    // from straying away from each other. This can happen if only one of them
    // is getting a preset and we're using the preset range.
    if (dialog->usePresetRange() &&
        (dialog->loadColors() ^ dialog->loadOpacities()) && sof) {
      double range[2];
      if (dialog->loadColors() &&
          vtkSMTransferFunctionProxy::GetRange(lut, range)) {
        vtkSMTransferFunctionProxy::RescaleTransferFunction(sof, range);
      } else if (dialog->loadOpacities() &&
                 vtkSMTransferFunctionProxy::GetRange(sof, range)) {
        vtkSMTransferFunctionProxy::RescaleTransferFunction(lut, range);
      }
    }
    renderViews();
    emit colorMapUpdated();
  }
}

void HistogramWidget::updateUI()
{
  auto view = ActiveObjects::instance().activeView();

  // Update widget to reflect scalar bar visibility.
  if (m_LUTProxy) {
    auto sbProxy = getScalarBarRepresentation(view);
    if (view && sbProxy) {
      m_colorLegendToolButton->blockSignals(true);
      m_colorLegendToolButton->
        setChecked(vtkSMPropertyHelper(sbProxy, "Visibility").GetAsInt() == 1);
      m_colorLegendToolButton->blockSignals(false);
    }
  }
}

void HistogramWidget::renderViews()
{
  pqView* view =
    tomviz::convert<pqView*>(ActiveObjects::instance().activeView());
  if (view) {
    view->render();
  }
}

void HistogramWidget::showEvent(QShowEvent* event)
{
  QWidget::showEvent(event);
  this->renderViews();
}
}
<commit_msg>Modify the RangeLabelFormat for the scalar bar<commit_after>/******************************************************************************

  This source file is part of the tomviz project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

******************************************************************************/
#include "HistogramWidget.h"

#include "ActiveObjects.h"
#include "DataSource.h"
#include "ModuleContour.h"
#include "ModuleManager.h"
#include "QVTKGLWidget.h"
#include "Utilities.h"

#include "vtkChartHistogramColorOpacityEditor.h"

#include <vtkContextScene.h>
#include <vtkContextView.h>
#include <vtkControlPointsItem.h>
#include <vtkEventQtSlotConnect.h>
#include <vtkPiecewiseFunction.h>
#include <vtkRenderWindow.h>
#include <vtkVector.h>

#include <pqApplicationCore.h>
#include <pqCoreUtilities.h>
#include <pqPresetDialog.h>
#include <pqRescaleRange.h>
#include <pqResetScalarRangeReaction.h>
#include <pqServerManagerModel.h>
#include <pqView.h>

#include <vtkPVDiscretizableColorTransferFunction.h>
#include <vtkSMPropertyHelper.h>
#include <vtkSMTransferFunctionManager.h>
#include <vtkSMTransferFunctionProxy.h>
#include <vtkSMViewProxy.h>

#include <QCheckBox>
#include <QColorDialog>
#include <QHBoxLayout>
#include <QToolButton>
#include <QVBoxLayout>

#include <QDebug>

namespace tomviz {

HistogramWidget::HistogramWidget(QWidget* parent)
  : QWidget(parent), m_qvtk(new QVTKGLWidget(this))
{
  // Set up our little chart.
  m_histogramView->SetRenderWindow(m_qvtk->GetRenderWindow());
  m_histogramView->SetInteractor(m_qvtk->GetInteractor());
  m_histogramView->GetScene()->AddItem(m_histogramColorOpacityEditor.Get());

  // Connect events from the histogram color/opacity editor.
  m_eventLink->Connect(m_histogramColorOpacityEditor.Get(),
                       vtkCommand::CursorChangedEvent,
                       this,
                       SLOT(histogramClicked(vtkObject*)));
  m_eventLink->Connect(m_histogramColorOpacityEditor.Get(),
                       vtkCommand::EndEvent,
                       this,
                       SLOT(onScalarOpacityFunctionChanged()));
  m_eventLink->Connect(m_histogramColorOpacityEditor.Get(),
                       vtkControlPointsItem::CurrentPointEditEvent,
                       this,
                       SLOT(onCurrentPointEditEvent()));

  auto hLayout = new QHBoxLayout(this);
  hLayout->addWidget(m_qvtk);
  auto vLayout = new QVBoxLayout;
  hLayout->addLayout(vLayout);
  hLayout->setContentsMargins(0, 0, 5, 0);

  vLayout->setContentsMargins(0, 0, 0, 0);
  vLayout->addStretch(1);

  auto button = new QToolButton;
  button->setIcon(QIcon(":/icons/pqResetRange.png"));
  button->setToolTip("Reset data range");
  connect(button, SIGNAL(clicked()), this, SLOT(onResetRangeClicked()));
  vLayout->addWidget(button);

  button = new QToolButton;
  button->setIcon(QIcon(":/icons/pqResetRangeCustom.png"));
  button->setToolTip("Specify data range");
  connect(button, SIGNAL(clicked()), this, SLOT(onCustomRangeClicked()));
  vLayout->addWidget(button);

  button = new QToolButton;
  button->setIcon(QIcon(":/icons/pqInvert.png"));
  button->setToolTip("Invert color map");
  connect(button, SIGNAL(clicked()), this, SLOT(onInvertClicked()));
  vLayout->addWidget(button);

  button = new QToolButton;
  button->setIcon(QIcon(":/icons/pqFavorites.png"));
  button->setToolTip("Choose preset color map");
  connect(button, SIGNAL(clicked()), this, SLOT(onPresetClicked()));
  vLayout->addWidget(button);

  button = new QToolButton;
  m_colorLegendToolButton = button;
  button->setIcon(QIcon(":/pqWidgets/Icons/pqScalarBar24.png"));
  button->setToolTip("Show color legend in the 3D window.");
  button->setCheckable(true);
  connect(button, SIGNAL(toggled(bool)), this, SIGNAL(colorLegendToggled(bool)));
  button->setChecked(false);
  vLayout->addWidget(button);

  vLayout->addStretch(1);

  connect(&ActiveObjects::instance(), SIGNAL(viewChanged(vtkSMViewProxy*)),
          this, SLOT(updateUI()));
  connect(this, SIGNAL(colorMapUpdated()), this, SLOT(updateUI()));

  setLayout(hLayout);
}

HistogramWidget::~HistogramWidget() = default;

void HistogramWidget::setLUT(vtkPVDiscretizableColorTransferFunction* lut)
{
  if (m_LUT != lut) {
    if (m_scalarOpacityFunction) {
      m_eventLink->Disconnect(m_scalarOpacityFunction,
                              vtkCommand::ModifiedEvent,
                              this,
                              SLOT(onScalarOpacityFunctionChanged()));
    }
    m_LUT = lut;
    m_scalarOpacityFunction = m_LUT->GetScalarOpacityFunction();
    m_eventLink->Connect(m_scalarOpacityFunction,
                         vtkCommand::ModifiedEvent,
                         this,
                         SLOT(onScalarOpacityFunctionChanged()));
    emit colorMapUpdated();
  }
}

void HistogramWidget::setLUTProxy(vtkSMProxy* proxy)
{
  if (m_LUTProxy != proxy) {
    m_LUTProxy = proxy;
    vtkPVDiscretizableColorTransferFunction* lut =
      vtkPVDiscretizableColorTransferFunction::SafeDownCast(
        proxy->GetClientSideObject());
    setLUT(lut);

    auto view = ActiveObjects::instance().activeView();

    // Update widget to reflect scalar bar visibility.
    if (m_LUTProxy) {
      auto sbProxy = getScalarBarRepresentation(view);
      if (sbProxy) {
        bool visible = vtkSMPropertyHelper(sbProxy, "Visibility").GetAsInt() == 1;
        m_colorLegendToolButton->setChecked(visible);
      }
    }
  }
}

void HistogramWidget::setInputData(vtkTable* table,
                                   const char* x_,
                                   const char* y_)
{
  m_histogramColorOpacityEditor->SetHistogramInputData(table, x_, y_);
  m_histogramColorOpacityEditor->SetOpacityFunction(m_scalarOpacityFunction);
  if (m_LUT && table) {
    m_histogramColorOpacityEditor->SetScalarVisibility(true);
    m_histogramColorOpacityEditor->SetColorTransferFunction(m_LUT);
    m_histogramColorOpacityEditor->SelectColorArray("image_extents");
  }
  m_histogramView->Render();
}

vtkSMProxy* HistogramWidget::getScalarBarRepresentation(vtkSMProxy* view)
{
  if (!view) {
    return nullptr;
  }

  vtkSMTransferFunctionProxy* tferProxy =
    vtkSMTransferFunctionProxy::SafeDownCast(m_LUTProxy);
  Q_ASSERT(tferProxy);

  auto sbProxy = tferProxy->FindScalarBarRepresentation(view);
  if (!sbProxy) {
    // No scalar bar representation exists yet, create it and initialize it
    // with some default settings.
    vtkNew<vtkSMTransferFunctionManager> tferManager;
    sbProxy = tferManager->GetScalarBarRepresentation(m_LUTProxy, view);
    vtkSMPropertyHelper(sbProxy, "Visibility").Set(0);
    vtkSMPropertyHelper(sbProxy, "Enabled").Set(0);
    vtkSMPropertyHelper(sbProxy, "Title").Set("");
    vtkSMPropertyHelper(sbProxy, "ComponentTitle").Set("");
    vtkSMPropertyHelper(sbProxy, "RangeLabelFormat").Set("%g");
    sbProxy->UpdateVTKObjects();
  }

  return sbProxy;
}

void HistogramWidget::onScalarOpacityFunctionChanged()
{
  auto core = pqApplicationCore::instance();
  auto smModel = core->getServerManagerModel();
  QList<pqView*> views = smModel->findItems<pqView*>();
  foreach (pqView* view, views) {
    view->render();
  }

  // Update the histogram
  m_histogramView->GetRenderWindow()->Render();

  // Update the scalar opacity function proxy as it does not update it's
  // internal state when the VTK object changes.
  if (!m_LUTProxy) {
    return;
  }

  vtkSMProxy* opacityMapProxy =
    vtkSMPropertyHelper(m_LUTProxy, "ScalarOpacityFunction", true).GetAsProxy();
  if (!opacityMapProxy) {
    return;
  }

  vtkSMPropertyHelper pointsHelper(opacityMapProxy, "Points");
  vtkObjectBase* opacityMapObject = opacityMapProxy->GetClientSideObject();
  auto pwf = vtkPiecewiseFunction::SafeDownCast(opacityMapObject);
  if (pwf) {
    pointsHelper.SetNumberOfElements(4 * pwf->GetSize());
    for (int i = 0; i < pwf->GetSize(); ++i) {
      double value[4];
      pwf->GetNodeValue(i, value);
      pointsHelper.Set(4 * i + 0, value[0]);
      pointsHelper.Set(4 * i + 1, value[1]);
      pointsHelper.Set(4 * i + 2, value[2]);
      pointsHelper.Set(4 * i + 3, value[3]);
    }
  }

  emit opacityChanged();
}

void HistogramWidget::onCurrentPointEditEvent()
{
  double rgb[3];
  if (m_histogramColorOpacityEditor->GetCurrentControlPointColor(rgb)) {
    QColor color =
      QColorDialog::getColor(QColor::fromRgbF(rgb[0], rgb[1], rgb[2]),
                             this,
                             "Select Color for Control Point",
                             QColorDialog::DontUseNativeDialog);
    if (color.isValid()) {
      rgb[0] = color.redF();
      rgb[1] = color.greenF();
      rgb[2] = color.blueF();
      m_histogramColorOpacityEditor->SetCurrentControlPointColor(rgb);
      onScalarOpacityFunctionChanged();
    }
  }
}

void HistogramWidget::histogramClicked(vtkObject*)
{
  auto activeDataSource = ActiveObjects::instance().activeDataSource();
  Q_ASSERT(activeDataSource);

  auto view = ActiveObjects::instance().activeView();
  if (!view) {
    return;
  }

  // Use active ModuleContour is possible. Otherwise, find the first existing
  // ModuleContour instance or just create a new one, if none exists.
  typedef ModuleContour ModuleContourType;

  auto contour =
    qobject_cast<ModuleContourType*>(ActiveObjects::instance().activeModule());
  if (!contour) {
    QList<ModuleContourType*> contours =
      ModuleManager::instance().findModules<ModuleContourType*>(
        activeDataSource, view);
    if (contours.size() == 0) {
      contour = qobject_cast<ModuleContourType*>(
        ModuleManager::instance().createAndAddModule(
          "Contour", activeDataSource, view));
    } else {
      contour = contours[0];
    }
    ActiveObjects::instance().setActiveModule(contour);
  }
  Q_ASSERT(contour);
  contour->setIsoValue(m_histogramColorOpacityEditor->GetContourValue());
  tomviz::convert<pqView*>(view)->render();
}

void HistogramWidget::onResetRangeClicked()
{
  pqResetScalarRangeReaction::resetScalarRangeToData(nullptr);
}

void HistogramWidget::onCustomRangeClicked()
{
  vtkVector2d range;
  vtkDiscretizableColorTransferFunction* discFunc =
    vtkDiscretizableColorTransferFunction::SafeDownCast(
      m_LUTProxy->GetClientSideObject());
  if (!discFunc) {
    return;
  }
  discFunc->GetRange(range.GetData());
  pqRescaleRange dialog(pqCoreUtilities::mainWidget());
  dialog.setRange(range[0], range[1]);
  if (dialog.exec() == QDialog::Accepted) {
    vtkSMTransferFunctionProxy::RescaleTransferFunction(
      m_LUTProxy, dialog.minimum(), dialog.maximum());
  }
  renderViews();
  emit colorMapUpdated();
}

void HistogramWidget::onInvertClicked()
{
  vtkSMTransferFunctionProxy::InvertTransferFunction(m_LUTProxy);
  renderViews();
  emit colorMapUpdated();
}

void HistogramWidget::onPresetClicked()
{
  pqPresetDialog dialog(pqCoreUtilities::mainWidget(),
                        pqPresetDialog::SHOW_NON_INDEXED_COLORS_ONLY);
  dialog.setCustomizableLoadColors(true);
  dialog.setCustomizableLoadOpacities(true);
  dialog.setCustomizableUsePresetRange(true);
  dialog.setCustomizableLoadAnnotations(false);
  connect(&dialog,
          SIGNAL(applyPreset(const Json::Value&)),
          SLOT(applyCurrentPreset()));
  dialog.exec();
}

void HistogramWidget::applyCurrentPreset()
{
  auto dialog = qobject_cast<pqPresetDialog*>(sender());
  Q_ASSERT(dialog);

  vtkSMProxy* lut = m_LUTProxy;
  if (!lut) {
    return;
  }

  if (dialog->loadColors() || dialog->loadOpacities()) {
    vtkSMProxy* sof =
      vtkSMPropertyHelper(lut, "ScalarOpacityFunction", true).GetAsProxy();
    if (dialog->loadColors()) {
      vtkSMTransferFunctionProxy::ApplyPreset(
        lut, dialog->currentPreset(), !dialog->usePresetRange());
    }
    if (dialog->loadOpacities()) {
      if (sof) {
        vtkSMTransferFunctionProxy::ApplyPreset(
          sof, dialog->currentPreset(), !dialog->usePresetRange());
      } else {
        qWarning("Cannot load opacities since 'ScalarOpacityFunction' is not "
                 "present.");
      }
    }

    // We need to take extra care to avoid the color and opacity function ranges
    // from straying away from each other. This can happen if only one of them
    // is getting a preset and we're using the preset range.
    if (dialog->usePresetRange() &&
        (dialog->loadColors() ^ dialog->loadOpacities()) && sof) {
      double range[2];
      if (dialog->loadColors() &&
          vtkSMTransferFunctionProxy::GetRange(lut, range)) {
        vtkSMTransferFunctionProxy::RescaleTransferFunction(sof, range);
      } else if (dialog->loadOpacities() &&
                 vtkSMTransferFunctionProxy::GetRange(sof, range)) {
        vtkSMTransferFunctionProxy::RescaleTransferFunction(lut, range);
      }
    }
    renderViews();
    emit colorMapUpdated();
  }
}

void HistogramWidget::updateUI()
{
  auto view = ActiveObjects::instance().activeView();

  // Update widget to reflect scalar bar visibility.
  if (m_LUTProxy) {
    auto sbProxy = getScalarBarRepresentation(view);
    if (view && sbProxy) {
      m_colorLegendToolButton->blockSignals(true);
      m_colorLegendToolButton->
        setChecked(vtkSMPropertyHelper(sbProxy, "Visibility").GetAsInt() == 1);
      m_colorLegendToolButton->blockSignals(false);
    }
  }
}

void HistogramWidget::renderViews()
{
  pqView* view =
    tomviz::convert<pqView*>(ActiveObjects::instance().activeView());
  if (view) {
    view->render();
  }
}

void HistogramWidget::showEvent(QShowEvent* event)
{
  QWidget::showEvent(event);
  this->renderViews();
}
}
<|endoftext|>


<commit_before>/*
    Copyright 2012 Frederik Gladhorn <gladhorn@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) version 3, or any
    later version accepted by the membership of KDE e.V. (or its
    successor approved by the membership of KDE e.V.), which shall
    act as a proxy defined in Section 6 of version 3 of the license.

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library.  If not, see <http://www.gnu.org/licenses/>.
*/

#define QT_GUI_LIB
#include <qtest.h>

#include <qpushbutton.h>
#include <qdebug.h>

#include "accessible/registry.h"
#include "accessible/accessibleobject.h"

#include "atspi/dbusconnection.h"

using namespace KAccessibleClient;

class AccessibilityClientTest :public QObject
{
    Q_OBJECT

private Q_SLOTS:
//    void initTestCase();
    void tst_navigation();

private:
    DBusConnection m_conn;
};

void AccessibilityClientTest::tst_navigation()
{
    QPushButton button;
    button.setText(QLatin1String("Hello a11y"));
    button.show();

    QTest::qWaitForWindowShown(&button);

    Registry r;

    QString appname = QLatin1String("Lib KAccessibleClient test");
    qApp->setApplicationName(appname);
    AccessibleObject app = r.applications().last();
    QVERIFY(app.isValid());
    QCOMPARE(app.name(), appname);

    QCOMPARE(app.childCount(), 1);
    AccessibleObject child1 = app.child(0);
    QVERIFY(child1.isValid());
    QCOMPARE(child1.name(), button.text());
    AccessibleObject child2 = app.children().first();
    QCOMPARE(child1, child2);
    AccessibleObject parent = child1.parent();
    QCOMPARE(parent, app);

    AccessibleObject invalidChild = child1.child(0);
    QVERIFY(!invalidChild.isValid());
    QVERIFY(invalidChild.name().isEmpty());

    AccessibleObject invalidParent = app.parent();
    QVERIFY(!invalidParent.isValid());
    QVERIFY(invalidParent.name().isEmpty());
}

QTEST_MAIN(AccessibilityClientTest)

#include "tst_accessibilityclient.moc"
<commit_msg>Remove unused var.<commit_after>/*
    Copyright 2012 Frederik Gladhorn <gladhorn@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) version 3, or any
    later version accepted by the membership of KDE e.V. (or its
    successor approved by the membership of KDE e.V.), which shall
    act as a proxy defined in Section 6 of version 3 of the license.

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library.  If not, see <http://www.gnu.org/licenses/>.
*/

#define QT_GUI_LIB
#include <qtest.h>

#include <qpushbutton.h>
#include <qdebug.h>

#include "accessible/registry.h"
#include "accessible/accessibleobject.h"

#include "atspi/dbusconnection.h"

using namespace KAccessibleClient;

class AccessibilityClientTest :public QObject
{
    Q_OBJECT

private Q_SLOTS:
    void tst_navigation();
};

void AccessibilityClientTest::tst_navigation()
{
    QPushButton button;
    button.setText(QLatin1String("Hello a11y"));
    button.show();

    QTest::qWaitForWindowShown(&button);

    Registry r;

    QString appname = QLatin1String("Lib KAccessibleClient test");
    qApp->setApplicationName(appname);
    AccessibleObject app = r.applications().last();
    QVERIFY(app.isValid());
    QCOMPARE(app.name(), appname);

    QCOMPARE(app.childCount(), 1);
    AccessibleObject child1 = app.child(0);
    QVERIFY(child1.isValid());
    QCOMPARE(child1.name(), button.text());
    AccessibleObject child2 = app.children().first();
    QCOMPARE(child1, child2);
    AccessibleObject parent = child1.parent();
    QCOMPARE(parent, app);

    AccessibleObject invalidChild = child1.child(0);
    QVERIFY(!invalidChild.isValid());
    QVERIFY(invalidChild.name().isEmpty());

    AccessibleObject invalidParent = app.parent();
    QVERIFY(!invalidParent.isValid());
    QVERIFY(invalidParent.name().isEmpty());
}

QTEST_MAIN(AccessibilityClientTest)

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